MFEM  v4.5.1
Finite element discretization library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
automata.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010-2022, 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 
35 using namespace std;
36 using namespace mfem;
37 
38 void PrintRule(bitset<8> & r);
39 void ApplyRule(vector<bool> * b[], bitset<8> & r, int ns, int s);
40 void ProjectStep(const vector<bool> & b, GridFunction & x, int ns, int s);
41 
42 int 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.
67  Mesh mesh = Mesh::MakeCartesian2D(2 * ns - 1, ns, Element::QUADRILATERAL,
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 
165 bool 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 
170 void 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 
185 void 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 
195 void 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] = (double)b[i];
200  }
201 }
Class for grid function - Vector with associated FE space.
Definition: gridfunc.hpp:30
virtual void Save(std::ostream &out) const
Save the GridFunction to an output stream.
Definition: gridfunc.cpp:3676
void Parse()
Parse the command-line options. Note that this function expects all the options provided through the ...
Definition: optparser.cpp:151
constexpr char vishost[]
double b
Definition: lissajous.cpp:42
constexpr int visport
void PrintRule(bitset< 8 > &r)
Definition: automata.cpp:170
void PrintUsage(std::ostream &out) const
Print the usage message.
Definition: optparser.cpp:454
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition: fespace.hpp:96
Collection of finite elements from the same family in multiple dimensions. This class is used to matc...
Definition: fe_coll.hpp:26
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 &#39;var&#39; to receive the value. Enable/disable tags are used to set the bool...
Definition: optparser.hpp:82
void ApplyRule(vector< bool > *b[], bitset< 8 > &r, int ns, int s)
Definition: automata.cpp:185
virtual void Print(std::ostream &os=mfem::out) const
Definition: mesh.hpp:1671
void ProjectStep(const vector< bool > &b, GridFunction &x, int ns, int s)
Definition: automata.cpp:195
void PrintOptions(std::ostream &out) const
Print the options.
Definition: optparser.cpp:324
bool Rule(bitset< 8 > &r, bool b0, bool b1, bool b2)
Definition: automata.cpp:165
int open(const char hostname[], int port)
Open the socket stream on &#39;port&#39; at &#39;hostname&#39;.
RefCoord s[3]
int main()
Arbitrary order &quot;L2-conforming&quot; discontinuous finite elements.
Definition: fe_coll.hpp:288
bool Good() const
Return true if the command line options were parsed successfully.
Definition: optparser.hpp:150