diff --git a/ProcessLib/PhaseField/PhaseFieldFEM-impl.h b/ProcessLib/PhaseField/PhaseFieldFEM-impl.h index 25db542f1081d1207e429a378e5b0956925a095f..812a4b36b1e6c5d554529354cec95ef3e29a68aa 100644 --- a/ProcessLib/PhaseField/PhaseFieldFEM-impl.h +++ b/ProcessLib/PhaseField/PhaseFieldFEM-impl.h @@ -14,6 +14,187 @@ namespace ProcessLib { namespace PhaseField { +template <typename ShapeFunction, typename IntegrationMethod, + int DisplacementDim> +void PhaseFieldLocalAssembler<ShapeFunction, IntegrationMethod, + DisplacementDim>:: + assembleWithJacobian(double const t, std::vector<double> const& local_x, + std::vector<double> const& local_xdot, + const double /*dxdot_dx*/, const double /*dx_dx*/, + std::vector<double>& /*local_M_data*/, + std::vector<double>& /*local_K_data*/, + std::vector<double>& local_rhs_data, + std::vector<double>& local_Jac_data) +{ + auto const local_matrix_size = local_x.size(); + assert(local_matrix_size == phasefield_size + displacement_size); + + auto d = Eigen::Map< + typename ShapeMatricesType::template VectorType<phasefield_size> const>( + local_x.data() + phasefield_index, phasefield_size); + + auto u = Eigen::Map<typename ShapeMatricesType::template VectorType< + displacement_size> const>(local_x.data() + displacement_index, + displacement_size); + + auto d_dot = Eigen::Map< + typename ShapeMatricesType::template VectorType<phasefield_size> const>( + local_xdot.data() + phasefield_index, phasefield_size); + + auto local_Jac = MathLib::createZeroedMatrix<JacobianMatrix>( + local_Jac_data, local_matrix_size, local_matrix_size); + + auto local_rhs = MathLib::createZeroedVector<RhsVector>(local_rhs_data, + local_matrix_size); + + typename ShapeMatricesType::template MatrixType<displacement_size, + phasefield_size> + Kud; + Kud.setZero(displacement_size, phasefield_size); + + typename ShapeMatricesType::template MatrixType<phasefield_size, + displacement_size> + Kdu; + Kdu.setZero(phasefield_size, displacement_size); + + typename ShapeMatricesType::NodalMatrixType Kdd; + Kdd.setZero(phasefield_size, phasefield_size); + + typename ShapeMatricesType::NodalMatrixType Ddd; + Ddd.setZero(phasefield_size, phasefield_size); + + double const& dt = _process_data.dt; + + SpatialPosition x_position; + x_position.setElementID(_element.getID()); + + unsigned const n_integration_points = + _integration_method.getNumberOfPoints(); + for (unsigned ip = 0; ip < n_integration_points; ip++) + { + x_position.setIntegrationPoint(ip); + auto const& w = _ip_data[ip].integration_weight; + auto const& N = _ip_data[ip].N; + auto const& dNdx = _ip_data[ip].dNdx; + + auto const x_coord = + interpolateXCoordinate<ShapeFunction, ShapeMatricesType>(_element, + N); + auto const& B = + LinearBMatrix::computeBMatrix<DisplacementDim, + ShapeFunction::NPOINTS, + typename BMatricesType::BMatrixType>( + dNdx, N, x_coord, _is_axially_symmetric); + + auto const& C_tensile = _ip_data[ip].C_tensile; + auto const& C_compressive = _ip_data[ip].C_compressive; + + auto& eps = _ip_data[ip].eps; + auto const& strain_energy_tensile = _ip_data[ip].strain_energy_tensile; + auto const& sigma_tensile = _ip_data[ip].sigma_tensile; + + auto& history_variable = _ip_data[ip].history_variable; + auto& history_variable_prev = _ip_data[ip].history_variable_prev; + + auto const& sigma_real = _ip_data[ip].sigma_real; + + // Kdd_1 defines one term which both used in Kdd and local_rhs for + // phase field + double const gc = _process_data.crack_resistance(t, x_position)[0]; + double const ls = _process_data.crack_length_scale(t, x_position)[0]; + typename ShapeMatricesType::NodalMatrixType const Kdd_1 = + dNdx.transpose() * 2 * gc * ls * dNdx; + + // + // displacement equation, displacement part + // + double const k = _process_data.residual_stiffness(t, x_position)[0]; + double const d_ip = N.dot(d); + double const degradation = d_ip * d_ip * (1 - k) + k; + eps.noalias() = B * u; + _ip_data[ip].updateConstitutiveRelation(t, x_position, dt, u, + degradation); + + local_Jac + .template block<displacement_size, displacement_size>( + displacement_index, displacement_index) + .noalias() += + B.transpose() * (degradation * C_tensile + C_compressive) * B * w; + + typename ShapeMatricesType::template MatrixType<DisplacementDim, + displacement_size> + N_u = ShapeMatricesType::template MatrixType< + DisplacementDim, displacement_size>::Zero(DisplacementDim, + displacement_size); + + for (int i = 0; i < DisplacementDim; ++i) + N_u.template block<1, displacement_size / DisplacementDim>( + i, i * displacement_size / DisplacementDim) + .noalias() = N; + + auto const rho_sr = _process_data.solid_density(t, x_position)[0]; + auto const& b = _process_data.specific_body_force; + local_rhs.template block<displacement_size, 1>(displacement_index, 0) + .noalias() -= + (B.transpose() * sigma_real - N_u.transpose() * rho_sr * b) * w; + + // + // displacement equation, phasefield part + // + + // Temporary storage used in the Kud and for potential reuse in the + // Kdu matrix. + auto const Kud_ip_contribution = + (B.transpose() * 2 * d_ip * sigma_tensile * N * w).eval(); + + Kud.noalias() += Kud_ip_contribution; + + if (history_variable_prev < strain_energy_tensile) + { + history_variable = strain_energy_tensile; + Kdu.noalias() += Kud_ip_contribution.transpose(); + } + else + { + history_variable = history_variable_prev; + } + + // + // phasefield equation, phasefield part. + // + Kdd.noalias() += (Kdd_1 + N.transpose() * 2 * history_variable * N + + N.transpose() * 0.5 * gc / ls * N) * + w; + double const M = _process_data.kinetic_coefficient(t, x_position)[0]; + double const d_dot_ip = N.dot(d_dot); + + local_rhs.template segment<phasefield_size>(phasefield_index) + .noalias() -= (N.transpose() * d_dot_ip / M + Kdd_1 * d + + N.transpose() * d_ip * 2 * history_variable - + N.transpose() * 0.5 * gc / ls * (1 - d_ip)) * + w; + + Ddd.noalias() += N.transpose() / M * N * w; + } + // displacement equation, phasefield part + local_Jac + .template block<displacement_size, phasefield_size>(displacement_index, + phasefield_index) + .noalias() += Kud; + + // phasefield equation, phasefield part. + local_Jac + .template block<phasefield_size, phasefield_size>(phasefield_index, + phasefield_index) + .noalias() += Kdd + Ddd / dt; + + // phasefield equation, displacement part. + local_Jac + .template block<phasefield_size, displacement_size>(phasefield_index, + displacement_index) + .noalias() += Kdu; +} + template <typename ShapeFunction, typename IntegrationMethod, int DisplacementDim> void PhaseFieldLocalAssembler<ShapeFunction, IntegrationMethod, diff --git a/ProcessLib/PhaseField/PhaseFieldFEM.h b/ProcessLib/PhaseField/PhaseFieldFEM.h index 976fa94a78bdc2f04f913e00efd6576883f6dbaa..7486f72abf1b544f0d71b74995ee56cd3712501d 100644 --- a/ProcessLib/PhaseField/PhaseFieldFEM.h +++ b/ProcessLib/PhaseField/PhaseFieldFEM.h @@ -190,180 +190,7 @@ public: std::vector<double>& /*local_M_data*/, std::vector<double>& /*local_K_data*/, std::vector<double>& local_rhs_data, - std::vector<double>& local_Jac_data) override - { - auto const local_matrix_size = local_x.size(); - assert(local_matrix_size == phasefield_size + displacement_size); - - auto d = Eigen::Map<typename ShapeMatricesType::template VectorType< - phasefield_size> const>(local_x.data() + phasefield_index, - phasefield_size); - - auto u = Eigen::Map<typename ShapeMatricesType::template VectorType< - displacement_size> const>(local_x.data() + displacement_index, - displacement_size); - - auto d_dot = Eigen::Map<typename ShapeMatricesType::template VectorType< - phasefield_size> const>(local_xdot.data() + phasefield_index, - phasefield_size); - - auto local_Jac = MathLib::createZeroedMatrix<JacobianMatrix>( - local_Jac_data, local_matrix_size, local_matrix_size); - - auto local_rhs = MathLib::createZeroedVector<RhsVector>( - local_rhs_data, local_matrix_size); - - typename ShapeMatricesType::template MatrixType<displacement_size, - phasefield_size> - Kud; - Kud.setZero(displacement_size, phasefield_size); - - typename ShapeMatricesType::template MatrixType<phasefield_size, - displacement_size> - Kdu; - Kdu.setZero(phasefield_size, displacement_size); - - typename ShapeMatricesType::NodalMatrixType Kdd; - Kdd.setZero(phasefield_size, phasefield_size); - - typename ShapeMatricesType::NodalMatrixType Ddd; - Ddd.setZero(phasefield_size, phasefield_size); - - double const& dt = _process_data.dt; - - SpatialPosition x_position; - x_position.setElementID(_element.getID()); - - unsigned const n_integration_points = - _integration_method.getNumberOfPoints(); - for (unsigned ip = 0; ip < n_integration_points; ip++) - { - x_position.setIntegrationPoint(ip); - auto const& w = _ip_data[ip].integration_weight; - auto const& N = _ip_data[ip].N; - auto const& dNdx = _ip_data[ip].dNdx; - - auto const x_coord = - interpolateXCoordinate<ShapeFunction, ShapeMatricesType>( - _element, N); - auto const& B = LinearBMatrix::computeBMatrix< - DisplacementDim, ShapeFunction::NPOINTS, - typename BMatricesType::BMatrixType>(dNdx, N, x_coord, - _is_axially_symmetric); - - auto const& C_tensile = _ip_data[ip].C_tensile; - auto const& C_compressive = _ip_data[ip].C_compressive; - - auto& eps = _ip_data[ip].eps; - auto const& strain_energy_tensile = - _ip_data[ip].strain_energy_tensile; - auto const& sigma_tensile = _ip_data[ip].sigma_tensile; - - auto& history_variable = _ip_data[ip].history_variable; - auto& history_variable_prev = _ip_data[ip].history_variable_prev; - - auto const& sigma_real = _ip_data[ip].sigma_real; - - // Kdd_1 defines one term which both used in Kdd and local_rhs for - // phase field - double const gc = _process_data.crack_resistance(t, x_position)[0]; - double const ls = - _process_data.crack_length_scale(t, x_position)[0]; - typename ShapeMatricesType::NodalMatrixType const Kdd_1 = - dNdx.transpose() * 2 * gc * ls * dNdx; - - // - // displacement equation, displacement part - // - double const k = _process_data.residual_stiffness(t, x_position)[0]; - double const d_ip = N.dot(d); - double const degradation = d_ip * d_ip * (1 - k) + k; - eps.noalias() = B * u; - _ip_data[ip].updateConstitutiveRelation(t, x_position, dt, u, - degradation); - - local_Jac - .template block<displacement_size, displacement_size>( - displacement_index, displacement_index) - .noalias() += B.transpose() * - (degradation * C_tensile + C_compressive) * B * w; - - typename ShapeMatricesType::template MatrixType<DisplacementDim, - displacement_size> - N_u = ShapeMatricesType::template MatrixType< - DisplacementDim, - displacement_size>::Zero(DisplacementDim, - displacement_size); - - for (int i = 0; i < DisplacementDim; ++i) - N_u.template block<1, displacement_size / DisplacementDim>( - i, i * displacement_size / DisplacementDim) - .noalias() = N; - - auto const rho_sr = _process_data.solid_density(t, x_position)[0]; - auto const& b = _process_data.specific_body_force; - local_rhs - .template block<displacement_size, 1>(displacement_index, 0) - .noalias() -= - (B.transpose() * sigma_real - N_u.transpose() * rho_sr * b) * w; - - // - // displacement equation, phasefield part - // - - // Temporary storage used in the Kud and for potential reuse in the - // Kdu matrix. - auto const Kud_ip_contribution = - (B.transpose() * 2 * d_ip * sigma_tensile * N * w).eval(); - - Kud.noalias() += Kud_ip_contribution; - - if (history_variable_prev < strain_energy_tensile) - { - history_variable = strain_energy_tensile; - Kdu.noalias() += Kud_ip_contribution.transpose(); - } - else - { - history_variable = history_variable_prev; - } - - // - // phasefield equation, phasefield part. - // - Kdd.noalias() += (Kdd_1 + N.transpose() * 2 * history_variable * N + - N.transpose() * 0.5 * gc / ls * N) * - w; - double const M = - _process_data.kinetic_coefficient(t, x_position)[0]; - double const d_dot_ip = N.dot(d_dot); - - local_rhs.template segment<phasefield_size>(phasefield_index) - .noalias() -= (N.transpose() * d_dot_ip / M + Kdd_1 * d + - N.transpose() * d_ip * 2 * history_variable - - N.transpose() * 0.5 * gc / ls * (1 - d_ip)) * - w; - - Ddd.noalias() += N.transpose() / M * N * w; - } - // displacement equation, phasefield part - local_Jac - .template block<displacement_size, phasefield_size>( - displacement_index, phasefield_index) - .noalias() += Kud; - - // phasefield equation, phasefield part. - local_Jac - .template block<phasefield_size, phasefield_size>(phasefield_index, - phasefield_index) - .noalias() += Kdd + Ddd / dt; - - // phasefield equation, displacement part. - local_Jac - .template block<phasefield_size, displacement_size>( - phasefield_index, displacement_index) - .noalias() += Kdu; - } + std::vector<double>& local_Jac_data) override; void assembleWithJacobianForStaggeredScheme( double const t, std::vector<double> const& local_xdot,