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.
cutting_iso_app.h
Go to the documentation of this file.
1 // KRATOS __ __ _____ ____ _ _ ___ _ _ ____
2 // | \/ | ____/ ___|| | | |_ _| \ | |/ ___|
3 // | |\/| | _| \___ \| |_| || || \| | | _
4 // | | | | |___ ___) | _ || || |\ | |_| |
5 // |_| |_|_____|____/|_| |_|___|_| \_|\____| APPLICATION
6 //
7 // License: BSD License
8 // license: MeshingApplication/license.txt
9 //
10 // Main authors: jirazabal
11 //
12 
13 #if !defined(KRATOS_CUTTING_ISOSURFACE_APPLICATION)
14 #define KRATOS_CUTTING_ISOSURFACE_APPLICATION
15 
16 // External excludes
17 #ifdef _OPENMP
18 #include <omp.h>
19 #endif
20 
21 // System includes
22 #include <string>
23 #include <iostream>
24 #include <cstdlib>
25 #include <cmath>
26 #include <algorithm>
27 
28 /* Project includes */
29 #include "includes/define.h"
30 #include "includes/model_part.h"
31 #include "includes/variables.h"
33 #include "utilities/math_utils.h"
39 
40 namespace Kratos
41 {
42 
44 
53 {
54 public:
55 
61  typedef boost::numeric::ublas::vector<Matrix> Matrix_Order_Tensor;
62  typedef boost::numeric::ublas::vector<Vector> Vector_Order_Tensor;
63  typedef boost::numeric::ublas::vector<Vector_Order_Tensor> Node_Vector_Order_Tensor;
64  typedef Node PointType;
65  typedef Node ::Pointer PointPointerType;
66  typedef std::vector<PointType::Pointer> PointVector;
67 
71 
74 
76  virtual ~Cutting_Isosurface_Application() = default;
77 
78 
80 
90  template <class TDataType>
91 
92  void GenerateVariableCut(ModelPart& mr_model_part, ModelPart& mr_new_model_part, Variable<TDataType>& variable, double isovalue, int isosurface_number, float tolerance)
93  {
94  KRATOS_WATCH("Generating Isosurface with the following data:")
95  KRATOS_WATCH(variable);
96  KRATOS_WATCH(isovalue);
98 
99  boost::numeric::ublas::vector<array_1d<int, 2 > > Position_Node;
100  boost::numeric::ublas::vector<int> List_New_Nodes;
101 
102  compressed_matrix<int> Coord;
103  ModelPart& this_model_part = mr_model_part;
104  ModelPart& new_model_part = mr_new_model_part;
105 
106  vector<double> Value_Nodes(this_model_part.Elements().size()); //value of the variable in each node
107  vector<int> Elems_In_Isosurface( this_model_part.Elements().size()); //our (int) vector, where we write 1 when the element is cut by the isosurface, when it is 2, it means we have 2 triangles (4 cutting points)
108  int number_of_triangles = 0;
109 
110  //finished creating the variables and vector/matrix needed. now we have to call the subroutines.
111 
112  CSR_Row_Matrix_Mod(this_model_part, Coord);
113 
114  FirstLoop(this_model_part, Coord, variable, isovalue, number_of_triangles, Elems_In_Isosurface, tolerance);
115 
116  Create_List_Of_New_Nodes_Mod(this_model_part, new_model_part, Coord, List_New_Nodes, Position_Node);
117 
118  Calculate_Coordinate_And_Insert_New_Nodes_Mod(this_model_part, new_model_part, Position_Node, List_New_Nodes, variable, isovalue, tolerance);
119 
120  GenerateElements (this_model_part, new_model_part, Position_Node, Elems_In_Isosurface, Coord, variable, isosurface_number);
121 
122  KRATOS_WATCH("Finished generating isosurface")
123  KRATOS_CATCH("")
124  }
125 
128 
130 
136  void AddModelPartElements(ModelPart& mr_model_part, ModelPart& mr_new_model_part, int number )
137  {
138  ModelPart& this_model_part = mr_model_part;
139  NodesArrayType::iterator it_begin_node_old = this_model_part.Nodes().ptr_begin();
140  ModelPart& new_model_part = mr_new_model_part;
141 
142  KRATOS_WATCH("Adding Skin Conditions to the new model part, added in layer:")
143  KRATOS_WATCH(number)
144  KRATOS_TRY
145 
146  vector<int> Element_Nodes( this_model_part.Nodes().size()); //our (int) vector, where we write -1 when the node is part of the condition faces
147  int number_of_tetrahedras = 0;
148  int number_of_nodes = 0; //same as above
149  int number_of_previous_nodes = 0; // nodes from the previous conditions (planes) created
150 
151  ElementsArrayType& rElements = this_model_part.Elements();
152 
153  if (new_model_part.Nodes().size()!=0) //it means this is not the first plane that has to be created
154  {
155  NodesArrayType& rNodes_new = new_model_part.Nodes(); //i need the model part just to check the id of the new nodes.
156  NodesArrayType::iterator it_end_node_new = rNodes_new.ptr_end();
157  NodesArrayType::iterator it_begin_node_new = rNodes_new.ptr_begin();
158  number_of_previous_nodes=(it_end_node_new-it_begin_node_new);
159  KRATOS_WATCH(number_of_previous_nodes)
160  }
161  else //nothing. number of triangles and nodes already set to 0
162  {
163  KRATOS_WATCH("First Cutting Plane");
164  }
165 
166  //we loop all the nodes in the old model part and copy the ones used by conditions to the new model part:
167  for (unsigned int index=0 ; index != this_model_part.Nodes().size() ; ++index)
168  {
169  ++number_of_nodes; //one new node!
170  Element_Nodes[index] = number_of_nodes + number_of_previous_nodes; //we give this node consecutives ids. now we create the new node
171  ModelPart::NodesContainerType::iterator it_node = this_model_part.Nodes().begin()+index;
172  Node ::Pointer pnode = new_model_part.CreateNewNode(number_of_nodes+number_of_previous_nodes, it_node->X(), it_node->Y(), it_node->Z()); //recordar que es el nueevo model part!!
173  pnode->SetBufferSize(this_model_part.NodesBegin()->GetBufferSize());
174  pnode->GetValue(FATHER_NODES).resize(0);
175  pnode->GetValue(FATHER_NODES).push_back( Node::WeakPointer( *it_node.base() ) ); // we keep the same size despite we only need one. to have everyhing with the same size
176  pnode->GetValue(FATHER_NODES).push_back( Node::WeakPointer( *it_node.base() ) );
177  pnode-> GetValue(WEIGHT_FATHER_NODES) = 1.0; //lo anterior no anduvo... creo q es así entonces. o hace falta el GetValue?
178 
179  pnode->X0() = it_node->X0();
180  pnode->Y0() = it_node->Y0();
181  pnode->Z0() = it_node->Z0();
182  }//finished the list of nodes to be added.
183 
184  //now to the conditions!
185  vector<int> tetrahedra_nodes(4); //here we'll save the nodes' ids with the new node names
186  Element const& rReferenceElement = KratosComponents<Element>::Get("Fluid3D"); //element type
187  Properties::Pointer properties = this_model_part.GetMesh().pGetProperties(number); //this will allow us later to turn this layer on/off in GID
188 
189  for(ModelPart::ElementsContainerType::iterator i_element = rElements.begin() ; i_element != rElements.end() ; i_element++) //looping all the elements
190  {
191  Geometry<Node >&geom = i_element->GetGeometry(); //current element(nodes, etc)
192  for(unsigned int i = 0; i < i_element->GetGeometry().size() ; i++) //looping the nodes
193  {
194  int position = this_model_part.Nodes().find(geom[i].Id()) - it_begin_node_old;
195  //int position = (geom[i].Id()) - 1; //the id of the node minus one is the position in the Condition_Node array (position0 = node1)
196  tetrahedra_nodes[i]=Element_Nodes[position]; // saving the i nodeId
197  } //nodes id saved. now we have to create the element.
198 
199  Tetrahedra3D4<Node > geometry(
200  new_model_part.Nodes()(tetrahedra_nodes[0]), //condition to be added
201  new_model_part.Nodes()(tetrahedra_nodes[1]),
202  new_model_part.Nodes()(tetrahedra_nodes[2]),
203  new_model_part.Nodes()(tetrahedra_nodes[3])
204  );
205 
206  Element::Pointer p_element = rReferenceElement.Create(number_of_tetrahedras+1, geometry, properties);
207  new_model_part.Elements().push_back(p_element);
208  ++number_of_tetrahedras;
209  }
210  KRATOS_WATCH(number_of_tetrahedras)
211  KRATOS_WATCH("Finished copying elements")
212  KRATOS_CATCH("")
213  }
214 
215 
218 
220 
226  void AddSkinConditions(ModelPart& mr_model_part, ModelPart& mr_new_model_part, int number )
227  {
228  ModelPart& this_model_part = mr_model_part;
229  ModelPart& new_model_part = mr_new_model_part;
230 
231  KRATOS_WATCH("Adding Skin Conditions to the new model part, added in layer:")
232  KRATOS_WATCH(number)
233  KRATOS_TRY
234  vector<int> Condition_Nodes( this_model_part.Nodes().size()); //our (int) vector, where we write -1 when the node is part of the condition faces
235  int number_of_triangles = 0; //we set it to zero to start
236  int number_of_nodes = 0; //same as above
237  int number_of_previous_nodes = 0; // nodes from the previous conditions (planes) created
238 
239  new_model_part.GetNodalSolutionStepVariablesList() = this_model_part.GetNodalSolutionStepVariablesList();
240  new_model_part.AddNodalSolutionStepVariable(FATHER_NODES);
241  new_model_part.AddNodalSolutionStepVariable(WEIGHT_FATHER_NODES);
242 
243  ConditionsArrayType& rConditions = this_model_part.Conditions();
244  //ConditionsArrayType::iterator cond_it_begin = rConditions.ptr_begin();
245  //ConditionsArrayType::iterator cond_it_end = rConditions.ptr_end();
246 
247  ConditionsArrayType& rConditions_new = new_model_part.Conditions();
248  ConditionsArrayType::iterator cond_it_end_new = rConditions_new.ptr_end();
249  ConditionsArrayType::iterator cond_it_begin_new = rConditions_new.ptr_begin();
250 
251  if (new_model_part.Nodes().size()!=0) //it means this is not the first plane that has to be created
252  {
253  NodesArrayType& rNodes_new = new_model_part.Nodes(); //i need the model part just to check the id of the new nodes.
254  NodesArrayType::iterator it_end_node_new = rNodes_new.ptr_end();
255  NodesArrayType::iterator it_begin_node_new = rNodes_new.ptr_begin();
256  number_of_previous_nodes=(it_end_node_new-it_begin_node_new);
257  number_of_triangles=cond_it_end_new - cond_it_begin_new ;
258  KRATOS_WATCH(number_of_triangles)
259  KRATOS_WATCH(number_of_previous_nodes)
260  //KRATOS_CATCH("")
261  }
262  else //nothing. number of triangles and nodes already set to 0
263  {
264  KRATOS_WATCH("First Cutting Plane");
265  }
266 
267  for (unsigned int index=0 ; index != this_model_part.Nodes().size() ; ++index) Condition_Nodes[index]=0; //initializing in zero the whole vector (meaning no useful nodes for the condition layer)
268 
269  for(ModelPart::ConditionsContainerType::iterator i_condition = rConditions.begin() ; i_condition != rConditions.end() ; i_condition++)
270  {
271  Geometry<Node >&geom = i_condition->GetGeometry();
272  for(unsigned int i = 0; i < i_condition->GetGeometry().size() ; i++)
273  {
274  int position = (geom[i].Id()) - 1; //the id of the node minus one is the position in the Condition_Node array (position0 = node1)
275  Condition_Nodes[position] = -1 ; //a -1 means we need this node!
276  }
277  }//done. now we know all the nodes that will have to be added to the new model part.
278 
279  //we loop all the nodes in the old model part and copy the ones used by conditions to the new model part:
280  for (unsigned int index=0 ; index != this_model_part.Nodes().size() ; ++index)
281  {
282  if (Condition_Nodes[index]==-1)
283  {
284  ++number_of_nodes; //one new node!
285  Condition_Nodes[index] = number_of_nodes + number_of_previous_nodes; //we give this node consecutives ids. now we create the new node
286  ModelPart::NodesContainerType::iterator it_node = this_model_part.Nodes().begin()+index;
287  Node ::Pointer pnode = new_model_part.CreateNewNode(number_of_nodes+number_of_previous_nodes, it_node->X(), it_node->Y(), it_node->Z()); //recordar que es el nueevo model part!!
288  pnode->SetBufferSize(this_model_part.NodesBegin()->GetBufferSize());
289  pnode->GetValue(FATHER_NODES).resize(0);
290  pnode->GetValue(FATHER_NODES).push_back( Node::WeakPointer( *it_node.base() ) ); // we keep the same size despite we only need one. to have everyhing with the same size
291  pnode->GetValue(FATHER_NODES).push_back( Node::WeakPointer( *it_node.base() ) );
292  pnode-> GetValue(WEIGHT_FATHER_NODES) = 1.0; //lo anterior no anduvo... creo q es así entonces. o hace falta el GetValue?
293 
294  pnode->X0() = it_node->X0();
295  pnode->Y0() = it_node->Y0();
296  pnode->Z0() = it_node->Z0();
297  }
298  }//finished the list of nodes to be added.
299 
300  //now to the conditions!
301  vector<int> triangle_nodes(3); //here we'll save the nodes' ids with the new node names
302  Condition const& rReferenceCondition = KratosComponents<Condition>::Get("SurfaceCondition3D3N"); //condition type
303  Properties::Pointer properties = this_model_part.GetMesh().pGetProperties(number); //this will allow us later to turn this layer on/off in GID
304 
305  for(ModelPart::ConditionsContainerType::iterator i_condition = rConditions.begin() ; i_condition != rConditions.end() ; i_condition++) //looping all the conditions
306  {
307  Geometry<Node >&geom = i_condition->GetGeometry(); //current condition(nodes, etc)
308  for(unsigned int i = 0; i < i_condition->GetGeometry().size() ; i++) //looping the nodes
309  {
310  int position = (geom[i].Id()) - 1; //the id of the node minus one is the position in the Condition_Node array (position0 = node1)
311  triangle_nodes[i]=Condition_Nodes[position]; // saving the i nodeId
312  } //nodes id saved. now we have to create the element.
313  Triangle3D3<Node > geometry(
314  new_model_part.Nodes()(triangle_nodes[0]), //condition to be added
315  new_model_part.Nodes()(triangle_nodes[1]),
316  new_model_part.Nodes()(triangle_nodes[2])
317  );
318  Condition::Pointer p_condition = rReferenceCondition.Create(number_of_triangles+1, geometry, properties); //está bien? acá la verdad ni idea. sobre todo number_of_triangles (la posición). o debe ser un puntero de elemento en vez de un entero?
319  new_model_part.Conditions().push_back(p_condition);
320  ++number_of_triangles;
321  }
322  KRATOS_WATCH("Finished copying conditions surfaces")
323  KRATOS_CATCH("")
324  }
325 
328 
330 
331  void CSR_Row_Matrix_Mod(ModelPart& this_model_part, compressed_matrix<int>& Coord)
332  {
333  NodesArrayType& pNodes = this_model_part.Nodes();
334  Coord.resize(pNodes.size(), pNodes.size());
335  NodesArrayType::iterator i_begin = pNodes.ptr_begin();
336  NodesArrayType::iterator i_end = pNodes.ptr_end();
337 
338  std::vector<unsigned int> aux(10000);
339 
340  for (ModelPart::NodeIterator i = i_begin; i != i_end; ++i)
341  {
342  int index_i = i->Id() - 1;
343  GlobalPointersVector< Node >& neighb_nodes = i->GetValue(NEIGHBOUR_NODES);
344  Coord.push_back(index_i, index_i, -1); //only modification added, now the diagonal is filled with -1 too.
345 
346  unsigned int active = 0;
347  for (GlobalPointersVector< Node >::iterator inode = neighb_nodes.begin(); inode != neighb_nodes.end(); inode++)
348  {
349  int index_j = inode->Id() - 1;
350  if (index_j > index_i)
351  {
352  aux[active] = index_j;
353  active++;
354  }
355  }
356  std::sort(aux.begin(), aux.begin() + active);
357 
358  for (unsigned int k = 0; k < active; k++)
359  {
360  Coord.push_back(index_i, aux[k], -1);
361  }
362  }
363  }
364 
366 
367  void FirstLoop(ModelPart& this_model_part, compressed_matrix<int>& Coord, Variable<double>& variable, double isovalue, int number_of_triangles, vector<int>& Elems_In_Isosurface, float tolerance)//
368  {
369  //varible is the variable that defines the isosurface
370  //isovalue is the value of the variable that defines the isosurface
371 
372  ElementsArrayType& rElements = this_model_part.Elements();
373 
374  ElementsArrayType::iterator it_begin = rElements.ptr_begin();
375  ElementsArrayType::iterator it_end = rElements.ptr_end();
376 
377 
378  array_1d<double, 4 > node_value; // value of the variable in the node
379  array_1d<double, 4 > neigh_value; // value of the variable in thr other node of the edge
380  array_1d<double, 4 > diff_node_value; // difference between the imposed value of the variable and its value in the node
381  array_1d<double, 4 > diff_neigh_value; // difference beween the variable value on other node of the edge (neighbour) and the imposed value
382  array_1d<unsigned int, 4 > list_matching_nodes; //used to save the new nodes that match exactly old nodes (very unlikely, but might be 4 for very plane elements)
383  unsigned int exact_nodes=0;
384 
385  number_of_triangles = 0;
386  int current_element= 0; //current element. it's a position. NOT ID!
387 
388  int number_of_cuts= 0; //this is the counter explained in the following lines
389 
390  for (ElementsArrayType::iterator it = it_begin; it != it_end; ++it) //looping all the elements
391  {
392  ++current_element;
393  number_of_cuts = 0;
394  exact_nodes = 0 ;
395  Geometry<Node >&geom = it->GetGeometry(); //geometry of the element
396  for(unsigned int i = 0; i < it->GetGeometry().size() ; i++) //size = 4 ; nodes per element. NOTICE WE'LL BE LOOPING THE EDGES TWICE. THIS IS A WASTE OF TIME BUT MAKES IT EASIER TO IDENTITY ELEMENTS. LOOK BELOW.
397  //when we have a triangle inside a thetraedra, its edges (or nodes) must be cut 3 times by the plane. if we loop all 2 times we can have a counter. when it's = 6 then we have a triangle. when tetrahedras are cutted 8 times then we have 2 triangles (or a cuatrilateral, the same)
398  {
399  node_value[i] = geom[i].FastGetSolutionStepValue(variable);
400 
401  diff_node_value[i] = isovalue - node_value[i];
402 
403  for(unsigned int j = 0; j < it->GetGeometry().size() ; j++) // looping on the neighbours
404  {
405  if (i != j) //(cant link node with itself)
406  {
407  neigh_value[j] = geom[j].FastGetSolutionStepValue(variable);
408 
409  diff_neigh_value[j] = isovalue - neigh_value[j];
410 
411  bool isovernode=false; // if true, then it can't be between the nodes
412 
413  if (fabs(diff_node_value[i]) < (tolerance)) //then our node is part of the plane (this should have been done before the loop on neighbours, but this way it is easier to read .
414  {
415  int index_i = geom[i].Id() -1 ; // i node id
416  Coord(index_i, index_i) = -2; //saving a -2 in the diagonal
417  isovernode=true;
418  number_of_cuts += 2; //since its neighbour wont take this case as a cut, we must save 2 cuts instead of one. (to reach number_of_cuts=6),
419  ++exact_nodes;
420  list_matching_nodes[i]= geom[i].Id();
421  break;
422  }
423  //check this last condition, used to avoid talking points that belong to other node. might cause some problems when the plane is almost paralel to an edge. to be improved! (it seems to be working correcly even when the edge is part of the plane.)
424  if ((diff_node_value[i]*diff_neigh_value[j]) < 0.0 && isovernode==false && fabs(diff_neigh_value[j]) > tolerance) // this means one has a bigger value than the imposed values and the other smaller, no need to do more checks, between there is a point that should match the value!
425  {
426  int index_i = geom[i].Id() - 1; //i node id
427  int index_j = geom[j].Id() - 1; //j node id
428  if (index_j > index_i) Coord(index_i, index_j) = -2; //saving a -2 in the upper side of the matrix
429  else Coord(index_j, index_i) = -2;
430  number_of_cuts += 1;
431  }
432  } //closing the i!=j if
433  } //closing the neighbour loop
434  } //closing the nodes loop
435  if (tolerance > (diff_node_value[0]) && tolerance > (diff_node_value[1]) && tolerance > (diff_node_value[2]) && tolerance > (diff_node_value[3])) //if all the nodes have the same the same value as the isovalue we do not take into account the triangles
436  {
437  for(unsigned int i = 0; i < it->GetGeometry().size() ; i++)
438  {
439  number_of_cuts -= 2;
440  --exact_nodes;
441  }
442  }
443  //now we have to save the data. we should get a list with the elements that will genereate triangles and the total number of triangles
444  Elems_In_Isosurface[current_element-1] = 0 ; //we initialize as 0
445 
446  if (number_of_cuts == 6) //it can be 8, in that case we have 2 triangles (the cut generates a square)
447  {
448  number_of_triangles +=1;
449  Elems_In_Isosurface[current_element-1] = 1 ; //i still don't know the number of the node so i'll have to do another loop later to assign to define node id's of each triangular element
450  }
451  else if (number_of_cuts == 8 ) // 2 triangles in the element!
452  {
453  number_of_triangles +=2;
454  Elems_In_Isosurface[ current_element-1] = 2 ;
455  }
456 
457  } //closing the elem loop
458  KRATOS_WATCH(number_of_triangles);
459  } //closing "FirstLoop"
460 
461  void FirstLoop(ModelPart& this_model_part, compressed_matrix<int>& Coord, Variable < array_1d<double,3> >& variable, double isovalue, int number_of_triangles, vector<int>& Elems_In_Isosurface, float tolerance)//
462  {
463  //varible is the variable that defines the isosurface
464  //isovalue is the value of the variable that defines the isosurface
465 
466  ElementsArrayType& rElements = this_model_part.Elements();
467 
468  ElementsArrayType::iterator it_begin = rElements.ptr_begin();
469  ElementsArrayType::iterator it_end = rElements.ptr_end();
470 
471  array_1d< array_1d<double,3>, 4 > vector_node_value; // value of the variable in the node
472  array_1d< array_1d<double,3>, 4 > vector_neigh_value; // value of the variable in the other node of the edge
473  array_1d<long double, 4 > squared_node_value;
474  array_1d<long double, 4 > squared_neigh_value;
475  double squared_isovalue = isovalue * isovalue;
476  double aux_value;
477  double a;
478  double b;
479  double c;
480  double weight1;
481  double weight2;
482  array_1d<double, 4 > node_value; // module of the variable in the node
483  array_1d<double, 4 > neigh_value; // module of the variable in the other node of the edge
484  array_1d<double, 4 > diff_node_value; // difference between the imposed value of the variable and its value in the node
485  array_1d<double, 4 > diff_neigh_value; // difference beween the variable value on other node of the edge (neighbour) and the imposed value
486  array_1d<unsigned int, 4 > list_matching_nodes; //used to save the new nodes that match exactly old nodes (very unlikely, but might be 4 for very plane elements)
487  unsigned int exact_nodes=0;
488 
489  number_of_triangles = 0;
490  int current_element= 0; //current element. it's a position. NOT ID!
491 
492  int number_of_cuts= 0; //this is the counter explained in the following lines
493 
494  for (ElementsArrayType::iterator it = it_begin; it != it_end; ++it) //looping all the elements
495  {
496  ++current_element;
497  number_of_cuts = 0;
498 
499  exact_nodes = 0 ;
500  Geometry<Node >&geom = it->GetGeometry(); //geometry of the element
501  for(unsigned int i = 0; i < it->GetGeometry().size() ; i++) //size = 4 ; nodes per element. NOTICE WE'LL BE LOOPING THE EDGES TWICE. THIS IS A WASTE OF TIME BUT MAKES IT EASIER TO IDENTITY ELEMENTS. LOOK BELOW.
502  //when we have a triangle inside a thetraedra, its edges (or nodes) must be cut 3 times by the plane. if we loop all 2 times we can have a counter. when it's = 6 then we have a triangle. when tetrahedras are cutted 8 times then we have 2 triangles (or a cuatrilateral, the same)
503  {
504  vector_node_value[i] = geom[i].FastGetSolutionStepValue(variable);
505 
506  squared_node_value[i] = (vector_node_value[i][0] * vector_node_value[i][0]) + (vector_node_value[i][1] * vector_node_value[i][1]) + (vector_node_value[i][2] * vector_node_value[i][2]);
507  node_value[i] = sqrt(squared_node_value[i]);
508 
509  diff_node_value[i] = isovalue - node_value[i];
510 
511  for(unsigned int j = 0; j < it->GetGeometry().size() ; j++) // looping on the neighbours
512  {
513  if (i != j) //(cant link node with itself)
514  {
515  vector_neigh_value[j] = geom[j].FastGetSolutionStepValue(variable);
516 
517  squared_neigh_value[j] = (vector_neigh_value[j][0] * vector_neigh_value[j][0]) + (vector_neigh_value[j][1] * vector_neigh_value[j][1]) + (vector_neigh_value[j][2] * vector_neigh_value[j][2]);
518  neigh_value[j] = sqrt(squared_neigh_value[j]);
519 
520  diff_neigh_value[j] = isovalue - neigh_value[j];
521 
522  aux_value = (vector_node_value[j][0] * vector_neigh_value[j][0]) + (vector_node_value[j][1] * vector_neigh_value[j][1]) + (vector_node_value[j][2] * vector_neigh_value[j][2]);
523 
524  a = squared_node_value[i] + squared_neigh_value[j] - (2 * aux_value);
525  b = 2 * (aux_value - squared_node_value[i]);
526  c = squared_node_value[i] - squared_isovalue;
527 
528  float tol = 0.000001;
529 
530  if (fabs(a) < tol)
531  {
532  if (a > 0) a = tol;
533  if (a < 0) a = -tol;
534  }
535  if (fabs(b) < tol) b = tol;
536  {
537  if (b > 0) b = tol;
538  if (b < 0) b = -tol;
539  }
540  if (fabs(c) < tol) c = tol;
541  {
542  if (c > 0) c = tol;
543  if (c < 0) c = -tol;
544  }
545 
546  weight1 = (-b + sqrt((b * b) - (4 * a * c))) / (2 * a);
547  weight2 = (-b - sqrt((b * b) - (4 * a * c))) / (2 * a);
548 
549  bool isovernode=false; // if true, then it can't be between the nodes
550 
551  if (fabs(diff_node_value[i]) <= (tolerance)) //then our node is part of the plane (this should have been done before the loop on neighbours, but this way it is easier to read .
552  {
553  int index_i = geom[i].Id() -1 ; // i node id
554  Coord(index_i, index_i) = -2; //saving a -2 in the diagonal
555  isovernode=true;
556  number_of_cuts += 2; //since its neighbour wont take this case as a cut, we must save 2 cuts instead of one. (to reach number_of_cuts=6),
557  ++exact_nodes;
558  list_matching_nodes[i]= geom[i].Id();
559  break;
560  }
561  //check this last condition, used to avoid talking points that belong to other node. might cause some problems when the plane is almost paralel to an edge. to be improved! (it seems to be working correcly even when the edge is part of the plane.)
562  if (weight1 > 0.0 && weight1 < 1.0 && fabs(diff_neigh_value[j]) > tolerance && isovernode==false) // this means one has a bigger value than the imposed values and the other smaller, no need to do more checks, between there is a point that should match the value!
563  {
564  int index_i = geom[i].Id() - 1; //i node id
565  int index_j = geom[j].Id() - 1; //j node id
566  if (index_j > index_i) Coord(index_i, index_j) = -2; //saving a -2 in the upper side of the matrix
567  else Coord(index_j, index_i) = -2;
568  isovernode=true;
569  number_of_cuts += 1;
570  break;
571  }
572  if (weight2 > 0.0 && weight2 < 1.0 && fabs(diff_neigh_value[j]) > tolerance && isovernode==false)
573  {
574  int index_i = geom[i].Id() - 1; //i node id
575  int index_j = geom[j].Id() - 1; //j node id
576  if (index_j > index_i) Coord(index_i, index_j) = -2; //saving a -2 in the upper side of the matrix
577  else Coord(index_j, index_i) = -2;
578  number_of_cuts += 1;
579  }
580  } //closing the i!=j if
581  } //closing the neighbour loop
582  } //closing the nodes loop
583  if (tolerance > (diff_node_value[0]) && tolerance > (diff_node_value[1]) && tolerance > (diff_node_value[2]) && tolerance > (diff_node_value[3])) //if all the nodes have the same the same value as the isovalue we do not take into account the triangles
584  {
585  for(unsigned int i = 0; i < it->GetGeometry().size() ; i++)
586  {
587  number_of_cuts -= 2;
588  --exact_nodes;
589  }
590  }
591  //now we have to save the data. we should get a list with the elements that will genereate triangles and the total number of triangles
592  Elems_In_Isosurface[current_element-1] = 0 ; //we initialize as 0
593 
594  if (number_of_cuts == 6) //it can be 8, in that case we have 2 triangles (the cut generates a square)
595  {
596  number_of_triangles +=1;
597  Elems_In_Isosurface[current_element-1] = 1 ; //i still don't know the number of the node so i'll have to do another loop later to assign to define node id's of each triangular element
598  }
599  else if (number_of_cuts == 8 ) // 2 triangles in the element!
600  {
601  number_of_triangles +=2;
602  Elems_In_Isosurface[ current_element-1] = 2 ;
603  }
604  } //closing the elem loop
605  KRATOS_WATCH(number_of_triangles);
606  } //closing "FirstLoop"
607 
609 
610  void Create_List_Of_New_Nodes_Mod(ModelPart& this_model_part, ModelPart& new_model_part, compressed_matrix<int>& Coord, boost::numeric::ublas::vector<int> &List_New_Nodes, boost::numeric::ublas::vector<array_1d<int, 2 > >& Position_Node) //surface number = 1 -- inf (but the first one should be always one!
611  {
612  unsigned int number_of_new_nodes = 0;
613  //NodesArrayType& pNodes = this_model_part.Nodes();
614  typedef compressed_matrix<int>::iterator1 i1_t;
615  typedef compressed_matrix<int>::iterator2 i2_t;
616 
618  for (i1_t i1 = Coord.begin1(); i1 != Coord.end1(); ++i1)
619  {
620  for (i2_t i2 = i1.begin(); i2 != i1.end(); ++i2)
621  {
622  if (Coord(i2.index1(), i2.index2()) == -2)
623  {
624  number_of_new_nodes++; //this should work without any change
625  }
626  }
627  }
628  if (number_of_new_nodes != 0)
629  {
631  List_New_Nodes.resize(number_of_new_nodes);
632  //int total_node = pNodes.size();
633 
634  if (new_model_part.Nodes().size()!=0) //it means this is not the first surface that has to be created
635  {
636  NodesArrayType& rNodes_new = new_model_part.Nodes(); //i need the model part just to check the id of the new nodes.
637  NodesArrayType::iterator it_end_node_new = rNodes_new.ptr_end();
638  NodesArrayType::iterator it_begin_node_new = rNodes_new.ptr_begin();
639  List_New_Nodes[0]=(it_end_node_new-it_begin_node_new)+1;
640  KRATOS_WATCH("New Cutting Surface")
641  first_cutting_surface = false;
642  }
643  else
644  {
645  List_New_Nodes[0]=1;
646  KRATOS_WATCH("First Cutting Surface");
647  first_cutting_surface = true;
648  }
649 
650  for (unsigned int i = 1; i < number_of_new_nodes; i++)
651  {
652  List_New_Nodes[i] = List_New_Nodes[0] + i; //just a list. necessary because other cutting surfaces might have been generated before
653  }
654 
656  Position_Node.resize(number_of_new_nodes);
657  unsigned int index = 0;
658  for (i1_t i1 = Coord.begin1(); i1 != Coord.end1(); ++i1)
659  {
660  for (i2_t i2 = i1.begin(); i2 != i1.end(); ++i2)
661  {
662  if (Coord(i2.index1(), i2.index2()) == -2)
663  {
664  Coord(i2.index1(), i2.index2()) = List_New_Nodes[index];
665  Position_Node[index][0] = i2.index1() + 1;
666  Position_Node[index][1] = i2.index2() + 1; //in the diagonal terms both indexes should point to the same node but still should work i guess
667  index++;
668  }
669  }
670  }
671  }
672  }
673 
675 
676  void Calculate_Coordinate_And_Insert_New_Nodes_Mod(ModelPart& this_model_part, ModelPart& new_model_part, const boost::numeric::ublas::vector<array_1d<int, 2 > >& Position_Node, const boost::numeric::ublas::vector<int> &List_New_Nodes, Variable<double>& variable, double isovalue, float tolerance)//,
677  {
678  array_1d<double, 3 > Coord_Node_1;
679  array_1d<double, 3 > Coord_Node_2;
680  array_1d<double, 3 > temp_dist;
681  array_1d<double, 3 > vector_distance;
682  double node_value;
683  double neigh_value;
684  double diff_node_value;
685  double diff_neigh_value;
686  double diff_neigh_node_value;
687  double weight;
688  boost::numeric::ublas::vector< array_1d<double, 3 > > Coordinate_New_Node;
689  Coordinate_New_Node.resize(Position_Node.size());
690 
691  new_model_part.GetNodalSolutionStepVariablesList() = this_model_part.GetNodalSolutionStepVariablesList();
692  new_model_part.AddNodalSolutionStepVariable(FATHER_NODES);
693  new_model_part.AddNodalSolutionStepVariable(WEIGHT_FATHER_NODES);
694 
695  for (unsigned int i = 0; i < Position_Node.size(); i++) //looping the new nodes
696  {
698  const int& node_i = Position_Node[i][0];
699  const int& node_j = Position_Node[i][1];
700  ModelPart::NodesContainerType::iterator it_node1 = this_model_part.Nodes().find(node_i);
701  noalias(Coord_Node_1) = it_node1->Coordinates();
702  ModelPart::NodesContainerType::iterator it_node2 = this_model_part.Nodes().find(node_j);
703  noalias(Coord_Node_2) = it_node2->Coordinates();
704  //ok, now we have both coordinates. now we must define a weight coefficient based on the distance.
705  //this coeff will be =node_plane_distance/node_neigh_distance (linear interpolation)
706  node_value = it_node1->FastGetSolutionStepValue(variable);
707  neigh_value = it_node2->FastGetSolutionStepValue(variable);
708 
709  diff_node_value = isovalue - node_value;
710  diff_neigh_value = isovalue - neigh_value;
711  diff_neigh_node_value = neigh_value - node_value;
712 
713  vector_distance = Coord_Node_2 - Coord_Node_1;
714 
715  if (fabs(diff_node_value) < tolerance) weight = 0.0;
716  else if (fabs(diff_neigh_value) < tolerance) weight = 1.0;
717  else weight = diff_node_value / diff_neigh_node_value;
718 
719  if (weight > 1.00005) KRATOS_WATCH("**** something's wrong! weight higher than 1! ****");
720 
721  for (unsigned int index=0; index!=3; ++index) //we loop the 3 coordinates)
722  {
723  if (Position_Node[i][0]!=Position_Node[i][1]) Coordinate_New_Node[i][index] = Coord_Node_1[index] + vector_distance[index] * weight;
724  else Coordinate_New_Node[i][index] = Coord_Node_1[index]; //when both nodes are the same it doesnt make any sense to interpolate
725 
727  Node ::Pointer pnode = new_model_part.CreateNewNode(List_New_Nodes[i], Coordinate_New_Node[i][0], Coordinate_New_Node[i][1], Coordinate_New_Node[i][2]); //remember that is the new model part!!
728 
729  pnode->SetBufferSize(this_model_part.NodesBegin()->GetBufferSize());
730 
731  pnode->GetValue(FATHER_NODES).resize(0);
732  pnode->GetValue(FATHER_NODES).push_back( Node::WeakPointer( *it_node1.base() ) ); //saving data about fathers in the model part
733  pnode->GetValue(FATHER_NODES).push_back( Node::WeakPointer( *it_node2.base() ) );
734  pnode-> GetValue(WEIGHT_FATHER_NODES) = weight;
735 
736  pnode->X0() = (1.0 - weight) * (it_node1->X0()) + weight * it_node2->X0();
737  pnode->Y0() = (1.0 - weight) * (it_node1->Y0()) + weight * it_node2->Y0();
738  pnode->Z0() = (1.0 - weight) * (it_node1->Z0()) + weight * it_node2->Z0();
739  }
740  }
741  }
742 
743  void Calculate_Coordinate_And_Insert_New_Nodes_Mod(ModelPart& this_model_part, ModelPart& new_model_part, const boost::numeric::ublas::vector<array_1d<int, 2 > >& Position_Node, const boost::numeric::ublas::vector<int> &List_New_Nodes, Variable< array_1d< double, 3> >& variable, double isovalue, float tolerance)//,
744  {
745  array_1d<double, 3 > Coord_Node_1;
746  array_1d<double, 3 > Coord_Node_2;
747  array_1d<double, 3 > temp_dist;
748  array_1d<double, 3 > vector_distance;
749  array_1d<double, 3 > vector_node_value;
750  array_1d<double, 3 > vector_neigh_value;
751  double squared_node_value;
752  double squared_neigh_value;
753  double node_value;
754  double neigh_value;
755  double aux_value;
756  double squared_isovalue;
757  double a;
758  double b;
759  double c;
760  double diff_node_value;
761  double diff_neigh_value;
762  double weight;
763  double weight1;
764  double weight2;
765  boost::numeric::ublas::vector< array_1d<double, 3 > > Coordinate_New_Node;
766  Coordinate_New_Node.resize(Position_Node.size());
767 
768  new_model_part.GetNodalSolutionStepVariablesList() = this_model_part.GetNodalSolutionStepVariablesList();
769  new_model_part.AddNodalSolutionStepVariable(FATHER_NODES);
770  new_model_part.AddNodalSolutionStepVariable(WEIGHT_FATHER_NODES);
771 
772  for (unsigned int i = 0; i < Position_Node.size(); i++) //looping the new nodes
773  {
775  const int& node_i = Position_Node[i][0];
776  const int& node_j = Position_Node[i][1];
777  ModelPart::NodesContainerType::iterator it_node1 = this_model_part.Nodes().find(node_i);
778  noalias(Coord_Node_1) = it_node1->Coordinates();
779  ModelPart::NodesContainerType::iterator it_node2 = this_model_part.Nodes().find(node_j);
780  noalias(Coord_Node_2) = it_node2->Coordinates();
781  //ok, now we have both coordinates. now we must define a weight coefficient based on the distance.
782  //this coeff will be =node_plane_distance/node_neigh_distance (linear interpolation)
783 
784  vector_node_value = it_node1->FastGetSolutionStepValue(variable);
785  squared_node_value = (vector_node_value[0] * vector_node_value[0]) + (vector_node_value[1] * vector_node_value[1]) + (vector_node_value[2] * vector_node_value[2]);
786  node_value = sqrt(squared_node_value);
787 
788  vector_neigh_value = it_node2->FastGetSolutionStepValue(variable);
789  squared_neigh_value = (vector_neigh_value[0] * vector_neigh_value[0]) + (vector_neigh_value[1] * vector_neigh_value[1]) + (vector_neigh_value[2] * vector_neigh_value[2]);
790  neigh_value = sqrt(squared_neigh_value);
791 
792  aux_value = (vector_node_value[0] * vector_neigh_value[0]) + (vector_node_value[1] * vector_neigh_value[1]) + (vector_node_value[2] * vector_neigh_value[2]);
793 
794  squared_isovalue = isovalue * isovalue;
795 
796  a = squared_node_value + squared_neigh_value - (2 * aux_value);
797  b = 2 * (aux_value - squared_node_value);
798  c = squared_node_value - squared_isovalue;
799 
800  float tol = 0.000001;
801 
802  if (fabs(a) < tol)
803  {
804  if (a > 0) a = tol;
805  if (a < 0) a = -tol;
806  }
807  if (fabs(b) < tol) b = tol;
808  {
809  if (b > 0) b = tol;
810  if (b < 0) b = -tol;
811  }
812  if (fabs(c) < tol) c = tol;
813  {
814  if (c > 0) c = tol;
815  if (c < 0) c = -tol;
816  }
817 
818  diff_node_value = isovalue - node_value;
819  diff_neigh_value = isovalue - neigh_value;
820 
821  vector_distance = Coord_Node_2 - Coord_Node_1;
822 
823  if (fabs(diff_node_value) < tolerance) weight = 0.0;
824  else if (fabs(diff_neigh_value) < tolerance) weight = 1.0;
825  else
826  {
827  weight1 = (-b + sqrt((b * b) - (4 * a * c))) / (2 * a);
828  weight2 = (-b - sqrt((b * b) - (4 * a * c))) / (2 * a);
829  if (weight1 < 1.0 && weight1 > 0.0) weight = weight1;
830  else if (weight2 < 1.0 && weight2 > 0.0) weight = weight2;
831  }
832  if (weight > 1.00005) KRATOS_WATCH("**** something's wrong! weight higher than 1! ****");
833 
834  for (unsigned int index=0; index!=3; ++index) //we loop the 3 coordinates)
835  {
836  if (Position_Node[i][0]!=Position_Node[i][1]) Coordinate_New_Node[i][index] = Coord_Node_1[index] + vector_distance[index] * weight;
837  else Coordinate_New_Node[i][index] = Coord_Node_1[index]; //when both nodes are the same it doesnt make any sense to interpolate
838 
840  Node ::Pointer pnode = new_model_part.CreateNewNode(List_New_Nodes[i], Coordinate_New_Node[i][0], Coordinate_New_Node[i][1], Coordinate_New_Node[i][2]); //remember that is the new model part!!
841 
842  pnode->SetBufferSize(this_model_part.NodesBegin()->GetBufferSize());
843 
844  pnode->GetValue(FATHER_NODES).resize(0);
845  pnode->GetValue(FATHER_NODES).push_back( Node::WeakPointer( *it_node1.base() ) ); //saving data about fathers in the model part
846  pnode->GetValue(FATHER_NODES).push_back( Node::WeakPointer( *it_node2.base() ) );
847  pnode-> GetValue(WEIGHT_FATHER_NODES) = weight;
848 
849  pnode->X0() = (1.0 - weight) * (it_node1->X0()) + weight * it_node2->X0();
850  pnode->Y0() = (1.0 - weight) * (it_node1->Y0()) + weight * it_node2->Y0();
851  pnode->Z0() = (1.0 - weight) * (it_node1->Z0()) + weight * it_node2->Z0();
852  }
853  weight = 0;
854  weight1 = 0;
855  weight2 = 0;
856  }
857  }
858 
860 
861  void GenerateElements (ModelPart& this_model_part, ModelPart& new_model_part, const boost::numeric::ublas::vector<array_1d<int, 4 > >& Position_Node, vector<int> Elems_In_Isosurface, compressed_matrix<int>& Coord, Variable<double>& variable, int surface_number)
862  {
863  array_1d<double, 3 > temp_vector1;
864  array_1d<double, 3 > temp_vector2;
865  array_1d<double, 3 > temp_vector3;
866  array_1d<double, 3 > temp_vector4;
867  array_1d<double, 3 > temp_vector5;
868  array_1d<double, 3 > Coord_Node;
869  array_1d<double, 3 > Coord_Node_1;
870  array_1d<double, 3 > Coord_Node_2;
871  array_1d<double, 3 > Coord_Node_3;
872  array_1d<double, 3 > Coord_Node_4;
873  array_1d<double, 3 > vector_max;
874  array_1d<double, 3 > vector_min;
875  array_1d<double, 3 > vector_normal;
876  double dist2; //to be used when there are 2 triangles in the tetrahedra
877  double dist3;
878  double control;
879  array_1d<int, 6 > nodes_for_2triang; //to be used when there are 2 triangles
880  array_1d<double, 4 > node_value;
881  unsigned int temp_int;
882  unsigned int first_element=0;
883 
884  ElementsArrayType& rElements_old = this_model_part.Elements();
885  ElementsArrayType::iterator it_begin_old = rElements_old.ptr_begin();
886  ElementsArrayType::iterator it_end_old = rElements_old.ptr_end();
887 
888  ElementsArrayType& rElements_new = new_model_part.Elements();
889  ElementsArrayType::iterator it_begin_new = rElements_new.ptr_begin();
890  ElementsArrayType::iterator it_end_new = rElements_new.ptr_end();
891 
892  boost::numeric::ublas::vector< array_1d<double, 3 > > Coordinate_New_Node;
893  Coordinate_New_Node.resize(Position_Node.size());
894 
895  if (first_cutting_surface == false) //it means this is not the first surface that has to be created
896  {
897  first_element=(it_end_new-it_begin_new);
898  KRATOS_WATCH("New Cutting Surface")
899  KRATOS_WATCH(first_element)
900  }
901  else
902  {
903  first_element=0; //or we're creating the first elements of the model part
904  KRATOS_WATCH("First Cutting Surface");
905  }
906 
907  Condition const& rReferenceCondition = KratosComponents<Condition>::Get("SurfaceCondition3D3N");
908  Properties::Pointer properties = this_model_part.GetMesh().pGetProperties(surface_number);
909 
910  int number_of_triangles = 0;
911  int current_element= 0;
912  unsigned int triangle_nodes= 0; // number of nodes already saved (of the current element)
913  bool new_node = false ; //used to check whether the current node has been saved or not
914 
915  array_1d<int, 4 > TriangleNodesArray; //nodes of the element to be generated. 4 in case they're 2 triangles
916  for (unsigned int k=0; k!=4; ++k)
917  {
918  TriangleNodesArray[k] = -1; //initializing in -1, meaning we have no nodes yet
919  }
920 
922  for (ElementsArrayType::iterator it = it_begin_old; it != it_end_old; ++it)
923  {
924  ++current_element;
925  triangle_nodes = 0; //starting, no nodes yet
927  if (Elems_In_Isosurface[current_element-1] == 1 ) //do not forget than can be both 1 or 2 triangles per tetrahedra. this is the simplest case. no need to check anything, we just create an element with the 3 nodes
928  {
929  //checking element conectivities
930  for(unsigned int i = 0; i < it->GetGeometry().size() ; i++)
931  {
932  Geometry<Node >&geom = it->GetGeometry(); //i node of the element
933  for(unsigned int j = 0; j < it->GetGeometry().size() ; j++) //j node of the element
934  {
935  new_node= true; //by default it's a new node
936  int index_i = geom[i].Id() - 1; //i node id
937  int index_j = geom[j].Id() - 1;
938  for (unsigned int l=0; l!=3; ++l)
939  {
940  if(TriangleNodesArray[l]==Coord(index_i, index_j) || Coord(index_i, index_j) <1 ) new_node=false; //if we have already saved this node or it has not been cutted, then we have no new node to add (coord(i,j)=-1)
941  }
942  //if it's a new node and the indexes are correct:
943  if (new_node && index_i<=index_j)
944  {
945  TriangleNodesArray[triangle_nodes]=Coord(index_i, index_j) ;
946  triangle_nodes++;
947  }
948  if (triangle_nodes ==3) break; //if we have already found 3 nodes then we can exit
949  } //closing j node loop
950  if (triangle_nodes ==3) break; //egal
951  } //closing i node loop
952  //now we have to check that the normal of the element is in the direction of the gradient of the scalar field. To do this the value of the variable in all the nodes of the element of the old model part is evaluated. With the biggest and the smallest values a vector between those coordinates is calculated. The inner product of that vector and the normal vector of the element should be positive.
953  for(unsigned int i = 0; i < it->GetGeometry().size() ; i++) //size = 4 ; nodes per element. NOTICE WE'LL BE LOOPING THE EDGES TWICE. THIS IS A WASTE OF TIME BUT MAKES IT EASIER TO IDENTITY ELEMENTS. LOOK BELOW.
954  {
955  Geometry<Node >&geom = it->GetGeometry();
956  node_value[i] = geom[i].FastGetSolutionStepValue(variable);
957 
958  Coord_Node[0] = geom[i].X();
959  Coord_Node[1] = geom[i].Y();
960  Coord_Node[2] = geom[i].Z();
961 
962  if(i == 0)
963  {
964  Coord_Node_1 = Coord_Node;
965  }
966  if(i == 1)
967  {
968  Coord_Node_2 = Coord_Node;
969  }
970  if(i == 2)
971  {
972  Coord_Node_3 = Coord_Node;
973  }
974  if(i == 3)
975  {
976  Coord_Node_4 = Coord_Node;
977  }
978  }
979 
980  if (node_value[0] >= node_value[1] && node_value[0] >= node_value[2] && node_value[0] >= node_value[3]) vector_max=Coord_Node_1;
981  if (node_value[1] > node_value[0] && node_value[1] > node_value[2] && node_value[1] > node_value[3]) vector_max=Coord_Node_2;
982  if (node_value[2] > node_value[0] && node_value[2] > node_value[1] && node_value[2] > node_value[3]) vector_max=Coord_Node_3;
983  if (node_value[3] > node_value[0] && node_value[3] > node_value[1] && node_value[3] > node_value[2]) vector_max=Coord_Node_4;
984 
985  if (node_value[0] < node_value[1] && node_value[0] < node_value[2] && node_value[0] < node_value[3]) vector_min=Coord_Node_1;
986  if (node_value[1] < node_value[0] && node_value[1] < node_value[2] && node_value[1] < node_value[3]) vector_min=Coord_Node_2;
987  if (node_value[2] < node_value[0] && node_value[2] < node_value[1] && node_value[2] < node_value[3]) vector_min=Coord_Node_3;
988  if (node_value[3] <= node_value[0] && node_value[3] <= node_value[1] && node_value[3] <= node_value[2]) vector_min=Coord_Node_4;
989 
990  vector_normal = vector_max - vector_min;
991 
992  ModelPart::NodesContainerType::iterator new_it_node1 = new_model_part.Nodes().find(TriangleNodesArray[0]);
993  noalias(temp_vector1) = new_it_node1->Coordinates(); //node 1
994 
995  ModelPart::NodesContainerType::iterator new_it_node2 = new_model_part.Nodes().find(TriangleNodesArray[1]);
996  noalias(temp_vector2) = new_it_node2->Coordinates(); //node 2
997 
998  ModelPart::NodesContainerType::iterator new_it_node3 = new_model_part.Nodes().find(TriangleNodesArray[2]);
999  noalias(temp_vector3) = new_it_node3->Coordinates(); //nodo 3
1000 
1001  temp_vector3 -=temp_vector1; //first edge
1002  temp_vector2 -=temp_vector1; //second edge
1003 
1004  MathUtils<double>::CrossProduct(temp_vector4, temp_vector2 , temp_vector3) ; //multiplying the 2 edges gives us a normal vector to the element
1005 
1006  if (inner_prod(temp_vector4,vector_normal)<0.0) //if the signs do not match then they have opposite directions
1007  {
1008  temp_int= TriangleNodesArray[2];
1009  TriangleNodesArray[2] = TriangleNodesArray[1];
1010  TriangleNodesArray[1] = temp_int; //we switch 2 nodes and ready
1011  }
1012 
1013  //generate new Elements
1014  Triangle3D3<Node > geom(
1015  new_model_part.Nodes()(TriangleNodesArray[0]),
1016  new_model_part.Nodes()(TriangleNodesArray[1]),
1017  new_model_part.Nodes()(TriangleNodesArray[2])
1018  );
1019 
1020  Condition::Pointer p_condition = rReferenceCondition.Create(number_of_triangles+1+first_element, geom, properties); //creating the element using the reference element. notice we are using the first element to avoid overriting nodes created by other cutting planes
1021  new_model_part.Conditions().push_back(p_condition);
1022  ++number_of_triangles;
1023 
1024  for (int counter=0; counter!=4; ++counter) TriangleNodesArray[counter]=0;//resetting, just in case
1025  for (int counter=0; counter!=3; ++counter)
1026  {
1027  Coord_Node_1[counter]=0;//resetting, just in case
1028  Coord_Node_2[counter]=0;//resetting, just in case
1029  Coord_Node_3[counter]=0;//resetting, just in case
1030  Coord_Node_4[counter]=0;//resetting, just in case
1031  vector_max[counter]=0;//resetting, just in case
1032  vector_min[counter]=0;//resetting, just in case
1033  vector_normal[counter]=0;//resetting, just in case
1034  }
1035  }//closing if elems_in_plane==6 (1 triangle)
1036 
1038  if (Elems_In_Isosurface[current_element-1] == 2) //now we have 2 elements. we cant just create 2 elements with a random node order because they might overlap and not cover the whole area defined by the trapezoid
1039  {
1040  //to fix this we'll first create a plane. see below
1041  //checking conectivities to find nodes
1042  for(unsigned int i = 0; i < it->GetGeometry().size() ; i++) //node i
1043  {
1044  Geometry<Node >&geom = it->GetGeometry();
1045  for(unsigned int j = 0; j < it->GetGeometry().size() ; j++) //node j
1046  {
1047  new_node= true;
1048  int index_i = geom[i].Id() - 1;
1049  int index_j = geom[j].Id() - 1;
1050  for (unsigned int l=0; l!=3; ++l)
1051  {
1052  if(TriangleNodesArray[l]==Coord(index_i, index_j) || Coord(index_i, index_j) < 1 ) //same as the part with only one triangle (look above)
1053  {
1054  new_node=false;
1055  }
1056  }
1057  if (new_node && index_i<index_j)
1058  {
1059  TriangleNodesArray[triangle_nodes]=Coord(index_i, index_j) ;
1060  triangle_nodes++;
1061  }
1062  if (triangle_nodes ==4) break; //once we've found the 4 nodes we can exit
1063  } //closing i loop
1064  if (triangle_nodes ==4) break;
1065  }
1066 
1067  //now we have to start checking the angles. the easiest way (i think) is creating a new plane using the original plane and a segment created by 2 nodes
1068  // using crossproduct we get a perpendicular plane. (either point can be used as origin).
1069  //since the cuadrilateral is created by the cut of teatraedra,
1070  //none of its internal angles can exceed 180 degrees and hence our new plane divides the cuadrilateral into 2 triangles if the distances to the other points have different signs (one on top and the other on the bottom of this new plane)
1071  //otherwise this edge is just an edge of the cuadrilateral and we have to look for another.
1072  //so let's begin! (we'll keep an origin node and we'll loop different nodes as the end of the segment till we find one that satisfies our criteria)
1073 
1074  for(unsigned int i = 0; i < it->GetGeometry().size() ; i++) //size = 4 ; nodes per element. NOTICE WE'LL BE LOOPING THE EDGES TWICE. THIS IS A WASTE OF TIME BUT MAKES IT EASIER TO IDENTITY ELEMENTS. LOOK BELOW.
1075  {
1076  Geometry<Node >&geom = it->GetGeometry();
1077  node_value[i] = geom[i].FastGetSolutionStepValue(variable);
1078 
1079  Coord_Node[0] = geom[i].X();
1080  Coord_Node[1] = geom[i].Y();
1081  Coord_Node[2] = geom[i].Z();
1082 
1083  if(i == 0) Coord_Node_1 = Coord_Node;
1084  if(i == 1) Coord_Node_2 = Coord_Node;
1085  if(i == 2) Coord_Node_3 = Coord_Node;
1086  if(i == 3) Coord_Node_4 = Coord_Node;
1087  }
1088 
1089  if (node_value[0] >= node_value[1] && node_value[0] >= node_value[2] && node_value[0] >= node_value[3]) vector_max=Coord_Node_1;
1090  if (node_value[1] > node_value[0] && node_value[1] > node_value[2] && node_value[1] > node_value[3]) vector_max=Coord_Node_2;
1091  if (node_value[2] > node_value[0] && node_value[2] > node_value[1] && node_value[2] > node_value[3]) vector_max=Coord_Node_3;
1092  if (node_value[3] > node_value[0] && node_value[3] > node_value[1] && node_value[3] > node_value[2]) vector_max=Coord_Node_4;
1093 
1094  if (node_value[0] < node_value[1] && node_value[0] < node_value[2] && node_value[0] < node_value[3]) vector_min=Coord_Node_1;
1095  if (node_value[1] < node_value[0] && node_value[1] < node_value[2] && node_value[1] < node_value[3]) vector_min=Coord_Node_2;
1096  if (node_value[2] < node_value[0] && node_value[2] < node_value[1] && node_value[2] < node_value[3]) vector_min=Coord_Node_3;
1097  if (node_value[3] <= node_value[0] && node_value[3] <= node_value[1] && node_value[3] <= node_value[2]) vector_min=Coord_Node_4;
1098 
1099  vector_normal = vector_max - vector_min;
1100  ModelPart::NodesContainerType::iterator it_node1 = new_model_part.Nodes().find(TriangleNodesArray[0]);
1101  noalias(temp_vector1) = it_node1->Coordinates(); //nodo 1 (origin)
1102  int jjj;
1103  int kkk;
1104 
1105  for (int iii=1; iii!=4; ++iii) //end node of the segment that will be used to create the plane (will be contained too)
1106  {
1107  it_node1=new_model_part.Nodes().find(TriangleNodesArray[iii]); //i node. we always keep node 0 as origin
1108  noalias(temp_vector2) = it_node1->Coordinates(); //node2 (end)
1109  noalias(temp_vector3) = temp_vector2 - temp_vector1; //segment 1-2
1110  //now i have to create the new plane
1111  MathUtils<double>::CrossProduct(temp_vector4, vector_normal , temp_vector3); //done. now temp_vector4 is the (normal to the) new plane, perpendicular to the one containing the triangles
1112  //the origin of the plane is temp_vector1 (temp_vector2 could also be used)
1113  //now we need to check distances to the other nodes (i+2 (let's call them jjj and i+3=kkk since we can't go futher than i=3)
1114 
1115  if (iii==1)
1116  {
1117  jjj=2;
1118  kkk=3;
1119  }
1120  else if (iii==2)
1121  {
1122  jjj=3;
1123  kkk=1;
1124  }
1125  else
1126  {
1127  jjj=2;
1128  kkk=1;
1129  }
1130 
1131  it_node1=new_model_part.Nodes().find(TriangleNodesArray[jjj]);
1132  noalias(temp_vector2) = it_node1->Coordinates(); //one of the remaining nodes;
1133 
1134  it_node1=new_model_part.Nodes().find(TriangleNodesArray[kkk]);
1135  noalias(temp_vector3) = it_node1->Coordinates(); //the other remaining node;
1136 
1137  noalias(temp_vector2) -=temp_vector1; // minus origin point of the plane
1138  noalias(temp_vector3) -=temp_vector1;
1139 
1140  dist2= inner_prod(temp_vector2,temp_vector4); // dot product
1141  dist3= inner_prod(temp_vector3,temp_vector4);
1142  control=dist2*dist3;
1143  //and that's it. we now have to check if the distance have different signs. to do so we multiply :
1144  if (control<0.0) //we have the right one! one node on each side of the plane generated by nodes 0 and iii
1145  {
1146  nodes_for_2triang[0] = TriangleNodesArray[0] ;
1147  nodes_for_2triang[1] = TriangleNodesArray[jjj];
1148  nodes_for_2triang[2] = TriangleNodesArray[iii]; //finish first triangle
1149  nodes_for_2triang[3] = TriangleNodesArray[iii];
1150  nodes_for_2triang[4] = TriangleNodesArray[kkk];
1151  nodes_for_2triang[5] = TriangleNodesArray[0]; //finish 2nd triangle
1152  break; //no need to keep looking, we can exit the loop
1153  } //closing the if
1154  }//by the time this finishes i should already have TriangleNodesArray
1155 
1156  //checking if the normal to our element is oriented correctly, just as we did when we had only 1 triangle (not commented here)
1157  for (int index=0 ; index !=2 ; ++index) //for triangle 1 and 2
1158  {
1159  ModelPart::NodesContainerType::iterator new_it_node1 = new_model_part.Nodes().find(nodes_for_2triang[index*3+0]);
1160  noalias(temp_vector1) = new_it_node1->Coordinates(); //node 1
1161 
1162  ModelPart::NodesContainerType::iterator new_it_node2 = new_model_part.Nodes().find(nodes_for_2triang[index*3+1]);
1163  noalias(temp_vector2) = new_it_node2->Coordinates(); //node 2
1164 
1165  ModelPart::NodesContainerType::iterator new_it_node3 = new_model_part.Nodes().find(nodes_for_2triang[index*3+2]);
1166  noalias(temp_vector3) = new_it_node3->Coordinates(); //nodo 3
1167 
1168  temp_vector3 -=temp_vector1;
1169  temp_vector2 -=temp_vector1;
1170  MathUtils<double>::CrossProduct(temp_vector4, temp_vector2 , temp_vector3) ;
1171 
1172  if (inner_prod(temp_vector4,vector_normal)<0.0)
1173  {
1174  temp_int= nodes_for_2triang[index*3+2];
1175  nodes_for_2triang[index*3+2] = nodes_for_2triang[index*3+1];
1176  nodes_for_2triang[index*3+1] = temp_int;
1177  }
1178 
1179  Triangle3D3<Node > geom(
1180  new_model_part.Nodes()(nodes_for_2triang[index*3+0]),
1181  new_model_part.Nodes()(nodes_for_2triang[index*3+1]),
1182  new_model_part.Nodes()(nodes_for_2triang[index*3+2])
1183  );
1184 
1185  Condition::Pointer p_condition = rReferenceCondition.Create(number_of_triangles+1+first_element, geom, properties);
1186 
1187  new_model_part.Conditions().push_back(p_condition);
1188  ++number_of_triangles;
1189  for (int counter=0; counter !=4; ++counter) TriangleNodesArray[counter]=0;//resetting, just in case
1190  for (int counter=0; counter !=3; ++counter)
1191  {
1192  Coord_Node_1[counter]=0;//resetting, just in case
1193  Coord_Node_2[counter]=0;//resetting, just in case
1194  Coord_Node_3[counter]=0;//resetting, just in case
1195  Coord_Node_4[counter]=0;//resetting, just in case
1196  vector_max[counter]=0;//resetting, just in case
1197  vector_min[counter]=0;//resetting, just in case
1198  vector_normal[counter]=0;//resetting, just in case
1199  }
1200  //for (int counter_2=0; counter_2 !=6; ++counter_2) nodes_for_2triang[counter_2]=0;//resetting, just in case
1201  }//cierro el index
1202  }//closing if elems_in_surface=2
1203  }//closing element loops
1204 
1205  }
1206 
1207  void GenerateElements (ModelPart& this_model_part, ModelPart& new_model_part, const boost::numeric::ublas::vector<array_1d<int, 4 > >& Position_Node, vector<int> Elems_In_Isosurface, compressed_matrix<int>& Coord, Variable<array_1d<double, 3 > >& variable, int surface_number)
1208  {
1209  array_1d<double, 3 > temp_vector1;
1210  array_1d<double, 3 > temp_vector2;
1211  array_1d<double, 3 > temp_vector3;
1212  array_1d<double, 3 > temp_vector4;
1213  array_1d<double, 3 > temp_vector5;
1214  array_1d<double, 3 > Coord_Node;
1215  array_1d<double, 3 > Coord_Node_1;
1216  array_1d<double, 3 > Coord_Node_2;
1217  array_1d<double, 3 > Coord_Node_3;
1218  array_1d<double, 3 > Coord_Node_4;
1219  array_1d<double, 3 > vector_max;
1220  array_1d<double, 3 > vector_min;
1221  array_1d<double, 3 > vector_normal;
1222  array_1d<int, 6 > nodes_for_2triang; //to be used when there are 2 triangles
1223  array_1d< array_1d <double, 3 >, 4 > vector_node_value;
1224  array_1d<double, 4 > node_value;
1225  unsigned int temp_int;
1226  unsigned int first_element=0;
1227 
1228  ElementsArrayType& rElements_old = this_model_part.Elements();
1229  ElementsArrayType::iterator it_begin_old = rElements_old.ptr_begin();
1230  ElementsArrayType::iterator it_end_old = rElements_old.ptr_end();
1231 
1232  ElementsArrayType& rElements_new = new_model_part.Elements();
1233  ElementsArrayType::iterator it_begin_new = rElements_new.ptr_begin();
1234  ElementsArrayType::iterator it_end_new = rElements_new.ptr_end();
1235 
1236  boost::numeric::ublas::vector< array_1d<double, 3 > > Coordinate_New_Node;
1237  Coordinate_New_Node.resize(Position_Node.size());
1238 
1239  if (first_cutting_surface == false) //it means this is not the first surface that has to be created
1240  {
1241  first_element=(it_end_new-it_begin_new);
1242  KRATOS_WATCH("New Cutting Surface")
1243  KRATOS_WATCH(first_element)
1244  }
1245  else
1246  {
1247  first_element=0; //or we're creating the first elements of the model part
1248  KRATOS_WATCH("First Cutting Surface");
1249  }
1250 
1251  Condition const& rReferenceCondition = KratosComponents<Condition>::Get("SurfaceCondition3D3N");
1252  Properties::Pointer properties = this_model_part.GetMesh().pGetProperties(surface_number);
1253 
1254  int number_of_triangles = 0;
1255  int current_element= 0;
1256  unsigned int triangle_nodes= 0; // number of nodes already saved (of the current element)
1257  bool new_node = false ; //used to check whether the current node has been saved or not
1258 
1259  array_1d<int, 4 > TriangleNodesArray; //nodes of the element to be generated. 4 in case they're 2 triangles
1260  for (unsigned int k=0; k!=4; ++k) TriangleNodesArray[k] = -1; //initializing in -1, meaning we have no nodes yet
1261 
1263  for (ElementsArrayType::iterator it = it_begin_old; it != it_end_old; ++it)
1264  {
1265  ++current_element;
1266  triangle_nodes = 0; //starting, no nodes yet
1267 
1269  if (Elems_In_Isosurface[current_element-1] == 1 ) //do not forget than can be both 1 or 2 triangles per tetrahedra. this is the simplest case. no need to check anything, we just create an element with the 3 nodes
1270  {
1271  //checking element conectivities
1272  for(unsigned int i = 0; i < it->GetGeometry().size() ; i++)
1273  {
1274  Geometry<Node >&geom = it->GetGeometry(); //i node of the element
1275  for(unsigned int j = 0; j < it->GetGeometry().size() ; j++) //j node of the element
1276  {
1277  new_node= true; //by default it's a new node
1278  int index_i = geom[i].Id() - 1; //i node id
1279  int index_j = geom[j].Id() - 1;
1280  for (unsigned int l=0; l!=3; ++l)
1281  {
1282  if(TriangleNodesArray[l]==Coord(index_i, index_j) || Coord(index_i, index_j) <1 ) new_node=false; //if we have already saved this node or it has not been cutted, then we have no new node to add (coord(i,j)=-1)
1283  }
1284  if (new_node && index_i<=index_j) //if it's a new node and the indexes are correct:
1285  {
1286  TriangleNodesArray[triangle_nodes]=Coord(index_i, index_j) ;
1287  triangle_nodes++;
1288  }
1289  if (triangle_nodes ==3) break; //if we have already found 3 nodes then we can exit
1290  } //closing j node loop
1291  if (triangle_nodes ==3) break; //egal
1292  } //closing i node loop
1293  //now we have to check that the normal of the element is in the direction of the gradient of the scalar field. To do this the value of the variable in all the nodes of the element of the old model part is evaluated. With the biggest and the smallest values a vector between those coordinates is calculated. The inner product of that vector and the normal vector of the element should be positive.
1294  for(unsigned int i = 0; i < it->GetGeometry().size() ; i++) //size = 4 ; nodes per element. NOTICE WE'LL BE LOOPING THE EDGES TWICE. THIS IS A WASTE OF TIME BUT MAKES IT EASIER TO IDENTITY ELEMENTS. LOOK BELOW.
1295  {
1296  Geometry<Node >&geom = it->GetGeometry();
1297  vector_node_value[i] = geom[i].FastGetSolutionStepValue(variable);
1298 
1299  node_value[i] = sqrt((vector_node_value[i][0] * vector_node_value[i][0]) + (vector_node_value[i][1] * vector_node_value[i][1]) + (vector_node_value[i][2] * vector_node_value[i][2]));
1300 
1301  Coord_Node[0] = geom[i].X();
1302  Coord_Node[1] = geom[i].Y();
1303  Coord_Node[2] = geom[i].Z();
1304 
1305  if(i == 0)
1306  {
1307  Coord_Node_1 = Coord_Node;
1308  }
1309  if(i == 1)
1310  {
1311  Coord_Node_2 = Coord_Node;
1312  }
1313  if(i == 2)
1314  {
1315  Coord_Node_3 = Coord_Node;
1316  }
1317  if(i == 3)
1318  {
1319  Coord_Node_4 = Coord_Node;
1320  }
1321  }
1322 
1323  if (node_value[0] >= node_value[1] && node_value[0] >= node_value[2] && node_value[0] >= node_value[3]) vector_max=Coord_Node_1;
1324  if (node_value[1] > node_value[0] && node_value[1] > node_value[2] && node_value[1] > node_value[3]) vector_max=Coord_Node_2;
1325  if (node_value[2] > node_value[0] && node_value[2] > node_value[1] && node_value[2] > node_value[3]) vector_max=Coord_Node_3;
1326  if (node_value[3] > node_value[0] && node_value[3] > node_value[1] && node_value[3] > node_value[2]) vector_max=Coord_Node_4;
1327 
1328  if (node_value[0] < node_value[1] && node_value[0] < node_value[2] && node_value[0] < node_value[3]) vector_min=Coord_Node_1;
1329  if (node_value[1] < node_value[0] && node_value[1] < node_value[2] && node_value[1] < node_value[3]) vector_min=Coord_Node_2;
1330  if (node_value[2] < node_value[0] && node_value[2] < node_value[1] && node_value[2] < node_value[3]) vector_min=Coord_Node_3;
1331  if (node_value[3] <= node_value[0] && node_value[3] <= node_value[1] && node_value[3] <= node_value[2]) vector_min=Coord_Node_4;
1332 
1333  vector_normal = vector_max - vector_min;
1334 
1335  ModelPart::NodesContainerType::iterator new_it_node1 = new_model_part.Nodes().find(TriangleNodesArray[0]);
1336  noalias(temp_vector1) = new_it_node1->Coordinates(); //node 1
1337 
1338  ModelPart::NodesContainerType::iterator new_it_node2 = new_model_part.Nodes().find(TriangleNodesArray[1]);
1339  noalias(temp_vector2) = new_it_node2->Coordinates(); //node 2
1340 
1341  ModelPart::NodesContainerType::iterator new_it_node3 = new_model_part.Nodes().find(TriangleNodesArray[2]);
1342  noalias(temp_vector3) = new_it_node3->Coordinates(); //nodo 3
1343 
1344  temp_vector3 -=temp_vector1; //first edge
1345  temp_vector2 -=temp_vector1; //second edge
1346 
1347  MathUtils<double>::CrossProduct(temp_vector4, temp_vector2 , temp_vector3) ; //multiplying the 2 edges gives us a normal vector to the element
1348 
1349  if (inner_prod(temp_vector4,vector_normal)<0.0) //if the signs do not match then they have opposite directions
1350  {
1351  temp_int= TriangleNodesArray[2];
1352  TriangleNodesArray[2] = TriangleNodesArray[1];
1353  TriangleNodesArray[1] = temp_int; //we switch 2 nodes and ready
1354  }
1355 
1356  //generate new Elements
1357  Triangle3D3<Node > geom(
1358  new_model_part.Nodes()(TriangleNodesArray[0]),
1359  new_model_part.Nodes()(TriangleNodesArray[1]),
1360  new_model_part.Nodes()(TriangleNodesArray[2])
1361  );
1362 
1363  Condition::Pointer p_condition = rReferenceCondition.Create(number_of_triangles+1+first_element, geom, properties); //creating the element using the reference element. notice we are using the first element to avoid overriting nodes created by other cutting planes
1364  new_model_part.Conditions().push_back(p_condition);
1365  ++number_of_triangles;
1366 
1367  for (int counter=0; counter!=4; ++counter) TriangleNodesArray[counter]=0;//resetting, just in case
1368  for (int counter=0; counter!=3; ++counter)
1369  {
1370  Coord_Node_1[counter]=0;//resetting, just in case
1371  Coord_Node_2[counter]=0;//resetting, just in case
1372  Coord_Node_3[counter]=0;//resetting, just in case
1373  Coord_Node_4[counter]=0;//resetting, just in case
1374  vector_max[counter]=0;//resetting, just in case
1375  vector_min[counter]=0;//resetting, just in case
1376  vector_normal[counter]=0;//resetting, just in case
1377  }
1378  }//closing if elems_in_plane==6 (1 triangle)
1379 
1381  if (Elems_In_Isosurface[current_element-1] == 2) //now we have 2 elements. we cant just create 2 elements with a random node order because they might overlap and not cover the whole area defined by the trapezoid
1382  {
1383  //to fix this we'll first create a plane. see below
1384  //checking conectivities to find nodes
1385  for(unsigned int i = 0; i < it->GetGeometry().size() ; i++) //node i
1386  {
1387  Geometry<Node >&geom = it->GetGeometry();
1388  for(unsigned int j = 0; j < it->GetGeometry().size() ; j++) //node j
1389  {
1390  new_node= true;
1391  int index_i = geom[i].Id() - 1;
1392  int index_j = geom[j].Id() - 1;
1393  for (unsigned int l=0; l!=3; ++l)
1394  {
1395  if(TriangleNodesArray[l]==Coord(index_i, index_j) || Coord(index_i, index_j) < 1 ) new_node=false; //same as the part with only one triangle (look above)
1396  }
1397  if (new_node && index_i<index_j)
1398  {
1399  TriangleNodesArray[triangle_nodes]=Coord(index_i, index_j) ;
1400  triangle_nodes++;
1401  }
1402  if (triangle_nodes ==4) break; //once we've found the 4 nodes we can exit
1403  } //closing i loop
1404  if (triangle_nodes ==4) break;
1405  }
1406  //now we have to start checking the angles. the easiest way (i think) is creating a new plane using the original plane and a segment created by 2 nodes
1407  // using crossproduct we get a perpendicular plane. (either point can be used as origin).
1408  //since the cuadrilateral is created by the cut of teatraedra,
1409  //none of its internal angles can exceed 180 degrees and hence our new plane divides the cuadrilateral into 2 triangles if the distances to the other points have different signs (one on top and the other on the bottom of this new plane)
1410  //otherwise this edge is just an edge of the cuadrilateral and we have to look for another.
1411  //so let's begin! (we'll keep an origin node and we'll loop different nodes as the end of the segment till we find one that satisfies our criteria)
1412  int jjj;
1413  int kkk;
1414  for (int iii=1; iii!=4; ++iii) //end node of the segment that will be used to create the plane (will be contained too)
1415  {
1416  if (iii==1)
1417  {
1418  jjj=2;
1419  kkk=3;
1420  }
1421  else if (iii==2)
1422  {
1423  jjj=3;
1424  kkk=1;
1425  }
1426  else
1427  {
1428  jjj=2;
1429  kkk=1;
1430  }
1431 
1432  nodes_for_2triang[0] = TriangleNodesArray[0] ;
1433  nodes_for_2triang[1] = TriangleNodesArray[jjj];
1434  nodes_for_2triang[2] = TriangleNodesArray[iii]; //finish first triangle
1435  nodes_for_2triang[3] = TriangleNodesArray[iii];
1436  nodes_for_2triang[4] = TriangleNodesArray[kkk];
1437  nodes_for_2triang[5] = TriangleNodesArray[0]; //finish 2nd triangle
1438  }//by the time this finishes i should already have TriangleNodesArray
1439  for(unsigned int i = 0; i < it->GetGeometry().size() ; i++) //size = 4 ; nodes per element. NOTICE WE'LL BE LOOPING THE EDGES TWICE. THIS IS A WASTE OF TIME BUT MAKES IT EASIER TO IDENTITY ELEMENTS. LOOK BELOW.
1440  {
1441  Geometry<Node >&geom = it->GetGeometry();
1442  vector_node_value[i] = geom[i].FastGetSolutionStepValue(variable);
1443 
1444  node_value[i] = sqrt((vector_node_value[i][0] * vector_node_value[i][0]) + (vector_node_value[i][1] * vector_node_value[i][1]) + (vector_node_value[i][2] * vector_node_value[i][2]));
1445 
1446  Coord_Node[0] = geom[i].X();
1447  Coord_Node[1] = geom[i].Y();
1448  Coord_Node[2] = geom[i].Z();
1449 
1450  if(i == 0) Coord_Node_1 = Coord_Node;
1451  if(i == 1) Coord_Node_2 = Coord_Node;
1452  if(i == 2) Coord_Node_3 = Coord_Node;
1453  if(i == 3) Coord_Node_4 = Coord_Node;
1454  }
1455 
1456  if (node_value[0] >= node_value[1] && node_value[0] >= node_value[2] && node_value[0] >= node_value[3]) vector_max=Coord_Node_1;
1457  if (node_value[1] > node_value[0] && node_value[1] > node_value[2] && node_value[1] > node_value[3]) vector_max=Coord_Node_2;
1458  if (node_value[2] > node_value[0] && node_value[2] > node_value[1] && node_value[2] > node_value[3]) vector_max=Coord_Node_3;
1459  if (node_value[3] > node_value[0] && node_value[3] > node_value[1] && node_value[3] > node_value[2]) vector_max=Coord_Node_4;
1460 
1461  if (node_value[0] < node_value[1] && node_value[0] < node_value[2] && node_value[0] < node_value[3]) vector_min=Coord_Node_1;
1462  if (node_value[1] < node_value[0] && node_value[1] < node_value[2] && node_value[1] < node_value[3]) vector_min=Coord_Node_2;
1463  if (node_value[2] < node_value[0] && node_value[2] < node_value[1] && node_value[2] < node_value[3]) vector_min=Coord_Node_3;
1464  if (node_value[3] <= node_value[0] && node_value[3] <= node_value[1] && node_value[3] <= node_value[2]) vector_min=Coord_Node_4;
1465 
1466  vector_normal = vector_max - vector_min;
1467 
1468  //checking if the normal to our element is oriented correctly, just as we did when we had only 1 triangle (not commented here)
1469 
1470  for (int index=0 ; index !=2 ; ++index) //for triangle 1 and 2
1471  {
1472  ModelPart::NodesContainerType::iterator new_it_node1 = new_model_part.Nodes().find(nodes_for_2triang[index*3+0]);
1473  noalias(temp_vector1) = new_it_node1->Coordinates(); //node 1
1474 
1475  ModelPart::NodesContainerType::iterator new_it_node2 = new_model_part.Nodes().find(nodes_for_2triang[index*3+1]);
1476  noalias(temp_vector2) = new_it_node2->Coordinates(); //node 2
1477 
1478  ModelPart::NodesContainerType::iterator new_it_node3 = new_model_part.Nodes().find(nodes_for_2triang[index*3+2]);
1479  noalias(temp_vector3) = new_it_node3->Coordinates(); //nodo 3
1480 
1481  temp_vector3 -=temp_vector1;
1482  temp_vector2 -=temp_vector1;
1483  MathUtils<double>::CrossProduct(temp_vector4, temp_vector2 , temp_vector3) ;
1484 
1485  if (inner_prod(temp_vector4,vector_normal)<0.0)
1486  {
1487  temp_int= nodes_for_2triang[index*3+2];
1488  nodes_for_2triang[index*3+2] = nodes_for_2triang[index*3+1];
1489  nodes_for_2triang[index*3+1] = temp_int;
1490  }
1491 
1492  Triangle3D3<Node > geom(
1493  new_model_part.Nodes()(nodes_for_2triang[index*3+0]),
1494  new_model_part.Nodes()(nodes_for_2triang[index*3+1]),
1495  new_model_part.Nodes()(nodes_for_2triang[index*3+2])
1496  );
1497 
1498  Condition::Pointer p_condition = rReferenceCondition.Create(number_of_triangles+1+first_element, geom, properties);
1499 
1500  new_model_part.Conditions().push_back(p_condition);
1501  ++number_of_triangles;
1502  for (int counter=0; counter!=4; ++counter) TriangleNodesArray[counter]=0;//resetting, just in case
1503  for (int counter=0; counter!=3; ++counter)
1504  {
1505  Coord_Node_1[counter]=0;//resetting, just in case
1506  Coord_Node_2[counter]=0;//resetting, just in case
1507  Coord_Node_3[counter]=0;//resetting, just in case
1508  Coord_Node_4[counter]=0;//resetting, just in case
1509  vector_max[counter]=0;//resetting, just in case
1510  vector_min[counter]=0;//resetting, just in case
1511  vector_normal[counter]=0;//resetting, just in case
1512  }
1513  //for (int counter_2=0; counter_2!=6; ++counter_2) nodes_for_2triang[counter_2]=0;//resetting, just in case
1514  }//cierro el index
1515  }//closing if elems_in_surface=2
1516  }//closing element loops
1517  }
1518 
1521 
1523 
1527  void UpdateCutData( ModelPart& new_model_part, ModelPart& old_model_part)
1528  {
1529  KRATOS_WATCH("Updating Cut Data");
1530  int step_data_size = old_model_part.GetNodalSolutionStepDataSize();
1531  array_1d<double, 3 > Coord_Node;
1532  //looping the nodes, no data is assigned to elements
1533  for (ModelPart::NodesContainerType::iterator it = new_model_part.NodesBegin(); it != new_model_part.NodesEnd(); it++)
1534  {
1535  double* node0_data = it->GetValue(FATHER_NODES)[0].SolutionStepData().Data(0); //current step only, (since we'll call this every timestep
1536  double* node1_data = it->GetValue(FATHER_NODES)[1].SolutionStepData().Data(0);
1537  double weight = it->GetValue(WEIGHT_FATHER_NODES);
1538  double* step_data = (it)->SolutionStepData().Data(0);
1539 
1540  //now we only have to copy the information from node_data to step_data
1541  for(int j= 0; j< step_data_size; j++) //looping all the variables and interpolating using weight
1542  {
1543  step_data[j] = (1.0-weight)*node0_data[j] + weight*node1_data[j];
1544  }
1545  }//closing node loop
1546  }//closing subroutine
1547 
1550 
1552 
1556  void DeleteCutData(ModelPart& new_model_part)
1557  {
1558  KRATOS_WATCH("Deleting Cut Data");
1559  new_model_part.Nodes().clear();
1560  new_model_part.Conditions().clear();
1561  new_model_part.Elements().clear();
1562  }
1563 
1566 private:
1567  bool first_cutting_surface; // to avoid checking again if we're working on the new cutting surface or if some have already been created
1568 
1569 };
1570 }
1571 
1572 #endif
Base class for all Conditions.
Definition: condition.h:59
virtual Pointer Create(IndexType NewId, NodesArrayType const &ThisNodes, PropertiesType::Pointer pProperties) const
It creates a new condition pointer.
Definition: condition.h:205
CUTTING ISOSURFACE APPLICATION.
Definition: cutting_iso_app.h:53
Node PointType
Definition: cutting_iso_app.h:64
Node ::Pointer PointPointerType
Definition: cutting_iso_app.h:65
void Create_List_Of_New_Nodes_Mod(ModelPart &this_model_part, ModelPart &new_model_part, compressed_matrix< int > &Coord, boost::numeric::ublas::vector< int > &List_New_Nodes, boost::numeric::ublas::vector< array_1d< int, 2 > > &Position_Node)
‍************************************************************************************************
Definition: cutting_iso_app.h:610
ModelPart::ConditionsContainerType ConditionsArrayType
Definition: cutting_iso_app.h:60
void AddSkinConditions(ModelPart &mr_model_part, ModelPart &mr_new_model_part, int number)
ADDSKINCONDITIONS: THIS FUNCTION ADDS TO THE NEW MODEL PART THE DATA OF THE CONDITIONS BELONGING TO T...
Definition: cutting_iso_app.h:226
ModelPart::NodesContainerType NodesArrayType
Definition: cutting_iso_app.h:58
void FirstLoop(ModelPart &this_model_part, compressed_matrix< int > &Coord, Variable< double > &variable, double isovalue, int number_of_triangles, vector< int > &Elems_In_Isosurface, float tolerance)
‍************************************************************************************************
Definition: cutting_iso_app.h:367
void CSR_Row_Matrix_Mod(ModelPart &this_model_part, compressed_matrix< int > &Coord)
LIST OF SUBROUTINES.
Definition: cutting_iso_app.h:331
Cutting_Isosurface_Application()=default
Default constructor.
boost::numeric::ublas::vector< Vector_Order_Tensor > Node_Vector_Order_Tensor
Definition: cutting_iso_app.h:63
void Calculate_Coordinate_And_Insert_New_Nodes_Mod(ModelPart &this_model_part, ModelPart &new_model_part, const boost::numeric::ublas::vector< array_1d< int, 2 > > &Position_Node, const boost::numeric::ublas::vector< int > &List_New_Nodes, Variable< double > &variable, double isovalue, float tolerance)
‍************************************************************************************************
Definition: cutting_iso_app.h:676
ModelPart::ElementsContainerType ElementsArrayType
Definition: cutting_iso_app.h:59
void AddModelPartElements(ModelPart &mr_model_part, ModelPart &mr_new_model_part, int number)
ADDMODELPARTELEMENTS: THIS FUNCTION ADDS TO THE NEW MODEL PART THE DATA BELONGING TO THE OLD MODEL PA...
Definition: cutting_iso_app.h:136
boost::numeric::ublas::vector< Matrix > Matrix_Order_Tensor
Definition: cutting_iso_app.h:61
void DeleteCutData(ModelPart &new_model_part)
DELETECUTDATA: THIS FUNCTION DELETES THE MESH FROM THE PREVIOUS TIME STEP.
Definition: cutting_iso_app.h:1556
std::vector< PointType::Pointer > PointVector
Definition: cutting_iso_app.h:66
void GenerateElements(ModelPart &this_model_part, ModelPart &new_model_part, const boost::numeric::ublas::vector< array_1d< int, 4 > > &Position_Node, vector< int > Elems_In_Isosurface, compressed_matrix< int > &Coord, Variable< double > &variable, int surface_number)
‍************************************************************************************************
Definition: cutting_iso_app.h:861
void Calculate_Coordinate_And_Insert_New_Nodes_Mod(ModelPart &this_model_part, ModelPart &new_model_part, const boost::numeric::ublas::vector< array_1d< int, 2 > > &Position_Node, const boost::numeric::ublas::vector< int > &List_New_Nodes, Variable< array_1d< double, 3 > > &variable, double isovalue, float tolerance)
Definition: cutting_iso_app.h:743
virtual ~Cutting_Isosurface_Application()=default
Destructor.
void GenerateElements(ModelPart &this_model_part, ModelPart &new_model_part, const boost::numeric::ublas::vector< array_1d< int, 4 > > &Position_Node, vector< int > Elems_In_Isosurface, compressed_matrix< int > &Coord, Variable< array_1d< double, 3 > > &variable, int surface_number)
Definition: cutting_iso_app.h:1207
boost::numeric::ublas::vector< Vector > Vector_Order_Tensor
Definition: cutting_iso_app.h:62
void FirstLoop(ModelPart &this_model_part, compressed_matrix< int > &Coord, Variable< array_1d< double, 3 > > &variable, double isovalue, int number_of_triangles, vector< int > &Elems_In_Isosurface, float tolerance)
Definition: cutting_iso_app.h:461
void GenerateVariableCut(ModelPart &mr_model_part, ModelPart &mr_new_model_part, Variable< TDataType > &variable, double isovalue, int isosurface_number, float tolerance)
This function Creates cutting isosurfaces by creating nodes and conditions (to define the conectiviti...
Definition: cutting_iso_app.h:92
void UpdateCutData(ModelPart &new_model_part, ModelPart &old_model_part)
UPDATECUTDATA: THIS FUNCTION UPDATES THE DATA OF THE NEW MODEL PART READING FROM THE DATA OF THE FATH...
Definition: cutting_iso_app.h:1527
Base class for all Elements.
Definition: element.h:60
virtual Pointer Create(IndexType NewId, NodesArrayType const &ThisNodes, PropertiesType::Pointer pProperties) const
It creates a new element pointer.
Definition: element.h:202
Geometry base class.
Definition: geometry.h:71
IndexType const & Id() const
Id of this Geometry.
Definition: geometry.h:964
This class is a vector which stores global pointers.
Definition: global_pointers_vector.h:61
boost::indirect_iterator< typename TContainerType::iterator > iterator
Definition: global_pointers_vector.h:79
iterator begin()
Definition: global_pointers_vector.h:221
iterator end()
Definition: global_pointers_vector.h:229
static const TComponentType & Get(const std::string &rName)
Retrieves a component with the specified name.
Definition: kratos_components.h:114
static T CrossProduct(const T &a, const T &b)
Performs the vector product of the two input vectors a,b.
Definition: math_utils.h:762
PropertiesType::Pointer pGetProperties(IndexType PropertiesId)
Definition: mesh.h:394
This class aims to manage meshes for multi-physics simulations.
Definition: model_part.h:77
MeshType::ConditionsContainerType ConditionsContainerType
Condintions container. A vector set of Conditions with their Id's as key.
Definition: model_part.h:183
NodeType::Pointer CreateNewNode(int Id, double x, double y, double z, VariablesList::Pointer pNewVariablesList, IndexType ThisIndex=0)
Definition: model_part.cpp:270
SizeType GetNodalSolutionStepDataSize()
Definition: model_part.h:571
MeshType::ElementsContainerType ElementsContainerType
Element container. A vector set of Elements with their Id's as key.
Definition: model_part.h:168
NodeIterator NodesBegin(IndexType ThisIndex=0)
Definition: model_part.h:487
ConditionsContainerType & Conditions(IndexType ThisIndex=0)
Definition: model_part.h:1381
void AddNodalSolutionStepVariable(VariableData const &ThisVariable)
Definition: model_part.h:532
MeshType::NodeIterator NodeIterator
Definition: model_part.h:134
ElementsContainerType & Elements(IndexType ThisIndex=0)
Definition: model_part.h:1189
MeshType::NodesContainerType NodesContainerType
Nodes container. Which is a vector set of nodes with their Id's as key.
Definition: model_part.h:128
NodeIterator NodesEnd(IndexType ThisIndex=0)
Definition: model_part.h:497
MeshType & GetMesh(IndexType ThisIndex=0)
Definition: model_part.h:1791
NodesContainerType & Nodes(IndexType ThisIndex=0)
Definition: model_part.h:507
VariablesList & GetNodalSolutionStepVariablesList()
Definition: model_part.h:549
This class defines the node.
Definition: node.h:65
A four node tetrahedra geometry with linear shape functions.
Definition: tetrahedra_3d_4.h:59
A three node 3D triangle geometry with linear shape functions.
Definition: triangle_3d_3.h:77
Variable class contains all information needed to store and retrive data from a data container.
Definition: variable.h:63
BOOST_UBLAS_INLINE void resize(size_type array_size, bool preserve=true)
Definition: array_1d.h:242
#define KRATOS_CATCH(MoreInfo)
Definition: define.h:110
#define KRATOS_WATCH(variable)
Definition: define.h:806
#define KRATOS_TRY
Definition: define.h:109
Parameters GetValue(Parameters &rParameters, const std::string &rEntry)
Definition: add_kratos_parameters_to_python.cpp:53
REF: G. R. Cowper, GAUSSIAN QUADRATURE FORMULAS FOR TRIANGLES.
Definition: mesh_condition.cpp:21
TExpression1Type::data_type inner_prod(AMatrix::MatrixExpression< TExpression1Type, TCategory1 > const &First, AMatrix::MatrixExpression< TExpression2Type, TCategory2 > const &Second)
Definition: amatrix_interface.h:592
T & noalias(T &TheMatrix)
Definition: amatrix_interface.h:484
Definition: control.py:1
active
Definition: generate_frictionless_components_mortar_condition.py:175
a
Definition: generate_stokes_twofluid_element.py:77
b
Definition: generate_total_lagrangian_mixed_volumetric_strain_element.py:31
c
Definition: generate_weakly_compressible_navier_stokes_element.py:108
int tol
Definition: hinsberg_optimization.py:138
int k
Definition: quadrature.py:595
int j
Definition: quadrature.py:648
int counter
Definition: script_THERMAL_CORRECT.py:218
integer i
Definition: TensorModule.f:17
integer l
Definition: TensorModule.f:17