Line data Source code
1 : //* This file is part of the MOOSE framework
2 : //* https://mooseframework.inl.gov
3 : //*
4 : //* All rights reserved, see COPYRIGHT for full restrictions
5 : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 : //*
7 : //* Licensed under LGPL 2.1, please see LICENSE for details
8 : //* https://www.gnu.org/licenses/lgpl-2.1.html
9 :
10 : #include "TransformGenerator.h"
11 : #include "libmesh/mesh_modification.h"
12 : #include "CastUniquePointer.h"
13 :
14 : #include "libmesh/mesh_tools.h"
15 :
16 : registerMooseObject("MooseApp", TransformGenerator);
17 :
18 : InputParameters
19 6245 : TransformGenerator::validParams()
20 : {
21 : MooseEnum transforms("TRANSLATE=1 TRANSLATE_CENTER_ORIGIN=2 TRANSLATE_MIN_ORIGIN=3 ROTATE=4 "
22 18735 : "SCALE=5 ROTATE_WITH_MATRIX=6 ROTATE_EXT=7");
23 :
24 6245 : InputParameters params = MeshGenerator::validParams();
25 :
26 24980 : params.addRequiredParam<MeshGeneratorName>("input", "The mesh we want to modify");
27 12490 : params.addClassDescription("Applies a linear transform to the entire mesh.");
28 24980 : params.addRequiredParam<MooseEnum>(
29 : "transform",
30 : transforms,
31 : "The type of transformation to perform (TRANSLATE, TRANSLATE_CENTER_ORIGIN, "
32 : "TRANSLATE_MIN_ORIGIN, ROTATE, SCALE, ROTATE_WITH_MATRIX, ROTATE_EXT)");
33 24980 : params.addParam<RealVectorValue>(
34 : "vector_value",
35 : "The value to use for the transformation. When using TRANSLATE or SCALE, the "
36 : "xyz coordinates are applied in each direction respectively. When using "
37 : "ROTATE, the values are interpreted as the Euler angles phi, theta and psi "
38 : "given in degrees. For ROTATE_EXT, an extrinsic rotation is carried out using prescribed "
39 : "Euler angles alpha, beta, and gamma in degrees.");
40 18735 : params.addParam<RealTensorValue>(
41 : "rotation_matrix",
42 : "Precomputed extrinsic rotation matrix to be applied to mesh (ROTATE_WITH_MATRIX option).");
43 :
44 12490 : return params;
45 6245 : }
46 :
47 1573 : TransformGenerator::TransformGenerator(const InputParameters & parameters)
48 : : MeshGenerator(parameters),
49 1573 : _input(getMesh("input")),
50 4719 : _transform(getParam<MooseEnum>("transform"))
51 : {
52 1563 : if ((_transform != "TRANSLATE_CENTER_ORIGIN" && _transform != "TRANSLATE_MIN_ORIGIN" &&
53 4311 : _transform != "ROTATE_WITH_MATRIX") &&
54 5098 : !isParamValid("vector_value"))
55 0 : paramError("transform",
56 : "The parameter 'vector_value' must be supplied with 'transform' = ",
57 0 : _transform);
58 1573 : }
59 :
60 : std::unique_ptr<MeshBase>
61 1506 : TransformGenerator::generate()
62 : {
63 1506 : std::unique_ptr<MeshBase> mesh = std::move(_input);
64 :
65 1506 : RealVectorValue vector_value;
66 1506 : RealTensorValue rotation_matrix;
67 1506 : if (_transform == 2 || _transform == 3)
68 : {
69 20 : const auto bbox = MeshTools::create_bounding_box(*mesh);
70 20 : if (_transform == 2)
71 10 : vector_value = -0.5 * (bbox.max() + bbox.min());
72 : else
73 10 : vector_value = -bbox.min();
74 : }
75 1486 : else if (_transform == 6)
76 1104 : rotation_matrix = getParam<RealTensorValue>("rotation_matrix");
77 : else
78 3354 : vector_value = getParam<RealVectorValue>("vector_value");
79 :
80 : // Any non-identity transform is going to invalidate any existing
81 : // point locator
82 1506 : mesh->clear_point_locator();
83 :
84 1506 : switch (_transform)
85 : {
86 714 : case 1:
87 : case 2:
88 : case 3:
89 714 : MeshTools::Modification::translate(*mesh, vector_value(0), vector_value(1), vector_value(2));
90 : // libMesh translate() fails to properly mark the spatial
91 : // dimension as unprepared in cases where we've displaced a 1D
92 : // mesh in y or z or a 2D mesh in z. Until that's fixed we work
93 : // around the bug.
94 714 : mesh->unset_has_cached_elem_data();
95 714 : break;
96 264 : case 4:
97 264 : MeshTools::Modification::rotate(*mesh, vector_value(0), vector_value(1), vector_value(2));
98 : // libMesh rotate() tries to set the spatial dimension properly,
99 : // and probably does for all realistic use cases, but there are
100 : // at least hypothetical cases where it could be wrong.
101 : //
102 : // Until that's fixed we work around it.
103 264 : mesh->unset_has_cached_elem_data();
104 264 : break;
105 54 : case 5:
106 54 : MeshTools::Modification::scale(*mesh, vector_value(0), vector_value(1), vector_value(2));
107 : // Is anybody using scale() to just squash a manifold's spatial
108 : // dimension down to its mesh dimension? Let's be safe until
109 : // libMesh is handling that case.
110 54 : mesh->unset_has_cached_elem_data();
111 54 : break;
112 368 : case 6:
113 368 : TransformGenerator::rotateWithMatrix(*mesh, rotation_matrix);
114 368 : break;
115 106 : case 7:
116 106 : TransformGenerator::rotateExtrinsic(*mesh, vector_value(0), vector_value(1), vector_value(2));
117 106 : break;
118 : }
119 :
120 1506 : mesh->unset_is_prepared();
121 3012 : return dynamic_pointer_cast<MeshBase>(mesh);
122 1506 : }
123 :
124 : void
125 106 : TransformGenerator::rotateExtrinsic(MeshBase & mesh,
126 : const Real alpha,
127 : const Real beta,
128 : const Real gamma)
129 : {
130 : #if LIBMESH_DIM == 3
131 : const auto R = RealTensorValue::extrinsic_rotation_matrix(
132 106 : alpha, beta, gamma); // this line is the only difference from rotate...
133 :
134 : // Let's not try to guess what this did to our spatial dimension (it
135 : // could have reduced it, depending on the input mesh!), let's just
136 : // mark that it needs to be recomputed.
137 106 : mesh.unset_has_cached_elem_data();
138 :
139 7748 : for (auto & node : mesh.node_ptr_range())
140 : {
141 7642 : Point & pt = *node;
142 7642 : pt = R * pt;
143 106 : }
144 : #else
145 : libmesh_ignore(mesh, alpha, beta, gamma);
146 : libmesh_error_msg(
147 : "MeshTools::Modification::rotate() requires libMesh to be compiled with LIBMESH_DIM==3");
148 : #endif
149 106 : }
150 :
151 : void
152 368 : TransformGenerator::rotateWithMatrix(MeshBase & mesh,
153 : const GenericRealTensorValue<false> & rotation_matrix)
154 : {
155 : #if LIBMESH_DIM == 3
156 : // Let's not try to guess what this did to our spatial dimension,
157 : // let's just mark that it needs to be recomputed.
158 368 : mesh.unset_has_cached_elem_data();
159 :
160 28932 : for (auto & node : mesh.node_ptr_range())
161 : {
162 28564 : Point & pt = *node;
163 28564 : pt = rotation_matrix * pt;
164 368 : }
165 :
166 : #else
167 : libmesh_ignore(mesh, phi, theta, psi);
168 : libmesh_error_msg(
169 : "MeshTools::Modification::rotate() requires libMesh to be compiled with LIBMESH_DIM==3");
170 : #endif
171 368 : }
|