diff --git a/src/model/materials/internal.hh b/src/model/materials/internal.hh index e71461b..8b93a7d 100644 --- a/src/model/materials/internal.hh +++ b/src/model/materials/internal.hh @@ -1,63 +1,63 @@ /* * SPDX-License-Indentifier: AGPL-3.0-or-later * * Copyright (©) 2016-2022 EPFL (École Polytechnique Fédérale de Lausanne), * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * */ /* -------------------------------------------------------------------------- */ #ifndef INTERNAL_HH #define INTERNAL_HH /* -------------------------------------------------------------------------- */ #include "grid.hh" #include /* -------------------------------------------------------------------------- */ namespace tamaas { template struct Internal { /// Stored field std::shared_ptr> field; /// Initialize previous field void initialize() { previous = std::make_shared>(field->sizes(), field->getNbComponents()); update(); } /// Update the field previous state void update() { *previous = *field; } /// Reset the current field void reset() { *field = *previous; } /// Assign the field pointer void operator=(decltype(field)&& field) { this->field = std::move(field); } /// Dereference the field pointer typename decltype(field)::element_type& operator*() { return *field; } /// Dereference the field pointer (const version) const typename decltype(field)::element_type& operator*() const { return *field; } /// Upcast to GridBase pointer operator std::shared_ptr>() { return field; } -private: +public: decltype(field) previous; }; } // namespace tamaas #endif // INTERNAL_HH diff --git a/src/model/materials/isotropic_hardening.cpp b/src/model/materials/isotropic_hardening.cpp index e6df614..62a5e66 100644 --- a/src/model/materials/isotropic_hardening.cpp +++ b/src/model/materials/isotropic_hardening.cpp @@ -1,178 +1,195 @@ /* * SPDX-License-Indentifier: AGPL-3.0-or-later * * Copyright (©) 2016-2022 EPFL (École Polytechnique Fédérale de Lausanne), * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "isotropic_hardening.hh" #include "influence.hh" /* -------------------------------------------------------------------------- */ namespace tamaas { /* -------------------------------------------------------------------------- */ template IsotropicHardening::IsotropicHardening(Model* model, Real sigma_0, Real h) : Material(model), sigma_0(sigma_0), h(h) { plastic_strain = model->request( "plastic_strain", model->getDiscretization(), trait::voigt); cumulated_plastic_strain = model->request( "cumulated_plastic_strain", model->getDiscretization(), 1); plastic_strain.initialize(); cumulated_plastic_strain.initialize(); } /* -------------------------------------------------------------------------- */ template <> void IsotropicHardening:: computeInelasticDeformationIncrement(Field& increment, const Field& strain, const Field& strain_increment) { influence::ElasticHelper elasticity(this->model->getShearModulus(), this->model->getPoissonRatio()); plastic_strain.reset(); cumulated_plastic_strain.reset(); Real sigma_0 = this->sigma_0, h = this->h; // for captures Loop::loop( [elasticity, sigma_0, h] CUDA_LAMBDA(Mat dep, // < plastic strain increment CMat epsilon, // < total strain CMat delta_epsilon, // < strain increment Mat ep, // < plastic strain Real & p /* < cumulated plastic strain */) { // Trial elastic stress auto sigma_tr = elasticity(epsilon - ep + delta_epsilon); // Zero increment by default dep = 0; // Deviatoric trial stress decltype(sigma_tr) dev; dev.deviatoric(sigma_tr); // Von-Mises stress Real von_mises = std::sqrt(1.5) * dev.l2norm(); // Plasticity condition if (von_mises - IsotropicHardening::hardening( p, h, sigma_0) > 0) { // radial return Real dp = (von_mises - IsotropicHardening::hardening( p, h, sigma_0)) / (3 * elasticity.mu + h); dev *= 3 * dp / (2 * von_mises); // saving memory (dev is delta ep) dep = dev; p += dp; ep += dep; } }, range(increment), range(strain), range(strain_increment), range(*plastic_strain), *cumulated_plastic_strain); } /* -------------------------------------------------------------------------- */ template <> void IsotropicHardening::computeStress( Field& stress, const Field& strain, const Field& strain_increment) { this->computeInelasticDeformationIncrement(stress, strain, strain_increment); const influence::ElasticHelper elasticity( this->model->getShearModulus(), this->model->getPoissonRatio()); Loop::loop( [elasticity] CUDA_LAMBDA(Mat sigma, // < stress CMat epsilon, // < total strain CMat delta_epsilon, // < strain increment CMat ep // < plastic strain ) { sigma = epsilon; sigma += delta_epsilon; sigma -= ep; sigma = elasticity(sigma); }, range(stress), range(strain), range(strain_increment), range(*plastic_strain)); } +/* -------------------------------------------------------------------------- */ +template <> +void IsotropicHardening::computeEigenStress( + Field& stress, const Field& strain, const Field& strain_increment) { + this->computeInelasticDeformationIncrement(stress, strain, strain_increment); + + const influence::ElasticHelper elasticity( + this->model->getShearModulus(), this->model->getPoissonRatio()); + + Loop::loop([elasticity] CUDA_LAMBDA(Mat sigma, // < stress + CMat ep, // < plastic strain + CMat ep_prev // < previous plastic strain + ) { sigma = elasticity(ep - ep_prev); }, + range(stress), range(*plastic_strain), + range(*plastic_strain.previous)); +} + /* -------------------------------------------------------------------------- */ template void IsotropicHardening::update() { plastic_strain.update(); cumulated_plastic_strain.update(); } /* -------------------------------------------------------------------------- */ template <> void IsotropicHardening::applyTangentIncrement( Grid& output, const Grid& input, const Grid& strain, const Grid& strain_increment) const { const influence::ElasticHelper elasticity( this->model->getShearModulus(), this->model->getPoissonRatio()); Real sigma_0 = this->sigma_0, h = this->h; // for captures Loop::loop( [elasticity, sigma_0, h] CUDA_LAMBDA(Mat out, CMat in, CMat epsilon, CMat delta_epsilon, CMat ep, const Real& p) { auto sigma_tr = elasticity(epsilon - ep + delta_epsilon); decltype(sigma_tr) dev; dev.deviatoric(sigma_tr, 3); auto von_mises = std::sqrt(1.5) * dev.l2norm(); if (von_mises - IsotropicHardening::hardening( p, h, sigma_0) > 0) { Real dp = (von_mises - IsotropicHardening::hardening( p, h, sigma_0)) / (3 * elasticity.mu + h); // Applying tangent from Bonnet & Frangi, p.175 const Real beta = 3 * elasticity.mu * dp / von_mises; const Real gamma = 3 * elasticity.mu / (3 * elasticity.mu + h); const Real dot = dev.dot(in); dev *= 3 * elasticity.mu * (gamma - beta) * dot / (von_mises * von_mises); out.deviatoric(in); out *= 2 * elasticity.mu * beta; out += dev; } else out = 0; }, range(output), range(input), range(strain), range(strain_increment), range(*this->plastic_strain), *this->cumulated_plastic_strain); } /* -------------------------------------------------------------------------- */ /* Template instanciation */ /* -------------------------------------------------------------------------- */ template class IsotropicHardening; } // namespace tamaas diff --git a/src/model/materials/isotropic_hardening.hh b/src/model/materials/isotropic_hardening.hh index 3191134..5d0253e 100644 --- a/src/model/materials/isotropic_hardening.hh +++ b/src/model/materials/isotropic_hardening.hh @@ -1,90 +1,94 @@ /* * SPDX-License-Indentifier: AGPL-3.0-or-later * * Copyright (©) 2016-2022 EPFL (École Polytechnique Fédérale de Lausanne), * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * */ /* -------------------------------------------------------------------------- */ #ifndef ISOTROPIC_HARDENING_HH #define ISOTROPIC_HARDENING_HH /* -------------------------------------------------------------------------- */ #include "grid.hh" #include "influence.hh" #include "internal.hh" #include "material.hh" #include "model.hh" #include "model_type.hh" /* -------------------------------------------------------------------------- */ namespace tamaas { /* -------------------------------------------------------------------------- */ template class IsotropicHardening : Material { using parent = Material; using trait = typename parent::trait; static constexpr UInt dim = parent::trait::dimension; using Field = typename parent::Field; public: /// Constructor IsotropicHardening(Model* model, Real sigma_0, Real h); /// Compute plastic strain increment with radial return algorithm void computeInelasticDeformationIncrement(Field& increment, const Field& strain, const Field& strain_increment) override; /// Compute stress void computeStress(Field& stress, const Field& strain, const Field& strain_increment) override; + /// Compute stress due to plastic strain increment + void computeEigenStress(Field& stress, const Field& strain, + const Field& strain_increment) override; + /// Update internal variables void update() override; void applyTangentIncrement(Field& output, const Field& input, const Field& strain, const Field& strain_increment) const; /// Linear hardening function static __device__ __host__ Real hardening(Real p, Real h, Real sigma_0) { return sigma_0 + h * p; } Real getHardeningModulus() const { return h; } Real getYieldStress() const { return sigma_0; } const GridBase& getPlasticStrain() const { return *plastic_strain; } GridBase& getPlasticStrain() { return *plastic_strain; } void setHardeningModulus(Real h_) { if (h_ < 0) TAMAAS_EXCEPTION("Hardening modulus should be positive"); h = h_; } void setYieldStress(Real sigma_0_) { if (sigma_0_ < 0) TAMAAS_EXCEPTION("Yield stress should be positive"); sigma_0 = sigma_0_; } protected: Real sigma_0; /// < initial yield stress Real h; /// < hardening modulus Internal plastic_strain, cumulated_plastic_strain; }; } // namespace tamaas /* -------------------------------------------------------------------------- */ #endif // ISOTROPIC_HARDENING_HH diff --git a/src/model/materials/material.hh b/src/model/materials/material.hh index af73116..67460f4 100644 --- a/src/model/materials/material.hh +++ b/src/model/materials/material.hh @@ -1,67 +1,71 @@ /* * SPDX-License-Indentifier: AGPL-3.0-or-later * * Copyright (©) 2016-2022 EPFL (École Polytechnique Fédérale de Lausanne), * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * */ /* -------------------------------------------------------------------------- */ #ifndef MATERIAL_HH #define MATERIAL_HH /* -------------------------------------------------------------------------- */ #include "grid.hh" #include "model.hh" #include "model_type.hh" /* -------------------------------------------------------------------------- */ namespace tamaas { template class Material { // Defining some helper types protected: using trait = model_type_traits; static constexpr UInt dim = trait::dimension; using Field = Grid; using Mat = SymMatrixProxy; using CMat = SymMatrixProxy; public: /// Constructor Material(Model* model) : model(model) {} /// Destructor virtual ~Material() = default; // Material Interface public: /// Compute the increment of inelastic deformation from the total strain and /// total strain increment virtual void computeInelasticDeformationIncrement(Field& increment, const Field& strain, const Field& strain_increment) = 0; /// Compute the stress from total strain and strain increment virtual void computeStress(Field& stress, const Field& strain, const Field& strain_increment) = 0; + /// Compute stress due to inelastic increment + virtual void computeEigenStress(Field& stress, const Field& strain, + const Field& strain_increment) = 0; + /// Update internal variables virtual void update() = 0; protected: Model* model; }; } // namespace tamaas #endif // MATERIAL_HH diff --git a/src/model/residual.cpp b/src/model/residual.cpp index b7fcd4f..72a4f46 100644 --- a/src/model/residual.cpp +++ b/src/model/residual.cpp @@ -1,159 +1,158 @@ /* * SPDX-License-Indentifier: AGPL-3.0-or-later * * Copyright (©) 2016-2023 EPFL (École Polytechnique Fédérale de Lausanne), * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * Copyright (©) 2020-2023 Lucas Frérot * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "residual.hh" #include "grid_view.hh" #include "model_factory.hh" #include "model_type.hh" #include #include /* -------------------------------------------------------------------------- */ namespace tamaas { /* -------------------------------------------------------------------------- */ template ResidualTemplate::ResidualTemplate(Model* model, Real sigma_0, Real h) : Residual(model), hardening(model, sigma_0, h) { // Registering operators for residual and displacement calculation ModelFactory::registerVolumeOperators(*model); const auto n = model->getDiscretization(); const auto nc = trait::voigt; strain = model->request("strain", n, nc); stress = model->request("stress", n, nc); residual = model->request("residual", n, nc); tmp = allocateGrid(n, nc); plastic_filter = [this](UInt layer) { #if 0 return true; #else return this->plastic_layers.find(layer) != this->plastic_layers.end(); #endif }; } /* -------------------------------------------------------------------------- */ template void ResidualTemplate::computeResidual(GridBase& strain_increment) { Grid inc(strain->sizes(), strain->getNbComponents(), strain_increment.view()); - hardening.computeInelasticDeformationIncrement(*residual, *strain, inc); + hardening.computeEigenStress(*residual, *strain, inc); this->updateFilter(*residual); - this->model->applyElasticity(*residual, *residual); integralOperator("mindlin_gradient") .applyIf(*residual, *residual, plastic_filter); integralOperator("boussinesq_gradient") .apply(this->model->getTraction(), *tmp); *residual -= strain_increment; *residual += *tmp; } /* -------------------------------------------------------------------------- */ template void ResidualTemplate::applyTangent( GridBase& output, GridBase& input, GridBase& current_strain_increment) { auto& inc = dynamic_cast&>(current_strain_increment); auto& out = dynamic_cast&>(output); auto& in = dynamic_cast&>(input); hardening.applyTangentIncrement(out, in, *strain, inc); this->updateFilter(out); integralOperator("mindlin_gradient").applyIf(out, out, plastic_filter); out -= in; } /* -------------------------------------------------------------------------- */ template void ResidualTemplate::computeStress(GridBase& strain_increment) { auto& inc = dynamic_cast&>(strain_increment); hardening.computeStress(*stress, *strain, inc); // integralOperator("boussinesq_gradient") // .apply(this->model->getTraction(), tmp); // this->model->applyElasticity(tmp, tmp); // stress += tmp; } /* -------------------------------------------------------------------------- */ template void ResidualTemplate::updateState( GridBase& converged_strain_increment) { auto& inc = dynamic_cast&>(converged_strain_increment); hardening.computeStress(*stress, *strain, inc); hardening.update(); this->model->applyElasticity(*residual, hardening.getPlasticStrain()); updateFilter(*residual); *strain += converged_strain_increment; // Computing displacements integralOperator("mindlin").applyIf(*residual, this->model->getDisplacement(), plastic_filter); Grid disp_tmp(this->model->getDiscretization(), trait::components); integralOperator("boussinesq").apply(this->model->getTraction(), disp_tmp); this->model->getDisplacement() += disp_tmp; } /* -------------------------------------------------------------------------- */ template void ResidualTemplate::computeResidualDisplacement( GridBase& strain_increment) { auto& inc = dynamic_cast&>(strain_increment); hardening.computeInelasticDeformationIncrement(*tmp, *strain, inc); updateFilter(*tmp); this->model->applyElasticity(*residual, *tmp); integralOperator("mindlin").applyIf(*residual, this->model->getDisplacement(), plastic_filter); } /* -------------------------------------------------------------------------- */ template void ResidualTemplate::updateFilter( Grid& plastic_strain_increment) { // plastic_layers.clear(); for (UInt i : Loop::range(plastic_strain_increment.sizes().front())) { auto slice = make_view(plastic_strain_increment, i); if (slice.dot(slice) / slice.globalDataSize() > 1e-14) plastic_layers.insert(i); } } /* -------------------------------------------------------------------------- */ template void ResidualTemplate::setIntegrationMethod(integration_method method, Real cutoff) { auto& mindlin = dynamic_cast&>( *this->model->getIntegralOperator("mindlin")); auto& mindlin_g = dynamic_cast&>( *this->model->getIntegralOperator("mindlin_gradient")); mindlin.setIntegrationMethod(method, cutoff); mindlin_g.setIntegrationMethod(method, cutoff); } /* -------------------------------------------------------------------------- */ template class ResidualTemplate; /* -------------------------------------------------------------------------- */ } // namespace tamaas