MFEM v4.9.0
Finite element discretization library
Loading...
Searching...
No Matches
generate_random_field.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// Gaussian Random Fields of Matern Covariance for Imperfect Materials
14// -------------------------------------------------------------------
15//
16// See README.md for detailed description.
17//
18// Compile with: make generate_random_field
19//
20// Sample runs:
21// (Basic usage)
22// mpirun -np 4 generate_random_field
23//
24// (Generate 5 particles with random imperfections)
25// mpirun -np 4 generate_random_field -o 1 -r 3 -rp 3 -nu 2 -l1 0.015 -l2 0.015 -l3 0.015 -s 0.01 -t 0.08 -n 5 -pl2 3 -top 0 -rs
26//
27// (Generate an Octet-Truss with random imperfections)
28// mpirun -np 4 generate_random_field -o 1 -r 3 -rp 3 -nu 2 -l1 0.02 -l2 0.02 -l3 0.02 -s 0.01 -t 0.08 -top 1 -rs
29//
30// (Generate an Octet-Truss with random imperfections following a uniform distribution)
31// mpirun -np 4 generate_random_field -o 1 -r 3 -rp 3 -nu 2 -l1 0.02 -l2 0.02 -l3 0.02 -umin 0.01 -umax 0.05 -t 0.08 -top 1 -urf -rs
32//
33// (2D random field with anisotropy)
34// mpirun -np 4 generate_random_field -o 1 -r 3 -rp 3 -nu 4 -l1 0.09 -l2 0.03 -l3 0.05 -s 0.01 -t 0.08 -top 1 -no-rs -m ../../data/ref-square.mesh
35
36#include <iostream>
37#include <string>
38#include "mfem.hpp"
39
40#include "material_metrics.hpp"
41#include "spde_solver.hpp"
42#include "transformation.hpp"
43#include "util.hpp"
44#include "visualizer.hpp"
45
46using namespace std;
47using namespace mfem;
48
50
51int main(int argc, char *argv[])
52{
53#ifdef MFEM_USE_SINGLE
54 cout << "This miniapp is not supported in single precision.\n\n";
55 return MFEM_SKIP_RETURN_VALUE;
56#endif
57
58 // 0. Initialize MPI.
59 Mpi::Init(argc, argv);
61
62 // 1. Parse command-line options.
63 const char *mesh_file = "../../data/ref-cube.mesh";
64 int order = 1;
65 int num_refs = 3;
66 int num_parallel_refs = 3;
67 int number_of_particles = 3;
68 int topological_support = TopologicalSupport::kOctetTruss;
69 real_t nu = 2.0;
70 real_t tau = 0.08;
71 real_t l1 = 0.02;
72 real_t l2 = 0.02;
73 real_t l3 = 0.02;
74 real_t e1 = 0;
75 real_t e2 = 0;
76 real_t e3 = 0;
77 real_t pl1 = 1.0;
78 real_t pl2 = 1.0;
79 real_t pl3 = 1.0;
80 real_t uniform_min = 0.0;
81 real_t uniform_max = 1.0;
82 real_t offset = 0.0;
83 real_t scale = 0.01;
84 real_t level_set_threshold = 0.0;
85 bool paraview_export = true;
86 bool glvis_export = true;
87 bool uniform_rf = false;
88 bool random_seed = true;
89 bool compute_boundary_integrals = false;
90
91 OptionsParser args(argc, argv);
92 args.AddOption(&mesh_file, "-m", "--mesh", "Mesh file to use.");
93 args.AddOption(&order, "-o", "--order",
94 "Finite element order (polynomial degree) or -1 for"
95 " isoparametric space.");
96 args.AddOption(&num_refs, "-r", "--refs", "Number of uniform refinements");
97 args.AddOption(&num_parallel_refs, "-rp", "--refs-parallel",
98 "Number of uniform refinements");
99 args.AddOption(&topological_support, "-top", "--topology",
100 "Topological support. 0 particles, 1 octet-truss");
101 args.AddOption(&nu, "-nu", "--nu", "Fractional exponent nu (smoothness)");
102 args.AddOption(&tau, "-t", "--tau", "Parameter for topology generation");
103 args.AddOption(&l1, "-l1", "--l1",
104 "First component of diagonal core of theta");
105 args.AddOption(&l2, "-l2", "--l2",
106 "Second component of diagonal core of theta");
107 args.AddOption(&l3, "-l3", "--l3",
108 "Third component of diagonal core of theta");
109 args.AddOption(&e1, "-e1", "--e1", "First euler angle for rotation of theta");
110 args.AddOption(&e2, "-e2", "--e2",
111 "Second euler angle for rotation of theta");
112 args.AddOption(&e3, "-e3", "--e3", "Third euler angle for rotation of theta");
113 args.AddOption(&pl1, "-pl1", "--pl1", "Length scale 1 of particles");
114 args.AddOption(&pl2, "-pl2", "--pl2", "Length scale 2 of particles");
115 args.AddOption(&pl3, "-pl3", "--pl3", "Length scale 3 of particles");
116 args.AddOption(&uniform_min, "-umin", "--uniform-min",
117 "Minimum value of uniform distribution");
118 args.AddOption(&uniform_max, "-umax", "--uniform-max",
119 "Maximum value of uniform distribution");
120 args.AddOption(&offset, "-off", "--offset",
121 "Offset for random field u(x) -> u(x) + a");
122 args.AddOption(&scale, "-s", "--scale",
123 "Scale for random field u(x) -> a * u(x)");
124 args.AddOption(&level_set_threshold, "-lst", "--level-set-threshold",
125 "Level set threshold");
126 args.AddOption(&number_of_particles, "-n", "--number-of-particles",
127 "Number of particles");
128 args.AddOption(&paraview_export, "-pvis", "--paraview-visualization",
129 "-no-pvis", "--no-paraview-visualization",
130 "Enable or disable ParaView visualization.");
131 args.AddOption(&glvis_export, "-vis", "--visualization", "-no-vis",
132 "--no-visualization",
133 "Enable or disable GLVis visualization.");
134 args.AddOption(&uniform_rf, "-urf", "--uniform-rf", "-no-urf",
135 "--no-uniform-rf",
136 "Enable or disable the transformation of GRF to URF.");
137 args.AddOption(&random_seed, "-rs", "--random-seed", "-no-rs",
138 "--no-random-seed", "Enable or disable random seed.");
139 args.AddOption(&compute_boundary_integrals, "-cbi",
140 "--compute-boundary-integrals", "-no-cbi",
141 "--no-compute-boundary-integrals",
142 "Enable or disable computation of boundary integrals.");
143 args.Parse();
144 if (!args.Good())
145 {
146 args.PrintUsage(cout);
147 return 1;
148 }
149 if (Mpi::Root())
150 {
151 args.PrintOptions(cout);
152 }
153
154 // 2. Read the mesh from the given mesh file.
155 Mesh mesh(mesh_file, 1, 1);
156 int dim = mesh.Dimension();
157 bool is_3d = (dim == 3);
158
159 // 3. Refine the mesh to increase the resolution.
160 for (int i = 0; i < num_refs; i++)
161 {
162 mesh.UniformRefinement();
163 }
164 ParMesh pmesh(MPI_COMM_WORLD, mesh);
165 mesh.Clear();
166 for (int i = 0; i < num_parallel_refs; i++)
167 {
168 pmesh.UniformRefinement();
169 }
170
171 // 4. Define a finite element space on the mesh.
172 H1_FECollection fec(order, dim);
173 ParFiniteElementSpace fespace(&pmesh, &fec);
174 HYPRE_BigInt size = fespace.GlobalTrueVSize();
175 if (Mpi::Root())
176 {
177 const Array<int> boundary(pmesh.bdr_attributes);
178 cout << "Number of finite element unknowns: " << size << "\n";
179 cout << "Boundary attributes: ";
180 boundary.Print(cout, 6);
181 }
182
183 // ========================================================================
184 // II. Generate topological support
185 // ========================================================================
186
187 ParGridFunction v(&fespace);
188 v = 0.0;
189 MaterialTopology *mdm = nullptr;
190
191 // II.1 Define the metric for the topological support.
192 if (is_3d)
193 {
194 if (topological_support == TopologicalSupport::kOctetTruss)
195 {
196 mdm = new OctetTrussTopology();
197 }
198 else if (topological_support == TopologicalSupport::kParticles)
199 {
200 // Create the same random particles on all processors.
201 std::vector<real_t> random_positions(3 * number_of_particles);
202 std::vector<real_t> random_rotations(9 * number_of_particles);
203 if (Mpi::Root())
204 {
205 // Generate random positions and rotations. We generate them on the root
206 // process and then broadcast them to all processes because we need the
207 // same random positions and rotations on all processes.
208 FillWithRandomNumbers(random_positions, 0.2, 0.8);
209 FillWithRandomRotations(random_rotations);
210 }
211
212 // Broadcast the random positions and rotations to all processes.
213 MPI_Bcast(random_positions.data(), 3 * number_of_particles,
214 MPITypeMap<real_t>::mpi_type, 0, MPI_COMM_WORLD);
215 MPI_Bcast(random_rotations.data(), 9 * number_of_particles,
216 MPITypeMap<real_t>::mpi_type, 0, MPI_COMM_WORLD);
217
218 mdm = new ParticleTopology(pl1, pl2, pl3, random_positions,
219 random_rotations);
220 }
221 else
222 {
223 if (Mpi::Root())
224 {
225 mfem::out << "Error: Selected topological support not valid."
226 << std::endl;
227 }
228 return 1;
229 }
230
231 // II.2 Define lambda to wrap the call to the distance metric.
232 auto topo = [&mdm, &tau](const Vector &x)
233 {
234 return (tau - mdm->ComputeMetric(x));
235 };
236
237 // II.3 Create a GridFunction for the topological support.
238 FunctionCoefficient topo_coeff(topo);
239 v.ProjectCoefficient(topo_coeff);
240 }
241
242 // ========================================================================
243 // III. Generate random imperfections via fractional PDE
244 // ========================================================================
245
246 /// III.1 Define the fractional PDE solution
247 ParGridFunction u(&fespace);
248 u = 0.0;
249
250 // III.2 Define the boundary conditions.
252 if (Mpi::Root())
253 {
254 bc.PrintInfo();
255 bc.VerifyDefinedBoundaries(pmesh);
256 }
257
258 // III.3 Solve the SPDE problem
259 spde::SPDESolver solver(nu, bc, &fespace, l1, l2, l3, e1, e2,
260 e3);
261 const int seed = (random_seed) ? 0 :
262 std::numeric_limits<int>::max() - Mpi::WorldRank();
263 solver.SetupRandomFieldGenerator(seed);
264 solver.GenerateRandomField(u);
265
266 /// III.4 Verify boundary conditions
267 if (compute_boundary_integrals)
268 {
270 }
271
272 // ========================================================================
273 // III. Combine topological support and random field
274 // ========================================================================
275
276 if (uniform_rf)
277 {
278 /// Transform the random field to a uniform random field.
279 spde::UniformGRFTransformer transformation(uniform_min, uniform_max);
280 transformation.Transform(u);
281 }
282 if (scale != 1.0)
283 {
284 /// Scale the random field.
286 transformation.Transform(u);
287 }
288 if (offset != 0.0)
289 {
290 /// Add an offset to the random field.
292 transformation.Transform(u);
293 }
294 ParGridFunction w(&fespace); // Noisy material field.
295 w = 0.0;
296 w += u;
297 w += v;
298 ParGridFunction level_set(w); // Level set field.
299 {
300 spde::LevelSetTransformer transformation(level_set_threshold);
301 transformation.Transform(level_set);
302 }
303
304 // ========================================================================
305 // IV. Export visualization to ParaView and GLVis
306 // ========================================================================
307
308 spde::Visualizer vis(pmesh, order, u, v, w, level_set, is_3d);
309 if (paraview_export)
310 {
311 vis.ExportToParaView();
312 }
313 if (glvis_export)
314 {
315 vis.SendToGLVis();
316 }
317
318 delete mdm;
319 return 0;
320}
void Print(std::ostream &out=mfem::out, int width=4) const
Prints array to stream with width elements per row.
Definition array.cpp:24
A general function coefficient.
Arbitrary order H1-conforming (continuous) finite elements.
Definition fe_coll.hpp:279
static void Init()
Initialize hypre by calling HYPRE_Init() and set default options. After calling Hypre::Init(),...
Definition hypre.cpp:33
Virtual class to define the interface for defining the material topology.
virtual real_t ComputeMetric(const Vector &x)=0
Compute the metric rho describing the material topology.
Mesh data type.
Definition mesh.hpp:65
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
Definition mesh.hpp:304
void Clear()
Clear the contents of the Mesh.
Definition mesh.hpp:827
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1306
void UniformRefinement(int i, const DSTable &, int *, int *, int *)
Definition mesh.cpp:11637
static bool Root()
Return true if the rank in MPI_COMM_WORLD is zero.
static int WorldRank()
Return the MPI rank in MPI_COMM_WORLD.
static void Init(int &argc, char **&argv, int required=default_thread_required, int *provided=nullptr)
Singleton creation with Mpi::Init(argc, argv).
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.
Abstract parallel finite element space.
Definition pfespace.hpp:31
HYPRE_BigInt GlobalTrueVSize() const
Definition pfespace.hpp:349
Class for parallel grid function.
Definition pgridfunc.hpp:50
void ProjectCoefficient(Coefficient &coeff) override
Project coeff Coefficient to this GridFunction. The projection computation depends on the choice of t...
Class for parallel meshes.
Definition pmesh.hpp:34
Class that implements the particle topology.
Vector data type.
Definition vector.hpp:82
Level Set Transformer, 1 for u(x) >= threshold, 0 otherwise.
Adds an constant offset to a grid function, i.e. u(x) = u(x) + offset.
void GenerateRandomField(ParGridFunction &x)
void SetupRandomFieldGenerator(int seed=0)
Transforms a grid function by scaling it by a constant factor.
void SendToGLVis(int visport=19916) const
int dim
Definition ex24.cpp:53
int main()
HYPRE_Int HYPRE_BigInt
void transformation(const Vector &p, Vector &v)
real_t u(const Vector &xvec)
Definition lor_mms.hpp:22
void FillWithRandomRotations(std::vector< real_t > &x)
Definition util.cpp:26
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
Definition globals.hpp:66
void FillWithRandomNumbers(std::vector< real_t > &x, real_t a, real_t b)
Fills the vector x with random numbers between a and b.
Definition util.cpp:18
float real_t
Definition config.hpp:46
Helper struct to convert a C++ type to an MPI type.
void PrintInfo(std::ostream &os=mfem::out) const
Print the information specifying the boundary conditions.
void ComputeBoundaryError(const ParGridFunction &solution)
void VerifyDefinedBoundaries(const Mesh &mesh) const