https://mooseframework.inl.gov
MeshCut2DRankTwoTensorNucleation.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 
11 
12 #include "MooseError.h"
13 #include "MooseTypes.h"
14 #include "libmesh/quadrature.h"
15 #include "RankTwoTensor.h"
16 #include "RankTwoScalarTools.h"
17 #include "Assembly.h"
18 
20 
23 {
25  params.addClassDescription(
26  "Nucleate a crack in MeshCut2D UO based on a scalar extracted from a RankTwoTensor");
27  params.addRangeCheckedParam<Real>(
28  "edge_extension_factor",
29  1e-5,
30  "edge_extension_factor >= 0",
31  "Factor by which the length of cracks that have been adjusted to coincide with element edges "
32  "are increased to avoid missing an intersection with the edge due to numerical tolerance "
33  "issues.");
34  params.addRangeCheckedParam<Real>(
35  "nucleation_length",
36  "nucleation_length >= 0",
37  "Size of crack to nucleate. Must be larger than the length of the element in which the "
38  "crack is nucleated, unless 'nucleate_across_full_element' is set to 'true'.");
39  params.addParam<MooseEnum>(
40  "scalar_type",
42  "Scalar quantity to be computed from tensor and used as a failure criterion");
43  params.addRequiredParam<std::string>("tensor", "The material tensor name.");
44  params.addRequiredCoupledVar(
45  "nucleation_threshold",
46  "Threshold for the scalar quantity of the RankTwoTensor to nucleate new cracks");
47  params.addParam<Point>(
48  "point1",
49  Point(0, 0, 0),
50  "Start point for axis used to calculate some cylindrical material tensor quantities");
51  params.addParam<Point>(
52  "point2",
53  Point(0, 1, 0),
54  "End point for axis used to calculate some cylindrical material tensor quantities");
55  params.addParam<bool>(
56  "nucleate_across_full_element",
57  false,
58  "Controls the behavior of nucleating cracks if 'nucleation_length' is smaller than the "
59  "length required to travserse an element with a nucleating crack. If this is set to 'false', "
60  "that condition will result in an error, but if set to 'true', a crack with the length "
61  "needed "
62  "to traverse the element will be inserted.");
63  return params;
64 }
65 
67  const InputParameters & parameters)
68  : MeshCut2DNucleationBase(parameters),
69  _edge_extension_factor(getParam<Real>("edge_extension_factor")),
70  _nucleate_across_full_element(getParam<bool>("nucleate_across_full_element")),
71  _is_nucleation_length_provided(isParamValid("nucleation_length")),
72  _nucleation_length(_is_nucleation_length_provided ? getParam<Real>("nucleation_length") : 0),
73  _tensor(getMaterialProperty<RankTwoTensor>(getParam<std::string>("tensor"))),
74  _nucleation_threshold(coupledValue("nucleation_threshold")),
75  _scalar_type(getParam<MooseEnum>("scalar_type")),
76  _point1(parameters.get<Point>("point1")),
77  _point2(parameters.get<Point>("point2")),
78  _JxW(_assembly.JxW()),
79  _coord(_assembly.coordTransformation())
80 {
81 }
82 
83 bool
85  std::pair<RealVectorValue, RealVectorValue> & cutterElemNodes)
86 {
87  bool does_it_crack = false;
88  unsigned int numqp = _qrule->n_points();
89  Point zero; // Used for checking whether cutter Element is zero length
90 
91  Real average_threshold = 0.0;
92  RankTwoTensor average_tensor;
93  Point average_point;
94  for (unsigned int qp = 0; qp < numqp; ++qp)
95  {
96  if (_nucleation_threshold[qp] <= 0.0)
97  mooseError("Threshold must be strictly positive in MeshCut2DRankTwoTensorNucleation");
98  average_threshold += _JxW[qp] * _coord[qp] * _nucleation_threshold[qp];
99  average_tensor += _JxW[qp] * _coord[qp] * _tensor[qp];
100  average_point += _JxW[qp] * _coord[qp] * _q_point[qp];
101  }
102  Point point_dir;
103  Real tensor_quantity = RankTwoScalarTools::getQuantity(
104  average_tensor, _scalar_type, _point1, _point2, average_point, point_dir);
105  if (point_dir.absolute_fuzzy_equals(zero))
106  mooseError("Cutter element has zero length in MeshCut2DRankTwoTensorNucleation");
107 
108  if (tensor_quantity > average_threshold)
109  {
110  does_it_crack = true;
111 
112  const Point elem_center(_current_elem->vertex_average());
113  Point crack_dir = point_dir.cross(Point(0, 0, 1));
114 
115  // get max element length to use for ray length
116  std::unique_ptr<const Elem> edge;
117  Real circumference = 0;
118  for (const auto e : _current_elem->edge_index_range())
119  {
120  _current_elem->build_edge_ptr(edge, e);
121  circumference += edge->length(0, 1);
122  }
123 
124  // Temporaries for doing things below
125  Real intersection_distance;
126 
127  Point point_0;
128  Point point_1;
129  bool is_point_0_on_external_boundary = false;
130  bool is_point_1_on_external_boundary = false;
131  for (const auto e : _current_elem->edge_index_range())
132  {
133  _current_elem->build_edge_ptr(edge, e);
134  const auto & edge0 = edge->point(0);
135  const auto & edge1 = edge->point(1);
137  elem_center, -crack_dir, circumference, edge0, edge1, point_0, intersection_distance))
138  is_point_0_on_external_boundary = (_current_elem->neighbor_ptr(e) == nullptr);
139  else if (lineLineIntersect2D(elem_center,
140  crack_dir,
141  circumference,
142  edge0,
143  edge1,
144  point_1,
145  intersection_distance))
146  is_point_1_on_external_boundary = (_current_elem->neighbor_ptr(e) == nullptr);
147  }
148 
149  // traverse_length is the length of a cut that goes across a single elment
150  // extend_length is the amount that needs to be added to each side of the traverse_length cut to
151  // make its length equal to the nucleation length
152  // We also add a small amount to the crack length to make sure it fully cuts the element edge.
153  // This factor is based on the element length.
154  Real traverse_length = (point_0 - point_1).norm();
155  Real extend_length = (_nucleation_length - traverse_length) / 2.0;
156  if (_nucleation_length < traverse_length)
157  {
159  mooseError(
160  "Trying to nucleate crack smaller than element length, increase nucleation_length.\n "
161  "Location of crack being nucleated: ",
162  point_0,
163  "\n nucleation_length: ",
165  "\n Length to traverse element: ",
166  traverse_length,
167  "\n This error can be suppressed by setting nucleate_across_full_element=True which "
168  "will nucleate a crack the size of the element.");
169  else
170  //_edge_extension_factor is used to make sure cut will cut both edges of the element.
171  extend_length = (traverse_length * _edge_extension_factor) / 2.0;
172  }
173 
174  // First create a cut assuming bulk nucleation
175  point_0 = point_0 - extend_length * crack_dir.unit();
176  point_1 = point_1 + extend_length * crack_dir.unit();
177 
178  // modify edges of cut to put them on the edge of the domain and have a length
179  // equal to nucleation_length
180  if (is_point_0_on_external_boundary)
181  {
182  // first move point back to edge
183  point_0 = point_0 + extend_length * crack_dir.unit();
184  // second move point a little bit over edge
185  point_0 = point_0 - (traverse_length * _edge_extension_factor) / 2.0 * crack_dir.unit();
186  // third, move point 1 so that crack equals nucleation length
187  point_1 = point_1 + extend_length * crack_dir.unit();
188  }
189  else if (is_point_1_on_external_boundary)
190  {
191  point_1 = point_1 - extend_length * crack_dir.unit();
192  point_1 = point_1 + (traverse_length * _edge_extension_factor) / 2.0 * crack_dir.unit();
193  point_0 = point_0 - extend_length * crack_dir.unit();
194  }
195  cutterElemNodes = {point_0, point_1};
196  }
197 
198  return does_it_crack;
199 }
200 
201 bool
203  const Point & direction,
204  const Real length,
205  const Point & v0,
206  const Point & v1,
207  Point & intersection_point,
208  Real & intersection_distance)
209 {
211  const Real TRACE_TOLERANCE = 1e-5;
212 
213  const auto r = direction * length;
214  const auto s = v1 - v0;
215  const auto rxs = r(0) * s(1) - r(1) * s(0);
216 
217  // Lines are parallel or colinear
218  if (std::abs(rxs) < TRACE_TOLERANCE)
219  return false;
220 
221  const auto v0mu0 = v0 - start;
222  const auto t = (v0mu0(0) * s(1) - v0mu0(1) * s(0)) / rxs;
223  if (0 >= t + TRACE_TOLERANCE || t - TRACE_TOLERANCE > 1.0)
224  {
225  return false;
226  }
227 
228  const auto u = (v0mu0(0) * r(1) - v0mu0(1) * r(0)) / rxs;
229  if (0 < u + TRACE_TOLERANCE && u - TRACE_TOLERANCE <= 1.0)
230  {
231  intersection_point = start + r * t;
232  intersection_distance = t * length;
233  return true;
234  }
235 
236  // Not parallel, but don't intersect
237  return false;
238 }
bool lineLineIntersect2D(const Point &start, const Point &direction, const Real length, const Point &v0, const Point &v1, Point &intersection_point, Real &intersection_distance)
T getQuantity(const RankTwoTensorTempl< T > &tensor, const MooseEnum &scalar_type, const Point &point1, const Point &point2, const Point &curr_point, Point &direction)
MeshCut2DRankTwoTensorNucleation(const InputParameters &parameters)
MooseEnum _scalar_type
The type of scalar to be extracted from the tensor.
const MooseArray< Point > & _q_point
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
MooseEnum scalarOptions()
This enum is left for legacy calls.
const Number zero
const Real _edge_extension_factor
scaling factor to extend the nucleated crack beyond the element edges.
void addRequiredParam(const std::string &name, const std::string &doc_string)
const Real TRACE_TOLERANCE
The standard tolerance to use in tracing.
Definition: TraceRayTools.h:48
const MooseArray< Real > & _JxW
Transformed Jacobian weights.
virtual bool doesElementCrack(std::pair< RealVectorValue, RealVectorValue > &cutterElemNodes) override
Determine whether the current element should be cut by a new crack.
const VariableValue & _nucleation_threshold
Threshold at which a crack is nucleated if exceeded.
const Real _nucleation_length
Length of the nucleated cracks.
auto norm(const T &a) -> decltype(std::abs(a))
void addRequiredCoupledVar(const std::string &name, const std::string &doc_string)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const QBase *const & _qrule
const Elem *const & _current_elem
void mooseError(Args &&... args) const
void addClassDescription(const std::string &doc_string)
registerMooseObject("XFEMApp", MeshCut2DRankTwoTensorNucleation)
void addRangeCheckedParam(const std::string &name, const T &value, const std::string &parsed_function, const std::string &doc_string)
static InputParameters validParams()
const MaterialProperty< RankTwoTensor > & _tensor
The tensor from which the scalar quantity used as a nucleating criterion is extracted.
const bool _is_nucleation_length_provided
is the nucleation length provided in the input file.
const Point _point1
Points used to define an axis of rotation for some scalar quantities.
const bool _nucleate_across_full_element
should element be cut if the nucleation_length is smaller than the element length.
const Elem & get(const ElemType type_in)