33 #include "libmesh/getpot.h"
34 #include "libmesh/elem.h"
35 #include "libmesh/edge_edge2.h"
36 #include "libmesh/enum_elem_type.h"
37 #include "libmesh/fe.h"
47 libmesh_not_implemented();
58 libmesh_error_msg(
"Please supply a theta value between -2*pi and 2*pi");
65 unsigned int rayfire_dim = input.vector_variable_size(
"QoI/"+qoi_string+
"/Rayfire/origin");
68 libmesh_error_msg(
"ERROR: Only 2D Rayfires are currently supported");
70 if (!input.have_variable(
"QoI/"+qoi_string+
"/Rayfire/origin"))
71 libmesh_error_msg(
"ERROR: No origin specified for Rayfire");
73 if (input.vector_variable_size(
"QoI/"+qoi_string+
"/Rayfire/origin") != 2)
74 libmesh_error_msg(
"ERROR: Please specify a 2D point (x,y) for the rayfire origin");
76 libMesh::Point origin;
77 _origin(0) = input(
"QoI/"+qoi_string+
"/Rayfire/origin", 0.0, 0);
78 _origin(1) = input(
"QoI/"+qoi_string+
"/Rayfire/origin", 0.0, 1);
80 if (input.have_variable(
"QoI/"+qoi_string+
"/Rayfire/theta"))
81 _theta = input(
"QoI/"+qoi_string+
"/Rayfire/theta", -7.0);
83 libmesh_error_msg(
"ERROR: Spherical polar angle theta must be given for Rayfire");
86 libmesh_error_msg(
"Please supply a theta value between -2*pi and 2*pi");
88 if (input.have_variable(
"QoI/"+qoi_string+
"/Rayfire/phi"))
89 libmesh_error_msg(
"ERROR: cannot specify spherical azimuthal angle phi for Rayfire, only 2D is currently supported");
94 _origin(original._origin),
95 _theta(original._theta),
98 if (original.
_mesh.get())
99 this->
_mesh.reset(
new libMesh::Mesh( *((original.
_mesh).get()) ) );
107 if(mesh_base.mesh_dimension() !=
_dim)
109 std::stringstream ss;
110 ss <<
"The supplied mesh object is " <<mesh_base.mesh_dimension()
111 <<
"D, but the RayfireMesh object was created with the "
112 <<
_dim <<
"D constructor";
114 libmesh_error_msg(ss.str());
117 _mesh.reset(
new libMesh::Mesh(mesh_base.comm(),(
unsigned char)1) );
119 libMesh::Point start_point(
_origin);
122 const libMesh::Elem* start_elem = this->
get_start_elem(mesh_base);
125 libmesh_error_msg(
"Origin is not on mesh");
132 libMesh::Node * start_node =
_mesh->add_point(start_point);
133 libMesh::Node * end_node = NULL;
135 libMesh::Point end_point;
137 const libMesh::Elem* next_elem;
138 const libMesh::Elem* prev_elem = start_elem;
144 next_elem = this->
get_next_elem(prev_elem,start_point,end_point);
149 libmesh_assert( next_elem->active() );
153 end_node =
_mesh->add_point(end_point);
154 libMesh::Elem* elem =
_mesh->add_elem(
new libMesh::Edge2);
155 elem->set_node(0) = start_node;
156 elem->set_node(1) = end_node;
159 if ( (start_point-end_point).norm() < libMesh::TOLERANCE)
161 std::stringstream ss;
164 <<
"Detected rayfire element shorter than TOLERANCE\n"
165 <<
"Element ID: " <<prev_elem->id() <<
", rayfire element length: " <<(start_point-end_point).norm();
167 libmesh_warning(ss.str());
173 start_point = end_point;
174 start_node = end_node;
175 prev_elem = next_elem;
189 std::map<libMesh::dof_id_type,libMesh::dof_id_type>::const_iterator it =
_elem_id_map.begin();
192 if (
_mesh->elem_ptr(it->second)->active())
193 id_vector.push_back(it->first);
203 std::vector<std::pair<const libMesh::Elem*,libMesh::Elem*> > elems_to_refine;
207 std::vector<const libMesh::Elem*> elems_to_coarsen;
212 std::map<libMesh::dof_id_type,libMesh::dof_id_type>::iterator it =
_elem_id_map.begin();
215 const libMesh::Elem* main_elem = mesh_base.elem_ptr(it->first);
216 libmesh_assert(main_elem);
218 if (main_elem->parent())
220 if (main_elem->parent()->refinement_flag() == libMesh::Elem::RefinementState::JUST_COARSENED)
221 elems_to_coarsen.push_back(main_elem);
224 libMesh::Elem::RefinementState state = main_elem->refinement_flag();
226 if (state == libMesh::Elem::RefinementState::INACTIVE)
228 if (main_elem->has_children())
229 if (main_elem->child_ptr(0)->refinement_flag() == libMesh::Elem::RefinementState::JUST_REFINED)
230 elems_to_refine.push_back(std::pair<const libMesh::Elem*, libMesh::Elem*>(main_elem,
_mesh->elem_ptr(it->second)));
235 for (
unsigned int i=0; i<elems_to_refine.size(); i++)
236 this->
refine(elems_to_refine[i].first, elems_to_refine[i].second);
239 for (
unsigned int i=0; i<elems_to_coarsen.size(); i++)
240 this->
coarsen(elems_to_coarsen[i]);
249 libmesh_assert(start_elem);
252 if ( !(start_elem->on_boundary()) )
253 libmesh_error_msg(
"The supplied origin point is not on a boundary element");
259 for (
unsigned int s=0; s<start_elem->n_sides(); s++)
262 if ( start_elem->neighbor_ptr(s) )
266 libMesh::UniquePtr<const libMesh::Elem> edge_elem = start_elem->build_edge_ptr(s);
267 valid |= edge_elem->contains_point(
_origin);
271 libmesh_error_msg(
"The supplied origin point is not on the boundary of the starting element");
277 const libMesh::Elem* start_elem = NULL;
279 libMesh::UniquePtr<libMesh::PointLocatorBase> locator = mesh_base.sub_point_locator();
280 const libMesh::Elem* elem = (*locator)(
_origin);
289 for (
unsigned int i=0; i<elem->n_neighbors(); i++)
291 const libMesh::Elem* neighbor_elem = elem->neighbor_ptr(i);
297 start_elem = neighbor_elem;
311 libMesh::Elem* retval = NULL;
313 std::map<libMesh::dof_id_type,libMesh::dof_id_type>::iterator it;
316 if (
_mesh->elem_ptr(it->second)->refinement_flag() != libMesh::Elem::RefinementState::INACTIVE)
317 retval =
_mesh->elem_ptr(it->second);
323 const libMesh::Elem*
RayfireMesh::get_next_elem(
const libMesh::Elem* cur_elem, libMesh::Point& start_point, libMesh::Point& next_point,
bool same_parent)
325 libmesh_assert(cur_elem);
327 libMesh::Point intersection_point;
330 for (
unsigned int s=0; s<cur_elem->n_sides(); s++)
332 libMesh::UniquePtr<const libMesh::Elem> edge_elem = cur_elem->build_edge_ptr(s);
336 if (edge_elem->contains_point(start_point,libMesh::TOLERANCE*0.1))
343 if ( this->
check_valid_point(intersection_point,start_point,*edge_elem,next_point) )
357 bool is_not_start = !(intersection_point.absolute_fuzzy_equals(start_point));
358 bool is_on_edge = edge_elem.contains_point(intersection_point);
360 bool is_valid = is_not_start && is_on_edge;
364 next_point(0) = intersection_point(0);
365 next_point(1) = intersection_point(1);
374 libmesh_assert(elem);
378 libMesh::Real L = 2*libMesh::TOLERANCE;
381 if ( elem->hmin() < libMesh::TOLERANCE )
382 L = elem->hmin() * 0.1;
385 libMesh::Real x = end_point(0) + L*std::cos(
_theta);
386 libMesh::Real y = end_point(1) + L*std::sin(
_theta);
388 return elem->contains_point(libMesh::Point(x,y));
392 bool RayfireMesh::validate_edge(
const libMesh::Point & start_point,
const libMesh::Point & end_point,
const libMesh::Elem * side_elem,
const libMesh::Elem * neighbor)
394 bool is_valid =
true;
396 const libMesh::Node * node0 = side_elem->node_ptr(0);
397 const libMesh::Node * node1 = side_elem->node_ptr(1);
399 unsigned int side = libMesh::invalid_uint;
401 for (
unsigned int s=0; s<neighbor->n_sides(); s++)
403 libMesh::UniquePtr<const libMesh::Elem> side_elem = neighbor->build_side_ptr(s);
405 if ( (side_elem->contains_point(*node0)) && (side_elem->contains_point(*node1)) )
412 if ( side != libMesh::invalid_uint )
414 libMesh::UniquePtr<const libMesh::Elem> edge_elem = neighbor->build_side_ptr(side);
416 bool start_point_on_edge = edge_elem->contains_point(start_point);
417 bool end_point_on_edge = edge_elem->contains_point(end_point);
419 if ( end_point_on_edge && start_point_on_edge )
421 bool l_to_r = ( start_point.absolute_fuzzy_equals(*(edge_elem->node_ptr(0))) ) && ( end_point.absolute_fuzzy_equals(*(edge_elem->node_ptr(1))) );
422 bool r_to_l = ( end_point.absolute_fuzzy_equals(*(edge_elem->node_ptr(0))) ) && ( start_point.absolute_fuzzy_equals(*(edge_elem->node_ptr(1))) );
424 is_valid &= ( l_to_r || r_to_l );
432 const libMesh::Elem*
RayfireMesh::get_correct_neighbor(libMesh::Point & start_point, libMesh::Point & end_point,
const libMesh::Elem * cur_elem,
unsigned int side,
bool same_parent)
434 libmesh_assert(cur_elem);
435 libmesh_assert(cur_elem->active());
437 const libMesh::Elem * neighbor = cur_elem->neighbor_ptr(side);
440 bool is_valid =
true;
442 is_valid = neighbor->active();
447 bool is_vertex =
false;
448 const libMesh::Node * vertex = NULL;
449 for(
unsigned int n=0; n<cur_elem->n_nodes(); n++)
451 if ((cur_elem->node_ptr(n))->absolute_fuzzy_equals(end_point))
454 vertex = cur_elem->node_ptr(n);
464 for (
unsigned int s=0; s<cur_elem->n_sides(); s++)
466 libMesh::UniquePtr<const libMesh::Elem> side_elem = cur_elem->build_side_ptr(s);
467 if (side_elem->contains_point(end_point))
469 const libMesh::Elem * neighbor = cur_elem->neighbor_ptr(s);
475 if (neighbor->parent())
477 if (neighbor->parent()->id() != cur_elem->parent()->id())
481 if (this->
validate_edge(start_point,end_point,side_elem.get(),neighbor))
489 if (this->
validate_edge(start_point,end_point,side_elem.get(),neighbor))
496 std::set<const libMesh::Elem*> elem_set;
497 cur_elem->find_point_neighbors(*vertex,elem_set);
498 std::set<const libMesh::Elem *>::const_iterator it = elem_set.begin();
499 const std::set<const libMesh::Elem *>::const_iterator end = elem_set.end();
502 for (; it != end; ++it)
504 const libMesh::Elem* elem = *it;
506 if (elem == cur_elem)
517 if( !(cur_elem->neighbor_ptr(side)) )
521 return cur_elem->neighbor_ptr(side);
526 for (
unsigned int c=0; c<neighbor->n_children(); c++)
528 const libMesh::Elem * child = neighbor->child_ptr(c);
530 if (child->contains_point(end_point))
543 libmesh_assert(edge_elem);
545 unsigned int iter_max = 20;
548 unsigned int n_sf = libMesh::FE<1,libMesh::LAGRANGE>::n_shape_functions(edge_elem->type(),edge_elem->default_order());
551 libMesh::Real x0 = initial_point(0);
552 libMesh::Real y0 = initial_point(1);
555 std::vector<libMesh::Real> phi(n_sf);
556 std::vector<libMesh::Real> dphi(n_sf);
562 libMesh::Real tan_theta = std::tan(
_theta);
565 libMesh::Real xi = 0.0;
568 for(
unsigned int it=0; it<iter_max; it++)
572 for(
unsigned int i=0; i<phi.size(); i++)
574 phi[i] = libMesh::FE<1,libMesh::LAGRANGE>::shape(edge_elem->type(),
575 edge_elem->default_order(),
579 dphi[i] = libMesh::FE<1,libMesh::LAGRANGE>::shape_deriv(edge_elem->type(),
580 edge_elem->default_order(),
586 libMesh::Real X=0.0, Y=0.0, dX=0.0, dY=0.0;
588 for(
unsigned int i=0; i<phi.size(); i++)
590 X += (*(edge_elem->node_ptr(i)))(0) * phi[i];
591 dX += (*(edge_elem->node_ptr(i)))(0) * dphi[i];
592 Y += (*(edge_elem->node_ptr(i)))(1) * phi[i];
593 dY += (*(edge_elem->node_ptr(i)))(1) * dphi[i];
596 libMesh::Real f = tan_theta*(X-x0) - (Y-y0);
597 libMesh::Real df = tan_theta*(dX) - dY;
601 if(std::abs(d_xi) < libMesh::TOLERANCE)
604 intersection_point(0) = X;
605 intersection_point(1) = Y;
620 libmesh_assert(main_elem);
621 libmesh_assert(rayfire_elem);
623 libmesh_assert_equal_to(main_elem->refinement_flag(),libMesh::Elem::RefinementState::INACTIVE);
626 libMesh::Node* start_node = rayfire_elem->node_ptr(0);
627 libMesh::Node* end_node = rayfire_elem->node_ptr(1);
630 rayfire_elem->set_refinement_flag(libMesh::Elem::RefinementState::INACTIVE);
633 libMesh::dof_id_type start_child = libMesh::invalid_uint;
634 for(
unsigned int i=0; i<main_elem->n_children(); i++)
636 if ( (main_elem->child_ptr(i))->contains_point(*start_node) )
639 bool is_vertex =
false;
640 for(
unsigned int n=0; n<main_elem->child_ptr(i)->n_nodes(); n++)
642 if ((main_elem->child_ptr(i)->node_ptr(n))->absolute_fuzzy_equals(*start_node))
666 libmesh_assert_not_equal_to(start_child,libMesh::invalid_uint);
670 libMesh::Point start_point = *start_node;
671 libMesh::Point end_point;
673 const libMesh::Elem* next_elem;
674 const libMesh::Elem* prev_elem = main_elem->child_ptr(start_child);
679 libmesh_assert_equal_to( prev_elem->refinement_flag(), libMesh::Elem::RefinementState::JUST_REFINED );
681 libMesh::Node * prev_node = start_node;
682 libMesh::Node * new_node = NULL;
687 next_elem = this->
get_next_elem(prev_elem,start_point,end_point,
true);
692 libmesh_assert( next_elem->active() );
696 new_node =
_mesh->add_point(end_point);
697 libMesh::Elem* elem =
_mesh->add_elem(
new libMesh::Edge2);
699 elem->set_node(0) = prev_node;
700 elem->set_node(1) = new_node;
702 libmesh_assert_less( (*(elem->node_ptr(0))-
_origin).norm(), (*(elem->node_ptr(1))-
_origin).norm());
705 if ( (start_point-end_point).norm() < libMesh::TOLERANCE)
707 std::stringstream ss;
710 <<
"Detected rayfire element shorter than TOLERANCE on refinement\n"
711 <<
"Element ID: " <<prev_elem->id() <<
", rayfire element length: " <<(start_point-end_point).norm();
713 libmesh_warning(ss.str());
718 elem->set_parent(rayfire_elem);
722 start_point = end_point;
723 prev_elem = next_elem;
724 prev_node = new_node;
726 }
while(!(new_node->absolute_fuzzy_equals(*end_node)));
733 libmesh_assert(child_elem);
737 const libMesh::Elem* parent_elem = child_elem->parent();
738 libmesh_assert(parent_elem);
740 const libMesh::Node* start_node = NULL;
741 const libMesh::Node* end_node = NULL;
743 for (
unsigned int c=0; c<parent_elem->n_children(); c++)
745 libMesh::Elem* rayfire_child = this->
get_rayfire_elem(parent_elem->child_ptr(c)->id());
751 start_node = rayfire_child->node_ptr(0);
752 end_node = rayfire_child->node_ptr(1);
756 if ( (this->
_origin - *(rayfire_child->node_ptr(0))).norm() < (this->
_origin - *start_node).norm() )
757 start_node = rayfire_child->node_ptr(0);
759 if ( (this->
_origin - *(rayfire_child->node_ptr(1))).norm() > (this->
_origin - *end_node).norm() )
760 end_node = rayfire_child->node_ptr(1);
763 rayfire_child->set_refinement_flag(libMesh::Elem::RefinementState::INACTIVE);
768 libmesh_assert(start_node);
769 libmesh_assert(end_node);
772 libMesh::Elem* elem =
_mesh->add_elem(
new libMesh::Edge2);
773 elem->set_node(0) =
_mesh->node_ptr(start_node->id());
774 elem->set_node(1) =
_mesh->node_ptr(end_node->id());
776 libmesh_assert_less( (*(elem->node_ptr(0))-
_origin).norm(), (*(elem->node_ptr(1))-
_origin).norm());
void coarsen(const libMesh::Elem *rayfire_elem)
Coarsening of a rayfire element whose main mesh counterpart was coarsened.
const libMesh::Elem * get_next_elem(const libMesh::Elem *cur_elem, libMesh::Point &start_point, libMesh::Point &end_point, bool same_parent=false)
Calculate the intersection point.
void refine(const libMesh::Elem *main_elem, libMesh::Elem *rayfire_elem)
Refinement of a rayfire element whose main mesh counterpart was refined.
bool validate_edge(const libMesh::Point &start_point, const libMesh::Point &end_point, const libMesh::Elem *side_elem, const libMesh::Elem *neighbor)
Ensures the rayfire doesn't wander into the middle of an elem.
const libMesh::Elem * map_to_rayfire_elem(const libMesh::dof_id_type elem_id)
This function takes in an elem_id on the main mesh and returns an elem from the 1D rayfire mesh...
libMesh::UniquePtr< libMesh::Mesh > _mesh
Internal 1D mesh of EDGE2 elements.
libMesh::Elem * get_rayfire_elem(const libMesh::dof_id_type elem_id)
Private function to get a rayfire elem from main_mesh elem ID.
bool check_valid_point(libMesh::Point &intersection_point, libMesh::Point &start_point, const libMesh::Elem &edge_elem, libMesh::Point &next_point)
Ensure the calculated intersection point is on the edge_elem and is not the start_point.
libMesh::Point _origin
Origin point.
const libMesh::Elem * get_correct_neighbor(libMesh::Point &start_point, libMesh::Point &end_point, const libMesh::Elem *cur_elem, unsigned int side, bool same_parent)
Knowing the end_point, get the appropraite next elem along the path.
const libMesh::Elem * get_start_elem(const libMesh::MeshBase &mesh_base)
Get the correct starting elem corresponding to _origin.
void init(const libMesh::MeshBase &mesh_base)
Initialization.
std::map< libMesh::dof_id_type, libMesh::dof_id_type > _elem_id_map
Map of main mesh elem_id to rayfire mesh elem_id.
const unsigned int _dim
Dimension of the main mesh.
void reinit(const libMesh::MeshBase &mesh_base)
Checks for refined and coarsened main mesh elements along the rayfire path.
bool newton_solve_intersection(libMesh::Point &initial_point, const libMesh::Elem *edge_elem, libMesh::Point &intersection_point)
Iterative solver for calculating the intersection point of the rayfire on the side of an elem...
void elem_ids_in_rayfire(std::vector< libMesh::dof_id_type > &id_vector) const
Returns a vector of elem IDs that are currently along the rayfire.
bool rayfire_in_elem(const libMesh::Point &end_point, const libMesh::Elem *elem)
Walks a short distance along the rayfire and checks if elem contains that point.
libMesh::Real _theta
Rayfire Spherical polar angle (in radians)
RayfireMesh()
User should never call the default constructor.
void check_origin_on_boundary(const libMesh::Elem *start_elem)
Ensure the supplied origin is on a boundary of the mesh.