|
| 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