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