libMesh
Loading...
Searching...
No Matches
write_vec_and_scalar.C
Go to the documentation of this file.
1// Basic include files
2#include "libmesh/distributed_mesh.h"
3#include "libmesh/equation_systems.h"
4#include "libmesh/exodusII_io.h"
5#include "libmesh/explicit_system.h"
6#include "libmesh/mesh_generation.h"
7#include "libmesh/nemesis_io.h"
8#include "libmesh/node.h"
9#include "libmesh/numeric_vector.h"
10#include "libmesh/replicated_mesh.h"
11#include "libmesh/string_to_enum.h"
12
13#include "test_comm.h"
14#include "libmesh_cppunit.h"
15
16
17// Bring in everything from the libMesh namespace
18using namespace libMesh;
19
20class WriteVecAndScalar : public CppUnit::TestCase
21{
25public:
27
28#if LIBMESH_DIM > 1
29#if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API)
34#endif
35#endif
36
38
39 void setupTests(UnstructuredMesh & mesh, EquationSystems & equation_systems)
40 {
41 // We set our initial conditions based on build_square node ids
43
45 1, 1,
46 -1., 1.,
47 -1., 1.,
48 Utility::string_to_enum<ElemType>("TRI6"));
49
50 ExplicitSystem & system = equation_systems.add_system<ExplicitSystem>("Tester");
51 system.add_variable("u", FIRST, NEDELEC_ONE);
52 system.add_variable("v", FIRST, LAGRANGE);
53
54 // Initialize the system
55 equation_systems.init();
56
57 // Mimic the initial conditions of u(i)=2*i in the serial case,
58 // but indexed by node id rather than dof id.
59 std::vector<Real> initial_vector({10, 0, 12, 8, 4, 2, 16, 6, 14});
60
61 NumericVector<Number> & sys_solution = *(system.solution);
62 for (const auto & node : mesh.node_ptr_range())
63 {
64 dof_id_type dof_id;
65 if (node->n_comp(0,0))
66 {
67 dof_id = node->dof_number(0,0,0);
68 }
69 else
70 {
71 CPPUNIT_ASSERT(node->n_comp(0,1));
72 dof_id = node->dof_number(0,1,0);
73 }
74 if (dof_id >= sys_solution.first_local_index() &&
75 dof_id < sys_solution.last_local_index())
76 sys_solution.set(dof_id, initial_vector[node->id()]);
77 if (mesh.n_processors() == 1)
78 CPPUNIT_ASSERT_EQUAL(initial_vector[node->id()], dof_id*Real(2));
79 }
80 sys_solution.close();
81 }
82
83
84 void testSolution (const MeshBase & read_mesh, const System & sys2)
85 {
86 // VariableGroup optimization means that DoFs iterate over each of
87 // the 3 variables on each node before proceeding to the next
88 // node.
89 // u_x, u_y, v
90 const std::vector<Real> gold_vector = {-1, 3, 10,
91 0, 1, 12,
92 2, 0, 14,
93 0, 1.5, 11,
94 0.5, 1, 13,
95 0.5, 1.5, 12,
96 3, 4, 16,
97 3, 1.5, 15,
98 0.5, 4, 13};
99
100 // Translation from a node's position on the generating 3x3 grid
101 // to dof indexing order as gets done in serial. We look nodes up
102 // by position (rather than by id) because Nemesis reassigns node
103 // ids on read based on partition ownership, so a read-back node's
104 // id need not match the id it had when the file was written.
105 const std::vector<dof_id_type>
106 node_reordering({0, 3, 1, 8, 5, 4, 6, 7, 2});
107
108 Real tol = 1e-12;
109 NumericVector<Number> & sys2_soln(*sys2.solution);
110 for (const auto & node : read_mesh.node_ptr_range())
111 {
112 if (node->processor_id() != read_mesh.processor_id())
113 continue;
114
115 // We write out real, imaginary, and magnitude for complex
116 // numbers
117#ifdef LIBMESH_USE_COMPLEX_NUMBERS
118 const unsigned int v2 = 3;
119#else
120 const unsigned int v2 = 1;
121#endif
122 CPPUNIT_ASSERT_EQUAL(node->n_vars(0), 3*v2);
123
124 // The mesh is the 3x3 grid of nodes generated by
125 // build_square(-1,1,-1,1), so each coordinate is one of
126 // {-1,0,1}; map that directly to a 0-based grid index.
127 const auto grid_index =
128 cast_int<dof_id_type>(std::lround((*node)(0)) + 1 +
129 3*(std::lround((*node)(1)) + 1));
130
131 CPPUNIT_ASSERT_LESS(node_reordering.size(), std::size_t(grid_index));
132 const dof_id_type gold_i_ux = node_reordering[grid_index] * 3;
133 const dof_id_type gold_i_uy = gold_i_ux + 1;
134 const dof_id_type gold_i_v = gold_i_uy + 1;
135 CPPUNIT_ASSERT_LESS(gold_vector.size(), std::size_t(gold_i_v));
136
137 LIBMESH_ASSERT_NUMBERS_EQUAL(sys2_soln(node->dof_number(0,0,0)),
138 gold_vector[gold_i_ux], tol);
139 LIBMESH_ASSERT_NUMBERS_EQUAL(sys2_soln(node->dof_number(0,v2,0)),
140 gold_vector[gold_i_uy], tol);
141 LIBMESH_ASSERT_NUMBERS_EQUAL(sys2_soln(node->dof_number(0,2*v2,0)),
142 gold_vector[gold_i_v], tol);
143
144 // Let's check imaginary parts and magnitude for good measure
145#ifdef LIBMESH_USE_COMPLEX_NUMBERS
146 LIBMESH_ASSERT_NUMBERS_EQUAL(sys2_soln(node->dof_number(0,1,0)),
147 0.0, tol);
148 LIBMESH_ASSERT_NUMBERS_EQUAL(sys2_soln(node->dof_number(0,2,0)),
149 std::abs(gold_vector[gold_i_ux]), tol);
150 LIBMESH_ASSERT_NUMBERS_EQUAL(sys2_soln(node->dof_number(0,4,0)),
151 0.0, tol);
152 LIBMESH_ASSERT_NUMBERS_EQUAL(sys2_soln(node->dof_number(0,5,0)),
153 std::abs(gold_vector[gold_i_uy]), tol);
154 LIBMESH_ASSERT_NUMBERS_EQUAL(sys2_soln(node->dof_number(0,7,0)),
155 0.0, tol);
156 LIBMESH_ASSERT_NUMBERS_EQUAL(sys2_soln(node->dof_number(0,8,0)),
157 std::abs(gold_vector[gold_i_v]), tol);
158#endif
159 }
160 }
161
162
163#ifdef LIBMESH_HAVE_EXODUS_API
164 template <typename MeshType>
165 void testWriteExodus(const std::string & filename)
166 {
167 MeshType mesh(*TestCommWorld);
168 EquationSystems equation_systems(mesh);
169
170 setupTests(mesh, equation_systems);
171
172 // Make sure any previous reads are done before the writing starts
173 TestCommWorld->barrier();
174
175 // We write the file in the ExodusII format.
176 ExodusII_IO(mesh).write_equation_systems(filename, equation_systems);
177
178 // Make sure that the writing is done before the reading starts.
179 TestCommWorld->barrier();
180
181 // Now read it back in
182 MeshType read_mesh(*TestCommWorld);
183 read_mesh.allow_renumbering(false);
184 ExodusII_IO exio(read_mesh);
185 exio.read(filename);
186
187 read_mesh.prepare_for_use();
188 EquationSystems es2(read_mesh);
189 ExplicitSystem & sys2 = es2.add_system<ExplicitSystem>("Test");
190
191 const std::vector<std::string> & nodal_vars(exio.get_nodal_var_names());
192
193 for (const auto & var_name : nodal_vars)
194 sys2.add_variable(var_name, SECOND, LAGRANGE);
195
196 es2.init();
197
198 for (const auto & var_name : nodal_vars)
199 exio.copy_nodal_solution(sys2, var_name, var_name, 1);
200
201 testSolution(read_mesh, sys2);
202 }
203
204 void testWriteExodusReplicated() { LOG_UNIT_TEST; testWriteExodus<ReplicatedMesh>("rep.e"); }
205 void testWriteExodusDistributed() { LOG_UNIT_TEST; testWriteExodus<DistributedMesh>("dist.e"); }
206#endif // #ifdef LIBMESH_HAVE_EXODUS_API
207
208
209#ifdef LIBMESH_HAVE_NEMESIS_API
210 template <typename MeshType>
211 void testWriteNemesis(const std::string & filename)
212 {
213 MeshType mesh(*TestCommWorld);
214 EquationSystems equation_systems(mesh);
215
216 setupTests(mesh, equation_systems);
217
218 // Make sure any previous reads are done before the writing starts
219 TestCommWorld->barrier();
220
221 // We write the file in the Nemesis format.
222 Nemesis_IO(mesh).write_equation_systems(filename, equation_systems);
223
224 // Make sure that the writing is done before the reading starts.
225 TestCommWorld->barrier();
226
227 // Now read it back in
228 MeshType read_mesh(*TestCommWorld);
229 read_mesh.allow_renumbering(false);
230 Nemesis_IO nemio(read_mesh);
231 nemio.read(filename);
232
233 read_mesh.prepare_for_use();
234 EquationSystems es2(read_mesh);
235 ExplicitSystem & sys2 = es2.add_system<ExplicitSystem>("Test");
236
237 const std::vector<std::string> & nodal_vars(nemio.get_nodal_var_names());
238
239 for (const auto & var_name : nodal_vars)
240 sys2.add_variable(var_name, SECOND, LAGRANGE);
241
242 es2.init();
243
244 for (const auto & var_name : nodal_vars)
245 nemio.copy_nodal_solution(sys2, var_name, var_name, 1);
246
247 testSolution(read_mesh, sys2);
248 }
249
250 void testWriteNemesisReplicated() { LOG_UNIT_TEST; testWriteNemesis<ReplicatedMesh>("rep.nem"); }
251 void testWriteNemesisDistributed() { LOG_UNIT_TEST; testWriteNemesis<DistributedMesh>("dist.nem"); }
252#endif // #ifdef LIBMESH_HAVE_NEMESIS_API
253
254};
255
void testSolution(const MeshBase &read_mesh, const System &sys2)
void setupTests(UnstructuredMesh &mesh, EquationSystems &equation_systems)
void testWriteExodus(const std::string &filename)
void testWriteNemesis(const std::string &filename)
CPPUNIT_TEST(testWriteExodusReplicated)
CPPUNIT_TEST(testWriteExodusDistributed)
LIBMESH_CPPUNIT_TEST_SUITE(WriteVecAndScalar)
This test ensures you can write both vector and scalar variables.
CPPUNIT_TEST(testWriteNemesisDistributed)
CPPUNIT_TEST(testWriteNemesisReplicated)
This is the EquationSystems class.
virtual void init()
Initialize all the systems.
virtual System & add_system(std::string_view system_type, std::string_view name)
Add the system of type system_type named name to the systems array.
The ExodusII_IO class implements reading meshes in the ExodusII file format from Sandia National Labs...
Definition exodusII_io.h:53
virtual void write_equation_systems(const std::string &fname, const EquationSystems &es, const std::set< std::string > *system_names=nullptr) override
Writes out the solution for no specific time or timestep.
void copy_nodal_solution(System &system, std::string system_var_name, std::string exodus_var_name, unsigned int timestep=1)
If we read in a nodal solution while reading in a mesh, we can attempt to copy that nodal solution in...
const std::vector< std::string > & get_nodal_var_names()
Return list of the nodal variable names.
virtual void read(const std::string &name) override
This method implements reading a mesh from a specified file.
Manages consistently variables, degrees of freedom, and coefficient vectors for explicit systems.
This is the MeshBase class.
Definition mesh_base.h:81
void allow_renumbering(bool allow)
If false is passed in then this mesh will no longer be renumbered when being prepared for use.
Definition mesh_base.h:1359
virtual void write_equation_systems(const std::string &, const EquationSystems &, const std::set< std::string > *system_names=nullptr)
This method implements writing a mesh with data to a specified file where the data is taken from the ...
Definition mesh_output.C:31
The Nemesis_IO class implements reading parallel meshes in the Nemesis file format from Sandia Nation...
Definition nemesis_io.h:54
const std::vector< std::string > & get_nodal_var_names()
Return list of the nodal variable names.
virtual void read(const std::string &base_filename) override
Implements reading the mesh from several different files.
Definition nemesis_io.C:215
void copy_nodal_solution(System &system, std::string system_var_name, std::string exodus_var_name, unsigned int timestep=1)
If we read in a nodal solution while reading in a mesh, we can attempt to copy that nodal solution in...
Provides a uniform interface to vector storage schemes for different linear algebra libraries.
processor_id_type processor_id() const
processor_id_type n_processors() const
Manages consistently variables, degrees of freedom, and coefficient vectors.
Definition system.h:100
unsigned int add_variable(std::string_view var, const FEType &type, const std::set< subdomain_id_type > *const active_subdomains=nullptr)
Adds the variable var to the list of variables for this system.
Definition system.C:1344
std::unique_ptr< NumericVector< Number > > solution
Data structure to hold solution values.
Definition system.h:1655
The UnstructuredMesh class is derived from the MeshBase class.
Communicator * TestCommWorld
MeshBase & mesh
void build_square(UnstructuredMesh &mesh, const unsigned int nx, const unsigned int ny, const Real xmin=0., const Real xmax=1., const Real ymin=0., const Real ymax=1., const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)
A specialized build_cube() for 2D meshes.
The libMesh namespace provides an interface to certain functionality in the library.
uint8_t dof_id_type
Definition id_types.h:67
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
CPPUNIT_TEST_SUITE_REGISTRATION(WriteVecAndScalar)