Skip to content

Commit 3bf078e

Browse files
authored
Merge pull request #13531 from KratosMultiphysics/PR_support_fluid_condition
[IgaApplication] Support fluid condition for Stokes fluids
2 parents e2b74ba + f6d0ace commit 3bf078e

File tree

8 files changed

+810
-73
lines changed

8 files changed

+810
-73
lines changed
Lines changed: 364 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,364 @@
1+
// | / |
2+
// ' / __| _` | __| _ \ __|
3+
// . \ | ( | | ( |\__ `
4+
// _|\_\_| \__,_|\__|\___/ ____/
5+
// Multi-Physics
6+
//
7+
// License: BSD License
8+
// Kratos default license: kratos/license.txt
9+
//
10+
// Main authors: Nicolò Antonelli
11+
//
12+
//
13+
14+
// System includes
15+
16+
// External includes
17+
18+
// Project includes
19+
#include "custom_conditions/support_fluid_condition.h"
20+
21+
namespace Kratos
22+
{
23+
24+
void SupportFluidCondition::Initialize(const ProcessInfo& rCurrentProcessInfo)
25+
{
26+
InitializeMemberVariables();
27+
InitializeMaterial();
28+
}
29+
30+
void SupportFluidCondition::CalculateAll(
31+
MatrixType& rLeftHandSideMatrix,
32+
VectorType& rRightHandSideVector,
33+
const ProcessInfo& rCurrentProcessInfo,
34+
const bool CalculateStiffnessMatrixFlag,
35+
const bool CalculateResidualVectorFlag
36+
)
37+
{
38+
KRATOS_TRY
39+
40+
const auto& r_geometry = GetGeometry();
41+
const SizeType number_of_nodes = r_geometry.size();
42+
43+
// Integration
44+
const GeometryType::IntegrationPointsArrayType& r_integration_points = r_geometry.IntegrationPoints();
45+
const GeometryType::ShapeFunctionsGradientsType& DN_De = r_geometry.ShapeFunctionsLocalGradients(r_geometry.GetDefaultIntegrationMethod());
46+
47+
Matrix DN_DX(number_of_nodes,mDim);
48+
noalias(DN_DX) = DN_De[0]; // prod(DN_De[point_number],InvJ0);
49+
50+
const SizeType mat_size = number_of_nodes * (mDim+1);
51+
//resizing as needed the LHS
52+
if(rLeftHandSideMatrix.size1() != mat_size)
53+
rLeftHandSideMatrix.resize(mat_size,mat_size,false);
54+
noalias(rLeftHandSideMatrix) = ZeroMatrix(mat_size,mat_size); //resetting LHS
55+
56+
// resizing as needed the RHS
57+
if(rRightHandSideVector.size() != mat_size)
58+
rRightHandSideVector.resize(mat_size,false);
59+
noalias(rRightHandSideVector) = ZeroVector(mat_size); //resetting RHS
60+
61+
// Compute the B matrix
62+
Matrix B = ZeroMatrix(3,number_of_nodes*mDim);
63+
CalculateB(B, DN_DX);
64+
65+
// constitutive law
66+
ConstitutiveLaw::Parameters Values(r_geometry, GetProperties(), rCurrentProcessInfo);
67+
ConstitutiveVariables constitutive_variables(3);
68+
ApplyConstitutiveLaw(B, Values, constitutive_variables);
69+
Vector& r_stress_vector = Values.GetStressVector();
70+
const Matrix& r_D = Values.GetConstitutiveMatrix();
71+
Matrix DB_voigt = Matrix(prod(r_D, B));
72+
73+
// Compute the normals
74+
array_1d<double, 3> normal_physical_space;
75+
// Compute the normals
76+
array_1d<double, 3> normal_parameter_space = - r_geometry.Normal(0, GetIntegrationMethod());
77+
normal_parameter_space = normal_parameter_space / MathUtils<double>::Norm(normal_parameter_space);
78+
normal_physical_space = normal_parameter_space;
79+
80+
const Matrix& H = r_geometry.ShapeFunctionsValues();
81+
82+
GeometryType::JacobiansType J0;
83+
r_geometry.Jacobian(J0,r_geometry.GetDefaultIntegrationMethod());
84+
// Jacobian matrix cause J0 is 3x2 and we need 3x3
85+
Matrix jacobian_matrix = ZeroMatrix(3,3);
86+
jacobian_matrix(0,0) = J0[0](0,0);
87+
jacobian_matrix(0,1) = J0[0](0,1);
88+
jacobian_matrix(1,0) = J0[0](1,0);
89+
jacobian_matrix(1,1) = J0[0](1,1);
90+
jacobian_matrix(2,2) = 1.0; // 2D case
91+
92+
array_1d<double, 3> tangent_parameter_space;
93+
r_geometry.Calculate(LOCAL_TANGENT, tangent_parameter_space); // Gives the result in the parameter space !!
94+
Vector determinant_factor = prod(jacobian_matrix, tangent_parameter_space);
95+
determinant_factor[2] = 0.0; // 2D case
96+
const double det_J0 = norm_2(determinant_factor);
97+
98+
double penalty_integration = mPenalty * r_integration_points[0].Weight() * std::abs(det_J0);
99+
const double integration_weight = r_integration_points[0].Weight() * std::abs(det_J0);
100+
101+
// Compute the pressure & velocity at the previous iteration
102+
double pressure_current_iteration = 0.0;
103+
Vector velocity_current_iteration = ZeroVector(2);
104+
for(unsigned int j = 0; j < number_of_nodes; ++j) {
105+
pressure_current_iteration += r_geometry[j].GetSolutionStepValue(PRESSURE) * H(0,j);
106+
velocity_current_iteration[0] += r_geometry[j].GetSolutionStepValue(VELOCITY_X) * H(0,j);
107+
velocity_current_iteration[1] += r_geometry[j].GetSolutionStepValue(VELOCITY_Y) * H(0,j);
108+
}
109+
110+
Vector n_tensor(2);
111+
n_tensor(0) = normal_parameter_space(0); // Component in x direction
112+
n_tensor(1) = normal_parameter_space(1); // Component in y direction
113+
114+
// Compute the traction vector: sigma * n using r_stress_vector
115+
Matrix stress_old = ZeroMatrix(2, 2);
116+
stress_old(0, 0) = r_stress_vector[0]; stress_old(0, 1) = r_stress_vector[2];
117+
stress_old(1, 0) = r_stress_vector[2]; stress_old(1, 1) = r_stress_vector[1];
118+
Vector traction_current_iteration = prod(stress_old, n_tensor);
119+
120+
for (IndexType i = 0; i < number_of_nodes; i++) {
121+
for (IndexType j = 0; j < number_of_nodes; j++) {
122+
for (IndexType idim = 0; idim < 2; idim++) {
123+
124+
// Penalty term for the velocity
125+
rLeftHandSideMatrix(3*i+idim, 3*j+idim) += H(0,i)*H(0,j)* penalty_integration;
126+
127+
for (IndexType jdim = 0; jdim < 2; jdim++) {
128+
// Extract the 2x2 block for the control point i from the DB_voigt.
129+
Matrix DB_contribution = ZeroMatrix(2, 2);
130+
DB_contribution(0, 0) = DB_voigt(0, 2*j+jdim);
131+
DB_contribution(0, 1) = DB_voigt(2, 2*j+jdim);
132+
DB_contribution(1, 0) = DB_voigt(2, 2*j+jdim);
133+
DB_contribution(1, 1) = DB_voigt(1, 2*j+jdim);
134+
// Compute the traction vector: sigma * n.
135+
Vector traction = prod(DB_contribution, n_tensor);
136+
137+
// integration by parts velocity --> With Constitutive law < v cdot (DB cdot n) >
138+
rLeftHandSideMatrix(3*i+idim, 3*j+jdim) -= H(0, i) * traction(idim) * integration_weight;
139+
140+
// Nitsche term --> With Constitutive law
141+
rLeftHandSideMatrix(3*j+jdim, 3*i+idim) += H(0, i) * traction(idim) * integration_weight;
142+
}
143+
144+
// integration by parts PRESSURE
145+
rLeftHandSideMatrix(3*i+idim, 3*j+2) += H(0,j)* ( H(0,i) * normal_parameter_space[idim] )
146+
* integration_weight;
147+
}
148+
}
149+
150+
// --- RHS corresponding term ---
151+
for (IndexType idim = 0; idim < 2; idim++) {
152+
// Penalty term for the velocity
153+
rRightHandSideVector(3*i+idim) -= H(0,i)* velocity_current_iteration[idim] * penalty_integration;
154+
// integration by parts velocity --> With Constitutive law
155+
rRightHandSideVector(3*i+idim) += H(0,i) * traction_current_iteration(idim) * integration_weight;
156+
// integration by parts PRESSURE
157+
rRightHandSideVector(3*i+idim) -= pressure_current_iteration * ( H(0,i) * normal_parameter_space[idim] ) * integration_weight;
158+
159+
// Nitsche term --> With Constitutive law
160+
Matrix DB_contribution = ZeroMatrix(2, 2); // Extract the 2x2 block for the control point i from the DB_voigt.
161+
DB_contribution(0, 0) = DB_voigt(0, 2*i+idim);
162+
DB_contribution(0, 1) = DB_voigt(2, 2*i+idim);
163+
DB_contribution(1, 0) = DB_voigt(2, 2*i+idim);
164+
DB_contribution(1, 1) = DB_voigt(1, 2*i+idim);
165+
// Compute the traction vector: sigma * n.
166+
Vector traction = prod(DB_contribution, n_tensor);
167+
rRightHandSideVector(3*i+idim) -= velocity_current_iteration[idim] * traction(idim) * integration_weight;
168+
}
169+
}
170+
171+
Vector u_D = ZeroVector(2);
172+
u_D[0] = this->GetValue(VELOCITY_X);
173+
u_D[1] = this->GetValue(VELOCITY_Y);
174+
175+
for (IndexType i = 0; i < number_of_nodes; i++) {
176+
177+
for (IndexType idim = 0; idim < 2; idim++) {
178+
179+
// Penalty term for the velocity
180+
rRightHandSideVector[3*i+idim] += H(0,i) * u_D[idim] * penalty_integration;
181+
182+
// Extract the 2x2 block for the control point i from the sigma matrix.
183+
Matrix sigma_block = ZeroMatrix(2, 2);
184+
185+
sigma_block(0, 0) = DB_voigt(0, 2*i+idim);
186+
sigma_block(0, 1) = DB_voigt(2, 2*i+idim);
187+
sigma_block(1, 0) = DB_voigt(2, 2*i+idim);
188+
sigma_block(1, 1) = DB_voigt(1, 2*i+idim);
189+
// Compute the traction vector: sigma * n.
190+
Vector traction = prod(sigma_block, n_tensor); // This results in a 2x1 vector.
191+
// Nitsche term --> With Constitutive law
192+
rRightHandSideVector[3*i+idim] += u_D[idim] * traction(idim) * integration_weight;
193+
194+
}
195+
}
196+
KRATOS_CATCH("")
197+
}
198+
199+
void SupportFluidCondition::InitializeMemberVariables()
200+
{
201+
// Compute class memeber variables
202+
const auto& r_geometry = this->GetGeometry();
203+
const auto& r_DN_De = r_geometry.ShapeFunctionsLocalGradients(r_geometry.GetDefaultIntegrationMethod());
204+
205+
// Initialize DN_DX
206+
mDim = r_DN_De[0].size2();
207+
208+
Vector mesh_size_uv = this->GetValue(KNOT_SPAN_SIZES);
209+
double h = std::min(mesh_size_uv[0], mesh_size_uv[1]);
210+
if (mDim == 3) {h = std::min(h, mesh_size_uv[2]);}
211+
212+
// Compute basis function order (Note: it is not allow to use different orders in different directions)
213+
if (mDim == 3) {
214+
mBasisFunctionsOrder = std::cbrt(r_DN_De[0].size1()) - 1;
215+
} else {
216+
mBasisFunctionsOrder = std::sqrt(r_DN_De[0].size1()) - 1;
217+
}
218+
219+
mPenalty = GetProperties()[PENALTY_FACTOR];
220+
KRATOS_ERROR_IF(mPenalty == -1.0)
221+
<< "Penalty-free formulation is not available for the Stokes problem" << std::endl;
222+
223+
// Modify the penalty factor: p^2 * penalty / h (NITSCHE APPROACH)
224+
mPenalty = mBasisFunctionsOrder * mBasisFunctionsOrder * mPenalty / h;
225+
}
226+
227+
void SupportFluidCondition::CalculateB(
228+
Matrix& rB,
229+
const ShapeDerivativesType& r_DN_DX) const
230+
{
231+
const SizeType number_of_control_points = GetGeometry().size();
232+
const SizeType mat_size = number_of_control_points * 2; // Only 2 DOFs per node in 2D
233+
234+
// Resize B matrix to 3 rows (strain vector size) and appropriate number of columns
235+
if (rB.size1() != 3 || rB.size2() != mat_size)
236+
rB.resize(3, mat_size);
237+
238+
noalias(rB) = ZeroMatrix(3, mat_size);
239+
240+
for (IndexType i = 0; i < number_of_control_points; ++i)
241+
{
242+
// x-derivatives of shape functions -> relates to strain component ε_11 (xx component)
243+
rB(0, 2 * i) = r_DN_DX(i, 0); // ∂N_i / ∂x
244+
// y-derivatives of shape functions -> relates to strain component ε_22 (yy component)
245+
rB(1, 2 * i + 1) = r_DN_DX(i, 1); // ∂N_i / ∂y
246+
// Symmetric shear strain component ε_12 (xy component)
247+
rB(2, 2 * i) = r_DN_DX(i, 1); // ∂N_i / ∂y
248+
rB(2, 2 * i + 1) = r_DN_DX(i, 0); // ∂N_i / ∂x
249+
}
250+
}
251+
252+
void SupportFluidCondition::ApplyConstitutiveLaw(
253+
const Matrix& rB,
254+
ConstitutiveLaw::Parameters& rValues,
255+
ConstitutiveVariables& rConstitutiveVariables) const
256+
{
257+
const SizeType number_of_nodes = GetGeometry().size();
258+
259+
// Set constitutive law flags:
260+
Flags& ConstitutiveLawOptions=rValues.GetOptions();
261+
ConstitutiveLawOptions.Set(ConstitutiveLaw::USE_ELEMENT_PROVIDED_STRAIN, true);
262+
ConstitutiveLawOptions.Set(ConstitutiveLaw::COMPUTE_STRESS, true);
263+
ConstitutiveLawOptions.Set(ConstitutiveLaw::COMPUTE_CONSTITUTIVE_TENSOR, true);
264+
Vector old_displacement(number_of_nodes*mDim);
265+
GetSolutionCoefficientVector(old_displacement);
266+
Vector old_strain = prod(rB,old_displacement);
267+
rValues.SetStrainVector(old_strain);
268+
rValues.SetStressVector(rConstitutiveVariables.StressVector);
269+
rValues.SetConstitutiveMatrix(rConstitutiveVariables.D);
270+
271+
//ATTENTION: here we assume that only one constitutive law is employed for all of the gauss points in the element.
272+
//this is ok under the hypothesis that no history dependent behavior is employed
273+
mpConstitutiveLaw->CalculateMaterialResponseCauchy(rValues);
274+
}
275+
276+
void SupportFluidCondition::InitializeMaterial()
277+
{
278+
KRATOS_TRY
279+
if ( GetProperties()[CONSTITUTIVE_LAW] != nullptr ) {
280+
const GeometryType& r_geometry = GetGeometry();
281+
const Properties& r_properties = GetProperties();
282+
const auto& N_values = r_geometry.ShapeFunctionsValues(this->GetIntegrationMethod());
283+
284+
mpConstitutiveLaw = GetProperties()[CONSTITUTIVE_LAW]->Clone();
285+
mpConstitutiveLaw->InitializeMaterial( r_properties, r_geometry, row(N_values , 0 ));
286+
287+
} else
288+
KRATOS_ERROR << "A constitutive law needs to be specified for the element with ID " << this->Id() << std::endl;
289+
290+
KRATOS_CATCH( "" );
291+
}
292+
293+
int SupportFluidCondition::Check(const ProcessInfo& rCurrentProcessInfo) const
294+
{
295+
KRATOS_ERROR_IF_NOT(GetProperties().Has(PENALTY_FACTOR))
296+
<< "No penalty factor (PENALTY_FACTOR) defined in property of SupportFluidCondition" << std::endl;
297+
return 0;
298+
}
299+
300+
301+
void SupportFluidCondition::EquationIdVector(EquationIdVectorType &rResult, const ProcessInfo &rCurrentProcessInfo) const
302+
{
303+
const GeometryType& rGeom = this->GetGeometry();
304+
const SizeType number_of_control_points = GetGeometry().size();
305+
const unsigned int LocalSize = (mDim + 1) * number_of_control_points;
306+
307+
if (rResult.size() != LocalSize)
308+
rResult.resize(LocalSize);
309+
310+
unsigned int Index = 0;
311+
312+
for (unsigned int i = 0; i < number_of_control_points; i++)
313+
{
314+
rResult[Index++] = rGeom[i].GetDof(VELOCITY_X).EquationId();
315+
rResult[Index++] = rGeom[i].GetDof(VELOCITY_Y).EquationId();
316+
if (mDim > 2) rResult[Index++] = rGeom[i].GetDof(VELOCITY_Z).EquationId();
317+
rResult[Index++] = rGeom[i].GetDof(PRESSURE).EquationId();
318+
}
319+
}
320+
321+
322+
void SupportFluidCondition::GetDofList(
323+
DofsVectorType& rElementalDofList,
324+
const ProcessInfo& rCurrentProcessInfo) const
325+
{
326+
KRATOS_TRY;
327+
328+
const SizeType number_of_control_points = GetGeometry().size();
329+
330+
rElementalDofList.resize(0);
331+
rElementalDofList.reserve((mDim+1) * number_of_control_points);
332+
333+
for (IndexType i = 0; i < number_of_control_points; ++i) {
334+
rElementalDofList.push_back(GetGeometry()[i].pGetDof(VELOCITY_X));
335+
rElementalDofList.push_back(GetGeometry()[i].pGetDof(VELOCITY_Y));
336+
if (mDim > 2) rElementalDofList.push_back(GetGeometry()[i].pGetDof(VELOCITY_Z));
337+
rElementalDofList.push_back(GetGeometry()[i].pGetDof(PRESSURE));
338+
}
339+
340+
KRATOS_CATCH("")
341+
};
342+
343+
344+
void SupportFluidCondition::GetSolutionCoefficientVector(
345+
Vector& rValues) const
346+
{
347+
const SizeType number_of_control_points = GetGeometry().size();
348+
const SizeType mat_size = number_of_control_points * mDim;
349+
350+
if (rValues.size() != mat_size)
351+
rValues.resize(mat_size, false);
352+
353+
for (IndexType i = 0; i < number_of_control_points; ++i)
354+
{
355+
const array_1d<double, 3 >& velocity = GetGeometry()[i].GetSolutionStepValue(VELOCITY);
356+
IndexType index = i * mDim;
357+
358+
rValues[index] = velocity[0];
359+
rValues[index + 1] = velocity[1];
360+
if (mDim > 3) rValues[index + 2] = velocity[2];
361+
}
362+
}
363+
364+
} // Namespace Kratos

0 commit comments

Comments
 (0)