17#include "libmesh/parallel_algebra.h"
18#include "libmesh/parallel_sync.h"
19#include "libmesh/enum_quadrature_type.h"
20#include "libmesh/fe_base.h"
21#include "libmesh/quadrature.h"
36 params.addRequiredParam<std::vector<BoundaryName>>(
37 "boundary",
"The list of boundaries where view factors are desired");
39 MooseEnum qorders(
"CONSTANT FIRST SECOND THIRD FOURTH FIFTH SIXTH SEVENTH EIGHTH NINTH TENTH "
40 "ELEVENTH TWELFTH THIRTEENTH FOURTEENTH FIFTEENTH SIXTEENTH SEVENTEENTH "
41 "EIGHTTEENTH NINTEENTH TWENTIETH",
43 params.addParam<
MooseEnum>(
"face_order", qorders,
"The face quadrature rule order");
46 params.addParam<
MooseEnum>(
"face_type", qtypes,
"The face quadrature type");
48 MooseEnum convention(
"positive=0 negative=1",
"positive");
50 "internal_convention",
52 "The convention for spawning rays from internal sidesets; denotes the sign of the dot "
53 "product between a ray and the internal sideset side normal");
55 params.addParam<
unsigned int>(
58 "Order of the polar quadrature [polar angle is between ray and normal]. Must be even.");
59 params.addParam<
unsigned int>(
60 "azimuthal_quad_order",
62 "Order of the azimuthal quadrature per quadrant [azimuthal angle is measured in "
63 "a plane perpendicular to the normal].");
66 params.set<
bool>(
"ray_kernel_coverage_check") =
false;
67 params.suppressParameter<
bool>(
"ray_kernel_coverage_check");
70 params.set<
bool>(
"force_preaux") =
true;
71 params.suppressParameter<
bool>(
"force_preaux");
74 params.set<
bool>(
"use_internal_sidesets") =
true;
75 params.suppressParameter<
bool>(
"use_internal_sidesets");
78 params.set<
bool>(
"verify_rays") =
false;
81 params.set<
bool>(
"_use_ray_registration") =
false;
83 params.set<
bool>(
"_bank_rays_on_completion") =
false;
85 params.addClassDescription(
86 "This ray study is used to compute view factors in cavities with obstruction. It sends out "
87 "rays from surfaces bounding the radiation cavity into a set of directions determined by an "
88 "angular quadrature. The rays are tracked and view factors are computed by determining the "
89 "surface where the ray dies.");
95 _bnd_ids_vec(_mesh.getBoundaryIDs(getParam<
std::vector<BoundaryName>>(
"boundary"))),
96 _bnd_ids(_bnd_ids_vec.begin(), _bnd_ids_vec.end()),
97 _internal_convention(getParam<
MooseEnum>(
"internal_convention")),
98 _ray_index_start_bnd_id(registerRayAuxData(
"start_bnd_id")),
99 _ray_index_start_total_weight(registerRayAuxData(
"start_total_weight")),
102 _mesh.dimension() - 1,
104 _is_3d(_mesh.dimension() == 3),
125 2 * getParam<unsigned int>(
"polar_quad_order"),
x, w);
129 for (
unsigned int j = 0; j <
x.size(); ++j)
138 _3d_aq = std::make_unique<RayTracingAngularQuadrature>(
140 getParam<unsigned int>(
"polar_quad_order"),
141 4 * getParam<unsigned int>(
"azimuthal_quad_order"),
156 mooseError(
"Not compatible with RayKernels.");
160 std::vector<RayBoundaryConditionBase *> ray_bcs;
162 unsigned int vf_bc_count = 0;
170 if (!view_factor_bc->hasBoundary(
_bnd_ids))
175 "' does not match 'boundary'");
182 if (reflect_bc->hasBoundary(
_bnd_ids))
183 mooseError(
"The boundaries applied in ReflectRayBC '",
185 "' cannot include any of the boundaries in ",
189 if (reflect_bc->hasBoundary(internal_bnd_id))
192 "' is defined on an internal boundary (",
195 "This is not allowed for view factor computation.");
200 " ray boundary condition.\nSupported RayBCs: ReflectRayBC and ViewFactorRayBC.");
202 if (vf_bc_count != 1)
203 mooseError(
"Requires one and only one ViewFactorRayBC.");
247 TIME_SECTION(
"generateRays", 3,
"ViewFactorRayStudy Generating Rays");
250 std::size_t num_local_rays = 0;
251 std::size_t num_local_start_points = 0;
254 num_local_start_points += start_elem._points.size();
255 num_local_rays += start_elem._points.size() *
_num_dir;
259 std::size_t num_total_points = num_local_start_points;
260 std::size_t num_total_rays = num_local_rays;
263 _console <<
"ViewFactorRayStudy generated " << num_total_points
264 <<
" points with an angular quadrature of " <<
_num_dir
265 <<
" directions per point requiring " << num_total_rays <<
" rays" << std::endl;
271 unsigned int num_rays_skipped = 0;
278 getSideNormal(start_elem._start_elem, start_elem._incoming_side, 0);
281 if (start_elem._start_elem != start_elem._elem)
286 !start_elem._start_elem->neighbor_ptr(start_elem._incoming_side))
292 _3d_aq->rotate(inward_normal);
295 for (std::size_t start_i = 0; start_i < start_elem._points.size(); ++start_i)
296 for (std::size_t l = 0; l <
_num_dir; ++l)
300 direction =
_3d_aq->getDirection(l);
305 direction(0) = cos_theta * inward_normal(0) - sin_theta * inward_normal(1);
306 direction(1) = sin_theta * inward_normal(0) + cos_theta * inward_normal(1);
315 const auto awf =
_is_3d ? inward_normal * direction *
_3d_aq->getTotalWeight(l)
317 const auto start_weight = start_elem._weights[start_i] * awf;
322 bool intersection_found =
false;
323 if (
_is_3d && start_elem._start_elem &&
324 !start_elem._start_elem->neighbor_ptr(start_elem._incoming_side) &&
328 Point intersection_point(std::numeric_limits<Real>::max(), -1, -1);
329 const auto side_elem = start_elem._start_elem->side_ptr(start_elem._incoming_side);
331 for (
const auto edge_i : side_elem->side_index_range())
333 const auto edge_1 = side_elem->side_ptr(edge_i);
335 const auto d1 = *edge_1->node_ptr(0) - start_elem._points[start_i];
336 const auto d2 = *edge_1->node_ptr(1) - start_elem._points[start_i];
337 const auto d1_unit = d1.
unit();
338 const auto d2_unit = d2.
unit();
340 if (MooseUtils::absoluteFuzzyEqual(std::abs(d1_unit * d2_unit), 1))
342 const auto normal = (d1_unit.cross(d2_unit)).unit();
345 if (d1 * direction < 0 && d2 * direction < 0)
348 proj_dir = (direction - (direction * normal) * normal).
unit();
351 if ((proj_dir * d2_unit > d1_unit * d2_unit) &&
352 (proj_dir * d1_unit > d1_unit * d2_unit))
355 start_elem._points[start_i], *edge_1->node_ptr(0), *edge_1->node_ptr(1));
357 intersection_point = start_elem._points[start_i] + dist * proj_dir;
358 intersection_found =
true;
364 const auto grazing_dir = (intersection_point - start_elem._points[start_i]).unit();
365 if (intersection_found && inward_normal * direction < inward_normal * grazing_dir)
375 start_elem._points[start_i], start_elem._start_elem, start_elem._incoming_side);
376 ray->setStartingDirection(direction);
384 if (num_rays_skipped)
386 " rays were skipped as they exited the mesh at their starting point through "
387 "non-planar sides.");
398 "Threaded view factor info does not have from boundary");
400 "Threaded view factor info does not have from -> to boundary");
410 mooseError(
"From boundary id ", from_id,
" not in view factor map.");
412 auto itt = it->second.find(to_id);
413 if (itt == it->second.end())
414 mooseError(
"From boundary id ", from_id,
" to boundary_id ", to_id,
" not in view factor map.");
421 const auto & points =
_fe_face->get_xyz();
422 const auto & weights =
_fe_face->get_JxW();
428 std::unordered_map<processor_id_type, std::vector<StartElem>> send_start_map;
433 const Elem * elem = belem->_elem;
434 const auto side = belem->_side;
435 const auto bnd_id = belem->_bnd_id;
448 "Cannot use GRID quadrature type with tetrahedral elements in ViewFactorRayStudy '",
454 const Elem * start_elem = elem;
455 auto start_side = side;
474 start_elem = neighbor;
483 add_to.emplace_back(elem, start_elem, start_side, bnd_id, points, weights);
492 auto append_start_elems = [
this](
processor_id_type,
const std::vector<StartElem> & start_elems)
495 for (
const StartElem & start_elem : start_elems)
500 Parallel::push_parallel_packed_range(
_communicator, send_start_map,
this, append_start_elems);
513 unsigned int total_size = 5;
515 total_size += num_points * 3;
517 total_size += num_points;
525 const std::size_t num_points = *in++;
526 return packing_size(num_points);
533 mooseAssert(start_elem.
_points.size() == start_elem.
_weights.size(),
"Size mismatch");
534 return packing_size(start_elem.
_points.size());
546 const std::size_t num_points =
static_cast<std::size_t
>(*in++);
561 start_elem.
_points.resize(num_points);
562 for (std::size_t i = 0; i < num_points; ++i)
564 start_elem.
_points[i](0) = *in++;
565 start_elem.
_points[i](1) = *in++;
566 start_elem.
_points[i](2) = *in++;
570 start_elem.
_weights.resize(num_points);
571 for (std::size_t i = 0; i < num_points; ++i)
580 std::back_insert_iterator<std::vector<Real>> data_out,
587 data_out = RayTracingPackingUtils::pack<buffer_type>(start_elem.
_elem, &study->
meshBase());
590 data_out = RayTracingPackingUtils::pack<buffer_type>(start_elem.
_start_elem, &study->
meshBase());
599 for (
const auto & point : start_elem.
_points)
607 std::copy(start_elem.
_weights.begin(), start_elem.
_weights.end(), data_out);
boundary_id_type BoundaryID
const std::vector< double > x
registerMooseObject("HeatTransferApp", ViewFactorRayStudy)
const ConsoleStream _console
const std::string & type() const
void mooseError(Args &&... args) const
const std::string & _name
void mooseInfo(Args &&... args) const
virtual unsigned int dimension() const
libMesh::StoredRange< MooseMesh::const_bnd_elem_iterator, const BndElement * > * getBoundaryElementRange()
Base class for the RayBC syntax.
static void gaussLegendre(const unsigned int order, std::vector< Real > &x, std::vector< Real > &w)
Builds Gauss-Legendre quadrature on [0, 1] (symmetric about 0.5), with weights that sum to 1.
Base class for Ray tracing studies that will generate Rays and then propagate all of them to terminat...
MeshBase & meshBase() const
Access to the libMesh MeshBase.
bool sideIsNonPlanar(const Elem *elem, const unsigned short s) const
Whether or not the side \s on elem elem is non-planar.
virtual void initialSetup() override
static InputParameters validParams()
MooseMesh & _mesh
The Mesh.
void moveRayToBuffer(std::shared_ptr< Ray > &ray)
Moves a ray to the buffer to be traced during generateRays().
void reserveRayBuffer(const std::size_t size)
Reserve size entires in the Ray buffer.
virtual const Point & getSideNormal(const Elem *elem, const unsigned short side, const THREAD_ID tid)
Get the outward normal for a given element side.
std::shared_ptr< Ray > acquireRay()
User APIs for constructing Rays within the RayTracingStudy.
const std::set< BoundaryID > & getInternalSidesets() const
Gets the internal sidesets (that have RayBCs) within the local domain.
void getRayBCs(std::vector< RayBoundaryConditionBase * > &result, BoundaryID id, THREAD_ID tid)
Fills the active RayBCs associated with this study and a boundary into result.
const processor_id_type _pid
The rank of this processor (this actually takes time to lookup - so just do it once)
bool hasRayKernels(const THREAD_ID tid)
Whether or not there are currently any active RayKernel objects.
bool currentlyPropagating() const
Whether or not the study is propagating (tracing Rays)
RayBC that reflects a Ray.
RayBC used in the computation of view factors using the angular quadrature ray tracing method.
RayTracingStudy used to generate Rays for view factor computation using the angular quadrature method...
void addToViewFactorInfo(Real value, const BoundaryID from_id, const BoundaryID to_id, const THREAD_ID tid)
Adds into the view factor info; to be used in ViewFactorRayBC.
std::map< BoundaryID, std::map< BoundaryID, Real > > _vf_info
Cumulative view factor information; [from_bid][to_bid] = val.
const std::set< BoundaryID > _bnd_ids
The user supplied boundary IDs we need view factors on.
void initialSetup() override
const RayDataIndex _ray_index_start_bnd_id
Index in the Ray aux data for the starting boundary ID.
std::vector< StartElem > _start_elems
The StartElem objects that this proc needs to spawn Rays from.
static InputParameters validParams()
Real viewFactorInfo(const BoundaryID from_id, const BoundaryID to_id) const
Accessor for the finalized view factor info.
void generateStartElems()
ViewFactorRayStudy(const InputParameters ¶meters)
std::unique_ptr< RayTracingAngularQuadrature > _3d_aq
const std::unique_ptr< libMesh::FEBase > _fe_face
Face FE used for creating face quadrature points and weights.
void generateRays() override
Subclasses should override this to determine how to generate Rays.
const std::unique_ptr< libMesh::QBase > _q_face
Face quadrature used for _fe_face.
void postExecuteStudy() override
Entry point after study execution.
void preExecuteStudy() override
Entry point before study execution.
std::vector< Real > _2d_aq_angles
angular quadrature info
const MooseEnum _internal_convention
The convention for spawning rays from internal sidesets.
std::vector< Real > _2d_aq_weights
const RayDataIndex _ray_index_start_total_weight
Index in the Ray aux data for the starting total weight (dot * qp weight)
std::vector< std::unordered_map< BoundaryID, std::unordered_map< BoundaryID, Real > > > _threaded_vf_info
View factor information by tid and then from/to pair; [tid][from_bid][to_bid] = val.
processor_id_type processor_id() const
unsigned int which_neighbor_am_i(const Elem *e) const
virtual ElemType type() const=0
const Elem * neighbor_ptr(unsigned int i) const
const Parallel::Communicator & _communicator
std::pair< T1, T2 > unpack(BufferIter in, Context *ctx)
static unsigned int packed_size(BufferIter iter)
unsigned int packable_size(const std::pair< T1, T2 > &pr, const Context *ctx)
void pack(const std::pair< T1, T2 > &pr, OutputIter data_out, const Context *ctx)
TypeVector< Real > unit() const
void unpack(const BufferType value_as_buffer_type, ValueType &value)
Unpacks value_as_buffer_type (which is packed with pack()) into value at a byte level.
libMesh::Real distanceFromLine(const libMesh::Point &pt, const libMesh::Point &line0, const libMesh::Point &line1)
The following methods are specializations for using the Parallel::packed_range_* routines for a vecto...
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
uint8_t processor_id_type
Data structure used for storing all of the information needed to spawn Rays from a single element.
const Elem * _start_elem
The element the trace will start from.
std::vector< Point > _points
The points on start_elem to spawn Rays from.
const Elem * _elem
The element the points originate from.
unsigned short int _incoming_side
The incoming side on start_elem that the trace will start from.
std::vector< Real > _weights
The weights associated with each point.
BoundaryID _bnd_id
The boundary ID associated with this start elem.