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"
34 params.addRequiredParam<std::vector<BoundaryName>>(
35 "boundary",
"The list of boundaries where view factors are desired");
37 MooseEnum qorders(
"CONSTANT FIRST SECOND THIRD FOURTH FIFTH SIXTH SEVENTH EIGHTH NINTH TENTH "
38 "ELEVENTH TWELFTH THIRTEENTH FOURTEENTH FIFTEENTH SIXTEENTH SEVENTEENTH "
39 "EIGHTTEENTH NINTEENTH TWENTIETH",
41 params.addParam<
MooseEnum>(
"face_order", qorders,
"The face quadrature rule order");
44 params.addParam<
MooseEnum>(
"face_type", qtypes,
"The face quadrature type");
46 MooseEnum convention(
"positive=0 negative=1",
"positive");
48 "internal_convention",
50 "The convention for spawning rays from internal sidesets; denotes the sign of the dot "
51 "product between a ray and the internal sideset side normal");
53 params.addParam<
unsigned int>(
56 "Order of the polar quadrature [polar angle is between ray and normal]. Must be even.");
57 params.addParam<
unsigned int>(
58 "azimuthal_quad_order",
60 "Order of the azimuthal quadrature per quadrant [azimuthal angle is measured in "
61 "a plane perpendicular to the normal].");
64 params.set<
bool>(
"ray_kernel_coverage_check") =
false;
65 params.suppressParameter<
bool>(
"ray_kernel_coverage_check");
68 params.set<
bool>(
"force_preaux") =
true;
69 params.suppressParameter<
bool>(
"force_preaux");
72 params.set<
bool>(
"use_internal_sidesets") =
true;
73 params.suppressParameter<
bool>(
"use_internal_sidesets");
76 params.set<
bool>(
"verify_rays") =
false;
79 params.set<
bool>(
"_use_ray_registration") =
false;
81 params.set<
bool>(
"_bank_rays_on_completion") =
false;
83 params.addClassDescription(
84 "This ray study is used to compute view factors in cavities with obstruction. It sends out "
85 "rays from surfaces bounding the radiation cavity into a set of directions determined by an "
86 "angular quadrature. The rays are tracked and view factors are computed by determining the "
87 "surface where the ray dies.");
93 _bnd_ids_vec(_mesh.getBoundaryIDs(getParam<
std::vector<BoundaryName>>(
"boundary"))),
94 _bnd_ids(_bnd_ids_vec.begin(), _bnd_ids_vec.end()),
95 _internal_convention(getParam<
MooseEnum>(
"internal_convention")),
96 _ray_index_start_bnd_id(registerRayAuxData(
"start_bnd_id")),
97 _ray_index_start_total_weight(registerRayAuxData(
"start_total_weight")),
98 _fe_face(FEBase::build(_mesh.dimension(), FEType(CONSTANT, MONOMIAL))),
99 _q_face(QBase::build(
Moose::stringToEnum<QuadratureType>(getParam<
MooseEnum>(
"face_type")),
100 _mesh.dimension() - 1,
102 _is_3d(_mesh.dimension() == 3),
103 _threaded_vf_info(
libMesh::n_threads())
123 2 * getParam<unsigned int>(
"polar_quad_order"),
x, w);
127 for (
unsigned int j = 0; j <
x.size(); ++j)
136 _3d_aq = std::make_unique<RayTracingAngularQuadrature>(
138 getParam<unsigned int>(
"polar_quad_order"),
139 4 * getParam<unsigned int>(
"azimuthal_quad_order"),
154 mooseError(
"Not compatible with RayKernels.");
158 std::vector<RayBoundaryConditionBase *> ray_bcs;
160 unsigned int vf_bc_count = 0;
168 if (!view_factor_bc->hasBoundary(
_bnd_ids))
173 "' does not match 'boundary'");
180 if (reflect_bc->hasBoundary(
_bnd_ids))
181 mooseError(
"The boundaries applied in ReflectRayBC '",
183 "' cannot include any of the boundaries in ",
187 if (reflect_bc->hasBoundary(internal_bnd_id))
190 "' is defined on an internal boundary (",
193 "This is not allowed for view factor computation.");
198 " ray boundary condition.\nSupported RayBCs: ReflectRayBC and ViewFactorRayBC.");
200 if (vf_bc_count != 1)
201 mooseError(
"Requires one and only one ViewFactorRayBC.");
228 Real & entry =
_vf_info[from_id][to_id];
245 TIME_SECTION(
"generateRays", 3,
"ViewFactorRayStudy Generating Rays");
248 std::size_t num_local_rays = 0;
249 std::size_t num_local_start_points = 0;
252 num_local_start_points += start_elem._points.size();
253 num_local_rays += start_elem._points.size() *
_num_dir;
257 std::size_t num_total_points = num_local_start_points;
258 std::size_t num_total_rays = num_local_rays;
261 _console <<
"ViewFactorRayStudy generated " << num_total_points
262 <<
" points with an angular quadrature of " <<
_num_dir
263 <<
" directions per point requiring " << num_total_rays <<
" rays" << std::endl;
269 unsigned int num_rays_skipped = 0;
276 getSideNormal(start_elem._start_elem, start_elem._incoming_side, 0);
279 if (start_elem._start_elem != start_elem._elem)
284 !start_elem._start_elem->neighbor_ptr(start_elem._incoming_side))
290 _3d_aq->rotate(inward_normal);
293 for (std::size_t start_i = 0; start_i < start_elem._points.size(); ++start_i)
294 for (std::size_t l = 0; l <
_num_dir; ++l)
298 direction =
_3d_aq->getDirection(l);
303 direction(0) = cos_theta * inward_normal(0) - sin_theta * inward_normal(1);
304 direction(1) = sin_theta * inward_normal(0) + cos_theta * inward_normal(1);
313 const auto awf =
_is_3d ? inward_normal * direction *
_3d_aq->getTotalWeight(l)
315 const auto start_weight = start_elem._weights[start_i] * awf;
320 bool intersection_found =
false;
321 if (
_is_3d && start_elem._start_elem &&
322 !start_elem._start_elem->neighbor_ptr(start_elem._incoming_side) &&
326 Point intersection_point(std::numeric_limits<Real>::max(), -1, -1);
327 const auto side_elem = start_elem._start_elem->side_ptr(start_elem._incoming_side);
329 for (
const auto edge_i : side_elem->side_index_range())
331 const auto edge_1 = side_elem->side_ptr(edge_i);
333 const auto d1 = *edge_1->node_ptr(0) - start_elem._points[start_i];
334 const auto d2 = *edge_1->node_ptr(1) - start_elem._points[start_i];
335 const auto d1_unit = d1.unit();
336 const auto d2_unit = d2.unit();
338 if (MooseUtils::absoluteFuzzyEqual(std::abs(d1_unit * d2_unit), 1))
340 const auto normal = (d1_unit.cross(d2_unit)).unit();
343 if (d1 * direction < 0 && d2 * direction < 0)
346 proj_dir = (direction - (direction * normal) * normal).unit();
349 if ((proj_dir * d2_unit > d1_unit * d2_unit) &&
350 (proj_dir * d1_unit > d1_unit * d2_unit))
353 start_elem._points[start_i], *edge_1->node_ptr(0), *edge_1->node_ptr(1));
355 intersection_point = start_elem._points[start_i] + dist * proj_dir;
356 intersection_found =
true;
362 const auto grazing_dir = (intersection_point - start_elem._points[start_i]).unit();
363 if (intersection_found && inward_normal * direction < inward_normal * grazing_dir)
373 start_elem._points[start_i], start_elem._start_elem, start_elem._incoming_side);
374 ray->setStartingDirection(direction);
382 if (num_rays_skipped)
384 " rays were skipped as they exited the mesh at their starting point through "
385 "non-planar sides.");
396 "Threaded view factor info does not have from boundary");
398 "Threaded view factor info does not have from -> to boundary");
408 mooseError(
"From boundary id ", from_id,
" not in view factor map.");
410 auto itt = it->second.find(to_id);
411 if (itt == it->second.end())
412 mooseError(
"From boundary id ", from_id,
" to boundary_id ", to_id,
" not in view factor map.");
419 const auto & points =
_fe_face->get_xyz();
420 const auto & weights =
_fe_face->get_JxW();
426 std::unordered_map<processor_id_type, std::vector<StartElem>> send_start_map;
431 const Elem * elem = belem->_elem;
432 const auto side = belem->_side;
433 const auto bnd_id = belem->_bnd_id;
436 if (elem->processor_id() !=
_pid)
446 "Cannot use GRID quadrature type with tetrahedral elements in ViewFactorRayStudy '",
452 const Elem * start_elem = elem;
453 auto start_side = side;
459 const Elem * neighbor = elem->neighbor_ptr(side);
462 if (!neighbor->active())
472 start_elem = neighbor;
473 start_side = neighbor->which_neighbor_am_i(elem);
479 const auto start_pid = start_elem->processor_id();
481 add_to.emplace_back(elem, start_elem, start_side, bnd_id, points, weights);
490 auto append_start_elems = [
this](processor_id_type,
const std::vector<StartElem> & start_elems)
493 for (
const StartElem & start_elem : start_elems)
498 Parallel::push_parallel_packed_range(
_communicator, send_start_map,
this, append_start_elems);
511 unsigned int total_size = 5;
513 total_size += num_points * 3;
515 total_size += num_points;
523 const std::size_t num_points = *in++;
524 return packing_size(num_points);
531 mooseAssert(start_elem.
_points.size() == start_elem.
_weights.size(),
"Size mismatch");
532 return packing_size(start_elem.
_points.size());
544 const std::size_t num_points =
static_cast<std::size_t
>(*in++);
559 start_elem.
_points.resize(num_points);
560 for (std::size_t i = 0; i < num_points; ++i)
562 start_elem.
_points[i](0) = *in++;
563 start_elem.
_points[i](1) = *in++;
564 start_elem.
_points[i](2) = *in++;
568 start_elem.
_weights.resize(num_points);
569 for (std::size_t i = 0; i < num_points; ++i)
578 std::back_insert_iterator<std::vector<Real>> data_out,
585 data_out = RayTracingPackingUtils::pack<buffer_type>(start_elem.
_elem, &study->
meshBase());
588 data_out = RayTracingPackingUtils::pack<buffer_type>(start_elem.
_start_elem, &study->
meshBase());
597 for (
const auto & point : start_elem.
_points)
605 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.
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)
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...
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.