AuxMeshTopology.h
Go to the documentation of this file.
1 /*
2 This file is part of the Ristra Wonton project.
3 Please see the license file at the root of this repository, or at:
4  https://github.com/laristra/wonton/blob/master/LICENSE
5 */
6 
7 
8 
9 // Copyright 2016, Los Alamos National Laboratory, NM, USA
10 
11 #ifndef AUX_MESH_TOPOLOGY_H_
12 #define AUX_MESH_TOPOLOGY_H_
13 
14 #include <vector>
15 #include <array>
16 #include <algorithm>
17 #include <utility>
18 #include <limits>
19 
20 #include "wonton/support/wonton.h"
21 #include "wonton/support/Point.h"
22 
23 namespace Wonton {
24 
25 using namespace Wonton;
26 // Some helper functions
28 inline
29 double calc_side_volume(std::array<Point<1>, 2> const& sxyz) {
30  return (sxyz[1][0]-sxyz[0][0]);
31 }
32 
34 inline
35 double calc_side_volume(std::array<Point<2>, 3> const& sxyz) {
36  Vector<2> vec1 = sxyz[1]-sxyz[0];
37  Vector<2> vec2 = sxyz[2]-sxyz[0];
38  return 0.5*cross(vec1, vec2);
39 }
40 
42 inline
43 double calc_side_volume(std::array<Point<3>, 4> const& sxyz) {
44  Vector<3> vec1 = sxyz[1]-sxyz[0];
45  Vector<3> vec2 = sxyz[2]-sxyz[0];
46  Vector<3> vec3 = sxyz[3]-sxyz[0];
47  Vector<3> cpvec = cross(vec1, vec2);
48  return dot(cpvec, vec3)/6.0;
49 }
50 
51 template<typename BasicMesh> class AuxMeshTopology;
52 template<typename BasicMesh>
54 template<typename BasicMesh>
56 template<typename BasicMesh>
58 
59 
77 //
172 
173 
174 
175 template<typename BasicMesh>
176 class AuxMeshTopology {
177  public:
178 
184 
185  AuxMeshTopology(bool request_sides = true,
186  bool request_wedges = true,
187  bool request_corners = true) :
188  sides_requested_(request_sides || request_wedges || request_corners),
189  wedges_requested_(request_wedges || request_corners),
190  corners_requested_(request_corners) {
191 
192  // we really cannot do anything without sides, so we will turn
193  // them on all the time. Don't want to change the interface at
194  // this time though.
195 
196  sides_requested_ = true;
197 
198  // Part of the CRTP magic. Knowing that we will be deriving the
199  // BasicMesh class from this class, we can cast a pointer to this
200  // class type to a pointer of BasicMesh class type and call its
201  // methods
202 
203  basicmesh_ptr_ = static_cast<BasicMesh*>(this);
204 
205  // Sadly we cannot trigger building of entities here because, this
206  // routine reaches into the derived class which has not yet had a chance
207  // to initialize some class data which will support the basic mesh queries
208  // needed. So we have to call this routine from the derived class
209 
210  // build_aux_entities()
211  }
212 
213 
214  // //! A method expected to be found in the BasicMesh class but defined
215  // //! here as pure virtual to prevent this class from ever being
216  // //! instantiated directly
217 
218  // virtual int space_dimension() const = 0;
219 
220 
222 
223  int num_owned_sides() const {
224  return num_sides_owned_;
225  }
226 
227 
229 
230  int num_owned_wedges() const {
231  return num_wedges_owned_;
232  }
233 
234 
236 
237  int num_owned_corners() const {
238  return num_corners_owned_;
239  }
240 
241 
243 
244  int num_ghost_sides() const {
245  return num_sides_ghost_;
246  }
247 
248 
250 
251  int num_ghost_wedges() const {
252  return num_wedges_ghost_;
253  }
254 
255 
257 
258  int num_ghost_corners() const {
259  return num_corners_ghost_;
260  }
261 
262 
264  int num_entities(Entity_kind const entity,
265  Entity_type const etype = Entity_type::ALL) const {
266  switch (entity) {
267  case CELL:
268  switch (etype) {
269  case PARALLEL_OWNED: return basicmesh_ptr_->num_owned_cells();
270  case PARALLEL_GHOST: return basicmesh_ptr_->num_ghost_cells();
271  case ALL: return (basicmesh_ptr_->num_owned_cells() +
272  basicmesh_ptr_->num_ghost_cells());
273  default: return 0;
274  }
275  case FACE:
276  switch (etype) {
277  case PARALLEL_OWNED: return basicmesh_ptr_->num_owned_faces();
278  case PARALLEL_GHOST: return basicmesh_ptr_->num_ghost_faces();
279  case ALL: return (basicmesh_ptr_->num_owned_faces() +
280  basicmesh_ptr_->num_ghost_faces());
281  default: return 0;
282  }
283  case NODE:
284  switch (etype) {
285  case PARALLEL_OWNED: return basicmesh_ptr_->num_owned_nodes();
286  case PARALLEL_GHOST: return basicmesh_ptr_->num_ghost_nodes();
287  case ALL: return (basicmesh_ptr_->num_owned_nodes() +
288  basicmesh_ptr_->num_ghost_nodes());
289  default: return 0;
290  }
291  case SIDE:
292  switch (etype) {
293  case PARALLEL_OWNED: return num_owned_sides();
294  case PARALLEL_GHOST: return num_ghost_sides();
295  case ALL: return (num_owned_sides() + num_ghost_sides());
296  default: return 0;
297  }
298  case WEDGE:
299  switch (etype) {
300  case PARALLEL_OWNED: return num_owned_wedges();
301  case PARALLEL_GHOST: return num_ghost_wedges();
302  case ALL: return (num_owned_wedges() + num_ghost_wedges());
303  default: return 0;
304  }
305  case CORNER:
306  switch (etype) {
307  case PARALLEL_OWNED: return num_owned_corners();
308  case PARALLEL_GHOST: return num_ghost_corners();
309  case ALL: return (num_owned_corners() + num_ghost_corners());
310  default: return 0;
311  }
312  default:
313  return 0;
314  }
315  }
316 
319  Entity_type const etype = Entity_type::ALL) const {
320  int start_index = 0;
321  return make_counting_iterator(start_index);
322  }
323 
326  Entity_type const etype = Entity_type::ALL) const {
327  int start_index = 0;
328  return (make_counting_iterator(start_index) + num_entities(entity, etype));
329  }
330 
331 
332 
341  void cell_get_node_adj_cells(int const cellid,
342  Entity_type const ptype,
343  std::vector<int> *adjcells) const {
344 
345  // If it does not interfere with the GPU implementation, we could
346  // insert into a std::set (nlog(n) instead of n^2) and then copy
347  // into the output vector
348 
349  adjcells->clear();
350 
351  // Find the nodes attached to this cell
352  std::vector<int> cellnodes;
353  basicmesh_ptr_->cell_get_nodes(cellid, &cellnodes);
354 
355  // Loop over these nodes and find the associated cells; these are the ones
356  // we seek, but make sure there are not duplicates.
357  for (auto const& n : cellnodes) {
358  std::vector<int> nodecells;
359  basicmesh_ptr_->node_get_cells(n, ptype, &nodecells);
360 
361  for (auto const& c : nodecells) {
362  if (c == cellid) continue;
363  if (std::find(adjcells->begin(), adjcells->end(), c) == adjcells->end())
364  adjcells->push_back(c);
365  }
366  }
367  } // cell_get_node_adj_cells
368 
369 
371  void face_get_cells(int const faceid, Entity_type const etype,
372  std::vector<int> *cells) const {
373  cells->clear();
374  int c0 = face_cell_ids_[faceid][0];
375  if (c0 != -1) {
376  Entity_type ctype0 = basicmesh_ptr_->cell_get_type(c0);
377  if (etype == Entity_type::ALL || ctype0 == etype)
378  cells->push_back(c0);
379  }
380  int c1 = face_cell_ids_[faceid][1];
381  if (c1 != -1) {
382  Entity_type ctype1 = basicmesh_ptr_->cell_get_type(c1);
383  if (etype == Entity_type::ALL || ctype1 == etype)
384  cells->push_back(c1);
385  }
386  }
387 
395  int cell_get_face_adj_cell(int cell, int face) const {
396  std::vector<int> cellfaces;
397  basicmesh_ptr_->face_get_cells(face, Entity_type::ALL, &cellfaces);
398  int const nb_adj_cells = cellfaces.size();
399 
400  // Interfaces we need are always connected to two cells
401  if (nb_adj_cells == 2) {
402  int index = (cellfaces[0] == cell ? 1 : 0);
403  return cellfaces[index];
404  }
405  return -1;
406  } // cell_get_face_incident_neigh
407 
418  void cell_get_face_adj_cells(int const cellid,
419  Entity_type const ptype,
420  std::vector<int> *adjcells) const {
421  adjcells->clear();
422 
423  // Find the faces attached to this cell
424  std::vector<int> cellfaces, cfdirs;
425  basicmesh_ptr_->cell_get_faces_and_dirs(cellid, &cellfaces, &cfdirs);
426 
427  // Loop over these faces and find the cells on the other side
428  for (auto const& f : cellfaces) {
429  std::vector<int> facecells;
430  basicmesh_ptr_->face_get_cells(f, ptype, &facecells);
431 
432  // Interfaces we need are always connected to two cells
433  if (facecells.size() == 2) {
434  int iac = (facecells[0] == cellid) ? 1 : 0;
435  adjcells->push_back(facecells[iac]);
436  }
437  }
438  } // cell_get_face_adj_cells
439 
448  void node_get_cell_adj_nodes(int const nodeid,
449  Entity_type const ptype,
450  std::vector<int> *adjnodes) const {
451  adjnodes->clear();
452 
453  // If it does not interfere with the GPU implementation, we could
454  // insert into a std::set (nlog(n) instead of n^2) and then copy
455  // into the output vector
456 
457  // Find the cells attached to this node
458  std::vector<int> nodecells;
459  basicmesh_ptr_->node_get_cells(nodeid, Entity_type::ALL, &nodecells);
460 
461  // Loop over these cells, and find their nodes; these are the ones we seek
462  // but make sure we aren't duplicating them
463  for (auto const& c : nodecells) {
464  std::vector<int> cellnodes;
465  basicmesh_ptr_->cell_get_nodes(c, &cellnodes);
466 
467  for (auto const& n : cellnodes) {
468  if (n == nodeid) continue;
469  Entity_type ntype = basicmesh_ptr_->node_get_type(n);
470  if (ptype == Entity_type::ALL || ntype == ptype) {
471  if (std::find(adjnodes->begin(), adjnodes->end(), n) == adjnodes->end())
472  adjnodes->push_back(n);
473  }
474  }
475  }
476  } // node_get_cell_adj_nodes
477 
478 
480  bool on_exterior_boundary(Entity_kind const entity, int const entity_id) const {
481  switch (entity) {
482  case NODE:
483  return node_on_exterior_boundary_[entity_id];
484  case FACE:
485  return face_on_exterior_boundary_[entity_id];
486  case CELL:
487  return cell_on_exterior_boundary_[entity_id];
488  case SIDE:
489  return cell_on_exterior_boundary_[side_cell_id_[entity_id]];
490  case CORNER:
491  return cell_on_exterior_boundary_[corner_cell_id_[entity_id]];
492  default:
493  return false;
494  }
495  }
496 
497 
499 
500  template <int D>
501  void cell_get_coordinates(int const cellid,
502  std::vector<Point<D>> *pplist) const;
503 
505 
506  template <int D>
507  void cell_centroid(int const cellid, Point<D> *ccen) const {
508 #ifdef DEBUG
509  assert(cellid < num_entities(CELL, ALL));
510 #endif
511  for (int d = 0; d < D; ++d)
512  (*ccen)[d] = cell_centroids_[cellid][d];
513  }
514 
516 
517  double cell_volume(int const cellid) const {
518 #ifdef DEBUG
519  assert(cellid < num_entities(CELL, ALL));
520 #endif
521  assert(sides_requested_);
522  return cell_volumes_[cellid];
523  }
524 
525 
527 
528  template <int D>
529  void face_centroid(int const faceid, Point<D> *fcen) const {
530 #ifdef DEBUG
531  assert(faceid < num_entities(FACE, ALL));
532 #endif
533  for (int d = 0; d < D; ++d)
534  (*fcen)[d] = face_centroids_[faceid][d];
535  }
536 
537 
546 
547  int side_get_node(int const sideid, int const inode) const {
548 #ifdef DEBUG
549  assert(sideid < num_entities(SIDE, ALL));
550 #endif
551  assert(sides_requested_);
552  assert(inode == 0 || inode == 1);
553  return side_node_ids_[sideid][inode];
554  }
555 
556 
558 
559  int side_get_cell(int const sideid) const {
560 #ifdef DEBUG
561  assert(sideid < num_entities(SIDE, ALL));
562 #endif
563  assert(sides_requested_);
564  return side_cell_id_[sideid];
565  }
566 
567 
569 
570  int side_get_face(int const sideid) const {
571 #ifdef DEBUG
572  assert(sideid < num_entities(SIDE, ALL));
573 #endif
574  assert(sides_requested_);
575  return side_face_id_[sideid];
576  }
577 
578 
585 
586  int side_get_wedge(int const sideid, int iwedge) const {
587 #ifdef DEBUG
588  assert(sideid < num_entities(SIDE, ALL));
589 #endif
590  assert(wedges_requested_);
591  return 2*sideid + iwedge;
592  }
593 
594 
601 
602  int side_get_opposite_side(int const sideid) const {
603 #ifdef DEBUG
604  assert(sideid < num_entities(SIDE, ALL));
605 #endif
606  assert(sides_requested_);
607  return side_opp_side_id_[sideid];
608  }
609 
610 
612 
613  void cell_get_sides(int const cellid, std::vector<int> *csides) const {
614 #ifdef DEBUG
615  assert(cellid < num_entities(CELL, ALL));
616 #endif
617  assert(sides_requested_);
618  csides->resize(cell_side_ids_[cellid].size());
619  std::copy(cell_side_ids_[cellid].begin(), cell_side_ids_[cellid].end(),
620  csides->begin());
621  }
622 
633 
634  void side_get_coordinates(int const sideid,
635  std::array<Point<3>, 4> *scoords,
636  bool posvol_order = false) const;
637 
648 
649  void side_get_coordinates(int const sideid,
650  std::array<Point<2>, 3> *scoords,
651  bool posvol_order = false) const;
652 
661 
662  void side_get_coordinates(int const sideid,
663  std::array<Point<1>, 2> *scoords,
664  bool posvol_order = false) const;
665 
666 
668 
669  double side_volume(int const sideid) const {
670 #ifdef DEBUG
671  assert(sideid < num_entities(SIDE, ALL));
672 #endif
673  assert(sides_requested_);
674  return side_volumes_[sideid];
675  }
676 
678 
679  int wedge_get_side(int const wedgeid) const {
680 #ifdef DEBUG
681  assert(wedgeid < num_entities(WEDGE, ALL));
682 #endif
683  assert(wedges_requested_);
684  return static_cast<int>(wedgeid/2);
685  }
686 
687 
689 
690  int wedge_get_cell(int const wedgeid) const {
691 #ifdef DEBUG
692  assert(wedgeid < num_entities(WEDGE, ALL));
693 #endif
694  assert(wedges_requested_);
695  int sideid = static_cast<int>(wedgeid/2);
696  return side_cell_id_[sideid];
697  }
698 
699 
701 
702  int wedge_get_face(int const wedgeid) const {
703 #ifdef DEBUG
704  assert(wedgeid < num_entities(WEDGE, ALL));
705 #endif
706  assert(wedges_requested_);
707  int sideid = static_cast<int>(wedgeid/2);
708  return side_face_id_[sideid];
709  }
710 
711 
713 
714  int wedge_get_corner(int const wedgeid) const {
715 #ifdef DEBUG
716  assert(wedgeid < num_entities(WEDGE, ALL));
717 #endif
718  assert(corners_requested_);
719  return wedge_corner_id_[wedgeid];
720  }
721 
722 
724 
725  int wedge_get_node(int const wedgeid) const {
726 #ifdef DEBUG
727  assert(wedgeid < num_entities(WEDGE, ALL));
728 #endif
729  assert(wedges_requested_);
730  int sideid = static_cast<int>(wedgeid/2);
731  return wedgeid%2 ? side_node_ids_[sideid][1] : side_node_ids_[sideid][0];
732  }
733 
734 
741 
742  int wedge_get_opposite_wedge(const int wedgeid) const {
743 #ifdef DEBUG
744  assert(wedgeid < num_entities(WEDGE, ALL));
745 #endif
746  assert(wedges_requested_);
747  int sideid = static_cast<int>(wedgeid/2);
748  int oppsideid = side_opp_side_id_[sideid];
749  if (oppsideid >= 0)
750  return (wedgeid%2 ? 2*oppsideid : 2*oppsideid + 1);
751  else
752  return -1;
753  }
754 
755 
761 
762  int wedge_get_adjacent_wedge(const int wedgeid) const {
763 #ifdef DEBUG
764  assert(wedgeid < num_entities(WEDGE, ALL));
765 #endif
766  // Wedges come in pairs; their IDs are (2*sideid) and (2*sideid+1)
767  // If the wedge ID is an odd number, then the adjacent wedge ID is
768  // wedge ID minus one; If it is an even number, the adjacent wedge
769  // ID is wedge ID plus one
770 
771  return (wedgeid%2 ? wedgeid - 1 : wedgeid + 1);
772  }
773 
774 
776 
777  double wedge_volume(int const wedgeid) const {
778 #ifdef DEBUG
779  assert(wedgeid < num_entities(WEDGE, ALL));
780 #endif
781  int sideid = static_cast<int>(wedgeid/2);
782  return 0.5*side_volumes_[sideid];
783  }
784 
785 
796 
797  void wedge_get_coordinates(int const wedgeid,
798  std::array<Point<3>, 4> *wcoords,
799  bool posvol_order = false) const;
800 
801 
812 
813  void wedge_get_coordinates(int const wedgeid,
814  std::array<Point<2>, 3> *wcoords,
815  bool posvol_order = false) const;
816 
817 
826 
827  void wedge_get_coordinates(int const wedgeid,
828  std::array<Point<1>, 2> *wcoords,
829  bool posvol_order = false) const;
830 
831 
833 
834  void cell_get_wedges(int const cellid, std::vector<int> *wedgeids) const {
835 #ifdef DEBUG
836  assert(cellid < num_entities(CELL, ALL));
837 #endif
838  int nsides = cell_side_ids_[cellid].size();
839  wedgeids->resize(2*nsides);
840  int iw = 0;
841  for (auto const& s : cell_side_ids_[cellid]) {
842  (*wedgeids)[iw++] = 2*s;
843  (*wedgeids)[iw++] = 2*s + 1;
844  }
845  }
846 
847 
849 
850  void node_get_wedges(int const nodeid, Entity_type const type,
851  std::vector<int> *wedgeids) const {
852 #ifdef DEBUG
853  assert(nodeid < num_entities(NODE, ALL));
854 #endif
855  assert(wedges_requested_ && corners_requested_);
856  wedgeids->clear();
857  for (auto const& cn : node_corner_ids_[nodeid]) {
858  std::vector<int> cnwedges = corner_wedge_ids_[cn];
859  for (auto const& w : cnwedges) {
860  int s = static_cast<int>(w/2);
861  int c = side_cell_id_[s];
862 
863  if (type == ALL ||
864  static_cast<int>(basicmesh_ptr_->cell_get_type(c)) == type)
865  wedgeids->push_back(w);
866  }
867  }
868  }
869 
870 
872 
873  int corner_get_node(const int cornerid) const {
874 #ifdef DEBUG
875  assert(cornerid < num_entities(CORNER, ALL));
876 #endif
877  assert(corners_requested_);
878  return corner_node_id_[cornerid];
879  }
880 
881 
883 
884  int corner_get_cell(int const cornerid) const {
885 #ifdef DEBUG
886  assert(cornerid < num_entities(CORNER, ALL));
887 #endif
888  assert(corners_requested_);
889  return corner_cell_id_[cornerid];
890  }
891 
892 
894 
895  void corner_get_wedges(int const cornerid, std::vector<int> *wedgeids) const {
896 #ifdef DEBUG
897  assert(cornerid < num_entities(CORNER, ALL));
898 #endif
899  assert(corners_requested_);
900  wedgeids->resize(corner_wedge_ids_[cornerid].size());
901  std::copy(corner_wedge_ids_[cornerid].begin(),
902  corner_wedge_ids_[cornerid].end(), wedgeids->begin());
903  }
904 
905 
907 
908  void node_get_corners(int const nodeid, Entity_type const type,
909  std::vector<int> *cornerids) const {
910 #ifdef DEBUG
911  assert(nodeid < num_entities(NODE, ALL));
912 #endif
913  assert(corners_requested_);
914  if (type == ALL) {
915  cornerids->resize(node_corner_ids_[nodeid].size());
916  std::copy(node_corner_ids_[nodeid].begin(),
917  node_corner_ids_[nodeid].end(),
918  cornerids->begin());
919  } else {
920  cornerids->clear();
921  for (auto const& cn : node_corner_ids_[nodeid]) {
922  int c = corner_cell_id_[cn];
923  if (static_cast<int>(basicmesh_ptr_->cell_get_type(c)) == type)
924  cornerids->push_back(cn);
925  }
926  }
927  }
928 
929 
931 
932  void cell_get_corners(int const cellid, std::vector<int> *cornerids) const {
933 #ifdef DEBUG
934  assert(cellid < num_entities(CELL, ALL));
935 #endif
936  assert(corners_requested_);
937  cornerids->resize(cell_corner_ids_[cellid].size());
938  std::copy(cell_corner_ids_[cellid].begin(), cell_corner_ids_[cellid].end(),
939  cornerids->begin());
940  }
941 
943 
944  int cell_get_corner_at_node(int const cellid, int const nodeid) const {
945 #ifdef DEBUG
946  assert(cellid < num_entities(CELL, ALL));
947 #endif
948  assert(corners_requested_);
949  for (auto const& cn : cell_corner_ids_[cellid]) {
950  if (corner_get_node(cn) == nodeid)
951  return cn;
952  }
953 
954  throw std::runtime_error("no corner found");
955  }
956 
958 
959  double corner_volume(int const cornerid) const {
960 #ifdef DEBUG
961  assert(cornerid < num_entities(CORNER, ALL));
962 #endif
963  assert(corners_requested_);
964  double cnvol = 0.0;
965  for (auto const& w : corner_wedge_ids_[cornerid])
966  cnvol += wedge_volume(w);
967  return cnvol;
968  }
969 
971  void cell_get_facetization(int const cellid,
972  std::vector<std::vector<int>> *facetpoints,
973  std::vector<Point<3>> *points) const;
974 
975 
978  void dual_cell_get_facetization(int const nodeid,
979  std::vector<std::vector<int>> *facetpoints,
980  std::vector<Point<3>> *points) const;
981 
982 
984 
985  void decompose_cell_into_tets(int cellid,
986  std::vector<std::array<Wonton::Point<3>, 4>> *tcoords,
987  const bool planar_hex) const {
988 #ifdef DEBUG
989  assert(cellid < num_entities(CELL, ALL));
990 #endif
991  if (planar_hex
992  && basicmesh_ptr_->cell_get_element_type(cellid) == HEX) {
993  // Decompose a hex into a 5-tet decomposition.
994 
995  // IMPORTANT: This only works well if the hex is planar. Otherwise we
996  // need to implement some more sophisticated solution.
997  std::vector<Point<3>> coords;
998  basicmesh_ptr_->cell_get_coordinates(cellid, &coords);
999  /*
1000 
1001  The hex is returned using the following numbering::
1002 
1003  7---6
1004  /| /|
1005  4---5 |
1006  | 3-|-2
1007  |/ |/
1008  0---1
1009 
1010  Then `indexes` contains the 5-tet decomposition of this hex.
1011 
1012  The tet's vertices are ordered in the following way:
1013 
1014  3
1015  / | \
1016  / | \
1017  2--|---1
1018  \ | /
1019  0
1020  */
1021  const int indexes[5][4] = {
1022  {0, 1, 3, 4},
1023  {1, 4, 5, 6},
1024  {1, 3, 4, 6},
1025  {1, 6, 2, 3},
1026  {4, 7, 6, 3}
1027  };
1028  for (unsigned int t = 0; t < 5; t++) {
1029  std::array<Wonton::Point<3>, 4> tmp;
1030  for (int i = 0; i < 4; i++) {
1031  for (int j = 0; j < 3; j++) {
1032  tmp[i][j] = coords[indexes[t][i]][j];
1033  }
1034  }
1035  tcoords->push_back(tmp);
1036  }
1037  } else {
1038  sides_get_coordinates(cellid, tcoords);
1039  }
1040  }
1041 
1042 
1044  // Input is the node ID 'nodeid', and it returns the vertex coordinates of
1045  // the dual cell around this node in `pplist`. The vertices are ordered CCW.
1046  // For boundary node 'nodeid', the first vertex is the node itself, this
1047  // uniquely determines the 'pplist' vector. For node 'nodeid' not on a
1048  // boundary, the vector 'pplist' starts with a random vertex, but it is still
1049  // ordered CCW. Use the 'dual_cell_coordinates_canonical_rotation' to rotate
1050  // the 'pplist' into a canonical (unique) form.
1051 
1052  void dual_cell_get_coordinates(int const nodeid,
1053  std::vector<Point<2>> *pplist) const {
1054 #ifdef DEBUG
1055  assert(nodeid < num_entities(NODE, ALL));
1056 #endif
1057  assert(basicmesh_ptr_->space_dimension() == 2);
1058  assert(wedges_requested_);
1059 
1060  int cornerid, wedgeid, wedgeid0;
1061  std::vector<int> cornerids, wedgeids;
1062  std::array<Point<2>, 3> wcoords; // (node, edge midpoint, centroid)
1063 
1064  // Start with an arbitrary corner
1065  node_get_corners(nodeid, ALL, &cornerids);
1066  cornerid = cornerids[0];
1067 
1068  // Process this corner
1069  corner_get_wedges(cornerid, &wedgeids);
1070  order_wedges_ccw(&wedgeids);
1071  wedge_get_coordinates(wedgeids[0], &wcoords);
1072  pplist->emplace_back(wcoords[2]); // centroid
1073  wedge_get_coordinates(wedgeids[1], &wcoords);
1074  pplist->emplace_back(wcoords[1]); // edge midpoint
1075 
1076  wedgeid0 = wedgeids[0];
1077 
1078  // Process the rest of the corners in the CCW manner
1079  wedgeid = wedge_get_opposite_wedge(wedgeids[1]);
1080  // wedgeid == -1 means we are on the boundary, and wedgeid == wedgeid0
1081  // means we are not on the boundary and we finished the loop
1082  while (wedgeid != -1 && wedgeid != wedgeid0) {
1083  cornerid = wedge_get_corner(wedgeid);
1084  corner_get_wedges(cornerid, &wedgeids);
1085  order_wedges_ccw(&wedgeids);
1086  assert(wedgeids[0] == wedgeid);
1087  wedge_get_coordinates(wedgeids[0], &wcoords);
1088  pplist->push_back(wcoords[2]); // centroid
1089  wedge_get_coordinates(wedgeids[1], &wcoords);
1090  pplist->push_back(wcoords[1]); // edge midpoint
1091  wedgeid = wedge_get_opposite_wedge(wedgeids[1]);
1092  }
1093 
1094  if (wedgeid == -1) {
1095  // This is a boundary node, go the other way in a CW manner to get all
1096  // the coordinates and include the node (nodeid) itself
1097  wedge_get_coordinates(wedgeid0, &wcoords);
1098  // edge midpoint
1099  pplist->insert(pplist->begin(), wcoords[1]);
1100 
1101  wedgeid = wedge_get_opposite_wedge(wedgeid0);
1102  // We must encounter the other boundary, so we only test for wedgeid ==
1103  // -1
1104  while (wedgeid != -1) {
1105  cornerid = wedge_get_corner(wedgeid);
1106  corner_get_wedges(cornerid, &wedgeids);
1107  order_wedges_ccw(&wedgeids);
1108  assert(wedgeids[1] == wedgeid);
1109  wedge_get_coordinates(wedgeids[1], &wcoords);
1110  // centroid
1111  pplist->insert(pplist->begin(), wcoords[2]);
1112  wedge_get_coordinates(wedgeids[0], &wcoords);
1113  // edge midpoint
1114  pplist->insert(pplist->begin(), wcoords[1]);
1115  wedgeid = wedge_get_opposite_wedge(wedgeids[0]);
1116  }
1117 
1118  // Include the node itself
1119  pplist->insert(pplist->begin(), wcoords[0]);
1120  }
1121  }
1122 
1123 
1125 
1126  void order_wedges_ccw(std::vector<int> *wedgeids) const {
1127  assert(wedges_requested_);
1128  assert(wedgeids->size() == 2);
1129  std::array<Point<2>, 3> wcoords;
1130  wedge_get_coordinates((*wedgeids)[0], &wcoords);
1131 
1132  // Ensure (*wedgeids)[0] is the first wedge in a CCW direction
1133  if (!ccw(wcoords[0], wcoords[1], wcoords[2])) {
1134  std::swap((*wedgeids)[0], (*wedgeids)[1]);
1135  }
1136  }
1137 
1140 
1141  bool ccw(Point<2> const& p1, Point<2> const& p2, Point<2> const& p3) const {
1142  return (p2[0] - p1[0]) * (p3[1] - p1[1]) -
1143  (p2[1] - p1[1]) * (p3[0] - p1[0]) > 0;
1144  }
1145 
1146  // Can go away when we stop using Clipper
1147  std::vector<Point<2>> cellToXY(int cellID) const {
1148  std::vector<Point<2>> cellPoints;
1149  basicmesh_ptr_->cell_get_coordinates(cellID, &cellPoints);
1150  return cellPoints;
1151  }
1152 
1154 
1155  void wedges_get_coordinates(int cellID,
1156  std::vector<std::array<Point<3>, 4>> *wcoords) const {
1157  assert(basicmesh_ptr_->space_dimension() == 3);
1158  assert(wedges_requested_);
1159 
1160  std::vector<int> wedges;
1161  cell_get_wedges(cellID, &wedges);
1162  int nwedges = wedges.size();
1163 
1164  wcoords->resize(nwedges);
1165  for (int i = 0; i < nwedges; ++i)
1166  wedge_get_coordinates(wedges[i], &((*wcoords)[i]), true);
1167  }
1168 
1170 
1171  void sides_get_coordinates(int cellID,
1172  std::vector<std::array<Point<3>, 4>> *scoords) const {
1173  assert(basicmesh_ptr_->space_dimension() == 3);
1174  assert(sides_requested_);
1175 
1176  std::vector<int> sides;
1177  cell_get_sides(cellID, &sides);
1178  int nsides = sides.size();
1179 
1180  scoords->resize(nsides);
1181  for (int i = 0; i < nsides; ++i)
1182  side_get_coordinates(sides[i], &((*scoords)[i]), true);
1183  }
1184 
1186  void dual_cell_get_node_adj_cells(int const nodeid,
1187  Entity_type const ptype,
1188  std::vector<int> *adjnodes) const {
1189 #ifdef DEBUG
1190  assert(nodeid < num_entities(NODE, ALL));
1191 #endif
1192  basicmesh_ptr_->node_get_cell_adj_nodes(nodeid, ptype, adjnodes);
1193  }
1194 
1195 
1197  // Input is the node ID 'nodeid', and it returns the vertex coordinates of
1198  // the dual cell around this node in `xyzlist`. The vertices are NOT ordered
1199  // in any particular way
1200 
1201  void dual_cell_get_coordinates(int const nodeid,
1202  std::vector<Point<3>> *pplist) const {
1203 #ifdef DEBUG
1204  assert(nodeid < num_entities(NODE, ALL));
1205 #endif
1206  assert(basicmesh_ptr_->space_dimension() == 3);
1207  assert(wedges_requested_);
1208 
1209  // If it does not interfere with the GPU implementation, we could
1210  // insert into a std::set (nlog(n) instead of n^2) and then copy
1211  // into the output vector
1212 
1213  // wedge_get_coordinates - (node, edge center, face centroid, cell centroid)
1214  std::array<Point<3>, 4> wcoords;
1215 
1216  std::vector<int> wedgeids;
1217  node_get_wedges(nodeid, ALL, &wedgeids);
1218 
1219  std::vector<int> face_list, cell_list;
1220  std::vector<std::pair<int, int>> edge_list;
1221 
1222  for (auto wedgeid : wedgeids) {
1223  wedge_get_coordinates(wedgeid, &wcoords);
1224 
1225  int sideid = wedge_get_side(wedgeid);
1226  int n0 = side_get_node(sideid, 0);
1227  int n1 = side_get_node(sideid, 1);
1228  if (n0 > n1) std::swap(n0, n1);
1229  std::pair<int, int> node_pair(n0, n1);
1230  if (std::find(edge_list.begin(), edge_list.end(), node_pair) ==
1231  edge_list.end()) {
1232  // This "edge" not encountered yet - put it in the edge list and add
1233  // the corresponding wedge point to the coordinate list
1234 
1235  edge_list.emplace_back(node_pair);
1236  pplist->emplace_back(wcoords[1]);
1237  }
1238 
1239  int faceid = wedge_get_face(wedgeid);
1240  if (std::find(face_list.begin(), face_list.end(), faceid) ==
1241  face_list.end()) {
1242  // This face not encountered yet - put it in the face list and add
1243  // the corresponding wedge point to the coordinate list
1244 
1245  face_list.push_back(faceid);
1246  pplist->emplace_back(wcoords[2]);
1247  }
1248 
1249  int cellid = wedge_get_cell(wedgeid);
1250  if (std::find(cell_list.begin(), cell_list.end(), cellid) ==
1251  cell_list.end()) {
1252  // This cell not encountered yet - put it in the cell list and add
1253  // the cooresponding wedge point to the coordinate list
1254 
1255  cell_list.push_back(cellid);
1256  pplist->emplace_back(wcoords[3]);
1257  }
1258  }
1259  }
1260 
1261  // Get the coordinates of the wedges of the dual mesh in 3D
1262 
1264  std::vector<std::array<Point<3>, 4>> *wcoords) const {
1265 #ifdef DEBUG
1266  assert(nodeid < num_entities(NODE, ALL));
1267 #endif
1268  assert(wedges_requested_);
1269  std::vector<int> wedges;
1270  node_get_wedges(nodeid, ALL, &wedges);
1271  int nwedges = wedges.size();
1272  wcoords->resize(nwedges);
1273 
1274  for (int i = 0; i < nwedges; ++i)
1275  wedge_get_coordinates(wedges[i], &((*wcoords)[i]), true);
1276  }
1277 
1279  //
1280  // Centroid of a dual cell.
1281 
1282  template <int D>
1283  void dual_cell_centroid(int nodeid, Point<D> *centroid) const {
1284 #ifdef DEBUG
1285  assert(nodeid < num_entities(NODE, ALL));
1286 #endif
1287  assert(wedges_requested_);
1288 
1289  bool posvol_order = true;
1290  std::vector<int> wedgeids;
1291  node_get_wedges(nodeid, ALL, &wedgeids);
1292  double vol = 0.0;
1293  for (int i = 0; i < D; i++) (*centroid)[i] = 0.0;
1294  Point<D> geom_cen;
1295  for (auto const wid : wedgeids) {
1296  double wvol = wedge_volume(wid);
1297 
1298  Point<D> wcen;
1299  std::array<Point<D>, D+1> wcoords;
1300  wedge_get_coordinates(wid, &wcoords, posvol_order);
1301  for (int i = 0; i < D+1; i++)
1302  wcen += wcoords[i];
1303  wcen /= D+1;
1304 
1305  geom_cen += wcen;
1306  *centroid += wvol*wcen;
1307  vol += wvol;
1308  }
1309  //If we have a degenerate dual cell of zero volume, we use the geometric center
1310  if (vol > std::numeric_limits<double>::epsilon()) *centroid /= vol;
1311  else *centroid = geom_cen/wedgeids.size();
1312  }
1313 
1314 
1316  double dual_cell_volume(int const nodeid) const {
1317 #ifdef DEBUG
1318  assert(nodeid < num_entities(NODE, ALL));
1319 #endif
1320  assert(corners_requested_);
1321  std::vector<int> cornerids;
1322  node_get_corners(nodeid, ALL, &cornerids);
1323  double vol = 0.0;
1324  for (auto const cid : cornerids)
1325  vol += corner_volume(cid);
1326  return vol;
1327  }
1328 
1329 
1330  protected:
1332  int dim = basicmesh_ptr_->space_dimension();
1333 
1334  // We will use the simplicial decomposition of cells to compute
1335  // the real centroid of the cells. The sides of a cell provide
1336  // such a decomposition but we have a chicken-and-egg problem
1337  // since one of the points of the sides is centroid of the
1338  // cell. To solve this, we build the simplices by using the
1339  // topology of the sides but the geometric centers of the cells
1340  // instead of the centroids. Then we compute the real centroids as
1341  // the volume weighted average of the centroids of these temporary
1342  // simplices.
1343  //
1344  // So the steps should be:
1345  //
1346  // compute_approximate_face_centroids
1347  // compute_approximate_cell_centroids
1348  //
1349  // build_sides (topology only)
1350  //
1351  // compute_face_centroids
1352  // compute_cell_centroids
1353  //
1354  // compute_side_volumes
1355 
1356  if (dim == 1) {
1357  compute_approximate_face_centroids<1>();
1358  compute_approximate_cell_centroids<1>();
1359 
1360  if (sides_requested_)
1361  build_sides_1D(*this);
1362 
1363  compute_face_centroids<1>();
1364  compute_cell_centroids<1>();
1365 
1366  if (sides_requested_)
1367  compute_side_volumes<1>();
1368 
1369  } else if (dim == 2) {
1370  compute_approximate_face_centroids<2>();
1371  compute_approximate_cell_centroids<2>();
1372 
1373  if (sides_requested_)
1374  build_sides_2D(*this);
1375 
1376  compute_face_centroids<2>();
1377  compute_cell_centroids<2>();
1378 
1379  if (sides_requested_)
1380  compute_side_volumes<2>();
1381 
1382  } else if (dim == 3) {
1383  compute_approximate_face_centroids<3>();
1384  compute_approximate_cell_centroids<3>();
1385 
1386  if (sides_requested_)
1387  build_sides_3D(*this);
1388 
1389  compute_face_centroids<3>();
1390  compute_cell_centroids<3>();
1391 
1392  if (sides_requested_)
1393  compute_side_volumes<3>();
1394  }
1395 
1396  compute_cell_volumes(); // needs side volumes
1397 
1398  if (wedges_requested_) build_wedges();
1399  if (corners_requested_) build_corners();
1400 
1401  build_face_to_cell_adjacency();
1402  flag_entities_on_exterior_boundary();
1403  }
1404 
1405 
1406  private:
1407  template<int dim> void compute_approximate_cell_centroids();
1408  template<int dim> void compute_approximate_face_centroids();
1409  template<int dim> void compute_cell_centroids();
1410  template<int dim> void compute_face_centroids();
1411  template<int dim> void compute_side_volumes();
1412  void compute_cell_volumes();
1413 
1414  void build_wedges();
1415  void build_corners();
1416 
1417  void build_face_to_cell_adjacency();
1418  void flag_entities_on_exterior_boundary();
1419 
1420  // External helper functions to build dimension-dependent side info
1421  // - forward declared at the top of the file so that only an
1422  // instantiation with the 'BasicMesh' template parameter of this
1423  // class not just any other 'BasicMesh'
1424 
1425  // WHEN WE TEMPLATE THIS CLASS ON DIMENSION, ALL OF THESE FUNCTIONS
1426  // WILL BE NAMED 'build_sides' BUT WILL BE DISTINGUISHED BY THE
1427  // DIFFERENT INTEGERS (1, 2 or 3) USED AS THE SECOND ARGUMENT FOR
1428  // AuxMeshTopology ARGUMENT
1429 
1430  friend
1431  void build_sides_1D<BasicMesh>(AuxMeshTopology<BasicMesh>& mesh);
1432  friend
1433  void build_sides_2D<BasicMesh>(AuxMeshTopology<BasicMesh>& mesh);
1434  friend
1435  void build_sides_3D<BasicMesh>(AuxMeshTopology<BasicMesh>& mesh);
1436 
1437  BasicMesh *basicmesh_ptr_ = nullptr;
1438  bool sides_requested_ = true;
1439  bool wedges_requested_ = true;
1440  bool corners_requested_ = true;
1441 
1442  std::vector<int> sideids_owned_, sideids_ghost_, sideids_all_;
1443  std::vector<int> wedgeids_owned_, wedgeids_ghost_, wedgeids_all_;
1444  std::vector<int> cornerids_owned_, cornerids_ghost_, cornerids_all_;
1445 
1446  int num_sides_owned_ = 0, num_sides_ghost_ = 0;
1447  int num_wedges_owned_ = 0, num_wedges_ghost_ = 0;
1448  int num_corners_owned_ = 0, num_corners_ghost_ = 0;
1449 
1450  // Cells
1451  std::vector<double> cell_volumes_;
1452 
1453  // If this class were templated on dimension D, we could make these
1454  // declarations std::vector<Wonton::Point<D>>
1455 
1456  std::vector<std::vector<double>> cell_centroids_;
1457 
1458  // Faces
1459  std::vector<std::vector<double>> face_centroids_;
1460 
1461  // compute this adjacency and store it - while many mesh frameworks
1462  // have it some may not and in particular, the flat mesh wrapper we
1463  // use within Wonton does not.
1464  std::vector<std::array<int, 2>> face_cell_ids_;
1465 
1466  // Sides
1467  std::vector<int> side_cell_id_;
1468  std::vector<int> side_face_id_;
1469  std::vector<std::array<int, 2>> side_node_ids_;
1470  std::vector<int> side_opp_side_id_;
1471  std::vector<double> side_volumes_;
1472 
1473  // Wedges - most wedge info is derived from sides
1474  std::vector<int> wedge_corner_id_; // need only in 2D if we want to build
1475  // // an oriented polygon out of corners
1476  // // or wedges connected to a node
1477 
1478  // Corners
1479  std::vector<int> corner_node_id_;
1480  std::vector<int> corner_cell_id_;
1481 
1482  // some other one-many adjacencies - MAY NEED TO REWORK TO BE ABLE
1483  // TO SEND A MESH FROM ONE PROCESSOR TO ANOTHER
1484  std::vector<std::vector<int>> cell_side_ids_;
1485  std::vector<std::vector<int>> cell_corner_ids_; // do we need this?
1486  std::vector<std::vector<int>> node_corner_ids_;
1487  std::vector<std::vector<int>> corner_wedge_ids_;
1488 
1489  // Flag indicating if entities (cells, faces, nodes) are on exterior boundary
1490  std::vector<bool> cell_on_exterior_boundary_;
1491  std::vector<bool> face_on_exterior_boundary_;
1492  std::vector<bool> node_on_exterior_boundary_;
1493 
1494 }; // class AuxMeshTopology
1495 
1496 
1498 template<typename BasicMesh>
1500  int nfaces = basicmesh_ptr_->num_entities(Entity_kind::FACE,
1502  // face_cell_ids_.resize(nfaces, {-1, -1}); // I think intel 15 barfs
1503  // // if I do this
1504  std::array<int, 2> iniarr = {-1, -1};
1505  face_cell_ids_.assign(nfaces, iniarr);
1506 
1507  int ncells = basicmesh_ptr_->num_entities(Entity_kind::CELL,
1509  for (int c = 0; c < ncells; c++) {
1510  std::vector<int> cfaces;
1511  std::vector<int> cfdirs;
1512  basicmesh_ptr_->cell_get_faces_and_dirs(c, &cfaces, &cfdirs);
1513  for (auto const& f : cfaces) {
1514  if (face_cell_ids_[f][0] == -1)
1515  face_cell_ids_[f][0] = c;
1516  else
1517  face_cell_ids_[f][1] = c;
1518  }
1519  }
1520 }
1521 
1522 
1523 // Flag entities on exterior boundaries
1524 template <typename BasicMesh>
1526 
1527  // Check and flag all entities, owned or ghost. However, ghost faces that
1528  // are the outer faces of the ghost layer of cells will be incorrectly
1529  // tagged as being exterior faces because they will have only one (ghost)
1530  // cell attached. We expect that this won't be a problem since we won't
1531  // have to query these faces anyway but if it is, then we will have to
1532  // do an exchange of information across nodes
1533 
1534  int ncells = basicmesh_ptr_->num_entities(Entity_kind::CELL,
1536  int nfaces = basicmesh_ptr_->num_entities(Entity_kind::FACE,
1538  int nnodes = basicmesh_ptr_->num_entities(Entity_kind::NODE,
1540 
1541  cell_on_exterior_boundary_.assign(ncells, false);
1542  face_on_exterior_boundary_.assign(nfaces, false);
1543  node_on_exterior_boundary_.assign(nnodes, false);
1544 
1545  for (int f = 0; f < nfaces; f++) {
1546  std::vector<int> fcells;
1547  basicmesh_ptr_->face_get_cells(f, Entity_type::ALL, &fcells);
1548 
1549  if (fcells.size() == 1) {
1550  face_on_exterior_boundary_[f] = true;
1551  cell_on_exterior_boundary_[fcells[0]] = true;
1552 
1553  // if the face is on an exterior boundary, all its nodes are too
1554  std::vector<int> fnodes;
1555  basicmesh_ptr_->face_get_nodes(f, &fnodes);
1556  for (auto const &n : fnodes)
1557  node_on_exterior_boundary_[n] = true;
1558  }
1559  }
1560 }
1561 
1563 template<typename BasicMesh>
1565  std::array<Point<1>, 2> *scoords,
1566  bool posvol_order) const {
1567  int c = side_cell_id_[s];
1568  int n = side_node_ids_[s][0];
1569  Point<1> nxyz;
1570  basicmesh_ptr_->node_get_coordinates(n, &nxyz);
1571 
1572  // There are two sides per cell in 1D, and going from left to right
1573  // (in a +ve direction), the side numbers are even, odd, even, odd
1574  // starting from 0. So for even sides, we need to return node
1575  // coordinate and cell centroid if we want the side coordinates to
1576  // be in positive volume order. For odd sides, we need to return
1577  // cell centroid and then the node coordinate
1578 
1579  if (posvol_order && s%2) {
1580  cell_centroid(c, &((*scoords)[0]));
1581  (*scoords)[1] = nxyz;
1582  } else {
1583  (*scoords)[0] = nxyz;
1584  cell_centroid(c, &((*scoords)[1]));
1585  }
1586 }
1587 
1589 
1590 template<typename BasicMesh>
1592  std::array<Point<2>, 3> *scoords,
1593  bool posvol_order) const {
1594  int c = side_cell_id_[s];
1595  int n[2];
1596  n[0] = side_node_ids_[s][0];
1597  n[1] = side_node_ids_[s][1];
1598 
1599  // Due to the way we set up the sides, the natural ordering of side
1600  // coordinates also results in a positive side volume in 3D
1601 
1602  basicmesh_ptr_->node_get_coordinates(n[0], &((*scoords)[0]));
1603  basicmesh_ptr_->node_get_coordinates(n[1], &((*scoords)[1]));
1604  cell_centroid(c, &((*scoords)[2]));
1605 }
1606 
1608 
1609 template<typename BasicMesh>
1611  std::array<Point<3>, 4> *scoords,
1612  bool posvol_order) const {
1613  int c = side_cell_id_[s];
1614  int f = side_face_id_[s];
1615  int n[2];
1616  n[0] = side_node_ids_[s][0];
1617  n[1] = side_node_ids_[s][1];
1618 
1619  // Due to the way we set up the sides, the natural ordering of side
1620  // coordinates also results in a positive side volume in 3D
1621 
1622  basicmesh_ptr_->node_get_coordinates(n[0], &((*scoords)[0]));
1623  basicmesh_ptr_->node_get_coordinates(n[1], &((*scoords)[1]));
1624  face_centroid(f, &((*scoords)[2]));
1625  cell_centroid(c, &((*scoords)[3]));
1626 }
1627 
1628 
1630 
1631 template<typename BasicMesh>
1633  std::array<Point<1>, 2> *wcoords,
1634  bool posvol_order) const {
1635  int s = w/2;
1636  int c = side_cell_id_[s];
1637  int iw = w%2; // wedge index in side
1638  int n = side_node_ids_[s][iw];
1639  Point<1> nxyz;
1640  basicmesh_ptr_->node_get_coordinates(n, &nxyz);
1641  if (posvol_order && iw) {
1642  cell_centroid(c, &((*wcoords)[0]));
1643  (*wcoords)[1] = nxyz;
1644  } else {
1645  (*wcoords)[0] = nxyz;
1646  cell_centroid(c, &((*wcoords)[1]));
1647  }
1648 }
1649 
1651 
1652 template<typename BasicMesh>
1654  std::array<Point<2>, 3> *wcoords,
1655  bool posvol_order) const {
1656  int s = w/2;
1657  int c = side_cell_id_[s];
1658  int iw = w%2;
1659  int n[2];
1660  n[0] = side_node_ids_[s][0];
1661  n[1] = side_node_ids_[s][1];
1662  Point<2> nxyz[2];
1663  basicmesh_ptr_->node_get_coordinates(n[0], &nxyz[0]);
1664  basicmesh_ptr_->node_get_coordinates(n[1], &nxyz[1]);
1665  Point<2> exyz = (nxyz[0] + nxyz[1])/2; // mid-point of edge
1666  if (posvol_order && iw) { // wedge 1 of side
1667  (*wcoords)[0] = nxyz[iw];
1668  cell_centroid(c, &((*wcoords)[1]));
1669  (*wcoords)[2] = exyz;
1670  } else {
1671  (*wcoords)[0] = nxyz[iw];
1672  (*wcoords)[1] = exyz;
1673  cell_centroid(c, &((*wcoords)[2]));
1674  }
1675 }
1676 
1678 
1679 template<typename BasicMesh>
1681  std::array<Point<3>, 4> *wcoords,
1682  bool posvol_order) const {
1683  int s = w/2;
1684  int c = side_cell_id_[s];
1685  int f = side_face_id_[s];
1686  int iw = w%2;
1687  int n[2];
1688  n[0] = side_node_ids_[s][0];
1689  n[1] = side_node_ids_[s][1];
1690  Point<3> nxyz[2];
1691  basicmesh_ptr_->node_get_coordinates(n[0], &nxyz[0]);
1692  basicmesh_ptr_->node_get_coordinates(n[1], &nxyz[1]);
1693  Point<3> exyz = (nxyz[0] + nxyz[1])/2.0; // mid-point of edge
1694  if (posvol_order && iw) {
1695  (*wcoords)[0] = nxyz[iw];
1696  face_centroid(f, &((*wcoords)[1]));
1697  (*wcoords)[2] = exyz;
1698  cell_centroid(c, &((*wcoords)[3]));
1699  } else {
1700  (*wcoords)[0] = nxyz[iw];
1701  (*wcoords)[1] = exyz;
1702  face_centroid(f, &((*wcoords)[2]));
1703  cell_centroid(c, &((*wcoords)[3]));
1704  }
1705 }
1706 
1707 
1708 // Build sides for 1D meshes (even though we currently don't support
1709 // 1D remapping)
1710 
1711 template<typename BasicMesh>
1713  int ncells_owned = mesh.basicmesh_ptr_->num_owned_cells();
1714  int ncells_ghost = mesh.basicmesh_ptr_->num_ghost_cells();
1715  int ncells = ncells_owned + ncells_ghost;
1716 
1717  mesh.cell_side_ids_.clear();
1718  mesh.cell_side_ids_.resize(ncells);
1719 
1720  int num_sides_all = 2*ncells;
1721  mesh.num_sides_owned_ = 2*ncells_owned;
1722  mesh.num_sides_ghost_ = 2*ncells_ghost;
1723 
1724  for (int c = 0; c < ncells; ++c)
1725  mesh.cell_side_ids_[c].reserve(2);
1726 
1727  mesh.sideids_owned_.resize(mesh.num_sides_owned_);
1728  mesh.sideids_ghost_.resize(mesh.num_sides_ghost_);
1729  mesh.sideids_all_.resize(num_sides_all);
1730  mesh.side_cell_id_.assign(num_sides_all, -1);
1731  mesh.side_face_id_.assign(num_sides_all, -1);
1732  mesh.side_opp_side_id_.assign(num_sides_all, -1);
1733  mesh.side_node_ids_.assign(num_sides_all, {{-1, -1}});
1734 
1735  int iall = 0, iown = 0, ighost = 0;
1736  for (int c = 0; c < ncells; ++c) {
1737  int sideid = 2*c; // always 2 sides per cell
1738 
1739  std::vector<int> nodeids;
1740  mesh.basicmesh_ptr_->cell_get_nodes(c, &nodeids);
1741 
1742  mesh.cell_side_ids_[c].push_back(sideid);
1743  mesh.cell_side_ids_[c].push_back(sideid+1);
1744  mesh.sideids_all_[iall++] = sideid;
1745  mesh.sideids_all_[iall++] = sideid+1;
1746  if (mesh.basicmesh_ptr_->cell_get_type(c) == PARALLEL_OWNED) {
1747  mesh.sideids_owned_[iown++] = sideid;
1748  mesh.sideids_owned_[iown++] = sideid+1;
1749  } else if (mesh.basicmesh_ptr_->cell_get_type(c) == PARALLEL_GHOST) {
1750  mesh.sideids_ghost_[ighost++] = sideid;
1751  mesh.sideids_ghost_[ighost++] = sideid+1;
1752  }
1753 
1754  // Sides in 1D are degenerate - instead of two nodes of an edge
1755  // the sides point to the same node
1756  mesh.side_node_ids_[sideid][0] = nodeids[0];
1757  mesh.side_node_ids_[sideid][1] = nodeids[0];
1758  mesh.side_node_ids_[sideid+1][0] = nodeids[1];
1759  mesh.side_node_ids_[sideid+1][1] = nodeids[1];
1760 
1761  mesh.side_cell_id_[sideid ] = c;
1762  mesh.side_cell_id_[sideid+1] = c;
1763 
1764  // face ids are same as node ids in 1D
1765  mesh.side_face_id_[sideid ] = nodeids[0];
1766  mesh.side_face_id_[sideid+1] = nodeids[1];
1767 
1768  // across face boundaries
1769  mesh.side_opp_side_id_[sideid ] = (sideid == 0) ? -1 : sideid-1;
1770  mesh.side_opp_side_id_[sideid+1] = (sideid+1 == num_sides_all-1) ?
1771  -1 : sideid+2;
1772  } // for c = 0, ncells-1
1773 } // build_sides in 1D
1774 
1775 
1776 // Build sides for 2D meshes
1777 
1778 template<typename BasicMesh>
1780  int ncells_owned = mesh.basicmesh_ptr_->num_owned_cells();
1781  int ncells_ghost = mesh.basicmesh_ptr_->num_ghost_cells();
1782  int ncells = ncells_owned + ncells_ghost;
1783 
1784  mesh.cell_side_ids_.clear();
1785  mesh.cell_side_ids_.resize(ncells);
1786 
1787  int nnodes_owned = mesh.basicmesh_ptr_->num_owned_nodes();
1788  int nnodes_ghost = mesh.basicmesh_ptr_->num_ghost_nodes();
1789  int nnodes = nnodes_owned + nnodes_ghost;
1790 
1791  int num_sides_all = 0;
1792  mesh.num_sides_owned_ = 0;
1793  mesh.num_sides_ghost_ = 0;
1794 
1795  for (int c = 0; c < ncells; ++c) {
1796  std::vector<int> cfaces, cfdirs;
1797  mesh.basicmesh_ptr_->cell_get_faces_and_dirs(c, &cfaces, &cfdirs);
1798 
1799  int numsides_in_cell = cfaces.size();
1800  num_sides_all += numsides_in_cell;
1801  if (mesh.basicmesh_ptr_->cell_get_type(c) == PARALLEL_OWNED)
1802  mesh.num_sides_owned_ += numsides_in_cell;
1803  else if (mesh.basicmesh_ptr_->cell_get_type(c) == PARALLEL_GHOST)
1804  mesh.num_sides_ghost_ += numsides_in_cell;
1805 
1806  mesh.cell_side_ids_[c].reserve(numsides_in_cell);
1807  }
1808 
1809  mesh.sideids_owned_.resize(mesh.num_sides_owned_);
1810  mesh.sideids_ghost_.resize(mesh.num_sides_ghost_);
1811  mesh.sideids_all_.resize(num_sides_all);
1812  mesh.side_cell_id_.assign(num_sides_all, -1);
1813  mesh.side_face_id_.assign(num_sides_all, -1);
1814  mesh.side_opp_side_id_.clear();
1815  mesh.side_opp_side_id_.resize(num_sides_all, -1);
1816  mesh.side_node_ids_.resize(num_sides_all, {{-1, -1}});
1817 
1818  std::vector<std::vector<int>> sides_of_node(nnodes); // Temp. var.
1819 
1820  int sideid = 0;
1821  int iall = 0, iown = 0, ighost = 0;
1822  for (int c = 0; c < ncells; ++c) {
1823  std::vector<int> cfaces, cfdirs;
1824  mesh.basicmesh_ptr_->cell_get_faces_and_dirs(c, &cfaces, &cfdirs);
1825 
1826  int ncfaces = cfaces.size();
1827  for (int i = 0; i < ncfaces; ++i) {
1828  int f = cfaces[i];
1829  int fdir = cfdirs[i];
1830  std::vector<int> fnodes;
1831  mesh.basicmesh_ptr_->face_get_nodes(f, &fnodes); // face=edge in 2D
1832  int n0 = (fdir == 1) ? fnodes[0] : fnodes[1];
1833  int n1 = (fdir == 1) ? fnodes[1] : fnodes[0];
1834  mesh.side_node_ids_[sideid][0] = n0;
1835  mesh.side_node_ids_[sideid][1] = n1;
1836 
1837  mesh.side_cell_id_[sideid] = c;
1838  mesh.cell_side_ids_[c].push_back(sideid);
1839 
1840  mesh.side_face_id_[sideid] = f;
1841 
1842  mesh.sideids_all_[iall++] = sideid;
1843  if (mesh.basicmesh_ptr_->cell_get_type(c) == PARALLEL_OWNED)
1844  mesh.sideids_owned_[iown++] = sideid;
1845  else if (mesh.basicmesh_ptr_->cell_get_type(c) == PARALLEL_GHOST)
1846  mesh.sideids_ghost_[ighost++] = sideid;
1847 
1848  // See if any of the other sides attached to the node
1849  // shares the same edge (pair of nodes) but is in the
1850  // adjacent cell. This is called the opposite side
1851 
1852  for (auto const& s2 : sides_of_node[n0]) {
1853  if (mesh.side_node_ids_[s2][0] == n1 && mesh.side_node_ids_[s2][1] == n0) {
1854  mesh.side_opp_side_id_[sideid] = s2;
1855  mesh.side_opp_side_id_[s2] = sideid;
1856  break;
1857  }
1858  }
1859  sides_of_node[n0].push_back(sideid);
1860 
1861  for (auto const& s2 : sides_of_node[n1]) {
1862  if (mesh.side_node_ids_[s2][0] == n1 && mesh.side_node_ids_[s2][1] == n0) {
1863  mesh.side_opp_side_id_[sideid] = s2;
1864  mesh.side_opp_side_id_[s2] = sideid;
1865  break;
1866  }
1867  }
1868  sides_of_node[n1].push_back(sideid);
1869  sideid++;
1870  }
1871  } // for c = 0, ncells-1
1872 } // build sides for 2D meshes
1873 
1874 
1875 // build sides for 3D meshes
1876 
1877 template<typename BasicMesh>
1879  int ncells_owned = mesh.basicmesh_ptr_->num_owned_cells();
1880  int ncells_ghost = mesh.basicmesh_ptr_->num_ghost_cells();
1881  int ncells = ncells_owned + ncells_ghost;
1882 
1883  mesh.cell_side_ids_.clear();
1884  mesh.cell_side_ids_.resize(ncells);
1885 
1886  int nnodes_owned = mesh.basicmesh_ptr_->num_owned_nodes();
1887  int nnodes_ghost = mesh.basicmesh_ptr_->num_ghost_nodes();
1888  int nnodes = nnodes_owned + nnodes_ghost;
1889 
1890  int num_sides_all = 0;
1891  mesh.num_sides_owned_ = 0;
1892  mesh.num_sides_ghost_ = 0;
1893 
1894  for (int c = 0; c < ncells; ++c) {
1895  std::vector<int> cfaces, cfdirs;
1896  mesh.basicmesh_ptr_->cell_get_faces_and_dirs(c, &cfaces, &cfdirs);
1897 
1898  int numsides_in_cell = 0;
1899  for (auto const & f : cfaces) {
1900  std::vector<int> fnodes;
1901  mesh.basicmesh_ptr_->face_get_nodes(f, &fnodes);
1902 
1903  int nfnodes = fnodes.size();
1904  num_sides_all += nfnodes;
1905  numsides_in_cell += nfnodes;
1906 
1907  if (mesh.basicmesh_ptr_->cell_get_type(c) == PARALLEL_OWNED)
1908  mesh.num_sides_owned_ += nfnodes;
1909  else if (mesh.basicmesh_ptr_->cell_get_type(c) == PARALLEL_GHOST)
1910  mesh.num_sides_ghost_ += nfnodes;
1911  }
1912 
1913  mesh.cell_side_ids_[c].reserve(numsides_in_cell);
1914  }
1915 
1916  mesh.sideids_owned_.resize(mesh.num_sides_owned_);
1917  mesh.sideids_ghost_.resize(mesh.num_sides_ghost_);
1918  mesh.sideids_all_.resize(num_sides_all);
1919  mesh.side_cell_id_.assign(num_sides_all, -1);
1920  mesh.side_face_id_.assign(num_sides_all, -1);
1921  mesh.side_opp_side_id_.clear();
1922  mesh.side_opp_side_id_.assign(num_sides_all, -1);
1923  mesh.side_node_ids_.assign(num_sides_all, {{-1, -1}});
1924 
1925  std::vector<std::vector<int>> sides_of_node(nnodes); // Temporary variable
1926 
1927  int sideid = 0;
1928  int iall = 0, iown = 0, ighost = 0;
1929  for (int c = 0; c < ncells; ++c) {
1930  std::vector<int> cfaces;
1931  std::vector<int> cfdirs;
1932  mesh.basicmesh_ptr_->cell_get_faces_and_dirs(c, &cfaces, &cfdirs);
1933 
1934  std::vector<int>::iterator itf = cfaces.begin();
1935  std::vector<int>::iterator itfd = cfdirs.begin();
1936  while (itf != cfaces.end()) {
1937  int f = *itf;
1938  int fdir = *itfd;
1939 
1940  std::vector<int> fnodes;
1941  mesh.basicmesh_ptr_->face_get_nodes(f, &fnodes);
1942 
1943  // We want the facet formed by side point 0, side point 1 and
1944  // the face center to point into the cell - this makes the side
1945  // volume calculation from its natural order of coordinates
1946  // direct. So, if the face is being used by the cell in the +ve
1947  // sense, then reverse the node order
1948 
1949  if (fdir == 1)
1950  std::reverse(fnodes.begin(), fnodes.end());
1951 
1952  int nfnodes = fnodes.size();
1953 
1954  for (int i = 0; i < nfnodes; ++i) {
1955  mesh.side_node_ids_[sideid][0] = fnodes[i];
1956  mesh.side_node_ids_[sideid][1] = fnodes[(i+1)%nfnodes];
1957 
1958  mesh.side_cell_id_[sideid] = c;
1959  mesh.cell_side_ids_[c].push_back(sideid);
1960 
1961  mesh.side_face_id_[sideid] = f;
1962 
1963  mesh.sideids_all_[iall++] = sideid;
1964  if (mesh.basicmesh_ptr_->cell_get_type(c) == PARALLEL_OWNED)
1965  mesh.sideids_owned_[iown++] = sideid;
1966  else if (mesh.basicmesh_ptr_->cell_get_type(c) == PARALLEL_GHOST)
1967  mesh.sideids_ghost_[ighost++] = sideid;
1968 
1969  // See if any of the other sides attached to the edge (pair
1970  // of nodes) shares the same edge and face but is in the
1971  // adjacent cell. This is called the opposite side
1972 
1973  for (auto const& s2 : sides_of_node[fnodes[i]]) {
1974  if ((mesh.side_node_ids_[s2][0] == fnodes[(i+1)%nfnodes] &&
1975  mesh.side_node_ids_[s2][1] == fnodes[i]) ||
1976  (mesh.side_node_ids_[s2][0] == fnodes[i] &&
1977  mesh.side_node_ids_[s2][1] == fnodes[(i+1)%nfnodes])) {
1978  if (mesh.side_face_id_[sideid] == mesh.side_face_id_[s2] &&
1979  mesh.side_cell_id_[sideid] != mesh.side_cell_id_[s2]) {
1980  mesh.side_opp_side_id_[sideid] = s2;
1981  mesh.side_opp_side_id_[s2] = sideid;
1982  break;
1983  }
1984  }
1985  }
1986  sides_of_node[fnodes[i]].push_back(sideid);
1987  sideid++;
1988  } // for (int i = 0; i < nfnodes; ++i)
1989 
1990  ++itf;
1991  ++itfd;
1992  } // while (itf != cfaces.end())
1993  } // for c = 0, ncells-1
1994 } // build sides for 3D meshes
1995 
1996 
1997 // Build wedge information - wedges are half a side
1998 
1999 template<typename BasicMesh>
2001 
2002  int nsides_owned = num_sides_owned_;
2003  int nsides_ghost = num_sides_ghost_;
2004  int nsides_all = nsides_owned + nsides_ghost;
2005 
2006  int num_wedges_all = 2*nsides_all;
2007  num_wedges_owned_ = 2*nsides_owned;
2008  num_wedges_ghost_ = 2*nsides_ghost;
2009 
2010  wedgeids_owned_.resize(num_wedges_owned_);
2011  wedgeids_ghost_.resize(num_wedges_ghost_);
2012  wedge_corner_id_.assign(num_wedges_all, -1); // filled when building corners
2013 
2014  int iown = 0, ighost = 0;
2015  for (int s = 0; s < nsides_all; ++s) {
2016  int wedgeid0 = 2*s;
2017  int wedgeid1 = 2*s + 1;
2018  int c = side_cell_id_[s];
2019  if (basicmesh_ptr_->cell_get_type(c) == PARALLEL_OWNED) {
2020  wedgeids_owned_[iown++] = wedgeid0;
2021  wedgeids_owned_[iown++] = wedgeid1;
2022  } else if (basicmesh_ptr_->cell_get_type(c) == PARALLEL_GHOST) {
2023  wedgeids_ghost_[ighost++] = wedgeid0;
2024  wedgeids_ghost_[ighost++] = wedgeid1;
2025  }
2026  }
2027 
2028  wedgeids_all_.reserve(num_wedges_all);
2029  wedgeids_all_ = wedgeids_owned_; // copy
2030  wedgeids_all_.insert(wedgeids_all_.end(), wedgeids_ghost_.begin(),
2031  wedgeids_ghost_.end());
2032 
2033 } // build_wedges
2034 
2035 
2036 // Build corner info
2037 
2038 template <typename BasicMesh>
2040  int ncells_owned = basicmesh_ptr_->num_owned_cells();
2041  int ncells_ghost = basicmesh_ptr_->num_ghost_cells();
2042  int ncells = ncells_owned + ncells_ghost;
2043 
2044  int nnodes_owned = basicmesh_ptr_->num_owned_nodes();
2045  int nnodes_ghost = basicmesh_ptr_->num_ghost_nodes();
2046  int nnodes = nnodes_owned + nnodes_ghost;
2047 
2048  cell_corner_ids_.clear();
2049  cell_corner_ids_.resize(ncells);
2050  node_corner_ids_.clear();
2051  node_corner_ids_.resize(nnodes);
2052 
2053  int num_corners_all = 0;
2054  num_corners_owned_ = 0;
2055  num_corners_ghost_ = 0;
2056 
2057  for (int c = 0; c < ncells; ++c) {
2058  std::vector<int> cnodes;
2059  basicmesh_ptr_->cell_get_nodes(c, &cnodes);
2060  cell_corner_ids_[c].reserve(cnodes.size());
2061 
2062  num_corners_all += cnodes.size(); // as many corners as nodes in cell
2063  if (basicmesh_ptr_->cell_get_type(c) == Entity_type::PARALLEL_OWNED)
2064  num_corners_owned_ += cnodes.size();
2065  else if (basicmesh_ptr_->cell_get_type(c) == Entity_type::PARALLEL_GHOST)
2066  num_corners_ghost_ += cnodes.size();
2067  }
2068 
2069  cornerids_owned_.resize(num_corners_owned_);
2070  cornerids_ghost_.resize(num_corners_ghost_);
2071  corner_wedge_ids_.clear();
2072  corner_wedge_ids_.resize(num_corners_all);
2073  corner_cell_id_.resize(num_corners_all);
2074  corner_node_id_.resize(num_corners_all);
2075 
2076  int cornerid = 0;
2077  int iown = 0, ighost = 0;
2078  for (int c = 0; c < ncells; ++c) {
2079  std::vector<int> cnodes;
2080  basicmesh_ptr_->cell_get_nodes(c, &cnodes);
2081 
2082  std::vector<int> cwedges;
2083  cell_get_wedges(c, &cwedges);
2084 
2085  for (auto const& n : cnodes) {
2086  corner_cell_id_[cornerid] = c;
2087  cell_corner_ids_[c].push_back(cornerid);
2088 
2089  corner_node_id_[cornerid] = n;
2090  node_corner_ids_[n].push_back(cornerid);
2091 
2092  if (basicmesh_ptr_->cell_get_type(c) == Entity_type::PARALLEL_OWNED)
2093  cornerids_owned_[iown++] = cornerid;
2094  else if (basicmesh_ptr_->cell_get_type(c) == Entity_type::PARALLEL_GHOST)
2095  cornerids_ghost_[ighost++] = cornerid;
2096 
2097  for (auto const& w : cwedges) {
2098  int n2 = wedge_get_node(w);
2099  if (n == n2) {
2100  corner_wedge_ids_[cornerid].push_back(w);
2101  wedge_corner_id_[w] = cornerid;
2102  }
2103  } // for (w : cwedges)
2104 
2105  ++cornerid;
2106  } // for (n : cnodes)
2107  } // for (c : cells())
2108 
2109  cornerids_all_.reserve(num_corners_all);
2110  cornerids_all_ = cornerids_owned_; // list copy
2111  cornerids_all_.insert(cornerids_all_.end(), cornerids_ghost_.begin(),
2112  cornerids_ghost_.end());
2113 
2114 } // build_corners
2115 
2116 
2117 // Compute an approximate centroid as the geometric center of the face nodes
2118 template<typename BasicMesh>
2119 template<int dim>
2121  int nfaces = basicmesh_ptr_->num_owned_faces() +
2122  basicmesh_ptr_->num_ghost_faces();
2123 
2124  std::vector<double> pnt(dim, 0.0);
2125  face_centroids_.assign(nfaces, pnt);
2126 
2127  for (int f = 0; f < nfaces; f++) {
2128  std::vector<int> fnodes;
2129  basicmesh_ptr_->face_get_nodes(f, &fnodes);
2130  int nfnodes = fnodes.size();
2131  Point<dim> geomcen;
2132 
2133  Wonton::Point<dim> ncoord;
2134  for (int n = 0; n < nfnodes; ++n) {
2135  basicmesh_ptr_->node_get_coordinates(fnodes[n], &ncoord);
2136  geomcen += ncoord;
2137  }
2138  geomcen /= nfnodes;
2139  for (int d = 0; d < dim; ++d)
2140  face_centroids_[f][d] = geomcen[d];
2141  }
2142 }
2143 
2144 
2145 // using approximate face centroids and triangulation of the face,
2146 // compute the real centroid as the area weighted average of the
2147 // centroids of the triangular facets
2148 
2149 template<typename BasicMesh>
2150 template<int dim>
2152  int nfaces = basicmesh_ptr_->num_owned_faces() +
2153  basicmesh_ptr_->num_ghost_faces();
2154 
2155  // Resize (just to be sure) but don't reinitialize since it contains
2156  // the approximate centroids (geometric centers)
2157  face_centroids_.resize(nfaces);
2158 
2159  std::vector<bool> face_processed(nfaces, false);
2160 
2161  int ncells = basicmesh_ptr_->num_owned_cells() +
2162  basicmesh_ptr_->num_ghost_cells();
2163 
2164  std::array<Point<dim>, dim+1> sxyz;
2165  bool posvol_order = true;
2166 
2167  for (int c = 0; c < ncells; c++) {
2168  std::vector<int> csides;
2169  cell_get_sides(c, &csides);
2170 
2171  std::vector<int> cfaces, cfdirs;
2172  basicmesh_ptr_->cell_get_faces_and_dirs(c, &cfaces, &cfdirs);
2173 
2174  std::vector<int> fsides;
2175  for (auto const& f : cfaces) {
2176  if (face_processed[f]) continue;
2177 
2178  // compute the real centroid as the area weighted average of the
2179  // facet centroids
2180 
2181  Point<dim> fcen;
2182  double farea = 0.0;
2183  for (auto const& s : csides) {
2184  if (side_get_face(s) == f) {
2185  side_get_coordinates(s, &sxyz, posvol_order);
2186 
2187  // Centroid of facet of side that lies on face (point in 1D,
2188  // line in 2D, triangle in 3D)
2189  Point<dim> fctcen;
2190  for (int j = 0; j < dim; j++)
2191  fctcen += sxyz[j];
2192  fctcen /= dim;
2193 
2194  double fctarea = 0.0;
2195  if (dim == 1)
2196  fctarea = 1.0;
2197  else if (dim == 2) {
2198  Vector<dim> evec = sxyz[1]-sxyz[0];
2199  fctarea = evec.norm();
2200  }
2201  else if (dim == 3) {
2202  Vector<3> vec0(sxyz[2][0]-sxyz[0][0], sxyz[2][1]-sxyz[0][1],
2203  sxyz[2][2]-sxyz[0][2]);
2204  Vector<3> vec1(sxyz[1][0]-sxyz[0][0], sxyz[1][1]-sxyz[0][1],
2205  sxyz[1][2]-sxyz[0][2]);
2206  Vector<3> cpvec = cross(vec0, vec1);
2207  fctarea = cpvec.norm();
2208  }
2209  farea += fctarea;
2210 
2211  fcen += fctcen*fctarea;
2212  }
2213  }
2214  //If we have a degenerate face of zero area, we use the geometric center
2215  if (farea > std::numeric_limits<double>::epsilon()) {
2216  fcen /= farea;
2217  for (int d = 0; d < dim; d++)
2218  face_centroids_[f][d] = fcen[d];
2219  }
2220  face_processed[f] = true;
2221  }
2222  }
2223 } // compute_face_centroids
2224 
2225 
2226 // Compute an approximate centroid as the geometric mean of the cell nodes
2227 
2228 template<typename BasicMesh>
2229 template<int dim>
2231  int ncells = basicmesh_ptr_->num_owned_cells() +
2232  basicmesh_ptr_->num_ghost_cells();
2233 
2234  std::vector<double> pnt(dim, 0.0);
2235  cell_centroids_.assign(ncells, pnt);
2236 
2237  for (int c = 0; c < ncells; ++c) {
2238 
2239  // temporarily set cell_centroid to be geometric center
2240  std::vector<int> cnodes;
2241  basicmesh_ptr_->cell_get_nodes(c, &cnodes);
2242  int ncnodes = cnodes.size();
2243  Point<dim> geomcen;
2244  Point<dim> ncoord;
2245  for (int n = 0; n < ncnodes; ++n) {
2246  basicmesh_ptr_->node_get_coordinates(cnodes[n], &ncoord);
2247  geomcen += ncoord;
2248  }
2249  geomcen /= ncnodes;
2250  for (int d = 0; d < dim; ++d)
2251  cell_centroids_[c][d] = geomcen[d];
2252  }
2253 }
2254 
2255 // Use approximate cell centroids and the geometry of sides (tets)
2256 // using these approximate centroids to compute the real
2257 // centroids. The real centroid is computed as the volume weighted
2258 // average of the centroids of the sides (tets)
2259 
2260 template<typename BasicMesh>
2261 template<int dim>
2263  int ncells = basicmesh_ptr_->num_owned_cells() +
2264  basicmesh_ptr_->num_ghost_cells();
2265 
2266  // Resize (just to be sure) but don't reinitialize since it contains
2267  // the approximate centroids (geometric centers)
2268 
2269  cell_centroids_.resize(ncells);
2270 
2271  std::array<Point<dim>, dim+1> sxyz;
2272  bool posvol_order = true;
2273  for (int c = 0; c < ncells; ++c) {
2274  // Now compute the real centroid as the volume weighted average of the
2275  // centroids of the sides with the temporary geometry
2276 
2277  std::vector<int> csides;
2278  basicmesh_ptr_->cell_get_sides(c, &csides);
2279 
2280  Point<dim> ccen;
2281  double cellvol = 0.0;
2282  for (auto const& s : csides) {
2283  side_get_coordinates(s, &sxyz, posvol_order);
2284  Point<dim> scen;
2285  for (int i = 0; i < dim+1; i++)
2286  scen += sxyz[i];
2287  scen /= (dim+1);
2288 
2289  double svol = calc_side_volume(sxyz);
2290  cellvol += svol;
2291 
2292  ccen += scen*svol;
2293  }
2294 
2295  //If we have a degenerate cell of zero volume, we use the geometric center
2296  if (cellvol > std::numeric_limits<double>::epsilon()) {
2297  ccen /= cellvol;
2298  for (int d = 0; d < dim; d++)
2299  cell_centroids_[c][d] = ccen[d]; // true centroid
2300  }
2301  }
2302 }
2303 
2304 
2305 template<typename BasicMesh>
2306 template<int dim>
2308  int num_sides_all = num_sides_owned_ + num_sides_ghost_;
2309  side_volumes_.resize(num_sides_all);
2310 
2311  std::array<Point<dim>, dim+1> sxyz;
2312  bool posvol_order = true;
2313  for (int s = 0; s < num_sides_all; s++) {
2314  side_get_coordinates(s, &sxyz, posvol_order);
2315  side_volumes_[s] = calc_side_volume(sxyz);
2316  }
2317 }
2318 
2319 
2320 template<typename BasicMesh>
2322  int ncells = basicmesh_ptr_->num_owned_cells() +
2323  basicmesh_ptr_->num_ghost_cells();
2324 
2325  cell_volumes_.clear();
2326  cell_volumes_.assign(ncells, 0.0);
2327 
2328  for (int c = 0; c < ncells; ++c)
2329  for (auto s : cell_side_ids_[c])
2330  cell_volumes_[c] += side_volumes_[s];
2331 }
2332 
2334 template <typename BasicMesh>
2335 template<int D>
2337  std::vector<Point<D>> *pplist) const {
2338  std::vector<int> cnodes;
2339  basicmesh_ptr_->cell_get_nodes(cellid, &cnodes);
2340 
2341  int ncnodes = cnodes.size();
2342  pplist->resize(ncnodes);
2343  for (int n = 0; n < ncnodes; ++n)
2344  basicmesh_ptr_->node_get_coordinates(cnodes[n], &((*pplist)[n]));
2345 }
2346 
2349 //
2350 // If a face of the cell is not guaranteed to be planar, it is faceted
2351 // by connecting its edges to a "central point" of the face. For now
2352 // the "central point" is merely the geometric center of its nodes. If
2353 // a client code wants to use a different point, it should furnish
2354 // this routine in its wrapper
2355 //
2356 // WE COULD DO THIS USING THE SIDES BUT IT WOULD BE A BIT MORE WORK TO
2357 // ELIMINATE DUPLICATE POINTS (SEE dual_cell_get_facetization). ALSO,
2358 // IF WE WANT TO HAVE THE OPTION OF A SIMPLER FACETIZATION IF WE KNOW
2359 // SOMETHING ABOUT THE CELL
2360 
2361 template <typename BasicMesh>
2363  std::vector<std::vector<int>> *facetpoints,
2364  std::vector<Point<3>> *points) const {
2365  facetpoints->clear();
2366  points->clear();
2367 
2368  std::vector<int> cnodes;
2369  basicmesh_ptr_->cell_get_nodes(cellid, &cnodes);
2370  int ncnodes = cnodes.size();
2371 
2372  points->resize(ncnodes);
2373  for (int n = 0; n < ncnodes; ++n)
2374  basicmesh_ptr_->node_get_coordinates(cnodes[n], &((*points)[n]));
2375 
2376  std::vector<int> cfaces, cfdirs;
2377  basicmesh_ptr_->cell_get_faces_and_dirs(cellid, &cfaces, &cfdirs);
2378  int ncfaces = cfaces.size();
2379 
2380  for (int f = 0; f < ncfaces; f++) {
2381  std::vector<int> fnodes;
2382  basicmesh_ptr_->face_get_nodes(cfaces[f], &fnodes);
2383  int nfnodes = fnodes.size();
2384 
2385  // Get the local indices (in the cell node list) of the face nodes
2386  std::vector<int> fnodes_local(nfnodes);
2387  for (int n = 0; n < nfnodes; n++) {
2388  bool found = false;
2389  int i = 0;
2390  while (!found && i < ncnodes) {
2391  found = (fnodes[n] == cnodes[i]);
2392  if (!found) i++;
2393  }
2394  assert(found);
2395  fnodes_local[n] = i;
2396  }
2397 
2398  if (nfnodes == 3) { // Triangle; guaranteed to be planar - no need to split
2399  if (cfdirs[f] != 1) { // reverse direction of nodes
2400  int tmp = fnodes_local[0];
2401  fnodes_local[0] = fnodes_local[1];
2402  fnodes_local[1] = tmp;
2403  }
2404  facetpoints->emplace_back(fnodes_local);
2405  } else {
2406  // quad or more general polygonal face which could be
2407  // curved. Facetize/Triangulate it by connecting each edge to a
2408  // central point in the face. This central point is computed as
2409  // the geometric center of the nodes of the face
2410 
2411  // Add centroid of face a new point to the point list
2412  Point<3> fcen;
2413  face_centroid(cfaces[f], &fcen);
2414  points->push_back(fcen);
2415  int icen = points->size() - 1;
2416 
2417  // Add the triangular facets formed using edges of face and centroid
2418  std::vector<int> fctpnts(3);
2419  for (int n = 0; n < nfnodes; n++) {
2420  if (cfdirs[f] == 1) {
2421  fctpnts[0] = fnodes_local[n];
2422  fctpnts[1] = fnodes_local[(n+1)%nfnodes];
2423  } else {
2424  fctpnts[0] = fnodes_local[(n+1)%nfnodes];
2425  fctpnts[1] = fnodes_local[n];
2426  }
2427  fctpnts[2] = icen;
2428  facetpoints->push_back(fctpnts);
2429  }
2430  }
2431  } // for (f...)
2432 } // cell_get_facetization
2433 
2434 
2437 template <typename BasicMesh>
2439  std::vector<std::vector<int>> *facetpoints,
2440  std::vector<Point<3>> *points) const {
2441  int64_t factor = 1e10; // used to manufacture unique edge ID from 2 node IDs
2442 
2443  facetpoints->clear();
2444  points->clear();
2445 
2446 #ifdef DEBUG
2447  assert(nodeid < num_entities(NODE, ALL));
2448 #endif
2449  assert(wedges_requested_);
2450  std::vector<int> wedges;
2451  node_get_wedges(nodeid, ALL, &wedges);
2452  int nwedges = wedges.size();
2453 
2454  points->reserve(3*nwedges);
2455  facetpoints->reserve(3*nwedges);
2456 
2457  // Tracking wedge facet points using these ID/type pairs will help
2458  // us identify duplicates without doing a distance check between
2459  // coordinates
2460  std::vector<int64_t> pntentids; // ID of entity that wedge point is on
2461  std::vector<int> pntenttypes; // Type of entity that wedge point is on
2462 
2463  pntentids.reserve(3*nwedges);
2464  pntenttypes.reserve(3*nwedges);
2465 
2466  int np = pntentids.size();
2467  for (auto const &w : wedges) {
2468  int s = w/2;
2469  int c = side_cell_id_[s];
2470  int f = side_face_id_[s];
2471  int iw = w%2;
2472  int n[2];
2473  n[0] = side_node_ids_[s][0];
2474  n[1] = side_node_ids_[s][1];
2475  // Since we don't explicitly have edges, manufacture a
2476  // (hopefully) unique edge ID
2477  int64_t e = (n[0] < n[1]) ? n[0]*factor + n[1] : n[1]*factor + n[0];
2478 
2479  int64_t wpentid[2][3];
2480  int wpenttyp[2][3];
2481  int nfct = 0;
2482  if (iw) {
2483  // facet in the interior of cell c
2484  wpentid[0][0] = e; wpentid[0][1] = c; wpentid[0][2] = f;
2485  wpenttyp[0][0] = 1; wpenttyp[0][1] = 3; wpenttyp[0][2] = 2;
2486  nfct++;
2487 
2488  // If the face associated with the wedge is on the exterior boundary
2489  // we have to add the facet on the boundary of cell c
2490  if (on_exterior_boundary(FACE, f)) {
2491  wpentid[1][0] = n[iw]; wpentid[1][1] = e; wpentid[1][2] = f;
2492  wpenttyp[1][0] = 0; wpenttyp[1][1] = 1; wpenttyp[1][2] = 2;
2493  nfct++;
2494  }
2495  } else {
2496  // facet in the interior of cell c
2497  wpentid[0][0] = e; wpentid[0][1] = f; wpentid[0][2] = c;
2498  wpenttyp[0][0] = 1; wpenttyp[0][1] = 2; wpenttyp[0][2] = 3;
2499  nfct++;
2500 
2501  // If the face associated with the wedge is on the exterior boundary
2502  // we have to add the facet on the boundary of cell c
2503  if (on_exterior_boundary(FACE, f)) {
2504  wpentid[1][0] = n[iw]; wpentid[1][1] = f; wpentid[1][2] = e;
2505  wpenttyp[1][0] = 0; wpenttyp[1][1] = 2; wpenttyp[1][2] = 1;
2506  nfct++;
2507  }
2508  }
2509 
2510  // Get local IDs for wedge facet points
2511  for (int i = 0; i < nfct; i++) {
2512  std::vector<int> fctpnts(3);
2513  for (int j = 0; j < 3; j++) {
2514  bool found = false;
2515  if (wpenttyp[i][j] != FACE) { // use id and type
2516  int k = 0;
2517  while (!found && k < np) {
2518  if (wpentid[i][j] == pntentids[k] &&
2519  wpenttyp[i][j] == pntenttypes[k]) {
2520  found = true;
2521  fctpnts[j] = k;
2522  } else
2523  k++;
2524  }
2525  } else { // use coordinate comparison because in distributed case
2526  // // flat mesh wrapper may have duplicate faces
2527  Point<3> fcen1;
2528  face_centroid(wpentid[i][j], &fcen1);
2529  int k = 0;
2530  while (!found && k < np) {
2531  if (pntenttypes[k] == FACE) {
2532  Point<3> fcen2;
2533  face_centroid(pntentids[k], &fcen2);
2534  if (approxEq(fcen1, fcen2, 1.0e-14)) {
2535  found = true;
2536  fctpnts[j] = k;
2537  }
2538  }
2539  k++;
2540  }
2541  }
2542  if (!found) { // point not in list
2543  pntentids.push_back(wpentid[i][j]);
2544  pntenttypes.push_back(wpenttyp[i][j]);
2545  fctpnts[j] = np++;
2546  }
2547  }
2548  facetpoints->push_back(fctpnts);
2549  }
2550  } // for (w : wedges)
2551 
2552  for (int i = 0; i < np; i++) {
2553  int64_t id = pntentids[i];
2554  int type = pntenttypes[i];
2555  Point<3> pxyz;
2556  switch (type) {
2557  case 0:
2558  basicmesh_ptr_->node_get_coordinates(id, &pxyz);
2559  break;
2560  case 1: {
2561  int n1 = id%factor;
2562  int n0 = (id-n1)/factor;
2563  Point<3> nxyz0, nxyz1;
2564  basicmesh_ptr_->node_get_coordinates(n0, &nxyz0);
2565  basicmesh_ptr_->node_get_coordinates(n1, &nxyz1);
2566  pxyz = (nxyz0 + nxyz1)/2.0; // mid-point of edge
2567  break;
2568  }
2569  case 2:
2570  basicmesh_ptr_->face_centroid(id, &pxyz);
2571  break;
2572  case 3:
2573  basicmesh_ptr_->cell_centroid(id, &pxyz);
2574  break;
2575  default:
2576  std::cerr << "Unknown type" << std::endl;
2577  }
2578  points->push_back(pxyz);
2579  } // Get coordinates of each unique point
2580 } // dual_cell_get_facetization
2581 
2582 
2585 template<size_t D, class MeshWrapper>
2586 void cell_radius(MeshWrapper &wrapper,
2587  int const cellid, double *radius) {
2588  Point<D> centroid;
2589  wrapper.cell_centroid(cellid, &centroid);
2590  std::vector<int> nodes;
2591  wrapper.cell_get_nodes(cellid, &nodes);
2592  Point<D> arm, node;
2593  *radius = 0.;
2594  int const dim = D;
2595  for (int & i : nodes) {
2596  wrapper.node_get_coordinates(i, &node);
2597  for (int j = 0; j < dim; j++) arm[j] = node[j]-centroid[j];
2598  double distance = 0.0;
2599  for (int j = 0; j < dim; j++) distance += arm[j]*arm[j];
2600  distance = sqrt(distance);
2601  if (distance > *radius) *radius = distance;
2602  }
2603 }
2604 
2605 
2608 template<size_t D, class MeshWrapper>
2609 void node_radius(MeshWrapper &wrapper,
2610  int const nodeid, double *radius) {
2611  std::vector<int> nodes;
2612  wrapper.node_get_cell_adj_nodes(nodeid, ALL, &nodes);
2613  Point<D> center;
2614  wrapper.node_get_coordinates(nodeid, &center);
2615  *radius = 0.;
2616  Point<D> arm, node;
2617  int const dim = D;
2618 
2619  for (int & i : nodes) {
2620  wrapper.node_get_coordinates(i, &node);
2621  for (int j = 0; j < dim; j++) arm[j] = node[j]-center[j];
2622  double distance = 0.0;
2623  for (int j = 0; j < dim; j++) distance += arm[j]*arm[j];
2624  distance = sqrt(distance);
2625  if (distance > *radius) *radius = distance;
2626  }
2627 }
2628 
2629 
2630 } // namespace Wonton
2631 
2632 #endif // AUX_MESH_TOPOLOGY_H_
double wedge_volume(int const wedgeid) const
Volume of a wedge - half its side volume.
Definition: AuxMeshTopology.h:777
int num_entities(Entity_kind const entity, Entity_type const etype=Entity_type::ALL) const
Number of items of given entity.
Definition: AuxMeshTopology.h:264
void side_get_coordinates(int const sideid, std::array< Point< 3 >, 4 > *scoords, bool posvol_order=false) const
side coordinates in 3D
Definition: AuxMeshTopology.h:1610
int num_ghost_sides() const
Number of ghost sides in the mesh.
Definition: AuxMeshTopology.h:244
Definition: wonton.h:130
Definition: wonton.h:128
void sides_get_coordinates(int cellID, std::vector< std::array< Point< 3 >, 4 >> *scoords) const
Get coordinates of side in 3D.
Definition: AuxMeshTopology.h:1171
AuxMeshTopology(bool request_sides=true, bool request_wedges=true, bool request_corners=true)
Constructor indicating which entities are wanted.
Definition: AuxMeshTopology.h:185
void build_sides_2D(AuxMeshTopology< BasicMesh > &mesh)
Definition: AuxMeshTopology.h:1779
friend void build_sides_2D(AuxMeshTopology< BasicMesh > &mesh)
Definition: AuxMeshTopology.h:1779
int wedge_get_adjacent_wedge(const int wedgeid) const
Definition: AuxMeshTopology.h:762
int corner_get_node(const int cornerid) const
Get node of corner.
Definition: AuxMeshTopology.h:873
int num_owned_corners() const
Number of owned corners in the mesh.
Definition: AuxMeshTopology.h:237
Definition: AuxMeshTopology.h:51
WONTON_INLINE double cross(const Vector< 2 > &a, const Vector< 2 > &b)
Cross product operator for two 2d vectors, .
Definition: Vector.h:304
counting_iterator end(Entity_kind const entity, Entity_type const etype=Entity_type::ALL) const
Iterator on mesh entity - end.
Definition: AuxMeshTopology.h:325
WONTON_INLINE double norm(bool doSqrt=true) const
Calculate the norm of a Vector.
Definition: Vector.h:148
void wedge_get_coordinates(int const wedgeid, std::array< Point< 3 >, 4 > *wcoords, bool posvol_order=false) const
Wedge coordinates in 3D.
Definition: AuxMeshTopology.h:1680
int num_ghost_corners() const
Number of ghost corners in the mesh.
Definition: AuxMeshTopology.h:258
Factorize a number N into D equal (or nearly equal) factors.
Definition: adaptive_refinement_mesh.h:31
std::vector< T > vector
Definition: wonton.h:285
Definition: wonton.h:87
bool on_exterior_boundary(Entity_kind const entity, int const entity_id) const
if entity is on exterior boundary
Definition: AuxMeshTopology.h:480
void cell_get_coordinates(int const cellid, std::vector< Point< D >> *pplist) const
Coordinates of nodes of cell.
Definition: AuxMeshTopology.h:2336
void order_wedges_ccw(std::vector< int > *wedgeids) const
Order wedges around a node in ccw manner.
Definition: AuxMeshTopology.h:1126
double dual_cell_volume(int const nodeid) const
Get the volume of dual cell by finding the corners that attach to the node.
Definition: AuxMeshTopology.h:1316
Definition: wonton.h:90
void dual_cell_get_node_adj_cells(int const nodeid, Entity_type const ptype, std::vector< int > *adjnodes) const
Get adjacent "dual cells" of a given "dual cell".
Definition: AuxMeshTopology.h:1186
Entity_type
The parallel type of a given entity.
Definition: wonton.h:124
void corner_get_wedges(int const cornerid, std::vector< int > *wedgeids) const
Get wedges of a corner.
Definition: AuxMeshTopology.h:895
Definition: wonton.h:85
void decompose_cell_into_tets(int cellid, std::vector< std::array< Wonton::Point< 3 >, 4 >> *tcoords, const bool planar_hex) const
Get the simplest possible decomposition of a 3D cell into tets.
Definition: AuxMeshTopology.h:985
Definition: wonton.h:161
int side_get_wedge(int const sideid, int iwedge) const
Definition: AuxMeshTopology.h:586
void cell_get_facetization(int const cellid, std::vector< std::vector< int >> *facetpoints, std::vector< Point< 3 >> *points) const
Get a triangular facetization of polyhedral cell boundary.
Definition: AuxMeshTopology.h:2362
double cell_volume(int const cellid) const
Volume of a cell.
Definition: AuxMeshTopology.h:517
int wedge_get_side(int const wedgeid) const
Side of wedge.
Definition: AuxMeshTopology.h:679
boost::counting_iterator< int > counting_iterator
Definition: wonton.h:290
int side_get_opposite_side(int const sideid) const
Definition: AuxMeshTopology.h:602
void cell_get_node_adj_cells(int const cellid, Entity_type const ptype, std::vector< int > *adjcells) const
Get the list of cell IDs for all cells attached to a specific cell through its nodes.
Definition: AuxMeshTopology.h:341
int num_ghost_wedges() const
Number of ghost wedges in the mesh.
Definition: AuxMeshTopology.h:251
int side_get_face(int const sideid) const
Face of side.
Definition: AuxMeshTopology.h:570
void dual_cell_centroid(int nodeid, Point< D > *centroid) const
Centroid of a dual cell.
Definition: AuxMeshTopology.h:1283
Definition: wonton.h:88
double side_volume(int const sideid) const
Volume of a side.
Definition: AuxMeshTopology.h:669
Represents a point in an N-dimensional space.
Definition: Point.h:50
void cell_get_wedges(int const cellid, std::vector< int > *wedgeids) const
Get all the wedges in a cell.
Definition: AuxMeshTopology.h:834
void cell_radius(MeshWrapper &wrapper, int const cellid, double *radius)
Definition: AuxMeshTopology.h:2586
int wedge_get_opposite_wedge(const int wedgeid) const
Definition: AuxMeshTopology.h:742
void node_get_wedges(int const nodeid, Entity_type const type, std::vector< int > *wedgeids) const
Get wedges at a node.
Definition: AuxMeshTopology.h:850
int side_get_cell(int const sideid) const
Cell of side.
Definition: AuxMeshTopology.h:559
counting_iterator begin(Entity_kind const entity, Entity_type const etype=Entity_type::ALL) const
Iterators on mesh entity - begin.
Definition: AuxMeshTopology.h:318
friend void build_sides_3D(AuxMeshTopology< BasicMesh > &mesh)
Definition: AuxMeshTopology.h:1878
counting_iterator make_counting_iterator(int const i)
Definition: wonton.h:291
void dual_wedges_get_coordinates(int nodeid, std::vector< std::array< Point< 3 >, 4 >> *wcoords) const
Definition: AuxMeshTopology.h:1263
WONTON_INLINE bool approxEq(const Point< D > &p1, const Point< D > &p2, double tol=1.0e-8)
Definition: Point.h:274
int cell_get_corner_at_node(int const cellid, int const nodeid) const
Get a cell&#39;s corner at a particular node of the cell.
Definition: AuxMeshTopology.h:944
friend void build_sides_1D(AuxMeshTopology< BasicMesh > &mesh)
Definition: AuxMeshTopology.h:1712
int num_owned_sides() const
Number of owned sides in the mesh.
Definition: AuxMeshTopology.h:223
int wedge_get_corner(int const wedgeid) const
Corner of a wedge.
Definition: AuxMeshTopology.h:714
Entity_kind
The type of mesh entity.
Definition: wonton.h:81
int side_get_node(int const sideid, int const inode) const
Definition: AuxMeshTopology.h:547
Definition: wonton.h:89
int cell_get_face_adj_cell(int cell, int face) const
Retrieve the cell incident to a given face of a given cell.
Definition: AuxMeshTopology.h:395
void dual_cell_get_coordinates(int const nodeid, std::vector< Point< 2 >> *pplist) const
2D version of coords of nodes of a dual cell
Definition: AuxMeshTopology.h:1052
int wedge_get_node(int const wedgeid) const
node of a wedge
Definition: AuxMeshTopology.h:725
void build_aux_entities()
Definition: AuxMeshTopology.h:1331
int wedge_get_cell(int const wedgeid) const
Cell of wedge.
Definition: AuxMeshTopology.h:690
double corner_volume(int const cornerid) const
Volume of a corner.
Definition: AuxMeshTopology.h:959
void cell_centroid(int const cellid, Point< D > *ccen) const
Centroid of a cell.
Definition: AuxMeshTopology.h:507
void cell_get_corners(int const cellid, std::vector< int > *cornerids) const
Get corners in a cell.
Definition: AuxMeshTopology.h:932
void build_sides_1D(AuxMeshTopology< BasicMesh > &mesh)
Definition: AuxMeshTopology.h:1712
int corner_get_cell(int const cornerid) const
Get cell of corner.
Definition: AuxMeshTopology.h:884
Definition: wonton.h:91
void face_centroid(int const faceid, Point< D > *fcen) const
Centroid of a face.
Definition: AuxMeshTopology.h:529
void dual_cell_get_facetization(int const nodeid, std::vector< std::vector< int >> *facetpoints, std::vector< Point< 3 >> *points) const
Definition: AuxMeshTopology.h:2438
void node_get_cell_adj_nodes(int const nodeid, Entity_type const ptype, std::vector< int > *adjnodes) const
Get the list of node IDs for all nodes attached to all cells attached to a specific node...
Definition: AuxMeshTopology.h:448
void node_get_corners(int const nodeid, Entity_type const type, std::vector< int > *cornerids) const
Get corners connected to a node.
Definition: AuxMeshTopology.h:908
void node_radius(MeshWrapper &wrapper, int const nodeid, double *radius)
Definition: AuxMeshTopology.h:2609
void face_get_cells(int const faceid, Entity_type const etype, std::vector< int > *cells) const
Get cells of given Entity_type connected to face (in no particular order)
Definition: AuxMeshTopology.h:371
int wedge_get_face(int const wedgeid) const
Face of wedge.
Definition: AuxMeshTopology.h:702
void wedges_get_coordinates(int cellID, std::vector< std::array< Point< 3 >, 4 >> *wcoords) const
Get coordinates of wedge in 3D.
Definition: AuxMeshTopology.h:1155
Definition: wonton.h:127
int num_owned_wedges() const
Number of owned wedges in the mesh.
Definition: AuxMeshTopology.h:230
void cell_get_face_adj_cells(int const cellid, Entity_type const ptype, std::vector< int > *adjcells) const
Get the list of cell IDs for all cells attached to a specific cell through its faces.
Definition: AuxMeshTopology.h:418
bool ccw(Point< 2 > const &p1, Point< 2 > const &p2, Point< 2 > const &p3) const
Definition: AuxMeshTopology.h:1141
void dual_cell_get_coordinates(int const nodeid, std::vector< Point< 3 >> *pplist) const
3D version of coords of nodes of a dual cell
Definition: AuxMeshTopology.h:1201
double calc_side_volume(std::array< Point< 1 >, 2 > const &sxyz)
Compute volume of 1D side.
Definition: AuxMeshTopology.h:29
void build_sides_3D(AuxMeshTopology< BasicMesh > &mesh)
Definition: AuxMeshTopology.h:1878
std::vector< Point< 2 > > cellToXY(int cellID) const
Definition: AuxMeshTopology.h:1147
Represents a vector in N-dimensional space.
Definition: Vector.h:40
void cell_get_sides(int const cellid, std::vector< int > *csides) const
Get all the sides of a cell.
Definition: AuxMeshTopology.h:613
WONTON_INLINE double dot(const Vector< D > &a, const Vector< D > &b)
Dot product of two vectors, .
Definition: Vector.h:248