https://mooseframework.inl.gov
InterfaceMeshCut3DUserObject.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://mooseframework.inl.gov
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 
12 #include "libmesh/enum_point_locator_type.h"
13 
15 
18 {
20  params.addClassDescription("A userobject to cut a 3D mesh using a 2D cutter mesh.");
21  return params;
22 }
23 
25  : InterfaceMeshCutUserObjectBase(parameters)
26 {
27  for (const auto & elem : _cutter_mesh->element_ptr_range())
28  if (elem->type() != TRI3)
29  mooseError("InterfaceMeshCut3DUserObject currently only supports TRI3 elements in the "
30  "cutting mesh.");
31 }
32 
33 void
35 {
36  _pseudo_normal.clear();
37 
38  for (const auto & elem : _cutter_mesh->element_ptr_range())
39  {
40  std::vector<Point> vertices{elem->node_ref(0), elem->node_ref(1), elem->node_ref(2)};
41  std::array<Point, 7> normal;
42  Plane elem_plane(vertices[0], vertices[1], vertices[2]);
43  normal[0] = 2.0 * libMesh::pi * elem_plane.unit_normal(vertices[0]);
44 
45  for (unsigned int i = 0; i < elem->n_nodes(); i++)
46  {
47  Point normal_at_node(0.0);
48  const Node & node = elem->node_ref(i);
49 
50  for (const auto & node_neigh_elem_id : _node_to_elem_map[node.id()])
51  {
52  const Elem & node_neigh_elem = _cutter_mesh->elem_ref(node_neigh_elem_id);
53  std::vector<Point> vertices{
54  node_neigh_elem.node_ref(0), node_neigh_elem.node_ref(1), node_neigh_elem.node_ref(2)};
55  Plane elem_plane(vertices[0], vertices[1], vertices[2]);
56  unsigned int j = node_neigh_elem.local_node(node.id());
57  Point normal_at_node_j = elem_plane.unit_normal(vertices[0]);
58  unsigned int m = j + 1 < 3 ? j + 1 : j + 1 - 3;
59  unsigned int n = j + 2 < 3 ? j + 2 : j + 2 - 3;
60  Point line_1 = node_neigh_elem.node_ref(j) - node_neigh_elem.node_ref(m);
61  Point line_2 = node_neigh_elem.node_ref(j) - node_neigh_elem.node_ref(n);
62  Real dot = line_1 * line_2;
63  Real lenSq1 = line_1 * line_1;
64  Real lenSq2 = line_2 * line_2;
65  Real angle = std::acos(dot / std::sqrt(lenSq1 * lenSq2));
66  normal_at_node += normal_at_node_j * angle;
67  }
68  normal[1 + i] = normal_at_node;
69  }
70 
71  for (unsigned int i = 0; i < elem->n_sides(); i++)
72  {
73  std::vector<Point> vertices{elem->node_ref(0), elem->node_ref(1), elem->node_ref(2)};
74 
75  Plane elem_plane(vertices[0], vertices[1], vertices[2]);
76  Point normal_at_edge = libMesh::pi * elem_plane.unit_normal(vertices[0]);
77 
78  const Elem * neighbor = elem->neighbor_ptr(i);
79 
80  if (neighbor != nullptr)
81  {
82  std::vector<Point> vertices{
83  neighbor->node_ref(0), neighbor->node_ref(1), neighbor->node_ref(2)};
84 
85  Plane elem_plane(vertices[0], vertices[1], vertices[2]);
86  normal_at_edge += libMesh::pi * elem_plane.unit_normal(vertices[0]);
87  }
88  normal[4 + i] = normal_at_edge;
89  }
90  _pseudo_normal.insert(std::make_pair(elem->id(), normal));
91  }
92 }
93 
94 Point
95 InterfaceMeshCut3DUserObject::nodeNormal(const unsigned int & node_id)
96 {
97  Point normal(0.0);
98 
99  for (const auto & node_neigh_elem_id : _node_to_elem_map[node_id])
100  {
101  const auto & elem = _cutter_mesh->elem_ref(node_neigh_elem_id);
102  Plane elem_plane(elem.node_ref(0), elem.node_ref(1), elem.node_ref(2));
103  normal += elem_plane.unit_normal(elem.node_ref(0));
104  }
105 
106  unsigned int num = _node_to_elem_map[node_id].size();
107  return normal / num;
108 }
109 
110 bool
112  std::vector<Xfem::CutEdge> & /*cut_edges*/,
113  std::vector<Xfem::CutNode> & /*cut_nodes*/) const
114 {
115  mooseError("invalid method for 3D mesh cutting");
116  return false;
117 }
118 
119 bool
121  std::vector<Xfem::CutFace> & cut_faces) const
122 {
123  mooseAssert(elem->dim() == 3, "Dimension of element to be cut must be 3");
124 
125  bool elem_cut = false;
126 
127  for (unsigned int i = 0; i < elem->n_sides(); ++i)
128  {
129  // This returns the lowest-order type of side.
130  std::unique_ptr<const Elem> curr_side = elem->side_ptr(i);
131 
132  mooseAssert(curr_side->dim() == 2, "Side dimension must be 2");
133 
134  unsigned int n_edges = curr_side->n_sides();
135 
136  std::vector<unsigned int> cut_edges;
137  std::vector<Real> cut_pos;
138 
139  for (unsigned int j = 0; j < n_edges; j++)
140  {
141  // This returns the lowest-order type of side.
142  std::unique_ptr<const Elem> curr_edge = curr_side->side_ptr(j);
143  if (curr_edge->type() != EDGE2)
144  mooseError("In cutElementByGeometry face edge must be EDGE2, but type is: ",
145  libMesh::Utility::enum_to_string(curr_edge->type()),
146  " base element type is: ",
147  libMesh::Utility::enum_to_string(elem->type()));
148  const Node * node1 = curr_edge->node_ptr(0);
149  const Node * node2 = curr_edge->node_ptr(1);
150 
151  for (const auto & cut_elem : _cutter_mesh->element_ptr_range())
152  {
153  std::vector<Point> vertices;
154 
155  for (auto & node : cut_elem->node_ref_range())
156  {
157  Point & this_point = node;
158  vertices.push_back(this_point);
159  }
160 
161  Point intersection;
162  if (Xfem::intersectWithEdge(*node1, *node2, vertices, intersection) &&
163  std::find(cut_edges.begin(), cut_edges.end(), j) == cut_edges.end())
164  {
165  cut_edges.push_back(j);
166  cut_pos.push_back(Xfem::getRelativePosition(*node1, *node2, intersection));
167  }
168  }
169  }
170 
171  // if two edges of an element are cut, it is considered as an element being cut
172  if (cut_edges.size() == 2)
173  {
174  elem_cut = true;
175  Xfem::CutFace mycut;
176  mycut._face_id = i;
177  mycut._face_edge.push_back(cut_edges[0]);
178  mycut._face_edge.push_back(cut_edges[1]);
179  mycut._position.push_back(cut_pos[0]);
180  mycut._position.push_back(cut_pos[1]);
181  cut_faces.push_back(mycut);
182  }
183  }
184 
185  return elem_cut;
186 }
187 
188 bool
190  std::vector<std::vector<Point>> & /*frag_edges*/,
191  std::vector<Xfem::CutEdge> & /*cut_edges*/) const
192 {
193  mooseError("invalid method for 3D mesh cutting");
194  return false;
195 }
196 
197 bool
199  std::vector<std::vector<Point>> & /*frag_faces*/,
200  std::vector<Xfem::CutFace> & /*cut_faces*/) const
201 {
202  mooseError("cutFragmentByGeometry not yet implemented for 3D mesh cutting");
203  return false;
204 }
205 
206 Real
208 {
209  std::vector<Real> distance;
210  Real min_dist = std::numeric_limits<Real>::max();
211  for (const auto & cut_elem : _cutter_mesh->element_ptr_range())
212  {
213  std::vector<Point> vertices{
214  cut_elem->node_ref(0), cut_elem->node_ref(1), cut_elem->node_ref(2)};
215  unsigned int region;
216  Point xp;
218  p, cut_elem->node_ref(0), cut_elem->node_ref(1), cut_elem->node_ref(2), xp, region);
219 
220  distance.push_back(std::abs(dist));
221 
222  if (dist < std::abs(min_dist))
223  {
224  min_dist = dist;
225  Point normal = (_pseudo_normal.find(cut_elem->id())->second)[region];
226  if (normal * (p - xp) < 0.0)
227  min_dist *= -1.0;
228  }
229  }
230  std::sort(distance.begin(), distance.end());
231  Real sum_dist = 0.0;
232  for (std::vector<Real>::iterator it = distance.begin(); it != distance.begin() + 1; ++it)
233  sum_dist += *it;
234 
235  if (min_dist < 0.0)
236  return -sum_dist / 1.0;
237  else
238  return sum_dist / 1.0;
239 }
std::unordered_map< unsigned int, std::array< Point, 7 > > _pseudo_normal
Map of information defining cutting elements, stored in this order for each element: pseudo normal...
virtual Real calculateSignedDistance(Point p) const override
Calculate the signed distance for a given point relative to the surface.
virtual Point nodeNormal(const unsigned int &node_id) override
return the normal at a node in the cutting mesh
std::vector< Real > _position
Fractional distance along the cut edges where the cut is located.
Real distance(const Point &p)
Data structure defining a cut through a face.
TRI3
Real getRelativePosition(const Point &p1, const Point &p2, const Point &p)
Get the relative position of p from p1 respect to the total length of the line segment.
Definition: XFEMFuncs.C:991
bool intersectWithEdge(const Point &p1, const Point &p2, const std::vector< Point > &vertices, Point &pint)
check if a line intersects with an element defined by vertices calculate the distance from a point to...
Definition: XFEMFuncs.C:948
InterfaceMeshCut3DUserObject(const InputParameters &parameters)
std::shared_ptr< MeshBase > _cutter_mesh
The cutter mesh.
virtual bool cutFragmentByGeometry(std::vector< std::vector< Point >> &frag_edges, std::vector< Xfem::CutEdge > &cut_edges) const override
std::string enum_to_string(const T e)
virtual void calculateNormals() override
calculate the element normal values for all of the elements.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
EDGE2
void mooseError(Args &&... args) const
void addClassDescription(const std::string &doc_string)
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
virtual bool cutElementByGeometry(const Elem *elem, std::vector< Xfem::CutEdge > &cut_edges, std::vector< Xfem::CutNode > &cut_nodes) const override
registerMooseObject("XFEMApp", InterfaceMeshCut3DUserObject)
std::unordered_map< dof_id_type, std::vector< dof_id_type > > _node_to_elem_map
node to element map of cut mesh
Real pointTriangleDistance(const Point &x0, const Point &x1, const Point &x2, const Point &x3, Point &xp, unsigned int &region)
Calculate the signed distance from a point to a triangle.
Definition: XFEMFuncs.C:836
std::vector< unsigned int > _face_edge
IDs of all cut faces.
unsigned int _face_id
ID of the cut face.
const Real pi