// Copyright (c) 2010-2023, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // // This file is part of the MFEM library. For more information and source code // availability visit https://mfem.org. // // MFEM is free software; you can redistribute it and/or modify it under the // terms of the BSD-3 license. We welcome feedback and contributions, see file // CONTRIBUTING.md for details. // // ---------------------------------------------------- // Automata Miniapp: Model of simple cellular automata // ---------------------------------------------------- // // This miniapp implements a one dimensional elementary cellular automata // as described in: mathworld.wolfram.com/ElementaryCellularAutomaton.html // // This miniapp shows a completely unnecessary use of the finite element // method to simply display binary data (but it's fun to play with). // // Compile with: make automata // // Sample runs: automata // automata -r 110 -ns 32 // automata -r 30 -ns 96 #include "mfem.hpp" #include #include #include #include #include using namespace std; using namespace mfem; void PrintRule(bitset<8> & r); void ApplyRule(vector * b[], bitset<8> & r, int ns, int s); void ProjectStep(const vector & b, GridFunction & x, int ns, int s); int main(int argc, char *argv[]) { // 1. Parse command-line options. int ns = 16; int r = 90; bool visualization = 1; OptionsParser args(argc, argv); args.AddOption(&ns, "-ns", "--num-steps", "Number of steps of the 1D cellular automaton."); args.AddOption(&r, "-r", "--rule", "Elementary cellular automaton rule [0-255]."); args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", "--no-visualization", "Enable or disable GLVis visualization."); args.Parse(); if (!args.Good()) { args.PrintUsage(cout); return 1; } args.PrintOptions(cout); // 2. Build a rectangular mesh of quadrilateral elements nearly twice // as wide as it is high. Mesh mesh = Mesh::MakeCartesian2D(2 * ns - 1, ns, Element::QUADRILATERAL, 0, 2 * ns - 1, ns, false); // 3. Define a finite element space on the mesh. Here we use discontinuous // Lagrange finite elements of order zero i.e. piecewise constant basis // functions. FiniteElementCollection *fec = new L2_FECollection(0, 2); FiniteElementSpace *fespace = new FiniteElementSpace(&mesh, fec); // 4. Initialize a pair of bit arrays to store two rows in the evolution // of our cellular automaton. int len = 2 * ns - 1; vector * vbp[2]; vector vb0(len); vector vb1(len); vbp[0] = &vb0; vbp[1] = &vb1; for (int i=0; i rbs = r; PrintRule(rbs); // Transfer the current row of the automaton to the vector x. ProjectStep(*vbp[0], x, ns, 0); // 8. Apply the rule iteratively cout << endl << "Applying rule..." << flush; for (int s=1; s & r, bool b0, bool b1, bool b2) { return r[(b0 ? 1 : 0) + (b1 ? 2 : 0) + (b2 ? 4 : 0)]; } void PrintRule(bitset<8> & r) { cout << endl << "Rule:" << endl; for (int i=7; i>=0; i--) { cout << " " << i/4 << (i/2)%2 << i%2; } cout << endl; for (int i=7; i>=0; i--) { cout << " " << Rule(r,i%2,(i/2)%2,i/4) << " "; } cout << endl; } void ApplyRule(vector * b[], bitset<8> & r, int ns, int s) { for (int i=0; i<2*ns-1; i++) { int i0 = (i + 2 * ns - 2) % (2 * ns - 1); int i2 = (i + 1) % (2 * ns - 1); (*b[1])[i] = Rule(r, (*b[0])[i0], (*b[0])[i], (*b[0])[i2]); } } void ProjectStep(const vector & b, GridFunction & x, int ns, int s) { for (int i=0; i<2*ns-1; i++) { x[s*(2*ns-1)+i] = (double)b[i]; } }