diff --git a/python/wrap/model.cpp b/python/wrap/model.cpp index 2afa2f6..e8bd58e 100644 --- a/python/wrap/model.cpp +++ b/python/wrap/model.cpp @@ -1,320 +1,360 @@ /** * @file * @section LICENSE * * Copyright (©) 2016-2020 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 "model.hh" #include "adhesion_functional.hh" #include "functional.hh" #include "integral_operator.hh" #include "model_dumper.hh" #include "model_extensions.hh" #include "model_factory.hh" #include "numpy.hh" #include "residual.hh" #include "wrap.hh" #include /* -------------------------------------------------------------------------- */ namespace tamaas { namespace wrap { using namespace py::literals; +struct model_operator_accessor { + Model& m; + + decltype(auto) get(std::string name) { + return m.getIntegralOperator(std::move(name)); + } +}; + /// Wrap functional classes void wrapFunctionals(py::module& mod) { py::class_, functional::wrap::PyFunctional> func(mod, "Functional"); func.def(py::init<>()) .def("computeF", &functional::Functional::computeF) .def("computeGradF", &functional::Functional::computeGradF); py::class_ adh(mod, "AdhesionFunctional", func); adh.def_property("parameters", &functional::AdhesionFunctional::getParameters, &functional::AdhesionFunctional::setParameters) // legacy wrapper code .def("setParameters", &functional::AdhesionFunctional::setParameters); py::class_( mod, "ExponentialAdhesionFunctional", adh) .def(py::init&>(), "surface"_a); py::class_( mod, "MaugisAdhesionFunctional", adh) .def(py::init&>(), "surface"_a); py::class_( mod, "SquaredExponentialAdhesionFunctional", adh) .def(py::init&>(), "surface"_a); } template std::unique_ptr> instanciateFromNumpy(numpy& num) { std::unique_ptr> result = nullptr; switch (num.ndim()) { case 2: result = std::make_unique>>(num); return result; case 3: result = std::make_unique>>(num); return result; case 4: result = std::make_unique>>(num); return result; default: TAMAAS_EXCEPTION("instanciateFromNumpy expects the last dimension of numpy " "array to be the number of components"); } } /// Wrap IntegralOperator void wrapIntegralOperator(py::module& mod) { py::class_(mod, "IntegralOperator") .def("apply", [](IntegralOperator& op, numpy input, numpy output) { auto in = instanciateFromNumpy(input); auto out = instanciateFromNumpy(output); op.apply(*in, *out); }) .def("updateFromModel", &IntegralOperator::updateFromModel) .def("getModel", &IntegralOperator::getModel, py::return_value_policy::reference) .def("getKind", &IntegralOperator::getKind) .def("getType", &IntegralOperator::getType); py::enum_(mod, "integration_method") .value("linear", integration_method::linear) .value("cutoff", integration_method::cutoff); } /// Wrap BEEngine classes void wrapBEEngine(py::module& mod) { py::class_(mod, "BEEngine") .def("solveNeumann", &BEEngine::solveNeumann) .def("solveDirichlet", &BEEngine::solveDirichlet) .def("getModel", &BEEngine::getModel, py::return_value_policy::reference) .def("registerNeumann", &BEEngine::registerNeumann) .def("registerDirichlet", &BEEngine::registerDirichlet); } template void wrapModelTypeTrait(py::module& mod) { using trait = model_type_traits; py::class_(mod, trait::repr) .def_property_readonly_static("dimension", [](py::object) { return trait::dimension; }) .def_property_readonly_static( "components", [](py::object) { return trait::components; }) .def_property_readonly_static( "boundary_dimension", [](py::object) { return trait::boundary_dimension; }) .def_property_readonly_static("voigt", [](py::object) { return trait::voigt; }) .def_property_readonly_static("indices", [](py::object) { return trait::indices; }); } /// Wrap Models void wrapModelClass(py::module& mod) { py::enum_(mod, "model_type") .value("basic_1d", model_type::basic_1d) .value("basic_2d", model_type::basic_2d) .value("surface_1d", model_type::surface_1d) .value("surface_2d", model_type::surface_2d) .value("volume_1d", model_type::volume_1d) .value("volume_2d", model_type::volume_2d); auto trait_mod = mod.def_submodule("_type_traits"); wrapModelTypeTrait(trait_mod); wrapModelTypeTrait(trait_mod); wrapModelTypeTrait(trait_mod); wrapModelTypeTrait(trait_mod); wrapModelTypeTrait(trait_mod); wrapModelTypeTrait(trait_mod); + py::class_(mod, "_model_operator_acessor") + .def(py::init()) + .def("__getitem__", + [](model_operator_accessor& acc, std::string name) { + try { + return acc.get(name); + } catch (std::out_of_range&) { + throw py::key_error(name); + } + }, + py::return_value_policy::reference_internal) + .def("__contains__", + [](model_operator_accessor& acc, std::string key) { + const auto ops = acc.m.getIntegralOperators(); + return std::find(ops.begin(), ops.end(), key) != ops.end(); + }) + .def("__iter__", + [](const model_operator_accessor& acc) { + const auto& ops = acc.m.getIntegralOperatorsMap(); + return py::make_key_iterator(ops.cbegin(), ops.cend()); + }, + py::keep_alive<0, 1>()); + py::class_(mod, "Model") .def_property_readonly("type", &Model::getType) .def("setElasticity", &Model::setElasticity, "E"_a, "nu"_a) .def_property("E", &Model::getYoungModulus, &Model::setYoungModulus) .def_property("nu", &Model::getPoissonRatio, &Model::setPoissonRatio) .def("getHertzModulus", &Model::getHertzModulus) .def("getYoungModulus", &Model::getYoungModulus) .def("getShearModulus", &Model::getShearModulus) .def("getPoissonRatio", &Model::getPoissonRatio) .def("getTraction", (GridBase & (Model::*)()) & Model::getTraction, py::return_value_policy::reference_internal) .def("getDisplacement", (GridBase & (Model::*)()) & Model::getDisplacement, py::return_value_policy::reference_internal) .def("getSystemSize", &Model::getSystemSize) .def("getDiscretization", &Model::getDiscretization) .def("getBoundarySystemSize", &Model::getBoundarySystemSize) .def("getBoundaryDiscretization", &Model::getBoundaryDiscretization) .def("solveNeumann", &Model::solveNeumann) .def("solveDirichlet", &Model::solveDirichlet) .def("dump", &Model::dump) .def("addDumper", &Model::addDumper, "dumper"_a, py::keep_alive<1, 2>()) .def("setDumper", [](Model&, const ModelDumper&) { TAMAAS_EXCEPTION("setDumper() is not a member of Model; use " "addDumper() instead"); }) .def("getBEEngine", &Model::getBEEngine, py::return_value_policy::reference_internal) .def("getIntegralOperator", &Model::getIntegralOperator, "operator_name"_a, py::return_value_policy::reference_internal) .def("registerField", [](Model& m, std::string name, numpy field) { auto f = instanciateFromNumpy(field); m.registerField(name, std::move(f)); }, "field_name"_a, "field"_a, py::keep_alive<1, 3>()) .def("getField", (GridBase & (Model::*)(const std::string&)) & Model::getField, "field_name"_a, py::return_value_policy::reference_internal) .def("getFields", &Model::getFields) .def("applyElasticity", [](Model& model, numpy stress, numpy strain) { auto out = instanciateFromNumpy(stress); auto in = instanciateFromNumpy(strain); model.applyElasticity(*out, *in); }) - // Python magic functions + // Python magic functions .def("__repr__", [](const Model& m) { std::stringstream ss; ss << m; return ss.str(); }) .def("__getitem__", [](const Model& m, std::string key) -> const GridBase& { try { return m.getField(key); } catch (std::out_of_range&) { - throw py::key_error(); + throw py::key_error(key); } }, py::return_value_policy::reference_internal) + .def("__setitem__", + [](Model& m, std::string name, numpy field) { + auto f = instanciateFromNumpy(field); + m.registerField(name, std::move(f)); + }, + py::keep_alive<1, 3>()) .def("__contains__", [](const Model& m, std::string key) { const auto fields = m.getFields(); return std::find(fields.begin(), fields.end(), key) != fields.end(); }, py::keep_alive<0, 1>()) .def("__iter__", [](const Model& m) { const auto& fields = m.getFieldsMap(); return py::make_key_iterator(fields.cbegin(), fields.cend()); }, py::keep_alive<0, 1>()) - - // More python-like access to model properties + .def_property_readonly( + "operators", [](Model& m) { return model_operator_accessor{m}; }, + "Returns a dict-like object allowing access to the model's integral " + "operators") + // More python-like access to model properties .def_property_readonly("shape", &Model::getDiscretization) .def_property_readonly("global_shape", &Model::getGlobalDiscretization) .def_property_readonly("boundary_shape", &Model::getBoundaryDiscretization) .def_property_readonly("system_size", &Model::getSystemSize); py::class_>( mod, "ModelDumper") .def(py::init<>()) .def("dump", &ModelDumper::dump, "model"_a) .def("__lshift__", [](ModelDumper& dumper, Model& model) { dumper << model; }); } /// Wrap factory for models void wrapModelFactory(py::module& mod) { py::class_(mod, "ModelFactory") .def_static("createModel", &ModelFactory::createModel, "model_type"_a, "system_size"_a, "global_discretization"_a) - .def_static("createResidual", &ModelFactory::createResidual, - "model"_a, "sigma_y"_a, "hardening"_a = 0.) + .def_static("createResidual", &ModelFactory::createResidual, "model"_a, + "sigma_y"_a, "hardening"_a = 0.) .def_static("registerVolumeOperators", &ModelFactory::registerVolumeOperators, "model"_a); } /// Wrap residual class void wrapResidual(py::module& mod) { // TODO adapt to n-dim py::class_(mod, "Residual") .def(py::init()) .def("computeResidual", [](Residual& res, numpy& x) { auto in = instanciateFromNumpy(x); res.computeResidual(*in); }) .def("computeStress", [](Residual& res, numpy& x) { auto in = instanciateFromNumpy(x); res.computeStress(*in); }) .def("updateState", [](Residual& res, numpy& x) { auto in = instanciateFromNumpy(x); res.updateState(*in); }) .def("computeResidualDisplacement", [](Residual& res, numpy& x) { auto in = instanciateFromNumpy(x); res.computeResidualDisplacement(*in); }) .def("applyTangent", [](Residual& res, numpy& output, numpy& input, numpy& current_strain_inc) { auto out = instanciateFromNumpy(output); auto in = instanciateFromNumpy(input); auto inc = instanciateFromNumpy(current_strain_inc); res.applyTangent(*out, *in, *inc); }, "output"_a, "input"_a, "current_strain_increment"_a) .def("getVector", &Residual::getVector, py::return_value_policy::reference_internal) .def("getPlasticStrain", &Residual::getPlasticStrain, py::return_value_policy::reference_internal) .def("getStress", &Residual::getStress, py::return_value_policy::reference_internal) .def("setIntegrationMethod", &Residual::setIntegrationMethod, "method"_a, "cutoff"_a = 1e-12) .def_property("yield_stress", &Residual::getYieldStress, &Residual::setYieldStress) .def_property("hardening_modulus", &Residual::getHardeningModulus, &Residual::setHardeningModulus) .def_property_readonly("model", &Residual::getModel); } void wrapModel(py::module& mod) { wrapBEEngine(mod); wrapModelClass(mod); wrapModelFactory(mod); wrapFunctionals(mod); wrapResidual(mod); wrapIntegralOperator(mod); } } // namespace wrap } // namespace tamaas diff --git a/src/SConscript b/src/SConscript index 4ec5151..853ca6c 100644 --- a/src/SConscript +++ b/src/SConscript @@ -1,188 +1,189 @@ # -*- mode:python; coding: utf-8 -*- # vim: set ft=python: # @file # @section LICENSE # # Copyright (©) 2016-2020 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 . import os Import('main_env') def prepend(path, list): return [os.path.join(path, x) for x in list] env = main_env.Clone() # Core core_list = """ fft_engine.cpp fftw_engine.cpp grid.cpp grid_hermitian.cpp statistics.cpp surface.cpp tamaas.cpp legacy_types.cpp loop.cpp computes.cpp logger.cpp """.split() if env['legacy_bem']: core_list.append('surface_statistics.cpp') core_list = prepend('core', core_list) info_file = main_env.Substfile('tamaas_info.cpp', 'tamaas_info.cpp.in') core_list.append(info_file) # Lib roughcontact generator_list = """ surface_generator.cpp surface_generator_filter.cpp surface_generator_filter_fft.cpp surface_generator_random_phase.cpp isopowerlaw.cpp regularized_powerlaw.cpp """.split() generator_list = prepend('surface', generator_list) # Lib PERCOLATION percolation_list = """ flood_fill.cpp """.split() percolation_list = prepend('percolation', percolation_list) # BEM PERCOLATION bem_list = """ bem_kato.cpp bem_polonski.cpp bem_gigi.cpp bem_gigipol.cpp bem_penalty.cpp bem_uzawa.cpp bem_fft_base.cpp bem_functional.cpp bem_meta_functional.cpp elastic_energy_functional.cpp exponential_adhesion_functional.cpp squared_exponential_adhesion_functional.cpp maugis_adhesion_functional.cpp complimentary_term_functional.cpp bem_grid.cpp bem_grid_polonski.cpp bem_grid_kato.cpp bem_grid_teboulle.cpp bem_grid_condat.cpp """.split() bem_list = prepend('bem', bem_list) # Model model_list = """ model.cpp model_factory.cpp model_type.cpp model_template.cpp integral_operator.cpp be_engine.cpp westergaard.cpp elastic_functional.cpp meta_functional.cpp adhesion_functional.cpp volume_potential.cpp kelvin.cpp mindlin.cpp boussinesq.cpp +hooke.cpp elasto_plastic/isotropic_hardening.cpp elasto_plastic/residual.cpp integration/element.cpp """.split() model_list = prepend('model', model_list) # Solvers solvers_list = """ contact_solver.cpp polonsky_keer_rey.cpp kato_saturated.cpp kato.cpp beck_teboulle.cpp condat.cpp polonsky_keer_tan.cpp ep_solver.cpp dfsane_solver.cpp epic.cpp """.split() solvers_list = prepend('solvers', solvers_list) # GPU API gpu_list = """ fftransform_cufft.cpp """.split() gpu_list = prepend('gpu', gpu_list) # MPI API mpi_list = """ fftw_mpi_engine.cpp mpi_interface.cpp """.split() mpi_list = prepend('mpi', mpi_list) # Assembling total list rough_contact_list = \ core_list + generator_list + percolation_list + model_list + solvers_list # Adding legacy code if env['legacy_bem']: rough_contact_list += bem_list # Adding GPU if needed if env['backend'] == 'cuda': rough_contact_list += gpu_list # Adding MPI if needed if env['use_mpi']: rough_contact_list += mpi_list # Adding extra warnings for Tamaas base lib env.AppendUnique(CXXFLAGS=['-Wextra']) # Allowing libTamaas.so to find libs in the same directory env.AppendUnique(RPATH=["'$$$$ORIGIN'"]) # Build static library for packaging if env['build_static_lib']: env.AppendUnique(CXXFLAGS='-fPIC') libTamaas = env.StaticLibrary('Tamaas', rough_contact_list) # Build shared library (default) else: libTamaas = env.SharedLibrary('Tamaas', rough_contact_list, SHLIBVERSION=env['version']) # Defining alias for cpp builds main_env.Alias('build-cpp', libTamaas) # Specify install target to install lib lib_prefix = os.path.join(env['prefix'], 'lib') lib_install = env.InstallVersionedLib(target=lib_prefix, source=libTamaas) main_env.Alias('install-lib', lib_install) # Export target for use in python builds Export('libTamaas') diff --git a/src/model/hooke.cpp b/src/model/hooke.cpp new file mode 100644 index 0000000..c48607d --- /dev/null +++ b/src/model/hooke.cpp @@ -0,0 +1,70 @@ +/** + * @file + * @section LICENSE + * + * Copyright (©) 2016-2020 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 "hooke.hh" +#include "influence.hh" +#include "loop.hh" +#include "model.hh" +/* -------------------------------------------------------------------------- */ + +namespace tamaas { + +template +void Hooke::apply(GridBase& strain, GridBase& stress) const { + constexpr auto dim = model_type_traits::dimension; + const influence::ElasticHelper elasticity( + this->model->getShearModulus(), this->model->getPoissonRatio()); + + // Checking incompressibility + if (elasticity.nu == 0.5) + TAMAAS_EXCEPTION("Incompressibility error"); + + // Checking number of components + if (strain.getNbComponents() == dim * dim) { + + Loop::loop([&elasticity](auto sigma, + auto epsilon) { sigma = elasticity(epsilon); }, + range>(stress), + range>(strain)); + } + + // in case we have voigt notation + else if (strain.getNbComponents() == voigt_size::value) { + Loop::loop([&elasticity](auto sigma, + auto epsilon) { sigma = elasticity(epsilon); }, + range>(stress), + range>(strain)); + } + + else + TAMAAS_EXCEPTION("Strain components do not match dimension"); +} + +/* -------------------------------------------------------------------------- */ +template class Hooke; +template class Hooke; +template class Hooke; +template class Hooke; +template class Hooke; +template class Hooke; + +} // namespace tamaas diff --git a/src/model/model_template.hh b/src/model/hooke.hh similarity index 52% copy from src/model/model_template.hh copy to src/model/hooke.hh index 0d4092d..a10e0b2 100644 --- a/src/model/model_template.hh +++ b/src/model/hooke.hh @@ -1,68 +1,56 @@ /** * @file * @section LICENSE * * Copyright (©) 2016-2020 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 __MODEL_TEMPLATE_HH__ -#define __MODEL_TEMPLATE_HH__ +#ifndef HOOKE_HH +#define HOOKE_HH /* -------------------------------------------------------------------------- */ -#include "grid_view.hh" -#include "model.hh" +#include "integral_operator.hh" #include "model_type.hh" /* -------------------------------------------------------------------------- */ + namespace tamaas { /** - * @brief Model class templated with model type - * Specializations of this class should take care of dimension specific code + * @brief Applies Hooke's law of elasticity */ template -class ModelTemplate : public Model { - using trait = model_type_traits; - static constexpr UInt dim = trait::dimension; - using ViewType = - GridView; - +class Hooke : public IntegralOperator { public: - /// Constructor - ModelTemplate(std::vector system_size, - std::vector discretization); - - // Get model type + Hooke(Model* m) : IntegralOperator(m) {} + /// Type of underlying model model_type getType() const override { return type; } - std::vector getGlobalDiscretization() const override; - std::vector getBoundaryDiscretization() const override; - std::vector getBoundarySystemSize() const override; + /// Hooke's law computes stresses ~ Neumann + IntegralOperator::kind getKind() const override { + return IntegralOperator::dirac; + } - void applyElasticity(GridBase& stress, - const GridBase& strain) const override; + /// Does not update + void updateFromModel() override {} -protected: - virtual void initializeBEEngine(); - -protected: - std::unique_ptr displacement_view = nullptr; - std::unique_ptr traction_view = nullptr; + /// Apply Hooke's tensor + void apply(GridBase& input, GridBase& output) const override; }; } // namespace tamaas -/* -------------------------------------------------------------------------- */ -#endif // __MODEL_TEMPLATE_HH__ + +#endif // HOOKE_HH diff --git a/src/model/influence.hh b/src/model/influence.hh index a7fd31b..39fb980 100644 --- a/src/model/influence.hh +++ b/src/model/influence.hh @@ -1,280 +1,327 @@ /** * @file * @section LICENSE * * Copyright (©) 2016-2020 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 INFLUENCE_HH #define INFLUENCE_HH /* -------------------------------------------------------------------------- */ #include "loop.hh" #include "static_types.hh" #include /* -------------------------------------------------------------------------- */ namespace tamaas { /* -------------------------------------------------------------------------- */ namespace influence { namespace { const Complex I(0, 1); /// < imaginary unit constexpr inline Real sign(bool upper) { return (upper) ? 1. : -1.; } } // namespace template // dim + 1 to help dim template deduction inline Vector computeD(const VectorProxy& q) { constexpr Real s = -sign(conjugate); const auto q_norm = q.l2norm(); return {{{Complex{0, s * q(0) / q_norm}, Complex{0, s * q(1) / q_norm}, Complex{1, 0}}}}; } template // dim + 1 to help dim template deduction inline Vector computeD2(const VectorProxy& q) { const auto q_norm = (q.l2norm() < 1e-16) ? 1 : q.l2norm(); return { {{Complex{0, q(0) / q_norm}, Complex{0, q(1) / q_norm}, Complex{0, 0}}}}; } +/* -------------------------------------------------------------------------- */ +/// Functor to apply Hooke's tensor +template +struct ElasticHelper { + ElasticHelper(Real mu, Real nu) + : mu(mu), nu(nu), lambda(2 * mu * nu / (1 - 2 * nu)) {} + + template + Matrix, dim, dim> + operator()(const StaticMatrix& gradu) const { + auto trace = gradu.trace(); + Matrix, dim, dim> sigma; + for (UInt i = 0; i < dim; ++i) + for (UInt j = 0; j < dim; ++j) + sigma(i, j) = + (i == j) * lambda * trace + mu * (gradu(i, j) + gradu(j, i)); + return sigma; + } + + template + SymMatrix, dim> + operator()(const StaticSymMatrix& eps) const { + SymMatrix, dim> sigma; + auto trace = eps.trace(); + for (UInt i = 0; i < dim; ++i) + sigma(i) = lambda * trace + 2 * mu * eps(i); + for (UInt i = dim; i < voigt_size::value; ++i) + sigma(i) = 2 * mu * eps(i); + return sigma; + } + + template + Matrix, dim, dim> + inverse(const StaticMatrix& sigma) const { + Matrix, dim, dim> epsilon; + auto trace = sigma.trace(); + auto c1 = 1. / (2 * mu); + auto c2 = -lambda / (3 * lambda + 2 * mu); + + for (UInt i = 0; i < dim; ++i) + for (UInt j = 0; j < dim; ++j) + epsilon(i, j) = c1 * (sigma(i, j) + c2 * trace * (i == j)); + } + + const Real mu, nu, lambda; +}; + /* -------------------------------------------------------------------------- */ /// Class for the Kelvin tensor template class Kelvin; /** * @brief Kelvin base tensor * See arXiv:1811.11558 for details. */ template <> class Kelvin<3, 0> { protected: static constexpr UInt dim = 3; static constexpr UInt order = 0; public: Kelvin(Real mu, Real nu) : mu(mu), b(4 * (1 - nu)) {} template inline Vector applyU0(const VectorProxy& q, const StaticVector& f) const { // upper is ignored here auto d2 = computeD2(q); auto q_power = (apply_q_power) ? 1. / q.l2norm() : 1.; d2 *= d2.dot(f); d2 += b * f; d2(2) -= f(2); d2 *= q_power / (2. * mu * b); return d2; } template inline Vector applyU1(const VectorProxy& q, const StaticVector& f) const { auto d = computeD(q); auto q_power = (apply_q_power) ? 1. / q.l2norm() : 1.; d *= d.dot(f); d *= q_power * sign(upper) / (2. * mu * b); return d; } protected: const Real mu, b; }; /* -------------------------------------------------------------------------- */ /// Kelvin first derivative template <> class Kelvin<3, 1> : protected Kelvin<3, 0> { using parent = Kelvin<3, 0>; protected: static constexpr UInt dim = parent::dim; static constexpr UInt order = parent::order + 1; public: using parent::parent; template inline Vector applyU0(const VectorProxy& q, const StaticMatrix& f) const { // apply_q_power is ignored here auto tmp = f * computeD(q); auto res = Kelvin<3, 0>::applyU0(q, tmp); res *= -sign(upper); Vector e3{{{0, 0, 1}}}; tmp.template mul(f, e3); res += Kelvin<3, 0>::applyU1(q, tmp); return res; } template inline Vector applyU1(const VectorProxy& q, const StaticMatrix& f) const { // apply_q_power is ignored here auto tmp = f * computeD(q); auto res = Kelvin<3, 0>::applyU1(q, tmp); res *= -sign(upper); return res; } }; /* -------------------------------------------------------------------------- */ /// Kelvin second derivative template <> class Kelvin<3, 2> : protected Kelvin<3, 1> { using parent = Kelvin<3, 1>; static constexpr UInt dim = parent::dim; static constexpr UInt order = parent::order + 1; public: using parent::parent; template inline Matrix applyU0(const VectorProxy& q, const StaticMatrix& f) const { auto tmp = Kelvin<3, 1>::applyU0(q, f); auto q_power = (apply_q_power) ? q.l2norm() : 1.; tmp *= -sign(upper); auto res = outer(computeD(q), tmp); Vector e3{{{0, 0, 1}}}; res += outer(e3, Kelvin<3, 1>::applyU1(q, f)); res *= -1. * q_power; // << -1 for grad_x return res; } template inline Matrix applyU1(const VectorProxy& q, const StaticMatrix& f) const { auto tmp = Kelvin<3, 1>::applyU1(q, f); auto q_power = (apply_q_power) ? q.l2norm() : 1.; auto res = outer(computeD(q), tmp); res *= -1. * -sign(upper) * q_power; // << -1 for grad_x return res; } template inline Matrix applyDiscontinuityTerm(const StaticMatrix& f) const { Vector e3{{{0, 0, 1}}}; auto res = (f * e3); res *= -this->b; res(2) += 2. * f(2, 2); e3(2) *= -1 / (this->mu * this->b); // << -1 for grad_x return outer(e3, res); } }; /* -------------------------------------------------------------------------- */ /// Class for the Boussinesq tensor template class Boussinesq; template <> class Boussinesq<3, 0> { protected: static constexpr UInt dim = 3; static constexpr UInt order = 0; public: /// Constructor Boussinesq(Real mu, Real nu) : mu(mu), nu(nu), lambda(2 * mu * nu / (1 - 2 * nu)) {} template inline Vector applyU0(const StaticVector& t, const VectorProxy& q) const { // This guy has the property Bt(q) = B(-q). Since we know we recieve -q as // an argument, we can just apply B without transpose auto dplus = computeD(q), dminus = computeD(q), d2 = computeD2(q); auto q_power = (apply_q_power) ? 1. / q.l2norm() : 1.; auto res = 2. * t; res += ((1. - 2. * nu) * dminus.dot(t)) * dplus; res += d2.dot(t) * d2; res(2) -= t(2); res *= q_power / (2. * mu); return res; } template inline Vector applyU1(const StaticVector& t, const VectorProxy& q) const { // This guy does not have the property that Bt(q) = B(-q), so we have to // apply Bt(q) for real. This makes us correct (in the line below) for the // fact that we recieve -q as an argument. auto dplus = computeD(q); auto q_power = (apply_q_power) ? 1. / q.l2norm() : 1.; auto res = q_power * (dplus.dot(t) / (2. * mu)) * dplus; return res; } protected: const Real mu, nu, lambda; }; /* -------------------------------------------------------------------------- */ /// Boussinesq first gradient template <> class Boussinesq<3, 1> : protected Boussinesq<3, 0> { protected: using parent = Boussinesq<3, 0>; static constexpr UInt dim = parent::dim; static constexpr UInt order = parent::order + 1; public: using parent::parent; template inline Matrix applyU0(const StaticVector& t, const VectorProxy& q) const { // taking into account K(-q) convolution auto dbar = computeD(q); Vector e3{{{0, 0, 1}}}; auto res = outer(dbar, Boussinesq<3, 0>::applyU0(t, q)); res *= -1.; res += outer(e3, Boussinesq<3, 0>::applyU1(t, q)); return res; } template inline Matrix applyU1(const StaticVector& t, const VectorProxy& q) const { // taking into account K(-q) convolution auto dbar = computeD(q); auto res = outer(dbar, Boussinesq<3, 0>::applyU1(t, q)); res *= -1; return res; } }; } // namespace influence /* -------------------------------------------------------------------------- */ } // namespace tamaas #endif // INFLUENCE_HH diff --git a/src/model/integral_operator.hh b/src/model/integral_operator.hh index ca1fbf1..f499167 100644 --- a/src/model/integral_operator.hh +++ b/src/model/integral_operator.hh @@ -1,84 +1,84 @@ /** * @file * @section LICENSE * * Copyright (©) 2016-2020 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 INTEGRAL_OPERATOR_HH #define INTEGRAL_OPERATOR_HH /* -------------------------------------------------------------------------- */ #include "grid_base.hh" #include "model_type.hh" /* -------------------------------------------------------------------------- */ namespace tamaas { /* -------------------------------------------------------------------------- */ class Model; /** * @brief Generic class for integral operators */ class IntegralOperator { public: /// Kind of operator - enum kind { neumann, dirichlet }; + enum kind { neumann, dirichlet, dirac }; public: /// Constructor IntegralOperator(Model* model) : model(model) {} /// Virtual destructor for subclasses virtual ~IntegralOperator() = default; /// Apply operator on input virtual void apply(GridBase& input, GridBase& output) const = 0; /// Apply operator on filtered input virtual void applyIf(GridBase& input, GridBase& output, std::function) const { apply(input, output); } /// Update any data dependent on model parameters virtual void updateFromModel() = 0; /// Get model const Model& getModel() const { return *model; } /// Kind virtual kind getKind() const = 0; /// Type virtual model_type getType() const = 0; /// Norm virtual Real getOperatorNorm() { TAMAAS_EXCEPTION("operator does not implement norm"); } protected: Model* model = nullptr; }; /* -------------------------------------------------------------------------- */ /* Printing IntegralOperator::kind to string */ /* -------------------------------------------------------------------------- */ std::ostream& operator<<(std::ostream& o, const IntegralOperator::kind& val); } // namespace tamaas #endif // INTEGRAL_OPERATOR_HH diff --git a/src/model/model.cpp b/src/model/model.cpp index 87eaeff..65f6ccc 100644 --- a/src/model/model.cpp +++ b/src/model/model.cpp @@ -1,163 +1,191 @@ /** * @file * @section LICENSE * * Copyright (©) 2016-2020 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 "model.hh" #include "be_engine.hh" #include "logger.hh" /* -------------------------------------------------------------------------- */ namespace tamaas { /* -------------------------------------------------------------------------- */ Model::Model(std::vector system_size, std::vector discretization) : system_size(std::move(system_size)), discretization(std::move(discretization)) {} /* -------------------------------------------------------------------------- */ Model::~Model() = default; /* -------------------------------------------------------------------------- */ void Model::setElasticity(Real E_, Real nu_) { setYoungModulus(E_); setPoissonRatio(nu_); updateOperators(); } +/* -------------------------------------------------------------------------- */ +void Model::applyElasticity(GridBase& stress, + const GridBase& strain) const { + operators.at("hooke")->apply(const_cast&>(strain), stress); +} + /* -------------------------------------------------------------------------- */ Real Model::getHertzModulus() const { return E / (1 - nu * nu); } /* -------------------------------------------------------------------------- */ GridBase& Model::getTraction() { return getField("traction"); } const GridBase& Model::getTraction() const { return getField("traction"); } /* -------------------------------------------------------------------------- */ GridBase& Model::getDisplacement() { return getField("displacement"); } const GridBase& Model::getDisplacement() const { return getField("displacement"); } /* -------------------------------------------------------------------------- */ const std::vector& Model::getSystemSize() const { return system_size; } /* -------------------------------------------------------------------------- */ const std::vector& Model::getDiscretization() const { return discretization; } /* -------------------------------------------------------------------------- */ void Model::solveNeumann() { engine->registerNeumann(); engine->solveNeumann(getField("traction"), getField("displacement")); } void Model::solveDirichlet() { engine->registerDirichlet(); engine->solveDirichlet(getField("displacement"), getField("traction")); } /* -------------------------------------------------------------------------- */ IntegralOperator* Model::getIntegralOperator(const std::string& name) { - return operators[name].get(); + return operators.at(name).get(); +} + +/* -------------------------------------------------------------------------- */ +std::vector Model::getIntegralOperators() const { + std::vector keys; + keys.reserve(operators.size()); + + std::transform(operators.begin(), operators.end(), std::back_inserter(keys), + [](auto&& pair) { return pair.first; }); + return keys; } /* -------------------------------------------------------------------------- */ void Model::updateOperators() { for (auto& op : operators) op.second->updateFromModel(); } /* -------------------------------------------------------------------------- */ void Model::addDumper(std::shared_ptr dumper) { this->dumpers.push_back(std::move(dumper)); } void Model::dump() const { for (auto& dumper : dumpers) if (dumper) dumper->dump(*this); } /* -------------------------------------------------------------------------- */ void Model::registerField(const std::string& name, std::shared_ptr> field) { fields[name] = std::move(field); } const GridBase& Model::getField(const std::string& name) const try { return *fields.at(name); } catch (std::out_of_range& e) { Logger().get(LogLevel::warning) << "Field " << name << " not registered in model\n"; throw e; } GridBase& Model::getField(const std::string& name) try { return *fields.at(name); } catch (std::out_of_range& e) { Logger().get(LogLevel::warning) << "Field " << name << " not registered in model\n"; throw e; } std::vector Model::getFields() const { std::vector keys; keys.reserve(fields.size()); std::transform(fields.begin(), fields.end(), std::back_inserter(keys), [](auto&& pair) { return pair.first; }); return keys; } /* -------------------------------------------------------------------------- */ std::ostream& operator<<(std::ostream& o, const Model& _this) { o << "Model<" << _this.getType() << "> (E = " << _this.getYoungModulus() << ", nu = " << _this.getPoissonRatio() << ")\n"; + auto out_collec = [&o](auto&& collec) { + std::for_each(collec.begin(), collec.end() - 1, + [&o](const auto& x) { o << x << ", "; }); + o << collec.back(); + }; + // Printing domain size o << " - domain = ["; - std::for_each(_this.getSystemSize().begin(), _this.getSystemSize().end() - 1, - [&o](const Real& x) { o << x << ", "; }); - o << _this.getSystemSize().back() << "]\n"; + out_collec(_this.getSystemSize()); + o << "]\n"; // Printing discretization o << " - discretization = ["; - std::for_each(_this.getDiscretization().begin(), - _this.getDiscretization().end() - 1, - [&o](const UInt& x) { o << x << ", "; }); - o << _this.getDiscretization().back() << "]"; + out_collec(_this.getDiscretization()); + o << "]\n"; + + // Print fields + o << " - registered fields = ["; + out_collec(_this.getFields()); + o << "]\n"; + + o << " - registered operators = ["; + out_collec(_this.getIntegralOperators()); + o << "]\n"; return o; } /* -------------------------------------------------------------------------- */ } // namespace tamaas diff --git a/src/model/model.hh b/src/model/model.hh index 3c6a9a8..36930ad 100644 --- a/src/model/model.hh +++ b/src/model/model.hh @@ -1,241 +1,195 @@ /** * @file * @section LICENSE * * Copyright (©) 2016-2020 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 MODEL_HH #define MODEL_HH /* -------------------------------------------------------------------------- */ #include "be_engine.hh" #include "grid_base.hh" #include "integral_operator.hh" #include "model_dumper.hh" #include "model_type.hh" #include "tamaas.hh" #include #include #include #include /* -------------------------------------------------------------------------- */ namespace tamaas { /* -------------------------------------------------------------------------- */ -/** - * @brief Class for linear isotropic elasticity - */ -namespace influence { -template -struct ElasticHelper { - ElasticHelper(Real mu, Real nu) - : mu(mu), nu(nu), lambda(2 * mu * nu / (1 - 2 * nu)) {} - - template - Matrix, dim, dim> - operator()(const StaticMatrix& gradu) const { - auto trace = gradu.trace(); - Matrix, dim, dim> sigma; - for (UInt i = 0; i < dim; ++i) - for (UInt j = 0; j < dim; ++j) - sigma(i, j) = - (i == j) * lambda * trace + mu * (gradu(i, j) + gradu(j, i)); - return sigma; - } - - template - SymMatrix, dim> - operator()(const StaticSymMatrix& eps) const { - SymMatrix, dim> sigma; - auto trace = eps.trace(); - for (UInt i = 0; i < dim; ++i) - sigma(i) = lambda * trace + 2 * mu * eps(i); - for (UInt i = dim; i < voigt_size::value; ++i) - sigma(i) = 2 * mu * eps(i); - return sigma; - } - - template - Matrix, dim, dim> - inverse(const StaticMatrix& sigma) const { - Matrix, dim, dim> epsilon; - auto trace = sigma.trace(); - auto c1 = 1. / (2 * mu); - auto c2 = -lambda / (3 * lambda + 2 * mu); - - for (UInt i = 0; i < dim; ++i) - for (UInt j = 0; j < dim; ++j) - epsilon(i, j) = c1 * (sigma(i, j) + c2 * trace * (i == j)); - } - - const Real mu, nu, lambda; -}; -} // namespace influence - /* -------------------------------------------------------------------------- */ /** * @brief Model containing pressure and displacement * This class is a container for the model fields. It is supposed to be * dimension agnostic, hence the GridBase members. */ class Model { protected: /// Constructor Model(std::vector system_size, std::vector discretization); public: /// Destructor virtual ~Model(); public: /// Set elasticity parameters void setElasticity(Real E, Real nu); /// Get Hertz contact modulus Real getHertzModulus() const; /// Get Young's modulus Real getYoungModulus() const { return E; } /// Get Poisson's ratio Real getPoissonRatio() const { return nu; } /// Get shear modulus Real getShearModulus() const { return E / (2 * (1 + nu)); } /// Set Young's modulus void setYoungModulus(Real E_) { if (E_ < 0) TAMAAS_EXCEPTION("Elastic modulus should be positive"); this->E = E_; updateOperators(); } /// Set Poisson's ratio void setPoissonRatio(Real nu_) { if (nu_ > 0.5 or nu_ <= -1) TAMAAS_EXCEPTION("Poisson ratio should be in ]-1, 0.5]"); this->nu = nu_; updateOperators(); } public: - virtual void applyElasticity(GridBase& stress, - const GridBase& strain) const = 0; + void applyElasticity(GridBase& stress, + const GridBase& strain) const; public: /// Get pressure GridBase& getTraction(); /// Get pressure const GridBase& getTraction() const; /// Get displacement GridBase& getDisplacement(); /// Get displacement const GridBase& getDisplacement() const; /// Get model type virtual model_type getType() const = 0; /// Get system physical size const std::vector& getSystemSize() const; /// Get boundary system physical size virtual std::vector getBoundarySystemSize() const = 0; /// Get discretization const std::vector& getDiscretization() const; /// Get discretization of global MPI system virtual std::vector getGlobalDiscretization() const = 0; /// Get boundary discretization virtual std::vector getBoundaryDiscretization() const = 0; /// Get boundary element engine BEEngine& getBEEngine() { TAMAAS_ASSERT(engine, "BEEngine was not initialized"); return *engine; } /// Solve Neumann problem using default neumann operator void solveNeumann(); /// Solve Dirichlet problem using default dirichlet operator void solveDirichlet(); public: /// Register a new integral operator template IntegralOperator* registerIntegralOperator(const std::string& name) { Logger().get(LogLevel::debug) << TAMAAS_DEBUG_MSG("registering operator " + name); operators[name] = std::make_unique(this); return operators[name].get(); } /// Get a registerd integral operator IntegralOperator* getIntegralOperator(const std::string& name); + /// Get list of integral operators + std::vector getIntegralOperators() const; + /// Get operators mapcar + const auto& getIntegralOperatorsMap() const { return operators; } /// Tell operators to update their cache void updateOperators(); public: /// Register a field void registerField(const std::string& name, std::shared_ptr> field); /// Get a field const GridBase& getField(const std::string& name) const; /// Get a non-const field GridBase& getField(const std::string& name); /// Get fields std::vector getFields() const; /// Get fields map const auto& getFieldsMap() const { return fields; } public: /// Set the dumper object void addDumper(std::shared_ptr dumper); /// Dump the model void dump() const; protected: Real E = 1, nu = 0; std::vector system_size; std::vector discretization; std::unique_ptr engine = nullptr; std::unordered_map> operators; std::unordered_map>> fields; std::vector> dumpers; }; /* -------------------------------------------------------------------------- */ /* Output model to stream */ /* -------------------------------------------------------------------------- */ std::ostream& operator<<(std::ostream& o, const Model& _this); /* -------------------------------------------------------------------------- */ /* Simpler grid allocation */ /* -------------------------------------------------------------------------- */ template std::unique_ptr> allocateGrid(Model& model) { return allocateGrid( model.getType(), (boundary) ? model.getBoundaryDiscretization() : model.getDiscretization()); } template std::unique_ptr> allocateGrid(Model& model, UInt nc) { return allocateGrid(model.getType(), (boundary) ? model.getBoundaryDiscretization() : model.getDiscretization(), nc); } } // namespace tamaas #endif // MODEL_HH diff --git a/src/model/model_template.cpp b/src/model/model_template.cpp index 0ddde97..1e264e5 100644 --- a/src/model/model_template.cpp +++ b/src/model/model_template.cpp @@ -1,160 +1,162 @@ /** * @file * @section LICENSE * * Copyright (©) 2016-2020 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 "model_template.hh" +#include "computes.hh" +#include "hooke.hh" #include "influence.hh" #include "partitioner.hh" #include "westergaard.hh" /* -------------------------------------------------------------------------- */ namespace tamaas { /* -------------------------------------------------------------------------- */ +namespace detail { +template +class ComputeOperator : public IntegralOperator { +public: + /// Constructor + ComputeOperator(Model* model) : IntegralOperator(model) {} + + IntegralOperator::kind getKind() const override { + return IntegralOperator::dirac; + } + model_type getType() const override { return model->getType(); } + void updateFromModel() override {} + + /// Apply functor + void apply(GridBase& in, GridBase& out) const override { + applyCompute(model->getType(), out, in); + } +}; +} // namespace detail + template ModelTemplate::ModelTemplate(std::vector system_size, std::vector discretization) : Model(std::move(system_size), std::move(discretization)) { constexpr UInt dim = trait::dimension; constexpr UInt dim_b = trait::boundary_dimension; constexpr UInt nb_components = trait::components; if (this->system_size.size() != dim) TAMAAS_EXCEPTION("System size does not match model type"); if (this->discretization.size() != dim) TAMAAS_EXCEPTION("Discretization size does not match model type"); // Copying sizes for traction grid std::array traction_size; auto disc_it = this->discretization.begin() + (dim > dim_b); std::copy(disc_it, this->discretization.end(), traction_size.begin()); // Adjust MPI sizes traction_size = Partitioner::local_size(traction_size); *disc_it = traction_size.front(); // Allocating auto traction = std::make_unique>(traction_size, nb_components); auto displacement = std::make_unique>(this->discretization, nb_components); registerField("traction", std::move(traction)); registerField("displacement", std::move(displacement)); this->initializeBEEngine(); + registerIntegralOperator>("hooke"); + registerIntegralOperator>( + "eigenvalues"); + registerIntegralOperator>( + "von_mises"); + registerIntegralOperator>( + "deviatoric"); } /* -------------------------------------------------------------------------- */ template void ModelTemplate::initializeBEEngine() { engine = std::make_unique>(this); } namespace { template std::vector extract(const std::vector& v, UInt n) { std::vector ex(v.size() - n); std::copy(v.begin() + n, v.end(), ex.begin()); return ex; } } // namespace template std::vector ModelTemplate::getGlobalDiscretization() const { auto global_bdisc = Partitioner::global_size( getBoundaryDiscretization()); if (trait::dimension != trait::boundary_dimension) global_bdisc.insert(global_bdisc.begin(), getDiscretization().front()); return global_bdisc; } template std::vector ModelTemplate::getBoundaryDiscretization() const { return getDiscretization(); } template <> std::vector ModelTemplate::getBoundaryDiscretization() const { return extract(getDiscretization(), 1); } template <> std::vector ModelTemplate::getBoundaryDiscretization() const { return extract(getDiscretization(), 1); } template std::vector ModelTemplate::getBoundarySystemSize() const { return getSystemSize(); } template <> std::vector ModelTemplate::getBoundarySystemSize() const { return extract(getSystemSize(), 1); } template <> std::vector ModelTemplate::getBoundarySystemSize() const { return extract(getSystemSize(), 1); } -/* -------------------------------------------------------------------------- */ -template -void ModelTemplate::applyElasticity(GridBase& stress, - const GridBase& strain) const { - const influence::ElasticHelper elasticity(getShearModulus(), - getPoissonRatio()); - // Checking number of components - if (strain.getNbComponents() == dim * dim) { - - Loop::loop([&elasticity](auto sigma, - auto epsilon) { sigma = elasticity(epsilon); }, - range>(stress), - range>(strain)); - } - - // in case we have voigt notation - else if (strain.getNbComponents() == voigt_size::value) { - Loop::loop([&elasticity](auto sigma, - auto epsilon) { sigma = elasticity(epsilon); }, - range>(stress), - range>(strain)); - } - - else - TAMAAS_EXCEPTION("Strain components do not match dimension"); -} - /* -------------------------------------------------------------------------- */ /* Template instanciation */ /* -------------------------------------------------------------------------- */ template class ModelTemplate; template class ModelTemplate; template class ModelTemplate; template class ModelTemplate; template class ModelTemplate; template class ModelTemplate; } // namespace tamaas diff --git a/src/model/model_template.hh b/src/model/model_template.hh index 0d4092d..ac2d516 100644 --- a/src/model/model_template.hh +++ b/src/model/model_template.hh @@ -1,68 +1,64 @@ /** * @file * @section LICENSE * * Copyright (©) 2016-2020 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 __MODEL_TEMPLATE_HH__ #define __MODEL_TEMPLATE_HH__ /* -------------------------------------------------------------------------- */ #include "grid_view.hh" #include "model.hh" #include "model_type.hh" /* -------------------------------------------------------------------------- */ namespace tamaas { /** * @brief Model class templated with model type * Specializations of this class should take care of dimension specific code */ template class ModelTemplate : public Model { using trait = model_type_traits; static constexpr UInt dim = trait::dimension; - using ViewType = - GridView; + using ViewType = GridView; public: /// Constructor ModelTemplate(std::vector system_size, std::vector discretization); // Get model type model_type getType() const override { return type; } std::vector getGlobalDiscretization() const override; std::vector getBoundaryDiscretization() const override; std::vector getBoundarySystemSize() const override; - void applyElasticity(GridBase& stress, - const GridBase& strain) const override; - protected: virtual void initializeBEEngine(); protected: std::unique_ptr displacement_view = nullptr; std::unique_ptr traction_view = nullptr; }; } // namespace tamaas /* -------------------------------------------------------------------------- */ #endif // __MODEL_TEMPLATE_HH__ diff --git a/src/model/westergaard.hh b/src/model/westergaard.hh index 11e07e0..87043a3 100644 --- a/src/model/westergaard.hh +++ b/src/model/westergaard.hh @@ -1,92 +1,92 @@ /** * @file * @section LICENSE * * Copyright (©) 2016-2020 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 __WESTERGAARD_HH__ -#define __WESTERGAARD_HH__ +#ifndef WESTERGAARD_HH +#define WESTERGAARD_HH /* -------------------------------------------------------------------------- */ #include "grid_hermitian.hh" #include "integral_operator.hh" #include "model_type.hh" #include "fftw_engine.hh" #include "tamaas.hh" /* -------------------------------------------------------------------------- */ namespace tamaas { /** * @brief Operator based on Westergaard solution and the Dicrete Fourier * Transform. * This class is templated with model type to allow efficient storage of the * influence coefficients. * The integral operator is only applied to surface pressure/displacements, * even for volume models. */ template class Westergaard : public IntegralOperator { using trait = model_type_traits; static constexpr UInt dim = trait::dimension; static constexpr UInt bdim = trait::boundary_dimension; static constexpr UInt comp = trait::components; public: /// Constuctor: initalizes influence coefficients and allocates buffer Westergaard(Model* model); /// Get influence coefficients const GridHermitian& getInfluence() const { return influence; } /// Apply influence coefficients to input void apply(GridBase& input, GridBase& ouput) const override; /// Update the influence coefficients void updateFromModel() override { initInfluence(); } /// Kind IntegralOperator::kind getKind() const override { return otype; } /// Type model_type getType() const override { return mtype; } private: /// Initialize influence coefficients void initInfluence(); template void initFromFunctor(Functor func); /// Apply a functor in Fourier space template void fourierApply(Functor func, GridBase& in, GridBase& out) const; /// Compute L_2 norm of influence functions Real getOperatorNorm() override; public: GridHermitian influence; mutable GridHermitian buffer; mutable std::unique_ptr engine; }; } // namespace tamaas #endif // __WESTERGAARD_HH__