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.
enrichmentutilities.h
Go to the documentation of this file.
1 // ' / __| _` | __| _ \ __|
2 // . \ | ( | | ( |\__ `
3 // _|\_\_| \__,_|\__|\___/ ____/
4 // Multi-Physics
5 //
6 // License: BSD License
7 // Kratos default license: kratos/license.txt
8 //
9 // Main authors: Author Julio Marti.
10 //
11 
12 
13 #if !defined(KRATOS_ENRICHMENTUTILITIES_INCLUDED )
14 #define KRATOS_ENRICHMENTUTILITIES_INCLUDED
15 
16 
17 
18 // System includes
19 #include <string>
20 #include <iostream>
21 #include <algorithm>
22 #include <limits>
23 
24 // External includes
25 
26 
27 // Project includes
28 #include "includes/define.h"
30 
31 
32 namespace Kratos
33 {
34 
40  {
41  public:
42 
43  //2D with information on the interfase
44  static int CalculateEnrichedShapeFuncions(BoundedMatrix<double,(2+1), 2 >& rPoints, BoundedMatrix<double, (2+1), 2 >& DN_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)>& NEnriched,array_1d<double,(3)>& rGPShapeFunctionValues_in_interfase, array_1d<double,(3)>& NEnriched_in_interfase, double & InterfaseArea)
45  {
47 
48  const double one_third=1.0/3.0;
49  BoundedMatrix<double,3,2> aux_points; //for auxiliary nodes 4(between 1 and 2) ,5(between 2 and 3) ,6 (between 3 and 1)
50  BoundedMatrix<double, 3, 2 > coord_subdomain; //used to pass arguments when we must calculate areas, shape functions, etc
51  BoundedMatrix<double,3,2> DN_DX_subdomain; //used to retrieve derivatives
52 
53  double most_common_sign=0; //the side of the cut in which two nodes are found (same sign) will be the ones that remains unchanged when builing the discontinuity
54  double Area;//area of the complete element
55  rGPShapeFunctionValues(0,0)=one_third; rGPShapeFunctionValues(0,1)=one_third; rGPShapeFunctionValues(0,2)=one_third; //default, when no interfase has been found
56  Area = CalculateVolume2D( rPoints );
57  array_1d<bool,3> cut_edges;
58  array_1d<double,3> aux_nodes_relative_locations;
59  BoundedMatrix<int,3,2> aux_nodes_father_nodes;
60 
61  //to begin with we must check whether our element is cut or not by the interfase.
62  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
63  {
64  rVolumes(0)=Area;
65  rGPShapeFunctionValues(0,0)=one_third; rGPShapeFunctionValues(0,1)=one_third; rGPShapeFunctionValues(0,2)=one_third;
66  NEnriched(0,0) = 0.0;
67  //type_of_cut=1;
68  for (int j = 0; j < 3; j++)
69  rGradientsValue[0](0, j) = 0.0;
70  if (rDistances(0) < 0.0) rPartitionsSign[0] = -1.0;
71  else rPartitionsSign[0] = 1.0;
72  //KRATOS_WATCH("one element not in the intefase")
73  return 1;
74  }
75 
76  //else //we must create the enrichement, it can be in 2 or 3 parts. we'll start with 3 always.
77 
78 
79  //const double epsilon = 1e-15; //1.00e-9;
80  //compute the gradient of the distance and normalize it
81  array_1d<double, 2 > grad_d;
82  noalias(grad_d) = prod(trans(DN_DX), rDistances);
83  /*
84  double norm = norm_2(grad_d);
85  if (norm > epsilon)
86  grad_d /= (norm);
87  */
88  array_1d<double, 3> exact_distance = rDistances;
89  array_1d<double, 3> abs_distance = ZeroVector(3);
90 
91 
92  //KRATOS_WATCH("one element IS in the intefase")
93  if ((rDistances(0)*rDistances(1))<0.0) //edge 12 is cut
94  cut_edges[0]=true;
95  else
96  cut_edges[0]=false;
97  if ((rDistances(1)*rDistances(2))<0.0) //edge 23 is cut.
98  cut_edges[1]=true;
99  else
100  cut_edges[1]=false;
101  if ((rDistances(2)*rDistances(0))<0.0) //edge 23 is cut.
102  cut_edges[2]=true;
103  else
104  cut_edges[2]=false;
105 
106  //'TRICK' TO AVOID HAVING THE INTERFASE TOO CLOSE TO THE NODES:
107  //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.
108  const double unsigned_distance0=fabs(rDistances(0));
109  const double unsigned_distance1=fabs(rDistances(1));
110  const double unsigned_distance2=fabs(rDistances(2));
111  //we begin by finding the largest distance:
112  double longest_distance=fabs(unsigned_distance0);
113  if (unsigned_distance1>longest_distance)
114  longest_distance=unsigned_distance1;
115  if (unsigned_distance2>longest_distance)
116  longest_distance=unsigned_distance2;
117  //Now we set a maximum relative distance
118  const double tolerable_distance =longest_distance*0.001; // (1/1,000,000 seems to have good results)
119  //and now we check if a distance is too small:
120  if (unsigned_distance0<tolerable_distance)
121  rDistances[0]=tolerable_distance*(rDistances[0]/fabs(rDistances[0]));
122  if (unsigned_distance1<tolerable_distance)
123  rDistances[1]=tolerable_distance*(rDistances[1]/fabs(rDistances[1]));
124  if (unsigned_distance2<tolerable_distance)
125  rDistances[2]=tolerable_distance*(rDistances[2]/fabs(rDistances[2]));
126  //END OF TRICK. REMEMBER TO OVERWRITE THE DISTANCE VARIABLE IN THE ELEMENT IN CASE THESE LINES HAVE MODIFIED THEM (distances)
127 
128 
129  for (unsigned int i=0; i<3; i++) //we go over the 3 edges:
130  {
131  int edge_begin_node=i;
132  int edge_end_node=i+1;
133  if (edge_end_node==3) edge_end_node=0; //it's a triangle, so node 3 is actually node 0
134 
135  if(cut_edges(i)==true)
136  {
137  aux_nodes_relative_locations(i)=fabs(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)
138  aux_nodes_father_nodes(i,0)=edge_begin_node;
139  aux_nodes_father_nodes(i,1)=edge_end_node;
140  }
141  else
142  {
143  if(fabs(rDistances(edge_end_node))>fabs(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
144  {
145  aux_nodes_relative_locations(i)=0.0;
146  aux_nodes_father_nodes(i,0)=edge_end_node;
147  aux_nodes_father_nodes(i,1)=edge_end_node;
148  }
149  else
150  {
151  aux_nodes_relative_locations(i)=1.0;
152  aux_nodes_father_nodes(i,0)=edge_begin_node;
153  aux_nodes_father_nodes(i,1)=edge_begin_node;
154  }
155  }
156 
157  //and we save the coordinate of the new aux nodes:
158  for (unsigned int j=0;j<2;j++) //x,y coordinates
159  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));
160  }
161 
162 
163  array_1d<double,2> base_point;
164  if (cut_edges(0)==true) // it means it is a cut edge, if it was 0.0 or 1.0 then it would be an uncut edge
165  {
166  base_point[0] = aux_points(0,0);
167  base_point[1] = aux_points(0,1);
168 
169  }
170  else //it means aux_point 0 is a clone of other point, so we go to the second edge.
171  {
172  base_point[0] = aux_points(1,0);
173  base_point[1] = aux_points(1,1);
174  }
175 
176  for (int i_node = 0; i_node < 3; i_node++)
177  {
178  double d = (rPoints(i_node,0) - base_point[0]) * grad_d[0] +
179  (rPoints(i_node,1) - base_point[1]) * grad_d[1] ;
180  abs_distance[i_node] = fabs(d);
181  }
182 
183  //assign correct sign to exact distance
184  for (int i = 0; i < 3; i++)
185  {
186  if (rDistances[i] < 0.0)
187  {
188  exact_distance[i] = -abs_distance[i];
189  --most_common_sign;
190  }
191  else
192  {
193  exact_distance[i] = abs_distance[i];
194  ++most_common_sign;
195  }
196  }
197 
198  //compute exact distance gradients
199  array_1d<double, 2 > exact_distance_gradient;
200  noalias(exact_distance_gradient) = prod(trans(DN_DX), exact_distance);
201 
202  array_1d<double, 2 > abs_distance_gradient;
203  noalias(abs_distance_gradient) = prod(trans(DN_DX), abs_distance);
204 
205 
206  double max_aux_dist_on_cut = -1;
207  for (int edge = 0; edge < 3; edge++)
208  {
209  const int i = edge;
210  int j = edge+1;
211  if (j==3) j=0;
212  if (rDistances[i] * rDistances[j] < 0.0)
213  {
214  const double tmp = fabs(rDistances[i]) / (fabs(rDistances[i]) + fabs(rDistances[j]));
215  //compute the position of the edge node
216  double abs_dist_on_cut = abs_distance[i] * tmp + abs_distance[j] * (1.00 - tmp);
217  if(abs_dist_on_cut > max_aux_dist_on_cut) max_aux_dist_on_cut = abs_dist_on_cut;
218  }
219  }
220 
221 
222  //we reset all data:
223  rGradientsValue[0]=ZeroMatrix(2,2);
224  rGradientsValue[1]=ZeroMatrix(2,2);
225  rGradientsValue[2]=ZeroMatrix(2,2);
226  NEnriched=ZeroMatrix(3,2);
227  rGPShapeFunctionValues=ZeroMatrix(3,3);
228 
229 
230  //now we must check the 4 created partitions of the domain.
231  //one has been collapsed, so we discard it and therefore save only one.
232  unsigned int partition_number=0; //
233  //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
234  //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.
235  bool found_empty_partition=false;
236  for (unsigned int i=0; i<4; i++) //i partition
237  {
238  unsigned int j_aux = i + 2;
239  if (j_aux>2) j_aux -= 3;
240  BoundedMatrix<int,3,2> partition_father_nodes;
242  if (i<3)
243  {
244  partition_father_nodes(0,0)=i;
245  partition_father_nodes(0,1)=i;
246  partition_father_nodes(1,0)=aux_nodes_father_nodes(i,0); //we are using i aux node
247  partition_father_nodes(1,1)=aux_nodes_father_nodes(i,1); //we are using i aux node
248  partition_father_nodes(2,0)=aux_nodes_father_nodes(j_aux,0); //we are using j_aux node
249  partition_father_nodes(2,1)=aux_nodes_father_nodes(j_aux,1); //we are using j_aux node
250 
251  coord_subdomain(0,0)=rPoints(i,0);
252  coord_subdomain(0,1)=rPoints(i,1);
253  coord_subdomain(1,0)=aux_points(i,0);
254  coord_subdomain(1,1)=aux_points(i,1);
255  coord_subdomain(2,0)=aux_points(j_aux,0);
256  coord_subdomain(2,1)=aux_points(j_aux,1);
257  }
258  else
259  {
260  //the last partition, made by the 3 aux nodes.
261  partition_father_nodes=aux_nodes_father_nodes;
262  coord_subdomain=aux_points;
263  //found_last_partition=true;
264  }
265  //calculate data of this partition
266  double temp_area;
267  CalculateGeometryData(coord_subdomain, DN_DX_subdomain, temp_area);
268  if (temp_area > 1.0e-20) //ok, it does not have zero area
269  {
270  rVolumes(partition_number)=temp_area;
271  //we look for the gauss point of the partition:
272  double x_GP_partition = one_third * ( coord_subdomain(0,0) + coord_subdomain(1,0) + coord_subdomain(2,0) );
273  double y_GP_partition = one_third * ( coord_subdomain(0,1) + coord_subdomain(1,1) + coord_subdomain(2,1) );
274  double z_GP_partition = 0.0;
275  //we reset the coord_subdomain matrix so that we have the whole element again:
276  coord_subdomain = rPoints;
277  //and we calculate its shape function values
278  CalculatePosition ( coord_subdomain , x_GP_partition ,y_GP_partition ,z_GP_partition , N);
279  //we check the partition sign.
280  const double partition_sign = (N(0)*rDistances(0) + N(1)*rDistances(1) + N(2)*rDistances(2))/fabs(N(0)*rDistances(0) + N(1)*rDistances(1) + N(2)*rDistances(2));
281  //rPartitionsSign(partition_number)=partition_sign;
282 
283  rGPShapeFunctionValues(partition_number,0)=N(0);
284  rGPShapeFunctionValues(partition_number,1)=N(1);
285  rGPShapeFunctionValues(partition_number,2)=N(2);
286 
287  //compute enriched shape function values
288  double dist = 0.0;
289  double abs_dist = 0.0;
290  for (int j = 0; j < 3; j++)
291  {
292  dist += rGPShapeFunctionValues(partition_number, j) * exact_distance[j];
293  abs_dist += rGPShapeFunctionValues(partition_number, j) * abs_distance[j];
294  }
295 
296  if (partition_sign < 0.0)
297  rPartitionsSign[partition_number] = -1.0;
298  else
299  rPartitionsSign[partition_number] = 1.0;
300 
301  //enrichment for the gradient (continuous pressure, discontinuous gradient. Coppola-Codina enrichment
302  NEnriched(partition_number, 0) = 0.5/max_aux_dist_on_cut * (abs_dist - rPartitionsSign[partition_number] * dist);
303  for (int j = 0; j < 2; j++)
304  {
305  rGradientsValue[partition_number](0, j) = (0.5/max_aux_dist_on_cut) * (abs_distance_gradient[j] - rPartitionsSign[partition_number] * exact_distance_gradient[j]);
306  }
307 
308  //enrichment to add a constant discontinuity along the interfase.
309  if (rPartitionsSign[partition_number]*most_common_sign > 0.0) //on this side we will copy the standard shape functions. (maybe we change the sign, but keeping the sign
310  {
311  NEnriched(partition_number, 1) = -1.0*rPartitionsSign[partition_number]*NEnriched(partition_number, 0) ;
312  for (int j = 0; j < 2; j++)
313  {
314  rGradientsValue[partition_number](1, j) = -1.0*rPartitionsSign[partition_number]*rGradientsValue[partition_number](0, j);
315  }
316  }
317  else //we have to construct the shape function to guarantee a constant jump to 2:
318  {
319  //notice that the partition to be changed must one the subdomains created with a real node. so the i index is also the real node. (used 4 lines below to recover the distance.
320 
321  NEnriched(partition_number, 1) = rPartitionsSign[partition_number]*( 1.0*NEnriched(partition_number, 0) - 0.6666666666666666666666666666 ) ;
322  for (int j = 0; j < 2; j++)
323  {
324  rGradientsValue[partition_number](1, j) = (rPartitionsSign[partition_number]*1.0*rGradientsValue[partition_number](0, j) - exact_distance_gradient[j]*1.0/(abs_distance[i]));
325  }
326 
327  }
328 
329 
330  partition_number++;
331 
332  }
333  else
334  found_empty_partition=true;
335 
336  }
337  if (found_empty_partition==false)
338  KRATOS_WATCH("WROOOONGGGGGGGGGGG");
339 
340  // finally the interfase:
341  if (cut_edges[0])
342  {
343  if (cut_edges[1])
344  {
345  InterfaseArea = sqrt(pow(aux_points(0,0)-aux_points(1,0),2)+pow(aux_points(0,1)-aux_points(1,1),2));
346  base_point[0] = (aux_points(0,0)+aux_points(1,0))*0.5;
347  base_point[1] = (aux_points(0,1)+aux_points(1,1))*0.5;
348  CalculatePosition ( rPoints , base_point[0] ,base_point[1] , 0.0 , rGPShapeFunctionValues_in_interfase);
349  double abs_dist_on_interfase = 0.0;
350  for (int j = 0; j < 3; j++)
351  abs_dist_on_interfase += rGPShapeFunctionValues_in_interfase ( j) * abs_distance[j];
352  NEnriched_in_interfase(0) = 0.5/max_aux_dist_on_cut * abs_dist_on_interfase;
353  }
354  else
355  {
356  InterfaseArea= sqrt(pow(aux_points(0,0)-aux_points(2,0),2)+pow(aux_points(0,1)-aux_points(2,1),2));
357  base_point[0] = (aux_points(0,0)+aux_points(2,0))*0.5;
358  base_point[1] = (aux_points(0,1)+aux_points(2,1))*0.5;
359  CalculatePosition ( rPoints , base_point[0] ,base_point[1] , 0.0 , rGPShapeFunctionValues_in_interfase);
360  double abs_dist_on_interfase = 0.0;
361  for (int j = 0; j < 3; j++)
362  abs_dist_on_interfase += rGPShapeFunctionValues_in_interfase ( j) * abs_distance[j];
363  NEnriched_in_interfase(0) = 0.5/max_aux_dist_on_cut * abs_dist_on_interfase;
364  }
365  }
366  else
367  {
368  InterfaseArea= sqrt(pow(aux_points(2,0)-aux_points(1,0),2)+pow(aux_points(2,1)-aux_points(1,1),2));
369  base_point[0] = (aux_points(2,0)+aux_points(1,0))*0.5;
370  base_point[1] = (aux_points(2,1)+aux_points(1,1))*0.5;
371  CalculatePosition ( rPoints , base_point[0] ,base_point[1] , 0.0 , rGPShapeFunctionValues_in_interfase);
372  double abs_dist_on_interfase = 0.0;
373  for (int j = 0; j < 3; j++)
374  abs_dist_on_interfase += rGPShapeFunctionValues_in_interfase ( j) * abs_distance[j];
375  NEnriched_in_interfase(0) = 0.5/max_aux_dist_on_cut * abs_dist_on_interfase;
376  }
377 
378 
379  //KRATOS_WATCH(NEnriched)
380  return 3;
381  KRATOS_CATCH("");
382 
383  }
384 
385 
386  static int CalculateEnrichedShapeFuncionsExtendedmodified(BoundedMatrix<double,(2+1), 2 >& rPoints, BoundedMatrix<double, (2+1), 2 >& DN_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), (5)>& NEnriched,BoundedMatrix<double,10, 2>& rGradientpositive,BoundedMatrix<double,10, 2>& rGradientnegative ,BoundedMatrix<int,3,3>& father_nodes)
387  {
388  KRATOS_TRY
389 
390  const double one_third=1.0/3.0;
391  BoundedMatrix<double,3,2> aux_points; //for auxiliary nodes 4(between 1 and 2) ,5(between 2 and 3) ,6 (between 3 and 1)
392  BoundedMatrix<double, 3, 2 > coord_subdomain; //used to pass arguments when we must calculate areas, shape functions, etc
393  BoundedMatrix<double,3,2> DN_DX_subdomain; //used to retrieve derivatives
394 
395  double most_common_sign=0; //the side of the cut in which two nodes are found (same sign) will be the ones that remains unchanged when builing the discontinuity
396  double Area;//area of the complete element
397  rGPShapeFunctionValues(0,0)=one_third; rGPShapeFunctionValues(0,1)=one_third; rGPShapeFunctionValues(0,2)=one_third; //default, when no interfase has been found
398  Area = CalculateVolume2D( rPoints );
399  array_1d<bool,3> cut_edges;
400  array_1d<double,3> aux_nodes_relative_locations;
401  BoundedMatrix<int,3,2> aux_nodes_father_nodes;
402 
403  //to begin with we must check whether our element is cut or not by the interfase.
404  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
405  {
406  rVolumes(0)=Area;
407  rGPShapeFunctionValues(0,0)=one_third; rGPShapeFunctionValues(0,1)=one_third; rGPShapeFunctionValues(0,2)=one_third;
408  NEnriched(0,0) = 0.0;
409  //type_of_cut=1;
410  for (int j = 0; j < 2; j++)
411  rGradientsValue[0](0, j) = 0.0;
412  if (rDistances(0) < 0.0) rPartitionsSign[0] = -1.0;
413  else rPartitionsSign[0] = 1.0;
414  return 1;
415  }
416 
417  //else //we must create the enrichement, it can be in 2 or 3 parts. we'll start with 3 always.
418 
419  //'TRICK' TO AVOID HAVING THE INTERFASE TOO CLOSE TO THE NODES:
420  //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.
421  const double unsigned_distance0=fabs(rDistances(0));
422  const double unsigned_distance1=fabs(rDistances(1));
423  const double unsigned_distance2=fabs(rDistances(2));
424  //we begin by finding the largest distance:
425  double longest_distance=fabs(unsigned_distance0);
426  if (unsigned_distance1>longest_distance)
427  longest_distance=unsigned_distance1;
428  if (unsigned_distance2>longest_distance)
429  longest_distance=unsigned_distance2;
430  //Now we set a maximum relative distance
431  //const double tolerable_distance =longest_distance*0.001;// 0.001 // (1/1,000,000 seems to have good results)
432  //and now we check if a distance is too small:
433 
434  //END OF TRICK. REMEMBER TO OVERWRITE THE DISTANCE VARIABLE IN THE ELEMENT IN CASE THESE LINES HAVE MODIFIED THEM (distances)
435 
436 
437  //const double epsilon = 1e-15; //1.00e-9;
438  //compute the gradient of the distance and normalize it
439  array_1d<double, 2 > grad_d;
440  noalias(grad_d) = prod(trans(DN_DX), rDistances);
441 
442 
443  array_1d<double, 3> exact_distance = rDistances;
444  array_1d<double, 3> abs_distance = ZeroVector(3);
445 
446  //KRATOS_WATCH("one element IS in the intefase")
447  if ((rDistances(0)*rDistances(1))<0.0) //edge 12 is cut
448  cut_edges[0]=true;
449  else
450  cut_edges[0]=false;
451  if ((rDistances(1)*rDistances(2))<0.0) //edge 23 is cut.
452  cut_edges[1]=true;
453  else
454  cut_edges[1]=false;
455  if ((rDistances(2)*rDistances(0))<0.0) //edge 23 is cut.
456  cut_edges[2]=true;
457  else
458  cut_edges[2]=false;
459 
460  //We have 3 edges, meaning we created 3 aux nodes. But one of them actually matches the position of a real node (the one that is not on an interface edge is displaced to one of the ends (a node)
461  //the new shape functions are built by setting the values in all (real and aux) nodes to zero except in one of the interphase nodes. in the array aux_node_shape_function_index we assign this value
462  array_1d<int, 3 > aux_node_enrichment_shape_function_index; //when not used, it must be -1;
463 
464  int shape_function_id=0;
465  father_nodes(0,0)=-1;
466  father_nodes(0,1)=-1;
467  father_nodes(0,2)=-1;
468  father_nodes(1,0)=-1;
469  father_nodes(1,1)=-1;
470  father_nodes(1,2)=-1;
471  father_nodes(2,0)=-1;
472  father_nodes(2,1)=-1;
473  father_nodes(2,2)=-1;
474 
475  //KRATOS_WATCH(father_nodes);
476  for (unsigned int i=0; i<3; i++) //we go over the 3 edges:
477  {
478  int edge_begin_node=i;
479  int edge_end_node=i+1;
480  if (edge_end_node==3) edge_end_node=0; //it's a triangle, so node 3 is actually node 0
481 
482  if(cut_edges(i)==true)
483  {
484  aux_nodes_relative_locations(i)=fabs(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)
485  //KRATOS_WATCH(aux_nodes_relative_locations(i));
486 
487  aux_nodes_father_nodes(i,0)=edge_begin_node;
488  aux_nodes_father_nodes(i,1)=edge_end_node;
489 
490  aux_node_enrichment_shape_function_index(i)=shape_function_id;
491  father_nodes(i,0)=edge_begin_node;
492  father_nodes(i,1)=edge_end_node;
493  father_nodes(i,2)=shape_function_id;
494  shape_function_id++;
495 
496  }
497  else
498  {//<
499  if(fabs(rDistances(edge_end_node))<fabs(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
500  {
501  aux_nodes_relative_locations(i)=0.0;
502  aux_nodes_father_nodes(i,0)=edge_end_node;
503  aux_nodes_father_nodes(i,1)=edge_end_node;
504  }
505  else
506  {
507  aux_nodes_relative_locations(i)=1.0;
508  aux_nodes_father_nodes(i,0)=edge_begin_node;
509  aux_nodes_father_nodes(i,1)=edge_begin_node;
510  }
511  //KRATOS_WATCH("compileddd");
512  aux_node_enrichment_shape_function_index(i)=-1;
513  }
514 
515  //and we save the coordinate of the new aux nodes:
516  for (unsigned int j=0;j<2;j++){ //x,y coordinates
517  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));
518  }
519  }
520 
521 
522  array_1d<double,2> base_point;
523  if (cut_edges(0)==true) // it means it is a cut edge, if it was 0.0 or 1.0 then it would be an uncut edge
524  {
525  base_point[0] = aux_points(0,0);
526  base_point[1] = aux_points(0,1);
527  }
528  else //it means aux_point 0 is a clone of other point, so we go to the second edge.
529  {
530  base_point[0] = aux_points(1,0);
531  base_point[1] = aux_points(1,1);
532  }
533 
534  for (int i_node = 0; i_node < 3; i_node++)
535  {
536  double d = (rPoints(i_node,0) - base_point[0]) * grad_d[0] + (rPoints(i_node,1) - base_point[1]) * grad_d[1] ;
537  abs_distance[i_node] = fabs(d);
538  }
539 
540  //assign correct sign to exact distance
541  for (int i = 0; i < 3; i++)
542  {
543  if (rDistances[i] < 0.0)
544  {
545  exact_distance[i] = -abs_distance[i];
546  --most_common_sign;
547  }
548  else
549  {
550  exact_distance[i] = abs_distance[i];
551  ++most_common_sign;
552  }
553  }
554 
555  //compute exact distance gradients
556  array_1d<double, 2 > exact_distance_gradient;
557  noalias(exact_distance_gradient) = prod(trans(DN_DX), exact_distance);
558 
559  array_1d<double, 2 > abs_distance_gradient;
560  noalias(abs_distance_gradient) = prod(trans(DN_DX), abs_distance);
561 
562 
563  double max_aux_dist_on_cut = -1;
564  for (int edge = 0; edge < 3; edge++)
565  {
566  const int i = edge;
567  int j = edge+1;
568  if (j==3) j=0;
569  if (rDistances[i] * rDistances[j] < 0.0)
570  {
571  const double tmp = fabs(rDistances[i]) / (fabs(rDistances[i]) + fabs(rDistances[j]));
572  //compute the position of the edge node
573  double abs_dist_on_cut = abs_distance[i] * tmp + abs_distance[j] * (1.00 - tmp);
574  if(abs_dist_on_cut > max_aux_dist_on_cut) max_aux_dist_on_cut = abs_dist_on_cut;
575  }
576  }
577  //we reset all data:
578  rGradientsValue[0]=ZeroMatrix(5,2);
579  rGradientsValue[1]=ZeroMatrix(5,2);
580  rGradientsValue[2]=ZeroMatrix(5,2);
581 
582  NEnriched=ZeroMatrix(3,5);
583  rGPShapeFunctionValues=ZeroMatrix(3,3);
584 
585 
586  //now we must check the 4 created partitions of the domain.
587  //one has been collapsed, so we discard it and therefore save only one.
588  unsigned int partition_number=0; //
589  //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
590  //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.
591  bool found_empty_partition=false;
592 
593  //the enrichment is directly the shape functions created by using the partition.
594  //we have to save for the enrichment 0 and 1 which is the node that will be active, that is, whose shape function value is zero (for some partitions all 3 shape functions are inactive)
595 
596 
597 
598  for (int i=0; i<4; i++) //i partition
599  {
600 
601  array_1d<int, 2 > active_node_in_enrichment_shape_function;
602  active_node_in_enrichment_shape_function(0)=-1; active_node_in_enrichment_shape_function(1)=-1; //initialized as if all are inactive -> gradient=0;
603  //the same but for the replacement shape functions
604  array_1d<int, 3 > active_node_in_replacement_shape_function;
605  active_node_in_replacement_shape_function(0)=-1; active_node_in_replacement_shape_function(1)=-1; active_node_in_replacement_shape_function(2)=-1; //initialized as if all are inactive -> gradient=0;
606 
607  int j_aux = i + 2;
608  if (j_aux>2) j_aux -= 3;
609  BoundedMatrix<int,3,2> partition_father_nodes;
610  array_1d<double,3> N; //bool useful=false;
611 
612  int useful_node_for_N0star=-1;
613  int useful_node_for_N1star=-1;
614 
615  if (i<3)
616  {
617  partition_father_nodes(0,0)=i;
618  partition_father_nodes(0,1)=i;
619  partition_father_nodes(1,0)=aux_nodes_father_nodes(i,0); //we are using i aux node
620  partition_father_nodes(1,1)=aux_nodes_father_nodes(i,1); //we are using i aux node
621  partition_father_nodes(2,0)=aux_nodes_father_nodes(j_aux,0); //we are using j_aux node
622  partition_father_nodes(2,1)=aux_nodes_father_nodes(j_aux,1); //we are using j_aux node
623 
624  coord_subdomain(0,0)=rPoints(i,0);
625  coord_subdomain(0,1)=rPoints(i,1);
626  coord_subdomain(1,0)=aux_points(i,0);
627  coord_subdomain(1,1)=aux_points(i,1);
628  coord_subdomain(2,0)=aux_points(j_aux,0);
629  coord_subdomain(2,1)=aux_points(j_aux,1);
630 
631  //KRATOS_WATCH(coord_subdomain)
632  //notice that local nodes 2 and 3 and the possible candidates, with indexes i and j_aux:
633  if (aux_node_enrichment_shape_function_index(i)> -1) //that is, local node 2 it is a useful node:
634  active_node_in_enrichment_shape_function( aux_node_enrichment_shape_function_index(i) )=1; //saving that local node 2 will be active for either enrichment 1 or 2.
635  // else we do nothing, we are not saving this node and the -1 stays
636 
637  //now the same for the local node 3 (j_aux)
638  if (aux_node_enrichment_shape_function_index(j_aux)> -1) //that is, local node 3 it is a useful node:
639  active_node_in_enrichment_shape_function( aux_node_enrichment_shape_function_index(j_aux) )=2; //saving that local node 3 will be active for either enrichment 1 or 2.
640  // else we do nothing, we are not saving this node and the -1 stays
641 
642  active_node_in_replacement_shape_function(i)=0; //standard shape function i will be replaced by the one of local subelement node 1
643  //now local nodes 2 and 3
644  if (aux_nodes_father_nodes(i,0)==aux_nodes_father_nodes(i,1))
645  active_node_in_replacement_shape_function(aux_nodes_father_nodes(i,0))=1;
646  if (aux_nodes_father_nodes(j_aux,0)==aux_nodes_father_nodes(j_aux,1))
647  active_node_in_replacement_shape_function(aux_nodes_father_nodes(j_aux,0))=2;
648  // if( (aux_nodes_father_nodes(i,0)!=aux_nodes_father_nodes(i,1)) && (aux_nodes_father_nodes(j_aux,0)!=aux_nodes_father_nodes(j_aux,1)))
649  //{
650  // useful=true;
651  //}
652 
653  coord_subdomain(0,0)=rPoints(i,0);
654  coord_subdomain(0,1)=rPoints(i,1);
655  coord_subdomain(1,0)=aux_points(i,0);
656  coord_subdomain(1,1)=aux_points(i,1);
657  coord_subdomain(2,0)=aux_points(j_aux,0);
658  coord_subdomain(2,1)=aux_points(j_aux,1);
659 
660  //an aux_node is useful when one of its father nodes is the real node of the subelement. that means that the edge is part of the subelement.
661  if(partition_father_nodes(1,0)==i || partition_father_nodes(1,1)==i) //if one of the father nodes of node_aux_i is equal to the real node i
662  {
663  if(aux_node_enrichment_shape_function_index(i)==0)
664  useful_node_for_N0star=1;
665  if(aux_node_enrichment_shape_function_index(i)==1)
666  useful_node_for_N1star=1;
667  }
668  if(partition_father_nodes(2,0)==j_aux || partition_father_nodes(2,1)==j_aux) //if one of the father nodes of node_aux_i is equal to the real node i
669  {
670  if(aux_node_enrichment_shape_function_index(j_aux)==0)
671  useful_node_for_N0star=2;
672  if(aux_node_enrichment_shape_function_index(j_aux)==1)
673  useful_node_for_N1star=2;
674  }
675  }
676  else
677  {
678  partition_father_nodes=aux_nodes_father_nodes;
679  coord_subdomain=aux_points;
680  //useful=true;
681  //int non_aux_node=-1; //one of the nodes of this partition is actually a real node, which has repeated father node
682  int non_aux_node_father_node=-1; //the real node id
683  //we have to check the 3 of them:
684  for (int j = 0; j < 3; j++)
685  {
686  if(partition_father_nodes(j,0)==partition_father_nodes(j,1))
687  {
688  //non_aux_node=j;
689  non_aux_node_father_node=partition_father_nodes(j,0);
690  }
691  }
692  for (int j = 0; j < 3; j++)
693  {
694  if (aux_node_enrichment_shape_function_index(j)> -1) //that is, local node j it is a useful node:
695  {
696  active_node_in_enrichment_shape_function( aux_node_enrichment_shape_function_index(j) ) = j;
697 
698  if(partition_father_nodes(j,0)==non_aux_node_father_node || partition_father_nodes(j,1)==non_aux_node_father_node)
699  {
700  if (aux_node_enrichment_shape_function_index(j)==0)
701  useful_node_for_N0star=j;
702  if (aux_node_enrichment_shape_function_index(j)==1)
703  useful_node_for_N1star=j;
704  }
705  }
706  //to replace the standard shape functions:
707  if (aux_nodes_father_nodes(j,0)==aux_nodes_father_nodes(j,1))
708  active_node_in_replacement_shape_function(aux_nodes_father_nodes(j,0))=j;
709  }
710  //found_last_partition=true;
711  }
712  //calculate data of this partition
713  double temp_area;
714  CalculateGeometryData(coord_subdomain, DN_DX_subdomain, temp_area);
715  if (temp_area > 1.0e-20) //ok, it does not have zero area
716  {
717  //KRATOS_ERROR(std::logic_error, "method not implemented", "");
718  rVolumes(partition_number)=temp_area;
719  //we look for the gauss point of the partition:
720  double x_GP_partition = one_third * ( coord_subdomain(0,0) + coord_subdomain(1,0) + coord_subdomain(2,0) );
721  double y_GP_partition = one_third * ( coord_subdomain(0,1) + coord_subdomain(1,1) + coord_subdomain(2,1) );
722  double z_GP_partition = 0.0;
723  //we reset the coord_subdomain matrix so that we have the whole element again:
724  coord_subdomain = rPoints;
725  //and we calculate its shape function values
726  CalculatePosition ( coord_subdomain , x_GP_partition ,y_GP_partition ,z_GP_partition , N);
727  //we check the partition sign.
728  const double partition_sign = (N(0)*rDistances(0) + N(1)*rDistances(1) + N(2)*rDistances(2))/fabs(N(0)*rDistances(0) + N(1)*rDistances(1) + N(2)*rDistances(2));
729  //rPartitionsSign(partition_number)=partition_sign;
730 
731  rGPShapeFunctionValues(partition_number,0)=N(0);
732  rGPShapeFunctionValues(partition_number,1)=N(1);
733  rGPShapeFunctionValues(partition_number,2)=N(2);
734 
735  //compute enriched shape function values
736  double dist = 0.0;
737  double abs_dist = 0.0;
738  for (int j = 0; j < 3; j++)
739  {
740  dist += rGPShapeFunctionValues(partition_number, j) * exact_distance[j];
741  abs_dist += rGPShapeFunctionValues(partition_number, j) * abs_distance[j];
742  }
743 
744  if (partition_sign < 0.0)
745  rPartitionsSign[partition_number] = -1.0;
746  else
747  rPartitionsSign[partition_number] = 1.0;
748 
749  //We use the sublement shape functions and derivatives:
750  //we loop the 2 enrichment shape functions:
751  for (int index_shape_function = 0; index_shape_function < 2; index_shape_function++) //enrichment shape function
752  {
753  if (active_node_in_enrichment_shape_function(index_shape_function) > -1) //recall some of them are inactive:
754  {
755  NEnriched(partition_number, index_shape_function+3 ) = one_third ; //only one gauss point. if more were to be used, it would still be simple (1/2,1/2,0);(0,1/2,1/2);(1/2,0,1/2);
756  for (int j = 0; j < 2; j++) //x,y,(z)
757  {
758  rGradientsValue[partition_number](index_shape_function+3, j) = DN_DX_subdomain(active_node_in_enrichment_shape_function(index_shape_function),j);
759  }
760 
761  }
762  else
763  {
764  NEnriched(partition_number, index_shape_function+3 ) = 0.0;
765  for (int j = 0; j < 2; j++) //x,y,(z)
766  {
767  rGradientsValue[partition_number](index_shape_function+3, j) = 0.0;
768  }
769  }
770 
771  }
772 
773  array_1d<int,(2+1)> replacement_shape_function_nodes = ZeroVector(3);
774  for (int index_shape_function = 0; index_shape_function < 3; index_shape_function++) //replacement shape function
775  {
776  int active_node=-1;
777  for (int j = 0; j < 3; j++) //number_of_nodes in the subelement
778  if (partition_father_nodes(j,0)==index_shape_function && partition_father_nodes(j,1)==index_shape_function)
779  {
780  active_node=j;
781  break;
782  }
783  if(active_node> -1)
784  {
785  for (int j = 0; j < 2; j++) //x,y,(z)
786  rGradientsValue[partition_number](index_shape_function, j) = DN_DX_subdomain(active_node,j);
787  NEnriched(partition_number, index_shape_function ) = one_third;
788  replacement_shape_function_nodes(index_shape_function) = active_node;
789  }
790  else
791  {
792  for (int j = 0; j < 2; j++) //x,y,(z)
793  rGradientsValue[partition_number](index_shape_function, j) = 0.0;
794  replacement_shape_function_nodes(index_shape_function) = -1;
795  }
796  }
797 
798  //We use the sublement shape functions and derivatives:
799  //we loop the 3 replacement shape functions:
800  unsigned int number_of_real_nodes=0; //(each partition can have either 1 or 2);
801  for (int index_shape_function = 0; index_shape_function < 3; index_shape_function++) //enrichment shape function
802  {
803  if (active_node_in_replacement_shape_function(index_shape_function) > -1) //recall some of them are inactive:
804  number_of_real_nodes++;
805  }
806 
807  if(useful_node_for_N0star > -1)
808  {
809  for (int j = 0; j < 2; j++) //x,y,(z)
810  {
811  if(partition_sign>0)
812  {
813  //first two rows are for the side where N*1 = 1
814  //row 1 is for gradN*1
815  rGradientpositive(3, j)=DN_DX_subdomain(useful_node_for_N0star, j);
816  //row 2 is for gradN*2
817  if (active_node_in_enrichment_shape_function(1) > -1)
818  rGradientpositive(4, j)=DN_DX_subdomain(active_node_in_enrichment_shape_function(1), j);
819 
820  for (int index_shape_function = 0; index_shape_function < 3; index_shape_function++) //replacement shape function
821  {
822  if(replacement_shape_function_nodes(index_shape_function)>-1)
823  {
824  rGradientpositive(index_shape_function, j) = DN_DX_subdomain(replacement_shape_function_nodes(index_shape_function), j);
825  }
826  }
827  }
828  else
829  {
830  rGradientnegative(3, j) =DN_DX_subdomain(useful_node_for_N0star, j);
831  if (active_node_in_enrichment_shape_function(1) > -1)
832  rGradientnegative(4, j) =DN_DX_subdomain(active_node_in_enrichment_shape_function(1), j);
833 
834  for (int index_shape_function = 0; index_shape_function < 3; index_shape_function++) //replacement shape function
835  {
836  if(replacement_shape_function_nodes(index_shape_function)>-1)
837  {
838  rGradientnegative(index_shape_function, j) = DN_DX_subdomain(replacement_shape_function_nodes(index_shape_function), j);
839  }
840  }
841  }
842  }
843  }
844  if(useful_node_for_N1star > -1)
845  {
846  for (int j = 0; j < 2; j++) //x,y,(z)
847  {
848  if(partition_sign>0)
849  {
850  //rows 3 and 4 are for the side where N*2 = 1
851  //row 4 is for gradN*2
852  rGradientpositive(9, j)=DN_DX_subdomain(useful_node_for_N1star, j);
853  //row 3 is for gradN*1
854  if (active_node_in_enrichment_shape_function(0) > -1)
855  rGradientpositive(8, j)=DN_DX_subdomain(active_node_in_enrichment_shape_function(0), j);
856 
857  for (int index_shape_function = 0; index_shape_function < 3; index_shape_function++) //replacement shape function
858  {
859  if(replacement_shape_function_nodes(index_shape_function)>-1)
860  {
861  rGradientpositive(index_shape_function+5, j) = DN_DX_subdomain(replacement_shape_function_nodes(index_shape_function), j);
862  }
863  }
864  }
865  else
866  {
867  rGradientnegative(9, j)=DN_DX_subdomain(useful_node_for_N1star, j);
868  if(active_node_in_enrichment_shape_function(0) > -1)
869  rGradientnegative(8, j)=DN_DX_subdomain(active_node_in_enrichment_shape_function(0), j);
870 
871  for (int index_shape_function = 0; index_shape_function < 3; index_shape_function++) //replacement shape function
872  {
873  if(replacement_shape_function_nodes(index_shape_function)>-1)
874  {
875  rGradientnegative(index_shape_function+5, j) = DN_DX_subdomain(replacement_shape_function_nodes(index_shape_function), j);
876  }
877  }
878  }
879  }
880  }
881 
882  partition_number++;
883 
884  }
885  else
886  found_empty_partition=true;
887  }
888  if (found_empty_partition==false)
889  KRATOS_WATCH("WROOOONGGGGGGGGGGG");
890 
891  //KRATOS_WATCH(NEnriched)
892  return 3;
893  KRATOS_CATCH("");
894 
895  }
896 
897 
898  //2D: 2 enrichment functions for capturing weak discontinities. All the shape functions follow the criteria of Partition of Unity.
899  static int CalculateEnrichedShapeFuncionsExtendedmodified_gausspoints(Geometry< Node >& trianglegeom,BoundedMatrix<double,(2+1), 2 >& rPoints, BoundedMatrix<double, (2+1), 2 >& DN_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), (5)>& NEnriched,BoundedMatrix<double,10, 2>& rGradientpositive,BoundedMatrix<double,10, 2>& rGradientnegative ,BoundedMatrix<int,3,3>& father_nodes,std::vector<Matrix>& PRUEBA, array_1d<double,6>& weight)
900  {
901  KRATOS_TRY
902 
903  const double one_third=1.0/3.0;
904  BoundedMatrix<double,3,2> aux_points; //for auxiliary nodes 4(between 1 and 2) ,5(between 2 and 3) ,6 (between 3 and 1)
905  BoundedMatrix<double, 3, 2 > coord_subdomain; //used to pass arguments when we must calculate areas, shape functions, etc
906  BoundedMatrix<double, 3, 2 > coord_subdomain_aux;
907  BoundedMatrix<double,3,2> DN_DX_subdomain; //used to retrieve derivatives
908 
909  double most_common_sign=0; //the side of the cut in which two nodes are found (same sign) will be the ones that remains unchanged when builing the discontinuity
910  double Area;//area of the complete element
911  rGPShapeFunctionValues(0,0)=one_third; rGPShapeFunctionValues(0,1)=one_third; rGPShapeFunctionValues(0,2)=one_third; //default, when no interfase has been found
912  Area = CalculateVolume2D( rPoints );
913  array_1d<bool,3> cut_edges;
914  array_1d<double,3> aux_nodes_relative_locations;
915  BoundedMatrix<int,3,2> aux_nodes_father_nodes;
916  BoundedMatrix<double,3,2> DN_DX_subdomainaux_1aux; //used to retrieve derivatives
917 
918  //to begin with we must check whether our element is cut or not by the interfase.
919  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
920  {
921  rVolumes(0)=Area;
922  rGPShapeFunctionValues(0,0)=one_third; rGPShapeFunctionValues(0,1)=one_third; rGPShapeFunctionValues(0,2)=one_third;
923  NEnriched(0,0) = 0.0;
924  //type_of_cut=1;
925  for (int j = 0; j < 2; j++)
926  rGradientsValue[0](0, j) = 0.0;
927  if (rDistances(0) < 0.0) rPartitionsSign[0] = -1.0;
928  else rPartitionsSign[0] = 1.0;
929  //KRATOS_WATCH("one element not in the intefase")
930  return 1;
931  }
932 
933  const double unsigned_distance0=fabs(rDistances(0));
934  const double unsigned_distance1=fabs(rDistances(1));
935  const double unsigned_distance2=fabs(rDistances(2));
936  //we begin by finding the largest distance:
937  double longest_distance=fabs(unsigned_distance0);
938  if (unsigned_distance1>longest_distance)
939  longest_distance=unsigned_distance1;
940  if (unsigned_distance2>longest_distance)
941  longest_distance=unsigned_distance2;
942  //Now we set a maximum relative distance
943  //const double tolerable_distance =longest_distance*0.001;// 0.001 // (1/1,000,000 seems to have good results)
944 
945  //const double epsilon = 1e-15; //1.00e-9;
946  //compute the gradient of the distance and normalize it
947  array_1d<double, 2 > grad_d;
948  noalias(grad_d) = prod(trans(DN_DX), rDistances);
949 
950  array_1d<double, 3> exact_distance = rDistances;
951  array_1d<double, 3> abs_distance = ZeroVector(3);
952 
953 
954  if ((rDistances(0)*rDistances(1))<0.0) //edge 12 is cut
955  cut_edges[0]=true;
956  else
957  cut_edges[0]=false;
958  if ((rDistances(1)*rDistances(2))<0.0) //edge 23 is cut.
959  cut_edges[1]=true;
960  else
961  cut_edges[1]=false;
962  if ((rDistances(2)*rDistances(0))<0.0) //edge 23 is cut.
963  cut_edges[2]=true;
964  else
965  cut_edges[2]=false;
966 
967  //We have 3 edges, meaning we created 3 aux nodes. But one of them actually matches the position of a real node (the one that is not on an interface edge is displaced to one of the ends (a node)
968  //the new shape functions are built by setting the values in all (real and aux) nodes to zero except in one of the interphase nodes. in the array aux_node_shape_function_index we assign this value
969  array_1d<int, 3 > aux_node_enrichment_shape_function_index; //when not used, it must be -1;
970 
971  int shape_function_id=0;
972  father_nodes(0,0)=-1;
973  father_nodes(0,1)=-1;
974  father_nodes(0,2)=-1;
975  father_nodes(1,0)=-1;
976  father_nodes(1,1)=-1;
977  father_nodes(1,2)=-1;
978  father_nodes(2,0)=-1;
979  father_nodes(2,1)=-1;
980  father_nodes(2,2)=-1;
981 
982  //KRATOS_WATCH(father_nodes);
983  for (unsigned int i=0; i<3; i++) //we go over the 3 edges:
984  {
985  int edge_begin_node=i;
986  int edge_end_node=i+1;
987  if (edge_end_node==3) edge_end_node=0; //it's a triangle, so node 3 is actually node 0
988 
989  if(cut_edges(i)==true)
990  {
991  aux_nodes_relative_locations(i)=fabs(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)
992 
993  aux_nodes_father_nodes(i,0)=edge_begin_node;
994  aux_nodes_father_nodes(i,1)=edge_end_node;
995  aux_node_enrichment_shape_function_index(i)=shape_function_id;
996  father_nodes(i,0)=edge_begin_node;
997  father_nodes(i,1)=edge_end_node;
998  father_nodes(i,2)=shape_function_id;
999  shape_function_id++;
1000 
1001 
1002  }
1003  else
1004  {//<
1005  if(fabs(rDistances(edge_end_node))<fabs(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
1006  {
1007  aux_nodes_relative_locations(i)=0.0;
1008  aux_nodes_father_nodes(i,0)=edge_end_node;
1009  aux_nodes_father_nodes(i,1)=edge_end_node;
1010  }
1011  else
1012  {
1013  aux_nodes_relative_locations(i)=1.0;
1014  aux_nodes_father_nodes(i,0)=edge_begin_node;
1015  aux_nodes_father_nodes(i,1)=edge_begin_node;
1016  }
1017  aux_node_enrichment_shape_function_index(i)=-1;
1018  }
1019 
1020  //and we save the coordinate of the new aux nodes:
1021  for (unsigned int j=0;j<2;j++){ //x,y coordinates
1022  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));
1023  }
1024  }
1025 
1026 
1027  array_1d<double,2> base_point;
1028  if (cut_edges(0)==true) // it means it is a cut edge, if it was 0.0 or 1.0 then it would be an uncut edge
1029  {
1030  base_point[0] = aux_points(0,0);
1031  base_point[1] = aux_points(0,1);
1032 
1033  }
1034  else //it means aux_point 0 is a clone of other point, so we go to the second edge.
1035  {
1036  base_point[0] = aux_points(1,0);
1037  base_point[1] = aux_points(1,1);
1038  }
1039 
1040  for (int i_node = 0; i_node < 3; i_node++)
1041  {
1042  double d = (rPoints(i_node,0) - base_point[0]) * grad_d[0] + (rPoints(i_node,1) - base_point[1]) * grad_d[1] ;
1043  abs_distance[i_node] = fabs(d);
1044  }
1045 
1046  //assign correct sign to exact distance
1047  for (int i = 0; i < 3; i++)
1048  {
1049  if (rDistances[i] < 0.0)
1050  {
1051  exact_distance[i] = -abs_distance[i];
1052  --most_common_sign;
1053  }
1054  else
1055  {
1056  exact_distance[i] = abs_distance[i];
1057  ++most_common_sign;
1058  }
1059  }
1060 
1061  //compute exact distance gradients
1062  array_1d<double, 2 > exact_distance_gradient;
1063  noalias(exact_distance_gradient) = prod(trans(DN_DX), exact_distance);
1064 
1065  array_1d<double, 2 > abs_distance_gradient;
1066  noalias(abs_distance_gradient) = prod(trans(DN_DX), abs_distance);
1067 
1068 
1069  double max_aux_dist_on_cut = -1;
1070  for (int edge = 0; edge < 3; edge++)
1071  {
1072  const int i = edge;
1073  int j = edge+1;
1074  if (j==3) j=0;
1075  if (rDistances[i] * rDistances[j] < 0.0)
1076  {
1077  const double tmp = fabs(rDistances[i]) / (fabs(rDistances[i]) + fabs(rDistances[j]));
1078  //compute the position of the edge node
1079  double abs_dist_on_cut = abs_distance[i] * tmp + abs_distance[j] * (1.00 - tmp);
1080  if(abs_dist_on_cut > max_aux_dist_on_cut) max_aux_dist_on_cut = abs_dist_on_cut;
1081  }
1082  }
1083  //we reset all data:
1084  rGradientsValue[0]=ZeroMatrix(5,2);
1085  rGradientsValue[1]=ZeroMatrix(5,2);
1086  rGradientsValue[2]=ZeroMatrix(5,2);
1087 
1088  NEnriched=ZeroMatrix(3,5);
1089  rGPShapeFunctionValues=ZeroMatrix(3,3);
1090 
1091  //now we must check the 4 created partitions of the domain.
1092  //one has been collapsed, so we discard it and therefore save only one.
1093  unsigned int partition_number=0; //
1094  //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
1095  //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.
1096  bool found_empty_partition=false;
1097 
1098  //the enrichment is directly the shape functions created by using the partition.
1099  //we have to save for the enrichment 0 and 1 which is the node that will be active, that is, whose shape function value is zero (for some partitions all 3 shape functions are inactive)
1100 
1101  for ( int i=0; i<4; i++) //i partition
1102  {
1103 
1104  array_1d<int, 2 > active_node_in_enrichment_shape_function;
1105  active_node_in_enrichment_shape_function(0)=-1; active_node_in_enrichment_shape_function(1)=-1; //initialized as if all are inactive -> gradient=0;
1106  //the same but for the replacement shape functions
1107  array_1d<int, 3 > active_node_in_replacement_shape_function;
1108  active_node_in_replacement_shape_function(0)=-1; active_node_in_replacement_shape_function(1)=-1; active_node_in_replacement_shape_function(2)=-1; //initialized as if all are inactive -> gradient=0;
1109 
1110  int j_aux = i + 2;
1111  if (j_aux>2) j_aux -= 3;
1112  BoundedMatrix<int,3,2> partition_father_nodes;
1113  array_1d<double,3> N; //bool useful=false;
1114 
1115  int useful_node_for_N0star=-1;
1116  int useful_node_for_N1star=-1;
1117 
1118  if (i<3)
1119  {
1120  partition_father_nodes(0,0)=i;
1121  partition_father_nodes(0,1)=i;
1122  partition_father_nodes(1,0)=aux_nodes_father_nodes(i,0); //we are using i aux node
1123  partition_father_nodes(1,1)=aux_nodes_father_nodes(i,1); //we are using i aux node
1124  partition_father_nodes(2,0)=aux_nodes_father_nodes(j_aux,0); //we are using j_aux node
1125  partition_father_nodes(2,1)=aux_nodes_father_nodes(j_aux,1); //we are using j_aux node
1126 
1127 
1128  coord_subdomain(0,0)=rPoints(i,0);
1129  coord_subdomain(0,1)=rPoints(i,1);
1130  coord_subdomain(1,0)=aux_points(i,0);
1131  coord_subdomain(1,1)=aux_points(i,1);
1132  coord_subdomain(2,0)=aux_points(j_aux,0);
1133  coord_subdomain(2,1)=aux_points(j_aux,1);
1134 
1135  //KRATOS_WATCH(coord_subdomain)
1136  //notice that local nodes 2 and 3 and the possible candidates, with indexes i and j_aux:
1137  if (aux_node_enrichment_shape_function_index(i)> -1) //that is, local node 2 it is a useful node:
1138  active_node_in_enrichment_shape_function( aux_node_enrichment_shape_function_index(i) )=1; //saving that local node 2 will be active for either enrichment 1 or 2.
1139  // else we do nothing, we are not saving this node and the -1 stays
1140 
1141  //now the same for the local node 3 (j_aux)
1142  if (aux_node_enrichment_shape_function_index(j_aux)> -1) //that is, local node 3 it is a useful node:
1143  active_node_in_enrichment_shape_function( aux_node_enrichment_shape_function_index(j_aux) )=2; //saving that local node 3 will be active for either enrichment 1 or 2.
1144  // else we do nothing, we are not saving this node and the -1 stays
1145 
1146  active_node_in_replacement_shape_function(i)=0; //standard shape function i will be replaced by the one of local subelement node 1
1147  //now local nodes 2 and 3
1148  if (aux_nodes_father_nodes(i,0)==aux_nodes_father_nodes(i,1))
1149  active_node_in_replacement_shape_function(aux_nodes_father_nodes(i,0))=1;
1150  if (aux_nodes_father_nodes(j_aux,0)==aux_nodes_father_nodes(j_aux,1))
1151  active_node_in_replacement_shape_function(aux_nodes_father_nodes(j_aux,0))=2;
1152  // if( (aux_nodes_father_nodes(i,0)!=aux_nodes_father_nodes(i,1)) && (aux_nodes_father_nodes(j_aux,0)!=aux_nodes_father_nodes(j_aux,1)))
1153  //{
1154  // useful=true;
1155  //}
1156 
1157  coord_subdomain(0,0)=rPoints(i,0);
1158  coord_subdomain(0,1)=rPoints(i,1);
1159  coord_subdomain(1,0)=aux_points(i,0);
1160  coord_subdomain(1,1)=aux_points(i,1);
1161  coord_subdomain(2,0)=aux_points(j_aux,0);
1162  coord_subdomain(2,1)=aux_points(j_aux,1);
1163 
1164 
1165  //an aux_node is useful when one of its father nodes is the real node of the subelement. that means that the edge is part of the subelement.
1166  if(partition_father_nodes(1,0)==i || partition_father_nodes(1,1)==i) //if one of the father nodes of node_aux_i is equal to the real node i
1167  {
1168  if(aux_node_enrichment_shape_function_index(i)==0)
1169  useful_node_for_N0star=1;
1170  if(aux_node_enrichment_shape_function_index(i)==1)
1171  useful_node_for_N1star=1;
1172  }
1173  if(partition_father_nodes(2,0)==j_aux || partition_father_nodes(2,1)==j_aux) //if one of the father nodes of node_aux_i is equal to the real node i
1174  {
1175  if(aux_node_enrichment_shape_function_index(j_aux)==0)
1176  useful_node_for_N0star=2;
1177  if(aux_node_enrichment_shape_function_index(j_aux)==1)
1178  useful_node_for_N1star=2;
1179  }
1180  }
1181  else
1182  {
1183  //the last partition, made by the 3 aux nodes.
1184  partition_father_nodes=aux_nodes_father_nodes;
1185  coord_subdomain=aux_points;
1186  //useful=true;
1187  //int non_aux_node=-1; //one of the nodes of this partition is actually a real node, which has repeated father node
1188  int non_aux_node_father_node=-1; //the real node id
1189  //we have to check the 3 of them:
1190  for (int j = 0; j < 3; j++)
1191  {
1192  if(partition_father_nodes(j,0)==partition_father_nodes(j,1))
1193  {
1194  //non_aux_node=j;
1195  non_aux_node_father_node=partition_father_nodes(j,0);
1196  }
1197  }
1198  for (int j = 0; j < 3; j++)
1199  {
1200  if (aux_node_enrichment_shape_function_index(j)> -1) //that is, local node j it is a useful node:
1201  {
1202  active_node_in_enrichment_shape_function( aux_node_enrichment_shape_function_index(j) ) = j;
1203 
1204  if(partition_father_nodes(j,0)==non_aux_node_father_node || partition_father_nodes(j,1)==non_aux_node_father_node)
1205  {
1206  if (aux_node_enrichment_shape_function_index(j)==0)
1207  useful_node_for_N0star=j;
1208  if (aux_node_enrichment_shape_function_index(j)==1)
1209  useful_node_for_N1star=j;
1210  }
1211  }
1212 
1213  //to replace the standard shape functions:
1214  if (aux_nodes_father_nodes(j,0)==aux_nodes_father_nodes(j,1))
1215  active_node_in_replacement_shape_function(aux_nodes_father_nodes(j,0))=j;
1216  }
1217 
1218  }
1219 
1220  //calculate data of this partition
1221  double temp_area;
1222  CalculateGeometryData(coord_subdomain, DN_DX_subdomain, temp_area);
1223  if (temp_area > 1.0e-20) //ok, it does not have zero area
1224  {
1225 
1226  rVolumes(partition_number)=temp_area;
1227  //we look for the gauss point of the partition:
1228  double x_GP_partition = one_third * ( coord_subdomain(0,0) + coord_subdomain(1,0) + coord_subdomain(2,0) );
1229  double y_GP_partition = one_third * ( coord_subdomain(0,1) + coord_subdomain(1,1) + coord_subdomain(2,1) );
1230  double z_GP_partition = 0.0;
1231  coord_subdomain_aux = coord_subdomain;
1232  //we reset the coord_subdomain matrix so that we have the whole element again:
1233  coord_subdomain = rPoints;
1234  //and we calculate its shape function values
1235  CalculatePosition ( coord_subdomain , x_GP_partition ,y_GP_partition ,z_GP_partition , N);
1236  //we check the partition sign.
1237  const double partition_sign = (N(0)*rDistances(0) + N(1)*rDistances(1) + N(2)*rDistances(2))/fabs(N(0)*rDistances(0) + N(1)*rDistances(1) + N(2)*rDistances(2));
1238  //rPartitionsSign(partition_number)=partition_sign;
1239 
1240  rGPShapeFunctionValues(partition_number,0)=N(0);
1241  rGPShapeFunctionValues(partition_number,1)=N(1);
1242  rGPShapeFunctionValues(partition_number,2)=N(2);
1243 
1244  //compute enriched shape function values
1245 
1247  IntegrationMethod mThisIntegrationMethod;
1248  std::vector< Matrix > mInvJ0;
1249  Vector mDetJ0;
1250 
1252  Node::Pointer p_new_node;
1253  int id_local=0;
1254  for (unsigned int j=0; j!=3; j++)
1255  {
1256  p_new_node = Node::Pointer(new Node(id_local, coord_subdomain_aux(j,0), coord_subdomain_aux(j,1), coord_subdomain_aux(j,2)));
1257  NewPoints.push_back(p_new_node);
1258  id_local++;
1259  }
1260 
1261  Geometry< Node >::Pointer pGeom = trianglegeom.Create(NewPoints);
1262  //const unsigned int number_of_points = pGeom->size();
1263  //KRATOS_WATCH(number_of_points);
1264  mThisIntegrationMethod= GeometryData::IntegrationMethod::GI_GAUSS_2;
1265 
1267  //const GeomtryType::IntegrationPointsArrayType& integration_points = pGeom->IntegrationPoints(mThisIntegrationMethod);
1268  const IntegrationPointsArrayType& integration_points = pGeom->IntegrationPoints(mThisIntegrationMethod);
1269 
1270  mInvJ0.resize(integration_points.size());
1271  mDetJ0.resize(integration_points.size(),false);
1272 
1273  //KRATOS_WATCH(integration_points.size());
1274  //KRATOS_ERROR(std::logic_error, "element with zero area found", "");
1276  J0 = pGeom->Jacobian(J0, mThisIntegrationMethod);
1277 
1279 
1280  double xp=0.0;
1281  double yp=0.0;
1282  double temp_areaaux_2=0.0;
1283  bounded_matrix<double, 4, 8 > N_new=ZeroMatrix(4,8);
1284 
1285  for(unsigned int PointNumber = 0; PointNumber<integration_points.size(); PointNumber++)
1286  {
1287  //unsigned int number_of_nodes = pGeom->PointsNumber();
1288  //unsigned int dimension = pGeom->WorkingSpaceDimension();
1289  const Vector& N=row(Ncontainer,PointNumber);
1290 
1291  MathUtils<double>::InvertMatrix(J0[PointNumber],mInvJ0[PointNumber],mDetJ0[PointNumber]);
1292  double Weight = integration_points[PointNumber].Weight()* mDetJ0[PointNumber];
1293 
1294  xp=0.0;
1295  yp=0.0;
1296 
1297  for (unsigned int tt=0; tt<3; tt++)
1298  {
1299  xp += N[tt] * coord_subdomain_aux(tt,0);
1300  yp += N[tt] * coord_subdomain_aux(tt,1);
1301  }
1302 
1303  for (unsigned int h=0; h<3; h++) //loop por los nodos del subelemento
1304  {
1305 
1306  bounded_matrix<double, 3, 2 > original_coordinates; //8 is the max number of nodes and aux_nodes
1307  for (unsigned int i = 0; i < 3; i++)
1308  for (unsigned int j = 0; j < 2; j++)
1309  original_coordinates(i, j) = rPoints(i, j);
1310 
1311 
1312  original_coordinates(h,0) = xp;
1313  original_coordinates(h,1) = yp;
1314 
1315 
1316  CalculateGeometryData(original_coordinates, DN_DX_subdomainaux_1aux, temp_areaaux_2);//222
1317 
1318  PRUEBA[partition_number](PointNumber,h) = temp_areaaux_2/Area;// * Weight;
1319  weight(partition_number)=Weight;
1320  }
1321 
1322  }
1323 
1324  double dist = 0.0;
1325  double abs_dist = 0.0;
1326  for (int j = 0; j < 3; j++)
1327  {
1328  dist += rGPShapeFunctionValues(partition_number, j) * exact_distance[j];
1329  abs_dist += rGPShapeFunctionValues(partition_number, j) * abs_distance[j];
1330  }
1331 
1332  if (partition_sign < 0.0)
1333  rPartitionsSign[partition_number] = -1.0;
1334  else
1335  rPartitionsSign[partition_number] = 1.0;
1336 
1337  //We use the sublement shape functions and derivatives:
1338  //we loop the 2 enrichment shape functions:
1339  for (int index_shape_function = 0; index_shape_function < 2; index_shape_function++) //enrichment shape function
1340  {
1341  if (active_node_in_enrichment_shape_function(index_shape_function) > -1) //recall some of them are inactive:
1342  {
1343  NEnriched(partition_number, index_shape_function+3 ) = one_third ; //only one gauss point. if more were to be used, it would still be simple (1/2,1/2,0);(0,1/2,1/2);(1/2,0,1/2);
1344  for (int j = 0; j < 2; j++) //x,y,(z)
1345  {
1346  rGradientsValue[partition_number](index_shape_function+3, j) = DN_DX_subdomain(active_node_in_enrichment_shape_function(index_shape_function),j);
1347  }
1348 
1349  }
1350  else
1351  {
1352  NEnriched(partition_number, index_shape_function+3 ) = 0.0;
1353  //NEnriched(partition_number, index_shape_function +2) = 0.0;
1354  for (int j = 0; j < 2; j++) //x,y,(z)
1355  {
1356  rGradientsValue[partition_number](index_shape_function+3, j) = 0.0;
1357  //KRATOS_WATCH(rGradientsValue);
1358  //rGradientsValue[partition_number](index_shape_function+2, j) = 0.0;
1359  }
1360  }
1361 
1362  }
1363 
1364  array_1d<int,(2+1)> replacement_shape_function_nodes = ZeroVector(3);
1365  for (int index_shape_function = 0; index_shape_function < 3; index_shape_function++) //replacement shape function
1366  {
1367  int active_node=-1;
1368  for (int j = 0; j < 3; j++) //number_of_nodes in the subelement
1369  if (partition_father_nodes(j,0)==index_shape_function && partition_father_nodes(j,1)==index_shape_function)
1370  {
1371  active_node=j;
1372  break;
1373  }
1374  if(active_node> -1)
1375  {
1376  for (int j = 0; j < 2; j++) //x,y,(z)
1377  rGradientsValue[partition_number](index_shape_function, j) = DN_DX_subdomain(active_node,j);
1378  NEnriched(partition_number, index_shape_function ) = one_third;
1379  replacement_shape_function_nodes(index_shape_function) = active_node;
1380  }
1381  else
1382  {
1383  for (int j = 0; j < 2; j++) //x,y,(z)
1384  rGradientsValue[partition_number](index_shape_function, j) = 0.0;
1385  replacement_shape_function_nodes(index_shape_function) = -1;
1386  }
1387  }
1388 
1389  //We use the sublement shape functions and derivatives:
1390  //we loop the 3 replacement shape functions:
1391  unsigned int number_of_real_nodes=0; //(each partition can have either 1 or 2);
1392  for (int index_shape_function = 0; index_shape_function < 3; index_shape_function++) //enrichment shape function
1393  {
1394  if (active_node_in_replacement_shape_function(index_shape_function) > -1) //recall some of them are inactive:
1395  number_of_real_nodes++;
1396  }
1397 
1398  if(useful_node_for_N0star > -1)
1399  {
1400  for (int j = 0; j < 2; j++) //x,y,(z)
1401  {
1402  if(partition_sign>0)
1403  {
1404  //first two rows are for the side where N*1 = 1
1405  //row 1 is for gradN*1
1406  rGradientpositive(3, j)=DN_DX_subdomain(useful_node_for_N0star, j);
1407  //row 2 is for gradN*2
1408  if (active_node_in_enrichment_shape_function(1) > -1)
1409  rGradientpositive(4, j)=DN_DX_subdomain(active_node_in_enrichment_shape_function(1), j);
1410 
1411  for (int index_shape_function = 0; index_shape_function < 3; index_shape_function++) //replacement shape function
1412  {
1413  if(replacement_shape_function_nodes(index_shape_function)>-1)
1414  {
1415  rGradientpositive(index_shape_function, j) = DN_DX_subdomain(replacement_shape_function_nodes(index_shape_function), j);
1416  }
1417  }
1418  }
1419  else
1420  {
1421  rGradientnegative(3, j) =DN_DX_subdomain(useful_node_for_N0star, j);
1422  //KRATOS_WATCH(rGradientnegative);
1423  if (active_node_in_enrichment_shape_function(1) > -1)
1424  rGradientnegative(4, j) =DN_DX_subdomain(active_node_in_enrichment_shape_function(1), j);
1425 
1426  for (int index_shape_function = 0; index_shape_function < 3; index_shape_function++) //replacement shape function
1427  {
1428  if(replacement_shape_function_nodes(index_shape_function)>-1)
1429  {
1430  rGradientnegative(index_shape_function, j) = DN_DX_subdomain(replacement_shape_function_nodes(index_shape_function), j);
1431  }
1432  }
1433  }
1434  }
1435  }
1436  if(useful_node_for_N1star > -1)
1437  {
1438  for (int j = 0; j < 2; j++) //x,y,(z)
1439  {
1440  if(partition_sign>0)
1441  {
1442  //rows 3 and 4 are for the side where N*2 = 1
1443  //row 4 is for gradN*2
1444  rGradientpositive(9, j)=DN_DX_subdomain(useful_node_for_N1star, j);
1445  //row 3 is for gradN*1
1446  if (active_node_in_enrichment_shape_function(0) > -1)
1447  rGradientpositive(8, j)=DN_DX_subdomain(active_node_in_enrichment_shape_function(0), j);
1448  //KRATOS_WATCH(rGradientpositive);
1449 
1450  for (int index_shape_function = 0; index_shape_function < 3; index_shape_function++) //replacement shape function
1451  {
1452  if(replacement_shape_function_nodes(index_shape_function)>-1)
1453  {
1454  rGradientpositive(index_shape_function+5, j) = DN_DX_subdomain(replacement_shape_function_nodes(index_shape_function), j);
1455  }
1456  }
1457  }
1458  else
1459  {
1460  rGradientnegative(9, j)=DN_DX_subdomain(useful_node_for_N1star, j);
1461  if(active_node_in_enrichment_shape_function(0) > -1)
1462  rGradientnegative(8, j)=DN_DX_subdomain(active_node_in_enrichment_shape_function(0), j);
1463  //KRATOS_WATCH(rGradientnegative);
1464 
1465  for (int index_shape_function = 0; index_shape_function < 3; index_shape_function++) //replacement shape function
1466  {
1467  if(replacement_shape_function_nodes(index_shape_function)>-1)
1468  {
1469  rGradientnegative(index_shape_function+5, j) = DN_DX_subdomain(replacement_shape_function_nodes(index_shape_function), j);
1470  }
1471  }
1472  }
1473  }
1474  }
1475 
1476  partition_number++;
1477 
1478  }
1479  else
1480  found_empty_partition=true;
1481  }
1482  if (found_empty_partition==false)
1483  KRATOS_WATCH("WROOOONGGGGGGGGGGG");
1484 
1485  return 3;
1486  KRATOS_CATCH("");
1487 
1488  }
1489 
1490  //for 3D
1491  static int CalculateEnrichedShapeFuncions_Simplified(Geometry< Node >& rGeom,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, std::vector<Matrix>& rGradientsValueaux, BoundedMatrix<double,3*(3-1), (2)>& NEnriched,int& number_interface_elements,BoundedMatrix<double, 2, 3 >& coord_interface_nodes, array_1d<double,6>& area_interface, array_1d<double,6>& area_inter, array_1d<double,6>& N_Star, bool& switch_off_e, std::vector<Matrix>& edges_t,std::vector<Matrix>& nodes,std::vector<Matrix>& original_edges, std::vector<Matrix>& rGradientaux1, int& totalnodes, std::vector<Matrix>& interface_nodes, BoundedMatrix<double, 3*(3-1), 8 >& Ngauss_new, std::vector<Matrix>& Tres, std::vector<Matrix>& PRUEBA, array_1d<double,6>& weight)
1492  {
1493  KRATOS_TRY
1494 
1495  const int n_nodes = 4; // it works only for tetrahedra
1496  const int n_edges = 6; // it works only for tetrahedra
1497  bool switch_off_ee=false;
1498  const int edge_i[] = {0, 0, 0, 1, 1, 2};
1499  const int edge_j[] = {1, 2, 3, 2, 3, 3};
1500  //int z=0;
1501  //int n=0;
1502  std::vector< Matrix > edges_o(8);
1503 
1504  for (unsigned int i = 0; i < 8; i++)
1505  {
1506  edges_o[i].resize(5, 3, false); //2 values of the 2 shape functions, and derivates in (xyz) direction).
1507  }
1508 
1509  const double epsilon = 1e-15; //1.00e-9;
1510  const double near_factor = 1.00e-12;
1511 
1512  bounded_matrix<double, 4, 3 > coord_node=ZeroMatrix(4,3);
1513 
1514  int number_of_partitions = 1;
1515  for (unsigned int i = 0; i < 8; i++)
1516  for (unsigned int j = 0; j < 5; j++)
1517  for (unsigned int k = 0; k < 3; k++)
1518  edges_t[i](j,k) =-1.0;
1519 
1520  for (unsigned int i = 0; i < 8; i++)
1521  for (unsigned int j = 0; j < 5; j++)
1522  for (unsigned int k = 0; k < 3; k++)
1523  original_edges[i](j,k) =-1.0;
1524 
1525  for (unsigned int i = 0; i < 6; i++) //4
1526  for (unsigned int j = 0; j < 8; j++)
1527  for (unsigned int k = 0; k < 3; k++)
1528  rGradientaux1[i](j,k) =0.0;
1529 
1530  array_1d<double, n_edges> edges_dx; // It will be initialize later
1531  array_1d<double, n_edges> edges_dy; // It will be initialize later
1532  array_1d<double, n_edges> edges_dz; // It will be initialize later
1533  array_1d<double, n_edges> edges_length; // It will be initialize later
1534  // The divided part length from first node of edge respect to the edge length
1535  array_1d<double, n_edges> edge_division_i = ZeroVector(n_edges); // The 0 is for no split
1536  // The divided part length from second node of edge respect to the edge length
1537  array_1d<double, n_edges> edge_division_j = ZeroVector(n_edges); // The 0 is for no split
1538 
1539  bounded_matrix<double, 8, 3 > aux_coordinates; //8 is the max number of nodes and aux_nodes
1540  for (unsigned int i = 0; i < 4; i++)
1541  for (unsigned int j = 0; j < 3; j++)
1542  aux_coordinates(i, j) = rPoints(i, j);
1543  for (unsigned int i = 4; i < 8; i++)
1544  for (unsigned int j = 0; j < 3; j++)
1545  aux_coordinates(i, j) = -10000.0; //set to a large number so that errors will be evident
1546 
1547  int split_edge[] = {0, 1, 2, 3, -1, -1, -1, -1, -1, -1, -1, -1};
1548  int new_node_id = 4;
1549  bounded_matrix<double, 4, 4 > length = ZeroMatrix(4, 4);
1550 
1551  //int n_zero_distance_nodes = 0;
1552  int n_negative_distance_nodes = 0;
1553  int n_positive_distance_nodes = 0;
1554  array_1d<int,4> signs(4,-2);//[] = {-2, -2, -2, -2};
1555  //int zero_distance_nodes[] = {-1, -1, -1, -1};
1556  array_1d<int,4> negative_distance_nodes(4,-1);//[] = {-1, -1, -1, -1};
1557  array_1d<int,4> positive_distance_nodes(4,-1);//[] = {-1, -1, -1, -1};
1558 
1559  for (int i = 0; i < 6; i++)
1560  for (int j = 0; j < n_nodes; j++)
1561  rShapeFunctionValues(i, j) = 0.25;
1562 
1563  for (int i = 0; i < 6; i++)
1564  for (int j = 0; j < 8; j++)
1565  Ngauss_new(i, j) = 0.0;
1566  //compute the gradient of the distance and normalize it
1567  array_1d<double, 3 > grad_d;
1568  noalias(grad_d) = prod(trans(DN_DX), rDistances);
1569  double norm = norm_2(grad_d);
1570  if (norm > epsilon)
1571  grad_d /= (norm);
1572 
1573  array_1d<double, n_nodes> exact_distance = rDistances;
1575  double sub_volumes_sum = 0.00;
1576 
1577  //compute edge lenghts and max_lenght
1578  double max_lenght = 0.0;
1579  for (int edge = 0; edge < n_edges; edge++)
1580  {
1581  const int i = edge_i[edge];
1582  const int j = edge_j[edge];
1583 
1584  double dx = rPoints(j, 0) - rPoints(i, 0);
1585  double dy = rPoints(j, 1) - rPoints(i, 1);
1586  double dz = rPoints(j, 2) - rPoints(i, 2);
1587 
1588  double l = sqrt(dx * dx + dy * dy + dz * dz);
1589 
1590  edges_dx[edge] = dx;
1591  edges_dy[edge] = dy;
1592  edges_dz[edge] = dz;
1593  edges_length[edge] = l;
1594 
1595  if(l > max_lenght)
1596  max_lenght = l;
1597  }
1598 
1599  double relatively_close = near_factor*max_lenght;
1600  array_1d<bool,4> collapsed_node;
1601  //identify collapsed nodes
1602  for (unsigned int i=0; i<4; i++)
1603  {
1604  if(fabs(rDistances[i]) < relatively_close)
1605  {
1606  collapsed_node[i] = true;
1607  rDistances[i] = 0.0;
1608  // KRATOS_WATCH("********************************!!!!!!!!!!!!!!!!!!!!!!!!!!!! collapsed node")
1609  }
1610  else
1611  collapsed_node[i] = false;
1612 
1613  abs_distance[i] = fabs(rDistances[i]);
1614  }
1615 
1616  //now decide splitting pattern
1617  for (int edge = 0; edge < n_edges; edge++)
1618  {
1619  const int i = edge_i[edge];
1620  const int j = edge_j[edge];
1621  if (rDistances[i] * rDistances[j] < 0.0)
1622  {
1623  const double tmp = fabs(rDistances[i]) / (fabs(rDistances[i]) + fabs(rDistances[j]));
1624 
1625  if (collapsed_node[i] == false && collapsed_node[j] == false)
1626  {
1627  split_edge[edge + 4] = new_node_id;
1628  edge_division_i[edge] = tmp;
1629  edge_division_j[edge] = 1.00 - tmp;
1630 
1631  //compute the position of the edge node
1632  for (unsigned int k = 0; k < 3; k++)
1633  aux_coordinates(new_node_id, k) = rPoints(i, k) * edge_division_j[edge] + rPoints(j, k) * edge_division_i[edge];
1634 
1635  new_node_id++;
1636  }
1637  }
1638  }
1639  totalnodes=new_node_id;
1640  for(int aux = 0; aux < 4; aux++)
1641  {
1642  nodes[aux](0,0)=rPoints(aux, 0);
1643  nodes[aux](0,1)=rPoints(aux, 1);
1644  nodes[aux](0,2)=rPoints(aux, 2);
1645 
1646  }
1647 
1648  for(int aux = 4; aux < new_node_id; aux++)
1649  {
1650  nodes[aux](0,0)=aux_coordinates(aux, 0);
1651  nodes[aux](0,1)=aux_coordinates(aux, 1);
1652  nodes[aux](0,2)=aux_coordinates(aux, 2);
1653 
1654  }
1655 
1656  //compute the abs exact distance for all of the nodes
1657  if(new_node_id > 4) //at least one edge is cut
1658  {
1659  array_1d<double,3> base_point;
1660  base_point[0] = aux_coordinates(4,0);
1661  base_point[1] = aux_coordinates(4,1);
1662  base_point[2] = aux_coordinates(4,2);
1663 
1664 
1665  for (int i_node = 0; i_node < n_nodes; i_node++)
1666  {
1667  double d = (rPoints(i_node,0) - base_point[0]) * grad_d[0] +
1668  (rPoints(i_node,1) - base_point[1]) * grad_d[1] +
1669  (rPoints(i_node,2) - base_point[2]) * grad_d[2] ;
1670  abs_distance[i_node] = fabs(d);
1671  }
1672 
1673  }
1674 
1675 
1676  for (int i_node = 0; i_node < n_nodes; i_node++)
1677  {
1678  if (rDistances[i_node] < 0.00)
1679  {
1680  signs[i_node] = -1;
1681  negative_distance_nodes[n_negative_distance_nodes++] = i_node;
1682  }
1683  else
1684  {
1685  signs[i_node] = 1;
1686  positive_distance_nodes[n_positive_distance_nodes++] = i_node;
1687  }
1688  }
1689 
1690  //assign correct sign to exact distance
1691  for (int i = 0; i < n_nodes; i++)
1692  {
1693  if (rDistances[i] < 0.0)
1694  exact_distance[i] = -abs_distance[i];
1695  else
1696  exact_distance[i] = abs_distance[i];
1697  }
1698 
1699  //compute exact distance gradients
1700  array_1d<double, 3 > exact_distance_gradient;
1701  noalias(exact_distance_gradient) = prod(trans(DN_DX), exact_distance);
1702 
1703  array_1d<double, 3 > abs_distance_gradient;
1704  noalias(abs_distance_gradient) = prod(trans(DN_DX), abs_distance);
1705 
1706  int number_of_splitted_edges = new_node_id - 4; //number of splitted edges
1707 
1708  double volume = edges_dx[0] * edges_dy[1] * edges_dz[2] -
1709  edges_dx[0] * edges_dz[1] * edges_dy[2] +
1710  edges_dy[0] * edges_dz[1] * edges_dx[2] -
1711  edges_dy[0] * edges_dx[1] * edges_dz[2] +
1712  edges_dz[0] * edges_dx[1] * edges_dy[2] -
1713  edges_dz[0] * edges_dy[1] * edges_dx[2];
1714 
1715  const double one_sixth = 1.00 / 6.00;
1716  volume *= one_sixth;
1717 
1718  if (number_of_splitted_edges == 0) // no splitting
1719  {
1720 
1721  rVolumes[0] = volume;
1722  sub_volumes_sum = volume;
1723  //take the sign from the node with min distance
1724  double min_distance = 1e9;
1725  for (int j = 0; j < 4; j++)
1726  if(exact_distance[j] < min_distance) min_distance = exact_distance[j];
1727 
1728  if(min_distance < 0.0)
1729  rPartitionsSign[0] = -1.0;
1730  else
1731  rPartitionsSign[0] = 1.0;
1732 
1734 
1735  for (int j = 0; j < 4; j++)
1736  rShapeFunctionValues(0, j) = 0.25;
1737 
1738  for (int j = 0; j < number_of_partitions; j++)
1739  NEnriched(j, 0) = 0.0;
1740 
1741  rGradientsValue[0] = ZeroMatrix(1,3);
1742  }
1743  else //if (number_of_splitted_edges == 4)
1744  {
1745  //define the splitting mode for the tetrahedra
1746  int edge_ids[6];
1747  TetrahedraSplit::TetrahedraSplitMode(split_edge, edge_ids);
1748  int nel; //number of elements generated
1749  int n_splitted_edges; //number of splitted edges
1750  int nint; //number of internal nodes
1751  int t[56];
1752  TetrahedraSplit::Split_Tetrahedra(edge_ids, t, &nel, &n_splitted_edges, &nint);
1753 
1754  if (nint != 0)
1755  KRATOS_ERROR<<"requiring an internal node for splitting ... can not accept this";
1756 
1757  //now obtain the tetras and compute their center coordinates and volume
1758  array_1d<double, 3 > center_position;
1759  for (int i = 0; i < nel; i++)
1760  {
1761  int i0, i1, i2, i3; //indices of the subtetrahedra
1762  TetrahedraSplit::TetrahedraGetNewConnectivityGID(i, t, split_edge, &i0, &i1, &i2, &i3);
1763 
1764  double sub_volume = ComputeSubTetraVolumeAndCenter(aux_coordinates, center_position, i0, i1, i2, i3);
1765 
1766  rVolumes[i] = sub_volume;
1767 
1768  sub_volumes_sum += sub_volume;
1769 
1771  ComputeElementCoordinates(N, center_position, rPoints, volume);
1772  for (int j = 0; j < 4; j++)
1773  rShapeFunctionValues(i, j) = N[j];
1774 
1775  }
1776  number_of_partitions = nel;
1777  }
1778 
1779  BoundedMatrix<double,4,3> DN_DX_subdomainaux1; //used to retrieve derivatives
1780  BoundedMatrix<double, 4, 3 > coord_subdomainaux1;
1781  double temp_areaaux1=0.0;
1782 
1783 
1784  CalculateGeometryData(rPoints, DN_DX_subdomainaux1, temp_areaaux1);//222
1785 
1786  if (number_of_partitions > 1) // we won't calculate the N and its gradients for element without partitions
1787  {
1788  //compute the maximum absolute distance on the cut so to normalize the shape functions
1789  //now decide splitting pattern
1790  double max_aux_dist_on_cut = -1;
1791  for (int edge = 0; edge < n_edges; edge++)
1792  {
1793  const int i = edge_i[edge];
1794  const int j = edge_j[edge];
1795  if (rDistances[i] * rDistances[j] < 0.0)
1796  {
1797  const double tmp = fabs(rDistances[i]) / (fabs(rDistances[i]) + fabs(rDistances[j]));
1798 
1799  //compute the position of the edge node
1800  double abs_dist_on_cut = abs_distance[i] * tmp + abs_distance[j] * (1.00 - tmp);
1801 
1802  if(abs_dist_on_cut > max_aux_dist_on_cut) max_aux_dist_on_cut = abs_dist_on_cut;
1803  }
1804  }
1805 
1806  if(max_aux_dist_on_cut < 1e-9*max_lenght)
1807  max_aux_dist_on_cut = 1e-9*max_lenght;
1808 
1809  int edge_ids[6];
1810  TetrahedraSplit::TetrahedraSplitMode(split_edge, edge_ids);
1811  int nel; //number of elements generated
1812  int n_splitted_edges; //number of splitted edges
1813  int nint; //number of internal nodes
1814  int t[56];
1815  TetrahedraSplit::Split_Tetrahedra(edge_ids, t, &nel, &n_splitted_edges, &nint);
1816 
1817  if (nint != 0)
1818  KRATOS_ERROR<<"requiring an internal node for splitting ... can not accept this";
1819  coord_node=ZeroMatrix(2,3);
1820  coord_interface_nodes=ZeroMatrix(2,3);
1821 
1822  array_1d<double, 3 > center_position;
1823  N_Star= ZeroVector(6);
1824 
1825  area_interface= ZeroVector(6);
1826  area_inter=ZeroVector(6);
1827 
1828  BoundedMatrix<double,4,3> DN_DX_subdomainaux; //used to retrieve derivatives
1829  BoundedMatrix<double,4,3> DN_DX_subdomainaux_1; //used to retrieve derivatives
1830  BoundedMatrix<double,4,3> DN_DX_subdomainaux_1aux; //used to retrieve derivatives
1831  BoundedMatrix<double, 4, 3 > coord_subdomainaux;
1832  BoundedMatrix<double, 4, 3 > coord_subdomainaux_aux;
1833  double temp_areaaux=0.0;
1834  int local=0;
1835 
1836  for (unsigned int i = 0; i < 6; i++)
1837  {
1838  PRUEBA[i].resize(4, 4, false);
1839  PRUEBA[i] *=0.0;
1840  }
1841 
1842  for (unsigned int i = 0; i < 6; i++)
1843  {
1844  Tres[i] *=0.0;
1845  }
1846 
1848  bounded_matrix<double, 4, 3 > original_coordinates; //8 is the max number of nodes and aux_nodes
1849  for (unsigned int i = 0; i < 4; i++)
1850  for (unsigned int j = 0; j < 3; j++)
1851  original_coordinates(i, j) = rPoints(i, j);
1852 
1854  double temp_areaaux_1=0.0;
1855  CalculateGeometryData(rPoints, DN_DX_subdomainaux_1aux, temp_areaaux_1);//222
1856 
1857 
1858  for (int i = 0; i < number_of_partitions; i++)
1859  {
1860  //compute enriched shape function values
1861 
1862  int i0, i1, i2, i3; //indices of the subtetrahedra
1863  TetrahedraSplit::TetrahedraGetNewConnectivityGID(i, t, split_edge, &i0, &i1, &i2, &i3);
1864 
1865  BoundedMatrix<double, 4, 3 > coord_subdomain; //used to pass arguments when we must calculate areas, shape functions, etc BoundedMatrix<double,4,3> DN_DX_subdomain; //used to retrieve derivatives
1866  BoundedMatrix<double, 4, 3 > coord_xg; //use
1867 
1868  coord_xg=ZeroMatrix(4,3);
1869 
1870  array_1d<int,4> partition_nodes;
1871  //double temp_area;
1872  partition_nodes[0]=i0;
1873  partition_nodes[1]=i1;
1874  partition_nodes[2]=i2;
1875  partition_nodes[3]=i3;
1876  //double interface_area=0.0;
1877 
1878  int nummm=0;
1879  for (unsigned int j=0; j!=4; j++)
1880  {//4 nodes of the partition
1881  const int node_id=partition_nodes[j];
1882  if(node_id>3){
1883  nummm++;
1884  }
1885  }
1886 
1887  std::vector<array_1d<double,3> > PointsOfFSTriangle;
1888  PointsOfFSTriangle.reserve(3);
1889 
1890  //int position=0;
1891 
1892  for (unsigned int j=0; j!=4; j++)
1893  {
1894  for (unsigned int k=0; k!=3; k++) {//x,y,z
1895  const int node_id=partition_nodes[j];
1896  coord_subdomainaux(j,k)= aux_coordinates( node_id ,k );
1897  }
1898  }
1899 
1900 
1901  for (unsigned int i = 0; i < 3; i++)
1902  {
1903  center_position[i] = aux_coordinates(0, i) + aux_coordinates(1, i) + aux_coordinates(2, i) + aux_coordinates(3, i);
1904  }
1905  center_position *= 0.25;
1906 
1907  CalculateGeometryData(coord_subdomainaux, DN_DX_subdomainaux, temp_areaaux);//222
1908 
1910  IntegrationMethod mThisIntegrationMethod;
1911  std::vector< Matrix > mInvJ0;
1912  Vector mDetJ0;
1913 
1914 
1917  //double Area=0.0;
1918 
1920  Node::Pointer p_new_node;
1921  int id_local=0;
1922  for (unsigned int j=0; j!=4; j++)
1923  {
1924  id_local=partition_nodes[j];
1925  p_new_node = Node::Pointer(new Node(id_local, coord_subdomainaux(j,0), coord_subdomainaux(j,1), coord_subdomainaux(j,2)));
1926  NewPoints.push_back(p_new_node);
1927  id_local++;
1928  }
1929  Geometry< Node >::Pointer pGeom = rGeom.Create(NewPoints);
1930  //const unsigned int number_of_points = pGeom->size();
1931  //number of gauss points
1932  mThisIntegrationMethod= GeometryData::IntegrationMethod::GI_GAUSS_2;
1933 
1935 
1936  const IntegrationPointsArrayType& integration_points = pGeom->IntegrationPoints(mThisIntegrationMethod);
1937 
1938  mInvJ0.resize(integration_points.size());
1939  mDetJ0.resize(integration_points.size(),false);
1940 
1942  J0 = pGeom->Jacobian(J0, mThisIntegrationMethod);
1943 
1945  double xp=0.0;
1946  double yp=0.0;
1947  double zp=0.0;
1948 
1949  double temp_areaaux_2=0.0;
1950  bounded_matrix<double, 4, 8 > N_new=ZeroMatrix(4,8);
1951 
1952  for(unsigned int PointNumber = 0; PointNumber<integration_points.size(); PointNumber++)
1953  {
1954  //unsigned int number_of_nodes = pGeom->PointsNumber();
1955  //unsigned int dimension = pGeom->WorkingSpaceDimension();
1956  const Vector& N=row(Ncontainer,PointNumber);
1957 
1958  MathUtils<double>::InvertMatrix(J0[PointNumber],mInvJ0[PointNumber],mDetJ0[PointNumber]);
1959  double Weight = integration_points[PointNumber].Weight()* mDetJ0[PointNumber];
1960 
1961  xp=0.0;
1962  yp=0.0;
1963  zp=0.0;
1964 
1965  for (unsigned int tt=0; tt!=4; tt++)
1966  {
1967  xp += N[tt] * coord_subdomainaux(tt,0);
1968  yp += N[tt] * coord_subdomainaux(tt,1);
1969  zp += N[tt] * coord_subdomainaux(tt,2);
1970  }
1971 
1972  for (unsigned int j=0; j!=4; j++) //loop por los nodos del subelemento
1973  {
1974  bounded_matrix<double, 8, 3 > aux_coordinates_aux;
1975  aux_coordinates_aux=aux_coordinates;
1976 
1977  bounded_matrix<double, 4, 3 > original_coordinates; //8 is the max number of nodes and aux_nodes
1978  for (unsigned int i = 0; i < 4; i++)
1979  for (unsigned int j = 0; j < 3; j++)
1980  original_coordinates(i, j) = rPoints(i, j);
1981 
1982 
1983  const int node_idaux=partition_nodes[j];
1984 
1985  aux_coordinates_aux(node_idaux,0)=xp;
1986  aux_coordinates_aux(node_idaux,1)=yp;
1987  aux_coordinates_aux(node_idaux,2)=zp;
1988 
1989  original_coordinates(j,0) = xp;
1990  original_coordinates(j,1) = yp;
1991  original_coordinates(j,2) = zp;
1992 
1993  for (unsigned int jj=0; jj!=4; jj++)
1994  {
1995  for (unsigned int k=0; k!=3; k++)
1996  {//x,y,z
1997  const int node_id=partition_nodes[jj];
1998  coord_subdomainaux_aux(jj,k)= aux_coordinates_aux( node_id ,k );
1999  }
2000  }
2001 
2003  CalculateGeometryData(original_coordinates, DN_DX_subdomainaux_1aux, temp_areaaux_2);//222
2004 
2005  PRUEBA[i](PointNumber,j) = temp_areaaux_2/temp_areaaux_1;
2006  weight(i)=Weight;
2007 
2008  }
2009 
2010  //int id_local_aux1=0;
2011  //int id_local_aux2=0;
2012 
2013  }
2014 
2015 
2016 
2017  bounded_matrix<double, 4, 3 > edges=ZeroMatrix(4,3);
2018  bounded_matrix<double, 4, 3 > edged_enriched= ZeroMatrix(4,3);
2019 
2020  array_1d<int, 2 > edgeone;
2021  array_1d<int, 2 > edgetwo;
2022  array_1d<int,3> edgetriangle;
2023  array_1d<int, 2 > active_node_in_enrichment_shape_function;
2024  active_node_in_enrichment_shape_function(0)=-1; active_node_in_enrichment_shape_function(1)=-1;
2025  array_1d<int, 2 > active_node_in_replacement_shape_function;
2026  active_node_in_replacement_shape_function(0)=-1; active_node_in_replacement_shape_function(1)=-1;
2027 
2028 
2029  edges(0,0)=partition_nodes[0];
2030  edges(0,1)=partition_nodes[2];
2031  edges(0,2)=partition_nodes[1];
2032 
2033  edges(1,0)=partition_nodes[0];
2034  edges(1,1)=partition_nodes[3];
2035  edges(1,2)=partition_nodes[2];
2036 
2037  edges(2,0)=partition_nodes[0];
2038  edges(2,1)=partition_nodes[1];
2039  edges(2,2)=partition_nodes[3];
2040 
2041  edges(3,0)=partition_nodes[2];
2042  edges(3,1)=partition_nodes[3];
2043  edges(3,2)=partition_nodes[1];
2044 
2045 
2046  int shape_function_id=0;
2047  int shape_function_aux_id=0;
2048  for(int i_aux=0; i_aux<4;i_aux++)
2049  {
2050  shape_function_id=0;
2051  shape_function_aux_id=0;
2052  active_node_in_enrichment_shape_function(0)=-1; active_node_in_enrichment_shape_function(1)=-1;
2053 
2054  active_node_in_replacement_shape_function(0)=-1; active_node_in_replacement_shape_function(1)=-1;
2055 
2056  edgeone(0)=-1; edgeone(1)=-1;
2057 
2058  edgetwo(0)=-1; edgetwo(1)=-1;
2059 
2060  edgetriangle(0)=-1;edgetriangle(1)=-1;edgetriangle(2)=-1;
2061 
2062  for (int j=0;j<3;j++)
2063  {
2064  if(edges(i_aux,j)<4)
2065  {
2066  active_node_in_replacement_shape_function(shape_function_id)=edges(i_aux,j);
2067  shape_function_id++;
2068  }
2069  else
2070  {
2071  active_node_in_enrichment_shape_function(shape_function_aux_id)=edges(i_aux,j);
2072  shape_function_aux_id++;
2073  }
2074  }
2075 
2076 
2077  //int t_max = shape_function_id;
2078 
2079  unsigned int index=shape_function_aux_id;
2080 
2081  for (unsigned int pos=0; pos<index; pos++)
2082  {
2083  for (unsigned int edge_aux=0; edge_aux<6; edge_aux++)
2084  {
2085  if (split_edge[4+edge_aux]> -1) //that is, loca
2086  {
2087  if(active_node_in_enrichment_shape_function(pos)==split_edge[4+edge_aux])
2088  {
2089  if(pos==0)
2090  {
2091  edgeone(0)=edge_i[edge_aux];
2092  edgeone(1)=edge_j[edge_aux];
2093 
2094 
2095  }
2096  else
2097  {
2098  edgetwo(0)=edge_i[edge_aux];
2099  edgetwo(1)=edge_j[edge_aux];
2100  }
2101  }
2102  }
2103  }
2104  }
2105  bool well=false;
2106  for (unsigned int pos=0; pos<index; pos++)
2107  {
2108  for (unsigned int k=0; k<2; k++)
2109  {
2110  if(edgeone(pos)==edgetwo(k)) well=true;
2111  }
2112  }
2113 
2114  edgetriangle(0)=edgeone(0);
2115  edgetriangle(1)=edgeone(1);
2116  for (unsigned int pos=0; pos<2; pos++)
2117  {
2118 
2119  if(edgetriangle(pos)==edgetwo(0))
2120  {
2121  edgetriangle(2)=edgetwo(1);
2122  }
2123  if(edgetriangle(pos)==edgetwo(1)) {
2124  edgetriangle(2)=edgetwo(0);
2125  }
2126  }
2127 
2128  if(index==1) well=true;
2129  if(index==1)
2130  {
2131 
2132  for (unsigned int pos=0; pos<2; pos++)
2133  {
2134 
2135  if(edgetriangle(pos)==active_node_in_replacement_shape_function(0))
2136  {
2137  edgetriangle(2)= active_node_in_replacement_shape_function(1);
2138  }
2139  if(edgetriangle(pos)==active_node_in_replacement_shape_function(1))
2140  {
2141  edgetriangle(2)=active_node_in_replacement_shape_function(0);
2142  }
2143  }
2144  }
2145  if(well==true)
2146  {
2147  for (unsigned int jj=0; jj<3; jj++){
2148  original_edges[i](i_aux,jj)=edgetriangle(jj);
2149  }
2150  }
2151 
2152  for(int aux=0; aux<2;aux++)
2153  {
2154  for (unsigned int edge_aux=0; edge_aux<6; edge_aux++)
2155  {
2156  if(active_node_in_replacement_shape_function(aux)==edge_i[edge_aux] || active_node_in_replacement_shape_function(aux)==edge_j[edge_aux] )
2157  {
2158  if (split_edge[4+edge_aux]> -1)
2159  {
2160 
2161  if(active_node_in_enrichment_shape_function(0)==split_edge[4+edge_aux])
2162  {
2163  if(well==true)
2164  {
2165  for (int j=0;j<3;j++)
2166  {
2167  edges_t[i](i_aux,j)=edges(i_aux,j);
2168 
2169  }
2170  }
2171  edges_o[i](i_aux,0)=edge_i[edge_aux];
2172  edges_o[i](i_aux,1)=edge_j[edge_aux];
2173  edges_o[i](i_aux,0)=active_node_in_enrichment_shape_function(1);
2174  }
2175  else if(active_node_in_enrichment_shape_function(1)==split_edge[4+edge_aux])
2176  {
2177  if(well==true)
2178  {
2179  for (int j=0;j<3;j++)
2180  {
2181  edges_t[i](i_aux,j)=edges(i_aux,j);
2182  }
2183  }
2184  edges_o[i](i_aux,0)=edge_i[edge_aux];
2185  edges_o[i](i_aux,1)=edge_j[edge_aux];
2186  edges_o[i](i_aux,0)=active_node_in_enrichment_shape_function(0);
2187  }
2188 
2189  }//
2190  }
2191  }
2192  }
2193  }
2194  for (unsigned int j=0; j!=4; j++)
2195  {
2196  for (unsigned int k=0; k!=3; k++) {
2197  const int node_id=partition_nodes[j];
2198  rGradientaux1[i](node_id,k)= DN_DX_subdomainaux(j,k);
2199  Ngauss_new(i,node_id)=0.25;
2200 
2201  }
2202  }
2203 
2204  double dist = 0.0;
2205  double abs_dist = 0.0;
2206  for (int j = 0; j < 4; j++)
2207  {
2208  dist += rShapeFunctionValues(i, j) * exact_distance[j];
2209  abs_dist += rShapeFunctionValues(i, j) * abs_distance[j];
2210  }
2211  if (dist < 0.0)
2212  rPartitionsSign[i] = -1.0;
2213  else
2214  rPartitionsSign[i] = 1.0;
2215 
2216  if(nummm==3)
2217  {
2218  if(rPartitionsSign[i] == 1.0 )
2219  {
2220  int index=0;
2221  for (unsigned int j=0; j!=4; j++)
2222  {
2223  const int node_id=partition_nodes[j];
2224  if(node_id>3) {
2225  interface_nodes[local](0,index)=node_id;
2226 
2227  index++;
2228  }
2229  }
2230  local++;
2231  }
2232 
2233  }
2234 
2235  NEnriched(i, 0) = 0.5 * (abs_dist - rPartitionsSign[i] * dist);
2236  //normalizing
2237  NEnriched(i, 0) /= max_aux_dist_on_cut;
2238 
2239  for (int j = 0; j < 3; j++)
2240  {
2241  rGradientsValue[i](0, j) = (0.5/max_aux_dist_on_cut) * (abs_distance_gradient[j] - rPartitionsSign[i] * exact_distance_gradient[j]);
2242  }
2243  }
2244  }
2245  else
2246  {
2247  NEnriched(0,0) = 0.0;
2248  switch_off_ee=true;
2249  switch_off_e=switch_off_ee;
2250  for (int j = 0; j < 3; j++)
2251  rGradientsValue[0](0, j) = 0.0;
2252  }
2253 
2254  return number_of_partitions;
2255  KRATOS_CATCH("");
2256  }
2257 
2258 
2259 
2260  private:
2261 
2262 
2263  static void ComputeElementCoordinates(array_1d<double, 4 > & N, const array_1d<double, 3 > & center_position, BoundedMatrix<double, 4, 3 > & rPoints, const double vol)
2264  {
2265  double x0 = rPoints(0, 0); //geom[0].X();
2266  double y0 = rPoints(0, 1); //geom[0].Y();
2267  double z0 = rPoints(0, 2); //geom[0].Z();
2268  double x1 = rPoints(1, 0); //geom[1].X();
2269  double y1 = rPoints(1, 1); //geom[1].Y();
2270  double z1 = rPoints(1, 2); //geom[1].Z();
2271  double x2 = rPoints(2, 0); //geom[2].X();
2272  double y2 = rPoints(2, 1); //geom[2].Y();
2273  double z2 = rPoints(2, 2); //geom[2].Z();
2274  double x3 = rPoints(3, 0); //geom[3].X();
2275  double y3 = rPoints(3, 1); //geom[3].Y();
2276  double z3 = rPoints(3, 2); //geom[3].Z();
2277 
2278  double xc = center_position[0];
2279  double yc = center_position[1];
2280  double zc = center_position[2];
2281 
2282  double inv_vol = 1.0 / vol;
2283  // N[0] = CalculateVol(x1, y1, z1, x3, y3, z3, x2, y2, z2, xc, yc, zc) * inv_vol;
2284  // N[1] = CalculateVol(x0, y0, z0, x1, y1, z1, x2, y2, z2, xc, yc, zc) * inv_vol;
2285  // N[2] = CalculateVol(x3, y3, z3, x1, y1, z1, x0, y0, z0, xc, yc, zc) * inv_vol;
2286  // N[3] = CalculateVol(x3, y3, z3, x0, y0, z0, x2, y2, z2, xc, yc, zc) * inv_vol;
2287  N[0] = CalculateVol(x1, y1, z1, x3, y3, z3, x2, y2, z2, xc, yc, zc) * inv_vol;
2288  N[1] = CalculateVol(x0, y0, z0, x2, y2, z2, x3, y3, z3, xc, yc, zc) * inv_vol;
2289  N[2] = CalculateVol(x3, y3, z3, x1, y1, z1, x0, y0, z0, xc, yc, zc) * inv_vol;
2290  N[3] = CalculateVol(x1, y1, z1, x2, y2, z2, x0, y0, z0, xc, yc, zc) * inv_vol;
2291 
2292  }
2293 
2294  static inline double CalculateVol(const double x0, const double y0, const double z0,const double x1, const double y1, const double z1,const double x2, const double y2, const double z2,const double x3, const double y3, const double z3)
2295  {
2296  double x10 = x1 - x0;
2297  double y10 = y1 - y0;
2298  double z10 = z1 - z0;
2299 
2300  double x20 = x2 - x0;
2301  double y20 = y2 - y0;
2302  double z20 = z2 - z0;
2303 
2304  double x30 = x3 - x0;
2305  double y30 = y3 - y0;
2306  double z30 = z3 - z0;
2307 
2308  double detJ = x10 * y20 * z30 - x10 * y30 * z20 + y10 * z20 * x30 - y10 * x20 * z30 + z10 * x20 * y30 - z10 * y20 * x30;
2309  return detJ * 0.1666666666666666666667;
2310  }
2311 
2312  //2d
2313  static inline void CalculateGeometryData(const bounded_matrix<double, 3, 3 > & coordinates,BoundedMatrix<double,3,2>& DN_DX,array_1d<double,3>& N,double& Area)
2314  {
2315  double x10 = coordinates(1,0) - coordinates(0,0);
2316  double y10 = coordinates(1,1) - coordinates(0,1);
2317 
2318  double x20 = coordinates(2,0) - coordinates(0,0);
2319  double y20 = coordinates(2,1) - coordinates (0,1);
2320 
2321  //Jacobian is calculated:
2322  // |dx/dxi dx/deta| |x1-x0 x2-x0|
2323  //J=| |= | |
2324  // |dy/dxi dy/deta| |y1-y0 y2-y0|
2325 
2326 
2327  double detJ = x10 * y20-y10 * x20;
2328 
2329  DN_DX(0,0) = -y20 + y10;
2330  DN_DX(0,1) = x20 - x10;
2331  DN_DX(1,0) = y20 ;
2332  DN_DX(1,1) = -x20 ;
2333  DN_DX(2,0) = -y10 ;
2334  DN_DX(2,1) = x10 ;
2335 
2336  DN_DX /= detJ;
2337  N[0] = 0.333333333333333;
2338  N[1] = 0.333333333333333;
2339  N[2] = 0.333333333333333;
2340 
2341  Area = 0.5*detJ;
2342  }
2343 
2344  //template<class TMatrixType, class TVectorType, class TGradientType>
2345  static inline double CalculateVolume2D( const bounded_matrix<double, 3, 3 > & coordinates)
2346  {
2347  double x10 = coordinates(1,0) - coordinates(0,0);
2348  double y10 = coordinates(1,1) - coordinates(0,1);
2349 
2350  double x20 = coordinates(2,0) - coordinates(0,0);
2351  double y20 = coordinates(2,1) - coordinates (0,1);
2352  double detJ = x10 * y20-y10 * x20;
2353  return 0.5*detJ;
2354  }
2355 
2356  static inline bool CalculatePosition(const bounded_matrix<double, 3, 3 > & coordinates,const double xc, const double yc, const double zc, array_1d<double, 3 > & N )
2357  {
2358  double x0 = coordinates(0,0);
2359  double y0 = coordinates(0,1);
2360  double x1 = coordinates(1,0);
2361  double y1 = coordinates(1,1);
2362  double x2 = coordinates(2,0);
2363  double y2 = coordinates(2,1);
2364 
2365  double area = CalculateVol(x0, y0, x1, y1, x2, y2);
2366  double inv_area = 0.0;
2367  if (area == 0.0)
2368  {
2369  KRATOS_ERROR<<"element with zero area found";
2370  } else
2371  {
2372  inv_area = 1.0 / area;
2373  }
2374 
2375 
2376  N[0] = CalculateVol(x1, y1, x2, y2, xc, yc) * inv_area;
2377  N[1] = CalculateVol(x2, y2, x0, y0, xc, yc) * inv_area;
2378  N[2] = CalculateVol(x0, y0, x1, y1, xc, yc) * inv_area;
2379  //KRATOS_WATCH(N);
2380 
2381  if (N[0] >= 0.0 && N[1] >= 0.0 && N[2] >= 0.0 && N[0] <= 1.0 && N[1] <= 1.0 && N[2] <= 1.0) //if the xc yc is inside the triangle return true
2382  return true;
2383 
2384  return false;
2385  }
2386 
2387  static inline double CalculateVol(const double x0, const double y0,const double x1, const double y1,const double x2, const double y2)
2388  {
2389  return 0.5 * ((x1 - x0)*(y2 - y0)- (y1 - y0)*(x2 - x0));
2390  }
2391 
2392  static inline void CalculateGeometryData(const bounded_matrix<double, 3, 3 > & coordinates,BoundedMatrix<double,3,2>& DN_DX, double& Area)
2393  {
2394  double x10 = coordinates(1,0) - coordinates(0,0);
2395  double y10 = coordinates(1,1) - coordinates(0,1);
2396 
2397  double x20 = coordinates(2,0) - coordinates(0,0);
2398  double y20 = coordinates(2,1) - coordinates (0,1);
2399 
2400  //Jacobian is calculated:
2401  // |dx/dxi dx/deta| |x1-x0 x2-x0|
2402  //J=| |= | |
2403  // |dy/dxi dy/deta| |y1-y0 y2-y0|
2404 
2405 
2406  double detJ = x10 * y20-y10 * x20;
2407 
2408  DN_DX(0,0) = -y20 + y10;
2409  DN_DX(0,1) = x20 - x10;
2410  DN_DX(1,0) = y20 ;
2411  DN_DX(1,1) = -x20 ;
2412  DN_DX(2,0) = -y10 ;
2413  DN_DX(2,1) = x10 ;
2414 
2415  DN_DX /= detJ;
2416 
2417  Area = 0.5*detJ;
2418  }
2419 
2420 
2421  static inline void CalculateGeometryData( BoundedMatrix<double, 4, 3 > & coordinates, BoundedMatrix<double,4,3>& DN_DX,double& Volume)
2422  {
2423  double x10 = coordinates(1,0) - coordinates(0,0);
2424  double y10 = coordinates(1,1) - coordinates(0,1);
2425  double z10 = coordinates(1,2) - coordinates(0,2);
2426 
2427  double x20 = coordinates(2,0) - coordinates(0,0);
2428  double y20 = coordinates(2,1) - coordinates (0,1);
2429  double z20 = coordinates(2,2) - coordinates (0,2);
2430 
2431  double x30 = coordinates(3,0) - coordinates(0,0);
2432  double y30 = coordinates(3,1) - coordinates (0,1);
2433  double z30 = coordinates(3,2) - coordinates (0,2);
2434 
2435  double detJ = x10 * y20 * z30 - x10 * y30 * z20 + y10 * z20 * x30 - y10 * x20 * z30 + z10 * x20 * y30 - z10 * y20 * x30;
2436 
2437  DN_DX(0,0) = -y20 * z30 + y30 * z20 + y10 * z30 - z10 * y30 - y10 * z20 + z10 * y20;
2438  DN_DX(0,1) = -z20 * x30 + x20 * z30 - x10 * z30 + z10 * x30 + x10 * z20 - z10 * x20;
2439  DN_DX(0,2) = -x20 * y30 + y20 * x30 + x10 * y30 - y10 * x30 - x10 * y20 + y10 * x20;
2440  DN_DX(1,0) = y20 * z30 - y30 * z20;
2441  DN_DX(1,1) = z20 * x30 - x20 * z30;
2442  DN_DX(1,2) = x20 * y30 - y20 * x30;
2443  DN_DX(2,0) = -y10 * z30 + z10 * y30;
2444  DN_DX(2,1) = x10 * z30 - z10 * x30;
2445  DN_DX(2,2) = -x10 * y30 + y10 * x30;
2446  DN_DX(3,0) = y10 * z20 - z10 * y20;
2447  DN_DX(3,1) = -x10 * z20 + z10 * x20;
2448  DN_DX(3,2) = x10 * y20 - y10 * x20;
2449 
2450  DN_DX /= detJ;
2451 
2452  Volume = detJ*0.1666666666666666666667;
2453  }
2454 
2455  static double ComputeSubTetraVolumeAndCenter(const bounded_matrix<double, 3, 8 > & aux_coordinates, array_1d<double, 3 > & center_position, const int i0, const int i1, const int i2, const int i3)
2456  {
2457  double x10 = aux_coordinates(i1, 0) - aux_coordinates(i0, 0); //geom[1].X() - geom[0].X();
2458  double y10 = aux_coordinates(i1, 1) - aux_coordinates(i0, 1); // geom[1].Y() - geom[0].Y();
2459  double z10 = aux_coordinates(i1, 2) - aux_coordinates(i0, 2); // geom[1].Z() - geom[0].Z();
2460 
2461  double x20 = aux_coordinates(i2, 0) - aux_coordinates(i0, 0); // geom[2].X() - geom[0].X();
2462  double y20 = aux_coordinates(i2, 1) - aux_coordinates(i0, 1); // geom[2].Y() - geom[0].Y();
2463  double z20 = aux_coordinates(i2, 2) - aux_coordinates(i0, 2); // geom[2].Z() - geom[0].Z();
2464 
2465  double x30 = aux_coordinates(i3, 0) - aux_coordinates(i0, 0); // geom[3].X() - geom[0].X();
2466  double y30 = aux_coordinates(i3, 1) - aux_coordinates(i0, 1); // geom[3].Y() - geom[0].Y();
2467  double z30 = aux_coordinates(i3, 2) - aux_coordinates(i0, 2); // geom[3].Z() - geom[0].Z();
2468 
2469  double detJ = x10 * y20 * z30 - x10 * y30 * z20 + y10 * z20 * x30 - y10 * x20 * z30 + z10 * x20 * y30 - z10 * y20 * x30;
2470  double vol = detJ * 0.1666666666666666666667;
2471 
2472  for (unsigned int i = 0; i < 3; i++)
2473  {
2474  center_position[i] = aux_coordinates(i0, i) + aux_coordinates(i1, i) + aux_coordinates(i2, i) + aux_coordinates(i3, i);
2475  }
2476  center_position *= 0.25;
2477 
2478  return vol;
2479  }
2480 
2481 
2482 
2483 
2484  };
2485 
2486 } // namespace Kratos.
2487 
2488 #endif // KRATOS_ENRICHMENT_UTILITIES_INCLUDED defined
Definition: enrichmentutilities.h:40
static int CalculateEnrichedShapeFuncionsExtendedmodified_gausspoints(Geometry< Node > &trianglegeom, BoundedMatrix< double,(2+1), 2 > &rPoints, BoundedMatrix< double,(2+1), 2 > &DN_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),(5)> &NEnriched, BoundedMatrix< double, 10, 2 > &rGradientpositive, BoundedMatrix< double, 10, 2 > &rGradientnegative, BoundedMatrix< int, 3, 3 > &father_nodes, std::vector< Matrix > &PRUEBA, array_1d< double, 6 > &weight)
Definition: enrichmentutilities.h:899
static int CalculateEnrichedShapeFuncions(BoundedMatrix< double,(2+1), 2 > &rPoints, BoundedMatrix< double,(2+1), 2 > &DN_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)> &NEnriched, array_1d< double,(3)> &rGPShapeFunctionValues_in_interfase, array_1d< double,(3)> &NEnriched_in_interfase, double &InterfaseArea)
Definition: enrichmentutilities.h:44
static int CalculateEnrichedShapeFuncionsExtendedmodified(BoundedMatrix< double,(2+1), 2 > &rPoints, BoundedMatrix< double,(2+1), 2 > &DN_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),(5)> &NEnriched, BoundedMatrix< double, 10, 2 > &rGradientpositive, BoundedMatrix< double, 10, 2 > &rGradientnegative, BoundedMatrix< int, 3, 3 > &father_nodes)
Definition: enrichmentutilities.h:386
static int CalculateEnrichedShapeFuncions_Simplified(Geometry< Node > &rGeom, 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, std::vector< Matrix > &rGradientsValueaux, BoundedMatrix< double, 3 *(3-1),(2)> &NEnriched, int &number_interface_elements, BoundedMatrix< double, 2, 3 > &coord_interface_nodes, array_1d< double, 6 > &area_interface, array_1d< double, 6 > &area_inter, array_1d< double, 6 > &N_Star, bool &switch_off_e, std::vector< Matrix > &edges_t, std::vector< Matrix > &nodes, std::vector< Matrix > &original_edges, std::vector< Matrix > &rGradientaux1, int &totalnodes, std::vector< Matrix > &interface_nodes, BoundedMatrix< double, 3 *(3-1), 8 > &Ngauss_new, std::vector< Matrix > &Tres, std::vector< Matrix > &PRUEBA, array_1d< double, 6 > &weight)
Definition: enrichmentutilities.h:1491
IntegrationMethod
Definition: geometry_data.h:76
Geometry base class.
Definition: geometry.h:71
std::vector< IntegrationPointType > IntegrationPointsArrayType
Definition: geometry.h:161
const Matrix & ShapeFunctionsValues() const
Definition: geometry.h:3393
const IntegrationPointsArrayType & IntegrationPoints() const
Definition: geometry.h:2284
virtual Pointer Create(PointsArrayType const &rThisPoints) const
Creates a new geometry pointer.
Definition: geometry.h:813
JacobiansType & Jacobian(JacobiansType &rResult) const
Definition: geometry.h:2901
Definition: amatrix_interface.h:41
void resize(std::size_t NewSize1, std::size_t NewSize2, bool preserve=0)
Definition: amatrix_interface.h:224
static BoundedMatrix< double, TDim, TDim > InvertMatrix(const BoundedMatrix< double, TDim, TDim > &rInputMatrix, double &rInputMatrixDet, const double Tolerance=ZeroTolerance)
Calculates the inverse of a 2x2, 3x3 and 4x4 matrices (using bounded matrix for performance)
Definition: math_utils.h:197
This class defines the node.
Definition: node.h:65
PointerVector is a container like stl vector but using a vector to store pointers to its data.
Definition: pointer_vector.h:72
void push_back(const TPointerType &x)
Definition: pointer_vector.h:270
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_WATCH(variable)
Definition: define.h:806
#define KRATOS_TRY
Definition: define.h:109
#define KRATOS_ERROR
Definition: exception.h:161
typename GeometryType::IntegrationPointsArrayType IntegrationPointsArrayType
Definition: add_geometries_to_python.cpp:61
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
GeometryData::IntegrationMethod IntegrationMethod
Type definition for integration methods.
Definition: exact_mortar_segmentation_utility.h:57
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::MatrixRow< const TExpressionType > row(AMatrix::MatrixExpression< TExpressionType, TCategory > const &TheExpression, std::size_t RowIndex)
Definition: amatrix_interface.h:649
AMatrix::TransposeMatrix< const T > trans(const T &TheMatrix)
Definition: amatrix_interface.h:486
REACTION_CHECK_STIFFNESS_FACTOR int
Definition: contact_structural_mechanics_application_variables.h:75
float dist
Definition: edgebased_PureConvection.py:89
h
Definition: generate_droplet_dynamics.py:91
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