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.
move_particle_utility.h
Go to the documentation of this file.
1 // KRATOS ___ ___ _ ___ __ ___ ___ ___ ___
2 // / __/ _ \| \| \ \ / /__| \_ _| __| __|
3 // | (_| (_) | .` |\ V /___| |) | || _|| _|
4 // \___\___/|_|\_| \_/ |___/___|_| |_| APPLICATION
5 //
6 // License: BSD License
7 // Kratos default license: kratos/license.txt
8 //
9 // Main authors: Pablo Becker
10 //
11 
12 #if !defined(KRATOS_MOVE_PARTICLE_UTILITY_FLUID_PFEM2_TRANSPORT_INCLUDED)
13 #define KRATOS_MOVE_PARTICLE_UTILITY_FLUID_PFEM2_TRANSPORT_INCLUDED
14 
15 // System includes
16 #include <string>
17 #include <iostream>
18 #include <algorithm>
19 
20 // External includes
21 
22 // Project includes
23 #include "includes/define.h"
24 #include "includes/node.h"
25 
27 #include "includes/dof.h"
28 #include "includes/variables.h"
29 #include "containers/array_1d.h"
31 #include "includes/mesh.h"
32 #include "utilities/math_utils.h"
34 
35 #include "utilities/geometry_utilities.h"
36 
37 #include "includes/model_part.h"
38 
39 
43 
45 
46 #include "geometries/line_2d_2.h"
49 #include "geometries/point.h"
50 
52 #include "convection_particle.h"
53 
54 #include "utilities/openmp_utils.h"
56 #include "time.h"
57 
58 //#include "processes/process.h"
59 
60 namespace Kratos
61 {
62  //this class is to be modified by the user to customize the interpolation process
63  template< unsigned int TDim>
65  {
66  public:
67 
69  typedef typename Configure::PointType PointType;
70  //typedef PointType::CoordinatesArrayType CoordinatesArrayType;
72  //typedef Configure::PointerType PointerType;
75  //typedef Configure::ResultPointerType ResultPointerType;
78  //typedef Configure::ContactPairType ContactPairType;
79  //typedef Configure::ContainerContactType ContainerContactType;
80  //typedef Configure::IteratorContactType IteratorContactType;
81  //typedef Configure::PointerContactType PointerContactType;
82  //typedef Configure::PointerTypeIterator PointerTypeIterator;
83 
85 
86  //template<unsigned int TDim>
87  MoveParticleUtilityScalarTransport(ModelPart& model_part, int maximum_number_of_particles)
88  : mr_model_part(model_part) , mmaximum_number_of_particles(maximum_number_of_particles) ,
89  mUnknownVar((model_part.GetProcessInfo()[CONVECTION_DIFFUSION_SETTINGS])->GetUnknownVariable()) ,
90  mProjectionVar((model_part.GetProcessInfo()[CONVECTION_DIFFUSION_SETTINGS])->GetProjectionVariable()) ,
91  mVelocityVar((model_part.GetProcessInfo()[CONVECTION_DIFFUSION_SETTINGS])->GetVelocityVariable()) ,
92  mMeshVelocityVar((model_part.GetProcessInfo()[CONVECTION_DIFFUSION_SETTINGS])->GetMeshVelocityVariable())
93  {
94  std::cout << "initializing moveparticle utility for scalar transport" << std::endl;
95 
96  Check();
97  //storing water and air density and their inverses, just in case it is needed for the streamline integration
98  //loop in elements to change their ID to their position in the array. Easier to get information later.
99  //DO NOT PARALELIZE THIS! IT MUST BE SERIAL!!!!!!!!!!!!!!!!!!!!!!
100  ModelPart::ElementsContainerType::iterator ielembegin = mr_model_part.ElementsBegin();
101  for(unsigned int ii=0; ii<mr_model_part.Elements().size(); ii++)
102  {
103  ModelPart::ElementsContainerType::iterator ielem = ielembegin+ii;
104  ielem->SetId(ii+1);
105  }
106  mlast_elem_id= (mr_model_part.ElementsEnd()-1)->Id();
107  int node_id=0;
108  // we look for the smallest edge. could be used as a weighting function when going lagrangian->eulerian instead of traditional shape functions(method currently used)
109  ModelPart::NodesContainerType::iterator inodebegin = mr_model_part.NodesBegin();
110  vector<unsigned int> node_partition;
111  #ifdef _OPENMP
112  int number_of_threads = omp_get_max_threads();
113  #else
114  int number_of_threads = 1;
115  #endif
116  OpenMPUtils::CreatePartition(number_of_threads, mr_model_part.Nodes().size(), node_partition);
117 
118  #pragma omp parallel for
119  for(int kkk=0; kkk<number_of_threads; kkk++)
120  {
121  for(unsigned int ii=node_partition[kkk]; ii<node_partition[kkk+1]; ii++)
122  {
123  ModelPart::NodesContainerType::iterator pnode = inodebegin+ii;
124  array_1d<double,3> position_node;
125  double distance=0.0;
126  position_node = pnode->Coordinates();
127  GlobalPointersVector< Node >& rneigh = pnode->GetValue(NEIGHBOUR_NODES);
128  //we loop all the nodes to check all the edges
129  const double number_of_neighbours = double(rneigh.size());
130  for( GlobalPointersVector<Node >::iterator inode = rneigh.begin(); inode!=rneigh.end(); inode++)
131  {
132  array_1d<double,3> position_difference;
133  position_difference = inode->Coordinates() - position_node;
134  double current_distance= sqrt(pow(position_difference[0],2)+pow(position_difference[1],2)+pow(position_difference[2],2));
135  //if (current_distance>distance)
136  // distance=current_distance;
137  distance += current_distance / number_of_neighbours;
138  }
139  //and we save the largest edge.
140  pnode->FastGetSolutionStepValue(MEAN_SIZE)=distance;
141 
142  node_id=pnode->GetId();
143  }
144  }
145  mlast_node_id=node_id;
146 
147  //we also calculate the element mean size in the same way, for the courant number
148  //also we set the right size to the LHS column for the pressure enrichments, in order to recover correctly the enrichment pressure
149  vector<unsigned int> element_partition;
150  OpenMPUtils::CreatePartition(number_of_threads, mr_model_part.Elements().size(), element_partition);
151 
152  //before doing anything we must reset the vector of nodes contained by each element (particles that are inside each element.
153  #pragma omp parallel for
154  for(int kkk=0; kkk<number_of_threads; kkk++)
155  {
156  for(unsigned int ii=element_partition[kkk]; ii<element_partition[kkk+1]; ii++)
157  {
158  ModelPart::ElementsContainerType::iterator ielem = ielembegin+ii;
159 
160  double mElemSize;
161  array_1d<double,3> Edge(3,0.0);
162  Edge = ielem->GetGeometry()[1].Coordinates() - ielem->GetGeometry()[0].Coordinates();
163  mElemSize = Edge[0]*Edge[0];
164  for (unsigned int d = 1; d < TDim; d++)
165  mElemSize += Edge[d]*Edge[d];
166 
167  for (unsigned int i = 2; i < (TDim+1); i++)
168  for(unsigned int j = 0; j < i; j++)
169  {
170  Edge = ielem->GetGeometry()[i].Coordinates() - ielem->GetGeometry()[j].Coordinates();
171  double Length = Edge[0]*Edge[0];
172  for (unsigned int d = 1; d < TDim; d++)
173  Length += Edge[d]*Edge[d];
174  if (Length < mElemSize) mElemSize = Length;
175  }
176  mElemSize = sqrt(mElemSize);
177  ielem->GetValue(MEAN_SIZE) = mElemSize;
178  }
179  }
180 
181 
182  //matrix containing the position of the 4/15/45 particles that we will seed at the beggining
183  BoundedMatrix<double, 5*(1+TDim), 3 > pos;
184  BoundedMatrix<double, 5*(1+TDim), (1+TDim) > N;
185 
186  int particle_id=0;
187  mnelems = mr_model_part.Elements().size();
188 
189  std::cout << "about to resize vectors" << std::endl;
190 
191 
192  //setting the right size to the vector containing the particles assigned to each element
193  //particles vector. this vector contains ALL the particles in the simulation.
194  mparticles_vector.resize(mnelems*mmaximum_number_of_particles);
195 
196  //and this vector contains the current number of particles that are in each element (currently zero)
197  mnumber_of_particles_in_elems.resize(mnelems);
198  mnumber_of_particles_in_elems=ZeroVector(mnelems);
199 
200  //when moving the particles, an auxiliary vector is necessary (to store the previous number)
201  mnumber_of_particles_in_elems_aux.resize(mnelems);
202 
203  //each element will have a list of pointers to all the particles that are inside.
204  //this vector contains the pointers to the vector of (particle) pointers of each element.
205  mvector_of_particle_pointers_vectors.resize(mnelems);
206  //int artz;
207  //std::cin >> artz;
208  int i_int=0; //careful! it's not the id, but the position inside the array!
209  std::cout << "about to create particles" << std::endl;
210  //now we seed: LOOP IN ELEMENTS
211  //using loop index, DO NOT paralelize this! change lines : mparticles_in_elems_pointers((ii*mmaximum_number_of_particles)+mparticles_in_elems_integers(ii)) = pparticle; and the next one
212 
213  moffset=0;
214  //Convection_Particle& firstparticle =mparticles_vector[0];
215  for(unsigned int ii=0; ii<mr_model_part.Elements().size(); ii++)
216  {
217  ModelPart::ElementsContainerType::iterator ielem = ielembegin+ii;
218  //(ielem->GetValue(BED_PARTICLE_POINTERS)) = ParticlePointerVector( mmaximum_number_of_particles*2, &firstparticle );
219  //ParticlePointerVector& particle_pointers = (ielem->GetValue(BED_PARTICLE_POINTERS));
220  //now we link the mpointers_to_particle_pointers_vectors to the corresponding element
221  //mpointers_to_particle_pointers_vectors(ii) = &particle_pointers;
222  //now we resize the vector of particle pointers. it is double sized because we move the particles from an initial position (first half) to a final position (second half).
223  //for(int j=0; j<(mmaximum_number_of_particles*2); j++)
224  // particle_pointers.push_back(&firstparticle);
225  mvector_of_particle_pointers_vectors[ii] = ParticlePointerVector( mmaximum_number_of_particles*2 );
226  ParticlePointerVector& particle_pointers = mvector_of_particle_pointers_vectors[ii];
227  //int & number_of_particles = ielem->GetValue(NUMBER_OF_BED_PARTICLES);
228  int & number_of_particles = mnumber_of_particles_in_elems[ii];
229  number_of_particles=0;
230 
231  Geometry< Node >& geom = ielem->GetGeometry();
232  //unsigned int elem_id = ielem->Id();
233  //mareas_vector[i_int]=CalculateArea(geom); UNUSED SO COMMENTED
234  ComputeGaussPointPositions_initial(geom, pos, N); //we also have the standard (4), and 45
235  //now we seed the particles in the current element
236  for (unsigned int j = 0; j < pos.size1(); j++)
237  {
238  ++particle_id;
239 
240  Convection_Particle& pparticle = mparticles_vector[particle_id-1];
241  pparticle.X()=pos(j,0);
242  pparticle.Y()=pos(j,1);
243  pparticle.Z()=pos(j,2);
244 
245  pparticle.GetEraseFlag()=false;
246 
247  float & scalar1= pparticle.GetScalar1();
248  scalar1=0.0;
249 
250  for (unsigned int k = 0; k < (TDim+1); k++)
251  {
252  scalar1 += N(j, k) * geom[k].FastGetSolutionStepValue(mUnknownVar);
253  }
254 
255 
256  particle_pointers(j) = &pparticle;
257  number_of_particles++ ;
258 
259  }
260  ++i_int;
261  }
262 
263  m_nparticles=particle_id; //we save the last particle created as the total number of particles we have. For the moment this is true.
264  KRATOS_WATCH(m_nparticles);
265  //KRATOS_WATCH(mlast_elem_id);
266  mparticle_printing_tool_initialized=false;
267  //std::cin >> artz;
268  }
269 
270 
272  {}
273 
274  void MountBin()
275  {
276  KRATOS_TRY
277 
278  //copy the elements to a new container, as the list will
279  //be shuffled duringthe construction of the tree
280  ContainerType& rElements = mr_model_part.ElementsArray();
281  IteratorType it_begin = rElements.begin();
282  IteratorType it_end = rElements.end();
283  //const int number_of_elem = rElements.size();
284 
286  paux.swap(mpBinsObjectDynamic);
287  //BinsObjectDynamic<Configure> mpBinsObjectDynamic(it_begin, it_end );
288 
289  std::cout << "finished mounting Bins" << std::endl;
290 
291  KRATOS_CATCH("")
292  }
293 
294  void MountBin(const double CellSize)
295  {
296  KRATOS_TRY
297 
298  //copy the elements to a new container, as the list will
299  //be shuffled duringthe construction of the tree
300  ContainerType& rElements = mr_model_part.ElementsArray();
301  IteratorType it_begin = rElements.begin();
302  IteratorType it_end = rElements.end();
303  typename BinsObjectDynamic<Configure>::Pointer paux = typename BinsObjectDynamic<Configure>::Pointer(new BinsObjectDynamic<Configure>(it_begin, it_end, CellSize ) );
304  paux.swap(mpBinsObjectDynamic);
305 
306  KRATOS_INFO("MoveParticleUtilityScalarTransport") << "Finished mounting Bins with cell size: " << CellSize << std::endl;
307 
308  KRATOS_CATCH("")
309  }
310 
312  {
313  KRATOS_TRY
314 
315  //ProcessInfo& CurrentProcessInfo = mr_model_part.GetProcessInfo();
316 
317  const double nodal_weight = 1.0/ (1.0 + double (TDim) );
318 
319  ModelPart::ElementsContainerType::iterator ielembegin = mr_model_part.ElementsBegin();
320  vector<unsigned int> element_partition;
321  #ifdef _OPENMP
322  int number_of_threads = omp_get_max_threads();
323  #else
324  int number_of_threads = 1;
325  #endif
326  OpenMPUtils::CreatePartition(number_of_threads, mr_model_part.Elements().size(), element_partition);
327 
328  #pragma omp parallel for
329  for(int kkk=0; kkk<number_of_threads; kkk++)
330  {
331  for(unsigned int ii=element_partition[kkk]; ii<element_partition[kkk+1]; ii++)
332  {
333  ModelPart::ElementsContainerType::iterator ielem = ielembegin+ii;
334  Geometry<Node >& geom = ielem->GetGeometry();
335 
336  array_1d<double, 3 >vector_mean_velocity=ZeroVector(3);
337 
338  for (unsigned int i=0; i != (TDim+1) ; i++)
339  vector_mean_velocity += geom[i].FastGetSolutionStepValue(mVelocityVar);
340  vector_mean_velocity *= nodal_weight;
341 
342  const double mean_velocity = sqrt ( pow(vector_mean_velocity[0],2) + pow(vector_mean_velocity[1],2) + pow(vector_mean_velocity[2],2) );
343  ielem->GetValue(MEAN_VEL_OVER_ELEM_SIZE) = mean_velocity / (ielem->GetValue(MEAN_SIZE));
344  }
345  }
346  KRATOS_CATCH("")
347  }
348 
349 
350 
351  //name self explained
353  {
354  KRATOS_TRY
355 
356  ModelPart::NodesContainerType::iterator inodebegin = mr_model_part.NodesBegin();
357  vector<unsigned int> node_partition;
358  #ifdef _OPENMP
359  int number_of_threads = omp_get_max_threads();
360  #else
361  int number_of_threads = 1;
362  #endif
363  OpenMPUtils::CreatePartition(number_of_threads, mr_model_part.Nodes().size(), node_partition);
364 
365  #pragma omp parallel for
366  for(int kkk=0; kkk<number_of_threads; kkk++)
367  {
368  for(unsigned int ii=node_partition[kkk]; ii<node_partition[kkk+1]; ii++)
369  {
370  ModelPart::NodesContainerType::iterator inode = inodebegin+ii;
371 
372  if (inode->IsFixed(mUnknownVar))
373  {
374  inode->FastGetSolutionStepValue(mUnknownVar)=inode->GetSolutionStepValue(mUnknownVar,1);
375  }
376  }
377  }
378 
379  KRATOS_CATCH("")
380  }
381 
383  {
384  KRATOS_TRY
385  ModelPart::NodesContainerType::iterator inodebegin = mr_model_part.NodesBegin();
386  vector<unsigned int> node_partition;
387  #ifdef _OPENMP
388  int number_of_threads = omp_get_max_threads();
389  #else
390  int number_of_threads = 1;
391  #endif
392  OpenMPUtils::CreatePartition(number_of_threads, mr_model_part.Nodes().size(), node_partition);
393 
394  #pragma omp parallel for
395  for(int kkk=0; kkk<number_of_threads; kkk++)
396  {
397  for(unsigned int ii=node_partition[kkk]; ii<node_partition[kkk+1]; ii++)
398  {
399  ModelPart::NodesContainerType::iterator inode = inodebegin+ii;
400  inode->FastGetSolutionStepValue(DELTA_SCALAR1) = inode->FastGetSolutionStepValue(mUnknownVar) - inode->FastGetSolutionStepValue(mProjectionVar) ;
401  }
402  }
403 
404  KRATOS_CATCH("")
405  }
406 
407 
410  {
411  KRATOS_TRY
412  ModelPart::NodesContainerType::iterator inodebegin = rNodes.begin();
413  vector<unsigned int> node_partition;
414  #ifdef _OPENMP
415  int number_of_threads = omp_get_max_threads();
416  #else
417  int number_of_threads = 1;
418  #endif
419  OpenMPUtils::CreatePartition(number_of_threads, rNodes.size(), node_partition);
420 
421  #pragma omp parallel for
422  for(int kkk=0; kkk<number_of_threads; kkk++)
423  {
424  for(unsigned int ii=node_partition[kkk]; ii<node_partition[kkk+1]; ii++)
425  {
426  ModelPart::NodesContainerType::iterator inode = inodebegin+ii;
427  inode->GetSolutionStepValue(OriginVariable,1) = inode->FastGetSolutionStepValue(OriginVariable);
428  }
429  }
430  KRATOS_CATCH("")
431  }
432 
433 
434  //to move all the particles across the streamlines. heavy task!
436  {
437 
438  KRATOS_TRY
439 
440  ProcessInfo& CurrentProcessInfo = mr_model_part.GetProcessInfo();
441 
442  const int offset = moffset; //the array of pointers for each element has twice the required size so that we use a part in odd timesteps and the other in even ones.
443  //moveparticlesdiff reads from the pointers of one part (ie odd) and saves into the other part (ie even part)
444  //since it is the only function in the whole procedure that does this, it must use alternatively one part and the other.
445  //KRATOS_WATCH(offset)
446 
447  bool even_timestep;
448  if (offset!=0) even_timestep=false;
449  else even_timestep=true;
450 
451  const int post_offset = mmaximum_number_of_particles*int(even_timestep); //and we also save the offset to know the location in which we will save the pointers after we've moved the particles
452  //KRATOS_WATCH(post_offset)
453 
454 
455  double delta_t = CurrentProcessInfo[DELTA_TIME];
456 
458  const unsigned int max_results = 10000;
459 
460  //double integration_distance= 2.0;
461 
462  max_nsubsteps = 10;
463  max_substep_dt=delta_t/double(max_nsubsteps);
464 
465  vector<unsigned int> element_partition;
466  #ifdef _OPENMP
467  int number_of_threads = omp_get_max_threads();
468  #else
469  int number_of_threads = 1;
470  #endif
471  OpenMPUtils::CreatePartition(number_of_threads, mr_model_part.Elements().size(), element_partition);
472 
473  ModelPart::ElementsContainerType::iterator ielembegin = mr_model_part.ElementsBegin();
474 
475 
476 
477  //before doing anything we must reset the vector of nodes contained by each element (particles that are inside each element.
478  #pragma omp parallel for
479  for(int kkk=0; kkk<number_of_threads; kkk++)
480  {
481  for(unsigned int ii=element_partition[kkk]; ii<element_partition[kkk+1]; ii++)
482  {
483  //ModelPart::ElementsContainerType::iterator old_element = ielembegin+ii;
484 
485  int & number_of_particles = mnumber_of_particles_in_elems[ii]; //old_element->GetValue(NUMBER_OF_BED_PARTICLES);
486 
487  mnumber_of_particles_in_elems_aux[ii]=number_of_particles;
488  mnumber_of_particles_in_elems[ii]=0;
489  //we reset the local vectors for a faster access;
490  }
491  }
492  std::cout << "convecting particles" << std::endl;
493  //We move the particles across the fixed mesh and saving change data into them (using the function MoveParticle)
494 
495  #pragma omp barrier
496 
497  #pragma omp parallel for
498  for(int kkk=0; kkk<number_of_threads; kkk++)
499  {
500 
501  ResultContainerType results(max_results);
502 
503  GlobalPointersVector< Element > elements_in_trajectory;
504  elements_in_trajectory.resize(20);
505 
506  for(unsigned int ielem=element_partition[kkk]; ielem<element_partition[kkk+1]; ielem++)
507  {
508  //for(unsigned int ielem=0; ielem<mr_model_part.Elements().size(); ielem++)
509  //{
510 
511  ModelPart::ElementsContainerType::iterator old_element = ielembegin+ielem;
512  const int old_element_id = old_element->Id();
513 
514  ParticlePointerVector& old_element_particle_pointers = mvector_of_particle_pointers_vectors(old_element_id-1);
515 
516  if ( (results.size()) !=max_results)
517  results.resize(max_results);
518 
519  unsigned int number_of_elements_in_trajectory=0; //excluding the origin one (current one, ielem)
520 
521  for(int ii=0; ii<(mnumber_of_particles_in_elems_aux(ielem)); ii++)
522  {
523 
524  Convection_Particle & pparticle = old_element_particle_pointers[offset+ii];
525 
526  Element::Pointer pcurrent_element( *old_element.base() );
527  ResultIteratorType result_begin = results.begin();
528  bool & erase_flag=pparticle.GetEraseFlag();
529  if (erase_flag==false){
530  MoveParticle(pparticle,pcurrent_element,elements_in_trajectory,number_of_elements_in_trajectory,result_begin,max_results); //saqué N de los argumentos, no lo necesito ya q empieza SIEMPRE en un nodo y no me importa donde termina
531 
532  const int current_element_id = pcurrent_element->Id();
533 
534  int & number_of_particles_in_current_elem = mnumber_of_particles_in_elems(current_element_id-1);
535  //int & number_of_water_particles_in_current_elem = mnumber_of_water_particles_in_elems(current_element_id-1);
536 
537  if (number_of_particles_in_current_elem<mmaximum_number_of_particles && erase_flag==false)
538  {
539  {
540 
541  ParticlePointerVector& current_element_particle_pointers = mvector_of_particle_pointers_vectors(current_element_id-1);
542 
543  #pragma omp critical
544  {
545  if (number_of_particles_in_current_elem<mmaximum_number_of_particles) // we cant go over this node, there's no room. otherwise we would be in the position of the first particle of the next element!!
546  {
547 
548  current_element_particle_pointers(post_offset+number_of_particles_in_current_elem) = &pparticle;
549 
550  number_of_particles_in_current_elem++ ;
551  if (number_of_particles_in_current_elem>mmaximum_number_of_particles)
552  KRATOS_WATCH("MAL");
553 
554  }
555  else
556  pparticle.GetEraseFlag()=true; //so we just delete it!
557  }
558  }
559  }
560  else
561  pparticle.GetEraseFlag()=true; //so we just delete it!
562 
563 
564 
565  }
566  }
567  }
568  }
569  /*
570  //now we pass info from the local vector to the elements:
571  #pragma omp parallel for
572  for(int kkk=0; kkk<number_of_threads; kkk++)
573  {
574  for(unsigned int ii=element_partition[kkk]; ii<element_partition[kkk+1]; ii++)
575  {
576  ModelPart::ElementsContainerType::iterator old_element = ielembegin+ii;
577 
578  old_element->GetValue(NUMBER_OF_BED_PARTICLES) = mnumber_of_particles_in_elems(ii);
579  //old_element->GetValue(NUMBER_OF_WATER_PARTICLES) = mnumber_of_water_particles_in_elems(ii);
580  }
581 
582  }
583  */
584 
585  //after having changed everything we change the status of the modd_timestep flag:
586  moffset = post_offset;; //
587 
588  KRATOS_CATCH("")
589  }
590 
592  {
593  KRATOS_TRY
594 
595  //ProcessInfo& CurrentProcessInfo = mr_model_part.GetProcessInfo();
596  //const double delta_t =CurrentProcessInfo[DELTA_TIME];
597  const double threshold= 0.0/(double(TDim)+1.0);
598 
599 
600  std::cout << "projecting info to mesh" << std::endl;
601 
602 
603  const int offset = moffset; //the array of pointers for each element has twice the required size so that we use a part in odd timesteps and the other in even ones.
604  //KRATOS_WATCH(offset) //(flag managed only by MoveParticles
605 
606  //we must project data from the particles (lagrangian) into the eulerian mesh
607  //ValuesVectorType eulerian_nodes_old_temperature;
608  //int nnodes = mr_model_part.Nodes().size();
609  //array_1d<double,(n_nodes)> eulerian_nodes_sumweights;
610 
611  //we save data from previous time step of the eulerian mesh in case we must reuse it later cos no particle was found around the nodes
612  //though we could've use a bigger buffer, to be changed later!
613  //after having saved data, we reset them to zero, this way it's easier to add the contribution of the surrounding particles.
614  ModelPart::NodesContainerType::iterator inodebegin = mr_model_part.NodesBegin();
615  vector<unsigned int> node_partition;
616  #ifdef _OPENMP
617  int number_of_threads = omp_get_max_threads();
618  #else
619  int number_of_threads = 1;
620  #endif
621  OpenMPUtils::CreatePartition(number_of_threads, mr_model_part.Nodes().size(), node_partition);
622 
623  #pragma omp parallel for
624  for(int kkk=0; kkk<number_of_threads; kkk++)
625  {
626  for(unsigned int ii=node_partition[kkk]; ii<node_partition[kkk+1]; ii++)
627  {
628  ModelPart::NodesContainerType::iterator inode = inodebegin+ii;
629  inode->FastGetSolutionStepValue(mProjectionVar)=0.0;
630  inode->FastGetSolutionStepValue(YP)=0.0;
631  }
632 
633  }
634 
635  //adding contribution, loop on elements, since each element has stored the particles found inside of it
636  vector<unsigned int> element_partition;
637  OpenMPUtils::CreatePartition(number_of_threads, mr_model_part.Elements().size(), element_partition);
638 
639  ModelPart::ElementsContainerType::iterator ielembegin = mr_model_part.ElementsBegin();
640  #pragma omp parallel for
641  for(int kkk=0; kkk<number_of_threads; kkk++)
642  {
643  for(unsigned int ii=element_partition[kkk]; ii<element_partition[kkk+1]; ii++)
644  {
645  ModelPart::ElementsContainerType::iterator ielem = ielembegin+ii;
646 
647  array_1d<double,3*(TDim+1)> nodes_positions;
648  array_1d<double,(TDim+1)> nodes_added_scalar1 = ZeroVector((TDim+1));
649  array_1d<double,(TDim+1)> nodes_addedweights = ZeroVector((TDim+1));
650  //array_1d<double,(TDim+1)> weighting_inverse_divisor;
651 
652  Geometry<Node >& geom = ielem->GetGeometry();
653 
654  for (int i=0 ; i!=(TDim+1) ; ++i)
655  {
656  nodes_positions[i*3+0]=geom[i].X();
657  nodes_positions[i*3+1]=geom[i].Y();
658  nodes_positions[i*3+2]=geom[i].Z();
659  //weighting_inverse_divisor[i]=1.0/((geom[i].FastGetSolutionStepValue(MEAN_SIZE))*1.01);
660  }
663 
664  //int & number_of_particles_in_elem= ielem->GetValue(NUMBER_OF_BED_PARTICLES);
665  //ParticlePointerVector& element_particle_pointers = (ielem->GetValue(BED_PARTICLE_POINTERS));
666  int & number_of_particles_in_elem= mnumber_of_particles_in_elems[ii];
667  ParticlePointerVector& element_particle_pointers = mvector_of_particle_pointers_vectors[ii];
668 
669 
670  for (int iii=0; iii<number_of_particles_in_elem ; iii++ )
671  {
672  if (iii==mmaximum_number_of_particles) //it means we are out of our portion of the array, abort loop!
673  break;
674 
675  Convection_Particle & pparticle = element_particle_pointers[offset+iii];
676 
677  if (pparticle.GetEraseFlag()==false)
678  {
679 
680  array_1d<double,3> & position = pparticle.Coordinates();
681 
682  const float& particle_scalar1 = pparticle.GetScalar1(); // -1 if water, +1 if air
683 
685  bool is_found = CalculatePosition(nodes_positions,position[0],position[1],position[2],N);
686  if (is_found==false) //something went wrong. if it was close enough to the edge we simply send it inside the element.
687  {
688  KRATOS_WATCH(N);
689  for (int j=0 ; j!=(TDim+1); j++)
690  if (N[j]<0.0 && N[j]> -1e-5)
691  N[j]=1e-10;
692 
693  }
694 
695  for (int j=0 ; j!=(TDim+1); j++) //going through the 3/4 nodes of the element
696  {
697  //double sq_dist = 0;
698  //these lines for a weighting function based on the distance (or square distance) from the node insteadof the shape functions
699  //for (int k=0 ; k!=(TDim); k++) sq_dist += ((position[k] - nodes_positions[j*3+k])*(position[k] - nodes_positions[j*3+k]));
700  //double weight = (1.0 - (sqrt(sq_dist)*weighting_inverse_divisor[j] ) );
701 
702  double weight=N(j)*N(j);
703  //weight=N(j)*N(j)*N(j);
704  if (weight<threshold) weight=1e-10;
705  if (weight<0.0) {KRATOS_WATCH(weight)}//;weight=0.0;KRATOS_WATCH(velocity);KRATOS_WATCH(N);KRATOS_WATCH(number_of_particles_in_elem);}//{KRATOS_WATCH(weight); KRATOS_WATCH(geom[j].Id()); KRATOS_WATCH(position);}
706  else
707  {
708  nodes_addedweights[j]+= weight;
709  //nodes_addedtemp[j] += weight * particle_temp;
710 
711  nodes_added_scalar1[j] += weight*particle_scalar1;
712 
713 
714  }//
715  }
716  }
717  }
718 
719  for (int i=0 ; i!=(TDim+1) ; ++i) {
720  geom[i].SetLock();
721  geom[i].FastGetSolutionStepValue(mProjectionVar) +=nodes_added_scalar1[i];
722  geom[i].FastGetSolutionStepValue(YP) +=nodes_addedweights[i];
723  geom[i].UnSetLock();
724  }
725  }
726  }
727 
728  #pragma omp parallel for
729  for(int kkk=0; kkk<number_of_threads; kkk++)
730  {
731  for(unsigned int ii=node_partition[kkk]; ii<node_partition[kkk+1]; ii++)
732  {
733  ModelPart::NodesContainerType::iterator inode = inodebegin+ii;
734  double sum_weights = inode->FastGetSolutionStepValue(YP);
735  if (sum_weights>0.00001)
736  {
737  //inode->FastGetSolutionStepValue(TEMPERATURE_OLD_IT)=(inode->FastGetSolutionStepValue(TEMPERATURE_OLD_IT))/sum_weights; //resetting the temperature
738  double & height = inode->FastGetSolutionStepValue(mProjectionVar);
739  height /=sum_weights; //resetting the density
740  }
741 
742  else //this should never happen because other ways to recover the information have been executed before, but leaving it just in case..
743  {
744  inode->FastGetSolutionStepValue(mProjectionVar)=inode->FastGetSolutionStepValue(mUnknownVar,1); //resetting the temperature
745  }
746  }
747  }
748 
749 
750  KRATOS_CATCH("")
751  }
752 
753 
754 
755  void TransferLagrangianToEulerianImp() //semi implicit
756  {
757  KRATOS_TRY
758 
759  // ProcessInfo& CurrentProcessInfo = mr_model_part.GetProcessInfo();
760 
761  std::cout << "projecting info to mesh (semi implicit)" << std::endl;
762 
763 
764  const int offset = moffset; //the array of pointers for each element has twice the required size so that we use a part in odd timesteps and the other in even ones.
765  //KRATOS_WATCH(offset) //(flag managed only by MoveParticles
766 
767  //we must project data from the particles (lagrangian) into the eulerian mesh
768  //ValuesVectorType eulerian_nodes_old_temperature;
769  //int nnodes = mr_model_part.Nodes().size();
770  //array_1d<double,(n_nodes)> eulerian_nodes_sumweights;
771 
772  //we save data from previous time step of the eulerian mesh in case we must reuse it later cos no particle was found around the nodes
773  //though we could've use a bigger buffer, to be changed later!
774  //after having saved data, we reset them to zero, this way it's easier to add the contribution of the surrounding particles.
775  ModelPart::NodesContainerType::iterator inodebegin = mr_model_part.NodesBegin();
776  vector<unsigned int> node_partition;
777  #ifdef _OPENMP
778  int number_of_threads = omp_get_max_threads();
779  #else
780  int number_of_threads = 1;
781  #endif
782  OpenMPUtils::CreatePartition(number_of_threads, mr_model_part.Nodes().size(), node_partition);
783 
784  #pragma omp parallel for
785  for(int kkk=0; kkk<number_of_threads; kkk++)
786  {
787  for(unsigned int ii=node_partition[kkk]; ii<node_partition[kkk+1]; ii++)
788  {
789  ModelPart::NodesContainerType::iterator inode = inodebegin+ii;
790  inode->FastGetSolutionStepValue(mProjectionVar)=0.0;
791  inode->FastGetSolutionStepValue(YP)=0.0;
792  }
793 
794  }
795 
796  //adding contribution, loop on elements, since each element has stored the particles found inside of it
797  vector<unsigned int> element_partition;
798  OpenMPUtils::CreatePartition(number_of_threads, mr_model_part.Elements().size(), element_partition);
799 
800  ModelPart::ElementsContainerType::iterator ielembegin = mr_model_part.ElementsBegin();
801  #pragma omp parallel for
802  for(int kkk=0; kkk<number_of_threads; kkk++)
803  {
804 
805  //creating a matrix for each of the problems.
806  BoundedMatrix<double, TDim+1 , TDim+1 > mass_matrix; // WE ONLY NEED ONE! they are the same for all the variables! //_x,mass_matrix_y,mass_matrix_z,mass_matrix_d; //mass matrices for the projected vel (x,y,z) and the distance
807  array_1d<double,(TDim+1)> rhs_scalar1;
808 
809  array_1d<double,3*(TDim+1)> nodes_positions;
810  array_1d<double,(TDim+1)> nodes_added_scalar1 = ZeroVector((TDim+1));
811  array_1d<double,(TDim+1)> nodes_addedweights = ZeroVector((TDim+1));
812 
813  for(unsigned int ii=element_partition[kkk]; ii<element_partition[kkk+1]; ii++)
814  {
815  ModelPart::ElementsContainerType::iterator ielem = ielembegin+ii;
816 
817  nodes_added_scalar1 = ZeroVector((TDim+1)); //resetting vectors
818  nodes_addedweights = ZeroVector((TDim+1)); //resetting vectors
819  mass_matrix = ZeroMatrix(TDim+1 , TDim+1 ); //resetting matrices. WE ONLY NEED ONE! they are the same for all the variable. only the rhs changes.
820  //mass_matrix_y = ZeroMatrix(TDim+1 , TDim+1 ); //resetting matrices
821  //mass_matrix_z = ZeroMatrix(TDim+1 , TDim+1 ); //resetting matrices
822  //mass_matrix_d = ZeroMatrix(TDim+1 , TDim+1 ); //resetting matrices
823  rhs_scalar1 = ZeroVector((TDim+1)); //resetting vectors
824 
825  Geometry<Node >& geom = ielem->GetGeometry();
826  const double elem_volume = geom.Area();
827 
828  for (int i=0 ; i!=(TDim+1) ; ++i) //saving the nodal positions for faster access
829  {
830  nodes_positions[i*3+0]=geom[i].X();
831  nodes_positions[i*3+1]=geom[i].Y();
832  nodes_positions[i*3+2]=geom[i].Z();
833  }
836 
837  //int & number_of_particles_in_elem= ielem->GetValue(NUMBER_OF_BED_PARTICLES);
838  //ParticlePointerVector& element_particle_pointers = (ielem->GetValue(BED_PARTICLE_POINTERS));
839  int & number_of_particles_in_elem= mnumber_of_particles_in_elems[ii];
840  ParticlePointerVector& element_particle_pointers = mvector_of_particle_pointers_vectors[ii];
841 
842  for (int iii=0; iii<number_of_particles_in_elem ; iii++ )
843  {
844  if (iii==mmaximum_number_of_particles) //it means we are out of our portion of the array, abort loop!
845  break;
846 
847  Convection_Particle & pparticle = element_particle_pointers[offset+iii];
848 
849  if (pparticle.GetEraseFlag()==false)
850  {
851 
852  array_1d<double,3> & position = pparticle.Coordinates();
853 
854  const float& particle_scalar1 = pparticle.GetScalar1(); // -1 if water, +1 if air
855 
857  bool is_found = CalculatePosition(nodes_positions,position[0],position[1],position[2],N);
858  if (is_found==false) //something went wrong. if it was close enough to the edge we simply send it inside the element.
859  {
860  KRATOS_WATCH(N);
861  for (int j=0 ; j!=(TDim+1); j++)
862  if (N[j]<0.0 && N[j]> -1e-5)
863  N[j]=1e-10;
864 
865  }
866 
867  for (int j=0 ; j!=(TDim+1); j++) //going through the 3/4 nodes of the element
868  {
869  double weight=N(j);
870  for (int k=0 ; k!=(TDim+1); k++) //building the mass matrix
871  mass_matrix(j,k) += weight*N(k);
872 
873  rhs_scalar1[j] += weight * double(particle_scalar1);
874 
875  //adding also a part with the lumped mass matrix to reduce overshoots and undershoots
876  if(true)
877  {
878  double this_particle_weight = weight*elem_volume/(double(number_of_particles_in_elem))*0.1; //can be increased or reduced to change the lumped mass contrubtion
879  nodes_addedweights[j]+= this_particle_weight;
880  nodes_added_scalar1[j] += this_particle_weight*particle_scalar1;
881  }
882  }
883  }
884  }
885 
886  //now we invert the matrix
887  BoundedMatrix<double, TDim+1 , TDim+1 > inverse_mass_matrix=ZeroMatrix(TDim+1 , TDim+1);
888  if constexpr (TDim==3)
889  InvertMatrix( mass_matrix, inverse_mass_matrix);
890  else
891  InvertMatrix3x3( mass_matrix, inverse_mass_matrix);
892  //and now compute the elemental contribution to the gobal system:
893 
894  if(number_of_particles_in_elem > static_cast<int>(TDim)*3) //otherwise it's impossible to define a correctly the gradients, therefore the results inside the element are useless.
895  {
896  for (int i=0 ; i!=(TDim+1); i++)
897  {
898  for (int j=0 ; j!=(TDim+1); j++)
899  {
900  nodes_added_scalar1[i] += inverse_mass_matrix(i,j)*rhs_scalar1[j]*elem_volume*(1.0/(double(1+TDim)));
901 
902  }
903  }
904  //and also to the mass matrix. LUMPED (but for the contribution of the grandient at elemental level.
905  for (int i=0 ; i!=(TDim+1); i++)
906  nodes_addedweights[i] += elem_volume*(1.0/(double(1+TDim)));
907  }
908 
909 
910  for (int i=0 ; i!=(TDim+1) ; ++i) {
911  geom[i].SetLock();
912  geom[i].FastGetSolutionStepValue(mProjectionVar) +=nodes_added_scalar1[i];
913  geom[i].FastGetSolutionStepValue(YP) +=nodes_addedweights[i];
914  geom[i].UnSetLock();
915  }
916  }
917  }
918 
919  #pragma omp parallel for
920  for(int kkk=0; kkk<number_of_threads; kkk++)
921  {
922  for(unsigned int ii=node_partition[kkk]; ii<node_partition[kkk+1]; ii++)
923  {
924  ModelPart::NodesContainerType::iterator inode = inodebegin+ii;
925  double sum_weights = inode->FastGetSolutionStepValue(YP);
926  if (sum_weights>0.00001)
927  {
928  double & scalar1 = inode->FastGetSolutionStepValue(mProjectionVar);
929  scalar1 /=sum_weights; //resetting the density
930  }
931 
932  else //this should never happen because other ways to recover the information have been executed before, but leaving it just in case..
933  {
934  inode->FastGetSolutionStepValue(mProjectionVar)=inode->FastGetSolutionStepValue(mUnknownVar,1);
935  }
936  }
937  }
938 
939 
940  KRATOS_CATCH("")
941  }
942 
944  {
945  KRATOS_TRY
946  //std::cout << "updating particles" << std::endl;
947  //ProcessInfo& CurrentProcessInfo = mr_model_part.GetProcessInfo();
948 
949  const int offset = moffset; //the array of pointers for each element has twice the required size so that we use a part in odd timesteps and the other in even ones.
950  //(flag managed only by MoveParticles
951  //KRATOS_WATCH(offset)
952  ModelPart::ElementsContainerType::iterator ielembegin = mr_model_part.ElementsBegin();
953 
954 
955  vector<unsigned int> element_partition;
956  #ifdef _OPENMP
957  int number_of_threads = omp_get_max_threads();
958  #else
959  int number_of_threads = 1;
960  #endif
961  OpenMPUtils::CreatePartition(number_of_threads, mr_model_part.Elements().size(), element_partition);
962 
963  #pragma omp parallel for
964  for(int kkk=0; kkk<number_of_threads; kkk++)
965  {
966  for(unsigned int ii=element_partition[kkk]; ii<element_partition[kkk+1]; ii++)
967  {
968  //const int & elem_id = ielem->Id();
969  ModelPart::ElementsContainerType::iterator ielem = ielembegin+ii;
970  Element::Pointer pelement(*ielem.base());
971  Geometry<Node >& geom = ielem->GetGeometry();
972 
973  //ParticlePointerVector& element_particle_pointers = (ielem->GetValue(BED_PARTICLE_POINTERS));
974  //int & number_of_particles_in_elem=ielem->GetValue(NUMBER_OF_BED_PARTICLES);
975  int & number_of_particles_in_elem= mnumber_of_particles_in_elems[ii];
976  ParticlePointerVector& element_particle_pointers = mvector_of_particle_pointers_vectors[ii];
977  //std::cout << "elem " << ii << " with " << (unsigned int)number_of_particles_in_elem << " particles" << std::endl;
978 
979  for (int iii=0; iii<number_of_particles_in_elem ; iii++ )
980  {
981  //KRATOS_WATCH(iii)
982  if (iii>mmaximum_number_of_particles) //it means we are out of our portion of the array, abort loop!
983  break;
984 
985  Convection_Particle & pparticle = element_particle_pointers[offset+iii];
986 
987 
988  bool erase_flag= pparticle.GetEraseFlag();
989  if (erase_flag==false)
990  {
991  CorrectParticleUsingDeltaVariables(pparticle,pelement,geom); //'lite' version, we pass by reference the geometry, so much cheaper
992  }
993 
994 
995  }
996  }
997  }
998  KRATOS_CATCH("")
999  }
1000 
1001  //**************************************************************************************************************
1002  //**************************************************************************************************************
1003 
1004 
1005  template< class TDataType > void AddUniqueWeakPointer
1006  (GlobalPointersVector< TDataType >& v, const typename TDataType::WeakPointer candidate)
1007  {
1008  typename GlobalPointersVector< TDataType >::iterator i = v.begin();
1009  typename GlobalPointersVector< TDataType >::iterator endit = v.end();
1010  while ( i != endit && (i)->Id() != (candidate)->Id())
1011  {
1012  i++;
1013  }
1014  if( i == endit )
1015  {
1016  v.push_back(candidate);
1017  }
1018 
1019  }
1020 
1021  //**************************************************************************************************************
1022  //**************************************************************************************************************
1023 
1024  void PreReseed(int minimum_number_of_particles)
1025  {
1026  KRATOS_TRY
1027 
1028 
1029  //ProcessInfo& CurrentProcessInfo = mr_model_part.GetProcessInfo();
1030  const int offset =moffset;
1031  const int max_results = 1000;
1032 
1033  //tools for the paralelization
1034  unsigned int number_of_threads = ParallelUtilities::GetNumThreads();
1035  vector<unsigned int> elem_partition;
1036  int number_of_rows=mr_model_part.Elements().size();
1037  elem_partition.resize(number_of_threads + 1);
1038  int elem_partition_size = number_of_rows / number_of_threads;
1039  elem_partition[0] = 0;
1040  elem_partition[number_of_threads] = number_of_rows;
1041  //KRATOS_WATCH(elem_partition_size);
1042  for (unsigned int i = 1; i < number_of_threads; i++)
1043  elem_partition[i] = elem_partition[i - 1] + elem_partition_size;
1044  ModelPart::ElementsContainerType::iterator ielembegin = mr_model_part.ElementsBegin();
1045 
1046  #pragma omp parallel firstprivate(elem_partition)
1047  {
1048  ResultContainerType results(max_results);
1049  int k = OpenMPUtils::ThisThread();
1050  //ModelPart::ElementsContainerType::iterator it_begin = mr_model_part.ElementsBegin() + elem_partition[k];
1051  //ModelPart::ElementsContainerType::iterator it_end = mr_model_part.ElementsBegin() + elem_partition[k+1] ;
1052  //ModelPart::NodesContainerType local_list=aux[k];
1053  //PointerVectorSet<Convection_Particle, IndexedObject> & list=aux[k];
1054  //KRATOS_WATCH(k);
1055  BoundedMatrix<double, (TDim+1), 3 > pos;
1056  BoundedMatrix<double, (TDim+1) , (TDim+1) > N;
1057  unsigned int freeparticle=0; //we start with the first position in the particles array
1058 
1059  //int local_id=1;
1060  for(unsigned int ii=elem_partition[k]; ii<elem_partition[k+1]; ii++)
1061  {
1062  //const int & elem_id = ielem->Id();
1063  ModelPart::ElementsContainerType::iterator ielem = ielembegin+ii;
1064  results.resize(max_results);
1065  //const int & elem_id = ielem->Id();
1066  //ParticlePointerVector& element_particle_pointers = (ielem->GetValue(BED_PARTICLE_POINTERS));
1067  //int & number_of_particles_in_elem=ielem->GetValue(NUMBER_OF_BED_PARTICLES);
1068  int & number_of_particles_in_elem= mnumber_of_particles_in_elems[ii];
1069  ParticlePointerVector& element_particle_pointers = mvector_of_particle_pointers_vectors[ii];
1070  if (number_of_particles_in_elem<(minimum_number_of_particles))// && (ielem->GetGeometry())[0].Y()<0.10 )
1071  {
1072  //KRATOS_WATCH("elem with little particles")
1073  Geometry< Node >& geom = ielem->GetGeometry();
1074  ComputeGaussPointPositionsForPreReseed(geom, pos, N);
1075  //double conductivity = ielem->GetProperties()[CONDUCTIVITY];
1076  //KRATOS_WATCH(conductivity);
1077  for (unsigned int j = 0; j < (pos.size1()); j++) //i am dropping the last one, the one in the middle of the element
1078  {
1079  bool keep_looking = true;
1080  while(keep_looking)
1081  {
1082  if (mparticles_vector[freeparticle].GetEraseFlag()==true)
1083  {
1084  #pragma omp critical
1085  {
1086  if (mparticles_vector[freeparticle].GetEraseFlag()==true)
1087  {
1088  mparticles_vector[freeparticle].GetEraseFlag()=false;
1089  keep_looking=false;
1090  }
1091  }
1092  if (keep_looking==false)
1093  break;
1094  else
1095  freeparticle++;
1096  }
1097  else
1098  {
1099  freeparticle++;
1100  }
1101  }
1102 
1103  Convection_Particle pparticle(pos(j,0),pos(j,1),pos(j,2));
1104 
1106  bool is_found = CalculatePosition(geom,pos(j,0),pos(j,1),pos(j,2),aux2_N);
1107  if (is_found==false)
1108  {
1109  KRATOS_WATCH(aux2_N);
1110  }
1111 
1112 
1113  pparticle.GetEraseFlag()=false;
1114 
1115  ResultIteratorType result_begin = results.begin();
1116  Element::Pointer pelement( *ielem.base() );
1117  MoveParticle_inverse_way(pparticle, pelement, result_begin, max_results);
1118 
1119  //and we copy it to the array:
1120  mparticles_vector[freeparticle] = pparticle;
1121 
1122  element_particle_pointers(offset+number_of_particles_in_elem) = &mparticles_vector[freeparticle];
1123  pparticle.GetEraseFlag()=false;
1124 
1125  number_of_particles_in_elem++;
1126 
1127 
1128  }
1129  }
1130  }
1131  }
1132 
1133 
1134 
1135 
1136  KRATOS_CATCH("")
1137  }
1138 
1139 
1140  //**************************************************************************************************************
1141  //**************************************************************************************************************
1142 
1143 
1144  void PostReseed(int minimum_number_of_particles) //pooyan's way
1145  {
1146  KRATOS_TRY
1147 
1148  //ProcessInfo& CurrentProcessInfo = mr_model_part.GetProcessInfo();
1149  const int offset = moffset;
1150 
1151  //TOOLS FOR THE PARALELIZATION
1152  //int last_id= (mr_linea_model_part.NodesEnd()-1)->Id();
1153  unsigned int number_of_threads = ParallelUtilities::GetNumThreads();
1154  //KRATOS_WATCH(number_of_threads);
1155  vector<unsigned int> elem_partition;
1156  int number_of_rows=mr_model_part.Elements().size();
1157  //KRATOS_WATCH(number_of_threads);
1158  //KRATOS_THROW_ERROR(std::logic_error, "Add ----NODAL_H---- variable!!!!!! ERROR", "");
1159  elem_partition.resize(number_of_threads + 1);
1160  int elem_partition_size = number_of_rows / number_of_threads;
1161  elem_partition[0] = 0;
1162  elem_partition[number_of_threads] = number_of_rows;
1163  //KRATOS_WATCH(elem_partition_size);
1164  for (unsigned int i = 1; i < number_of_threads; i++)
1165  elem_partition[i] = elem_partition[i - 1] + elem_partition_size;
1166  //typedef Node PointType;
1167  //std::vector<ModelPart::NodesContainerType> aux;// aux;
1168  //aux.resize(number_of_threads);
1169 
1170  //ModelPart::NodesContainerType::iterator it_begin_particle_model_part = mr_linea_model_part.NodesBegin();
1171  //ModelPart::NodesContainerType::iterator it_end_particle_model_part = mr_linea_model_part.NodesEnd();
1172  ModelPart::ElementsContainerType::iterator ielembegin = mr_model_part.ElementsBegin();
1173 
1174  #pragma omp parallel firstprivate(elem_partition) // firstprivate(results)//we will add the nodes in different parts of aux and later assemple everything toghether, remaming particles ids to get consecutive ids
1175  {
1176  unsigned int reused_particles=0;
1177 
1178  unsigned int freeparticle = 0; //we start by the first position;
1179 
1180  int k = OpenMPUtils::ThisThread();
1181  //ModelPart::ElementsContainerType::iterator it_begin = mr_model_part.ElementsBegin() + elem_partition[k];
1182  //ModelPart::ElementsContainerType::iterator it_end = mr_model_part.ElementsBegin() + elem_partition[k+1] ;
1183 
1184  BoundedMatrix<double, (3+2*TDim), 3 > pos; //7 particles (2D) or 9 particles (3D)
1185  BoundedMatrix<double, (3+2*TDim), (TDim+1) > N;
1186 
1187  double mesh_scalar1;
1188 
1189  array_1d<int, (3+2*TDim) > positions;
1190 
1191  unsigned int number_of_reseeded_particles;
1192  //unsigned int number_of_water_reseeded_particles;
1193 
1194  //array_1d<double, 3 > nodes_distances;
1195 
1196  for(unsigned int ii=elem_partition[k]; ii<elem_partition[k+1]; ii++)
1197  {
1198  //const int & elem_id = ielem->Id();
1199  ModelPart::ElementsContainerType::iterator ielem = ielembegin+ii;
1200 
1201  //int & number_of_particles_in_elem= ielem->GetValue(NUMBER_OF_BED_PARTICLES);
1202  //ParticlePointerVector& element_particle_pointers = (ielem->GetValue(BED_PARTICLE_POINTERS));
1203  int & number_of_particles_in_elem= mnumber_of_particles_in_elems[ii];
1204  ParticlePointerVector& element_particle_pointers = mvector_of_particle_pointers_vectors[ii];
1205 
1206  Geometry< Node >& geom = ielem->GetGeometry();
1207  if ( (number_of_particles_in_elem<(minimum_number_of_particles)))// && (geom[0].Y()<0.10) ) || (number_of_water_particles_in_elem>2 && number_of_particles_in_elem<(minimum_number_of_particles) ) )
1208  {
1209 
1210  //bool reseed_more=false;
1211  number_of_reseeded_particles=0;
1212 
1213 
1214  //reseed_more=true;
1215  number_of_reseeded_particles= 3+2*TDim;
1216  ComputeGaussPointPositionsForPostReseed(geom, pos, N);
1217 
1218  for (unsigned int j = 0; j < number_of_reseeded_particles; j++)
1219  {
1220  //now we have to find an empty space ( a particle that was about to be deleted) in the particles model part. once found. there will be our renewed particle:
1221  bool keep_looking = true;
1222  while(keep_looking)
1223  {
1224  if (mparticles_vector[freeparticle].GetEraseFlag()==true)
1225  {
1226  #pragma omp critical
1227  {
1228  if (mparticles_vector[freeparticle].GetEraseFlag()==true)
1229  {
1230  mparticles_vector[freeparticle].GetEraseFlag()=false;
1231  keep_looking=false;
1232  }
1233  }
1234  if (keep_looking==false)
1235  break;
1236 
1237  else
1238  freeparticle++;
1239  }
1240  else
1241  {
1242  freeparticle++;
1243  }
1244  }
1245 
1246  Convection_Particle pparticle(pos(j,0),pos(j,1),pos(j,2));
1247 
1249  bool is_found = CalculatePosition(geom,pos(j,0),pos(j,1),pos(j,2),aux_N);
1250  if (is_found==false)
1251  {
1252  KRATOS_WATCH(aux_N);
1253  KRATOS_WATCH(j)
1254  KRATOS_WATCH(ielem->Id())
1255  }
1256 
1257  mesh_scalar1 = 0.0;
1258 
1259  for (unsigned int l = 0; l < (TDim+1); l++)
1260  {
1261  mesh_scalar1 += N(j,l) * geom[l].FastGetSolutionStepValue(mUnknownVar);
1262  }
1263  pparticle.GetScalar1()=mesh_scalar1;
1264  pparticle.GetEraseFlag()=false;
1265 
1266 
1267  mparticles_vector[freeparticle]=pparticle;
1268  element_particle_pointers(offset+number_of_particles_in_elem) = &mparticles_vector[freeparticle];
1269  number_of_particles_in_elem++;
1270 
1271 
1272  if (keep_looking)
1273  {
1274  KRATOS_THROW_ERROR(std::logic_error, "FINISHED THE LIST AND COULDNT FIND A FREE CELL FOR THE NEW PARTICLE!", "");
1275  }
1276  else
1277  {
1278  reused_particles++;
1279  }
1280 
1281  }
1282  }
1283  }
1284  }
1285 
1286  KRATOS_CATCH("")
1287  }
1288 
1290  {
1291  KRATOS_TRY
1292  //mfilter_factor; //we will only print one out of every "filter_factor" particles of the total particle list
1293 
1294  if(mparticle_printing_tool_initialized==false)
1295  {
1296  mfilter_factor=input_filter_factor;
1297 
1298  if(lagrangian_model_part.NodesBegin()-lagrangian_model_part.NodesEnd()>0)
1299  KRATOS_THROW_ERROR(std::logic_error, "AN EMPTY MODEL PART IS REQUIRED FOR THE PRINTING OF PARTICLES", "");
1300 
1301  lagrangian_model_part.AddNodalSolutionStepVariable(DISPLACEMENT);
1302  lagrangian_model_part.AddNodalSolutionStepVariable(mUnknownVar);
1303 
1304  for (unsigned int i=0; i!=((mmaximum_number_of_particles*mnelems)/mfilter_factor)+mfilter_factor; i++)
1305  {
1306  Node ::Pointer pnode = lagrangian_model_part.CreateNewNode( i+mlast_node_id+1 , 0.0, 0.0, 0.0); //recordar que es el nueevo model part!!
1307  //pnode->SetBufferSize(mr_model_part.NodesBegin()->GetBufferSize());
1308  pnode->SetBufferSize(1);
1309  }
1310  mparticle_printing_tool_initialized=true;
1311  }
1312 
1313  //resetting data of the unused particles
1314  const double inactive_particle_position= -10.0;
1315  array_1d<double,3>inactive_particle_position_vector;
1316  inactive_particle_position_vector(0)=inactive_particle_position;
1317  inactive_particle_position_vector(1)=inactive_particle_position;
1318  inactive_particle_position_vector(2)=inactive_particle_position;
1319  ModelPart::NodesContainerType::iterator inodebegin = lagrangian_model_part.NodesBegin();
1320  for(unsigned int ii=0; ii<lagrangian_model_part.Nodes().size(); ii++)
1321  {
1322  ModelPart::NodesContainerType::iterator inode = inodebegin+ii;
1323  inode->FastGetSolutionStepValue(mUnknownVar) = 0.0;
1324  inode->FastGetSolutionStepValue(DISPLACEMENT) = inactive_particle_position_vector;
1325  }
1326 
1327 
1328  int counter=0;
1329  //ModelPart::NodesContainerType::iterator it_begin = lagrangian_model_part.NodesBegin();
1330  for (int i=0; i!=mmaximum_number_of_particles*mnelems; i++)
1331  {
1332  Convection_Particle& pparticle =mparticles_vector[i];
1333  if(pparticle.GetEraseFlag()==false && i%mfilter_factor==0)
1334  {
1335  ModelPart::NodesContainerType::iterator inode = inodebegin+counter; //copying info from the particle to the (printing) node.
1336  inode->FastGetSolutionStepValue(mUnknownVar) = pparticle.GetScalar1();
1337  inode->FastGetSolutionStepValue(DISPLACEMENT) = pparticle.Coordinates();
1338  counter++;
1339  }
1340  }
1341 
1342  KRATOS_CATCH("")
1343 
1344  }
1345 
1346  protected:
1347 
1348 
1349  private:
1350 
1351 
1355  void MoveParticle( Convection_Particle & pparticle,
1356  Element::Pointer & pelement,
1357  GlobalPointersVector< Element >& elements_in_trajectory,
1358  unsigned int & number_of_elements_in_trajectory,
1359  ResultIteratorType result_begin,
1360  const unsigned int MaxNumberOfResults)
1361  {
1362 
1363  ProcessInfo& CurrentProcessInfo = mr_model_part.GetProcessInfo();
1364  double delta_t = CurrentProcessInfo[DELTA_TIME];
1365  unsigned int nsubsteps;
1366  double substep_dt;
1367 
1368 
1369  bool KEEP_INTEGRATING=false;
1370  bool is_found;
1371  //bool have_air_node;
1372  //bool have_water_node;
1373 
1375  array_1d<double,3> vel_without_other_phase_nodes=ZeroVector(3);
1376  array_1d<double,3> position;
1377  array_1d<double,3> mid_position;
1379 
1380  //we start with the first position, then it will enter the loop.
1381  position = pparticle.Coordinates(); //initial coordinates
1382 
1383 
1384  is_found = FindNodeOnMesh(position, N ,pelement,result_begin,MaxNumberOfResults); //good, now we know where this point is:
1385  if(is_found == true)
1386  {
1387  KEEP_INTEGRATING=true;
1388  Geometry< Node >& geom = pelement->GetGeometry();//the element we're in
1389  vel=ZeroVector(3);
1390 
1391  for(unsigned int j=0; j<(TDim+1); j++)
1392  {
1393  noalias(vel) += geom[j].FastGetSolutionStepValue(mVelocityVar)*N[j];
1394  }
1395 
1396  //calculating substep to get +- courant(substep) = 0.1
1397  nsubsteps = 10.0 * (delta_t * pelement->GetValue(MEAN_VEL_OVER_ELEM_SIZE));
1398  if (nsubsteps<1)
1399  nsubsteps=1;
1400  substep_dt = delta_t / double(nsubsteps);
1401 
1402  position += vel*substep_dt;//weight;
1403 
1404  //DONE THE FIRST LOCATION OF THE PARTICLE, NOW WE PROCEED TO STREAMLINE INTEGRATION USING THE MESH SEDIMENT_VELOCITY
1406  unsigned int check_from_element_number=0;
1407 
1408 
1409  for(unsigned int i=0; i<(nsubsteps-1); i++)// this is for the substeps n+1. in the first one we already knew the position of the particle.
1410  {
1411  if (KEEP_INTEGRATING==true)
1412  {
1413  is_found = FindNodeOnMesh(position, N ,pelement,elements_in_trajectory,number_of_elements_in_trajectory,check_from_element_number,result_begin,MaxNumberOfResults); //good, now we know where this point is:
1414  if(is_found == true)
1415  {
1416  Geometry< Node >& geom = pelement->GetGeometry();//the element we're in
1417 
1418  vel = ZeroVector(3);
1419  for(unsigned int j=0; j<(TDim+1); j++)
1420  {
1421  noalias(vel) += geom[j].FastGetSolutionStepValue(mVelocityVar)*N[j];
1422  }
1423 
1424 
1425  position+=vel*substep_dt;//weight;
1426 
1427  }
1428  else
1429  {
1430  KEEP_INTEGRATING=false;
1431  break;
1432  }
1433  }
1434  else
1435  break;
1436 
1437 
1438  }
1439 
1440  }
1441 
1442  if (KEEP_INTEGRATING==false) (pparticle.GetEraseFlag()=true);
1443  else is_found = FindNodeOnMesh(position, N ,pelement,result_begin,MaxNumberOfResults); //we must save the pointer of the last element that we're in (inside the pointervector pelement)
1444 
1445  if (is_found==false) ( pparticle.GetEraseFlag()=true);
1446 
1447  pparticle.Coordinates() = position;
1448  }
1449 
1450 
1451  void CorrectParticleUsingDeltaVariables(
1452  Convection_Particle & pparticle,
1453  Element::Pointer & pelement,
1454  Geometry< Node >& geom)
1455  {
1456  array_1d<double,TDim+1> N;
1457 
1458  //we start with the first position, then it will enter the loop.
1459  array_1d<double,3> coords = pparticle.Coordinates();
1460  float & particle_scalar1 = pparticle.GetScalar1();
1461  //double distance=0.0;
1462  double delta_scalar1 = 0.0;
1463 
1464  bool is_found = CalculatePosition(geom,coords[0],coords[1],coords[2],N);
1465  if(is_found == false)
1466  {
1467  KRATOS_WATCH(N)
1468  for (int j=0 ; j!=(TDim+1); j++)
1469  if (N[j]<0.0 )
1470  N[j]=1e-10;
1471  }
1472 
1473 
1474  for(unsigned int j=0; j<(TDim+1); j++)
1475  {
1476  delta_scalar1 += geom[j].FastGetSolutionStepValue(DELTA_SCALAR1)*N[j];
1477  }
1478  particle_scalar1 = particle_scalar1 + delta_scalar1;
1479  }
1480 
1481  void MoveParticle_inverse_way(
1482  Convection_Particle & pparticle,
1483  Element::Pointer & pelement, //NOT A REFERENCE!! WE SHALL NOT OVERWRITE THE ELEMENT IT BELONGS TO!
1484  ResultIteratorType result_begin,
1485  const unsigned int MaxNumberOfResults)
1486  {
1487 
1488  ProcessInfo& CurrentProcessInfo = mr_model_part.GetProcessInfo();
1489  double delta_t = CurrentProcessInfo[DELTA_TIME];
1490  unsigned int nsubsteps;
1491  double substep_dt;
1492 
1493 
1494  bool KEEP_INTEGRATING=false;
1495  bool is_found;
1496 
1497  array_1d<double,3> vel;
1498  array_1d<double,3> position;
1499  array_1d<double,3> mid_position;
1500  array_1d<double,TDim+1> N;
1501  double scalar1 = 0.0;
1502 
1503 
1504  //we start with the first position, then it will enter the loop.
1505  position = pparticle.Coordinates(); // + (pparticle)->FastGetSolutionStepValue(DISPLACEMENT); //initial coordinates
1506 
1507 
1508  is_found = FindNodeOnMesh(position, N ,pelement,result_begin,MaxNumberOfResults); //good, now we know where this point is:
1509  if(is_found == true)
1510  {
1511  KEEP_INTEGRATING=true;
1512  Geometry< Node >& geom = pelement->GetGeometry();//the element we're in
1513  vel=ZeroVector(3);
1514  scalar1=0.0;
1515 
1516  for(unsigned int j=0; j<(TDim+1); j++)
1517  {
1518  scalar1 += geom[j].FastGetSolutionStepValue(mUnknownVar)*N(j);
1519  noalias(vel) += geom[j].FastGetSolutionStepValue(mVelocityVar)*N[j];
1520  }
1521  //calculating substep to get +- courant(substep) = 1/4
1522  nsubsteps = 10.0 * (delta_t * pelement->GetValue(MEAN_VEL_OVER_ELEM_SIZE));
1523  if (nsubsteps<1)
1524  nsubsteps=1;
1525  substep_dt = delta_t / double(nsubsteps);
1526 
1527  position -= vel*substep_dt;//weight;
1528 
1529  for(unsigned int i=0; i<(nsubsteps-1); i++)// this is for the substeps n+1. in the first one we already knew the position of the particle.
1530  { if (KEEP_INTEGRATING==true) {
1531  is_found = FindNodeOnMesh(position, N ,pelement,result_begin,MaxNumberOfResults); //good, now we know where this point is:
1532  if(is_found == true)
1533  {
1534  Geometry< Node >& geom = pelement->GetGeometry();//the element we're in
1535 
1536  vel=ZeroVector(3);
1537  scalar1=0.0;
1538 
1539 
1540  for(unsigned int j=0; j<(TDim+1); j++)
1541  {
1542  noalias(vel) += geom[j].FastGetSolutionStepValue(mVelocityVar)*N[j] ;
1543  scalar1 += geom[j].FastGetSolutionStepValue(mUnknownVar)*N(j);
1544  }
1545 
1546 
1547  position-=vel*substep_dt;//weight;
1548  }
1549  else KEEP_INTEGRATING=false;
1550  }
1551 
1552 
1553  }
1554 
1555  pparticle.GetScalar1()=scalar1;
1556  }
1557  //else {KRATOS_WATCH(position); }
1558 
1559  }
1560 
1561 
1562 
1567  bool FindNodeOnMesh( array_1d<double,3>& position,
1568  array_1d<double,TDim+1>& N,
1569  Element::Pointer & pelement,
1570  ResultIteratorType result_begin,
1571  const unsigned int MaxNumberOfResults)
1572  {
1573  typedef std::size_t SizeType;
1574 
1575  const array_1d<double,3>& coords = position;
1576  array_1d<double,TDim+1> aux_N;
1577  //before using the bin to search for possible elements we check first the last element in which the particle was.
1578  Geometry<Node >& geom_default = pelement->GetGeometry(); //(*(i))->GetGeometry();
1579  bool is_found_1 = CalculatePosition(geom_default,coords[0],coords[1],coords[2],N);
1580  if(is_found_1 == true) //that was easy!
1581  {
1582  return true;
1583  }
1584 
1585  //to begin with we check the neighbour elements; it is a bit more expensive
1586  GlobalPointersVector< Element >& neighb_elems = pelement->GetValue(NEIGHBOUR_ELEMENTS);
1587  //the first we check is the one that has negative shape function, because it means it went outside in this direction:
1588  //commented, it is not faster than simply checking all the neighbours (branching)
1589  /*
1590  unsigned int checked_element=0;
1591  for (unsigned int i=0;i!=(TDim+1);i++)
1592  {
1593  if (N[i]<0.0)
1594  {
1595  checked_element=i;
1596  Geometry<Node >& geom = neighb_elems[i].GetGeometry();
1597  bool is_found_2 = CalculatePosition(geom,coords[0],coords[1],coords[2],aux_N);
1598  if (is_found_2)
1599  {
1600  pelement=Element::Pointer(((neighb_elems(i))));
1601  N=aux_N;
1602  return true;
1603  }
1604  break;
1605  }
1606  }
1607  */
1608  //we check all the neighbour elements
1609  for (unsigned int i=0;i!=(neighb_elems.size());i++)
1610  {
1611  if(neighb_elems(i).get()!=nullptr)
1612  {
1613  Geometry<Node >& geom = neighb_elems[i].GetGeometry();
1614  bool is_found_2 = CalculatePosition(geom,coords[0],coords[1],coords[2],N);
1615  if (is_found_2)
1616  {
1617  pelement=neighb_elems(i)->shared_from_this();
1618  return true;
1619  }
1620  }
1621  }
1622 
1623  //if checking all the neighbour elements did not work, we have to use the bins
1624  //ask to the container for the list of candidate elements
1625  SizeType results_found = mpBinsObjectDynamic->SearchObjectsInCell(Point{coords}, result_begin, MaxNumberOfResults );
1626 
1627  if(results_found>0){
1628  //loop over the candidate elements and check if the particle falls within
1629  for(SizeType i = 0; i< results_found; i++)
1630  {
1631  Geometry<Node >& geom = (*(result_begin+i))->GetGeometry();
1632 
1633  //find local position
1634  bool is_found = CalculatePosition(geom,coords[0],coords[1],coords[2],N);
1635 
1636  if(is_found == true)
1637  {
1638  pelement=Element::Pointer((*(result_begin+i)));
1639  return true;
1640  }
1641  }
1642  }
1643  //if nothing worked, then:
1644  //not found case
1645  return false;
1646  }
1647 
1648 
1649  // VERSION INCLUDING PREDEFINED ELEMENTS FOLLOWING A TRAJECTORY
1650  bool FindNodeOnMesh( array_1d<double,3>& position,
1651  array_1d<double,TDim+1>& N,
1652  Element::Pointer & pelement,
1653  GlobalPointersVector< Element >& elements_in_trajectory,
1654  unsigned int & number_of_elements_in_trajectory,
1655  unsigned int & check_from_element_number,
1656  ResultIteratorType result_begin,
1657  const unsigned int MaxNumberOfResults)
1658  {
1659  typedef std::size_t SizeType;
1660 
1661  const array_1d<double,3>& coords = position;
1662  array_1d<double,TDim+1> aux_N;
1663  //before using the bin to search for possible elements we check first the last element in which the particle was.
1664  Geometry<Node >& geom_default = pelement->GetGeometry(); //(*(i))->GetGeometry();
1665  bool is_found_1 = CalculatePosition(geom_default,coords[0],coords[1],coords[2],N);
1666  if(is_found_1 == true)
1667  {
1668  return true; //that was easy!
1669  }
1670 
1671  //if it was not found in the first element, we can proceed to check in the following elements (in the trajectory defined by previous particles that started from the same element.
1672  for (unsigned int i=(check_from_element_number);i!=number_of_elements_in_trajectory;i++)
1673  {
1674  Geometry<Node >& geom = elements_in_trajectory[i].GetGeometry();
1675  bool is_found_2 = CalculatePosition(geom,coords[0],coords[1],coords[2],aux_N);
1676  if (is_found_2)
1677  {
1678  pelement=elements_in_trajectory(i)->shared_from_this();
1679  N=aux_N;
1680  check_from_element_number = i+1 ; //now i element matches pelement, so to avoid cheching twice the same element we send the counter to the following element.
1681  return true;
1682  }
1683 
1684  }
1685 
1686  //now we check the neighbour elements:
1687  auto& neighb_elems = pelement->GetValue(NEIGHBOUR_ELEMENTS);
1688  //the first we check is the one that has negative shape function, because it means it went outside in this direction:
1689  //commented, it is not faster than simply checking all the neighbours (branching)
1690  /*
1691  unsigned int checked_element=0;
1692  for (unsigned int i=0;i!=(TDim+1);i++)
1693  {
1694  if (N[i]<0.0)
1695  {
1696  checked_element=i;
1697  Geometry<Node >& geom = neighb_elems[i].GetGeometry();
1698  bool is_found_2 = CalculatePosition(geom,coords[0],coords[1],coords[2],aux_N);
1699  if (is_found_2)
1700  {
1701  pelement=Element::Pointer(((neighb_elems(i))));
1702  N=aux_N;
1703  return true;
1704  }
1705  break;
1706  }
1707  }
1708  */
1709  //we check all the neighbour elements
1710  for (unsigned int i=0;i!=(neighb_elems.size());i++)
1711  {
1712  if(neighb_elems(i).get()!=nullptr)
1713  {
1714  Geometry<Node >& geom = neighb_elems[i].GetGeometry();
1715  bool is_found_2 = CalculatePosition(geom,coords[0],coords[1],coords[2],N);
1716  if (is_found_2)
1717  {
1718  pelement=neighb_elems(i)->shared_from_this();
1719  if (number_of_elements_in_trajectory<20)
1720  {
1721  elements_in_trajectory(number_of_elements_in_trajectory)=pelement;
1722  number_of_elements_in_trajectory++;
1723  check_from_element_number = number_of_elements_in_trajectory; //we do it after doing the ++ to the counter, so we woudlnt enter the loop that searches in the elements_in_trajectory list. we are the particle that is adding elements to the list
1724  }
1725  return true;
1726  }
1727  }
1728  }
1729 
1730 
1731  //if checking all the neighbour elements did not work, we have to use the bins
1732  //ask to the container for the list of candidate elements
1733  SizeType results_found = mpBinsObjectDynamic->SearchObjectsInCell(Point{coords}, result_begin, MaxNumberOfResults );
1734 
1735  if(results_found>0)
1736  {
1737  //loop over the candidate elements and check if the particle falls within
1738  for(SizeType i = 0; i< results_found; i++)
1739  {
1740  Geometry<Node >& geom = (*(result_begin+i))->GetGeometry();
1741 
1742  //find local position
1743  bool is_found = CalculatePosition(geom,coords[0],coords[1],coords[2],N);
1744 
1745  if(is_found == true)
1746  {
1747  pelement=Element::Pointer((*(result_begin+i)));
1748  if (number_of_elements_in_trajectory<20)
1749  {
1750  elements_in_trajectory(number_of_elements_in_trajectory)=pelement;
1751  number_of_elements_in_trajectory++;
1752  check_from_element_number = number_of_elements_in_trajectory; //we do it after doing the ++ to the counter, so we woudlnt enter the loop that searches in the elements_in_trajectory list. we are the particle that is adding elements to the list
1753  }
1754  return true;
1755  }
1756  }
1757  }
1758 
1759  //not found case
1760  return false;
1761  }
1762 
1763 
1764 
1765  //***************************************
1766  //***************************************
1767 
1768  inline bool CalculatePosition(Geometry<Node >&geom,
1769  const double xc, const double yc, const double zc,
1770  array_1d<double, 3 > & N
1771  )
1772  {
1773  double x0 = geom[0].X();
1774  double y0 = geom[0].Y();
1775  double x1 = geom[1].X();
1776  double y1 = geom[1].Y();
1777  double x2 = geom[2].X();
1778  double y2 = geom[2].Y();
1779 
1780  double area = CalculateVol(x0, y0, x1, y1, x2, y2);
1781  double inv_area = 0.0;
1782  if (area == 0.0)
1783  {
1784  KRATOS_THROW_ERROR(std::logic_error, "element with zero area found", "");
1785  } else
1786  {
1787  inv_area = 1.0 / area;
1788  }
1789 
1790 
1791  N[0] = CalculateVol(x1, y1, x2, y2, xc, yc) * inv_area;
1792  N[1] = CalculateVol(x2, y2, x0, y0, xc, yc) * inv_area;
1793  N[2] = CalculateVol(x0, y0, x1, y1, xc, yc) * inv_area;
1794  //KRATOS_WATCH(N);
1795 
1796  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
1797  return true;
1798 
1799  return false;
1800  }
1802  //using the pre loaded nodal coordinates
1803  inline bool CalculatePosition(const array_1d<double,3*(TDim+1)>& nodes_positions,
1804  const double xc, const double yc, const double zc,
1805  array_1d<double, 3 > & N
1806  )
1807  {
1808  const double& x0 = nodes_positions[0];
1809  const double& y0 = nodes_positions[1];
1810  const double& x1 = nodes_positions[3];
1811  const double& y1 = nodes_positions[4];
1812  const double& x2 = nodes_positions[6];
1813  const double& y2 = nodes_positions[7];
1814 
1815  double area = CalculateVol(x0, y0, x1, y1, x2, y2);
1816  double inv_area = 0.0;
1817  if (area == 0.0)
1818  {
1819  KRATOS_THROW_ERROR(std::logic_error, "element with zero area found", "");
1820  } else
1821  {
1822  inv_area = 1.0 / area;
1823  }
1824 
1825 
1826  N[0] = CalculateVol(x1, y1, x2, y2, xc, yc) * inv_area;
1827  N[1] = CalculateVol(x2, y2, x0, y0, xc, yc) * inv_area;
1828  N[2] = CalculateVol(x0, y0, x1, y1, xc, yc) * inv_area;
1829  //KRATOS_WATCH(N);
1830 
1831  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
1832  return true;
1833 
1834  return false;
1835  }
1836 
1837 
1838  //***************************************
1839  //***************************************
1840 
1841  inline bool CalculatePosition(Geometry<Node >&geom,
1842  const double xc, const double yc, const double zc,
1843  array_1d<double, 4 > & N
1844  )
1845  {
1846 
1847  double x0 = geom[0].X();
1848  double y0 = geom[0].Y();
1849  double z0 = geom[0].Z();
1850  double x1 = geom[1].X();
1851  double y1 = geom[1].Y();
1852  double z1 = geom[1].Z();
1853  double x2 = geom[2].X();
1854  double y2 = geom[2].Y();
1855  double z2 = geom[2].Z();
1856  double x3 = geom[3].X();
1857  double y3 = geom[3].Y();
1858  double z3 = geom[3].Z();
1859 
1860  double vol = CalculateVol(x0, y0, z0, x1, y1, z1, x2, y2, z2, x3, y3, z3);
1861 
1862  double inv_vol = 0.0;
1863  if (vol < 0.000000000000000000000000000001)
1864  {
1865  KRATOS_THROW_ERROR(std::logic_error, "element with zero vol found", "");
1866  } else
1867  {
1868  inv_vol = 1.0 / vol;
1869  }
1870 
1871  N[0] = CalculateVol(x1, y1, z1, x3, y3, z3, x2, y2, z2, xc, yc, zc) * inv_vol;
1872  N[1] = CalculateVol(x0, y0, z0, x1, y1, z1, x2, y2, z2, xc, yc, zc) * inv_vol;
1873  N[2] = CalculateVol(x3, y3, z3, x1, y1, z1, x0, y0, z0, xc, yc, zc) * inv_vol;
1874  N[3] = CalculateVol(x3, y3, z3, x0, y0, z0, x2, y2, z2, xc, yc, zc) * inv_vol;
1875 
1876 
1877  if (N[0] >= 0.0 && N[1] >= 0.0 && N[2] >= 0.0 && N[3] >= 0.0 &&
1878  N[0] <= 1.0 && N[1] <= 1.0 && N[2] <= 1.0 && N[3] <= 1.0)
1879  //if the xc yc zc is inside the tetrahedron return true
1880  return true;
1881 
1882  return false;
1883  }
1885  //using the pre loaded nodal coordinates
1886  inline bool CalculatePosition(const array_1d<double,3*(TDim+1)>& nodes_positions,
1887  const double xc, const double yc, const double zc,
1888  array_1d<double, 4 > & N
1889  )
1890  {
1891 
1892  const double& x0 = nodes_positions[0];
1893  const double& y0 = nodes_positions[1];
1894  const double& z0 = nodes_positions[2];
1895  const double& x1 = nodes_positions[3];
1896  const double& y1 = nodes_positions[4];
1897  const double& z1 = nodes_positions[5];
1898  const double& x2 = nodes_positions[6];
1899  const double& y2 = nodes_positions[7];
1900  const double& z2 = nodes_positions[8];
1901  const double& x3 = nodes_positions[9];
1902  const double& y3 = nodes_positions[10];
1903  const double& z3 = nodes_positions[11];
1904 
1905  double vol = CalculateVol(x0, y0, z0, x1, y1, z1, x2, y2, z2, x3, y3, z3);
1906 
1907  double inv_vol = 0.0;
1908  if (vol < 0.000000000000000000000000000001)
1909  {
1910  KRATOS_THROW_ERROR(std::logic_error, "element with zero vol found", "");
1911  } else
1912  {
1913  inv_vol = 1.0 / vol;
1914  }
1915 
1916  N[0] = CalculateVol(x1, y1, z1, x3, y3, z3, x2, y2, z2, xc, yc, zc) * inv_vol;
1917  N[1] = CalculateVol(x0, y0, z0, x1, y1, z1, x2, y2, z2, xc, yc, zc) * inv_vol;
1918  N[2] = CalculateVol(x3, y3, z3, x1, y1, z1, x0, y0, z0, xc, yc, zc) * inv_vol;
1919  N[3] = CalculateVol(x3, y3, z3, x0, y0, z0, x2, y2, z2, xc, yc, zc) * inv_vol;
1920 
1921 
1922  if (N[0] >= 0.0 && N[1] >= 0.0 && N[2] >= 0.0 && N[3] >= 0.0 &&
1923  N[0] <= 1.0 && N[1] <= 1.0 && N[2] <= 1.0 && N[3] <= 1.0)
1924  //if the xc yc zc is inside the tetrahedron return true
1925  return true;
1926 
1927  return false;
1928  }
1929 
1930  inline double CalculateVol(const double x0, const double y0,
1931  const double x1, const double y1,
1932  const double x2, const double y2
1933  )
1934  {
1935  return 0.5 * ((x1 - x0)*(y2 - y0)- (y1 - y0)*(x2 - x0));
1936  }
1937  //***************************************
1938  //***************************************
1939 
1940  inline double CalculateVol(const double x0, const double y0, const double z0,
1941  const double x1, const double y1, const double z1,
1942  const double x2, const double y2, const double z2,
1943  const double x3, const double y3, const double z3
1944  )
1945  {
1946  double x10 = x1 - x0;
1947  double y10 = y1 - y0;
1948  double z10 = z1 - z0;
1949 
1950  double x20 = x2 - x0;
1951  double y20 = y2 - y0;
1952  double z20 = z2 - z0;
1953 
1954  double x30 = x3 - x0;
1955  double y30 = y3 - y0;
1956  double z30 = z3 - z0;
1957 
1958  double detJ = x10 * y20 * z30 - x10 * y30 * z20 + y10 * z20 * x30 - y10 * x20 * z30 + z10 * x20 * y30 - z10 * y20 * x30;
1959  return detJ * 0.1666666666666666666667;
1960  }
1961 
1962 
1963 
1964  void ComputeGaussPointPositions_4(Geometry< Node >& geom, BoundedMatrix<double, 7, 3 > & pos,BoundedMatrix<double, 7, 3 > & N)
1965  {
1966  double one_third = 1.0 / 3.0;
1967  double one_sixt = 0.15; //1.0 / 6.0;
1968  double two_third = 0.7; //2.0 * one_third;
1969 
1970  N(0, 0) = one_sixt;
1971  N(0, 1) = one_sixt;
1972  N(0, 2) = two_third;
1973  N(1, 0) = two_third;
1974  N(1, 1) = one_sixt;
1975  N(1, 2) = one_sixt;
1976  N(2, 0) = one_sixt;
1977  N(2, 1) = two_third;
1978  N(2, 2) = one_sixt;
1979  N(3, 0) = one_third;
1980  N(3, 1) = one_third;
1981  N(3, 2) = one_third;
1982 
1983  //first
1984  pos(0, 0) = one_sixt * geom[0].X() + one_sixt * geom[1].X() + two_third * geom[2].X();
1985  pos(0, 1) = one_sixt * geom[0].Y() + one_sixt * geom[1].Y() + two_third * geom[2].Y();
1986  pos(0, 2) = one_sixt * geom[0].Z() + one_sixt * geom[1].Z() + two_third * geom[2].Z();
1987 
1988  //second
1989  pos(1, 0) = two_third * geom[0].X() + one_sixt * geom[1].X() + one_sixt * geom[2].X();
1990  pos(1, 1) = two_third * geom[0].Y() + one_sixt * geom[1].Y() + one_sixt * geom[2].Y();
1991  pos(1, 2) = two_third * geom[0].Z() + one_sixt * geom[1].Z() + one_sixt * geom[2].Z();
1992 
1993  //third
1994  pos(2, 0) = one_sixt * geom[0].X() + two_third * geom[1].X() + one_sixt * geom[2].X();
1995  pos(2, 1) = one_sixt * geom[0].Y() + two_third * geom[1].Y() + one_sixt * geom[2].Y();
1996  pos(2, 2) = one_sixt * geom[0].Z() + two_third * geom[1].Z() + one_sixt * geom[2].Z();
1997 
1998  //fourth
1999  pos(3, 0) = one_third * geom[0].X() + one_third * geom[1].X() + one_third * geom[2].X();
2000  pos(3, 1) = one_third * geom[0].Y() + one_third * geom[1].Y() + one_third * geom[2].Y();
2001  pos(3, 2) = one_third * geom[0].Z() + one_third * geom[1].Z() + one_third * geom[2].Z();
2002 
2003  }
2004 
2005 
2006  void ComputeGaussPointPositionsForPostReseed(Geometry< Node >& geom, BoundedMatrix<double, 7, 3 > & pos,BoundedMatrix<double, 7, 3 > & N) //2d
2007  {
2008  double one_third = 1.0 / 3.0;
2009  double one_eight = 0.12; //1.0 / 6.0;
2010  double three_quarters = 0.76; //2.0 * one_third;
2011 
2012  N(0, 0) = one_eight;
2013  N(0, 1) = one_eight;
2014  N(0, 2) = three_quarters;
2015 
2016  N(1, 0) = three_quarters;
2017  N(1, 1) = one_eight;
2018  N(1, 2) = one_eight;
2019 
2020  N(2, 0) = one_eight;
2021  N(2, 1) = three_quarters;
2022  N(2, 2) = one_eight;
2023 
2024  N(3, 0) = one_third;
2025  N(3, 1) = one_third;
2026  N(3, 2) = one_third;
2027 
2028  N(4, 0) = one_eight;
2029  N(4, 1) = 0.44;
2030  N(4, 2) = 0.44;
2031 
2032  N(5, 0) = 0.44;
2033  N(5, 1) = one_eight;
2034  N(5, 2) = 0.44;
2035 
2036  N(6, 0) = 0.44;
2037  N(6, 1) = 0.44;
2038  N(6, 2) = one_eight;
2039 
2040 
2041  //first
2042  pos(0, 0) = one_eight * geom[0].X() + one_eight * geom[1].X() + three_quarters * geom[2].X();
2043  pos(0, 1) = one_eight * geom[0].Y() + one_eight * geom[1].Y() + three_quarters * geom[2].Y();
2044  pos(0, 2) = one_eight * geom[0].Z() + one_eight * geom[1].Z() + three_quarters * geom[2].Z();
2045 
2046  //second
2047  pos(1, 0) = three_quarters * geom[0].X() + one_eight * geom[1].X() + one_eight * geom[2].X();
2048  pos(1, 1) = three_quarters * geom[0].Y() + one_eight * geom[1].Y() + one_eight * geom[2].Y();
2049  pos(1, 2) = three_quarters * geom[0].Z() + one_eight * geom[1].Z() + one_eight * geom[2].Z();
2050 
2051  //third
2052  pos(2, 0) = one_eight * geom[0].X() + three_quarters * geom[1].X() + one_eight * geom[2].X();
2053  pos(2, 1) = one_eight * geom[0].Y() + three_quarters * geom[1].Y() + one_eight * geom[2].Y();
2054  pos(2, 2) = one_eight * geom[0].Z() + three_quarters * geom[1].Z() + one_eight * geom[2].Z();
2055 
2056  //fourth
2057  pos(3, 0) = one_third * geom[0].X() + one_third * geom[1].X() + one_third * geom[2].X();
2058  pos(3, 1) = one_third * geom[0].Y() + one_third * geom[1].Y() + one_third * geom[2].Y();
2059  pos(3, 2) = one_third * geom[0].Z() + one_third * geom[1].Z() + one_third * geom[2].Z();
2060 
2061  //fifth
2062  pos(4, 0) = one_eight * geom[0].X() + 0.44 * geom[1].X() + 0.44 * geom[2].X();
2063  pos(4, 1) = one_eight * geom[0].Y() + 0.44 * geom[1].Y() + 0.44 * geom[2].Y();
2064  pos(4, 2) = one_eight * geom[0].Z() + 0.44 * geom[1].Z() + 0.44 * geom[2].Z();
2065 
2066  //sixth
2067  pos(5, 0) = 0.44 * geom[0].X() + one_eight * geom[1].X() + 0.44 * geom[2].X();
2068  pos(5, 1) = 0.44 * geom[0].Y() + one_eight * geom[1].Y() + 0.44 * geom[2].Y();
2069  pos(5, 2) = 0.44 * geom[0].Z() + one_eight * geom[1].Z() + 0.44 * geom[2].Z();
2070 
2071  //seventh
2072  pos(6, 0) = 0.44 * geom[0].X() + 0.44 * geom[1].X() + one_eight * geom[2].X();
2073  pos(6, 1) = 0.44 * geom[0].Y() + 0.44 * geom[1].Y() + one_eight * geom[2].Y();
2074  pos(6, 2) = 0.44 * geom[0].Z() + 0.44 * geom[1].Z() + one_eight * geom[2].Z();
2075 
2076 
2077 
2078 
2079  }
2080 
2081  void ComputeGaussPointPositionsForPostReseed(Geometry< Node >& geom, BoundedMatrix<double, 9, 3 > & pos,BoundedMatrix<double, 9, 4 > & N) //3D
2082  {
2083  double one_quarter = 0.25;
2084  double small_fraction = 0.1; //1.0 / 6.0;
2085  double big_fraction = 0.7; //2.0 * one_third;
2086  double mid_fraction = 0.3; //2.0 * one_third;
2087 
2088  N(0, 0) = big_fraction;
2089  N(0, 1) = small_fraction;
2090  N(0, 2) = small_fraction;
2091  N(0, 3) = small_fraction;
2092 
2093  N(1, 0) = small_fraction;
2094  N(1, 1) = big_fraction;
2095  N(1, 2) = small_fraction;
2096  N(1, 3) = small_fraction;
2097 
2098  N(2, 0) = small_fraction;
2099  N(2, 1) = small_fraction;
2100  N(2, 2) = big_fraction;
2101  N(2, 3) = small_fraction;
2102 
2103  N(3, 0) = small_fraction;
2104  N(3, 1) = small_fraction;
2105  N(3, 2) = small_fraction;
2106  N(3, 3) = big_fraction;
2107 
2108  N(4, 0) = one_quarter;
2109  N(4, 1) = one_quarter;
2110  N(4, 2) = one_quarter;
2111  N(4, 3) = one_quarter;
2112 
2113  N(5, 0) = small_fraction;
2114  N(5, 1) = mid_fraction;
2115  N(5, 2) = mid_fraction;
2116  N(5, 3) = mid_fraction;
2117 
2118  N(6, 0) = mid_fraction;
2119  N(6, 1) = small_fraction;
2120  N(6, 2) = mid_fraction;
2121  N(6, 3) = mid_fraction;
2122 
2123  N(7, 0) = mid_fraction;
2124  N(7, 1) = mid_fraction;
2125  N(7, 2) = small_fraction;
2126  N(7, 3) = mid_fraction;
2127 
2128  N(8, 0) = mid_fraction;
2129  N(8, 1) = mid_fraction;
2130  N(8, 2) = mid_fraction;
2131  N(8, 3) = small_fraction;
2132 
2133  pos=ZeroMatrix(9,3);
2134  for (unsigned int i=0; i!=4; i++) //going through the 4 nodes
2135  {
2136  array_1d<double, 3 > & coordinates = geom[i].Coordinates();
2137  for (unsigned int j=0; j!=9; j++) //going through the 9 particles
2138  {
2139  for (unsigned int k=0; k!=3; k++) //x,y,z
2140  pos(j,k) += N(j,i) * coordinates[k];
2141  }
2142  }
2143 
2144 
2145  }
2146 
2147 
2148 
2149  void ComputeGaussPointPositionsForPreReseed(Geometry< Node >& geom, BoundedMatrix<double, 3, 3 > & pos,BoundedMatrix<double, 3, 3 > & N) //2D
2150  {
2151 
2152  N(0, 0) = 0.5;
2153  N(0, 1) = 0.25;
2154  N(0, 2) = 0.25;
2155 
2156  N(1, 0) = 0.25;
2157  N(1, 1) = 0.5;
2158  N(1, 2) = 0.25;
2159 
2160  N(2, 0) = 0.25;
2161  N(2, 1) = 0.25;
2162  N(2, 2) = 0.5;
2163 
2164  //first
2165  pos(0, 0) = 0.5 * geom[0].X() + 0.25 * geom[1].X() + 0.25 * geom[2].X();
2166  pos(0, 1) = 0.5 * geom[0].Y() + 0.25 * geom[1].Y() + 0.25 * geom[2].Y();
2167  pos(0, 2) = 0.5 * geom[0].Z() + 0.25 * geom[1].Z() + 0.25 * geom[2].Z();
2168 
2169  //second
2170  pos(1, 0) = 0.25 * geom[0].X() + 0.5 * geom[1].X() + 0.25 * geom[2].X();
2171  pos(1, 1) = 0.25 * geom[0].Y() + 0.5 * geom[1].Y() + 0.25 * geom[2].Y();
2172  pos(1, 2) = 0.25 * geom[0].Z() + 0.5 * geom[1].Z() + 0.25 * geom[2].Z();
2173 
2174  //third
2175  pos(2, 0) = 0.25 * geom[0].X() + 0.25 * geom[1].X() + 0.5 * geom[2].X();
2176  pos(2, 1) = 0.25 * geom[0].Y() + 0.25 * geom[1].Y() + 0.5 * geom[2].Y();
2177  pos(2, 2) = 0.25 * geom[0].Z() + 0.25 * geom[1].Z() + 0.5 * geom[2].Z();
2178 
2179  }
2180 
2181  void ComputeGaussPointPositionsForPreReseed(Geometry< Node >& geom, BoundedMatrix<double, 4, 3 > & pos,BoundedMatrix<double, 4, 4 > & N) //3D
2182  {
2183  //creating 4 particles, each will be closer to a node and equidistant to the other nodes
2184 
2185 
2186  N(0, 0) = 0.4;
2187  N(0, 1) = 0.2;
2188  N(0, 2) = 0.2;
2189  N(0, 3) = 0.2;
2190 
2191  N(1, 0) = 0.2;
2192  N(1, 1) = 0.4;
2193  N(1, 2) = 0.2;
2194  N(1, 3) = 0.2;
2195 
2196  N(2, 0) = 0.2;
2197  N(2, 1) = 0.2;
2198  N(2, 2) = 0.4;
2199  N(2, 3) = 0.2;
2200 
2201  N(3, 0) = 0.2;
2202  N(3, 1) = 0.2;
2203  N(3, 2) = 0.2;
2204  N(3, 3) = 0.4;
2205 
2206  pos=ZeroMatrix(4,3);
2207  for (unsigned int i=0; i!=4; i++) //going through the 4 nodes
2208  {
2209  array_1d<double, 3 > & coordinates = geom[i].Coordinates();
2210  for (unsigned int j=0; j!=4; j++) //going through the 4 particles
2211  {
2212  for (unsigned int k=0; k!=3; k++) //x,y,z
2213  pos(j,k) += N(j,i) * coordinates[k];
2214  }
2215  }
2216 
2217  }
2218 
2219 
2220 
2221  void ComputeGaussPointPositions_45(Geometry< Node >& geom, BoundedMatrix<double, 45, 3 > & pos,BoundedMatrix<double, 45, 3 > & N)
2222  {
2223  //std::cout << "NEW ELEMENT" << std::endl;
2224  unsigned int counter=0;
2225  for (unsigned int i=0; i!=9;i++)
2226  {
2227  for (unsigned int j=0; j!=(9-i);j++)
2228  {
2229  N(counter,0)=0.05+double(i)*0.1;
2230  N(counter,1)=0.05+double(j)*0.1;
2231  N(counter,2)=1.0 - ( N(counter,1)+ N(counter,0) ) ;
2232  pos(counter, 0) = N(counter,0) * geom[0].X() + N(counter,1) * geom[1].X() + N(counter,2) * geom[2].X();
2233  pos(counter, 1) = N(counter,0) * geom[0].Y() + N(counter,1) * geom[1].Y() + N(counter,2) * geom[2].Y();
2234  pos(counter, 2) = N(counter,0) * geom[0].Z() + N(counter,1) * geom[1].Z() + N(counter,2) * geom[2].Z();
2235  //std::cout << N(counter,0) << " " << N(counter,1) << " " << N(counter,2) << " " << std::endl;
2236  counter++;
2237 
2238  }
2239  }
2240 
2241  }
2242 
2243  void ComputeGaussPointPositions_initial(Geometry< Node >& geom, BoundedMatrix<double, 15, 3 > & pos,BoundedMatrix<double, 15, 3 > & N) //2D
2244  {
2245  //std::cout << "NEW ELEMENT" << std::endl;
2246  unsigned int counter=0;
2247  for (unsigned int i=0; i!=5;i++)
2248  {
2249  for (unsigned int j=0; j!=(5-i);j++)
2250  {
2251  N(counter,0)=0.05+double(i)*0.2;
2252  N(counter,1)=0.05+double(j)*0.2;
2253  N(counter,2)=1.0 - ( N(counter,1)+ N(counter,0) ) ;
2254  pos(counter, 0) = N(counter,0) * geom[0].X() + N(counter,1) * geom[1].X() + N(counter,2) * geom[2].X();
2255  pos(counter, 1) = N(counter,0) * geom[0].Y() + N(counter,1) * geom[1].Y() + N(counter,2) * geom[2].Y();
2256  pos(counter, 2) = N(counter,0) * geom[0].Z() + N(counter,1) * geom[1].Z() + N(counter,2) * geom[2].Z();
2257  //std::cout << N(counter,0) << " " << N(counter,1) << " " << N(counter,2) << " " << std::endl;
2258  counter++;
2259 
2260  }
2261  }
2262 
2263  }
2264 
2265  void ComputeGaussPointPositions_initial(Geometry< Node >& geom, BoundedMatrix<double, 20, 3 > & pos,BoundedMatrix<double, 20, 4 > & N) //3D
2266  {
2267  //std::cout << "NEW ELEMENT" << std::endl;
2268  //double total;
2269  double fraction_increment;
2270  unsigned int counter=0;
2271  for (unsigned int i=0; i!=4;i++) //going to build a particle "pyramid"(tetrahedra) by layers. the first layer will be made by a triangle of 4 base X 4 height. since it is a triangle, it means it will have 10 particles
2272  {
2273  //std::cout << "inside i" << i << std::endl;
2274  for (unsigned int j=0; j!=(4-i);j++)
2275  {
2276  //std::cout << "inside j" << j << std::endl;
2277  for (unsigned int k=0; k!=(4-i-j);k++)
2278  {
2279  //std::cout << "inside k" << k << std::endl;
2280  N(counter,0)= 0.27 * ( 0.175 + double(i) ) ; //this is our "surface" in which we will build each layer, so we must construct a triangle using what's left of the shape functions total (a total of 1)
2281 
2282  //total = 1.0 - N(counter,0);
2283  fraction_increment = 0.27; //
2284 
2285  N(counter,1)=fraction_increment * (0.175 + double(j));
2286  N(counter,2)=fraction_increment * (0.175 + double(k));
2287  N(counter,3)=1.0 - ( N(counter,0)+ N(counter,1) + N(counter,2) ) ;
2288  pos(counter, 0) = N(counter,0) * geom[0].X() + N(counter,1) * geom[1].X() + N(counter,2) * geom[2].X() + N(counter,3) * geom[3].X();
2289  pos(counter, 1) = N(counter,0) * geom[0].Y() + N(counter,1) * geom[1].Y() + N(counter,2) * geom[2].Y() + N(counter,3) * geom[3].Y();
2290  pos(counter, 2) = N(counter,0) * geom[0].Z() + N(counter,1) * geom[1].Z() + N(counter,2) * geom[2].Z() + N(counter,3) * geom[3].Z();
2291  //std::cout << N(counter,0) << " " << N(counter,1) << " " << N(counter,2) << " " << std::endl;
2292  counter++;
2293  }
2294 
2295  }
2296  }
2297 
2298  }
2299 
2300  template<class T>
2301  bool InvertMatrix(const T& input, T& inverse)
2302  {
2303  typedef permutation_matrix<std::size_t> pmatrix;
2304 
2305  // create a working copy of the input
2306  T A(input);
2307 
2308  // create a permutation matrix for the LU-factorization
2309  pmatrix pm(A.size1());
2310 
2311  // perform LU-factorization
2312  int res = lu_factorize(A, pm);
2313  if (res != 0)
2314  return false;
2315 
2316  // create identity matrix of "inverse"
2317  inverse.assign(identity_matrix<double> (A.size1()));
2318 
2319  // backsubstitute to get the inverse
2320  lu_substitute(A, pm, inverse);
2321 
2322  return true;
2323  }
2324 
2325  bool InvertMatrix3x3(const BoundedMatrix<double, TDim+1 , TDim+1 >& A, BoundedMatrix<double, TDim+1 , TDim+1 >& result)
2326  {
2327  double determinant = +A(0,0)*(A(1,1)*A(2,2)-A(2,1)*A(1,2))
2328  -A(0,1)*(A(1,0)*A(2,2)-A(1,2)*A(2,0))
2329  +A(0,2)*(A(1,0)*A(2,1)-A(1,1)*A(2,0));
2330  double invdet = 1/determinant;
2331  result(0,0) = (A(1,1)*A(2,2)-A(2,1)*A(1,2))*invdet;
2332  result(1,0) = -(A(0,1)*A(2,2)-A(0,2)*A(2,1))*invdet;
2333  result(2,0) = (A(0,1)*A(1,2)-A(0,2)*A(1,1))*invdet;
2334  result(0,1) = -(A(1,0)*A(2,2)-A(1,2)*A(2,0))*invdet;
2335  result(1,1) = (A(0,0)*A(2,2)-A(0,2)*A(2,0))*invdet;
2336  result(2,1) = -(A(0,0)*A(1,2)-A(1,0)*A(0,2))*invdet;
2337  result(0,2) = (A(1,0)*A(2,1)-A(2,0)*A(1,1))*invdet;
2338  result(1,2) = -(A(0,0)*A(2,1)-A(2,0)*A(0,1))*invdet;
2339  result(2,2) = (A(0,0)*A(1,1)-A(1,0)*A(0,1))*invdet;
2340 
2341  return true;
2342  }
2343 
2344  virtual int Check()
2345  {
2346  KRATOS_TRY
2347  ProcessInfo& rCurrentProcessInfo = mr_model_part.GetProcessInfo();
2348  if (rCurrentProcessInfo.Has(CONVECTION_DIFFUSION_SETTINGS)==false)
2349  KRATOS_THROW_ERROR(std::logic_error, "no CONVECTION_DIFFUSION_SETTINGS in model_part", "");
2350  //std::cout << "ConvDiff::Check(). If crashes, check CONVECTION_DIFFUSION_SETTINGS is defined" << std::endl;
2351 
2352  ConvectionDiffusionSettings::Pointer my_settings = rCurrentProcessInfo.GetValue(CONVECTION_DIFFUSION_SETTINGS);
2353 
2354  //UNKNOWN VARIABLE
2355  if(my_settings->IsDefinedUnknownVariable()==true)
2356  {
2357  if (mr_model_part.NodesBegin()->SolutionStepsDataHas(my_settings->GetUnknownVariable()) == false)
2358  KRATOS_THROW_ERROR(std::logic_error, "ConvDiffSettings: Unknown Variable defined but not contained in the model part", "");
2359  }
2360  else
2361  KRATOS_THROW_ERROR(std::logic_error, "ConvDiffSettings: Unknown Variable not defined!", "");
2362 
2363 
2364  //PROJECTION VARIABLE
2365  //used as intermediate variable, is the variable at time n+1 but only accounting for the convective term.
2366  if(my_settings->IsDefinedProjectionVariable()==true)
2367  {
2368  if (mr_model_part.NodesBegin()->SolutionStepsDataHas(my_settings->GetProjectionVariable()) == false)
2369  KRATOS_THROW_ERROR(std::logic_error, "ConvDiffSettings: Projection Variable defined but not contained in the model part", "");
2370  }
2371  else
2372  KRATOS_THROW_ERROR(std::logic_error, "No Projection variable assigned for ConvDiff!", "");
2373 
2374 
2375  //CONVECTION VELOCITY VARIABLE
2376  //CURRENTLY WE ARE USING (VELOCITY -MESH_VELOCITY) TO CONVECT, so the ConvectionVariable must not be used:
2377  //if(my_settings->IsDefinedConvectionVariable()==true)
2378  //{
2379  // if (BaseType::GetModelPart().NodesBegin()->SolutionStepsDataHas(my_settings->GetConvectionVariable()) == false)
2380  // KRATOS_THROW_ERROR(std::logic_error, "ConvDiffSettings: Convection Variable defined but not contained in the model part", "");
2381  //}
2382  //else
2383  // std::cout << "No Projection variable assigned for ConvDiff. Assuming Convection=0" << std::endl;
2384  if(my_settings->IsDefinedConvectionVariable()==true)
2385  KRATOS_THROW_ERROR(std::logic_error, "ConvDiffSettings: ConvectionVariable not used. Use VelocityVariable instead", "");
2386 
2387  //VELOCITY VARIABLE
2388  if(my_settings->IsDefinedVelocityVariable()==true)
2389  {
2390  if (mr_model_part.NodesBegin()->SolutionStepsDataHas(my_settings->GetVelocityVariable()) == false)
2391  KRATOS_THROW_ERROR(std::logic_error, "ConvDiffSettings: Velocity Variable defined but not contained in the model part", "");
2392  }
2393  else
2394  KRATOS_THROW_ERROR(std::logic_error, "No Velocity variable assigned for ConvDiff!", "");
2395 
2396  if (mr_model_part.NodesBegin()->SolutionStepsDataHas(MEAN_SIZE) == false)
2397  KRATOS_THROW_ERROR(std::logic_error, "Add MEAN_SIZE variable to model part!", "");
2398 
2399  if (mr_model_part.NodesBegin()->SolutionStepsDataHas(DELTA_SCALAR1) == false)
2400  KRATOS_THROW_ERROR(std::logic_error, "Add DELTA_SCALAR1 variable to model part!", "");
2401 
2402  return 0;
2403 
2404  KRATOS_CATCH("")
2405 
2406  }
2407 
2408 
2409 
2410 
2411  ModelPart& mr_model_part;
2412  int m_nparticles;
2413  int mnelems;
2414  int moffset;
2415  //vector<double> mareas_vector; UNUSED SO COMMENTED
2416  int max_nsubsteps;
2417  double max_substep_dt;
2418  int mmaximum_number_of_particles;
2419  std::vector< Convection_Particle > mparticles_vector; //Point<3>
2420  int mlast_elem_id;
2421  bool modd_timestep;
2422  bool mparticle_printing_tool_initialized;
2423  unsigned int mfilter_factor;
2424  unsigned int mlast_node_id;
2425  //ModelPart& mr_particle_model_part;
2426 
2427  vector<int> mnumber_of_particles_in_elems;
2428  vector<int> mnumber_of_particles_in_elems_aux;
2429  //vector<ParticlePointerVector*> mpointers_to_particle_pointers_vectors; //pointing to the GetValue of each element
2430  vector<ParticlePointerVector> mvector_of_particle_pointers_vectors;
2431 
2432  typename BinsObjectDynamic<Configure>::Pointer mpBinsObjectDynamic;
2433 
2434  const Variable<double>& mUnknownVar;
2435  const Variable<double>& mProjectionVar;
2436  const Variable<array_1d<double,3> >& mVelocityVar;
2437  const Variable<array_1d<double,3> >& mMeshVelocityVar;
2438 
2439  };
2440 
2441 } // namespace Kratos.
2442 
2443 #endif // KRATOS_MOVE_PARTICLE_UTILITY_FLUID_PFEM2_TRANSPORT_INCLUDED defined
Short class definition.
Definition: bins_dynamic_objects.h:57
PFEM Particle class.
Definition: convection_particle.h:62
bool & GetEraseFlag()
Definition: convection_particle.h:111
float & GetScalar1()
Definition: convection_particle.h:106
Geometry base class.
Definition: geometry.h:71
virtual double Area() const
This method calculate and return area or surface area of this geometry depending to it's dimension.
Definition: geometry.h:1345
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
size_type size() const
Definition: global_pointers_vector.h:307
void resize(size_type new_dim) const
Definition: global_pointers_vector.h:366
iterator end()
Definition: global_pointers_vector.h:229
Definition: amatrix_interface.h:41
This class aims to manage meshes for multi-physics simulations.
Definition: model_part.h:77
ElementIterator ElementsBegin(IndexType ThisIndex=0)
Definition: model_part.h:1169
NodeIterator NodesBegin(IndexType ThisIndex=0)
Definition: model_part.h:487
ProcessInfo & GetProcessInfo()
Definition: model_part.h:1746
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
ElementIterator ElementsEnd(IndexType ThisIndex=0)
Definition: model_part.h:1179
NodesContainerType & Nodes(IndexType ThisIndex=0)
Definition: model_part.h:507
ElementsContainerType::ContainerType & ElementsArray(IndexType ThisIndex=0)
Definition: model_part.h:1209
Definition: move_particle_utility.h:65
PointerVector< Convection_Particle, Convection_Particle *, std::vector< Convection_Particle * > > ParticlePointerVector
Definition: move_particle_utility.h:77
void TransferLagrangianToEulerian()
Definition: move_particle_utility.h:591
void CopyScalarVarToPreviousTimeStep(const Variable< double > &OriginVariable, ModelPart::NodesContainerType &rNodes)
Definition: move_particle_utility.h:408
void MountBin(const double CellSize)
Definition: move_particle_utility.h:294
void MoveParticles()
Definition: move_particle_utility.h:435
Configure::ContainerType ContainerType
Definition: move_particle_utility.h:71
void ExecuteParticlesPritingTool(ModelPart &lagrangian_model_part, int input_filter_factor)
Definition: move_particle_utility.h:1289
void CorrectParticlesWithoutMovingUsingDeltaVariables()
Definition: move_particle_utility.h:943
Configure::PointType PointType
Definition: move_particle_utility.h:69
Configure::ResultIteratorType ResultIteratorType
Definition: move_particle_utility.h:76
void CalculateDeltaVariables()
Definition: move_particle_utility.h:382
void TransferLagrangianToEulerianImp()
Definition: move_particle_utility.h:755
void CalculateVelOverElemSize()
Definition: move_particle_utility.h:311
void AddUniqueWeakPointer(GlobalPointersVector< TDataType > &v, const typename TDataType::WeakPointer candidate)
Definition: move_particle_utility.h:1006
void ResetBoundaryConditions()
Definition: move_particle_utility.h:352
void PreReseed(int minimum_number_of_particles)
Definition: move_particle_utility.h:1024
Configure::IteratorType IteratorType
Definition: move_particle_utility.h:73
SpatialContainersConfigure< TDim > Configure
Definition: move_particle_utility.h:68
KRATOS_CLASS_POINTER_DEFINITION(MoveParticleUtilityScalarTransport)
MoveParticleUtilityScalarTransport(ModelPart &model_part, int maximum_number_of_particles)
Definition: move_particle_utility.h:87
void MountBin()
Definition: move_particle_utility.h:274
virtual ~MoveParticleUtilityScalarTransport()
Definition: move_particle_utility.h:271
void PostReseed(int minimum_number_of_particles)
Definition: move_particle_utility.h:1144
Configure::ResultContainerType ResultContainerType
Definition: move_particle_utility.h:74
static int ThisThread()
Wrapper for omp_get_thread_num().
Definition: openmp_utils.h:108
static int GetNumThreads()
Returns the current number of threads.
Definition: parallel_utilities.cpp:34
Point class.
Definition: point.h:59
CoordinatesArrayType const & Coordinates() const
Definition: point.h:215
double Y() const
Definition: point.h:187
double Z() const
Definition: point.h:193
double X() const
Definition: point.h:181
PointerVector is a container like stl vector but using a vector to store pointers to its data.
Definition: pointer_vector.h:72
ProcessInfo holds the current value of different solution parameters.
Definition: process_info.h:59
Thhis class is a container for spatial search.
Definition: spatial_containers_configure.h:59
typename ContainerType::iterator IteratorType
Definition: spatial_containers_configure.h:82
typename ResultContainerType::iterator ResultIteratorType
Definition: spatial_containers_configure.h:85
typename PointerVectorSet< TEntity, IndexedObject >::ContainerType ContainerType
Container definition.
Definition: spatial_containers_configure.h:80
typename PointerVectorSet< TEntity, IndexedObject >::ContainerType ResultContainerType
Definition: spatial_containers_configure.h:83
#define KRATOS_THROW_ERROR(ExceptionType, ErrorMessage, MoreInfo)
Definition: define.h:77
#define KRATOS_CATCH(MoreInfo)
Definition: define.h:110
#define KRATOS_WATCH(variable)
Definition: define.h:806
#define KRATOS_TRY
Definition: define.h:109
#define KRATOS_INFO(label)
Definition: logger.h:250
Kratos::ModelPart ModelPart
Definition: kratos_wrapper.h:31
ProcessInfo & GetProcessInfo(ModelPart &rModelPart)
Definition: add_model_part_to_python.cpp:54
const Variable< double > & GetVelocityVariable()
REF: G. R. Cowper, GAUSSIAN QUADRATURE FORMULAS FOR TRIANGLES.
Definition: mesh_condition.cpp:21
KratosZeroVector< double > ZeroVector
Definition: amatrix_interface.h:561
KratosZeroMatrix< double > ZeroMatrix
Definition: amatrix_interface.h:559
std::size_t SizeType
The definition of the size type.
Definition: mortar_classes.h:43
T & noalias(T &TheMatrix)
Definition: amatrix_interface.h:484
REACTION_CHECK_STIFFNESS_FACTOR int
Definition: contact_structural_mechanics_application_variables.h:75
TABLE_NUMBER_ANGULAR_VELOCITY TABLE_NUMBER_MOMENT I33 BEAM_INERTIA_ROT_UNIT_LENGHT_Y KRATOS_DEFINE_APPLICATION_VARIABLE(DEM_APPLICATION, double, BEAM_INERTIA_ROT_UNIT_LENGHT_Z) typedef std double
Definition: DEM_application_variables.h:182
ProcessInfo
Definition: edgebased_PureConvection.py:116
model_part
Definition: face_heat.py:14
res
Definition: generate_convection_diffusion_explicit_element.py:211
v
Definition: generate_convection_diffusion_explicit_element.py:114
input
Definition: generate_frictional_mortar_condition.py:435
x2
Definition: generate_frictional_mortar_condition.py:122
x1
Definition: generate_frictional_mortar_condition.py:121
threshold
Definition: isotropic_damage_automatic_differentiation.py:135
lagrangian_model_part
Definition: lagrangian_droplet_test.py:45
int d
Definition: ode_solve.py:397
vel
Definition: pure_conduction.py:76
int k
Definition: quadrature.py:595
int j
Definition: quadrature.py:648
int node_id
Definition: read_stl.py:12
float xc
Definition: rotating_cone.py:77
float yc
Definition: rotating_cone.py:78
float delta_t
Definition: rotatingcone_PureConvectionBenchmarking.py:129
int counter
Definition: script_THERMAL_CORRECT.py:218
A
Definition: sensitivityMatrix.py:70
N
Definition: sensitivityMatrix.py:29
integer i
Definition: TensorModule.f:17
integer l
Definition: TensorModule.f:17
e
Definition: run_cpp_mpi_tests.py:31
Configure::ResultIteratorType ResultIteratorType
Definition: transfer_utility.h:252