PRISMS-PF Manual
Loading...
Searching...
No Matches
spatial_discretization.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: © 2025 PRISMS Center at the University of Michigan
2// SPDX-License-Identifier: GNU Lesser General Public Version 2.1
3
4#pragma once
5
6#include <deal.II/base/parameter_handler.h>
7#include <deal.II/distributed/tria.h>
8#include <deal.II/grid/grid_generator.h>
9#include <deal.II/grid/grid_tools.h>
10#include <deal.II/grid/tria.h>
11
15#include <prismspf/core/types.h>
16
18
19#include <prismspf/config.h>
20
22
32
33template <unsigned int dim>
35 std::conditional_t<dim == 1,
36 dealii::Triangulation<dim>,
37 dealii::parallel::distributed::Triangulation<dim>>;
38
42template <unsigned int dim>
44{
48 RectangularMesh() = default;
49
53 RectangularMesh(dealii::Tensor<1, dim, double> _size,
54 dealii::Tensor<1, dim, double> _lower_bound,
55 std::array<unsigned int, dim> _subdivisions)
56 : size(_size)
57 , lower_bound(_lower_bound)
58 , subdivisions(_subdivisions) {};
59
63 void
64 generate_mesh(Triangulation<dim> &triangulation) const
65 {
66 validate();
67 dealii::GridGenerator::subdivided_hyper_rectangle(triangulation,
69 dealii::Point<dim>(lower_bound),
70 dealii::Point<dim>(size));
71 mark_boundaries(triangulation);
72 mark_periodic(triangulation);
73 };
74
78 void
79 validate() const
80 {}
81
85 dealii::Tensor<1, dim, double> size;
86
90 dealii::Tensor<1, dim, double> lower_bound;
91
95 std::vector<unsigned int> subdivisions = std::vector<unsigned int>(dim, 1);
96
100 std::set<unsigned int> periodic_directions;
101
105 void
107 {
108 // Loop through the cells
109 for (const auto &cell : triangulation.active_cell_iterators())
110 {
111 // Mark the faces (faces_per_cell = 2*dim)
112 for (unsigned int face_number = 0;
113 face_number < dealii::GeometryInfo<dim>::faces_per_cell;
114 ++face_number)
115 {
116 // Direction for quad and hex cells
117 unsigned int direction = face_number / 2;
118
119 // Mark the boundary id for x=0, y=0, z=0 and x=max, y=max, z=max
120 if (std::fabs(cell->face(face_number)->center()(direction)) <
122 std::fabs(cell->face(face_number)->center()(direction) -
123 size[direction]) < Defaults::mesh_tolerance)
124 {
125 cell->face(face_number)->set_boundary_id(face_number);
126 }
127 }
128 }
129 }
130
134 void
135 mark_periodic(Triangulation<dim> &triangulation) const
136 {
137 // Create a vector of matched pairs that we fill and enforce upon the
138 // constraints
139 std::vector<
140 dealii::GridTools::PeriodicFacePair<typename Triangulation<dim>::cell_iterator>>
141 periodicity_vector;
142 collect_periodic_faces(triangulation, periodicity_vector);
143
144 // Add periodicity
145 triangulation.add_periodicity(periodicity_vector);
146 }
147
151 template <typename MeshType> // triangulation or dofhandler
152 void
154 const MeshType &triangulation,
155 std::vector<dealii::GridTools::PeriodicFacePair<typename MeshType::cell_iterator>>
156 &periodicity_vector) const
157 {
158 for (unsigned int direction : periodic_directions)
159 {
160 // Collect the matched pairs on the coarsest level of the mesh
161 unsigned int boundary_id = direction * 2;
162 dealii::GridTools::collect_periodic_faces(triangulation,
163 boundary_id,
164 boundary_id + 1,
165 direction,
166 periodicity_vector);
167 }
168 }
169};
170
174template <unsigned int dim>
176{
180 SphericalMesh() = default;
181
185 explicit SphericalMesh(double _radius)
186 : radius(_radius)
187 {}
188
192 void
193 generate_mesh(Triangulation<dim> &triangulation) const
194 {
195 validate();
196 // TODO: can we just generate a 1d mesh using
197 // dealii::GridGenerator::subdivided_hyper_rectangle instead of throwing an exception?
198 AssertThrow(dim != 1, dealii::ExcMessage("Spherical mesh not valid in 1D"));
199 dealii::GridGenerator::hyper_ball(triangulation, dealii::Point<dim>(), radius);
200 mark_boundaries(triangulation);
201 };
202
206 void
207 validate() const
208 {}
209
213 double radius = 1.0;
214
215private:
219 void
220 mark_boundaries([[maybe_unused]] Triangulation<dim> &triangulation) const
221 {
222 // TODO mark all as 0, or come up with something complicated
223 }
224};
225
229template <unsigned int dim>
231{
235 void
237
241 void
243 { // Check that AMR is not enabled for 1D
244 AssertThrow(
245 (!has_adaptivity || dim != 1),
246 dealii::ExcMessage(
247 "Adaptive meshing for the matrix-free method is not currently supported."));
248
249 // Some check if AMR is enabled
250 if (has_adaptivity)
251 {
252 // Check that the minimum and maximum refinement levels are valid
253 AssertThrow((max_refinement >= global_refinement),
254 dealii::ExcMessage(
255 "The maximum refinement level must be greater than or equal to the "
256 "global refinement level."));
257 AssertThrow((min_refinement <= global_refinement),
258 dealii::ExcMessage(
259 "The minimum refinement level must be less than or equal to the "
260 "global refinement level."));
261 AssertThrow((max_refinement >= min_refinement),
262 dealii::ExcMessage(
263 "The maximum refinement level must be greater than or equal to the "
264 "minimum refinement level."));
265 }
266 // Validate whichever mesh generator is being used
268 {
269 rectangular_mesh.validate();
270 }
272 {
273 spherical_mesh.validate();
274 }
276 {
277 return;
278 }
279 AssertThrow(false, UnreachableCode("Invalid TriangulationType"));
280 }
281
285 [[nodiscard]] bool
286 should_refine_mesh(unsigned int increment) const
287 {
288 return increment % remeshing_period == 0;
289 }
290
294 void
295 declare_parameters(dealii::ParameterHandler &parameter_handler,
296 unsigned int max_criteria = 5) const;
297
301 void
302 assign_parameters(dealii::ParameterHandler &parameter_handler,
303 unsigned int max_criteria = 5);
304
305 // Triangulation type
307
308 // Rectangular mesh parameters
310
311 // Spherical mesh parameters
313
314 // Global refinement of mesh
315 unsigned int global_refinement = 0;
316
317 // Element polynomial degree
318 unsigned int degree = 1;
319
320 // Whether adaptive meshing (AMR) is enabled
321 bool has_adaptivity = false;
322
323 // Maximum global refinement for AMR
324 unsigned int max_refinement = 0;
325
326 // Minimum global refinement for AMR
327 unsigned int min_refinement = 0;
328
329 // The number of steps between remeshing
330 unsigned int remeshing_period = UINT_MAX;
331
332 // The criteria used for remeshing
333 std::map<std::string, RefinementCriterion> refinement_criteria;
334};
335
336template <unsigned int dim>
337inline void
339{
341 << "================================================\n"
342 << " Spatial Discretization\n"
343 << "================================================\n";
344
346 {
347 }
349 {
350 }
352 {
353 }
354
356 << "Global refinement: " << global_refinement << "\n"
357 << "Degree: " << degree << "\n"
358 << "Adaptivity enabled: " << bool_to_string(has_adaptivity) << "\n"
359 << "Max refinement: " << max_refinement << "\n"
360 << "Min refinement: " << min_refinement << "\n"
361 << "Remeshing period: " << remeshing_period << "\n";
362
363 if (!refinement_criteria.empty())
364 {
365 ConditionalOStreams::pout_summary() << "Refinement criteria:\n";
366 for (const auto &[field_name, criterion] : refinement_criteria)
367 {
369 << " Field name: " << field_name << "\n"
370 << " Criterion type: " << criterion.criterion_string() << "\n"
371 << " Value lower bound: " << criterion.value_lower_bound << "\n"
372 << " Value upper bound: " << criterion.value_upper_bound << "\n"
373 << " Gradient lower bound: " << criterion.gradient_lower_bound << "\n\n";
374 }
375 }
376
377 ConditionalOStreams::pout_summary() << "\n" << std::flush;
378}
379
380template <unsigned int dim>
381inline void
383 dealii::ParameterHandler &parameter_handler,
384 unsigned int max_criteria) const
385{
386 parameter_handler.declare_entry("global refinement",
387 "0",
388 dealii::Patterns::Integer(0, INT_MAX),
389 "The number of initial refinements of the coarse mesh.",
390 true);
391
392 parameter_handler.enter_subsection("Rectangular mesh");
393 {
394 parameter_handler.declare_entry("x size",
395 "0.0",
396 dealii::Patterns::Double(0.0, DBL_MAX),
397 "The size of the domain in the x direction.");
398 parameter_handler.declare_entry("y size",
399 "0.0",
400 dealii::Patterns::Double(0.0, DBL_MAX),
401 "The size of the domain in the y direction.");
402 parameter_handler.declare_entry("z size",
403 "0.0",
404 dealii::Patterns::Double(0.0, DBL_MAX),
405 "The size of the domain in the z direction.");
406 parameter_handler.declare_entry("x lower bound",
407 "0.0",
408 dealii::Patterns::Double(-DBL_MAX, DBL_MAX),
409 "The lower bound of the domain in the x direction.");
410 parameter_handler.declare_entry("y lower bound",
411 "0.0",
412 dealii::Patterns::Double(-DBL_MAX, DBL_MAX),
413 "The lower bound of the domain in the y direction.");
414 parameter_handler.declare_entry("z lower bound",
415 "0.0",
416 dealii::Patterns::Double(-DBL_MAX, DBL_MAX),
417 "The lower bound of the domain in the z direction.");
418 parameter_handler.declare_entry(
419 "x subdivisions",
420 "1",
421 dealii::Patterns::Integer(1, INT_MAX),
422 "The number of mesh subdivisions in the x direction.");
423 parameter_handler.declare_entry(
424 "y subdivisions",
425 "1",
426 dealii::Patterns::Integer(1, INT_MAX),
427 "The number of mesh subdivisions in the y direction.");
428 parameter_handler.declare_entry(
429 "z subdivisions",
430 "1",
431 dealii::Patterns::Integer(1, INT_MAX),
432 "The number of mesh subdivisions in the z direction.");
433
434 parameter_handler.declare_entry("periodic x",
435 "false",
436 dealii::Patterns::Bool(),
437 "Whether to have periodicity in the x-direction.");
438 parameter_handler.declare_entry("periodic y",
439 "false",
440 dealii::Patterns::Bool(),
441 "Whether to have periodicity in the y-direction.");
442 parameter_handler.declare_entry("periodic z",
443 "false",
444 dealii::Patterns::Bool(),
445 "Whether to have periodicity in the z-direction.");
446 }
447 parameter_handler.leave_subsection();
448
449 parameter_handler.enter_subsection("Spherical mesh");
450 {
451 parameter_handler.declare_entry("radius",
452 "0",
453 dealii::Patterns::Double(0.0, DBL_MAX),
454 "The radius of the domain.");
455 }
456 parameter_handler.leave_subsection();
457
458 parameter_handler.declare_entry("mesh adaptivity",
459 "false",
460 dealii::Patterns::Bool(),
461 "Whether to enable mesh adaptivity.");
462 parameter_handler.declare_entry("max refinement",
463 "0",
464 dealii::Patterns::Integer(0, INT_MAX),
465 "The maximum level of refinement.");
466 parameter_handler.declare_entry("min refinement",
467 "0",
468 dealii::Patterns::Integer(0, INT_MAX),
469 "The minimum level of refinement.");
470 parameter_handler.declare_entry(
471 "remeshing period",
472 "2147483647",
473 dealii::Patterns::Integer(1, INT_MAX),
474 "The number of time steps between mesh refinement operations.");
475
476 for (unsigned int criterion_id = 0; criterion_id < max_criteria; criterion_id++)
477 {
478 std::string subsection_text =
479 "refinement criterion: " + std::to_string(criterion_id);
480 parameter_handler.enter_subsection(subsection_text);
481 {
482 parameter_handler.declare_entry(
483 "variables",
484 "",
485 dealii::Patterns::Anything(),
486 "The names of the fields that will use this refinement criterion.");
487 parameter_handler.declare_entry(
488 "type",
489 "none",
490 dealii::Patterns::Selection("none|value|gradient|value_and_gradient"),
491 "The type of criterion used to determine if a cell should be "
492 "refined. The options are none, value, gradient, value_and_gradient.");
493 parameter_handler.declare_entry(
494 "value lower bound",
495 "0.0",
496 dealii::Patterns::Double(-DBL_MAX, DBL_MAX),
497 "The lower bound for the window determining where the mesh should be "
498 "refined.");
499 parameter_handler.declare_entry(
500 "value upper bound",
501 "0.0",
502 dealii::Patterns::Double(-DBL_MAX, DBL_MAX),
503 "The upper bound for the window determining where the mesh should be "
504 "refined.");
505 parameter_handler.declare_entry("gradient magnitude lower bound",
506 "2147483647",
507 dealii::Patterns::Double(0.0, DBL_MAX),
508 "The magnitude of the gradient above "
509 "which the mesh should be refined.");
510 parameter_handler.declare_alias("gradient magnitude lower bound",
511 "gradient lower bound");
512 }
513 parameter_handler.leave_subsection();
514 }
515}
516
517template <unsigned int dim>
518inline void
519SpatialDiscretization<dim>::assign_parameters(dealii::ParameterHandler &parameter_handler,
520 unsigned int max_criteria)
521{
522 // Rectangular mesh
523 parameter_handler.enter_subsection("Rectangular mesh");
524 {
525 static const std::vector<std::string> axis_labels = {"x", "y", "z"};
527 for (unsigned int i = 0; i < dim; ++i)
528 {
529 rect.size[i] = parameter_handler.get_double(axis_labels[i] + " size");
530 rect.lower_bound[i] =
531 parameter_handler.get_double(axis_labels[i] + " lower bound");
532 rect.subdivisions[i] = static_cast<unsigned int>(
533 parameter_handler.get_integer(axis_labels[i] + " subdivisions"));
534 if (parameter_handler.get_bool("periodic " + axis_labels[i]))
535 {
536 rect.periodic_directions.insert(i);
537 }
538 }
539 }
540 parameter_handler.leave_subsection();
541 // Spherical mesh
542 parameter_handler.enter_subsection("Spherical mesh");
543 {
544 spherical_mesh.radius = parameter_handler.get_double("radius");
545 }
546 parameter_handler.leave_subsection();
547
549 (static_cast<unsigned int>(parameter_handler.get_integer("global refinement")));
550
551 has_adaptivity = (parameter_handler.get_bool("mesh adaptivity"));
552
554 (static_cast<unsigned int>(parameter_handler.get_integer("remeshing period")));
555
557 (static_cast<unsigned int>(parameter_handler.get_integer("max refinement")));
559 (static_cast<unsigned int>(parameter_handler.get_integer("min refinement")));
560
561 for (unsigned int criterion_id = 0; criterion_id < max_criteria; criterion_id++)
562 {
563 std::string subsection_text =
564 "refinement criterion: " + std::to_string(criterion_id);
565 parameter_handler.enter_subsection(subsection_text);
566 {
567 std::vector<std::string> field_names =
568 dealii::Utilities::split_string_list(parameter_handler.get("variables"));
569 static const std::map<std::string, RefinementFlags> crit_map {
571 {"none", RefinementFlags::Nothing },
572 {"value", RefinementFlags::Value },
573 {"gradient", RefinementFlags::Gradient },
574 {"value_and_gradient", RefinementFlags::Value | RefinementFlags::Gradient}
575 };
576 // todo: make case insensitive
577 RefinementCriterion criterion(crit_map.at(parameter_handler.get("type")),
578 parameter_handler.get_double("value lower bound"),
579 parameter_handler.get_double("value upper bound"),
580 parameter_handler.get_double(
581 "gradient magnitude lower bound"));
582 for (const auto &field_name : field_names)
583 {
584 refinement_criteria[field_name] = criterion;
585 }
586 }
587 parameter_handler.leave_subsection();
588 }
589}
590
591PRISMS_PF_END_NAMESPACE
static dealii::ConditionalOStream & pout_summary()
Log output stream for writing a summary.log file.
Definition conditional_ostreams.cc:35
@ Value
Use value of the variable as a criterion for refinement.
Definition grid_refiner_criterion.h:31
@ Nothing
No adaptive refinement criterion.
Definition grid_refiner_criterion.h:26
@ Gradient
Use gradient of the variable as a criterion for refinement.
Definition grid_refiner_criterion.h:36
static const double mesh_tolerance
Default mesh tolerance.
Definition types.h:62
Definition conditional_ostreams.cc:20
std::conditional_t< dim==1, dealii::Triangulation< dim >, dealii::parallel::distributed::Triangulation< dim > > Triangulation
Definition spatial_discretization.h:34
TriangulationType
Internal enum for various triangulation types.
Definition spatial_discretization.h:27
@ Custom
Definition spatial_discretization.h:30
@ Rectangular
Definition spatial_discretization.h:28
@ Spherical
Definition spatial_discretization.h:29
Class for rectangular mesh parameters.
Definition spatial_discretization.h:44
void mark_periodic(Triangulation< dim > &triangulation) const
Mark the periodic faces of the mesh.
Definition spatial_discretization.h:135
RectangularMesh(dealii::Tensor< 1, dim, double > _size, dealii::Tensor< 1, dim, double > _lower_bound, std::array< unsigned int, dim > _subdivisions)
Constructor.
Definition spatial_discretization.h:53
void mark_boundaries(Triangulation< dim > &triangulation) const
Mark the boundaries of the mesh.
Definition spatial_discretization.h:106
dealii::Tensor< 1, dim, double > lower_bound
Domain extents in each cartesian direction.
Definition spatial_discretization.h:90
dealii::Tensor< 1, dim, double > size
Domain extents in each cartesian direction.
Definition spatial_discretization.h:85
void generate_mesh(Triangulation< dim > &triangulation) const
Generate the mesh.
Definition spatial_discretization.h:64
std::set< unsigned int > periodic_directions
Which directions have periodic conditions.
Definition spatial_discretization.h:100
std::vector< unsigned int > subdivisions
Mesh subdivisions in each cartesian direction.
Definition spatial_discretization.h:95
void collect_periodic_faces(const MeshType &triangulation, std::vector< dealii::GridTools::PeriodicFacePair< typename MeshType::cell_iterator > > &periodicity_vector) const
Get the periodic face pairs.
Definition spatial_discretization.h:153
RectangularMesh()=default
Constructor.
void validate() const
Validate.
Definition spatial_discretization.h:79
Definition grid_refiner_criterion.h:78
Struct that holds spatial discretization parameters.
Definition spatial_discretization.h:231
unsigned int min_refinement
Definition spatial_discretization.h:327
unsigned int degree
Definition spatial_discretization.h:318
TriangulationType type
Definition spatial_discretization.h:306
RectangularMesh< dim > rectangular_mesh
Definition spatial_discretization.h:309
std::map< std::string, RefinementCriterion > refinement_criteria
Definition spatial_discretization.h:333
void validate()
Validate.
Definition spatial_discretization.h:242
SphericalMesh< dim > spherical_mesh
Definition spatial_discretization.h:312
void declare_parameters(dealii::ParameterHandler &parameter_handler, unsigned int max_criteria=5) const
Declare the parameters to be read from an input file.
Definition spatial_discretization.h:382
unsigned int remeshing_period
Definition spatial_discretization.h:330
unsigned int global_refinement
Definition spatial_discretization.h:315
bool should_refine_mesh(unsigned int increment) const
Whether the provided increment is a valid grid refinement step.
Definition spatial_discretization.h:286
void assign_parameters(dealii::ParameterHandler &parameter_handler, unsigned int max_criteria=5)
Assign the parameters read from an input file to this object.
Definition spatial_discretization.h:519
unsigned int max_refinement
Definition spatial_discretization.h:324
bool has_adaptivity
Definition spatial_discretization.h:321
void print_parameter_summary() const
Print parameters to summary.log.
Definition spatial_discretization.h:338
Class for spherical mesh parameters.
Definition spatial_discretization.h:176
SphericalMesh()=default
Constructor.
double radius
Radius of the spherical domain.
Definition spatial_discretization.h:213
void generate_mesh(Triangulation< dim > &triangulation) const
Generate the mesh.
Definition spatial_discretization.h:193
void mark_boundaries(Triangulation< dim > &triangulation) const
Mark the boundaries of the mesh.
Definition spatial_discretization.h:220
void validate() const
Validate.
Definition spatial_discretization.h:207
SphericalMesh(double _radius)
Constructor.
Definition spatial_discretization.h:185
const char * bool_to_string(bool boolean)
Convert bool to string.
Definition utilities.h:399