From 1c8caac16c8dad626c74228cefeb28a710c54e55 Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 10 Mar 2020 20:13:58 -0700 Subject: [PATCH 01/72] add fluid particle --- include/particles/fluid_particle.h | 135 ++++++++++++ include/particles/fluid_particle.tcc | 306 +++++++++++++++++++++++++++ src/particle.cc | 13 +- 3 files changed, 453 insertions(+), 1 deletion(-) create mode 100644 include/particles/fluid_particle.h create mode 100644 include/particles/fluid_particle.tcc diff --git a/include/particles/fluid_particle.h b/include/particles/fluid_particle.h new file mode 100644 index 000000000..6032d5e16 --- /dev/null +++ b/include/particles/fluid_particle.h @@ -0,0 +1,135 @@ +#ifndef MPM_FLUID_PARTICLE_H_ +#define MPM_FLUID_PARTICLE_H_ + +#include +#include +#include +#include +#include + +#include "logger.h" +#include "particle.h" + +namespace mpm { + +//! Fluid Particle class +//! \brief Class with function specific to fluid particles +//! \tparam Tdim Dimension +template +class FluidParticle : public mpm::Particle { + public: + //! Define a vector of size dimension + using VectorDim = Eigen::Matrix; + + //! Construct a particle with id and coordinates + //! \param[in] id Particle id + //! \param[in] coord Coordinates of the particles + FluidParticle(Index id, const VectorDim& coord); + + //! Destructor + ~FluidParticle() override{}; + + //! Delete copy constructor + FluidParticle(const FluidParticle&) = delete; + + //! Delete assignment operator + FluidParticle& operator=(const FluidParticle&) = delete; + + //! Compute both solid and liquid mass + void compute_mass() noexcept override; + + //! Compute stress + void compute_stress() noexcept override; + + //! Map internal force + inline void map_internal_force() noexcept override; + + // FIXME: NAMING ERROR + //! Initial pressure + //! \param[in] pressure Initial pressure + void initial_pore_pressure(double pressure) override { + state_variables_.at("pressure") = pressure; + } + + // //! Map drag force coefficient + // bool map_drag_force_coefficient() override; + + // //! Update particle permeability + // //! \retval status Update status + // bool update_permeability() override; + + // //! Assign particle pressure constraints + // //! \retval status Assignment status + // bool assign_particle_pressure_constraint(double pressure) override; + + //------------------------------------------------------------ + //! Semi-implict mpm + //! Assigning beta parameter to particle + void assign_semi_implicit_param(double parameter) override { + this->beta_ = parameter; + }; + + //! Map laplacian element matrix to cell + bool map_L_to_cell() override; + + //! Map F element matrix to cell (used in poisson equation RHS) + bool map_F_to_cell() override; + + //! Map K_cor element matrix to cell + bool map_K_cor_to_cell() override; + + bool compute_updated_pressure() override; + + private: + // //! Assign particle permeability + // //! \retval status Assignment status + // virtual bool assign_permeability(); + + //! Compute stress + virtual Eigen::Matrix compute_turbulent_stress(); + + protected: + //! Cell + using ParticleBase::cell_; + //! Nodes + using ParticleBase::nodes_; + //! State variables + using ParticleBase::state_variables_; + //! Shape functions + using Particle::shapefn_; + //! dN/dX + using Particle::dn_dx_; + //! Fluid strain rate + using Particle::strain_rate_; + //! Fluid material + using Particle::material_; + //! Effective stress of soil skeleton + using Particle::stress_; + //! Particle mass density + using Particle::mass_density_; + //! Particle mass density + using Particle::mass_; + //! Particle total volume + using Particle::volume_; + //! Porosity + using Particle::porosity_; + //! Beta parameter for semi-implicit update + double beta_{0.0}; + //! Pressure constraint + double pressure_constraint_{std::numeric_limits::max()}; + //! Logger + std::unique_ptr console_; + //! --------------------------------------------------------------------- + //! semi-implicit + //! Degree of saturation + double liquid_saturation_{1.0}; + //! Permeability + VectorDim permeability_; + //! Permeability parameter + VectorDim c1_; +}; // FluidParticle class +} // namespace mpm + +#include "fluid_particle.tcc" + +#endif // MPM_FLUID_PARTICLE_H__ diff --git a/include/particles/fluid_particle.tcc b/include/particles/fluid_particle.tcc new file mode 100644 index 000000000..a49c941cd --- /dev/null +++ b/include/particles/fluid_particle.tcc @@ -0,0 +1,306 @@ +//! Construct a two phase particle with id and coordinates +template +mpm::FluidParticle::FluidParticle(Index id, const VectorDim& coord) + : mpm::Particle(id, coord) { + + // Set initial private variables + this->porosity_ = 1.; + this->liquid_saturation_ = 1.; + + // Initialize vector data properties + this->properties_["pressure"] = [&]() { + Eigen::VectorXd vec_pressure = Eigen::VectorXd::Zero(3); + vec_pressure[0] = this->pressure(); + // FIXME: This is to check free surface particles + // TODO: To be removed somewhere + vec_pressure[1] = this->free_surface(); + return vec_pressure; + }; + + // Logger + std::string logger = + "FluidParticle" + std::to_string(Tdim) + "d::" + std::to_string(id); + console_ = std::make_unique(logger, mpm::stdout_sink); +} + +// Compute mass of fluid particle +template +void mpm::FluidParticle::compute_mass() noexcept { + // Check if particle volume is set and material ptr is valid + assert(volume_ != std::numeric_limits::max() && material_ != nullptr); + // Mass = volume of particle * mass_density + this->mass_density_ = + material_->template property(std::string("density")) * + this->liquid_saturation_ * this->porosity_; + this->mass_ = volume_ * mass_density_; +} + +// Compute stress +template +void mpm::FluidParticle::compute_stress() noexcept { + // Run particle compute stress + mpm::Particle::compute_stress(); + + // Calculate fluid turbulent stress + this->stress_ += this->compute_turbulent_stress(); +} + +// Compute turbulent stress +template +Eigen::Matrix + mpm::FluidParticle::compute_turbulent_stress() { + // Compute turbulent stress depends on the model + Eigen::Matrix tstress; + tstress.setZero(); + + // TODO: To be implemented + + return tstress; +} + +//! Map internal force +template <> +inline void mpm::FluidParticle<1>::map_internal_force() noexcept { + // initialise a vector of total stress (deviatoric + turbulent - pressure) + Eigen::Matrix total_stress = this->stress_; + total_stress(0) -= this->beta_ * state_variables_.at("pressure"); + // Compute nodal internal forces + for (unsigned i = 0; i < nodes_.size(); ++i) { + // Compute force: -pstress * volume + Eigen::Matrix force; + force[0] = dn_dx_(i, 0) * total_stress[0]; + force *= -1 * this->volume_; + + nodes_[i]->update_internal_force(true, mpm::ParticlePhase::SinglePhase, + force); + } +} + +//! Map internal force +template <> +inline void mpm::FluidParticle<2>::map_internal_force() noexcept { + // initialise a vector of total stress (deviatoric + turbulent - pressure) + Eigen::Matrix total_stress = this->stress_; + total_stress(0) -= this->beta_ * state_variables_.at("pressure"); + total_stress(1) -= this->beta_ * state_variables_.at("pressure"); + + // Compute nodal internal forces + for (unsigned i = 0; i < nodes_.size(); ++i) { + // Compute force: -pstress * volume + Eigen::Matrix force; + force[0] = dn_dx_(i, 0) * total_stress[0] + dn_dx_(i, 1) * total_stress[3]; + force[1] = dn_dx_(i, 1) * total_stress[1] + dn_dx_(i, 0) * total_stress[3]; + + force *= -1. * this->volume_; + + nodes_[i]->update_internal_force(true, mpm::ParticlePhase::SinglePhase, + force); + } +} + +//! Map internal force +template <> +inline void mpm::FluidParticle<3>::map_internal_force() noexcept { + // initialise a vector of total stress (deviatoric + turbulent - pressure) + Eigen::Matrix total_stress = this->stress_; + total_stress(0) -= this->beta_ * state_variables_.at("pressure"); + total_stress(1) -= this->beta_ * state_variables_.at("pressure"); + total_stress(2) -= this->beta_ * state_variables_.at("pressure"); + + // Compute nodal internal forces + for (unsigned i = 0; i < nodes_.size(); ++i) { + // Compute force: -pstress * volume + Eigen::Matrix force; + force[0] = dn_dx_(i, 0) * total_stress[0] + dn_dx_(i, 1) * total_stress[3] + + dn_dx_(i, 2) * total_stress[5]; + + force[1] = dn_dx_(i, 1) * total_stress[1] + dn_dx_(i, 0) * total_stress[3] + + dn_dx_(i, 2) * total_stress[4]; + + force[2] = dn_dx_(i, 2) * total_stress[2] + dn_dx_(i, 1) * total_stress[4] + + dn_dx_(i, 0) * total_stress[5]; + + force *= -1. * this->volume_; + + nodes_[i]->update_internal_force(true, mpm::ParticlePhase::SinglePhase, + force); + } +} + +// TODO: Check whether this is important +//! Assign particle pressure constraints +// template +// bool mpm::FluidParticle::assign_particle_pressure_constraint( +// double pressure) { +// bool status = true; +// try { +// this->pressure_constraint_ = pressure; +// } catch (std::exception& exception) { +// console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); +// status = false; +// } +// return status; +// } + +//! Compute laplacian matrix element +template +bool mpm::FluidParticle::map_L_to_cell() { + bool status = true; + try { + // Compute local matrix of Laplacian + cell_->compute_L_element(dn_dx_, volume_, 1.0); + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +//! Compute element F_s_element and F_m_element +template +bool mpm::FluidParticle::map_F_to_cell() { + bool status = true; + try { + // Compute local matrix of F + cell_->compute_F_element( + shapefn_, dn_dx_, + material_->template property(std::string("density")) * volume_); + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +//! Compute element K_cor_w_element_ +template +bool mpm::FluidParticle::map_K_cor_to_cell() { + bool status = true; + try { + cell_->compute_K_cor_element(shapefn_, dn_dx_, volume_); + + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + } + return status; +} + +// Compute updated pore pressure of the particle based on nodal pressure +template +bool mpm::FluidParticle::compute_updated_pressure() { + bool status = true; + + try { + double pressure_increment = 0; + for (unsigned i = 0; i < nodes_.size(); ++i) { + pressure_increment += shapefn_(i) * nodes_[i]->pressure_increment(); + } + // Get interpolated nodal pore pressure + state_variables_.at("pressure") = + state_variables_.at("pressure") * beta_ + pressure_increment; + // Apply free surface + if (this->free_surface()) state_variables_.at("pressure") = 0.0; + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +// //! Assign particle permeability +// template +// bool mpm::FluidParticle::assign_permeability() { +// bool status = true; +// try { +// // Check if material ptr is valid +// if (material_ != nullptr) { +// // Porosity parameter +// const double k_p = +// std::pow(this->porosity_, 3) / std::pow((1. - this->porosity_), 2); +// switch (Tdim) { +// case (1): { +// permeability_(0) = material_->template property("k_x"); +// c1_(0) = permeability_(0) / k_p; +// break; +// } +// case (2): { +// permeability_(0) = material_->template property("k_x"); +// permeability_(1) = material_->template property("k_y"); +// c1_(0) = permeability_(0) / k_p; +// c1_(1) = permeability_(1) / k_p; +// break; +// } +// default: { +// permeability_(0) = material_->template property("k_x"); +// permeability_(1) = material_->template property("k_y"); +// permeability_(2) = material_->template property("k_z"); +// c1_(0) = permeability_(0) / k_p; +// c1_(1) = permeability_(1) / k_p; +// c1_(2) = permeability_(2) / k_p; +// break; +// } +// } +// } else { +// throw std::runtime_error("Material is invalid"); +// } +// } catch (std::exception& exception) { +// console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); +// status = false; +// } +// return status; +// } + +// //! Update particle permeability +// template +// bool mpm::FluidParticle::update_permeability() { +// bool status = true; +// try { +// // Porosity parameter +// const double k_p = +// std::pow(this->porosity_, 3) / std::pow((1. - this->porosity_), 2); + +// // Update permeability by KC equation +// permeability_ = k_p * c1_; + +// } catch (std::exception& exception) { +// console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); +// status = false; +// } +// return status; +// } + +// //! Map drag force +// template +// bool mpm::FluidParticle::map_drag_force_coefficient() { +// bool status = true; +// try { +// // Update permeability +// this->update_permeability(); +// // Initialise drag force coefficient +// VectorDim drag_force_coefficient; +// drag_force_coefficient.setZero(); + +// // Check if permeability coefficient is valid +// for (unsigned i = 0; i < Tdim; ++i) { +// if (permeability_(i) > 0.) +// drag_force_coefficient(i) = +// porosity_ * porosity_ * 9.81 * +// // liquid_material_->template property( +// // std::string("density")) / +// material_->template property(std::string("density")) / +// permeability_(i); +// else +// throw std::runtime_error("Permeability coefficient is invalid"); +// } + +// // Map drag forces from particle to nodes +// for (unsigned j = 0; j < nodes_.size(); ++j) +// nodes_[j]->update_drag_force_coefficient( +// true, drag_force_coefficient * this->volume_ * shapefn_(j)); + +// } catch (std::exception& exception) { +// console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); +// status = false; +// } +// return status; +// } \ No newline at end of file diff --git a/src/particle.cc b/src/particle.cc index 7488c8023..6dc323c00 100644 --- a/src/particle.cc +++ b/src/particle.cc @@ -1,6 +1,7 @@ -#include "particle.h" #include "factory.h" #include "particle_base.h" +#include "particle.h" +#include "fluid_particle.h" // Particle2D (2 Dim) static Register, mpm::Particle<2>, mpm::Index, @@ -11,3 +12,13 @@ static Register, mpm::Particle<2>, mpm::Index, static Register, mpm::Particle<3>, mpm::Index, const Eigen::Matrix&> particle3d("P3D"); + +// Single phase (fluid) particle2D (2 Dim) +static Register, mpm::FluidParticle<2>, mpm::Index, + const Eigen::Matrix&> + particle2dfluid("P2DFLUID"); + +// Single phase (fluid) particle3D (3 Dim) +static Register, mpm::FluidParticle<3>, mpm::Index, + const Eigen::Matrix&> + particle3dfluid("P3DFLUID"); \ No newline at end of file From 32aa0f4161909ec0fea560295680c6e3ad11975a Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 10 Mar 2020 23:28:37 -0700 Subject: [PATCH 02/72] add some functions to base classes --- include/particles/particle.h | 17 ++++++-- include/particles/particle.tcc | 29 +++++++++++++ include/particles/particle_base.h | 70 ++++++++++++++++++++++++++++++- src/particle.cc | 2 +- 4 files changed, 112 insertions(+), 6 deletions(-) diff --git a/include/particles/particle.h b/include/particles/particle.h index 8776ff123..957c08656 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -132,7 +132,6 @@ class Particle : public ParticleBase { void update_volume() noexcept override; //! Return mass density - //! \param[in] phase Index corresponding to the phase double mass_density() const override { return mass_density_; } //! Compute mass as volume * density @@ -213,7 +212,6 @@ class Particle : public ParticleBase { bool assign_traction(unsigned direction, double traction) override; //! Return traction of the particle - //! \param[in] phase Index corresponding to the phase VectorDim traction() const override { return traction_; } //! Map traction force @@ -262,6 +260,17 @@ class Particle : public ParticleBase { //! Assign material id of this particle to nodes void append_material_id_to_nodes() const override; + //! Assign free surface + void assign_free_surface(bool free_surface) override { + free_surface_ = free_surface; + }; + + //! Return free surface bool + bool free_surface() override { return free_surface_; }; + + //! Compute free surface + bool compute_free_surface() override; + //! Return the number of neighbour particles unsigned nneighbours() const override { return neighbours_.size(); }; @@ -278,7 +287,7 @@ class Particle : public ParticleBase { inline Eigen::Matrix compute_strain_rate( const Eigen::MatrixXd& dn_dx, unsigned phase) noexcept; - private: + protected: //! particle id using ParticleBase::id_; //! coordinates @@ -343,6 +352,8 @@ class Particle : public ParticleBase { std::unique_ptr console_; //! Map of vector properties std::map> properties_; + //! Free surface + bool free_surface_{false}; }; // Particle class } // namespace mpm diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index 253983df6..8262a281f 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -789,6 +789,35 @@ void mpm::Particle::append_material_id_to_nodes() const { nodes_[i]->append_material_id(material_id_); } +//! Compute free surface +template +bool mpm::Particle::compute_free_surface() { + bool status = true; + try { + this->free_surface_ = false; + // Check if particle has a valid cell ptr + if (cell_ != nullptr) { + // TODO: Tobe uncomment when free surface is implemented + // 1. Simple approach of density comparison (Hamad, 2015) + // Get interpolated nodal density + // double nodal_mass_density = 0; + + // for (unsigned i = 0; i < nodes_.size(); ++i) + // nodal_mass_density += + // shapefn_[i] * nodes_[i]->density(mpm::ParticlePhase::Solid); + + // // Compare smoothen density to actual particle mass density + // if ((nodal_mass_density / mass_density_) <= 0.65) + // if (cell_->free_surface()) this->free_surface_ = true; + } + + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +}; + //! Assign neighbour particles template void mpm::Particle::assign_neighbours( diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index ff627467b..cd5923460 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -19,7 +19,12 @@ template class Material; //! Particle phases -enum ParticlePhase : unsigned int { Solid = 0, Liquid = 1, Gas = 2 }; +enum ParticlePhase : unsigned int { + SinglePhase = 0, + Solid = 0, + Liquid = 1, + Gas = 2 +}; //! ParticleBase class //! \brief Base class that stores the information about particleBases @@ -180,7 +185,7 @@ class ParticleBase { virtual double dvolumetric_strain() const = 0; //! Initial stress - virtual void initial_stress(const Eigen::Matrix&) = 0; + virtual void initial_stress(const Eigen::Matrix& stress) = 0; //! Compute stress virtual void compute_stress() noexcept = 0; @@ -239,6 +244,15 @@ class ParticleBase { //! Assign material id of this particle to nodes virtual void append_material_id_to_nodes() const = 0; + //! Assign particle free surface + virtual void assign_free_surface(bool free_surface) = 0; + + //! Assign particle free surface + virtual bool free_surface() = 0; + + //! Compute free surface + virtual bool compute_free_surface() = 0; + //! Return the number of neighbour particles virtual unsigned nneighbours() const = 0; @@ -250,6 +264,58 @@ class ParticleBase { //! Return neighbour ids virtual std::vector neighbours() const = 0; + //! Initial pressure + //! \param[in] pressure Initial pressure + virtual void initial_pressure(double pressure) { + throw std::runtime_error( + "Calling the base class function " + "(initial_pressure) in " + "ParticleBase:: illegal operation!"); + }; + + //! Assigning beta parameter to particle + //! \param[in] pressure parameter determining type of projection + virtual void assign_projection_parameter(double parameter) { + throw std::runtime_error( + "Calling the base class function (assign_projection_parameter) in " + "ParticleBase:: illegal operation!"); + }; + + //! Map laplacian element matrix to cell (used in poisson equation LHS) + virtual bool map_laplacian_to_cell() { + throw std::runtime_error( + "Calling the base class function (map_laplacian_to_cell) in " + "ParticleBase:: " + "illegal operation!"); + return 0; + }; + + //! Map poisson rhs element matrix to cell (used in poisson equation RHS) + virtual bool map_poisson_rhs_to_cell() { + throw std::runtime_error( + "Calling the base class function (map_poisson_rhs_to_cell) in " + "ParticleBase:: " + "illegal operation!"); + return 0; + }; + + //! Map correction matrix element matrix to cell (used to correct velocity) + virtual bool map_correction_matrix_to_cell() { + throw std::runtime_error( + "Calling the base class function (map_correction_matrix_to_cell) in " + "ParticleBase:: " + "illegal operation!"); + return 0; + }; + + //! Update pressure after solving poisson equation + virtual bool compute_updated_pressure() { + throw std::runtime_error( + "Calling the base class function (compute_updated_pressure) in " + "ParticleBase:: illegal operation!"); + return 0; + }; + protected: //! particleBase id Index id_{std::numeric_limits::max()}; diff --git a/src/particle.cc b/src/particle.cc index 6dc323c00..a90ef31de 100644 --- a/src/particle.cc +++ b/src/particle.cc @@ -1,6 +1,6 @@ +#include "particle.h" #include "factory.h" #include "particle_base.h" -#include "particle.h" #include "fluid_particle.h" // Particle2D (2 Dim) From 0705b03c51aca2e03aaea19df6817c9e5fdc2dd1 Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 10 Mar 2020 23:28:52 -0700 Subject: [PATCH 03/72] fluid particle compiled --- include/particles/fluid_particle.h | 58 +++------ include/particles/fluid_particle.tcc | 170 +++++---------------------- 2 files changed, 47 insertions(+), 181 deletions(-) diff --git a/include/particles/fluid_particle.h b/include/particles/fluid_particle.h index 6032d5e16..dde80e2b8 100644 --- a/include/particles/fluid_particle.h +++ b/include/particles/fluid_particle.h @@ -44,51 +44,39 @@ class FluidParticle : public mpm::Particle { //! Map internal force inline void map_internal_force() noexcept override; - // FIXME: NAMING ERROR //! Initial pressure //! \param[in] pressure Initial pressure - void initial_pore_pressure(double pressure) override { + void initial_pressure(double pressure) override { state_variables_.at("pressure") = pressure; } - // //! Map drag force coefficient - // bool map_drag_force_coefficient() override; + //! ---------------------------------------------------------------- + //! Semi-Implicit integration functions based on Chorin's Projection + //! ---------------------------------------------------------------- - // //! Update particle permeability - // //! \retval status Update status - // bool update_permeability() override; - - // //! Assign particle pressure constraints - // //! \retval status Assignment status - // bool assign_particle_pressure_constraint(double pressure) override; - - //------------------------------------------------------------ - //! Semi-implict mpm //! Assigning beta parameter to particle - void assign_semi_implicit_param(double parameter) override { - this->beta_ = parameter; + //! \param[in] pressure parameter determining type of projection + void assign_projection_parameter(double parameter) override { + this->projection_param_ = parameter; }; - //! Map laplacian element matrix to cell - bool map_L_to_cell() override; + //! Map laplacian element matrix to cell (used in poisson equation LHS) + bool map_laplacian_to_cell() override; - //! Map F element matrix to cell (used in poisson equation RHS) - bool map_F_to_cell() override; + //! Map poisson rhs element matrix to cell (used in poisson equation RHS) + bool map_poisson_rhs_to_cell() override; - //! Map K_cor element matrix to cell - bool map_K_cor_to_cell() override; + //! Map correction matrix element matrix to cell (used to correct velocity) + bool map_correction_matrix_to_cell() override; + //! Update pressure after solving poisson equation bool compute_updated_pressure() override; private: - // //! Assign particle permeability - // //! \retval status Assignment status - // virtual bool assign_permeability(); - - //! Compute stress + //! Compute turbulent stress virtual Eigen::Matrix compute_turbulent_stress(); - protected: + private: //! Cell using ParticleBase::cell_; //! Nodes @@ -111,22 +99,12 @@ class FluidParticle : public mpm::Particle { using Particle::mass_; //! Particle total volume using Particle::volume_; - //! Porosity - using Particle::porosity_; - //! Beta parameter for semi-implicit update - double beta_{0.0}; + //! Projection parameter for semi-implicit update + double projection_param_{0.0}; //! Pressure constraint double pressure_constraint_{std::numeric_limits::max()}; //! Logger std::unique_ptr console_; - //! --------------------------------------------------------------------- - //! semi-implicit - //! Degree of saturation - double liquid_saturation_{1.0}; - //! Permeability - VectorDim permeability_; - //! Permeability parameter - VectorDim c1_; }; // FluidParticle class } // namespace mpm diff --git a/include/particles/fluid_particle.tcc b/include/particles/fluid_particle.tcc index a49c941cd..06d476d23 100644 --- a/include/particles/fluid_particle.tcc +++ b/include/particles/fluid_particle.tcc @@ -3,10 +3,6 @@ template mpm::FluidParticle::FluidParticle(Index id, const VectorDim& coord) : mpm::Particle(id, coord) { - // Set initial private variables - this->porosity_ = 1.; - this->liquid_saturation_ = 1.; - // Initialize vector data properties this->properties_["pressure"] = [&]() { Eigen::VectorXd vec_pressure = Eigen::VectorXd::Zero(3); @@ -30,8 +26,7 @@ void mpm::FluidParticle::compute_mass() noexcept { assert(volume_ != std::numeric_limits::max() && material_ != nullptr); // Mass = volume of particle * mass_density this->mass_density_ = - material_->template property(std::string("density")) * - this->liquid_saturation_ * this->porosity_; + material_->template property(std::string("density")); this->mass_ = volume_ * mass_density_; } @@ -63,7 +58,7 @@ template <> inline void mpm::FluidParticle<1>::map_internal_force() noexcept { // initialise a vector of total stress (deviatoric + turbulent - pressure) Eigen::Matrix total_stress = this->stress_; - total_stress(0) -= this->beta_ * state_variables_.at("pressure"); + total_stress(0) -= this->projection_param_ * state_variables_.at("pressure"); // Compute nodal internal forces for (unsigned i = 0; i < nodes_.size(); ++i) { // Compute force: -pstress * volume @@ -81,8 +76,8 @@ template <> inline void mpm::FluidParticle<2>::map_internal_force() noexcept { // initialise a vector of total stress (deviatoric + turbulent - pressure) Eigen::Matrix total_stress = this->stress_; - total_stress(0) -= this->beta_ * state_variables_.at("pressure"); - total_stress(1) -= this->beta_ * state_variables_.at("pressure"); + total_stress(0) -= this->projection_param_ * state_variables_.at("pressure"); + total_stress(1) -= this->projection_param_ * state_variables_.at("pressure"); // Compute nodal internal forces for (unsigned i = 0; i < nodes_.size(); ++i) { @@ -103,9 +98,9 @@ template <> inline void mpm::FluidParticle<3>::map_internal_force() noexcept { // initialise a vector of total stress (deviatoric + turbulent - pressure) Eigen::Matrix total_stress = this->stress_; - total_stress(0) -= this->beta_ * state_variables_.at("pressure"); - total_stress(1) -= this->beta_ * state_variables_.at("pressure"); - total_stress(2) -= this->beta_ * state_variables_.at("pressure"); + total_stress(0) -= this->projection_param_ * state_variables_.at("pressure"); + total_stress(1) -= this->projection_param_ * state_variables_.at("pressure"); + total_stress(2) -= this->projection_param_ * state_variables_.at("pressure"); // Compute nodal internal forces for (unsigned i = 0; i < nodes_.size(); ++i) { @@ -127,28 +122,14 @@ inline void mpm::FluidParticle<3>::map_internal_force() noexcept { } } -// TODO: Check whether this is important -//! Assign particle pressure constraints -// template -// bool mpm::FluidParticle::assign_particle_pressure_constraint( -// double pressure) { -// bool status = true; -// try { -// this->pressure_constraint_ = pressure; -// } catch (std::exception& exception) { -// console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); -// status = false; -// } -// return status; -// } - -//! Compute laplacian matrix element +//! Map laplacian element matrix to cell (used in poisson equation LHS) template -bool mpm::FluidParticle::map_L_to_cell() { +bool mpm::FluidParticle::map_laplacian_to_cell() { bool status = true; try { + // TODO: Tobe uncomment once cell is implemented // Compute local matrix of Laplacian - cell_->compute_L_element(dn_dx_, volume_, 1.0); + // cell_->compute_L_element(dn_dx_, volume_, 1.0); } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); status = false; @@ -156,15 +137,17 @@ bool mpm::FluidParticle::map_L_to_cell() { return status; } -//! Compute element F_s_element and F_m_element +//! Map poisson rhs element matrix to cell (used in poisson equation RHS) template -bool mpm::FluidParticle::map_F_to_cell() { +bool mpm::FluidParticle::map_poisson_rhs_to_cell() { bool status = true; try { + // TODO: Tobe uncomment once cell is implemented // Compute local matrix of F - cell_->compute_F_element( - shapefn_, dn_dx_, - material_->template property(std::string("density")) * volume_); + // cell_->compute_F_element( + // shapefn_, dn_dx_, + // material_->template property(std::string("density")) * + // volume_); } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); status = false; @@ -172,12 +155,13 @@ bool mpm::FluidParticle::map_F_to_cell() { return status; } -//! Compute element K_cor_w_element_ +//! Map correction matrix element matrix to cell (used to correct velocity) template -bool mpm::FluidParticle::map_K_cor_to_cell() { +bool mpm::FluidParticle::map_correction_matrix_to_cell() { bool status = true; try { - cell_->compute_K_cor_element(shapefn_, dn_dx_, volume_); + // TODO: Tobe uncomment once cell is implemented + // cell_->compute_K_cor_element(shapefn_, dn_dx_, volume_); } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); @@ -192,12 +176,14 @@ bool mpm::FluidParticle::compute_updated_pressure() { try { double pressure_increment = 0; - for (unsigned i = 0; i < nodes_.size(); ++i) { - pressure_increment += shapefn_(i) * nodes_[i]->pressure_increment(); - } + // TODO: Tobe uncomment once node is implemented + // for (unsigned i = 0; i < nodes_.size(); ++i) { + // pressure_increment += shapefn_(i) * nodes_[i]->pressure_increment(); + // } // Get interpolated nodal pore pressure state_variables_.at("pressure") = - state_variables_.at("pressure") * beta_ + pressure_increment; + state_variables_.at("pressure") * projection_param_ + + pressure_increment; // Apply free surface if (this->free_surface()) state_variables_.at("pressure") = 0.0; } catch (std::exception& exception) { @@ -205,102 +191,4 @@ bool mpm::FluidParticle::compute_updated_pressure() { status = false; } return status; -} - -// //! Assign particle permeability -// template -// bool mpm::FluidParticle::assign_permeability() { -// bool status = true; -// try { -// // Check if material ptr is valid -// if (material_ != nullptr) { -// // Porosity parameter -// const double k_p = -// std::pow(this->porosity_, 3) / std::pow((1. - this->porosity_), 2); -// switch (Tdim) { -// case (1): { -// permeability_(0) = material_->template property("k_x"); -// c1_(0) = permeability_(0) / k_p; -// break; -// } -// case (2): { -// permeability_(0) = material_->template property("k_x"); -// permeability_(1) = material_->template property("k_y"); -// c1_(0) = permeability_(0) / k_p; -// c1_(1) = permeability_(1) / k_p; -// break; -// } -// default: { -// permeability_(0) = material_->template property("k_x"); -// permeability_(1) = material_->template property("k_y"); -// permeability_(2) = material_->template property("k_z"); -// c1_(0) = permeability_(0) / k_p; -// c1_(1) = permeability_(1) / k_p; -// c1_(2) = permeability_(2) / k_p; -// break; -// } -// } -// } else { -// throw std::runtime_error("Material is invalid"); -// } -// } catch (std::exception& exception) { -// console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); -// status = false; -// } -// return status; -// } - -// //! Update particle permeability -// template -// bool mpm::FluidParticle::update_permeability() { -// bool status = true; -// try { -// // Porosity parameter -// const double k_p = -// std::pow(this->porosity_, 3) / std::pow((1. - this->porosity_), 2); - -// // Update permeability by KC equation -// permeability_ = k_p * c1_; - -// } catch (std::exception& exception) { -// console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); -// status = false; -// } -// return status; -// } - -// //! Map drag force -// template -// bool mpm::FluidParticle::map_drag_force_coefficient() { -// bool status = true; -// try { -// // Update permeability -// this->update_permeability(); -// // Initialise drag force coefficient -// VectorDim drag_force_coefficient; -// drag_force_coefficient.setZero(); - -// // Check if permeability coefficient is valid -// for (unsigned i = 0; i < Tdim; ++i) { -// if (permeability_(i) > 0.) -// drag_force_coefficient(i) = -// porosity_ * porosity_ * 9.81 * -// // liquid_material_->template property( -// // std::string("density")) / -// material_->template property(std::string("density")) / -// permeability_(i); -// else -// throw std::runtime_error("Permeability coefficient is invalid"); -// } - -// // Map drag forces from particle to nodes -// for (unsigned j = 0; j < nodes_.size(); ++j) -// nodes_[j]->update_drag_force_coefficient( -// true, drag_force_coefficient * this->volume_ * shapefn_(j)); - -// } catch (std::exception& exception) { -// console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); -// status = false; -// } -// return status; -// } \ No newline at end of file +} \ No newline at end of file From 96349e4624d20bf3c218a5a821fb6b55c7b387d2 Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 10 Mar 2020 23:43:53 -0700 Subject: [PATCH 04/72] add solver all commented --- .../solvers/mpm_semi_implicit_navierstokes.h | 101 +++++ .../mpm_semi_implicit_navierstokes.tcc | 394 ++++++++++++++++++ src/mpm.cc | 11 + 3 files changed, 506 insertions(+) create mode 100644 include/solvers/mpm_semi_implicit_navierstokes.h create mode 100644 include/solvers/mpm_semi_implicit_navierstokes.tcc diff --git a/include/solvers/mpm_semi_implicit_navierstokes.h b/include/solvers/mpm_semi_implicit_navierstokes.h new file mode 100644 index 000000000..4c02b6d3e --- /dev/null +++ b/include/solvers/mpm_semi_implicit_navierstokes.h @@ -0,0 +1,101 @@ +#ifndef MPM_MPM_SEMI_IMPLICIT_NAVIER_STOKES_H_ +#define MPM_MPM_SEMI_IMPLICIT_NAVIER_STOKES_H_ + +#ifdef USE_GRAPH_PARTITIONING +#include "graph.h" +#endif + +#include "solvers/mpm_base.h" + +#include "matrix/assembler_base.h" +#include "matrix/assembler_eigen_semi_implicit_navierstokes.h" +#include "matrix/cg_eigen.h" +#include "matrix/solver_base.h" + +namespace mpm { + +//! MPMSemiImplicit Navier Stokes class +//! \brief A class that implements the fractional step navier-stokes mpm +//! \tparam Tdim Dimension +template +class MPMSemiImplicitNavierStokes : public MPMBase { + public: + //! Default constructor + MPMSemiImplicitNavierStokes(const std::shared_ptr& io); + + //! Return matrix assembler pointer + std::shared_ptr> matrix_assembler() { + return matrix_assembler_; + } + + //! Solve + bool solve() override; + + //! Pressure smoothing + //! \param[in] phase Phase to smooth pressure + void pressure_smoothing(unsigned phase) override; + + //! Class private functions + private: + //! Initialise matrix + virtual bool initialise_matrix(); + + //! Initialise matrix + virtual bool reinitialise_matrix(); + + //! Compute poisson equation + bool compute_poisson_equation(std::string solver_type = "cg"); + + //! Compute corrected velocity + bool compute_corrected_force(); + + //! Class private variables + private: + // Generate a unique id for the analysis + using mpm::MPMBase::uuid_; + //! Time step size + using mpm::MPMBase::dt_; + //! Current step + using mpm::MPMBase::step_; + //! Number of steps + using mpm::MPMBase::nsteps_; + //! Output steps + using mpm::MPMBase::output_steps_; + //! A unique ptr to IO object + using mpm::MPMBase::io_; + //! JSON analysis object + using mpm::MPMBase::analysis_; + //! JSON post-process object + using mpm::MPMBase::post_process_; + //! Logger + using mpm::MPMBase::console_; + //! Stress update + using mpm::MPMBase::stress_update_; + //! velocity update + using mpm::MPMBase::velocity_update_; + //! Gravity + using mpm::MPMBase::gravity_; + //! Mesh object + using mpm::MPMBase::mesh_; + //! Materials + using mpm::MPMBase::materials_; + //! VTK attributes + using mpm::MPMBase::vtk_attributes_; + //! Pressure smoothing + bool pressure_smoothing_{false}; + // Projection method paramter (beta) + double beta_{1}; + //! Matrix assembler object + std::shared_ptr> matrix_assembler_; + //! Matrix solver object + std::shared_ptr> matrix_solver_; + // TODO: Check if this is usefull, or remove. + //! Volume tolerance for free surface + double volume_tolerance_{0}; + +}; // MPMSemiImplicit class +} // namespace mpm + +#include "mpm_semi_implicit_navierstokes.tcc" + +#endif // MPM_MPM_SEMI_IMPLICIT_NAVIER_STOKES_H_ diff --git a/include/solvers/mpm_semi_implicit_navierstokes.tcc b/include/solvers/mpm_semi_implicit_navierstokes.tcc new file mode 100644 index 000000000..4b45bb94c --- /dev/null +++ b/include/solvers/mpm_semi_implicit_navierstokes.tcc @@ -0,0 +1,394 @@ +//! Constructor +template +mpm::MPMSemiImplicitNavierStokes::MPMSemiImplicitNavierStokes( + const std::shared_ptr& io) + : mpm::MPMBase(io) { + //! Logger + console_ = spdlog::get("MPMSemiImplicitNavierStokes"); +} + +//! MPM semi-implicit two phase solver +template +bool mpm::MPMSemiImplicitNavierStokes::solve() { + bool status = true; + + // console_->info("MPM analysis type {}", io_->analysis_type()); + + // // Initialise MPI rank and size + // int mpi_rank = 0; + // int mpi_size = 1; + + // #ifdef USE_MPI + // // Get MPI rank + // MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + // // Get number of MPI ranks + // MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + // #endif + + // // This solver consider only fluid variables + // // NOTE: Due to indexing purposes + // const unsigned fluid = mpm::ParticlePhase::SinglePhase; + + // // Test if checkpoint resume is needed + // bool resume = false; + // if (analysis_.find("resume") != analysis_.end()) + // resume = analysis_["resume"]["resume"].template get(); + + // // Pressure smoothing + // if (analysis_.find("pressure_smoothing") != analysis_.end()) + // pressure_smoothing_ = analysis_["pressure_smoothing"].template + // get(); + + // // Projection method parameter (beta) + // if (analysis_.find("semi_implicit") != analysis_.end()) + // beta_ = analysis_["semi_implicit"]["beta"].template get(); + + // // Initialise material + // bool mat_status = this->initialise_materials(); + // if (!mat_status) { + // status = false; + // throw std::runtime_error("Initialisation of materials failed"); + // } + + // // Initialise mesh + // bool mesh_status = this->initialise_mesh(); + // if (!mesh_status) { + // status = false; + // throw std::runtime_error("Initialisation of mesh failed"); + // } + + // // Initialise particles + // bool particle_status = this->initialise_particles(); + // if (!particle_status) { + // status = false; + // throw std::runtime_error("Initialisation of particles failed"); + // } + + // // Initialise loading conditions + // bool loading_status = this->initialise_loads(); + // if (!loading_status) { + // status = false; + // throw std::runtime_error("Initialisation of loads failed"); + // } + + // // Initialise matrix + // bool matrix_status = this->initialise_matrix(); + // if (!matrix_status) { + // status = false; + // throw std::runtime_error("Initialisation of matrix failed"); + // } + + // // Compute mass for each phase + // mesh_->iterate_over_particles( + // std::bind(&mpm::ParticleBase::compute_mass, + // std::placeholders::_1)); + + // // Assign beta to each particle + // mesh_->iterate_over_particles( + // std::bind(&mpm::ParticleBase::assign_semi_implicit_param, + // std::placeholders::_1, beta_)); + + // // Check point resume + // if (resume) this->checkpoint_resume(); + + // auto solver_begin = std::chrono::steady_clock::now(); + // // Main loop + // for (; step_ < nsteps_; ++step_) { + // if (mpi_rank == 0) console_->info("Step: {} of {}.\n", step_, nsteps_); + + // // Create a TBB task group + // tbb::task_group task_group; + + // // Spawn a task for initialising nodes and cells + // task_group.run([&] { + // // Initialise nodes + // mesh_->iterate_over_nodes( + // std::bind(&mpm::NodeBase::initialise, + // std::placeholders::_1)); + + // mesh_->iterate_over_cells( + // std::bind(&mpm::Cell::activate_nodes, + // std::placeholders::_1)); + // }); + // task_group.wait(); + + // // Spawn a task for particles + // task_group.run([&] { + // // Iterate over each particle to compute shapefn + // mesh_->iterate_over_particles(std::bind( + // &mpm::ParticleBase::compute_shapefn, + // std::placeholders::_1)); + // }); + + // task_group.wait(); + + // // Assign mass and momentum to nodes + // // Solid skeleton + // mesh_->iterate_over_particles( + // std::bind(&mpm::ParticleBase::map_mass_momentum_to_nodes, + // std::placeholders::_1)); + + // // Compute nodal velocity at the begining of time step + // mesh_->iterate_over_nodes_predicate( + // std::bind(&mpm::NodeBase::compute_velocity, + // std::placeholders::_1), + // std::bind(&mpm::NodeBase::status, std::placeholders::_1)); + + // // Iterate over each particle to compute strain rate + // mesh_->iterate_over_particles(std::bind( + // &mpm::ParticleBase::compute_strain, std::placeholders::_1, + // dt_)); + + // // Iterate over each particle to compute shear (deviatoric) stress + // mesh_->iterate_over_particles(std::bind( + // &mpm::ParticleBase::compute_stress, std::placeholders::_1)); + + // // Spawn a task for external force + // task_group.run([&] { + // // Iterate over particles to compute nodal body force + // mesh_->iterate_over_particles( + // std::bind(&mpm::ParticleBase::map_body_force, + // std::placeholders::_1, this->gravity_)); + + // // Apply particle traction and map to nodes + // mesh_->apply_traction_on_particles(this->step_ * this->dt_); + // }); + + // // Spawn a task for internal force + // task_group.run([&] { + // // Iterate over particles to compute nodal internal force + // mesh_->iterate_over_particles(std::bind( + // &mpm::ParticleBase::map_internal_force, + // std::placeholders::_1)); + // }); + // task_group.wait(); + + // // Compute free surface cells, nodes, and particles + // mesh_->compute_free_surface(volume_tolerance_); + + // // Compute intermediate velocity + // mesh_->iterate_over_nodes_predicate( + // std::bind(&mpm::NodeBase::compute_acceleration_velocity, + // std::placeholders::_1, fluid, this->dt_), + // std::bind(&mpm::NodeBase::status, std::placeholders::_1)); + + // // Reinitialise system matrix to perform PPE + // bool matrix_reinitialization_status = this->reinitialise_matrix(); + // if (!matrix_reinitialization_status) { + // status = false; + // throw std::runtime_error("Reinitialisation of matrix failed"); + // } + + // // Compute poisson equation + // this->compute_poisson_equation(); + + // // Assign pore pressure to nodes + // mesh_->iterate_over_nodes_predicate( + // std::bind(&mpm::NodeBase::update_pressure_increment, + // std::placeholders::_1, + // matrix_assembler_->pressure_increment(), fluid, + // this->step_ * this->dt_), + // std::bind(&mpm::NodeBase::status, std::placeholders::_1)); + + // // Use nodal pressure to update particle pressure + // mesh_->iterate_over_particles( + // std::bind(&mpm::ParticleBase::compute_updated_pressure, + // std::placeholders::_1)); + + // // Compute corrected force + // this->compute_corrected_force(); + + // // Compute corrected acceleration and velocity + // mesh_->iterate_over_nodes_predicate( + // std::bind( + // &mpm::NodeBase< + // Tdim>::compute_acceleration_velocity_navierstokes_semi_implicit, + // std::placeholders::_1, fluid, this->dt_), + // std::bind(&mpm::NodeBase::status, std::placeholders::_1)); + + // // Update particle position and kinematics + // mesh_->iterate_over_particles( + // std::bind(&mpm::ParticleBase::compute_updated_position, + // std::placeholders::_1, this->dt_, velocity_update_)); + + // // Apply particle velocity constraints + // mesh_->apply_particle_velocity_constraints(); + + // // Pressure smoothing + // if (pressure_smoothing_) this->pressure_smoothing(fluid); + + // // Locate particles + // auto unlocatable_particles = mesh_->locate_particles_mesh(); + + // if (!unlocatable_particles.empty()) + // throw std::runtime_error("Particle outside the mesh domain"); + + // if (step_ % output_steps_ == 0) { + // // HDF5 outputs + // this->write_hdf5(this->step_, this->nsteps_); + // #ifdef USE_VTK + // // VTK outputs + // this->write_vtk(this->step_, this->nsteps_); + // #endif + // } + // } + auto solver_end = std::chrono::steady_clock::now(); + console_->info("Rank {}, SemiImplicit_NavierStokes {} solver duration: {} ms", + mpi_rank, + std::chrono::duration_cast( + solver_end - solver_begin) + .count()); + + return status; +} + +// Semi-implicit functions +// Initialise matrix +template +bool mpm::MPMSemiImplicitNavierStokes::initialise_matrix() { + bool status = true; + // try { + // // Max iteration steps + // unsigned max_iter = + // analysis_["matrix"]["max_iter"].template get(); + // // Tolerance + // double tolerance = analysis_["matrix"]["tolerance"].template + // get(); + // // Get matrix assembler type + // std::string assembler_type = + // analysis_["matrix"]["assembler_type"].template get(); + // // Get matrix solver type + // std::string solver_type = + // analysis_["matrix"]["solver_type"].template get(); + // // TODO: Check if this is usefull, or remove. + // // Get volume tolerance for free surface + // volume_tolerance_ = + // analysis_["matrix"]["volume_tolerance"].template get(); + // // Create matrix assembler + // matrix_assembler_ = + // Factory>::instance()->create(assembler_type); + // // Create matrix solver + // matrix_solver_ = + // Factory, unsigned, double>::instance()->create( + // solver_type, std::move(max_iter), std::move(tolerance)); + // // Transfer the mesh pointer + // matrix_assembler_->assign_mesh_pointer(mesh_); + + // } catch (std::exception& exception) { + // console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + // status = false; + // } + return status; +} + +// Reinitialise and resize matrices at the beginning of every time step +template +bool mpm::MPMSemiImplicitNavierStokes::reinitialise_matrix() { + bool status = true; + // try { + // // Assigning matrix id + // const auto active_dof = mesh_->assign_active_node_id(); + + // // Assign global node indice + // matrix_assembler_->assign_global_node_indices(active_dof); + + // // Assign pressure cpnstraints + // matrix_assembler_->assign_pressure_constraints(this->beta_, + // this->step_ * this->dt_); + + // // Initialise element matrix + // mesh_->iterate_over_cells(std::bind( + // &mpm::Cell::initialise_element_matrix, std::placeholders::_1)); + + // } catch (std::exception& exception) { + // console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + // status = false; + // } + return status; +} + +// FIXME: This is a copy of pressure_smoothing in explicit two-phase +//! MPM Explicit two-phase pressure smoothing +template +void mpm::MPMSemiImplicitNavierStokes::pressure_smoothing( + unsigned phase) { + + // // Map pressures to nodes + // mesh_->iterate_over_particles( + // std::bind(&mpm::ParticleBase::map_pressure_to_nodes, + // std::placeholders::_1, this->step_ * this->dt_)); + + // #ifdef USE_MPI + // int mpi_size = 1; + + // // Get number of MPI ranks + // MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + + // // Run if there is more than a single MPI task + // if (mpi_size > 1) { + // // MPI all reduce nodal pressure + // mesh_->template nodal_halo_exchange( + // std::bind(&mpm::NodeBase::pressure, std::placeholders::_1, + // phase), std::bind(&mpm::NodeBase::assign_pressure, + // std::placeholders::_1, + // phase, std::placeholders::_2)); + // } + // #endif + + // // Map Pressure back to particles + // mesh_->iterate_over_particles( + // std::bind(&mpm::ParticleBase::compute_pressure_smoothing, + // std::placeholders::_1)); +} + +// Compute poisson equation +template +bool mpm::MPMSemiImplicitNavierStokes::compute_poisson_equation( + std::string solver_type) { + bool status = true; + // try { + // // Map Laplacian elements + // mesh_->iterate_over_particles(std::bind( + // &mpm::ParticleBase::map_L_to_cell, std::placeholders::_1)); + // // Assemble laplacian matrix + // matrix_assembler_->assemble_laplacian_matrix(dt_); + // // Map Fs & Fm matrix + // mesh_->iterate_over_particles(std::bind( + // &mpm::ParticleBase::map_F_to_cell, std::placeholders::_1)); + // // Assemble force vector + // matrix_assembler_->assemble_poisson_right(mesh_, dt_); + // // Assign free surface + // matrix_assembler_->assign_free_surface(mesh_->free_surface_nodes()); + // // Apply constraints + // matrix_assembler_->apply_pressure_constraints(); + // // Solve matrix equation (compute pore pressure) + // matrix_assembler_->assign_pressure_increment(matrix_solver_->solve( + // matrix_assembler_->laplacian_matrix(), + // matrix_assembler_->force_laplacian_matrix(), solver_type)); + // } catch (std::exception& exception) { + // console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + // status = false; + // } + return status; +} + +//! Compute corrected force +template +bool mpm::MPMSemiImplicitNavierStokes::compute_corrected_force() { + bool status = true; + // try { + // mesh_->iterate_over_particles(std::bind( + // &mpm::ParticleBase::map_K_cor_to_cell, std::placeholders::_1)); + // // Assemble corrected force matrix + // matrix_assembler_->assemble_K_cor_matrix(mesh_, dt_); + // // Assign corrected force + // mesh_->compute_nodal_corrected_force_navierstokes( + // matrix_assembler_->K_cor_matrix(), + // matrix_assembler_->pressure_increment(), dt_); + + // } catch (std::exception& exception) { + // console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + // status = false; + // } + return status; +} diff --git a/src/mpm.cc b/src/mpm.cc index 19b3f5dc9..8327f959d 100644 --- a/src/mpm.cc +++ b/src/mpm.cc @@ -4,6 +4,7 @@ #include "io.h" #include "mpm.h" #include "mpm_explicit.h" +#include "mpm_semi_implicit_navierstokes.h" namespace mpm { // Stress update method @@ -20,3 +21,13 @@ static Register, const std::shared_ptr&> // 3D Explicit MPM static Register, const std::shared_ptr&> mpm_explicit_3d("MPMExplicit3D"); + +// 2D SemiImplicit Navier Stokes MPM +static Register, + const std::shared_ptr&> + mpm_semi_implicit_navierstokes_2d("MPMSemiImplicitNavierStokes2D"); + +// 3D SemiImplicit Navier Stokes MPM +static Register, + const std::shared_ptr&> + mpm_semi_implicit_navierstokes_3d("MPMSemiImplicitNavierStokes3D"); \ No newline at end of file From d76a013cca64dd17bdafbb8ef31a92d0b55b4466 Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 11 Mar 2020 00:08:49 -0700 Subject: [PATCH 05/72] add matrix --- CMakeLists.txt | 1 + include/matrix/assembler_base.h | 186 ++++++++++++ ...sembler_eigen_semi_implicit_navierstokes.h | 99 +++++++ ...mbler_eigen_semi_implicit_navierstokes.tcc | 275 ++++++++++++++++++ include/matrix/cg_eigen.h | 57 ++++ include/matrix/cg_eigen.tcc | 119 ++++++++ include/matrix/solver_base.h | 38 +++ src/matrix.cc | 23 ++ 8 files changed, 798 insertions(+) create mode 100644 include/matrix/assembler_base.h create mode 100644 include/matrix/assembler_eigen_semi_implicit_navierstokes.h create mode 100644 include/matrix/assembler_eigen_semi_implicit_navierstokes.tcc create mode 100644 include/matrix/cg_eigen.h create mode 100644 include/matrix/cg_eigen.tcc create mode 100644 include/matrix/solver_base.h create mode 100644 src/matrix.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 47c7b8aa5..9dd2655a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -170,6 +170,7 @@ SET(mpm_src ${mpm_SOURCE_DIR}/src/io/logger.cc ${mpm_SOURCE_DIR}/src/io/partio_writer.cc ${mpm_SOURCE_DIR}/src/material.cc + ${mpm_SOURCE_DIR}/src/matrix.cc ${mpm_SOURCE_DIR}/src/mpm.cc ${mpm_SOURCE_DIR}/src/node.cc ${mpm_SOURCE_DIR}/src/particle.cc diff --git a/include/matrix/assembler_base.h b/include/matrix/assembler_base.h new file mode 100644 index 000000000..3e34f3934 --- /dev/null +++ b/include/matrix/assembler_base.h @@ -0,0 +1,186 @@ +#ifndef MPM_ASSEMBLER_BASE_H_ +#define MPM_ASSEMBLER_BASE_H_ + +#include +#include +#include +#include +#include + +#include + +#include "mesh.h" +#include "node_base.h" + +namespace mpm { + +// Matrix assembler base class +//! \brief Assemble matrixs (stiffness matrix) +//! \details Get local stiffness matrix and node ids from cell +//! \tparam Tdim Dimension +template +class AssemblerBase { + public: + AssemblerBase() { + //! Global degrees of freedom + active_dof_ = 0; + } + // Virtual destructor + virtual ~AssemblerBase() = default; + + //! Copy constructor + // AssemblerBase(const AssemblerBase&) = default; + + //! Assignment operator + // AssemblerBase& operator=(const AssemblerBase&) = default; + + //! Move constructor + // AssemblerBase(AssemblerBase&&) = default; + + //! Assign mesh pointer + void assign_mesh_pointer(std::shared_ptr>& mesh) { + mesh_ = mesh; + } + + //! Create a pair between nodes and index in Matrix / Vector + virtual bool assign_global_node_indices(unsigned active_dof) = 0; + + //! Assemble displacement vector + // virtual void assemble_disp_vector() = 0; + + //! Apply displacement to nodes + // virtual void apply_displacement_nodes() = 0; + + //! Apply forces to nodes + // virtual void apply_forces_nodes() = 0; + + //! Apply restraints + // virtual Eigen::VectorXd global_restraints() = 0; + + //! Initialise force vector to zero + // virtual void initialise_force_zero() = 0; + + virtual bool assemble_K_cor_matrix(std::shared_ptr>& mesh_, + double dt) = 0; + + //! Assemble laplacian matrix + virtual bool assemble_laplacian_matrix(double dt) = 0; + + //! Assemble poisson right + virtual bool assemble_poisson_right(std::shared_ptr>& mesh_, + double dt) = 0; + + virtual void assign_pressure_increment( + Eigen::VectorXd pressure_increment) = 0; + + virtual Eigen::SparseMatrix& K_cor_matrix() = 0; + + virtual Eigen::SparseMatrix& laplacian_matrix() = 0; + + virtual Eigen::VectorXd& force_laplacian_matrix() = 0; + + virtual Eigen::VectorXd& pressure_increment() = 0; + + virtual void apply_pressure_constraints() = 0; + + virtual bool assign_pressure_constraints(double beta, + const double current_time) = 0; + + virtual std::set free_surface() = 0; + + virtual void assign_free_surface( + const std::set& free_surface_id) = 0; + + virtual unsigned active_dof() { return active_dof_; }; + + //! Assemble stiffness matrix (semi-implicit) + virtual bool assemble_stiffness_matrix(unsigned dir, double dt) { + throw std::runtime_error( + "Calling the base class function " + "(assemble_stiffness_matrix) in " + "AssemblerBase:: illegal operation!"); + return false; + }; + + //! Assemble force vector (semi-implicit) + virtual bool assemble_force_vector(double dt) { + throw std::runtime_error( + "Calling the base class function " + "(assemble_force_vector) in " + "AssemblerBase:: illegal operation!"); + return false; + }; + + //! Return stiffness matrix + virtual Eigen::SparseMatrix& stiffness_matrix(unsigned dir) { + static Eigen::SparseMatrix error; + throw std::runtime_error( + "Calling the base class function " + "(stiffness_matrix) in " + "AssemblerBase:: illegal operation!"); + return error; + }; + + //! Return intermediate force + virtual Eigen::MatrixXd& force_inter() { + static Eigen::MatrixXd error; + throw std::runtime_error( + "Calling the base class function " + "(force_inter) in " + "AssemblerBase:: illegal operation!"); + return error; + }; + + //! Assign intermediate acceleration + virtual void assign_intermediate_acceleration( + unsigned dim, Eigen::VectorXd acceleration_inter) { + throw std::runtime_error( + "Calling the base class function " + "(assign_intermediate_acceleration) in " + "AssemblerBase:: illegal operation!"); + }; + + //! Return intermediate velocity + virtual Eigen::MatrixXd& acceleration_inter() { + static Eigen::MatrixXd error; + throw std::runtime_error( + "Calling the base class function " + "(acceleration_inter) in " + "AssemblerBase:: illegal operation!"); + return error; + }; + + virtual bool assign_velocity_constraints() { + throw std::runtime_error( + "Calling the base class function " + "(assign_velocity_constraints) in " + "AssemblerBase:: illegal operation!"); + return false; + }; + + //! Apply velocity constraints + virtual bool apply_velocity_constraints() { + throw std::runtime_error( + "Calling the base class function " + "(apply_velocity_constraints) in " + "AssemblerBase:: illegal operation!"); + return false; + }; + + protected: + //! Active node number + unsigned active_dof_; + //! Mesh object + std::shared_ptr> mesh_; + //! Sparse Stiffness Matrix + std::shared_ptr> stiffness_matrix_; + //! Force vector + std::shared_ptr force_inter_; + //! Intermediate velocity vector + std::shared_ptr velocity_inter_vector_; + //! Displacement vector + std::shared_ptr displacement_vector_; +}; +} // namespace mpm + +#endif // MPM_ASSEMBLER_BASE_H_ \ No newline at end of file diff --git a/include/matrix/assembler_eigen_semi_implicit_navierstokes.h b/include/matrix/assembler_eigen_semi_implicit_navierstokes.h new file mode 100644 index 000000000..a261bc051 --- /dev/null +++ b/include/matrix/assembler_eigen_semi_implicit_navierstokes.h @@ -0,0 +1,99 @@ +#ifndef MPM_ASSEMBLER_EIGEN_SEMI_IMPLICIT_NAVIERSTOKES_H_ +#define MPM_ASSEMBLER_EIGEN_SEMI_IMPLICIT_NAVIERSTOKES_H_ + +#include +#include + +// Speed log +#include "assembler_base.h" +#include "spdlog/spdlog.h" + +#include "cg_eigen.h" +#include "mesh.h" + +namespace mpm { +template +class AssemblerEigenSemiImplicitNavierStokes : public AssemblerBase { + public: + //! Constructor + AssemblerEigenSemiImplicitNavierStokes(); + + //! Create a pair between nodes and index in Matrix / Vector + bool assign_global_node_indices(unsigned active_dof) override; + + //! Resize containers of matrix + bool resize_semi_implicit_matrix(); + + //! Assemble K_cor matrix (used in correcting nodal velocity) + bool assemble_K_cor_matrix(std::shared_ptr>& mesh_, + double dt) override; + + //! Assemble_laplacian_matrix + bool assemble_laplacian_matrix(double dt) override; + + //! Assemble_poisson_right + bool assemble_poisson_right(std::shared_ptr>& mesh_, + double dt) override; + + void assign_pressure_increment(Eigen::VectorXd pressure_increment) override { + pressure_increment_ = pressure_increment; + } + + Eigen::SparseMatrix& K_cor_matrix() override { return K_cor_matrix_; } + + Eigen::SparseMatrix& laplacian_matrix() override { + return laplacian_matrix_; + } + + Eigen::VectorXd& force_laplacian_matrix() override { + return force_laplacian_matrix_; + } + + Eigen::VectorXd& pressure_increment() override { return pressure_increment_; } + + std::set free_surface() override { return free_surface_; } + + void assign_free_surface( + const std::set& free_surface_id) override { + free_surface_ = free_surface_id; + } + + bool assign_pressure_constraints(double beta, + const double current_time) override; + + void apply_pressure_constraints(); + + protected: + //! Logger + std::shared_ptr console_; + + private: + //! number of nodes + using AssemblerBase::active_dof_; + //! Mesh object + using AssemblerBase::mesh_; + //! poisson equation RHS (F31 and F32) + Eigen::VectorXd force_laplacian_matrix_; + //! Laplacian matrix + Eigen::SparseMatrix laplacian_matrix_; + //! K_cor_matrix + Eigen::SparseMatrix K_cor_matrix_; + //! p^(t+1) - beta * p^(t) + Eigen::VectorXd pressure_increment_; + //! Laplacian coefficient + Eigen::VectorXd poisson_right_vector_; + //! Solver base + std::shared_ptr> solver_; + //! Global node indices + std::vector global_node_indices_; + //! Velocity constraints + Eigen::SparseMatrix velocity_constraints_; + //! Pressure constraints + Eigen::SparseVector pressure_constraints_; + //! Free surface + std::set free_surface_; +}; +} // namespace mpm + +#include "assembler_eigen_semi_implicit_navierstokes.tcc" +#endif // MPM_ASSEMBLER_EIGEN_SEMI_IMPLICIT_NAVIERSTOKES_H_ diff --git a/include/matrix/assembler_eigen_semi_implicit_navierstokes.tcc b/include/matrix/assembler_eigen_semi_implicit_navierstokes.tcc new file mode 100644 index 000000000..fc1ed4409 --- /dev/null +++ b/include/matrix/assembler_eigen_semi_implicit_navierstokes.tcc @@ -0,0 +1,275 @@ +//! Construct a semi-implicit eigen matrix assembler +template +mpm::AssemblerEigenSemiImplicitNavierStokes< + Tdim>::AssemblerEigenSemiImplicitNavierStokes() + : mpm::AssemblerBase() { + //! Logger + console_ = spdlog::stdout_color_mt("AssemblerEigenSemiImplicitNavierStokes"); +} + +//! Assign global node indices +template +bool mpm::AssemblerEigenSemiImplicitNavierStokes< + Tdim>::assign_global_node_indices(unsigned active_dof) { + bool status = true; + // try { + // active_dof_ = active_dof; + + // global_node_indices_ = mesh_->global_node_indices(); + + // } catch (std::exception& exception) { + // console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + // status = false; + // } + return status; +} + +//! Assemble Laplacian matrix +template +bool mpm::AssemblerEigenSemiImplicitNavierStokes< + Tdim>::assemble_laplacian_matrix(double dt) { + bool status = true; + // try { + // // Initialise Laplacian matrix + // laplacian_matrix_.resize(active_dof_, active_dof_); + // laplacian_matrix_.setZero(); + // // TODO: Make the storage being able to adaptively resize + // // Reserve storage for sparse matrix + // switch (Tdim) { + // // For 2d: 10 entries /column + // case (2): { + // laplacian_matrix_.reserve(Eigen::VectorXi::Constant(active_dof_, + // 10)); break; + // } + // // For 3d: 30 entries /column + // case (3): { + // laplacian_matrix_.reserve(Eigen::VectorXi::Constant(active_dof_, + // 30)); break; + // } + // } + // // Cell pointer + // const auto& cells = mesh_->cells(); + // // Iterate over cells + // // active cell id + // mpm::Index cid = 0; + // for (auto cell_itr = cells.cbegin(); cell_itr != cells.cend(); + // ++cell_itr) { + // if ((*cell_itr)->status()) { + // // Node ids in each cell + // const auto nids = global_node_indices_.at(cid); + // // Laplacian element of cell + // const auto L_element = (*cell_itr)->L_element(); + // // Compute Laplacian elements + // for (unsigned i = 0; i < nids.size(); ++i) { + // for (unsigned j = 0; j < nids.size(); ++j) { + // laplacian_matrix_.coeffRef(global_node_indices_.at(cid)(i), + // global_node_indices_.at(cid)(j)) += + // L_element(i, j); + // } + // } + // ++cid; + // } + // } + // laplacian_matrix_ *= dt; + // } catch (std::exception& exception) { + // console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + // status = false; + // } + return status; +} + +template +bool mpm::AssemblerEigenSemiImplicitNavierStokes::assemble_poisson_right( + std::shared_ptr>& mesh_, double dt) { + bool status = true; + // try { + // // Initialise Fs & Fm matrix + // Eigen::SparseMatrix F_s_matrix; + // // Resize Fs matrix + // F_s_matrix.resize(active_dof_, active_dof_ * Tdim); + // F_s_matrix.setZero(); + // // Reserve storage for sparse matrix + // switch (Tdim) { + // // For 2d: 10 entries /column + // case (2): { + // F_s_matrix.reserve(Eigen::VectorXi::Constant(active_dof_ * Tdim, + // 10)); break; + // } + // // For 3d: 30 entries /column + // case (3): { + // F_s_matrix.reserve(Eigen::VectorXi::Constant(active_dof_ * Tdim, + // 30)); break; + // } + // } + // // Cell pointer + // const auto& cells = mesh_->cells(); + // // Iterate over cells + // // active cell id + // mpm::Index cid = 0; + // for (auto cell_itr = cells.cbegin(); cell_itr != cells.cend(); + // ++cell_itr) { + // // Cell id + // if ((*cell_itr)->status()) { + // // Node ids in each cell + // const auto nids = global_node_indices_.at(cid); + // // Fs element of cell + // auto F_s_element = (*cell_itr)->F_s_element(); + // // Compute Fs & Fm + // for (unsigned i = 0; i < nids.size(); ++i) { + // for (unsigned j = 0; j < nids.size(); ++j) { + // for (unsigned k = 0; k < Tdim; ++k) { + // F_s_matrix.coeffRef( + // global_node_indices_.at(cid)(i), + // global_node_indices_.at(cid)(j) + k * active_dof_) += + // F_s_element(i, j + k * nids.size()); + // } + // } + // } + // cid++; + // } + // } + + // // Resize poisson right matrix + // force_laplacian_matrix_.resize(active_dof_); + // force_laplacian_matrix_.setZero(); + // // Compute velocity + // Eigen::MatrixXd fluid_velocity; + // fluid_velocity.resize(active_dof_, Tdim); + // fluid_velocity.setZero(); + + // // Active nodes + // const auto& active_nodes = mesh_->active_nodes(); + // const unsigned fluid = mpm::ParticlePhase::SinglePhase; + // unsigned node_index = 0; + + // for (auto node_itr = active_nodes.cbegin(); node_itr != + // active_nodes.cend(); + // ++node_itr) { + // // Compute nodal intermediate force + // fluid_velocity.row(node_index) = + // (*node_itr)->velocity(fluid).transpose(); node_index++; + // } + + // fluid_velocity.resize(active_dof_ * Tdim, 1); + + // force_laplacian_matrix_ = -F_s_matrix * fluid_velocity; + // } catch (std::exception& exception) { + // console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + // status = false; + // } + return status; +} + +//! Assemble K_cor_matrix +template +bool mpm::AssemblerEigenSemiImplicitNavierStokes::assemble_K_cor_matrix( + std::shared_ptr>& mesh_, double dt) { + bool status = true; + // try { + // K_cor_matrix_.resize(active_dof_, active_dof_ * Tdim); + // K_cor_matrix_.setZero(); + + // K_cor_matrix_.reserve(Eigen::VectorXi::Constant(active_dof_ * Tdim, 20)); + + // unsigned nnodes_per_cell = global_node_indices_.at(0).size(); + + // const auto& cell = mesh_->cells(); + + // unsigned cid = 0; + // for (auto cell_itr = cell.cbegin(); cell_itr != cell.cend(); ++cell_itr) + // { + // if ((*cell_itr)->status()) { + // auto k_cor_element_water = (*cell_itr)->K_cor_w_element(); + // for (unsigned k = 0; k < Tdim; k++) { + // for (unsigned i = 0; i < nnodes_per_cell; i++) { + // for (unsigned j = 0; j < nnodes_per_cell; j++) { + // // Fluid + // K_cor_matrix_.coeffRef( + // global_node_indices_.at(cid)(i), + // k * active_dof_ + global_node_indices_.at(cid)(j)) += + // k_cor_element_water(i, j + k * nnodes_per_cell); + // } + // } + // } + // cid++; + // } + // } + // } catch (std::exception& exception) { + // console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + // status = false; + // } + return status; +} + +//! Apply pressure constraints vector +template +void mpm::AssemblerEigenSemiImplicitNavierStokes< + Tdim>::apply_pressure_constraints() { + // try { + // // Modify force_laplacian_matrix_ + // force_laplacian_matrix_ -= laplacian_matrix_ * pressure_constraints_; + + // // Apply free surface + // if (!free_surface_.empty()) { + // const auto& nodes = mesh_->nodes(); + // for (const auto& free_node : free_surface_) { + // const auto column_index = nodes[free_node]->active_id(); + // // Modify force_laplacian_matrix + // force_laplacian_matrix_(column_index) = 0; + // // Modify laplacian_matrix + // laplacian_matrix_.row(column_index) *= 0; + // laplacian_matrix_.col(column_index) *= 0; + // laplacian_matrix_.coeffRef(column_index, column_index) = 1; + // } + // // Clear the vector + // free_surface_.clear(); + // } + + // // Iterate over pressure constraints + // for (Eigen::SparseVector::InnerIterator + // it(pressure_constraints_); + // it; ++it) { + // // Modify force_laplacian_matrix + // force_laplacian_matrix_(it.index()) = it.value(); + // // Modify laplacian_matrix + // laplacian_matrix_.row(it.index()) *= 0; + // laplacian_matrix_.col(it.index()) *= 0; + // laplacian_matrix_.coeffRef(it.index(), it.index()) = 1; + // } + // } catch (std::exception& exception) { + // console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + // } +} + +//! Assign pressure constraints +template +bool mpm::AssemblerEigenSemiImplicitNavierStokes< + Tdim>::assign_pressure_constraints(double beta, const double current_time) { + bool status = false; + // try { + // // Phase index + // const unsigned pore_liquid = mpm::ParticlePhase::Liquid; + // // Resize pressure constraints vector + // pressure_constraints_.resize(active_dof_); + // pressure_constraints_.reserve(int(0.5 * active_dof_)); + + // // Nodes container + // const auto& nodes = mesh_->active_nodes(); + // // Iterate over nodes to get pressure constraints + // for (auto node = nodes.cbegin(); node != nodes.cend(); ++node) { + // // Assign total pressure constraint + // const double pressure_constraint = + // (*node)->pressure_constraint(1, current_time); + // // Check if there is a pressure constraint + // if (pressure_constraint != std::numeric_limits::max()) { + // // Insert the pressure constraints + // pressure_constraints_.insert((*node)->active_id()) = + // pressure_constraint; + // } + // } + // status = true; + // } catch (std::exception& exception) { + // console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + // } + return status; +} diff --git a/include/matrix/cg_eigen.h b/include/matrix/cg_eigen.h new file mode 100644 index 000000000..44e66447d --- /dev/null +++ b/include/matrix/cg_eigen.h @@ -0,0 +1,57 @@ +#ifndef MPM_CG_EIGEN_H_ +#define MPM_CG_EIGEN_H_ + +#include + +#include "factory.h" +#include "solver_base.h" +#include +#include +#include +#include + +namespace mpm { + +//! MPM Eigen CG class +//! \brief Conjugate Gradient solver class using Eigen +template +class CGEigen : public SolverBase { + public: + //! Constructor + //! \param[in] max_iter Maximum number of iterations + + //! \param[in] tolerance Tolerance for solver to achieve convergence + CGEigen(unsigned max_iter, double tolerance) + : mpm::SolverBase(max_iter, tolerance) { + //! Logger + console_ = spdlog::stdout_color_mt("EigenSolver"); + }; + + //! Matrix solver with default initial guess + Eigen::VectorXd solve(const Eigen::SparseMatrix& A, + const Eigen::VectorXd& b, + std::string solver_type) override; + + //! Matrix solver with defined initial guess + Eigen::VectorXd solve(const Eigen::SparseMatrix& A, + const Eigen::VectorXd& b, std::string solver_type, + const Eigen::VectorXd& initial_guess) override; + + //! Return the type of solver + std::string solver_type() const { return "Eigen"; } + + protected: + //! Maximum number of iterations + using SolverBase::max_iter_; + //! Tolerance + using SolverBase::tolerance_; + //! Logger + using SolverBase::console_; + //! cg_type_ (leastSquaresConjugateGradient or ConjugateGradient) + std::string cg_type_; +}; +} // namespace mpm + +#include "cg_eigen.tcc" + +#endif // MPM_CG_EIGEN_H_ diff --git a/include/matrix/cg_eigen.tcc b/include/matrix/cg_eigen.tcc new file mode 100644 index 000000000..4ede0b9c0 --- /dev/null +++ b/include/matrix/cg_eigen.tcc @@ -0,0 +1,119 @@ +//! Conjugate Gradient Solver +template +Eigen::VectorXd mpm::CGEigen::solve(const Eigen::SparseMatrix& A, + const Eigen::VectorXd& b, + std::string solver_type) { + Eigen::VectorXd x; + try { + + if (solver_type == "cg") { + Eigen::ConjugateGradient> solver; + + solver.setMaxIterations(max_iter_); + solver.setTolerance(tolerance_); + solver.compute(A); + + x = solver.solve(b); + + if (solver.info() != Eigen::Success) { + throw std::runtime_error("Fail to solve intermediate acceleration\n"); + } + + } else if (solver_type == "lscg") { + + // Another option is LDLT, but not accurate as lscg + // Eigen::SimplicialLDLT> solver; + Eigen::LeastSquaresConjugateGradient> solver; + + solver.setMaxIterations(max_iter_); + solver.setTolerance(tolerance_); + solver.compute(A); + + x = solver.solve(b); + + if (solver.info() != Eigen::Success) { + throw std::runtime_error("Fail to solve intermediate acceleration\n"); + } + } + + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + } + return x; +} + +//! Conjugate Gradient Solver +template +Eigen::VectorXd mpm::CGEigen::solve( + const Eigen::SparseMatrix& A, const Eigen::VectorXd& b, + std::string solver_type, const Eigen::VectorXd& initial_guess) { + Eigen::VectorXd x; + try { + + if (solver_type == "cg") { + Eigen::ConjugateGradient> solver; + + solver.setMaxIterations(max_iter_); + solver.setTolerance(tolerance_); + solver.compute(A); + + x = solver.solveWithGuess(b, initial_guess); + + if (solver.info() != Eigen::Success) { + throw std::runtime_error("Fail to solve intermediate acceleration\n"); + } + + } else if (solver_type == "lscg") { + + Eigen::LeastSquaresConjugateGradient> solver; + + solver.setMaxIterations(max_iter_); + solver.setTolerance(tolerance_); + solver.compute(A); + x = solver.solveWithGuess(b, initial_guess); + + if (solver.info() != Eigen::Success) { + throw std::runtime_error("Fail to solve intermediate acceleration\n"); + } + } + + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + } + return x; +} + +/* +//! Precondition Jacobian +template +typename mpm::CGEigen::Eigen::VectorXd + mpm::CGEigen::precondition_jacobian() { + const size_t n = vec_b_->size(); + Eigen::VectorXd vm(n); + + vm.setZero(); + for (auto& mat_a : *mat_a_) { + for (size_t i = 0; i < n; ++i) { + vm[i] += mat_a.coeff(i, i); + } + } + for (size_t i = 0; i < n; ++i) { + vm[i] = 1 / vm[i]; + // When beta is zero, the stiffness matrix will have zero value elements + if (!std::isfinite(vm[i])) vm[i] = 1.0; + } + vm = vm.array() * vrestraints_.array(); + return vm; +} + +//! Cholesky solver +template +bool mpm::CGEigen::cholesky() { + SparseMatrix stiff; + for (auto& mat_a : *mat_a_) stiff += mat_a; + + Eigen::SimplicialCholesky cholesky(stiff); + *vec_x_ = cholesky.solve(*vec_b_); + return (cholesky.info() == Eigen::Success); +} +*/ diff --git a/include/matrix/solver_base.h b/include/matrix/solver_base.h new file mode 100644 index 000000000..33768781a --- /dev/null +++ b/include/matrix/solver_base.h @@ -0,0 +1,38 @@ +#ifndef MPM_SOLVER_BASE_H_ +#define MPM_SOLVER_BASE_H_ + +#include "spdlog/spdlog.h" +namespace mpm { +template +class SolverBase { + public: + //! Constructor with min and max iterations and tolerance + SolverBase(unsigned max_iter, double tolerance) { + //! Logger + max_iter_ = max_iter; + tolerance_ = tolerance; + console_ = spdlog::stdout_color_mt("SolverBase"); + }; + + //! Matrix solver with default initial guess + virtual Eigen::VectorXd solve(const Eigen::SparseMatrix& A, + const Eigen::VectorXd& b, + std::string solver_type) = 0; + + //! Matrix solver with defined initial guess + virtual Eigen::VectorXd solve(const Eigen::SparseMatrix& A, + const Eigen::VectorXd& b, + std::string solver_type, + const Eigen::VectorXd& initial_guess) = 0; + + protected: + //! Maximum number of iterations + unsigned max_iter_; + //! Tolerance + double tolerance_; + //! Logger + std::shared_ptr console_; +}; +} // namespace mpm + +#endif \ No newline at end of file diff --git a/src/matrix.cc b/src/matrix.cc new file mode 100644 index 000000000..bb90d55ea --- /dev/null +++ b/src/matrix.cc @@ -0,0 +1,23 @@ +#include "matrix/assembler_base.h" +#include "matrix/assembler_eigen_semi_implicit_navierstokes.h" + +#include "matrix/cg_eigen.h" +#include "matrix/solver_base.h" + +// Assembler collections +// Asssembler 2D +static Register, + mpm::AssemblerEigenSemiImplicitNavierStokes<2>> + AssemblerEigenSemiImplicitNavierStokes2d("EigenSemiImplicitNavierStokes2D"); +// Asssembler 3D +static Register, + mpm::AssemblerEigenSemiImplicitNavierStokes<3>> + AssemblerEigenSemiImplicitNavierStokes3d("EigenSemiImplicitNavierStokes3D"); + +// Linear Solver collections +// Solver 2D +static Register, mpm::CGEigen<2>, unsigned, double> + solvereigencg2d("EigenCG2D"); +// Solver 3D +static Register, mpm::CGEigen<3>, unsigned, double> + solvereigencg3d("EigenCG3D"); \ No newline at end of file From 2615f212aea4f3e77e9fc6c9d5b775f02c7432e6 Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 11 Mar 2020 00:08:58 -0700 Subject: [PATCH 06/72] add empty solver --- include/io/logger.h | 4 ++++ include/solvers/mpm_semi_implicit_navierstokes.h | 4 ++-- include/solvers/mpm_semi_implicit_navierstokes.tcc | 10 +++++----- src/io/logger.cc | 5 +++++ 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/include/io/logger.h b/include/io/logger.h index 082a0e874..1ecbce67f 100644 --- a/include/io/logger.h +++ b/include/io/logger.h @@ -41,6 +41,10 @@ struct Logger { // Create a logger for MPM Explicit USL static const std::shared_ptr mpm_explicit_usl_logger; + + // Create a logger for MPM Semi-implicit Navier Stokes + static const std::shared_ptr + mpm_semi_implicit_navier_stokes_logger; }; } // namespace mpm diff --git a/include/solvers/mpm_semi_implicit_navierstokes.h b/include/solvers/mpm_semi_implicit_navierstokes.h index 4c02b6d3e..65aef763d 100644 --- a/include/solvers/mpm_semi_implicit_navierstokes.h +++ b/include/solvers/mpm_semi_implicit_navierstokes.h @@ -5,7 +5,7 @@ #include "graph.h" #endif -#include "solvers/mpm_base.h" +#include "mpm_base.h" #include "matrix/assembler_base.h" #include "matrix/assembler_eigen_semi_implicit_navierstokes.h" @@ -33,7 +33,7 @@ class MPMSemiImplicitNavierStokes : public MPMBase { //! Pressure smoothing //! \param[in] phase Phase to smooth pressure - void pressure_smoothing(unsigned phase) override; + void pressure_smoothing(unsigned phase); //! Class private functions private: diff --git a/include/solvers/mpm_semi_implicit_navierstokes.tcc b/include/solvers/mpm_semi_implicit_navierstokes.tcc index 4b45bb94c..345c85577 100644 --- a/include/solvers/mpm_semi_implicit_navierstokes.tcc +++ b/include/solvers/mpm_semi_implicit_navierstokes.tcc @@ -12,11 +12,11 @@ template bool mpm::MPMSemiImplicitNavierStokes::solve() { bool status = true; - // console_->info("MPM analysis type {}", io_->analysis_type()); + console_->info("MPM analysis type {}", io_->analysis_type()); - // // Initialise MPI rank and size - // int mpi_rank = 0; - // int mpi_size = 1; + // Initialise MPI rank and size + int mpi_rank = 0; + int mpi_size = 1; // #ifdef USE_MPI // // Get MPI rank @@ -91,7 +91,7 @@ bool mpm::MPMSemiImplicitNavierStokes::solve() { // // Check point resume // if (resume) this->checkpoint_resume(); - // auto solver_begin = std::chrono::steady_clock::now(); + auto solver_begin = std::chrono::steady_clock::now(); // // Main loop // for (; step_ < nsteps_; ++step_) { // if (mpi_rank == 0) console_->info("Step: {} of {}.\n", step_, nsteps_); diff --git a/src/io/logger.cc b/src/io/logger.cc index 82e2b262c..26b18caeb 100644 --- a/src/io/logger.cc +++ b/src/io/logger.cc @@ -35,3 +35,8 @@ const std::shared_ptr mpm::Logger::mpm_explicit_usf_logger = // Create a logger for MPM Explicit USL const std::shared_ptr mpm::Logger::mpm_explicit_usl_logger = spdlog::stdout_color_st("MPMExplicitUSL"); + +// Create a logger for MPM Semi Implicit Two Phase +const std::shared_ptr + mpm::Logger::mpm_semi_implicit_navier_stokes_logger = + spdlog::stdout_color_st("MPMSemiImplicitNavierStokes"); \ No newline at end of file From 1618d477fad982a9fa9af685b6ebd192a90976da Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 11 Mar 2020 15:58:17 -0700 Subject: [PATCH 07/72] before loop begin --- include/particles/fluid_particle.h | 3 - include/particles/fluid_particle.tcc | 11 -- .../mpm_semi_implicit_navierstokes.tcc | 154 +++++++++--------- 3 files changed, 78 insertions(+), 90 deletions(-) diff --git a/include/particles/fluid_particle.h b/include/particles/fluid_particle.h index dde80e2b8..53119f53d 100644 --- a/include/particles/fluid_particle.h +++ b/include/particles/fluid_particle.h @@ -35,9 +35,6 @@ class FluidParticle : public mpm::Particle { //! Delete assignment operator FluidParticle& operator=(const FluidParticle&) = delete; - //! Compute both solid and liquid mass - void compute_mass() noexcept override; - //! Compute stress void compute_stress() noexcept override; diff --git a/include/particles/fluid_particle.tcc b/include/particles/fluid_particle.tcc index 06d476d23..0776f69da 100644 --- a/include/particles/fluid_particle.tcc +++ b/include/particles/fluid_particle.tcc @@ -19,17 +19,6 @@ mpm::FluidParticle::FluidParticle(Index id, const VectorDim& coord) console_ = std::make_unique(logger, mpm::stdout_sink); } -// Compute mass of fluid particle -template -void mpm::FluidParticle::compute_mass() noexcept { - // Check if particle volume is set and material ptr is valid - assert(volume_ != std::numeric_limits::max() && material_ != nullptr); - // Mass = volume of particle * mass_density - this->mass_density_ = - material_->template property(std::string("density")); - this->mass_ = volume_ * mass_density_; -} - // Compute stress template void mpm::FluidParticle::compute_stress() noexcept { diff --git a/include/solvers/mpm_semi_implicit_navierstokes.tcc b/include/solvers/mpm_semi_implicit_navierstokes.tcc index 345c85577..aa79ac6a5 100644 --- a/include/solvers/mpm_semi_implicit_navierstokes.tcc +++ b/include/solvers/mpm_semi_implicit_navierstokes.tcc @@ -18,78 +18,76 @@ bool mpm::MPMSemiImplicitNavierStokes::solve() { int mpi_rank = 0; int mpi_size = 1; - // #ifdef USE_MPI - // // Get MPI rank - // MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); - // // Get number of MPI ranks - // MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); - // #endif - - // // This solver consider only fluid variables - // // NOTE: Due to indexing purposes - // const unsigned fluid = mpm::ParticlePhase::SinglePhase; - - // // Test if checkpoint resume is needed - // bool resume = false; - // if (analysis_.find("resume") != analysis_.end()) - // resume = analysis_["resume"]["resume"].template get(); - - // // Pressure smoothing - // if (analysis_.find("pressure_smoothing") != analysis_.end()) - // pressure_smoothing_ = analysis_["pressure_smoothing"].template - // get(); - - // // Projection method parameter (beta) - // if (analysis_.find("semi_implicit") != analysis_.end()) - // beta_ = analysis_["semi_implicit"]["beta"].template get(); - - // // Initialise material - // bool mat_status = this->initialise_materials(); - // if (!mat_status) { - // status = false; - // throw std::runtime_error("Initialisation of materials failed"); - // } - - // // Initialise mesh - // bool mesh_status = this->initialise_mesh(); - // if (!mesh_status) { - // status = false; - // throw std::runtime_error("Initialisation of mesh failed"); - // } - - // // Initialise particles - // bool particle_status = this->initialise_particles(); - // if (!particle_status) { - // status = false; - // throw std::runtime_error("Initialisation of particles failed"); - // } - - // // Initialise loading conditions - // bool loading_status = this->initialise_loads(); - // if (!loading_status) { - // status = false; - // throw std::runtime_error("Initialisation of loads failed"); - // } - - // // Initialise matrix - // bool matrix_status = this->initialise_matrix(); - // if (!matrix_status) { - // status = false; - // throw std::runtime_error("Initialisation of matrix failed"); - // } - - // // Compute mass for each phase - // mesh_->iterate_over_particles( - // std::bind(&mpm::ParticleBase::compute_mass, - // std::placeholders::_1)); - - // // Assign beta to each particle - // mesh_->iterate_over_particles( - // std::bind(&mpm::ParticleBase::assign_semi_implicit_param, - // std::placeholders::_1, beta_)); - - // // Check point resume - // if (resume) this->checkpoint_resume(); +#ifdef USE_MPI + // Get MPI rank + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + // Get number of MPI ranks + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); +#endif + + // This solver consider only fluid variables + // NOTE: Due to indexing purposes + const unsigned fluid = mpm::ParticlePhase::SinglePhase; + + // Test if checkpoint resume is needed + bool resume = false; + if (analysis_.find("resume") != analysis_.end()) + resume = analysis_["resume"]["resume"].template get(); + + // Pressure smoothing + if (analysis_.find("pressure_smoothing") != analysis_.end()) + pressure_smoothing_ = analysis_["pressure_smoothing"].template get(); + + // Projection method parameter (beta) + if (analysis_.find("semi_implicit") != analysis_.end()) + beta_ = analysis_["semi_implicit"]["beta"].template get(); + + // Initialise material + bool mat_status = this->initialise_materials(); + if (!mat_status) { + status = false; + throw std::runtime_error("Initialisation of materials failed"); + } + + // Initialise mesh + bool mesh_status = this->initialise_mesh(); + if (!mesh_status) { + status = false; + throw std::runtime_error("Initialisation of mesh failed"); + } + + // Initialise particles + bool particle_status = this->initialise_particles(); + if (!particle_status) { + status = false; + throw std::runtime_error("Initialisation of particles failed"); + } + + // Initialise loading conditions + bool loading_status = this->initialise_loads(); + if (!loading_status) { + status = false; + throw std::runtime_error("Initialisation of loads failed"); + } + + // Initialise matrix + bool matrix_status = this->initialise_matrix(); + if (!matrix_status) { + status = false; + throw std::runtime_error("Initialisation of matrix failed"); + } + + // Compute mass for each phase + mesh_->iterate_over_particles( + std::bind(&mpm::ParticleBase::compute_mass, std::placeholders::_1)); + + // Assign beta to each particle + mesh_->iterate_over_particles( + std::bind(&mpm::ParticleBase::assign_projection_parameter, + std::placeholders::_1, beta_)); + + // Check point resume + if (resume) this->checkpoint_resume(); auto solver_begin = std::chrono::steady_clock::now(); // // Main loop @@ -269,7 +267,8 @@ bool mpm::MPMSemiImplicitNavierStokes::initialise_matrix() { // Factory>::instance()->create(assembler_type); // // Create matrix solver // matrix_solver_ = - // Factory, unsigned, double>::instance()->create( + // Factory, unsigned, + // double>::instance()->create( // solver_type, std::move(max_iter), std::move(tolerance)); // // Transfer the mesh pointer // matrix_assembler_->assign_mesh_pointer(mesh_); @@ -294,11 +293,13 @@ bool mpm::MPMSemiImplicitNavierStokes::reinitialise_matrix() { // // Assign pressure cpnstraints // matrix_assembler_->assign_pressure_constraints(this->beta_, - // this->step_ * this->dt_); + // this->step_ * + // this->dt_); // // Initialise element matrix // mesh_->iterate_over_cells(std::bind( - // &mpm::Cell::initialise_element_matrix, std::placeholders::_1)); + // &mpm::Cell::initialise_element_matrix, + // std::placeholders::_1)); // } catch (std::exception& exception) { // console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); @@ -378,7 +379,8 @@ bool mpm::MPMSemiImplicitNavierStokes::compute_corrected_force() { bool status = true; // try { // mesh_->iterate_over_particles(std::bind( - // &mpm::ParticleBase::map_K_cor_to_cell, std::placeholders::_1)); + // &mpm::ParticleBase::map_K_cor_to_cell, + // std::placeholders::_1)); // // Assemble corrected force matrix // matrix_assembler_->assemble_K_cor_matrix(mesh_, dt_); // // Assign corrected force From 63b2483cd6ed1b0e7cb7da7a437fa73afbc22b43 Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 11 Mar 2020 21:00:31 -0700 Subject: [PATCH 08/72] some nodal function updates --- include/node.h | 48 +++ include/node.tcc | 99 ++++++ include/node_base.h | 35 +++ .../mpm_semi_implicit_navierstokes.tcc | 291 +++++++++--------- 4 files changed, 330 insertions(+), 143 deletions(-) diff --git a/include/node.h b/include/node.h index 05cf4610c..a567e32ba 100644 --- a/include/node.h +++ b/include/node.h @@ -236,6 +236,42 @@ class Node : public NodeBase { //! Set ghost id void ghost_id(Index gid) override { ghost_id_ = gid; } + //! Compute navier-stokes semi-implicit acceleration and velocity + //! \param[in] phase Index corresponding to the phase + //! \param[in] dt Timestep in analysis + //! \retval status Computation status + bool compute_acceleration_velocity_navierstokes_semi_implicit( + unsigned phase, double dt) override; + + //! Update pore pressure increment at the node + void update_pressure_increment(const Eigen::VectorXd& pressure_increment, + unsigned phase, + double current_time = 0.) override; + + //! Return real density at a given node for a given phase + //! \param[in] phase Index corresponding to the phase + double density(unsigned phase) override { return density_(phase); } + + //! Compute nodal density + void compute_density() override; + + //! Compute nodal corrector force term + bool compute_nodal_corrected_force(VectorDim& force_cor_part_water) override; + + //! Assign free surface + void assign_free_surface(bool free_surface) override { + free_surface_ = free_surface; + } + + //! Return free surface bool + bool free_surface() override { return free_surface_; } + + //! Assign active id + void assign_active_id(Index id) override { active_id_ = id; } + + //! Return active id + mpm::Index active_id() override { return active_id_; } + private: //! Mutex std::mutex node_mutex_; @@ -267,6 +303,8 @@ class Node : public NodeBase { Eigen::Matrix acceleration_; //! Velocity constraints std::map velocity_constraints_; + //! Pressure constraint + std::map pressure_constraints_; //! Rotation matrix for general velocity constraints Eigen::Matrix rotation_matrix_; //! Material ids whose information was passed to this node @@ -285,6 +323,16 @@ class Node : public NodeBase { std::unique_ptr console_; //! MPI ranks std::set mpi_ranks_; + //! Global index for active node + Index active_id_{std::numeric_limits::max()}; + //! Interpolated density + Eigen::Matrix density_; + //! p^(t+1) - beta * p^(t) + double pressure_increment_; + //! Correction force + Eigen::Matrix force_cor_; + //! Free surface + bool free_surface_{false}; }; // Node class } // namespace mpm diff --git a/include/node.tcc b/include/node.tcc index 8f2764e54..45ee2d7ed 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -31,6 +31,9 @@ void mpm::Node::initialise() noexcept { velocity_.setZero(); momentum_.setZero(); acceleration_.setZero(); + free_surface_ = false; + pressure_increment_ = 0.; + force_cor_.setZero(); status_ = false; material_ids_.clear(); } @@ -518,3 +521,99 @@ bool mpm::Node::mpi_rank(unsigned rank) { auto status = this->mpi_ranks_.insert(rank); return status.second; } + +//! Compute mass density (Z. Wiezckowski, 2004) +//! density = mass / lumped volume +template +void mpm::Node::compute_density() { + try { + const double tolerance = 1.E-16; // std::numeric_limits::lowest(); + + for (unsigned phase = 0; phase < Tnphases; ++phase) { + if (mass_(phase) > tolerance) { + if (volume_(phase) > tolerance) + density_(phase) = mass_(phase) / volume_(phase); + + // Check to see if value is below threshold + if (std::abs(density_(phase)) < 1.E-15) density_(phase) = 0.; + + } else + throw std::runtime_error("Nodal mass is zero or below threshold"); + } + + // Apply velocity constraints, which also sets acceleration to 0, + // when velocity is set. + this->apply_velocity_constraints(); + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + } +} + +//! Compute nodal corrected force +template +bool mpm::Node::compute_nodal_corrected_force( + VectorDim& force_cor_part_water) { + bool status = true; + + try { + // Compute corrected force for water phase + force_cor_.col(0) = force_cor_part_water; + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} +//! Update pore pressure increment at the node +template +void mpm::Node::update_pressure_increment( + const Eigen::VectorXd& pressure_increment, unsigned phase, + double current_time) { + this->pressure_increment_ = pressure_increment(active_id_); + + // If pressure boundary, increment is zero + if (pressure_constraints_.find(phase) != pressure_constraints_.end() || + this->free_surface()) + this->pressure_increment_ = 0; +} + +//! Compute semi-implicit acceleration and velocity +template +bool mpm::Node:: + compute_acceleration_velocity_navierstokes_semi_implicit(unsigned phase, + double dt) { + bool status = true; + const double tolerance = std::numeric_limits::min(); + try { + + // Semi-implicit solver + Eigen::Matrix acceleration_corrected = + force_cor_.col(phase) / mass_(phase); + + // Acceleration + this->acceleration_.col(phase) += acceleration_corrected; + + // Update velocity + velocity_.col(phase) += acceleration_corrected * dt; + + // Apply friction constraints + this->apply_friction_constraints(dt); + + // Apply velocity constraints, which also sets acceleration to 0, + // when velocity is set. + this->apply_velocity_constraints(); + + // Set a threshold + for (unsigned i = 0; i < Tdim; ++i) { + if (std::abs(velocity_.col(phase)(i)) < tolerance) + velocity_.col(phase)(i) = 0.; + if (std::abs(acceleration_.col(phase)(i)) < tolerance) + acceleration_.col(phase)(i) = 0.; + } + + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} \ No newline at end of file diff --git a/include/node_base.h b/include/node_base.h index 5658201bf..b7921cac3 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -226,6 +226,41 @@ class NodeBase { //! Set ghost id virtual void ghost_id(Index gid) = 0; + //! Compute navier-stokes semi-implicit acceleration and velocity + //! \param[in] phase Index corresponding to the phase + //! \param[in] dt Timestep in analysis + //! \retval status Computation status + virtual bool compute_acceleration_velocity_navierstokes_semi_implicit( + unsigned phase, double dt) = 0; + + //! Update pore pressure increment at the node + virtual void update_pressure_increment( + const Eigen::VectorXd& pressure_increment, unsigned phase, + double current_time = 0.) = 0; + + //! Return real density at a given node for a given phase + //! \param[in] phase Index corresponding to the phase + virtual double density(unsigned phase) = 0; + + //! Compute nodal density + virtual void compute_density() = 0; + + //! Compute nodal corrector force term + virtual bool compute_nodal_corrected_force( + VectorDim& force_cor_part_water) = 0; + + //! Assign free surface + virtual void assign_free_surface(bool free_surface) = 0; + + //! Return free surface bool + virtual bool free_surface() = 0; + + //! Assign active id + virtual void assign_active_id(Index id) = 0; + + //! Return active id + virtual mpm::Index active_id() = 0; + }; // NodeBase class } // namespace mpm diff --git a/include/solvers/mpm_semi_implicit_navierstokes.tcc b/include/solvers/mpm_semi_implicit_navierstokes.tcc index aa79ac6a5..610860f41 100644 --- a/include/solvers/mpm_semi_implicit_navierstokes.tcc +++ b/include/solvers/mpm_semi_implicit_navierstokes.tcc @@ -90,146 +90,150 @@ bool mpm::MPMSemiImplicitNavierStokes::solve() { if (resume) this->checkpoint_resume(); auto solver_begin = std::chrono::steady_clock::now(); - // // Main loop - // for (; step_ < nsteps_; ++step_) { - // if (mpi_rank == 0) console_->info("Step: {} of {}.\n", step_, nsteps_); - - // // Create a TBB task group - // tbb::task_group task_group; - - // // Spawn a task for initialising nodes and cells - // task_group.run([&] { - // // Initialise nodes - // mesh_->iterate_over_nodes( - // std::bind(&mpm::NodeBase::initialise, - // std::placeholders::_1)); - - // mesh_->iterate_over_cells( - // std::bind(&mpm::Cell::activate_nodes, - // std::placeholders::_1)); - // }); - // task_group.wait(); - - // // Spawn a task for particles - // task_group.run([&] { - // // Iterate over each particle to compute shapefn - // mesh_->iterate_over_particles(std::bind( - // &mpm::ParticleBase::compute_shapefn, - // std::placeholders::_1)); - // }); - - // task_group.wait(); - - // // Assign mass and momentum to nodes - // // Solid skeleton - // mesh_->iterate_over_particles( - // std::bind(&mpm::ParticleBase::map_mass_momentum_to_nodes, - // std::placeholders::_1)); - - // // Compute nodal velocity at the begining of time step - // mesh_->iterate_over_nodes_predicate( - // std::bind(&mpm::NodeBase::compute_velocity, - // std::placeholders::_1), - // std::bind(&mpm::NodeBase::status, std::placeholders::_1)); - - // // Iterate over each particle to compute strain rate - // mesh_->iterate_over_particles(std::bind( - // &mpm::ParticleBase::compute_strain, std::placeholders::_1, - // dt_)); - - // // Iterate over each particle to compute shear (deviatoric) stress - // mesh_->iterate_over_particles(std::bind( - // &mpm::ParticleBase::compute_stress, std::placeholders::_1)); - - // // Spawn a task for external force - // task_group.run([&] { - // // Iterate over particles to compute nodal body force - // mesh_->iterate_over_particles( - // std::bind(&mpm::ParticleBase::map_body_force, - // std::placeholders::_1, this->gravity_)); - - // // Apply particle traction and map to nodes - // mesh_->apply_traction_on_particles(this->step_ * this->dt_); - // }); - - // // Spawn a task for internal force - // task_group.run([&] { - // // Iterate over particles to compute nodal internal force - // mesh_->iterate_over_particles(std::bind( - // &mpm::ParticleBase::map_internal_force, - // std::placeholders::_1)); - // }); - // task_group.wait(); - - // // Compute free surface cells, nodes, and particles - // mesh_->compute_free_surface(volume_tolerance_); - - // // Compute intermediate velocity - // mesh_->iterate_over_nodes_predicate( - // std::bind(&mpm::NodeBase::compute_acceleration_velocity, - // std::placeholders::_1, fluid, this->dt_), - // std::bind(&mpm::NodeBase::status, std::placeholders::_1)); - - // // Reinitialise system matrix to perform PPE - // bool matrix_reinitialization_status = this->reinitialise_matrix(); - // if (!matrix_reinitialization_status) { - // status = false; - // throw std::runtime_error("Reinitialisation of matrix failed"); - // } - - // // Compute poisson equation - // this->compute_poisson_equation(); - - // // Assign pore pressure to nodes - // mesh_->iterate_over_nodes_predicate( - // std::bind(&mpm::NodeBase::update_pressure_increment, - // std::placeholders::_1, - // matrix_assembler_->pressure_increment(), fluid, - // this->step_ * this->dt_), - // std::bind(&mpm::NodeBase::status, std::placeholders::_1)); - - // // Use nodal pressure to update particle pressure - // mesh_->iterate_over_particles( - // std::bind(&mpm::ParticleBase::compute_updated_pressure, - // std::placeholders::_1)); - - // // Compute corrected force - // this->compute_corrected_force(); - - // // Compute corrected acceleration and velocity - // mesh_->iterate_over_nodes_predicate( - // std::bind( - // &mpm::NodeBase< - // Tdim>::compute_acceleration_velocity_navierstokes_semi_implicit, - // std::placeholders::_1, fluid, this->dt_), - // std::bind(&mpm::NodeBase::status, std::placeholders::_1)); - - // // Update particle position and kinematics - // mesh_->iterate_over_particles( - // std::bind(&mpm::ParticleBase::compute_updated_position, - // std::placeholders::_1, this->dt_, velocity_update_)); - - // // Apply particle velocity constraints - // mesh_->apply_particle_velocity_constraints(); - - // // Pressure smoothing - // if (pressure_smoothing_) this->pressure_smoothing(fluid); - - // // Locate particles - // auto unlocatable_particles = mesh_->locate_particles_mesh(); - - // if (!unlocatable_particles.empty()) - // throw std::runtime_error("Particle outside the mesh domain"); - - // if (step_ % output_steps_ == 0) { - // // HDF5 outputs - // this->write_hdf5(this->step_, this->nsteps_); - // #ifdef USE_VTK - // // VTK outputs - // this->write_vtk(this->step_, this->nsteps_); - // #endif - // } - // } + // Main loop + for (; step_ < nsteps_; ++step_) { + if (mpi_rank == 0) console_->info("Step: {} of {}.\n", step_, nsteps_); + + // Create a TBB task group + tbb::task_group task_group; + + // Spawn a task for initialising nodes and cells + task_group.run([&] { + // Initialise nodes + mesh_->iterate_over_nodes( + std::bind(&mpm::NodeBase::initialise, std::placeholders::_1)); + + // mesh_->iterate_over_cells( + // std::bind(&mpm::Cell::activate_nodes, + // std::placeholders::_1)); + // }); + // task_group.wait(); + + // // Spawn a task for particles + // task_group.run([&] { + // // Iterate over each particle to compute shapefn + // mesh_->iterate_over_particles(std::bind( + // &mpm::ParticleBase::compute_shapefn, + // std::placeholders::_1)); + }); + + // task_group.wait(); + + // // Assign mass and momentum to nodes + // // Solid skeleton + // mesh_->iterate_over_particles( + // std::bind(&mpm::ParticleBase::map_mass_momentum_to_nodes, + // std::placeholders::_1)); + + // // Compute nodal velocity at the begining of time step + // mesh_->iterate_over_nodes_predicate( + // std::bind(&mpm::NodeBase::compute_velocity, + // std::placeholders::_1), + // std::bind(&mpm::NodeBase::status, + // std::placeholders::_1)); + + // // Iterate over each particle to compute strain rate + // mesh_->iterate_over_particles(std::bind( + // &mpm::ParticleBase::compute_strain, + // std::placeholders::_1, dt_)); + + // // Iterate over each particle to compute shear (deviatoric) stress + // mesh_->iterate_over_particles(std::bind( + // &mpm::ParticleBase::compute_stress, + // std::placeholders::_1)); + + // // Spawn a task for external force + // task_group.run([&] { + // // Iterate over particles to compute nodal body force + // mesh_->iterate_over_particles( + // std::bind(&mpm::ParticleBase::map_body_force, + // std::placeholders::_1, this->gravity_)); + + // // Apply particle traction and map to nodes + // mesh_->apply_traction_on_particles(this->step_ * this->dt_); + // }); + + // // Spawn a task for internal force + // task_group.run([&] { + // // Iterate over particles to compute nodal internal force + // mesh_->iterate_over_particles(std::bind( + // &mpm::ParticleBase::map_internal_force, + // std::placeholders::_1)); + // }); + // task_group.wait(); + + // // Compute free surface cells, nodes, and particles + // mesh_->compute_free_surface(volume_tolerance_); + + // // Compute intermediate velocity + // mesh_->iterate_over_nodes_predicate( + // std::bind(&mpm::NodeBase::compute_acceleration_velocity, + // std::placeholders::_1, fluid, this->dt_), + // std::bind(&mpm::NodeBase::status, + // std::placeholders::_1)); + + // // Reinitialise system matrix to perform PPE + // bool matrix_reinitialization_status = this->reinitialise_matrix(); + // if (!matrix_reinitialization_status) { + // status = false; + // throw std::runtime_error("Reinitialisation of matrix failed"); + // } + + // // Compute poisson equation + // this->compute_poisson_equation(); + + // // Assign pore pressure to nodes + // mesh_->iterate_over_nodes_predicate( + // std::bind(&mpm::NodeBase::update_pressure_increment, + // std::placeholders::_1, + // matrix_assembler_->pressure_increment(), fluid, + // this->step_ * this->dt_), + // std::bind(&mpm::NodeBase::status, + // std::placeholders::_1)); + + // // Use nodal pressure to update particle pressure + // mesh_->iterate_over_particles( + // std::bind(&mpm::ParticleBase::compute_updated_pressure, + // std::placeholders::_1)); + + // // Compute corrected force + // this->compute_corrected_force(); + + // // Compute corrected acceleration and velocity + // mesh_->iterate_over_nodes_predicate( + // std::bind( + // &mpm::NodeBase< + // Tdim>::compute_acceleration_velocity_navierstokes_semi_implicit, + // std::placeholders::_1, fluid, this->dt_), + // std::bind(&mpm::NodeBase::status, + // std::placeholders::_1)); + + // // Update particle position and kinematics + // mesh_->iterate_over_particles( + // std::bind(&mpm::ParticleBase::compute_updated_position, + // std::placeholders::_1, this->dt_, velocity_update_)); + + // // Apply particle velocity constraints + // mesh_->apply_particle_velocity_constraints(); + + // // Pressure smoothing + // if (pressure_smoothing_) this->pressure_smoothing(fluid); + + // // Locate particles + // auto unlocatable_particles = mesh_->locate_particles_mesh(); + + // if (!unlocatable_particles.empty()) + // throw std::runtime_error("Particle outside the mesh domain"); + + // if (step_ % output_steps_ == 0) { + // // HDF5 outputs + // this->write_hdf5(this->step_, this->nsteps_); + // #ifdef USE_VTK + // // VTK outputs + // this->write_vtk(this->step_, this->nsteps_); + // #endif + // } + } auto solver_end = std::chrono::steady_clock::now(); console_->info("Rank {}, SemiImplicit_NavierStokes {} solver duration: {} ms", mpi_rank, @@ -254,7 +258,8 @@ bool mpm::MPMSemiImplicitNavierStokes::initialise_matrix() { // get(); // // Get matrix assembler type // std::string assembler_type = - // analysis_["matrix"]["assembler_type"].template get(); + // analysis_["matrix"]["assembler_type"].template + // get(); // // Get matrix solver type // std::string solver_type = // analysis_["matrix"]["solver_type"].template get(); @@ -274,8 +279,8 @@ bool mpm::MPMSemiImplicitNavierStokes::initialise_matrix() { // matrix_assembler_->assign_mesh_pointer(mesh_); // } catch (std::exception& exception) { - // console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - // status = false; + // console_->error("{} #{}: {}\n", __FILE__, __LINE__, + // exception.what()); status = false; // } return status; } From 47eec5a3841a546ff1771e44ee432efbda60a500 Mon Sep 17 00:00:00 2001 From: Nanda Date: Thu, 12 Mar 2020 00:41:20 -0700 Subject: [PATCH 09/72] add function until prediction --- .../mpm_semi_implicit_navierstokes.tcc | 124 ++++++++---------- 1 file changed, 57 insertions(+), 67 deletions(-) diff --git a/include/solvers/mpm_semi_implicit_navierstokes.tcc b/include/solvers/mpm_semi_implicit_navierstokes.tcc index 610860f41..e4efed2e8 100644 --- a/include/solvers/mpm_semi_implicit_navierstokes.tcc +++ b/include/solvers/mpm_semi_implicit_navierstokes.tcc @@ -103,74 +103,66 @@ bool mpm::MPMSemiImplicitNavierStokes::solve() { mesh_->iterate_over_nodes( std::bind(&mpm::NodeBase::initialise, std::placeholders::_1)); - // mesh_->iterate_over_cells( - // std::bind(&mpm::Cell::activate_nodes, - // std::placeholders::_1)); - // }); - // task_group.wait(); - - // // Spawn a task for particles - // task_group.run([&] { - // // Iterate over each particle to compute shapefn - // mesh_->iterate_over_particles(std::bind( - // &mpm::ParticleBase::compute_shapefn, - // std::placeholders::_1)); + mesh_->iterate_over_cells( + std::bind(&mpm::Cell::activate_nodes, std::placeholders::_1)); }); + task_group.wait(); - // task_group.wait(); + // Spawn a task for particles + task_group.run([&] { + // Iterate over each particle to compute shapefn + mesh_->iterate_over_particles(std::bind( + &mpm::ParticleBase::compute_shapefn, std::placeholders::_1)); + }); - // // Assign mass and momentum to nodes - // // Solid skeleton - // mesh_->iterate_over_particles( - // std::bind(&mpm::ParticleBase::map_mass_momentum_to_nodes, - // std::placeholders::_1)); + task_group.wait(); - // // Compute nodal velocity at the begining of time step - // mesh_->iterate_over_nodes_predicate( - // std::bind(&mpm::NodeBase::compute_velocity, - // std::placeholders::_1), - // std::bind(&mpm::NodeBase::status, - // std::placeholders::_1)); + // Assign mass and momentum to nodes + mesh_->iterate_over_particles( + std::bind(&mpm::ParticleBase::map_mass_momentum_to_nodes, + std::placeholders::_1)); - // // Iterate over each particle to compute strain rate - // mesh_->iterate_over_particles(std::bind( - // &mpm::ParticleBase::compute_strain, - // std::placeholders::_1, dt_)); + // Compute nodal velocity at the begining of time step + mesh_->iterate_over_nodes_predicate( + std::bind(&mpm::NodeBase::compute_velocity, + std::placeholders::_1), + std::bind(&mpm::NodeBase::status, std::placeholders::_1)); - // // Iterate over each particle to compute shear (deviatoric) stress - // mesh_->iterate_over_particles(std::bind( - // &mpm::ParticleBase::compute_stress, - // std::placeholders::_1)); + // Iterate over each particle to compute strain rate + mesh_->iterate_over_particles(std::bind( + &mpm::ParticleBase::compute_strain, std::placeholders::_1, dt_)); - // // Spawn a task for external force - // task_group.run([&] { - // // Iterate over particles to compute nodal body force - // mesh_->iterate_over_particles( - // std::bind(&mpm::ParticleBase::map_body_force, - // std::placeholders::_1, this->gravity_)); - - // // Apply particle traction and map to nodes - // mesh_->apply_traction_on_particles(this->step_ * this->dt_); - // }); - - // // Spawn a task for internal force - // task_group.run([&] { - // // Iterate over particles to compute nodal internal force - // mesh_->iterate_over_particles(std::bind( - // &mpm::ParticleBase::map_internal_force, - // std::placeholders::_1)); - // }); - // task_group.wait(); - - // // Compute free surface cells, nodes, and particles - // mesh_->compute_free_surface(volume_tolerance_); - - // // Compute intermediate velocity - // mesh_->iterate_over_nodes_predicate( - // std::bind(&mpm::NodeBase::compute_acceleration_velocity, - // std::placeholders::_1, fluid, this->dt_), - // std::bind(&mpm::NodeBase::status, - // std::placeholders::_1)); + // Iterate over each particle to compute shear (deviatoric) stress + mesh_->iterate_over_particles(std::bind( + &mpm::ParticleBase::compute_stress, std::placeholders::_1)); + + // Spawn a task for external force + task_group.run([&] { + // Iterate over particles to compute nodal body force + mesh_->iterate_over_particles( + std::bind(&mpm::ParticleBase::map_body_force, + std::placeholders::_1, this->gravity_)); + + // Apply particle traction and map to nodes + mesh_->apply_traction_on_particles(this->step_ * this->dt_); + }); + + // Spawn a task for internal force + task_group.run([&] { + // Iterate over particles to compute nodal internal force + mesh_->iterate_over_particles(std::bind( + &mpm::ParticleBase::map_internal_force, std::placeholders::_1)); + }); + task_group.wait(); + + // // Compute free surface cells, nodes, and particles + // mesh_->compute_free_surface(volume_tolerance_); + + // Compute intermediate velocity + mesh_->iterate_over_nodes_predicate( + std::bind(&mpm::NodeBase::compute_acceleration_velocity, + std::placeholders::_1, fluid, this->dt_), + std::bind(&mpm::NodeBase::status, std::placeholders::_1)); // // Reinitialise system matrix to perform PPE // bool matrix_reinitialization_status = this->reinitialise_matrix(); @@ -258,8 +250,7 @@ bool mpm::MPMSemiImplicitNavierStokes::initialise_matrix() { // get(); // // Get matrix assembler type // std::string assembler_type = - // analysis_["matrix"]["assembler_type"].template - // get(); + // analysis_["matrix"]["assembler_type"].template get(); // // Get matrix solver type // std::string solver_type = // analysis_["matrix"]["solver_type"].template get(); @@ -272,15 +263,14 @@ bool mpm::MPMSemiImplicitNavierStokes::initialise_matrix() { // Factory>::instance()->create(assembler_type); // // Create matrix solver // matrix_solver_ = - // Factory, unsigned, - // double>::instance()->create( + // Factory, unsigned, double>::instance()->create( // solver_type, std::move(max_iter), std::move(tolerance)); // // Transfer the mesh pointer // matrix_assembler_->assign_mesh_pointer(mesh_); // } catch (std::exception& exception) { - // console_->error("{} #{}: {}\n", __FILE__, __LINE__, - // exception.what()); status = false; + // console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + // status = false; // } return status; } From 55b887bb2997357c82b4ead2ab6106689197f8f4 Mon Sep 17 00:00:00 2001 From: Nanda Date: Thu, 12 Mar 2020 15:32:26 -0700 Subject: [PATCH 10/72] add free surface particle computation --- include/cell.h | 26 +++ include/cell.tcc | 22 ++- include/mesh.h | 19 +++ include/mesh.tcc | 161 ++++++++++++++++++ include/particles/particle.tcc | 22 +-- .../mpm_semi_implicit_navierstokes.tcc | 4 +- src/particle.cc | 2 +- 7 files changed, 242 insertions(+), 14 deletions(-) diff --git a/include/cell.h b/include/cell.h index 6b0c1cf7b..ff596cd63 100644 --- a/include/cell.h +++ b/include/cell.h @@ -204,6 +204,28 @@ class Cell { //! Return rank unsigned rank() const; + //! Assign free surface + //! \param[in] free_surface boolean indicating free surface cell + void assign_free_surface(bool free_surface) { free_surface_ = free_surface; }; + + //! Return free surface bool + //! \retval free_surface_ indicating free surface cell + bool free_surface() { return free_surface_; }; + + //! Assign volume traction to node + //! \param[in] volume_fraction cell volume fraction + void assign_volume_fraction(double volume_fraction) { + volume_fraction_ = volume_fraction; + }; + + //! Return cell volume fraction + //! \retval volume_fraction_ cell volume fraction + double volume_fraction() { return volume_fraction_; }; + + //! Map cell volume to the nodes + //! \retval phase to map volume + bool map_cell_volume_to_nodes(unsigned phase); + private: //! Approximately check if a point is in a cell //! \param[in] point Coordinates of point @@ -247,6 +269,10 @@ class Cell { //! Normal of face //! first-> face_id, second->vector of the normal std::map face_normals_; + //! Free surface bool + bool free_surface_{false}; + //! Volume fraction + double volume_fraction_{0.0}; //! Logger std::unique_ptr console_; }; // Cell class diff --git a/include/cell.tcc b/include/cell.tcc index 952c94426..68bce00f7 100644 --- a/include/cell.tcc +++ b/include/cell.tcc @@ -399,7 +399,7 @@ inline Eigen::Matrix mpm::Cell<2>::local_coordinates_point( if (indices.size() == 3) { // 2 0 // |\ - // | \ + // | \ // c | \ b // | \ // | \ @@ -821,3 +821,23 @@ template inline unsigned mpm::Cell::rank() const { return this->rank_; } + +//! Map cell volume to nodes +template +bool mpm::Cell::map_cell_volume_to_nodes(unsigned phase) { + bool status = true; + try { + // Check if cell volume is set + if (volume_ == std::numeric_limits::lowest()) + this->compute_volume(); + + for (unsigned i = 0; i < nodes_.size(); ++i) { + nodes_[i]->update_volume(true, phase, volume_ / nnodes_); + } + + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} diff --git a/include/mesh.h b/include/mesh.h index 9520d81e5..30a4ceeaa 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -432,6 +432,25 @@ class Mesh { //! Inject particles void inject_particles(double current_time); + //! Compute free surface + bool compute_free_surface( + double tolerance = std::numeric_limits::epsilon()); + + //! Get free surface node set + std::set free_surface_nodes(); + + //! Get free surface cell set + std::set free_surface_cells(); + + //! Get free surface particle set + std::set free_surface_particles(); + + //! Assign id for active node + unsigned assign_active_node_id(); + + //! Return container of active nodes + mpm::Vector> active_nodes() { return active_nodes_; } + private: // Read particles from file bool read_particles_file(const std::shared_ptr& io, diff --git a/include/mesh.tcc b/include/mesh.tcc index 294bde4ab..36ecbbd44 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1795,3 +1795,164 @@ bool mpm::Mesh::assign_nodal_friction_constraints( } return status; } + +//! Compute free surface cells, nodes, and particles +template +bool mpm::Mesh::compute_free_surface(double tolerance) { + bool status = true; + try { + // Reset free surface cell + this->iterate_over_cells(std::bind(&mpm::Cell::assign_free_surface, + std::placeholders::_1, false)); + + // Reset volume fraction + this->iterate_over_cells(std::bind(&mpm::Cell::assign_volume_fraction, + std::placeholders::_1, 0.0)); + + // Compute and assign volume fraction to each cell + for (auto citr = this->cells_.cbegin(); citr != this->cells_.cend(); + ++citr) { + if ((*citr)->status()) { + // Compute volume fraction + double cell_volume_fraction = 0.0; + for (const auto p_id : (*citr)->particles()) + cell_volume_fraction += map_particles_[p_id]->volume(); + + cell_volume_fraction = cell_volume_fraction / (*citr)->volume(); + (*citr)->assign_volume_fraction(cell_volume_fraction); + } + } + + // Compute boundary cells and nodes based on geometry + std::set boundary_cells; + std::set boundary_nodes; + for (auto citr = this->cells_.cbegin(); citr != this->cells_.cend(); + ++citr) { + + if ((*citr)->status()) { + bool cell_at_interface = false; + const auto& node_id = (*citr)->nodes_id(); + bool internal = true; + + //! Check internal cell + for (const auto c_id : (*citr)->neighbours()) { + if (!map_cells_[c_id]->status()) { + internal = false; + break; + } + } + + //! Check volume fraction only for boundary cell + if (!internal) { + if ((*citr)->volume_fraction() < tolerance) { + cell_at_interface = true; + for (const auto id : node_id) { + map_nodes_[id]->assign_free_surface(cell_at_interface); + boundary_nodes.insert(id); + } + } else { + for (const auto n_id : (*citr)->neighbours()) { + if (map_cells_[n_id]->volume_fraction() < tolerance) { + cell_at_interface = true; + const auto& n_node_id = map_cells_[n_id]->nodes_id(); + + // Detect common node id + std::set common_node_id; + std::set_intersection( + node_id.begin(), node_id.end(), n_node_id.begin(), + n_node_id.end(), + std::inserter(common_node_id, common_node_id.begin())); + + // Assign free surface nodes + if (!common_node_id.empty()) { + for (const auto common_id : common_node_id) { + map_nodes_[common_id]->assign_free_surface( + cell_at_interface); + boundary_nodes.insert(common_id); + } + } + } + } + } + + // Assign free surface cell + if (cell_at_interface) { + (*citr)->assign_free_surface(cell_at_interface); + boundary_cells.insert((*citr)->id()); + } + } + } + } + + // Compute boundary particles based on density function + // Lump cell volume to nodes + this->iterate_over_cells(std::bind( + &mpm::Cell::map_cell_volume_to_nodes, std::placeholders::_1, 0)); + + // Compute nodal value of mass density + this->iterate_over_nodes_predicate( + std::bind(&mpm::NodeBase::compute_density, std::placeholders::_1), + std::bind(&mpm::NodeBase::status, std::placeholders::_1)); + + // Evaluate free surface particles + this->iterate_over_particles(std::bind( + &mpm::ParticleBase::compute_free_surface, std::placeholders::_1)); + + // Assign pressure at free surface to be zero + std::set boundary_particles = this->free_surface_particles(); + for (const auto boundary_particle : boundary_particles) + map_particles_[boundary_particle]->initial_pressure(0.0); + + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + } + return status; +} + +//! Get free surface node set +template +std::set mpm::Mesh::free_surface_nodes() { + std::set id_set; + for (auto nitr = this->nodes_.cbegin(); nitr != this->nodes_.cend(); ++nitr) + if ((*nitr)->free_surface()) id_set.insert((*nitr)->id()); + return id_set; +} + +//! Get free surface cell set +template +std::set mpm::Mesh::free_surface_cells() { + std::set id_set; + for (auto citr = this->cells_.cbegin(); citr != this->cells_.cend(); ++citr) + if ((*citr)->free_surface()) id_set.insert((*citr)->id()); + return id_set; +} + +//! Get free surface particle set +template +std::set mpm::Mesh::free_surface_particles() { + std::set id_set; + for (auto pitr = this->particles_.cbegin(); pitr != this->particles_.cend(); + ++pitr) + if ((*pitr)->free_surface()) id_set.insert((*pitr)->id()); + return id_set; +} + +//! Create a list of active nodes in mesh and assign active node id +template +unsigned mpm::Mesh::assign_active_node_id() { + // Clear existing list of active nodes + this->active_nodes_.clear(); + Index active_id = 0; + + for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { + if ((*nitr)->status()) { + this->active_nodes_.add(*nitr); + (*nitr)->assign_active_id(active_id); + active_id++; + } else { + (*nitr)->assign_active_id(std::numeric_limits::max()); + } + } + + return active_id; +} \ No newline at end of file diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index 8262a281f..cf71cf712 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -763,6 +763,10 @@ bool mpm::Particle::compute_pressure_smoothing() noexcept { pressure += shapefn_[i] * nodes_[i]->pressure(mpm::ParticlePhase::Solid); state_variables_.at("pressure") = pressure; + + // If free_surface particle, overwrite pressure to zero + if (free_surface_) state_variables_.at("pressure") = 0.0; + status = true; } return status; @@ -797,18 +801,16 @@ bool mpm::Particle::compute_free_surface() { this->free_surface_ = false; // Check if particle has a valid cell ptr if (cell_ != nullptr) { - // TODO: Tobe uncomment when free surface is implemented // 1. Simple approach of density comparison (Hamad, 2015) // Get interpolated nodal density - // double nodal_mass_density = 0; - - // for (unsigned i = 0; i < nodes_.size(); ++i) - // nodal_mass_density += - // shapefn_[i] * nodes_[i]->density(mpm::ParticlePhase::Solid); - - // // Compare smoothen density to actual particle mass density - // if ((nodal_mass_density / mass_density_) <= 0.65) - // if (cell_->free_surface()) this->free_surface_ = true; + double nodal_mass_density = 0; + for (unsigned i = 0; i < nodes_.size(); ++i) + nodal_mass_density += + shapefn_[i] * nodes_[i]->density(mpm::ParticlePhase::Solid); + + // Compare smoothen density to actual particle mass density + if ((nodal_mass_density / mass_density_) <= 0.65) + if (cell_->free_surface()) this->free_surface_ = true; } } catch (std::exception& exception) { diff --git a/include/solvers/mpm_semi_implicit_navierstokes.tcc b/include/solvers/mpm_semi_implicit_navierstokes.tcc index e4efed2e8..4ea48f40a 100644 --- a/include/solvers/mpm_semi_implicit_navierstokes.tcc +++ b/include/solvers/mpm_semi_implicit_navierstokes.tcc @@ -155,8 +155,8 @@ bool mpm::MPMSemiImplicitNavierStokes::solve() { }); task_group.wait(); - // // Compute free surface cells, nodes, and particles - // mesh_->compute_free_surface(volume_tolerance_); + // Compute free surface cells, nodes, and particles + mesh_->compute_free_surface(volume_tolerance_); // Compute intermediate velocity mesh_->iterate_over_nodes_predicate( diff --git a/src/particle.cc b/src/particle.cc index a90ef31de..3ae854cb5 100644 --- a/src/particle.cc +++ b/src/particle.cc @@ -1,7 +1,7 @@ #include "particle.h" #include "factory.h" -#include "particle_base.h" #include "fluid_particle.h" +#include "particle_base.h" // Particle2D (2 Dim) static Register, mpm::Particle<2>, mpm::Index, From 161d8f44751c51080137f38b213236729a06df80 Mon Sep 17 00:00:00 2001 From: Nanda Date: Thu, 12 Mar 2020 15:59:19 -0700 Subject: [PATCH 11/72] change matrix to linear solvers --- CMakeLists.txt | 3 ++- include/{matrix => linear_solvers}/assembler_base.h | 0 .../assembler_eigen_semi_implicit_navierstokes.h | 0 .../assembler_eigen_semi_implicit_navierstokes.tcc | 0 include/{matrix => linear_solvers}/cg_eigen.h | 0 include/{matrix => linear_solvers}/cg_eigen.tcc | 0 include/{matrix => linear_solvers}/solver_base.h | 0 src/{matrix.cc => linear_solver.cc} | 8 ++++---- 8 files changed, 6 insertions(+), 5 deletions(-) rename include/{matrix => linear_solvers}/assembler_base.h (100%) rename include/{matrix => linear_solvers}/assembler_eigen_semi_implicit_navierstokes.h (100%) rename include/{matrix => linear_solvers}/assembler_eigen_semi_implicit_navierstokes.tcc (100%) rename include/{matrix => linear_solvers}/cg_eigen.h (100%) rename include/{matrix => linear_solvers}/cg_eigen.tcc (100%) rename include/{matrix => linear_solvers}/solver_base.h (100%) rename src/{matrix.cc => linear_solver.cc} (79%) diff --git a/CMakeLists.txt b/CMakeLists.txt index c2ddf3928..86c35d4f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -148,6 +148,7 @@ include_directories(BEFORE ${mpm_SOURCE_DIR}/include/functions/ ${mpm_SOURCE_DIR}/include/generators/ ${mpm_SOURCE_DIR}/include/io/ + ${mpm_SOURCE_DIR}/include/linear_solvers/ ${mpm_SOURCE_DIR}/include/loads_bcs/ ${mpm_SOURCE_DIR}/include/materials/ ${mpm_SOURCE_DIR}/include/particles/ @@ -170,8 +171,8 @@ SET(mpm_src ${mpm_SOURCE_DIR}/src/io/io_mesh.cc ${mpm_SOURCE_DIR}/src/io/logger.cc ${mpm_SOURCE_DIR}/src/io/partio_writer.cc + ${mpm_SOURCE_DIR}/src/linear_solver.cc ${mpm_SOURCE_DIR}/src/material.cc - ${mpm_SOURCE_DIR}/src/matrix.cc ${mpm_SOURCE_DIR}/src/mpm.cc ${mpm_SOURCE_DIR}/src/node.cc ${mpm_SOURCE_DIR}/src/particle.cc diff --git a/include/matrix/assembler_base.h b/include/linear_solvers/assembler_base.h similarity index 100% rename from include/matrix/assembler_base.h rename to include/linear_solvers/assembler_base.h diff --git a/include/matrix/assembler_eigen_semi_implicit_navierstokes.h b/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.h similarity index 100% rename from include/matrix/assembler_eigen_semi_implicit_navierstokes.h rename to include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.h diff --git a/include/matrix/assembler_eigen_semi_implicit_navierstokes.tcc b/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.tcc similarity index 100% rename from include/matrix/assembler_eigen_semi_implicit_navierstokes.tcc rename to include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.tcc diff --git a/include/matrix/cg_eigen.h b/include/linear_solvers/cg_eigen.h similarity index 100% rename from include/matrix/cg_eigen.h rename to include/linear_solvers/cg_eigen.h diff --git a/include/matrix/cg_eigen.tcc b/include/linear_solvers/cg_eigen.tcc similarity index 100% rename from include/matrix/cg_eigen.tcc rename to include/linear_solvers/cg_eigen.tcc diff --git a/include/matrix/solver_base.h b/include/linear_solvers/solver_base.h similarity index 100% rename from include/matrix/solver_base.h rename to include/linear_solvers/solver_base.h diff --git a/src/matrix.cc b/src/linear_solver.cc similarity index 79% rename from src/matrix.cc rename to src/linear_solver.cc index bb90d55ea..48b5ac2ea 100644 --- a/src/matrix.cc +++ b/src/linear_solver.cc @@ -1,8 +1,8 @@ -#include "matrix/assembler_base.h" -#include "matrix/assembler_eigen_semi_implicit_navierstokes.h" +#include "assembler_base.h" +#include "assembler_eigen_semi_implicit_navierstokes.h" -#include "matrix/cg_eigen.h" -#include "matrix/solver_base.h" +#include "cg_eigen.h" +#include "solver_base.h" // Assembler collections // Asssembler 2D From 56ac0c265856ab401d5aab0073ed758cecb55b4e Mon Sep 17 00:00:00 2001 From: Nanda Date: Thu, 12 Mar 2020 16:37:25 -0700 Subject: [PATCH 12/72] change mesh to shared_ptr --- include/solvers/mpm_base.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/solvers/mpm_base.h b/include/solvers/mpm_base.h index 42e41608c..8d8cef3c0 100644 --- a/include/solvers/mpm_base.h +++ b/include/solvers/mpm_base.h @@ -177,7 +177,7 @@ class MPMBase : public MPM { //! Gravity Eigen::Matrix gravity_; //! Mesh object - std::unique_ptr> mesh_; + std::shared_ptr> mesh_; //! Materials std::map>> materials_; //! Mathematical functions From 14b7eea806d86788e45d62fa0942c2ca89046fda Mon Sep 17 00:00:00 2001 From: Nanda Date: Thu, 12 Mar 2020 17:58:56 -0700 Subject: [PATCH 13/72] initialise and reinitialise matrices --- include/cell.h | 8 +- include/cell.tcc | 55 +++++++++ include/linear_solvers/assembler_base.h | 28 +++-- ...mbler_eigen_semi_implicit_navierstokes.tcc | 63 ++++++----- include/mesh.h | 3 + include/mesh.tcc | 19 ++++ include/node.h | 51 +++++++-- include/node.tcc | 40 ++++++- include/node_base.h | 36 ++++-- .../solvers/mpm_semi_implicit_navierstokes.h | 9 +- .../mpm_semi_implicit_navierstokes.tcc | 104 +++++++++--------- src/linear_solver.cc | 10 +- 12 files changed, 288 insertions(+), 138 deletions(-) diff --git a/include/cell.h b/include/cell.h index ff596cd63..c604bddb7 100644 --- a/include/cell.h +++ b/include/cell.h @@ -223,9 +223,15 @@ class Cell { double volume_fraction() { return volume_fraction_; }; //! Map cell volume to the nodes - //! \retval phase to map volume + //! \param[in] phase to map volume bool map_cell_volume_to_nodes(unsigned phase); + //! Initialize local elemental matrices + bool initialise_element_matrix(); + + //! Return local node indices + Eigen::VectorXi local_node_indices(); + private: //! Approximately check if a point is in a cell //! \param[in] point Coordinates of point diff --git a/include/cell.tcc b/include/cell.tcc index 68bce00f7..a7f973c45 100644 --- a/include/cell.tcc +++ b/include/cell.tcc @@ -841,3 +841,58 @@ bool mpm::Cell::map_cell_volume_to_nodes(unsigned phase) { } return status; } + +//! Initialise element matrix +template +bool mpm::Cell::initialise_element_matrix() { + bool status = true; + if (this->status()) { + try { + // // Initialse K_inter matrix (NxN) + // K_inter_element_.resize(nnodes_, nnodes_); + // K_inter_element_.setZero(); + + // // Initialse Laplacian matrix (NxN) + // L_element_.resize(nnodes_, nnodes_); + // L_element_.setZero(); + + // // Initialse Fs matrix (NxTdim) + // F_s_element_.resize(nnodes_, nnodes_ * Tdim); + // F_s_element_.setZero(); + + // // Initialse Fm matrix (NxTdim) + // F_m_element_.resize(nnodes_, nnodes_ * Tdim); + // F_m_element_.setZero(); + + // K_cor_s_element_.resize(nnodes_, nnodes_ * Tdim); + // K_cor_s_element_.setZero(); + + // K_cor_w_element_.resize(nnodes_, nnodes_ * Tdim); + // K_cor_w_element_.setZero(); + + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + } + return status; +} + +//! Return local node indices +template +Eigen::VectorXi mpm::Cell::local_node_indices() { + Eigen::VectorXi indices; + try { + indices.resize(nodes_.size()); + indices.setZero(); + unsigned node_idx = 0; + for (auto node_itr = nodes_.cbegin(); node_itr != nodes_.cend(); + ++node_itr) { + indices(node_idx) = (*node_itr)->active_id(); + node_idx++; + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + } + return indices; +} \ No newline at end of file diff --git a/include/linear_solvers/assembler_base.h b/include/linear_solvers/assembler_base.h index 3e34f3934..2421d77bf 100644 --- a/include/linear_solvers/assembler_base.h +++ b/include/linear_solvers/assembler_base.h @@ -14,9 +14,9 @@ namespace mpm { -// Matrix assembler base class -//! \brief Assemble matrixs (stiffness matrix) -//! \details Get local stiffness matrix and node ids from cell +// Linear solver assembler base class +//! \brief Perform matrix assembly procedures +//! \details Build global matrices considering local element matrices //! \tparam Tdim Dimension template class AssemblerBase { @@ -25,19 +25,21 @@ class AssemblerBase { //! Global degrees of freedom active_dof_ = 0; } + // Virtual destructor virtual ~AssemblerBase() = default; //! Copy constructor - // AssemblerBase(const AssemblerBase&) = default; + AssemblerBase(const AssemblerBase&) = default; //! Assignment operator - // AssemblerBase& operator=(const AssemblerBase&) = default; + AssemblerBase& operator=(const AssemblerBase&) = default; //! Move constructor - // AssemblerBase(AssemblerBase&&) = default; + AssemblerBase(AssemblerBase&&) = default; //! Assign mesh pointer + //! \param[in] mesh mesh pointer void assign_mesh_pointer(std::shared_ptr>& mesh) { mesh_ = mesh; } @@ -45,6 +47,13 @@ class AssemblerBase { //! Create a pair between nodes and index in Matrix / Vector virtual bool assign_global_node_indices(unsigned active_dof) = 0; + //! Assign pressure constraints + virtual bool assign_pressure_constraints(double beta, + const double current_time) = 0; + + //! Apply pressure constraints to poisson equation + virtual void apply_pressure_constraints() = 0; + //! Assemble displacement vector // virtual void assemble_disp_vector() = 0; @@ -81,11 +90,6 @@ class AssemblerBase { virtual Eigen::VectorXd& pressure_increment() = 0; - virtual void apply_pressure_constraints() = 0; - - virtual bool assign_pressure_constraints(double beta, - const double current_time) = 0; - virtual std::set free_surface() = 0; virtual void assign_free_surface( @@ -168,7 +172,7 @@ class AssemblerBase { }; protected: - //! Active node number + //! Number of total active_dof unsigned active_dof_; //! Mesh object std::shared_ptr> mesh_; diff --git a/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.tcc b/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.tcc index fc1ed4409..f0508a6f5 100644 --- a/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.tcc +++ b/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.tcc @@ -10,17 +10,18 @@ mpm::AssemblerEigenSemiImplicitNavierStokes< //! Assign global node indices template bool mpm::AssemblerEigenSemiImplicitNavierStokes< - Tdim>::assign_global_node_indices(unsigned active_dof) { + Tdim>::assign_global_node_indices(unsigned nactive_node) { bool status = true; - // try { - // active_dof_ = active_dof; + try { + // Total number of active node + active_dof_ = nactive_node; - // global_node_indices_ = mesh_->global_node_indices(); + global_node_indices_ = mesh_->global_node_indices(); - // } catch (std::exception& exception) { - // console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - // status = false; - // } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } return status; } @@ -246,30 +247,28 @@ template bool mpm::AssemblerEigenSemiImplicitNavierStokes< Tdim>::assign_pressure_constraints(double beta, const double current_time) { bool status = false; - // try { - // // Phase index - // const unsigned pore_liquid = mpm::ParticlePhase::Liquid; - // // Resize pressure constraints vector - // pressure_constraints_.resize(active_dof_); - // pressure_constraints_.reserve(int(0.5 * active_dof_)); + try { + // Resize pressure constraints vector + pressure_constraints_.resize(active_dof_); + pressure_constraints_.reserve(int(0.5 * active_dof_)); - // // Nodes container - // const auto& nodes = mesh_->active_nodes(); - // // Iterate over nodes to get pressure constraints - // for (auto node = nodes.cbegin(); node != nodes.cend(); ++node) { - // // Assign total pressure constraint - // const double pressure_constraint = - // (*node)->pressure_constraint(1, current_time); - // // Check if there is a pressure constraint - // if (pressure_constraint != std::numeric_limits::max()) { - // // Insert the pressure constraints - // pressure_constraints_.insert((*node)->active_id()) = - // pressure_constraint; - // } - // } - // status = true; - // } catch (std::exception& exception) { - // console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - // } + // Nodes container + const auto& nodes = mesh_->active_nodes(); + // Iterate over nodes to get pressure constraints + for (auto node = nodes.cbegin(); node != nodes.cend(); ++node) { + // Assign total pressure constraint + const double pressure_constraint = + (*node)->pressure_constraint(1, current_time); + // Check if there is a pressure constraint + if (pressure_constraint != std::numeric_limits::max()) { + // Insert the pressure constraints + pressure_constraints_.insert((*node)->active_id()) = + pressure_constraint; + } + } + status = true; + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + } return status; } diff --git a/include/mesh.h b/include/mesh.h index 30a4ceeaa..df97487bc 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -451,6 +451,9 @@ class Mesh { //! Return container of active nodes mpm::Vector> active_nodes() { return active_nodes_; } + //! Return global node indices + std::vector global_node_indices() const; + private: // Read particles from file bool read_particles_file(const std::shared_ptr& io, diff --git a/include/mesh.tcc b/include/mesh.tcc index 36ecbbd44..5c0eba770 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1955,4 +1955,23 @@ unsigned mpm::Mesh::assign_active_node_id() { } return active_id; +} + +//! Return global node indices +template +std::vector mpm::Mesh::global_node_indices() const { + // Vector of node_pairs + std::vector node_indices; + try { + // Iterate over cells + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + if ((*citr)->status()) { + node_indices.emplace_back((*citr)->local_node_indices()); + } + } + + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + } + return node_indices; } \ No newline at end of file diff --git a/include/node.h b/include/node.h index a567e32ba..46d798e52 100644 --- a/include/node.h +++ b/include/node.h @@ -236,18 +236,6 @@ class Node : public NodeBase { //! Set ghost id void ghost_id(Index gid) override { ghost_id_ = gid; } - //! Compute navier-stokes semi-implicit acceleration and velocity - //! \param[in] phase Index corresponding to the phase - //! \param[in] dt Timestep in analysis - //! \retval status Computation status - bool compute_acceleration_velocity_navierstokes_semi_implicit( - unsigned phase, double dt) override; - - //! Update pore pressure increment at the node - void update_pressure_increment(const Eigen::VectorXd& pressure_increment, - unsigned phase, - double current_time = 0.) override; - //! Return real density at a given node for a given phase //! \param[in] phase Index corresponding to the phase double density(unsigned phase) override { return density_(phase); } @@ -272,6 +260,43 @@ class Node : public NodeBase { //! Return active id mpm::Index active_id() override { return active_id_; } + //! Return nodal pressure constraint + //! \param[in] phase Index corresponding to the phase + //! \param[in] current_time current time of the analysis + //! \retval pressure constraint at proper time for given phase + double pressure_constraint(const unsigned phase, + const double current_time) override { + if (pressure_constraints_.find(phase) != pressure_constraints_.end()) { + const double scalar = + (pressure_function_.find(phase) != pressure_function_.end()) + ? pressure_function_[phase]->value(current_time) + : 1.0; + + return scalar * pressure_constraints_[phase]; + } else + return std::numeric_limits::max(); + } + + //! Assign pressure constraint + //! \param[in] phase Index corresponding to the phase + //! \param[in] pressure Applied pressure constraint + //! \param[in] function math function + bool assign_pressure_constraint( + const unsigned phase, const double pressure, + const std::shared_ptr& function) override; + + //! Update pore pressure increment at the node + void update_pressure_increment(const Eigen::VectorXd& pressure_increment, + unsigned phase, + double current_time = 0.) override; + + //! Compute navier-stokes semi-implicit acceleration and velocity + //! \param[in] phase Index corresponding to the phase + //! \param[in] dt Timestep in analysis + //! \retval status Computation status + bool compute_acceleration_velocity_navierstokes_semi_implicit( + unsigned phase, double dt) override; + private: //! Mutex std::mutex node_mutex_; @@ -319,6 +344,8 @@ class Node : public NodeBase { Eigen::Matrix concentrated_force_; //! Mathematical function for force std::shared_ptr force_function_{nullptr}; + //! Mathematical function for pressure + std::map> pressure_function_; //! Logger std::unique_ptr console_; //! MPI ranks diff --git a/include/node.tcc b/include/node.tcc index 45ee2d7ed..ced10dcca 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -549,21 +549,33 @@ void mpm::Node::compute_density() { } } -//! Compute nodal corrected force +//! Assign pressure constraint template -bool mpm::Node::compute_nodal_corrected_force( - VectorDim& force_cor_part_water) { +bool mpm::Node::assign_pressure_constraint( + const unsigned phase, const double pressure, + const std::shared_ptr& function) { bool status = true; - try { - // Compute corrected force for water phase - force_cor_.col(0) = force_cor_part_water; + // Constrain directions can take values between 0 and Tnphases + if (phase < Tnphases) { + this->pressure_constraints_.insert(std::make_pair( + static_cast(phase), static_cast(pressure))); + // Assign pressure function + if (function != nullptr) + this->pressure_function_.insert( + std::make_pair>( + static_cast(phase), + static_cast>(function))); + } else + throw std::runtime_error("Pressure constraint phase is out of bounds"); + } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); status = false; } return status; } + //! Update pore pressure increment at the node template void mpm::Node::update_pressure_increment( @@ -577,6 +589,22 @@ void mpm::Node::update_pressure_increment( this->pressure_increment_ = 0; } +//! Compute nodal corrected force +template +bool mpm::Node::compute_nodal_corrected_force( + VectorDim& force_cor_part_water) { + bool status = true; + + try { + // Compute corrected force for water phase + force_cor_.col(0) = force_cor_part_water; + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + //! Compute semi-implicit acceleration and velocity template bool mpm::Node:: diff --git a/include/node_base.h b/include/node_base.h index b7921cac3..7a8fa51fa 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -226,18 +226,6 @@ class NodeBase { //! Set ghost id virtual void ghost_id(Index gid) = 0; - //! Compute navier-stokes semi-implicit acceleration and velocity - //! \param[in] phase Index corresponding to the phase - //! \param[in] dt Timestep in analysis - //! \retval status Computation status - virtual bool compute_acceleration_velocity_navierstokes_semi_implicit( - unsigned phase, double dt) = 0; - - //! Update pore pressure increment at the node - virtual void update_pressure_increment( - const Eigen::VectorXd& pressure_increment, unsigned phase, - double current_time = 0.) = 0; - //! Return real density at a given node for a given phase //! \param[in] phase Index corresponding to the phase virtual double density(unsigned phase) = 0; @@ -261,6 +249,30 @@ class NodeBase { //! Return active id virtual mpm::Index active_id() = 0; + //! Compute navier-stokes semi-implicit acceleration and velocity + //! \param[in] phase Index corresponding to the phase + //! \param[in] dt Timestep in analysis + //! \retval status Computation status + virtual bool compute_acceleration_velocity_navierstokes_semi_implicit( + unsigned phase, double dt) = 0; + + //! Return pressure constraint + virtual double pressure_constraint(const unsigned phase, + const double current_time) = 0; + + //! Assign pressure constraint + //! \param[in] phase Index corresponding to the phase + //! \param[in] pressure Applied pressure constraint + //! \param[in] function math function + virtual bool assign_pressure_constraint( + const unsigned phase, double pressure, + const std::shared_ptr& function) = 0; + + //! Update pore pressure increment at the node + virtual void update_pressure_increment( + const Eigen::VectorXd& pressure_increment, unsigned phase, + double current_time = 0.) = 0; + }; // NodeBase class } // namespace mpm diff --git a/include/solvers/mpm_semi_implicit_navierstokes.h b/include/solvers/mpm_semi_implicit_navierstokes.h index 65aef763d..44d8a7494 100644 --- a/include/solvers/mpm_semi_implicit_navierstokes.h +++ b/include/solvers/mpm_semi_implicit_navierstokes.h @@ -7,10 +7,10 @@ #include "mpm_base.h" -#include "matrix/assembler_base.h" -#include "matrix/assembler_eigen_semi_implicit_navierstokes.h" -#include "matrix/cg_eigen.h" -#include "matrix/solver_base.h" +#include "assembler_base.h" +#include "assembler_eigen_semi_implicit_navierstokes.h" +#include "cg_eigen.h" +#include "solver_base.h" namespace mpm { @@ -89,7 +89,6 @@ class MPMSemiImplicitNavierStokes : public MPMBase { std::shared_ptr> matrix_assembler_; //! Matrix solver object std::shared_ptr> matrix_solver_; - // TODO: Check if this is usefull, or remove. //! Volume tolerance for free surface double volume_tolerance_{0}; diff --git a/include/solvers/mpm_semi_implicit_navierstokes.tcc b/include/solvers/mpm_semi_implicit_navierstokes.tcc index 4ea48f40a..2d36d8519 100644 --- a/include/solvers/mpm_semi_implicit_navierstokes.tcc +++ b/include/solvers/mpm_semi_implicit_navierstokes.tcc @@ -164,12 +164,12 @@ bool mpm::MPMSemiImplicitNavierStokes::solve() { std::placeholders::_1, fluid, this->dt_), std::bind(&mpm::NodeBase::status, std::placeholders::_1)); - // // Reinitialise system matrix to perform PPE - // bool matrix_reinitialization_status = this->reinitialise_matrix(); - // if (!matrix_reinitialization_status) { - // status = false; - // throw std::runtime_error("Reinitialisation of matrix failed"); - // } + // Reinitialise system matrix to perform PPE + bool matrix_reinitialization_status = this->reinitialise_matrix(); + if (!matrix_reinitialization_status) { + status = false; + throw std::runtime_error("Reinitialisation of matrix failed"); + } // // Compute poisson equation // this->compute_poisson_equation(); @@ -241,37 +241,35 @@ bool mpm::MPMSemiImplicitNavierStokes::solve() { template bool mpm::MPMSemiImplicitNavierStokes::initialise_matrix() { bool status = true; - // try { - // // Max iteration steps - // unsigned max_iter = - // analysis_["matrix"]["max_iter"].template get(); - // // Tolerance - // double tolerance = analysis_["matrix"]["tolerance"].template - // get(); - // // Get matrix assembler type - // std::string assembler_type = - // analysis_["matrix"]["assembler_type"].template get(); - // // Get matrix solver type - // std::string solver_type = - // analysis_["matrix"]["solver_type"].template get(); - // // TODO: Check if this is usefull, or remove. - // // Get volume tolerance for free surface - // volume_tolerance_ = - // analysis_["matrix"]["volume_tolerance"].template get(); - // // Create matrix assembler - // matrix_assembler_ = - // Factory>::instance()->create(assembler_type); - // // Create matrix solver - // matrix_solver_ = - // Factory, unsigned, double>::instance()->create( - // solver_type, std::move(max_iter), std::move(tolerance)); - // // Transfer the mesh pointer - // matrix_assembler_->assign_mesh_pointer(mesh_); - - // } catch (std::exception& exception) { - // console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - // status = false; - // } + try { + // Max iteration steps + unsigned max_iter = + analysis_["matrix"]["max_iter"].template get(); + // Tolerance + double tolerance = analysis_["matrix"]["tolerance"].template get(); + // Get matrix assembler type + std::string assembler_type = + analysis_["matrix"]["assembler_type"].template get(); + // Get matrix solver type + std::string solver_type = + analysis_["matrix"]["solver_type"].template get(); + // Get volume tolerance for free surface + volume_tolerance_ = + analysis_["matrix"]["volume_tolerance"].template get(); + // Create matrix assembler + matrix_assembler_ = + Factory>::instance()->create(assembler_type); + // Create matrix solver + matrix_solver_ = + Factory, unsigned, double>::instance()->create( + solver_type, std::move(max_iter), std::move(tolerance)); + // Assign mesh pointer to assembler + matrix_assembler_->assign_mesh_pointer(mesh_); + + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } return status; } @@ -279,27 +277,25 @@ bool mpm::MPMSemiImplicitNavierStokes::initialise_matrix() { template bool mpm::MPMSemiImplicitNavierStokes::reinitialise_matrix() { bool status = true; - // try { - // // Assigning matrix id - // const auto active_dof = mesh_->assign_active_node_id(); + try { + // Assigning matrix id + const auto nactive_node = mesh_->assign_active_node_id(); - // // Assign global node indice - // matrix_assembler_->assign_global_node_indices(active_dof); + // Assign global node indice + matrix_assembler_->assign_global_node_indices(nactive_node); - // // Assign pressure cpnstraints - // matrix_assembler_->assign_pressure_constraints(this->beta_, - // this->step_ * - // this->dt_); + // Assign pressure cpnstraints + matrix_assembler_->assign_pressure_constraints(this->beta_, + this->step_ * this->dt_); - // // Initialise element matrix - // mesh_->iterate_over_cells(std::bind( - // &mpm::Cell::initialise_element_matrix, - // std::placeholders::_1)); + // Initialise element matrix + mesh_->iterate_over_cells(std::bind( + &mpm::Cell::initialise_element_matrix, std::placeholders::_1)); - // } catch (std::exception& exception) { - // console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - // status = false; - // } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } return status; } diff --git a/src/linear_solver.cc b/src/linear_solver.cc index 48b5ac2ea..e64da9a5e 100644 --- a/src/linear_solver.cc +++ b/src/linear_solver.cc @@ -8,16 +8,18 @@ // Asssembler 2D static Register, mpm::AssemblerEigenSemiImplicitNavierStokes<2>> - AssemblerEigenSemiImplicitNavierStokes2d("EigenSemiImplicitNavierStokes2D"); + assembler_eigen_semi_implicit_navierstokes_2d( + "EigenSemiImplicitNavierStokes2D"); // Asssembler 3D static Register, mpm::AssemblerEigenSemiImplicitNavierStokes<3>> - AssemblerEigenSemiImplicitNavierStokes3d("EigenSemiImplicitNavierStokes3D"); + assembler_eigen_semi_implicit_navierstokes_3d( + "EigenSemiImplicitNavierStokes3D"); // Linear Solver collections // Solver 2D static Register, mpm::CGEigen<2>, unsigned, double> - solvereigencg2d("EigenCG2D"); + solver_eigen_cg_2d("EigenCG2D"); // Solver 3D static Register, mpm::CGEigen<3>, unsigned, double> - solvereigencg3d("EigenCG3D"); \ No newline at end of file + solver_eigen_cg_3d("EigenCG3D"); \ No newline at end of file From e0ddac0312e4e71ae76bd0e3ad7fd37d3fabeaaf Mon Sep 17 00:00:00 2001 From: Nanda Date: Fri, 13 Mar 2020 20:13:46 -0700 Subject: [PATCH 14/72] complete PPE --- include/cell.h | 28 ++ include/cell.tcc | 74 +++-- include/linear_solvers/assembler_base.h | 37 ++- ...sembler_eigen_semi_implicit_navierstokes.h | 65 ++-- ...mbler_eigen_semi_implicit_navierstokes.tcc | 313 +++++++++--------- include/mesh.h | 3 + include/mesh.tcc | 1 + include/particles/fluid_particle.h | 2 +- include/particles/fluid_particle.tcc | 15 +- include/particles/particle_base.h | 4 +- .../mpm_semi_implicit_navierstokes.tcc | 59 ++-- 11 files changed, 340 insertions(+), 261 deletions(-) diff --git a/include/cell.h b/include/cell.h index c604bddb7..fc9fd40e6 100644 --- a/include/cell.h +++ b/include/cell.h @@ -232,6 +232,30 @@ class Cell { //! Return local node indices Eigen::VectorXi local_node_indices(); + //! Return local laplacian + const Eigen::MatrixXd& laplacian_matrix() { return laplacian_matrix_; }; + + //! Compute local laplacian matrix + //! \param[in] grad_shapefn shape function gradient + //! \param[in] pvolume volume weight + //! \param[in] multiplier multiplier + void compute_local_laplacian(const Eigen::MatrixXd& grad_shapefn, + double pvolume, + double multiplier = 1.0) noexcept; + + //! Return local laplacian RHS matrix + const Eigen::MatrixXd& poisson_right_matrix() { + return poisson_right_matrix_; + }; + + //! Compute local poisson RHS matrix (Used in poisson equation) + //! \param[in] shapefn shape function + //! \param[in] grad_shapefn shape function gradient + //! \param[in] pvolume volume weight + void compute_local_poisson_right(const Eigen::VectorXd& shapefn, + const Eigen::MatrixXd& grad_shapefn, + double pvolume) noexcept; + private: //! Approximately check if a point is in a cell //! \param[in] point Coordinates of point @@ -279,6 +303,10 @@ class Cell { bool free_surface_{false}; //! Volume fraction double volume_fraction_{0.0}; + //! Local laplacian matrix + Eigen::MatrixXd laplacian_matrix_; + //! Local poisson RHS matrix + Eigen::MatrixXd poisson_right_matrix_; //! Logger std::unique_ptr console_; }; // Cell class diff --git a/include/cell.tcc b/include/cell.tcc index a7f973c45..c42b8f192 100644 --- a/include/cell.tcc +++ b/include/cell.tcc @@ -842,23 +842,38 @@ bool mpm::Cell::map_cell_volume_to_nodes(unsigned phase) { return status; } +//! Return local node indices +template +Eigen::VectorXi mpm::Cell::local_node_indices() { + Eigen::VectorXi indices; + try { + indices.resize(nodes_.size()); + indices.setZero(); + unsigned node_idx = 0; + for (auto node_itr = nodes_.cbegin(); node_itr != nodes_.cend(); + ++node_itr) { + indices(node_idx) = (*node_itr)->active_id(); + node_idx++; + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + } + return indices; +} + //! Initialise element matrix template bool mpm::Cell::initialise_element_matrix() { bool status = true; if (this->status()) { try { - // // Initialse K_inter matrix (NxN) - // K_inter_element_.resize(nnodes_, nnodes_); - // K_inter_element_.setZero(); + // Initialse Laplacian matrix (NxN) + laplacian_matrix_.resize(nnodes_, nnodes_); + laplacian_matrix_.setZero(); - // // Initialse Laplacian matrix (NxN) - // L_element_.resize(nnodes_, nnodes_); - // L_element_.setZero(); - - // // Initialse Fs matrix (NxTdim) - // F_s_element_.resize(nnodes_, nnodes_ * Tdim); - // F_s_element_.setZero(); + // Initialse poisson RHS matrix (Nx(N*Tdim)) + poisson_right_matrix_.resize(nnodes_, nnodes_ * Tdim); + poisson_right_matrix_.setZero(); // // Initialse Fm matrix (NxTdim) // F_m_element_.resize(nnodes_, nnodes_ * Tdim); @@ -878,21 +893,30 @@ bool mpm::Cell::initialise_element_matrix() { return status; } -//! Return local node indices +//! Compute local matrix of laplacian template -Eigen::VectorXi mpm::Cell::local_node_indices() { - Eigen::VectorXi indices; - try { - indices.resize(nodes_.size()); - indices.setZero(); - unsigned node_idx = 0; - for (auto node_itr = nodes_.cbegin(); node_itr != nodes_.cend(); - ++node_itr) { - indices(node_idx) = (*node_itr)->active_id(); - node_idx++; - } - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); +void mpm::Cell::compute_local_laplacian( + const Eigen::MatrixXd& grad_shapefn, double pvolume, + double multiplier) noexcept { + // Lock the storage + std::lock_guard guard(cell_mutex_); + laplacian_matrix_ += + grad_shapefn * grad_shapefn.transpose() * multiplier * pvolume; +} + +//! Compute local poisson RHS matrix +//! Used in poisson equation RHS for Navier Stokes solver +template +void mpm::Cell::compute_local_poisson_right( + const Eigen::VectorXd& shapefn, const Eigen::MatrixXd& grad_shapefn, + double pvolume) noexcept { + // Lock the storage + std::lock_guard guard(cell_mutex_); + + // Compute components at nodes + for (unsigned i = 0; i < Tdim; i++) { + // F_s_element + poisson_right_matrix_.block(0, i * nnodes_, nnodes_, nnodes_) += + shapefn * grad_shapefn.col(i).transpose() * pvolume; } - return indices; } \ No newline at end of file diff --git a/include/linear_solvers/assembler_base.h b/include/linear_solvers/assembler_base.h index 2421d77bf..5272f33e9 100644 --- a/include/linear_solvers/assembler_base.h +++ b/include/linear_solvers/assembler_base.h @@ -51,9 +51,29 @@ class AssemblerBase { virtual bool assign_pressure_constraints(double beta, const double current_time) = 0; + //! Assemble laplacian matrix + virtual Eigen::SparseMatrix& laplacian_matrix() = 0; + + //! Assemble laplacian matrix + virtual bool assemble_laplacian_matrix(double dt) = 0; + + //! Assemble poisson RHS vector + virtual Eigen::VectorXd& poisson_rhs_vector() = 0; + + //! Assemble poisson RHS vector + virtual bool assemble_poisson_right(std::shared_ptr>& mesh_, + double dt) = 0; + + //! Assign free surface node id + virtual void assign_free_surface( + const std::set& free_surface_id) = 0; + //! Apply pressure constraints to poisson equation virtual void apply_pressure_constraints() = 0; + virtual void assign_pressure_increment( + Eigen::VectorXd pressure_increment) = 0; + //! Assemble displacement vector // virtual void assemble_disp_vector() = 0; @@ -72,29 +92,12 @@ class AssemblerBase { virtual bool assemble_K_cor_matrix(std::shared_ptr>& mesh_, double dt) = 0; - //! Assemble laplacian matrix - virtual bool assemble_laplacian_matrix(double dt) = 0; - - //! Assemble poisson right - virtual bool assemble_poisson_right(std::shared_ptr>& mesh_, - double dt) = 0; - - virtual void assign_pressure_increment( - Eigen::VectorXd pressure_increment) = 0; - virtual Eigen::SparseMatrix& K_cor_matrix() = 0; - virtual Eigen::SparseMatrix& laplacian_matrix() = 0; - - virtual Eigen::VectorXd& force_laplacian_matrix() = 0; - virtual Eigen::VectorXd& pressure_increment() = 0; virtual std::set free_surface() = 0; - virtual void assign_free_surface( - const std::set& free_surface_id) = 0; - virtual unsigned active_dof() { return active_dof_; }; //! Assemble stiffness matrix (semi-implicit) diff --git a/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.h b/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.h index a261bc051..cc2374fdc 100644 --- a/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.h +++ b/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.h @@ -21,47 +21,49 @@ class AssemblerEigenSemiImplicitNavierStokes : public AssemblerBase { //! Create a pair between nodes and index in Matrix / Vector bool assign_global_node_indices(unsigned active_dof) override; - //! Resize containers of matrix - bool resize_semi_implicit_matrix(); - - //! Assemble K_cor matrix (used in correcting nodal velocity) - bool assemble_K_cor_matrix(std::shared_ptr>& mesh_, - double dt) override; + //! Return laplacian matrix + Eigen::SparseMatrix& laplacian_matrix() override { + return laplacian_matrix_; + } - //! Assemble_laplacian_matrix + //! Assemble laplacian matrix bool assemble_laplacian_matrix(double dt) override; - //! Assemble_poisson_right + //! Return poisson RHS vector + Eigen::VectorXd& poisson_rhs_vector() override { return poisson_rhs_vector_; } + + //! Assemble poisson RHS vector bool assemble_poisson_right(std::shared_ptr>& mesh_, double dt) override; - void assign_pressure_increment(Eigen::VectorXd pressure_increment) override { - pressure_increment_ = pressure_increment; + //! Assign free surface node id + void assign_free_surface( + const std::set& free_surface_id) override { + free_surface_ = free_surface_id; } - Eigen::SparseMatrix& K_cor_matrix() override { return K_cor_matrix_; } + //! Return free surface node id + std::set free_surface() override { return free_surface_; } - Eigen::SparseMatrix& laplacian_matrix() override { - return laplacian_matrix_; - } + //! Apply pressure constraints to poisson equation + void apply_pressure_constraints(); - Eigen::VectorXd& force_laplacian_matrix() override { - return force_laplacian_matrix_; + //! Assign pressure increment + void assign_pressure_increment(Eigen::VectorXd pressure_increment) override { + pressure_increment_ = pressure_increment; } + //! Return pressure increment Eigen::VectorXd& pressure_increment() override { return pressure_increment_; } - std::set free_surface() override { return free_surface_; } - - void assign_free_surface( - const std::set& free_surface_id) override { - free_surface_ = free_surface_id; - } + Eigen::SparseMatrix& K_cor_matrix() override { return K_cor_matrix_; } bool assign_pressure_constraints(double beta, const double current_time) override; - void apply_pressure_constraints(); + //! Assemble K_cor matrix (used in correcting nodal velocity) + bool assemble_K_cor_matrix(std::shared_ptr>& mesh_, + double dt) override; protected: //! Logger @@ -72,14 +74,19 @@ class AssemblerEigenSemiImplicitNavierStokes : public AssemblerBase { using AssemblerBase::active_dof_; //! Mesh object using AssemblerBase::mesh_; - //! poisson equation RHS (F31 and F32) - Eigen::VectorXd force_laplacian_matrix_; //! Laplacian matrix Eigen::SparseMatrix laplacian_matrix_; + //! Poisson RHS vector + Eigen::VectorXd poisson_rhs_vector_; + //! Free surface + std::set free_surface_; + //! Pressure constraints + Eigen::SparseVector pressure_constraints_; + //! \delta p^(t+1) = p^(t+1) - beta * p^(t) + Eigen::VectorXd pressure_increment_; + //! K_cor_matrix Eigen::SparseMatrix K_cor_matrix_; - //! p^(t+1) - beta * p^(t) - Eigen::VectorXd pressure_increment_; //! Laplacian coefficient Eigen::VectorXd poisson_right_vector_; //! Solver base @@ -88,10 +95,6 @@ class AssemblerEigenSemiImplicitNavierStokes : public AssemblerBase { std::vector global_node_indices_; //! Velocity constraints Eigen::SparseMatrix velocity_constraints_; - //! Pressure constraints - Eigen::SparseVector pressure_constraints_; - //! Free surface - std::set free_surface_; }; } // namespace mpm diff --git a/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.tcc b/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.tcc index f0508a6f5..e3cb51af6 100644 --- a/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.tcc +++ b/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.tcc @@ -30,52 +30,57 @@ template bool mpm::AssemblerEigenSemiImplicitNavierStokes< Tdim>::assemble_laplacian_matrix(double dt) { bool status = true; - // try { - // // Initialise Laplacian matrix - // laplacian_matrix_.resize(active_dof_, active_dof_); - // laplacian_matrix_.setZero(); - // // TODO: Make the storage being able to adaptively resize - // // Reserve storage for sparse matrix - // switch (Tdim) { - // // For 2d: 10 entries /column - // case (2): { - // laplacian_matrix_.reserve(Eigen::VectorXi::Constant(active_dof_, - // 10)); break; - // } - // // For 3d: 30 entries /column - // case (3): { - // laplacian_matrix_.reserve(Eigen::VectorXi::Constant(active_dof_, - // 30)); break; - // } - // } - // // Cell pointer - // const auto& cells = mesh_->cells(); - // // Iterate over cells - // // active cell id - // mpm::Index cid = 0; - // for (auto cell_itr = cells.cbegin(); cell_itr != cells.cend(); - // ++cell_itr) { - // if ((*cell_itr)->status()) { - // // Node ids in each cell - // const auto nids = global_node_indices_.at(cid); - // // Laplacian element of cell - // const auto L_element = (*cell_itr)->L_element(); - // // Compute Laplacian elements - // for (unsigned i = 0; i < nids.size(); ++i) { - // for (unsigned j = 0; j < nids.size(); ++j) { - // laplacian_matrix_.coeffRef(global_node_indices_.at(cid)(i), - // global_node_indices_.at(cid)(j)) += - // L_element(i, j); - // } - // } - // ++cid; - // } - // } - // laplacian_matrix_ *= dt; - // } catch (std::exception& exception) { - // console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - // status = false; - // } + try { + // Initialise Laplacian matrix + laplacian_matrix_.resize(active_dof_, active_dof_); + laplacian_matrix_.setZero(); + + // Reserve storage for sparse matrix + switch (Tdim) { + // For 2d: 10 entries /column + case (2): { + laplacian_matrix_.reserve(Eigen::VectorXi::Constant(active_dof_, 10)); + break; + } + // For 3d: 30 entries /column + case (3): { + laplacian_matrix_.reserve(Eigen::VectorXi::Constant(active_dof_, 30)); + break; + } + } + + // Cell pointer + const auto& cells = mesh_->cells(); + + // Iterate over cells + mpm::Index cid = 0; + for (auto cell_itr = cells.cbegin(); cell_itr != cells.cend(); ++cell_itr) { + if ((*cell_itr)->status()) { + // Node ids in each cell + const auto nids = global_node_indices_.at(cid); + + // Laplacian element of cell + const auto cell_laplacian = (*cell_itr)->laplacian_matrix(); + + // Assemble global laplacian matrix + for (unsigned i = 0; i < nids.size(); ++i) { + for (unsigned j = 0; j < nids.size(); ++j) { + laplacian_matrix_.coeffRef(global_node_indices_.at(cid)(i), + global_node_indices_.at(cid)(j)) += + cell_laplacian(i, j); + } + } + + ++cid; + } + } + + laplacian_matrix_ *= dt; + + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } return status; } @@ -83,81 +88,87 @@ template bool mpm::AssemblerEigenSemiImplicitNavierStokes::assemble_poisson_right( std::shared_ptr>& mesh_, double dt) { bool status = true; - // try { - // // Initialise Fs & Fm matrix - // Eigen::SparseMatrix F_s_matrix; - // // Resize Fs matrix - // F_s_matrix.resize(active_dof_, active_dof_ * Tdim); - // F_s_matrix.setZero(); - // // Reserve storage for sparse matrix - // switch (Tdim) { - // // For 2d: 10 entries /column - // case (2): { - // F_s_matrix.reserve(Eigen::VectorXi::Constant(active_dof_ * Tdim, - // 10)); break; - // } - // // For 3d: 30 entries /column - // case (3): { - // F_s_matrix.reserve(Eigen::VectorXi::Constant(active_dof_ * Tdim, - // 30)); break; - // } - // } - // // Cell pointer - // const auto& cells = mesh_->cells(); - // // Iterate over cells - // // active cell id - // mpm::Index cid = 0; - // for (auto cell_itr = cells.cbegin(); cell_itr != cells.cend(); - // ++cell_itr) { - // // Cell id - // if ((*cell_itr)->status()) { - // // Node ids in each cell - // const auto nids = global_node_indices_.at(cid); - // // Fs element of cell - // auto F_s_element = (*cell_itr)->F_s_element(); - // // Compute Fs & Fm - // for (unsigned i = 0; i < nids.size(); ++i) { - // for (unsigned j = 0; j < nids.size(); ++j) { - // for (unsigned k = 0; k < Tdim; ++k) { - // F_s_matrix.coeffRef( - // global_node_indices_.at(cid)(i), - // global_node_indices_.at(cid)(j) + k * active_dof_) += - // F_s_element(i, j + k * nids.size()); - // } - // } - // } - // cid++; - // } - // } + try { + // Initialise Poisson RHS matrix + Eigen::SparseMatrix poisson_right_matrix; + poisson_right_matrix.resize(active_dof_, active_dof_ * Tdim); + poisson_right_matrix.setZero(); - // // Resize poisson right matrix - // force_laplacian_matrix_.resize(active_dof_); - // force_laplacian_matrix_.setZero(); - // // Compute velocity - // Eigen::MatrixXd fluid_velocity; - // fluid_velocity.resize(active_dof_, Tdim); - // fluid_velocity.setZero(); - - // // Active nodes - // const auto& active_nodes = mesh_->active_nodes(); - // const unsigned fluid = mpm::ParticlePhase::SinglePhase; - // unsigned node_index = 0; - - // for (auto node_itr = active_nodes.cbegin(); node_itr != - // active_nodes.cend(); - // ++node_itr) { - // // Compute nodal intermediate force - // fluid_velocity.row(node_index) = - // (*node_itr)->velocity(fluid).transpose(); node_index++; - // } + // Reserve storage for sparse matrix + switch (Tdim) { + // For 2d: 10 entries /column + case (2): { + poisson_right_matrix.reserve( + Eigen::VectorXi::Constant(active_dof_ * Tdim, 10)); + break; + } + // For 3d: 30 entries /column + case (3): { + poisson_right_matrix.reserve( + Eigen::VectorXi::Constant(active_dof_ * Tdim, 30)); + break; + } + } - // fluid_velocity.resize(active_dof_ * Tdim, 1); + // Cell pointer + const auto& cells = mesh_->cells(); - // force_laplacian_matrix_ = -F_s_matrix * fluid_velocity; - // } catch (std::exception& exception) { - // console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - // status = false; - // } + // Iterate over cells + mpm::Index cid = 0; + for (auto cell_itr = cells.cbegin(); cell_itr != cells.cend(); ++cell_itr) { + if ((*cell_itr)->status()) { + // Node ids in each cell + const auto nids = global_node_indices_.at(cid); + + // Local Poisson RHS matrix + auto cell_poisson_right = (*cell_itr)->poisson_right_matrix(); + + // Assemble global poisson RHS matrix + for (unsigned i = 0; i < nids.size(); ++i) { + for (unsigned j = 0; j < nids.size(); ++j) { + for (unsigned k = 0; k < Tdim; ++k) { + poisson_right_matrix.coeffRef( + global_node_indices_.at(cid)(i), + global_node_indices_.at(cid)(j) + k * active_dof_) += + cell_poisson_right(i, j + k * nids.size()); + } + } + } + cid++; + } + } + + // Resize poisson right vector + poisson_rhs_vector_.resize(active_dof_); + poisson_rhs_vector_.setZero(); + + // Compute velocity + Eigen::MatrixXd fluid_velocity; + fluid_velocity.resize(active_dof_, Tdim); + fluid_velocity.setZero(); + + // Active nodes + const auto& active_nodes = mesh_->active_nodes(); + const unsigned fluid = mpm::ParticlePhase::SinglePhase; + unsigned node_index = 0; + + for (auto node_itr = active_nodes.cbegin(); node_itr != active_nodes.cend(); + ++node_itr) { + // Compute nodal intermediate force + fluid_velocity.row(node_index) = (*node_itr)->velocity(fluid).transpose(); + node_index++; + } + + // Resize fluid velocity + fluid_velocity.resize(active_dof_ * Tdim, 1); + + // Compute poisson RHS vector + poisson_rhs_vector_ = -poisson_right_matrix * fluid_velocity; + + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } return status; } @@ -206,40 +217,40 @@ bool mpm::AssemblerEigenSemiImplicitNavierStokes::assemble_K_cor_matrix( template void mpm::AssemblerEigenSemiImplicitNavierStokes< Tdim>::apply_pressure_constraints() { - // try { - // // Modify force_laplacian_matrix_ - // force_laplacian_matrix_ -= laplacian_matrix_ * pressure_constraints_; - - // // Apply free surface - // if (!free_surface_.empty()) { - // const auto& nodes = mesh_->nodes(); - // for (const auto& free_node : free_surface_) { - // const auto column_index = nodes[free_node]->active_id(); - // // Modify force_laplacian_matrix - // force_laplacian_matrix_(column_index) = 0; - // // Modify laplacian_matrix - // laplacian_matrix_.row(column_index) *= 0; - // laplacian_matrix_.col(column_index) *= 0; - // laplacian_matrix_.coeffRef(column_index, column_index) = 1; - // } - // // Clear the vector - // free_surface_.clear(); - // } + try { + // Modify poisson_rhs_vector_ + poisson_rhs_vector_ -= laplacian_matrix_ * pressure_constraints_; - // // Iterate over pressure constraints - // for (Eigen::SparseVector::InnerIterator - // it(pressure_constraints_); - // it; ++it) { - // // Modify force_laplacian_matrix - // force_laplacian_matrix_(it.index()) = it.value(); - // // Modify laplacian_matrix - // laplacian_matrix_.row(it.index()) *= 0; - // laplacian_matrix_.col(it.index()) *= 0; - // laplacian_matrix_.coeffRef(it.index(), it.index()) = 1; - // } - // } catch (std::exception& exception) { - // console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - // } + // Apply free surface + if (!free_surface_.empty()) { + const auto& nodes = mesh_->nodes(); + for (const auto& free_node : free_surface_) { + const auto column_index = nodes[free_node]->active_id(); + // Modify poisson_rhs_vector + poisson_rhs_vector_(column_index) = 0; + // Modify laplacian_matrix + laplacian_matrix_.row(column_index) *= 0; + laplacian_matrix_.col(column_index) *= 0; + laplacian_matrix_.coeffRef(column_index, column_index) = 1; + } + // Clear the vector + free_surface_.clear(); + } + + // Apply pressure constraints + for (Eigen::SparseVector::InnerIterator it(pressure_constraints_); + it; ++it) { + // Modify poisson_rhs_vector + poisson_rhs_vector_(it.index()) = it.value(); + // Modify laplacian_matrix + laplacian_matrix_.row(it.index()) *= 0; + laplacian_matrix_.col(it.index()) *= 0; + laplacian_matrix_.coeffRef(it.index(), it.index()) = 1; + } + + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + } } //! Assign pressure constraints diff --git a/include/mesh.h b/include/mesh.h index df97487bc..5c7e77dd8 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -99,6 +99,9 @@ class Mesh { //! Return the number of nodes mpm::Index nnodes() const { return nodes_.size(); } + //! Return container of nodes + mpm::Vector> nodes() { return nodes_; } + //! Iterate over nodes //! \tparam Toper Callable object typically a baseclass functor template diff --git a/include/mesh.tcc b/include/mesh.tcc index 5c0eba770..34bdd3211 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1937,6 +1937,7 @@ std::set mpm::Mesh::free_surface_particles() { return id_set; } +//! FIXME: This function is essentially the same as find_active_nodes() //! Create a list of active nodes in mesh and assign active node id template unsigned mpm::Mesh::assign_active_node_id() { diff --git a/include/particles/fluid_particle.h b/include/particles/fluid_particle.h index 53119f53d..540d82a9b 100644 --- a/include/particles/fluid_particle.h +++ b/include/particles/fluid_particle.h @@ -61,7 +61,7 @@ class FluidParticle : public mpm::Particle { bool map_laplacian_to_cell() override; //! Map poisson rhs element matrix to cell (used in poisson equation RHS) - bool map_poisson_rhs_to_cell() override; + bool map_poisson_right_to_cell() override; //! Map correction matrix element matrix to cell (used to correct velocity) bool map_correction_matrix_to_cell() override; diff --git a/include/particles/fluid_particle.tcc b/include/particles/fluid_particle.tcc index 0776f69da..e97529f23 100644 --- a/include/particles/fluid_particle.tcc +++ b/include/particles/fluid_particle.tcc @@ -116,9 +116,8 @@ template bool mpm::FluidParticle::map_laplacian_to_cell() { bool status = true; try { - // TODO: Tobe uncomment once cell is implemented // Compute local matrix of Laplacian - // cell_->compute_L_element(dn_dx_, volume_, 1.0); + cell_->compute_local_laplacian(dn_dx_, volume_); } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); status = false; @@ -128,15 +127,13 @@ bool mpm::FluidParticle::map_laplacian_to_cell() { //! Map poisson rhs element matrix to cell (used in poisson equation RHS) template -bool mpm::FluidParticle::map_poisson_rhs_to_cell() { +bool mpm::FluidParticle::map_poisson_right_to_cell() { bool status = true; try { - // TODO: Tobe uncomment once cell is implemented - // Compute local matrix of F - // cell_->compute_F_element( - // shapefn_, dn_dx_, - // material_->template property(std::string("density")) * - // volume_); + // Compute local poisson rhs matrix + cell_->compute_local_poisson_right( + shapefn_, dn_dx_, + material_->template property(std::string("density")) * volume_); } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); status = false; diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 45b3988fc..3044d2145 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -291,9 +291,9 @@ class ParticleBase { }; //! Map poisson rhs element matrix to cell (used in poisson equation RHS) - virtual bool map_poisson_rhs_to_cell() { + virtual bool map_poisson_right_to_cell() { throw std::runtime_error( - "Calling the base class function (map_poisson_rhs_to_cell) in " + "Calling the base class function (map_poisson_right_to_cell) in " "ParticleBase:: " "illegal operation!"); return 0; diff --git a/include/solvers/mpm_semi_implicit_navierstokes.tcc b/include/solvers/mpm_semi_implicit_navierstokes.tcc index 2d36d8519..e26885aa0 100644 --- a/include/solvers/mpm_semi_implicit_navierstokes.tcc +++ b/include/solvers/mpm_semi_implicit_navierstokes.tcc @@ -171,8 +171,8 @@ bool mpm::MPMSemiImplicitNavierStokes::solve() { throw std::runtime_error("Reinitialisation of matrix failed"); } - // // Compute poisson equation - // this->compute_poisson_equation(); + // Compute poisson equation + this->compute_poisson_equation(); // // Assign pore pressure to nodes // mesh_->iterate_over_nodes_predicate( @@ -338,29 +338,38 @@ template bool mpm::MPMSemiImplicitNavierStokes::compute_poisson_equation( std::string solver_type) { bool status = true; - // try { - // // Map Laplacian elements - // mesh_->iterate_over_particles(std::bind( - // &mpm::ParticleBase::map_L_to_cell, std::placeholders::_1)); - // // Assemble laplacian matrix - // matrix_assembler_->assemble_laplacian_matrix(dt_); - // // Map Fs & Fm matrix - // mesh_->iterate_over_particles(std::bind( - // &mpm::ParticleBase::map_F_to_cell, std::placeholders::_1)); - // // Assemble force vector - // matrix_assembler_->assemble_poisson_right(mesh_, dt_); - // // Assign free surface - // matrix_assembler_->assign_free_surface(mesh_->free_surface_nodes()); - // // Apply constraints - // matrix_assembler_->apply_pressure_constraints(); - // // Solve matrix equation (compute pore pressure) - // matrix_assembler_->assign_pressure_increment(matrix_solver_->solve( - // matrix_assembler_->laplacian_matrix(), - // matrix_assembler_->force_laplacian_matrix(), solver_type)); - // } catch (std::exception& exception) { - // console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - // status = false; - // } + try { + // Construct local cell laplacian matrix + mesh_->iterate_over_particles( + std::bind(&mpm::ParticleBase::map_laplacian_to_cell, + std::placeholders::_1)); + + // Assemble global laplacian matrix + matrix_assembler_->assemble_laplacian_matrix(dt_); + + // Map Poisson RHS matrix + mesh_->iterate_over_particles( + std::bind(&mpm::ParticleBase::map_poisson_right_to_cell, + std::placeholders::_1)); + + // Assemble poisson RHS vector + matrix_assembler_->assemble_poisson_right(mesh_, dt_); + + // Assign free surface to assembler + matrix_assembler_->assign_free_surface(mesh_->free_surface_nodes()); + + // Apply constraints + matrix_assembler_->apply_pressure_constraints(); + + // Solve matrix equation + matrix_assembler_->assign_pressure_increment(matrix_solver_->solve( + matrix_assembler_->laplacian_matrix(), + matrix_assembler_->poisson_rhs_vector(), solver_type)); + + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } return status; } From a99ad6ab000b372b79191c1ed32bd201fb5c8b54 Mon Sep 17 00:00:00 2001 From: Nanda Date: Sat, 14 Mar 2020 13:35:28 -0700 Subject: [PATCH 15/72] add update pressure increment --- include/node.h | 5 +++- include/node_base.h | 3 +++ include/particles/fluid_particle.tcc | 7 +++-- .../mpm_semi_implicit_navierstokes.tcc | 27 +++++++++---------- 4 files changed, 23 insertions(+), 19 deletions(-) diff --git a/include/node.h b/include/node.h index 46d798e52..d8b3baee5 100644 --- a/include/node.h +++ b/include/node.h @@ -285,11 +285,14 @@ class Node : public NodeBase { const unsigned phase, const double pressure, const std::shared_ptr& function) override; - //! Update pore pressure increment at the node + //! Update pressure increment at the node void update_pressure_increment(const Eigen::VectorXd& pressure_increment, unsigned phase, double current_time = 0.) override; + //! Return nodal pressure increment + double pressure_increment() const override { return pressure_increment_; } + //! Compute navier-stokes semi-implicit acceleration and velocity //! \param[in] phase Index corresponding to the phase //! \param[in] dt Timestep in analysis diff --git a/include/node_base.h b/include/node_base.h index 7a8fa51fa..641a380ec 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -273,6 +273,9 @@ class NodeBase { const Eigen::VectorXd& pressure_increment, unsigned phase, double current_time = 0.) = 0; + //! Return nodal pressure increment + virtual double pressure_increment() const = 0; + }; // NodeBase class } // namespace mpm diff --git a/include/particles/fluid_particle.tcc b/include/particles/fluid_particle.tcc index e97529f23..0b86ba97c 100644 --- a/include/particles/fluid_particle.tcc +++ b/include/particles/fluid_particle.tcc @@ -162,10 +162,9 @@ bool mpm::FluidParticle::compute_updated_pressure() { try { double pressure_increment = 0; - // TODO: Tobe uncomment once node is implemented - // for (unsigned i = 0; i < nodes_.size(); ++i) { - // pressure_increment += shapefn_(i) * nodes_[i]->pressure_increment(); - // } + for (unsigned i = 0; i < nodes_.size(); ++i) { + pressure_increment += shapefn_(i) * nodes_[i]->pressure_increment(); + } // Get interpolated nodal pore pressure state_variables_.at("pressure") = state_variables_.at("pressure") * projection_param_ + diff --git a/include/solvers/mpm_semi_implicit_navierstokes.tcc b/include/solvers/mpm_semi_implicit_navierstokes.tcc index e26885aa0..127d72462 100644 --- a/include/solvers/mpm_semi_implicit_navierstokes.tcc +++ b/include/solvers/mpm_semi_implicit_navierstokes.tcc @@ -174,22 +174,21 @@ bool mpm::MPMSemiImplicitNavierStokes::solve() { // Compute poisson equation this->compute_poisson_equation(); - // // Assign pore pressure to nodes - // mesh_->iterate_over_nodes_predicate( - // std::bind(&mpm::NodeBase::update_pressure_increment, - // std::placeholders::_1, - // matrix_assembler_->pressure_increment(), fluid, - // this->step_ * this->dt_), - // std::bind(&mpm::NodeBase::status, - // std::placeholders::_1)); + // Assign pore pressure to nodes + mesh_->iterate_over_nodes_predicate( + std::bind(&mpm::NodeBase::update_pressure_increment, + std::placeholders::_1, + matrix_assembler_->pressure_increment(), fluid, + this->step_ * this->dt_), + std::bind(&mpm::NodeBase::status, std::placeholders::_1)); - // // Use nodal pressure to update particle pressure - // mesh_->iterate_over_particles( - // std::bind(&mpm::ParticleBase::compute_updated_pressure, - // std::placeholders::_1)); + // Use nodal pressure to update particle pressure + mesh_->iterate_over_particles( + std::bind(&mpm::ParticleBase::compute_updated_pressure, + std::placeholders::_1)); - // // Compute corrected force - // this->compute_corrected_force(); + // // Compute corrected force + // this->compute_corrected_force(); // // Compute corrected acceleration and velocity // mesh_->iterate_over_nodes_predicate( From 953c9da853248e96a6985574c7c17adacce96287 Mon Sep 17 00:00:00 2001 From: Nanda Date: Sat, 14 Mar 2020 22:51:28 -0700 Subject: [PATCH 16/72] compute corrected force - step 1 --- include/cell.h | 12 ++- include/cell.tcc | 33 ++++--- include/linear_solvers/assembler_base.h | 26 +++--- ...sembler_eigen_semi_implicit_navierstokes.h | 28 +++--- ...mbler_eigen_semi_implicit_navierstokes.tcc | 86 +++++++++++-------- include/node.tcc | 2 +- include/node_base.h | 2 +- include/particles/fluid_particle.tcc | 32 +++---- .../solvers/mpm_semi_implicit_navierstokes.h | 2 +- .../mpm_semi_implicit_navierstokes.tcc | 42 ++++----- 10 files changed, 153 insertions(+), 112 deletions(-) diff --git a/include/cell.h b/include/cell.h index fc9fd40e6..104e766d9 100644 --- a/include/cell.h +++ b/include/cell.h @@ -235,7 +235,7 @@ class Cell { //! Return local laplacian const Eigen::MatrixXd& laplacian_matrix() { return laplacian_matrix_; }; - //! Compute local laplacian matrix + //! Compute local laplacian matrix (Used in poisson equation) //! \param[in] grad_shapefn shape function gradient //! \param[in] pvolume volume weight //! \param[in] multiplier multiplier @@ -256,6 +256,14 @@ class Cell { const Eigen::MatrixXd& grad_shapefn, double pvolume) noexcept; + //! Return local correction matrix + const Eigen::MatrixXd& correction_matrix() { return correction_matrix_; }; + + //! Compute local correction matrix (Used to correct velocity) + void compute_local_correction_matrix(const Eigen::VectorXd& shapefn, + const Eigen::MatrixXd& grad_shapefn, + double pvolume) noexcept; + private: //! Approximately check if a point is in a cell //! \param[in] point Coordinates of point @@ -307,6 +315,8 @@ class Cell { Eigen::MatrixXd laplacian_matrix_; //! Local poisson RHS matrix Eigen::MatrixXd poisson_right_matrix_; + //! Local correction RHS matrix + Eigen::MatrixXd correction_matrix_; //! Logger std::unique_ptr console_; }; // Cell class diff --git a/include/cell.tcc b/include/cell.tcc index c42b8f192..b5e52e97e 100644 --- a/include/cell.tcc +++ b/include/cell.tcc @@ -875,15 +875,9 @@ bool mpm::Cell::initialise_element_matrix() { poisson_right_matrix_.resize(nnodes_, nnodes_ * Tdim); poisson_right_matrix_.setZero(); - // // Initialse Fm matrix (NxTdim) - // F_m_element_.resize(nnodes_, nnodes_ * Tdim); - // F_m_element_.setZero(); - - // K_cor_s_element_.resize(nnodes_, nnodes_ * Tdim); - // K_cor_s_element_.setZero(); - - // K_cor_w_element_.resize(nnodes_, nnodes_ * Tdim); - // K_cor_w_element_.setZero(); + // Initialse correction RHS matrix (NxTdim) + correction_matrix_.resize(nnodes_, nnodes_ * Tdim); + correction_matrix_.setZero(); } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); @@ -898,7 +892,7 @@ template void mpm::Cell::compute_local_laplacian( const Eigen::MatrixXd& grad_shapefn, double pvolume, double multiplier) noexcept { - // Lock the storage + std::lock_guard guard(cell_mutex_); laplacian_matrix_ += grad_shapefn * grad_shapefn.transpose() * multiplier * pvolume; @@ -910,13 +904,24 @@ template void mpm::Cell::compute_local_poisson_right( const Eigen::VectorXd& shapefn, const Eigen::MatrixXd& grad_shapefn, double pvolume) noexcept { - // Lock the storage - std::lock_guard guard(cell_mutex_); - // Compute components at nodes + std::lock_guard guard(cell_mutex_); for (unsigned i = 0; i < Tdim; i++) { - // F_s_element poisson_right_matrix_.block(0, i * nnodes_, nnodes_, nnodes_) += shapefn * grad_shapefn.col(i).transpose() * pvolume; } +} + +//! Compute local correction matrix +//! Used to compute corrector of nodal velocity for Navier Stokes solver +template +void mpm::Cell::compute_local_correction_matrix( + const Eigen::VectorXd& shapefn, const Eigen::MatrixXd& grad_shapefn, + double pvolume) noexcept { + + std::lock_guard guard(cell_mutex_); + for (unsigned i = 0; i < Tdim; i++) { + correction_matrix_.block(0, i * nnodes_, nnodes_, nnodes_) += + shapefn * grad_shapefn.col(i).transpose() * pvolume; + } } \ No newline at end of file diff --git a/include/linear_solvers/assembler_base.h b/include/linear_solvers/assembler_base.h index 5272f33e9..9f046ab64 100644 --- a/include/linear_solvers/assembler_base.h +++ b/include/linear_solvers/assembler_base.h @@ -47,10 +47,6 @@ class AssemblerBase { //! Create a pair between nodes and index in Matrix / Vector virtual bool assign_global_node_indices(unsigned active_dof) = 0; - //! Assign pressure constraints - virtual bool assign_pressure_constraints(double beta, - const double current_time) = 0; - //! Assemble laplacian matrix virtual Eigen::SparseMatrix& laplacian_matrix() = 0; @@ -68,12 +64,27 @@ class AssemblerBase { virtual void assign_free_surface( const std::set& free_surface_id) = 0; + //! Assign pressure constraints + virtual bool assign_pressure_constraints(double beta, + const double current_time) = 0; + //! Apply pressure constraints to poisson equation virtual void apply_pressure_constraints() = 0; + //! Return pressure increment + virtual Eigen::VectorXd& pressure_increment() = 0; + + //! Assign pressure increment virtual void assign_pressure_increment( Eigen::VectorXd pressure_increment) = 0; + //! Return correction matrix + virtual Eigen::SparseMatrix& correction_matrix() = 0; + + //! Assemble corrector RHS + virtual bool assemble_corrector_right(std::shared_ptr>& mesh_, + double dt) = 0; + //! Assemble displacement vector // virtual void assemble_disp_vector() = 0; @@ -89,13 +100,6 @@ class AssemblerBase { //! Initialise force vector to zero // virtual void initialise_force_zero() = 0; - virtual bool assemble_K_cor_matrix(std::shared_ptr>& mesh_, - double dt) = 0; - - virtual Eigen::SparseMatrix& K_cor_matrix() = 0; - - virtual Eigen::VectorXd& pressure_increment() = 0; - virtual std::set free_surface() = 0; virtual unsigned active_dof() { return active_dof_; }; diff --git a/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.h b/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.h index cc2374fdc..3b807a7bf 100644 --- a/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.h +++ b/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.h @@ -45,25 +45,29 @@ class AssemblerEigenSemiImplicitNavierStokes : public AssemblerBase { //! Return free surface node id std::set free_surface() override { return free_surface_; } + //! Assign pressure constraints + bool assign_pressure_constraints(double beta, + const double current_time) override; + //! Apply pressure constraints to poisson equation void apply_pressure_constraints(); + //! Return pressure increment + Eigen::VectorXd& pressure_increment() override { return pressure_increment_; } + //! Assign pressure increment void assign_pressure_increment(Eigen::VectorXd pressure_increment) override { pressure_increment_ = pressure_increment; } - //! Return pressure increment - Eigen::VectorXd& pressure_increment() override { return pressure_increment_; } - - Eigen::SparseMatrix& K_cor_matrix() override { return K_cor_matrix_; } - - bool assign_pressure_constraints(double beta, - const double current_time) override; + //! Return correction matrix + Eigen::SparseMatrix& correction_matrix() override { + return correction_matrix_; + } - //! Assemble K_cor matrix (used in correcting nodal velocity) - bool assemble_K_cor_matrix(std::shared_ptr>& mesh_, - double dt) override; + //! Assemble corrector RHS + bool assemble_corrector_right(std::shared_ptr>& mesh_, + double dt) override; protected: //! Logger @@ -84,9 +88,9 @@ class AssemblerEigenSemiImplicitNavierStokes : public AssemblerBase { Eigen::SparseVector pressure_constraints_; //! \delta p^(t+1) = p^(t+1) - beta * p^(t) Eigen::VectorXd pressure_increment_; + //! correction_matrix + Eigen::SparseMatrix correction_matrix_; - //! K_cor_matrix - Eigen::SparseMatrix K_cor_matrix_; //! Laplacian coefficient Eigen::VectorXd poisson_right_vector_; //! Solver base diff --git a/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.tcc b/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.tcc index e3cb51af6..068303805 100644 --- a/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.tcc +++ b/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.tcc @@ -174,42 +174,58 @@ bool mpm::AssemblerEigenSemiImplicitNavierStokes::assemble_poisson_right( //! Assemble K_cor_matrix template -bool mpm::AssemblerEigenSemiImplicitNavierStokes::assemble_K_cor_matrix( - std::shared_ptr>& mesh_, double dt) { +bool mpm::AssemblerEigenSemiImplicitNavierStokes< + Tdim>::assemble_corrector_right(std::shared_ptr>& mesh_, + double dt) { bool status = true; - // try { - // K_cor_matrix_.resize(active_dof_, active_dof_ * Tdim); - // K_cor_matrix_.setZero(); - - // K_cor_matrix_.reserve(Eigen::VectorXi::Constant(active_dof_ * Tdim, 20)); - - // unsigned nnodes_per_cell = global_node_indices_.at(0).size(); - - // const auto& cell = mesh_->cells(); - - // unsigned cid = 0; - // for (auto cell_itr = cell.cbegin(); cell_itr != cell.cend(); ++cell_itr) - // { - // if ((*cell_itr)->status()) { - // auto k_cor_element_water = (*cell_itr)->K_cor_w_element(); - // for (unsigned k = 0; k < Tdim; k++) { - // for (unsigned i = 0; i < nnodes_per_cell; i++) { - // for (unsigned j = 0; j < nnodes_per_cell; j++) { - // // Fluid - // K_cor_matrix_.coeffRef( - // global_node_indices_.at(cid)(i), - // k * active_dof_ + global_node_indices_.at(cid)(j)) += - // k_cor_element_water(i, j + k * nnodes_per_cell); - // } - // } - // } - // cid++; - // } - // } - // } catch (std::exception& exception) { - // console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - // status = false; - // } + try { + // Resize correction matrix + correction_matrix_.resize(active_dof_, active_dof_ * Tdim); + correction_matrix_.setZero(); + + // Reserve storage for sparse matrix + switch (Tdim) { + // For 2d: 10 entries /column + case (2): { + correction_matrix_.reserve( + Eigen::VectorXi::Constant(active_dof_ * Tdim, 10)); + break; + } + // For 3d: 30 entries /column + case (3): { + correction_matrix_.reserve( + Eigen::VectorXi::Constant(active_dof_ * Tdim, 30)); + break; + } + } + + // Cell pointer + unsigned nnodes_per_cell = global_node_indices_.at(0).size(); + const auto& cells = mesh_->cells(); + + // Iterate over cells + unsigned cid = 0; + for (auto cell_itr = cells.cbegin(); cell_itr != cells.cend(); ++cell_itr) { + if ((*cell_itr)->status()) { + auto cell_correction_matrix = (*cell_itr)->correction_matrix(); + for (unsigned k = 0; k < Tdim; k++) { + for (unsigned i = 0; i < nnodes_per_cell; i++) { + for (unsigned j = 0; j < nnodes_per_cell; j++) { + // Fluid + correction_matrix_.coeffRef( + global_node_indices_.at(cid)(i), + k * active_dof_ + global_node_indices_.at(cid)(j)) += + cell_correction_matrix(i, j + k * nnodes_per_cell); + } + } + } + cid++; + } + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } return status; } diff --git a/include/node.tcc b/include/node.tcc index ced10dcca..06998a831 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -576,7 +576,7 @@ bool mpm::Node::assign_pressure_constraint( return status; } -//! Update pore pressure increment at the node +//! Update pressure increment at the node template void mpm::Node::update_pressure_increment( const Eigen::VectorXd& pressure_increment, unsigned phase, diff --git a/include/node_base.h b/include/node_base.h index 641a380ec..14750aa4a 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -268,7 +268,7 @@ class NodeBase { const unsigned phase, double pressure, const std::shared_ptr& function) = 0; - //! Update pore pressure increment at the node + //! Update pressure increment at the node virtual void update_pressure_increment( const Eigen::VectorXd& pressure_increment, unsigned phase, double current_time = 0.) = 0; diff --git a/include/particles/fluid_particle.tcc b/include/particles/fluid_particle.tcc index 0b86ba97c..98eda10aa 100644 --- a/include/particles/fluid_particle.tcc +++ b/include/particles/fluid_particle.tcc @@ -141,21 +141,7 @@ bool mpm::FluidParticle::map_poisson_right_to_cell() { return status; } -//! Map correction matrix element matrix to cell (used to correct velocity) -template -bool mpm::FluidParticle::map_correction_matrix_to_cell() { - bool status = true; - try { - // TODO: Tobe uncomment once cell is implemented - // cell_->compute_K_cor_element(shapefn_, dn_dx_, volume_); - - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - } - return status; -} - -// Compute updated pore pressure of the particle based on nodal pressure +// Compute updated pressure of the particle based on nodal pressure template bool mpm::FluidParticle::compute_updated_pressure() { bool status = true; @@ -165,7 +151,8 @@ bool mpm::FluidParticle::compute_updated_pressure() { for (unsigned i = 0; i < nodes_.size(); ++i) { pressure_increment += shapefn_(i) * nodes_[i]->pressure_increment(); } - // Get interpolated nodal pore pressure + + // Get interpolated nodal pressure state_variables_.at("pressure") = state_variables_.at("pressure") * projection_param_ + pressure_increment; @@ -176,4 +163,17 @@ bool mpm::FluidParticle::compute_updated_pressure() { status = false; } return status; +} + +//! Map correction matrix element matrix to cell (used to correct velocity) +template +bool mpm::FluidParticle::map_correction_matrix_to_cell() { + bool status = true; + try { + cell_->compute_local_correction_matrix(shapefn_, dn_dx_, volume_); + + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + } + return status; } \ No newline at end of file diff --git a/include/solvers/mpm_semi_implicit_navierstokes.h b/include/solvers/mpm_semi_implicit_navierstokes.h index 44d8a7494..c6f74be1f 100644 --- a/include/solvers/mpm_semi_implicit_navierstokes.h +++ b/include/solvers/mpm_semi_implicit_navierstokes.h @@ -47,7 +47,7 @@ class MPMSemiImplicitNavierStokes : public MPMBase { bool compute_poisson_equation(std::string solver_type = "cg"); //! Compute corrected velocity - bool compute_corrected_force(); + bool compute_correction_force(); //! Class private variables private: diff --git a/include/solvers/mpm_semi_implicit_navierstokes.tcc b/include/solvers/mpm_semi_implicit_navierstokes.tcc index 127d72462..64bfd23a9 100644 --- a/include/solvers/mpm_semi_implicit_navierstokes.tcc +++ b/include/solvers/mpm_semi_implicit_navierstokes.tcc @@ -174,7 +174,7 @@ bool mpm::MPMSemiImplicitNavierStokes::solve() { // Compute poisson equation this->compute_poisson_equation(); - // Assign pore pressure to nodes + // Assign pressure to nodes mesh_->iterate_over_nodes_predicate( std::bind(&mpm::NodeBase::update_pressure_increment, std::placeholders::_1, @@ -187,8 +187,8 @@ bool mpm::MPMSemiImplicitNavierStokes::solve() { std::bind(&mpm::ParticleBase::compute_updated_pressure, std::placeholders::_1)); - // // Compute corrected force - // this->compute_corrected_force(); + // Compute corrected force + this->compute_correction_force(); // // Compute corrected acceleration and velocity // mesh_->iterate_over_nodes_predicate( @@ -283,7 +283,7 @@ bool mpm::MPMSemiImplicitNavierStokes::reinitialise_matrix() { // Assign global node indice matrix_assembler_->assign_global_node_indices(nactive_node); - // Assign pressure cpnstraints + // Assign pressure constraints matrix_assembler_->assign_pressure_constraints(this->beta_, this->step_ * this->dt_); @@ -374,22 +374,24 @@ bool mpm::MPMSemiImplicitNavierStokes::compute_poisson_equation( //! Compute corrected force template -bool mpm::MPMSemiImplicitNavierStokes::compute_corrected_force() { +bool mpm::MPMSemiImplicitNavierStokes::compute_correction_force() { bool status = true; - // try { - // mesh_->iterate_over_particles(std::bind( - // &mpm::ParticleBase::map_K_cor_to_cell, - // std::placeholders::_1)); - // // Assemble corrected force matrix - // matrix_assembler_->assemble_K_cor_matrix(mesh_, dt_); - // // Assign corrected force - // mesh_->compute_nodal_corrected_force_navierstokes( - // matrix_assembler_->K_cor_matrix(), - // matrix_assembler_->pressure_increment(), dt_); - - // } catch (std::exception& exception) { - // console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - // status = false; - // } + try { + mesh_->iterate_over_particles( + std::bind(&mpm::ParticleBase::map_correction_matrix_to_cell, + std::placeholders::_1)); + + // Assemble correction matrix + matrix_assembler_->assemble_corrector_right(mesh_, dt_); + + // // Assign corrected force + // mesh_->compute_nodal_corrected_force_navierstokes( + // matrix_assembler_->K_cor_matrix(), + // matrix_assembler_->pressure_increment(), dt_); + + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } return status; } From 8ec176cea12d8b76afbd34c3c7dc4b89d122dd21 Mon Sep 17 00:00:00 2001 From: Nanda Date: Sat, 14 Mar 2020 23:07:34 -0700 Subject: [PATCH 17/72] correction force - step 2 --- ...mbler_eigen_semi_implicit_navierstokes.tcc | 2 +- include/mesh.h | 5 + include/mesh.tcc | 128 ++++++++++++------ include/node.h | 7 +- include/node.tcc | 10 +- include/node_base.h | 8 +- .../mpm_semi_implicit_navierstokes.tcc | 8 +- 7 files changed, 106 insertions(+), 62 deletions(-) diff --git a/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.tcc b/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.tcc index 068303805..45b65543c 100644 --- a/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.tcc +++ b/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.tcc @@ -172,7 +172,7 @@ bool mpm::AssemblerEigenSemiImplicitNavierStokes::assemble_poisson_right( return status; } -//! Assemble K_cor_matrix +//! Assemble corrector right matrix template bool mpm::AssemblerEigenSemiImplicitNavierStokes< Tdim>::assemble_corrector_right(std::shared_ptr>& mesh_, diff --git a/include/mesh.h b/include/mesh.h index 1488025fc..f21ad6809 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -10,6 +10,7 @@ // Eigen #include "Eigen/Dense" +#include // MPI #ifdef USE_MPI #include "mpi.h" @@ -461,6 +462,10 @@ class Mesh { //! Return global node indices std::vector global_node_indices() const; + bool compute_nodal_correction_force( + Eigen::SparseMatrix& correction_matrix, + Eigen::VectorXd& pressure_increment, double dt); + private: // Read particles from file //! \param[in] pset_id Set ID of the particles diff --git a/include/mesh.tcc b/include/mesh.tcc index 946338b12..2494edc26 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -69,27 +69,26 @@ bool mpm::Mesh::remove_node( template template void mpm::Mesh::iterate_over_nodes(Toper oper) { - tbb::parallel_for( - tbb::blocked_range(size_t(0), size_t(nodes_.size()), - tbb_grain_size_), - [&](const tbb::blocked_range& range) { - for (int i = range.begin(); i != range.end(); ++i) oper(nodes_[i]); - }, - tbb::simple_partitioner()); + tbb::parallel_for(tbb::blocked_range(size_t(0), size_t(nodes_.size()), + tbb_grain_size_), + [&](const tbb::blocked_range& range) { + for (int i = range.begin(); i != range.end(); ++i) + oper(nodes_[i]); + }, + tbb::simple_partitioner()); } //! Iterate over nodes template template void mpm::Mesh::iterate_over_nodes_predicate(Toper oper, Tpred pred) { - tbb::parallel_for( - tbb::blocked_range(size_t(0), size_t(nodes_.size()), - tbb_grain_size_), - [&](const tbb::blocked_range& range) { - for (int i = range.begin(); i != range.end(); ++i) - if (pred(nodes_[i])) oper(nodes_[i]); - }, - tbb::simple_partitioner()); + tbb::parallel_for(tbb::blocked_range(size_t(0), size_t(nodes_.size()), + tbb_grain_size_), + [&](const tbb::blocked_range& range) { + for (int i = range.begin(); i != range.end(); ++i) + if (pred(nodes_[i])) oper(nodes_[i]); + }, + tbb::simple_partitioner()); } //! Create a list of active nodes in mesh @@ -278,13 +277,13 @@ bool mpm::Mesh::remove_cell( template template void mpm::Mesh::iterate_over_cells(Toper oper) { - tbb::parallel_for( - tbb::blocked_range(size_t(0), size_t(cells_.size()), - tbb_grain_size_), - [&](const tbb::blocked_range& range) { - for (int i = range.begin(); i != range.end(); ++i) oper(cells_[i]); - }, - tbb::simple_partitioner()); + tbb::parallel_for(tbb::blocked_range(size_t(0), size_t(cells_.size()), + tbb_grain_size_), + [&](const tbb::blocked_range& range) { + for (int i = range.begin(); i != range.end(); ++i) + oper(cells_[i]); + }, + tbb::simple_partitioner()); } //! Create cells from node lists @@ -299,22 +298,21 @@ void mpm::Mesh::find_cell_neighbours() { } // Assign neighbour to cells - tbb::parallel_for( - tbb::blocked_range(size_t(0), size_t(cells_.size()), - tbb_grain_size_), - [&](const tbb::blocked_range& range) { - for (int i = range.begin(); i != range.end(); ++i) { - // Iterate over each node in current cell - for (auto id : cells_[i]->nodes_id()) { - auto cell_id = cells_[i]->id(); - // Get the cells associated with each node - for (auto neighbour_id : node_cell_map[id]) - if (neighbour_id != cell_id) - cells_[i]->add_neighbour(neighbour_id); - } - } - }, - tbb::simple_partitioner()); + tbb::parallel_for(tbb::blocked_range(size_t(0), size_t(cells_.size()), + tbb_grain_size_), + [&](const tbb::blocked_range& range) { + for (int i = range.begin(); i != range.end(); ++i) { + // Iterate over each node in current cell + for (auto id : cells_[i]->nodes_id()) { + auto cell_id = cells_[i]->id(); + // Get the cells associated with each node + for (auto neighbour_id : node_cell_map[id]) + if (neighbour_id != cell_id) + cells_[i]->add_neighbour(neighbour_id); + } + } + }, + tbb::simple_partitioner()); } //! Find particle neighbours for all particle @@ -878,13 +876,13 @@ bool mpm::Mesh::locate_particle_cells( template template void mpm::Mesh::iterate_over_particles(Toper oper) { - tbb::parallel_for( - tbb::blocked_range(size_t(0), size_t(particles_.size()), - tbb_grain_size_), - [&](const tbb::blocked_range& range) { - for (int i = range.begin(); i != range.end(); ++i) oper(particles_[i]); - }, - tbb::simple_partitioner()); + tbb::parallel_for(tbb::blocked_range( + size_t(0), size_t(particles_.size()), tbb_grain_size_), + [&](const tbb::blocked_range& range) { + for (int i = range.begin(); i != range.end(); ++i) + oper(particles_[i]); + }, + tbb::simple_partitioner()); } //! Iterate over particle set @@ -1823,6 +1821,46 @@ bool mpm::Mesh::assign_nodal_friction_constraints( return status; } +//! Compute nodal correction force +template +bool mpm::Mesh::compute_nodal_correction_force( + Eigen::SparseMatrix& correction_matrix, + Eigen::VectorXd& pressure_increment, double dt) { + bool status = true; + try { + //! Active node size + const auto nactive_node = active_nodes_.size(); + + // Part of nodal corrected force of one direction + Eigen::MatrixXd correction_force; + correction_force.resize(nactive_node, Tdim); + + // Iterate over each direction + for (unsigned i = 0; i < Tdim; ++i) { + correction_force.block(0, i, nactive_node, 1) = + -correction_matrix.block(0, nactive_node * i, nactive_node, + nactive_node) * + pressure_increment; + } + + // Iterate over each active node + VectorDim nodal_correction_force; + for (auto nitr = active_nodes_.cbegin(); nitr != active_nodes_.cend(); + ++nitr) { + unsigned active_id = (*nitr)->active_id(); + nodal_correction_force = (correction_force.row(active_id)).transpose(); + + // Compute correction force for each node + map_nodes_[(*nitr)->id()]->compute_nodal_correction_force( + nodal_correction_force); + } + + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + } + return status; +}; + //! Compute free surface cells, nodes, and particles template bool mpm::Mesh::compute_free_surface(double tolerance) { diff --git a/include/node.h b/include/node.h index d8b3baee5..902cfcdfb 100644 --- a/include/node.h +++ b/include/node.h @@ -243,8 +243,9 @@ class Node : public NodeBase { //! Compute nodal density void compute_density() override; - //! Compute nodal corrector force term - bool compute_nodal_corrected_force(VectorDim& force_cor_part_water) override; + //! Compute nodal correction force term + bool compute_nodal_correction_force( + const VectorDim& correction_force) override; //! Assign free surface void assign_free_surface(bool free_surface) override { @@ -360,7 +361,7 @@ class Node : public NodeBase { //! p^(t+1) - beta * p^(t) double pressure_increment_; //! Correction force - Eigen::Matrix force_cor_; + Eigen::Matrix correction_force_; //! Free surface bool free_surface_{false}; }; // Node class diff --git a/include/node.tcc b/include/node.tcc index 06998a831..f19e75b94 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -33,7 +33,7 @@ void mpm::Node::initialise() noexcept { acceleration_.setZero(); free_surface_ = false; pressure_increment_ = 0.; - force_cor_.setZero(); + correction_force_.setZero(); status_ = false; material_ids_.clear(); } @@ -591,13 +591,13 @@ void mpm::Node::update_pressure_increment( //! Compute nodal corrected force template -bool mpm::Node::compute_nodal_corrected_force( - VectorDim& force_cor_part_water) { +bool mpm::Node::compute_nodal_correction_force( + const VectorDim& correction_force) { bool status = true; try { // Compute corrected force for water phase - force_cor_.col(0) = force_cor_part_water; + correction_force_.col(0) = correction_force; } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); status = false; @@ -616,7 +616,7 @@ bool mpm::Node:: // Semi-implicit solver Eigen::Matrix acceleration_corrected = - force_cor_.col(phase) / mass_(phase); + correction_force_.col(phase) / mass_(phase); // Acceleration this->acceleration_.col(phase) += acceleration_corrected; diff --git a/include/node_base.h b/include/node_base.h index 14750aa4a..bbd4a0e09 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -233,10 +233,6 @@ class NodeBase { //! Compute nodal density virtual void compute_density() = 0; - //! Compute nodal corrector force term - virtual bool compute_nodal_corrected_force( - VectorDim& force_cor_part_water) = 0; - //! Assign free surface virtual void assign_free_surface(bool free_surface) = 0; @@ -276,6 +272,10 @@ class NodeBase { //! Return nodal pressure increment virtual double pressure_increment() const = 0; + //! Compute nodal correction force term + virtual bool compute_nodal_correction_force( + const VectorDim& correction_force) = 0; + }; // NodeBase class } // namespace mpm diff --git a/include/solvers/mpm_semi_implicit_navierstokes.tcc b/include/solvers/mpm_semi_implicit_navierstokes.tcc index 64bfd23a9..7db1ddc40 100644 --- a/include/solvers/mpm_semi_implicit_navierstokes.tcc +++ b/include/solvers/mpm_semi_implicit_navierstokes.tcc @@ -384,10 +384,10 @@ bool mpm::MPMSemiImplicitNavierStokes::compute_correction_force() { // Assemble correction matrix matrix_assembler_->assemble_corrector_right(mesh_, dt_); - // // Assign corrected force - // mesh_->compute_nodal_corrected_force_navierstokes( - // matrix_assembler_->K_cor_matrix(), - // matrix_assembler_->pressure_increment(), dt_); + // Assign corrected force + mesh_->compute_nodal_correction_force( + matrix_assembler_->correction_matrix(), + matrix_assembler_->pressure_increment(), dt_); } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); From 8552f8b2deffcb2751ab5b8eb46ac96c3f4ad046 Mon Sep 17 00:00:00 2001 From: Nanda Date: Sat, 14 Mar 2020 23:12:18 -0700 Subject: [PATCH 18/72] update velocity position --- include/mesh.tcc | 88 ++++++++++--------- include/node.tcc | 1 - .../mpm_semi_implicit_navierstokes.tcc | 55 ++++++------ 3 files changed, 72 insertions(+), 72 deletions(-) diff --git a/include/mesh.tcc b/include/mesh.tcc index 2494edc26..3f67bf2c8 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -69,26 +69,27 @@ bool mpm::Mesh::remove_node( template template void mpm::Mesh::iterate_over_nodes(Toper oper) { - tbb::parallel_for(tbb::blocked_range(size_t(0), size_t(nodes_.size()), - tbb_grain_size_), - [&](const tbb::blocked_range& range) { - for (int i = range.begin(); i != range.end(); ++i) - oper(nodes_[i]); - }, - tbb::simple_partitioner()); + tbb::parallel_for( + tbb::blocked_range(size_t(0), size_t(nodes_.size()), + tbb_grain_size_), + [&](const tbb::blocked_range& range) { + for (int i = range.begin(); i != range.end(); ++i) oper(nodes_[i]); + }, + tbb::simple_partitioner()); } //! Iterate over nodes template template void mpm::Mesh::iterate_over_nodes_predicate(Toper oper, Tpred pred) { - tbb::parallel_for(tbb::blocked_range(size_t(0), size_t(nodes_.size()), - tbb_grain_size_), - [&](const tbb::blocked_range& range) { - for (int i = range.begin(); i != range.end(); ++i) - if (pred(nodes_[i])) oper(nodes_[i]); - }, - tbb::simple_partitioner()); + tbb::parallel_for( + tbb::blocked_range(size_t(0), size_t(nodes_.size()), + tbb_grain_size_), + [&](const tbb::blocked_range& range) { + for (int i = range.begin(); i != range.end(); ++i) + if (pred(nodes_[i])) oper(nodes_[i]); + }, + tbb::simple_partitioner()); } //! Create a list of active nodes in mesh @@ -277,13 +278,13 @@ bool mpm::Mesh::remove_cell( template template void mpm::Mesh::iterate_over_cells(Toper oper) { - tbb::parallel_for(tbb::blocked_range(size_t(0), size_t(cells_.size()), - tbb_grain_size_), - [&](const tbb::blocked_range& range) { - for (int i = range.begin(); i != range.end(); ++i) - oper(cells_[i]); - }, - tbb::simple_partitioner()); + tbb::parallel_for( + tbb::blocked_range(size_t(0), size_t(cells_.size()), + tbb_grain_size_), + [&](const tbb::blocked_range& range) { + for (int i = range.begin(); i != range.end(); ++i) oper(cells_[i]); + }, + tbb::simple_partitioner()); } //! Create cells from node lists @@ -298,21 +299,22 @@ void mpm::Mesh::find_cell_neighbours() { } // Assign neighbour to cells - tbb::parallel_for(tbb::blocked_range(size_t(0), size_t(cells_.size()), - tbb_grain_size_), - [&](const tbb::blocked_range& range) { - for (int i = range.begin(); i != range.end(); ++i) { - // Iterate over each node in current cell - for (auto id : cells_[i]->nodes_id()) { - auto cell_id = cells_[i]->id(); - // Get the cells associated with each node - for (auto neighbour_id : node_cell_map[id]) - if (neighbour_id != cell_id) - cells_[i]->add_neighbour(neighbour_id); - } - } - }, - tbb::simple_partitioner()); + tbb::parallel_for( + tbb::blocked_range(size_t(0), size_t(cells_.size()), + tbb_grain_size_), + [&](const tbb::blocked_range& range) { + for (int i = range.begin(); i != range.end(); ++i) { + // Iterate over each node in current cell + for (auto id : cells_[i]->nodes_id()) { + auto cell_id = cells_[i]->id(); + // Get the cells associated with each node + for (auto neighbour_id : node_cell_map[id]) + if (neighbour_id != cell_id) + cells_[i]->add_neighbour(neighbour_id); + } + } + }, + tbb::simple_partitioner()); } //! Find particle neighbours for all particle @@ -876,13 +878,13 @@ bool mpm::Mesh::locate_particle_cells( template template void mpm::Mesh::iterate_over_particles(Toper oper) { - tbb::parallel_for(tbb::blocked_range( - size_t(0), size_t(particles_.size()), tbb_grain_size_), - [&](const tbb::blocked_range& range) { - for (int i = range.begin(); i != range.end(); ++i) - oper(particles_[i]); - }, - tbb::simple_partitioner()); + tbb::parallel_for( + tbb::blocked_range(size_t(0), size_t(particles_.size()), + tbb_grain_size_), + [&](const tbb::blocked_range& range) { + for (int i = range.begin(); i != range.end(); ++i) oper(particles_[i]); + }, + tbb::simple_partitioner()); } //! Iterate over particle set diff --git a/include/node.tcc b/include/node.tcc index f19e75b94..c846874a6 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -614,7 +614,6 @@ bool mpm::Node:: const double tolerance = std::numeric_limits::min(); try { - // Semi-implicit solver Eigen::Matrix acceleration_corrected = correction_force_.col(phase) / mass_(phase); diff --git a/include/solvers/mpm_semi_implicit_navierstokes.tcc b/include/solvers/mpm_semi_implicit_navierstokes.tcc index 7db1ddc40..54b95f5ae 100644 --- a/include/solvers/mpm_semi_implicit_navierstokes.tcc +++ b/include/solvers/mpm_semi_implicit_navierstokes.tcc @@ -190,40 +190,39 @@ bool mpm::MPMSemiImplicitNavierStokes::solve() { // Compute corrected force this->compute_correction_force(); - // // Compute corrected acceleration and velocity - // mesh_->iterate_over_nodes_predicate( - // std::bind( - // &mpm::NodeBase< - // Tdim>::compute_acceleration_velocity_navierstokes_semi_implicit, - // std::placeholders::_1, fluid, this->dt_), - // std::bind(&mpm::NodeBase::status, - // std::placeholders::_1)); - - // // Update particle position and kinematics - // mesh_->iterate_over_particles( - // std::bind(&mpm::ParticleBase::compute_updated_position, - // std::placeholders::_1, this->dt_, velocity_update_)); - - // // Apply particle velocity constraints - // mesh_->apply_particle_velocity_constraints(); + // Compute corrected acceleration and velocity + mesh_->iterate_over_nodes_predicate( + std::bind( + &mpm::NodeBase< + Tdim>::compute_acceleration_velocity_navierstokes_semi_implicit, + std::placeholders::_1, fluid, this->dt_), + std::bind(&mpm::NodeBase::status, std::placeholders::_1)); + + // Update particle position and kinematics + mesh_->iterate_over_particles( + std::bind(&mpm::ParticleBase::compute_updated_position, + std::placeholders::_1, this->dt_, velocity_update_)); + + // Apply particle velocity constraints + mesh_->apply_particle_velocity_constraints(); // // Pressure smoothing // if (pressure_smoothing_) this->pressure_smoothing(fluid); - // // Locate particles - // auto unlocatable_particles = mesh_->locate_particles_mesh(); + // Locate particles + auto unlocatable_particles = mesh_->locate_particles_mesh(); - // if (!unlocatable_particles.empty()) - // throw std::runtime_error("Particle outside the mesh domain"); + if (!unlocatable_particles.empty()) + throw std::runtime_error("Particle outside the mesh domain"); - // if (step_ % output_steps_ == 0) { - // // HDF5 outputs - // this->write_hdf5(this->step_, this->nsteps_); - // #ifdef USE_VTK - // // VTK outputs - // this->write_vtk(this->step_, this->nsteps_); - // #endif - // } + if (step_ % output_steps_ == 0) { + // HDF5 outputs + this->write_hdf5(this->step_, this->nsteps_); +#ifdef USE_VTK + // VTK outputs + this->write_vtk(this->step_, this->nsteps_); +#endif + } } auto solver_end = std::chrono::steady_clock::now(); console_->info("Rank {}, SemiImplicit_NavierStokes {} solver duration: {} ms", From fe75ce9063966c02c7b6195a63a3f5821eeee81c Mon Sep 17 00:00:00 2001 From: Nanda Date: Sat, 14 Mar 2020 23:17:35 -0700 Subject: [PATCH 19/72] add pressure smoothing --- .../mpm_semi_implicit_navierstokes.tcc | 54 +++++++++---------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/include/solvers/mpm_semi_implicit_navierstokes.tcc b/include/solvers/mpm_semi_implicit_navierstokes.tcc index 54b95f5ae..3977552ad 100644 --- a/include/solvers/mpm_semi_implicit_navierstokes.tcc +++ b/include/solvers/mpm_semi_implicit_navierstokes.tcc @@ -206,8 +206,8 @@ bool mpm::MPMSemiImplicitNavierStokes::solve() { // Apply particle velocity constraints mesh_->apply_particle_velocity_constraints(); - // // Pressure smoothing - // if (pressure_smoothing_) this->pressure_smoothing(fluid); + // Pressure smoothing + if (pressure_smoothing_) this->pressure_smoothing(fluid); // Locate particles auto unlocatable_particles = mesh_->locate_particles_mesh(); @@ -303,32 +303,30 @@ template void mpm::MPMSemiImplicitNavierStokes::pressure_smoothing( unsigned phase) { - // // Map pressures to nodes - // mesh_->iterate_over_particles( - // std::bind(&mpm::ParticleBase::map_pressure_to_nodes, - // std::placeholders::_1, this->step_ * this->dt_)); - - // #ifdef USE_MPI - // int mpi_size = 1; - - // // Get number of MPI ranks - // MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); - - // // Run if there is more than a single MPI task - // if (mpi_size > 1) { - // // MPI all reduce nodal pressure - // mesh_->template nodal_halo_exchange( - // std::bind(&mpm::NodeBase::pressure, std::placeholders::_1, - // phase), std::bind(&mpm::NodeBase::assign_pressure, - // std::placeholders::_1, - // phase, std::placeholders::_2)); - // } - // #endif - - // // Map Pressure back to particles - // mesh_->iterate_over_particles( - // std::bind(&mpm::ParticleBase::compute_pressure_smoothing, - // std::placeholders::_1)); + // Map pressures to nodes + mesh_->iterate_over_particles(std::bind( + &mpm::ParticleBase::map_pressure_to_nodes, std::placeholders::_1)); + +#ifdef USE_MPI + int mpi_size = 1; + + // Get number of MPI ranks + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + + // Run if there is more than a single MPI task + if (mpi_size > 1) { + // MPI all reduce nodal pressure + mesh_->template nodal_halo_exchange( + std::bind(&mpm::NodeBase::pressure, std::placeholders::_1, phase), + std::bind(&mpm::NodeBase::assign_pressure, std::placeholders::_1, + phase, std::placeholders::_2)); + } +#endif + + // Map Pressure back to particles + mesh_->iterate_over_particles( + std::bind(&mpm::ParticleBase::compute_pressure_smoothing, + std::placeholders::_1)); } // Compute poisson equation From 3bb5e2edc8d2e8b1127b3d5f39fe3210df0bbeeb Mon Sep 17 00:00:00 2001 From: Nanda Date: Sun, 15 Mar 2020 11:16:32 -0700 Subject: [PATCH 20/72] cleanup --- include/linear_solvers/assembler_base.h | 107 +----------------- ...sembler_eigen_semi_implicit_navierstokes.h | 16 +-- ...mbler_eigen_semi_implicit_navierstokes.tcc | 6 +- include/mesh.tcc | 2 +- include/node.tcc | 4 +- .../mpm_semi_implicit_navierstokes.tcc | 14 +-- 6 files changed, 17 insertions(+), 132 deletions(-) diff --git a/include/linear_solvers/assembler_base.h b/include/linear_solvers/assembler_base.h index 9f046ab64..75185fb3c 100644 --- a/include/linear_solvers/assembler_base.h +++ b/include/linear_solvers/assembler_base.h @@ -57,8 +57,7 @@ class AssemblerBase { virtual Eigen::VectorXd& poisson_rhs_vector() = 0; //! Assemble poisson RHS vector - virtual bool assemble_poisson_right(std::shared_ptr>& mesh_, - double dt) = 0; + virtual bool assemble_poisson_right(double dt) = 0; //! Assign free surface node id virtual void assign_free_surface( @@ -82,115 +81,13 @@ class AssemblerBase { virtual Eigen::SparseMatrix& correction_matrix() = 0; //! Assemble corrector RHS - virtual bool assemble_corrector_right(std::shared_ptr>& mesh_, - double dt) = 0; - - //! Assemble displacement vector - // virtual void assemble_disp_vector() = 0; - - //! Apply displacement to nodes - // virtual void apply_displacement_nodes() = 0; - - //! Apply forces to nodes - // virtual void apply_forces_nodes() = 0; - - //! Apply restraints - // virtual Eigen::VectorXd global_restraints() = 0; - - //! Initialise force vector to zero - // virtual void initialise_force_zero() = 0; - - virtual std::set free_surface() = 0; - - virtual unsigned active_dof() { return active_dof_; }; - - //! Assemble stiffness matrix (semi-implicit) - virtual bool assemble_stiffness_matrix(unsigned dir, double dt) { - throw std::runtime_error( - "Calling the base class function " - "(assemble_stiffness_matrix) in " - "AssemblerBase:: illegal operation!"); - return false; - }; - - //! Assemble force vector (semi-implicit) - virtual bool assemble_force_vector(double dt) { - throw std::runtime_error( - "Calling the base class function " - "(assemble_force_vector) in " - "AssemblerBase:: illegal operation!"); - return false; - }; - - //! Return stiffness matrix - virtual Eigen::SparseMatrix& stiffness_matrix(unsigned dir) { - static Eigen::SparseMatrix error; - throw std::runtime_error( - "Calling the base class function " - "(stiffness_matrix) in " - "AssemblerBase:: illegal operation!"); - return error; - }; - - //! Return intermediate force - virtual Eigen::MatrixXd& force_inter() { - static Eigen::MatrixXd error; - throw std::runtime_error( - "Calling the base class function " - "(force_inter) in " - "AssemblerBase:: illegal operation!"); - return error; - }; - - //! Assign intermediate acceleration - virtual void assign_intermediate_acceleration( - unsigned dim, Eigen::VectorXd acceleration_inter) { - throw std::runtime_error( - "Calling the base class function " - "(assign_intermediate_acceleration) in " - "AssemblerBase:: illegal operation!"); - }; - - //! Return intermediate velocity - virtual Eigen::MatrixXd& acceleration_inter() { - static Eigen::MatrixXd error; - throw std::runtime_error( - "Calling the base class function " - "(acceleration_inter) in " - "AssemblerBase:: illegal operation!"); - return error; - }; - - virtual bool assign_velocity_constraints() { - throw std::runtime_error( - "Calling the base class function " - "(assign_velocity_constraints) in " - "AssemblerBase:: illegal operation!"); - return false; - }; - - //! Apply velocity constraints - virtual bool apply_velocity_constraints() { - throw std::runtime_error( - "Calling the base class function " - "(apply_velocity_constraints) in " - "AssemblerBase:: illegal operation!"); - return false; - }; + virtual bool assemble_corrector_right(double dt) = 0; protected: //! Number of total active_dof unsigned active_dof_; //! Mesh object std::shared_ptr> mesh_; - //! Sparse Stiffness Matrix - std::shared_ptr> stiffness_matrix_; - //! Force vector - std::shared_ptr force_inter_; - //! Intermediate velocity vector - std::shared_ptr velocity_inter_vector_; - //! Displacement vector - std::shared_ptr displacement_vector_; }; } // namespace mpm diff --git a/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.h b/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.h index 3b807a7bf..c6393dff6 100644 --- a/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.h +++ b/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.h @@ -33,8 +33,7 @@ class AssemblerEigenSemiImplicitNavierStokes : public AssemblerBase { Eigen::VectorXd& poisson_rhs_vector() override { return poisson_rhs_vector_; } //! Assemble poisson RHS vector - bool assemble_poisson_right(std::shared_ptr>& mesh_, - double dt) override; + bool assemble_poisson_right(double dt) override; //! Assign free surface node id void assign_free_surface( @@ -42,9 +41,6 @@ class AssemblerEigenSemiImplicitNavierStokes : public AssemblerBase { free_surface_ = free_surface_id; } - //! Return free surface node id - std::set free_surface() override { return free_surface_; } - //! Assign pressure constraints bool assign_pressure_constraints(double beta, const double current_time) override; @@ -66,8 +62,7 @@ class AssemblerEigenSemiImplicitNavierStokes : public AssemblerBase { } //! Assemble corrector RHS - bool assemble_corrector_right(std::shared_ptr>& mesh_, - double dt) override; + bool assemble_corrector_right(double dt) override; protected: //! Logger @@ -90,15 +85,8 @@ class AssemblerEigenSemiImplicitNavierStokes : public AssemblerBase { Eigen::VectorXd pressure_increment_; //! correction_matrix Eigen::SparseMatrix correction_matrix_; - - //! Laplacian coefficient - Eigen::VectorXd poisson_right_vector_; - //! Solver base - std::shared_ptr> solver_; //! Global node indices std::vector global_node_indices_; - //! Velocity constraints - Eigen::SparseMatrix velocity_constraints_; }; } // namespace mpm diff --git a/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.tcc b/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.tcc index 45b65543c..a44cb6d22 100644 --- a/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.tcc +++ b/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.tcc @@ -86,7 +86,7 @@ bool mpm::AssemblerEigenSemiImplicitNavierStokes< template bool mpm::AssemblerEigenSemiImplicitNavierStokes::assemble_poisson_right( - std::shared_ptr>& mesh_, double dt) { + double dt) { bool status = true; try { // Initialise Poisson RHS matrix @@ -175,8 +175,7 @@ bool mpm::AssemblerEigenSemiImplicitNavierStokes::assemble_poisson_right( //! Assemble corrector right matrix template bool mpm::AssemblerEigenSemiImplicitNavierStokes< - Tdim>::assemble_corrector_right(std::shared_ptr>& mesh_, - double dt) { + Tdim>::assemble_corrector_right(double dt) { bool status = true; try { // Resize correction matrix @@ -286,6 +285,7 @@ bool mpm::AssemblerEigenSemiImplicitNavierStokes< // Assign total pressure constraint const double pressure_constraint = (*node)->pressure_constraint(1, current_time); + // Check if there is a pressure constraint if (pressure_constraint != std::numeric_limits::max()) { // Insert the pressure constraints diff --git a/include/mesh.tcc b/include/mesh.tcc index 3f67bf2c8..a4e37c6e1 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1833,7 +1833,7 @@ bool mpm::Mesh::compute_nodal_correction_force( //! Active node size const auto nactive_node = active_nodes_.size(); - // Part of nodal corrected force of one direction + // Part of nodal correction force of one direction Eigen::MatrixXd correction_force; correction_force.resize(nactive_node, Tdim); diff --git a/include/node.tcc b/include/node.tcc index c846874a6..ac0d05752 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -589,14 +589,14 @@ void mpm::Node::update_pressure_increment( this->pressure_increment_ = 0; } -//! Compute nodal corrected force +//! Compute nodal correction force template bool mpm::Node::compute_nodal_correction_force( const VectorDim& correction_force) { bool status = true; try { - // Compute corrected force for water phase + // Compute correction force for water phase correction_force_.col(0) = correction_force; } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); diff --git a/include/solvers/mpm_semi_implicit_navierstokes.tcc b/include/solvers/mpm_semi_implicit_navierstokes.tcc index 3977552ad..3a095d14f 100644 --- a/include/solvers/mpm_semi_implicit_navierstokes.tcc +++ b/include/solvers/mpm_semi_implicit_navierstokes.tcc @@ -187,7 +187,7 @@ bool mpm::MPMSemiImplicitNavierStokes::solve() { std::bind(&mpm::ParticleBase::compute_updated_pressure, std::placeholders::_1)); - // Compute corrected force + // Compute correction force this->compute_correction_force(); // Compute corrected acceleration and velocity @@ -297,8 +297,8 @@ bool mpm::MPMSemiImplicitNavierStokes::reinitialise_matrix() { return status; } -// FIXME: This is a copy of pressure_smoothing in explicit two-phase -//! MPM Explicit two-phase pressure smoothing +// FIXME: This is a copy of pressure_smoothing in MPM explicit +//! Pressure smoothing template void mpm::MPMSemiImplicitNavierStokes::pressure_smoothing( unsigned phase) { @@ -349,7 +349,7 @@ bool mpm::MPMSemiImplicitNavierStokes::compute_poisson_equation( std::placeholders::_1)); // Assemble poisson RHS vector - matrix_assembler_->assemble_poisson_right(mesh_, dt_); + matrix_assembler_->assemble_poisson_right(dt_); // Assign free surface to assembler matrix_assembler_->assign_free_surface(mesh_->free_surface_nodes()); @@ -369,7 +369,7 @@ bool mpm::MPMSemiImplicitNavierStokes::compute_poisson_equation( return status; } -//! Compute corrected force +//! Compute correction force template bool mpm::MPMSemiImplicitNavierStokes::compute_correction_force() { bool status = true; @@ -379,9 +379,9 @@ bool mpm::MPMSemiImplicitNavierStokes::compute_correction_force() { std::placeholders::_1)); // Assemble correction matrix - matrix_assembler_->assemble_corrector_right(mesh_, dt_); + matrix_assembler_->assemble_corrector_right(dt_); - // Assign corrected force + // Assign correction force mesh_->compute_nodal_correction_force( matrix_assembler_->correction_matrix(), matrix_assembler_->pressure_increment(), dt_); From 4f412ed543fc7385b43618e1b2663447bbc6b3cf Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 17 Mar 2020 17:26:06 -0700 Subject: [PATCH 21/72] remove vtk attribute --- include/solvers/mpm_semi_implicit_navierstokes.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/solvers/mpm_semi_implicit_navierstokes.h b/include/solvers/mpm_semi_implicit_navierstokes.h index c6f74be1f..399a026cd 100644 --- a/include/solvers/mpm_semi_implicit_navierstokes.h +++ b/include/solvers/mpm_semi_implicit_navierstokes.h @@ -79,8 +79,6 @@ class MPMSemiImplicitNavierStokes : public MPMBase { using mpm::MPMBase::mesh_; //! Materials using mpm::MPMBase::materials_; - //! VTK attributes - using mpm::MPMBase::vtk_attributes_; //! Pressure smoothing bool pressure_smoothing_{false}; // Projection method paramter (beta) From f87511810971cb4e2e1f3f6e9d5099353fbe3f09 Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 17 Mar 2020 20:51:33 -0700 Subject: [PATCH 22/72] pressure_smoothing --- include/mesh.h | 2 +- include/mesh.tcc | 79 +++++++++---------- include/solvers/mpm_base.h | 4 + include/solvers/mpm_base.tcc | 29 +++++++ include/solvers/mpm_explicit.h | 4 - include/solvers/mpm_explicit.tcc | 29 ------- .../solvers/mpm_semi_implicit_navierstokes.h | 4 - .../mpm_semi_implicit_navierstokes.tcc | 34 +------- 8 files changed, 74 insertions(+), 111 deletions(-) diff --git a/include/mesh.h b/include/mesh.h index 685ea43ab..cc90ba792 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -455,7 +455,7 @@ class Mesh { std::set free_surface_particles(); //! Assign id for active node - unsigned assign_active_node_id(); + unsigned assign_active_nodes_id(); //! Return container of active nodes mpm::Vector> active_nodes() { return active_nodes_; } diff --git a/include/mesh.tcc b/include/mesh.tcc index 20cdf5db9..9986d2fd6 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -102,6 +102,45 @@ void mpm::Mesh::find_active_nodes() { if ((*nitr)->status()) this->active_nodes_.add(*nitr); } +//! Create a list of active nodes in mesh and assign active node id +template +unsigned mpm::Mesh::assign_active_nodes_id() { + // Clear existing list of active nodes + this->active_nodes_.clear(); + Index active_id = 0; + + for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { + if ((*nitr)->status()) { + this->active_nodes_.add(*nitr); + (*nitr)->assign_active_id(active_id); + active_id++; + } else { + (*nitr)->assign_active_id(std::numeric_limits::max()); + } + } + + return active_id; +} + +//! Return global node indices +template +std::vector mpm::Mesh::global_node_indices() const { + // Vector of node_pairs + std::vector node_indices; + try { + // Iterate over cells + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + if ((*citr)->status()) { + node_indices.emplace_back((*citr)->local_node_indices()); + } + } + + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + } + return node_indices; +} + //! Iterate over active nodes template template @@ -2004,43 +2043,3 @@ std::set mpm::Mesh::free_surface_particles() { if ((*pitr)->free_surface()) id_set.insert((*pitr)->id()); return id_set; } - -//! FIXME: This function is essentially the same as find_active_nodes() -//! Create a list of active nodes in mesh and assign active node id -template -unsigned mpm::Mesh::assign_active_node_id() { - // Clear existing list of active nodes - this->active_nodes_.clear(); - Index active_id = 0; - - for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { - if ((*nitr)->status()) { - this->active_nodes_.add(*nitr); - (*nitr)->assign_active_id(active_id); - active_id++; - } else { - (*nitr)->assign_active_id(std::numeric_limits::max()); - } - } - - return active_id; -} - -//! Return global node indices -template -std::vector mpm::Mesh::global_node_indices() const { - // Vector of node_pairs - std::vector node_indices; - try { - // Iterate over cells - for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { - if ((*citr)->status()) { - node_indices.emplace_back((*citr)->local_node_indices()); - } - } - - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - } - return node_indices; -} \ No newline at end of file diff --git a/include/solvers/mpm_base.h b/include/solvers/mpm_base.h index be12f56e3..34cb24070 100644 --- a/include/solvers/mpm_base.h +++ b/include/solvers/mpm_base.h @@ -69,6 +69,10 @@ class MPMBase : public MPM { //! Checkpoint resume bool checkpoint_resume() override; + //! Pressure smoothing + //! \param[in] phase Phase to smooth pressure + void pressure_smoothing(unsigned phase); + #ifdef USE_VTK //! Write VTK files void write_vtk(mpm::Index step, mpm::Index max_steps) override; diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index aff59e877..67e553b12 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -1050,3 +1050,32 @@ bool mpm::MPMBase::initialise_damping(const Json& damping_props) { return status; } + +//! Pressure smoothing +template +void mpm::MPMBase::pressure_smoothing(unsigned phase) { + // Assign pressure to nodes + mesh_->iterate_over_particles(std::bind( + &mpm::ParticleBase::map_pressure_to_nodes, std::placeholders::_1)); + +#ifdef USE_MPI + int mpi_size = 1; + + // Get number of MPI ranks + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + + // Run if there is more than a single MPI task + if (mpi_size > 1) { + // MPI all reduce nodal pressure + mesh_->template nodal_halo_exchange( + std::bind(&mpm::NodeBase::pressure, std::placeholders::_1, phase), + std::bind(&mpm::NodeBase::assign_pressure, std::placeholders::_1, + phase, std::placeholders::_2)); + } +#endif + + // Smooth pressure over particles + mesh_->iterate_over_particles( + std::bind(&mpm::ParticleBase::compute_pressure_smoothing, + std::placeholders::_1)); +} \ No newline at end of file diff --git a/include/solvers/mpm_explicit.h b/include/solvers/mpm_explicit.h index 4dd052390..6a35b8950 100644 --- a/include/solvers/mpm_explicit.h +++ b/include/solvers/mpm_explicit.h @@ -25,10 +25,6 @@ class MPMExplicit : public MPMBase { //! Solve bool solve() override; - //! Pressure smoothing - //! \param[in] phase Phase to smooth pressure - void pressure_smoothing(unsigned phase); - //! Compute stress strain //! \param[in] phase Phase to smooth pressure void compute_stress_strain(unsigned phase); diff --git a/include/solvers/mpm_explicit.tcc b/include/solvers/mpm_explicit.tcc index 03e7a2f8b..4dbb37501 100644 --- a/include/solvers/mpm_explicit.tcc +++ b/include/solvers/mpm_explicit.tcc @@ -59,35 +59,6 @@ void mpm::MPMExplicit::mpi_domain_decompose() { #endif // MPI } -//! MPM Explicit pressure smoothing -template -void mpm::MPMExplicit::pressure_smoothing(unsigned phase) { - // Assign pressure to nodes - mesh_->iterate_over_particles(std::bind( - &mpm::ParticleBase::map_pressure_to_nodes, std::placeholders::_1)); - -#ifdef USE_MPI - int mpi_size = 1; - - // Get number of MPI ranks - MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); - - // Run if there is more than a single MPI task - if (mpi_size > 1) { - // MPI all reduce nodal pressure - mesh_->template nodal_halo_exchange( - std::bind(&mpm::NodeBase::pressure, std::placeholders::_1, phase), - std::bind(&mpm::NodeBase::assign_pressure, std::placeholders::_1, - phase, std::placeholders::_2)); - } -#endif - - // Smooth pressure over particles - mesh_->iterate_over_particles( - std::bind(&mpm::ParticleBase::compute_pressure_smoothing, - std::placeholders::_1)); -} - //! MPM Explicit compute stress strain template void mpm::MPMExplicit::compute_stress_strain(unsigned phase) { diff --git a/include/solvers/mpm_semi_implicit_navierstokes.h b/include/solvers/mpm_semi_implicit_navierstokes.h index 399a026cd..c8abf8ad9 100644 --- a/include/solvers/mpm_semi_implicit_navierstokes.h +++ b/include/solvers/mpm_semi_implicit_navierstokes.h @@ -31,10 +31,6 @@ class MPMSemiImplicitNavierStokes : public MPMBase { //! Solve bool solve() override; - //! Pressure smoothing - //! \param[in] phase Phase to smooth pressure - void pressure_smoothing(unsigned phase); - //! Class private functions private: //! Initialise matrix diff --git a/include/solvers/mpm_semi_implicit_navierstokes.tcc b/include/solvers/mpm_semi_implicit_navierstokes.tcc index 3a095d14f..8d24a4858 100644 --- a/include/solvers/mpm_semi_implicit_navierstokes.tcc +++ b/include/solvers/mpm_semi_implicit_navierstokes.tcc @@ -277,7 +277,7 @@ bool mpm::MPMSemiImplicitNavierStokes::reinitialise_matrix() { bool status = true; try { // Assigning matrix id - const auto nactive_node = mesh_->assign_active_node_id(); + const auto nactive_node = mesh_->assign_active_nodes_id(); // Assign global node indice matrix_assembler_->assign_global_node_indices(nactive_node); @@ -297,38 +297,6 @@ bool mpm::MPMSemiImplicitNavierStokes::reinitialise_matrix() { return status; } -// FIXME: This is a copy of pressure_smoothing in MPM explicit -//! Pressure smoothing -template -void mpm::MPMSemiImplicitNavierStokes::pressure_smoothing( - unsigned phase) { - - // Map pressures to nodes - mesh_->iterate_over_particles(std::bind( - &mpm::ParticleBase::map_pressure_to_nodes, std::placeholders::_1)); - -#ifdef USE_MPI - int mpi_size = 1; - - // Get number of MPI ranks - MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); - - // Run if there is more than a single MPI task - if (mpi_size > 1) { - // MPI all reduce nodal pressure - mesh_->template nodal_halo_exchange( - std::bind(&mpm::NodeBase::pressure, std::placeholders::_1, phase), - std::bind(&mpm::NodeBase::assign_pressure, std::placeholders::_1, - phase, std::placeholders::_2)); - } -#endif - - // Map Pressure back to particles - mesh_->iterate_over_particles( - std::bind(&mpm::ParticleBase::compute_pressure_smoothing, - std::placeholders::_1)); -} - // Compute poisson equation template bool mpm::MPMSemiImplicitNavierStokes::compute_poisson_equation( From 1d5227239c08dfe31ee3ec080d8821b16fc089f2 Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 17 Mar 2020 20:55:16 -0700 Subject: [PATCH 23/72] minor cleanup --- include/mesh.tcc | 3 --- include/particles/fluid_particle.tcc | 10 ---------- include/solvers/mpm_base.tcc | 4 ---- 3 files changed, 17 deletions(-) diff --git a/include/mesh.tcc b/include/mesh.tcc index 9986d2fd6..0d9389938 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1033,7 +1033,6 @@ template bool mpm::Mesh::assign_particles_volumes( const std::vector>& particle_volumes) { bool status = true; - const unsigned phase = 0; try { if (!particles_.size()) throw std::runtime_error( @@ -1280,8 +1279,6 @@ template bool mpm::Mesh::assign_particles_stresses( const std::vector>& particle_stresses) { bool status = true; - // TODO: Remove phase - const unsigned phase = 0; try { if (!particles_.size()) throw std::runtime_error( diff --git a/include/particles/fluid_particle.tcc b/include/particles/fluid_particle.tcc index 98eda10aa..bfa7e3428 100644 --- a/include/particles/fluid_particle.tcc +++ b/include/particles/fluid_particle.tcc @@ -3,16 +3,6 @@ template mpm::FluidParticle::FluidParticle(Index id, const VectorDim& coord) : mpm::Particle(id, coord) { - // Initialize vector data properties - this->properties_["pressure"] = [&]() { - Eigen::VectorXd vec_pressure = Eigen::VectorXd::Zero(3); - vec_pressure[0] = this->pressure(); - // FIXME: This is to check free surface particles - // TODO: To be removed somewhere - vec_pressure[1] = this->free_surface(); - return vec_pressure; - }; - // Logger std::string logger = "FluidParticle" + std::to_string(Tdim) + "d::" + std::to_string(id); diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index 67e553b12..dfa01b08e 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -105,8 +105,6 @@ mpm::MPMBase::MPMBase(const std::shared_ptr& io) : mpm::MPM(io) { // Initialise mesh template bool mpm::MPMBase::initialise_mesh() { - // TODO: Fix phase - const unsigned phase = 0; bool status = true; try { @@ -222,8 +220,6 @@ bool mpm::MPMBase::initialise_mesh() { // Initialise particles template bool mpm::MPMBase::initialise_particles() { - // TODO: Fix phase - const unsigned phase = 0; bool status = true; try { From c69acfa3ff9db4ab2929c5af72b6201a3eb8ad79 Mon Sep 17 00:00:00 2001 From: Nanda Date: Thu, 19 Mar 2020 20:19:19 -0700 Subject: [PATCH 24/72] adding LES turbulent viscosity --- include/particles/fluid_particle.tcc | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/include/particles/fluid_particle.tcc b/include/particles/fluid_particle.tcc index bfa7e3428..7c04e3d16 100644 --- a/include/particles/fluid_particle.tcc +++ b/include/particles/fluid_particle.tcc @@ -27,7 +27,29 @@ Eigen::Matrix Eigen::Matrix tstress; tstress.setZero(); - // TODO: To be implemented + // Apply LES Smagorinsky closure + const double smagorinsky_constant = 0.2; + const double grid_spacing = std::pow(cell_->volume(), 1 / (double)Tdim); + const auto strain_rate = this->strain_rate(); + double local_strain_rate = 0.0; + local_strain_rate += + 2 * (strain_rate[0] * strain_rate[0] + strain_rate[1] * strain_rate[1] + + strain_rate[2] * strain_rate[2]) + + strain_rate[3] * strain_rate[3] + strain_rate[4] * strain_rate[4] + + strain_rate[5] * strain_rate[5]; + local_strain_rate = std::sqrt(local_strain_rate); + + // Turbulent Eddy Viscosity + const double turbulent_viscosity = + std::pow(smagorinsky_constant * grid_spacing, 2) * local_strain_rate; + + // Turbulent stress + tstress(0) = 2. * turbulent_viscosity / mass_density_ * strain_rate(0); + tstress(1) = 2. * turbulent_viscosity / mass_density_ * strain_rate(1); + tstress(2) = 2. * turbulent_viscosity / mass_density_ * strain_rate(2); + tstress(3) = turbulent_viscosity / mass_density_ * strain_rate(3); + tstress(4) = turbulent_viscosity / mass_density_ * strain_rate(4); + tstress(5) = turbulent_viscosity / mass_density_ * strain_rate(5); return tstress; } From 290d53ac3fc6c64d937f2fc946dd5da1e29458bd Mon Sep 17 00:00:00 2001 From: Nanda Date: Fri, 20 Mar 2020 21:20:19 -0700 Subject: [PATCH 25/72] move locate particle inside solver --- include/solvers/mpm_base.h | 12 ++++++++---- include/solvers/mpm_base.tcc | 14 ++++++++++++++ include/solvers/mpm_explicit.tcc | 11 ++--------- include/solvers/mpm_semi_implicit_navierstokes.tcc | 7 ++----- 4 files changed, 26 insertions(+), 18 deletions(-) diff --git a/include/solvers/mpm_base.h b/include/solvers/mpm_base.h index 34cb24070..a78b4d86f 100644 --- a/include/solvers/mpm_base.h +++ b/include/solvers/mpm_base.h @@ -69,10 +69,6 @@ class MPMBase : public MPM { //! Checkpoint resume bool checkpoint_resume() override; - //! Pressure smoothing - //! \param[in] phase Phase to smooth pressure - void pressure_smoothing(unsigned phase); - #ifdef USE_VTK //! Write VTK files void write_vtk(mpm::Index step, mpm::Index max_steps) override; @@ -86,6 +82,14 @@ class MPMBase : public MPM { //! Write HDF5 files void write_hdf5(mpm::Index step, mpm::Index max_steps) override; + protected: + //! Pressure smoothing + //! \param[in] phase Phase to smooth pressure + void pressure_smoothing(unsigned phase); + + //! Locate particle + void locate_particle(); + private: //! Return if a mesh will be isoparametric or not //! \retval isoparametric Status of mesh type diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index dfa01b08e..a0f8b5b33 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -1074,4 +1074,18 @@ void mpm::MPMBase::pressure_smoothing(unsigned phase) { mesh_->iterate_over_particles( std::bind(&mpm::ParticleBase::compute_pressure_smoothing, std::placeholders::_1)); +} + +//! Locate particle +template +void mpm::MPMBase::locate_particle() { + // Locate particle + auto unlocatable_particles = mesh_->locate_particles_mesh(); + + if (!unlocatable_particles.empty() && this->locate_particles_) + throw std::runtime_error("Particle outside the mesh domain"); + // If unable to locate particles remove particles + if (!unlocatable_particles.empty() && !this->locate_particles_) + for (const auto& remove_particle : unlocatable_particles) + mesh_->remove_particle(remove_particle); } \ No newline at end of file diff --git a/include/solvers/mpm_explicit.tcc b/include/solvers/mpm_explicit.tcc index 4dbb37501..546837e38 100644 --- a/include/solvers/mpm_explicit.tcc +++ b/include/solvers/mpm_explicit.tcc @@ -291,15 +291,8 @@ bool mpm::MPMExplicit::solve() { if (this->stress_update_ == mpm::StressUpdate::USL) this->compute_stress_strain(phase); - // Locate particles - auto unlocatable_particles = mesh_->locate_particles_mesh(); - - if (!unlocatable_particles.empty() && this->locate_particles_) - throw std::runtime_error("Particle outside the mesh domain"); - // If unable to locate particles remove particles - if (!unlocatable_particles.empty() && !this->locate_particles_) - for (const auto& remove_particle : unlocatable_particles) - mesh_->remove_particle(remove_particle); + // Locate particle + this->locate_particle(); #ifdef USE_MPI #ifdef USE_GRAPH_PARTITIONING diff --git a/include/solvers/mpm_semi_implicit_navierstokes.tcc b/include/solvers/mpm_semi_implicit_navierstokes.tcc index 8d24a4858..0b50006e1 100644 --- a/include/solvers/mpm_semi_implicit_navierstokes.tcc +++ b/include/solvers/mpm_semi_implicit_navierstokes.tcc @@ -209,11 +209,8 @@ bool mpm::MPMSemiImplicitNavierStokes::solve() { // Pressure smoothing if (pressure_smoothing_) this->pressure_smoothing(fluid); - // Locate particles - auto unlocatable_particles = mesh_->locate_particles_mesh(); - - if (!unlocatable_particles.empty()) - throw std::runtime_error("Particle outside the mesh domain"); + // Locate particle + this->locate_particle(); if (step_ % output_steps_ == 0) { // HDF5 outputs From 5eabcdc91cd04d250916f08db48dc22e53f6ab1f Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 25 Mar 2020 19:47:57 -0700 Subject: [PATCH 26/72] add framework compute_free_surface based on geom --- include/mesh.tcc | 253 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 189 insertions(+), 64 deletions(-) diff --git a/include/mesh.tcc b/include/mesh.tcc index 0d9389938..1da173c1a 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1909,6 +1909,8 @@ bool mpm::Mesh::compute_free_surface(double tolerance) { this->iterate_over_cells(std::bind(&mpm::Cell::assign_free_surface, std::placeholders::_1, false)); + // First, we detect the cell with possible free surfaces through volume + // fraction // Reset volume fraction this->iterate_over_cells(std::bind(&mpm::Cell::assign_volume_fraction, std::placeholders::_1, 0.0)); @@ -1928,84 +1930,91 @@ bool mpm::Mesh::compute_free_surface(double tolerance) { } // Compute boundary cells and nodes based on geometry - std::set boundary_cells; - std::set boundary_nodes; + std::set free_surface_candidate_cells; for (auto citr = this->cells_.cbegin(); citr != this->cells_.cend(); ++citr) { - + // Cell contains particles if ((*citr)->status()) { - bool cell_at_interface = false; - const auto& node_id = (*citr)->nodes_id(); - bool internal = true; - - //! Check internal cell - for (const auto c_id : (*citr)->neighbours()) { - if (!map_cells_[c_id]->status()) { - internal = false; - break; + bool candidate_cell = false; + // Check volume fraction only for boundary cell + if ((*citr)->volume_fraction() < tolerance) { + candidate_cell = true; + } else { + // Loop over neighbouring cells, if volume fraction is above + // tolerance, but a free surface cell + for (const auto n_id : (*citr)->neighbours()) { + if (map_cells_[n_id]->volume_fraction() < tolerance) { + candidate_cell = true; + break; + } } } - //! Check volume fraction only for boundary cell - if (!internal) { - if ((*citr)->volume_fraction() < tolerance) { - cell_at_interface = true; - for (const auto id : node_id) { - map_nodes_[id]->assign_free_surface(cell_at_interface); - boundary_nodes.insert(id); - } - } else { - for (const auto n_id : (*citr)->neighbours()) { - if (map_cells_[n_id]->volume_fraction() < tolerance) { - cell_at_interface = true; - const auto& n_node_id = map_cells_[n_id]->nodes_id(); - - // Detect common node id - std::set common_node_id; - std::set_intersection( - node_id.begin(), node_id.end(), n_node_id.begin(), - n_node_id.end(), - std::inserter(common_node_id, common_node_id.begin())); - - // Assign free surface nodes - if (!common_node_id.empty()) { - for (const auto common_id : common_node_id) { - map_nodes_[common_id]->assign_free_surface( - cell_at_interface); - boundary_nodes.insert(common_id); - } - } - } - } - } + // Assign free surface cell + if (candidate_cell) { + (*citr)->assign_free_surface(candidate_cell); + free_surface_candidate_cells.insert((*citr)->id()); - // Assign free surface cell - if (cell_at_interface) { - (*citr)->assign_free_surface(cell_at_interface); - boundary_cells.insert((*citr)->id()); + // FIXME: Assigned all FS Cell nodes to be free surface node (to be + // removed/optimized) + const auto& node_id = (*citr)->nodes_id(); + for (const auto id : node_id) { + map_nodes_[id]->assign_free_surface(candidate_cell); } } } } - // Compute boundary particles based on density function - // Lump cell volume to nodes - this->iterate_over_cells(std::bind( - &mpm::Cell::map_cell_volume_to_nodes, std::placeholders::_1, 0)); - - // Compute nodal value of mass density - this->iterate_over_nodes_predicate( - std::bind(&mpm::NodeBase::compute_density, std::placeholders::_1), - std::bind(&mpm::NodeBase::status, std::placeholders::_1)); + // Compute particle neighbours for particles at candidate cells + std::vector free_surface_candidate_particles; + for (const auto cell_id : free_surface_candidate_cells) { + this->find_particle_neighbours(map_cells_[cell_id]); + const auto& particle_ids = map_cells_[cell_id]->particles(); + free_surface_candidate_particles.insert( + free_surface_candidate_particles.end(), particle_ids.begin(), + particle_ids.end()); + } - // Evaluate free surface particles - this->iterate_over_particles(std::bind( - &mpm::ParticleBase::compute_free_surface, std::placeholders::_1)); + // Find free surface particles through geometry + std::set free_surface_particles; + for (const auto p_id : free_surface_candidate_particles) { + // Initialize renormalization matrix + Eigen::Matrix renormalization_matrix; + renormalization_matrix.setZero(); + + // Loop over neighbours + const auto& p_coord = map_particles_[p_id]->coordinates(); + const auto& neighbour_particles = map_particles_[p_id]->neighbours(); + for (const auto n_id : neighbour_particles) { + const auto& n_coord = map_particles_[n_id]->coordinates(); + const VectorDim rel_coord = n_coord - p_coord; + const double rel_distance = rel_coord.norm(); + } - // Assign pressure at free surface to be zero - std::set boundary_particles = this->free_surface_particles(); - for (const auto boundary_particle : boundary_particles) - map_particles_[boundary_particle]->initial_pressure(0.0); + // Matrix inversion to get renormalization_matrix + + // Find matrix eigenvalue + + // Categorize based on lambda + double lambda = 0; + bool secondary_check = false; + if (lambda <= 0.2) + free_surface_particles.insert(p_id); + else if (lambda > 0.2 && lambda <= 0.75) + secondary_check = true; + + // If secondary check is needed + if (secondary_check) { + // Compute numerical normal vector + VectorDim normal; + for (const auto n_id : neighbour_particles) { + const auto& n_coord = map_particles_[n_id]->coordinates(); + const VectorDim rel_coord = n_coord - p_coord; + const double rel_distance = rel_coord.norm(); + } + normal *= 1. / normal.norm(); + } + } } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); @@ -2013,6 +2022,122 @@ bool mpm::Mesh::compute_free_surface(double tolerance) { return status; } +// //! Compute free surface cells, nodes, and particles +// template +// bool mpm::Mesh::compute_free_surface(double tolerance) { +// bool status = true; +// try { +// // Reset free surface cell +// this->iterate_over_cells(std::bind(&mpm::Cell::assign_free_surface, +// std::placeholders::_1, false)); + +// // Reset volume fraction +// this->iterate_over_cells(std::bind(&mpm::Cell::assign_volume_fraction, +// std::placeholders::_1, 0.0)); + +// // Compute and assign volume fraction to each cell +// for (auto citr = this->cells_.cbegin(); citr != this->cells_.cend(); +// ++citr) { +// if ((*citr)->status()) { +// // Compute volume fraction +// double cell_volume_fraction = 0.0; +// for (const auto p_id : (*citr)->particles()) +// cell_volume_fraction += map_particles_[p_id]->volume(); + +// cell_volume_fraction = cell_volume_fraction / (*citr)->volume(); +// (*citr)->assign_volume_fraction(cell_volume_fraction); +// } +// } + +// // Compute boundary cells and nodes based on geometry +// std::set boundary_cells; +// std::set boundary_nodes; +// for (auto citr = this->cells_.cbegin(); citr != this->cells_.cend(); +// ++citr) { + +// if ((*citr)->status()) { +// bool cell_at_interface = false; +// const auto& node_id = (*citr)->nodes_id(); +// bool internal = true; + +// //! Check internal cell +// for (const auto c_id : (*citr)->neighbours()) { +// if (!map_cells_[c_id]->status()) { +// internal = false; +// break; +// } +// } + +// //! Check volume fraction only for boundary cell +// if (!internal) { +// if ((*citr)->volume_fraction() < tolerance) { +// cell_at_interface = true; +// for (const auto id : node_id) { +// map_nodes_[id]->assign_free_surface(cell_at_interface); +// boundary_nodes.insert(id); +// } +// } else { +// for (const auto n_id : (*citr)->neighbours()) { +// if (map_cells_[n_id]->volume_fraction() < tolerance) { +// cell_at_interface = true; +// const auto& n_node_id = map_cells_[n_id]->nodes_id(); + +// // Detect common node id +// std::set common_node_id; +// std::set_intersection( +// node_id.begin(), node_id.end(), n_node_id.begin(), +// n_node_id.end(), +// std::inserter(common_node_id, common_node_id.begin())); + +// // Assign free surface nodes +// if (!common_node_id.empty()) { +// for (const auto common_id : common_node_id) { +// map_nodes_[common_id]->assign_free_surface( +// cell_at_interface); +// boundary_nodes.insert(common_id); +// } +// } +// } +// } +// } + +// // Assign free surface cell +// if (cell_at_interface) { +// (*citr)->assign_free_surface(cell_at_interface); +// boundary_cells.insert((*citr)->id()); +// } +// } +// } +// } + +// // Compute boundary particles based on density function +// // Lump cell volume to nodes +// this->iterate_over_cells(std::bind( +// &mpm::Cell::map_cell_volume_to_nodes, std::placeholders::_1, +// 0)); + +// // Compute nodal value of mass density +// this->iterate_over_nodes_predicate( +// std::bind(&mpm::NodeBase::compute_density, +// std::placeholders::_1), std::bind(&mpm::NodeBase::status, +// std::placeholders::_1)); + +// // Evaluate free surface particles +// this->iterate_over_particles(std::bind( +// &mpm::ParticleBase::compute_free_surface, +// std::placeholders::_1)); + +// // Assign pressure at free surface to be zero +// std::set boundary_particles = this->free_surface_particles(); +// for (const auto boundary_particle : boundary_particles) +// map_particles_[boundary_particle]->initial_pressure(0.0); + +// } catch (std::exception& exception) { +// console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); +// } +// return status; +// } + //! Get free surface node set template std::set mpm::Mesh::free_surface_nodes() { From 94a6fba10cb36b13e235231f39f9ef0d60018471 Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 25 Mar 2020 20:18:31 -0700 Subject: [PATCH 27/72] add RBF --- include/utilities/radial_basis_function.h | 132 ++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 include/utilities/radial_basis_function.h diff --git a/include/utilities/radial_basis_function.h b/include/utilities/radial_basis_function.h new file mode 100644 index 000000000..b6dbc88bd --- /dev/null +++ b/include/utilities/radial_basis_function.h @@ -0,0 +1,132 @@ +#ifndef MPM_RADIAL_BASIS_FUNCTION_H_ +#define MPM_RADIAL_BASIS_FUNCTION_H_ + +#include + +#include "Eigen/Dense" + +#include "logger.h" + +namespace mpm { + +// Namespace for radial basis function handling +namespace RadialBasisFunction { +//! Cubic Spline Radial Basis Function +//! Source: Monaghan, 1985; Monaghan, 1992 +template +double cubic_spline(const double& smoothing_length, + const double& norm_distance) { + + // Assign multiplier depends on dimension + double multiplier; + if (Tdim == 2) + multiplier = 15.0 / (7.0 * M_PI * std::pow(smoothing_length, 2)); + else if (Tdim == 3) + multiplier = 3.0 / (2.0 * M_PI * std::pow(smoothing_length, 3)); + else + throw std::runtime_error("Tdim is invalid"); + + // Compute basis function + double basis_function = multiplier; + const double radius = norm_distance / smoothing_length; + if (radius >= 0.0 && radius < 1.0) + basis_function *= + 2.0 / 3.0 - std::pow(radius, 2) + 0.5 * std::pow(radius, 3); + else if (radius >= 1.0 && radius < 2.0) + basis_function *= 1.0 / 6.0 * std::pow((2.0 - radius), 3); + else + basis_function = 0.0; + + return basis_function; +} + +//! Quintic Spline Radial Basis Function +//! Source: Liu, 2010 +template +double quintic_spline(const double& smoothing_length, + const double& norm_distance) { + + // Assign multiplier depends on dimension + double multiplier; + if (Tdim == 2) + multiplier = 1.0 / (478.0 * M_PI * std::pow(smoothing_length, 2)); + else if (Tdim == 3) + multiplier = 3.0 / (359.0 * M_PI * std::pow(smoothing_length, 3)); + else + throw std::runtime_error("Tdim is invalid"); + + // Compute basis function + double basis_function = multiplier; + const double radius = norm_distance / smoothing_length; + if (radius >= 0.0 && radius < 1.0) + basis_function *= + (std::pow(3.0 - radius, 5) - 6 * std::pow(2.0 - radius, 5) + + 15 * std::pow(1.0 - radius, 5)); + else if (radius >= 1.0 && radius < 2.0) + basis_function *= + (std::pow(3.0 - radius, 5) - 6 * std::pow(2.0 - radius, 5)); + else if (radius >= 2.0 && radius < 3.0) + basis_function *= (std::pow(3.0 - radius, 5)); + else + basis_function = 0.0; + + return basis_function; +} + +//! Gaussian Kernel +//! Source: Liu, 2010 +template +double gaussian_kernel(const double& smoothing_length, + const double& norm_distance) { + + // Assign multiplier depends on dimension + double multiplier; + if (Tdim == 2) + multiplier = 1.0 / (M_PI * std::pow(smoothing_length, 2)); + else if (Tdim == 3) + multiplier = 1.0 / std::pow((std::sqrt(M_PI) * smoothing_length), 3); + else + throw std::runtime_error("Tdim is invalid"); + + // Compute basis function + double basis_function = multiplier; + const double radius = norm_distance / smoothing_length; + if (radius >= 0.0 && radius < 3.0) + basis_function *= std::exp(-std::pow(radius, 2)); + else + basis_function = 0.0; + + return basis_function; +} + +//! Super Gaussian Kernel +//! Source: Monaghan, 1992 +template +double super_gaussian_kernel(const double& smoothing_length, + const double& norm_distance) { + + // Assign multiplier depends on dimension + double multiplier; + if (Tdim == 2) + multiplier = 1.0 / std::pow((std::sqrt(M_PI) * smoothing_length), 2); + else if (Tdim == 3) + multiplier = 1.0 / std::pow((std::sqrt(M_PI) * smoothing_length), 3); + else + throw std::runtime_error("Tdim is invalid"); + + // Compute basis function + double basis_function = multiplier; + const double radius = norm_distance / smoothing_length; + if (radius >= 0.0 && radius < 3.0) + basis_function *= + std::exp(-std::pow(radius, 2)) * (Tdim / 2.0 + 1.0 - radius * radius); + else + basis_function = 0.0; + + return basis_function; +} + +} // namespace RadialBasisFunction + +} // namespace mpm +#endif \ No newline at end of file From 82d4a9fc69715c653a65c45e45224c2294e92e24 Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 25 Mar 2020 23:23:14 -0700 Subject: [PATCH 28/72] add RBF kernel --- CMakeLists.txt | 1 + include/mesh.h | 1 + include/utilities/radial_basis_function.h | 25 +++++++++++++++++++++++ 3 files changed, 27 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index eb0a7118f..88e8dc6c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -153,6 +153,7 @@ include_directories(BEFORE ${mpm_SOURCE_DIR}/include/materials/ ${mpm_SOURCE_DIR}/include/particles/ ${mpm_SOURCE_DIR}/include/solvers/ + ${mpm_SOURCE_DIR}/include/utilities/ ${mpm_SOURCE_DIR}/external/ ${mpm_SOURCE_DIR}/tests/include/ ) diff --git a/include/mesh.h b/include/mesh.h index cc90ba792..147826d62 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -39,6 +39,7 @@ using Json = nlohmann::json; #include "node.h" #include "particle.h" #include "particle_base.h" +#include "radial_basis_function.h" #include "traction.h" #include "vector.h" #include "velocity_constraint.h" diff --git a/include/utilities/radial_basis_function.h b/include/utilities/radial_basis_function.h index b6dbc88bd..662d7ccbc 100644 --- a/include/utilities/radial_basis_function.h +++ b/include/utilities/radial_basis_function.h @@ -11,6 +11,7 @@ namespace mpm { // Namespace for radial basis function handling namespace RadialBasisFunction { + //! Cubic Spline Radial Basis Function //! Source: Monaghan, 1985; Monaghan, 1992 template @@ -126,6 +127,30 @@ double super_gaussian_kernel(const double& smoothing_length, return basis_function; } +//! General Radial Basis Function Kernel call +template +double kernel(const double& smoothing_length, const double& norm_distance, + const std::string type) { + if (type == "cubic_spline") { + return mpm::RadialBasisFunction::cubic_spline(smoothing_length, + norm_distance); + } else if (type == "quintic_spline") { + return mpm::RadialBasisFunction::quintic_spline(smoothing_length, + norm_distance); + } else if (type == "gaussian") { + return mpm::RadialBasisFunction::gaussian_kernel(smoothing_length, + norm_distance); + } else if (type == "super_gaussian") { + return mpm::RadialBasisFunction::super_gaussian_kernel( + smoothing_length, norm_distance); + } else { + throw std::runtime_error( + "RadialBasisFunction kernel type is invalid. Available types are: " + "\"cubic_spline\", \"quintic_spline\", \"gaussian\", and, " + "\"super_gaussian\"."); + } +} + } // namespace RadialBasisFunction } // namespace mpm From 2280ff70d00cc065e0b126f000e1225479934689 Mon Sep 17 00:00:00 2001 From: Nanda Date: Thu, 26 Mar 2020 15:47:57 -0700 Subject: [PATCH 29/72] add gradient RBF --- include/utilities/radial_basis_function.h | 187 +++++++++++++++++++--- 1 file changed, 169 insertions(+), 18 deletions(-) diff --git a/include/utilities/radial_basis_function.h b/include/utilities/radial_basis_function.h index 662d7ccbc..e0d290106 100644 --- a/include/utilities/radial_basis_function.h +++ b/include/utilities/radial_basis_function.h @@ -15,8 +15,7 @@ namespace RadialBasisFunction { //! Cubic Spline Radial Basis Function //! Source: Monaghan, 1985; Monaghan, 1992 template -double cubic_spline(const double& smoothing_length, - const double& norm_distance) { +double cubic_spline(const double smoothing_length, const double norm_distance) { // Assign multiplier depends on dimension double multiplier; @@ -41,11 +40,39 @@ double cubic_spline(const double& smoothing_length, return basis_function; } +//! Cubic Spline Radial Basis Function derivative +//! Source: Monaghan, 1985; Monaghan, 1992 +template +double cubic_spline_derivative(const double smoothing_length, + const double norm_distance) { + + // Assign multiplier depends on dimension + double multiplier; + if (Tdim == 2) + multiplier = 15.0 / (7.0 * M_PI * std::pow(smoothing_length, 2)); + else if (Tdim == 3) + multiplier = 3.0 / (2.0 * M_PI * std::pow(smoothing_length, 3)); + else + throw std::runtime_error("Tdim is invalid"); + + // Compute basis function derivative + double dw_dr = multiplier; + const double radius = norm_distance / smoothing_length; + if (radius >= 0.0 && radius < 1.0) + dw_dr *= -2.0 * radius + 1.5 * std::pow(radius, 2); + else if (radius >= 1.0 && radius < 2.0) + dw_dr *= -0.5 * std::pow((2.0 - radius), 2); + else + dw_dr = 0.0; + + return dw_dr; +} + //! Quintic Spline Radial Basis Function //! Source: Liu, 2010 template -double quintic_spline(const double& smoothing_length, - const double& norm_distance) { +double quintic_spline(const double smoothing_length, + const double norm_distance) { // Assign multiplier depends on dimension double multiplier; @@ -61,11 +88,11 @@ double quintic_spline(const double& smoothing_length, const double radius = norm_distance / smoothing_length; if (radius >= 0.0 && radius < 1.0) basis_function *= - (std::pow(3.0 - radius, 5) - 6 * std::pow(2.0 - radius, 5) + - 15 * std::pow(1.0 - radius, 5)); + (std::pow(3.0 - radius, 5) - 6.0 * std::pow(2.0 - radius, 5) + + 15.0 * std::pow(1.0 - radius, 5)); else if (radius >= 1.0 && radius < 2.0) basis_function *= - (std::pow(3.0 - radius, 5) - 6 * std::pow(2.0 - radius, 5)); + (std::pow(3.0 - radius, 5) - 6.0 * std::pow(2.0 - radius, 5)); else if (radius >= 2.0 && radius < 3.0) basis_function *= (std::pow(3.0 - radius, 5)); else @@ -74,11 +101,43 @@ double quintic_spline(const double& smoothing_length, return basis_function; } +//! Quintic Spline Radial Basis Function derivative +//! Source: Liu, 2010 +template +double quintic_spline_derivative(const double smoothing_length, + const double norm_distance) { + + // Assign multiplier depends on dimension + double multiplier; + if (Tdim == 2) + multiplier = 1.0 / (478.0 * M_PI * std::pow(smoothing_length, 2)); + else if (Tdim == 3) + multiplier = 3.0 / (359.0 * M_PI * std::pow(smoothing_length, 3)); + else + throw std::runtime_error("Tdim is invalid"); + + // Compute basis function + double dw_dr = multiplier; + const double radius = norm_distance / smoothing_length; + if (radius >= 0.0 && radius < 1.0) + dw_dr *= + (-5.0 * std::pow(3.0 - radius, 4) + 30. * std::pow(2.0 - radius, 4) - + 75. * std::pow(1.0 - radius, 4)); + else if (radius >= 1.0 && radius < 2.0) + dw_dr *= + (-5.0 * std::pow(3.0 - radius, 4) + 30. * std::pow(2.0 - radius, 4)); + else if (radius >= 2.0 && radius < 3.0) + dw_dr *= (-5.0 * std::pow(3.0 - radius, 4)); + else + dw_dr = 0.0; + + return dw_dr; +} + //! Gaussian Kernel //! Source: Liu, 2010 template -double gaussian_kernel(const double& smoothing_length, - const double& norm_distance) { +double gaussian(const double smoothing_length, const double norm_distance) { // Assign multiplier depends on dimension double multiplier; @@ -100,11 +159,37 @@ double gaussian_kernel(const double& smoothing_length, return basis_function; } +//! Gaussian Kernel derivative +//! Source: Liu, 2010 +template +double gaussian_derivative(const double smoothing_length, + const double norm_distance) { + + // Assign multiplier depends on dimension + double multiplier; + if (Tdim == 2) + multiplier = 1.0 / (M_PI * std::pow(smoothing_length, 2)); + else if (Tdim == 3) + multiplier = 1.0 / std::pow((std::sqrt(M_PI) * smoothing_length), 3); + else + throw std::runtime_error("Tdim is invalid"); + + // Compute basis function + double dw_dr = multiplier; + const double radius = norm_distance / smoothing_length; + if (radius >= 0.0 && radius < 3.0) + dw_dr *= -2.0 * radius * std::exp(-std::pow(radius, 2)); + else + dw_dr = 0.0; + + return dw_dr; +} + //! Super Gaussian Kernel //! Source: Monaghan, 1992 template -double super_gaussian_kernel(const double& smoothing_length, - const double& norm_distance) { +double super_gaussian(const double smoothing_length, + const double norm_distance) { // Assign multiplier depends on dimension double multiplier; @@ -119,17 +204,44 @@ double super_gaussian_kernel(const double& smoothing_length, double basis_function = multiplier; const double radius = norm_distance / smoothing_length; if (radius >= 0.0 && radius < 3.0) - basis_function *= - std::exp(-std::pow(radius, 2)) * (Tdim / 2.0 + 1.0 - radius * radius); + basis_function *= radius * (2.0 * radius * radius - (double)Tdim - 4.0) * + std::exp(-std::pow(radius, 2)); else basis_function = 0.0; return basis_function; } +//! Super Gaussian Kernel derivative +//! Source: Monaghan, 1992 +template +double super_gaussian_derivative(const double smoothing_length, + const double norm_distance) { + + // Assign multiplier depends on dimension + double multiplier; + if (Tdim == 2) + multiplier = 1.0 / std::pow((std::sqrt(M_PI) * smoothing_length), 2); + else if (Tdim == 3) + multiplier = 1.0 / std::pow((std::sqrt(M_PI) * smoothing_length), 3); + else + throw std::runtime_error("Tdim is invalid"); + + // Compute basis function + double dw_dr = multiplier; + const double radius = norm_distance / smoothing_length; + if (radius >= 0.0 && radius < 3.0) + dw_dr *= std::exp(-std::pow(radius, 2)) * + ((double)Tdim / 2.0 + 1.0 - radius * radius); + else + dw_dr = 0.0; + + return dw_dr; +} + //! General Radial Basis Function Kernel call template -double kernel(const double& smoothing_length, const double& norm_distance, +double kernel(const double smoothing_length, const double norm_distance, const std::string type) { if (type == "cubic_spline") { return mpm::RadialBasisFunction::cubic_spline(smoothing_length, @@ -138,11 +250,11 @@ double kernel(const double& smoothing_length, const double& norm_distance, return mpm::RadialBasisFunction::quintic_spline(smoothing_length, norm_distance); } else if (type == "gaussian") { - return mpm::RadialBasisFunction::gaussian_kernel(smoothing_length, - norm_distance); + return mpm::RadialBasisFunction::gaussian(smoothing_length, + norm_distance); } else if (type == "super_gaussian") { - return mpm::RadialBasisFunction::super_gaussian_kernel( - smoothing_length, norm_distance); + return mpm::RadialBasisFunction::super_gaussian(smoothing_length, + norm_distance); } else { throw std::runtime_error( "RadialBasisFunction kernel type is invalid. Available types are: " @@ -151,6 +263,45 @@ double kernel(const double& smoothing_length, const double& norm_distance, } } +//! General Radial Basis Function Kernel call +template +Eigen::Matrix gradient( + const double smoothing_length, + const Eigen::Matrix& relative_distance, + const std::string type) { + + // Compute norm distance + const double norm_distance = relative_distance.norm(); + double dw_dr; + if (type == "cubic_spline") { + dw_dr = mpm::RadialBasisFunction::cubic_spline_derivative( + smoothing_length, norm_distance); + } else if (type == "quintic_spline") { + dw_dr = mpm::RadialBasisFunction::quintic_spline_derivative( + smoothing_length, norm_distance); + } else if (type == "gaussian") { + dw_dr = mpm::RadialBasisFunction::gaussian_derivative( + smoothing_length, norm_distance); + } else if (type == "super_gaussian") { + dw_dr = mpm::RadialBasisFunction::super_gaussian_derivative( + smoothing_length, norm_distance); + } else { + throw std::runtime_error( + "RadialBasisFunction gradient type is invalid. Available types are: " + "\"cubic_spline\", \"quintic_spline\", \"gaussian\", and, " + "\"super_gaussian\"."); + } + + // Gradient = dw_dr * r / ||r|| / h + Eigen::Matrix gradient = relative_distance; + if (norm_distance > 1.e-12) + gradient *= dw_dr / (norm_distance * smoothing_length); + else + gradient *= 0.0; + + return gradient; +} + } // namespace RadialBasisFunction } // namespace mpm From 356ceab614462853955527a1158a396ea2eb8fa2 Mon Sep 17 00:00:00 2001 From: Nanda Date: Fri, 27 Mar 2020 00:29:47 -0700 Subject: [PATCH 30/72] modify default radial basis function --- include/utilities/radial_basis_function.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/utilities/radial_basis_function.h b/include/utilities/radial_basis_function.h index e0d290106..d872a2097 100644 --- a/include/utilities/radial_basis_function.h +++ b/include/utilities/radial_basis_function.h @@ -31,9 +31,9 @@ double cubic_spline(const double smoothing_length, const double norm_distance) { const double radius = norm_distance / smoothing_length; if (radius >= 0.0 && radius < 1.0) basis_function *= - 2.0 / 3.0 - std::pow(radius, 2) + 0.5 * std::pow(radius, 3); + (2.0 / 3.0 - std::pow(radius, 2) + 0.5 * std::pow(radius, 3)); else if (radius >= 1.0 && radius < 2.0) - basis_function *= 1.0 / 6.0 * std::pow((2.0 - radius), 3); + basis_function *= (1.0 / 6.0 * std::pow((2.0 - radius), 3)); else basis_function = 0.0; @@ -59,7 +59,7 @@ double cubic_spline_derivative(const double smoothing_length, double dw_dr = multiplier; const double radius = norm_distance / smoothing_length; if (radius >= 0.0 && radius < 1.0) - dw_dr *= -2.0 * radius + 1.5 * std::pow(radius, 2); + dw_dr *= (-2.0 * radius + 1.5 * std::pow(radius, 2)); else if (radius >= 1.0 && radius < 2.0) dw_dr *= -0.5 * std::pow((2.0 - radius), 2); else @@ -242,7 +242,7 @@ double super_gaussian_derivative(const double smoothing_length, //! General Radial Basis Function Kernel call template double kernel(const double smoothing_length, const double norm_distance, - const std::string type) { + const std::string type = "cubic_spline") { if (type == "cubic_spline") { return mpm::RadialBasisFunction::cubic_spline(smoothing_length, norm_distance); @@ -268,7 +268,7 @@ template Eigen::Matrix gradient( const double smoothing_length, const Eigen::Matrix& relative_distance, - const std::string type) { + const std::string type = "cubic_spline") { // Compute norm distance const double norm_distance = relative_distance.norm(); From a5ac395882f97a6a7cd9b2d81b1dbdb67761969a Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 31 Mar 2020 17:26:05 -0700 Subject: [PATCH 31/72] add particle diameter --- include/particles/particle.h | 6 ++++++ include/particles/particle_base.h | 3 +++ 2 files changed, 9 insertions(+) diff --git a/include/particles/particle.h b/include/particles/particle.h index e32b51254..e2e3e99cb 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -122,6 +122,12 @@ class Particle : public ParticleBase { //! Return volume double volume() const override { return volume_; } + //! Return the approximate particle diameter + double diameter() const override { + if (Tdim == 2) return 2.0 * std::sqrt(volume_ / M_PI); + if (Tdim == 3) return 2.0 * std::pow(volume_ * 0.75 / M_PI, (1 / 3)); + } + //! Return size of particle in natural coordinates VectorDim natural_size() const override { return natural_size_; } diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index d5a98f0dd..fe64ca1d3 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -126,6 +126,9 @@ class ParticleBase { //! Return volume virtual double volume() const = 0; + //! Return the approximate particle diameter + virtual double diameter() const = 0; + //! Return size of particle in natural coordinates virtual VectorDim natural_size() const = 0; From 71c60b3826b523e4cc2a7e911524d39178fa903c Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 31 Mar 2020 17:27:56 -0700 Subject: [PATCH 32/72] compute numerical normal --- include/mesh.tcc | 45 +++++++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/include/mesh.tcc b/include/mesh.tcc index 1da173c1a..ebf848411 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1979,24 +1979,33 @@ bool mpm::Mesh::compute_free_surface(double tolerance) { std::set free_surface_particles; for (const auto p_id : free_surface_candidate_particles) { // Initialize renormalization matrix - Eigen::Matrix renormalization_matrix; - renormalization_matrix.setZero(); + Eigen::Matrix renormalization_matrix_inv; + renormalization_matrix_inv.setZero(); // Loop over neighbours - const auto& p_coord = map_particles_[p_id]->coordinates(); - const auto& neighbour_particles = map_particles_[p_id]->neighbours(); + const auto& particle = map_particles_[p_id]; + const auto& p_coord = particle->coordinates(); + const auto& neighbour_particles = particle->neighbours(); for (const auto n_id : neighbour_particles) { const auto& n_coord = map_particles_[n_id]->coordinates(); const VectorDim rel_coord = n_coord - p_coord; - const double rel_distance = rel_coord.norm(); - } - // Matrix inversion to get renormalization_matrix + // Compute kernel gradient + const double smoothing_length = 1.33 * particle->diameter(); + const VectorDim kernel_gradient = + mpm::RadialBasisFunction::gradient(smoothing_length, + -rel_coord, "gaussian"); - // Find matrix eigenvalue + // Inverse of renormalization matrix B + renormalization_matrix_inv += + (particle->mass() / particle->mass_density()) * kernel_gradient * + rel_coord.transpose(); + } // Categorize based on lambda - double lambda = 0; + Eigen::SelfAdjointEigenSolver es( + renormalization_matrix_inv); + double lambda = es.eigenvalues().minCoeff(); bool secondary_check = false; if (lambda <= 0.2) free_surface_particles.insert(p_id); @@ -2006,13 +2015,25 @@ bool mpm::Mesh::compute_free_surface(double tolerance) { // If secondary check is needed if (secondary_check) { // Compute numerical normal vector - VectorDim normal; + VectorDim temporary_vec; + temporary_vec.setZero(); for (const auto n_id : neighbour_particles) { const auto& n_coord = map_particles_[n_id]->coordinates(); const VectorDim rel_coord = n_coord - p_coord; - const double rel_distance = rel_coord.norm(); + + // Compute kernel gradient + const double smoothing_length = 1.33 * particle->diameter(); + const VectorDim kernel_gradient = + mpm::RadialBasisFunction::gradient(smoothing_length, + -rel_coord, "gaussian"); + + // Sum of kernel by volume + temporary_vec += + (particle->mass() / particle->mass_density()) * kernel_gradient; } - normal *= 1. / normal.norm(); + const VectorDim direction_vector = + -renormalization_matrix_inv.inverse() * temporary_vec; + const VectorDim normal = direction_vector / direction_vector.norm(); } } From c4ca0ae6097c09d4089bafb029cf1d6d0d7c902a Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 31 Mar 2020 18:39:36 -0700 Subject: [PATCH 33/72] add normals in particles --- include/particles/particle.h | 8 ++++++++ include/particles/particle.tcc | 2 ++ include/particles/particle_base.h | 6 ++++++ 3 files changed, 16 insertions(+) diff --git a/include/particles/particle.h b/include/particles/particle.h index e2e3e99cb..b816acd12 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -277,6 +277,12 @@ class Particle : public ParticleBase { //! Compute free surface bool compute_free_surface() override; + //! Assign normal vector + void assign_normal(const VectorDim& normal) override { normal_ = normal; }; + + //! Return normal vector + VectorDim normal() override { return normal_; }; + //! Return the number of neighbour particles unsigned nneighbours() const override { return neighbours_.size(); }; @@ -360,6 +366,8 @@ class Particle : public ParticleBase { std::map> properties_; //! Free surface bool free_surface_{false}; + //! Free surface + Eigen::Matrix normal_; }; // Particle class } // namespace mpm diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index aab3d3ba0..93cdc8cf3 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -232,6 +232,7 @@ void mpm::Particle::initialise() { stress_.setZero(); traction_.setZero(); velocity_.setZero(); + normal_.setZero(); volume_ = std::numeric_limits::max(); volumetric_strain_centroid_ = 0.; @@ -240,6 +241,7 @@ void mpm::Particle::initialise() { this->properties_["strains"] = [&]() { return strain(); }; this->properties_["velocities"] = [&]() { return velocity(); }; this->properties_["displacements"] = [&]() { return displacement(); }; + this->properties_["normals"] = [&]() { return normal(); }; } //! Assign material state variables from neighbour particle diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index fe64ca1d3..d78af2823 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -256,6 +256,12 @@ class ParticleBase { //! Compute free surface virtual bool compute_free_surface() = 0; + //! Assign normal vector + virtual void assign_normal(const VectorDim& normal) = 0; + + //! Return normal vector + virtual VectorDim normal() = 0; + //! Return the number of neighbour particles virtual unsigned nneighbours() const = 0; From fc03f9999f4b80443f9ef7c59683be5e4d078f05 Mon Sep 17 00:00:00 2001 From: Nanda Date: Thu, 2 Apr 2020 01:26:22 -0700 Subject: [PATCH 34/72] fix structure --- include/mesh.tcc | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/include/mesh.tcc b/include/mesh.tcc index ebf848411..8b01a3c09 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -2002,19 +2002,25 @@ bool mpm::Mesh::compute_free_surface(double tolerance) { rel_coord.transpose(); } - // Categorize based on lambda + // Compute lambda: minimum eigenvalue of B_inverse Eigen::SelfAdjointEigenSolver es( renormalization_matrix_inv); double lambda = es.eigenvalues().minCoeff(); + + // Categorize particle based on lambda + bool free_surface = false; bool secondary_check = false; + bool interior = false; if (lambda <= 0.2) - free_surface_particles.insert(p_id); + free_surface = true; else if (lambda > 0.2 && lambda <= 0.75) secondary_check = true; + else + interior = true; - // If secondary check is needed - if (secondary_check) { - // Compute numerical normal vector + // Compute numerical normal vector + VectorDim normal; + if (!interior) { VectorDim temporary_vec; temporary_vec.setZero(); for (const auto n_id : neighbour_particles) { @@ -2033,7 +2039,17 @@ bool mpm::Mesh::compute_free_surface(double tolerance) { } const VectorDim direction_vector = -renormalization_matrix_inv.inverse() * temporary_vec; - const VectorDim normal = direction_vector / direction_vector.norm(); + normal = direction_vector / direction_vector.norm(); + } + + // If secondary check is needed + if (secondary_check) { + } + + // Assign normal only to validated free surface + if (free_surface) { + free_surface_particles.insert(p_id); + particle->assign_normal(normal); } } From 5a54f4324828a0378460b8306b07f5602f0dfdb8 Mon Sep 17 00:00:00 2001 From: Nanda Date: Thu, 2 Apr 2020 02:20:48 -0700 Subject: [PATCH 35/72] add secondary check --- include/mesh.tcc | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/include/mesh.tcc b/include/mesh.tcc index 8b01a3c09..4f624799f 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1986,12 +1986,12 @@ bool mpm::Mesh::compute_free_surface(double tolerance) { const auto& particle = map_particles_[p_id]; const auto& p_coord = particle->coordinates(); const auto& neighbour_particles = particle->neighbours(); + const double smoothing_length = 1.33 * particle->diameter(); for (const auto n_id : neighbour_particles) { const auto& n_coord = map_particles_[n_id]->coordinates(); const VectorDim rel_coord = n_coord - p_coord; // Compute kernel gradient - const double smoothing_length = 1.33 * particle->diameter(); const VectorDim kernel_gradient = mpm::RadialBasisFunction::gradient(smoothing_length, -rel_coord, "gaussian"); @@ -2028,7 +2028,6 @@ bool mpm::Mesh::compute_free_surface(double tolerance) { const VectorDim rel_coord = n_coord - p_coord; // Compute kernel gradient - const double smoothing_length = 1.33 * particle->diameter(); const VectorDim kernel_gradient = mpm::RadialBasisFunction::gradient(smoothing_length, -rel_coord, "gaussian"); @@ -2037,19 +2036,46 @@ bool mpm::Mesh::compute_free_surface(double tolerance) { temporary_vec += (particle->mass() / particle->mass_density()) * kernel_gradient; } - const VectorDim direction_vector = - -renormalization_matrix_inv.inverse() * temporary_vec; - normal = direction_vector / direction_vector.norm(); + normal = -renormalization_matrix_inv.inverse() * temporary_vec; + normal.normalize(); } // If secondary check is needed if (secondary_check) { + // Construct scanning region + // TODO: spacing distance should be a function of porosity + const double spacing_distance = smoothing_length; + VectorDim t_coord = p_coord + spacing_distance * normal; + + // Check all neighbours + for (const auto n_id : neighbour_particles) { + const auto& n_coord = map_particles_[n_id]->coordinates(); + const VectorDim rel_coord_np = n_coord - p_coord; + const double distance_np = rel_coord_np.norm(); + const VectorDim rel_coord_nt = n_coord - t_coord; + const double distance_nt = rel_coord_nt.norm(); + + free_surface = true; + if (distance_np < std::sqrt(2) * spacing_distance) { + if (std::acos(normal.dot(rel_coord_np) / distance_np) < M_PI / 4) { + free_surface = false; + break; + } + } else { + if (distance_nt < spacing_distance) { + free_surface = false; + break; + } + } + } } // Assign normal only to validated free surface if (free_surface) { - free_surface_particles.insert(p_id); + particle->assign_free_surface(free_surface); particle->assign_normal(normal); + particle->initial_pressure(0.0); + free_surface_particles.insert(p_id); } } From e156c2605f7e7551df8497d2ab5b68137e95ac30 Mon Sep 17 00:00:00 2001 From: Nanda Date: Thu, 2 Apr 2020 10:35:44 -0700 Subject: [PATCH 36/72] move initial pressure to a separate function --- include/mesh.h | 6 ++++++ include/mesh.tcc | 15 ++++++++++++++- .../solvers/mpm_semi_implicit_navierstokes.tcc | 16 +++++++++++++--- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/include/mesh.h b/include/mesh.h index 147826d62..729b21344 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -221,6 +221,12 @@ class Mesh { template void iterate_over_particles(Toper oper); + //! Iterate over particles with predicate + //! \tparam Toper Callable object typically a baseclass functor + //! \tparam Tpred Predicate + template + void iterate_over_particles_predicate(Toper oper, Tpred pred); + //! Iterate over particle set //! \tparam Toper Callable object typically a baseclass functor //! \param[in] set_id particle set id diff --git a/include/mesh.tcc b/include/mesh.tcc index 4f624799f..1ffa5871a 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -926,6 +926,20 @@ void mpm::Mesh::iterate_over_particles(Toper oper) { tbb::simple_partitioner()); } +//! Iterate over particles +template +template +void mpm::Mesh::iterate_over_particles_predicate(Toper oper, Tpred pred) { + tbb::parallel_for( + tbb::blocked_range(size_t(0), size_t(particles_.size()), + tbb_grain_size_), + [&](const tbb::blocked_range& range) { + for (int i = range.begin(); i != range.end(); ++i) + if (pred(particles_[i])) oper(particles_[i]); + }, + tbb::simple_partitioner()); +} + //! Iterate over particle set template template @@ -2074,7 +2088,6 @@ bool mpm::Mesh::compute_free_surface(double tolerance) { if (free_surface) { particle->assign_free_surface(free_surface); particle->assign_normal(normal); - particle->initial_pressure(0.0); free_surface_particles.insert(p_id); } } diff --git a/include/solvers/mpm_semi_implicit_navierstokes.tcc b/include/solvers/mpm_semi_implicit_navierstokes.tcc index 0b50006e1..2f227da60 100644 --- a/include/solvers/mpm_semi_implicit_navierstokes.tcc +++ b/include/solvers/mpm_semi_implicit_navierstokes.tcc @@ -117,6 +117,19 @@ bool mpm::MPMSemiImplicitNavierStokes::solve() { task_group.wait(); + // Compute free surface cells, nodes, and particles + task_group.run([&] { + mesh_->compute_free_surface(volume_tolerance_); + + // Assign initial pressure + mesh_->iterate_over_particles_predicate( + std::bind(&mpm::ParticleBase::initial_pressure, + std::placeholders::_1, 0.0), + std::bind(&mpm::ParticleBase::free_surface, + std::placeholders::_1)); + }); + task_group.wait(); + // Assign mass and momentum to nodes mesh_->iterate_over_particles( std::bind(&mpm::ParticleBase::map_mass_momentum_to_nodes, @@ -155,9 +168,6 @@ bool mpm::MPMSemiImplicitNavierStokes::solve() { }); task_group.wait(); - // Compute free surface cells, nodes, and particles - mesh_->compute_free_surface(volume_tolerance_); - // Compute intermediate velocity mesh_->iterate_over_nodes_predicate( std::bind(&mpm::NodeBase::compute_acceleration_velocity, From 211bb84962c2eae90b4a0605337cca2e24ba153a Mon Sep 17 00:00:00 2001 From: Nanda Date: Thu, 2 Apr 2020 11:50:19 -0700 Subject: [PATCH 37/72] reset free surface particle --- include/mesh.tcc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/mesh.tcc b/include/mesh.tcc index 1ffa5871a..cfeb069f1 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1919,10 +1919,14 @@ template bool mpm::Mesh::compute_free_surface(double tolerance) { bool status = true; try { - // Reset free surface cell + // Reset free surface cell and particles this->iterate_over_cells(std::bind(&mpm::Cell::assign_free_surface, std::placeholders::_1, false)); + this->iterate_over_particles( + std::bind(&mpm::ParticleBase::assign_free_surface, + std::placeholders::_1, false)); + // First, we detect the cell with possible free surfaces through volume // fraction // Reset volume fraction From d5f101d9beb0c27a6c29df034561307c2d18d0ad Mon Sep 17 00:00:00 2001 From: Nanda Date: Sat, 4 Apr 2020 11:08:48 -0700 Subject: [PATCH 38/72] reset normal --- include/mesh.tcc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/mesh.tcc b/include/mesh.tcc index cfeb069f1..1f9879ab8 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1923,6 +1923,14 @@ bool mpm::Mesh::compute_free_surface(double tolerance) { this->iterate_over_cells(std::bind(&mpm::Cell::assign_free_surface, std::placeholders::_1, false)); + VectorDim temp_normal; + temp_normal.setZero(); + this->iterate_over_particles_predicate( + std::bind(&mpm::ParticleBase::assign_normal, + std::placeholders::_1, temp_normal), + std::bind(&mpm::ParticleBase::free_surface, + std::placeholders::_1)); + this->iterate_over_particles( std::bind(&mpm::ParticleBase::assign_free_surface, std::placeholders::_1, false)); From d1b8d91bfd4d06711f2e7bff248df2ac8db94d18 Mon Sep 17 00:00:00 2001 From: Nanda Date: Sat, 4 Apr 2020 22:09:31 -0700 Subject: [PATCH 39/72] improve accuracy fs detection --- include/mesh.tcc | 58 ++++++++++++++++++------------------------------ 1 file changed, 21 insertions(+), 37 deletions(-) diff --git a/include/mesh.tcc b/include/mesh.tcc index 1f9879ab8..6a9cbe749 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1935,26 +1935,7 @@ bool mpm::Mesh::compute_free_surface(double tolerance) { std::bind(&mpm::ParticleBase::assign_free_surface, std::placeholders::_1, false)); - // First, we detect the cell with possible free surfaces through volume - // fraction - // Reset volume fraction - this->iterate_over_cells(std::bind(&mpm::Cell::assign_volume_fraction, - std::placeholders::_1, 0.0)); - - // Compute and assign volume fraction to each cell - for (auto citr = this->cells_.cbegin(); citr != this->cells_.cend(); - ++citr) { - if ((*citr)->status()) { - // Compute volume fraction - double cell_volume_fraction = 0.0; - for (const auto p_id : (*citr)->particles()) - cell_volume_fraction += map_particles_[p_id]->volume(); - - cell_volume_fraction = cell_volume_fraction / (*citr)->volume(); - (*citr)->assign_volume_fraction(cell_volume_fraction); - } - } - + // First, we detect the cell with possible free surfaces // Compute boundary cells and nodes based on geometry std::set free_surface_candidate_cells; for (auto citr = this->cells_.cbegin(); citr != this->cells_.cend(); @@ -1962,16 +1943,25 @@ bool mpm::Mesh::compute_free_surface(double tolerance) { // Cell contains particles if ((*citr)->status()) { bool candidate_cell = false; - // Check volume fraction only for boundary cell - if ((*citr)->volume_fraction() < tolerance) { - candidate_cell = true; - } else { - // Loop over neighbouring cells, if volume fraction is above - // tolerance, but a free surface cell - for (const auto n_id : (*citr)->neighbours()) { - if (map_cells_[n_id]->volume_fraction() < tolerance) { - candidate_cell = true; - break; + const auto& node_id = (*citr)->nodes_id(); + // Loop over neighbouring cells + for (const auto n_id : (*citr)->neighbours()) { + if (!map_cells_[n_id]->status()) { + candidate_cell = true; + const auto& n_node_id = map_cells_[n_id]->nodes_id(); + + // Detect common node id + std::set common_node_id; + std::set_intersection( + node_id.begin(), node_id.end(), n_node_id.begin(), + n_node_id.end(), + std::inserter(common_node_id, common_node_id.begin())); + + // Assign free surface nodes + if (!common_node_id.empty()) { + for (const auto common_id : common_node_id) { + map_nodes_[common_id]->assign_free_surface(candidate_cell); + } } } } @@ -1980,13 +1970,6 @@ bool mpm::Mesh::compute_free_surface(double tolerance) { if (candidate_cell) { (*citr)->assign_free_surface(candidate_cell); free_surface_candidate_cells.insert((*citr)->id()); - - // FIXME: Assigned all FS Cell nodes to be free surface node (to be - // removed/optimized) - const auto& node_id = (*citr)->nodes_id(); - for (const auto id : node_id) { - map_nodes_[id]->assign_free_surface(candidate_cell); - } } } } @@ -2046,6 +2029,7 @@ bool mpm::Mesh::compute_free_surface(double tolerance) { // Compute numerical normal vector VectorDim normal; + normal.setZero(); if (!interior) { VectorDim temporary_vec; temporary_vec.setZero(); From 0c880f3374164f14196dde7b90cbfe696a0d17af Mon Sep 17 00:00:00 2001 From: Nanda Date: Sun, 5 Apr 2020 20:19:19 -0700 Subject: [PATCH 40/72] move compute free surface position --- include/solvers/mpm_semi_implicit_navierstokes.tcc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/solvers/mpm_semi_implicit_navierstokes.tcc b/include/solvers/mpm_semi_implicit_navierstokes.tcc index 2f227da60..660bc4576 100644 --- a/include/solvers/mpm_semi_implicit_navierstokes.tcc +++ b/include/solvers/mpm_semi_implicit_navierstokes.tcc @@ -117,6 +117,11 @@ bool mpm::MPMSemiImplicitNavierStokes::solve() { task_group.wait(); + // Assign mass and momentum to nodes + mesh_->iterate_over_particles( + std::bind(&mpm::ParticleBase::map_mass_momentum_to_nodes, + std::placeholders::_1)); + // Compute free surface cells, nodes, and particles task_group.run([&] { mesh_->compute_free_surface(volume_tolerance_); @@ -130,11 +135,6 @@ bool mpm::MPMSemiImplicitNavierStokes::solve() { }); task_group.wait(); - // Assign mass and momentum to nodes - mesh_->iterate_over_particles( - std::bind(&mpm::ParticleBase::map_mass_momentum_to_nodes, - std::placeholders::_1)); - // Compute nodal velocity at the begining of time step mesh_->iterate_over_nodes_predicate( std::bind(&mpm::NodeBase::compute_velocity, From a9889ebd4b6f01b9a33512954fb74b34b756797b Mon Sep 17 00:00:00 2001 From: Nanda Date: Sun, 5 Apr 2020 20:29:19 -0700 Subject: [PATCH 41/72] correct compute_density --- include/node.tcc | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/include/node.tcc b/include/node.tcc index ac0d05752..7b4f1c198 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -526,26 +526,18 @@ bool mpm::Node::mpi_rank(unsigned rank) { //! density = mass / lumped volume template void mpm::Node::compute_density() { - try { - const double tolerance = 1.E-16; // std::numeric_limits::lowest(); - - for (unsigned phase = 0; phase < Tnphases; ++phase) { - if (mass_(phase) > tolerance) { - if (volume_(phase) > tolerance) - density_(phase) = mass_(phase) / volume_(phase); + const double tolerance = 1.E-16; // std::numeric_limits::lowest(); - // Check to see if value is below threshold - if (std::abs(density_(phase)) < 1.E-15) density_(phase) = 0.; + for (unsigned phase = 0; phase < Tnphases; ++phase) { + if (mass_(phase) > tolerance) { + if (volume_(phase) > tolerance) + density_(phase) = mass_(phase) / volume_(phase); - } else - throw std::runtime_error("Nodal mass is zero or below threshold"); - } + // Check to see if value is below threshold + if (std::abs(density_(phase)) < 1.E-15) density_(phase) = 0.; - // Apply velocity constraints, which also sets acceleration to 0, - // when velocity is set. - this->apply_velocity_constraints(); - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + } else + throw std::runtime_error("Nodal mass is zero or below threshold"); } } From 473fa0c06299bfe89fef7cd6fd465dd6543ddbda Mon Sep 17 00:00:00 2001 From: Nanda Date: Sun, 5 Apr 2020 20:39:19 -0700 Subject: [PATCH 42/72] modify compute free surface --- include/mesh.tcc | 42 ++++++++++++++++++++++++++-------- include/particles/particle.tcc | 30 +++++++++--------------- 2 files changed, 44 insertions(+), 28 deletions(-) diff --git a/include/mesh.tcc b/include/mesh.tcc index 6a9cbe749..94154abef 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1984,9 +1984,26 @@ bool mpm::Mesh::compute_free_surface(double tolerance) { particle_ids.end()); } + // Compute boundary particles based on density function + // Lump cell volume to nodes + this->iterate_over_cells(std::bind( + &mpm::Cell::map_cell_volume_to_nodes, std::placeholders::_1, 0)); + + // Compute nodal value of mass density + this->iterate_over_nodes_predicate( + std::bind(&mpm::NodeBase::compute_density, std::placeholders::_1), + std::bind(&mpm::NodeBase::status, std::placeholders::_1)); + + std::set free_surface_candidate_particles_second; + for (const auto p_id : free_surface_candidate_particles) { + const auto& particle = map_particles_[p_id]; + bool status = particle->compute_free_surface(); + if (status) free_surface_candidate_particles_second.insert(p_id); + } + // Find free surface particles through geometry std::set free_surface_particles; - for (const auto p_id : free_surface_candidate_particles) { + for (const auto p_id : free_surface_candidate_particles_second) { // Initialize renormalization matrix Eigen::Matrix renormalization_matrix_inv; renormalization_matrix_inv.setZero(); @@ -2107,6 +2124,11 @@ bool mpm::Mesh::compute_free_surface(double tolerance) { // this->iterate_over_cells(std::bind(&mpm::Cell::assign_volume_fraction, // std::placeholders::_1, 0.0)); +// // Reset free surface particle +// this->iterate_over_particles( +// std::bind(&mpm::ParticleBase::assign_free_surface, +// std::placeholders::_1, false)); + // // Compute and assign volume fraction to each cell // for (auto citr = this->cells_.cbegin(); citr != this->cells_.cend(); // ++citr) { @@ -2195,14 +2217,16 @@ bool mpm::Mesh::compute_free_surface(double tolerance) { // std::placeholders::_1)); // // Evaluate free surface particles -// this->iterate_over_particles(std::bind( -// &mpm::ParticleBase::compute_free_surface, -// std::placeholders::_1)); - -// // Assign pressure at free surface to be zero -// std::set boundary_particles = this->free_surface_particles(); -// for (const auto boundary_particle : boundary_particles) -// map_particles_[boundary_particle]->initial_pressure(0.0); +// std::set boundary_particles; +// for (auto pitr = this->particles_.cbegin(); pitr != +// this->particles_.cend(); +// ++pitr) { +// bool status = (*pitr)->compute_free_surface(); +// if (status) { +// (*pitr)->assign_free_surface(status); +// boundary_particles.insert((*pitr)->id()); +// } +// } // } catch (std::exception& exception) { // console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index 93cdc8cf3..dab36c73f 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -798,26 +798,18 @@ void mpm::Particle::append_material_id_to_nodes() const { //! Compute free surface template bool mpm::Particle::compute_free_surface() { - bool status = true; - try { - this->free_surface_ = false; - // Check if particle has a valid cell ptr - if (cell_ != nullptr) { - // 1. Simple approach of density comparison (Hamad, 2015) - // Get interpolated nodal density - double nodal_mass_density = 0; - for (unsigned i = 0; i < nodes_.size(); ++i) - nodal_mass_density += - shapefn_[i] * nodes_[i]->density(mpm::ParticlePhase::Solid); - - // Compare smoothen density to actual particle mass density - if ((nodal_mass_density / mass_density_) <= 0.65) - if (cell_->free_surface()) this->free_surface_ = true; - } + bool status = false; + // Check if particle has a valid cell ptr + if (cell_ != nullptr) { + // Simple approach of density comparison (Hamad, 2015) + // Get interpolated nodal density + double nodal_mass_density = 0; + for (unsigned i = 0; i < nodes_.size(); ++i) + nodal_mass_density += + shapefn_[i] * nodes_[i]->density(mpm::ParticlePhase::Solid); - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; + // Compare smoothen density to actual particle mass density + if ((nodal_mass_density / mass_density_) <= 0.70) status = true; } return status; }; From d4e67448f6ee57d2998b2d4c1ace01374d2e2534 Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 7 Apr 2020 23:25:25 -0700 Subject: [PATCH 43/72] register parallel assembler --- ...bler_parallel_semi_implicit_navierstokes.h | 94 ++++++ ...er_parallel_semi_implicit_navierstokes.tcc | 302 ++++++++++++++++++ .../solvers/mpm_semi_implicit_navierstokes.h | 1 - src/linear_solver.cc | 11 + 4 files changed, 407 insertions(+), 1 deletion(-) create mode 100644 include/linear_solvers/assembler_parallel_semi_implicit_navierstokes.h create mode 100644 include/linear_solvers/assembler_parallel_semi_implicit_navierstokes.tcc diff --git a/include/linear_solvers/assembler_parallel_semi_implicit_navierstokes.h b/include/linear_solvers/assembler_parallel_semi_implicit_navierstokes.h new file mode 100644 index 000000000..ccdf8dcc9 --- /dev/null +++ b/include/linear_solvers/assembler_parallel_semi_implicit_navierstokes.h @@ -0,0 +1,94 @@ +#ifndef MPM_ASSEMBLER_PARALLEL_SEMI_IMPLICIT_NAVIERSTOKES_H_ +#define MPM_ASSEMBLER_PARALLEL_SEMI_IMPLICIT_NAVIERSTOKES_H_ + +#include +#include + +// Speed log +#include "assembler_base.h" +#include "spdlog/spdlog.h" + +#include "cg_eigen.h" +#include "mesh.h" + +namespace mpm { +template +class AssemblerParallelSemiImplicitNavierStokes : public AssemblerBase { + public: + //! Constructor + AssemblerParallelSemiImplicitNavierStokes(); + + //! Create a pair between nodes and index in Matrix / Vector + bool assign_global_node_indices(unsigned active_dof) override; + + //! Return laplacian matrix + Eigen::SparseMatrix& laplacian_matrix() override { + return laplacian_matrix_; + } + + //! Assemble laplacian matrix + bool assemble_laplacian_matrix(double dt) override; + + //! Return poisson RHS vector + Eigen::VectorXd& poisson_rhs_vector() override { return poisson_rhs_vector_; } + + //! Assemble poisson RHS vector + bool assemble_poisson_right(double dt) override; + + //! Assign free surface node id + void assign_free_surface( + const std::set& free_surface_id) override { + free_surface_ = free_surface_id; + } + + //! Assign pressure constraints + bool assign_pressure_constraints(double beta, + const double current_time) override; + + //! Apply pressure constraints to poisson equation + void apply_pressure_constraints(); + + //! Return pressure increment + Eigen::VectorXd& pressure_increment() override { return pressure_increment_; } + + //! Assign pressure increment + void assign_pressure_increment(Eigen::VectorXd pressure_increment) override { + pressure_increment_ = pressure_increment; + } + + //! Return correction matrix + Eigen::SparseMatrix& correction_matrix() override { + return correction_matrix_; + } + + //! Assemble corrector RHS + bool assemble_corrector_right(double dt) override; + + protected: + //! Logger + std::shared_ptr console_; + + private: + //! number of nodes + using AssemblerBase::active_dof_; + //! Mesh object + using AssemblerBase::mesh_; + //! Laplacian matrix + Eigen::SparseMatrix laplacian_matrix_; + //! Poisson RHS vector + Eigen::VectorXd poisson_rhs_vector_; + //! Free surface + std::set free_surface_; + //! Pressure constraints + Eigen::SparseVector pressure_constraints_; + //! \delta p^(t+1) = p^(t+1) - beta * p^(t) + Eigen::VectorXd pressure_increment_; + //! correction_matrix + Eigen::SparseMatrix correction_matrix_; + //! Global node indices + std::vector global_node_indices_; +}; +} // namespace mpm + +#include "assembler_parallel_semi_implicit_navierstokes.tcc" +#endif // MPM_ASSEMBLER_PARALLEL_SEMI_IMPLICIT_NAVIERSTOKES_H_ diff --git a/include/linear_solvers/assembler_parallel_semi_implicit_navierstokes.tcc b/include/linear_solvers/assembler_parallel_semi_implicit_navierstokes.tcc new file mode 100644 index 000000000..d85a10728 --- /dev/null +++ b/include/linear_solvers/assembler_parallel_semi_implicit_navierstokes.tcc @@ -0,0 +1,302 @@ +//! Construct a semi-implicit eigen matrix assembler +template +mpm::AssemblerParallelSemiImplicitNavierStokes< + Tdim>::AssemblerParallelSemiImplicitNavierStokes() + : mpm::AssemblerBase() { + //! Logger + console_ = + spdlog::stdout_color_mt("AssemblerParallelSemiImplicitNavierStokes"); +} + +//! Assign global node indices +template +bool mpm::AssemblerParallelSemiImplicitNavierStokes< + Tdim>::assign_global_node_indices(unsigned nactive_node) { + bool status = true; + try { + // Total number of active node + active_dof_ = nactive_node; + + global_node_indices_ = mesh_->global_node_indices(); + + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +//! Assemble Laplacian matrix +template +bool mpm::AssemblerParallelSemiImplicitNavierStokes< + Tdim>::assemble_laplacian_matrix(double dt) { + bool status = true; + try { + // Initialise Laplacian matrix + laplacian_matrix_.resize(active_dof_, active_dof_); + laplacian_matrix_.setZero(); + + // Reserve storage for sparse matrix + switch (Tdim) { + // For 2d: 10 entries /column + case (2): { + laplacian_matrix_.reserve(Eigen::VectorXi::Constant(active_dof_, 10)); + break; + } + // For 3d: 30 entries /column + case (3): { + laplacian_matrix_.reserve(Eigen::VectorXi::Constant(active_dof_, 30)); + break; + } + } + + // Cell pointer + const auto& cells = mesh_->cells(); + + // Iterate over cells + mpm::Index cid = 0; + for (auto cell_itr = cells.cbegin(); cell_itr != cells.cend(); ++cell_itr) { + if ((*cell_itr)->status()) { + // Node ids in each cell + const auto nids = global_node_indices_.at(cid); + + // Laplacian element of cell + const auto cell_laplacian = (*cell_itr)->laplacian_matrix(); + + // Assemble global laplacian matrix + for (unsigned i = 0; i < nids.size(); ++i) { + for (unsigned j = 0; j < nids.size(); ++j) { + laplacian_matrix_.coeffRef(global_node_indices_.at(cid)(i), + global_node_indices_.at(cid)(j)) += + cell_laplacian(i, j); + } + } + + ++cid; + } + } + + laplacian_matrix_ *= dt; + + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +template +bool mpm::AssemblerParallelSemiImplicitNavierStokes< + Tdim>::assemble_poisson_right(double dt) { + bool status = true; + try { + // Initialise Poisson RHS matrix + Eigen::SparseMatrix poisson_right_matrix; + poisson_right_matrix.resize(active_dof_, active_dof_ * Tdim); + poisson_right_matrix.setZero(); + + // Reserve storage for sparse matrix + switch (Tdim) { + // For 2d: 10 entries /column + case (2): { + poisson_right_matrix.reserve( + Eigen::VectorXi::Constant(active_dof_ * Tdim, 10)); + break; + } + // For 3d: 30 entries /column + case (3): { + poisson_right_matrix.reserve( + Eigen::VectorXi::Constant(active_dof_ * Tdim, 30)); + break; + } + } + + // Cell pointer + const auto& cells = mesh_->cells(); + + // Iterate over cells + mpm::Index cid = 0; + for (auto cell_itr = cells.cbegin(); cell_itr != cells.cend(); ++cell_itr) { + if ((*cell_itr)->status()) { + // Node ids in each cell + const auto nids = global_node_indices_.at(cid); + + // Local Poisson RHS matrix + auto cell_poisson_right = (*cell_itr)->poisson_right_matrix(); + + // Assemble global poisson RHS matrix + for (unsigned i = 0; i < nids.size(); ++i) { + for (unsigned j = 0; j < nids.size(); ++j) { + for (unsigned k = 0; k < Tdim; ++k) { + poisson_right_matrix.coeffRef( + global_node_indices_.at(cid)(i), + global_node_indices_.at(cid)(j) + k * active_dof_) += + cell_poisson_right(i, j + k * nids.size()); + } + } + } + cid++; + } + } + + // Resize poisson right vector + poisson_rhs_vector_.resize(active_dof_); + poisson_rhs_vector_.setZero(); + + // Compute velocity + Eigen::MatrixXd fluid_velocity; + fluid_velocity.resize(active_dof_, Tdim); + fluid_velocity.setZero(); + + // Active nodes + const auto& active_nodes = mesh_->active_nodes(); + const unsigned fluid = mpm::ParticlePhase::SinglePhase; + unsigned node_index = 0; + + for (auto node_itr = active_nodes.cbegin(); node_itr != active_nodes.cend(); + ++node_itr) { + // Compute nodal intermediate force + fluid_velocity.row(node_index) = (*node_itr)->velocity(fluid).transpose(); + node_index++; + } + + // Resize fluid velocity + fluid_velocity.resize(active_dof_ * Tdim, 1); + + // Compute poisson RHS vector + poisson_rhs_vector_ = -poisson_right_matrix * fluid_velocity; + + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +//! Assemble corrector right matrix +template +bool mpm::AssemblerParallelSemiImplicitNavierStokes< + Tdim>::assemble_corrector_right(double dt) { + bool status = true; + try { + // Resize correction matrix + correction_matrix_.resize(active_dof_, active_dof_ * Tdim); + correction_matrix_.setZero(); + + // Reserve storage for sparse matrix + switch (Tdim) { + // For 2d: 10 entries /column + case (2): { + correction_matrix_.reserve( + Eigen::VectorXi::Constant(active_dof_ * Tdim, 10)); + break; + } + // For 3d: 30 entries /column + case (3): { + correction_matrix_.reserve( + Eigen::VectorXi::Constant(active_dof_ * Tdim, 30)); + break; + } + } + + // Cell pointer + unsigned nnodes_per_cell = global_node_indices_.at(0).size(); + const auto& cells = mesh_->cells(); + + // Iterate over cells + unsigned cid = 0; + for (auto cell_itr = cells.cbegin(); cell_itr != cells.cend(); ++cell_itr) { + if ((*cell_itr)->status()) { + auto cell_correction_matrix = (*cell_itr)->correction_matrix(); + for (unsigned k = 0; k < Tdim; k++) { + for (unsigned i = 0; i < nnodes_per_cell; i++) { + for (unsigned j = 0; j < nnodes_per_cell; j++) { + // Fluid + correction_matrix_.coeffRef( + global_node_indices_.at(cid)(i), + k * active_dof_ + global_node_indices_.at(cid)(j)) += + cell_correction_matrix(i, j + k * nnodes_per_cell); + } + } + } + cid++; + } + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +//! Apply pressure constraints vector +template +void mpm::AssemblerParallelSemiImplicitNavierStokes< + Tdim>::apply_pressure_constraints() { + try { + // Modify poisson_rhs_vector_ + poisson_rhs_vector_ -= laplacian_matrix_ * pressure_constraints_; + + // Apply free surface + if (!free_surface_.empty()) { + const auto& nodes = mesh_->nodes(); + for (const auto& free_node : free_surface_) { + const auto column_index = nodes[free_node]->active_id(); + // Modify poisson_rhs_vector + poisson_rhs_vector_(column_index) = 0; + // Modify laplacian_matrix + laplacian_matrix_.row(column_index) *= 0; + laplacian_matrix_.col(column_index) *= 0; + laplacian_matrix_.coeffRef(column_index, column_index) = 1; + } + // Clear the vector + free_surface_.clear(); + } + + // Apply pressure constraints + for (Eigen::SparseVector::InnerIterator it(pressure_constraints_); + it; ++it) { + // Modify poisson_rhs_vector + poisson_rhs_vector_(it.index()) = it.value(); + // Modify laplacian_matrix + laplacian_matrix_.row(it.index()) *= 0; + laplacian_matrix_.col(it.index()) *= 0; + laplacian_matrix_.coeffRef(it.index(), it.index()) = 1; + } + + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + } +} + +//! Assign pressure constraints +template +bool mpm::AssemblerParallelSemiImplicitNavierStokes< + Tdim>::assign_pressure_constraints(double beta, const double current_time) { + bool status = false; + try { + // Resize pressure constraints vector + pressure_constraints_.resize(active_dof_); + pressure_constraints_.reserve(int(0.5 * active_dof_)); + + // Nodes container + const auto& nodes = mesh_->active_nodes(); + // Iterate over nodes to get pressure constraints + for (auto node = nodes.cbegin(); node != nodes.cend(); ++node) { + // Assign total pressure constraint + const double pressure_constraint = + (*node)->pressure_constraint(1, current_time); + + // Check if there is a pressure constraint + if (pressure_constraint != std::numeric_limits::max()) { + // Insert the pressure constraints + pressure_constraints_.insert((*node)->active_id()) = + pressure_constraint; + } + } + status = true; + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + } + return status; +} diff --git a/include/solvers/mpm_semi_implicit_navierstokes.h b/include/solvers/mpm_semi_implicit_navierstokes.h index c8abf8ad9..b93e435c2 100644 --- a/include/solvers/mpm_semi_implicit_navierstokes.h +++ b/include/solvers/mpm_semi_implicit_navierstokes.h @@ -8,7 +8,6 @@ #include "mpm_base.h" #include "assembler_base.h" -#include "assembler_eigen_semi_implicit_navierstokes.h" #include "cg_eigen.h" #include "solver_base.h" diff --git a/src/linear_solver.cc b/src/linear_solver.cc index e64da9a5e..8f3b35398 100644 --- a/src/linear_solver.cc +++ b/src/linear_solver.cc @@ -1,5 +1,6 @@ #include "assembler_base.h" #include "assembler_eigen_semi_implicit_navierstokes.h" +#include "assembler_parallel_semi_implicit_navierstokes.h" #include "cg_eigen.h" #include "solver_base.h" @@ -15,6 +16,16 @@ static Register, mpm::AssemblerEigenSemiImplicitNavierStokes<3>> assembler_eigen_semi_implicit_navierstokes_3d( "EigenSemiImplicitNavierStokes3D"); +// Asssembler parallel 2D +static Register, + mpm::AssemblerParallelSemiImplicitNavierStokes<2>> + assembler_parallel_semi_implicit_navierstokes_2d( + "ParallelSemiImplicitNavierStokes2D"); +// Asssembler parallel 3D +static Register, + mpm::AssemblerParallelSemiImplicitNavierStokes<3>> + assembler_parallel_semi_implicit_navierstokes_3d( + "ParallelSemiImplicitNavierStokes3D"); // Linear Solver collections // Solver 2D From ac9dbd2f8d106059f29116fa6fcf7f41109dd95f Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 8 Apr 2020 22:12:30 -0700 Subject: [PATCH 44/72] modify function --- include/cell.h | 3 ++- include/cell.tcc | 4 ++-- include/mesh.tcc | 6 +++--- include/particles/fluid_particle.tcc | 4 ++-- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/include/cell.h b/include/cell.h index 104e766d9..4db739184 100644 --- a/include/cell.h +++ b/include/cell.h @@ -254,7 +254,8 @@ class Cell { //! \param[in] pvolume volume weight void compute_local_poisson_right(const Eigen::VectorXd& shapefn, const Eigen::MatrixXd& grad_shapefn, - double pvolume) noexcept; + double pvolume, + double multiplier = 1.0) noexcept; //! Return local correction matrix const Eigen::MatrixXd& correction_matrix() { return correction_matrix_; }; diff --git a/include/cell.tcc b/include/cell.tcc index b5e52e97e..7c9689569 100644 --- a/include/cell.tcc +++ b/include/cell.tcc @@ -903,12 +903,12 @@ void mpm::Cell::compute_local_laplacian( template void mpm::Cell::compute_local_poisson_right( const Eigen::VectorXd& shapefn, const Eigen::MatrixXd& grad_shapefn, - double pvolume) noexcept { + double pvolume, double multiplier) noexcept { std::lock_guard guard(cell_mutex_); for (unsigned i = 0; i < Tdim; i++) { poisson_right_matrix_.block(0, i * nnodes_, nnodes_, nnodes_) += - shapefn * grad_shapefn.col(i).transpose() * pvolume; + shapefn * grad_shapefn.col(i).transpose() * multiplier * pvolume; } } diff --git a/include/mesh.tcc b/include/mesh.tcc index 94154abef..02eaa5d47 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1960,7 +1960,7 @@ bool mpm::Mesh::compute_free_surface(double tolerance) { // Assign free surface nodes if (!common_node_id.empty()) { for (const auto common_id : common_node_id) { - map_nodes_[common_id]->assign_free_surface(candidate_cell); + map_nodes_[common_id]->assign_free_surface(true); } } } @@ -1968,7 +1968,7 @@ bool mpm::Mesh::compute_free_surface(double tolerance) { // Assign free surface cell if (candidate_cell) { - (*citr)->assign_free_surface(candidate_cell); + (*citr)->assign_free_surface(true); free_surface_candidate_cells.insert((*citr)->id()); } } @@ -2099,7 +2099,7 @@ bool mpm::Mesh::compute_free_surface(double tolerance) { // Assign normal only to validated free surface if (free_surface) { - particle->assign_free_surface(free_surface); + particle->assign_free_surface(true); particle->assign_normal(normal); free_surface_particles.insert(p_id); } diff --git a/include/particles/fluid_particle.tcc b/include/particles/fluid_particle.tcc index 7c04e3d16..79364239f 100644 --- a/include/particles/fluid_particle.tcc +++ b/include/particles/fluid_particle.tcc @@ -144,8 +144,8 @@ bool mpm::FluidParticle::map_poisson_right_to_cell() { try { // Compute local poisson rhs matrix cell_->compute_local_poisson_right( - shapefn_, dn_dx_, - material_->template property(std::string("density")) * volume_); + shapefn_, dn_dx_, volume_, + material_->template property(std::string("density"))); } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); status = false; From 921e00c4d1b52126e86a715ee881c888bb94c5a1 Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Fri, 10 Apr 2020 18:43:56 -0500 Subject: [PATCH 45/72] :computer: Add PETSc to CMake --- CMakeLists.txt | 6 ++ cmake/FindPETSc.cmake | 154 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 160 insertions(+) create mode 100644 cmake/FindPETSc.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 59ed86445..a6b9c8336 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -106,6 +106,12 @@ if (MKL_FOUND) endif() endif() +# PETSc +find_package(PETSc COMPONENTS C) +if (PETSC_FOUND) + include_directories(${PETSC_INCLUDES}) + link_libraries(${PETSC_LIBRARIES}) +endif() # KaHIP if (MPI_FOUND) diff --git a/cmake/FindPETSc.cmake b/cmake/FindPETSc.cmake new file mode 100644 index 000000000..dedbe2d84 --- /dev/null +++ b/cmake/FindPETSc.cmake @@ -0,0 +1,154 @@ +################################################################# +# Try to find PETSc # +# # +# Once done this will define: # +# PETSC_FOUND - system has PETSc # +# PETSC_DIR - PETSc directory # +# PETSC_ARCH - PETSc architecture # +# PETSC_INC - PETSc include directory # +# PETSC_LIB - PETSc library (static or dynamic) # +# PETSC_VARIABLES - Content of PETSc 'petscvariables' file # +# # +# PETSC_MUMPS - Was PETSc compiled with MUMPS? # +# PETSC_MUMPS_INC - PETSc MUMPS include file # +# PETSC_MUMPS_LIB - PETSc MUMPS libraries # +# # +# PETSC_SCALAPACK - Was PETSc compiled with ScaLAPACK? # +# PETSC_SCALAPACK_LIB - PETSc ScaLAPACK libraries # +# # +# PETSC_PARMETIS - Was PETSc compiled with ParMETIS? # +# PETSC_PARMETIS_LIB - PETSc ParMETIS libraries # +# # +# PETSC_METIS - Was PETSc compiled with Metis? # +# PETSC_METIS_LIB - PETSc METIS libraries # +# # +# PETSC_MPIUNI - Was PETSc compiled with MPIUNI? # +# PETSC_MPIUNI_INC - MPIUNI include file # +# # +# Usage: # +# find_package(PETSc) # +# # +# Setting these changes the behavior of the search # +# PETSC_DIR - PETSc directory # +# PETSC_ARCH - PETSc architecture # +################################################################# + +## Try to set PETSC_DIR and PETSC_ARCH ## +######################################### +if(NOT DEFINED PETSC_DIR) + set(PETSC_DIR $ENV{PETSC_DIR}) +endif() +if(NOT DEFINED PETSC_ARCH) + set(PETSC_ARCH $ENV{PETSC_ARCH}) +endif() + +## Includes ## +############## +if(EXISTS "${PETSC_DIR}/include" AND + EXISTS "${PETSC_DIR}/${PETSC_ARCH}/include") + set(PETSC_INC "${PETSC_DIR}/include" "${PETSC_DIR}/${PETSC_ARCH}/include") +else() + message(SEND_ERROR "PETSc includes not found") +endif() + +## Library ## +############# +if(EXISTS "${PETSC_DIR}/${PETSC_ARCH}/lib/libpetsc.so") + set(PETSC_LIB "${PETSC_DIR}/${PETSC_ARCH}/lib/libpetsc.so") +elseif(EXISTS "${PETSC_DIR}/${PETSC_ARCH}/lib/libpetsc.a") + set(PETSC_LIB "${PETSC_DIR}/${PETSC_ARCH}/lib/libpetsc.a") +else() + message(SEND_ERROR "PETSc library not found") +endif() + +## PETSc variables ## +##################### +if(EXISTS ${PETSC_DIR}/${PETSC_ARCH}/conf/petscvariables) + file(STRINGS ${PETSC_DIR}/${PETSC_ARCH}/conf/petscvariables + PETSC_VARIABLES NEWLINE_CONSUME) +elseif(EXISTS ${PETSC_DIR}/${PETSC_ARCH}/lib/petsc/conf/petscvariables) + file(STRINGS ${PETSC_DIR}/${PETSC_ARCH}/lib/petsc/conf/petscvariables + PETSC_VARIABLES NEWLINE_CONSUME) +else() + message(SEND_ERROR "PETSc variables not found") +endif() + +## MUMPS ## +########### +if(EXISTS ${PETSC_DIR}/${PETSC_ARCH}/lib/libmumps_common.a) + set(PETSC_MUMPS TRUE) + set(PETSC_MUMPS_INC ${PETSC_INC}) + set(PETSC_MUMPS_LIB + ${PETSC_DIR}/${PETSC_ARCH}/lib/libcmumps.a + ${PETSC_DIR}/${PETSC_ARCH}/lib/libdmumps.a + ${PETSC_DIR}/${PETSC_ARCH}/lib/libsmumps.a + ${PETSC_DIR}/${PETSC_ARCH}/lib/libzmumps.a + ${PETSC_DIR}/${PETSC_ARCH}/lib/libmumps_common.a + ${PETSC_DIR}/${PETSC_ARCH}/lib/libpord.a) + + if(EXISTS ${PETSC_DIR}/${PETSC_ARCH}/lib/libmpiseq.a) + set(PETSC_MUMPS_SEQ ${PETSC_DIR}/${PETSC_ARCH}/lib/libmpiseq.a) + else() + set(PETSC_MUMPS_SEQ "") + endif() + +else() + set(PETSC_MUMPS FALSE) + set(PETSC_MUMPS_INC "") + set(PETSC_MUMPS_LIB "") + set(PETSC_MUMPS_SEQ "") +endif() + +## ScaLAPACK ## +############### +if(EXISTS ${PETSC_DIR}/${PETSC_ARCH}/lib/libscalapack.a) + set(PETSC_SCALAPACK TRUE) + set(PETSC_SCALAPACK_LIB ${PETSC_DIR}/${PETSC_ARCH}/lib/libscalapack.a) +else() + set(PETSC_SCALAPACK FALSE) + set(PETSC_SCALAPACK_LIB "") +endif() + +## ParMETIS ## +############## +if(EXISTS ${PETSC_DIR}/${PETSC_ARCH}/lib/libparmetis.so) + set(PETSC_PARMETIS TRUE) + set(PETSC_PARMETIS_LIB ${PETSC_DIR}/${PETSC_ARCH}/lib/libparmetis.so) +else() + set(PETSC_PARMETIS FALSE) + set(PETSC_PARMETIS_LIB "") +endif() + +## METIS ## +############ +if(EXISTS ${PETSC_DIR}/${PETSC_ARCH}/lib/libmetis.so) + set(PETSC_METIS TRUE) + set(PETSC_METIS_LIB ${PETSC_DIR}/${PETSC_ARCH}/lib/libmetis.so) +else() + set(PETSC_METIS FALSE) + set(PETSC_METIS_LIB "") +endif() + +## MPI Uni ## +############# +string(REGEX MATCH "MPI_IS_MPIUNI = [^\n\r]*" PETSC_MPIUNI ${PETSC_VARIABLES}) +if(PETSC_MPIUNI) + string(REPLACE "MPI_IS_MPIUNI = " "" PETSC_MPIUNI ${PETSC_MPIUNI}) + string(STRIP ${PETSC_MPIUNI} PETSC_MPIUNI) + string(COMPARE EQUAL ${PETSC_MPIUNI} "1" PETSC_MPIUNI) + + string(REGEX MATCH "MPI_INCLUDE = -I[^\n\r]*" + PETSC_MPIUNI_INC ${PETSC_VARIABLES}) + string(REPLACE "MPI_INCLUDE = -I" "" PETSC_MPIUNI_INC ${PETSC_MPIUNI_INC}) + string(STRIP ${PETSC_MPIUNI_INC} PETSC_MPIUNI_INC) +else() + set(PETSC_MPIUNI FALSE) + set(PETSC_MPIUNI_INC "") +endif() + +## CMake check and done ## +########################## +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(PETSc + "PETSc could not be found: be sure to set PETSC_DIR and PETSC_ARCH in your environment variables" + PETSC_LIB PETSC_INC PETSC_DIR PETSC_ARCH) From d59d84a3af103f6b23116bcddfc4d8dbbc40da11 Mon Sep 17 00:00:00 2001 From: Nanda Date: Fri, 10 Apr 2020 21:36:05 -0700 Subject: [PATCH 46/72] add mkl --- include/linear_solvers/cg_mkl.h | 43 ++++++++++++++ include/linear_solvers/cg_mkl.tcc | 98 +++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 include/linear_solvers/cg_mkl.h create mode 100644 include/linear_solvers/cg_mkl.tcc diff --git a/include/linear_solvers/cg_mkl.h b/include/linear_solvers/cg_mkl.h new file mode 100644 index 000000000..ca0064dad --- /dev/null +++ b/include/linear_solvers/cg_mkl.h @@ -0,0 +1,43 @@ +#ifndef MPM_CG_MKL_H_ +#define MPM_CG_MKL_H_ + +#include + +#include +#include + +#include "cg_eigen.h" + +namespace mpm { +template +class CGMKL; +} + +//! MPM Eigen CG class +//! \brief Conjugate Gradient solver class using Intel MKL +template +class mpm::CGMKL : public CGEigen { + public: + using CGEigen::CGEigen; + + bool solve() override; + + protected: + //! Logger + using Solver::console_; +}; + +//! Handle raw pointers in MKL +//! Only functionality is: +//! 1) to delete the memory when the object goes out of scope and; +//! 2) implicitly cast to the raw pointer so it can be passed to MKL directly. +//! \tparam T Type +template +struct ptr_t : std::unique_ptr { + ptr_t(const size_t& n) : std::unique_ptr(new T[n]) {} + operator T*() { return this->get(); } +}; + +#include "cg_mkl.tcc" + +#endif // MPM_CG_MKL_H_ \ No newline at end of file diff --git a/include/linear_solvers/cg_mkl.tcc b/include/linear_solvers/cg_mkl.tcc new file mode 100644 index 000000000..7d299e3db --- /dev/null +++ b/include/linear_solvers/cg_mkl.tcc @@ -0,0 +1,98 @@ +//! Conjugate Gradient Solver +template +bool lem::CGMKL::solve() { + bool convergence = false; + double init_delta, new_delta; + + const MKL_INT n = this->vec_b_->size(), incr = 1; + ptr_t vs(n), vd(n), vq(n), vm(n); + + double* vec_x = this->vec_x_->data(); + double* vec_b = this->vec_b_->data(); + const double* vrestraints = this->vrestraints_.data(); + + // Residual + // (*vec_b_) -= mat_a * (*vec_x_); + for (const auto& mat_a : *this->mat_a_) { + // y := alpha*A*x + beta*y + const double a = -1.0, b = 1.0; + mkl_dcsrmv("N", &n, &n, &a, "GiiC", mat_a.valuePtr(), mat_a.innerIndexPtr(), + mat_a.outerIndexPtr(), mat_a.outerIndexPtr() + 1, vec_x, &b, + vec_b); + } + + Eigen::Map(vm, n) = this->precondition_jacobian(); + + // vd = vm * vec_b + vdMul(n, vm, vec_b, vd); + + init_delta = new_delta = ddot(&n, vd, &incr, vec_b, &incr); + + unsigned i = 0; + double alpha = 0., old_delta = 0.; + for (i = 0; i < this->max_iter_; ++i) { + // vq = mat_a_ * vd; + memset(vq, 0, n * sizeof(double)); + for (const auto& mat_a : *this->mat_a_) { + const double a = 1.0, b = 1.0; + // y := alpha*A*x + beta*y + mkl_dcsrmv("N", &n, &n, &a, "GiiC", mat_a.valuePtr(), + mat_a.innerIndexPtr(), mat_a.outerIndexPtr(), + mat_a.outerIndexPtr() + 1, vd, &b, vq); + } + // Apply restraints + // vq = vq * vrestraints + vdMul(n, vq, vrestraints, vq); + + // alpha = new_delta / vd.dot(vq) + alpha = new_delta / ddot(&n, vd, &incr, vq, &incr); + + { // vec_x += alpha * vd + double a = alpha; + daxpy(&n, &a, vd, &incr, vec_x, &incr); + } + { // vec_b -= alpha * vq + double a = -alpha; + daxpy(&n, &a, vq, &incr, vec_b, &incr); + } + + // vs = vm * vec_b + vdMul(n, vm, vec_b, vs); + + old_delta = new_delta; + new_delta = ddot(&n, vec_b, &incr, vs, &incr); + + { // vd = vs + (new_delta / old_delta) * vd; + double a = 1.0; + double b = new_delta / old_delta; + daxpby(&n, &a, vs, &incr, &b, vd, &incr); + } + + // Break if convergence criterion is achieved + if (new_delta < + std::fabs(this->tolerance_ * this->tolerance_ * init_delta)) { + convergence = true; + break; + } + } + + // Update external nodal force in the system + (this->vec_b_)->setZero(); + // (*vec_b_) = mat_a * (*vec_x_); + for (const auto& mat_a : *this->mat_a_) { + // y := alpha*A*x + beta*y + const double a = 1., b = 1.; + mkl_dcsrmv("N", &n, &n, &a, "GiiC", mat_a.valuePtr(), mat_a.innerIndexPtr(), + mat_a.outerIndexPtr(), mat_a.outerIndexPtr() + 1, vec_x, &b, + vec_b); + } + + // Update delta and iterations + this->delta_ = new_delta; + this->niterations_ = i; + + console_->info("Iteration: {} of {}; delta: {}", i, this->max_iter_, + new_delta); + + return convergence; +} \ No newline at end of file From 89e1fbb249305a900f165d0776ca0ccdcf60ee13 Mon Sep 17 00:00:00 2001 From: Nanda Date: Sat, 11 Apr 2020 15:19:19 -0700 Subject: [PATCH 47/72] change template argument --- include/linear_solvers/cg_eigen.h | 12 +++++----- include/linear_solvers/cg_eigen.tcc | 22 +++++++++---------- include/linear_solvers/solver_base.h | 2 +- .../solvers/mpm_semi_implicit_navierstokes.h | 2 +- .../mpm_semi_implicit_navierstokes.tcc | 5 +++-- src/linear_solver.cc | 10 ++++----- 6 files changed, 26 insertions(+), 27 deletions(-) diff --git a/include/linear_solvers/cg_eigen.h b/include/linear_solvers/cg_eigen.h index 44e66447d..796be7dc6 100644 --- a/include/linear_solvers/cg_eigen.h +++ b/include/linear_solvers/cg_eigen.h @@ -14,15 +14,15 @@ namespace mpm { //! MPM Eigen CG class //! \brief Conjugate Gradient solver class using Eigen -template -class CGEigen : public SolverBase { +template +class CGEigen : public SolverBase { public: //! Constructor //! \param[in] max_iter Maximum number of iterations //! \param[in] tolerance Tolerance for solver to achieve convergence CGEigen(unsigned max_iter, double tolerance) - : mpm::SolverBase(max_iter, tolerance) { + : mpm::SolverBase(max_iter, tolerance) { //! Logger console_ = spdlog::stdout_color_mt("EigenSolver"); }; @@ -42,11 +42,11 @@ class CGEigen : public SolverBase { protected: //! Maximum number of iterations - using SolverBase::max_iter_; + using SolverBase::max_iter_; //! Tolerance - using SolverBase::tolerance_; + using SolverBase::tolerance_; //! Logger - using SolverBase::console_; + using SolverBase::console_; //! cg_type_ (leastSquaresConjugateGradient or ConjugateGradient) std::string cg_type_; }; diff --git a/include/linear_solvers/cg_eigen.tcc b/include/linear_solvers/cg_eigen.tcc index 4ede0b9c0..2feae13eb 100644 --- a/include/linear_solvers/cg_eigen.tcc +++ b/include/linear_solvers/cg_eigen.tcc @@ -1,8 +1,8 @@ //! Conjugate Gradient Solver -template -Eigen::VectorXd mpm::CGEigen::solve(const Eigen::SparseMatrix& A, - const Eigen::VectorXd& b, - std::string solver_type) { +template +Eigen::VectorXd mpm::CGEigen::solve( + const Eigen::SparseMatrix& A, const Eigen::VectorXd& b, + std::string solver_type) { Eigen::VectorXd x; try { @@ -43,8 +43,8 @@ Eigen::VectorXd mpm::CGEigen::solve(const Eigen::SparseMatrix& A, } //! Conjugate Gradient Solver -template -Eigen::VectorXd mpm::CGEigen::solve( +template +Eigen::VectorXd mpm::CGEigen::solve( const Eigen::SparseMatrix& A, const Eigen::VectorXd& b, std::string solver_type, const Eigen::VectorXd& initial_guess) { Eigen::VectorXd x; @@ -85,9 +85,9 @@ Eigen::VectorXd mpm::CGEigen::solve( /* //! Precondition Jacobian -template -typename mpm::CGEigen::Eigen::VectorXd - mpm::CGEigen::precondition_jacobian() { +template +typename mpm::CGEigen::Eigen::VectorXd + mpm::CGEigen::precondition_jacobian() { const size_t n = vec_b_->size(); Eigen::VectorXd vm(n); @@ -107,8 +107,8 @@ typename mpm::CGEigen::Eigen::VectorXd } //! Cholesky solver -template -bool mpm::CGEigen::cholesky() { +template +bool mpm::CGEigen::cholesky() { SparseMatrix stiff; for (auto& mat_a : *mat_a_) stiff += mat_a; diff --git a/include/linear_solvers/solver_base.h b/include/linear_solvers/solver_base.h index 33768781a..0b7745d1a 100644 --- a/include/linear_solvers/solver_base.h +++ b/include/linear_solvers/solver_base.h @@ -3,7 +3,7 @@ #include "spdlog/spdlog.h" namespace mpm { -template +template class SolverBase { public: //! Constructor with min and max iterations and tolerance diff --git a/include/solvers/mpm_semi_implicit_navierstokes.h b/include/solvers/mpm_semi_implicit_navierstokes.h index b93e435c2..1196542dd 100644 --- a/include/solvers/mpm_semi_implicit_navierstokes.h +++ b/include/solvers/mpm_semi_implicit_navierstokes.h @@ -81,7 +81,7 @@ class MPMSemiImplicitNavierStokes : public MPMBase { //! Matrix assembler object std::shared_ptr> matrix_assembler_; //! Matrix solver object - std::shared_ptr> matrix_solver_; + std::shared_ptr>> matrix_solver_; //! Volume tolerance for free surface double volume_tolerance_{0}; diff --git a/include/solvers/mpm_semi_implicit_navierstokes.tcc b/include/solvers/mpm_semi_implicit_navierstokes.tcc index 660bc4576..fc3a56931 100644 --- a/include/solvers/mpm_semi_implicit_navierstokes.tcc +++ b/include/solvers/mpm_semi_implicit_navierstokes.tcc @@ -266,8 +266,9 @@ bool mpm::MPMSemiImplicitNavierStokes::initialise_matrix() { Factory>::instance()->create(assembler_type); // Create matrix solver matrix_solver_ = - Factory, unsigned, double>::instance()->create( - solver_type, std::move(max_iter), std::move(tolerance)); + Factory>, unsigned, + double>::instance() + ->create(solver_type, std::move(max_iter), std::move(tolerance)); // Assign mesh pointer to assembler matrix_assembler_->assign_mesh_pointer(mesh_); diff --git a/src/linear_solver.cc b/src/linear_solver.cc index 8f3b35398..3b8a92673 100644 --- a/src/linear_solver.cc +++ b/src/linear_solver.cc @@ -28,9 +28,7 @@ static Register, "ParallelSemiImplicitNavierStokes3D"); // Linear Solver collections -// Solver 2D -static Register, mpm::CGEigen<2>, unsigned, double> - solver_eigen_cg_2d("EigenCG2D"); -// Solver 3D -static Register, mpm::CGEigen<3>, unsigned, double> - solver_eigen_cg_3d("EigenCG3D"); \ No newline at end of file +// Eigen Conjugate Gradient +static Register>, + mpm::CGEigen>, unsigned, double> + solver_eigen_cg("EigenCG"); \ No newline at end of file From 7fff2aed2b2b56e5224be795c079b4056356c2ac Mon Sep 17 00:00:00 2001 From: Nanda Date: Sat, 11 Apr 2020 15:20:19 -0700 Subject: [PATCH 48/72] cleanup eigen cg --- include/linear_solvers/cg_eigen.tcc | 49 +++++------------------------ 1 file changed, 7 insertions(+), 42 deletions(-) diff --git a/include/linear_solvers/cg_eigen.tcc b/include/linear_solvers/cg_eigen.tcc index 2feae13eb..b3cebe9c9 100644 --- a/include/linear_solvers/cg_eigen.tcc +++ b/include/linear_solvers/cg_eigen.tcc @@ -1,4 +1,4 @@ -//! Conjugate Gradient Solver +//! Conjugate Gradient with default initial guess template Eigen::VectorXd mpm::CGEigen::solve( const Eigen::SparseMatrix& A, const Eigen::VectorXd& b, @@ -16,7 +16,7 @@ Eigen::VectorXd mpm::CGEigen::solve( x = solver.solve(b); if (solver.info() != Eigen::Success) { - throw std::runtime_error("Fail to solve intermediate acceleration\n"); + throw std::runtime_error("Fail to solve linear systems!\n"); } } else if (solver_type == "lscg") { @@ -32,7 +32,7 @@ Eigen::VectorXd mpm::CGEigen::solve( x = solver.solve(b); if (solver.info() != Eigen::Success) { - throw std::runtime_error("Fail to solve intermediate acceleration\n"); + throw std::runtime_error("Fail to solve linear systems!\n"); } } @@ -42,7 +42,7 @@ Eigen::VectorXd mpm::CGEigen::solve( return x; } -//! Conjugate Gradient Solver +//! Conjugate Gradient with defined initial guess template Eigen::VectorXd mpm::CGEigen::solve( const Eigen::SparseMatrix& A, const Eigen::VectorXd& b, @@ -60,7 +60,7 @@ Eigen::VectorXd mpm::CGEigen::solve( x = solver.solveWithGuess(b, initial_guess); if (solver.info() != Eigen::Success) { - throw std::runtime_error("Fail to solve intermediate acceleration\n"); + throw std::runtime_error("Fail to solve linear systems!\n"); } } else if (solver_type == "lscg") { @@ -73,7 +73,7 @@ Eigen::VectorXd mpm::CGEigen::solve( x = solver.solveWithGuess(b, initial_guess); if (solver.info() != Eigen::Success) { - throw std::runtime_error("Fail to solve intermediate acceleration\n"); + throw std::runtime_error("Fail to solve linear systems!\n"); } } @@ -81,39 +81,4 @@ Eigen::VectorXd mpm::CGEigen::solve( console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); } return x; -} - -/* -//! Precondition Jacobian -template -typename mpm::CGEigen::Eigen::VectorXd - mpm::CGEigen::precondition_jacobian() { - const size_t n = vec_b_->size(); - Eigen::VectorXd vm(n); - - vm.setZero(); - for (auto& mat_a : *mat_a_) { - for (size_t i = 0; i < n; ++i) { - vm[i] += mat_a.coeff(i, i); - } - } - for (size_t i = 0; i < n; ++i) { - vm[i] = 1 / vm[i]; - // When beta is zero, the stiffness matrix will have zero value elements - if (!std::isfinite(vm[i])) vm[i] = 1.0; - } - vm = vm.array() * vrestraints_.array(); - return vm; -} - -//! Cholesky solver -template -bool mpm::CGEigen::cholesky() { - SparseMatrix stiff; - for (auto& mat_a : *mat_a_) stiff += mat_a; - - Eigen::SimplicialCholesky cholesky(stiff); - *vec_x_ = cholesky.solve(*vec_b_); - return (cholesky.info() == Eigen::Success); -} -*/ +} \ No newline at end of file From 132d1e6288763afbcc43540dff70a60b2f23d2d4 Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Mon, 13 Apr 2020 18:58:23 -0500 Subject: [PATCH 49/72] :construction: Test PETSc environment variables --- .circleci/config.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 8c8541ea6..7128c2301 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -16,6 +16,8 @@ jobs: export MODULEPATH=$MODULEPATH:/usr/share/modulefiles module load mpi/openmpi-x86_64 export CXX_COMPILER=mpicxx + export PETSC_ARCH=arch-linux2-c-opt + export PETSC_DIR=/home/cbgeo/petsc/ cmake -GNinja -DMPM_BUILD_LIB=On -DCMAKE_CXX_COMPILER=mpicxx -DCMAKE_EXPORT_COMPILE_COMMANDS=On -DKAHIP_ROOT=/home/cbgeo/KaHIP/ -DPARTIO_ROOT=/home/cbgeo/partio/ .. ninja -j2 ctest -VV @@ -32,6 +34,8 @@ jobs: mkdir -p build [ "$(ls -A build)" ] && rm -rf build/* cd build + export PETSC_ARCH=arch-linux2-c-opt + export PETSC_DIR=/home/cbgeo/petsc/ scan-build cmake -GNinja -DCMAKE_BUILD_TYPE=Debug -DMPM_BUILD_LIB=On -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang -DCMAKE_EXPORT_COMPILE_COMMANDS=On -DKAHIP_ROOT=/home/cbgeo/KaHIP/ -DPARTIO_ROOT=/home/cbgeo/partio/ .. scan-build -k -V ninja -j2 ctest -VV @@ -64,6 +68,8 @@ jobs: mkdir -p build [ "$(ls -A build)" ] && rm -rf build/* cd build + export PETSC_ARCH=arch-linux2-c-opt + export PETSC_DIR=/home/cbgeo/petsc/ cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=mpicxx -DCMAKE_EXPORT_COMPILE_COMMANDS=On -DENABLE_COVERAGE=On -DKAHIP_ROOT=/home/cbgeo/KaHIP/ -DPARTIO_ROOT=/home/cbgeo/partio/ .. make mpmtest_coverage -j2 ./mpmtest_coverage From b087eca5869da2ca32293d732ebd577d84c23576 Mon Sep 17 00:00:00 2001 From: Nanda Date: Mon, 13 Apr 2020 17:09:55 -0700 Subject: [PATCH 50/72] remove mkl --- include/linear_solvers/cg_mkl.h | 43 -------------- include/linear_solvers/cg_mkl.tcc | 98 ------------------------------- 2 files changed, 141 deletions(-) delete mode 100644 include/linear_solvers/cg_mkl.h delete mode 100644 include/linear_solvers/cg_mkl.tcc diff --git a/include/linear_solvers/cg_mkl.h b/include/linear_solvers/cg_mkl.h deleted file mode 100644 index ca0064dad..000000000 --- a/include/linear_solvers/cg_mkl.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef MPM_CG_MKL_H_ -#define MPM_CG_MKL_H_ - -#include - -#include -#include - -#include "cg_eigen.h" - -namespace mpm { -template -class CGMKL; -} - -//! MPM Eigen CG class -//! \brief Conjugate Gradient solver class using Intel MKL -template -class mpm::CGMKL : public CGEigen { - public: - using CGEigen::CGEigen; - - bool solve() override; - - protected: - //! Logger - using Solver::console_; -}; - -//! Handle raw pointers in MKL -//! Only functionality is: -//! 1) to delete the memory when the object goes out of scope and; -//! 2) implicitly cast to the raw pointer so it can be passed to MKL directly. -//! \tparam T Type -template -struct ptr_t : std::unique_ptr { - ptr_t(const size_t& n) : std::unique_ptr(new T[n]) {} - operator T*() { return this->get(); } -}; - -#include "cg_mkl.tcc" - -#endif // MPM_CG_MKL_H_ \ No newline at end of file diff --git a/include/linear_solvers/cg_mkl.tcc b/include/linear_solvers/cg_mkl.tcc deleted file mode 100644 index 7d299e3db..000000000 --- a/include/linear_solvers/cg_mkl.tcc +++ /dev/null @@ -1,98 +0,0 @@ -//! Conjugate Gradient Solver -template -bool lem::CGMKL::solve() { - bool convergence = false; - double init_delta, new_delta; - - const MKL_INT n = this->vec_b_->size(), incr = 1; - ptr_t vs(n), vd(n), vq(n), vm(n); - - double* vec_x = this->vec_x_->data(); - double* vec_b = this->vec_b_->data(); - const double* vrestraints = this->vrestraints_.data(); - - // Residual - // (*vec_b_) -= mat_a * (*vec_x_); - for (const auto& mat_a : *this->mat_a_) { - // y := alpha*A*x + beta*y - const double a = -1.0, b = 1.0; - mkl_dcsrmv("N", &n, &n, &a, "GiiC", mat_a.valuePtr(), mat_a.innerIndexPtr(), - mat_a.outerIndexPtr(), mat_a.outerIndexPtr() + 1, vec_x, &b, - vec_b); - } - - Eigen::Map(vm, n) = this->precondition_jacobian(); - - // vd = vm * vec_b - vdMul(n, vm, vec_b, vd); - - init_delta = new_delta = ddot(&n, vd, &incr, vec_b, &incr); - - unsigned i = 0; - double alpha = 0., old_delta = 0.; - for (i = 0; i < this->max_iter_; ++i) { - // vq = mat_a_ * vd; - memset(vq, 0, n * sizeof(double)); - for (const auto& mat_a : *this->mat_a_) { - const double a = 1.0, b = 1.0; - // y := alpha*A*x + beta*y - mkl_dcsrmv("N", &n, &n, &a, "GiiC", mat_a.valuePtr(), - mat_a.innerIndexPtr(), mat_a.outerIndexPtr(), - mat_a.outerIndexPtr() + 1, vd, &b, vq); - } - // Apply restraints - // vq = vq * vrestraints - vdMul(n, vq, vrestraints, vq); - - // alpha = new_delta / vd.dot(vq) - alpha = new_delta / ddot(&n, vd, &incr, vq, &incr); - - { // vec_x += alpha * vd - double a = alpha; - daxpy(&n, &a, vd, &incr, vec_x, &incr); - } - { // vec_b -= alpha * vq - double a = -alpha; - daxpy(&n, &a, vq, &incr, vec_b, &incr); - } - - // vs = vm * vec_b - vdMul(n, vm, vec_b, vs); - - old_delta = new_delta; - new_delta = ddot(&n, vec_b, &incr, vs, &incr); - - { // vd = vs + (new_delta / old_delta) * vd; - double a = 1.0; - double b = new_delta / old_delta; - daxpby(&n, &a, vs, &incr, &b, vd, &incr); - } - - // Break if convergence criterion is achieved - if (new_delta < - std::fabs(this->tolerance_ * this->tolerance_ * init_delta)) { - convergence = true; - break; - } - } - - // Update external nodal force in the system - (this->vec_b_)->setZero(); - // (*vec_b_) = mat_a * (*vec_x_); - for (const auto& mat_a : *this->mat_a_) { - // y := alpha*A*x + beta*y - const double a = 1., b = 1.; - mkl_dcsrmv("N", &n, &n, &a, "GiiC", mat_a.valuePtr(), mat_a.innerIndexPtr(), - mat_a.outerIndexPtr(), mat_a.outerIndexPtr() + 1, vec_x, &b, - vec_b); - } - - // Update delta and iterations - this->delta_ = new_delta; - this->niterations_ = i; - - console_->info("Iteration: {} of {}; delta: {}", i, this->max_iter_, - new_delta); - - return convergence; -} \ No newline at end of file From 992e98397aa4b6ab5d63a0d456c99e28b57ddbdd Mon Sep 17 00:00:00 2001 From: Bodhinanda Chandra Date: Mon, 13 Apr 2020 19:34:39 -0500 Subject: [PATCH 51/72] add default using PETSC as off --- CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a6b9c8336..f7ee5780a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,6 +44,9 @@ option(MPM_BUILD_LIB "enable libmpm" OFF) # Halo exchange option(HALO_EXCHANGE "Enable halo exchange" OFF) +# PETSC +option(USE_PETSC "Use PETSC solver library" OFF) + # CMake Modules set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) @@ -107,7 +110,9 @@ if (MKL_FOUND) endif() # PETSc -find_package(PETSc COMPONENTS C) +if (USE_PETSC) + find_package(PETSc COMPONENTS C) +endif() if (PETSC_FOUND) include_directories(${PETSC_INCLUDES}) link_libraries(${PETSC_LIBRARIES}) From 5eeecaafc9af2c4a6e01a18793d0a732f0135a3a Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 14 Apr 2020 18:38:35 -0700 Subject: [PATCH 52/72] add sign distance computation --- include/mesh.tcc | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/include/mesh.tcc b/include/mesh.tcc index 02eaa5d47..34929413d 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1938,6 +1938,7 @@ bool mpm::Mesh::compute_free_surface(double tolerance) { // First, we detect the cell with possible free surfaces // Compute boundary cells and nodes based on geometry std::set free_surface_candidate_cells; + std::set free_surface_candidate_nodes; for (auto citr = this->cells_.cbegin(); citr != this->cells_.cend(); ++citr) { // Cell contains particles @@ -1970,6 +1971,7 @@ bool mpm::Mesh::compute_free_surface(double tolerance) { if (candidate_cell) { (*citr)->assign_free_surface(true); free_surface_candidate_cells.insert((*citr)->id()); + free_surface_candidate_nodes.insert(node_id.begin(), node_id.end()); } } } @@ -2064,7 +2066,10 @@ bool mpm::Mesh::compute_free_surface(double tolerance) { (particle->mass() / particle->mass_density()) * kernel_gradient; } normal = -renormalization_matrix_inv.inverse() * temporary_vec; - normal.normalize(); + if (normal.norm() > std::numeric_limits::epsilon()) + normal.normalize(); + else + normal.setZero(); } // If secondary check is needed @@ -2105,6 +2110,29 @@ bool mpm::Mesh::compute_free_surface(double tolerance) { } } + // Compute node sign distance function + for (const auto node_id : free_surface_candidate_nodes) { + const auto& node_coord = map_nodes_[node_id]->coordinates(); + double closest_distance = std::numeric_limits::max(); + double sign_distance = std::numeric_limits::max(); + for (const auto fs_id : free_surface_particles) { + const auto& fs_particle = map_particles_[fs_id]; + const VectorDim fs_coord = + fs_particle->coordinates() + + 0.5 * fs_particle->diameter() * fs_particle->normal(); + const VectorDim rel_coord = fs_coord - node_coord; + const double distance = rel_coord.norm(); + if (distance < closest_distance) { + closest_distance = distance; + sign_distance = (rel_coord).dot(fs_particle->normal()); + } + } + + // If sign distance is negative, node is outside the body + if (sign_distance <= std::numeric_limits::epsilon()) + map_nodes_[node_id]->assign_free_surface(true); + } + } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); } From bba0ec928f17647d082cf0b83ef14f210eec6258 Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 14 Apr 2020 22:06:24 -0700 Subject: [PATCH 53/72] add sign distance --- include/mesh.tcc | 9 ++++++--- include/node.h | 10 ++++++++++ include/node_base.h | 6 ++++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/include/mesh.tcc b/include/mesh.tcc index 34929413d..a4e617c95 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -2114,7 +2114,7 @@ bool mpm::Mesh::compute_free_surface(double tolerance) { for (const auto node_id : free_surface_candidate_nodes) { const auto& node_coord = map_nodes_[node_id]->coordinates(); double closest_distance = std::numeric_limits::max(); - double sign_distance = std::numeric_limits::max(); + double signed_distance = std::numeric_limits::max(); for (const auto fs_id : free_surface_particles) { const auto& fs_particle = map_particles_[fs_id]; const VectorDim fs_coord = @@ -2124,12 +2124,15 @@ bool mpm::Mesh::compute_free_surface(double tolerance) { const double distance = rel_coord.norm(); if (distance < closest_distance) { closest_distance = distance; - sign_distance = (rel_coord).dot(fs_particle->normal()); + signed_distance = (rel_coord).dot(fs_particle->normal()); } } + // Assign signed distance to node + map_nodes_[node_id]->assign_signed_distance(signed_distance); + // If sign distance is negative, node is outside the body - if (sign_distance <= std::numeric_limits::epsilon()) + if (signed_distance <= std::numeric_limits::epsilon()) map_nodes_[node_id]->assign_free_surface(true); } diff --git a/include/node.h b/include/node.h index 902cfcdfb..8fc43c059 100644 --- a/include/node.h +++ b/include/node.h @@ -255,6 +255,14 @@ class Node : public NodeBase { //! Return free surface bool bool free_surface() override { return free_surface_; } + //! Assign signed distance + void assign_signed_distance(double signed_distance) override { + signed_distance_ = signed_distance; + } + + //! Return signed distance + double signed_distance() override { return signed_distance_; } + //! Assign active id void assign_active_id(Index id) override { active_id_ = id; } @@ -364,6 +372,8 @@ class Node : public NodeBase { Eigen::Matrix correction_force_; //! Free surface bool free_surface_{false}; + //! Signed distance + double signed_distance_; }; // Node class } // namespace mpm diff --git a/include/node_base.h b/include/node_base.h index bbd4a0e09..abd8aafd4 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -239,6 +239,12 @@ class NodeBase { //! Return free surface bool virtual bool free_surface() = 0; + //! Assign signed distance + virtual void assign_signed_distance(double signed_distance) = 0; + + //! Return signed distance + virtual double signed_distance() = 0; + //! Assign active id virtual void assign_active_id(Index id) = 0; From 266e16c58320f4fba732674a8cd80d63cec36e23 Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 15 Apr 2020 15:20:19 -0700 Subject: [PATCH 54/72] add modification free surface --- include/mesh.tcc | 63 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 21 deletions(-) diff --git a/include/mesh.tcc b/include/mesh.tcc index a4e617c95..012c62d36 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1935,6 +1935,24 @@ bool mpm::Mesh::compute_free_surface(double tolerance) { std::bind(&mpm::ParticleBase::assign_free_surface, std::placeholders::_1, false)); + // Reset volume fraction + this->iterate_over_cells(std::bind(&mpm::Cell::assign_volume_fraction, + std::placeholders::_1, 0.0)); + + // Compute and assign volume fraction to each cell + for (auto citr = this->cells_.cbegin(); citr != this->cells_.cend(); + ++citr) { + if ((*citr)->status()) { + // Compute volume fraction + double cell_volume_fraction = 0.0; + for (const auto p_id : (*citr)->particles()) + cell_volume_fraction += map_particles_[p_id]->volume(); + + cell_volume_fraction = cell_volume_fraction / (*citr)->volume(); + (*citr)->assign_volume_fraction(cell_volume_fraction); + } + } + // First, we detect the cell with possible free surfaces // Compute boundary cells and nodes based on geometry std::set free_surface_candidate_cells; @@ -1945,23 +1963,30 @@ bool mpm::Mesh::compute_free_surface(double tolerance) { if ((*citr)->status()) { bool candidate_cell = false; const auto& node_id = (*citr)->nodes_id(); - // Loop over neighbouring cells - for (const auto n_id : (*citr)->neighbours()) { - if (!map_cells_[n_id]->status()) { - candidate_cell = true; - const auto& n_node_id = map_cells_[n_id]->nodes_id(); - - // Detect common node id - std::set common_node_id; - std::set_intersection( - node_id.begin(), node_id.end(), n_node_id.begin(), - n_node_id.end(), - std::inserter(common_node_id, common_node_id.begin())); - - // Assign free surface nodes - if (!common_node_id.empty()) { - for (const auto common_id : common_node_id) { - map_nodes_[common_id]->assign_free_surface(true); + if ((*citr)->volume_fraction() < tolerance) { + candidate_cell = true; + for (const auto id : node_id) { + map_nodes_[id]->assign_free_surface(true); + } + } else { + // Loop over neighbouring cells + for (const auto n_id : (*citr)->neighbours()) { + if (!map_cells_[n_id]->status()) { + candidate_cell = true; + const auto& n_node_id = map_cells_[n_id]->nodes_id(); + + // Detect common node id + std::set common_node_id; + std::set_intersection( + node_id.begin(), node_id.end(), n_node_id.begin(), + n_node_id.end(), + std::inserter(common_node_id, common_node_id.begin())); + + // Assign free surface nodes + if (!common_node_id.empty()) { + for (const auto common_id : common_node_id) { + map_nodes_[common_id]->assign_free_surface(true); + } } } } @@ -2130,10 +2155,6 @@ bool mpm::Mesh::compute_free_surface(double tolerance) { // Assign signed distance to node map_nodes_[node_id]->assign_signed_distance(signed_distance); - - // If sign distance is negative, node is outside the body - if (signed_distance <= std::numeric_limits::epsilon()) - map_nodes_[node_id]->assign_free_surface(true); } } catch (std::exception& exception) { From 458891f03b9cdea3e3e640a6cf8c779d5407a120 Mon Sep 17 00:00:00 2001 From: Bodhinanda Chandra Date: Sun, 10 May 2020 11:25:34 -0700 Subject: [PATCH 55/72] add nodal pressure constraint - tobe CP --- include/io/io_mesh.h | 5 ++ include/io/io_mesh_ascii.h | 6 ++ include/io/io_mesh_ascii.tcc | 43 ++++++++++++ ...mbler_eigen_semi_implicit_navierstokes.tcc | 2 +- include/mesh.h | 15 +++++ include/mesh.tcc | 67 +++++++++++++++++++ include/solvers/mpm_base.h | 6 ++ include/solvers/mpm_base.tcc | 63 +++++++++++++++++ 8 files changed, 206 insertions(+), 1 deletion(-) diff --git a/include/io/io_mesh.h b/include/io/io_mesh.h index 4150af5b0..f1c05af6d 100644 --- a/include/io/io_mesh.h +++ b/include/io/io_mesh.h @@ -98,6 +98,11 @@ class IOMesh { read_friction_constraints( const std::string& friction_constraints_file) = 0; + //! Read pressure constraints file + //! \param[in] pressure_constraints_files file name with pressure constraints + virtual std::vector> read_pressure_constraints( + const std::string& _pressure_constraints_file) = 0; + //! Read forces file //! \param[in] forces_files file name with nodal concentrated force virtual std::vector> read_forces( diff --git a/include/io/io_mesh_ascii.h b/include/io/io_mesh_ascii.h index 433661546..9a9cbf4e1 100644 --- a/include/io/io_mesh_ascii.h +++ b/include/io/io_mesh_ascii.h @@ -91,6 +91,12 @@ class IOMeshAscii : public IOMesh { std::vector> read_forces( const std::string& forces_file) override; + //! Read pressure constraints file + //! \param[in] pressure_constraints_files file name with pressure + //! constraints + std::vector> read_pressure_constraints( + const std::string& pressure_constraints_file) override; + private: //! Logger std::shared_ptr console_; diff --git a/include/io/io_mesh_ascii.tcc b/include/io/io_mesh_ascii.tcc index 0f09fdc1a..1059c6542 100644 --- a/include/io/io_mesh_ascii.tcc +++ b/include/io/io_mesh_ascii.tcc @@ -486,6 +486,49 @@ std::vector> return constraints; } +//! Read pressure constraints file +template +std::vector> + mpm::IOMeshAscii::read_pressure_constraints( + const std::string& pressure_constraints_file) { + // Particle pressure constraints + std::vector> constraints; + constraints.clear(); + + // input file stream + std::fstream file; + file.open(pressure_constraints_file.c_str(), std::ios::in); + + try { + if (file.is_open() && file.good()) { + // Line + std::string line; + while (std::getline(file, line)) { + boost::algorithm::trim(line); + std::istringstream istream(line); + // ignore comment lines (# or !) or blank lines + if ((line.find('#') == std::string::npos) && + (line.find('!') == std::string::npos) && (line != "")) { + while (istream.good()) { + // ID + mpm::Index id; + // Pressure + double pressure; + // Read stream + istream >> id >> pressure; + constraints.emplace_back(std::make_tuple(id, pressure)); + } + } + } + } + file.close(); + } catch (std::exception& exception) { + console_->error("Read pressure constraints: {}", exception.what()); + file.close(); + } + return constraints; +} + //! Return particles force template std::vector> diff --git a/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.tcc b/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.tcc index a44cb6d22..a931e95b2 100644 --- a/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.tcc +++ b/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.tcc @@ -284,7 +284,7 @@ bool mpm::AssemblerEigenSemiImplicitNavierStokes< for (auto node = nodes.cbegin(); node != nodes.cend(); ++node) { // Assign total pressure constraint const double pressure_constraint = - (*node)->pressure_constraint(1, current_time); + (*node)->pressure_constraint(0, current_time); // Check if there is a pressure constraint if (pressure_constraint != std::numeric_limits::max()) { diff --git a/include/mesh.h b/include/mesh.h index 35ae2367c..a93892a47 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -319,6 +319,21 @@ class Mesh { const std::shared_ptr& mfunction, int set_id, unsigned dir, double force); + //! Assign nodal pressure constraints + //! \param[in] mfunction Math function if defined + //! \param[in] setid Node set id + //! \param[in] phase Index corresponding to the phase + //! \param[in] pconstraint Pressure constraint at node + bool assign_nodal_pressure_constraint( + const std::shared_ptr& mfunction, int set_id, + const unsigned phase, const unsigned pconstraint); + + //! Assign nodal pressure constraints to nodes + //! \param[in] pressure_constraints Constraint at node, pressure + bool assign_nodal_pressure_constraints( + const unsigned phase, + const std::vector>& pressure_constraints); + //! Assign particles stresses //! \param[in] particle_stresses Initial stresses of particle bool assign_particles_stresses( diff --git a/include/mesh.tcc b/include/mesh.tcc index 012c62d36..2319c237c 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1314,6 +1314,73 @@ bool mpm::Mesh::assign_particles_stresses( return status; } +//! Assign nodal pressure constraints +template +bool mpm::Mesh::assign_nodal_pressure_constraint( + const std::shared_ptr& mfunction, int set_id, + const unsigned phase, const unsigned pconstraint) { + bool status = true; + try { + if (set_id == -1 || node_sets_.find(set_id) != node_sets_.end()) { + + // If set id is -1, use all nodes + auto nset = (set_id == -1) ? this->nodes_ : node_sets_.at(set_id); + + tbb::parallel_for( + tbb::blocked_range(size_t(0), size_t(nset.size()), + tbb_grain_size_), + [&](const tbb::blocked_range& range) { + for (int i = range.begin(); i != range.end(); ++i) { + status = nset[i]->assign_pressure_constraint(phase, pconstraint, + mfunction); + if (!status) + throw std::runtime_error( + "Failed to initialise pressure constraint at node"); + } + }, + tbb::simple_partitioner()); + } else + throw std::runtime_error( + "No node set found to assign pressure constraint"); + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +//! Assign nodal pressure constraints to nodes +template +bool mpm::Mesh::assign_nodal_pressure_constraints( + const unsigned phase, + const std::vector>& pressure_constraints) { + bool status = false; + try { + if (!nodes_.size()) + throw std::runtime_error( + "No nodes have been assigned in mesh, cannot assign pressure " + "constraints"); + + for (const auto& pressure_constraint : pressure_constraints) { + // Node id + mpm::Index nid = std::get<0>(pressure_constraint); + // Pressure + double pressure = std::get<1>(pressure_constraint); + + // Apply constraint + status = + map_nodes_[nid]->assign_pressure_constraint(phase, pressure, nullptr); + + if (!status) + throw std::runtime_error("Node or pressure constraint is invalid"); + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + //! Assign particle cells template bool mpm::Mesh::assign_particles_cells( diff --git a/include/solvers/mpm_base.h b/include/solvers/mpm_base.h index a78b4d86f..74ffc93cc 100644 --- a/include/solvers/mpm_base.h +++ b/include/solvers/mpm_base.h @@ -149,6 +149,12 @@ class MPMBase : public MPM { const Json& mesh_prop, const std::shared_ptr>& particle_io); + //! Nodal pressure constraints + //! \param[in] mesh_prop Mesh properties + //! \param[in] mesh_io Mesh IO handle + void nodal_pressure_constraints( + const Json& mesh_prop, const std::shared_ptr>& mesh_io); + //! Particle entity sets //! \param[in] mesh_prop Mesh properties //! \param[in] check Check duplicates diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index a0f8b5b33..9f64cb373 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -177,6 +177,9 @@ bool mpm::MPMBase::initialise_mesh() { // Read and assign friction constraints this->nodal_frictional_constraints(mesh_props, mesh_io); + // Read and assign friction constraints + this->nodal_pressure_constraints(mesh_props, mesh_io); + // Initialise cell auto cells_begin = std::chrono::steady_clock::now(); // Shape function name @@ -858,6 +861,66 @@ void mpm::MPMBase::nodal_frictional_constraints( } } +// Nodal pressure constraints +template +void mpm::MPMBase::nodal_pressure_constraints( + const Json& mesh_props, const std::shared_ptr>& mesh_io) { + try { + + unsigned phase = 0; + + // Read and assign pressure constraints + if (mesh_props.find("boundary_conditions") != mesh_props.end() && + mesh_props["boundary_conditions"].find("pressure_constraints") != + mesh_props["boundary_conditions"].end()) { + + // Iterate over pressure constraints + for (const auto& constraints : + mesh_props["boundary_conditions"]["pressure_constraints"]) { + + // Check if it is pressure increment constraints + if (constraints.find("increment_boundary") != constraints.end() && + constraints["increment_boundary"]) + phase += 1; + + // Pressure constraints are specified in a file + if (constraints.find("file") != constraints.end()) { + + std::string pressure_constraints_file = + constraints.at("file").template get(); + bool ppressure_constraints = mesh_->assign_nodal_pressure_constraints( + phase, mesh_io->read_pressure_constraints( + io_->file_name(pressure_constraints_file))); + if (!ppressure_constraints) + throw std::runtime_error( + "Pressure constraints are not properly assigned"); + } else { + + // Get the math function + std::shared_ptr pfunction = nullptr; + if (constraints.find("math_function_id") != constraints.end()) + pfunction = math_functions_.at( + constraints.at("math_function_id").template get()); + + // Set id + int nset_id = constraints.at("nset_id").template get(); + // Pressure + double pressure = constraints.at("pressure").template get(); + + // Add pressure constraint to mesh + mesh_->assign_nodal_pressure_constraint(pfunction, nset_id, phase, + pressure); + } + } + } else + throw std::runtime_error("Pressure constraints JSON not found"); + + } catch (std::exception& exception) { + console_->warn("#{}: Pressure conditions are undefined {} ", __LINE__, + exception.what()); + } +} + //! Cell entity sets template void mpm::MPMBase::cell_entity_sets(const Json& mesh_props, From 0a656dc8e33de968937967be2c6167bfb2ebb196 Mon Sep 17 00:00:00 2001 From: Bodhinanda Chandra Date: Wed, 27 May 2020 15:56:43 -0700 Subject: [PATCH 56/72] :rewind: reverting PETSC from the current branch --- .circleci/config.yml | 6 - CMakeLists.txt | 12 - cmake/FindPETSc.cmake | 154 --------- ...bler_parallel_semi_implicit_navierstokes.h | 94 ------ ...er_parallel_semi_implicit_navierstokes.tcc | 302 ------------------ src/linear_solver.cc | 11 - 6 files changed, 579 deletions(-) delete mode 100644 cmake/FindPETSc.cmake delete mode 100644 include/linear_solvers/assembler_parallel_semi_implicit_navierstokes.h delete mode 100644 include/linear_solvers/assembler_parallel_semi_implicit_navierstokes.tcc diff --git a/.circleci/config.yml b/.circleci/config.yml index 7128c2301..8c8541ea6 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -16,8 +16,6 @@ jobs: export MODULEPATH=$MODULEPATH:/usr/share/modulefiles module load mpi/openmpi-x86_64 export CXX_COMPILER=mpicxx - export PETSC_ARCH=arch-linux2-c-opt - export PETSC_DIR=/home/cbgeo/petsc/ cmake -GNinja -DMPM_BUILD_LIB=On -DCMAKE_CXX_COMPILER=mpicxx -DCMAKE_EXPORT_COMPILE_COMMANDS=On -DKAHIP_ROOT=/home/cbgeo/KaHIP/ -DPARTIO_ROOT=/home/cbgeo/partio/ .. ninja -j2 ctest -VV @@ -34,8 +32,6 @@ jobs: mkdir -p build [ "$(ls -A build)" ] && rm -rf build/* cd build - export PETSC_ARCH=arch-linux2-c-opt - export PETSC_DIR=/home/cbgeo/petsc/ scan-build cmake -GNinja -DCMAKE_BUILD_TYPE=Debug -DMPM_BUILD_LIB=On -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang -DCMAKE_EXPORT_COMPILE_COMMANDS=On -DKAHIP_ROOT=/home/cbgeo/KaHIP/ -DPARTIO_ROOT=/home/cbgeo/partio/ .. scan-build -k -V ninja -j2 ctest -VV @@ -68,8 +64,6 @@ jobs: mkdir -p build [ "$(ls -A build)" ] && rm -rf build/* cd build - export PETSC_ARCH=arch-linux2-c-opt - export PETSC_DIR=/home/cbgeo/petsc/ cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=mpicxx -DCMAKE_EXPORT_COMPILE_COMMANDS=On -DENABLE_COVERAGE=On -DKAHIP_ROOT=/home/cbgeo/KaHIP/ -DPARTIO_ROOT=/home/cbgeo/partio/ .. make mpmtest_coverage -j2 ./mpmtest_coverage diff --git a/CMakeLists.txt b/CMakeLists.txt index aa37ce88a..df335bff3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,9 +44,6 @@ option(MPM_BUILD_LIB "enable libmpm" OFF) # Halo exchange option(HALO_EXCHANGE "Enable halo exchange" OFF) -# PETSC -option(USE_PETSC "Use PETSC solver library" OFF) - # CMake Modules set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) @@ -109,15 +106,6 @@ if (MKL_FOUND) endif() endif() -# PETSc -if (USE_PETSC) - find_package(PETSc COMPONENTS C) -endif() -if (PETSC_FOUND) - include_directories(${PETSC_INCLUDES}) - link_libraries(${PETSC_LIBRARIES}) -endif() - # KaHIP if (MPI_FOUND) if (NO_KAHIP) diff --git a/cmake/FindPETSc.cmake b/cmake/FindPETSc.cmake deleted file mode 100644 index dedbe2d84..000000000 --- a/cmake/FindPETSc.cmake +++ /dev/null @@ -1,154 +0,0 @@ -################################################################# -# Try to find PETSc # -# # -# Once done this will define: # -# PETSC_FOUND - system has PETSc # -# PETSC_DIR - PETSc directory # -# PETSC_ARCH - PETSc architecture # -# PETSC_INC - PETSc include directory # -# PETSC_LIB - PETSc library (static or dynamic) # -# PETSC_VARIABLES - Content of PETSc 'petscvariables' file # -# # -# PETSC_MUMPS - Was PETSc compiled with MUMPS? # -# PETSC_MUMPS_INC - PETSc MUMPS include file # -# PETSC_MUMPS_LIB - PETSc MUMPS libraries # -# # -# PETSC_SCALAPACK - Was PETSc compiled with ScaLAPACK? # -# PETSC_SCALAPACK_LIB - PETSc ScaLAPACK libraries # -# # -# PETSC_PARMETIS - Was PETSc compiled with ParMETIS? # -# PETSC_PARMETIS_LIB - PETSc ParMETIS libraries # -# # -# PETSC_METIS - Was PETSc compiled with Metis? # -# PETSC_METIS_LIB - PETSc METIS libraries # -# # -# PETSC_MPIUNI - Was PETSc compiled with MPIUNI? # -# PETSC_MPIUNI_INC - MPIUNI include file # -# # -# Usage: # -# find_package(PETSc) # -# # -# Setting these changes the behavior of the search # -# PETSC_DIR - PETSc directory # -# PETSC_ARCH - PETSc architecture # -################################################################# - -## Try to set PETSC_DIR and PETSC_ARCH ## -######################################### -if(NOT DEFINED PETSC_DIR) - set(PETSC_DIR $ENV{PETSC_DIR}) -endif() -if(NOT DEFINED PETSC_ARCH) - set(PETSC_ARCH $ENV{PETSC_ARCH}) -endif() - -## Includes ## -############## -if(EXISTS "${PETSC_DIR}/include" AND - EXISTS "${PETSC_DIR}/${PETSC_ARCH}/include") - set(PETSC_INC "${PETSC_DIR}/include" "${PETSC_DIR}/${PETSC_ARCH}/include") -else() - message(SEND_ERROR "PETSc includes not found") -endif() - -## Library ## -############# -if(EXISTS "${PETSC_DIR}/${PETSC_ARCH}/lib/libpetsc.so") - set(PETSC_LIB "${PETSC_DIR}/${PETSC_ARCH}/lib/libpetsc.so") -elseif(EXISTS "${PETSC_DIR}/${PETSC_ARCH}/lib/libpetsc.a") - set(PETSC_LIB "${PETSC_DIR}/${PETSC_ARCH}/lib/libpetsc.a") -else() - message(SEND_ERROR "PETSc library not found") -endif() - -## PETSc variables ## -##################### -if(EXISTS ${PETSC_DIR}/${PETSC_ARCH}/conf/petscvariables) - file(STRINGS ${PETSC_DIR}/${PETSC_ARCH}/conf/petscvariables - PETSC_VARIABLES NEWLINE_CONSUME) -elseif(EXISTS ${PETSC_DIR}/${PETSC_ARCH}/lib/petsc/conf/petscvariables) - file(STRINGS ${PETSC_DIR}/${PETSC_ARCH}/lib/petsc/conf/petscvariables - PETSC_VARIABLES NEWLINE_CONSUME) -else() - message(SEND_ERROR "PETSc variables not found") -endif() - -## MUMPS ## -########### -if(EXISTS ${PETSC_DIR}/${PETSC_ARCH}/lib/libmumps_common.a) - set(PETSC_MUMPS TRUE) - set(PETSC_MUMPS_INC ${PETSC_INC}) - set(PETSC_MUMPS_LIB - ${PETSC_DIR}/${PETSC_ARCH}/lib/libcmumps.a - ${PETSC_DIR}/${PETSC_ARCH}/lib/libdmumps.a - ${PETSC_DIR}/${PETSC_ARCH}/lib/libsmumps.a - ${PETSC_DIR}/${PETSC_ARCH}/lib/libzmumps.a - ${PETSC_DIR}/${PETSC_ARCH}/lib/libmumps_common.a - ${PETSC_DIR}/${PETSC_ARCH}/lib/libpord.a) - - if(EXISTS ${PETSC_DIR}/${PETSC_ARCH}/lib/libmpiseq.a) - set(PETSC_MUMPS_SEQ ${PETSC_DIR}/${PETSC_ARCH}/lib/libmpiseq.a) - else() - set(PETSC_MUMPS_SEQ "") - endif() - -else() - set(PETSC_MUMPS FALSE) - set(PETSC_MUMPS_INC "") - set(PETSC_MUMPS_LIB "") - set(PETSC_MUMPS_SEQ "") -endif() - -## ScaLAPACK ## -############### -if(EXISTS ${PETSC_DIR}/${PETSC_ARCH}/lib/libscalapack.a) - set(PETSC_SCALAPACK TRUE) - set(PETSC_SCALAPACK_LIB ${PETSC_DIR}/${PETSC_ARCH}/lib/libscalapack.a) -else() - set(PETSC_SCALAPACK FALSE) - set(PETSC_SCALAPACK_LIB "") -endif() - -## ParMETIS ## -############## -if(EXISTS ${PETSC_DIR}/${PETSC_ARCH}/lib/libparmetis.so) - set(PETSC_PARMETIS TRUE) - set(PETSC_PARMETIS_LIB ${PETSC_DIR}/${PETSC_ARCH}/lib/libparmetis.so) -else() - set(PETSC_PARMETIS FALSE) - set(PETSC_PARMETIS_LIB "") -endif() - -## METIS ## -############ -if(EXISTS ${PETSC_DIR}/${PETSC_ARCH}/lib/libmetis.so) - set(PETSC_METIS TRUE) - set(PETSC_METIS_LIB ${PETSC_DIR}/${PETSC_ARCH}/lib/libmetis.so) -else() - set(PETSC_METIS FALSE) - set(PETSC_METIS_LIB "") -endif() - -## MPI Uni ## -############# -string(REGEX MATCH "MPI_IS_MPIUNI = [^\n\r]*" PETSC_MPIUNI ${PETSC_VARIABLES}) -if(PETSC_MPIUNI) - string(REPLACE "MPI_IS_MPIUNI = " "" PETSC_MPIUNI ${PETSC_MPIUNI}) - string(STRIP ${PETSC_MPIUNI} PETSC_MPIUNI) - string(COMPARE EQUAL ${PETSC_MPIUNI} "1" PETSC_MPIUNI) - - string(REGEX MATCH "MPI_INCLUDE = -I[^\n\r]*" - PETSC_MPIUNI_INC ${PETSC_VARIABLES}) - string(REPLACE "MPI_INCLUDE = -I" "" PETSC_MPIUNI_INC ${PETSC_MPIUNI_INC}) - string(STRIP ${PETSC_MPIUNI_INC} PETSC_MPIUNI_INC) -else() - set(PETSC_MPIUNI FALSE) - set(PETSC_MPIUNI_INC "") -endif() - -## CMake check and done ## -########################## -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(PETSc - "PETSc could not be found: be sure to set PETSC_DIR and PETSC_ARCH in your environment variables" - PETSC_LIB PETSC_INC PETSC_DIR PETSC_ARCH) diff --git a/include/linear_solvers/assembler_parallel_semi_implicit_navierstokes.h b/include/linear_solvers/assembler_parallel_semi_implicit_navierstokes.h deleted file mode 100644 index ccdf8dcc9..000000000 --- a/include/linear_solvers/assembler_parallel_semi_implicit_navierstokes.h +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef MPM_ASSEMBLER_PARALLEL_SEMI_IMPLICIT_NAVIERSTOKES_H_ -#define MPM_ASSEMBLER_PARALLEL_SEMI_IMPLICIT_NAVIERSTOKES_H_ - -#include -#include - -// Speed log -#include "assembler_base.h" -#include "spdlog/spdlog.h" - -#include "cg_eigen.h" -#include "mesh.h" - -namespace mpm { -template -class AssemblerParallelSemiImplicitNavierStokes : public AssemblerBase { - public: - //! Constructor - AssemblerParallelSemiImplicitNavierStokes(); - - //! Create a pair between nodes and index in Matrix / Vector - bool assign_global_node_indices(unsigned active_dof) override; - - //! Return laplacian matrix - Eigen::SparseMatrix& laplacian_matrix() override { - return laplacian_matrix_; - } - - //! Assemble laplacian matrix - bool assemble_laplacian_matrix(double dt) override; - - //! Return poisson RHS vector - Eigen::VectorXd& poisson_rhs_vector() override { return poisson_rhs_vector_; } - - //! Assemble poisson RHS vector - bool assemble_poisson_right(double dt) override; - - //! Assign free surface node id - void assign_free_surface( - const std::set& free_surface_id) override { - free_surface_ = free_surface_id; - } - - //! Assign pressure constraints - bool assign_pressure_constraints(double beta, - const double current_time) override; - - //! Apply pressure constraints to poisson equation - void apply_pressure_constraints(); - - //! Return pressure increment - Eigen::VectorXd& pressure_increment() override { return pressure_increment_; } - - //! Assign pressure increment - void assign_pressure_increment(Eigen::VectorXd pressure_increment) override { - pressure_increment_ = pressure_increment; - } - - //! Return correction matrix - Eigen::SparseMatrix& correction_matrix() override { - return correction_matrix_; - } - - //! Assemble corrector RHS - bool assemble_corrector_right(double dt) override; - - protected: - //! Logger - std::shared_ptr console_; - - private: - //! number of nodes - using AssemblerBase::active_dof_; - //! Mesh object - using AssemblerBase::mesh_; - //! Laplacian matrix - Eigen::SparseMatrix laplacian_matrix_; - //! Poisson RHS vector - Eigen::VectorXd poisson_rhs_vector_; - //! Free surface - std::set free_surface_; - //! Pressure constraints - Eigen::SparseVector pressure_constraints_; - //! \delta p^(t+1) = p^(t+1) - beta * p^(t) - Eigen::VectorXd pressure_increment_; - //! correction_matrix - Eigen::SparseMatrix correction_matrix_; - //! Global node indices - std::vector global_node_indices_; -}; -} // namespace mpm - -#include "assembler_parallel_semi_implicit_navierstokes.tcc" -#endif // MPM_ASSEMBLER_PARALLEL_SEMI_IMPLICIT_NAVIERSTOKES_H_ diff --git a/include/linear_solvers/assembler_parallel_semi_implicit_navierstokes.tcc b/include/linear_solvers/assembler_parallel_semi_implicit_navierstokes.tcc deleted file mode 100644 index d85a10728..000000000 --- a/include/linear_solvers/assembler_parallel_semi_implicit_navierstokes.tcc +++ /dev/null @@ -1,302 +0,0 @@ -//! Construct a semi-implicit eigen matrix assembler -template -mpm::AssemblerParallelSemiImplicitNavierStokes< - Tdim>::AssemblerParallelSemiImplicitNavierStokes() - : mpm::AssemblerBase() { - //! Logger - console_ = - spdlog::stdout_color_mt("AssemblerParallelSemiImplicitNavierStokes"); -} - -//! Assign global node indices -template -bool mpm::AssemblerParallelSemiImplicitNavierStokes< - Tdim>::assign_global_node_indices(unsigned nactive_node) { - bool status = true; - try { - // Total number of active node - active_dof_ = nactive_node; - - global_node_indices_ = mesh_->global_node_indices(); - - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; - } - return status; -} - -//! Assemble Laplacian matrix -template -bool mpm::AssemblerParallelSemiImplicitNavierStokes< - Tdim>::assemble_laplacian_matrix(double dt) { - bool status = true; - try { - // Initialise Laplacian matrix - laplacian_matrix_.resize(active_dof_, active_dof_); - laplacian_matrix_.setZero(); - - // Reserve storage for sparse matrix - switch (Tdim) { - // For 2d: 10 entries /column - case (2): { - laplacian_matrix_.reserve(Eigen::VectorXi::Constant(active_dof_, 10)); - break; - } - // For 3d: 30 entries /column - case (3): { - laplacian_matrix_.reserve(Eigen::VectorXi::Constant(active_dof_, 30)); - break; - } - } - - // Cell pointer - const auto& cells = mesh_->cells(); - - // Iterate over cells - mpm::Index cid = 0; - for (auto cell_itr = cells.cbegin(); cell_itr != cells.cend(); ++cell_itr) { - if ((*cell_itr)->status()) { - // Node ids in each cell - const auto nids = global_node_indices_.at(cid); - - // Laplacian element of cell - const auto cell_laplacian = (*cell_itr)->laplacian_matrix(); - - // Assemble global laplacian matrix - for (unsigned i = 0; i < nids.size(); ++i) { - for (unsigned j = 0; j < nids.size(); ++j) { - laplacian_matrix_.coeffRef(global_node_indices_.at(cid)(i), - global_node_indices_.at(cid)(j)) += - cell_laplacian(i, j); - } - } - - ++cid; - } - } - - laplacian_matrix_ *= dt; - - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; - } - return status; -} - -template -bool mpm::AssemblerParallelSemiImplicitNavierStokes< - Tdim>::assemble_poisson_right(double dt) { - bool status = true; - try { - // Initialise Poisson RHS matrix - Eigen::SparseMatrix poisson_right_matrix; - poisson_right_matrix.resize(active_dof_, active_dof_ * Tdim); - poisson_right_matrix.setZero(); - - // Reserve storage for sparse matrix - switch (Tdim) { - // For 2d: 10 entries /column - case (2): { - poisson_right_matrix.reserve( - Eigen::VectorXi::Constant(active_dof_ * Tdim, 10)); - break; - } - // For 3d: 30 entries /column - case (3): { - poisson_right_matrix.reserve( - Eigen::VectorXi::Constant(active_dof_ * Tdim, 30)); - break; - } - } - - // Cell pointer - const auto& cells = mesh_->cells(); - - // Iterate over cells - mpm::Index cid = 0; - for (auto cell_itr = cells.cbegin(); cell_itr != cells.cend(); ++cell_itr) { - if ((*cell_itr)->status()) { - // Node ids in each cell - const auto nids = global_node_indices_.at(cid); - - // Local Poisson RHS matrix - auto cell_poisson_right = (*cell_itr)->poisson_right_matrix(); - - // Assemble global poisson RHS matrix - for (unsigned i = 0; i < nids.size(); ++i) { - for (unsigned j = 0; j < nids.size(); ++j) { - for (unsigned k = 0; k < Tdim; ++k) { - poisson_right_matrix.coeffRef( - global_node_indices_.at(cid)(i), - global_node_indices_.at(cid)(j) + k * active_dof_) += - cell_poisson_right(i, j + k * nids.size()); - } - } - } - cid++; - } - } - - // Resize poisson right vector - poisson_rhs_vector_.resize(active_dof_); - poisson_rhs_vector_.setZero(); - - // Compute velocity - Eigen::MatrixXd fluid_velocity; - fluid_velocity.resize(active_dof_, Tdim); - fluid_velocity.setZero(); - - // Active nodes - const auto& active_nodes = mesh_->active_nodes(); - const unsigned fluid = mpm::ParticlePhase::SinglePhase; - unsigned node_index = 0; - - for (auto node_itr = active_nodes.cbegin(); node_itr != active_nodes.cend(); - ++node_itr) { - // Compute nodal intermediate force - fluid_velocity.row(node_index) = (*node_itr)->velocity(fluid).transpose(); - node_index++; - } - - // Resize fluid velocity - fluid_velocity.resize(active_dof_ * Tdim, 1); - - // Compute poisson RHS vector - poisson_rhs_vector_ = -poisson_right_matrix * fluid_velocity; - - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; - } - return status; -} - -//! Assemble corrector right matrix -template -bool mpm::AssemblerParallelSemiImplicitNavierStokes< - Tdim>::assemble_corrector_right(double dt) { - bool status = true; - try { - // Resize correction matrix - correction_matrix_.resize(active_dof_, active_dof_ * Tdim); - correction_matrix_.setZero(); - - // Reserve storage for sparse matrix - switch (Tdim) { - // For 2d: 10 entries /column - case (2): { - correction_matrix_.reserve( - Eigen::VectorXi::Constant(active_dof_ * Tdim, 10)); - break; - } - // For 3d: 30 entries /column - case (3): { - correction_matrix_.reserve( - Eigen::VectorXi::Constant(active_dof_ * Tdim, 30)); - break; - } - } - - // Cell pointer - unsigned nnodes_per_cell = global_node_indices_.at(0).size(); - const auto& cells = mesh_->cells(); - - // Iterate over cells - unsigned cid = 0; - for (auto cell_itr = cells.cbegin(); cell_itr != cells.cend(); ++cell_itr) { - if ((*cell_itr)->status()) { - auto cell_correction_matrix = (*cell_itr)->correction_matrix(); - for (unsigned k = 0; k < Tdim; k++) { - for (unsigned i = 0; i < nnodes_per_cell; i++) { - for (unsigned j = 0; j < nnodes_per_cell; j++) { - // Fluid - correction_matrix_.coeffRef( - global_node_indices_.at(cid)(i), - k * active_dof_ + global_node_indices_.at(cid)(j)) += - cell_correction_matrix(i, j + k * nnodes_per_cell); - } - } - } - cid++; - } - } - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; - } - return status; -} - -//! Apply pressure constraints vector -template -void mpm::AssemblerParallelSemiImplicitNavierStokes< - Tdim>::apply_pressure_constraints() { - try { - // Modify poisson_rhs_vector_ - poisson_rhs_vector_ -= laplacian_matrix_ * pressure_constraints_; - - // Apply free surface - if (!free_surface_.empty()) { - const auto& nodes = mesh_->nodes(); - for (const auto& free_node : free_surface_) { - const auto column_index = nodes[free_node]->active_id(); - // Modify poisson_rhs_vector - poisson_rhs_vector_(column_index) = 0; - // Modify laplacian_matrix - laplacian_matrix_.row(column_index) *= 0; - laplacian_matrix_.col(column_index) *= 0; - laplacian_matrix_.coeffRef(column_index, column_index) = 1; - } - // Clear the vector - free_surface_.clear(); - } - - // Apply pressure constraints - for (Eigen::SparseVector::InnerIterator it(pressure_constraints_); - it; ++it) { - // Modify poisson_rhs_vector - poisson_rhs_vector_(it.index()) = it.value(); - // Modify laplacian_matrix - laplacian_matrix_.row(it.index()) *= 0; - laplacian_matrix_.col(it.index()) *= 0; - laplacian_matrix_.coeffRef(it.index(), it.index()) = 1; - } - - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - } -} - -//! Assign pressure constraints -template -bool mpm::AssemblerParallelSemiImplicitNavierStokes< - Tdim>::assign_pressure_constraints(double beta, const double current_time) { - bool status = false; - try { - // Resize pressure constraints vector - pressure_constraints_.resize(active_dof_); - pressure_constraints_.reserve(int(0.5 * active_dof_)); - - // Nodes container - const auto& nodes = mesh_->active_nodes(); - // Iterate over nodes to get pressure constraints - for (auto node = nodes.cbegin(); node != nodes.cend(); ++node) { - // Assign total pressure constraint - const double pressure_constraint = - (*node)->pressure_constraint(1, current_time); - - // Check if there is a pressure constraint - if (pressure_constraint != std::numeric_limits::max()) { - // Insert the pressure constraints - pressure_constraints_.insert((*node)->active_id()) = - pressure_constraint; - } - } - status = true; - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - } - return status; -} diff --git a/src/linear_solver.cc b/src/linear_solver.cc index 3b8a92673..718694507 100644 --- a/src/linear_solver.cc +++ b/src/linear_solver.cc @@ -1,6 +1,5 @@ #include "assembler_base.h" #include "assembler_eigen_semi_implicit_navierstokes.h" -#include "assembler_parallel_semi_implicit_navierstokes.h" #include "cg_eigen.h" #include "solver_base.h" @@ -16,16 +15,6 @@ static Register, mpm::AssemblerEigenSemiImplicitNavierStokes<3>> assembler_eigen_semi_implicit_navierstokes_3d( "EigenSemiImplicitNavierStokes3D"); -// Asssembler parallel 2D -static Register, - mpm::AssemblerParallelSemiImplicitNavierStokes<2>> - assembler_parallel_semi_implicit_navierstokes_2d( - "ParallelSemiImplicitNavierStokes2D"); -// Asssembler parallel 3D -static Register, - mpm::AssemblerParallelSemiImplicitNavierStokes<3>> - assembler_parallel_semi_implicit_navierstokes_3d( - "ParallelSemiImplicitNavierStokes3D"); // Linear Solver collections // Eigen Conjugate Gradient From f3ebc7e758ddd82ab3fd5cc976e41cca7e998aaf Mon Sep 17 00:00:00 2001 From: Nanda Date: Sat, 13 Jun 2020 19:58:19 -0700 Subject: [PATCH 57/72] :wrench: fix compilation error --- include/particles/particle.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/particles/particle.h b/include/particles/particle.h index eae454a40..bf726cfbd 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -124,8 +124,10 @@ class Particle : public ParticleBase { //! Return the approximate particle diameter double diameter() const override { - if (Tdim == 2) return 2.0 * std::sqrt(volume_ / M_PI); - if (Tdim == 3) return 2.0 * std::pow(volume_ * 0.75 / M_PI, (1 / 3)); + double diameter = 0.; + if (Tdim == 2) diameter = 2.0 * std::sqrt(volume_ / M_PI); + if (Tdim == 3) diameter = 2.0 * std::pow(volume_ * 0.75 / M_PI, (1 / 3)); + return diameter; } //! Return size of particle in natural coordinates From 6cf5e7de838cb7c7f9f4b40f64adde1df36e8e4f Mon Sep 17 00:00:00 2001 From: Nanda Date: Mon, 15 Jun 2020 17:02:38 -0700 Subject: [PATCH 58/72] :wrench: move pressure constraint to constraints.h --- include/loads_bcs/constraints.h | 16 ++++++ include/loads_bcs/constraints.tcc | 62 +++++++++++++++++++++++ include/loads_bcs/pressure_constraint.h | 35 +++++++++++++ include/mesh.h | 15 ------ include/mesh.tcc | 67 ------------------------- include/solvers/mpm_base.tcc | 18 ++++--- 6 files changed, 125 insertions(+), 88 deletions(-) create mode 100644 include/loads_bcs/pressure_constraint.h diff --git a/include/loads_bcs/constraints.h b/include/loads_bcs/constraints.h index 53c894620..d652f9ee2 100644 --- a/include/loads_bcs/constraints.h +++ b/include/loads_bcs/constraints.h @@ -10,6 +10,7 @@ #include "friction_constraint.h" #include "logger.h" #include "mesh.h" +#include "pressure_constraint.h" #include "velocity_constraint.h" namespace mpm { @@ -52,6 +53,21 @@ class Constraints { const std::vector>& friction_constraints); + //! Assign nodal pressure constraints + //! \param[in] mfunction Math function if defined + //! \param[in] setid Node set id + //! \param[in] phase Index corresponding to the phase + //! \param[in] pconstraint Pressure constraint at node + bool assign_nodal_pressure_constraint( + const std::shared_ptr& mfunction, + const std::shared_ptr& pconstraint); + + //! Assign nodal pressure constraints to nodes + //! \param[in] pressure_constraints Constraint at node, pressure + bool assign_nodal_pressure_constraints( + const unsigned phase, + const std::vector>& pressure_constraints); + private: //! Mesh object std::shared_ptr> mesh_; diff --git a/include/loads_bcs/constraints.tcc b/include/loads_bcs/constraints.tcc index 2cc894e42..202727037 100644 --- a/include/loads_bcs/constraints.tcc +++ b/include/loads_bcs/constraints.tcc @@ -125,3 +125,65 @@ bool mpm::Constraints::assign_nodal_friction_constraints( } return status; } + +//! Assign nodal pressure constraints +template +bool mpm::Constraints::assign_nodal_pressure_constraint( + const std::shared_ptr& mfunction, + const std::shared_ptr& pconstraint) { + bool status = true; + try { + int set_id = pconstraint->setid(); + auto nset = mesh_->nodes(set_id); + if (nset.size() != 0) { + unsigned phase = pconstraint->phase(); + double pressure = pconstraint->pressure(); + tbb::parallel_for( + tbb::blocked_range(size_t(0), size_t(nset.size())), + [&](const tbb::blocked_range& range) { + for (int i = range.begin(); i != range.end(); ++i) { + status = nset[i]->assign_pressure_constraint(phase, pressure, + mfunction); + if (!status) + throw std::runtime_error( + "Failed to initialise pressure constraint at node"); + } + }, + tbb::simple_partitioner()); + } else + throw std::runtime_error( + "Nodal assignment of pressure constraint failed"); + + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +//! Assign nodal pressure constraints to nodes +template +bool mpm::Constraints::assign_nodal_pressure_constraints( + const unsigned phase, + const std::vector>& pressure_constraints) { + bool status = false; + try { + for (const auto& pressure_constraint : pressure_constraints) { + // Node id + mpm::Index nid = std::get<0>(pressure_constraint); + // Pressure + double pressure = std::get<1>(pressure_constraint); + + // Apply constraint + status = mesh_->node(nid)->assign_pressure_constraint(phase, pressure, + nullptr); + + if (!status) + throw std::runtime_error("Node or pressure constraint is invalid"); + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} diff --git a/include/loads_bcs/pressure_constraint.h b/include/loads_bcs/pressure_constraint.h new file mode 100644 index 000000000..4ea68bb06 --- /dev/null +++ b/include/loads_bcs/pressure_constraint.h @@ -0,0 +1,35 @@ +#ifndef MPM_PRESSURE_CONSTRAINT_H_ +#define MPM_PRESSURE_CONSTRAINT_H_ + +namespace mpm { + +//! PressureConstraint class to store pressure constraint on a set +//! \brief PressureConstraint class to store a constraint on a set +//! \details PressureConstraint stores the constraint as a static value +class PressureConstraint { + public: + // Constructor + //! \param[in] setid set id + //! \param[in] pressure Constraint pressure + PressureConstraint(int setid, unsigned phase, double pressure) + : setid_{setid}, phase_{phase}, pressure_{pressure} {}; + + // Set id + int setid() const { return setid_; } + + // Return phase + unsigned phase() const { return phase_; } + + // Return pressure + double pressure() const { return pressure_; } + + private: + // ID + int setid_; + // Phase + unsigned phase_; + // Velocity + double pressure_; +}; +} // namespace mpm +#endif // MPM_PRESSURE_CONSTRAINT_H_ diff --git a/include/mesh.h b/include/mesh.h index 915729f7b..385b512b7 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -324,21 +324,6 @@ class Mesh { const std::shared_ptr& mfunction, int set_id, unsigned dir, double force); - //! Assign nodal pressure constraints - //! \param[in] mfunction Math function if defined - //! \param[in] setid Node set id - //! \param[in] phase Index corresponding to the phase - //! \param[in] pconstraint Pressure constraint at node - bool assign_nodal_pressure_constraint( - const std::shared_ptr& mfunction, int set_id, - const unsigned phase, const unsigned pconstraint); - - //! Assign nodal pressure constraints to nodes - //! \param[in] pressure_constraints Constraint at node, pressure - bool assign_nodal_pressure_constraints( - const unsigned phase, - const std::vector>& pressure_constraints); - //! Assign particles stresses //! \param[in] particle_stresses Initial stresses of particle bool assign_particles_stresses( diff --git a/include/mesh.tcc b/include/mesh.tcc index 6e317b882..c684dbb19 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1409,73 +1409,6 @@ bool mpm::Mesh::assign_particles_stresses( return status; } -//! Assign nodal pressure constraints -template -bool mpm::Mesh::assign_nodal_pressure_constraint( - const std::shared_ptr& mfunction, int set_id, - const unsigned phase, const unsigned pconstraint) { - bool status = true; - try { - if (set_id == -1 || node_sets_.find(set_id) != node_sets_.end()) { - - // If set id is -1, use all nodes - auto nset = (set_id == -1) ? this->nodes_ : node_sets_.at(set_id); - - tbb::parallel_for( - tbb::blocked_range(size_t(0), size_t(nset.size()), - tbb_grain_size_), - [&](const tbb::blocked_range& range) { - for (int i = range.begin(); i != range.end(); ++i) { - status = nset[i]->assign_pressure_constraint(phase, pconstraint, - mfunction); - if (!status) - throw std::runtime_error( - "Failed to initialise pressure constraint at node"); - } - }, - tbb::simple_partitioner()); - } else - throw std::runtime_error( - "No node set found to assign pressure constraint"); - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; - } - return status; -} - -//! Assign nodal pressure constraints to nodes -template -bool mpm::Mesh::assign_nodal_pressure_constraints( - const unsigned phase, - const std::vector>& pressure_constraints) { - bool status = false; - try { - if (!nodes_.size()) - throw std::runtime_error( - "No nodes have been assigned in mesh, cannot assign pressure " - "constraints"); - - for (const auto& pressure_constraint : pressure_constraints) { - // Node id - mpm::Index nid = std::get<0>(pressure_constraint); - // Pressure - double pressure = std::get<1>(pressure_constraint); - - // Apply constraint - status = - map_nodes_[nid]->assign_pressure_constraint(phase, pressure, nullptr); - - if (!status) - throw std::runtime_error("Node or pressure constraint is invalid"); - } - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; - } - return status; -} - //! Assign particle cells template bool mpm::Mesh::assign_particles_cells( diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index 50696ac73..bf61eb79e 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -905,9 +905,10 @@ void mpm::MPMBase::nodal_pressure_constraints( std::string pressure_constraints_file = constraints.at("file").template get(); - bool ppressure_constraints = mesh_->assign_nodal_pressure_constraints( - phase, mesh_io->read_pressure_constraints( - io_->file_name(pressure_constraints_file))); + bool ppressure_constraints = + constraints_->assign_nodal_pressure_constraints( + phase, mesh_io->read_pressure_constraints( + io_->file_name(pressure_constraints_file))); if (!ppressure_constraints) throw std::runtime_error( "Pressure constraints are not properly assigned"); @@ -923,10 +924,15 @@ void mpm::MPMBase::nodal_pressure_constraints( int nset_id = constraints.at("nset_id").template get(); // Pressure double pressure = constraints.at("pressure").template get(); - + // Phase if available + if (constraints.contains("phase")) + phase = constraints.at("phase").template get(); + // Add friction constraint to mesh + auto pressure_constraint = std::make_shared( + nset_id, phase, pressure); // Add pressure constraint to mesh - mesh_->assign_nodal_pressure_constraint(pfunction, nset_id, phase, - pressure); + constraints_->assign_nodal_pressure_constraint(pfunction, + pressure_constraint); } } } else From 424bd60f2ddbda96771d0685bdc4fb79d7206a63 Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 16 Jun 2020 16:28:56 -0700 Subject: [PATCH 59/72] :art: change linear solver name Conflicts: src/linear_solver.cc --- src/linear_solver.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/linear_solver.cc b/src/linear_solver.cc index 718694507..4314689e2 100644 --- a/src/linear_solver.cc +++ b/src/linear_solver.cc @@ -20,4 +20,4 @@ static Register, // Eigen Conjugate Gradient static Register>, mpm::CGEigen>, unsigned, double> - solver_eigen_cg("EigenCG"); \ No newline at end of file + solver_eigen_cg("CGEigen"); From bf7d687aad94816ea365fc5ccd6945c46f501f66 Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 16 Jun 2020 18:35:50 -0700 Subject: [PATCH 60/72] :art: cleanup assemble function arguments Conflicts: include/solvers/mpm_semi_implicit_navierstokes.tcc --- include/linear_solvers/assembler_base.h | 6 +++--- .../assembler_eigen_semi_implicit_navierstokes.h | 6 +++--- .../assembler_eigen_semi_implicit_navierstokes.tcc | 2 +- include/mesh.h | 7 ++++--- include/mesh.tcc | 6 +++--- include/node.tcc | 1 + include/particles/fluid_particle.tcc | 4 ++-- include/solvers/mpm_semi_implicit_navierstokes.tcc | 9 +++++---- 8 files changed, 22 insertions(+), 19 deletions(-) diff --git a/include/linear_solvers/assembler_base.h b/include/linear_solvers/assembler_base.h index 75185fb3c..859acbfd5 100644 --- a/include/linear_solvers/assembler_base.h +++ b/include/linear_solvers/assembler_base.h @@ -40,7 +40,7 @@ class AssemblerBase { //! Assign mesh pointer //! \param[in] mesh mesh pointer - void assign_mesh_pointer(std::shared_ptr>& mesh) { + void assign_mesh_pointer(const std::shared_ptr>& mesh) { mesh_ = mesh; } @@ -65,7 +65,7 @@ class AssemblerBase { //! Assign pressure constraints virtual bool assign_pressure_constraints(double beta, - const double current_time) = 0; + double current_time) = 0; //! Apply pressure constraints to poisson equation virtual void apply_pressure_constraints() = 0; @@ -75,7 +75,7 @@ class AssemblerBase { //! Assign pressure increment virtual void assign_pressure_increment( - Eigen::VectorXd pressure_increment) = 0; + const Eigen::VectorXd& pressure_increment) = 0; //! Return correction matrix virtual Eigen::SparseMatrix& correction_matrix() = 0; diff --git a/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.h b/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.h index c6393dff6..2679b7da5 100644 --- a/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.h +++ b/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.h @@ -42,8 +42,7 @@ class AssemblerEigenSemiImplicitNavierStokes : public AssemblerBase { } //! Assign pressure constraints - bool assign_pressure_constraints(double beta, - const double current_time) override; + bool assign_pressure_constraints(double beta, double current_time) override; //! Apply pressure constraints to poisson equation void apply_pressure_constraints(); @@ -52,7 +51,8 @@ class AssemblerEigenSemiImplicitNavierStokes : public AssemblerBase { Eigen::VectorXd& pressure_increment() override { return pressure_increment_; } //! Assign pressure increment - void assign_pressure_increment(Eigen::VectorXd pressure_increment) override { + void assign_pressure_increment( + const Eigen::VectorXd& pressure_increment) override { pressure_increment_ = pressure_increment; } diff --git a/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.tcc b/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.tcc index a931e95b2..f913109bd 100644 --- a/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.tcc +++ b/include/linear_solvers/assembler_eigen_semi_implicit_navierstokes.tcc @@ -271,7 +271,7 @@ void mpm::AssemblerEigenSemiImplicitNavierStokes< //! Assign pressure constraints template bool mpm::AssemblerEigenSemiImplicitNavierStokes< - Tdim>::assign_pressure_constraints(double beta, const double current_time) { + Tdim>::assign_pressure_constraints(double beta, double current_time) { bool status = false; try { // Resize pressure constraints vector diff --git a/include/mesh.h b/include/mesh.h index 385b512b7..06adeb35f 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -464,7 +464,8 @@ class Mesh { //! Get free surface particle set std::set free_surface_particles(); - //! Assign id for active node + //! Create a list of active nodes in mesh and assign active node id + //! (rank-wise) unsigned assign_active_nodes_id(); //! Return container of active nodes @@ -475,8 +476,8 @@ class Mesh { //! Compute correction force in the node bool compute_nodal_correction_force( - Eigen::SparseMatrix& correction_matrix, - Eigen::VectorXd& pressure_increment, double dt); + const Eigen::SparseMatrix& correction_matrix, + const Eigen::VectorXd& pressure_increment, double dt); // Create the nodal properties' map void create_nodal_properties(); diff --git a/include/mesh.tcc b/include/mesh.tcc index c684dbb19..65698c8ce 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -102,7 +102,7 @@ void mpm::Mesh::find_active_nodes() { if ((*nitr)->status()) this->active_nodes_.add(*nitr); } -//! Create a list of active nodes in mesh and assign active node id +//! Create a list of active nodes in mesh and assign active node id (rank-wise) template unsigned mpm::Mesh::assign_active_nodes_id() { // Clear existing list of active nodes @@ -1961,8 +1961,8 @@ void mpm::Mesh::create_nodal_properties() { //! Compute nodal correction force template bool mpm::Mesh::compute_nodal_correction_force( - Eigen::SparseMatrix& correction_matrix, - Eigen::VectorXd& pressure_increment, double dt) { + const Eigen::SparseMatrix& correction_matrix, + const Eigen::VectorXd& pressure_increment, double dt) { bool status = true; try { //! Active node size diff --git a/include/node.tcc b/include/node.tcc index 0d81e472e..1123c63ca 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -645,6 +645,7 @@ bool mpm::Node:: } return status; } + //! Update nodal property at the nodes from particle template void mpm::Node::update_property( diff --git a/include/particles/fluid_particle.tcc b/include/particles/fluid_particle.tcc index 79364239f..86fd296bf 100644 --- a/include/particles/fluid_particle.tcc +++ b/include/particles/fluid_particle.tcc @@ -157,7 +157,6 @@ bool mpm::FluidParticle::map_poisson_right_to_cell() { template bool mpm::FluidParticle::compute_updated_pressure() { bool status = true; - try { double pressure_increment = 0; for (unsigned i = 0; i < nodes_.size(); ++i) { @@ -168,7 +167,8 @@ bool mpm::FluidParticle::compute_updated_pressure() { state_variables_.at("pressure") = state_variables_.at("pressure") * projection_param_ + pressure_increment; - // Apply free surface + + // Overwrite pressure if free surface if (this->free_surface()) state_variables_.at("pressure") = 0.0; } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); diff --git a/include/solvers/mpm_semi_implicit_navierstokes.tcc b/include/solvers/mpm_semi_implicit_navierstokes.tcc index fc3a56931..8ef9d748f 100644 --- a/include/solvers/mpm_semi_implicit_navierstokes.tcc +++ b/include/solvers/mpm_semi_implicit_navierstokes.tcc @@ -123,10 +123,10 @@ bool mpm::MPMSemiImplicitNavierStokes::solve() { std::placeholders::_1)); // Compute free surface cells, nodes, and particles - task_group.run([&] { - mesh_->compute_free_surface(volume_tolerance_); + mesh_->compute_free_surface(volume_tolerance_); - // Assign initial pressure + task_group.run([&] { + // Assign initial pressure for all free-surface particle mesh_->iterate_over_particles_predicate( std::bind(&mpm::ParticleBase::initial_pressure, std::placeholders::_1, 0.0), @@ -333,7 +333,7 @@ bool mpm::MPMSemiImplicitNavierStokes::compute_poisson_equation( // Apply constraints matrix_assembler_->apply_pressure_constraints(); - // Solve matrix equation + // Solve matrix equation and assign solution to assembler matrix_assembler_->assign_pressure_increment(matrix_solver_->solve( matrix_assembler_->laplacian_matrix(), matrix_assembler_->poisson_rhs_vector(), solver_type)); @@ -350,6 +350,7 @@ template bool mpm::MPMSemiImplicitNavierStokes::compute_correction_force() { bool status = true; try { + // Map correction matrix from particles to cell mesh_->iterate_over_particles( std::bind(&mpm::ParticleBase::map_correction_matrix_to_cell, std::placeholders::_1)); From 17d83328e559463752a54269261d1d7e556ed399 Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 16 Jun 2020 18:47:53 -0700 Subject: [PATCH 61/72] :wrench: fix argument error --- include/solvers/mpm_semi_implicit_navierstokes.tcc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/solvers/mpm_semi_implicit_navierstokes.tcc b/include/solvers/mpm_semi_implicit_navierstokes.tcc index 8ef9d748f..654511a12 100644 --- a/include/solvers/mpm_semi_implicit_navierstokes.tcc +++ b/include/solvers/mpm_semi_implicit_navierstokes.tcc @@ -232,7 +232,7 @@ bool mpm::MPMSemiImplicitNavierStokes::solve() { } } auto solver_end = std::chrono::steady_clock::now(); - console_->info("Rank {}, SemiImplicit_NavierStokes {} solver duration: {} ms", + console_->info("Rank {}, SemiImplicit_NavierStokes solver duration: {} ms", mpi_rank, std::chrono::duration_cast( solver_end - solver_begin) From c0b3250dd6c13d3150e86557392bfc3b2f50a134 Mon Sep 17 00:00:00 2001 From: Nanda Date: Sat, 4 Jul 2020 19:02:00 -0700 Subject: [PATCH 62/72] :wrench: remove unused private variable --- include/linear_solvers/cg_eigen.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/linear_solvers/cg_eigen.h b/include/linear_solvers/cg_eigen.h index 796be7dc6..b8b37f511 100644 --- a/include/linear_solvers/cg_eigen.h +++ b/include/linear_solvers/cg_eigen.h @@ -19,7 +19,6 @@ class CGEigen : public SolverBase { public: //! Constructor //! \param[in] max_iter Maximum number of iterations - //! \param[in] tolerance Tolerance for solver to achieve convergence CGEigen(unsigned max_iter, double tolerance) : mpm::SolverBase(max_iter, tolerance) { @@ -47,8 +46,6 @@ class CGEigen : public SolverBase { using SolverBase::tolerance_; //! Logger using SolverBase::console_; - //! cg_type_ (leastSquaresConjugateGradient or ConjugateGradient) - std::string cg_type_; }; } // namespace mpm From b8d693b596e48850616318ebd9d2e0d5214a305c Mon Sep 17 00:00:00 2001 From: Nanda Date: Mon, 13 Jul 2020 18:18:24 -0700 Subject: [PATCH 63/72] :wrench: fix clang-format --- include/solvers/mpm_base.tcc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index 7fb5359b3..3efeab2dd 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -814,8 +814,9 @@ void mpm::MPMBase::nodal_velocity_constraints( // Add velocity constraint to mesh auto velocity_constraint = std::make_shared(nset_id, dir, velocity); - bool velocity_constraints = constraints_->assign_nodal_velocity_constraint( - nset_id, velocity_constraint); + bool velocity_constraints = + constraints_->assign_nodal_velocity_constraint( + nset_id, velocity_constraint); if (!velocity_constraints) throw std::runtime_error( "Nodal velocity constraint is not properly assigned"); From 7e07053fc1e747b9f3726e510f802bb63a6ebf2a Mon Sep 17 00:00:00 2001 From: Nanda Date: Mon, 13 Jul 2020 18:18:37 -0700 Subject: [PATCH 64/72] :wrench: change tbb to openmp --- include/loads_bcs/constraints.tcc | 18 +-- include/mesh.tcc | 12 +- .../mpm_semi_implicit_navierstokes.tcc | 103 ++++++++++-------- 3 files changed, 65 insertions(+), 68 deletions(-) diff --git a/include/loads_bcs/constraints.tcc b/include/loads_bcs/constraints.tcc index b766b48f0..7126d6f92 100644 --- a/include/loads_bcs/constraints.tcc +++ b/include/loads_bcs/constraints.tcc @@ -118,18 +118,12 @@ bool mpm::Constraints::assign_nodal_pressure_constraint( if (nset.size() != 0) { unsigned phase = pconstraint->phase(); double pressure = pconstraint->pressure(); - tbb::parallel_for( - tbb::blocked_range(size_t(0), size_t(nset.size())), - [&](const tbb::blocked_range& range) { - for (int i = range.begin(); i != range.end(); ++i) { - status = nset[i]->assign_pressure_constraint(phase, pressure, - mfunction); - if (!status) - throw std::runtime_error( - "Failed to initialise pressure constraint at node"); - } - }, - tbb::simple_partitioner()); + + for (auto nitr = nset.cbegin(); nitr != nset.cend(); ++nitr) { + if (!(*nitr)->assign_pressure_constraint(phase, pressure, mfunction)) + throw std::runtime_error( + "Failed to initialise pressure constraint at node"); + } } else throw std::runtime_error( "Nodal assignment of pressure constraint failed"); diff --git a/include/mesh.tcc b/include/mesh.tcc index 283fb9fb6..124d1c746 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1060,14 +1060,10 @@ void mpm::Mesh::iterate_over_particles(Toper oper) { template template void mpm::Mesh::iterate_over_particles_predicate(Toper oper, Tpred pred) { - tbb::parallel_for( - tbb::blocked_range(size_t(0), size_t(particles_.size()), - tbb_grain_size_), - [&](const tbb::blocked_range& range) { - for (int i = range.begin(); i != range.end(); ++i) - if (pred(particles_[i])) oper(particles_[i]); - }, - tbb::simple_partitioner()); +#pragma omp parallel for + for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { + if (pred(*pitr)) oper(*pitr); + } } //! Iterate over particle set diff --git a/include/solvers/mpm_semi_implicit_navierstokes.tcc b/include/solvers/mpm_semi_implicit_navierstokes.tcc index 654511a12..1969614a0 100644 --- a/include/solvers/mpm_semi_implicit_navierstokes.tcc +++ b/include/solvers/mpm_semi_implicit_navierstokes.tcc @@ -94,28 +94,26 @@ bool mpm::MPMSemiImplicitNavierStokes::solve() { for (; step_ < nsteps_; ++step_) { if (mpi_rank == 0) console_->info("Step: {} of {}.\n", step_, nsteps_); - // Create a TBB task group - tbb::task_group task_group; - - // Spawn a task for initialising nodes and cells - task_group.run([&] { - // Initialise nodes - mesh_->iterate_over_nodes( - std::bind(&mpm::NodeBase::initialise, std::placeholders::_1)); - - mesh_->iterate_over_cells( - std::bind(&mpm::Cell::activate_nodes, std::placeholders::_1)); - }); - task_group.wait(); - - // Spawn a task for particles - task_group.run([&] { - // Iterate over each particle to compute shapefn - mesh_->iterate_over_particles(std::bind( - &mpm::ParticleBase::compute_shapefn, std::placeholders::_1)); - }); - - task_group.wait(); +#pragma omp parallel sections + { + // Spawn a task for initialising nodes and cells +#pragma omp section + { + // Initialise nodes + mesh_->iterate_over_nodes( + std::bind(&mpm::NodeBase::initialise, std::placeholders::_1)); + + mesh_->iterate_over_cells( + std::bind(&mpm::Cell::activate_nodes, std::placeholders::_1)); + } + // Spawn a task for particles +#pragma omp section + { + // Iterate over each particle to compute shapefn + mesh_->iterate_over_particles(std::bind( + &mpm::ParticleBase::compute_shapefn, std::placeholders::_1)); + } + } // Wait to complete // Assign mass and momentum to nodes mesh_->iterate_over_particles( @@ -125,15 +123,19 @@ bool mpm::MPMSemiImplicitNavierStokes::solve() { // Compute free surface cells, nodes, and particles mesh_->compute_free_surface(volume_tolerance_); - task_group.run([&] { - // Assign initial pressure for all free-surface particle - mesh_->iterate_over_particles_predicate( - std::bind(&mpm::ParticleBase::initial_pressure, - std::placeholders::_1, 0.0), - std::bind(&mpm::ParticleBase::free_surface, - std::placeholders::_1)); - }); - task_group.wait(); + // Spawn a task for initializing pressure at free surface +#pragma omp parallel sections + { +#pragma omp section + { + // Assign initial pressure for all free-surface particle + mesh_->iterate_over_particles_predicate( + std::bind(&mpm::ParticleBase::initial_pressure, + std::placeholders::_1, 0.0), + std::bind(&mpm::ParticleBase::free_surface, + std::placeholders::_1)); + } + } // Wait to complete // Compute nodal velocity at the begining of time step mesh_->iterate_over_nodes_predicate( @@ -150,23 +152,28 @@ bool mpm::MPMSemiImplicitNavierStokes::solve() { &mpm::ParticleBase::compute_stress, std::placeholders::_1)); // Spawn a task for external force - task_group.run([&] { - // Iterate over particles to compute nodal body force - mesh_->iterate_over_particles( - std::bind(&mpm::ParticleBase::map_body_force, - std::placeholders::_1, this->gravity_)); - - // Apply particle traction and map to nodes - mesh_->apply_traction_on_particles(this->step_ * this->dt_); - }); - - // Spawn a task for internal force - task_group.run([&] { - // Iterate over particles to compute nodal internal force - mesh_->iterate_over_particles(std::bind( - &mpm::ParticleBase::map_internal_force, std::placeholders::_1)); - }); - task_group.wait(); +#pragma omp parallel sections + { +#pragma omp section + { + // Iterate over particles to compute nodal body force + mesh_->iterate_over_particles( + std::bind(&mpm::ParticleBase::map_body_force, + std::placeholders::_1, this->gravity_)); + + // Apply particle traction and map to nodes + mesh_->apply_traction_on_particles(this->step_ * this->dt_); + } + +#pragma omp section + { + // Spawn a task for internal force + // Iterate over each particle to compute nodal internal force + mesh_->iterate_over_particles( + std::bind(&mpm::ParticleBase::map_internal_force, + std::placeholders::_1)); + } + } // Wait for tasks to finish // Compute intermediate velocity mesh_->iterate_over_nodes_predicate( From 81c54266fd445241ae282a0926bede236a780a45 Mon Sep 17 00:00:00 2001 From: Nanda Date: Fri, 24 Jul 2020 20:48:15 -0700 Subject: [PATCH 65/72] :wrench: add parallel schedule to iterate over particle predicate --- include/mesh.tcc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mesh.tcc b/include/mesh.tcc index c3f489483..6844f25ec 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1060,7 +1060,7 @@ void mpm::Mesh::iterate_over_particles(Toper oper) { template template void mpm::Mesh::iterate_over_particles_predicate(Toper oper, Tpred pred) { -#pragma omp parallel for +#pragma omp parallel for schedule(runtime) for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { if (pred(*pitr)) oper(*pitr); } From 13692de25583e6c8769a0eb47c84dc4cb249811c Mon Sep 17 00:00:00 2001 From: Nanda Date: Fri, 24 Jul 2020 20:48:51 -0700 Subject: [PATCH 66/72] :wrench: fix clang-format --- include/solvers/mpm_base.tcc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index 17313138a..e539762a6 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -348,8 +348,8 @@ bool mpm::MPMBase::initialise_particles() { } } } catch (std::exception& exception) { - console_->warn("{} #{}: Material sets are not specified", __FILE__, __LINE__, - exception.what()); + console_->warn("{} #{}: Material sets are not specified", __FILE__, + __LINE__, exception.what()); } } catch (std::exception& exception) { From f8fa3e9ab346047c21b181eb40fd46f9b9ea1d48 Mon Sep 17 00:00:00 2001 From: Nanda Date: Sat, 25 Jul 2020 14:12:54 -0700 Subject: [PATCH 67/72] :wrench: fix material and state variable phase --- include/particles/fluid_particle.h | 6 ++--- include/particles/fluid_particle.tcc | 35 ++++++++++++++++++++-------- include/solvers/mpm_base.h | 6 +---- include/solvers/mpm_base.tcc | 29 ----------------------- 4 files changed, 29 insertions(+), 47 deletions(-) diff --git a/include/particles/fluid_particle.h b/include/particles/fluid_particle.h index 540d82a9b..afc2a34b9 100644 --- a/include/particles/fluid_particle.h +++ b/include/particles/fluid_particle.h @@ -44,7 +44,7 @@ class FluidParticle : public mpm::Particle { //! Initial pressure //! \param[in] pressure Initial pressure void initial_pressure(double pressure) override { - state_variables_.at("pressure") = pressure; + state_variables_[mpm::ParticlePhase::SinglePhase].at("pressure") = pressure; } //! ---------------------------------------------------------------- @@ -78,6 +78,8 @@ class FluidParticle : public mpm::Particle { using ParticleBase::cell_; //! Nodes using ParticleBase::nodes_; + //! Fluid material + using ParticleBase::material_; //! State variables using ParticleBase::state_variables_; //! Shape functions @@ -86,8 +88,6 @@ class FluidParticle : public mpm::Particle { using Particle::dn_dx_; //! Fluid strain rate using Particle::strain_rate_; - //! Fluid material - using Particle::material_; //! Effective stress of soil skeleton using Particle::stress_; //! Particle mass density diff --git a/include/particles/fluid_particle.tcc b/include/particles/fluid_particle.tcc index 86fd296bf..65050f5ed 100644 --- a/include/particles/fluid_particle.tcc +++ b/include/particles/fluid_particle.tcc @@ -59,7 +59,9 @@ template <> inline void mpm::FluidParticle<1>::map_internal_force() noexcept { // initialise a vector of total stress (deviatoric + turbulent - pressure) Eigen::Matrix total_stress = this->stress_; - total_stress(0) -= this->projection_param_ * state_variables_.at("pressure"); + total_stress(0) -= + this->projection_param_ * + this->state_variables(mpm::ParticlePhase::SinglePhase)["pressure"]; // Compute nodal internal forces for (unsigned i = 0; i < nodes_.size(); ++i) { // Compute force: -pstress * volume @@ -77,8 +79,12 @@ template <> inline void mpm::FluidParticle<2>::map_internal_force() noexcept { // initialise a vector of total stress (deviatoric + turbulent - pressure) Eigen::Matrix total_stress = this->stress_; - total_stress(0) -= this->projection_param_ * state_variables_.at("pressure"); - total_stress(1) -= this->projection_param_ * state_variables_.at("pressure"); + total_stress(0) -= + this->projection_param_ * + this->state_variables(mpm::ParticlePhase::SinglePhase)["pressure"]; + total_stress(1) -= + this->projection_param_ * + this->state_variables(mpm::ParticlePhase::SinglePhase)["pressure"]; // Compute nodal internal forces for (unsigned i = 0; i < nodes_.size(); ++i) { @@ -99,9 +105,15 @@ template <> inline void mpm::FluidParticle<3>::map_internal_force() noexcept { // initialise a vector of total stress (deviatoric + turbulent - pressure) Eigen::Matrix total_stress = this->stress_; - total_stress(0) -= this->projection_param_ * state_variables_.at("pressure"); - total_stress(1) -= this->projection_param_ * state_variables_.at("pressure"); - total_stress(2) -= this->projection_param_ * state_variables_.at("pressure"); + total_stress(0) -= + this->projection_param_ * + this->state_variables(mpm::ParticlePhase::SinglePhase)["pressure"]; + total_stress(1) -= + this->projection_param_ * + this->state_variables(mpm::ParticlePhase::SinglePhase)["pressure"]; + total_stress(2) -= + this->projection_param_ * + this->state_variables(mpm::ParticlePhase::SinglePhase)["pressure"]; // Compute nodal internal forces for (unsigned i = 0; i < nodes_.size(); ++i) { @@ -145,7 +157,8 @@ bool mpm::FluidParticle::map_poisson_right_to_cell() { // Compute local poisson rhs matrix cell_->compute_local_poisson_right( shapefn_, dn_dx_, volume_, - material_->template property(std::string("density"))); + this->material(mpm::ParticlePhase::SinglePhase) + ->template property(std::string("density"))); } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); status = false; @@ -164,12 +177,14 @@ bool mpm::FluidParticle::compute_updated_pressure() { } // Get interpolated nodal pressure - state_variables_.at("pressure") = - state_variables_.at("pressure") * projection_param_ + + state_variables_[mpm::ParticlePhase::SinglePhase].at("pressure") = + state_variables_[mpm::ParticlePhase::SinglePhase].at("pressure") * + projection_param_ + pressure_increment; // Overwrite pressure if free surface - if (this->free_surface()) state_variables_.at("pressure") = 0.0; + if (this->free_surface()) + state_variables_[mpm::ParticlePhase::SinglePhase].at("pressure") = 0.0; } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); status = false; diff --git a/include/solvers/mpm_base.h b/include/solvers/mpm_base.h index e29777839..bdb327569 100644 --- a/include/solvers/mpm_base.h +++ b/include/solvers/mpm_base.h @@ -80,11 +80,11 @@ class MPMBase : public MPM { //! Write HDF5 files void write_hdf5(mpm::Index step, mpm::Index max_steps) override; - protected: //! Pressure smoothing //! \param[in] phase Phase to smooth pressure void pressure_smoothing(unsigned phase); + protected: //! Locate particle void locate_particle(); @@ -92,10 +92,6 @@ class MPMBase : public MPM { //! \param[in] initial_step Start of simulation or later steps void mpi_domain_decompose(bool initial_step = false) override; - //! Pressure smoothing - //! \param[in] phase Phase to smooth pressure - void pressure_smoothing(unsigned phase); - private: //! Return if a mesh will be isoparametric or not //! \retval isoparametric Status of mesh type diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index d318659af..4ddbb5b9e 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -1165,35 +1165,6 @@ bool mpm::MPMBase::initialise_damping(const Json& damping_props) { return status; } -//! Pressure smoothing -template -void mpm::MPMBase::pressure_smoothing(unsigned phase) { - // Assign pressure to nodes - mesh_->iterate_over_particles(std::bind( - &mpm::ParticleBase::map_pressure_to_nodes, std::placeholders::_1)); - -#ifdef USE_MPI - int mpi_size = 1; - - // Get number of MPI ranks - MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); - - // Run if there is more than a single MPI task - if (mpi_size > 1) { - // MPI all reduce nodal pressure - mesh_->template nodal_halo_exchange( - std::bind(&mpm::NodeBase::pressure, std::placeholders::_1, phase), - std::bind(&mpm::NodeBase::assign_pressure, std::placeholders::_1, - phase, std::placeholders::_2)); - } -#endif - - // Smooth pressure over particles - mesh_->iterate_over_particles( - std::bind(&mpm::ParticleBase::compute_pressure_smoothing, - std::placeholders::_1)); -} - //! Locate particle template void mpm::MPMBase::locate_particle() { From 965b3fdc7218b0453afccd3ffa64095aeb567754 Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 28 Jul 2020 14:39:46 -0700 Subject: [PATCH 68/72] :wrench: add assign_state_var and pressure and cleanup --- include/particles/particle.h | 44 +++++++++++++++++++++---------- include/particles/particle_base.h | 35 +++++++++++++----------- tests/particle_test.cc | 24 ++++++++++++----- 3 files changed, 68 insertions(+), 35 deletions(-) diff --git a/include/particles/particle.h b/include/particles/particle.h index 1ad7ec0ae..98d45d8bd 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -59,16 +59,6 @@ class Particle : public ParticleBase { const HDF5Particle& particle, const std::shared_ptr>& material) override; - //! Assign material history variables - //! \param[in] state_vars State variables - //! \param[in] material Material associated with the particle - //! \param[in] phase Index to indicate material phase - //! \retval status Status of cloning HDF5 particle - bool assign_material_state_vars( - const mpm::dense_map& state_vars, - const std::shared_ptr>& material, - unsigned phase = mpm::ParticlePhase::Solid) override; - //! Retrun particle data as HDF5 //! \retval particle HDF5 data of the particle HDF5Particle hdf5() const override; @@ -240,6 +230,27 @@ class Particle : public ParticleBase { void compute_updated_position(double dt, bool velocity_update = false) noexcept override; + //! Assign material history variables + //! \param[in] state_vars State variables + //! \param[in] material Material associated with the particle + //! \param[in] phase Index to indicate material phase + //! \retval status Status of cloning HDF5 particle + bool assign_material_state_vars( + const mpm::dense_map& state_vars, + const std::shared_ptr>& material, + unsigned phase = mpm::ParticlePhase::Solid) override; + + //! Assign a state variable + //! \param[in] var State variable + //! \param[in] value State variable to be assigned + //! \param[in] phase Index to indicate phase + void assign_state_variable( + const std::string& var, double value, + unsigned phase = mpm::ParticlePhase::Solid) override { + if (state_variables_[phase].find(var) != state_variables_[phase].end()) + state_variables_[phase].at(var) = value; + } + //! Return a state variable //! \param[in] var State variable //! \param[in] phase Index to indicate phase @@ -261,13 +272,18 @@ class Particle : public ParticleBase { bool compute_pressure_smoothing( unsigned phase = mpm::ParticlePhase::Solid) noexcept override; + //! Assign a state variable + //! \param[in] value Particle pressure to be assigned + //! \param[in] phase Index to indicate phase + void assign_pressure(double pressure, + unsigned phase = mpm::ParticlePhase::Solid) override { + this->assign_state_variable("pressure", pressure, phase); + } + //! Return pressure of the particles //! \param[in] phase Index to indicate phase double pressure(unsigned phase = mpm::ParticlePhase::Solid) const override { - return (state_variables_[phase].find("pressure") != - state_variables_[phase].end()) - ? state_variables_[phase].at("pressure") - : std::numeric_limits::quiet_NaN(); + return this->state_variable("pressure", phase); } //! Return tensor data of particles diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 9f2cded6e..da0cba0a6 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -69,16 +69,6 @@ class ParticleBase { const HDF5Particle& particle, const std::shared_ptr>& material) = 0; - //! Assign material history variables - //! \param[in] state_vars State variables - //! \param[in] material Material associated with the particle - //! \param[in] phase Index to indicate material phase - //! \retval status Status of cloning HDF5 particle - virtual bool assign_material_state_vars( - const mpm::dense_map& state_vars, - const std::shared_ptr>& material, - unsigned phase = mpm::ParticlePhase::Solid) = 0; - //! Retrun particle data as HDF5 //! \retval particle HDF5 data of the particle virtual HDF5Particle hdf5() const = 0; @@ -175,6 +165,12 @@ class ParticleBase { return material_id_[phase]; } + //! Assign material state variables + virtual bool assign_material_state_vars( + const mpm::dense_map& state_vars, + const std::shared_ptr>& material, + unsigned phase = mpm::ParticlePhase::Solid) = 0; + //! Return state variables //! \param[in] phase Index to indicate material phase mpm::dense_map state_variables( @@ -182,6 +178,16 @@ class ParticleBase { return state_variables_[phase]; } + //! Assign a state variable + virtual void assign_state_variable( + const std::string& var, double value, + unsigned phase = mpm::ParticlePhase::Solid) = 0; + + //! Return a state variable + virtual double state_variable( + const std::string& var, + unsigned phase = mpm::ParticlePhase::Solid) const = 0; + //! Assign status void assign_status(bool status) { status_ = status; } @@ -197,6 +203,10 @@ class ParticleBase { //! Return mass virtual double mass() const = 0; + //! Assign pressure + virtual void assign_pressure(double pressure, + unsigned phase = mpm::ParticlePhase::Solid) = 0; + //! Return pressure virtual double pressure(unsigned phase = mpm::ParticlePhase::Solid) const = 0; @@ -260,11 +270,6 @@ class ParticleBase { virtual void compute_updated_position( double dt, bool velocity_update = false) noexcept = 0; - //! Return a state variable - virtual double state_variable( - const std::string& var, - unsigned phase = mpm::ParticlePhase::Solid) const = 0; - //! Return tensor data of particles //! \param[in] property Property string //! \retval vecdata Tensor data of particle property diff --git a/tests/particle_test.cc b/tests/particle_test.cc index 0d2656f54..1e80c0a7a 100644 --- a/tests/particle_test.cc +++ b/tests/particle_test.cc @@ -1137,9 +1137,15 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { SECTION("Assign state variables") { // Assign material properties REQUIRE(particle->assign_material(mc_material) == true); - // Assing state variables + // Assign state variables REQUIRE(particle->assign_material_state_vars(state_variables, mc_material) == true); + // Assign and read a state variable + REQUIRE_NOTHROW(particle->assign_state_variable("phi", 30.)); + REQUIRE(particle->state_variable("phi") == 30.); + // Assign and read pressure though MC does not contain pressure + REQUIRE_NOTHROW(particle->assign_pressure(1000)); + REQUIRE(std::isnan(particle->pressure()) == true); } SECTION("Assign state variables fail on state variables size") { @@ -1157,7 +1163,7 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { // Assign material properties REQUIRE(particle->assign_material(newtonian_material) == true); - // Assing state variables + // Assign state variables REQUIRE(particle->assign_material_state_vars(state_variables, mc_material) == false); } @@ -1177,7 +1183,7 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { // Assign material properties REQUIRE(particle->assign_material(newtonian_material) == true); - // Assing state variables + // Assign state variables REQUIRE(particle->assign_material_state_vars(state_variables, mc_material) == false); } @@ -2389,9 +2395,15 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { SECTION("Assign state variables") { // Assign material properties REQUIRE(particle->assign_material(mc_material) == true); - // Assing state variables + // Assign state variables REQUIRE(particle->assign_material_state_vars(state_variables, mc_material) == true); + // Assign and read a state variable + REQUIRE_NOTHROW(particle->assign_state_variable("phi", 30.)); + REQUIRE(particle->state_variable("phi") == 30.); + // Assign and read pressure though MC does not contain pressure + REQUIRE_NOTHROW(particle->assign_pressure(1000)); + REQUIRE(std::isnan(particle->pressure()) == true); } SECTION("Assign state variables fail on state variables size") { @@ -2409,7 +2421,7 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { // Assign material properties REQUIRE(particle->assign_material(newtonian_material) == true); - // Assing state variables + // Assign state variables REQUIRE(particle->assign_material_state_vars(state_variables, mc_material) == false); } @@ -2429,7 +2441,7 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { // Assign material properties REQUIRE(particle->assign_material(newtonian_material) == true); - // Assing state variables + // Assign state variables REQUIRE(particle->assign_material_state_vars(state_variables, mc_material) == false); } From d73a5f02776e61342b11166804e18ecbe003f7be Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 28 Jul 2020 14:43:37 -0700 Subject: [PATCH 69/72] :wrench: change initial_pressure to assign_pressure --- include/particles/fluid_particle.h | 6 ------ include/particles/particle_base.h | 9 --------- include/solvers/mpm_semi_implicit_navierstokes.tcc | 4 ++-- 3 files changed, 2 insertions(+), 17 deletions(-) diff --git a/include/particles/fluid_particle.h b/include/particles/fluid_particle.h index afc2a34b9..17fdbd9ae 100644 --- a/include/particles/fluid_particle.h +++ b/include/particles/fluid_particle.h @@ -41,12 +41,6 @@ class FluidParticle : public mpm::Particle { //! Map internal force inline void map_internal_force() noexcept override; - //! Initial pressure - //! \param[in] pressure Initial pressure - void initial_pressure(double pressure) override { - state_variables_[mpm::ParticlePhase::SinglePhase].at("pressure") = pressure; - } - //! ---------------------------------------------------------------- //! Semi-Implicit integration functions based on Chorin's Projection //! ---------------------------------------------------------------- diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index da0cba0a6..b722bc3a8 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -310,15 +310,6 @@ class ParticleBase { //! Return neighbour ids virtual std::vector neighbours() const = 0; - //! Initial pressure - //! \param[in] pressure Initial pressure - virtual void initial_pressure(double pressure) { - throw std::runtime_error( - "Calling the base class function " - "(initial_pressure) in " - "ParticleBase:: illegal operation!"); - }; - //! Assigning beta parameter to particle //! \param[in] pressure parameter determining type of projection virtual void assign_projection_parameter(double parameter) { diff --git a/include/solvers/mpm_semi_implicit_navierstokes.tcc b/include/solvers/mpm_semi_implicit_navierstokes.tcc index 1969614a0..58715c124 100644 --- a/include/solvers/mpm_semi_implicit_navierstokes.tcc +++ b/include/solvers/mpm_semi_implicit_navierstokes.tcc @@ -130,8 +130,8 @@ bool mpm::MPMSemiImplicitNavierStokes::solve() { { // Assign initial pressure for all free-surface particle mesh_->iterate_over_particles_predicate( - std::bind(&mpm::ParticleBase::initial_pressure, - std::placeholders::_1, 0.0), + std::bind(&mpm::ParticleBase::assign_pressure, + std::placeholders::_1, 0.0, fluid), std::bind(&mpm::ParticleBase::free_surface, std::placeholders::_1)); } From 48b56c633e36315ea60ab0aaf510a4ff717c0d19 Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 29 Jul 2020 13:14:52 -0700 Subject: [PATCH 70/72] :wrench: reformat free surface detection --- include/mesh.h | 26 +- include/mesh.tcc | 265 +++++++++--------- include/particles/particle.h | 7 +- include/particles/particle.tcc | 8 +- include/particles/particle_base.h | 5 +- .../solvers/mpm_semi_implicit_navierstokes.h | 2 + .../mpm_semi_implicit_navierstokes.tcc | 8 +- 7 files changed, 187 insertions(+), 134 deletions(-) diff --git a/include/mesh.h b/include/mesh.h index 19d4690db..6c16e3dc4 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -453,8 +453,32 @@ class Mesh { void inject_particles(double current_time); //! Compute free surface + //! \param[in] method Type of method to use + //! \param[in] volume_tolerance for volume_fraction approach + //! \retval status Status of compute_free_surface bool compute_free_surface( - double tolerance = std::numeric_limits::epsilon()); + std::string method, + double volume_tolerance = std::numeric_limits::epsilon()); + + //! Compute free surface by density method + //! \details Using simple approach of volume fraction approach as (Kularathna + //! & Soga, 2017) and density ratio comparison (Hamad, 2015). This method is + //! fast, but less accurate. + //! \param[in] volume_tolerance for volume_fraction approach + //! \retval status Status of compute_free_surface + bool compute_free_surface_by_density( + double volume_tolerance = std::numeric_limits::epsilon()); + + //! Compute free surface by geometry method + //! \details Using a more expensive approach using neighbouring particles and + //! current geometry. This method combine multiple checks in order to simplify + //! and fasten the process: (1) Volume fraction approach as (Kularathna & Soga + //! 2017), (2) Density comparison approach as (Hamad, 2015), and (3) Geometry + //! based approach as (Marrone et al. 2010) + //! \param[in] volume_tolerance for volume_fraction approach + //! \retval status Status of compute_free_surface + bool compute_free_surface_by_geometry( + double volume_tolerance = std::numeric_limits::epsilon()); //! Get free surface node set std::set free_surface_nodes(); diff --git a/include/mesh.tcc b/include/mesh.tcc index cf0192ee7..f090d0477 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1976,7 +1976,25 @@ bool mpm::Mesh::compute_nodal_correction_force( //! Compute free surface cells, nodes, and particles template -bool mpm::Mesh::compute_free_surface(double tolerance) { +bool mpm::Mesh::compute_free_surface(std::string method, + double volume_tolerance) { + if (method == "density") { + return this->compute_free_surface_by_density(volume_tolerance); + } else if (method == "geometry") { + return this->compute_free_surface_by_geometry(volume_tolerance); + } else { + console_->info( + "The selected free-surface computation method: {}\n is not available. " + "Using density approach as default method.", + method); + return this->compute_free_surface_by_density(volume_tolerance); + } +} + +//! Compute free surface cells, nodes, and particles by density and geometry +template +bool mpm::Mesh::compute_free_surface_by_geometry( + double volume_tolerance) { bool status = true; try { // Reset free surface cell and particles @@ -2023,7 +2041,7 @@ bool mpm::Mesh::compute_free_surface(double tolerance) { if ((*citr)->status()) { bool candidate_cell = false; const auto& node_id = (*citr)->nodes_id(); - if ((*citr)->volume_fraction() < tolerance) { + if ((*citr)->volume_fraction() < volume_tolerance) { candidate_cell = true; for (const auto id : node_id) { map_nodes_[id]->assign_free_surface(true); @@ -2084,7 +2102,7 @@ bool mpm::Mesh::compute_free_surface(double tolerance) { std::set free_surface_candidate_particles_second; for (const auto p_id : free_surface_candidate_particles) { const auto& particle = map_particles_[p_id]; - bool status = particle->compute_free_surface(); + bool status = particle->compute_free_surface_by_density(); if (status) free_surface_candidate_particles_second.insert(p_id); } @@ -2223,128 +2241,125 @@ bool mpm::Mesh::compute_free_surface(double tolerance) { return status; } -// //! Compute free surface cells, nodes, and particles -// template -// bool mpm::Mesh::compute_free_surface(double tolerance) { -// bool status = true; -// try { -// // Reset free surface cell -// this->iterate_over_cells(std::bind(&mpm::Cell::assign_free_surface, -// std::placeholders::_1, false)); - -// // Reset volume fraction -// this->iterate_over_cells(std::bind(&mpm::Cell::assign_volume_fraction, -// std::placeholders::_1, 0.0)); - -// // Reset free surface particle -// this->iterate_over_particles( -// std::bind(&mpm::ParticleBase::assign_free_surface, -// std::placeholders::_1, false)); - -// // Compute and assign volume fraction to each cell -// for (auto citr = this->cells_.cbegin(); citr != this->cells_.cend(); -// ++citr) { -// if ((*citr)->status()) { -// // Compute volume fraction -// double cell_volume_fraction = 0.0; -// for (const auto p_id : (*citr)->particles()) -// cell_volume_fraction += map_particles_[p_id]->volume(); - -// cell_volume_fraction = cell_volume_fraction / (*citr)->volume(); -// (*citr)->assign_volume_fraction(cell_volume_fraction); -// } -// } - -// // Compute boundary cells and nodes based on geometry -// std::set boundary_cells; -// std::set boundary_nodes; -// for (auto citr = this->cells_.cbegin(); citr != this->cells_.cend(); -// ++citr) { - -// if ((*citr)->status()) { -// bool cell_at_interface = false; -// const auto& node_id = (*citr)->nodes_id(); -// bool internal = true; - -// //! Check internal cell -// for (const auto c_id : (*citr)->neighbours()) { -// if (!map_cells_[c_id]->status()) { -// internal = false; -// break; -// } -// } - -// //! Check volume fraction only for boundary cell -// if (!internal) { -// if ((*citr)->volume_fraction() < tolerance) { -// cell_at_interface = true; -// for (const auto id : node_id) { -// map_nodes_[id]->assign_free_surface(cell_at_interface); -// boundary_nodes.insert(id); -// } -// } else { -// for (const auto n_id : (*citr)->neighbours()) { -// if (map_cells_[n_id]->volume_fraction() < tolerance) { -// cell_at_interface = true; -// const auto& n_node_id = map_cells_[n_id]->nodes_id(); - -// // Detect common node id -// std::set common_node_id; -// std::set_intersection( -// node_id.begin(), node_id.end(), n_node_id.begin(), -// n_node_id.end(), -// std::inserter(common_node_id, common_node_id.begin())); - -// // Assign free surface nodes -// if (!common_node_id.empty()) { -// for (const auto common_id : common_node_id) { -// map_nodes_[common_id]->assign_free_surface( -// cell_at_interface); -// boundary_nodes.insert(common_id); -// } -// } -// } -// } -// } - -// // Assign free surface cell -// if (cell_at_interface) { -// (*citr)->assign_free_surface(cell_at_interface); -// boundary_cells.insert((*citr)->id()); -// } -// } -// } -// } - -// // Compute boundary particles based on density function -// // Lump cell volume to nodes -// this->iterate_over_cells(std::bind( -// &mpm::Cell::map_cell_volume_to_nodes, std::placeholders::_1, -// 0)); - -// // Compute nodal value of mass density -// this->iterate_over_nodes_predicate( -// std::bind(&mpm::NodeBase::compute_density, -// std::placeholders::_1), std::bind(&mpm::NodeBase::status, -// std::placeholders::_1)); - -// // Evaluate free surface particles -// std::set boundary_particles; -// for (auto pitr = this->particles_.cbegin(); pitr != -// this->particles_.cend(); -// ++pitr) { -// bool status = (*pitr)->compute_free_surface(); -// if (status) { -// (*pitr)->assign_free_surface(status); -// boundary_particles.insert((*pitr)->id()); -// } -// } - -// } catch (std::exception& exception) { -// console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); -// } -// return status; -// } +//! Compute free surface cells, nodes, and particles by density +template +bool mpm::Mesh::compute_free_surface_by_density(double volume_tolerance) { + bool status = true; + try { + // Reset free surface cell + this->iterate_over_cells(std::bind(&mpm::Cell::assign_free_surface, + std::placeholders::_1, false)); + + // Reset volume fraction + this->iterate_over_cells(std::bind(&mpm::Cell::assign_volume_fraction, + std::placeholders::_1, 0.0)); + + // Reset free surface particle + this->iterate_over_particles( + std::bind(&mpm::ParticleBase::assign_free_surface, + std::placeholders::_1, false)); + + // Compute and assign volume fraction to each cell + for (auto citr = this->cells_.cbegin(); citr != this->cells_.cend(); + ++citr) { + if ((*citr)->status()) { + // Compute volume fraction + double cell_volume_fraction = 0.0; + for (const auto p_id : (*citr)->particles()) + cell_volume_fraction += map_particles_[p_id]->volume(); + + cell_volume_fraction = cell_volume_fraction / (*citr)->volume(); + (*citr)->assign_volume_fraction(cell_volume_fraction); + } + } + + // Compute boundary cells and nodes based on geometry + std::set boundary_cells; + std::set boundary_nodes; + for (auto citr = this->cells_.cbegin(); citr != this->cells_.cend(); + ++citr) { + + if ((*citr)->status()) { + bool cell_at_interface = false; + const auto& node_id = (*citr)->nodes_id(); + bool internal = true; + + //! Check internal cell + for (const auto c_id : (*citr)->neighbours()) { + if (!map_cells_[c_id]->status()) { + internal = false; + break; + } + } + + //! Check volume fraction only for boundary cell + if (!internal) { + if ((*citr)->volume_fraction() < volume_tolerance) { + cell_at_interface = true; + for (const auto id : node_id) { + map_nodes_[id]->assign_free_surface(cell_at_interface); + boundary_nodes.insert(id); + } + } else { + for (const auto n_id : (*citr)->neighbours()) { + if (map_cells_[n_id]->volume_fraction() < volume_tolerance) { + cell_at_interface = true; + const auto& n_node_id = map_cells_[n_id]->nodes_id(); + + // Detect common node id + std::set common_node_id; + std::set_intersection( + node_id.begin(), node_id.end(), n_node_id.begin(), + n_node_id.end(), + std::inserter(common_node_id, common_node_id.begin())); + + // Assign free surface nodes + if (!common_node_id.empty()) { + for (const auto common_id : common_node_id) { + map_nodes_[common_id]->assign_free_surface( + cell_at_interface); + boundary_nodes.insert(common_id); + } + } + } + } + } + + // Assign free surface cell + if (cell_at_interface) { + (*citr)->assign_free_surface(cell_at_interface); + boundary_cells.insert((*citr)->id()); + } + } + } + } + + // Compute boundary particles based on density function + // Lump cell volume to nodes + this->iterate_over_cells(std::bind( + &mpm::Cell::map_cell_volume_to_nodes, std::placeholders::_1, 0)); + + // Compute nodal value of mass density + this->iterate_over_nodes_predicate( + std::bind(&mpm::NodeBase::compute_density, std::placeholders::_1), + std::bind(&mpm::NodeBase::status, std::placeholders::_1)); + + // Evaluate free surface particles + std::set boundary_particles; + for (auto pitr = this->particles_.cbegin(); pitr != this->particles_.cend(); + ++pitr) { + bool status = (*pitr)->compute_free_surface_by_density(); + if (status) { + (*pitr)->assign_free_surface(status); + boundary_particles.insert((*pitr)->id()); + } + } + + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + } + return status; +} //! Get free surface node set template diff --git a/include/particles/particle.h b/include/particles/particle.h index 98d45d8bd..e9f7843bb 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -308,8 +308,11 @@ class Particle : public ParticleBase { //! Return free surface bool bool free_surface() override { return free_surface_; }; - //! Compute free surface - bool compute_free_surface() override; + //! Compute free surface in particle level by density ratio comparison + //! \param[in] density_ratio_tolerance Tolerance of density ratio comparison + //! \retval status Status of compute_free_surface + bool compute_free_surface_by_density( + double density_ratio_tolerance = 0.70) override; //! Assign normal vector void assign_normal(const VectorDim& normal) override { normal_ = normal; }; diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index 5b665c147..31b316eea 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -871,9 +871,10 @@ void mpm::Particle::append_material_id_to_nodes() const { nodes_[i]->append_material_id(this->material_id()); } -//! Compute free surface +//! Compute free surface in particle level by density ratio comparison template -bool mpm::Particle::compute_free_surface() { +bool mpm::Particle::compute_free_surface_by_density( + double density_ratio_tolerance) { bool status = false; // Check if particle has a valid cell ptr if (cell_ != nullptr) { @@ -885,7 +886,8 @@ bool mpm::Particle::compute_free_surface() { shapefn_[i] * nodes_[i]->density(mpm::ParticlePhase::Solid); // Compare smoothen density to actual particle mass density - if ((nodal_mass_density / mass_density_) <= 0.70) status = true; + if ((nodal_mass_density / mass_density_) <= density_ratio_tolerance) + status = true; } return status; }; diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index b722bc3a8..cfbffb953 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -290,8 +290,9 @@ class ParticleBase { //! Assign particle free surface virtual bool free_surface() = 0; - //! Compute free surface - virtual bool compute_free_surface() = 0; + //! Compute free surface in particle level by density ratio comparison + virtual bool compute_free_surface_by_density( + double density_ratio_tolerance = 0.70) = 0; //! Assign normal vector virtual void assign_normal(const VectorDim& normal) = 0; diff --git a/include/solvers/mpm_semi_implicit_navierstokes.h b/include/solvers/mpm_semi_implicit_navierstokes.h index 1196542dd..d0d9be995 100644 --- a/include/solvers/mpm_semi_implicit_navierstokes.h +++ b/include/solvers/mpm_semi_implicit_navierstokes.h @@ -82,6 +82,8 @@ class MPMSemiImplicitNavierStokes : public MPMBase { std::shared_ptr> matrix_assembler_; //! Matrix solver object std::shared_ptr>> matrix_solver_; + //! Method to detect free surface detection + std::string free_surface_detection_; //! Volume tolerance for free surface double volume_tolerance_{0}; diff --git a/include/solvers/mpm_semi_implicit_navierstokes.tcc b/include/solvers/mpm_semi_implicit_navierstokes.tcc index 58715c124..7af0a092c 100644 --- a/include/solvers/mpm_semi_implicit_navierstokes.tcc +++ b/include/solvers/mpm_semi_implicit_navierstokes.tcc @@ -121,7 +121,7 @@ bool mpm::MPMSemiImplicitNavierStokes::solve() { std::placeholders::_1)); // Compute free surface cells, nodes, and particles - mesh_->compute_free_surface(volume_tolerance_); + mesh_->compute_free_surface(free_surface_detection_, volume_tolerance_); // Spawn a task for initializing pressure at free surface #pragma omp parallel sections @@ -265,6 +265,12 @@ bool mpm::MPMSemiImplicitNavierStokes::initialise_matrix() { // Get matrix solver type std::string solver_type = analysis_["matrix"]["solver_type"].template get(); + // Get method to detect free surface detection + free_surface_detection_ = "density"; + if (analysis_["matrix"].contains("free_surface_detection_type")) + free_surface_detection_ = + analysis_["matrix"]["free_surface_detection_type"] + .template get(); // Get volume tolerance for free surface volume_tolerance_ = analysis_["matrix"]["volume_tolerance"].template get(); From b38c3c2f05c9dc03ab65d6d37cb00f148969b92a Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 29 Jul 2020 14:25:12 -0700 Subject: [PATCH 71/72] :wrench: refactor assembler, linear solver, and fs_detection --- .../solvers/mpm_semi_implicit_navierstokes.h | 10 +-- .../mpm_semi_implicit_navierstokes.tcc | 65 +++++++++---------- 2 files changed, 37 insertions(+), 38 deletions(-) diff --git a/include/solvers/mpm_semi_implicit_navierstokes.h b/include/solvers/mpm_semi_implicit_navierstokes.h index d0d9be995..5e0fbe6af 100644 --- a/include/solvers/mpm_semi_implicit_navierstokes.h +++ b/include/solvers/mpm_semi_implicit_navierstokes.h @@ -24,7 +24,7 @@ class MPMSemiImplicitNavierStokes : public MPMBase { //! Return matrix assembler pointer std::shared_ptr> matrix_assembler() { - return matrix_assembler_; + return assembler_; } //! Solve @@ -78,10 +78,10 @@ class MPMSemiImplicitNavierStokes : public MPMBase { bool pressure_smoothing_{false}; // Projection method paramter (beta) double beta_{1}; - //! Matrix assembler object - std::shared_ptr> matrix_assembler_; - //! Matrix solver object - std::shared_ptr>> matrix_solver_; + //! Assembler object + std::shared_ptr> assembler_; + //! Linear solver object + std::shared_ptr>> linear_solver_; //! Method to detect free surface detection std::string free_surface_detection_; //! Volume tolerance for free surface diff --git a/include/solvers/mpm_semi_implicit_navierstokes.tcc b/include/solvers/mpm_semi_implicit_navierstokes.tcc index 7af0a092c..1383489f7 100644 --- a/include/solvers/mpm_semi_implicit_navierstokes.tcc +++ b/include/solvers/mpm_semi_implicit_navierstokes.tcc @@ -194,9 +194,8 @@ bool mpm::MPMSemiImplicitNavierStokes::solve() { // Assign pressure to nodes mesh_->iterate_over_nodes_predicate( std::bind(&mpm::NodeBase::update_pressure_increment, - std::placeholders::_1, - matrix_assembler_->pressure_increment(), fluid, - this->step_ * this->dt_), + std::placeholders::_1, assembler_->pressure_increment(), + fluid, this->step_ * this->dt_), std::bind(&mpm::NodeBase::status, std::placeholders::_1)); // Use nodal pressure to update particle pressure @@ -256,34 +255,35 @@ bool mpm::MPMSemiImplicitNavierStokes::initialise_matrix() { try { // Max iteration steps unsigned max_iter = - analysis_["matrix"]["max_iter"].template get(); + analysis_["linear_solver"]["max_iter"].template get(); // Tolerance - double tolerance = analysis_["matrix"]["tolerance"].template get(); + double tolerance = + analysis_["linear_solver"]["tolerance"].template get(); // Get matrix assembler type - std::string assembler_type = - analysis_["matrix"]["assembler_type"].template get(); + std::string assembler_type = analysis_["linear_solver"]["assembler_type"] + .template get(); // Get matrix solver type std::string solver_type = - analysis_["matrix"]["solver_type"].template get(); - // Get method to detect free surface detection - free_surface_detection_ = "density"; - if (analysis_["matrix"].contains("free_surface_detection_type")) - free_surface_detection_ = - analysis_["matrix"]["free_surface_detection_type"] - .template get(); - // Get volume tolerance for free surface - volume_tolerance_ = - analysis_["matrix"]["volume_tolerance"].template get(); + analysis_["linear_solver"]["solver_type"].template get(); // Create matrix assembler - matrix_assembler_ = + assembler_ = Factory>::instance()->create(assembler_type); // Create matrix solver - matrix_solver_ = + linear_solver_ = Factory>, unsigned, double>::instance() ->create(solver_type, std::move(max_iter), std::move(tolerance)); // Assign mesh pointer to assembler - matrix_assembler_->assign_mesh_pointer(mesh_); + assembler_->assign_mesh_pointer(mesh_); + + // Get method to detect free surface detection + free_surface_detection_ = "density"; + if (analysis_["free_surface_detection"].contains("type")) + free_surface_detection_ = analysis_["free_surface_detection"]["type"] + .template get(); + // Get volume tolerance for free surface + volume_tolerance_ = analysis_["free_surface_detection"]["volume_tolerance"] + .template get(); } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); @@ -301,11 +301,11 @@ bool mpm::MPMSemiImplicitNavierStokes::reinitialise_matrix() { const auto nactive_node = mesh_->assign_active_nodes_id(); // Assign global node indice - matrix_assembler_->assign_global_node_indices(nactive_node); + assembler_->assign_global_node_indices(nactive_node); // Assign pressure constraints - matrix_assembler_->assign_pressure_constraints(this->beta_, - this->step_ * this->dt_); + assembler_->assign_pressure_constraints(this->beta_, + this->step_ * this->dt_); // Initialise element matrix mesh_->iterate_over_cells(std::bind( @@ -330,7 +330,7 @@ bool mpm::MPMSemiImplicitNavierStokes::compute_poisson_equation( std::placeholders::_1)); // Assemble global laplacian matrix - matrix_assembler_->assemble_laplacian_matrix(dt_); + assembler_->assemble_laplacian_matrix(dt_); // Map Poisson RHS matrix mesh_->iterate_over_particles( @@ -338,18 +338,18 @@ bool mpm::MPMSemiImplicitNavierStokes::compute_poisson_equation( std::placeholders::_1)); // Assemble poisson RHS vector - matrix_assembler_->assemble_poisson_right(dt_); + assembler_->assemble_poisson_right(dt_); // Assign free surface to assembler - matrix_assembler_->assign_free_surface(mesh_->free_surface_nodes()); + assembler_->assign_free_surface(mesh_->free_surface_nodes()); // Apply constraints - matrix_assembler_->apply_pressure_constraints(); + assembler_->apply_pressure_constraints(); // Solve matrix equation and assign solution to assembler - matrix_assembler_->assign_pressure_increment(matrix_solver_->solve( - matrix_assembler_->laplacian_matrix(), - matrix_assembler_->poisson_rhs_vector(), solver_type)); + assembler_->assign_pressure_increment( + linear_solver_->solve(assembler_->laplacian_matrix(), + assembler_->poisson_rhs_vector(), solver_type)); } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); @@ -369,12 +369,11 @@ bool mpm::MPMSemiImplicitNavierStokes::compute_correction_force() { std::placeholders::_1)); // Assemble correction matrix - matrix_assembler_->assemble_corrector_right(dt_); + assembler_->assemble_corrector_right(dt_); // Assign correction force mesh_->compute_nodal_correction_force( - matrix_assembler_->correction_matrix(), - matrix_assembler_->pressure_increment(), dt_); + assembler_->correction_matrix(), assembler_->pressure_increment(), dt_); } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); From 76a7e0bd9d435bdadfae615505bad0c10ba2ca43 Mon Sep 17 00:00:00 2001 From: Nanda Date: Thu, 30 Jul 2020 14:25:12 -0700 Subject: [PATCH 72/72] :construction: modify linear solver --- include/linear_solvers/cg_eigen.h | 6 ---- include/linear_solvers/cg_eigen.tcc | 41 ---------------------------- include/linear_solvers/solver_base.h | 6 ---- 3 files changed, 53 deletions(-) diff --git a/include/linear_solvers/cg_eigen.h b/include/linear_solvers/cg_eigen.h index b8b37f511..359df75b7 100644 --- a/include/linear_solvers/cg_eigen.h +++ b/include/linear_solvers/cg_eigen.h @@ -8,7 +8,6 @@ #include #include #include -#include namespace mpm { @@ -31,11 +30,6 @@ class CGEigen : public SolverBase { const Eigen::VectorXd& b, std::string solver_type) override; - //! Matrix solver with defined initial guess - Eigen::VectorXd solve(const Eigen::SparseMatrix& A, - const Eigen::VectorXd& b, std::string solver_type, - const Eigen::VectorXd& initial_guess) override; - //! Return the type of solver std::string solver_type() const { return "Eigen"; } diff --git a/include/linear_solvers/cg_eigen.tcc b/include/linear_solvers/cg_eigen.tcc index b3cebe9c9..783b247fb 100644 --- a/include/linear_solvers/cg_eigen.tcc +++ b/include/linear_solvers/cg_eigen.tcc @@ -36,47 +36,6 @@ Eigen::VectorXd mpm::CGEigen::solve( } } - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - } - return x; -} - -//! Conjugate Gradient with defined initial guess -template -Eigen::VectorXd mpm::CGEigen::solve( - const Eigen::SparseMatrix& A, const Eigen::VectorXd& b, - std::string solver_type, const Eigen::VectorXd& initial_guess) { - Eigen::VectorXd x; - try { - - if (solver_type == "cg") { - Eigen::ConjugateGradient> solver; - - solver.setMaxIterations(max_iter_); - solver.setTolerance(tolerance_); - solver.compute(A); - - x = solver.solveWithGuess(b, initial_guess); - - if (solver.info() != Eigen::Success) { - throw std::runtime_error("Fail to solve linear systems!\n"); - } - - } else if (solver_type == "lscg") { - - Eigen::LeastSquaresConjugateGradient> solver; - - solver.setMaxIterations(max_iter_); - solver.setTolerance(tolerance_); - solver.compute(A); - x = solver.solveWithGuess(b, initial_guess); - - if (solver.info() != Eigen::Success) { - throw std::runtime_error("Fail to solve linear systems!\n"); - } - } - } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); } diff --git a/include/linear_solvers/solver_base.h b/include/linear_solvers/solver_base.h index 0b7745d1a..111b2cb08 100644 --- a/include/linear_solvers/solver_base.h +++ b/include/linear_solvers/solver_base.h @@ -19,12 +19,6 @@ class SolverBase { const Eigen::VectorXd& b, std::string solver_type) = 0; - //! Matrix solver with defined initial guess - virtual Eigen::VectorXd solve(const Eigen::SparseMatrix& A, - const Eigen::VectorXd& b, - std::string solver_type, - const Eigen::VectorXd& initial_guess) = 0; - protected: //! Maximum number of iterations unsigned max_iter_;