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.
bfecc_convection.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: Riccardo Rossi
10 //
11 
12 #if !defined(KRATOS_BFECC_CONVECTION_INCLUDED )
13 #define KRATOS_BFECC_CONVECTION_INCLUDED
14 
15 #define PRESSURE_ON_EULERIAN_MESH
16 #define USE_FEW_PARTICLES
17 
18 // System includes
19 #include <string>
20 #include <iostream>
21 #include <algorithm>
22 
23 // External includes
24 
25 // Project includes
26 #include "includes/define.h"
27 #include "includes/model_part.h"
28 #include "utilities/geometry_utilities.h"
30 #include "includes/variables.h"
31 #include "utilities/timer.h"
33 #include "utilities/openmp_utils.h"
38 
39 namespace Kratos
40 {
41 
42 template<std::size_t TDim>
44 {
45 public:
47 
49  typename BinBasedFastPointLocator<TDim>::Pointer pSearchStructure,
50  const bool PartialDt = false,
51  const bool ActivateLimiter = false)
52  : mpSearchStructure(pSearchStructure), mActivateLimiter(ActivateLimiter)
53  {
54  }
55 
57  {
58  }
59 
60  //**********************************************************************************************
61  //**********************************************************************************************
63  ModelPart& rModelPart,
64  const Variable< double >& rVar,
65  const Variable<array_1d<double,3> >& conv_var,
66  const double substeps)
67  {
69  const double dt = rModelPart.GetProcessInfo()[DELTA_TIME];
70 
71  //do movement
72  Vector N(TDim + 1);
73  Vector N_valid(TDim + 1);
74  const int max_results = 10000;
75  typename BinBasedFastPointLocator<TDim>::ResultContainerType results(max_results);
76 
77  const int nparticles = rModelPart.Nodes().size();
78 
79  PointerVector< Element > elem_backward( rModelPart.Nodes().size());
80  std::vector< Vector > Ns( rModelPart.Nodes().size());
81  std::vector< bool > found( rModelPart.Nodes().size());
82 
83  // Allocate non-historical variables
84  block_for_each(rModelPart.Nodes(), [&](Node& rNode){
85  rNode.SetValue(rVar, 0.0);
86  });
87 
88  mLimiter.resize(nparticles);
89  if (mActivateLimiter){
90  CalculateLimiter(rModelPart, rVar);
91  } else{
92  for (int i = 0; i < nparticles; i++){
93  mLimiter[i] = 1.0;
94  }
95  }
96 
97  //FIRST LOOP: estimate rVar(n+1)
98  #pragma omp parallel for firstprivate(results,N,N_valid)
99  for (int i = 0; i < nparticles; i++)
100  {
101  typename BinBasedFastPointLocator<TDim>::ResultIteratorType result_begin = results.begin();
102 
103  ModelPart::NodesContainerType::iterator it_particle = rModelPart.NodesBegin() + i;
104 
105  Element::Pointer pelement;
106  Element::Pointer pelement_valid;
107 
108  array_1d<double,3> bckPos = it_particle->Coordinates();
109  const array_1d<double,3>& vel = it_particle->FastGetSolutionStepValue(conv_var);
110  bool has_valid_elem_pointer = false;
111  bool is_found = ConvectBySubstepping(dt,bckPos,vel, N,N_valid, pelement,pelement_valid, result_begin, max_results, -1.0, substeps, conv_var, has_valid_elem_pointer);
112  found[i] = is_found;
113 
114  if(is_found) {
115  //save position backwards
116  elem_backward(i) = pelement;
117  Ns[i] = N;
118 
119  Geometry< Node >& geom = pelement->GetGeometry();
120  double phi1 = N[0] * ( geom[0].FastGetSolutionStepValue(rVar,1));
121  for (unsigned int k = 1; k < geom.size(); k++) {
122  phi1 += N[k] * ( geom[k].FastGetSolutionStepValue(rVar,1) );
123  }
124 
125  it_particle->FastGetSolutionStepValue(rVar) = phi1;
126  }
127  else if(has_valid_elem_pointer)
128  {
129  //save position backwards
130  elem_backward(i) = pelement_valid;
131  Ns[i] = N_valid;
132 
133  Geometry< Node >& geom = pelement_valid->GetGeometry();
134  double phi1 = N[0] * ( geom[0].FastGetSolutionStepValue(rVar,1));
135  for (unsigned int k = 1; k < geom.size(); k++) {
136  phi1 += N_valid[k] * ( geom[k].FastGetSolutionStepValue(rVar,1) );
137  }
138 
139  it_particle->FastGetSolutionStepValue(rVar) = phi1;
140  }
141  }
142 
143  //now obtain the value AT TIME STEP N by taking it from N+1
144  #pragma omp parallel for firstprivate(results,N,N_valid)
145  for (int i = 0; i < nparticles; i++)
146  {
147  typename BinBasedFastPointLocator<TDim>::ResultIteratorType result_begin = results.begin();
148 
149  ModelPart::NodesContainerType::iterator it_particle = rModelPart.NodesBegin() + i;
150 
151  Element::Pointer pelement;
152  Element::Pointer pelement_valid;
153 
154  array_1d<double,3> fwdPos = it_particle->Coordinates();
155  const array_1d<double,3>& vel = it_particle->FastGetSolutionStepValue(conv_var,1);
156  bool has_valid_elem_pointer = false;
157  bool is_found = ConvectBySubstepping(dt,fwdPos,vel, N, N_valid, pelement, pelement_valid, result_begin, max_results, 1.0, substeps, conv_var,has_valid_elem_pointer);
158 
159  if(is_found) {
160  Geometry< Node >& geom = pelement->GetGeometry();
161  double phi_old = N[0] * ( geom[0].FastGetSolutionStepValue(rVar));
162 
163  for (unsigned int k = 1; k < geom.size(); k++) {
164  phi_old += N[k] * ( geom[k].FastGetSolutionStepValue(rVar) );
165  }
166 
167  //store correction
168  const auto limiter_factor = 0.5*mLimiter[i];
169  it_particle->GetValue(rVar) = (1.0 + limiter_factor)*it_particle->FastGetSolutionStepValue(rVar,1) - limiter_factor*phi_old;
170 // iparticle->FastGetSolutionStepValue(rVar) = iparticle->GetValue(rVar) - 0.5 * (phi2 - iparticle->FastGetSolutionStepValue(rVar,1));
171  }
172  else
173  {
174  it_particle->GetValue(rVar) = it_particle->FastGetSolutionStepValue(rVar,1);
175  }
176  }
177 
178  #pragma omp parallel for
179  for (int i = 0; i < nparticles; i++)
180  {
181  ModelPart::NodesContainerType::iterator it_particle = rModelPart.NodesBegin() + i;
182  bool is_found = found[i];
183  if(is_found) {
184  Vector N = Ns[i];
185  Geometry< Node >& geom = elem_backward[i].GetGeometry();
186  double phi1 = N[0] * ( geom[0].GetValue(rVar));
187  for (unsigned int k = 1; k < geom.size(); k++) {
188  phi1 += N[k] * ( geom[k].GetValue(rVar) );
189  }
190 
191  it_particle->FastGetSolutionStepValue(rVar) = phi1;
192  }
193 // else
194 // std::cout << "it should find it" << std::endl;
195  }
196 
197  KRATOS_CATCH("")
198  }
199 
201  const double dt,
202  array_1d<double,3>& position, //IT WILL BE MODIFIED
203  const array_1d<double,3>& initial_velocity,
204  Vector& N,
205  Vector& N_valid,
206  Element::Pointer& pelement,
207  Element::Pointer& pelement_valid,
209  const unsigned int max_results,
210  const double velocity_sign,
211  const double subdivisions,
212  const Variable<array_1d<double,3> >& conv_var,
213  bool& has_valid_elem_pointer)
214  {
215  bool is_found = false;
216  array_1d<double,3> veulerian;
217  const double small_dt = dt/subdivisions;
218 
219  if(velocity_sign > 0.0) //going from the past to the future
220  {
221  noalias(position) += small_dt*initial_velocity;
222  unsigned int substep=0;
223  while(substep++ < subdivisions)
224  {
225  is_found = mpSearchStructure->FindPointOnMesh(position, N, pelement, result_begin, max_results);
226 
227  if (is_found == true)
228  {
229  Geometry< Node >& geom = pelement->GetGeometry();
230 
231  const double new_step_factor = static_cast<double>(substep)/subdivisions;
232  const double old_step_factor = (1.0 - new_step_factor);
233 
234  noalias(veulerian) = N[0] * ( new_step_factor*geom[0].FastGetSolutionStepValue(conv_var) + old_step_factor*geom[0].FastGetSolutionStepValue(conv_var,1));
235  for (unsigned int k = 1; k < geom.size(); k++)
236  noalias(veulerian) += N[k] * ( new_step_factor*geom[k].FastGetSolutionStepValue(conv_var) + old_step_factor*geom[k].FastGetSolutionStepValue(conv_var,1) );
237 
238  noalias(position) += small_dt*veulerian;
239 
240  N_valid = N;
241  pelement_valid = pelement;
242  has_valid_elem_pointer = true;
243 
244  }
245  else
246  break;
247  }
248  }
249  else //going from the future to the past
250  {
251  noalias(position) -= small_dt*initial_velocity;
252  unsigned int substep=0;
253  while(substep++ < subdivisions)
254  {
255  is_found = mpSearchStructure->FindPointOnMesh(position, N, pelement, result_begin, max_results);
256 
257  if (is_found == true)
258  {
259  Geometry< Node >& geom = pelement->GetGeometry();
260 
261  //this factors get inverted from the other case
262  const double old_step_factor = static_cast<double>(substep)/subdivisions;
263  const double new_step_factor = (1.0 - old_step_factor);
264 
265  noalias(veulerian) = N[0] * ( new_step_factor*geom[0].FastGetSolutionStepValue(conv_var) + old_step_factor*geom[0].FastGetSolutionStepValue(conv_var,1));
266  for (unsigned int k = 1; k < geom.size(); k++)
267  noalias(veulerian) += N[k] * ( new_step_factor*geom[k].FastGetSolutionStepValue(conv_var) + old_step_factor*geom[k].FastGetSolutionStepValue(conv_var,1) );
268 
269  noalias(position) -= small_dt*veulerian;
270 
271  N_valid = N;
272  pelement_valid = pelement;
273  has_valid_elem_pointer = true;
274 
275 
276  }
277  else
278  break;
279  }
280  }
281 
282  return is_found;
283 
284  }
285 
286  // ************************************************************************************************************
287  // See [Kuzmin et al., Comput. Methods Appl. Mech. Engrg., 322 (2017) 23–41] for more info about this limiter
288  // Befor calling make sure that non-historical variable "DISTANCE_GRADIENT" contains the nodal gradient of rVar
290  ModelPart& rModelPart,
291  const Variable< double >& rVar)
292  {
293  const double epsilon = 1.0e-15;
294  const double power = 2.0;
295 
296  const int nparticles = rModelPart.Nodes().size();
297 
298  if(static_cast<int>(mSigmaPlus.size()) != nparticles){
299  mSigmaPlus.resize(nparticles);
300  mSigmaMinus.resize(nparticles);
301  }
302 
303  auto& r_default_comm = rModelPart.GetCommunicator().GetDataCommunicator();
305 
306  for (int i_node = 0; i_node < static_cast<int>(rModelPart.NumberOfNodes()); ++i_node){
307  auto it_node = rModelPart.NodesBegin() + i_node;
308  GlobalPointersVector< Node >& global_pointer_list = it_node->GetValue(NEIGHBOUR_NODES);
309 
310  for (unsigned int j = 0; j< global_pointer_list.size(); ++j)
311  {
312  auto& global_pointer = global_pointer_list(j);
313  gp_list.push_back(global_pointer);
314  }
315  }
316 
317  GlobalPointerCommunicator< Node > pointer_comm(r_default_comm, gp_list);
318 
319  auto coordinate_proxy = pointer_comm.Apply(
321  {
322  return global_pointer->Coordinates();
323  }
324  );
325 
326  auto distance_proxy = pointer_comm.Apply(
327  [&](GlobalPointer<Node >& global_pointer) -> double
328  {
329  return global_pointer->FastGetSolutionStepValue(rVar);
330  }
331  );
332 
333  IndexPartition<int>(nparticles).for_each(
334  [&](int i_node){
335  auto it_node = rModelPart.NodesBegin() + i_node;
336  const auto& X_i = it_node->Coordinates();
337  const auto& grad_i = it_node->GetValue(DISTANCE_GRADIENT);
338 
339  double S_plus = 0.0;
340  double S_minus = 0.0;
341 
342  GlobalPointersVector< Node >& global_pointer_list = it_node->GetValue(NEIGHBOUR_NODES);
343 
344  for (unsigned int j = 0; j< global_pointer_list.size(); ++j)
345  {
346 
347  /* if (it_node->Id() == j_node->Id())
348  continue; */
349 
350  auto& global_pointer = global_pointer_list(j);
351  auto X_j = coordinate_proxy.Get(global_pointer);
352 
353  S_plus += std::max(0.0, inner_prod(grad_i, X_i-X_j));
354  S_minus += std::min(0.0, inner_prod(grad_i, X_i-X_j));
355  }
356 
357  mSigmaPlus[i_node] = std::min(1.0, (std::abs(S_minus)+epsilon)/(S_plus+epsilon));
358  mSigmaMinus[i_node] = std::min(1.0, (S_plus+epsilon)/(std::abs(S_minus)+epsilon));
359  }
360  );
361 
362  IndexPartition<int>(nparticles).for_each(
363  [&](int i_node){
364  auto it_node = rModelPart.NodesBegin() + i_node;
365  const double distance_i = it_node->FastGetSolutionStepValue(rVar);
366  const auto& X_i = it_node->Coordinates();
367  const auto& grad_i = it_node->GetValue(DISTANCE_GRADIENT);
368 
369  double numerator = 0.0;
370  double denominator = 0.0;
371 
372  GlobalPointersVector< Node >& global_pointer_list = it_node->GetValue(NEIGHBOUR_NODES);
373 
374  for (unsigned int j = 0; j< global_pointer_list.size(); ++j)
375  {
376 
377  /* if (it_node->Id() == j_node->Id())
378  continue; */
379 
380  auto& global_pointer = global_pointer_list(j);
381  auto X_j = coordinate_proxy.Get(global_pointer);
382  const double distance_j = distance_proxy.Get(global_pointer);
383 
384  double beta_ij = 1.0;
385  if (inner_prod(grad_i, X_i-X_j) > 0)
386  beta_ij = mSigmaPlus[i_node];
387  else if (inner_prod(grad_i, X_i-X_j) < 0)
388  beta_ij = mSigmaMinus[i_node];
389 
390  numerator += beta_ij*(distance_i - distance_j);
391  denominator += beta_ij*std::abs(distance_i - distance_j);
392  }
393 
394  const double fraction = (std::abs(numerator)/* +epsilon */) / (denominator + epsilon);
395  mLimiter[i_node] = 1.0 - std::pow(fraction, power);
396  }
397  );
398  }
399 
400 
401  void ResetBoundaryConditions(ModelPart& rModelPart, const Variable< double >& rVar)
402  {
403  KRATOS_TRY
404 
405  ModelPart::NodesContainerType::iterator inodebegin = rModelPart.NodesBegin();
406  vector<int> node_partition;
407  #ifdef _OPENMP
408  int number_of_threads = omp_get_max_threads();
409  #else
410  int number_of_threads = 1;
411  #endif
412  OpenMPUtils::CreatePartition(number_of_threads, rModelPart.Nodes().size(), node_partition);
413 
414  #pragma omp parallel for
415  for(int kkk=0; kkk<number_of_threads; kkk++)
416  {
417  for(int ii=node_partition[kkk]; ii<node_partition[kkk+1]; ii++)
418  {
419  ModelPart::NodesContainerType::iterator inode = inodebegin+ii;
420 
421  if (inode->IsFixed(rVar))
422  {
423  inode->FastGetSolutionStepValue(rVar)=inode->GetSolutionStepValue(rVar,1);
424  }
425  }
426  }
427 
428  KRATOS_CATCH("")
429  }
430 
432  {
433  KRATOS_TRY
434  ModelPart::NodesContainerType::iterator inodebegin = rModelPart.NodesBegin();
435  vector<int> node_partition;
436  #ifdef _OPENMP
437  int number_of_threads = omp_get_max_threads();
438  #else
439  int number_of_threads = 1;
440  #endif
441  OpenMPUtils::CreatePartition(number_of_threads, rModelPart.Nodes().size(), node_partition);
442 
443  #pragma omp parallel for
444  for(int kkk=0; kkk<number_of_threads; kkk++)
445  {
446  for(int ii=node_partition[kkk]; ii<node_partition[kkk+1]; ii++)
447  {
448  ModelPart::NodesContainerType::iterator inode = inodebegin+ii;
449  inode->GetSolutionStepValue(rVar,1) = inode->FastGetSolutionStepValue(rVar);
450  }
451  }
452  KRATOS_CATCH("")
453  }
454 
455 protected:
457 
458 private:
459  typename BinBasedFastPointLocator<TDim>::Pointer mpSearchStructure;
460  //const bool mPartialDt;
461  const bool mActivateLimiter;
462 
463 
464 
465 };
466 
467 } // namespace Kratos.
468 
469 #endif // KRATOS_BFECC_CONVECTION_INCLUDED defined
Definition: bfecc_convection.h:44
void CopyScalarVarToPreviousTimeStep(ModelPart &rModelPart, const Variable< double > &rVar)
Definition: bfecc_convection.h:431
~BFECCConvection()
Definition: bfecc_convection.h:56
void BFECCconvect(ModelPart &rModelPart, const Variable< double > &rVar, const Variable< array_1d< double, 3 > > &conv_var, const double substeps)
Definition: bfecc_convection.h:62
Kratos::Vector mSigmaPlus
Definition: bfecc_convection.h:456
KRATOS_CLASS_POINTER_DEFINITION(BFECCConvection< TDim >)
Kratos::Vector mSigmaMinus
Definition: bfecc_convection.h:456
Kratos::Vector mLimiter
Definition: bfecc_convection.h:456
void CalculateLimiter(ModelPart &rModelPart, const Variable< double > &rVar)
Definition: bfecc_convection.h:289
BFECCConvection(typename BinBasedFastPointLocator< TDim >::Pointer pSearchStructure, const bool PartialDt=false, const bool ActivateLimiter=false)
Definition: bfecc_convection.h:48
bool ConvectBySubstepping(const double dt, array_1d< double, 3 > &position, const array_1d< double, 3 > &initial_velocity, Vector &N, Vector &N_valid, Element::Pointer &pelement, Element::Pointer &pelement_valid, typename BinBasedFastPointLocator< TDim >::ResultIteratorType &result_begin, const unsigned int max_results, const double velocity_sign, const double subdivisions, const Variable< array_1d< double, 3 > > &conv_var, bool &has_valid_elem_pointer)
Definition: bfecc_convection.h:200
void ResetBoundaryConditions(ModelPart &rModelPart, const Variable< double > &rVar)
Definition: bfecc_convection.h:401
This class is designed to allow the fast location of MANY points on the top of a 3D mesh.
Definition: binbased_fast_point_locator.h:68
ConfigureType::ResultIteratorType ResultIteratorType
Definition: binbased_fast_point_locator.h:82
ConfigureType::ResultContainerType ResultContainerType
Definition: binbased_fast_point_locator.h:81
virtual const DataCommunicator & GetDataCommunicator() const
Definition: communicator.cpp:340
Geometry base class.
Definition: geometry.h:71
SizeType size() const
Definition: geometry.h:518
TVariableType::Type & GetValue(const TVariableType &rThisVariable)
Definition: geometry.h:627
A template class for handling communication related to global pointers.
Definition: pointer_communicator.h:178
ResultsProxy< TPointerDataType, TFunctorType > Apply(TFunctorType &&UserFunctor)
Applies a user-provided function to the global pointers and return a proxy to the results.
Definition: pointer_communicator.h:266
This class is a wrapper for a pointer to a data that is located in a different rank.
Definition: global_pointer.h:44
This class is a vector which stores global pointers.
Definition: global_pointers_vector.h:61
void push_back(TPointerType x)
Definition: global_pointers_vector.h:322
size_type size() const
Definition: global_pointers_vector.h:307
This class is useful for index iteration over containers.
Definition: parallel_utilities.h:451
void for_each(TUnaryFunction &&f)
Definition: parallel_utilities.h:514
void resize(std::size_t NewSize1, std::size_t NewSize2, bool preserve=0)
Definition: amatrix_interface.h:224
This class aims to manage meshes for multi-physics simulations.
Definition: model_part.h:77
Communicator & GetCommunicator()
Definition: model_part.h:1821
NodeIterator NodesBegin(IndexType ThisIndex=0)
Definition: model_part.h:487
ProcessInfo & GetProcessInfo()
Definition: model_part.h:1746
SizeType NumberOfNodes(IndexType ThisIndex=0) const
Definition: model_part.h:341
NodesContainerType & Nodes(IndexType ThisIndex=0)
Definition: model_part.h:507
This class defines the node.
Definition: node.h:65
PointerVector is a container like stl vector but using a vector to store pointers to its data.
Definition: pointer_vector.h:72
#define KRATOS_CATCH(MoreInfo)
Definition: define.h:110
#define KRATOS_TRY
Definition: define.h:109
dt
Definition: DEM_benchmarks.py:173
static double max(double a, double b)
Definition: GeometryFunctions.h:79
static double min(double a, double b)
Definition: GeometryFunctions.h:71
REF: G. R. Cowper, GAUSSIAN QUADRATURE FORMULAS FOR TRIANGLES.
Definition: mesh_condition.cpp:21
void block_for_each(TIterator itBegin, TIterator itEnd, TFunction &&rFunction)
Execute a functor on all items of a range in parallel.
Definition: parallel_utilities.h:299
TExpression1Type::data_type inner_prod(AMatrix::MatrixExpression< TExpression1Type, TCategory1 > const &First, AMatrix::MatrixExpression< TExpression2Type, TCategory2 > const &Second)
Definition: amatrix_interface.h:592
T & noalias(T &TheMatrix)
Definition: amatrix_interface.h:484
list fraction
Definition: angle_finder.py:11
phi_old
Definition: generate_convection_diffusion_explicit_element.py:103
vel
Definition: pure_conduction.py:76
int k
Definition: quadrature.py:595
int j
Definition: quadrature.py:648
N
Definition: sensitivityMatrix.py:29
integer i
Definition: TensorModule.f:17