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();
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);
bool hasRayKernels(const THREAD_ID tid)
Whether or not there are currently any active RayKernel objects.
static void gaussLegendre(const unsigned int order, std::vector< Real > &x, std::vector< Real > &w)
Builds Gauss-Legendre quadrature on 0, 1, with weights that sum to 1.
bool absoluteFuzzyEqual(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
virtual void initialSetup() override
const Elem * _start_elem
The element the trace will start from.
const std::set< BoundaryID > _bnd_ids
The user supplied boundary IDs we need view factors on.
MooseMesh & _mesh
The Mesh.
void initialSetup() override
std::vector< StartElem > _start_elems
The StartElem objects that this proc needs to spawn Rays from.
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.
void mooseInfo(Args &&... args) const
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.
T stringToEnum(const std::string &s)
Converts a string to an enum.
std::vector< Real > _2d_aq_weights
const Parallel::Communicator & _communicator
void postExecuteStudy() override
Entry point after study execution.
std::unique_ptr< RayTracingAngularQuadrature > _3d_aq
The following methods are specializations for using the Parallel::packed_range_* routines for a vecto...
ViewFactorRayStudy(const InputParameters ¶meters)
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.
void preExecuteStudy() override
Entry point before study execution.
static T unpack(BufferIter in, Context *ctx)
const std::unique_ptr< libMesh::QBase > _q_face
Face quadrature used for _fe_face.
static unsigned int packable_size(const T &object, const Context *context)
std::vector< Real > _weights
The weights associated with each point.
RayBC that reflects a Ray.
std::vector< Point > _points
The points on start_elem to spawn Rays from.
RayTracingStudy used to generate Rays for view factor computation using the angular quadrature method...
std::map< BoundaryID, std::map< BoundaryID, Real > > _vf_info
Cumulative view factor information; [from_bid][to_bid] = val.
RayBC used in the computation of view factors using the angular quadrature ray tracing method...
uint8_t processor_id_type
TypeVector< Real > unit() const
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.
static InputParameters validParams()
void generateStartElems()
Real value(unsigned n, unsigned alpha, unsigned beta, Real x)
const std::unique_ptr< libMesh::FEBase > _fe_face
Face FE used for creating face quadrature points and weights.
const Elem * _elem
The element the points originate from.
const std::vector< double > x
virtual unsigned int dimension() const
unsigned int which_neighbor_am_i(const Elem *e) const
boundary_id_type BoundaryID
static unsigned int packed_size(BufferIter iter)
const RayDataIndex _ray_index_start_total_weight
Index in the Ray aux data for the starting total weight (dot * qp weight)
void reserveRayBuffer(const std::size_t size)
Reserve size entires in the Ray buffer.
const std::string & type() const
static InputParameters validParams()
libMesh::Real distanceFromLine(const libMesh::Point &pt, const libMesh::Point &line0, const libMesh::Point &line1)
std::vector< BoundaryID > getBoundaryIDs(const libMesh::MeshBase &mesh, const std::vector< BoundaryName > &boundary_name, bool generate_unknown, const std::set< BoundaryID > &mesh_boundary_ids)
static void pack(const T &object, OutputIter data_out, const Context *context)
const RayDataIndex _ray_index_start_bnd_id
Index in the Ray aux data for the starting boundary ID.
bool sideIsNonPlanar(const Elem *elem, const unsigned short s) const
Whether or not the side on elem elem is non-planar.
registerMooseObject("HeatTransferApp", ViewFactorRayStudy)
Data structure used for storing all of the information needed to spawn Rays from a single element...
const Elem * neighbor_ptr(unsigned int i) const
virtual const Point & getSideNormal(const Elem *elem, const unsigned short side, const THREAD_ID tid)
Get the outward normal for a given element side.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
bool currentlyPropagating() const
Whether or not the study is propagating (tracing Rays)
const MooseEnum _internal_convention
The convention for spawning rays from internal sidesets.
void getRayBCs(std::vector< RayBoundaryConditionBase *> &result, BoundaryID id, THREAD_ID tid)
Fills the active RayBCs associated with this study and a boundary into result.
void mooseError(Args &&... args) const
MeshBase & meshBase() const
Access to the libMesh MeshBase.
const processor_id_type _pid
The rank of this processor (this actually takes time to lookup - so just do it once) ...
BoundaryID _bnd_id
The boundary ID associated with this start elem.
void moveRayToBuffer(std::shared_ptr< Ray > &ray)
Moves a ray to the buffer to be traced during generateRays().
Real viewFactorInfo(const BoundaryID from_id, const BoundaryID to_id) const
Accessor for the finalized view factor info.
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
std::vector< Real > _2d_aq_angles
angular quadrature info
libMesh::StoredRange< MooseMesh::const_bnd_elem_iterator, const BndElement *> * getBoundaryElementRange()
const ConsoleStream _console
unsigned short int _incoming_side
The incoming side on start_elem that the trace will start from.
Base class for the RayBC syntax.
void generateRays() override
Subclasses should override this to determine how to generate Rays.
processor_id_type processor_id() const
virtual ElemType type() const=0
Base class for Ray tracing studies that will generate Rays and then propagate all of them to terminat...