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.
dynamic_smagorinsky_utilities.h
Go to the documentation of this file.
1 // | / |
2 // ' / __| _` | __| _ \ __|
3 // . \ | ( | | ( |\__ `
4 // _|\_\_| \__,_|\__|\___/ ____/
5 // Multi-Physics
6 //
7 // License: BSD License
8 // Kratos default license: kratos/license.txt
9 //
10 // Main authors: Jordi Cotela
11 //
12 
13 // System includes
14 #include <vector>
15 #include <map>
16 
17 // External includes
18 
19 // Project includes
20 #include "includes/define.h"
21 #include "includes/model_part.h"
22 #include "includes/node.h"
23 #include "includes/element.h"
24 #include "utilities/openmp_utils.h"
26 #include "utilities/geometry_utilities.h"
27 
28 #include "includes/cfd_variables.h"
31 
32 #ifndef KRATOS_DYNAMIC_SMAGORINSKY_UTILITIES_H_INCLUDED
33 #define KRATOS_DYNAMIC_SMAGORINSKY_UTILITIES_H_INCLUDED
34 
35 namespace Kratos
36 {
39 
42 
44 
64 {
65 public:
66 
69 
71 
75  DynamicSmagorinskyUtils(ModelPart& rModelPart, unsigned int DomainSize):
76  mrModelPart(rModelPart),
77  mDomainSize(DomainSize),
78  mCoarseMesh(),
79  mPatchIndices()
80  {}
81 
84 
88 
90 
94  {
95  // Clear existing mesh (if any)
96  mCoarseMesh.clear();
97 
98  // Store current mesh
99  for( ModelPart::ElementsContainerType::ptr_iterator itpElem = mrModelPart.Elements().ptr_begin();
100  itpElem != mrModelPart.Elements().ptr_end(); ++itpElem)
101  {
102 // (*itpElem)->GetValue(C_SMAGORINSKY) = 0.0; // Set the Smagorinsky parameter to zero for the coarse mesh (do this once to reset any input values)
103  mCoarseMesh.push_back(*itpElem);
104  }
105 
106  // Count the number of patches in the model (in parallel)
107  const int NumThreads = ParallelUtilities::GetNumThreads();
108  OpenMPUtils::PartitionVector ElementPartition;
109  OpenMPUtils::DivideInPartitions(mCoarseMesh.size(),NumThreads,ElementPartition);
110 
111  std::vector< std::vector<int> > LocalIndices(NumThreads);
112 
113  #pragma omp parallel
114  {
115  int k = OpenMPUtils::ThisThread();
116  ModelPart::ElementsContainerType::iterator ElemBegin = mCoarseMesh.begin() + ElementPartition[k];
117  ModelPart::ElementsContainerType::iterator ElemEnd = mCoarseMesh.begin() + ElementPartition[k+1];
118 
119  for( ModelPart::ElementIterator itElem = ElemBegin; itElem != ElemEnd; ++itElem)
120  {
121  this->AddNewIndex(LocalIndices[k],itElem->GetValue(PATCH_INDEX));
122  }
123  }
124 
125  // Combine the partial lists and create a map for PATCH_INDEX -> Vector position
126  unsigned int Counter = 0;
127  std::pair<int, unsigned int> NewVal;
128  std::pair< std::map<int, unsigned int>::iterator, bool > Result;
129  for( std::vector< std::vector<int> >::iterator itList = LocalIndices.begin(); itList != LocalIndices.end(); ++itList )
130  {
131  for( std::vector<int>::iterator itIndex = itList->begin(); itIndex != itList->end(); ++itIndex)
132  {
133  // Note that instering in map already sorts and checks for uniqueness
134  NewVal.first = *itIndex;
135  NewVal.second = Counter;
136  Result = mPatchIndices.insert(NewVal);
137  if (Result.second)
138  ++Counter;
139  }
140  }
141  }
142 
144  void CalculateC()
145  {
146  // Update the velocity values for the terms that belong to the coarse mesh
147  this->SetCoarseVel();
148 
149  // Partitioning
150  const int NumThreads = ParallelUtilities::GetNumThreads();
151  OpenMPUtils::PartitionVector CoarseElementPartition,FineElementPartition;
152  OpenMPUtils::DivideInPartitions(mCoarseMesh.size(),NumThreads,CoarseElementPartition);
153  OpenMPUtils::DivideInPartitions(mrModelPart.Elements().size(),NumThreads,FineElementPartition);
154 
155  // Initialize temporary containers
156  unsigned int PatchNumber = mPatchIndices.size();
157 
158  std::vector< std::vector<double> > GlobalPatchNum(NumThreads); // Numerator on each patch
159  std::vector< std::vector<double> > GlobalPatchDen(NumThreads); // Denominator on each patch
160 
161  const double EnergyTol = 0.005;
162  double TotalDissipation = 0;
163 
164  #pragma omp parallel reduction(+:TotalDissipation)
165  {
166  int k = OpenMPUtils::ThisThread();
167 
168  // Initialize the iterator boundaries for this thread
169  ModelPart::ElementsContainerType::iterator CoarseElemBegin = mCoarseMesh.begin() + CoarseElementPartition[k];
170  ModelPart::ElementsContainerType::iterator CoarseElemEnd = mCoarseMesh.begin() + CoarseElementPartition[k+1];
171 
172  ModelPart::ElementsContainerType::iterator FineElemBegin = mrModelPart.ElementsBegin() + FineElementPartition[k];
173  ModelPart::ElementsContainerType::iterator FineElemEnd = mrModelPart.ElementsBegin() + FineElementPartition[k+1];
174 
175  // Initialize some thread-local variables
176  Vector LocalValues, LocalCoarseVel;
177  Matrix LocalMassMatrix;
178  ProcessInfo& rProcessInfo = mrModelPart.GetProcessInfo();
179 
180  double Residual,Model;
181  unsigned int PatchPosition;
182 
183  // Thread-local containers for the values in each patch
184  std::vector<double>& rPatchNum = GlobalPatchNum[k];
185  std::vector<double>& rPatchDen = GlobalPatchDen[k];
186  rPatchNum.resize(PatchNumber,0.0);// Fill with zeros
187  rPatchDen.resize(PatchNumber,0.0);
188 
189  if (mDomainSize == 2)
190  {
191  LocalValues.resize(9);
192  LocalCoarseVel.resize(9);
193  LocalMassMatrix.resize(9,9,false);
197 
198  // Evaluate the N-S and model terms in each coarse element
199  for( ModelPart::ElementsContainerType::iterator itElem = CoarseElemBegin; itElem != CoarseElemEnd; ++itElem)
200  {
201  PatchPosition = mPatchIndices[ itElem->GetValue(PATCH_INDEX) ];
202  this->GermanoTerms2D(*itElem,N,DN_DX,dv_dx,LocalValues,LocalCoarseVel,LocalMassMatrix,rProcessInfo,Residual,Model);
203 
204  rPatchNum[PatchPosition] += Residual;
205  rPatchDen[PatchPosition] += Model;
206  TotalDissipation += Residual;
207  }
208 
209  // Now evaluate the corresponding terms in the fine mesh
210  for( ModelPart::ElementsContainerType::iterator itElem = FineElemBegin; itElem != FineElemEnd; ++itElem)
211  {
212  // Deactivate Smagorinsky to compute the residual of galerkin+stabilization terms only
213  itElem->GetValue(C_SMAGORINSKY) = 0.0;
214 
215  PatchPosition = mPatchIndices[ itElem->GetValue(PATCH_INDEX) ];
216  this->GermanoTerms2D(*itElem,N,DN_DX,dv_dx,LocalValues,LocalCoarseVel,LocalMassMatrix,rProcessInfo,Residual,Model);
217 
218  rPatchNum[PatchPosition] -= Residual;
219  rPatchDen[PatchPosition] -= Model;
220  }
221  }
222  else // mDomainSize == 3
223  {
224  LocalValues.resize(16);
225  LocalCoarseVel.resize(16);
226  LocalMassMatrix.resize(16,16,false);
230 
231  // Evaluate the N-S and model terms in each coarse element
232  for( ModelPart::ElementsContainerType::iterator itElem = CoarseElemBegin; itElem != CoarseElemEnd; ++itElem)
233  {
234  PatchPosition = mPatchIndices[ itElem->GetValue(PATCH_INDEX) ];
235  this->GermanoTerms3D(*itElem,N,DN_DX,dv_dx,LocalValues,LocalCoarseVel,LocalMassMatrix,rProcessInfo,Residual,Model);
236 
237  rPatchNum[PatchPosition] += Residual;
238  rPatchDen[PatchPosition] += Model;
239  TotalDissipation += Residual;
240  }
241 
242  // Now evaluate the corresponding terms in the fine mesh
243  for( ModelPart::ElementsContainerType::iterator itElem = FineElemBegin; itElem != FineElemEnd; ++itElem)
244  {
245  // Deactivate Smagorinsky to compute the residual of galerkin+stabilization terms only
246  itElem->GetValue(C_SMAGORINSKY) = 0.0;
247 
248  PatchPosition = mPatchIndices[ itElem->GetValue(PATCH_INDEX) ];
249  this->GermanoTerms3D(*itElem,N,DN_DX,dv_dx,LocalValues,LocalCoarseVel,LocalMassMatrix,rProcessInfo,Residual,Model);
250 
251  rPatchNum[PatchPosition] -= Residual;
252  rPatchDen[PatchPosition] -= Model;
253  }
254  }
255  }
256 
257  // Combine the results of each thread in position 0
258  for( std::vector< std::vector<double> >::iterator itNum = GlobalPatchNum.begin()+1, itDen = GlobalPatchDen.begin()+1;
259  itNum != GlobalPatchNum.end(); ++itNum, ++itDen)
260  {
261  for( std::vector<double>::iterator TotalNum = GlobalPatchNum[0].begin(), LocalNum = itNum->begin(),
262  TotalDen = GlobalPatchDen[0].begin(), LocalDen = itDen->begin();
263  TotalNum != GlobalPatchNum[0].end(); ++TotalNum,++LocalNum,++TotalDen,++LocalDen)
264  {
265  *TotalNum += *LocalNum;
266  *TotalDen += *LocalDen;
267  }
268  }
269 
270  // Compute the smagorinsky coefficient for each patch by combining the values from each thread
271  std::vector<double> PatchC(PatchNumber);
272  double NumTol = EnergyTol * fabs(TotalDissipation);
273  for( std::vector<double>::iterator itNum = GlobalPatchNum[0].begin(), itDen = GlobalPatchDen[0].begin(), itC = PatchC.begin();
274  itC != PatchC.end(); ++itNum, ++itDen, ++itC)
275  {
276  // If the dissipation we are "missing" by not considering Smagorinsky is small, do not use Smagorinsky (this avoids a division by ~0, as the denominator should go to zero too)
277  if ( (fabs(*itNum) < NumTol) )//|| (fabs(*itDen) < 1.0e-12) )
278  *itC = 0.0;
279  else
280  *itC = sqrt( 0.5 * fabs( *itNum / *itDen ) );
281  }
282 
283  // Finally, assign each element its new smagorinsky value
284  #pragma omp parallel
285  {
286  int k = OpenMPUtils::ThisThread();
287  ModelPart::ElementsContainerType::iterator ElemBegin = mrModelPart.ElementsBegin() + FineElementPartition[k];
288  ModelPart::ElementsContainerType::iterator ElemEnd = mrModelPart.ElementsBegin() + FineElementPartition[k+1];
289 
290  unsigned int PatchPosition;
291 
292  for( ModelPart::ElementIterator itElem = ElemBegin; itElem != ElemEnd; ++itElem)
293  {
294  PatchPosition = mPatchIndices[ itElem->GetValue(PATCH_INDEX) ];
295  itElem->GetValue(C_SMAGORINSKY) = PatchC[PatchPosition];
296  }
297  }
298  }
299 
301 
306  void CorrectFlagValues(Variable<double>& rThisVariable = FLAG_VARIABLE)
307  {
308  // Loop over coarse mesh to evaluate all terms that do not involve the fine mesh
309  const int NumThreads = ParallelUtilities::GetNumThreads();
310  OpenMPUtils::PartitionVector NodePartition;
311  OpenMPUtils::DivideInPartitions(mrModelPart.NumberOfNodes(),NumThreads,NodePartition);
312 
313  #pragma omp parallel
314  {
315  int k = OpenMPUtils::ThisThread();
316  ModelPart::NodeIterator NodesBegin = mrModelPart.NodesBegin() + NodePartition[k];
317  ModelPart::NodeIterator NodesEnd = mrModelPart.NodesBegin() + NodePartition[k+1];
318 
319  double Value0, Value1;
320 
321  for( ModelPart::NodeIterator itNode = NodesBegin; itNode != NodesEnd; ++itNode)
322  {
323  if( itNode->GetValue(FATHER_NODES).size() == 2 ) // If the node is refined
324  {
325  Value0 = itNode->GetValue(FATHER_NODES)[0].FastGetSolutionStepValue(rThisVariable);
326  Value1 = itNode->GetValue(FATHER_NODES)[1].FastGetSolutionStepValue(rThisVariable);
327 
328  if( Value0 != Value1 ) // If this node is problematic
329  {
330  if ( Value0 == 0.0 || Value1 == 0.0 )
331  {
332  // if either of the parents is not on the boundary, this node is not on the boundary
333  itNode->FastGetSolutionStepValue(rThisVariable) = 0.0;
334  }
335  /* All remaining cases are unlikely in well-posed problems,
336  I'm arbitrarily giving priority to the outlet,
337  so that the node is only inlet or bridge surface if both parents are
338  */
339  else if( Value0 == 3.0 )
340  {
341  itNode->FastGetSolutionStepValue(rThisVariable) = Value0;
342  }
343  else if( Value1 == 3.0 )
344  {
345  // The node is only bridge surface if both parents are
346  itNode->FastGetSolutionStepValue(rThisVariable) = Value1;
347  }
348  else // Default behaviour: Parent 0 takes precedence
349  {
350  itNode->FastGetSolutionStepValue(rThisVariable) = Value0;
351  }
352  }
353  }
354  }
355  }
356  }
357 
359 
360 private:
361 
364 
366  ModelPart& mrModelPart;
368  unsigned int mDomainSize;
372  std::map<int, unsigned int> mPatchIndices;
373 
376 
378 
383  void SetCoarseVel()
384  {
385  /*
386  Note: This loop can't be parallelized, as we are relying on the fact that refined nodes are at the end of the list and their parents will be updated before the refined nodes
387  are reached. There is an alternative solution (always calculate the coarse mesh velocity from the historic database) which can be parallelized but won't work for multiple
388  levels of refinement
389  */
390  for( ModelPart::NodeIterator itNode = mrModelPart.NodesBegin(); itNode != mrModelPart.NodesEnd(); ++itNode)
391  {
392  if( itNode->GetValue(FATHER_NODES).size() == 2 )
393  {
394  Node& rParent1 = itNode->GetValue(FATHER_NODES)[0];
395  Node& rParent2 = itNode->GetValue(FATHER_NODES)[1];
396 
397  itNode->GetValue(COARSE_VELOCITY) = 0.5 * ( rParent1.FastGetSolutionStepValue(VELOCITY) + rParent2.FastGetSolutionStepValue(VELOCITY) );
398  }
399  else
400  {
401  itNode->GetValue(COARSE_VELOCITY) = itNode->FastGetSolutionStepValue(VELOCITY);
402  }
403  }
404  }
405 
407  void GermanoTerms2D(Element& rElem,
408  array_1d<double,3>& rShapeFunc,
409  BoundedMatrix<double,3,2>& rShapeDeriv,
410  BoundedMatrix<double,2,2>& rGradient,
411  Vector& rNodalResidualContainer,
412  Vector& rNodalVelocityContainer,
413  Matrix& rMassMatrix,
414  ProcessInfo& rProcessInfo,
415  double& rResidual,
416  double& rModel)
417  {
418  const double Dim = 2;
419  const double NumNodes = 3;
420 
421  // Initialize
422  double Area;
423  double Density = 0.0;
424  rGradient = ZeroMatrix(Dim,Dim);
425 
426  rResidual = 0.0;
427  rModel = 0.0;
428 
429  // Calculate the residual
430  this->CalculateResidual(rElem,rMassMatrix,rNodalVelocityContainer,rNodalResidualContainer,rProcessInfo); // We use rNodalVelocityContainer as an auxiliaty variable
431  this->GetCoarseVelocity2D(rElem,rNodalVelocityContainer);
432 
433  for( Vector::iterator itRHS = rNodalResidualContainer.begin(), itVel = rNodalVelocityContainer.begin(); itRHS != rNodalResidualContainer.end(); ++itRHS, ++itVel)
434  rResidual += (*itVel) * (*itRHS);
435 
436  // Calculate the model term
437  GeometryUtils::CalculateGeometryData( rElem.GetGeometry(), rShapeDeriv, rShapeFunc, Area);
438 
439  // Compute Grad(u), Density and < Grad(w), Grad(u) >
440  for (unsigned int j = 0; j < NumNodes; ++j) // Columns of <Grad(Ni),Grad(Nj)>
441  {
442  Density += rShapeFunc[j] * rElem.GetGeometry()[j].FastGetSolutionStepValue(DENSITY);
443  const array_1d< double,3 >& rNodeVel = rElem.GetGeometry()[j].FastGetSolutionStepValue(VELOCITY); // Nodal velocity
444 
445  for (unsigned int i = 0; i < NumNodes; ++i) // Rows of <Grad(Ni),Grad(Nj)>
446  {
447  const array_1d< double,3 >& rNodeTest = rElem.GetGeometry()[i].GetValue(COARSE_VELOCITY); // Test function (particularized to coarse velocity)
448 
449  for (unsigned int k = 0; k < Dim; ++k) // Space Dimensions
450  rModel += rNodeTest[k] * rShapeDeriv(i,k) * rShapeDeriv(j,k) * rNodeVel[k];
451  }
452 
453  for (unsigned int m = 0; m < Dim; ++m) // Calculate symmetric gradient
454  {
455  for (unsigned int n = 0; n < m; ++n) // Off-diagonal
456  rGradient(m,n) += 0.5 * (rShapeDeriv(j,n) * rNodeVel[m] + rShapeDeriv(j,m) * rNodeVel[n]); // Symmetric gradient, only lower half is written
457  rGradient(m,m) += rShapeDeriv(j,m) * rNodeVel[m]; // Diagonal
458  }
459  }
460 
461  rModel *= Area; // To this point, rModel contains the integral over the element of Grad(U_coarse):Grad(U)
462 
463  // Norm[ Grad(u) ]
464  double SqNorm = 0.0;
465  for (unsigned int i = 0; i < Dim; ++i)
466  {
467  for (unsigned int j = 0; j < i; ++j)
468  SqNorm += 2.0 * rGradient(i,j) * rGradient(i,j); // Adding off-diagonal terms (twice, as matrix is symmetric)
469  SqNorm += rGradient(i,i) * rGradient(i,i); // Diagonal terms
470  }
471 
472  // "Fixed" part of Smagorinsky viscosity: Density * FilterWidth^2 * Norm(SymmetricGrad(U)). 2*C^2 is accounted for in the caller function
473  const double sqH = 2*Area;
474  rModel *= Density * sqH * sqrt(SqNorm);
475  }
476 
478  void GermanoTerms3D(Element& rElem,
479  array_1d<double,4>& rShapeFunc,
480  BoundedMatrix<double,4,3>& rShapeDeriv,
481  BoundedMatrix<double,3,3>& rGradient,
482  Vector& rNodalResidualContainer,
483  Vector& rNodalVelocityContainer,
484  Matrix& rMassMatrix,
485  ProcessInfo& rProcessInfo,
486  double& rResidual,
487  double& rModel)
488  {
489  const double Dim = 3;
490  const double NumNodes = 4;
491 
492  // Initialize
493  double Volume;
494  double Density = 0.0;
495  rGradient = ZeroMatrix(Dim,Dim);
496 
497  rResidual = 0.0;
498  rModel = 0.0;
499 
500  // Calculate the residual
501  this->CalculateResidual(rElem,rMassMatrix,rNodalVelocityContainer,rNodalResidualContainer,rProcessInfo); // We use rNodalVelocityContainer as an auxiliaty variable
502  this->GetCoarseVelocity3D(rElem,rNodalVelocityContainer);
503 
504  for( Vector::iterator itRHS = rNodalResidualContainer.begin(), itVel = rNodalVelocityContainer.begin(); itRHS != rNodalResidualContainer.end(); ++itRHS, ++itVel)
505  rResidual += (*itVel) * (*itRHS);
506 
507  // Calculate the model term
508  GeometryUtils::CalculateGeometryData( rElem.GetGeometry(), rShapeDeriv, rShapeFunc, Volume);
509 
510  // Compute Grad(u), Density and < Grad(w), Grad(u) >
511  for (unsigned int j = 0; j < NumNodes; ++j) // Columns of <Grad(Ni),Grad(Nj)>
512  {
513  Density += rShapeFunc[j] * rElem.GetGeometry()[j].FastGetSolutionStepValue(DENSITY);
514  const array_1d< double,3 >& rNodeVel = rElem.GetGeometry()[j].FastGetSolutionStepValue(VELOCITY); // Nodal velocity
515 
516  for (unsigned int i = 0; i < NumNodes; ++i) // Rows of <Grad(Ni),Grad(Nj)>
517  {
518  const array_1d< double,3 >& rNodeTest = rElem.GetGeometry()[i].GetValue(COARSE_VELOCITY); // Test function (particularized to coarse velocity)
519 
520  for (unsigned int k = 0; k < Dim; ++k) // Space Dimensions
521  rModel += rNodeTest[k] * rShapeDeriv(i,k) * rShapeDeriv(j,k) * rNodeVel[k];
522  }
523 
524  for (unsigned int m = 0; m < Dim; ++m) // Calculate symmetric gradient
525  {
526  for (unsigned int n = 0; n < m; ++n) // Off-diagonal
527  rGradient(m,n) += 0.5 * (rShapeDeriv(j,n) * rNodeVel[m] + rShapeDeriv(j,m) * rNodeVel[n]); // Symmetric gradient, only lower half is written
528  rGradient(m,m) += rShapeDeriv(j,m) * rNodeVel[m]; // Diagonal
529  }
530  }
531 
532  rModel *= Volume; // To this point, rModel contains the integral over the element of Grad(U_coarse):Grad(U)
533 
534  // Norm[ Symmetric Grad(u) ] = ( 2 * Sij * Sij )^(1/2), we compute the Sij * Sij part in the following loop:
535  double SqNorm = 0.0;
536  for (unsigned int i = 0; i < Dim; ++i)
537  {
538  for (unsigned int j = 0; j < i; ++j)
539  SqNorm += 2.0 * rGradient(i,j) * rGradient(i,j); // Adding off-diagonal terms (twice, as matrix is symmetric)
540  SqNorm += rGradient(i,i) * rGradient(i,i); // Diagonal terms
541  }
542 
543  const double cubeH = 6*Volume;
544  rModel *= Density * pow(cubeH, 2.0/3.0) * sqrt(2.0 * SqNorm);
545  }
546 
548  void GetCoarseVelocity2D(Element& rElement,
549  Vector& rVar)
550  {
551  unsigned int LocalIndex = 0;
552  const Element::GeometryType& rGeom = rElement.GetGeometry();
553 
554  for (unsigned int itNode = 0; itNode < 3; ++itNode)
555  {
556  const array_1d< double,3>& rCoarseVel = rGeom[itNode].GetValue(COARSE_VELOCITY);
557  rVar[LocalIndex++] = rCoarseVel[0];
558  rVar[LocalIndex++] = rCoarseVel[1];
559  rVar[LocalIndex++] = 0.0; // Pressure Dof
560  }
561  }
562 
564  void GetCoarseVelocity3D(Element& rElement,
565  Vector& rVar)
566  {
567  unsigned int LocalIndex = 0;
568  const Element::GeometryType& rGeom = rElement.GetGeometry();
569 
570  for (unsigned int itNode = 0; itNode < 4; ++itNode)
571  {
572  const array_1d< double,3>& rCoarseVel = rGeom[itNode].GetValue(COARSE_VELOCITY);
573  rVar[LocalIndex++] = rCoarseVel[0];
574  rVar[LocalIndex++] = rCoarseVel[1];
575  rVar[LocalIndex++] = rCoarseVel[2];
576  rVar[LocalIndex++] = 0.0; // Pressure Dof
577  }
578  }
579 
581  void CalculateResidual(Element& rElement,
582  Matrix& rMassMatrix,
583  Vector& rAuxVector,
584  Vector& rResidual,
585  const ProcessInfo& rCurrentProcessInfo)
586  {
587  const auto& r_const_elem_ref = rElement;
588  rElement.InitializeNonLinearIteration(rCurrentProcessInfo);
589 
590  // Dynamic stabilization terms
591  rElement.CalculateRightHandSide(rResidual,rCurrentProcessInfo);
592 
593  // Dynamic Terms
594  rElement.CalculateMassMatrix(rMassMatrix,rCurrentProcessInfo);
595  r_const_elem_ref.GetSecondDerivativesVector(rAuxVector,0);
596 
597  noalias(rResidual) -= prod(rMassMatrix,rAuxVector);
598 
599  // Velocity Terms
600  rElement.CalculateLocalVelocityContribution(rMassMatrix,rResidual,rCurrentProcessInfo); // Note that once we are here, we no longer need the mass matrix
601  }
602 
604  void AddNewIndex( std::vector<int>& rIndices,
605  int ThisIndex )
606  {
607  bool IsNew = true;
608  for( std::vector<int>::iterator itIndex = rIndices.begin(); itIndex != rIndices.end(); ++itIndex)
609  {
610  if( ThisIndex == *itIndex)
611  {
612  IsNew = false;
613  break;
614  }
615  }
616 
617  if (IsNew)
618  rIndices.push_back(ThisIndex);
619  }
620 
622 
623 };
624 
626 
628 
629 } // namespace Kratos
630 
631 #endif /* KRATOS_DYNAMIC_SMAGORINSKY_UTILITIES_H_INCLUDED */
Short class definition.
Definition: counter.h:60
Helper class to dynamically determine a value for the Smagorinsly parameter.
Definition: dynamic_smagorinsky_utilities.h:64
~DynamicSmagorinskyUtils()
Destructor.
Definition: dynamic_smagorinsky_utilities.h:83
void CorrectFlagValues(Variable< double > &rThisVariable=FLAG_VARIABLE)
For the bridge analysis problem, correct the boundary flag after the refinement.
Definition: dynamic_smagorinsky_utilities.h:306
void CalculateC()
Provide a value for the Smagorinsky coefficient using the Variational Germano Identity.
Definition: dynamic_smagorinsky_utilities.h:144
void StoreCoarseMesh()
Store current mesh as coarse mesh. Call before refining.
Definition: dynamic_smagorinsky_utilities.h:93
DynamicSmagorinskyUtils(ModelPart &rModelPart, unsigned int DomainSize)
Constructor.
Definition: dynamic_smagorinsky_utilities.h:75
Geometry< NodeType > GeometryType
definition of the geometry type with given NodeType
Definition: element.h:83
static void CalculateGeometryData(const GeometryType &rGeometry, BoundedMatrix< double, 4, 3 > &rDN_DX, array_1d< double, 4 > &rN, double &rVolume)
This function is designed to compute the shape function derivatives, shape functions and volume in 3D...
Definition: geometry_utilities.h:176
void resize(std::size_t NewSize1, std::size_t NewSize2, bool preserve=0)
Definition: amatrix_interface.h:224
AMatrix::RandomAccessIterator< double > iterator
Definition: amatrix_interface.h:52
This class aims to manage different model parts across multi-physics simulations.
Definition: model.h:60
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
MeshType::ElementsContainerType ElementsContainerType
Element container. A vector set of Elements with their Id's as key.
Definition: model_part.h:168
NodeIterator NodesBegin(IndexType ThisIndex=0)
Definition: model_part.h:487
ProcessInfo & GetProcessInfo()
Definition: model_part.h:1746
MeshType::NodeIterator NodeIterator
Definition: model_part.h:134
ElementsContainerType & Elements(IndexType ThisIndex=0)
Definition: model_part.h:1189
MeshType::ElementIterator ElementIterator
Definition: model_part.h:174
SizeType NumberOfNodes(IndexType ThisIndex=0) const
Definition: model_part.h:341
This class defines the node.
Definition: node.h:65
TVariableType::Type & FastGetSolutionStepValue(const TVariableType &rThisVariable)
Definition: node.h:435
TVariableType::Type & GetValue(const TVariableType &rThisVariable)
Definition: node.h:466
static void DivideInPartitions(const int NumTerms, const int NumThreads, PartitionVector &Partitions)
Divide an array of length NumTerms between NumThreads threads.
Definition: openmp_utils.h:158
static int ThisThread()
Wrapper for omp_get_thread_num().
Definition: openmp_utils.h:108
std::vector< int > PartitionVector
Vector type for the output of DivideInPartitions method.
Definition: openmp_utils.h:53
static int GetNumThreads()
Returns the current number of threads.
Definition: parallel_utilities.cpp:34
ProcessInfo holds the current value of different solution parameters.
Definition: process_info.h:59
REF: G. R. Cowper, GAUSSIAN QUADRATURE FORMULAS FOR TRIANGLES.
Definition: mesh_condition.cpp:21
Internals::Matrix< double, AMatrix::dynamic, 1 > Vector
Definition: amatrix_interface.h:472
KratosZeroMatrix< double > ZeroMatrix
Definition: amatrix_interface.h:559
Internals::Matrix< double, AMatrix::dynamic, AMatrix::dynamic > Matrix
Definition: amatrix_interface.h:470
AMatrix::MatrixProductExpression< TExpression1Type, TExpression2Type > prod(AMatrix::MatrixExpression< TExpression1Type, TCategory1 > const &First, AMatrix::MatrixExpression< TExpression2Type, TCategory2 > const &Second)
Definition: amatrix_interface.h:568
T & noalias(T &TheMatrix)
Definition: amatrix_interface.h:484
int n
manufactured solution and derivatives (u=0 at z=0 dudz=0 at z=domain_height)
Definition: ode_solve.py:402
int k
Definition: quadrature.py:595
int j
Definition: quadrature.py:648
int m
Definition: run_marine_rain_substepping.py:8
dictionary Model
TODO replace this "model" for real one once available in kratos core.
Definition: script.py:94
N
Definition: sensitivityMatrix.py:29
integer i
Definition: TensorModule.f:17