Line data Source code
1 : #pragma once
2 :
3 : #include "GeneralUserObject.h"
4 : #include "MaterialBase.h"
5 : #include "MooseMesh.h"
6 :
7 : #include "moab/Core.hpp"
8 : #include "moab/Skinner.hpp"
9 : #include "moab/GeomTopoTool.hpp"
10 : #include "MBTagConventions.hpp"
11 :
12 : /**
13 : * \brief Skins the [Mesh] according to individual bins for temperature, density, and subdomain ID
14 : *
15 : * Skins a [Mesh] according to temperature, density, and subdomain. The MOAB surfaces bounding
16 : * those grouped elements are then generated, providing geometry information needed for DAGMC
17 : * to then track particles on this new geometry.
18 : */
19 : class MoabSkinner : public GeneralUserObject
20 : {
21 : public:
22 : MoabSkinner(const InputParameters & parameters);
23 :
24 : static InputParameters validParams();
25 :
26 : virtual void execute() override;
27 :
28 : virtual void initialize() override;
29 :
30 : virtual void finalize() override;
31 :
32 0 : virtual void threadJoin(const UserObject & /* uo */) override {}
33 :
34 : /**
35 : * Wrap the error handling in MOAB to print errors to user
36 : * @param[in] input MOAB error code
37 : * @return error mode
38 : */
39 : virtual moab::ErrorCode check(const moab::ErrorCode input) const;
40 :
41 : std::string materialName(const unsigned int & block,
42 : const unsigned int & density,
43 : const unsigned int & temp) const;
44 :
45 : /// Perform the skinning operation
46 : virtual void update();
47 :
48 : /**
49 : * Set the names to be used for naming the subdomains in the skinned mesh;
50 : * there should be one name per subdomain.
51 : * @param[in] names names for subdomains
52 : */
53 19 : virtual void setMaterialNames(std::vector<std::string> names) { _material_names = names; }
54 :
55 : /**
56 : * Get the total number of bins
57 : * @return total number of bins
58 : */
59 : unsigned int nBins() const;
60 :
61 : /**
62 : * Get the bin index for the temperature
63 : * @param[in] elem element
64 : * @return temperature bin index
65 : */
66 : virtual unsigned int getTemperatureBin(const Elem * const elem) const;
67 :
68 : /**
69 : * Get the bin index for the density
70 : * @param[in] elem element
71 : * @return density bin index
72 : */
73 : virtual unsigned int getDensityBin(const Elem * const elem) const;
74 :
75 : /**
76 : * Get the bin index for the subdomain
77 : * @param[in] elem element
78 : * @return subdomain bin index
79 : */
80 86582 : virtual unsigned int getSubdomainBin(const Elem * const elem) const
81 : {
82 86582 : return _blocks.at(elem->subdomain_id());
83 : }
84 :
85 : /**
86 : * Override the user parameter for use_displaced
87 : * @param[in] use whether to use the displaced mesh
88 : */
89 : void setUseDisplacedMesh(const bool & use);
90 :
91 : /**
92 : * Set the length multiplier to get from [Mesh] units into centimeters
93 : * @param[in] scale multiplier
94 : */
95 20 : virtual void setScaling(const Real & scale) { _scaling = scale; }
96 :
97 : /**
98 : * Set the verbosity level
99 : * @param[in] verbose whether to print diagnostic information
100 : */
101 20 : virtual void setVerbosity(const bool & verbose) { _verbose = verbose; }
102 :
103 : /**
104 : * Indicate whether this userobject is run by itself (for testing purposes)
105 : * or controlled by some other class.
106 : */
107 20 : virtual void makeDependentOnExternalAction() { _standalone = false; }
108 :
109 : /**
110 : * Get variable number in the auxiliary system
111 : * @param[in] name variable name
112 : * @param[in] param_name parameter name, for printing a helpful error message
113 : * @return variable number
114 : */
115 : unsigned int getAuxiliaryVariableNumber(const std::string & name,
116 : const std::string & param_name) const;
117 :
118 : /// Clear mesh data
119 : void reset();
120 :
121 : /**
122 : * Get total bin index given individual indices for the temperature, density, and subdomain bins
123 : * @param[in] temp_bin temperature bin
124 : * @param[in] density_bin density bin
125 : * @param[in] subdomain_bin subdomain ID bin
126 : * @return total bin index
127 : */
128 : virtual unsigned int getBin(const unsigned int & temp_bin,
129 : const unsigned int & density_bin,
130 : const unsigned int & subdomain_bin) const;
131 :
132 : /**
133 : * Whether the skinner builds a graveyard
134 : * @return whether a graveyard is built
135 : */
136 0 : virtual const bool & hasGraveyard() const { return _build_graveyard; }
137 :
138 : /**
139 : * Set the graveyard setting
140 : * @param[in] build whether to build a graveyard
141 : */
142 : void setGraveyard(bool build);
143 :
144 : /**
145 : * Number of density bins; if greater than 1, this means we must be re-generating
146 : * OpenMC materials during the course of the simulation.
147 : * @return number of density bins
148 : */
149 0 : virtual unsigned int nDensityBins() const { return _n_density_bins; }
150 :
151 : /**
152 : * Whether density skinning is applied
153 : * @return using density skinning
154 : */
155 23 : virtual bool hasDensitySkinning() const { return _bin_by_density; }
156 :
157 : /**
158 : * Get pointer to underlying moab interface
159 : * @return pointer to moab interface
160 : */
161 : const std::shared_ptr<moab::Interface> & moabPtr() const { return _moab; }
162 :
163 : protected:
164 : std::unique_ptr<NumericVector<Number>> _serialized_solution;
165 :
166 : /// MOAB interface
167 : std::shared_ptr<moab::Interface> _moab;
168 :
169 : /// Whether to print diagnostic information
170 : bool _verbose;
171 :
172 : /// Name of the temperature variable
173 : const std::string & _temperature_name;
174 :
175 : /// Lower bound of temperature bins
176 : const Real & _temperature_min;
177 :
178 : /// Upper bound of temperature bins
179 : const Real & _temperature_max;
180 :
181 : /// Number of temperature bins
182 : const unsigned int & _n_temperature_bins;
183 :
184 : /// Temperature bin width
185 : const Real _temperature_bin_width;
186 :
187 : /// Whether elements are binned by density (in addition to temperature and block)
188 : const bool _bin_by_density;
189 :
190 : /// Material names corresponding to each subdomain. These are used to name the
191 : /// new skinned volumes in MOAB
192 : std::vector<std::string> _material_names;
193 :
194 : /// Faceting tolerence needed by DAGMC
195 : const Real & _faceting_tol;
196 :
197 : /// Geometry tolerence needed by DAGMC
198 : const Real & _geom_tol;
199 :
200 : /// Multiplier on bounding box for inner surface of graveyard
201 : const Real & _graveyard_scale_inner;
202 :
203 : /// Multiplier on bounding box for outer surface of graveyard
204 : const Real & _graveyard_scale_outer;
205 :
206 : /// Whether to output the MOAB mesh skins to a .h5m file
207 : const bool & _output_skins;
208 :
209 : /// Whether to output the MOAB mesh to a .h5m file
210 : const bool & _output_full;
211 :
212 : /**
213 : * Whether to build a graveyard as two additional cube surfaces surrounding the mesh.
214 : * This is only needed if the skinned geometry is fed into a Monte Carlo code.
215 : */
216 : bool _build_graveyard;
217 :
218 : /// Whether to assign a material to the implicit complement region
219 : bool _set_implicit_complement_material = false;
220 :
221 : /// OpenMC material name or ID which will be assigned to the implicit complement
222 : std::string _implicit_complement_group_name;
223 :
224 : /// Whether the skinned mesh should be generated from a displaced mesh
225 : bool _use_displaced;
226 :
227 : /// Length multiplier to get from [Mesh] units into OpenMC's centimeters
228 : Real _scaling;
229 :
230 : /// Count number of times output files have been written
231 : unsigned int _n_write;
232 :
233 : /// Whether this class runs by itself, or is controlled by an external class
234 : bool _standalone;
235 :
236 : /// True when buildTetMesh() is called
237 : bool _tet_mesh_built;
238 :
239 : /// TET4 clone of the MOOSE mesh. Present only when the source mesh contains non-tetrahedral elements. Rebuilt each update() cycle.
240 : std::unique_ptr<MeshBase> _tet_mesh;
241 :
242 : /// Encode the whether the surface normal faces into or out of the volume
243 : enum Sense
244 : {
245 : BACKWARDS = -1,
246 : FORWARDS = 1
247 : };
248 :
249 : /// Encode MOAB information about volumes needed when creating surfaces
250 : struct VolData
251 : {
252 : moab::EntityHandle vol;
253 : Sense sense;
254 : };
255 :
256 : /// Get the MooseMesh (displaced or not, depending on _use_displaced)
257 : MooseMesh & getMooseMesh();
258 :
259 : /**
260 : * Return the mesh used for DAGMC geometry construction.
261 : * @return *_tet_mesh when the source mesh contained non-tetrahedral elements
262 : * and an internal conversion was performed; otherwise returns getMooseMesh().getMesh().
263 : */
264 : MeshBase & getDAGMCGeometryMesh();
265 :
266 : /// If the mesh has non-tetrahedral elements, clone it into _tet_mesh and convert to all-TET4
267 : void buildTetMesh();
268 :
269 : /**
270 : * Copy the libMesh [Mesh] into a MOAB mesh. This first loops through all of the
271 : * nodes, and rebuilds each as a MOAB vertex. Then, we loop over all of the elements
272 : * and rebuild each as a TET4 (if the libMesh mesh has TET10 elements, they are each
273 : * rebuilt into 8 TET4 elements). When the source mesh contained non-tetrahedral elements,
274 : * the geometry mesh is the internally-converted all-TET4 clone rather than the MOOSE mesh
275 : */
276 : void createMOABElems();
277 :
278 : /// Helper method to create MOAB tags
279 : virtual void createTags();
280 :
281 : /**
282 : * Helper method to create MOAB group entity set
283 : * @param[in] id ID for the group
284 : * @param[in] name name for the group
285 : * @param[in] group_set group of entities
286 : */
287 : void
288 : createGroup(const unsigned int & id, const std::string & name, moab::EntityHandle & group_set);
289 :
290 : /// Helper method to create MOAB volume entity set
291 : void
292 : createVol(const unsigned int & id, moab::EntityHandle & volume_set, moab::EntityHandle group_set);
293 :
294 : /// Helper method to create MOAB surface entity set
295 : void createSurf(const unsigned int & id,
296 : moab::EntityHandle & surface_set,
297 : moab::Range & faces,
298 : const std::vector<VolData> & voldata);
299 :
300 : /// Helper method to create MOAB surfaces with no overlaps
301 : void createSurfaces(moab::Range & reversed, VolData & voldata, unsigned int & surf_id);
302 :
303 : /**
304 : * Create a MOAB surface from a bounding box
305 : */
306 : void createSurfaceFromBox(const BoundingBox & box,
307 : const VolData & voldata,
308 : unsigned int & surf_id,
309 : bool normalout,
310 : const Real & factor);
311 :
312 : /**
313 : * Create MOAB nodes from a bounding box
314 : * @param[in] box bounding box
315 : * @param[in] factor multiplicative factor to resize the bounding box sides
316 : * @return nodes
317 : */
318 : std::vector<moab::EntityHandle> createNodesFromBox(const BoundingBox & box,
319 : const Real & factor) const;
320 :
321 : /// Create 3 tri faces stemming from one corner of a cude (an open tetrahedron)
322 : void createCornerTris(const std::vector<moab::EntityHandle> & verts,
323 : unsigned int corner,
324 : unsigned int v1,
325 : unsigned int v2,
326 : unsigned int v3,
327 : bool normalout,
328 : moab::Range & surface_tris);
329 :
330 : /// Create MOAB tri surface element
331 : moab::EntityHandle createTri(const std::vector<moab::EntityHandle> & vertices,
332 : unsigned int v1,
333 : unsigned int v2,
334 : unsigned int v3);
335 :
336 : /// Add parent-child metadata relating a surface to its volume
337 : void updateSurfData(moab::EntityHandle surface_set, const VolData & data);
338 :
339 : /// Generic method to set the tags that DAGMC requires
340 : void
341 : setTags(moab::EntityHandle ent, std::string name, std::string category, unsigned int id, int dim);
342 :
343 : /// Helper function to wrap moab::tag_set_data for a string
344 : void setTagData(moab::Tag tag, moab::EntityHandle ent, std::string data, unsigned int SIZE);
345 :
346 : /// Helper function to wrap moab::tag_set_data for a generic pointer
347 : void setTagData(moab::Tag tag, moab::EntityHandle ent, void * data);
348 :
349 : /**
350 : * Get the node numberings for the MOAB TET4 elements to build for each [Mesh] element
351 : * @param[in] type element type
352 : */
353 : const std::vector<std::vector<unsigned int>> & getTetSets(ElemType type) const;
354 :
355 : /**
356 : * \brief Build a graveyard volume around the domain
357 : *
358 : * The graveyard is a containing volume which bounds the volume of interest. This is
359 : * only needed if the skinned geometry is going to be input into a Monte Carlo solver. For
360 : * performance reasons, a cubic shell is optimal. So, here we build two cubic surfaces,
361 : * both larger than the bounding box of the "actual" geometry. We name this region
362 : * "mat:Graveyard", so that when OpenMC parses the geometry it knows to assign "void"
363 : * to this region, and set vacuum BCs on the outer surfaces of the cubic shell. The
364 : * remaining space between the "actual" geometry and the inner graveyard surface is
365 : * treated as the implicit complement of the rest of the geometry (e.g. a transmissive region).
366 : */
367 : void buildGraveyard(unsigned int & vol_id, unsigned int & surf_id);
368 :
369 : /// Store a mapping from [Mesh] subdomain IDs to an index, to be used for binning by block ID
370 : virtual void findBlocks();
371 :
372 : /// Sort all the elements in the [Mesh] into bins for temperature, density, and subdomain.
373 : virtual void sortElemsByResults();
374 :
375 : /// Group the binned elems into local temperature regions and find their surfaces
376 : void findSurfaces();
377 :
378 : /// Group a given bin into local regions
379 : /// NB elems in param is a copy, localElems is a reference
380 : void groupLocalElems(std::set<dof_id_type> elems, std::vector<moab::Range> & localElems);
381 :
382 : /// Clear MOAB entity sets
383 : bool resetMOAB();
384 :
385 : /// Find the surfaces for the provided range and add to group
386 : void findSurface(const moab::Range & region,
387 : moab::EntityHandle group,
388 : unsigned int & vol_id,
389 : unsigned int & surf_id,
390 : moab::EntityHandle & volume_set);
391 :
392 : /// Write MOAB volume and/or skin meshes to file
393 : virtual void write();
394 :
395 : /// Moab skinner for finding temperature surfaces
396 : std::unique_ptr<moab::Skinner> skinner;
397 :
398 : /// Topology tool for setting surface sense
399 : std::unique_ptr<moab::GeomTopoTool> gtt;
400 :
401 : /// Map from libmesh id to MOAB element entity handles
402 : std::map<dof_id_type, std::vector<moab::EntityHandle>> _id_to_elem_handles;
403 :
404 : /// Save the first tet entity handle
405 : moab::EntityHandle offset;
406 :
407 : /// Name of the MOOSE variable containing the density
408 : std::string _density_name;
409 :
410 : /// Lower bound of density bins
411 : Real _density_min;
412 :
413 : /// Upper bound of density bins
414 : Real _density_max;
415 :
416 : /// Density bin width
417 : Real _density_bin_width;
418 :
419 : /// Number of density bins
420 : unsigned int _n_density_bins;
421 :
422 : /// Number of block bins
423 : unsigned int _n_block_bins;
424 :
425 : /// Mapping from total bin ID to a set of elements sorted into that bin
426 : std::vector<std::set<dof_id_type>> _elem_bins;
427 :
428 : /// Blocks in the [Mesh]
429 : std::map<SubdomainID, unsigned int> _blocks;
430 :
431 : /// Entity handle to represent the set of all tets
432 : moab::EntityHandle _all_tets;
433 :
434 : /// Save some topological data: map from surface handle to vol handle and sense
435 : std::map<moab::EntityHandle, std::vector<VolData>> surfsToVols;
436 :
437 : /// Tag for dimension for geometry
438 : moab::Tag geometry_dimension_tag;
439 :
440 : /// Tag for entitiy set ID
441 : moab::Tag id_tag;
442 :
443 : /// Tag for faceting tolerance
444 : moab::Tag faceting_tol_tag;
445 :
446 : /// Tag needed by DAGMC
447 : moab::Tag geometry_resabs_tag;
448 :
449 : /// Tag for type of entity set
450 : moab::Tag category_tag;
451 :
452 : /// Tag for name of entity set
453 : moab::Tag name_tag;
454 :
455 : /// Bounds of the temperature bins
456 : std::vector<Real> _temperature_bin_bounds;
457 :
458 : /// Bounds of the density bins
459 : std::vector<Real> _density_bin_bounds;
460 :
461 : /// Node ordering for a TET4 MOAB element, based on libMesh node numberings
462 : std::vector<std::vector<unsigned int>> _tet4_nodes;
463 :
464 : /**
465 : * Node ordering for eight TET4 MOAB elements, based on libMesh node numberings
466 : * for a TET10 element. We re-build the libMesh element into first-order MOAB elements.
467 : */
468 : std::vector<std::vector<unsigned int>> _tet10_nodes;
469 :
470 : /// Auxiliary variable number for temperature
471 : unsigned int _temperature_var_num;
472 :
473 : /// Auxiliary variable number for density
474 : unsigned int _density_var_num;
475 :
476 : /// Number of nodes per MOAB tet (which are first order, so TET4)
477 : const unsigned int NODES_PER_MOAB_TET = 4;
478 :
479 : /// Tolerance to use for comparing values to bin bounds
480 : const Real BIN_TOLERANCE = 1e-6;
481 : };
|