MFEM v4.8.0
Finite element discretization library
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
spiral.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2025, 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// Spiral Miniapp: Animation of a spiral cone toy
14// -----------------------------------------------
15//
16// Model of an interesting fidget spiral cone toy. The toy is made out of two
17// parts which can (surprisingly) pass through each other regardless of their
18// orientation.
19//
20// - STL model by Per Lundberg from https://www.thingiverse.com/thing:6682243
21// - Surface mesh generated by Gmsh (NOTE: not suitable for FEM simulations)
22//
23// NOTE: This miniapp requires a large mesh that is stored in the mfem/data
24// repository. Make sure to clone it from https://github.com/mfem/data.
25//
26// Compile with: make spiral
27//
28// Sample runs: spiral
29// spiral -c 2 -s 200
30// spiral -c 3 -no-col
31// spiral -c 7 -s 400 --movie
32// spiral -c 8
33
34#include "mfem.hpp"
35#include <fstream>
36#include <iostream>
37
38using namespace std;
39using namespace mfem;
40
41int main(int argc, char *argv[])
42{
43 // Parse command-line options.
44 string mfem_data_dir = "../../../data";
45 int conf = 1;
46 int steps = 100;
47 bool color = true;
48 bool movie = false;
49 bool visualization = true;
50
51 OptionsParser args(argc, argv);
52 args.AddOption(&mfem_data_dir, "-data", "--mfem_data_dir",
53 "Path to the mfem/data repo (required). Clone it from:\n"
54 "\t\thttps://github.com/mfem/data");
55 args.AddOption(&conf, "-c", "--configuration",
56 "Which configuration of the two parts to animate.\n"
57 "\tThere are 8 options denoted as P1 -> P2 for part P1\n"
58 "\tpassing through part P2, using the following notation:\n"
59 "\tI/O = inner/outer part, S/F = sharp/flat end.\n"
60 "\t\t1) OS -> IS 5) IS -> OS \n"
61 "\t\t2) OF -> IS 6) IS -> OF \n"
62 "\t\t3) OS -> IF 7) IF -> OS \n"
63 "\t\t4) OF -> IF 8) IF -> OF ");
64 args.AddOption(&steps, "-s", "--steps",
65 "Number of visualization steps in the animation.");
66 args.AddOption(&color, "-col", "--color", "-no-col", "--no-color",
67 "Visualize the parts with different colors.");
68 args.AddOption(&movie, "-mov", "--movie", "-no-mov", "--no-movie",
69 "Ask GLVis to take screenshots to make a movie.");
70 args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
71 "--no-visualization",
72 "Enable or disable GLVis visualization.");
73 args.Parse();
74 if (!args.Good())
75 {
76 args.PrintUsage(cout);
77 return 1;
78 }
79 args.PrintOptions(cout);
80
81 // Check that the required mesh (spiral-toy.vtk from mfem/data repo) exists
82 string mesh_file = mfem_data_dir + "/vtk/spiral-toy.vtk";
83 ifstream file(mesh_file);
84 if (!file.good())
85 {
86 cout << "Can't find the mesh file '" << mesh_file << "'\n"
87 << "Make sure the github.com/mfem/data repository is cloned in '"
88 << mfem_data_dir << "'\n";
89 return 2;
90 }
91
92 // Check for valid configuration
93 if (conf < 1 || conf > 8)
94 {
95 cerr << "Configuration option should be between 1 and 8. Setting to 1.\n";
96 conf = 1;
97 }
98
99 // Load mesh with the two spiral parts (below "inner" and "outer")
100 Mesh mesh(mfem_data_dir+"/vtk/spiral-toy.vtk", 1, 1);
101 H1_FECollection fec(1, 3);
102 FiniteElementSpace fespace(&mesh, &fec);
103 GridFunction part(&fespace);
104
105 // Mark inner/outer part vertices with 1.0/2.0 in the grid function part
106 for (int i = 0; i < mesh.GetNV(); i++)
107 {
108 real_t *v = mesh.GetVertex(i);
109 part[i] = (v[1] < -26.55) ? 1.0 : 2.0;
110 }
111
112 // Set different attributes for elements in inner/outer parts
113 for (int i = 0; i < mesh.GetNE(); i++)
114 {
115 Vector c(3);
116 mesh.GetElementCenter(i, c);
117 mesh.SetAttribute(i, (c(1) < -26.55) ? 1 : 2);
118 }
119
120 // Initiate visualization
121 char vishost[] = "localhost";
122 int visport = 19916;
123 socketstream sol_sock;
124
125 // Animate the two parts passing each other
126 for (int d = 0; d <= steps; d++)
127 {
128 // Fraction of the animation, from 0 to 1
129 real_t frac = ((real_t) d) / steps;
130
131 // Angle of rotation as function of frac
132 real_t phi = 0.0;
133 if (conf == 1 || conf == 5)
134 {
135 phi = -(10 * frac + 3.7);
136 }
137 if (conf == 2 || conf == 6)
138 {
139 phi = -(10 * frac + 2.8);
140 }
141 if (conf == 3 || conf == 7)
142 {
143 phi = -(10 * frac + 2.8);
144 }
145 if (conf == 4 || conf == 8)
146 {
147 phi = -(10 * frac + 3.2);
148 }
149
150 // Copy the mesh, as we will move the parts below
151 Mesh mesh2(mesh);
152
153 for (int i = 0; i < mesh.GetNV(); i++)
154 {
155 real_t *v = mesh2.GetVertex(i);
156
157 // Temporary variables
158 real_t v0 = 0.0;
159 real_t v1 = 0.0;
160 real_t v2 = 0.0;
161
162 // Move and rotate the outer part
163 if (part[i] == 1.0)
164 {
165 if (conf == 1 || conf == 3 || conf == 5 || conf == 7)
166 {
167 v0 = -v[0];
168 v1 = v[1] + 50.45;
169 v2 = 133.4 - 133.4*frac - v[2];
170 }
171
172 if (conf == 2 || conf == 4 || conf == 6 || conf == 8)
173 {
174 v0 = v[0];
175 v1 = v[1] + 50.45;
176 v2 = 73.04 - 133.4*frac + v[2];
177 }
178
179 if (conf == 1 || conf == 2 || conf == 3 || conf == 4)
180 {
181 v[0] = cos(phi)*v0 - sin(phi)*v1;
182 v[1] = sin(phi)*v0 + cos(phi)*v1;
183 v[2] = v2;
184 }
185
186 if (conf == 5 || conf == 6 || conf == 7 || conf == 8)
187 {
188 v[0] = -v0;
189 v[1] = v1;
190 v[2] = 133.4-v2;
191 }
192 }
193
194 // Move and rotate the inner part
195 if (part[i] == 2.0)
196 {
197 if (conf == 3 || conf == 4)
198 {
199 v[0] = -v[0];
200 v[2] = 73.04 - v[2];
201 }
202
203 if (conf == 5 || conf == 6)
204 {
205 v0 = -v[0];
206 v1 = v[1];
207 v[0] = cos(phi)*v0 - sin(phi)*v1;
208 v[1] = sin(phi)*v0 + cos(phi)*v1;
209 v[2] = 133.4-v[2];
210 }
211
212 if (conf == 7 || conf == 8)
213 {
214 v0 = v[0];
215 v1 = v[1];
216 v[0] = cos(phi)*v0 - sin(phi)*v1;
217 v[1] = sin(phi)*v0 + cos(phi)*v1;
218 v[2] = 60.36+v[2];
219 }
220 }
221 }
222
223 // Visualize the current configuration
224 if (visualization)
225 {
226 if (d == 0) // initial setup
227 {
228 sol_sock.open(vishost, visport);
229 sol_sock.precision(8);
230
231 if (color)
232 {
233 sol_sock << "solution\n" << mesh2 << part
234 << "keys A\n" << "palette 16\n";
235 }
236 else
237 {
238 sol_sock << "mesh\n" << mesh2
239 << "keys maaappppppptA\n" << "palette 12\n";
240 }
241
242 sol_sock << "window_geometry 0 0 500 1000\n"
243 << "zoom 3\n" << "autoscale on\n" << "pause\n";
244
245 cout << "To see the animation, press 'space' in the GLVis window\n";
246 }
247 else
248 {
249 if (color) // after the first frame
250 {
251 sol_sock << "solution\n" << mesh2 << part;
252 }
253 else
254 {
255 sol_sock << "mesh\n" << mesh2;
256 }
257 }
258
259 if (movie)
260 {
261 sol_sock << "screenshot spiral"
262 << setfill('0') << setw(3) << d << ".png\n";
263 }
264
265 sol_sock << flush;
266 }
267 }
268
269 if (movie)
270 {
271 cout << "A sequence of screenshot files: spiral000.png ... spiral"
272 << setfill('0') << setw(3) << steps << ".png\n"
273 << "have been saved in the directory from which GLVis is running.\n";
274 }
275
276 return 0;
277}
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition fespace.hpp:244
Class for grid function - Vector with associated FE space.
Definition gridfunc.hpp:31
Arbitrary order H1-conforming (continuous) finite elements.
Definition fe_coll.hpp:275
Mesh data type.
Definition mesh.hpp:64
void SetAttribute(int i, int attr)
Set the attribute of element i.
Definition mesh.cpp:7629
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1282
int GetNV() const
Returns number of vertices. Vertices are only at the corners of elements, where you would expect them...
Definition mesh.hpp:1279
void GetElementCenter(int i, Vector &center)
Definition mesh.cpp:77
const real_t * GetVertex(int i) const
Return pointer to vertex i's coordinates.
Definition mesh.hpp:1321
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.
Vector data type.
Definition vector.hpp:82
int open(const char hostname[], int port)
Open the socket stream on 'port' at 'hostname'.
int main()
float real_t
Definition config.hpp:43
const char vishost[]