MFEM v4.7.0
Finite element discretization library
Loading...
Searching...
No Matches
automata.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11//
12// ----------------------------------------------------
13// Automata Miniapp: Model of simple cellular automata
14// ----------------------------------------------------
15//
16// This miniapp implements a one dimensional elementary cellular automata
17// as described in: mathworld.wolfram.com/ElementaryCellularAutomaton.html
18//
19// This miniapp shows a completely unnecessary use of the finite element
20// method to simply display binary data (but it's fun to play with).
21//
22// Compile with: make automata
23//
24// Sample runs: automata
25// automata -r 110 -ns 32
26// automata -r 30 -ns 96
27
28#include "mfem.hpp"
29#include <algorithm>
30#include <fstream>
31#include <iostream>
32#include <bitset>
33#include <vector>
34
35using namespace std;
36using namespace mfem;
37
38void PrintRule(bitset<8> & r);
39void ApplyRule(vector<bool> * b[], bitset<8> & r, int ns, int s);
40void ProjectStep(const vector<bool> & b, GridFunction & x, int ns, int s);
41
42int main(int argc, char *argv[])
43{
44 // 1. Parse command-line options.
45 int ns = 16;
46 int r = 90;
47 bool visualization = 1;
48
49 OptionsParser args(argc, argv);
50 args.AddOption(&ns, "-ns", "--num-steps",
51 "Number of steps of the 1D cellular automaton.");
52 args.AddOption(&r, "-r", "--rule",
53 "Elementary cellular automaton rule [0-255].");
54 args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
55 "--no-visualization",
56 "Enable or disable GLVis visualization.");
57 args.Parse();
58 if (!args.Good())
59 {
60 args.PrintUsage(cout);
61 return 1;
62 }
63 args.PrintOptions(cout);
64
65 // 2. Build a rectangular mesh of quadrilateral elements nearly twice
66 // as wide as it is high.
68 0, 2 * ns - 1, ns, false);
69
70 // 3. Define a finite element space on the mesh. Here we use discontinuous
71 // Lagrange finite elements of order zero i.e. piecewise constant basis
72 // functions.
74 FiniteElementSpace *fespace = new FiniteElementSpace(&mesh, fec);
75
76 // 4. Initialize a pair of bit arrays to store two rows in the evolution
77 // of our cellular automaton.
78 int len = 2 * ns - 1;
79
80 vector<bool> * vbp[2];
81 vector<bool> vb0(len);
82 vector<bool> vb1(len);
83
84 vbp[0] = &vb0;
85 vbp[1] = &vb1;
86
87 for (int i=0; i<len; i++)
88 {
89 vb0[i] = false;
90 vb1[i] = false;
91 }
92 vb0[ns-1] = true;
93
94 // 5. Define the vector x as a finite element grid function corresponding
95 // to fespace which will be used to visualize the cellular automata.
96 // Initialize x with initial condition of zero, which indicates a
97 // "white" or "off" cell in our automaton.
98 GridFunction x(fespace);
99 x = 0.0;
100
101 // 6. Open a socket to GLVis to visualize the automaton.
102 socketstream sol_sock;
103 if (visualization)
104 {
105 char vishost[] = "localhost";
106 int visport = 19916;
107 sol_sock.open(vishost, visport);
108 }
109
110 // 7. Create the rule as a bitset and display it for the user
111 bitset<8> rbs = r;
112 PrintRule(rbs);
113
114 // Transfer the current row of the automaton to the vector x.
115 ProjectStep(*vbp[0], x, ns, 0);
116
117 // 8. Apply the rule iteratively
118 cout << endl << "Applying rule..." << flush;
119 for (int s=1; s<ns; s++)
120 {
121 // Compute the next row from the current row
122 ApplyRule(vbp, rbs, ns, s);
123
124 // Transfer the new row of the automaton to the vector x.
125 ProjectStep(*vbp[1], x, ns, s);
126
127 // Swap bit arrays
128 std::swap(vbp[0], vbp[1]);
129
130 // 9. Send the solution by socket to a GLVis server.
131 if (visualization)
132 {
133 sol_sock << "solution\n" << mesh << x << flush;
134 {
135 static int once = 1;
136 if (once)
137 {
138 sol_sock << "keys Ajl\n";
139 sol_sock << "view 0 180\n";
140 sol_sock << "zoom 2.2\n";
141 sol_sock << "palette 24\n";
142 once = 0;
143 }
144 }
145 }
146 }
147 cout << "done." << endl;
148
149 // 10. Save the mesh and the final state of the automaton. This output can be
150 // viewed later using GLVis: "glvis -m automata.mesh -g automata.gf".
151 ofstream mesh_ofs("automata.mesh");
152 mesh_ofs.precision(8);
153 mesh.Print(mesh_ofs);
154 ofstream sol_ofs("automata.gf");
155 sol_ofs.precision(8);
156 x.Save(sol_ofs);
157
158 // 11. Free the used memory.
159 delete fespace;
160 delete fec;
161
162 return 0;
163}
164
165bool Rule(bitset<8> & r, bool b0, bool b1, bool b2)
166{
167 return r[(b0 ? 1 : 0) + (b1 ? 2 : 0) + (b2 ? 4 : 0)];
168}
169
170void PrintRule(bitset<8> & r)
171{
172 cout << endl << "Rule:" << endl;
173 for (int i=7; i>=0; i--)
174 {
175 cout << " " << i/4 << (i/2)%2 << i%2;
176 }
177 cout << endl;
178 for (int i=7; i>=0; i--)
179 {
180 cout << " " << Rule(r,i%2,(i/2)%2,i/4) << " ";
181 }
182 cout << endl;
183}
184
185void ApplyRule(vector<bool> * b[], bitset<8> & r, int ns, int s)
186{
187 for (int i=0; i<2*ns-1; i++)
188 {
189 int i0 = (i + 2 * ns - 2) % (2 * ns - 1);
190 int i2 = (i + 1) % (2 * ns - 1);
191 (*b[1])[i] = Rule(r, (*b[0])[i0], (*b[0])[i], (*b[0])[i2]);
192 }
193}
194
195void ProjectStep(const vector<bool> & b, GridFunction & x, int ns, int s)
196{
197 for (int i=0; i<2*ns-1; i++)
198 {
199 x[s*(2*ns-1)+i] = (real_t)b[i];
200 }
201}
void ProjectStep(const vector< bool > &b, GridFunction &x, int ns, int s)
Definition automata.cpp:195
bool Rule(bitset< 8 > &r, bool b0, bool b1, bool b2)
Definition automata.cpp:165
void ApplyRule(vector< bool > *b[], bitset< 8 > &r, int ns, int s)
Definition automata.cpp:185
void PrintRule(bitset< 8 > &r)
Definition automata.cpp:170
Collection of finite elements from the same family in multiple dimensions. This class is used to matc...
Definition fe_coll.hpp:27
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition fespace.hpp:220
Class for grid function - Vector with associated FE space.
Definition gridfunc.hpp:31
virtual void Save(std::ostream &out) const
Save the GridFunction to an output stream.
Arbitrary order "L2-conforming" discontinuous finite elements.
Definition fe_coll.hpp:330
Mesh data type.
Definition mesh.hpp:56
virtual void Print(std::ostream &os=mfem::out, const std::string &comments="") const
Definition mesh.hpp:2288
static Mesh MakeCartesian2D(int nx, int ny, Element::Type type, bool generate_edges=false, real_t sx=1.0, real_t sy=1.0, bool sfc_ordering=true)
Creates mesh for the rectangle [0,sx]x[0,sy], divided into nx*ny quadrilaterals if type = QUADRILATER...
Definition mesh.cpp:4243
void Parse()
Parse the command-line options. Note that this function expects all the options provided through the ...
void PrintUsage(std::ostream &out) const
Print the usage message.
void PrintOptions(std::ostream &out) const
Print the options.
void AddOption(bool *var, const char *enable_short_name, const char *enable_long_name, const char *disable_short_name, const char *disable_long_name, const char *description, bool required=false)
Add a boolean option and set 'var' to receive the value. Enable/disable tags are used to set the bool...
Definition optparser.hpp:82
bool Good() const
Return true if the command line options were parsed successfully.
int open(const char hostname[], int port)
Open the socket stream on 'port' at 'hostname'.
int main()
real_t b
Definition lissajous.cpp:42
const int visport
float real_t
Definition config.hpp:43
const char vishost[]
RefCoord s[3]