KratosMultiphysics
KRATOS Multiphysics (Kratos) is a framework for building parallel, multi-disciplinary simulation software, aiming at modularity, extensibility, and high performance. Kratos is written in C++, and counts with an extensive Python interface.
discont_2d.h
Go to the documentation of this file.
1 // | / |
2 // ' / __| _` | __| _ \ __|
3 // . \ | ( | | ( |\__ `
4 // _|\_\_| \__,_|\__|\___/ ____/
5 // Multi-Physics
6 //
7 // License: BSD License
8 // Kratos default license: kratos/license.txt
9 //
10 // Main authors: Pablo Becker
11 //
12 //
13 
14 
15 #if !defined(KRATOS_DISCONTINUOUS_2D_UTILITIES_INCLUDED )
16 #define KRATOS_DISCONTINUOUS_2D_UTILITIES_INCLUDED
17 
18 
19 
20 // System includes
21 #include <string>
22 #include <iostream>
23 #include <algorithm>
24 #include <limits>
25 
26 // External includes
27 
28 
29 // Project includes
30 #include "includes/define.h"
31 //#include "utilities/split_tetrahedra.h"
32 
33 namespace Kratos
34 {
35 
41 {
42 public:
43 
81  //with some added vectors, to be used when we need information about the interfase between the 2 elements
82  //template<class TMatrixType, class TVectorType, class TGradientType>
83  /*
84  static int CalculateTriangleDiscontinuousShapeFunctions(BoundedMatrix<double,(TDim+1), TDim >& rPoints, BoundedMatrix<double, (TDim+1), TDim >& DN_DX,
85  array_1d<double,(TDim+1)>& rDistances, array_1d<double,(3*(TDim-1))>& rVolumes, BoundedMatrix<double, 3*(TDim-1), (TDim+1) >& rGPShapeFunctionValues,
86  array_1d<double,(3*(TDim-1))>& rPartitionsSign, std::vector<TMatrixType>& rGradientsValue, BoundedMatrix<double,3*(TDim-1), (TDim+1)>& NEnriched, //and information about the interfase:
87  array_1d<double,(3)>& face_gauss_N, array_1d<double,(3)>& face_gauss_Nenriched, double& face_Area, array_1d<double,(3)>& face_n ,unsigned int& type_of_cut)
88  *
89 /*
90  static int CalculateTriangleDiscontinuousShapeFunctions(BoundedMatrix<double,(2+1), 2 >& rPoints, BoundedMatrix<double, (2+1), 2 >& DN_DX,
91  array_1d<double,(2+1)>& rDistances, array_1d<double,(3*(2-1))>& rVolumes, BoundedMatrix<double, 3*(2-1), (2+1) >& rGPShapeFunctionValues,
92  array_1d<double,(3*(2-1))>& rPartitionsSign, std::vector<Matrix>& rGradientsValue, BoundedMatrix<double,3*(2-1), (2+1)>& NEnriched, //and information about the interfase:
93  array_1d<double,(3)>& face_gauss_N, array_1d<double,(3)>& face_gauss_Nenriched, double& face_Area, array_1d<double,(3)>& face_n ,unsigned int& type_of_cut)
94 
95  */
96  template<class TMatrixType, class TVectorType, class TGradientType>
97  static int CalculateTriangleDiscontinuousShapeFunctions(TMatrixType const& rPoints, TGradientType const& DN_DX,
98  TVectorType rDistances, TVectorType& rVolumes, TMatrixType& rGPShapeFunctionValues,
99  TVectorType& rPartitionsSign, std::vector<TMatrixType>& rGradientsValue, TMatrixType& Nenriched, //and information about the interfase:
100  TVectorType& face_gauss_N, TVectorType& face_gauss_Nenriched, double& face_Area, TVectorType& face_n ,unsigned int& type_of_cut)
101 
102  {
103  KRATOS_TRY
104 
105  //unsigned int i,j,k;
106  //unsigned int i_aux,j_aux,k_aux; //
107  type_of_cut = 0; // 0 means no cuts, 1 means element is cut through edges ij,ik; 2 ij,jk ; 3 ik , kj ; INTERFASES ON nodes are not contemplated
108  const double one_third=1.0/3.0;
109  BoundedMatrix<double,3,2> aux_points; //for auxiliary nodes 4(between 1 and 2) ,5(between 2 and 3) ,6 (between 3 and 1)
110  BoundedMatrix<double, 3, 2 > coord_subdomain; //used to pass arguments when we must calculate areas, shape functions, etc
111  BoundedMatrix<double,3,2> DN_DX_subdomain; //used to retrieve derivatives
112 
113 
114  double Area;//area of the complete element
115  rGPShapeFunctionValues(0,0)=one_third; rGPShapeFunctionValues(0,1)=one_third; rGPShapeFunctionValues(0,2)=one_third; //default, when no interfase has been found
116  Area = CalculateVolume2D( rPoints );
117  array_1d<bool,3> cut_edges;
118  array_1d<double,3> aux_nodes_relative_locations;
119  BoundedMatrix<int,3,2> aux_nodes_father_nodes;
120 
121  //to begin with we must check whether our element is cut or not by the interfase.
122  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
123  {
124  rVolumes(0)=Area;
125  rGPShapeFunctionValues(0,0)=one_third; rGPShapeFunctionValues(0,1)=one_third; rGPShapeFunctionValues(0,2)=one_third;
126  Nenriched(0,0) = 0.0;
127  type_of_cut=1;
128  for (int j = 0; j < 3; j++)
129  rGradientsValue[0](0, j) = 0.0;
130  if (rDistances(0) < 0.0) rPartitionsSign[0] = -1.0;
131  else rPartitionsSign[0] = 1.0;
132  //KRATOS_WATCH("one element not in the intefase")
133  return 1;
134  }
135 
136  else //we must create the enrichement, it can be in 2 or 3 parts. we'll start with 3 always.
137  {
138  //to begin with we reset the NEnriched:
139  Nenriched=ZeroMatrix(3,3);
140 
141  //KRATOS_WATCH("one element IS in the intefase")
142  if ((rDistances(0)*rDistances(1))<0.0) //edge 12 is cut
143  cut_edges[0]=true;
144  else
145  cut_edges[0]=false;
146  if ((rDistances(1)*rDistances(2))<0.0) //edge 23 is cut.
147  cut_edges[1]=true;
148  else
149  cut_edges[1]=false;
150  if ((rDistances(2)*rDistances(0))<0.0) //edge 23 is cut.
151  cut_edges[2]=true;
152  else
153  cut_edges[2]=false;
154 
155  }
156 
157  //'TRICK' TO AVOID HAVING THE INTERFASE TOO CLOSE TO THE NODES:
158  //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.
159  const double unsigned_distance0=fabs(rDistances(0));
160  const double unsigned_distance1=fabs(rDistances(1));
161  const double unsigned_distance2=fabs(rDistances(2));
162  //we begin by finding the largest distance:
163  double longest_distance=fabs(unsigned_distance0);
164  if (unsigned_distance1>longest_distance)
165  longest_distance=unsigned_distance1;
166  if (unsigned_distance2>longest_distance)
167  longest_distance=unsigned_distance2;
168  //Now we set a maximum relative distance
169  const double tolerable_distance =longest_distance*0.001; // (1/1,000,000 seems to have good results)
170  //and now we check if a distance is too small:
171  if (unsigned_distance0<tolerable_distance)
172  rDistances[0]=tolerable_distance*(rDistances[0]/fabs(rDistances[0]));
173  if (unsigned_distance1<tolerable_distance)
174  rDistances[1]=tolerable_distance*(rDistances[1]/fabs(rDistances[1]));
175  if (unsigned_distance2<tolerable_distance)
176  rDistances[2]=tolerable_distance*(rDistances[2]/fabs(rDistances[2]));
177  //END OF TRICK. REMEMBER TO OVERWRITE THE DISTANCE VARIABLE IN THE ELEMENT IN CASE THESE LINES HAVE MODIFIED THEM (distances)
178 
179 
180  //for (int jj = 0; jj < 3; jj++)
181  // KRATOS_WATCH(rDistances(jj));
182  for (unsigned int i=0; i<3; i++) //we go over the 3 edges:
183  {
184  int edge_begin_node=i;
185  int edge_end_node=i+1;
186  if (edge_end_node==3) edge_end_node=0; //it's a triangle, so node 3 is actually node 0
187 
188  if(cut_edges(i)==true)
189  {
190  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)
191  aux_nodes_father_nodes(i,0)=edge_begin_node;
192  aux_nodes_father_nodes(i,1)=edge_end_node;
193  }
194  else
195  {
196  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
197  {
198  aux_nodes_relative_locations(i)=0.0;
199  aux_nodes_father_nodes(i,0)=edge_end_node;
200  aux_nodes_father_nodes(i,1)=edge_end_node;
201  }
202  else
203  {
204  aux_nodes_relative_locations(i)=1.0;
205  aux_nodes_father_nodes(i,0)=edge_begin_node;
206  aux_nodes_father_nodes(i,1)=edge_begin_node;
207  }
208  }
209 
210  //and we save the coordinate of the new aux nodes:
211  for (unsigned int j=0;j<2;j++) //x,y coordinates
212  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));
213  }
214 
215 
216  //we reset all data:
217  rGradientsValue[0]=ZeroMatrix(3,2);
218  rGradientsValue[1]=ZeroMatrix(3,2);
219  rGradientsValue[2]=ZeroMatrix(3,2);
220  Nenriched=ZeroMatrix(3,3);
221  rGPShapeFunctionValues=ZeroMatrix(3,3);
222 
223 
224  //now we must check the 4 created partitions of the domain.
225  //one has been collapsed, so we discard it and therefore save only one.
226  unsigned int partition_number=0; //
227  //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
228  //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.
229  for (unsigned int i=0; i<4; i++) //i partition
230  {
231  unsigned int j_aux = i + 2;
232  if (j_aux>2) j_aux -= 3;
233  BoundedMatrix<int,3,2> partition_father_nodes;
235  if (i<4)
236  {
237  partition_father_nodes(0,0)=i;
238  partition_father_nodes(0,1)=i;
239  partition_father_nodes(1,0)=aux_nodes_father_nodes(i,0); //we are using i aux node
240  partition_father_nodes(1,1)=aux_nodes_father_nodes(i,1); //we are using i aux node
241  partition_father_nodes(2,0)=aux_nodes_father_nodes(j_aux,0); //we are using j_aux node
242  partition_father_nodes(2,1)=aux_nodes_father_nodes(j_aux,1); //we are using j_aux node
243 
244  coord_subdomain(0,0)=rPoints(i,0);
245  coord_subdomain(0,1)=rPoints(i,1);
246  coord_subdomain(1,0)=aux_points(i,0);
247  coord_subdomain(1,1)=aux_points(i,1);
248  coord_subdomain(2,0)=aux_points(j_aux,0);
249  coord_subdomain(2,1)=aux_points(j_aux,1);
250  }
251  else
252  {
253  //the last partition, made by the 3 aux nodes.
254  partition_father_nodes=aux_nodes_father_nodes;
255  coord_subdomain=aux_points;
256  }
257  //calculate data of this partition
258  double temp_area;
259  CalculateGeometryData(coord_subdomain, DN_DX_subdomain, temp_area);
260  if (temp_area > 1.0e-20) //ok, it does not have zero area
261  {
262  rVolumes(partition_number)=temp_area;
263  //we look for the gauss point of the partition:
264  double x_GP_partition = one_third * ( coord_subdomain(0,0) + coord_subdomain(1,0) + coord_subdomain(2,0) );
265  double y_GP_partition = one_third * ( coord_subdomain(0,1) + coord_subdomain(1,1) + coord_subdomain(2,1) );
266  double z_GP_partition = 0.0;
267  //we reset the coord_subdomain matrix so that we have the whole element again:
268  coord_subdomain = rPoints;
269  //and we calculate its shape function values
270  bool is_found = CalculatePosition ( coord_subdomain , x_GP_partition ,y_GP_partition ,z_GP_partition , N);
271  //we check the partition sign.
272  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));
273  rPartitionsSign(partition_number)=partition_sign;
274  //now we must add the contribution to the normal nodes only if they have the same sign:
275  for (unsigned int j=0;j<3;j++) //j (real) node
276  {
277  if((partition_sign*rDistances(j))>0) //ok. add contribution!
278  {
279  //now we loop in the nodes that define the partition.
280  for (unsigned int k=0;k<3;k++) //partition
281  if (partition_father_nodes(k,0)==j || partition_father_nodes(k,1)==j )// (first node)
282  {
283  Nenriched(partition_number,j)+=one_third; //partition, shape function
284  rGradientsValue[partition_number](j,0)+=DN_DX_subdomain(k,0); //[i_partition], (shape function gradient,direction(x,y))
285  rGradientsValue[partition_number](j,1)+=DN_DX_subdomain(k,1); //[i_partition], (shape function gradient,direction(x,y))
286  }
287 
288  }
289  //else //do nothing. it simply can't add to a node that is not in the same side, since we are creating discontinous shape functions
290  }
291 
292  rGPShapeFunctionValues(partition_number,0)=N(0);
293  rGPShapeFunctionValues(partition_number,1)=N(1);
294  rGPShapeFunctionValues(partition_number,2)=N(2);
295 
296  partition_number++;
297 
298  }
299 
300  }
301 
302 
303 
304 
305  return 3;
306  KRATOS_CATCH("");
307 
308  }
309 
310  //with some added vectors, to be used when we need information about the interfase between the 2 elements
311  template<class TMatrixType, class TVectorType, class TGradientType>
312  static int CalculateTriangleDiscontinuousShapeFunctions_ZeroInBoundary(TMatrixType const& rPoints, TGradientType const& DN_DX,
313  TVectorType rDistances, TVectorType& rVolumes, TMatrixType& rGPShapeFunctionValues,
314  TVectorType& rPartitionsSign, std::vector<TMatrixType>& rGradientsValue, TMatrixType& NEnriched, //and information about the interfase:
315  TVectorType& face_gauss_N, TVectorType& face_gauss_Nenriched, double& face_Area, TVectorType& face_n ,unsigned int& type_of_cut)
316  {
317  KRATOS_TRY
318 
319  //unsigned int i,j,k;
320  unsigned int i_aux,j_aux,k_aux; //
321  type_of_cut = 0; // 0 means no cuts, 1 means element is cut through edges ij,ik; 2 ij,jk ; 3 ik , kj ; INTERFASES ON nodes are not contemplated
322  const double one_third=1.0/3.0;
323  BoundedMatrix<double, 3, 2 > coord_subdomain; //used to pass arguments when we must calculate areas, shape functions, etc
324  BoundedMatrix<double,3,2> DN_DX_subdomain; //used to retrieve derivatives
325  double Area;//area of the complete element
326  rGPShapeFunctionValues(0,0)=one_third; rGPShapeFunctionValues(0,1)=one_third; rGPShapeFunctionValues(0,2)=one_third; //default, when no interfase has been found
327  Area = CalculateVolume2D( rPoints );
328 
329 
330  //to begin with we must check whether our element is cut or not by the interfase.
331  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
332  {
333  rVolumes(0)=Area;
334  rGPShapeFunctionValues(0,0)=one_third; rGPShapeFunctionValues(0,1)=one_third; rGPShapeFunctionValues(0,2)=one_third;
335  NEnriched(0,0) = 0.0;
336  type_of_cut=1;
337  for (int j = 0; j < 3; j++)
338  rGradientsValue[0](0, j) = 0.0;
339  if (rDistances(0) < 0.0) rPartitionsSign[0] = -1.0;
340  else rPartitionsSign[0] = 1.0;
341  //KRATOS_WATCH("one element not in the intefase")
342  return 1;
343  }
344 
345  else //we must create the enrichement, it can be in 2 or 3 parts. we'll start with 3 always.
346  {
347  //to begin with we reset the NEnriched:
348  NEnriched=ZeroMatrix(3,2);
349 
350  //KRATOS_WATCH("one element IS in the intefase")
351  if ((rDistances(0)*rDistances(1))<0.0) //edge 12 is cut
352  {
353  if ((rDistances(0)*rDistances(2))<0.0) //edge 13 is cut.
354  {
355  //check distances later to see if they're close to nodes and belong to case 4,5or6. for the moment we suppose all edges are cut (cases 1-3)
356  type_of_cut=1;
357  }
358  else
359  {
360  type_of_cut=2;
361  }
362  }
363  else //edge ij is not cut
364  {
365  type_of_cut=3;
366  }
367  }
368 
369  //KRATOS_WATCH(type_of_cut)
370  switch (type_of_cut)
371  {
372  case 1: // edge 12 and 13 is cut
373  i_aux=0;
374  j_aux=1;
375  k_aux=2;
376 
377  break;
378  case 2: // edge 12 and 23 is cut
379  i_aux=1;
380  j_aux=2;
381  k_aux=0;
382  break;
383  case 3: // edge 23 and 13 is cut
384  i_aux=2;
385  j_aux=0;
386  k_aux=1;
387  break;
388  }
389  /*
390  KRATOS_WATCH(i_aux)
391  KRATOS_WATCH(j_aux)
392  KRATOS_WATCH(k_aux)
393  */
394  //const double dist12=abs(rDistances(0)-rDistances(1) );
395  if (rDistances(i_aux) < 0.0)
396  {
397  rPartitionsSign[0] = -1.0;
398  rPartitionsSign[1] = 1.0;
399  rPartitionsSign[2] = 1.0;
400  }
401  else
402  {
403  rPartitionsSign[0] = 1.0;
404  rPartitionsSign[1] = -1.0;
405  rPartitionsSign[2] = -1.0;
406  }
407 
408  //'TRICK' TO AVOID HAVING THE INTERFASE TOO CLOSE TO THE NODES:
409  //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.
410 
411  const double unsigned_distance0=fabs(rDistances(0));
412  const double unsigned_distance1=fabs(rDistances(1));
413  const double unsigned_distance2=fabs(rDistances(2));
414  //we begin by finding the largest distance:
415  double longest_distance=fabs(unsigned_distance0);
416  if (unsigned_distance1>longest_distance)
417  longest_distance=unsigned_distance1;
418  if (unsigned_distance2>longest_distance)
419  longest_distance=unsigned_distance2;
420  //Now we set a maximum relative distance
421  const double tolerable_distance =longest_distance*0.01; // (1/1,000,000 seems to have good results)
422 
423  //and now we check if a distance is too small:
424  if (unsigned_distance0<tolerable_distance)
425  rDistances[0]=tolerable_distance*(rDistances[0]/fabs(rDistances[0]));
426  if (unsigned_distance1<tolerable_distance)
427  rDistances[1]=tolerable_distance*(rDistances[1]/fabs(rDistances[1]));
428  if (unsigned_distance2<tolerable_distance)
429  rDistances[2]=tolerable_distance*(rDistances[2]/fabs(rDistances[2]));
430 
431  //END OF TRICK. REMEMBER TO OVERWRITE THE DISTANCE VARIABLE IN THE ELEMENT IN CASE THESE LINES HAVE MODIFIED THEM (distances)
432 
433 
434  //for (int jj = 0; jj < 3; jj++)
435  // KRATOS_WATCH(rDistances(jj));
436 
437  const double node4_relative_position=fabs(rDistances(j_aux)/(rDistances(i_aux)-rDistances(j_aux) ) ) ; //position in 'natural' coordinates of edge 12, 0 when it passes over node 2. (it is over the edge 12)
438  const double node5_relative_position=fabs(rDistances(k_aux)/(rDistances(i_aux)-rDistances(k_aux) ) ) ; //position in 'natural' coordinates of edge 12, 0 when it passes over node 2. (it is over the edge 23)
439  //KRATOS_WATCH(node4_relative_position);
440  //KRATOS_WATCH(node5_relative_position);
441 
442  //Standard Shape function values in the 'new nodes' created by the interfase:
443  const double Ni_aux_node4 = node4_relative_position;
444  const double Nj_aux_node4 = (1.0-node4_relative_position);
445  //Nk_aux_node_4 is zero (we are on the ij edge)
446  const double Ni_aux_node5 = node5_relative_position;
447  //Nj_aux_node_5 is zero (we are on the ik edge)
448  const double Nk_aux_node5 = (1.0-node5_relative_position);
449 
450  //location of the midpoint of the interface : halfway between the two points
451  const double x_midpoint=((rPoints(i_aux,0)*Ni_aux_node4+rPoints(j_aux,0)*Nj_aux_node4)+
452  (rPoints(i_aux,0)*Ni_aux_node5+rPoints(k_aux,0)*Nk_aux_node5))*0.5;
453  const double y_midpoint=((rPoints(i_aux,1)*Ni_aux_node4+rPoints(j_aux,1)*Nj_aux_node4)+
454  (rPoints(i_aux,1)*Ni_aux_node5+rPoints(k_aux,1)*Nk_aux_node5))*0.5;
455  const double z_midpoint=0.0;
456 
457  //now we look for the shape function values in the midpoint:
458  coord_subdomain = rPoints;
460  bool is_found = CalculatePosition ( coord_subdomain , x_midpoint,y_midpoint,z_midpoint, N);
461  face_gauss_N = N;
462 
463  //we will adimensionalize the new shape functions so that the value is one on the midpoint on the interfase:
464  const double adim_Nenriched_i_aux = 1.0 /(face_gauss_N(i_aux)); //for partitions 2 and 3
465  //also the other 2 shape fuctions must be resized so that the new enrichment is constant along the interfase:
466  const double adim_Nenriched_j_aux = adim_Nenriched_i_aux * Ni_aux_node4 / Nj_aux_node4 ; //to have a constant value in the interfase at node 4: =N_j_aux_node4 / N_j_aux when adimensionalized
467  const double adim_Nenriched_k_aux = adim_Nenriched_i_aux * Ni_aux_node5 / Nk_aux_node5 ; //to have a constant value in the interfase at node 5: = N_k_aux_node4 / N_k_aux when adimensionalized
468 
469  //for the jump, we will create a shape function that holds a constant difference of 2 along the interfase:
470  const double adim_Nenriched_j_aux_b = (2.0 - node4_relative_position * adim_Nenriched_i_aux) / Nj_aux_node4;
471  const double adim_Nenriched_k_aux_b = (2.0 - node5_relative_position * adim_Nenriched_i_aux) / Nk_aux_node5;
472 
473 
474  //value of the shape functions in the interfase
475  face_gauss_Nenriched(i_aux)= 1.0;
476  face_gauss_Nenriched(j_aux)= 0.0; //actualy it's not defined, it's a discontinous function
477 
478  //first partition
479  //now we must calculate the position of the new nodes to get the area.
480  coord_subdomain(0,0)=rPoints(i_aux,0);
481  coord_subdomain(0,1)=rPoints(i_aux,1);
482  coord_subdomain(1,0)=rPoints(i_aux,0)*Ni_aux_node4+rPoints(j_aux,0)*Nj_aux_node4;
483  coord_subdomain(1,1)=rPoints(i_aux,1)*Ni_aux_node4+rPoints(j_aux,1)*Nj_aux_node4;
484  coord_subdomain(2,0)=rPoints(i_aux,0)*Ni_aux_node5+rPoints(k_aux,0)*Nk_aux_node5;
485  coord_subdomain(2,1)=rPoints(i_aux,1)*Ni_aux_node5+rPoints(k_aux,1)*Nk_aux_node5;
486  //rVolumes(0)=CalculateVolume2D(coord_subdomain);
487 
488  CalculateGeometryData(coord_subdomain, DN_DX_subdomain, rVolumes(0));
489 
490  rGradientsValue[0]=ZeroMatrix(3,2);
491  rGradientsValue[0](i_aux,0)=DN_DX_subdomain(0,0);
492  rGradientsValue[0](i_aux,1)=DN_DX_subdomain(0,1);
493  //all the others are zero!!
494 
495  //we look for the gauss point of the partition:
496  double x_GP_partition = one_third * ( coord_subdomain(0,0) + coord_subdomain(1,0) + coord_subdomain(2,0) );
497  double y_GP_partition = one_third * ( coord_subdomain(0,1) + coord_subdomain(1,1) + coord_subdomain(2,1) );
498  double z_GP_partition = 0.0;
499  //we reset the coord_subdomain matrix so that we have the whole element again:
500  coord_subdomain = rPoints;
501  //and we calculate its shape function values
502  is_found = CalculatePosition ( coord_subdomain , x_GP_partition ,y_GP_partition ,z_GP_partition , N);
503  rGPShapeFunctionValues(0,0)=N(0);
504  rGPShapeFunctionValues(0,1)=N(1);
505  rGPShapeFunctionValues(0,2)=N(2);
506 
507  NEnriched(0,i_aux)=one_third;
508  //the others are zero
509  //NEnriched(0,j_aux)=0.0;
510  //NEnriched(0,k_aux)=0.0;
511 
512 
513  //KRATOS_WATCH(rVolumes(0));
514 
515  //now the face area(actually it's just the distance from point 4 to 5.
516  face_Area=sqrt(pow((coord_subdomain(2,0)-coord_subdomain(1,0)),2)+pow((coord_subdomain(2,1)-coord_subdomain(1,1)),2));
517  //and the normal vector. face_Area already has the modulus of the vector, so:
518  face_n(0)=(coord_subdomain(2,1)-coord_subdomain(1,1))/face_Area;
519  face_n(1)=-(coord_subdomain(2,0)-coord_subdomain(1,0))/face_Area;
520 
521  /*
522  KRATOS_WATCH(coord_subdomain(0,0));
523  KRATOS_WATCH(coord_subdomain(0,1));
524  KRATOS_WATCH(coord_subdomain(1,0));
525  KRATOS_WATCH(coord_subdomain(1,1));
526  KRATOS_WATCH(coord_subdomain(2,0));
527  KRATOS_WATCH(coord_subdomain(2,1));
528  KRATOS_WATCH(rGPShapeFunctionValues(0,i_aux));
529  KRATOS_WATCH(rGPShapeFunctionValues(0,j_aux));
530  KRATOS_WATCH(rGPShapeFunctionValues(0,k_aux));
531  KRATOS_WATCH( rGradientsValue[0](0,0))
532  KRATOS_WATCH( rGradientsValue[0](0,1))
533  */
534 
535 
536 
537  //second partition and second GP
538 
539 
540  //now we must calculate the position of the new nodes to get the area.
541  //coord_subdomain = rPoints; //easier to start this way. node 2 is already ok.
542  coord_subdomain(0,0) = rPoints(j_aux,0);
543  coord_subdomain(0,1) = rPoints(j_aux,1);
544  coord_subdomain(1,0) = rPoints(k_aux,0);
545  coord_subdomain(1,1) = rPoints(k_aux,1);
546  coord_subdomain(2,0) = rPoints(i_aux,0)*Ni_aux_node5+rPoints(k_aux,0)*Nk_aux_node5;
547  coord_subdomain(2,1) = rPoints(i_aux,1)*Ni_aux_node5+rPoints(k_aux,1)*Nk_aux_node5;
548 
549  //rVolumes(1)=CalculateVolume2D(coord_subdomain);
550  CalculateGeometryData(coord_subdomain, DN_DX_subdomain, rVolumes(1));
551 
552  //for the first Shape Funct(i_aux) they art zero
553  rGradientsValue[1]=ZeroMatrix(3,2);
554  rGradientsValue[1](j_aux,0)=DN_DX_subdomain(0,0);
555  rGradientsValue[1](j_aux,1)=DN_DX_subdomain(0,1);
556  rGradientsValue[1](k_aux,0)= DN_DX_subdomain(1,0);
557  rGradientsValue[1](k_aux,1)= DN_DX_subdomain(1,1);
558 
559 
560 
561  //we look for the gauss point of the partition:
562  x_GP_partition = one_third * ( coord_subdomain(0,0) + coord_subdomain(1,0) + coord_subdomain(2,0) );
563  y_GP_partition = one_third * ( coord_subdomain(0,1) + coord_subdomain(1,1) + coord_subdomain(2,1) );
564  z_GP_partition = 0.0;
565  //we reset the coord_subdomain matrix so that we have the whole element again:
566  coord_subdomain = rPoints;
567  //and we calculate the shape functions at it
568  is_found = CalculatePosition ( coord_subdomain , x_GP_partition ,y_GP_partition ,z_GP_partition , N);
569  rGPShapeFunctionValues(1,0)=N(0);
570  rGPShapeFunctionValues(1,1)=N(1);
571  rGPShapeFunctionValues(1,2)=N(2);
572  //now the values of the shape functions. both are zero except the first one
573  //NEnriched(1,i_aux) = 0.0;
574  NEnriched(1,j_aux) = one_third;
575  NEnriched(1,k_aux) = one_third;
576  /*
577  KRATOS_WATCH(rVolumes(1));
578  KRATOS_WATCH(coord_subdomain(0,0));
579  KRATOS_WATCH(coord_subdomain(0,1));
580  KRATOS_WATCH(coord_subdomain(1,0));
581  KRATOS_WATCH(coord_subdomain(1,1));
582  KRATOS_WATCH(coord_subdomain(2,0));
583  KRATOS_WATCH(coord_subdomain(2,1));
584  KRATOS_WATCH(rGPShapeFunctionValues(1,i_aux));
585  KRATOS_WATCH(rGPShapeFunctionValues(1,j_aux));
586  KRATOS_WATCH(rGPShapeFunctionValues(1,k_aux));
587  KRATOS_WATCH( rGradientsValue[1](0,0))
588  KRATOS_WATCH( rGradientsValue[1](0,1))
589  */
590 
591  //NOT A PARTITION, just the volume of a different conectivity:
592  //just replacing the third node. Useful only to recover information, for example N(i,j,k) of node5
593  coord_subdomain(2,0) = rPoints(i_aux,0)*Ni_aux_node4+rPoints(j_aux,0)*Nj_aux_node4;
594  coord_subdomain(2,1) = rPoints(i_aux,1)*Ni_aux_node4+rPoints(j_aux,1)*Nj_aux_node4;
595  rVolumes(3)=CalculateVolume2D(coord_subdomain);
596 
597  //third partition:
598 
599  coord_subdomain(0,0) = rPoints(j_aux,0);
600  coord_subdomain(0,1) = rPoints(j_aux,1);
601  coord_subdomain(1,0)=rPoints(i_aux,0)*Ni_aux_node5+rPoints(k_aux,0)*Nk_aux_node5;
602  coord_subdomain(1,1)=rPoints(i_aux,1)*Ni_aux_node5+rPoints(k_aux,1)*Nk_aux_node5;
603  coord_subdomain(2,0)=rPoints(i_aux,0)*Ni_aux_node4+rPoints(j_aux,0)*Nj_aux_node4;
604  coord_subdomain(2,1)=rPoints(i_aux,1)*Ni_aux_node4+rPoints(j_aux,1)*Nj_aux_node4;
605  //rVolumes(2)=Area-rVolumes(0)-rVolumes(1);
606  CalculateGeometryData(coord_subdomain, DN_DX_subdomain, rVolumes(2));
607  //for the first Shape Funct(i_aux) and second(j_aux) they art zero
608  rGradientsValue[2]=ZeroMatrix(3,2);
609  rGradientsValue[2](j_aux,0)= DN_DX_subdomain(0,0);
610  rGradientsValue[2](j_aux,1)= DN_DX_subdomain(0,1);
611  //now the values of the shape functions. both are zero except the second one
612  //NEnriched(1,i_aux) = 0.0;
613  //NEnriched(1,j_aux) = one_third;
614  NEnriched(2,j_aux) = one_third;
615 
616 
617  x_GP_partition = one_third * ( coord_subdomain(0,0) + coord_subdomain(1,0) + coord_subdomain(2,0) );
618  y_GP_partition = one_third * ( coord_subdomain(0,1) + coord_subdomain(1,1) + coord_subdomain(2,1) );
619  z_GP_partition = 0.0;
620  coord_subdomain = rPoints;
621  is_found = CalculatePosition ( coord_subdomain , x_GP_partition ,y_GP_partition ,z_GP_partition , N);
622  rGPShapeFunctionValues(2,0)=N(0);
623  rGPShapeFunctionValues(2,1)=N(1);
624  rGPShapeFunctionValues(2,2)=N(2);
625 
626  /*
627  KRATOS_WATCH(rVolumes(2));
628  KRATOS_WATCH(coord_subdomain(0,0));
629  KRATOS_WATCH(coord_subdomain(0,1));
630  KRATOS_WATCH(coord_subdomain(1,0));
631  KRATOS_WATCH(coord_subdomain(1,1));
632  KRATOS_WATCH(coord_subdomain(2,0));
633  KRATOS_WATCH(coord_subdomain(2,1));
634  KRATOS_WATCH(rGPShapeFunctionValues(2,i_aux));
635  KRATOS_WATCH(rGPShapeFunctionValues(2,j_aux));
636  KRATOS_WATCH(rGPShapeFunctionValues(2,k_aux));
637  KRATOS_WATCH( rGradientsValue[2](0,0))
638  KRATOS_WATCH( rGradientsValue[2](0,1))
639  */
640  /*
641  std::cout <<"GAUSS POINTS" << '\n';
642  for (unsigned int ji=0; ji<3; ji++)
643  std::cout <<rGPShapeFunctionValues(ji,0)<< " " << rGPShapeFunctionValues(ji,1) << " " << rGPShapeFunctionValues(ji,2) <<'\n';
644 
645  std::cout <<"GRADIENTS" << '\n';
646  for (unsigned int ji=0; ji<3; ji++)
647  {
648  std::cout << "first Shape function" << '\n';
649  std::cout << rGradientsValue[ji](0,0) << " " <<rGradientsValue[ji](0,1) <<'\n';
650  std::cout << "second Shape function" << '\n';
651  std::cout << rGradientsValue[ji](1,0) << " " <<rGradientsValue[ji](1,1) <<'\n';
652  }
653  */
654  return 3;
655  KRATOS_CATCH("");
656 
657  }
658 
659 
660 
661 
662 
669  private:
670 
671  static inline void CalculateGeometryData(
672  const BoundedMatrix<double, 3, 3 > & coordinates,
674  double& Area)
675  {
676  double x10 = coordinates(1,0) - coordinates(0,0);
677  double y10 = coordinates(1,1) - coordinates(0,1);
678 
679  double x20 = coordinates(2,0) - coordinates(0,0);
680  double y20 = coordinates(2,1) - coordinates (0,1);
681 
682  //Jacobian is calculated:
683  // |dx/dxi dx/deta| |x1-x0 x2-x0|
684  //J=| |= | |
685  // |dy/dxi dy/deta| |y1-y0 y2-y0|
686 
687 
688  double detJ = x10 * y20-y10 * x20;
689 
690  DN_DX(0,0) = -y20 + y10;
691  DN_DX(0,1) = x20 - x10;
692  DN_DX(1,0) = y20 ;
693  DN_DX(1,1) = -x20 ;
694  DN_DX(2,0) = -y10 ;
695  DN_DX(2,1) = x10 ;
696 
697  DN_DX /= detJ;
698 
699  Area = 0.5*detJ;
700  }
701 
702  //template<class TMatrixType, class TVectorType, class TGradientType>
703  static inline double CalculateVolume2D(
704  const BoundedMatrix<double, 3, 3 > & coordinates)
705  {
706  double x10 = coordinates(1,0) - coordinates(0,0);
707  double y10 = coordinates(1,1) - coordinates(0,1);
708 
709  double x20 = coordinates(2,0) - coordinates(0,0);
710  double y20 = coordinates(2,1) - coordinates (0,1);
711  double detJ = x10 * y20-y10 * x20;
712  return 0.5*detJ;
713  }
714 
715  static inline bool CalculatePosition(const BoundedMatrix<double, 3, 3 > & coordinates,
716  const double xc, const double yc, const double zc,
717  array_1d<double, 3 > & N
718  )
719  {
720  double x0 = coordinates(0,0);
721  double y0 = coordinates(0,1);
722  double x1 = coordinates(1,0);
723  double y1 = coordinates(1,1);
724  double x2 = coordinates(2,0);
725  double y2 = coordinates(2,1);
726 
727  double area = CalculateVol(x0, y0, x1, y1, x2, y2);
728  double inv_area = 0.0;
729  if (area == 0.0)
730  {
731  KRATOS_THROW_ERROR(std::logic_error, "element with zero area found", "");
732  } else
733  {
734  inv_area = 1.0 / area;
735  }
736 
737 
738  N[0] = CalculateVol(x1, y1, x2, y2, xc, yc) * inv_area;
739  N[1] = CalculateVol(x2, y2, x0, y0, xc, yc) * inv_area;
740  N[2] = CalculateVol(x0, y0, x1, y1, xc, yc) * inv_area;
741  //KRATOS_WATCH(N);
742 
743  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
744  return true;
745 
746  return false;
747  }
748 
749  static inline double CalculateVol(const double x0, const double y0,
750  const double x1, const double y1,
751  const double x2, const double y2
752  )
753  {
754  return 0.5 * ((x1 - x0)*(y2 - y0)- (y1 - y0)*(x2 - x0));
755  }
756 
757 
758 
759  };
760 
761 } // namespace Kratos.
762 
763 #endif // KRATOS_DISCONTINUOUS_2D_UTILITIES_INCLUDED defined
764 
765 
This utility can be used to calculate the enriched shape function for tetrahedra element.
Definition: discont_2d.h:41
static int CalculateTriangleDiscontinuousShapeFunctions_ZeroInBoundary(TMatrixType const &rPoints, TGradientType const &DN_DX, TVectorType rDistances, TVectorType &rVolumes, TMatrixType &rGPShapeFunctionValues, TVectorType &rPartitionsSign, std::vector< TMatrixType > &rGradientsValue, TMatrixType &NEnriched, TVectorType &face_gauss_N, TVectorType &face_gauss_Nenriched, double &face_Area, TVectorType &face_n, unsigned int &type_of_cut)
Definition: discont_2d.h:312
static int CalculateTriangleDiscontinuousShapeFunctions(TMatrixType const &rPoints, TGradientType const &DN_DX, TVectorType rDistances, TVectorType &rVolumes, TMatrixType &rGPShapeFunctionValues, TVectorType &rPartitionsSign, std::vector< TMatrixType > &rGradientsValue, TMatrixType &Nenriched, TVectorType &face_gauss_N, TVectorType &face_gauss_Nenriched, double &face_Area, TVectorType &face_n, unsigned int &type_of_cut)
The method to calculate the enriched shape functions for given triangle.
Definition: discont_2d.h:97
Definition: amatrix_interface.h:41
#define KRATOS_THROW_ERROR(ExceptionType, ErrorMessage, MoreInfo)
Definition: define.h:77
#define KRATOS_CATCH(MoreInfo)
Definition: define.h:110
#define KRATOS_TRY
Definition: define.h:109
REF: G. R. Cowper, GAUSSIAN QUADRATURE FORMULAS FOR TRIANGLES.
Definition: mesh_condition.cpp:21
KratosZeroMatrix< double > ZeroMatrix
Definition: amatrix_interface.h:559
x2
Definition: generate_frictional_mortar_condition.py:122
x1
Definition: generate_frictional_mortar_condition.py:121
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
integer i
Definition: TensorModule.f:17