GRINS-0.8.0
rayfire_mesh.C
Go to the documentation of this file.
1 //-----------------------------------------------------------------------bl-
2 //--------------------------------------------------------------------------
3 //
4 // GRINS - General Reacting Incompressible Navier-Stokes
5 //
6 // Copyright (C) 2014-2017 Paul T. Bauman, Roy H. Stogner
7 // Copyright (C) 2010-2013 The PECOS Development Team
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the Version 2.1 GNU Lesser General
11 // Public License as published by the Free Software Foundation.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Lesser General Public License for more details.
17 //
18 // You should have received a copy of the GNU Lesser General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc. 51 Franklin Street, Fifth Floor,
21 // Boston, MA 02110-1301 USA
22 //
23 //-----------------------------------------------------------------------el-
24 
25 
26 // This class
27 #include "grins/rayfire_mesh.h"
28 
29 // GRINS
30 #include "grins/math_constants.h"
31 
32 // libMesh
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"
38 
39 namespace GRINS
40 {
41  RayfireMesh::RayfireMesh(libMesh::Point& origin, libMesh::Real theta, libMesh::Real phi) :
42  _dim(3),
43  _origin(origin),
44  _theta(theta),
45  _phi(phi)
46  {
47  libmesh_not_implemented();
48  }
49 
50 
51  RayfireMesh::RayfireMesh(libMesh::Point& origin, libMesh::Real theta) :
52  _dim(2),
53  _origin(origin),
54  _theta(theta),
55  _phi(-7.0) // bounds on angles are +/- 2pi
56  {
57  if (std::abs(_theta) > 2.0*Constants::pi)
58  libmesh_error_msg("Please supply a theta value between -2*pi and 2*pi");
59  }
60 
61  RayfireMesh::RayfireMesh(const GetPot & input, const std::string & qoi_string) :
62  _dim(2),
63  _phi(-7.0)
64  {
65  unsigned int rayfire_dim = input.vector_variable_size("QoI/"+qoi_string+"/Rayfire/origin");
66 
67  if (rayfire_dim != 2)
68  libmesh_error_msg("ERROR: Only 2D Rayfires are currently supported");
69 
70  if (!input.have_variable("QoI/"+qoi_string+"/Rayfire/origin"))
71  libmesh_error_msg("ERROR: No origin specified for Rayfire");
72 
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");
75 
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);
79 
80  if (input.have_variable("QoI/"+qoi_string+"/Rayfire/theta"))
81  _theta = input("QoI/"+qoi_string+"/Rayfire/theta", -7.0);
82  else
83  libmesh_error_msg("ERROR: Spherical polar angle theta must be given for Rayfire");
84 
85  if (std::abs(_theta) > 2.0*Constants::pi)
86  libmesh_error_msg("Please supply a theta value between -2*pi and 2*pi");
87 
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");
90  }
91 
93  _dim(original._dim),
94  _origin(original._origin),
95  _theta(original._theta),
96  _phi(original._phi)
97  {
98  if (original._mesh.get())
99  this->_mesh.reset( new libMesh::Mesh( *((original._mesh).get()) ) );
100 
101  this->_elem_id_map = original._elem_id_map;
102  }
103 
104  void RayfireMesh::init(const libMesh::MeshBase& mesh_base)
105  {
106  // consistency check
107  if(mesh_base.mesh_dimension() != _dim)
108  {
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";
113 
114  libmesh_error_msg(ss.str());
115  }
116 
117  _mesh.reset( new libMesh::Mesh(mesh_base.comm(),(unsigned char)1) );
118 
119  libMesh::Point start_point(_origin);
120 
121  // get first element
122  const libMesh::Elem* start_elem = this->get_start_elem(mesh_base);
123 
124  if (!start_elem)
125  libmesh_error_msg("Origin is not on mesh");
126 
127  // ensure the origin is on a boundary element
128  // AND on the boundary of said element
129  this->check_origin_on_boundary(start_elem);
130 
131  // add the origin point to the point list
132  libMesh::Node * start_node = _mesh->add_point(start_point);
133  libMesh::Node * end_node = NULL;
134 
135  libMesh::Point end_point;
136 
137  const libMesh::Elem* next_elem;
138  const libMesh::Elem* prev_elem = start_elem;
139 
140  do
141  {
142  // calculate the end point and
143  // get the next elem in the rayfire
144  next_elem = this->get_next_elem(prev_elem,start_point,end_point);
145 
146 #ifndef NDEBUG
147  // make sure we are only picking up active elements
148  if (next_elem)
149  libmesh_assert( next_elem->active() );
150 #endif
151 
152  // add end point as node on the rayfire mesh
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;
157 
158  // warn if rayfire elem is shorter than TOLERANCE
159  if ( (start_point-end_point).norm() < libMesh::TOLERANCE)
160  {
161  std::stringstream ss;
162  ss <<"********\n"
163  <<"WARNING\n"
164  <<"Detected rayfire element shorter than TOLERANCE\n"
165  <<"Element ID: " <<prev_elem->id() <<", rayfire element length: " <<(start_point-end_point).norm();
166 
167  libmesh_warning(ss.str());
168  }
169 
170  // add new rayfire elem to the map
171  _elem_id_map[prev_elem->id()] = elem->id();
172 
173  start_point = end_point;
174  start_node = end_node;
175  prev_elem = next_elem;
176  } while(next_elem);
177 
178  }
179 
180 
181  const libMesh::Elem* RayfireMesh::map_to_rayfire_elem(const libMesh::dof_id_type elem_id)
182  {
183  return this->get_rayfire_elem(elem_id);
184  }
185 
186 
187  void RayfireMesh::elem_ids_in_rayfire(std::vector<libMesh::dof_id_type>& id_vector) const
188  {
189  std::map<libMesh::dof_id_type,libMesh::dof_id_type>::const_iterator it = _elem_id_map.begin();
190  for(; it != _elem_id_map.end(); it++)
191  {
192  if (_mesh->elem_ptr(it->second)->active())
193  id_vector.push_back(it->first);
194  }
195  }
196 
197 
198  void RayfireMesh::reinit(const libMesh::MeshBase& mesh_base)
199  {
200  // store the elems to be refined until later
201  // so we don't mess with the _elem_id_map while we
202  // iterate over it
203  std::vector<std::pair<const libMesh::Elem*,libMesh::Elem*> > elems_to_refine;
204 
205  // same with elems to coarsen
206  // store the main_mesh elem
207  std::vector<const libMesh::Elem*> elems_to_coarsen;
208 
209  // iterate over all main elems along the rayfire and look for
210  // refinement: INACTIVE parent with JUST_REFINED children
211  // coarsening: JUST_COARSENED parent
212  std::map<libMesh::dof_id_type,libMesh::dof_id_type>::iterator it = _elem_id_map.begin();
213  for(; it != _elem_id_map.end(); it++)
214  {
215  const libMesh::Elem* main_elem = mesh_base.elem_ptr(it->first);
216  libmesh_assert(main_elem);
217 
218  if (main_elem->parent())
219  {
220  if (main_elem->parent()->refinement_flag() == libMesh::Elem::RefinementState::JUST_COARSENED)
221  elems_to_coarsen.push_back(main_elem);
222  }
223 
224  libMesh::Elem::RefinementState state = main_elem->refinement_flag();
225 
226  if (state == libMesh::Elem::RefinementState::INACTIVE)
227  {
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)));
231  }
232  }
233 
234  // refine the elements that need it
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);
237 
238  // coarsen the elements that need it
239  for (unsigned int i=0; i<elems_to_coarsen.size(); i++)
240  this->coarsen(elems_to_coarsen[i]);
241 
242  }
243 
244 
245  // private functions
246 
247  void RayfireMesh::check_origin_on_boundary(const libMesh::Elem* start_elem)
248  {
249  libmesh_assert(start_elem);
250 
251  // first, make sure the elem is on a boundary
252  if ( !(start_elem->on_boundary()) )
253  libmesh_error_msg("The supplied origin point is not on a boundary element");
254 
255  // second, check all boundary sides of the elem
256  // to see if one of them conatins the origin point
257  bool valid = false;
258 
259  for (unsigned int s=0; s<start_elem->n_sides(); s++)
260  {
261  // neighbor_ptr() returns NULL on boundary elems
262  if ( start_elem->neighbor_ptr(s) )
263  continue;
264 
265  // we found a boundary elem, so make an edge and see if it contains the origin
266  libMesh::UniquePtr<const libMesh::Elem> edge_elem = start_elem->build_edge_ptr(s);
267  valid |= edge_elem->contains_point(_origin);
268  }
269 
270  if (!valid)
271  libmesh_error_msg("The supplied origin point is not on the boundary of the starting element");
272  }
273 
274 
275  const libMesh::Elem* RayfireMesh::get_start_elem(const libMesh::MeshBase& mesh_base)
276  {
277  const libMesh::Elem* start_elem = NULL;
278 
279  libMesh::UniquePtr<libMesh::PointLocatorBase> locator = mesh_base.sub_point_locator();
280  const libMesh::Elem* elem = (*locator)(_origin);
281 
282  // elem would be NULL if origin is not on mesh
283  if (elem)
284  {
285  if (this->rayfire_in_elem(_origin,elem))
286  start_elem = elem;
287  else
288  {
289  for (unsigned int i=0; i<elem->n_neighbors(); i++)
290  {
291  const libMesh::Elem* neighbor_elem = elem->neighbor_ptr(i);
292  if (!neighbor_elem)
293  continue;
294 
295  if (this->rayfire_in_elem(_origin,neighbor_elem))
296  {
297  start_elem = neighbor_elem;
298  break;
299  }
300  }
301  }
302  }
303 
304  return start_elem; // might be NULL if _origin is not on mesh
305  }
306 
307 
308  libMesh::Elem* RayfireMesh::get_rayfire_elem(const libMesh::dof_id_type elem_id)
309  {
310  // return value; set if valid rayfire elem is found
311  libMesh::Elem* retval = NULL;
312 
313  std::map<libMesh::dof_id_type,libMesh::dof_id_type>::iterator it;
314  it = _elem_id_map.find(elem_id);
315  if (it != _elem_id_map.end())
316  if (_mesh->elem_ptr(it->second)->refinement_flag() != libMesh::Elem::RefinementState::INACTIVE)
317  retval = _mesh->elem_ptr(it->second);
318 
319  return retval;
320  }
321 
322 
323  const libMesh::Elem* RayfireMesh::get_next_elem(const libMesh::Elem* cur_elem, libMesh::Point& start_point, libMesh::Point& next_point, bool same_parent)
324  {
325  libmesh_assert(cur_elem);
326 
327  libMesh::Point intersection_point;
328 
329  // loop over all sides of the elem and check each one for intersection
330  for (unsigned int s=0; s<cur_elem->n_sides(); s++)
331  {
332  libMesh::UniquePtr<const libMesh::Elem> edge_elem = cur_elem->build_edge_ptr(s);
333 
334  // Using the default tol can cause a false positive when start_point is near a node,
335  // causing this loop to skip over an otherwise valid edge to check
336  if (edge_elem->contains_point(start_point,libMesh::TOLERANCE*0.1))
337  continue;
338 
339  bool converged = this->newton_solve_intersection(start_point,edge_elem.get(),intersection_point);
340 
341  if (converged)
342  {
343  if ( this->check_valid_point(intersection_point,start_point,*edge_elem,next_point) )
344  return this->get_correct_neighbor(start_point,intersection_point,cur_elem,s,same_parent);
345  }
346  else
347  continue;
348 
349  } // for s
350 
351  return NULL; // no intersection
352  }
353 
354 
355  bool RayfireMesh::check_valid_point(libMesh::Point& intersection_point, libMesh::Point& start_point, const libMesh::Elem& edge_elem, libMesh::Point& next_point)
356  {
357  bool is_not_start = !(intersection_point.absolute_fuzzy_equals(start_point));
358  bool is_on_edge = edge_elem.contains_point(intersection_point);
359 
360  bool is_valid = is_not_start && is_on_edge;
361 
362  if ( is_valid )
363  {
364  next_point(0) = intersection_point(0);
365  next_point(1) = intersection_point(1);
366  }
367 
368  return is_valid;
369  }
370 
371 
372  bool RayfireMesh::rayfire_in_elem(const libMesh::Point& end_point, const libMesh::Elem* elem)
373  {
374  libmesh_assert(elem);
375 
376  // move a little bit along the rayfire and see if we are still in the elem
377  // need to move more than TOLERANCE to avoid false positive on contains_point()
378  libMesh::Real L = 2*libMesh::TOLERANCE;
379 
380  // If the elem is too small, need to shorten L so we stay within the elem
381  if ( elem->hmin() < libMesh::TOLERANCE )
382  L = elem->hmin() * 0.1;
383 
384  // parametric representation of rayfire line
385  libMesh::Real x = end_point(0) + L*std::cos(_theta);
386  libMesh::Real y = end_point(1) + L*std::sin(_theta);
387 
388  return elem->contains_point(libMesh::Point(x,y));
389  }
390 
391 
392  bool RayfireMesh::validate_edge(const libMesh::Point & start_point, const libMesh::Point & end_point, const libMesh::Elem * side_elem, const libMesh::Elem * neighbor)
393  {
394  bool is_valid = true;
395 
396  const libMesh::Node * node0 = side_elem->node_ptr(0);
397  const libMesh::Node * node1 = side_elem->node_ptr(1);
398 
399  unsigned int side = libMesh::invalid_uint;
400 
401  for (unsigned int s=0; s<neighbor->n_sides(); s++)
402  {
403  libMesh::UniquePtr<const libMesh::Elem> side_elem = neighbor->build_side_ptr(s);
404 
405  if ( (side_elem->contains_point(*node0)) && (side_elem->contains_point(*node1)) )
406  {
407  side = s;
408  break;
409  }
410  }
411 
412  if ( side != libMesh::invalid_uint )
413  {
414  libMesh::UniquePtr<const libMesh::Elem> edge_elem = neighbor->build_side_ptr(side);
415 
416  bool start_point_on_edge = edge_elem->contains_point(start_point);
417  bool end_point_on_edge = edge_elem->contains_point(end_point);
418 
419  if ( end_point_on_edge && start_point_on_edge )
420  {
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))) );
423 
424  is_valid &= ( l_to_r || r_to_l );
425  }
426  }
427 
428  return is_valid;
429  }
430 
431 
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)
433  {
434  libmesh_assert(cur_elem);
435  libmesh_assert(cur_elem->active());
436 
437  const libMesh::Elem * neighbor = cur_elem->neighbor_ptr(side);
438 
439  // a valid neighbor is an ACTIVE elem or null
440  bool is_valid = true;
441  if (neighbor)
442  is_valid = neighbor->active();
443 
444  if (is_valid)
445  {
446  // check if the intersection point is a vertex
447  bool is_vertex = false;
448  const libMesh::Node * vertex = NULL;
449  for(unsigned int n=0; n<cur_elem->n_nodes(); n++)
450  {
451  if ((cur_elem->node_ptr(n))->absolute_fuzzy_equals(end_point))
452  {
453  is_vertex = true;
454  vertex = cur_elem->node_ptr(n);
455  break;
456  }
457  }
458 
459  if (is_vertex)
460  {
461  // rayfire goes through vertex
462 
463  // check elem neighbors first
464  for (unsigned int s=0; s<cur_elem->n_sides(); s++)
465  {
466  libMesh::UniquePtr<const libMesh::Elem> side_elem = cur_elem->build_side_ptr(s);
467  if (side_elem->contains_point(end_point))
468  {
469  const libMesh::Elem * neighbor = cur_elem->neighbor_ptr(s);
470  if (!neighbor)
471  continue;
472 
473  if (same_parent)
474  {
475  if (neighbor->parent())
476  {
477  if (neighbor->parent()->id() != cur_elem->parent()->id())
478  continue;
479  else
480  if (this->rayfire_in_elem(end_point,neighbor))
481  if (this->validate_edge(start_point,end_point,side_elem.get(),neighbor))
482  return neighbor;
483  }
484  else
485  continue;
486  }
487  else
488  if (this->rayfire_in_elem(end_point,neighbor))
489  if (this->validate_edge(start_point,end_point,side_elem.get(),neighbor))
490  return neighbor;
491  }
492  }
493 
494  // next elem is not a neighbor,
495  // so get all elems that share this vertex
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();
500 
501  // iterate over each elem
502  for (; it != end; ++it)
503  {
504  const libMesh::Elem* elem = *it;
505 
506  if (elem == cur_elem) // skip the current elem
507  continue;
508 
509  if (this->rayfire_in_elem(end_point,elem))
510  return elem;
511  }
512 
513  }
514  else
515  {
516  // check if side is a boundary
517  if( !(cur_elem->neighbor_ptr(side)) )
518  return NULL;
519 
520  // not a vertex or boundary, so just get the elem on that side
521  return cur_elem->neighbor_ptr(side);
522  }
523  } // if (is_valid)
524  else
525  {
526  for (unsigned int c=0; c<neighbor->n_children(); c++)
527  {
528  const libMesh::Elem * child = neighbor->child_ptr(c);
529 
530  if (child->contains_point(end_point))
531  if (this->rayfire_in_elem(end_point,child))
532  return child;
533  }
534  // could not find a valid child elem, so we return NULL below
535  }
536 
537  return NULL;
538  }
539 
540 
541  bool RayfireMesh::newton_solve_intersection(libMesh::Point& initial_point, const libMesh::Elem* edge_elem, libMesh::Point& intersection_point)
542  {
543  libmesh_assert(edge_elem);
544 
545  unsigned int iter_max = 20; // max iterations
546 
547  // the number of shape functions needed for the edge_elem
548  unsigned int n_sf = libMesh::FE<1,libMesh::LAGRANGE>::n_shape_functions(edge_elem->type(),edge_elem->default_order());
549 
550  // starting point on the elem
551  libMesh::Real x0 = initial_point(0);
552  libMesh::Real y0 = initial_point(1);
553 
554  // shape functions and derivatives w.r.t reference coordinate
555  std::vector<libMesh::Real> phi(n_sf);
556  std::vector<libMesh::Real> dphi(n_sf);
557 
558  // Newton iteration step
559  libMesh::Real d_xi;
560 
561  // tan(theta) is the slope, so precompute since it is used repeatedly
562  libMesh::Real tan_theta = std::tan(_theta);
563 
564  // Initial guess is center of the edge_elem
565  libMesh::Real xi = 0.0;
566 
567  // Newton iteration
568  for(unsigned int it=0; it<iter_max; it++)
569  {
570  // Get the shape function and derivative values at the reference coordinate
571  // phi.size() == dphi.size()
572  for(unsigned int i=0; i<phi.size(); i++)
573  {
574  phi[i] = libMesh::FE<1,libMesh::LAGRANGE>::shape(edge_elem->type(),
575  edge_elem->default_order(),
576  i,
577  xi);
578 
579  dphi[i] = libMesh::FE<1,libMesh::LAGRANGE>::shape_deriv(edge_elem->type(),
580  edge_elem->default_order(),
581  i,
582  0, // const unsigned int libmesh_dbg_varj
583  xi);
584  } // for i
585 
586  libMesh::Real X=0.0, Y=0.0, dX=0.0, dY=0.0;
587 
588  for(unsigned int i=0; i<phi.size(); i++)
589  {
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];
594  }
595 
596  libMesh::Real f = tan_theta*(X-x0) - (Y-y0);
597  libMesh::Real df = tan_theta*(dX) - dY;
598 
599  d_xi = f/df;
600 
601  if(std::abs(d_xi) < libMesh::TOLERANCE)
602  {
603  // convergence
604  intersection_point(0) = X;
605  intersection_point(1) = Y;
606  return true;
607  }
608  else
609  xi -= d_xi;
610 
611  } // for it
612 
613  // no convergence
614  return false;
615  }
616 
617 
618  void RayfireMesh::refine(const libMesh::Elem* main_elem, libMesh::Elem* rayfire_elem)
619  {
620  libmesh_assert(main_elem);
621  libmesh_assert(rayfire_elem);
622 
623  libmesh_assert_equal_to(main_elem->refinement_flag(),libMesh::Elem::RefinementState::INACTIVE);
624 
625  // these nodes cannot change
626  libMesh::Node* start_node = rayfire_elem->node_ptr(0);
627  libMesh::Node* end_node = rayfire_elem->node_ptr(1);
628 
629  // set the rayfire_elem as INACTIVE
630  rayfire_elem->set_refinement_flag(libMesh::Elem::RefinementState::INACTIVE);
631 
632  // find which child elem we start with
633  libMesh::dof_id_type start_child = libMesh::invalid_uint;
634  for(unsigned int i=0; i<main_elem->n_children(); i++)
635  {
636  if ( (main_elem->child_ptr(i))->contains_point(*start_node) )
637  {
638  // check if the start point is a vertex
639  bool is_vertex = false;
640  for(unsigned int n=0; n<main_elem->child_ptr(i)->n_nodes(); n++)
641  {
642  if ((main_elem->child_ptr(i)->node_ptr(n))->absolute_fuzzy_equals(*start_node))
643  {
644  is_vertex = true;
645  break;
646  }
647  }
648 
649  if (is_vertex)
650  {
651  if ( this->rayfire_in_elem(*start_node, main_elem->child_ptr(i)) )
652  {
653  start_child = i;
654  break;
655  }
656  }
657  else
658  {
659  start_child = i;
660  break;
661  }
662  }
663  }
664 
665  // make sure we found a starting child elem
666  libmesh_assert_not_equal_to(start_child,libMesh::invalid_uint);
667 
668  // we found the starting element, so perform the rayfire
669  // until we reach the stored end_node
670  libMesh::Point start_point = *start_node;
671  libMesh::Point end_point;
672 
673  const libMesh::Elem* next_elem;
674  const libMesh::Elem* prev_elem = main_elem->child_ptr(start_child);
675 
676  // if prev_elem is INACTIVE, then more than one refinement
677  // has taken place between reinit() calls and will
678  // break this
679  libmesh_assert_equal_to( prev_elem->refinement_flag(), libMesh::Elem::RefinementState::JUST_REFINED );
680 
681  libMesh::Node * prev_node = start_node;
682  libMesh::Node * new_node = NULL;
683 
684  // iterate until we reach the stored end_node
685  do
686  {
687  next_elem = this->get_next_elem(prev_elem,start_point,end_point,true);
688 
689 #ifndef NDEBUG
690  // make sure we are only picking up active elements
691  if (next_elem)
692  libmesh_assert( next_elem->active() );
693 #endif
694 
695  // add end point as node on the rayfire mesh
696  new_node = _mesh->add_point(end_point);
697  libMesh::Elem* elem = _mesh->add_elem(new libMesh::Edge2);
698 
699  elem->set_node(0) = prev_node;
700  elem->set_node(1) = new_node;
701 
702  libmesh_assert_less( (*(elem->node_ptr(0))-_origin).norm(), (*(elem->node_ptr(1))-_origin).norm());
703 
704  // warn if rayfire elem is shorter than TOLERANCE
705  if ( (start_point-end_point).norm() < libMesh::TOLERANCE)
706  {
707  std::stringstream ss;
708  ss <<"********\n"
709  <<"WARNING\n"
710  <<"Detected rayfire element shorter than TOLERANCE on refinement\n"
711  <<"Element ID: " <<prev_elem->id() <<", rayfire element length: " <<(start_point-end_point).norm();
712 
713  libmesh_warning(ss.str());
714  }
715 
716  // set rayfire_elem as the parent of this new elem
717  // in case it gets coarsened
718  elem->set_parent(rayfire_elem);
719 
720  // add new rayfire elem to the map
721  _elem_id_map[prev_elem->id()] = elem->id();
722  start_point = end_point;
723  prev_elem = next_elem;
724  prev_node = new_node;
725 
726  } while(!(new_node->absolute_fuzzy_equals(*end_node)));
727 
728  }
729 
730 
731  void RayfireMesh::coarsen(const libMesh::Elem* child_elem)
732  {
733  libmesh_assert(child_elem);
734 
735  if (this->get_rayfire_elem(child_elem->id()))
736  {
737  const libMesh::Elem* parent_elem = child_elem->parent();
738  libmesh_assert(parent_elem);
739 
740  const libMesh::Node* start_node = NULL;
741  const libMesh::Node* end_node = NULL;
742 
743  for (unsigned int c=0; c<parent_elem->n_children(); c++)
744  {
745  libMesh::Elem* rayfire_child = this->get_rayfire_elem(parent_elem->child_ptr(c)->id());
746 
747  if (rayfire_child)
748  {
749  if (!start_node)
750  {
751  start_node = rayfire_child->node_ptr(0);
752  end_node = rayfire_child->node_ptr(1);
753  }
754  else
755  {
756  if ( (this->_origin - *(rayfire_child->node_ptr(0))).norm() < (this->_origin - *start_node).norm() )
757  start_node = rayfire_child->node_ptr(0);
758 
759  if ( (this->_origin - *(rayfire_child->node_ptr(1))).norm() > (this->_origin - *end_node).norm() )
760  end_node = rayfire_child->node_ptr(1);
761  }
762 
763  rayfire_child->set_refinement_flag(libMesh::Elem::RefinementState::INACTIVE);
764  }
765  } // for c
766 
767  // make sure we found nodes
768  libmesh_assert(start_node);
769  libmesh_assert(end_node);
770 
771  // add a new rayfire elem
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());
775 
776  libmesh_assert_less( (*(elem->node_ptr(0))-_origin).norm(), (*(elem->node_ptr(1))-_origin).norm());
777 
778  // add new rayfire elem to the map
779  _elem_id_map[parent_elem->id()] = elem->id();
780  }
781 
782  }
783 
784 } //namespace GRINS
void coarsen(const libMesh::Elem *rayfire_elem)
Coarsening of a rayfire element whose main mesh counterpart was coarsened.
Definition: rayfire_mesh.C:731
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.
Definition: rayfire_mesh.C:323
void refine(const libMesh::Elem *main_elem, libMesh::Elem *rayfire_elem)
Refinement of a rayfire element whose main mesh counterpart was refined.
Definition: rayfire_mesh.C:618
RayfireMesh.
Definition: rayfire_mesh.h:65
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.
Definition: rayfire_mesh.C:392
const libMesh::Real pi
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...
Definition: rayfire_mesh.C:181
libMesh::UniquePtr< libMesh::Mesh > _mesh
Internal 1D mesh of EDGE2 elements.
Definition: rayfire_mesh.h:148
libMesh::Elem * get_rayfire_elem(const libMesh::dof_id_type elem_id)
Private function to get a rayfire elem from main_mesh elem ID.
Definition: rayfire_mesh.C:308
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.
Definition: rayfire_mesh.C:355
GRINS namespace.
libMesh::Point _origin
Origin point.
Definition: rayfire_mesh.h:139
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.
Definition: rayfire_mesh.C:432
const libMesh::Elem * get_start_elem(const libMesh::MeshBase &mesh_base)
Get the correct starting elem corresponding to _origin.
Definition: rayfire_mesh.C:275
void init(const libMesh::MeshBase &mesh_base)
Initialization.
Definition: rayfire_mesh.C:104
std::map< libMesh::dof_id_type, libMesh::dof_id_type > _elem_id_map
Map of main mesh elem_id to rayfire mesh elem_id.
Definition: rayfire_mesh.h:151
const unsigned int _dim
Dimension of the main mesh.
Definition: rayfire_mesh.h:136
void reinit(const libMesh::MeshBase &mesh_base)
Checks for refined and coarsened main mesh elements along the rayfire path.
Definition: rayfire_mesh.C:198
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...
Definition: rayfire_mesh.C:541
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.
Definition: rayfire_mesh.C:187
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.
Definition: rayfire_mesh.C:372
libMesh::Real _theta
Rayfire Spherical polar angle (in radians)
Definition: rayfire_mesh.h:142
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.
Definition: rayfire_mesh.C:247

Generated on Tue Dec 19 2017 12:47:28 for GRINS-0.8.0 by  doxygen 1.8.9.1