MFEM v4.8.0
Finite element discretization library
Loading...
Searching...
No Matches
klein-bottle.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// Klein Bottle Miniapp: Generate Klein bottle meshes
14// ---------------------------------------------------
15//
16// This miniapp generates three types of Klein bottle surfaces. It is similar to
17// the mobius-strip miniapp. The klein-bottle and klein-donut meshes in the
18// data/ directory were generated with this miniapp.
19//
20// Compile with: make klein-bottle
21//
22// Sample runs: klein-bottle
23// klein-bottle -o 6 -nx 8 -ny 4
24// klein-bottle -t 0
25// klein-bottle -t 0 -o 6 -nx 6 -ny 4
26// klein-bottle -t 2
27
28#include "mfem.hpp"
29#include <fstream>
30#include <iostream>
31
32using namespace std;
33using namespace mfem;
34
35void figure8_trans(const Vector &x, Vector &p);
36void bottle_trans(const Vector &x, Vector &p);
37void bottle2_trans(const Vector &x, Vector &p);
38
39int main(int argc, char *argv[])
40{
41 const char *new_mesh_file = "klein-bottle.mesh";
42 int nx = 16;
43 int ny = 8;
44 int order = 3;
45 int trans_type = 1;
46 bool dg_mesh = false;
47 int visport = 19916;
48 bool visualization = true;
49
50 OptionsParser args(argc, argv);
51 args.AddOption(&new_mesh_file, "-m", "--mesh-out-file",
52 "Output Mesh file to write.");
53 args.AddOption(&nx, "-nx", "--num-elements-x",
54 "Number of elements in x-direction.");
55 args.AddOption(&ny, "-ny", "--num-elements-y",
56 "Number of elements in y-direction.");
57 args.AddOption(&order, "-o", "--mesh-order",
58 "Order (polynomial degree) of the mesh elements.");
59 args.AddOption(&trans_type, "-t", "--transformation-type",
60 "Set the transformation type: 0 - \"figure-8\","
61 " 1 - \"bottle\", 2 - \"bottle2\".");
62 args.AddOption(&dg_mesh, "-dm", "--discont-mesh", "-cm", "--cont-mesh",
63 "Use discontinuous or continuous space for the mesh nodes.");
64 args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
65 "--no-visualization",
66 "Enable or disable GLVis visualization.");
67 args.AddOption(&visport, "-p", "--send-port", "Socket for GLVis.");
68 args.Parse();
69 if (!args.Good())
70 {
71 args.PrintUsage(cout);
72 return 1;
73 }
74 args.PrintOptions(cout);
75
76 // The mesh could use quads (default) or triangles
78 // Element::Type el_type = Element::TRIANGLE;
79 Mesh mesh = Mesh::MakeCartesian2D(nx, ny, el_type, 1, 2*M_PI, 2*M_PI);
80
81 mesh.SetCurvature(order, true, 3, Ordering::byVDIM);
82
83 {
84 Array<int> v2v(mesh.GetNV());
85 for (int i = 0; i < v2v.Size(); i++)
86 {
87 v2v[i] = i;
88 }
89 // identify vertices on horizontal lines (without a flip)
90 for (int i = 0; i <= nx; i++)
91 {
92 int v_old = i + ny * (nx + 1);
93 int v_new = i;
94 v2v[v_old] = v_new;
95 }
96 // identify vertices on vertical lines (with a flip)
97 for (int j = 0; j <= ny; j++)
98 {
99 int v_old = nx + j * (nx + 1);
100 int v_new = (ny - j) * (nx + 1);
101 v2v[v_old] = v2v[v_new];
102 }
103 // renumber elements
104 for (int i = 0; i < mesh.GetNE(); i++)
105 {
106 Element *el = mesh.GetElement(i);
107 int *v = el->GetVertices();
108 int nv = el->GetNVertices();
109 for (int j = 0; j < nv; j++)
110 {
111 v[j] = v2v[v[j]];
112 }
113 }
114 // renumber boundary elements
115 for (int i = 0; i < mesh.GetNBE(); i++)
116 {
117 Element *el = mesh.GetBdrElement(i);
118 int *v = el->GetVertices();
119 int nv = el->GetNVertices();
120 for (int j = 0; j < nv; j++)
121 {
122 v[j] = v2v[v[j]];
123 }
124 }
127 }
128
129 switch (trans_type)
130 {
131 case 0: mesh.Transform(figure8_trans); break;
132 case 1: mesh.Transform(bottle_trans); break;
133 case 2: mesh.Transform(bottle2_trans); break;
134 default: mesh.Transform(bottle_trans); break;
135 }
136
137 if (!dg_mesh)
138 {
139 mesh.SetCurvature(order, false, 3, Ordering::byVDIM);
140 }
141
142 GridFunction &nodes = *mesh.GetNodes();
143 for (int i = 0; i < nodes.Size(); i++)
144 {
145 if (std::abs(nodes(i)) < 1e-12)
146 {
147 nodes(i) = 0.0;
148 }
149 }
150
151 ofstream ofs(new_mesh_file);
152 ofs.precision(8);
153 mesh.Print(ofs);
154 ofs.close();
155
156 if (visualization)
157 {
158 char vishost[] = "localhost";
159 socketstream sol_sock(vishost, visport);
160 sol_sock.precision(8);
161 sol_sock << "mesh\n" << mesh << flush;
162 }
163
164 return 0;
165}
166
167void figure8_trans(const Vector &x, Vector &p)
168{
169 const real_t r = 2.5;
170 real_t a = r + cos(x(0)/2) * sin(x(1)) - sin(x(0)/2) * sin(2*x(1));
171
172 p.SetSize(3);
173 p(0) = a * cos(x(0));
174 p(1) = a * sin(x(0));
175 p(2) = sin(x(0)/2) * sin(x(1)) + cos(x(0)/2) * sin(2*x(1));
176}
177
178void bottle_trans(const Vector &x, Vector &p)
179{
180 real_t u = x(0);
181 real_t v = x(1) + M_PI_2;
182 real_t a = 6.*cos(u)*(1.+sin(u));
183 real_t b = 16.*sin(u);
184 real_t r = 4.*(1.-cos(u)/2.);
185
186 if (u <= M_PI)
187 {
188 p(0) = a+r*cos(u)*cos(v);
189 p(1) = b+r*sin(u)*cos(v);
190 }
191 else
192 {
193 p(0) = a+r*cos(v+M_PI);
194 p(1) = b;
195 }
196 p(2) = r*sin(v);
197}
198
199void bottle2_trans(const Vector &x, Vector &p)
200{
201 real_t u = x(1)-M_PI_2, v = 2*x(0);
202 const real_t pi = M_PI;
203
204 p(0) = (v<pi ? (2.5-1.5*cos(v))*cos(u) :
205 (v<2*pi ? (2.5-1.5*cos(v))*cos(u) :
206 (v<3*pi ? -2+(2+cos(u))*cos(v) : -2+2*cos(v)-cos(u))));
207 p(1) = (v<pi ? (2.5-1.5*cos(v))*sin(u) :
208 (v<2*pi ? (2.5-1.5*cos(v))*sin(u) :
209 (v<3*pi ? sin(u) : sin(u))));
210 p(2) = (v<pi ? -2.5*sin(v) :
211 (v<2*pi ? 3*v-3*pi :
212 (v<3*pi ? (2+cos(u))*sin(v)+3*pi : -3*v+12*pi)));
213}
int Size() const
Return the logical size of the array.
Definition array.hpp:147
Abstract data type element.
Definition element.hpp:29
virtual void GetVertices(Array< int > &v) const =0
Get the indices defining the vertices.
Type
Constants for the classes derived from Element.
Definition element.hpp:41
virtual int GetNVertices() const =0
Class for grid function - Vector with associated FE space.
Definition gridfunc.hpp:31
Mesh data type.
Definition mesh.hpp:64
const Element * GetElement(int i) const
Return pointer to the i'th element object.
Definition mesh.hpp:1339
virtual void Print(std::ostream &os=mfem::out, const std::string &comments="") const
Definition mesh.hpp:2433
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1282
const Element * GetBdrElement(int i) const
Return pointer to the i'th boundary element object.
Definition mesh.hpp:1354
void GetNodes(Vector &node_coord) const
Definition mesh.cpp:9294
int GetNV() const
Returns number of vertices. Vertices are only at the corners of elements, where you would expect them...
Definition mesh.hpp:1279
int GetNBE() const
Returns number of boundary elements.
Definition mesh.hpp:1285
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 RemoveInternalBoundaries()
Definition mesh.cpp:13304
void RemoveUnusedVertices()
Remove unused vertices and rebuild mesh connectivity.
Definition mesh.cpp:13197
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 main()
void figure8_trans(const Vector &x, Vector &p)
void bottle_trans(const Vector &x, Vector &p)
void bottle2_trans(const Vector &x, Vector &p)
real_t b
Definition lissajous.cpp:42
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)
std::array< int, NCMesh::MaxFaceNodes > nodes