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