KratosMultiphysics
KRATOS Multiphysics (Kratos) is a framework for building parallel, multi-disciplinary simulation software, aiming at modularity, extensibility, and high performance. Kratos is written in C++, and counts with an extensive Python interface.
discont_utils.h
Go to the documentation of this file.
1 // | / |
2 // ' / __| _` | __| _ \ __|
3 // . \ | ( | | ( |\__ `
4 // _|\_\_| \__,_|\__|\___/ ____/
5 // Multi-Physics
6 //
7 // License: BSD License
8 // Kratos default license: kratos/license.txt
9 //
10 // Main authors: Pablo Becker
11 //
12 //
13 
14 
15 #if !defined(KRATOS_DISCONTINUOUS_UTILITIES_INCLUDED )
16 #define KRATOS_DISCONTINUOUS_UTILITIES_INCLUDED
17 
18 
19 
20 // System includes
21 #include <string>
22 #include <iostream>
23 #include <algorithm>
24 #include <limits>
25 
26 // External includes
27 
28 
29 // Project includes
30 #include "includes/define.h"
32 
33 
34 namespace Kratos
35 {
36 
42 {
43 public:
44 
65  /*
66  template<class TMatrixType, class TVectorType, class TGradientType>
67  static int CalculateTetrahedraDiscontinuousShapeFunctions(TMatrixType const& rPoints, TGradientType const& DN_DX,
68  TVectorType rDistances, TVectorType& rVolumes, TMatrixType& rShapeFunctionValues,
69  TVectorType& rPartitionsSign, std::vector<TMatrixType>& rGradientsValue, TMatrixType& NEnriched)
70  */
71 
72  //3D
74  BoundedMatrix<double,(3+1), 3 >& rPoints,
75  BoundedMatrix<double, (3+1), 3 >& DN_DX,
76  array_1d<double,(3+1)>& rDistances, array_1d<double,(3*(3-1))>& rVolumes,
77  BoundedMatrix<double, 3*(3-1), (3+1) >& rShapeFunctionValues,
78  array_1d<double,(3*(3-1))>& rPartitionsSign, std::vector<Matrix>& rGradientsValue,
79  BoundedMatrix<double,3*(3-1), (3+1)>& Nenriched,
80  array_1d<double,6>& edge_areas
81  )
82  {
84 
85  const int n_nodes = 4; // it works only for tetrahedra
86  const int n_edges = 6; // it works only for tetrahedra
87  const double one_quarter=0.25;
88 
89  const int edge_i[] = {0, 0, 0, 1, 1, 2};
90  const int edge_j[] = {1, 2, 3, 2, 3, 3};
91 
92  //to begin with we reset all data:
93  rGradientsValue[0]=ZeroMatrix(4,3);
94  rGradientsValue[1]=ZeroMatrix(4,3);
95  rGradientsValue[2]=ZeroMatrix(4,3);
96  rGradientsValue[3]=ZeroMatrix(4,3);
97  rGradientsValue[4]=ZeroMatrix(4,3);
98  rGradientsValue[5]=ZeroMatrix(4,3);
99  Nenriched=ZeroMatrix(6,4);
100 
101  double tot_vol;
102  CalculateGeometryData(rPoints, DN_DX, tot_vol);
103 
104  const double epsilon = 1e-15; //1.00e-9;
105  const double near_factor = 1.00e-12;
106 
107  int number_of_partitions = 1;
108 
109  array_1d<double, n_edges> edges_dx; // It will be initialize later
110  array_1d<double, n_edges> edges_dy; // It will be initialize later
111  array_1d<double, n_edges> edges_dz; // It will be initialize later
112  array_1d<double, n_edges> edges_length; // It will be initialize later
113  // The divided part length from first node of edge respect to the edge length
114  array_1d<double, n_edges> edge_division_i = ZeroVector(n_edges); // The 0 is for no split
115  // The divided part length from second node of edge respect to the edge length
116  array_1d<double, n_edges> edge_division_j = ZeroVector(n_edges); // The 0 is for no split
117 
118  BoundedMatrix<double, 8, 3 > aux_coordinates; //8 is the max number of nodes and aux_nodes
119  for (unsigned int i = 0; i < 4; i++)
120  for (unsigned int j = 0; j < 3; j++)
121  aux_coordinates(i, j) = rPoints(i, j);
122  for (unsigned int i = 4; i < 8; i++)
123  for (unsigned int j = 0; j < 3; j++)
124  aux_coordinates(i, j) = -10000.0; //set to a large number so that errors will be evident
125 
126  int split_edge[] = {0, 1, 2, 3, -1, -1, -1, -1, -1, -1, -1, -1};
127 
128  int new_node_id = 4;
129 
130  int n_negative_distance_nodes = 0;
131  int n_positive_distance_nodes = 0;
132  array_1d<int,4> signs(4,-2); // [] = {-2, -2, -2, -2};
133  array_1d<int,4> negative_distance_nodes(4,-1); // [] = {-1, -1, -1, -1};
134  array_1d<int,4> positive_distance_nodes(4,-1); // [] = {-1, -1, -1, -1};
135 
136  //compute the gradient of the distance and normalize it
137  array_1d<double, 3 > grad_d;
138  noalias(grad_d) = prod(trans(DN_DX), rDistances);
139  double norm = norm_2(grad_d);
140  if (norm > epsilon)
141  grad_d /= (norm);
142 
143  array_1d<double, n_nodes> exact_distance = rDistances;
145  //double sub_volumes_sum = 0.00;
146 
147  //compute edge lenghts and max_lenght
148  double max_lenght = 0.0;
149  for (int edge = 0; edge < n_edges; edge++)
150  {
151  const int i = edge_i[edge];
152  const int j = edge_j[edge];
153 
154  double dx = rPoints(j, 0) - rPoints(i, 0);
155  double dy = rPoints(j, 1) - rPoints(i, 1);
156  double dz = rPoints(j, 2) - rPoints(i, 2);
157 
158  double l = sqrt(dx * dx + dy * dy + dz * dz);
159 
160  edges_dx[edge] = dx;
161  edges_dy[edge] = dy;
162  edges_dz[edge] = dz;
163  edges_length[edge] = l;
164 
165  if(l > max_lenght)
166  max_lenght = l;
167  }
168 
169  double relatively_close = near_factor*max_lenght;
170  array_1d<bool,4> collapsed_node;
171  //identify collapsed nodes
172  for (unsigned int i=0; i<4; i++)
173  {
174  if(std::abs(rDistances[i]) < relatively_close)
175  {
176  collapsed_node[i] = true;
177  rDistances[i] = 0.0;
178  }
179  else
180  {
181  collapsed_node[i] = false;
182  }
183 
184  abs_distance[i] = std::abs(rDistances[i]);
185  }
186 
187  //now decide splitting pattern
188  for (int edge = 0; edge < n_edges; edge++)
189  {
190  const int i = edge_i[edge];
191  const int j = edge_j[edge];
192  if (rDistances[i] * rDistances[j] < 0.0)
193  {
194  const double tmp = std::abs(rDistances[i]) / (std::abs(rDistances[i]) + std::abs(rDistances[j]));
195 
196  if (collapsed_node[i] == false && collapsed_node[j] == false)
197  {
198  split_edge[edge + 4] = new_node_id;
199  edge_division_i[edge] = tmp;
200  edge_division_j[edge] = 1.00 - tmp;
201 
202  //compute the position of the edge node
203  for (unsigned int k = 0; k < 3; k++)
204  aux_coordinates(new_node_id, k) = rPoints(i, k) * edge_division_j[edge] + rPoints(j, k) * edge_division_i[edge];
205 
206  new_node_id++;
207  }
208  }
209  }
210 
211  //compute the abs exact distance for all of the nodes
212  if(new_node_id > 4) //at least one edge is cut
213  {
214  array_1d<double,3> base_point;
215  base_point[0] = aux_coordinates(4,0);
216  base_point[1] = aux_coordinates(4,1);
217  base_point[2] = aux_coordinates(4,2);
218 
219 
220  for (int i_node = 0; i_node < n_nodes; i_node++)
221  {
222  double d = (rPoints(i_node,0) - base_point[0]) * grad_d[0] +
223  (rPoints(i_node,1) - base_point[1]) * grad_d[1] +
224  (rPoints(i_node,2) - base_point[2]) * grad_d[2] ;
225  abs_distance[i_node] = std::abs(d);
226  }
227 
228  }
229 
230 
231  for (int i_node = 0; i_node < n_nodes; i_node++)
232  {
233  if (rDistances[i_node] < 0.00)
234  {
235  signs[i_node] = -1;
236  negative_distance_nodes[n_negative_distance_nodes++] = i_node;
237  }
238  else
239  {
240  signs[i_node] = 1;
241  positive_distance_nodes[n_positive_distance_nodes++] = i_node;
242  }
243  }
244 
245  //assign correct sign to exact distance
246  for (int i = 0; i < n_nodes; i++)
247  {
248  if (rDistances[i] < 0.0)
249  exact_distance[i] = -abs_distance[i];
250  else
251  exact_distance[i] = abs_distance[i];
252  }
253 
254  //compute exact distance gradients
255  array_1d<double, 3 > exact_distance_gradient;
256  noalias(exact_distance_gradient) = prod(trans(DN_DX), exact_distance);
257 
258  array_1d<double, 3 > abs_distance_gradient;
259  noalias(abs_distance_gradient) = prod(trans(DN_DX), abs_distance);
260 
261  int number_of_splitted_edges = new_node_id - 4; //number of splitted edges
262 
263  double volume = edges_dx[0] * edges_dy[1] * edges_dz[2] -
264  edges_dx[0] * edges_dz[1] * edges_dy[2] +
265  edges_dy[0] * edges_dz[1] * edges_dx[2] -
266  edges_dy[0] * edges_dx[1] * edges_dz[2] +
267  edges_dz[0] * edges_dx[1] * edges_dy[2] -
268  edges_dz[0] * edges_dy[1] * edges_dx[2];
269 
270  const double one_sixth = 1.00 / 6.00;
271  volume *= one_sixth;
272 
273 
274  // KRATOS_WATCH(volume)
275  if (number_of_splitted_edges == 0) // no splitting
276  {
277  rVolumes[0] = volume;
278  //sub_volumes_sum = volume;
279 
280  //take the sign from the node with min distance
281  double min_distance = 1e9;
282  for (int j = 0; j < 4; j++)
283  if(exact_distance[j] < min_distance) min_distance = exact_distance[j];
284 
285  if(min_distance < 0.0)
286  rPartitionsSign[0] = -1.0;
287  else
288  rPartitionsSign[0] = 1.0;
289 
291 
292  for (int j = 0; j < 4; j++)
293  rShapeFunctionValues(0, j) = 0.25;
294 
295 
296  rGradientsValue[0] = ZeroMatrix(1,3);
297  }
298  else //if (number_of_splitted_edges == 4)
299  {
300  //define the splitting mode for the tetrahedra
301  int edge_ids[6];
302  TetrahedraSplit::TetrahedraSplitMode(split_edge, edge_ids);
303  int nel = 0; //number of elements generated
304  int n_splitted_edges; //number of splitted edges
305  int nint; //number of internal nodes
306  int t[56];
307  TetrahedraSplit::Split_Tetrahedra(edge_ids, t, &nel, &n_splitted_edges, &nint);
308  array_1d<double,4> local_subtet_indices;
309 
310  if (nint != 0)
311  {
312  KRATOS_ERROR << "Requiring an internal node for splitting ... can not accept this";
313  }
314 
315  //now obtain the tetras and compute their center coordinates and volume
316  noalias(edge_areas) = ZeroVector(6);
317  array_1d<double, 3 > center_position;
318  for (int i = 0; i < nel; i++)
319  {
320  int i0, i1, i2, i3; //indices of the subtetrahedra
321  TetrahedraSplit::TetrahedraGetNewConnectivityGID(i, t, split_edge, &i0, &i1, &i2, &i3);
322  double sub_volume = ComputeSubTetraVolumeAndCenter(aux_coordinates, center_position, i0, i1, i2, i3);
323 
324 
325  local_subtet_indices[0] = t[i*4];
326  local_subtet_indices[1] = t[i*4+1];
327  local_subtet_indices[2] = t[i*4+2];
328  local_subtet_indices[3] = t[i*4+3];
329 
330  AddToEdgeAreas<3>(edge_areas,exact_distance,local_subtet_indices,sub_volume);
331 
332  BoundedMatrix<double, 4, 3 > coord_subdomain; //used to pass arguments when we must calculate areas, shape functions, etc
333  BoundedMatrix<double,4,3> DN_DX_subdomain; //used to retrieve derivatives
334 
335  array_1d<int,4> partition_nodes;
336  double temp_area;
337  partition_nodes[0]=i0;
338  partition_nodes[1]=i1;
339  partition_nodes[2]=i2;
340  partition_nodes[3]=i3;
341  for (unsigned int j=0; j!=4; j++) //4 nodes of the partition
342  for (unsigned int k=0; k!=3; k++) //x,y,z
343  {
344  const int node_id=partition_nodes[j];
345  coord_subdomain(j,k)= aux_coordinates( node_id ,k );
346  }
347 
348  CalculateGeometryData(coord_subdomain, DN_DX_subdomain, temp_area);
349 
350  rVolumes[i] = sub_volume;
351 
352  //sub_volumes_sum += sub_volume;
353 
355  ComputeElementCoordinates(N, center_position, rPoints, volume);
356 
357  double dist = 0.0;
358  //double abs_dist = 0.0;
359  for (int j = 0; j < 4; j++) {
360  rShapeFunctionValues(i, j) = N[j];
361  dist += rShapeFunctionValues(i, j) * exact_distance[j];
362  //abs_dist += rShapeFunctionValues(i, j) * abs_distance[j];
363  }
364 
365  if (dist < 0.0)
366  rPartitionsSign[i] = -1.0;
367  else
368  rPartitionsSign[i] = 1.0;
369 
370  double partition_sign=rPartitionsSign[i];
371 
372  //now we must add the contribution to the normal nodes only if they have the same sign:
373  for (int j=0; j<4; j++) //j (real) node
374  {
375  if((partition_sign*rDistances(j))>0) //ok. add contribution!
376  {
377  //now we loop in the nodes that define the partition.
378  for (unsigned int k=0; k<4; k++) //loop on nodes of the subelement:
379  {
380  const int current_node= partition_nodes[k];
381  bool add_contribution=false;
382  if (current_node<4)
383  {
384  if (current_node==j)
385  add_contribution=true;
386  }
387  else
388  {
389  for (unsigned int edge=0; edge!=6 ; edge++) //we look for the edge that defines our node:
390  {
391  if (split_edge[4+edge]==current_node)
392  {
393  const int i_node = edge_i[edge];
394  const int j_node = edge_j[edge];
395  if (i_node==j || j_node==j)
396  add_contribution=true;
397  }
398 
399  }
400 
401  }
402 
403  if (add_contribution)
404  {
405  Nenriched(i,j)+=one_quarter; //partition, shape function
406  rGradientsValue[i](j,0)+=DN_DX_subdomain(k,0); //[i_partition], (shape function gradient,direction(x,y))
407  rGradientsValue[i](j,1)+=DN_DX_subdomain(k,1); //[i_partition], (shape function gradient,direction(x,y))
408  rGradientsValue[i](j,2)+=DN_DX_subdomain(k,2); //[i_partition], (shape function gradient,direction(x,y))
409  }
410  }
411 
412  }
413  //else //do nothing. it simply can't add to a node that is not in the same side, since we are creating discontinous shape functions
414  }
415  }
416 
417  number_of_partitions = nel;
418  }
419 
420  if (number_of_partitions == 1)
421  {
422  Nenriched(0,0) = 0.0;
423 
424  for (int j = 0; j < 3; j++)
425  rGradientsValue[0](0, j) = 0.0;
426  }
427 
428  return number_of_partitions;
429  KRATOS_CATCH("");
430  }
431 
432 
433 
434  //2D
435  static int CalculateDiscontinuousShapeFunctions(const BoundedMatrix<double,(2+1), 2 >& rPoints,
436  BoundedMatrix<double, (2+1), 2 >& rDN_DX,
437  array_1d<double,(2+1)>& rDistances,
438  array_1d<double,(3*(2-1))>& rVolumes,
439  BoundedMatrix<double, 3*(2-1), (2+1) >& rGPShapeFunctionValues,
440  array_1d<double,(3*(2-1))>& rPartitionsSign,
441  std::vector<Matrix>& rGradientsValue,
442  BoundedMatrix<double,3*(2-1), (2+1)>& rNenriched,
443  array_1d<double,3>& rEdgeAreas)
444  {
445  KRATOS_TRY
446 
447  // TRICK TO AVOID INTERSECTIONS TOO CLOSE TO THE NODES
448  const double unsigned_distance_0 = std::abs(rDistances(0));
449  const double unsigned_distance_1 = std::abs(rDistances(1));
450  const double unsigned_distance_2 = std::abs(rDistances(2));
451 
452  // We begin by finding the largest distance:
453  const double longest_distance = std::max(unsigned_distance_0, std::max(unsigned_distance_1, unsigned_distance_2));
454 
455  // Set a maximum relative distance
456  const double tolerable_distance = longest_distance*0.001; // (1/1,000,000 seems to have good results)
457 
458  if (unsigned_distance_0 < tolerable_distance)
459  {
460  rDistances[0] = tolerable_distance;
461  }
462  if (unsigned_distance_1 < tolerable_distance)
463  {
464  rDistances[1] = tolerable_distance;
465  }
466  if (unsigned_distance_2 < tolerable_distance)
467  {
468  rDistances[2] = tolerable_distance;
469  }
470  //END OF TRICK. REMEMBER TO OVERWRITE THE DISTANCE VARIABLE IN THE ELEMENT IN CASE THESE LINES HAVE MODIFIED THEM (distances)
471 
472  const double one_third = 1.0/3.0;
473  BoundedMatrix<double, 3, 2> aux_points; // For auxiliary nodes 4(between 1 and 2) ,5(between 2 and 3) ,6 (between 3 and 1)
474  BoundedMatrix<double, 3, 2> coord_subdomain; // Used to pass arguments when we must calculate areas, shape functions, etc
475  BoundedMatrix<double, 3, 2> DN_DX_subdomain; // Used to retrieve derivatives
476 
477  // Area of the complete element
478  const double Area = CalculateVol(rPoints(0,0), rPoints(0,1),
479  rPoints(1,0), rPoints(1,1),
480  rPoints(2,0), rPoints(2,1));
481 
482  array_1d<bool, 3> cut_edges;
483  array_1d<double, 3> aux_nodes_relative_locations;
484  BoundedMatrix<int, 3, 2> aux_nodes_father_nodes;
485 
486  // Check whether the element is cut or not by the interface
487  if( (rDistances(0)*rDistances(1))>0.0 && (rDistances(0)*rDistances(2))>0.0 ) // The element IS NOT cut by the interfase. we must return data of a normal, non-enriched element
488  {
489  rVolumes(0)=Area;
490  rGPShapeFunctionValues(0,0) = one_third;
491  rGPShapeFunctionValues(0,1) = one_third;
492  rGPShapeFunctionValues(0,2) = one_third;
493  rNenriched(0,0) = 0.0;
494  rGradientsValue[0] = ZeroMatrix(3, 3);
495  rDistances[0] = (rDistances(0) < 0.0) ? -1.0 : 1.0;
496 
497  return 1;
498  }
499 
500  else // Create the enrichement, it can be in 2 or 3 parts. always start with 3.
501  {
502  rNenriched = ZeroMatrix(3,3); // Reset the enriched shape functions values
503 
504  cut_edges[0] = ((rDistances(0)*rDistances(1))<0.0) ? true : false; // Edge 12 is cut
505  cut_edges[1] = ((rDistances(1)*rDistances(2))<0.0) ? true : false; // Edge 23 is cut
506  cut_edges[2] = ((rDistances(2)*rDistances(0))<0.0) ? true : false; // Edge 13 is cut
507  }
508 
509  // Go over the 3 edges
510  for (unsigned int i=0; i<3; i++)
511  {
512  const unsigned int edge_begin_node = i;
513  const unsigned int edge_end_node = (i+1 == 3) ? 0 : i+1; // It's a triangle, so node 3 is actually node 0
514 
515  if(cut_edges(i) == true)
516  {
517  aux_nodes_relative_locations(i)=std::abs(rDistances(edge_end_node)/(rDistances(edge_end_node)-rDistances(edge_begin_node) ) ) ; // Position in 'natural' coordinates of edge 12, 1 when it passes over node 1. (it is over the edge 01)
518  aux_nodes_father_nodes(i,0)=edge_begin_node;
519  aux_nodes_father_nodes(i,1)=edge_end_node;
520  }
521  else
522  {
523  if(std::abs(rDistances(edge_end_node))>std::abs(rDistances(edge_begin_node))) // If edge is not cut, we collapse the aux node into the node which has the highest absolute value to have "nicer" (less "slivery") subelements
524  {
525  aux_nodes_relative_locations(i)=0.0;
526  aux_nodes_father_nodes(i,0)=edge_end_node;
527  aux_nodes_father_nodes(i,1)=edge_end_node;
528  }
529  else
530  {
531  aux_nodes_relative_locations(i)=1.0;
532  aux_nodes_father_nodes(i,0)=edge_begin_node;
533  aux_nodes_father_nodes(i,1)=edge_begin_node;
534  }
535  }
536 
537  // Save the x and y-coordinates of the new aux nodes
538  for (unsigned int j=0; j<2; j++)
539  {
540  aux_points(i,j)= rPoints(edge_begin_node,j) * aux_nodes_relative_locations(i) + rPoints(edge_end_node,j) * (1.0- aux_nodes_relative_locations(i));
541  }
542  }
543 
544  // Compute the edge areas
545  unsigned int aux_counter = 0;
546  BoundedMatrix<double, 2, 2> intersection_aux_points;
547 
548  for (unsigned int iedge = 0; iedge<3; ++iedge)
549  {
550  if (cut_edges(iedge) == true)
551  {
552  intersection_aux_points(aux_counter, 0) = aux_points(iedge, 0);
553  intersection_aux_points(aux_counter, 1) = aux_points(iedge, 1);
554  aux_counter++;
555  }
556  }
557 
558  const double intersection_length = std::sqrt(std::pow(intersection_aux_points(0,0)-intersection_aux_points(1,0), 2) +
559  std::pow(intersection_aux_points(0,1)-intersection_aux_points(1,1), 2));
560 
561  rEdgeAreas[0] = (cut_edges(0) == true) ? intersection_length*0.5 : 0.0;
562  rEdgeAreas[1] = (cut_edges(1) == true) ? intersection_length*0.5 : 0.0;
563  rEdgeAreas[2] = (cut_edges(2) == true) ? intersection_length*0.5 : 0.0;
564 
565  // Reset all data:
566  rGradientsValue[0]=ZeroMatrix(3,2);
567  rGradientsValue[1]=ZeroMatrix(3,2);
568  rGradientsValue[2]=ZeroMatrix(3,2);
569  rNenriched=ZeroMatrix(3,3);
570  rGPShapeFunctionValues=ZeroMatrix(3,3);
571 
572  BoundedMatrix<unsigned int, 4, 3> partition_nodes_id;
573 
574  // Now we must check the 4 created partitions of the domain.
575  // One has been collapsed, so we discard it and therefore save only one.
576  // The 3 first partitions are created using 2 auxiliary nodes and a normal node. at least one of these will be discarded due to zero area
577  // The last one is composed by the 3 auxiliary nodes. it 'looks' wrong, but since at least one has been collapsed, it actually has a normal node.
578  unsigned int partition_number=0;
579 
580  for (unsigned int i=0; i<4; i++) // i partition
581  {
582 
583  const unsigned int j_aux = (i+2 > 2) ? i-1 : i+2;
584 
585  BoundedMatrix<int,3,2> partition_father_nodes;
587 
588  partition_nodes_id(i,0) = i;
589  partition_nodes_id(i,1) = i+2;
590  partition_nodes_id(i,2) = j_aux;
591 
592  if (i<3)
593  {
594  partition_father_nodes(0,0)=i;
595  partition_father_nodes(0,1)=i;
596  partition_father_nodes(1,0)=aux_nodes_father_nodes(i,0); //we are using i aux node
597  partition_father_nodes(1,1)=aux_nodes_father_nodes(i,1); //we are using i aux node
598  partition_father_nodes(2,0)=aux_nodes_father_nodes(j_aux,0); //we are using j_aux node
599  partition_father_nodes(2,1)=aux_nodes_father_nodes(j_aux,1); //we are using j_aux node
600 
601  coord_subdomain(0,0)=rPoints(i,0);
602  coord_subdomain(0,1)=rPoints(i,1);
603  coord_subdomain(1,0)=aux_points(i,0);
604  coord_subdomain(1,1)=aux_points(i,1);
605  coord_subdomain(2,0)=aux_points(j_aux,0);
606  coord_subdomain(2,1)=aux_points(j_aux,1);
607  }
608  else
609  {
610  // Last partition, made by the 3 aux nodes.
611  partition_father_nodes=aux_nodes_father_nodes;
612  coord_subdomain=aux_points;
613  }
614 
615  // Calculate data of this partition
616  double temp_area;
617  CalculateGeometryData(coord_subdomain, DN_DX_subdomain, temp_area);
618 
619  if (temp_area > std::numeric_limits<double>::epsilon()) // Check if it does have zero area
620  {
621  rVolumes(partition_number) = temp_area;
622 
623  // Look for the gauss point of the partition:
624  const double x_GP_partition = one_third * ( coord_subdomain(0,0) + coord_subdomain(1,0) + coord_subdomain(2,0) );
625  const double y_GP_partition = one_third * ( coord_subdomain(0,1) + coord_subdomain(1,1) + coord_subdomain(2,1) );
626  const double z_GP_partition = 0.0;
627 
628  // Reset the coord_subdomain matrix to have the whole element again
629  coord_subdomain = rPoints;
630 
631  // Calculate its shape function values
632  CalculatePosition ( coord_subdomain , x_GP_partition ,y_GP_partition ,z_GP_partition , N);
633 
634  // Check the partition sign.
635  const double partition_sign = (N(0)*rDistances(0) + N(1)*rDistances(1) + N(2)*rDistances(2))/std::abs(N(0)*rDistances(0) + N(1)*rDistances(1) + N(2)*rDistances(2));
636  rPartitionsSign(partition_number) = partition_sign;
637 
638  // Add the contribution to the normal nodes only if they have the same sign
639  for (int j=0; j<3; j++) //j (real) node
640  {
641  if((partition_sign*rDistances(j)) > 0) // Add contribution!
642  {
643  // Loop in the nodes that define the partition.
644  for (unsigned int k=0; k<3; k++) // Loop on k nodes of the current subelement
645  {
646  if (partition_father_nodes(k,0)==j || partition_father_nodes(k,1)==j )// (first node)
647  {
648  rNenriched(partition_number,j) += one_third; // Partition, shape function
649  rGradientsValue[partition_number](j,0) += DN_DX_subdomain(k,0); // [i_partition], (shape function gradient,direction(x,y))
650  rGradientsValue[partition_number](j,1) += DN_DX_subdomain(k,1); // [i_partition], (shape function gradient,direction(x,y))
651  }
652  }
653  }
654  // Else do nothing it simply can't add to a node that is not in the same side, since we are creating discontinous shape functions
655  }
656 
657  rGPShapeFunctionValues(partition_number,0) = N(0);
658  rGPShapeFunctionValues(partition_number,1) = N(1);
659  rGPShapeFunctionValues(partition_number,2) = N(2);
660 
661  partition_number++;
662  }
663 
664  }
665 
666  double tot_area;
667  CalculateGeometryData(rPoints, rDN_DX, tot_area);
668 
669  return 3;
670 
671  KRATOS_CATCH("");
672  }
673 
674  //2D IN LOCAL AXIS
676  BoundedMatrix<double,(2+1), 2 >& rOriginalPoints,
677  BoundedMatrix<double,(2+1), 2 >& rRotatedPoints,
678  BoundedMatrix<double, (2+1), 2 >& DN_DX_original,
679  array_1d<double,(2+1)>& rDistances,
680  array_1d<double,(3*(2-1))>& rVolumes,
681  BoundedMatrix<double, 3*(2-1), (2+1) >& rGPShapeFunctionValues,
682  array_1d<double,(3*(2-1))>& rPartitionsSign,
683  std::vector<Matrix>& rGradientsValue,
684  BoundedMatrix<double,3*(2-1), (2+1)>& Nenriched,
685  BoundedMatrix<double,(2), 2 >& rRotationMatrix,
686  BoundedMatrix<double, (2+1), 2 >& DN_DX_in_local_axis )
687  {
688  KRATOS_TRY
689 
690  double temp_area;
691  const double one_third=1.0/3.0;
692  BoundedMatrix<double,3,2> aux_points; //for auxiliary nodes 4(between 1 and 2) ,5(between 2 and 3) ,6 (between 3 and 1)
693  BoundedMatrix<double, 3, 2 > coord_subdomain; //used to pass arguments when we must calculate areas, shape functions, etc
694  BoundedMatrix<double,3,2> DN_DX_subdomain; //used to retrieve derivatives
695 
696  rGPShapeFunctionValues(0,0)=one_third;
697  rGPShapeFunctionValues(0,1)=one_third;
698  rGPShapeFunctionValues(0,2)=one_third; //default, when no interfase has been found
699 
700  // Area of the complete element
701  const double Area = CalculateVol(rOriginalPoints(0,0), rOriginalPoints(0,1),
702  rOriginalPoints(1,0), rOriginalPoints(1,1),
703  rOriginalPoints(2,0), rOriginalPoints(2,1));
704  array_1d<bool,3> cut_edges;
705  array_1d<double,3> aux_nodes_relative_locations;
706  BoundedMatrix<int,3,2> aux_nodes_father_nodes;
707 
708  //to begin with we must check whether our element is cut or not by the interfase.
709  if( (rDistances(0)*rDistances(1))>0.0 && (rDistances(0)*rDistances(2))>0.0 ) //it means that this element IS NOT cut by the interfase. we must return data of a normal, non-enriched element
710  {
711  rVolumes(0)=Area;
712  rGPShapeFunctionValues(0,0)=one_third;
713  rGPShapeFunctionValues(0,1)=one_third;
714  rGPShapeFunctionValues(0,2)=one_third;
715  Nenriched(0,0) = 0.0;
716  for (int j = 0; j < 3; j++)
717  rGradientsValue[0](0, j) = 0.0;
718  if (rDistances(0) < 0.0) rPartitionsSign[0] = -1.0;
719  else rPartitionsSign[0] = 1.0;
720  return 1;
721  }
722  else //we must create the enrichement, it can be in 2 or 3 parts. we'll start with 3 always.
723  {
724  if ((rDistances(0)*rDistances(1))<0.0) //edge 12 is cut
725  cut_edges[0]=true;
726  else
727  cut_edges[0]=false;
728  if ((rDistances(1)*rDistances(2))<0.0) //edge 23 is cut.
729  cut_edges[1]=true;
730  else
731  cut_edges[1]=false;
732  if ((rDistances(2)*rDistances(0))<0.0) //edge 23 is cut.
733  cut_edges[2]=true;
734  else
735  cut_edges[2]=false;
736 
737  //we reset the NEnriched:
738  Nenriched=ZeroMatrix(3,3);
739 
740  //'TRICK' TO AVOID HAVING THE INTERFASE TOO CLOSE TO THE NODES:
741  //since we cannot collapse node because we have to contemplate the possibility of discontinuities, we will move a little the intefase so that it is not that close.
742  const double unsigned_distance0=std::abs(rDistances(0));
743  const double unsigned_distance1=std::abs(rDistances(1));
744  const double unsigned_distance2=std::abs(rDistances(2));
745  //we begin by finding the largest distance:
746  double longest_distance=std::abs(unsigned_distance0);
747  if (unsigned_distance1>longest_distance)
748  longest_distance=unsigned_distance1;
749  if (unsigned_distance2>longest_distance)
750  longest_distance=unsigned_distance2;
751  //Now we set a maximum relative distance
752  const double tolerable_distance =longest_distance*0.001; // (1/1,000,000 seems to have good results)
753  //and now we check if a distance is too small:
754  if (unsigned_distance0<tolerable_distance)
755  rDistances[0]=tolerable_distance*(rDistances[0]/std::abs(rDistances[0]));
756  if (unsigned_distance1<tolerable_distance)
757  rDistances[1]=tolerable_distance*(rDistances[1]/std::abs(rDistances[1]));
758  if (unsigned_distance2<tolerable_distance)
759  rDistances[2]=tolerable_distance*(rDistances[2]/std::abs(rDistances[2]));
760  //END OF TRICK. REMEMBER TO OVERWRITE THE DISTANCE VARIABLE IN THE ELEMENT IN CASE THESE LINES HAVE MODIFIED THEM (distances)
761 
762  for (unsigned int i=0; i<3; i++) //we go over the 3 edges:
763  {
764  int edge_begin_node=i;
765  int edge_end_node=i+1;
766  if (edge_end_node==3) edge_end_node=0; //it's a triangle, so node 3 is actually node 0
767 
768  if(cut_edges(i)==true)
769  {
770  aux_nodes_relative_locations(i)=std::abs(rDistances(edge_end_node)/(rDistances(edge_end_node)-rDistances(edge_begin_node) ) ) ; //position in 'natural' coordinates of edge 12, 1 when it passes over node 1. (it is over the edge 01)
771  aux_nodes_father_nodes(i,0)=edge_begin_node;
772  aux_nodes_father_nodes(i,1)=edge_end_node;
773  }
774  else
775  {
776  if(std::abs(rDistances(edge_end_node))>std::abs(rDistances(edge_begin_node))) //if edge is not cut, we collapse the aux node into the node which has the highest absolute value to have "nicer" (less "slivery") subelements
777  {
778  aux_nodes_relative_locations(i)=0.0;
779  aux_nodes_father_nodes(i,0)=edge_end_node;
780  aux_nodes_father_nodes(i,1)=edge_end_node;
781  }
782  else
783  {
784  aux_nodes_relative_locations(i)=1.0;
785  aux_nodes_father_nodes(i,0)=edge_begin_node;
786  aux_nodes_father_nodes(i,1)=edge_begin_node;
787  }
788  }
789 
790  //and we save the coordinate of the new aux nodes:
791  for (unsigned int j=0; j<2; j++) //x,y coordinates
792  aux_points(i,j)= rOriginalPoints(edge_begin_node,j) * aux_nodes_relative_locations(i) + rOriginalPoints(edge_end_node,j) * (1.0- aux_nodes_relative_locations(i));
793  }
794 
795  //having gathered all the points location in local coordinates, we will proceed to move everything to a local system. the reference point will be the first point of aux_points.
796  double x_reference=aux_points(0,0);
797  double y_reference=aux_points(0,1);
798  double cosinus=0.0;
799  double sinus=0.0;
800  if (cut_edges[0]==false) //then the segment is defined by aux_points 1 and 2. so the values used to initialize were wrong. changing them:
801  {
802  x_reference=aux_points(1,0);
803  y_reference=aux_points(1,1);
804  const double one_over_interfase_lenght = 1.0/sqrt( pow((aux_points(2,0) - x_reference),2) + pow((aux_points(2,1) - y_reference),2));
805  cosinus = (aux_points(2,0) - x_reference)*one_over_interfase_lenght;
806  sinus = - (aux_points(2,1) - y_reference)*one_over_interfase_lenght; //WARNING; THERE IS A MINUS IN FRONT TO GET THE INVERSE ROTATION (FROM REFERENCE TO LOCAL)
807  }
808  else if(cut_edges[1]==true)
809  {
810  const double one_over_interfase_lenght = 1.0/sqrt( pow((aux_points(1,0) - x_reference),2) + pow((aux_points(1,1) - y_reference),2));
811  cosinus = (aux_points(1,0) - x_reference)*one_over_interfase_lenght;
812  sinus = - (aux_points(1,1) - y_reference)*one_over_interfase_lenght; //WARNING; THERE IS A MINUS IN FRONT TO GET THE INVERSE ROTATION (FROM REFERENCE TO LOCAL)
813  }
814  else
815  {
816  const double one_over_interfase_lenght = 1.0/sqrt( pow((aux_points(2,0) - x_reference),2) + pow((aux_points(2,1) - y_reference),2));
817  cosinus = (aux_points(2,0) - x_reference)*one_over_interfase_lenght;
818  sinus = - (aux_points(2,1) - y_reference)*one_over_interfase_lenght; //WARNING; THERE IS A MINUS IN FRONT TO GET THE INVERSE ROTATION (FROM REFERENCE TO LOCAL)
819  }
820 
821  for (unsigned int i=0; i<3; i++) //we go over the 3 nodes and 3 aux nodes to move them to the new coordinates:
822  {
823  rRotatedPoints(i,0)= cosinus * (rOriginalPoints(i,0)-x_reference) - sinus * (rOriginalPoints(i,1)-y_reference);
824  rRotatedPoints(i,1)= cosinus * (rOriginalPoints(i,1)-y_reference) + sinus * (rOriginalPoints(i,0)-x_reference);
825 
826  //and we directly change the aux points, anyway they are used only locally so it's fine:
827  double aux_x_coord=aux_points(i,0);
828  aux_points(i,0)= cosinus * (aux_x_coord-x_reference) - sinus * (aux_points(i,1)-y_reference);
829  aux_points(i,1)= cosinus * (aux_points(i,1)-y_reference) + sinus * (aux_x_coord-x_reference);
830  }
831 
832  //to calculate the new rigidity matrix in local coordinates, the element will need the derivated in the rotated axis and the rotation matrix:
833  CalculateGeometryData(rRotatedPoints, DN_DX_in_local_axis, temp_area);
834 
835  rRotationMatrix(0,0)=cosinus;
836  rRotationMatrix(0,1)= sinus;
837  rRotationMatrix(1,0)= -sinus;
838  rRotationMatrix(1,1)=cosinus;
839 
840  //we reset all data:
841  rGradientsValue[0]=ZeroMatrix(3,2);
842  rGradientsValue[1]=ZeroMatrix(3,2);
843  rGradientsValue[2]=ZeroMatrix(3,2);
844  Nenriched=ZeroMatrix(3,3);
845  rGPShapeFunctionValues=ZeroMatrix(3,3);
846 
847  //now we must check the 4 created partitions of the domain.
848  //one has been collapsed, so we discard it and therefore save only one.
849  unsigned int partition_number=0; //
850  //the 3 first partitions are created using 2 auxiliary nodes and a normal node. at least one of these will be discarded due to zero area
851  //the last one is composed by the 3 auxiliary nodes. it 'looks' wrong, but since at least one has been collapsed, it actually has a normal node.
852  for (unsigned int i=0; i<4; i++) //i partition
853  {
854  unsigned int j_aux = i + 2;
855  if (j_aux>2) j_aux -= 3;
856  BoundedMatrix<int,3,2> partition_father_nodes;
858  if (i<3)
859  {
860  partition_father_nodes(0,0)=i;
861  partition_father_nodes(0,1)=i;
862  partition_father_nodes(1,0)=aux_nodes_father_nodes(i,0); //we are using i aux node
863  partition_father_nodes(1,1)=aux_nodes_father_nodes(i,1); //we are using i aux node
864  partition_father_nodes(2,0)=aux_nodes_father_nodes(j_aux,0); //we are using j_aux node
865  partition_father_nodes(2,1)=aux_nodes_father_nodes(j_aux,1); //we are using j_aux node
866 
867  coord_subdomain(0,0)=rRotatedPoints(i,0);
868  coord_subdomain(0,1)=rRotatedPoints(i,1);
869  coord_subdomain(1,0)=aux_points(i,0);
870  coord_subdomain(1,1)=aux_points(i,1);
871  coord_subdomain(2,0)=aux_points(j_aux,0);
872  coord_subdomain(2,1)=aux_points(j_aux,1);
873  }
874  else
875  {
876  //the last partition, made by the 3 aux nodes.
877  partition_father_nodes=aux_nodes_father_nodes;
878  coord_subdomain=aux_points;
879  }
880 
881  //calculate data of this partition
882  CalculateGeometryData(coord_subdomain, DN_DX_subdomain, temp_area);
883  if (temp_area > std::numeric_limits<double>::epsilon()) //ok, it does not have zero area
884  {
885  rVolumes(partition_number)=temp_area;
886  //we look for the gauss point of the partition:
887  double x_GP_partition = one_third * ( coord_subdomain(0,0) + coord_subdomain(1,0) + coord_subdomain(2,0) );
888  double y_GP_partition = one_third * ( coord_subdomain(0,1) + coord_subdomain(1,1) + coord_subdomain(2,1) );
889  double z_GP_partition = 0.0;
890  //we reset the coord_subdomain matrix so that we have the whole element again:
891  coord_subdomain = rRotatedPoints;
892  //and we calculate its shape function values
893  CalculatePosition ( coord_subdomain , x_GP_partition ,y_GP_partition ,z_GP_partition , N);
894  //we check the partition sign.
895  const double partition_sign = (N(0)*rDistances(0) + N(1)*rDistances(1) + N(2)*rDistances(2))/std::abs(N(0)*rDistances(0) + N(1)*rDistances(1) + N(2)*rDistances(2));
896  rPartitionsSign(partition_number)=partition_sign;
897  //now we must add the contribution to the normal nodes only if they have the same sign:
898  for (int j=0; j<3; j++) //j (real) node
899  {
900  if((partition_sign*rDistances(j))>0) //ok. add contribution!
901  {
902  //now we loop in the nodes that define the partition.
903  for (unsigned int k=0; k<3; k++) //loop on k nodes of the current subelement
904  if (partition_father_nodes(k,0)==j || partition_father_nodes(k,1)==j )// (first node)
905  {
906  Nenriched(partition_number,j)+=one_third; //partition, shape function
907  rGradientsValue[partition_number](j,0)+=DN_DX_subdomain(k,0); //[i_partition], (shape function gradient,direction(x,y))
908  rGradientsValue[partition_number](j,1)+=DN_DX_subdomain(k,1); //[i_partition], (shape function gradient,direction(x,y))
909  }
910  }
911  //else do nothing. it simply can't add to a node that is not in the same side, since we are creating discontinous shape functions
912  }
913 
914  rGPShapeFunctionValues(partition_number,0)=N(0);
915  rGPShapeFunctionValues(partition_number,1)=N(1);
916  rGPShapeFunctionValues(partition_number,2)=N(2);
917 
918  partition_number++;
919 
920  }
921  }
922 
923  return 3;
924  }
925 
926  KRATOS_CATCH("");
927  }
928 
929 
930 private:
931 
932  template<class TMatrixType>
933  static void CopyShapeFunctionsValues(TMatrixType& rShapeFunctionValues, int OriginId, int DestinationId)
934  {
935  const int n_nodes = 4;
936  for (int i = 0; i < n_nodes; i++)
937  rShapeFunctionValues(DestinationId, i) = rShapeFunctionValues(OriginId, i);
938  }
939 
940  template<class TMatrixType, class TVectorType>
941  static void Divide1To2(array_1d<double, 6 > const& EdgeDivisionI, array_1d<double, 6 > const& EdgeDivisionJ, int Edge,
942  int Volume1Id, int Volume2Id, double Volume, TMatrixType& rShapeFunctionValues, TVectorType& rVolumes)
943  {
944  const int edge_i[] = {0, 0, 0, 1, 1, 2};
945  const int edge_j[] = {1, 2, 3, 2, 3, 3};
946 
947  const double division_i = EdgeDivisionI[Edge];
948  const double division_j = EdgeDivisionJ[Edge];
949 
950  rVolumes[Volume1Id] = division_i * Volume;
951  rVolumes[Volume2Id] = division_j * Volume;
952 
953  const int i = edge_i[Edge];
954  const int j = edge_j[Edge];
955 
956  double delta1 = rShapeFunctionValues(Volume1Id, i) * (1.00 - division_i);
957  rShapeFunctionValues(Volume1Id, i) += delta1;
958  rShapeFunctionValues(Volume1Id, j) -= delta1;
959 
960  double delta2 = rShapeFunctionValues(Volume2Id, i) * (1.00 - division_j);
961  rShapeFunctionValues(Volume2Id, j) += delta2;
962  rShapeFunctionValues(Volume2Id, i) -= delta2;
963  }
964 
965  static double ComputeSubTetraVolumeAndCenter(const BoundedMatrix<double, 3, 8 > & rAuxCoordinates,
966  array_1d<double, 3 > & rCenterPosition,
967  const int i0, const int i1, const int i2, const int i3)
968  {
969  const double x10 = rAuxCoordinates(i1, 0) - rAuxCoordinates(i0, 0);
970  const double y10 = rAuxCoordinates(i1, 1) - rAuxCoordinates(i0, 1);
971  const double z10 = rAuxCoordinates(i1, 2) - rAuxCoordinates(i0, 2);
972 
973  const double x20 = rAuxCoordinates(i2, 0) - rAuxCoordinates(i0, 0);
974  const double y20 = rAuxCoordinates(i2, 1) - rAuxCoordinates(i0, 1);
975  const double z20 = rAuxCoordinates(i2, 2) - rAuxCoordinates(i0, 2);
976 
977  const double x30 = rAuxCoordinates(i3, 0) - rAuxCoordinates(i0, 0);
978  const double y30 = rAuxCoordinates(i3, 1) - rAuxCoordinates(i0, 1);
979  const double z30 = rAuxCoordinates(i3, 2) - rAuxCoordinates(i0, 2);
980 
981  const double detJ = x10 * y20 * z30 - x10 * y30 * z20 + y10 * z20 * x30 - y10 * x20 * z30 + z10 * x20 * y30 - z10 * y20 * x30;
982  const double vol = detJ / 6.0;
983 
984  for (unsigned int i = 0; i < 3; i++)
985  {
986  rCenterPosition[i] = rAuxCoordinates(i0, i) + rAuxCoordinates(i1, i) + rAuxCoordinates(i2, i) + rAuxCoordinates(i3, i);
987  }
988 
989  rCenterPosition *= 0.25;
990 
991  return vol;
992  }
993 
994  template<class TMatrixType>
995  static void ComputeElementCoordinates(array_1d<double, 4 > & rN,
996  const array_1d<double, 3 > & rCenterPosition,
997  const TMatrixType& rPoints,
998  const double Vol)
999  {
1000  const double x0 = rPoints(0, 0);
1001  const double y0 = rPoints(0, 1);
1002  const double z0 = rPoints(0, 2);
1003  const double x1 = rPoints(1, 0);
1004  const double y1 = rPoints(1, 1);
1005  const double z1 = rPoints(1, 2);
1006  const double x2 = rPoints(2, 0);
1007  const double y2 = rPoints(2, 1);
1008  const double z2 = rPoints(2, 2);
1009  const double x3 = rPoints(3, 0);
1010  const double y3 = rPoints(3, 1);
1011  const double z3 = rPoints(3, 2);
1012 
1013  const double xc = rCenterPosition[0];
1014  const double yc = rCenterPosition[1];
1015  const double zc = rCenterPosition[2];
1016 
1017  const double inv_vol = 1.0 / Vol;
1018 
1019  rN[0] = CalculateVol(x1, y1, z1, x3, y3, z3, x2, y2, z2, xc, yc, zc) * inv_vol;
1020  rN[1] = CalculateVol(x0, y0, z0, x2, y2, z2, x3, y3, z3, xc, yc, zc) * inv_vol;
1021  rN[2] = CalculateVol(x3, y3, z3, x1, y1, z1, x0, y0, z0, xc, yc, zc) * inv_vol;
1022  rN[3] = CalculateVol(x1, y1, z1, x2, y2, z2, x0, y0, z0, xc, yc, zc) * inv_vol;
1023  }
1024 
1025  static inline double CalculateVol(const double x0, const double y0, const double z0,
1026  const double x1, const double y1, const double z1,
1027  const double x2, const double y2, const double z2,
1028  const double x3, const double y3, const double z3)
1029  {
1030  const double x10 = x1 - x0;
1031  const double y10 = y1 - y0;
1032  const double z10 = z1 - z0;
1033 
1034  const double x20 = x2 - x0;
1035  const double y20 = y2 - y0;
1036  const double z20 = z2 - z0;
1037 
1038  const double x30 = x3 - x0;
1039  const double y30 = y3 - y0;
1040  const double z30 = z3 - z0;
1041 
1042  const double detJ = x10 * y20 * z30 - x10 * y30 * z20 + y10 * z20 * x30 - y10 * x20 * z30 + z10 * x20 * y30 - z10 * y20 * x30;
1043 
1044  return detJ / 6.0;
1045  }
1046 
1047  static inline double CalculateVol(const double x0, const double y0,
1048  const double x1, const double y1,
1049  const double x2, const double y2)
1050  {
1051  return 0.5 * ((x1 - x0)*(y2 - y0)- (y1 - y0)*(x2 - x0));
1052  }
1053 
1054  static inline void CalculateGeometryData(const BoundedMatrix<double, 3, 2 > & rCoordinates,
1055  BoundedMatrix<double,3,2>& rDN_DX,
1056  double& rArea)
1057  {
1058  const double x10 = rCoordinates(1,0) - rCoordinates(0,0);
1059  const double y10 = rCoordinates(1,1) - rCoordinates(0,1);
1060 
1061  const double x20 = rCoordinates(2,0) - rCoordinates(0,0);
1062  const double y20 = rCoordinates(2,1) - rCoordinates (0,1);
1063 
1064  //Jacobian is calculated:
1065  // |dx/dxi dx/deta| |x1-x0 x2-x0|
1066  //J=| |= | |
1067  // |dy/dxi dy/deta| |y1-y0 y2-y0|
1068 
1069  const double detJ = x10 * y20-y10 * x20;
1070 
1071  rDN_DX(0,0) = -y20 + y10;
1072  rDN_DX(0,1) = x20 - x10;
1073  rDN_DX(1,0) = y20;
1074  rDN_DX(1,1) = -x20;
1075  rDN_DX(2,0) = -y10;
1076  rDN_DX(2,1) = x10;
1077 
1078  rDN_DX /= detJ;
1079 
1080  rArea = 0.5*detJ;
1081  }
1082 
1083  static inline void CalculateGeometryData(const BoundedMatrix<double, 4, 3 > & rCoordinates,
1084  BoundedMatrix<double,4,3>& rDN_DX,
1085  double& rVolume)
1086  {
1087  const double x10 = rCoordinates(1,0) - rCoordinates(0,0);
1088  const double y10 = rCoordinates(1,1) - rCoordinates(0,1);
1089  const double z10 = rCoordinates(1,2) - rCoordinates(0,2);
1090 
1091  const double x20 = rCoordinates(2,0) - rCoordinates(0,0);
1092  const double y20 = rCoordinates(2,1) - rCoordinates (0,1);
1093  const double z20 = rCoordinates(2,2) - rCoordinates (0,2);
1094 
1095  const double x30 = rCoordinates(3,0) - rCoordinates(0,0);
1096  const double y30 = rCoordinates(3,1) - rCoordinates (0,1);
1097  const double z30 = rCoordinates(3,2) - rCoordinates (0,2);
1098 
1099  const double detJ = x10 * y20 * z30 - x10 * y30 * z20 + y10 * z20 * x30 - y10 * x20 * z30 + z10 * x20 * y30 - z10 * y20 * x30;
1100 
1101  rDN_DX(0,0) = -y20 * z30 + y30 * z20 + y10 * z30 - z10 * y30 - y10 * z20 + z10 * y20;
1102  rDN_DX(0,1) = -z20 * x30 + x20 * z30 - x10 * z30 + z10 * x30 + x10 * z20 - z10 * x20;
1103  rDN_DX(0,2) = -x20 * y30 + y20 * x30 + x10 * y30 - y10 * x30 - x10 * y20 + y10 * x20;
1104  rDN_DX(1,0) = y20 * z30 - y30 * z20;
1105  rDN_DX(1,1) = z20 * x30 - x20 * z30;
1106  rDN_DX(1,2) = x20 * y30 - y20 * x30;
1107  rDN_DX(2,0) = -y10 * z30 + z10 * y30;
1108  rDN_DX(2,1) = x10 * z30 - z10 * x30;
1109  rDN_DX(2,2) = -x10 * y30 + y10 * x30;
1110  rDN_DX(3,0) = y10 * z20 - z10 * y20;
1111  rDN_DX(3,1) = -x10 * z20 + z10 * x20;
1112  rDN_DX(3,2) = x10 * y20 - y10 * x20;
1113 
1114  rDN_DX /= detJ;
1115 
1116  rVolume = detJ / 6.0;
1117  }
1118 
1119  static inline void CalculatePosition(const BoundedMatrix<double, 3, 2 > & rCoordinates,
1120  const double xc,
1121  const double yc,
1122  const double zc,
1123  array_1d<double, 3 > & rN)
1124  {
1125  const double x0 = rCoordinates(0,0);
1126  const double y0 = rCoordinates(0,1);
1127  const double x1 = rCoordinates(1,0);
1128  const double y1 = rCoordinates(1,1);
1129  const double x2 = rCoordinates(2,0);
1130  const double y2 = rCoordinates(2,1);
1131 
1132  const double area = CalculateVol(x0, y0, x1, y1, x2, y2);
1133  double inv_area = 0.0;
1134  if (area == 0.0)
1135  {
1136  KRATOS_ERROR << "Element with zero area found.";
1137  }
1138  else
1139  {
1140  inv_area = 1.0 / area;
1141  }
1142 
1143  rN[0] = CalculateVol(x1, y1, x2, y2, xc, yc) * inv_area;
1144  rN[1] = CalculateVol(x2, y2, x0, y0, xc, yc) * inv_area;
1145  rN[2] = CalculateVol(x0, y0, x1, y1, xc, yc) * inv_area;
1146  }
1147 
1148  template <int TDim>
1149  static void AddToEdgeAreas(array_1d<double, (TDim-1)*3 >& rEdgeAreas,
1150  const array_1d<double, TDim+1 >& rExactDistance,
1151  const array_1d<double, TDim+1 >& rIndices,
1152  const double SubVolume)
1153  {
1154  // Check if the element has 3 "nodes" on the cut surface and if the remaining one is positive
1155  // To do so, remember that edge nodes are marked with an id greater than 3
1156  unsigned int ncut=0, pos=0, positive_pos=0;
1157  for(unsigned int i=0; i<TDim+1; i++)
1158  {
1159  if(rIndices[i] > TDim)
1160  {
1161  ncut++;
1162  }
1163  else if(rExactDistance[rIndices[i]] > 0)
1164  {
1165  positive_pos = rIndices[i];
1166  pos++;
1167  }
1168  }
1169 
1170  if(ncut == TDim && pos==1) //cut face with a positive node!!
1171  {
1172  double edge_area = SubVolume*3.0/std::abs(rExactDistance[positive_pos]);
1173  edge_area /= static_cast<double>(TDim);
1174  for(unsigned int i=0; i<TDim+1; i++)
1175  {
1176  if( rIndices[i] > TDim)
1177  {
1178  int edge_index = rIndices[i] - TDim - 1;
1179  rEdgeAreas[edge_index] += edge_area;
1180  }
1181  }
1182  }
1183  }
1184 };
1185 
1186 } // namespace Kratos.
1187 
1188 #endif // KRATOS_DISCONTINUOUS_UTILITIES_INCLUDED defined
Definition: discont_utils.h:42
static int CalculateDiscontinuousShapeFunctions(BoundedMatrix< double,(3+1), 3 > &rPoints, BoundedMatrix< double,(3+1), 3 > &DN_DX, array_1d< double,(3+1)> &rDistances, array_1d< double,(3 *(3-1))> &rVolumes, BoundedMatrix< double, 3 *(3-1),(3+1) > &rShapeFunctionValues, array_1d< double,(3 *(3-1))> &rPartitionsSign, std::vector< Matrix > &rGradientsValue, BoundedMatrix< double, 3 *(3-1),(3+1)> &Nenriched, array_1d< double, 6 > &edge_areas)
Definition: discont_utils.h:73
static int CalculateDiscontinuousShapeFunctions(const BoundedMatrix< double,(2+1), 2 > &rPoints, BoundedMatrix< double,(2+1), 2 > &rDN_DX, array_1d< double,(2+1)> &rDistances, array_1d< double,(3 *(2-1))> &rVolumes, BoundedMatrix< double, 3 *(2-1),(2+1) > &rGPShapeFunctionValues, array_1d< double,(3 *(2-1))> &rPartitionsSign, std::vector< Matrix > &rGradientsValue, BoundedMatrix< double, 3 *(2-1),(2+1)> &rNenriched, array_1d< double, 3 > &rEdgeAreas)
Definition: discont_utils.h:435
static int CalculateDiscontinuousShapeFunctionsInLocalAxis(BoundedMatrix< double,(2+1), 2 > &rOriginalPoints, BoundedMatrix< double,(2+1), 2 > &rRotatedPoints, BoundedMatrix< double,(2+1), 2 > &DN_DX_original, array_1d< double,(2+1)> &rDistances, array_1d< double,(3 *(2-1))> &rVolumes, BoundedMatrix< double, 3 *(2-1),(2+1) > &rGPShapeFunctionValues, array_1d< double,(3 *(2-1))> &rPartitionsSign, std::vector< Matrix > &rGradientsValue, BoundedMatrix< double, 3 *(2-1),(2+1)> &Nenriched, BoundedMatrix< double,(2), 2 > &rRotationMatrix, BoundedMatrix< double,(2+1), 2 > &DN_DX_in_local_axis)
Definition: discont_utils.h:675
Definition: amatrix_interface.h:41
static int Split_Tetrahedra(const int edges[6], int t[56], int *nel, int *splitted_edges, int *nint)
Function to split a tetrahedron For a given edges splitting pattern, this function computes the inter...
Definition: split_tetrahedra.h:177
static void TetrahedraGetNewConnectivityGID(const int tetra_index, const int t[56], const int aux_ids[11], int *id0, int *id1, int *id2, int *id3)
Returns the ids of a subtetra Provided the splitting connectivities array and the array containing th...
Definition: split_tetrahedra.h:150
static void TetrahedraSplitMode(int aux_ids[11], int edge_ids[6])
Returns the edges vector filled with the splitting pattern. Provided the array of nodal ids,...
Definition: split_tetrahedra.h:91
Short class definition.
Definition: array_1d.h:61
#define KRATOS_CATCH(MoreInfo)
Definition: define.h:110
#define KRATOS_TRY
Definition: define.h:109
#define KRATOS_ERROR
Definition: exception.h:161
static double max(double a, double b)
Definition: GeometryFunctions.h:79
REF: G. R. Cowper, GAUSSIAN QUADRATURE FORMULAS FOR TRIANGLES.
Definition: mesh_condition.cpp:21
KratosZeroVector< double > ZeroVector
Definition: amatrix_interface.h:561
TExpressionType::data_type norm_2(AMatrix::MatrixExpression< TExpressionType, TCategory > const &TheExpression)
Definition: amatrix_interface.h:625
KratosZeroMatrix< double > ZeroMatrix
Definition: amatrix_interface.h:559
AMatrix::MatrixProductExpression< TExpression1Type, TExpression2Type > prod(AMatrix::MatrixExpression< TExpression1Type, TCategory1 > const &First, AMatrix::MatrixExpression< TExpression2Type, TCategory2 > const &Second)
Definition: amatrix_interface.h:568
T & noalias(T &TheMatrix)
Definition: amatrix_interface.h:484
AMatrix::TransposeMatrix< const T > trans(const T &TheMatrix)
Definition: amatrix_interface.h:486
float dist
Definition: edgebased_PureConvection.py:89
x2
Definition: generate_frictional_mortar_condition.py:122
x1
Definition: generate_frictional_mortar_condition.py:121
tuple tmp
Definition: generate_total_lagrangian_mixed_volumetric_strain_element.py:98
int n_nodes
Definition: generate_total_lagrangian_mixed_volumetric_strain_element.py:15
int t
Definition: ode_solve.py:392
int d
Definition: ode_solve.py:397
int k
Definition: quadrature.py:595
int j
Definition: quadrature.py:648
int node_id
Definition: read_stl.py:12
float xc
Definition: rotating_cone.py:77
float yc
Definition: rotating_cone.py:78
N
Definition: sensitivityMatrix.py:29
volume
Definition: sp_statistics.py:15
number_of_partitions
Definition: square_domain.py:61
integer i
Definition: TensorModule.f:17
integer l
Definition: TensorModule.f:17
e
Definition: run_cpp_mpi_tests.py:31