MFEM v4.8.0
Finite element discretization library
Loading...
Searching...
No Matches
lissajous.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// Lissajous Miniapp: Spinning optical illusion
14// ---------------------------------------------
15//
16// This miniapp generates two different Lissajous curves in 3D which appear to
17// spin vertically and/or horizontally, even though the net motion is the same.
18// Based on the 2019 Illusion of the year "Dual Axis Illusion" by Frank Force,
19// see http://illusionoftheyear.com/2019/12/dual-axis-illusion.
20//
21// Compile with: make lissajous
22//
23// Sample runs: lissajous
24// lissajous -a 5 -b 4
25// lissajous -a 4 -b 3 -delta -90
26// lissajous -o 8 -nx 3 -ny 3
27// lissajous -a 11 -b 10 -o 4
28
29#include "mfem.hpp"
30#include <fstream>
31#include <iostream>
32
33using namespace std;
34using namespace mfem;
35
36real_t u_function(const Vector &x);
37void lissajous_trans_v(const Vector &x, Vector &p);
38void lissajous_trans_h(const Vector &x, Vector &p);
39
40// Default Lissajous curve parameters
41real_t a = 3.0;
42real_t b = 2.0;
44
45int main(int argc, char *argv[])
46{
47 int nx = 32;
48 int ny = 3;
49 int order = 2;
50 int visport = 19916;
51 bool visualization = true;
52
53 OptionsParser args(argc, argv);
54 args.AddOption(&nx, "-nx", "--num-elements-x",
55 "Number of elements in x-direction.");
56 args.AddOption(&ny, "-ny", "--num-elements-y",
57 "Number of elements in y-direction.");
58 args.AddOption(&order, "-o", "--mesh-order",
59 "Order (polynomial degree) of the mesh elements.");
60 args.AddOption(&a, "-a", "--x-frequency",
61 "Frequency of the x-component.");
62 args.AddOption(&b, "-b", "--y-frequency",
63 "Frequency of the y-component.");
64 args.AddOption(&delta, "-delta", "--x-phase",
65 "Phase angle of the x-component.");
66 args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
67 "--no-visualization",
68 "Enable or disable GLVis visualization.");
69 args.AddOption(&visport, "-p", "--send-port", "Socket for GLVis.");
70 args.Parse();
71 if (!args.Good())
72 {
73 args.PrintUsage(cout);
74 return 1;
75 }
76 args.PrintOptions(cout);
77
78 delta *= M_PI / 180.0; // convert to radians
79
80 char vishost[] = "localhost";
81 socketstream soutv, south;
82
83 {
85 nx, ny, Element::QUADRILATERAL, 1, 2*M_PI, 2*M_PI);
86 mesh.SetCurvature(order, true, 3, Ordering::byVDIM);
88
89 H1_FECollection fec(order, 3);
90 FiniteElementSpace fes(&mesh, &fec);
91 GridFunction u(&fes);
93 u.ProjectCoefficient(ufc);
94
95 if (visualization)
96 {
97 soutv.open(vishost, visport);
98 soutv << "solution\n" << mesh << u;
99 soutv << "keys 'ARRj" << std::string(90, '7') << "'\n";
100 soutv << "palette 17 zoom 1.65 subdivisions 32 0\n";
101 soutv << "window_title 'V' window_geometry 0 0 500 500\n";
102 soutv << flush;
103 }
104 }
105
106 {
108 nx, ny, Element::QUADRILATERAL, 1, 2*M_PI, 2*M_PI);
109 mesh.SetCurvature(order, true, 3, Ordering::byVDIM);
111
112 H1_FECollection fec(order, 3);
113 FiniteElementSpace fes(&mesh, &fec);
114 GridFunction u(&fes);
116 u.ProjectCoefficient(ufc);
117
118 if (visualization)
119 {
120 south.open(vishost, visport);
121 south << "solution\n" << mesh << u;
122 south << "keys 'ARRj'\n";
123 south << "palette 17 zoom 1.65 subdivisions 32 0\n";
124 south << "window_title 'H' window_geometry 500 0 500 500\n";
125 south << flush;
126 }
127
128 ofstream mesh_ofs("lissajous.mesh");
129 mesh_ofs.precision(8);
130 mesh.Print(mesh_ofs);
131 ofstream sol_ofs("lissajous.gf");
132 sol_ofs.precision(8);
133 u.Save(sol_ofs);
134 }
135
136 soutv << "keys '.0" << std::string((int)b, '0') << "'\n" << flush;
137 south << "keys '.0" << std::string((int)a, '0') << "'\n" << flush;
138
139 cout << "Which direction(s) are the two curves spinning in?\n";
140
141 return 0;
142}
143
144// Simple function to project to help identify the spinning
146{
147 return x[2];
148}
149
150// Tubular Lissajous curve with the given parameters (a, b, theta)
152 real_t a_, real_t b_, real_t delta_)
153{
154 p.SetSize(3);
155
156 real_t phi = x[0];
157 real_t theta = x[1];
158 real_t t = phi;
159
160 real_t A = b_; // Scaling of the curve along the x-axis
161 real_t B = a_; // Scaling of the curve along the y-axis
162
163 // Lissajous curve on a 3D cylinder
164 p[0] = B*cos(b_*t);
165 p[1] = B*sin(b_*t); // Y
166 p[2] = A*sin(a_*t + delta_); // X
167
168 // Turn the curve into a tubular surface
169 {
170 // tubular radius
171 real_t R = 0.02*(A+B);
172
173 // normal to the cylinder at p(t)
174 real_t normal[3] = { cos(b_*t), sin(b_*t), 0 };
175
176 // tangent to the curve, dp/dt(t)
177 // real_t tangent[3] = { -b_*B*sin(b_*t), b_*B*cos(b_*t), A*a_*cos(a_*t+delta_) };
178
179 // normalized cross product of tangent and normal at p(t)
180#ifdef MFEM_USE_SINGLE
181 real_t cn = 1e-32;
182#elif defined MFEM_USE_DOUBLE
183 real_t cn = 1e-128;
184#else
185 real_t cn = 0;
186 MFEM_ABORT("Floating point type undefined");
187#endif
188 real_t cross[3] = { A*a_*sin(b_*t)*cos(a_*t+delta_), -A*a_*cos(b_*t)*cos(a_*t+delta_), b_*B };
189 for (int i = 0; i < 3; i++) { cn += cross[i]*cross[i]; }
190 for (int i = 0; i < 3; i++) { cross[i] /= sqrt(cn); }
191
192 // create a tubular surface of radius R around the curve p(t), in the plane
193 // orthogonal to the tangent (with basis given by normal and cross)
194 for (int i = 0; i < 3; i++)
195 {
196 p[i] += R * (cos(theta)*normal[i] + sin(theta)*cross[i]);
197 }
198 }
199}
200
201// Vertically spinning curve
203{
204 return lissajous_trans(x, p, a, b, delta);
205}
206
207// Horizontally spinning curve
209{
210 return lissajous_trans(x, p, b, a, delta);
211}
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition fespace.hpp:244
A general function coefficient.
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
virtual void Print(std::ostream &os=mfem::out, const std::string &comments="") const
Definition mesh.hpp:2433
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:4471
virtual void SetCurvature(int order, bool discont=false, int space_dim=-1, int ordering=1)
Set the curvature of the mesh nodes using the given polynomial degree.
Definition mesh.cpp:6484
void Transform(void(*f)(const Vector &, Vector &))
Definition mesh.cpp:13146
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
void SetSize(int s)
Resize the vector to size s.
Definition vector.hpp:558
int open(const char hostname[], int port)
Open the socket stream on 'port' at 'hostname'.
int main()
real_t b
Definition lissajous.cpp:42
void lissajous_trans_v(const Vector &x, Vector &p)
void lissajous_trans(const Vector &x, Vector &p, real_t a_, real_t b_, real_t delta_)
real_t delta
Definition lissajous.cpp:43
void lissajous_trans_h(const Vector &x, Vector &p)
real_t u_function(const Vector &x)
real_t a
Definition lissajous.cpp:41
real_t u(const Vector &xvec)
Definition lor_mms.hpp:22
float real_t
Definition config.hpp:43
const char vishost[]
real_t p(const Vector &x, real_t t)