From bbf7c51f3744c6cf74e3379bdc189dc1dc1b08de Mon Sep 17 00:00:00 2001 From: Tianchi Date: Sun, 28 Jun 2020 22:08:21 -0700 Subject: [PATCH 001/175] Add twophase particle functions --- include/node.h | 9 + include/node.tcc | 25 +- include/node_base.h | 7 + include/particles/particle.h | 4 +- include/particles/particle_base.h | 226 ++++++- include/particles/twophase_particle.h | 283 +++++++++ include/particles/twophase_particle.tcc | 777 ++++++++++++++++++++++++ src/node.cc | 10 + src/particle.cc | 11 + 9 files changed, 1348 insertions(+), 4 deletions(-) create mode 100644 include/particles/twophase_particle.h create mode 100644 include/particles/twophase_particle.tcc diff --git a/include/node.h b/include/node.h index 775f7f003..22c7baea7 100644 --- a/include/node.h +++ b/include/node.h @@ -133,6 +133,13 @@ class Node : public NodeBase { void update_mass_pressure(unsigned phase, double mass_pressure) noexcept override; + //! Update drag force coefficient + //! \param[in] update A boolean to update (true) or assign (false) + //! \param[in] drag_force Drag force from the particles in a cell + //! \retval status Update status + bool update_drag_force_coefficient( + bool update, const VectorDim& drag_force_coefficient) override; + //! Assign pressure at the nodes from particle //! \param[in] update A boolean to update (true) or assign (false) //! \param[in] phase Index corresponding to the phase @@ -280,6 +287,8 @@ class Node : public NodeBase { Eigen::Matrix external_force_; //! Internal force Eigen::Matrix internal_force_; + //! Drag force coefficient + Eigen::Matrix drag_force_coefficient_; //! Pressure Eigen::Matrix pressure_; //! Velocity diff --git a/include/node.tcc b/include/node.tcc index 823e2e0e7..7dd091105 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -27,6 +27,7 @@ void mpm::Node::initialise() noexcept { volume_.setZero(); external_force_.setZero(); internal_force_.setZero(); + drag_force_coefficient_.setZero(); pressure_.setZero(); velocity_.setZero(); momentum_.setZero(); @@ -165,6 +166,28 @@ void mpm::Node::update_mass_pressure( } } +//! Update drag force coefficient +template +bool mpm::Node::update_drag_force_coefficient( + bool update, const Eigen::Matrix& drag_force_coefficient) { + bool status = false; + try { + // Decide to update or assign + double factor = 1.0; + if (!update) factor = 0.; + + // Update/assign drag force coefficient + std::lock_guard guard(node_mutex_); + drag_force_coefficient_ = + drag_force_coefficient_ * factor + drag_force_coefficient; + status = true; + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + //! Assign pressure at the nodes from particle template void mpm::Node::assign_pressure(unsigned phase, @@ -553,7 +576,7 @@ void mpm::Node momentum = property_handle_->property("momenta", prop_id_, *mitr, Tdim); const Eigen::Matrix change_in_momenta = - velocity_ * mass - momentum; + velocity_.col(0) * mass - momentum; property_handle_->update_property("change_in_momenta", prop_id_, *mitr, change_in_momenta, Tdim); } diff --git a/include/node_base.h b/include/node_base.h index 0d4b1a5b2..6c85d9a74 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -133,6 +133,13 @@ class NodeBase { virtual void update_mass_pressure(unsigned phase, double mass_pressure) noexcept = 0; + //! Update drag force coefficient + //! \param[in] update A boolean to update (true) or assign (false) + //! \param[in] drag_force Drag force from the particles in a cell + //! \retval status Update status + virtual bool update_drag_force_coefficient(bool update, + const VectorDim& drag_force) = 0; + //! Assign pressure at the nodes from particle //! \param[in] update A boolean to update (true) or assign (false) //! \param[in] phase Index corresponding to the phase diff --git a/include/particles/particle.h b/include/particles/particle.h index 761fdda89..de89bb6cf 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -276,12 +276,12 @@ class Particle : public ParticleBase { //! Return neighbour ids std::vector neighbours() const override { return neighbours_; }; - private: + protected: //! Compute strain rate inline Eigen::Matrix compute_strain_rate( const Eigen::MatrixXd& dn_dx, unsigned phase) noexcept; - private: + protected: //! particle id using ParticleBase::id_; //! coordinates diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 042796ccc..9f29c5e5d 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 { + Mixture = 0, + Solid = 0, + Liquid = 1, + Gas = 2 +}; //! ParticleBase class //! \brief Base class that stores the information about particleBases @@ -253,6 +258,225 @@ class ParticleBase { //! Return neighbour ids virtual std::vector neighbours() const = 0; + // Twophase particle functions------------------------------------------------ + + //! Assign porosity + virtual bool assign_porosity() { + throw std::runtime_error( + "Calling the base class function " + "(assign_porosity) in " + "ParticleBase:: illegal operation!"); + return false; + }; + + //! Assign particle free surface + virtual bool free_surface() { + throw std::runtime_error( + "Calling the base class function " + "(free_surface) in " + "ParticleBase:: illegal operation!"); + return false; + }; + + //! Assign particle pressure constraints + virtual bool assign_particle_pore_pressure_constraint(double pressure) { + throw std::runtime_error( + "Calling the base class function " + "(assign_particle_pore_pressure_constraint) in " + "ParticleBase:: illegal operation!"); + return false; + }; + + //! Initialise liquid phase + virtual void initialise_liquid_phase() { + throw std::runtime_error( + "Calling the base class function (initialise_liquid_phase) in " + "ParticleBase:: illegal operation!"); + }; + + //! Assign material + //! \param[in] material Pointer to a material + virtual bool assign_liquid_material( + const std::shared_ptr>& material) { + throw std::runtime_error( + "Calling the base class function (assign_liquid_material) in " + "ParticleBase:: illegal operation!"); + return false; + }; + + //! Assign pore pressure + //! \param[in] pressure Pore liquid pressure + virtual void assign_pore_pressure(double pressure) { + throw std::runtime_error( + "Calling the base class function (assign_pore_pressure) in " + "ParticleBase:: illegal operation!"); + }; + + //! Assign liquid traction + //! \param[in] direction Index corresponding to the direction of traction + //! \param[in] traction Particle traction in specified direction + //! \retval status Assignment status + virtual bool assign_liquid_traction(unsigned direction, double traction) { + throw std::runtime_error( + "Calling the base class function (assign_liquid_traction) in " + "ParticleBase:: illegal operation!"); + return false; + }; + + //! Return liquid phase traction + virtual VectorDim liquid_traction() const { + auto error = VectorDim::Zero(); + throw std::runtime_error( + "Calling the base class function (liquid_traction) in " + "ParticleBase:: illegal operation!"); + return error; + }; + + //! Return liquid mass + //! \retval liquid mass Liquid phase mass + virtual double liquid_mass() const { + throw std::runtime_error( + "Calling the base class function (liquid_mass) in " + "ParticleBase:: illegal operation!"); + return 0; + }; + + //! Assign velocity to the particle liquid phase + //! \param[in] velocity A vector of particle liquid phase velocity + //! \retval status Assignment status + virtual bool assign_liquid_velocity(const VectorDim& velocity) { + throw std::runtime_error( + "Calling the base class function (assign_liquid_velocity) in " + "ParticleBase:: illegal operation!"); + return false; + }; + + //! Return velocity of the particle liquid phase + //! \retval liquid velocity Liquid phase velocity + virtual VectorDim liquid_velocity() const { + auto error = VectorDim::Zero(); + throw std::runtime_error( + "Calling the base class function (liquid_velocity) in " + "ParticleBase:: illegal operation!"); + return error; + }; + + //! Return strain of the particle liquid phase + //! \retval liquid strain Liquid phase strain + virtual Eigen::Matrix liquid_strain() const { + auto error = Eigen::Matrix::Zero(); + throw std::runtime_error( + "Calling the base class function (liquid_strain) in " + "ParticleBase:: illegal operation!"); + return error; + }; + + //! Assign pore pressure to nodes + virtual void map_pore_pressure_to_nodes() { + throw std::runtime_error( + "Calling the base class function (map_pore_pressure_to_nodes) in " + "ParticleBase:: illegal operation!"); + }; + + //! Compute pore pressure somoothening by interpolating nodal pressure + virtual bool compute_pore_pressure_smoothing() { + throw std::runtime_error( + "Calling the base class function (compute_pore_pressure_smoothing) in " + "ParticleBase:: illegal operation!"); + return false; + }; + + //! Compute pore pressure + //! \param[in] dt Time step size + virtual void compute_pore_pressure(double dt) { + throw std::runtime_error( + "Calling the base class function (compute_pore_pressure) in " + "ParticleBase:: illegal operation!"); + }; + + //! Return pore pressure + //! \retval pore pressure Pore liquid pressure + virtual double pore_pressure() const { + throw std::runtime_error( + "Calling the base class function (pore_pressure) in " + "ParticleBase:: illegal operation!"); + return 0; + }; + + //! Return free surface status + //! \retval free surface Free surface status + virtual bool free_surface() const { + throw std::runtime_error( + "Calling the base class function (free_surface) in " + "ParticleBase:: illegal operation!"); + return 0; + }; + + //! Return excessive pore pressure + //! \retval excessive pore pressure Excessive pore pressure + virtual double excessive_pore_pressure() const { + throw std::runtime_error( + "Calling the base class function (excessive_pore_pressure) in " + "ParticleBase:: illegal operation!"); + return 0; + }; + + //! Update particle permeability + virtual VectorDim update_permeability() { + auto error = VectorDim::Zero(); + throw std::runtime_error( + "Calling the base class function (update_permeability) in " + "ParticleBase:: illegal operation!"); + return error; + }; + + //! Update porosity + virtual bool update_porosity(double dt) { + throw std::runtime_error( + "Calling the base class function (update_porosity) in " + "ParticleBase:: illegal operation!"); + return false; + }; + + //! Map drag force coefficient + virtual bool map_drag_force_coefficient() { + throw std::runtime_error( + "Calling the base class function (map_drag_force_coefficient) in " + "ParticleBase:: illegal operation!"); + return false; + }; + + //! Assign particle liquid phase velocity constraints + virtual bool assign_particle_liquid_velocity_constraint(unsigned dir, + double velocity) { + throw std::runtime_error( + "Calling the base class function " + "(assign_particle_liquid_velocity_constraint) in " + "ParticleBase:: illegal operation!"); + return false; + }; + + //! Apply particle liquid phase velocity constraints + virtual void apply_particle_liquid_velocity_constraints() { + throw std::runtime_error( + "Calling the base class function " + "(apply_particle_liquid_velocity_constraints) in " + "ParticleBase:: illegal operation!"); + }; + + //! Initialise particle pore pressure by watertable + virtual bool initialise_pore_pressure_watertable( + const unsigned dir_v, const unsigned dir_h, + std::map& refernece_points) { + throw std::runtime_error( + "Calling the base class function " + "(initialise_pore_pressure_watertable) in " + "ParticleBase:: illegal operation!"); + return false; + }; + + // --------------------------------------------------------------------------- + protected: //! particleBase id Index id_{std::numeric_limits::max()}; diff --git a/include/particles/twophase_particle.h b/include/particles/twophase_particle.h new file mode 100644 index 000000000..0a5727cbc --- /dev/null +++ b/include/particles/twophase_particle.h @@ -0,0 +1,283 @@ +#ifndef MPM_TWOPHASE_PARTICLE_H_ +#define MPM_TWOPHASE_PARTICLE_H_ + +#include +#include +#include +#include +#include + +#include "logger.h" +#include "particle.h" + +namespace mpm { + +//! TwoPhaseParticle class +//! \brief Class that stores the information about twophase particles +//! Derive from particle +//! \tparam Tdim Dimension +template +class TwoPhaseParticle : public mpm::Particle { + public: + //! Define a vector of size dimension + using VectorDim = Eigen::Matrix; + + //! Construct a twophase particle with id and coordinates + //! \param[in] id Particle id + //! \param[in] coord Coordinates of the particles + TwoPhaseParticle(Index id, const VectorDim& coord); + + //! Construct a twophase particle with id, coordinates and status + //! \param[in] id Particle id + //! \param[in] coord coordinates of the particle + //! \param[in] status Particle status (active / inactive) + TwoPhaseParticle(Index id, const VectorDim& coord, bool status); + + //! Destructor + ~TwoPhaseParticle() override{}; + + //! Delete copy constructor + TwoPhaseParticle(const TwoPhaseParticle&) = delete; + + //! Delete assignment operator + TwoPhaseParticle& operator=(const TwoPhaseParticle&) = delete; + + //! Initialise particle from HDF5 data + //! \param[in] particle HDF5 data of particle + //! \retval status Status of reading HDF5 particle + bool initialise_particle(const HDF5Particle& particle) override; + + //! Initialise particle HDF5 data and material + //! \param[in] particle HDF5 data of particle + //! \param[in] material Material associated with the particle + //! \retval status Status of reading HDF5 particle + bool initialise_particle( + const HDF5Particle& particle, + const std::shared_ptr>& material) override; + + //! Initialise liquid phase + void initialise_liquid_phase() override; + + //! Retrun particle data as HDF5 + //! \retval particle HDF5 data of the particle + HDF5Particle hdf5() const override; + + //! Assign material + //! \param[in] material Pointer to a material + bool assign_liquid_material( + const std::shared_ptr>& material) override; + + //! Assign porosity + bool assign_porosity() override; + + //! Assign pore pressure + //! \param[in] pressure Pore liquid pressure + void assign_pore_pressure(double pressure) override { + this->pore_pressure_ = pressure; + } + + //! Assign liquid traction + //! \param[in] direction Index corresponding to the direction of traction + //! \param[in] traction Particle traction in specified direction + //! \retval status Assignment status + bool assign_liquid_traction(unsigned direction, double traction) override; + + //! Return liquid phase traction + VectorDim liquid_traction() const { return liquid_traction_; }; + + //! Compute both solid and liquid mass + void compute_mass() noexcept override; + + //! Map particle mass and momentum to nodes (both solid and liquid) + void map_mass_momentum_to_nodes() noexcept override; + + //! Map body force + //! \param[in] pgravity Gravity of a particle + void map_body_force(const VectorDim& pgravity) noexcept override; + + //! Map internal force + inline void map_internal_force() noexcept override; + + //! Compute updated position of the particle and kinematics of both solid and + //! liquid phase \param[in] dt Analysis time step \param[in] velocity_update + //! Update particle velocity from nodal vel when true + void compute_updated_position(double dt, + bool velocity_update = false) noexcept override; + + //! Assign velocity to the particle liquid phase + //! \param[in] velocity A vector of particle liquid phase velocity + //! \retval status Assignment status + bool assign_liquid_velocity(const VectorDim& velocity) override; + + //! Return velocity of the particle liquid phase + //! \retval liquid velocity Liquid phase velocity + VectorDim liquid_velocity() const override { return liquid_velocity_; } + + //! Return liquid strain of the particle + Eigen::Matrix liquid_strain() const override { + return liquid_strain_; + } + + //! Return liquid mass + //! \retval liquid mass Liquid phase mass + double liquid_mass() const override { return liquid_mass_; } + + //! Assign pore pressure to nodes + void map_pore_pressure_to_nodes() noexcept override; + + //! Compute pore pressure somoothening by interpolating nodal pressure + bool compute_pore_pressure_smoothing() noexcept override; + + //! Compute pore pressure + //! \param[in] dt Time step size + void compute_pore_pressure(double dt) noexcept override; + + //! Return pore pressure + //! \retval pore_pressure Pore pressure + double pore_pressure() const override { return pore_pressure_; } + + //! Return excessive pore pressure + //! \retval excessive pore pressure Excessive pore pressure + double excessive_pore_pressure() const override { + return excessive_pore_pressure_; + } + + //! Return free surface status + //! \retval free surface Free surface status + bool free_surface() const override { return free_surface_; } + + //! Map drag force coefficient + bool map_drag_force_coefficient() override; + + //! Update particle permeability + //! \retval status Update status + VectorDim update_permeability() override; + + //! Update porosity + //! \param[in] dt Analysis time step + bool update_porosity(double dt) override; + + //! Assign particle liquid phase velocity constraints + //! Directions can take values between 0 and Dim + //! \param[in] dir Direction of particle velocity constraint + //! \param[in] velocity Applied particle liquid phase velocity constraint + //! \retval status Assignment status + bool assign_particle_liquid_velocity_constraint(unsigned dir, + double velocity) override; + + //! Apply particle liquid phase velocity constraints + void apply_particle_liquid_velocity_constraints() override; + + //! Assign particle pressure constraints + //! \retval status Assignment status + bool assign_particle_pore_pressure_constraint(double pressure) override; + + //! Assign particles initial pore pressure by watertable + bool initialise_pore_pressure_watertable( + const unsigned dir_v, const unsigned dir_h, + std::map& refernece_points); + + private: + //! Assign particle permeability + //! \retval status Assignment status + virtual bool assign_permeability(); + + //! Compute liquid mass + virtual void compute_liquid_mass() noexcept; + + //! Assign liquid mass and momentum to nodes + virtual void map_liquid_mass_momentum_to_nodes() noexcept; + + //! Map two phase mixture body force + //! \param[in] mixture Identification for Mixture + //! \param[in] pgravity Gravity of the particle + virtual void map_mixture_body_force(unsigned mixture, + const VectorDim& pgravity) noexcept; + + //! Map liquid body force + //! \param[in] pgravity Gravity of a particle + virtual void map_liquid_body_force(const VectorDim& pgravity) noexcept; + + //! Map liquid phase traction force + virtual void map_liquid_traction_force() noexcept; + + //! Map liquid internal force + virtual void map_liquid_internal_force() noexcept; + + //! Map two phase mixture internal force + //! \param[in] mixture Identification for Mixture + virtual void map_mixture_internal_force(unsigned mixture) noexcept; + + //! Compute updated velocity of the particle based on nodal velocity + //! \param[in] dt Analysis time step + //! \retval status Compute status + virtual void compute_updated_liquid_velocity(double dt, + bool velocity_update) noexcept; + + protected: + //! coordinates + using ParticleBase::coordinates_; + //! Cell + using ParticleBase::cell_; + //! Nodes + using ParticleBase::nodes_; + //! Shape functions + using Particle::shapefn_; + //! Effective stress of soil skeleton + using Particle::stress_; + //! Soil skeleton strain rate + using Particle::strain_rate_; + //! Soil skeleton material + using Particle::material_; + //! Particle total volume + using Particle::volume_; + //! Particle mass density + using Particle::mass_density_; + //! dN/dX + using Particle::dn_dx_; + //! dN/dX at cell centroid + using Particle::dn_dx_centroid_; + //! Solid mass + using Particle::mass_; + //! Set traction + using Particle::set_traction_; + //! Material + std::shared_ptr> liquid_material_; + //! Liquid material id + unsigned liquid_material_id_{std::numeric_limits::max()}; + //! Liquid mass density (bulk density = liquid mass / total volume) + double liquid_mass_density_{0.}; + //! Liquid mass + double liquid_mass_{0.}; + //! Porosity + double porosity_{0.}; + //! Permeability c1 (k = k_p * c1_) + Eigen::Matrix permeability_c1_; + //! Liquid velocity + Eigen::Matrix liquid_velocity_; + //! Particle liquid phase velocity constraints + std::map liquid_velocity_constraints_; + //! Pore pressure + double pore_pressure_{0.}; + //! Excessive pore pressure + double excessive_pore_pressure_{0.}; + //! Free surface + bool free_surface_{false}; + //! Pore pressure constraint + double pore_pressure_constraint_{std::numeric_limits::max()}; + //! Set liquid phase traction + bool set_liquid_traction_{false}; + //! Traction for liquid phase + Eigen::Matrix liquid_traction_; + //! Liquid strain rate + Eigen::Matrix liquid_strain_rate_; + //! Liquid strain rate + Eigen::Matrix liquid_strain_; + //! Logger + std::unique_ptr console_; +}; // TwoPhaseParticle class +} // namespace mpm + +#include "twophase_particle.tcc" + +#endif // MPM_TWOPHASE_PARTICLE_H__ diff --git a/include/particles/twophase_particle.tcc b/include/particles/twophase_particle.tcc new file mode 100644 index 000000000..eb774d291 --- /dev/null +++ b/include/particles/twophase_particle.tcc @@ -0,0 +1,777 @@ +//! Construct a twophase particle with id and coordinates +template +mpm::TwoPhaseParticle::TwoPhaseParticle(Index id, const VectorDim& coord) + : mpm::Particle(id, coord) { + // Initialise variables for solid phase + mpm::Particle::initialise(); + // Initialise variables for liquid phase + this->initialise_liquid_phase(); + // Clear cell ptr + cell_ = nullptr; + // Nodes + nodes_.clear(); + // Set material pointer to null + material_ = nullptr; + liquid_material_ = nullptr; + // Logger + std::string logger = + "twophaseparticle" + std::to_string(Tdim) + "d::" + std::to_string(id); + console_ = std::make_unique(logger, mpm::stdout_sink); +} + +//! Construct a twophase particle with id, coordinates and status +template +mpm::TwoPhaseParticle::TwoPhaseParticle(Index id, const VectorDim& coord, + bool status) + : mpm::Particle(id, coord, status) { + // Initialise variables for solid phase + mpm::Particle::initialise(); + // Initialise variables for liquid phase + this->initialise_liquid_phase(); + // Clear cell ptr + cell_ = nullptr; + // Nodes + nodes_.clear(); + // Set material pointer to null + material_ = nullptr; + liquid_material_ = nullptr; + // Logger + std::string logger = + "twophaseparticle" + std::to_string(Tdim) + "d::" + std::to_string(id); + console_ = std::make_unique(logger, mpm::stdout_sink); +} + +//! Initialise particle data from HDF5 +template +bool mpm::TwoPhaseParticle::initialise_particle( + const HDF5Particle& particle) { + // Derive from particle + mpm::Particle::initialise_particle(particle); + + // TODO:HDF5 + // // Liquid mass + // this->liquid_mass_ = particle.liquid_mass; + // // Liquid mass Density + // this->liquid_mass_density_ = particle.mass / particle.volume; + // // Pore pressure + // this->pore_pressure_ = particle.pore_pressure; + // // Liquid velocity + // Eigen::Vector3d liquid_velocity; + // liquid_velocity << particle.liquid_velocity_x, particle.liquid_velocity_y, + // particle.liquid_velocity_z; + // // Initialise velocity + // for (unsigned i = 0; i < Tdim; ++i) + // this->liquid_velocity_(i) = liquid_velocity(i); + // // Liquid strain + // this->liquid_strain_[0] = particle.liquid_strain_xx; + // this->liquid_strain_[1] = particle.liquid_strain_yy; + // this->liquid_strain_[2] = particle.liquid_strain_zz; + // this->liquid_strain_[3] = particle.liquid_gamma_xy; + // this->liquid_strain_[4] = particle.liquid_gamma_yz; + // this->liquid_strain_[5] = particle.liquid_gamma_xz; + // // Liquid material id + // this->liquid_material_id_ = particle.liquid_material_id; + + return true; +} + +//! Initialise particle data from HDF5 +template +bool mpm::TwoPhaseParticle::initialise_particle( + const HDF5Particle& particle, + const std::shared_ptr>& material) { + bool status = this->initialise_particle(particle); + if (material != nullptr) { + if (this->material_id_ == material->id() || + this->material_id_ == std::numeric_limits::max()) { + material_ = material; + // Reinitialize state variables + auto mat_state_vars = material_->initialise_state_variables(); + if (mat_state_vars.size() == particle.nstate_vars) { + unsigned i = 0; + auto state_variables = material_->state_variables(); + for (const auto& state_var : state_variables) { + this->state_variables_.at(state_var) = particle.svars[i]; + ++i; + } + } + } else { + status = false; + throw std::runtime_error("Material is invalid to assign to particle!"); + } + } + return status; +} + +//! Return particle data in HDF5 format +template +// cppcheck-suppress * +mpm::HDF5Particle mpm::TwoPhaseParticle::hdf5() const { + // Derive from particle + auto particle_data = mpm::Particle::hdf5(); + // TODO:HDF5 + // // Particle liquid velocity + // Eigen::Vector3d liquid_velocity; + // liquid_velocity.setZero(); + // for (unsigned j = 0; j < Tdim; ++j) + // liquid_velocity[j] = this->liquid_velocity_[j]; + // // Particle liquid strain + // Eigen::Matrix liquid_strain = this->liquid_strain_; + // // Particle liquid mass + // particle_data.liquid_mass = this->liquid_mass_; + // // Particle pore pressure + // particle_data.pore_pressure = this->pore_pressure_; + // // Particle liquid velocity + // particle_data.liquid_velocity_x = liquid_velocity[0]; + // particle_data.liquid_velocity_y = liquid_velocity[1]; + // particle_data.liquid_velocity_z = liquid_velocity[2]; + // // Particle liquid strain + // particle_data.liquid_strain_xx = liquid_strain[0]; + // particle_data.liquid_strain_yy = liquid_strain[1]; + // particle_data.liquid_strain_zz = liquid_strain[2]; + // particle_data.liquid_gamma_xy = liquid_strain[3]; + // particle_data.liquid_gamma_yz = liquid_strain[4]; + // particle_data.liquid_gamma_xz = liquid_strain[5]; + // // Particle liquid material id + // particle_data.liquid_material_id = this->liquid_material_id_; + + return particle_data; +} + +// Initialise liquid phase particle properties +template +void mpm::TwoPhaseParticle::initialise_liquid_phase() { + liquid_mass_ = 0.; + pore_pressure_ = 0.; + porosity_ = 0.; + liquid_velocity_.setZero(); + liquid_strain_rate_.setZero(); + liquid_strain_.setZero(); + liquid_traction_.setZero(); + permeability_c1_.setZero(); + set_liquid_traction_ = false; + + // Initialize vector data properties + this->properties_["liquid_strains"] = [&]() { return liquid_strain(); }; + this->properties_["liquid_velocities"] = [&]() { return liquid_velocity(); }; + this->properties_["pore_pressure"] = [&]() { + Eigen::VectorXd pore_pressure = Eigen::VectorXd::Zero(3); + // Total pore pressure + pore_pressure[0] = this->pore_pressure(); + // Excessive pore pressure + pore_pressure[1] = this->excessive_pore_pressure(); + // Free surface + pore_pressure[2] = this->free_surface(); + + return pore_pressure; + }; +} + +// Assign a liquid material to particle +template +bool mpm::TwoPhaseParticle::assign_liquid_material( + const std::shared_ptr>& material) { + bool status = false; + try { + // Check if material is valid and properties are set + if (material != nullptr) { + liquid_material_ = material; + liquid_material_id_ = liquid_material_->id(); + status = true; + } else { + throw std::runtime_error("Liquid material is undefined!"); + } + + // Assign porosity + this->assign_porosity(); + // Assign permeability + this->assign_permeability(); + + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + } + return status; +} + +//! Assign particle permeability +template +bool mpm::TwoPhaseParticle::assign_permeability() { + bool status = true; + try { + // Check if material ptr is valid + if (material_ != nullptr) { + // Porosity parameter k_p + const double k_p = + std::pow(this->porosity_, 3) / std::pow((1. - this->porosity_), 2); + // Different dimensions permeability + switch (Tdim) { + case (1): { + permeability_c1_(0) = + material_->template property("k_x") / k_p; + break; + } + case (2): { + permeability_c1_(0) = + material_->template property("k_x") / k_p; + permeability_c1_(1) = + material_->template property("k_y") / k_p; + break; + } + default: { + permeability_c1_(0) = + material_->template property("k_x") / k_p; + permeability_c1_(1) = + material_->template property("k_y") / k_p; + permeability_c1_(2) = + material_->template property("k_z") / k_p; + break; + } + } + } else { + throw std::runtime_error( + "Material is invalid, could not assign permeability"); + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +// Assign particle porosity +template +bool mpm::TwoPhaseParticle::assign_porosity() { + bool status = true; + try { + // Check if material ptr is valid + if (material_ != nullptr) { + porosity_ = material_->template property(std::string("porosity")); + // Check if the porosity value is valid + if (porosity_ < 0. || porosity_ > 1.) + throw std::runtime_error( + "Particle porosity is negative or larger than one"); + } else { + throw std::runtime_error( + "Material is invalid, could not assign porosity"); + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +// Assign velocity to the particle liquid phase +template +bool mpm::TwoPhaseParticle::assign_liquid_velocity( + const Eigen::Matrix& velocity) { + bool status = false; + try { + // Assign velocity + liquid_velocity_ = velocity; + status = true; + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +// Assign traction to the liquid phase +template +bool mpm::TwoPhaseParticle::assign_liquid_traction(unsigned direction, + double traction) { + bool status = false; + try { + if (direction >= Tdim || + this->volume_ == std::numeric_limits::max()) { + throw std::runtime_error( + "Particle liquid traction property: volume / direction is invalid"); + } + // Assign liquid traction + liquid_traction_(direction) = + traction * this->volume_ / this->size_(direction); + status = true; + this->set_liquid_traction_ = true; + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +// Compute mass of particle (both solid and liquid) +template +void mpm::TwoPhaseParticle::compute_mass() noexcept { + // Compute mass of particle (solid phase) + mpm::Particle::compute_mass(); + // Compute mass of particle (liquid phase) + this->compute_liquid_mass(); +} + +// Compute liquid mass of particle +template +void mpm::TwoPhaseParticle::compute_liquid_mass() noexcept { + // Check if particle volume is set and liquid material ptr is valid + assert(volume_ != std::numeric_limits::max() && + liquid_material_ != nullptr); + + // Mass = volume of particle * bulk_density + this->liquid_mass_density_ = + porosity_ * + liquid_material_->template property(std::string("density")); + this->liquid_mass_ = volume_ * liquid_mass_density_; +} + +//! Map particle mass and momentum to nodes +template +void mpm::TwoPhaseParticle::map_mass_momentum_to_nodes() noexcept { + // Map particle mass and momentum to nodes (solid phase) + mpm::Particle::map_mass_momentum_to_nodes(); + // Map particle mass and momentum to nodes (liquid phase) + this->map_liquid_mass_momentum_to_nodes(); +} + +//! Map liquid mass and momentum to nodes +template +void mpm::TwoPhaseParticle::map_liquid_mass_momentum_to_nodes() noexcept { + // Check if liquid mass is set and positive + assert(liquid_mass_ != std::numeric_limits::max()); + + // Map liquid mass and momentum to nodes + for (unsigned i = 0; i < nodes_.size(); ++i) { + nodes_[i]->update_mass(true, mpm::ParticlePhase::Liquid, + liquid_mass_ * shapefn_[i]); + nodes_[i]->update_momentum(true, mpm::ParticlePhase::Liquid, + liquid_mass_ * shapefn_[i] * liquid_velocity_); + } +} + +//! Compute pore pressure (compressible fluid) +template +void mpm::TwoPhaseParticle::compute_pore_pressure(double dt) noexcept { + // Check if liquid material and cell pointer are set and positive + assert(liquid_material_ != nullptr && cell_ != nullptr); + // Apply free surface + if (this->free_surface()) this->pore_pressure_ = 0.0; + // Compute pore pressure + else { + // get the bulk modulus of liquid + double K = liquid_material_->template property( + std::string("bulk_modulus")); + // Compute strain rate of liquid phase at centroid + auto liquid_strain_rate_centroid = mpm::Particle::compute_strain_rate( + dn_dx_centroid_, mpm::ParticlePhase::Liquid); + // update pressure + this->pore_pressure_ += + -dt * (K / porosity_) * + ((1 - porosity_) * strain_rate_.head(Tdim).sum() + + porosity_ * liquid_strain_rate_centroid.head(Tdim).sum()); + } +} + +//! Map particle pore liquid pressure to nodes +template +void mpm::TwoPhaseParticle::map_pore_pressure_to_nodes() noexcept { + // Check if particle mass is set + assert(liquid_mass_ != std::numeric_limits::max()); + // Map particle liquid mass and pore pressure to nodes + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->update_mass_pressure( + mpm::ParticlePhase::Liquid, + shapefn_[i] * liquid_mass_ * pore_pressure_); +} + +// Compute pore liquid pressure smoothing based on nodal pressure +template +bool mpm::TwoPhaseParticle::compute_pore_pressure_smoothing() noexcept { + // Check if particle has a valid cell ptr + assert(cell_ != nullptr); + + bool status = false; + // Check if particle has a valid cell ptr + if (cell_ != nullptr) { + // Apply free surface + if (this->free_surface()) this->pore_pressure_ = 0.0; + // Compute particle pore pressure from nodal values + else { + double pore_pressure = 0; + for (unsigned i = 0; i < nodes_.size(); ++i) + pore_pressure += + shapefn_(i) * nodes_[i]->pressure(mpm::ParticlePhase::Liquid); + // Update pore liquid pressure to interpolated nodal pressure + this->pore_pressure_ = pore_pressure; + } + } + return status; +} + +//! Map body force for both mixture and liquid +template +void mpm::TwoPhaseParticle::map_body_force( + const VectorDim& pgravity) noexcept { + //! Map body force for mixture + this->map_mixture_body_force(mpm::ParticlePhase::Mixture, pgravity); + //! Map body force for liquid + this->map_liquid_body_force(pgravity); +} + +//! Map liquid phase body force +template +void mpm::TwoPhaseParticle::map_liquid_body_force( + const VectorDim& pgravity) noexcept { + // Compute nodal liquid body forces + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->update_external_force( + true, mpm::ParticlePhase::Liquid, + (pgravity * this->liquid_mass_ * shapefn_(i))); +} + +//! Map mixture body force +template +void mpm::TwoPhaseParticle::map_mixture_body_force( + unsigned mixture, const VectorDim& pgravity) noexcept { + // Compute nodal mixture body forces + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->update_external_force( + true, mixture, + (pgravity * (this->liquid_mass_ + this->mass_) * shapefn_(i))); +} + +//! Map liquid traction force +template +void mpm::TwoPhaseParticle::map_liquid_traction_force() noexcept { + if (this->set_liquid_traction_) { + // Map particle liquid traction forces to nodes + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->update_external_force( + true, mpm::ParticlePhase::Liquid, + (-1. * shapefn_[i] * porosity_ * this->liquid_traction_)); + } +} + +//! Map both mixture and liquid internal force +template +inline void mpm::TwoPhaseParticle::map_internal_force() noexcept { + //! Map mixture internal force + mpm::TwoPhaseParticle::map_mixture_internal_force( + mpm::ParticlePhase::Mixture); + //! Map liquid internal force + mpm::TwoPhaseParticle::map_liquid_internal_force(); +} + +//! Map liquid phase internal force +template <> +void mpm::TwoPhaseParticle<2>::map_liquid_internal_force() noexcept { + // initialise a vector of pore pressure + Eigen::Matrix pressure; + pressure.setZero(); + pressure(0) = -this->pore_pressure_; + pressure(1) = -this->pore_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) * pressure[0] * this->porosity_; + force[1] = dn_dx_(i, 1) * pressure[1] * this->porosity_; + + force *= -1. * this->volume_; + + nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Liquid, force); + } +} + +template <> +void mpm::TwoPhaseParticle<3>::map_liquid_internal_force() noexcept { + // initialise a vector of pore pressure + Eigen::Matrix pressure; + pressure.setZero(); + pressure(0) = -this->pore_pressure_; + pressure(1) = -this->pore_pressure_; + pressure(2) = -this->pore_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) * pressure[0] * this->porosity_; + force[1] = dn_dx_(i, 1) * pressure[1] * this->porosity_; + force[2] = dn_dx_(i, 2) * pressure[2] * this->porosity_; + + force *= -1. * this->volume_; + + nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Liquid, force); + } +} + +//! Map mixture internal force +template <> +void mpm::TwoPhaseParticle<2>::map_mixture_internal_force( + unsigned mixture) noexcept { + // initialise a vector of pore pressure + Eigen::Matrix total_stress = this->stress_; + total_stress(0) -= this->pore_pressure_; + total_stress(1) -= this->pore_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, mixture, force); + } +} + +template <> +void mpm::TwoPhaseParticle<3>::map_mixture_internal_force( + unsigned mixture) noexcept { + // initialise a vector of pore pressure + Eigen::Matrix total_stress = this->stress_; + total_stress(0) -= this->pore_pressure_; + total_stress(1) -= this->pore_pressure_; + total_stress(2) -= this->pore_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, mixture, force); + } +} + +//! Map drag force coefficient +template +bool mpm::TwoPhaseParticle::map_drag_force_coefficient() { + bool status = true; + try { + // Update permeability + auto 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) { + drag_force_coefficient(i) = + porosity_ * porosity_ * 9.81 * + liquid_material_->template property(std::string("density")) / + permeability(i); + } + + // 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; +} + +//! Update particle permeability +template +Eigen::Matrix + mpm::TwoPhaseParticle::update_permeability() { + // Initialise permeability + Eigen::Matrix permeability; + permeability.setZero(); + 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 * permeability_c1_; + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + } + return permeability; +} + +// Update particle porosity +template +bool mpm::TwoPhaseParticle::update_porosity(double dt) { + bool status = true; + try { + // Update particle porosity + this->porosity_ = + 1 - (1 - this->porosity_) / (1 + dt * strain_rate_.head(Tdim).sum()); + // Check if the value is valid + if (this->porosity_ < 0) this->porosity_ = 1E-5; + if (this->porosity_ < 1) this->porosity_ = 1 - 1E-5; + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +// Compute updated position and velocities +template +void mpm::TwoPhaseParticle::compute_updated_position( + double dt, bool velocity_update) noexcept { + // Compute updated position + mpm::Particle::compute_updated_position(dt, velocity_update); + // Compute updated liquid velocities + this->compute_updated_liquid_velocity(dt, velocity_update); +} + +// Compute updated velocity of the liquid phase based on nodal velocity +template +void mpm::TwoPhaseParticle::compute_updated_liquid_velocity( + double dt, bool velocity_update) noexcept { + // Check if particle has a valid cell ptr + assert(cell_ != nullptr); + + if (!velocity_update) { + // Get interpolated nodal acceleration + Eigen::Matrix acceleration; + acceleration.setZero(); + + for (unsigned i = 0; i < nodes_.size(); ++i) + acceleration += + shapefn_(i) * nodes_[i]->acceleration(mpm::ParticlePhase::Liquid); + + // Update particle velocity from interpolated nodal acceleration + this->liquid_velocity_ += acceleration * dt; + } else { + // Get interpolated nodal velocity + Eigen::Matrix velocity; + velocity.setZero(); + + for (unsigned i = 0; i < nodes_.size(); ++i) + velocity += shapefn_(i) * nodes_[i]->velocity(mpm::ParticlePhase::Liquid); + + // Update particle velocity to interpolated nodal velocity + this->liquid_velocity_ = velocity; + } + + // Apply particle velocity constraints + this->apply_particle_liquid_velocity_constraints(); +} + +//! Assign particle liquid phase velocity constraint +//! Constrain directions can take values between 0 and Dim +template +bool mpm::TwoPhaseParticle::assign_particle_liquid_velocity_constraint( + unsigned dir, double velocity) { + bool status = true; + try { + //! Constrain directions can take values between 0 and Dim + if (dir < Tdim) + this->liquid_velocity_constraints_.insert( + std::make_pair(static_cast(dir), + static_cast(velocity))); + else + throw std::runtime_error( + "Particle liquid velocity constraint direction is out of bounds"); + + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +//! Apply particle velocity constraints +template +void mpm::TwoPhaseParticle::apply_particle_liquid_velocity_constraints() { + // Set particle velocity constraint + for (const auto& constraint : this->liquid_velocity_constraints_) { + // Direction value in the constraint (0, Dim) + const unsigned dir = constraint.first; + // Direction: dir % Tdim (modulus) + const auto direction = static_cast(dir % Tdim); + this->liquid_velocity_(direction) = constraint.second; + } +} + +//! Assign particle pressure constraints +template +bool mpm::TwoPhaseParticle::assign_particle_pore_pressure_constraint( + double pressure) { + bool status = true; + try { + this->pore_pressure_constraint_ = pressure; + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +//! Initial pore pressure by water table +template +bool mpm::TwoPhaseParticle::initialise_pore_pressure_watertable( + const unsigned dir_v, const unsigned dir_h, + std::map& refernece_points) { + bool status = true; + try { + // Initialise left boundary position (coordinate) and h0 + double left_boundary = std::numeric_limits::lowest(); + double h0_left = 0.; + // Initialise right boundary position (coordinate) and h0 + double right_boundary = std::numeric_limits::max(); + double h0_right = 0.; + // Position and h0 of particle (coordinate) + const double position = this->coordinates_(dir_h); + // Iterate over each refernece_points + for (const auto& refernece_point : refernece_points) { + // Find boundary + if (refernece_point.first > left_boundary && + refernece_point.first <= position) { + // Left boundary position and h0 + left_boundary = refernece_point.first; + h0_left = refernece_point.second; + } else if (refernece_point.first > position && + refernece_point.first <= right_boundary) { + // Right boundary position and h0 + right_boundary = refernece_point.first; + h0_right = refernece_point.second; + } + } + // Check if the boundaries are assigned + if (left_boundary != std::numeric_limits::lowest()) { + // Particle with left and right boundary + if (right_boundary != std::numeric_limits::max()) { + this->pore_pressure_ = + ((h0_right - h0_left) / (right_boundary - left_boundary) * + (position - left_boundary) + + h0_left - this->coordinates_(dir_v)) * + 1000 * 9.81; + } else + // Particle with only left boundary + this->pore_pressure_ = + (h0_left - this->coordinates_(dir_v)) * 1000 * 9.81; + } + // Particle with only right boundary + else if (right_boundary != std::numeric_limits::max()) + this->pore_pressure_ = + (h0_right - this->coordinates_(dir_v)) * 1000 * 9.81; + + else + throw std::runtime_error( + "Particle pore pressure can not be initialised by water table"); + } 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/node.cc b/src/node.cc index 8c7ce2748..fda6589bc 100644 --- a/src/node.cc +++ b/src/node.cc @@ -11,3 +11,13 @@ static Register, mpm::Node<2, 2, 1>, mpm::Index, static Register, mpm::Node<3, 3, 1>, mpm::Index, const Eigen::Matrix&> node3d("N3D"); + +// Node2D (2 DoF, 2 Phase) +static Register, mpm::Node<2, 2, 2>, mpm::Index, + const Eigen::Matrix&> + node2d2phase("N2D2PHASE"); + +// Node3D (3 DoF, 2 Phase) +static Register, mpm::Node<3, 3, 2>, mpm::Index, + const Eigen::Matrix&> + node3d2phase("N3D2PHASE"); \ No newline at end of file diff --git a/src/particle.cc b/src/particle.cc index 7488c8023..7770a8750 100644 --- a/src/particle.cc +++ b/src/particle.cc @@ -1,6 +1,7 @@ #include "particle.h" #include "factory.h" #include "particle_base.h" +#include "twophase_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"); + +// Two phase particle2D (2 Dim) +static Register, mpm::TwoPhaseParticle<2>, mpm::Index, + const Eigen::Matrix&> + particle2d2phase("P2D2PHASE"); + +// Two phase particle3D (3 Dim) +static Register, mpm::TwoPhaseParticle<3>, mpm::Index, + const Eigen::Matrix&> + particle3d2phase("P3D2PHASE"); \ No newline at end of file From f3f6fb29e812f4ed26f9ac51774371a3ac9492d1 Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Mon, 29 Jun 2020 12:43:10 -0500 Subject: [PATCH 002/175] :computer: Refactor particle to handle scalar and vector properties --- include/node.h | 34 ++++++++++++ include/node.tcc | 48 +++++++++++++++++ include/node_base.h | 30 +++++++++++ include/particles/particle.h | 9 ++-- include/particles/particle.tcc | 3 ++ include/particles/particle_base.h | 55 ++++++++++++++++++++ include/particles/particle_base.tcc | 81 +++++++++++++++++++++++++++++ 7 files changed, 257 insertions(+), 3 deletions(-) diff --git a/include/node.h b/include/node.h index c1e17e531..019f663d1 100644 --- a/include/node.h +++ b/include/node.h @@ -65,6 +65,33 @@ class Node : public NodeBase { //! Return status bool status() const override { return status_; } + //! Update scalar property at the nodes + //! \param[in] property Name of the property to update + //! \param[in] update A boolean to update (true) or assign (false) + //! \param[in] phase Index corresponding to the phase + //! \param[in] value Property value from the particles in a cell + void update_scalar_property(mpm::properties::Scalar property, bool update, + unsigned phase, double value) noexcept override; + + //! Return property at a given node for a given phase + //! \param[in] phase Index corresponding to the phase + double scalar_property(mpm::properties::Scalar property, + unsigned phase) const override; + + //! Update vector property at the nodes + //! \param[in] property Name of the property to update + //! \param[in] update A boolean to update (true) or assign (false) + //! \param[in] phase Index corresponding to the phase + //! \param[in] value Property value from the particles in a cell + virtual void update_vector_property( + mpm::properties::Vector property, bool update, unsigned phase, + const Eigen::Matrix& value) noexcept override; + + //! Return property at a given node for a given phase + //! \param[in] phase Index corresponding to the phase + virtual Eigen::Matrix vector_property( + mpm::properties::Vector property, unsigned phase) const override; + //! Update mass at the nodes from particle //! \param[in] update A boolean to update (true) or assign (false) //! \param[in] phase Index corresponding to the phase @@ -275,6 +302,13 @@ class Node : public NodeBase { unsigned dof_{std::numeric_limits::max()}; //! Status bool status_{false}; + //! Scalar properties + tsl::ordered_map> + scalar_properties_; + //! Vector properties + tsl::ordered_map> + vector_properties_; //! Mass Eigen::Matrix mass_; //! Volume diff --git a/include/node.tcc b/include/node.tcc index 8c4d4b542..e4ab6700e 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -17,6 +17,10 @@ mpm::Node::Node( // Clear any velocity constraints velocity_constraints_.clear(); concentrated_force_.setZero(); + scalar_properties_.emplace( + std::make_pair(mpm::properties::Scalar::Mass, + Eigen::Matrix::Zero())); + this->initialise(); } @@ -34,6 +38,7 @@ void mpm::Node::initialise() noexcept { acceleration_.setZero(); status_ = false; material_ids_.clear(); + scalar_properties_.at(mpm::properties::Scalar::Mass).setZero(); } //! Initialise shared pointer to nodal properties pool @@ -46,6 +51,49 @@ void mpm::Node::initialise_property_handle( this->prop_id_ = prop_id; } +//! Update scalar property at the nodes from particle +template +void mpm::Node::update_scalar_property( + mpm::properties::Scalar property, bool update, unsigned phase, + double value) noexcept { + // Decide to update or assign + const double factor = (update == true) ? 1. : 0.; + + // Update/assign mass + std::lock_guard guard(node_mutex_); + scalar_properties_.at(property)[phase] = + (scalar_properties_.at(property)[phase] * factor) + value; +} + +//! Update scalar property at the nodes from particle +template +double mpm::Node::scalar_property( + mpm::properties::Scalar property, unsigned phase) const { + return scalar_properties_.at(property)[phase]; +} + +//! Update vector property at the nodes from particle +template +void mpm::Node::update_vector_property( + mpm::properties::Vector property, bool update, unsigned phase, + const Eigen::Matrix& value) noexcept { + // Decide to update or assign + const double factor = (update == true) ? 1. : 0.; + + // Update/assign mass + std::lock_guard guard(node_mutex_); + Eigen::Matrix vecvalue = + vector_properties_.at(property).col(phase); + vector_properties_.at(property).col(phase) = (vecvalue * factor) + value; +} + +//! Update vector property at the nodes from particle +template +Eigen::Matrix mpm::Node::vector_property( + mpm::properties::Vector property, unsigned phase) const { + return vector_properties_.at(property).col(phase); +} + //! Update mass at the nodes from particle template void mpm::Node::update_mass(bool update, unsigned phase, diff --git a/include/node_base.h b/include/node_base.h index 81dfc62f4..636234703 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -10,9 +10,11 @@ #include #include +#include #include "data_types.h" #include "function_base.h" +#include "mpm_properties.h" #include "nodal_properties.h" namespace mpm { @@ -70,6 +72,34 @@ class NodeBase { //! Return status virtual bool status() const = 0; + //! Update scalar property at the nodes + //! \param[in] property Name of the property to update + //! \param[in] update A boolean to update (true) or assign (false) + //! \param[in] phase Index corresponding to the phase + //! \param[in] value Property value from the particles in a cell + virtual void update_scalar_property(mpm::properties::Scalar property, + bool update, unsigned phase, + double value) noexcept = 0; + + //! Return property at a given node for a given phase + //! \param[in] phase Index corresponding to the phase + virtual double scalar_property(mpm::properties::Scalar property, + unsigned phase) const = 0; + + //! Update vector property at the nodes + //! \param[in] property Name of the property to update + //! \param[in] update A boolean to update (true) or assign (false) + //! \param[in] phase Index corresponding to the phase + //! \param[in] value Property value from the particles in a cell + virtual void update_vector_property( + mpm::properties::Vector property, bool update, unsigned phase, + const Eigen::Matrix& value) noexcept = 0; + + //! Return property at a given node for a given phase + //! \param[in] phase Index corresponding to the phase + virtual Eigen::Matrix vector_property( + mpm::properties::Vector property, unsigned phase) const = 0; + //! Update mass at the nodes from particle //! \param[in] update A boolean to update (true) or assign (false) //! \param[in] phase Index corresponding to the phase diff --git a/include/particles/particle.h b/include/particles/particle.h index 4d7a4b918..542764001 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -131,7 +131,6 @@ class Particle : public ParticleBase { //! Update volume based on centre volumetric strain rate void update_volume() noexcept override; - //! Return mass density //! \param[in] phase Index corresponding to the phase double mass_density() const override { return mass_density_; } @@ -307,6 +306,12 @@ class Particle : public ParticleBase { using ParticleBase::state_variables_; //! Neighbour particles using ParticleBase::neighbours_; + //! Scalar properties + using ParticleBase::scalar_properties_; + //! Vector properties + using ParticleBase::vector_properties_; + //! Shape functions + using ParticleBase::shapefn_; //! Volumetric mass density (mass / volume) double mass_density_{0.}; //! Mass @@ -339,8 +344,6 @@ class Particle : public ParticleBase { bool set_traction_{false}; //! Surface Traction (given as a stress; force/area) Eigen::Matrix traction_; - //! Shape functions - Eigen::VectorXd shapefn_; //! dN/dX Eigen::MatrixXd dn_dx_; //! dN/dX at cell centroid diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index b35f2c1a2..2115d59f4 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -9,6 +9,9 @@ mpm::Particle::Particle(Index id, const VectorDim& coord) nodes_.clear(); // Set material pointer to null material_ = nullptr; + // Scalar properties + scalar_properties_.emplace( + std::make_pair(mpm::properties::Scalar::Mass, double(0.))); // Logger std::string logger = "particle" + std::to_string(Tdim) + "d::" + std::to_string(id); diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index ab60f8fb5..32afefd8b 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -130,6 +130,54 @@ class ParticleBase { //! Update volume based on centre volumetric strain rate virtual void update_volume() noexcept = 0; + //! Update scalar property at the particle + //! \param[in] property Name of the property to update + //! \param[in] update A boolean to update (true) or assign (false) + //! \param[in] value Property value from the particles in a cell + void update_scalar_property(mpm::properties::Scalar property, bool update, + double value) noexcept; + + //! Return property + //! \param[in] phase Index corresponding to the phase + double scalar_property(mpm::properties::Scalar property) const; + + //! Map scalar property to the nodes + //! \param[in] property Name of the property to update + //! \param[in] update A boolean to update (true) or assign (false) + //! \param[in] phase Index corresponding to the phase + void map_scalar_property_nodes(mpm::properties::Scalar property, bool update, + unsigned phase) noexcept; + + //! Return property at a given node for a given phase + //! \param[in] phase Index corresponding to the phase + double interpolate_scalar_property_nodes(mpm::properties::Scalar property, + unsigned phase) const; + + //! Update vector property at the particle + //! \param[in] property Name of the property to update + //! \param[in] update A boolean to update (true) or assign (false) + //! \param[in] value Property value from the particles in a cell + void update_vector_property( + mpm::properties::Vector property, bool update, + const Eigen::Matrix& value) noexcept; + + //! Return property + //! \param[in] phase Index corresponding to the phase + Eigen::Matrix vector_property( + mpm::properties::Vector property) const; + + //! Map vector property to the nodes + //! \param[in] property Name of the property to update + //! \param[in] update A boolean to update (true) or assign (false) + //! \param[in] phase Index corresponding to the phase + void map_vector_property_nodes(mpm::properties::Vector property, bool update, + unsigned phase) noexcept; + + //! Return property at a given node for a given phase + //! \param[in] phase Index corresponding to the phase + double interpolate_vector_property_nodes(mpm::properties::Vector property, + unsigned phase) const; + //! Return mass density virtual double mass_density() const = 0; @@ -279,6 +327,13 @@ class ParticleBase { mpm::dense_map state_variables_; //! Vector of particle neighbour ids std::vector neighbours_; + //! Shape functions + Eigen::VectorXd shapefn_; + //! Scalar properties + tsl::ordered_map scalar_properties_; + //! Vector properties + tsl::ordered_map> + vector_properties_; }; // ParticleBase class } // namespace mpm diff --git a/include/particles/particle_base.tcc b/include/particles/particle_base.tcc index a75e8ca0b..58f52f426 100644 --- a/include/particles/particle_base.tcc +++ b/include/particles/particle_base.tcc @@ -15,3 +15,84 @@ mpm::ParticleBase::ParticleBase(Index id, const VectorDim& coord, : mpm::ParticleBase::ParticleBase(id, coord) { status_ = status; } + +//! Update scalar property at particle +template +void mpm::ParticleBase::update_scalar_property( + mpm::properties::Scalar property, bool update, double value) noexcept { + // Decide to update or assign + const double factor = (update == true) ? 1. : 0.; + scalar_properties_.at(property) = + scalar_properties_.at(property) * factor + value; +} + +//! Update scalar property at particle +template +double mpm::ParticleBase::scalar_property( + mpm::properties::Scalar property) const { + return scalar_properties_.at(property); +} + +//! Map scalar property to nodes +template +void mpm::ParticleBase::map_scalar_property_nodes( + mpm::properties::Scalar property, bool update, unsigned phase) noexcept { + // Check if particle property is set + assert(scalar_properties_.at(property) != std::numeric_limits::max()); + + // Map scalar property to nodes + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->update_scalar_property( + property, update, phase, scalar_properties_.at(property) * shapefn_[i]); +} + +//! Interpolate scalar property from nodes +template +double mpm::ParticleBase::interpolate_scalar_property_nodes( + mpm::properties::Scalar property, unsigned phase) const { + double value = 0.; + // Interpolate scalar property from nodes + for (unsigned i = 0; i < nodes_.size(); ++i) + value += nodes_[i]->scalar_property(property, phase) * shapefn_[i]; + return value; +} + +//! Update vector property at particle +template +void mpm::ParticleBase::update_vector_property( + mpm::properties::Vector property, bool update, + const Eigen::Matrix& value) noexcept { + // Decide to update or assign + const double factor = (update == true) ? 1. : 0.; + vector_properties_.at(property) = + vector_properties_.at(property) * factor + value; +} + +//! Update vector property at particle +template +Eigen::Matrix mpm::ParticleBase::vector_property( + mpm::properties::Vector property) const { + return vector_properties_.at(property); +} + +//! Map vector property to nodes +template +void mpm::ParticleBase::map_vector_property_nodes( + mpm::properties::Vector property, bool update, unsigned phase) noexcept { + // TODO: Check assert needed? + // Map vector property to nodes + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->update_vector_property( + property, update, phase, vector_properties_.at(property) * shapefn_[i]); +} + +//! Interpolate vector property from nodes +template +double mpm::ParticleBase::interpolate_vector_property_nodes( + mpm::properties::Vector property, unsigned phase) const { + Eigen::Matrix value = Eigen::Matrix::Zero(); + // Interpolate vector property from nodes + for (unsigned i = 0; i < nodes_.size(); ++i) + value += nodes_[i]->vector_property(property, phase) * shapefn_[i]; + return value; +} From ad09dfaa2cb1e614062692d429e08d12f0bf099c Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Mon, 29 Jun 2020 12:47:31 -0500 Subject: [PATCH 003/175] :dart: Add testing to particle refactor of scalar properties --- external/tsl/ordered_hash.h | 1617 +++++++++++++++++++++++++++++++++++ external/tsl/ordered_map.h | 833 ++++++++++++++++++ external/tsl/ordered_set.h | 688 +++++++++++++++ include/mpm_properties.h | 13 + tests/particle_test.cc | 24 + 5 files changed, 3175 insertions(+) create mode 100644 external/tsl/ordered_hash.h create mode 100644 external/tsl/ordered_map.h create mode 100644 external/tsl/ordered_set.h create mode 100644 include/mpm_properties.h diff --git a/external/tsl/ordered_hash.h b/external/tsl/ordered_hash.h new file mode 100644 index 000000000..46d9b4877 --- /dev/null +++ b/external/tsl/ordered_hash.h @@ -0,0 +1,1617 @@ +/** + * MIT License + * + * Copyright (c) 2017 Thibaut Goetghebuer-Planchon + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef TSL_ORDERED_HASH_H +#define TSL_ORDERED_HASH_H + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/** + * Macros for compatibility with GCC 4.8 + */ +#if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 9)) +# define TSL_OH_NO_CONTAINER_ERASE_CONST_ITERATOR +# define TSL_OH_NO_CONTAINER_EMPLACE_CONST_ITERATOR +#endif + +/** + * Only activate tsl_oh_assert if TSL_DEBUG is defined. + * This way we avoid the performance hit when NDEBUG is not defined with assert as tsl_oh_assert is used a lot + * (people usually compile with "-O3" and not "-O3 -DNDEBUG"). + */ +#ifdef TSL_DEBUG +# define tsl_oh_assert(expr) assert(expr) +#else +# define tsl_oh_assert(expr) (static_cast(0)) +#endif + +/** + * If exceptions are enabled, throw the exception passed in parameter, otherwise call std::terminate. + */ +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || (defined (_MSC_VER) && defined (_CPPUNWIND))) && !defined(TSL_NO_EXCEPTIONS) +# define TSL_OH_THROW_OR_TERMINATE(ex, msg) throw ex(msg) +#else +# define TSL_OH_NO_EXCEPTIONS +# ifdef NDEBUG +# define TSL_OH_THROW_OR_TERMINATE(ex, msg) std::terminate() +# else +# include +# define TSL_OH_THROW_OR_TERMINATE(ex, msg) do { std::cerr << msg << std::endl; std::terminate(); } while(0) +# endif +#endif + + +namespace tsl { + +namespace detail_ordered_hash { + +template +struct make_void { + using type = void; +}; + +template +struct has_is_transparent: std::false_type { +}; + +template +struct has_is_transparent::type>: std::true_type { +}; + + +template +struct is_vector: std::false_type { +}; + +template +struct is_vector>::value + >::type>: std::true_type { +}; + +// Only available in C++17, we need to be compatible with C++11 +template +const T& clamp( const T& v, const T& lo, const T& hi) { + return std::min(hi, std::max(lo, v)); +} + +template +static T numeric_cast(U value, const char* error_message = "numeric_cast() failed.") { + T ret = static_cast(value); + if(static_cast(ret) != value) { + TSL_OH_THROW_OR_TERMINATE(std::runtime_error, error_message); + } + + const bool is_same_signedness = (std::is_unsigned::value && std::is_unsigned::value) || + (std::is_signed::value && std::is_signed::value); + if(!is_same_signedness && (ret < T{}) != (value < U{})) { + TSL_OH_THROW_OR_TERMINATE(std::runtime_error, error_message); + } + + return ret; +} + + +/** + * Fixed size type used to represent size_type values on serialization. Need to be big enough + * to represent a std::size_t on 32 and 64 bits platforms, and must be the same size on both platforms. + */ +using slz_size_type = std::uint64_t; +static_assert(std::numeric_limits::max() >= std::numeric_limits::max(), + "slz_size_type must be >= std::size_t"); + +template +static T deserialize_value(Deserializer& deserializer) { + // MSVC < 2017 is not conformant, circumvent the problem by removing the template keyword +#if defined (_MSC_VER) && _MSC_VER < 1910 + return deserializer.Deserializer::operator()(); +#else + return deserializer.Deserializer::template operator()(); +#endif +} + + +/** + * Each bucket entry stores an index which is the index in m_values corresponding to the bucket's value + * and a hash (which may be truncated to 32 bits depending on IndexType) corresponding to the hash of the value. + * + * The size of IndexType limits the size of the hash table to std::numeric_limits::max() - 1 elements (-1 due to + * a reserved value used to mark a bucket as empty). + */ +template +class bucket_entry { + static_assert(std::is_unsigned::value, "IndexType must be an unsigned value."); + static_assert(std::numeric_limits::max() <= std::numeric_limits::max(), + "std::numeric_limits::max() must be <= std::numeric_limits::max()."); + +public: + using index_type = IndexType; + using truncated_hash_type = typename std::conditional::max() <= + std::numeric_limits::max(), + std::uint_least32_t, + std::size_t>::type; + + bucket_entry() noexcept: m_index(EMPTY_MARKER_INDEX), m_hash(0) { + } + + bool empty() const noexcept { + return m_index == EMPTY_MARKER_INDEX; + } + + void clear() noexcept { + m_index = EMPTY_MARKER_INDEX; + } + + index_type index() const noexcept { + tsl_oh_assert(!empty()); + return m_index; + } + + index_type& index_ref() noexcept { + tsl_oh_assert(!empty()); + return m_index; + } + + void set_index(index_type index) noexcept { + tsl_oh_assert(index <= max_size()); + + m_index = index; + } + + truncated_hash_type truncated_hash() const noexcept { + tsl_oh_assert(!empty()); + return m_hash; + } + + truncated_hash_type& truncated_hash_ref() noexcept { + tsl_oh_assert(!empty()); + return m_hash; + } + + void set_hash(std::size_t hash) noexcept { + m_hash = truncate_hash(hash); + } + + template + void serialize(Serializer& serializer) const { + const slz_size_type index = m_index; + serializer(index); + + const slz_size_type hash = m_hash; + serializer(hash); + } + + template + static bucket_entry deserialize(Deserializer& deserializer) { + const slz_size_type index = deserialize_value(deserializer); + const slz_size_type hash = deserialize_value(deserializer); + + bucket_entry bentry; + bentry.m_index = numeric_cast(index, "Deserialized index is too big."); + bentry.m_hash = numeric_cast(hash, "Deserialized hash is too big."); + + return bentry; + } + + + + static truncated_hash_type truncate_hash(std::size_t hash) noexcept { + return truncated_hash_type(hash); + } + + static std::size_t max_size() noexcept { + return static_cast(std::numeric_limits::max()) - NB_RESERVED_INDEXES; + } + +private: + static const index_type EMPTY_MARKER_INDEX = std::numeric_limits::max(); + static const std::size_t NB_RESERVED_INDEXES = 1; + + index_type m_index; + truncated_hash_type m_hash; +}; + + + +/** + * Internal common class used by ordered_map and ordered_set. + * + * ValueType is what will be stored by ordered_hash (usually std::pair for map and Key for set). + * + * KeySelect should be a FunctionObject which takes a ValueType in parameter and return a reference to the key. + * + * ValueSelect should be a FunctionObject which takes a ValueType in parameter and return a reference to the value. + * ValueSelect should be void if there is no value (in set for example). + * + * ValueTypeContainer is the container which will be used to store ValueType values. + * Usually a std::deque or std::vector. + * + * + * + * The ordered_hash structure is a hash table which preserves the order of insertion of the elements. + * To do so, it stores the values in the ValueTypeContainer (m_values) using emplace_back at each + * insertion of a new element. Another structure (m_buckets of type std::vector) will + * serve as buckets array for the hash table part. Each bucket stores an index which corresponds to + * the index in m_values where the bucket's value is and the (truncated) hash of this value. An index + * is used instead of a pointer to the value to reduce the size of each bucket entry. + * + * To resolve collisions in the buckets array, the structures use robin hood linear probing with + * backward shift deletion. + */ +template +class ordered_hash: private Hash, private KeyEqual { +private: + template + using has_mapped_type = typename std::integral_constant::value>; + + static_assert(std::is_same::value, + "ValueTypeContainer::value_type != ValueType. " + "Check that the ValueTypeContainer has 'Key' as type for a set or 'std::pair' as type for a map."); + + static_assert(std::is_same::value, + "ValueTypeContainer::allocator_type != Allocator. " + "Check that the allocator for ValueTypeContainer is the same as Allocator."); + + static_assert(std::is_same::value, + "Allocator::value_type != ValueType. " + "Check that the allocator has 'Key' as type for a set or 'std::pair' as type for a map."); + + +public: + template + class ordered_iterator; + + using key_type = typename KeySelect::key_type; + using value_type = ValueType; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using hasher = Hash; + using key_equal = KeyEqual; + using allocator_type = Allocator; + using reference = value_type&; + using const_reference = const value_type&; + using pointer = value_type*; + using const_pointer = const value_type*; + using iterator = ordered_iterator; + using const_iterator = ordered_iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + using values_container_type = ValueTypeContainer; + +public: + template + class ordered_iterator { + friend class ordered_hash; + + private: + using iterator = typename std::conditional::type; + + + ordered_iterator(iterator it) noexcept: m_iterator(it) { + } + + public: + using iterator_category = std::random_access_iterator_tag; + using value_type = const typename ordered_hash::value_type; + using difference_type = typename iterator::difference_type; + using reference = value_type&; + using pointer = value_type*; + + + ordered_iterator() noexcept { + } + + // Copy constructor from iterator to const_iterator. + template::type* = nullptr> + ordered_iterator(const ordered_iterator& other) noexcept: m_iterator(other.m_iterator) { + } + + ordered_iterator(const ordered_iterator& other) = default; + ordered_iterator(ordered_iterator&& other) = default; + ordered_iterator& operator=(const ordered_iterator& other) = default; + ordered_iterator& operator=(ordered_iterator&& other) = default; + + const typename ordered_hash::key_type& key() const { + return KeySelect()(*m_iterator); + } + + template::value && IsConst>::type* = nullptr> + const typename U::value_type& value() const { + return U()(*m_iterator); + } + + template::value && !IsConst>::type* = nullptr> + typename U::value_type& value() { + return U()(*m_iterator); + } + + reference operator*() const { return *m_iterator; } + pointer operator->() const { return m_iterator.operator->(); } + + ordered_iterator& operator++() { ++m_iterator; return *this; } + ordered_iterator& operator--() { --m_iterator; return *this; } + + ordered_iterator operator++(int) { ordered_iterator tmp(*this); ++(*this); return tmp; } + ordered_iterator operator--(int) { ordered_iterator tmp(*this); --(*this); return tmp; } + + reference operator[](difference_type n) const { return m_iterator[n]; } + + ordered_iterator& operator+=(difference_type n) { m_iterator += n; return *this; } + ordered_iterator& operator-=(difference_type n) { m_iterator -= n; return *this; } + + ordered_iterator operator+(difference_type n) { ordered_iterator tmp(*this); tmp += n; return tmp; } + ordered_iterator operator-(difference_type n) { ordered_iterator tmp(*this); tmp -= n; return tmp; } + + friend bool operator==(const ordered_iterator& lhs, const ordered_iterator& rhs) { + return lhs.m_iterator == rhs.m_iterator; + } + + friend bool operator!=(const ordered_iterator& lhs, const ordered_iterator& rhs) { + return lhs.m_iterator != rhs.m_iterator; + } + + friend bool operator<(const ordered_iterator& lhs, const ordered_iterator& rhs) { + return lhs.m_iterator < rhs.m_iterator; + } + + friend bool operator>(const ordered_iterator& lhs, const ordered_iterator& rhs) { + return lhs.m_iterator > rhs.m_iterator; + } + + friend bool operator<=(const ordered_iterator& lhs, const ordered_iterator& rhs) { + return lhs.m_iterator <= rhs.m_iterator; + } + + friend bool operator>=(const ordered_iterator& lhs, const ordered_iterator& rhs) { + return lhs.m_iterator >= rhs.m_iterator; + } + + friend ordered_iterator operator+(difference_type n, const ordered_iterator& it) { + return n + it.m_iterator; + } + + friend difference_type operator-(const ordered_iterator& lhs, const ordered_iterator& rhs) { + return lhs.m_iterator - rhs.m_iterator; + } + + private: + iterator m_iterator; + }; + + +private: + using bucket_entry = tsl::detail_ordered_hash::bucket_entry; + + using buckets_container_allocator = typename + std::allocator_traits::template rebind_alloc; + + using buckets_container_type = std::vector; + + + using truncated_hash_type = typename bucket_entry::truncated_hash_type; + using index_type = typename bucket_entry::index_type; + +public: + ordered_hash(size_type bucket_count, + const Hash& hash, + const KeyEqual& equal, + const Allocator& alloc, + float max_load_factor): Hash(hash), + KeyEqual(equal), + m_buckets_data(alloc), + m_buckets(static_empty_bucket_ptr()), + m_hash_mask(0), + m_values(alloc), + m_grow_on_next_insert(false) + { + if(bucket_count > max_bucket_count()) { + TSL_OH_THROW_OR_TERMINATE(std::length_error, "The map exceeds its maximum size."); + } + + if(bucket_count > 0) { + bucket_count = round_up_to_power_of_two(bucket_count); + + m_buckets_data.resize(bucket_count); + m_buckets = m_buckets_data.data(), + m_hash_mask = bucket_count - 1; + } + + this->max_load_factor(max_load_factor); + } + + ordered_hash(const ordered_hash& other): Hash(other), + KeyEqual(other), + m_buckets_data(other.m_buckets_data), + m_buckets(m_buckets_data.empty()?static_empty_bucket_ptr(): + m_buckets_data.data()), + m_hash_mask(other.m_hash_mask), + m_values(other.m_values), + m_load_threshold(other.m_load_threshold), + m_max_load_factor(other.m_max_load_factor), + m_grow_on_next_insert(other.m_grow_on_next_insert) + { + } + + ordered_hash(ordered_hash&& other) noexcept(std::is_nothrow_move_constructible::value && + std::is_nothrow_move_constructible::value && + std::is_nothrow_move_constructible::value && + std::is_nothrow_move_constructible::value) + : Hash(std::move(static_cast(other))), + KeyEqual(std::move(static_cast(other))), + m_buckets_data(std::move(other.m_buckets_data)), + m_buckets(m_buckets_data.empty()?static_empty_bucket_ptr(): + m_buckets_data.data()), + m_hash_mask(other.m_hash_mask), + m_values(std::move(other.m_values)), + m_load_threshold(other.m_load_threshold), + m_max_load_factor(other.m_max_load_factor), + m_grow_on_next_insert(other.m_grow_on_next_insert) + { + other.m_buckets_data.clear(); + other.m_buckets = static_empty_bucket_ptr(); + other.m_hash_mask = 0; + other.m_values.clear(); + other.m_load_threshold = 0; + other.m_grow_on_next_insert = false; + } + + ordered_hash& operator=(const ordered_hash& other) { + if(&other != this) { + Hash::operator=(other); + KeyEqual::operator=(other); + + m_buckets_data = other.m_buckets_data; + m_buckets = m_buckets_data.empty()?static_empty_bucket_ptr(): + m_buckets_data.data(); + + m_hash_mask = other.m_hash_mask; + m_values = other.m_values; + m_load_threshold = other.m_load_threshold; + m_max_load_factor = other.m_max_load_factor; + m_grow_on_next_insert = other.m_grow_on_next_insert; + } + + return *this; + } + + ordered_hash& operator=(ordered_hash&& other) { + other.swap(*this); + other.clear(); + + return *this; + } + + allocator_type get_allocator() const { + return m_values.get_allocator(); + } + + + /* + * Iterators + */ + iterator begin() noexcept { + return iterator(m_values.begin()); + } + + const_iterator begin() const noexcept { + return cbegin(); + } + + const_iterator cbegin() const noexcept { + return const_iterator(m_values.cbegin()); + } + + iterator end() noexcept { + return iterator(m_values.end()); + } + + const_iterator end() const noexcept { + return cend(); + } + + const_iterator cend() const noexcept { + return const_iterator(m_values.cend()); + } + + + reverse_iterator rbegin() noexcept { + return reverse_iterator(m_values.end()); + } + + const_reverse_iterator rbegin() const noexcept { + return rcbegin(); + } + + const_reverse_iterator rcbegin() const noexcept { + return const_reverse_iterator(m_values.cend()); + } + + reverse_iterator rend() noexcept { + return reverse_iterator(m_values.begin()); + } + + const_reverse_iterator rend() const noexcept { + return rcend(); + } + + const_reverse_iterator rcend() const noexcept { + return const_reverse_iterator(m_values.cbegin()); + } + + + /* + * Capacity + */ + bool empty() const noexcept { + return m_values.empty(); + } + + size_type size() const noexcept { + return m_values.size(); + } + + size_type max_size() const noexcept { + return std::min(bucket_entry::max_size(), m_values.max_size()); + } + + + /* + * Modifiers + */ + void clear() noexcept { + for(auto& bucket: m_buckets_data) { + bucket.clear(); + } + + m_values.clear(); + m_grow_on_next_insert = false; + } + + template + std::pair insert(P&& value) { + return insert_impl(KeySelect()(value), std::forward

(value)); + } + + template + iterator insert_hint(const_iterator hint, P&& value) { + if(hint != cend() && compare_keys(KeySelect()(*hint), KeySelect()(value))) { + return mutable_iterator(hint); + } + + return insert(std::forward

(value)).first; + } + + template + void insert(InputIt first, InputIt last) { + if(std::is_base_of::iterator_category>::value) + { + const auto nb_elements_insert = std::distance(first, last); + const size_type nb_free_buckets = m_load_threshold - size(); + tsl_oh_assert(m_load_threshold >= size()); + + if(nb_elements_insert > 0 && nb_free_buckets < size_type(nb_elements_insert)) { + reserve(size() + size_type(nb_elements_insert)); + } + } + + for(; first != last; ++first) { + insert(*first); + } + } + + + + template + std::pair insert_or_assign(K&& key, M&& value) { + auto it = try_emplace(std::forward(key), std::forward(value)); + if(!it.second) { + it.first.value() = std::forward(value); + } + + return it; + } + + template + iterator insert_or_assign(const_iterator hint, K&& key, M&& obj) { + if(hint != cend() && compare_keys(KeySelect()(*hint), key)) { + auto it = mutable_iterator(hint); + it.value() = std::forward(obj); + + return it; + } + + return insert_or_assign(std::forward(key), std::forward(obj)).first; + } + + + + template + std::pair emplace(Args&&... args) { + return insert(value_type(std::forward(args)...)); + } + + template + iterator emplace_hint(const_iterator hint, Args&&... args) { + return insert_hint(hint, value_type(std::forward(args)...)); + } + + + + template + std::pair try_emplace(K&& key, Args&&... value_args) { + return insert_impl(key, std::piecewise_construct, + std::forward_as_tuple(std::forward(key)), + std::forward_as_tuple(std::forward(value_args)...)); + } + + template + iterator try_emplace_hint(const_iterator hint, K&& key, Args&&... args) { + if(hint != cend() && compare_keys(KeySelect()(*hint), key)) { + return mutable_iterator(hint); + } + + return try_emplace(std::forward(key), std::forward(args)...).first; + } + + + + /** + * Here to avoid `template size_type erase(const K& key)` being used when + * we use an `iterator` instead of a `const_iterator`. + */ + iterator erase(iterator pos) { + return erase(const_iterator(pos)); + } + + iterator erase(const_iterator pos) { + tsl_oh_assert(pos != cend()); + + const std::size_t index_erase = iterator_to_index(pos); + + auto it_bucket = find_key(pos.key(), hash_key(pos.key())); + tsl_oh_assert(it_bucket != m_buckets_data.end()); + + erase_value_from_bucket(it_bucket); + + /* + * One element was removed from m_values, due to the left shift the next element + * is now at the position of the previous element (or end if none). + */ + return begin() + index_erase; + } + + iterator erase(const_iterator first, const_iterator last) { + if(first == last) { + return mutable_iterator(first); + } + + tsl_oh_assert(std::distance(first, last) > 0); + const std::size_t start_index = iterator_to_index(first); + const std::size_t nb_values = std::size_t(std::distance(first, last)); + const std::size_t end_index = start_index + nb_values; + + // Delete all values +#ifdef TSL_OH_NO_CONTAINER_ERASE_CONST_ITERATOR + auto next_it = m_values.erase(mutable_iterator(first).m_iterator, mutable_iterator(last).m_iterator); +#else + auto next_it = m_values.erase(first.m_iterator, last.m_iterator); +#endif + + /* + * Mark the buckets corresponding to the values as empty and do a backward shift. + * + * Also, the erase operation on m_values has shifted all the values on the right of last.m_iterator. + * Adapt the indexes for these values. + */ + std::size_t ibucket = 0; + while(ibucket < m_buckets_data.size()) { + if(m_buckets[ibucket].empty()) { + ibucket++; + } + else if(m_buckets[ibucket].index() >= start_index && m_buckets[ibucket].index() < end_index) { + m_buckets[ibucket].clear(); + backward_shift(ibucket); + // Don't increment ibucket, backward_shift may have replaced current bucket. + } + else if(m_buckets[ibucket].index() >= end_index) { + m_buckets[ibucket].set_index(index_type(m_buckets[ibucket].index() - nb_values)); + ibucket++; + } + else { + ibucket++; + } + } + + return iterator(next_it); + } + + + template + size_type erase(const K& key) { + return erase(key, hash_key(key)); + } + + template + size_type erase(const K& key, std::size_t hash) { + return erase_impl(key, hash); + } + + void swap(ordered_hash& other) { + using std::swap; + + swap(static_cast(*this), static_cast(other)); + swap(static_cast(*this), static_cast(other)); + swap(m_buckets_data, other.m_buckets_data); + swap(m_buckets, other.m_buckets); + swap(m_hash_mask, other.m_hash_mask); + swap(m_values, other.m_values); + swap(m_load_threshold, other.m_load_threshold); + swap(m_max_load_factor, other.m_max_load_factor); + swap(m_grow_on_next_insert, other.m_grow_on_next_insert); + } + + + + + /* + * Lookup + */ + template::value>::type* = nullptr> + typename U::value_type& at(const K& key) { + return at(key, hash_key(key)); + } + + template::value>::type* = nullptr> + typename U::value_type& at(const K& key, std::size_t hash) { + return const_cast(static_cast(this)->at(key, hash)); + } + + template::value>::type* = nullptr> + const typename U::value_type& at(const K& key) const { + return at(key, hash_key(key)); + } + + template::value>::type* = nullptr> + const typename U::value_type& at(const K& key, std::size_t hash) const { + auto it = find(key, hash); + if(it != end()) { + return it.value(); + } + else { + TSL_OH_THROW_OR_TERMINATE(std::out_of_range, "Couldn't find the key."); + } + } + + + template::value>::type* = nullptr> + typename U::value_type& operator[](K&& key) { + return try_emplace(std::forward(key)).first.value(); + } + + + template + size_type count(const K& key) const { + return count(key, hash_key(key)); + } + + template + size_type count(const K& key, std::size_t hash) const { + if(find(key, hash) == cend()) { + return 0; + } + else { + return 1; + } + } + + template + iterator find(const K& key) { + return find(key, hash_key(key)); + } + + template + iterator find(const K& key, std::size_t hash) { + auto it_bucket = find_key(key, hash); + return (it_bucket != m_buckets_data.end())?iterator(m_values.begin() + it_bucket->index()):end(); + } + + template + const_iterator find(const K& key) const { + return find(key, hash_key(key)); + } + + template + const_iterator find(const K& key, std::size_t hash) const { + auto it_bucket = find_key(key, hash); + return (it_bucket != m_buckets_data.cend())?const_iterator(m_values.begin() + it_bucket->index()):end(); + } + + + template + std::pair equal_range(const K& key) { + return equal_range(key, hash_key(key)); + } + + template + std::pair equal_range(const K& key, std::size_t hash) { + iterator it = find(key, hash); + return std::make_pair(it, (it == end())?it:std::next(it)); + } + + template + std::pair equal_range(const K& key) const { + return equal_range(key, hash_key(key)); + } + + template + std::pair equal_range(const K& key, std::size_t hash) const { + const_iterator it = find(key, hash); + return std::make_pair(it, (it == cend())?it:std::next(it)); + } + + + /* + * Bucket interface + */ + size_type bucket_count() const { + return m_buckets_data.size(); + } + + size_type max_bucket_count() const { + return m_buckets_data.max_size(); + } + + /* + * Hash policy + */ + float load_factor() const { + if(bucket_count() == 0) { + return 0; + } + + return float(size())/float(bucket_count()); + } + + float max_load_factor() const { + return m_max_load_factor; + } + + void max_load_factor(float ml) { + m_max_load_factor = clamp(ml, float(MAX_LOAD_FACTOR__MINIMUM), + float(MAX_LOAD_FACTOR__MAXIMUM)); + + m_max_load_factor = ml; + m_load_threshold = size_type(float(bucket_count())*m_max_load_factor); + } + + void rehash(size_type count) { + count = std::max(count, size_type(std::ceil(float(size())/max_load_factor()))); + rehash_impl(count); + } + + void reserve(size_type count) { + reserve_space_for_values(count); + + count = size_type(std::ceil(float(count)/max_load_factor())); + rehash(count); + } + + + /* + * Observers + */ + hasher hash_function() const { + return static_cast(*this); + } + + key_equal key_eq() const { + return static_cast(*this); + } + + + /* + * Other + */ + iterator mutable_iterator(const_iterator pos) { + return iterator(m_values.begin() + iterator_to_index(pos)); + } + + iterator nth(size_type index) { + tsl_oh_assert(index <= size()); + return iterator(m_values.begin() + index); + } + + const_iterator nth(size_type index) const { + tsl_oh_assert(index <= size()); + return const_iterator(m_values.cbegin() + index); + } + + const_reference front() const { + tsl_oh_assert(!empty()); + return m_values.front(); + } + + const_reference back() const { + tsl_oh_assert(!empty()); + return m_values.back(); + } + + const values_container_type& values_container() const noexcept { + return m_values; + } + + template::value>::type* = nullptr> + const typename values_container_type::value_type* data() const noexcept { + return m_values.data(); + } + + template::value>::type* = nullptr> + size_type capacity() const noexcept { + return m_values.capacity(); + } + + void shrink_to_fit() { + m_values.shrink_to_fit(); + } + + + template + std::pair insert_at_position(const_iterator pos, P&& value) { + return insert_at_position_impl(pos.m_iterator, KeySelect()(value), std::forward

(value)); + } + + template + std::pair emplace_at_position(const_iterator pos, Args&&... args) { + return insert_at_position(pos, value_type(std::forward(args)...)); + } + + template + std::pair try_emplace_at_position(const_iterator pos, K&& key, Args&&... value_args) { + return insert_at_position_impl(pos.m_iterator, key, + std::piecewise_construct, + std::forward_as_tuple(std::forward(key)), + std::forward_as_tuple(std::forward(value_args)...)); + } + + + void pop_back() { + tsl_oh_assert(!empty()); + erase(std::prev(end())); + } + + + /** + * Here to avoid `template size_type unordered_erase(const K& key)` being used when + * we use a iterator instead of a const_iterator. + */ + iterator unordered_erase(iterator pos) { + return unordered_erase(const_iterator(pos)); + } + + iterator unordered_erase(const_iterator pos) { + const std::size_t index_erase = iterator_to_index(pos); + unordered_erase(pos.key()); + + /* + * One element was deleted, index_erase now points to the next element as the elements after + * the deleted value were shifted to the left in m_values (will be end() if we deleted the last element). + */ + return begin() + index_erase; + } + + template + size_type unordered_erase(const K& key) { + return unordered_erase(key, hash_key(key)); + } + + template + size_type unordered_erase(const K& key, std::size_t hash) { + auto it_bucket_key = find_key(key, hash); + if(it_bucket_key == m_buckets_data.end()) { + return 0; + } + + /** + * If we are not erasing the last element in m_values, we swap + * the element we are erasing with the last element. We then would + * just have to do a pop_back() in m_values. + */ + if(!compare_keys(key, KeySelect()(back()))) { + auto it_bucket_last_elem = find_key(KeySelect()(back()), hash_key(KeySelect()(back()))); + tsl_oh_assert(it_bucket_last_elem != m_buckets_data.end()); + tsl_oh_assert(it_bucket_last_elem->index() == m_values.size() - 1); + + using std::swap; + swap(m_values[it_bucket_key->index()], m_values[it_bucket_last_elem->index()]); + swap(it_bucket_key->index_ref(), it_bucket_last_elem->index_ref()); + } + + erase_value_from_bucket(it_bucket_key); + + return 1; + } + + template + void serialize(Serializer& serializer) const { + serialize_impl(serializer); + } + + template + void deserialize(Deserializer& deserializer, bool hash_compatible) { + deserialize_impl(deserializer, hash_compatible); + } + + friend bool operator==(const ordered_hash& lhs, const ordered_hash& rhs) { + return lhs.m_values == rhs.m_values; + } + + friend bool operator!=(const ordered_hash& lhs, const ordered_hash& rhs) { + return lhs.m_values != rhs.m_values; + } + + friend bool operator<(const ordered_hash& lhs, const ordered_hash& rhs) { + return lhs.m_values < rhs.m_values; + } + + friend bool operator<=(const ordered_hash& lhs, const ordered_hash& rhs) { + return lhs.m_values <= rhs.m_values; + } + + friend bool operator>(const ordered_hash& lhs, const ordered_hash& rhs) { + return lhs.m_values > rhs.m_values; + } + + friend bool operator>=(const ordered_hash& lhs, const ordered_hash& rhs) { + return lhs.m_values >= rhs.m_values; + } + + +private: + template + std::size_t hash_key(const K& key) const { + return Hash::operator()(key); + } + + template + bool compare_keys(const K1& key1, const K2& key2) const { + return KeyEqual::operator()(key1, key2); + } + + template + typename buckets_container_type::iterator find_key(const K& key, std::size_t hash) { + auto it = static_cast(this)->find_key(key, hash); + return m_buckets_data.begin() + std::distance(m_buckets_data.cbegin(), it); + } + + /** + * Return bucket which has the key 'key' or m_buckets_data.end() if none. + * + * From the bucket_for_hash, search for the value until we either find an empty bucket + * or a bucket which has a value with a distance from its ideal bucket longer + * than the probe length for the value we are looking for. + */ + template + typename buckets_container_type::const_iterator find_key(const K& key, std::size_t hash) const { + for(std::size_t ibucket = bucket_for_hash(hash), dist_from_ideal_bucket = 0; ; + ibucket = next_bucket(ibucket), dist_from_ideal_bucket++) + { + if(m_buckets[ibucket].empty()) { + return m_buckets_data.end(); + } + else if(m_buckets[ibucket].truncated_hash() == bucket_entry::truncate_hash(hash) && + compare_keys(key, KeySelect()(m_values[m_buckets[ibucket].index()]))) + { + return m_buckets_data.begin() + ibucket; + } + else if(dist_from_ideal_bucket > distance_from_ideal_bucket(ibucket)) { + return m_buckets_data.end(); + } + } + } + + void rehash_impl(size_type bucket_count) { + tsl_oh_assert(bucket_count >= size_type(std::ceil(float(size())/max_load_factor()))); + + if(bucket_count > max_bucket_count()) { + TSL_OH_THROW_OR_TERMINATE(std::length_error, "The map exceeds its maximum size."); + } + + if(bucket_count > 0) { + bucket_count = round_up_to_power_of_two(bucket_count); + } + + if(bucket_count == this->bucket_count()) { + return; + } + + + buckets_container_type old_buckets(bucket_count); + m_buckets_data.swap(old_buckets); + m_buckets = m_buckets_data.empty()?static_empty_bucket_ptr(): + m_buckets_data.data(); + // Everything should be noexcept from here. + + m_hash_mask = (bucket_count > 0)?(bucket_count - 1):0; + this->max_load_factor(m_max_load_factor); + m_grow_on_next_insert = false; + + + + for(const bucket_entry& old_bucket: old_buckets) { + if(old_bucket.empty()) { + continue; + } + + truncated_hash_type insert_hash = old_bucket.truncated_hash(); + index_type insert_index = old_bucket.index(); + + for(std::size_t ibucket = bucket_for_hash(insert_hash), dist_from_ideal_bucket = 0; ; + ibucket = next_bucket(ibucket), dist_from_ideal_bucket++) + { + if(m_buckets[ibucket].empty()) { + m_buckets[ibucket].set_index(insert_index); + m_buckets[ibucket].set_hash(insert_hash); + break; + } + + const std::size_t distance = distance_from_ideal_bucket(ibucket); + if(dist_from_ideal_bucket > distance) { + std::swap(insert_index, m_buckets[ibucket].index_ref()); + std::swap(insert_hash, m_buckets[ibucket].truncated_hash_ref()); + dist_from_ideal_bucket = distance; + } + } + } + } + + template::value>::type* = nullptr> + void reserve_space_for_values(size_type count) { + m_values.reserve(count); + } + + template::value>::type* = nullptr> + void reserve_space_for_values(size_type /*count*/) { + } + + /** + * Swap the empty bucket with the values on its right until we cross another empty bucket + * or if the other bucket has a distance_from_ideal_bucket == 0. + */ + void backward_shift(std::size_t empty_ibucket) noexcept { + tsl_oh_assert(m_buckets[empty_ibucket].empty()); + + std::size_t previous_ibucket = empty_ibucket; + for(std::size_t current_ibucket = next_bucket(previous_ibucket); + !m_buckets[current_ibucket].empty() && distance_from_ideal_bucket(current_ibucket) > 0; + previous_ibucket = current_ibucket, current_ibucket = next_bucket(current_ibucket)) + { + std::swap(m_buckets[current_ibucket], m_buckets[previous_ibucket]); + } + } + + void erase_value_from_bucket(typename buckets_container_type::iterator it_bucket) { + tsl_oh_assert(it_bucket != m_buckets_data.end() && !it_bucket->empty()); + + m_values.erase(m_values.begin() + it_bucket->index()); + + /* + * m_values.erase shifted all the values on the right of the erased value, + * shift the indexes by -1 in the buckets array for these values. + */ + if(it_bucket->index() != m_values.size()) { + shift_indexes_in_buckets(it_bucket->index(), -1); + } + + // Mark the bucket as empty and do a backward shift of the values on the right + it_bucket->clear(); + backward_shift(std::size_t(std::distance(m_buckets_data.begin(), it_bucket))); + } + + /** + * Go through each value from [from_ivalue, m_values.size()) in m_values and for each + * bucket corresponding to the value, shift the index by delta. + * + * delta must be equal to 1 or -1. + */ + void shift_indexes_in_buckets(index_type from_ivalue, int delta) noexcept { + tsl_oh_assert(delta == 1 || delta == -1); + + for(std::size_t ivalue = from_ivalue; ivalue < m_values.size(); ivalue++) { + // All the values in m_values have been shifted by delta. Find the bucket corresponding + // to the value m_values[ivalue] + const index_type old_index = static_cast(ivalue - delta); + + std::size_t ibucket = bucket_for_hash(hash_key(KeySelect()(m_values[ivalue]))); + while(m_buckets[ibucket].index() != old_index) { + ibucket = next_bucket(ibucket); + } + + m_buckets[ibucket].set_index(index_type(ivalue)); + } + } + + template + size_type erase_impl(const K& key, std::size_t hash) { + auto it_bucket = find_key(key, hash); + if(it_bucket != m_buckets_data.end()) { + erase_value_from_bucket(it_bucket); + + return 1; + } + else { + return 0; + } + } + + /** + * Insert the element at the end. + */ + template + std::pair insert_impl(const K& key, Args&&... value_type_args) { + const std::size_t hash = hash_key(key); + + std::size_t ibucket = bucket_for_hash(hash); + std::size_t dist_from_ideal_bucket = 0; + + while(!m_buckets[ibucket].empty() && dist_from_ideal_bucket <= distance_from_ideal_bucket(ibucket)) { + if(m_buckets[ibucket].truncated_hash() == bucket_entry::truncate_hash(hash) && + compare_keys(key, KeySelect()(m_values[m_buckets[ibucket].index()]))) + { + return std::make_pair(begin() + m_buckets[ibucket].index(), false); + } + + ibucket = next_bucket(ibucket); + dist_from_ideal_bucket++; + } + + if(size() >= max_size()) { + TSL_OH_THROW_OR_TERMINATE(std::length_error, "We reached the maximum size for the hash table."); + } + + + if(grow_on_high_load()) { + ibucket = bucket_for_hash(hash); + dist_from_ideal_bucket = 0; + } + + + m_values.emplace_back(std::forward(value_type_args)...); + insert_index(ibucket, dist_from_ideal_bucket, + index_type(m_values.size() - 1), bucket_entry::truncate_hash(hash)); + + + return std::make_pair(std::prev(end()), true); + } + + /** + * Insert the element before insert_position. + */ + template + std::pair insert_at_position_impl(typename values_container_type::const_iterator insert_position, + const K& key, Args&&... value_type_args) + { + const std::size_t hash = hash_key(key); + + std::size_t ibucket = bucket_for_hash(hash); + std::size_t dist_from_ideal_bucket = 0; + + while(!m_buckets[ibucket].empty() && dist_from_ideal_bucket <= distance_from_ideal_bucket(ibucket)) { + if(m_buckets[ibucket].truncated_hash() == bucket_entry::truncate_hash(hash) && + compare_keys(key, KeySelect()(m_values[m_buckets[ibucket].index()]))) + { + return std::make_pair(begin() + m_buckets[ibucket].index(), false); + } + + ibucket = next_bucket(ibucket); + dist_from_ideal_bucket++; + } + + if(size() >= max_size()) { + TSL_OH_THROW_OR_TERMINATE(std::length_error, "We reached the maximum size for the hash table."); + } + + + if(grow_on_high_load()) { + ibucket = bucket_for_hash(hash); + dist_from_ideal_bucket = 0; + } + + + const index_type index_insert_position = index_type(std::distance(m_values.cbegin(), insert_position)); + +#ifdef TSL_OH_NO_CONTAINER_EMPLACE_CONST_ITERATOR + m_values.emplace(m_values.begin() + std::distance(m_values.cbegin(), insert_position), std::forward(value_type_args)...); +#else + m_values.emplace(insert_position, std::forward(value_type_args)...); +#endif + + insert_index(ibucket, dist_from_ideal_bucket, + index_insert_position, bucket_entry::truncate_hash(hash)); + + /* + * The insertion didn't happend at the end of the m_values container, + * we need to shift the indexes in m_buckets_data. + */ + if(index_insert_position != m_values.size() - 1) { + shift_indexes_in_buckets(index_insert_position + 1, 1); + } + + return std::make_pair(iterator(m_values.begin() + index_insert_position), true); + } + + void insert_index(std::size_t ibucket, std::size_t dist_from_ideal_bucket, + index_type index_insert, truncated_hash_type hash_insert) noexcept + { + while(!m_buckets[ibucket].empty()) { + const std::size_t distance = distance_from_ideal_bucket(ibucket); + if(dist_from_ideal_bucket > distance) { + std::swap(index_insert, m_buckets[ibucket].index_ref()); + std::swap(hash_insert, m_buckets[ibucket].truncated_hash_ref()); + + dist_from_ideal_bucket = distance; + } + + + ibucket = next_bucket(ibucket); + dist_from_ideal_bucket++; + + + if(dist_from_ideal_bucket > REHASH_ON_HIGH_NB_PROBES__NPROBES && !m_grow_on_next_insert && + load_factor() >= REHASH_ON_HIGH_NB_PROBES__MIN_LOAD_FACTOR) + { + // We don't want to grow the map now as we need this method to be noexcept. + // Do it on next insert. + m_grow_on_next_insert = true; + } + } + + + m_buckets[ibucket].set_index(index_insert); + m_buckets[ibucket].set_hash(hash_insert); + } + + std::size_t distance_from_ideal_bucket(std::size_t ibucket) const noexcept { + const std::size_t ideal_bucket = bucket_for_hash(m_buckets[ibucket].truncated_hash()); + + if(ibucket >= ideal_bucket) { + return ibucket - ideal_bucket; + } + // If the bucket is smaller than the ideal bucket for the value, there was a wrapping at the end of the + // bucket array due to the modulo. + else { + return (bucket_count() + ibucket) - ideal_bucket; + } + } + + std::size_t next_bucket(std::size_t index) const noexcept { + tsl_oh_assert(index < m_buckets_data.size()); + + index++; + return (index < m_buckets_data.size())?index:0; + } + + std::size_t bucket_for_hash(std::size_t hash) const noexcept { + return hash & m_hash_mask; + } + + std::size_t iterator_to_index(const_iterator it) const noexcept { + const auto dist = std::distance(cbegin(), it); + tsl_oh_assert(dist >= 0); + + return std::size_t(dist); + } + + /** + * Return true if the map has been rehashed. + */ + bool grow_on_high_load() { + if(m_grow_on_next_insert || size() >= m_load_threshold) { + rehash_impl(std::max(size_type(1), bucket_count() * 2)); + m_grow_on_next_insert = false; + + return true; + } + else { + return false; + } + } + + template + void serialize_impl(Serializer& serializer) const { + const slz_size_type version = SERIALIZATION_PROTOCOL_VERSION; + serializer(version); + + const slz_size_type nb_elements = m_values.size(); + serializer(nb_elements); + + const slz_size_type bucket_count = m_buckets_data.size(); + serializer(bucket_count); + + const float max_load_factor = m_max_load_factor; + serializer(max_load_factor); + + + for(const value_type& value: m_values) { + serializer(value); + } + + for(const bucket_entry& bucket: m_buckets_data) { + bucket.serialize(serializer); + } + } + + template + void deserialize_impl(Deserializer& deserializer, bool hash_compatible) { + tsl_oh_assert(m_buckets_data.empty()); // Current hash table must be empty + + const slz_size_type version = deserialize_value(deserializer); + // For now we only have one version of the serialization protocol. + // If it doesn't match there is a problem with the file. + if(version != SERIALIZATION_PROTOCOL_VERSION) { + TSL_OH_THROW_OR_TERMINATE(std::runtime_error, "Can't deserialize the ordered_map/set. " + "The protocol version header is invalid."); + } + + const slz_size_type nb_elements = deserialize_value(deserializer); + const slz_size_type bucket_count_ds = deserialize_value(deserializer); + const float max_load_factor = deserialize_value(deserializer); + + if(max_load_factor < MAX_LOAD_FACTOR__MINIMUM || max_load_factor > MAX_LOAD_FACTOR__MAXIMUM) { + TSL_OH_THROW_OR_TERMINATE(std::runtime_error, "Invalid max_load_factor. Check that the serializer " + "and deserializer support floats correctly as they " + "can be converted implicitly to ints."); + } + + + this->max_load_factor(max_load_factor); + + if(bucket_count_ds == 0) { + tsl_oh_assert(nb_elements == 0); + return; + } + + + if(!hash_compatible) { + reserve(numeric_cast(nb_elements, "Deserialized nb_elements is too big.")); + for(slz_size_type el = 0; el < nb_elements; el++) { + insert(deserialize_value(deserializer)); + } + } + else { + m_buckets_data.reserve(numeric_cast(bucket_count_ds, "Deserialized bucket_count is too big.")); + m_buckets = m_buckets_data.data(), + m_hash_mask = m_buckets_data.capacity() - 1; + + reserve_space_for_values(numeric_cast(nb_elements, "Deserialized nb_elements is too big.")); + for(slz_size_type el = 0; el < nb_elements; el++) { + m_values.push_back(deserialize_value(deserializer)); + } + + for(slz_size_type b = 0; b < bucket_count_ds; b++) { + m_buckets_data.push_back(bucket_entry::deserialize(deserializer)); + } + } + } + + static std::size_t round_up_to_power_of_two(std::size_t value) { + if(is_power_of_two(value)) { + return value; + } + + if(value == 0) { + return 1; + } + + --value; + for(std::size_t i = 1; i < sizeof(std::size_t) * CHAR_BIT; i *= 2) { + value |= value >> i; + } + + return value + 1; + } + + static constexpr bool is_power_of_two(std::size_t value) { + return value != 0 && (value & (value - 1)) == 0; + } + + +public: + static const size_type DEFAULT_INIT_BUCKETS_SIZE = 0; + static constexpr float DEFAULT_MAX_LOAD_FACTOR = 0.75f; + +private: + static constexpr float MAX_LOAD_FACTOR__MINIMUM = 0.1f; + static constexpr float MAX_LOAD_FACTOR__MAXIMUM = 0.95f; + + static const size_type REHASH_ON_HIGH_NB_PROBES__NPROBES = 128; + static constexpr float REHASH_ON_HIGH_NB_PROBES__MIN_LOAD_FACTOR = 0.15f; + + /** + * Protocol version currenlty used for serialization. + */ + static const slz_size_type SERIALIZATION_PROTOCOL_VERSION = 1; + + /** + * Return an always valid pointer to an static empty bucket_entry with last_bucket() == true. + */ + bucket_entry* static_empty_bucket_ptr() { + static bucket_entry empty_bucket; + return &empty_bucket; + } + +private: + buckets_container_type m_buckets_data; + + /** + * Points to m_buckets_data.data() if !m_buckets_data.empty() otherwise points to static_empty_bucket_ptr. + * This variable is useful to avoid the cost of checking if m_buckets_data is empty when trying + * to find an element. + * + * TODO Remove m_buckets_data and only use a pointer+size instead of a pointer+vector to save some space in the ordered_hash object. + */ + bucket_entry* m_buckets; + + size_type m_hash_mask; + + values_container_type m_values; + + size_type m_load_threshold; + float m_max_load_factor; + + bool m_grow_on_next_insert; +}; + + +} // end namespace detail_ordered_hash + +} // end namespace tsl + +#endif diff --git a/external/tsl/ordered_map.h b/external/tsl/ordered_map.h new file mode 100644 index 000000000..c8b8b6bb2 --- /dev/null +++ b/external/tsl/ordered_map.h @@ -0,0 +1,833 @@ +/** + * MIT License + * + * Copyright (c) 2017 Thibaut Goetghebuer-Planchon + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef TSL_ORDERED_MAP_H +#define TSL_ORDERED_MAP_H + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ordered_hash.h" + + +namespace tsl { + + +/** + * Implementation of an hash map using open addressing with robin hood with backshift delete to resolve collisions. + * + * The particularity of this hash map is that it remembers the order in which the elements were added and + * provide a way to access the structure which stores these values through the 'values_container()' method. + * The used container is defined by ValueTypeContainer, by default a std::deque is used (grows faster) but + * a std::vector may be used. In this case the map provides a 'data()' method which give a direct access + * to the memory used to store the values (which can be useful to communicate with C API's). + * + * The Key and T must be copy constructible and/or move constructible. To use `unordered_erase` they both + * must be swappable. + * + * The behaviour of the hash map is undefined if the destructor of Key or T throws an exception. + * + * By default the maximum size of a map is limited to 2^32 - 1 values, if needed this can be changed through + * the IndexType template parameter. Using an `uint64_t` will raise this limit to 2^64 - 1 values but each + * bucket will use 16 bytes instead of 8 bytes in addition to the space needed to store the values. + * + * Iterators invalidation: + * - clear, operator=, reserve, rehash: always invalidate the iterators (also invalidate end()). + * - insert, emplace, emplace_hint, operator[]: when a std::vector is used as ValueTypeContainer + * and if size() < capacity(), only end(). + * Otherwise all the iterators are invalidated if an insert occurs. + * - erase, unordered_erase: when a std::vector is used as ValueTypeContainer invalidate the iterator of + * the erased element and all the ones after the erased element (including end()). + * Otherwise all the iterators are invalidated if an erase occurs. + */ +template, + class KeyEqual = std::equal_to, + class Allocator = std::allocator>, + class ValueTypeContainer = std::deque, Allocator>, + class IndexType = std::uint_least32_t> +class ordered_map { +private: + template + using has_is_transparent = tsl::detail_ordered_hash::has_is_transparent; + + class KeySelect { + public: + using key_type = Key; + + const key_type& operator()(const std::pair& key_value) const noexcept { + return key_value.first; + } + + key_type& operator()(std::pair& key_value) noexcept { + return key_value.first; + } + }; + + class ValueSelect { + public: + using value_type = T; + + const value_type& operator()(const std::pair& key_value) const noexcept { + return key_value.second; + } + + value_type& operator()(std::pair& key_value) noexcept { + return key_value.second; + } + }; + + using ht = detail_ordered_hash::ordered_hash, KeySelect, ValueSelect, + Hash, KeyEqual, Allocator, ValueTypeContainer, IndexType>; + +public: + using key_type = typename ht::key_type; + using mapped_type = T; + using value_type = typename ht::value_type; + using size_type = typename ht::size_type; + using difference_type = typename ht::difference_type; + using hasher = typename ht::hasher; + using key_equal = typename ht::key_equal; + using allocator_type = typename ht::allocator_type; + using reference = typename ht::reference; + using const_reference = typename ht::const_reference; + using pointer = typename ht::pointer; + using const_pointer = typename ht::const_pointer; + using iterator = typename ht::iterator; + using const_iterator = typename ht::const_iterator; + using reverse_iterator = typename ht::reverse_iterator; + using const_reverse_iterator = typename ht::const_reverse_iterator; + + using values_container_type = typename ht::values_container_type; + + + /* + * Constructors + */ + ordered_map(): ordered_map(ht::DEFAULT_INIT_BUCKETS_SIZE) { + } + + explicit ordered_map(size_type bucket_count, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual(), + const Allocator& alloc = Allocator()): + m_ht(bucket_count, hash, equal, alloc, ht::DEFAULT_MAX_LOAD_FACTOR) + { + } + + ordered_map(size_type bucket_count, + const Allocator& alloc): ordered_map(bucket_count, Hash(), KeyEqual(), alloc) + { + } + + ordered_map(size_type bucket_count, + const Hash& hash, + const Allocator& alloc): ordered_map(bucket_count, hash, KeyEqual(), alloc) + { + } + + explicit ordered_map(const Allocator& alloc): ordered_map(ht::DEFAULT_INIT_BUCKETS_SIZE, alloc) { + } + + template + ordered_map(InputIt first, InputIt last, + size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual(), + const Allocator& alloc = Allocator()): ordered_map(bucket_count, hash, equal, alloc) + { + insert(first, last); + } + + template + ordered_map(InputIt first, InputIt last, + size_type bucket_count, + const Allocator& alloc): ordered_map(first, last, bucket_count, Hash(), KeyEqual(), alloc) + { + } + + template + ordered_map(InputIt first, InputIt last, + size_type bucket_count, + const Hash& hash, + const Allocator& alloc): ordered_map(first, last, bucket_count, hash, KeyEqual(), alloc) + { + } + + ordered_map(std::initializer_list init, + size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual(), + const Allocator& alloc = Allocator()): + ordered_map(init.begin(), init.end(), bucket_count, hash, equal, alloc) + { + } + + ordered_map(std::initializer_list init, + size_type bucket_count, + const Allocator& alloc): + ordered_map(init.begin(), init.end(), bucket_count, Hash(), KeyEqual(), alloc) + { + } + + ordered_map(std::initializer_list init, + size_type bucket_count, + const Hash& hash, + const Allocator& alloc): + ordered_map(init.begin(), init.end(), bucket_count, hash, KeyEqual(), alloc) + { + } + + + ordered_map& operator=(std::initializer_list ilist) { + m_ht.clear(); + + m_ht.reserve(ilist.size()); + m_ht.insert(ilist.begin(), ilist.end()); + + return *this; + } + + allocator_type get_allocator() const { return m_ht.get_allocator(); } + + + + /* + * Iterators + */ + iterator begin() noexcept { return m_ht.begin(); } + const_iterator begin() const noexcept { return m_ht.begin(); } + const_iterator cbegin() const noexcept { return m_ht.cbegin(); } + + iterator end() noexcept { return m_ht.end(); } + const_iterator end() const noexcept { return m_ht.end(); } + const_iterator cend() const noexcept { return m_ht.cend(); } + + reverse_iterator rbegin() noexcept { return m_ht.rbegin(); } + const_reverse_iterator rbegin() const noexcept { return m_ht.rbegin(); } + const_reverse_iterator rcbegin() const noexcept { return m_ht.rcbegin(); } + + reverse_iterator rend() noexcept { return m_ht.rend(); } + const_reverse_iterator rend() const noexcept { return m_ht.rend(); } + const_reverse_iterator rcend() const noexcept { return m_ht.rcend(); } + + + /* + * Capacity + */ + bool empty() const noexcept { return m_ht.empty(); } + size_type size() const noexcept { return m_ht.size(); } + size_type max_size() const noexcept { return m_ht.max_size(); } + + /* + * Modifiers + */ + void clear() noexcept { m_ht.clear(); } + + + + std::pair insert(const value_type& value) { return m_ht.insert(value); } + + template::value>::type* = nullptr> + std::pair insert(P&& value) { return m_ht.emplace(std::forward

(value)); } + + std::pair insert(value_type&& value) { return m_ht.insert(std::move(value)); } + + + iterator insert(const_iterator hint, const value_type& value) { + return m_ht.insert_hint(hint, value); + } + + template::value>::type* = nullptr> + iterator insert(const_iterator hint, P&& value) { + return m_ht.emplace_hint(hint, std::forward

(value)); + } + + iterator insert(const_iterator hint, value_type&& value) { + return m_ht.insert_hint(hint, std::move(value)); + } + + + template + void insert(InputIt first, InputIt last) { m_ht.insert(first, last); } + void insert(std::initializer_list ilist) { m_ht.insert(ilist.begin(), ilist.end()); } + + + + + template + std::pair insert_or_assign(const key_type& k, M&& obj) { + return m_ht.insert_or_assign(k, std::forward(obj)); + } + + template + std::pair insert_or_assign(key_type&& k, M&& obj) { + return m_ht.insert_or_assign(std::move(k), std::forward(obj)); + } + + + template + iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj) { + return m_ht.insert_or_assign(hint, k, std::forward(obj)); + } + + template + iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj) { + return m_ht.insert_or_assign(hint, std::move(k), std::forward(obj)); + } + + /** + * Due to the way elements are stored, emplace will need to move or copy the key-value once. + * The method is equivalent to insert(value_type(std::forward(args)...)); + * + * Mainly here for compatibility with the std::unordered_map interface. + */ + template + std::pair emplace(Args&&... args) { return m_ht.emplace(std::forward(args)...); } + + /** + * Due to the way elements are stored, emplace_hint will need to move or copy the key-value once. + * The method is equivalent to insert(hint, value_type(std::forward(args)...)); + * + * Mainly here for compatibility with the std::unordered_map interface. + */ + template + iterator emplace_hint(const_iterator hint, Args&&... args) { + return m_ht.emplace_hint(hint, std::forward(args)...); + } + + + + + template + std::pair try_emplace(const key_type& k, Args&&... args) { + return m_ht.try_emplace(k, std::forward(args)...); + } + + template + std::pair try_emplace(key_type&& k, Args&&... args) { + return m_ht.try_emplace(std::move(k), std::forward(args)...); + } + + template + iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args) { + return m_ht.try_emplace_hint(hint, k, std::forward(args)...); + } + + template + iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args) { + return m_ht.try_emplace_hint(hint, std::move(k), std::forward(args)...); + } + + + + + /** + * When erasing an element, the insert order will be preserved and no holes will be present in the container + * returned by 'values_container()'. + * + * The method is in O(n), if the order is not important 'unordered_erase(...)' method is faster with an O(1) + * average complexity. + */ + iterator erase(iterator pos) { return m_ht.erase(pos); } + + /** + * @copydoc erase(iterator pos) + */ + iterator erase(const_iterator pos) { return m_ht.erase(pos); } + + /** + * @copydoc erase(iterator pos) + */ + iterator erase(const_iterator first, const_iterator last) { return m_ht.erase(first, last); } + + /** + * @copydoc erase(iterator pos) + */ + size_type erase(const key_type& key) { return m_ht.erase(key); } + + /** + * @copydoc erase(iterator pos) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup to the value if you already have the hash. + */ + size_type erase(const key_type& key, std::size_t precalculated_hash) { + return m_ht.erase(key, precalculated_hash); + } + + /** + * @copydoc erase(iterator pos) + * + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + size_type erase(const K& key) { return m_ht.erase(key); } + + /** + * @copydoc erase(const key_type& key, std::size_t precalculated_hash) + * + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + size_type erase(const K& key, std::size_t precalculated_hash) { + return m_ht.erase(key, precalculated_hash); + } + + + + void swap(ordered_map& other) { other.m_ht.swap(m_ht); } + + /* + * Lookup + */ + T& at(const Key& key) { return m_ht.at(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + T& at(const Key& key, std::size_t precalculated_hash) { return m_ht.at(key, precalculated_hash); } + + + const T& at(const Key& key) const { return m_ht.at(key); } + + /** + * @copydoc at(const Key& key, std::size_t precalculated_hash) + */ + const T& at(const Key& key, std::size_t precalculated_hash) const { return m_ht.at(key, precalculated_hash); } + + + /** + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + T& at(const K& key) { return m_ht.at(key); } + + /** + * @copydoc at(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + T& at(const K& key, std::size_t precalculated_hash) { return m_ht.at(key, precalculated_hash); } + + /** + * @copydoc at(const K& key) + */ + template::value>::type* = nullptr> + const T& at(const K& key) const { return m_ht.at(key); } + + /** + * @copydoc at(const K& key, std::size_t precalculated_hash) + */ + template::value>::type* = nullptr> + const T& at(const K& key, std::size_t precalculated_hash) const { return m_ht.at(key, precalculated_hash); } + + + + T& operator[](const Key& key) { return m_ht[key]; } + T& operator[](Key&& key) { return m_ht[std::move(key)]; } + + + + size_type count(const Key& key) const { return m_ht.count(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + size_type count(const Key& key, std::size_t precalculated_hash) const { + return m_ht.count(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + size_type count(const K& key) const { return m_ht.count(key); } + + /** + * @copydoc count(const K& key) const + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + size_type count(const K& key, std::size_t precalculated_hash) const { + return m_ht.count(key, precalculated_hash); + } + + + + iterator find(const Key& key) { return m_ht.find(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + iterator find(const Key& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); } + + const_iterator find(const Key& key) const { return m_ht.find(key); } + + /** + * @copydoc find(const Key& key, std::size_t precalculated_hash) + */ + const_iterator find(const Key& key, std::size_t precalculated_hash) const { + return m_ht.find(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + iterator find(const K& key) { return m_ht.find(key); } + + /** + * @copydoc find(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + iterator find(const K& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); } + + /** + * @copydoc find(const K& key) + */ + template::value>::type* = nullptr> + const_iterator find(const K& key) const { return m_ht.find(key); } + + /** + * @copydoc find(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + const_iterator find(const K& key, std::size_t precalculated_hash) const { + return m_ht.find(key, precalculated_hash); + } + + + + std::pair equal_range(const Key& key) { return m_ht.equal_range(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + std::pair equal_range(const Key& key, std::size_t precalculated_hash) { + return m_ht.equal_range(key, precalculated_hash); + } + + std::pair equal_range(const Key& key) const { return m_ht.equal_range(key); } + + /** + * @copydoc equal_range(const Key& key, std::size_t precalculated_hash) + */ + std::pair equal_range(const Key& key, std::size_t precalculated_hash) const { + return m_ht.equal_range(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + std::pair equal_range(const K& key) { return m_ht.equal_range(key); } + + /** + * @copydoc equal_range(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + std::pair equal_range(const K& key, std::size_t precalculated_hash) { + return m_ht.equal_range(key, precalculated_hash); + } + + /** + * @copydoc equal_range(const K& key) + */ + template::value>::type* = nullptr> + std::pair equal_range(const K& key) const { return m_ht.equal_range(key); } + + /** + * @copydoc equal_range(const K& key, std::size_t precalculated_hash) + */ + template::value>::type* = nullptr> + std::pair equal_range(const K& key, std::size_t precalculated_hash) const { + return m_ht.equal_range(key, precalculated_hash); + } + + + + /* + * Bucket interface + */ + size_type bucket_count() const { return m_ht.bucket_count(); } + size_type max_bucket_count() const { return m_ht.max_bucket_count(); } + + + /* + * Hash policy + */ + float load_factor() const { return m_ht.load_factor(); } + float max_load_factor() const { return m_ht.max_load_factor(); } + void max_load_factor(float ml) { m_ht.max_load_factor(ml); } + + void rehash(size_type count) { m_ht.rehash(count); } + void reserve(size_type count) { m_ht.reserve(count); } + + + /* + * Observers + */ + hasher hash_function() const { return m_ht.hash_function(); } + key_equal key_eq() const { return m_ht.key_eq(); } + + + + /* + * Other + */ + + /** + * Convert a const_iterator to an iterator. + */ + iterator mutable_iterator(const_iterator pos) { + return m_ht.mutable_iterator(pos); + } + + /** + * Requires index <= size(). + * + * Return an iterator to the element at index. Return end() if index == size(). + */ + iterator nth(size_type index) { return m_ht.nth(index); } + + /** + * @copydoc nth(size_type index) + */ + const_iterator nth(size_type index) const { return m_ht.nth(index); } + + + /** + * Return const_reference to the first element. Requires the container to not be empty. + */ + const_reference front() const { return m_ht.front(); } + + /** + * Return const_reference to the last element. Requires the container to not be empty. + */ + const_reference back() const { return m_ht.back(); } + + + /** + * Only available if ValueTypeContainer is a std::vector. Same as calling 'values_container().data()'. + */ + template::value>::type* = nullptr> + const typename values_container_type::value_type* data() const noexcept { return m_ht.data(); } + + /** + * Return the container in which the values are stored. The values are in the same order as the insertion order + * and are contiguous in the structure, no holes (size() == values_container().size()). + */ + const values_container_type& values_container() const noexcept { return m_ht.values_container(); } + + template::value>::type* = nullptr> + size_type capacity() const noexcept { return m_ht.capacity(); } + + void shrink_to_fit() { m_ht.shrink_to_fit(); } + + + + /** + * Insert the value before pos shifting all the elements on the right of pos (including pos) one position + * to the right. + * + * Amortized linear time-complexity in the distance between pos and end(). + */ + std::pair insert_at_position(const_iterator pos, const value_type& value) { + return m_ht.insert_at_position(pos, value); + } + + /** + * @copydoc insert_at_position(const_iterator pos, const value_type& value) + */ + std::pair insert_at_position(const_iterator pos, value_type&& value) { + return m_ht.insert_at_position(pos, std::move(value)); + } + + /** + * @copydoc insert_at_position(const_iterator pos, const value_type& value) + * + * Same as insert_at_position(pos, value_type(std::forward(args)...), mainly + * here for coherence. + */ + template + std::pair emplace_at_position(const_iterator pos, Args&&... args) { + return m_ht.emplace_at_position(pos, std::forward(args)...); + } + + /** + * @copydoc insert_at_position(const_iterator pos, const value_type& value) + */ + template + std::pair try_emplace_at_position(const_iterator pos, const key_type& k, Args&&... args) { + return m_ht.try_emplace_at_position(pos, k, std::forward(args)...); + } + + /** + * @copydoc insert_at_position(const_iterator pos, const value_type& value) + */ + template + std::pair try_emplace_at_position(const_iterator pos, key_type&& k, Args&&... args) { + return m_ht.try_emplace_at_position(pos, std::move(k), std::forward(args)...); + } + + + + void pop_back() { m_ht.pop_back(); } + + /** + * Faster erase operation with an O(1) average complexity but it doesn't preserve the insertion order. + * + * If an erasure occurs, the last element of the map will take the place of the erased element. + */ + iterator unordered_erase(iterator pos) { return m_ht.unordered_erase(pos); } + + /** + * @copydoc unordered_erase(iterator pos) + */ + iterator unordered_erase(const_iterator pos) { return m_ht.unordered_erase(pos); } + + /** + * @copydoc unordered_erase(iterator pos) + */ + size_type unordered_erase(const key_type& key) { return m_ht.unordered_erase(key); } + + /** + * @copydoc unordered_erase(iterator pos) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + size_type unordered_erase(const key_type& key, std::size_t precalculated_hash) { + return m_ht.unordered_erase(key, precalculated_hash); + } + + /** + * @copydoc unordered_erase(iterator pos) + * + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + size_type unordered_erase(const K& key) { return m_ht.unordered_erase(key); } + + /** + * @copydoc unordered_erase(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + size_type unordered_erase(const K& key, std::size_t precalculated_hash) { + return m_ht.unordered_erase(key, precalculated_hash); + } + + /** + * Serialize the map through the `serializer` parameter. + * + * The `serializer` parameter must be a function object that supports the following call: + * - `template void operator()(const U& value);` where the types `std::uint64_t`, `float` and `std::pair` must be supported for U. + * + * The implementation leaves binary compatibility (endianness, IEEE 754 for floats, ...) of the types it serializes + * in the hands of the `Serializer` function object if compatibility is required. + */ + template + void serialize(Serializer& serializer) const { + m_ht.serialize(serializer); + } + + /** + * Deserialize a previously serialized map through the `deserializer` parameter. + * + * The `deserializer` parameter must be a function object that supports the following calls: + * - `template U operator()();` where the types `std::uint64_t`, `float` and `std::pair` must be supported for U. + * + * If the deserialized hash map type is hash compatible with the serialized map, the deserialization process can be + * sped up by setting `hash_compatible` to true. To be hash compatible, the Hash and KeyEqual must behave the same way + * than the ones used on the serialized map. The `std::size_t` must also be of the same size as the one on the platform used + * to serialize the map, the same apply for `IndexType`. If these criteria are not met, the behaviour is undefined with + * `hash_compatible` sets to true. + * + * The behaviour is undefined if the type `Key` and `T` of the `ordered_map` are not the same as the + * types used during serialization. + * + * The implementation leaves binary compatibility (endianness, IEEE 754 for floats, size of int, ...) of the types it + * deserializes in the hands of the `Deserializer` function object if compatibility is required. + */ + template + static ordered_map deserialize(Deserializer& deserializer, bool hash_compatible = false) { + ordered_map map(0); + map.m_ht.deserialize(deserializer, hash_compatible); + + return map; + } + + + + friend bool operator==(const ordered_map& lhs, const ordered_map& rhs) { return lhs.m_ht == rhs.m_ht; } + friend bool operator!=(const ordered_map& lhs, const ordered_map& rhs) { return lhs.m_ht != rhs.m_ht; } + friend bool operator<(const ordered_map& lhs, const ordered_map& rhs) { return lhs.m_ht < rhs.m_ht; } + friend bool operator<=(const ordered_map& lhs, const ordered_map& rhs) { return lhs.m_ht <= rhs.m_ht; } + friend bool operator>(const ordered_map& lhs, const ordered_map& rhs) { return lhs.m_ht > rhs.m_ht; } + friend bool operator>=(const ordered_map& lhs, const ordered_map& rhs) { return lhs.m_ht >= rhs.m_ht; } + + friend void swap(ordered_map& lhs, ordered_map& rhs) { lhs.swap(rhs); } + +private: + ht m_ht; +}; + +} // end namespace tsl + +#endif diff --git a/external/tsl/ordered_set.h b/external/tsl/ordered_set.h new file mode 100644 index 000000000..0932f54b9 --- /dev/null +++ b/external/tsl/ordered_set.h @@ -0,0 +1,688 @@ +/** + * MIT License + * + * Copyright (c) 2017 Thibaut Goetghebuer-Planchon + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef TSL_ORDERED_SET_H +#define TSL_ORDERED_SET_H + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ordered_hash.h" + + +namespace tsl { + + +/** + * Implementation of an hash set using open addressing with robin hood with backshift delete to resolve collisions. + * + * The particularity of this hash set is that it remembers the order in which the elements were added and + * provide a way to access the structure which stores these values through the 'values_container()' method. + * The used container is defined by ValueTypeContainer, by default a std::deque is used (grows faster) but + * a std::vector may be used. In this case the set provides a 'data()' method which give a direct access + * to the memory used to store the values (which can be useful to communicate with C API's). + * + * The Key must be copy constructible and/or move constructible. To use `unordered_erase` it also must be swappable. + * + * The behaviour of the hash set is undefined if the destructor of Key throws an exception. + * + * By default the maximum size of a set is limited to 2^32 - 1 values, if needed this can be changed through + * the IndexType template parameter. Using an `uint64_t` will raise this limit to 2^64 - 1 values but each + * bucket will use 16 bytes instead of 8 bytes in addition to the space needed to store the values. + * + * Iterators invalidation: + * - clear, operator=, reserve, rehash: always invalidate the iterators (also invalidate end()). + * - insert, emplace, emplace_hint, operator[]: when a std::vector is used as ValueTypeContainer + * and if size() < capacity(), only end(). + * Otherwise all the iterators are invalidated if an insert occurs. + * - erase, unordered_erase: when a std::vector is used as ValueTypeContainer invalidate the iterator of + * the erased element and all the ones after the erased element (including end()). + * Otherwise all the iterators are invalidated if an erase occurs. + */ +template, + class KeyEqual = std::equal_to, + class Allocator = std::allocator, + class ValueTypeContainer = std::deque, + class IndexType = std::uint_least32_t> +class ordered_set { +private: + template + using has_is_transparent = tsl::detail_ordered_hash::has_is_transparent; + + class KeySelect { + public: + using key_type = Key; + + const key_type& operator()(const Key& key) const noexcept { + return key; + } + + key_type& operator()(Key& key) noexcept { + return key; + } + }; + + using ht = detail_ordered_hash::ordered_hash; + +public: + using key_type = typename ht::key_type; + using value_type = typename ht::value_type; + using size_type = typename ht::size_type; + using difference_type = typename ht::difference_type; + using hasher = typename ht::hasher; + using key_equal = typename ht::key_equal; + using allocator_type = typename ht::allocator_type; + using reference = typename ht::reference; + using const_reference = typename ht::const_reference; + using pointer = typename ht::pointer; + using const_pointer = typename ht::const_pointer; + using iterator = typename ht::iterator; + using const_iterator = typename ht::const_iterator; + using reverse_iterator = typename ht::reverse_iterator; + using const_reverse_iterator = typename ht::const_reverse_iterator; + + using values_container_type = typename ht::values_container_type; + + + /* + * Constructors + */ + ordered_set(): ordered_set(ht::DEFAULT_INIT_BUCKETS_SIZE) { + } + + explicit ordered_set(size_type bucket_count, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual(), + const Allocator& alloc = Allocator()): + m_ht(bucket_count, hash, equal, alloc, ht::DEFAULT_MAX_LOAD_FACTOR) + { + } + + ordered_set(size_type bucket_count, + const Allocator& alloc): ordered_set(bucket_count, Hash(), KeyEqual(), alloc) + { + } + + ordered_set(size_type bucket_count, + const Hash& hash, + const Allocator& alloc): ordered_set(bucket_count, hash, KeyEqual(), alloc) + { + } + + explicit ordered_set(const Allocator& alloc): ordered_set(ht::DEFAULT_INIT_BUCKETS_SIZE, alloc) { + } + + template + ordered_set(InputIt first, InputIt last, + size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual(), + const Allocator& alloc = Allocator()): ordered_set(bucket_count, hash, equal, alloc) + { + insert(first, last); + } + + template + ordered_set(InputIt first, InputIt last, + size_type bucket_count, + const Allocator& alloc): ordered_set(first, last, bucket_count, Hash(), KeyEqual(), alloc) + { + } + + template + ordered_set(InputIt first, InputIt last, + size_type bucket_count, + const Hash& hash, + const Allocator& alloc): ordered_set(first, last, bucket_count, hash, KeyEqual(), alloc) + { + } + + ordered_set(std::initializer_list init, + size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual(), + const Allocator& alloc = Allocator()): + ordered_set(init.begin(), init.end(), bucket_count, hash, equal, alloc) + { + } + + ordered_set(std::initializer_list init, + size_type bucket_count, + const Allocator& alloc): + ordered_set(init.begin(), init.end(), bucket_count, Hash(), KeyEqual(), alloc) + { + } + + ordered_set(std::initializer_list init, + size_type bucket_count, + const Hash& hash, + const Allocator& alloc): + ordered_set(init.begin(), init.end(), bucket_count, hash, KeyEqual(), alloc) + { + } + + + ordered_set& operator=(std::initializer_list ilist) { + m_ht.clear(); + + m_ht.reserve(ilist.size()); + m_ht.insert(ilist.begin(), ilist.end()); + + return *this; + } + + allocator_type get_allocator() const { return m_ht.get_allocator(); } + + + /* + * Iterators + */ + iterator begin() noexcept { return m_ht.begin(); } + const_iterator begin() const noexcept { return m_ht.begin(); } + const_iterator cbegin() const noexcept { return m_ht.cbegin(); } + + iterator end() noexcept { return m_ht.end(); } + const_iterator end() const noexcept { return m_ht.end(); } + const_iterator cend() const noexcept { return m_ht.cend(); } + + reverse_iterator rbegin() noexcept { return m_ht.rbegin(); } + const_reverse_iterator rbegin() const noexcept { return m_ht.rbegin(); } + const_reverse_iterator rcbegin() const noexcept { return m_ht.rcbegin(); } + + reverse_iterator rend() noexcept { return m_ht.rend(); } + const_reverse_iterator rend() const noexcept { return m_ht.rend(); } + const_reverse_iterator rcend() const noexcept { return m_ht.rcend(); } + + + /* + * Capacity + */ + bool empty() const noexcept { return m_ht.empty(); } + size_type size() const noexcept { return m_ht.size(); } + size_type max_size() const noexcept { return m_ht.max_size(); } + + /* + * Modifiers + */ + void clear() noexcept { m_ht.clear(); } + + + + std::pair insert(const value_type& value) { return m_ht.insert(value); } + std::pair insert(value_type&& value) { return m_ht.insert(std::move(value)); } + + iterator insert(const_iterator hint, const value_type& value) { + return m_ht.insert_hint(hint, value); + } + + iterator insert(const_iterator hint, value_type&& value) { + return m_ht.insert_hint(hint, std::move(value)); + } + + template + void insert(InputIt first, InputIt last) { m_ht.insert(first, last); } + void insert(std::initializer_list ilist) { m_ht.insert(ilist.begin(), ilist.end()); } + + + + /** + * Due to the way elements are stored, emplace will need to move or copy the key-value once. + * The method is equivalent to insert(value_type(std::forward(args)...)); + * + * Mainly here for compatibility with the std::unordered_map interface. + */ + template + std::pair emplace(Args&&... args) { return m_ht.emplace(std::forward(args)...); } + + /** + * Due to the way elements are stored, emplace_hint will need to move or copy the key-value once. + * The method is equivalent to insert(hint, value_type(std::forward(args)...)); + * + * Mainly here for compatibility with the std::unordered_map interface. + */ + template + iterator emplace_hint(const_iterator hint, Args&&... args) { + return m_ht.emplace_hint(hint, std::forward(args)...); + } + + /** + * When erasing an element, the insert order will be preserved and no holes will be present in the container + * returned by 'values_container()'. + * + * The method is in O(n), if the order is not important 'unordered_erase(...)' method is faster with an O(1) + * average complexity. + */ + iterator erase(iterator pos) { return m_ht.erase(pos); } + + /** + * @copydoc erase(iterator pos) + */ + iterator erase(const_iterator pos) { return m_ht.erase(pos); } + + /** + * @copydoc erase(iterator pos) + */ + iterator erase(const_iterator first, const_iterator last) { return m_ht.erase(first, last); } + + /** + * @copydoc erase(iterator pos) + */ + size_type erase(const key_type& key) { return m_ht.erase(key); } + + /** + * @copydoc erase(iterator pos) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup to the value if you already have the hash. + */ + size_type erase(const key_type& key, std::size_t precalculated_hash) { + return m_ht.erase(key, precalculated_hash); + } + + /** + * @copydoc erase(iterator pos) + * + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + size_type erase(const K& key) { return m_ht.erase(key); } + + /** + * @copydoc erase(const key_type& key, std::size_t precalculated_hash) + * + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + size_type erase(const K& key, std::size_t precalculated_hash) { + return m_ht.erase(key, precalculated_hash); + } + + + + void swap(ordered_set& other) { other.m_ht.swap(m_ht); } + + /* + * Lookup + */ + size_type count(const Key& key) const { return m_ht.count(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + size_type count(const Key& key, std::size_t precalculated_hash) const { + return m_ht.count(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + size_type count(const K& key) const { return m_ht.count(key); } + + /** + * @copydoc count(const K& key) const + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + size_type count(const K& key, std::size_t precalculated_hash) const { + return m_ht.count(key, precalculated_hash); + } + + + + + iterator find(const Key& key) { return m_ht.find(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + iterator find(const Key& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); } + + const_iterator find(const Key& key) const { return m_ht.find(key); } + + /** + * @copydoc find(const Key& key, std::size_t precalculated_hash) + */ + const_iterator find(const Key& key, std::size_t precalculated_hash) const { + return m_ht.find(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + iterator find(const K& key) { return m_ht.find(key); } + + /** + * @copydoc find(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + iterator find(const K& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); } + + /** + * @copydoc find(const K& key) + */ + template::value>::type* = nullptr> + const_iterator find(const K& key) const { return m_ht.find(key); } + + /** + * @copydoc find(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + const_iterator find(const K& key, std::size_t precalculated_hash) const { + return m_ht.find(key, precalculated_hash); + } + + + + std::pair equal_range(const Key& key) { return m_ht.equal_range(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + std::pair equal_range(const Key& key, std::size_t precalculated_hash) { + return m_ht.equal_range(key, precalculated_hash); + } + + std::pair equal_range(const Key& key) const { return m_ht.equal_range(key); } + + /** + * @copydoc equal_range(const Key& key, std::size_t precalculated_hash) + */ + std::pair equal_range(const Key& key, std::size_t precalculated_hash) const { + return m_ht.equal_range(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + std::pair equal_range(const K& key) { return m_ht.equal_range(key); } + + /** + * @copydoc equal_range(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + std::pair equal_range(const K& key, std::size_t precalculated_hash) { + return m_ht.equal_range(key, precalculated_hash); + } + + /** + * @copydoc equal_range(const K& key) + */ + template::value>::type* = nullptr> + std::pair equal_range(const K& key) const { return m_ht.equal_range(key); } + + /** + * @copydoc equal_range(const K& key, std::size_t precalculated_hash) + */ + template::value>::type* = nullptr> + std::pair equal_range(const K& key, std::size_t precalculated_hash) const { + return m_ht.equal_range(key, precalculated_hash); + } + + + /* + * Bucket interface + */ + size_type bucket_count() const { return m_ht.bucket_count(); } + size_type max_bucket_count() const { return m_ht.max_bucket_count(); } + + + /* + * Hash policy + */ + float load_factor() const { return m_ht.load_factor(); } + float max_load_factor() const { return m_ht.max_load_factor(); } + void max_load_factor(float ml) { m_ht.max_load_factor(ml); } + + void rehash(size_type count) { m_ht.rehash(count); } + void reserve(size_type count) { m_ht.reserve(count); } + + + /* + * Observers + */ + hasher hash_function() const { return m_ht.hash_function(); } + key_equal key_eq() const { return m_ht.key_eq(); } + + + /* + * Other + */ + + /** + * Convert a const_iterator to an iterator. + */ + iterator mutable_iterator(const_iterator pos) { + return m_ht.mutable_iterator(pos); + } + + /** + * Requires index <= size(). + * + * Return an iterator to the element at index. Return end() if index == size(). + */ + iterator nth(size_type index) { return m_ht.nth(index); } + + /** + * @copydoc nth(size_type index) + */ + const_iterator nth(size_type index) const { return m_ht.nth(index); } + + + /** + * Return const_reference to the first element. Requires the container to not be empty. + */ + const_reference front() const { return m_ht.front(); } + + /** + * Return const_reference to the last element. Requires the container to not be empty. + */ + const_reference back() const { return m_ht.back(); } + + + /** + * Only available if ValueTypeContainer is a std::vector. Same as calling 'values_container().data()'. + */ + template::value>::type* = nullptr> + const typename values_container_type::value_type* data() const noexcept { return m_ht.data(); } + + /** + * Return the container in which the values are stored. The values are in the same order as the insertion order + * and are contiguous in the structure, no holes (size() == values_container().size()). + */ + const values_container_type& values_container() const noexcept { return m_ht.values_container(); } + + template::value>::type* = nullptr> + size_type capacity() const noexcept { return m_ht.capacity(); } + + void shrink_to_fit() { m_ht.shrink_to_fit(); } + + + + /** + * Insert the value before pos shifting all the elements on the right of pos (including pos) one position + * to the right. + * + * Amortized linear time-complexity in the distance between pos and end(). + */ + std::pair insert_at_position(const_iterator pos, const value_type& value) { + return m_ht.insert_at_position(pos, value); + } + + /** + * @copydoc insert_at_position(const_iterator pos, const value_type& value) + */ + std::pair insert_at_position(const_iterator pos, value_type&& value) { + return m_ht.insert_at_position(pos, std::move(value)); + } + + /** + * @copydoc insert_at_position(const_iterator pos, const value_type& value) + * + * Same as insert_at_position(pos, value_type(std::forward(args)...), mainly + * here for coherence. + */ + template + std::pair emplace_at_position(const_iterator pos, Args&&... args) { + return m_ht.emplace_at_position(pos, std::forward(args)...); + } + + + + void pop_back() { m_ht.pop_back(); } + + /** + * Faster erase operation with an O(1) average complexity but it doesn't preserve the insertion order. + * + * If an erasure occurs, the last element of the map will take the place of the erased element. + */ + iterator unordered_erase(iterator pos) { return m_ht.unordered_erase(pos); } + + /** + * @copydoc unordered_erase(iterator pos) + */ + iterator unordered_erase(const_iterator pos) { return m_ht.unordered_erase(pos); } + + /** + * @copydoc unordered_erase(iterator pos) + */ + size_type unordered_erase(const key_type& key) { return m_ht.unordered_erase(key); } + + /** + * @copydoc unordered_erase(iterator pos) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + size_type unordered_erase(const key_type& key, std::size_t precalculated_hash) { + return m_ht.unordered_erase(key, precalculated_hash); + } + + /** + * @copydoc unordered_erase(iterator pos) + * + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + size_type unordered_erase(const K& key) { return m_ht.unordered_erase(key); } + + /** + * @copydoc unordered_erase(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + size_type unordered_erase(const K& key, std::size_t precalculated_hash) { + return m_ht.unordered_erase(key, precalculated_hash); + } + + /** + * Serialize the set through the `serializer` parameter. + * + * The `serializer` parameter must be a function object that supports the following call: + * - `void operator()(const U& value);` where the types `std::uint64_t`, `float` and `Key` must be supported for U. + * + * The implementation leaves binary compatibility (endianness, IEEE 754 for floats, ...) of the types it serializes + * in the hands of the `Serializer` function object if compatibility is required. + */ + template + void serialize(Serializer& serializer) const { + m_ht.serialize(serializer); + } + + /** + * Deserialize a previously serialized set through the `deserializer` parameter. + * + * The `deserializer` parameter must be a function object that supports the following calls: + * - `template U operator()();` where the types `std::uint64_t`, `float` and `Key` must be supported for U. + * + * If the deserialized hash set type is hash compatible with the serialized set, the deserialization process can be + * sped up by setting `hash_compatible` to true. To be hash compatible, the Hash and KeyEqual must behave the same way + * than the ones used on the serialized map. The `std::size_t` must also be of the same size as the one on the platform used + * to serialize the map, the same apply for `IndexType`. If these criteria are not met, the behaviour is undefined with + * `hash_compatible` sets to true. + * + * The behaviour is undefined if the type `Key` of the `ordered_set` is not the same as the + * type used during serialization. + * + * The implementation leaves binary compatibility (endianness, IEEE 754 for floats, size of int, ...) of the types it + * deserializes in the hands of the `Deserializer` function object if compatibility is required. + */ + template + static ordered_set deserialize(Deserializer& deserializer, bool hash_compatible = false) { + ordered_set set(0); + set.m_ht.deserialize(deserializer, hash_compatible); + + return set; + } + + + + friend bool operator==(const ordered_set& lhs, const ordered_set& rhs) { return lhs.m_ht == rhs.m_ht; } + friend bool operator!=(const ordered_set& lhs, const ordered_set& rhs) { return lhs.m_ht != rhs.m_ht; } + friend bool operator<(const ordered_set& lhs, const ordered_set& rhs) { return lhs.m_ht < rhs.m_ht; } + friend bool operator<=(const ordered_set& lhs, const ordered_set& rhs) { return lhs.m_ht <= rhs.m_ht; } + friend bool operator>(const ordered_set& lhs, const ordered_set& rhs) { return lhs.m_ht > rhs.m_ht; } + friend bool operator>=(const ordered_set& lhs, const ordered_set& rhs) { return lhs.m_ht >= rhs.m_ht; } + + friend void swap(ordered_set& lhs, ordered_set& rhs) { lhs.swap(rhs); } + +private: + ht m_ht; +}; + +} // end namespace tsl + +#endif diff --git a/include/mpm_properties.h b/include/mpm_properties.h new file mode 100644 index 000000000..cff0edced --- /dev/null +++ b/include/mpm_properties.h @@ -0,0 +1,13 @@ +#ifndef MPM_PROPERTIES_H_ +#define MPM_PROPERTIES_H_ + +namespace mpm { +namespace properties { +//! Scalar Properties +enum Scalar : unsigned int { Mass }; +//! Vector Properties +enum Vector : unsigned int { Velocity, Displacement, Acceleration }; +} // namespace properties +} // namespace mpm + +#endif // MPM_PROPERTIES_H_ diff --git a/tests/particle_test.cc b/tests/particle_test.cc index 0d2656f54..2d65d097e 100644 --- a/tests/particle_test.cc +++ b/tests/particle_test.cc @@ -144,6 +144,18 @@ TEST_CASE("Particle is checked for 1D case", "[particle][1D]") { std::shared_ptr> particle = std::make_shared>(id, coords); + // Check scalar properties + SECTION("Check scalar properties") { + // Check mass + REQUIRE(particle->scalar_property(mpm::properties::Scalar::Mass) == + Approx(0.0).epsilon(Tolerance)); + double mass = 100.5; + particle->update_scalar_property(mpm::properties::Scalar::Mass, true, + mass); + REQUIRE(particle->scalar_property(mpm::properties::Scalar::Mass) == + Approx(100.5).epsilon(Tolerance)); + } + // Check mass REQUIRE(particle->mass() == Approx(0.0).epsilon(Tolerance)); double mass = 100.5; @@ -1222,6 +1234,18 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { std::shared_ptr> particle = std::make_shared>(id, coords); + // Check scalar properties + SECTION("Check scalar properties") { + // Check mass + REQUIRE(particle->scalar_property(mpm::properties::Scalar::Mass) == + Approx(0.0).epsilon(Tolerance)); + double mass = 100.5; + particle->update_scalar_property(mpm::properties::Scalar::Mass, true, + mass); + REQUIRE(particle->scalar_property(mpm::properties::Scalar::Mass) == + Approx(100.5).epsilon(Tolerance)); + } + // Check mass REQUIRE(particle->mass() == Approx(0.0).epsilon(Tolerance)); double mass = 100.5; From 26e5ed92fb6c7eb992b69c2516169563e2b75b7f Mon Sep 17 00:00:00 2001 From: Tianchi Date: Tue, 30 Jun 2020 17:48:06 -0700 Subject: [PATCH 004/175] Add explicit twophase solver --- include/node.h | 16 + include/node.tcc | 117 +++++++ include/node_base.h | 21 ++ include/solvers/mpm_explicit.h | 2 +- include/solvers/mpm_explicit_twophase.h | 89 +++++ include/solvers/mpm_explicit_twophase.tcc | 383 ++++++++++++++++++++++ src/mpm.cc | 11 + 7 files changed, 638 insertions(+), 1 deletion(-) create mode 100644 include/solvers/mpm_explicit_twophase.h create mode 100644 include/solvers/mpm_explicit_twophase.tcc diff --git a/include/node.h b/include/node.h index 2f59f5dde..3dcc32ff3 100644 --- a/include/node.h +++ b/include/node.h @@ -127,6 +127,11 @@ class Node : public NodeBase { return internal_force_.col(phase); } + //! Return drag force coefficient + VectorDim drag_force_coefficient() const override { + return drag_force_coefficient_; + } + //! Update pressure at the nodes from particle //! \param[in] phase Index corresponding to the phase //! \param[in] mass_pressure Product of mass x pressure of a particle @@ -267,6 +272,17 @@ class Node : public NodeBase { //! Compute multimaterial separation vector void compute_multimaterial_separation_vector() override; + //! Compute acceleration and velocity for two phase + //! \param[in] dt Timestep in analysis + bool compute_acceleration_velocity_twophase_explicit( + double dt) noexcept override; + + //! Compute acceleration and velocity for two phase with cundall damping + //! factor \param[in] dt Timestep in analysis \param[in] damping_factor + //! Damping factor + bool compute_acceleration_velocity_twophase_explicit_cundall( + double dt, double damping_factor) noexcept override; + private: //! Mutex std::mutex node_mutex_; diff --git a/include/node.tcc b/include/node.tcc index 9b8ee2975..0606c20a3 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -622,3 +622,120 @@ void mpm::Node +bool mpm::Node:: + compute_acceleration_velocity_twophase_explicit(double dt) noexcept { + bool status = false; + const double tolerance = 1.0E-15; + if (mass_(mpm::NodePhase::nSolid) > tolerance && + mass_(mpm::NodePhase::nLiquid) > tolerance) { + // Compute drag force + VectorDim drag_force = drag_force_coefficient_.cwiseProduct( + velocity_.col(mpm::NodePhase::nLiquid) - + velocity_.col(mpm::NodePhase::nSolid)); + + // Acceleration of pore fluid (momentume balance of fluid phase) + this->acceleration_.col(mpm::NodePhase::nLiquid) = + (this->external_force_.col(mpm::NodePhase::nLiquid) + + this->internal_force_.col(mpm::NodePhase::nLiquid) - drag_force) / + this->mass_(mpm::NodePhase::nLiquid); + + // Acceleration of solid skeleton (momentume balance of mixture) + this->acceleration_.col(mpm::NodePhase::nSolid) = + (this->external_force_.col(mpm::NodePhase::nMixture) + + this->internal_force_.col(mpm::NodePhase::nMixture) - + this->mass_(mpm::NodePhase::nLiquid) * + this->acceleration_.col(mpm::NodePhase::nLiquid)) / + this->mass_(mpm::NodePhase::nSolid); + + // Apply friction constraints + this->apply_friction_constraints(dt); + + // Velocity += acceleration * dt + this->velocity_ += this->acceleration_ * 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(mpm::NodePhase::nSolid)(i)) < tolerance) + velocity_.col(mpm::NodePhase::nSolid)(i) = 0.; + if (std::abs(acceleration_.col(mpm::NodePhase::nSolid)(i)) < tolerance) + acceleration_.col(mpm::NodePhase::nSolid)(i) = 0.; + if (std::abs(velocity_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) + velocity_.col(mpm::NodePhase::nLiquid)(i) = 0.; + if (std::abs(acceleration_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) + acceleration_.col(mpm::NodePhase::nLiquid)(i) = 0.; + } + } + return status; +} + +//! Compute acceleration and velocity for two phase with damping +template +bool mpm::Node:: + compute_acceleration_velocity_twophase_explicit_cundall( + double dt, double damping_factor) noexcept { + bool status = false; + const double tolerance = 1.0E-15; + + if (mass_(mpm::NodePhase::nSolid) > tolerance && + mass_(mpm::NodePhase::nLiquid) > tolerance) { + // Compute drag force + VectorDim drag_force = drag_force_coefficient_.cwiseProduct( + velocity_.col(mpm::NodePhase::nLiquid) - + velocity_.col(mpm::NodePhase::nSolid)); + + // Unbalanced force of liquid phase + auto unbalanced_force_liquid = + this->external_force_.col(mpm::NodePhase::nLiquid) + + this->internal_force_.col(mpm::NodePhase::nLiquid) - drag_force; + // Acceleration of liquid phase (momentume balance of fluid phase) + this->acceleration_.col(mpm::NodePhase::nLiquid) = + (unbalanced_force_liquid - + damping_factor * unbalanced_force_liquid.norm() * + this->velocity_.col(mpm::NodePhase::nLiquid).cwiseSign()) / + this->mass_(mpm::NodePhase::nLiquid); + + // Unbalanced force of solid phase + auto unbalanced_force_solid = + this->external_force_.col(mpm::NodePhase::nMixture) + + this->internal_force_.col(mpm::NodePhase::nMixture) - + this->mass_(mpm::NodePhase::nLiquid) * + this->acceleration_.col(mpm::NodePhase::nLiquid); + // Acceleration of solid phase (momentume balance of mixture) + this->acceleration_.col(mpm::NodePhase::nSolid) = + (unbalanced_force_solid - + damping_factor * unbalanced_force_solid.norm() * + this->velocity_.col(mpm::NodePhase::nSolid).cwiseSign()) / + this->mass_(mpm::NodePhase::nSolid); + + // Apply friction constraints + this->apply_friction_constraints(dt); + + // Velocity += acceleration * dt + this->velocity_ += this->acceleration_ * 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(mpm::NodePhase::nSolid)(i)) < tolerance) + velocity_.col(mpm::NodePhase::nSolid)(i) = 0.; + if (std::abs(acceleration_.col(mpm::NodePhase::nSolid)(i)) < tolerance) + acceleration_.col(mpm::NodePhase::nSolid)(i) = 0.; + if (std::abs(velocity_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) + velocity_.col(mpm::NodePhase::nLiquid)(i) = 0.; + if (std::abs(acceleration_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) + acceleration_.col(mpm::NodePhase::nLiquid)(i) = 0.; + } + status = true; + } + return status; +} \ No newline at end of file diff --git a/include/node_base.h b/include/node_base.h index 4b978051f..698f9c8a1 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -17,6 +17,14 @@ namespace mpm { +//! Nodal phases +enum NodePhase : unsigned int { + nMixture = 0, + nSolid = 0, + nLiquid = 1, + nGas = 2 +}; + //! NodeBase base class for nodes //! \brief Base class that stores the information about node_bases //! \details NodeBase class: id_ and coordinates. @@ -127,6 +135,9 @@ class NodeBase { //! \param[in] phase Index corresponding to the phase virtual VectorDim internal_force(unsigned phase) const = 0; + //! Return drag force coefficient + virtual VectorDim drag_force_coefficient() const = 0; + //! Update pressure at the nodes from particle //! \param[in] phase Index corresponding to the phase //! \param[in] mass_pressure Product of mass x pressure of a particle @@ -257,6 +268,16 @@ class NodeBase { //! Compute multimaterial change in momentum virtual void compute_multimaterial_separation_vector() = 0; + //! Compute acceleration and velocity for two phase + //! \param[in] dt Timestep in analysis + virtual bool compute_acceleration_velocity_twophase_explicit( + double dt) noexcept = 0; + + //! Compute acceleration and velocity for two phase with cundall damping + //! \param[in] dt Timestep in analysis + virtual bool compute_acceleration_velocity_twophase_explicit_cundall( + double dt, double damping_factor) noexcept = 0; + }; // NodeBase class } // namespace mpm diff --git a/include/solvers/mpm_explicit.h b/include/solvers/mpm_explicit.h index 60ee53040..a7e6020ca 100644 --- a/include/solvers/mpm_explicit.h +++ b/include/solvers/mpm_explicit.h @@ -39,7 +39,7 @@ class MPMExplicit : public MPMBase { using mpm::MPMBase::step_; //! Number of steps using mpm::MPMBase::nsteps_; - //! Number of steps + //! Load balance step using mpm::MPMBase::nload_balance_steps_; //! Output steps using mpm::MPMBase::output_steps_; diff --git a/include/solvers/mpm_explicit_twophase.h b/include/solvers/mpm_explicit_twophase.h new file mode 100644 index 000000000..3e1f395c8 --- /dev/null +++ b/include/solvers/mpm_explicit_twophase.h @@ -0,0 +1,89 @@ +#ifndef MPM_MPM_EXPLICIT_TWOPHASE_H_ +#define MPM_MPM_EXPLICIT_TWOPHASE_H_ + +#ifdef USE_GRAPH_PARTITIONING +#include "graph.h" +#endif + +#include "mpm_base.h" + +namespace mpm { + +//! MPMExplicitTwoPhase class +//! \brief A class that implements the fully explicit two phase mpm +//! \details A two-phase explicit MPM +//! \tparam Tdim Dimension +template +class MPMExplicitTwoPhase : public MPMBase { + public: + //! Default constructor + MPMExplicitTwoPhase(const std::shared_ptr& io); + + //! Solve + bool solve() override; + + //! Pressure smoothing + //! \param[in] phase Phase to smooth pressure + void pressure_smoothing(unsigned phase); + + //! Compute stress strain + void compute_stress_strain(); + + protected: + // 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_; + //! Load balance step + using mpm::MPMBase::nload_balance_steps_; + //! 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_; + +#ifdef USE_GRAPH_PARTITIONING + //! Graph + using mpm::MPMBase::graph_; +#endif + + //! 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_; + //! Node concentrated force + using mpm::MPMBase::set_node_concentrated_force_; + //! Damping type + using mpm::MPMBase::damping_type_; + //! Damping factor + using mpm::MPMBase::damping_factor_; + //! Locate particles + using mpm::MPMBase::locate_particles_; + + private: + //! Pressure smoothing + bool pressure_smoothing_{false}; + //! Pore pressure smoothing + bool pore_pressure_smoothing_{true}; + +}; // MPMExplicitTwoPhase class +} // namespace mpm + +#include "mpm_explicit_twophase.tcc" + +#endif // MPM_MPM_EXPLICIT_TWOPHASE_H_ diff --git a/include/solvers/mpm_explicit_twophase.tcc b/include/solvers/mpm_explicit_twophase.tcc new file mode 100644 index 000000000..a3406b1d4 --- /dev/null +++ b/include/solvers/mpm_explicit_twophase.tcc @@ -0,0 +1,383 @@ +//! Constructor +template +mpm::MPMExplicitTwoPhase::MPMExplicitTwoPhase( + const std::shared_ptr& io) + : mpm::MPMBase(io) { + //! Logger + console_ = spdlog::get("MPMExplicitTwoPhase"); +} + +//! MPM Explicit two-phase pressure smoothing +template +void mpm::MPMExplicitTwoPhase::pressure_smoothing(unsigned phase) { + + // Map pressures to nodes + if (phase == mpm::ParticlePhase::Solid) { + // Assign pressure to nodes + mesh_->iterate_over_particles( + std::bind(&mpm::ParticleBase::map_pressure_to_nodes, + std::placeholders::_1)); + } else if (phase == mpm::ParticlePhase::Liquid) { + // Assign pore pressure to nodes + mesh_->iterate_over_particles( + std::bind(&mpm::ParticleBase::map_pore_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 + if (phase == mpm::ParticlePhase::Solid) { + // Smooth pressure over particles + mesh_->iterate_over_particles( + std::bind(&mpm::ParticleBase::compute_pressure_smoothing, + std::placeholders::_1)); + } else if (phase == mpm::ParticlePhase::Liquid) { + // Smooth pore pressure over particles + mesh_->iterate_over_particles( + std::bind(&mpm::ParticleBase::compute_pore_pressure_smoothing, + std::placeholders::_1)); + } +} + +//! MPM Explicit two-phase compute stress strain +template +void mpm::MPMExplicitTwoPhase::compute_stress_strain() { + // Iterate over each particle to calculate strain + mesh_->iterate_over_particles(std::bind( + &mpm::ParticleBase::compute_strain, std::placeholders::_1, dt_)); + + // Iterate over each particle to update particle volume + mesh_->iterate_over_particles(std::bind( + &mpm::ParticleBase::update_volume, std::placeholders::_1)); + + // Iterate over each particle to update particle porosity + mesh_->iterate_over_particles(std::bind( + &mpm::ParticleBase::update_porosity, std::placeholders::_1, dt_)); + + // Pressure smoothing + if (pressure_smoothing_) this->pressure_smoothing(mpm::ParticlePhase::Solid); + + // Iterate over each particle to compute stress + mesh_->iterate_over_particles(std::bind( + &mpm::ParticleBase::compute_stress, std::placeholders::_1)); + + // Iterate over each particle to compute pore pressure + mesh_->iterate_over_particles( + std::bind(&mpm::ParticleBase::compute_pore_pressure, + std::placeholders::_1, dt_)); + + // Pore pressure smoothing + if (pore_pressure_smoothing_) + this->pressure_smoothing(mpm::ParticlePhase::Liquid); +} + +//! MPM Explicit two-phase solver +template +bool mpm::MPMExplicitTwoPhase::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 + + // 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(); + + // Pore pressure smoothing + if (analysis_.find("pore_pressure_smoothing") != analysis_.end()) + pore_pressure_smoothing_ = + analysis_["pore_pressure_smoothing"].template get(); + + // Initialise materials + 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"); + } + + // Compute mass for each phase + mesh_->iterate_over_particles( + std::bind(&mpm::ParticleBase::compute_mass, std::placeholders::_1)); + + // Check point resume + if (resume) this->checkpoint_resume(); + + // Domain decompose + bool initial_step = (resume == true) ? false : true; + this->mpi_domain_decompose(initial_step); + + 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_); + +#ifdef USE_MPI +#ifdef USE_GRAPH_PARTITIONING + // Run load balancer at a specified frequency + if (step_ % nload_balance_steps_ == 0 && step_ != 0) + this->mpi_domain_decompose(false); +#endif +#endif + + // 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)); + }); + + // 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 + mesh_->iterate_over_particles( + std::bind(&mpm::ParticleBase::map_mass_momentum_to_nodes, + std::placeholders::_1)); + +#ifdef USE_MPI + // Run if there is more than a single MPI task + if (mpi_size > 1) { + // MPI all reduce nodal mass for solid phase + mesh_->template nodal_halo_exchange( + std::bind(&mpm::NodeBase::mass, std::placeholders::_1, + mpm::ParticlePhase::Solid), + std::bind(&mpm::NodeBase::update_mass, std::placeholders::_1, + false, mpm::ParticlePhase::Solid, std::placeholders::_2)); + // MPI all reduce nodal momentum for solid phase + mesh_->template nodal_halo_exchange, Tdim>( + std::bind(&mpm::NodeBase::momentum, std::placeholders::_1, + mpm::ParticlePhase::Solid), + std::bind(&mpm::NodeBase::update_momentum, + std::placeholders::_1, false, mpm::ParticlePhase::Solid, + std::placeholders::_2)); + + // MPI all reduce nodal mass for liquid phase + mesh_->template nodal_halo_exchange( + std::bind(&mpm::NodeBase::mass, std::placeholders::_1, + mpm::ParticlePhase::Liquid), + std::bind(&mpm::NodeBase::update_mass, std::placeholders::_1, + false, mpm::ParticlePhase::Liquid, std::placeholders::_2)); + // MPI all reduce nodal momentum for liquid phase + mesh_->template nodal_halo_exchange, Tdim>( + std::bind(&mpm::NodeBase::momentum, std::placeholders::_1, + mpm::ParticlePhase::Liquid), + std::bind(&mpm::NodeBase::update_momentum, + std::placeholders::_1, false, mpm::ParticlePhase::Liquid, + std::placeholders::_2)); + } +#endif + + // 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)); + + // Update stress first + if (this->stress_update_ == mpm::StressUpdate::USF) + this->compute_stress_strain(); + + // 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_); + + // Iterate over each node to add concentrated node force to external force + if (set_node_concentrated_force_) + mesh_->iterate_over_nodes( + std::bind(&mpm::NodeBase::apply_concentrated_force, + std::placeholders::_1, mpm::ParticlePhase::Solid, + (this->step_ * this->dt_))); + }); + + // Spawn a task for internal force + task_group.run([&] { + // Iterate over particles to compute nodal mixture and fluid internal + // force + mesh_->iterate_over_particles(std::bind( + &mpm::ParticleBase::map_internal_force, std::placeholders::_1)); + + // Iterate over particles to compute nodal drag force coefficient + mesh_->iterate_over_particles( + std::bind(&mpm::ParticleBase::map_drag_force_coefficient, + std::placeholders::_1)); + }); + task_group.wait(); + +#ifdef USE_MPI + // Run if there is more than a single MPI task + if (mpi_size > 1) { + // MPI all reduce external force of mixture + mesh_->template nodal_halo_exchange, Tdim>( + std::bind(&mpm::NodeBase::external_force, std::placeholders::_1, + mpm::ParticlePhase::Mixture), + std::bind(&mpm::NodeBase::update_external_force, + std::placeholders::_1, false, mpm::ParticlePhase::Mixture, + std::placeholders::_2)); + // MPI all reduce external force of pore fluid + mesh_->template nodal_halo_exchange, Tdim>( + std::bind(&mpm::NodeBase::external_force, std::placeholders::_1, + mpm::ParticlePhase::Liquid), + std::bind(&mpm::NodeBase::update_external_force, + std::placeholders::_1, false, mpm::ParticlePhase::Liquid, + std::placeholders::_2)); + + // MPI all reduce internal force of mixture + mesh_->template nodal_halo_exchange, Tdim>( + std::bind(&mpm::NodeBase::internal_force, std::placeholders::_1, + mpm::ParticlePhase::Mixture), + std::bind(&mpm::NodeBase::update_internal_force, + std::placeholders::_1, false, mpm::ParticlePhase::Mixture, + std::placeholders::_2)); + // MPI all reduce internal force of pore liquid + mesh_->template nodal_halo_exchange, Tdim>( + std::bind(&mpm::NodeBase::internal_force, std::placeholders::_1, + mpm::ParticlePhase::Liquid), + std::bind(&mpm::NodeBase::update_internal_force, + std::placeholders::_1, false, mpm::ParticlePhase::Liquid, + std::placeholders::_2)); + + // MPI all reduce drag force + mesh_->template nodal_halo_exchange, Tdim>( + std::bind(&mpm::NodeBase::drag_force_coefficient, + std::placeholders::_1), + std::bind(&mpm::NodeBase::update_drag_force_coefficient, + std::placeholders::_1, false, std::placeholders::_2)); + } +#endif + + // Check if damping has been specified and accordingly Iterate over + // active nodes to compute acceleratation and velocity + if (damping_type_ == mpm::Damping::Cundall) + mesh_->iterate_over_nodes_predicate( + std::bind(&mpm::NodeBase:: + compute_acceleration_velocity_twophase_explicit_cundall, + std::placeholders::_1, this->dt_, damping_factor_), + std::bind(&mpm::NodeBase::status, std::placeholders::_1)); + else + mesh_->iterate_over_nodes_predicate( + std::bind(&mpm::NodeBase< + Tdim>::compute_acceleration_velocity_twophase_explicit, + std::placeholders::_1, 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(); + + // Update Stress Last + if (this->stress_update_ == mpm::StressUpdate::USL) + this->compute_stress_strain(); + + // 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); + +#ifdef USE_MPI +#ifdef USE_GRAPH_PARTITIONING + mesh_->transfer_halo_particles(); +#endif +#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 +#ifdef USE_PARTIO + // Partio outputs + this->write_partio(this->step_, this->nsteps_); +#endif + } + } + auto solver_end = std::chrono::steady_clock::now(); + console_->info( + "Rank {}, ExplicitTwoPhase {} solver duration: {} ms", mpi_rank, + (this->stress_update_ == mpm::StressUpdate::USL ? "USL" : "USF"), + std::chrono::duration_cast(solver_end - + solver_begin) + .count()); + + return status; +} \ No newline at end of file diff --git a/src/mpm.cc b/src/mpm.cc index 19b3f5dc9..02bd0e17f 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_explicit_twophase.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 Explicit Two Phase MPM +static Register, + const std::shared_ptr&> + mpm_explicit_twophase_2d("MPMExplicitTwoPhase2D"); + +// 3D Explicit Two Phase MPM +static Register, + const std::shared_ptr&> + mpm_explicit_twophase_3d("MPMExplicitTwoPhase3D"); \ No newline at end of file From e68ab89ced068421a49e758de032eb98a98ed40d Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Sat, 4 Jul 2020 16:16:54 -0500 Subject: [PATCH 005/175] :computer: Compute mass free function --- include/particles/particle.h | 5 +++++ include/particles/particle.tcc | 6 ++++++ include/particles/particle_base.h | 4 ++++ include/particles/particle_functions.tcc | 17 +++++++++++++++++ tests/particle_test.cc | 7 ++++++- 5 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 include/particles/particle_functions.tcc diff --git a/include/particles/particle.h b/include/particles/particle.h index 542764001..b22aa09f9 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -159,6 +159,10 @@ class Particle : public ParticleBase { bool assign_material( const std::shared_ptr>& material) override; + //! Return material + //! \retval material Pointer to a material + std::shared_ptr> material() const override; + //! Compute strain //! \param[in] dt Analysis time step void compute_strain(double dt) noexcept override; @@ -357,5 +361,6 @@ class Particle : public ParticleBase { } // namespace mpm #include "particle.tcc" +#include "particle_functions.tcc" #endif // MPM_PARTICLE_H__ diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index 2115d59f4..d80589759 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -393,6 +393,12 @@ bool mpm::Particle::assign_material( return status; } +// Return material of particle +template +std::shared_ptr> mpm::Particle::material() const { + return material_; +} + // Compute reference location cell to particle template bool mpm::Particle::compute_reference_location() noexcept { diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 32afefd8b..5e0128abc 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -197,6 +197,10 @@ class ParticleBase { virtual bool assign_material( const std::shared_ptr>& material) = 0; + //! Return material + //! \retval material Pointer to a material + virtual std::shared_ptr> material() const = 0; + //! Return material id unsigned material_id() const { return material_id_; } diff --git a/include/particles/particle_functions.tcc b/include/particles/particle_functions.tcc new file mode 100644 index 000000000..0a5a71f4c --- /dev/null +++ b/include/particles/particle_functions.tcc @@ -0,0 +1,17 @@ +// Compute mass of particle +namespace mpm { +namespace particle { +template +void compute_mass(std::shared_ptr> particle) noexcept { + // Check if particle volume is set and material ptr is valid + assert(particle->volume() != std::numeric_limits::max() && + particle->material() != nullptr); + // Mass = volume of particle * mass_density + auto density = + (particle->material())->template property(std::string("density")); + // Update particle mass + particle->update_scalar_property(mpm::properties::Scalar::Mass, false, + particle->volume() * density); +} +} // namespace particle +} // namespace mpm diff --git a/tests/particle_test.cc b/tests/particle_test.cc index 2d65d097e..0dfe49a8d 100644 --- a/tests/particle_test.cc +++ b/tests/particle_test.cc @@ -630,7 +630,8 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { // Add particle mpm::Index id = 0; coords << 0.75, 0.75; - auto particle = std::make_shared>(id, coords); + std::shared_ptr> particle = + std::make_shared>(id, coords); // Time-step const double dt = 0.1; @@ -752,6 +753,10 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { REQUIRE_NOTHROW(particle->compute_mass()); // Mass REQUIRE(particle->mass() == Approx(1000.).epsilon(Tolerance)); + // Compute mass function + REQUIRE_NOTHROW(mpm::particle::compute_mass(particle)); + REQUIRE(particle->scalar_property(mpm::properties::Scalar::Mass) == + Approx(1000.).epsilon(Tolerance)); // Map particle mass to nodes particle->assign_mass(std::numeric_limits::max()); From 67303d8e9d2bd8736b50fba63e4a16ce9474cf69 Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 8 Jul 2020 16:20:24 -0700 Subject: [PATCH 006/175] :wrench: modify mass, mass_density_volume --- include/particles/particle.h | 22 +++++----- include/particles/particle.tcc | 79 +++++++++++++++++++--------------- tests/particle_test.cc | 12 +++--- 3 files changed, 63 insertions(+), 50 deletions(-) diff --git a/include/particles/particle.h b/include/particles/particle.h index 92f392063..1b692ca97 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -117,7 +117,9 @@ class Particle : public ParticleBase { bool assign_volume(double volume) override; //! Return volume - double volume() const override { return volume_; } + double volume() const override { + return this->scalar_property(mpm::properties::Scalar::Volume); + } //! Return size of particle in natural coordinates VectorDim natural_size() const override { return natural_size_; } @@ -129,7 +131,9 @@ class Particle : public ParticleBase { void update_volume() noexcept override; //! \param[in] phase Index corresponding to the phase - double mass_density() const override { return mass_density_; } + double mass_density() const override { + return this->scalar_property(mpm::properties::Scalar::MassDensity); + } //! Compute mass as volume * density void compute_mass() noexcept override; @@ -149,10 +153,14 @@ class Particle : public ParticleBase { //! Assign nodal mass to particles //! \param[in] mass Mass from the particles in a cell //! \retval status Assignment status - void assign_mass(double mass) override { mass_ = mass; } + void assign_mass(double mass) override { + scalar_properties_.at(mpm::properties::Scalar::Mass) = mass; + } //! Return mass of the particles - double mass() const override { return mass_; } + double mass() const override { + return this->scalar_property(mpm::properties::Scalar::Mass); + } //! Assign material //! \param[in] material Pointer to a material @@ -316,12 +324,6 @@ class Particle : public ParticleBase { using ParticleBase::vector_properties_; //! Shape functions using ParticleBase::shapefn_; - //! Volumetric mass density (mass / volume) - double mass_density_{0.}; - //! Mass - double mass_{0.}; - //! Volume - double volume_{0.}; //! Size of particle Eigen::Matrix size_; //! Size of particle in natural coordinates diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index af5984e9b..5eb9cdf72 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -9,9 +9,6 @@ mpm::Particle::Particle(Index id, const VectorDim& coord) nodes_.clear(); // Set material pointer to null material_ = nullptr; - // Scalar properties - scalar_properties_.emplace( - std::make_pair(mpm::properties::Scalar::Mass, double(0.))); // Logger std::string logger = "particle" + std::to_string(Tdim) + "d::" + std::to_string(id); @@ -39,11 +36,12 @@ bool mpm::Particle::initialise_particle(const HDF5Particle& particle) { // Assign id this->id_ = particle.id; // Mass - this->mass_ = particle.mass; + scalar_properties_.at(mpm::properties::Scalar::Mass) = particle.mass; // Volume - this->volume_ = particle.volume; + scalar_properties_.at(mpm::properties::Scalar::Volume) = particle.volume; // Mass Density - this->mass_density_ = particle.mass / particle.volume; + scalar_properties_.at(mpm::properties::Scalar::MassDensity) = + particle.mass / particle.volume; // Set local size of particle Eigen::Vector3d psize; psize << particle.nsize_x, particle.nsize_y, particle.nsize_z; @@ -228,7 +226,6 @@ template void mpm::Particle::initialise() { displacement_.setZero(); dstrain_.setZero(); - mass_ = 0.; natural_size_.setZero(); set_traction_ = false; size_.setZero(); @@ -237,9 +234,16 @@ void mpm::Particle::initialise() { stress_.setZero(); traction_.setZero(); velocity_.setZero(); - volume_ = std::numeric_limits::max(); volumetric_strain_centroid_ = 0.; + // Initialize scalar properties + scalar_properties_.emplace( + std::make_pair(mpm::properties::Scalar::Mass, double(0.))); + scalar_properties_.emplace( + std::make_pair(mpm::properties::Scalar::MassDensity, double(0.))); + scalar_properties_.emplace(std::make_pair( + mpm::properties::Scalar::Volume, std::numeric_limits::max())); + // Initialize vector data properties this->properties_["stresses"] = [&]() { return stress(); }; this->properties_["strains"] = [&]() { return strain(); }; @@ -442,10 +446,10 @@ bool mpm::Particle::assign_volume(double volume) { if (volume <= 0.) throw std::runtime_error("Particle volume cannot be negative"); - this->volume_ = volume; + scalar_properties_.at(mpm::properties::Scalar::Volume) = volume; // Compute size of particle in each direction const double length = - std::pow(this->volume_, static_cast(1. / Tdim)); + std::pow(this->volume(), static_cast(1. / Tdim)); // Set particle size as length on each side this->size_.fill(length); @@ -479,36 +483,42 @@ void mpm::Particle::compute_volume() noexcept { template void mpm::Particle::update_volume() noexcept { // Check if particle has a valid cell ptr and a valid volume - assert(cell_ != nullptr && volume_ != std::numeric_limits::max()); + assert(cell_ != nullptr && + this->volume() != std::numeric_limits::max()); // Compute at centroid // Strain rate for reduced integration - this->volume_ *= (1. + dvolumetric_strain_); - this->mass_density_ = this->mass_density_ / (1. + dvolumetric_strain_); + scalar_properties_.at(mpm::properties::Scalar::Volume) *= + (1. + dvolumetric_strain_); + scalar_properties_.at(mpm::properties::Scalar::MassDensity) = + scalar_properties_.at(mpm::properties::Scalar::MassDensity) / + (1. + dvolumetric_strain_); } // Compute mass of particle template void mpm::Particle::compute_mass() noexcept { // Check if particle volume is set and material ptr is valid - assert(volume_ != std::numeric_limits::max() && material_ != nullptr); + assert(this->volume() != std::numeric_limits::max() && + material_ != nullptr); // Mass = volume of particle * mass_density - this->mass_density_ = + scalar_properties_.at(mpm::properties::Scalar::MassDensity) = material_->template property(std::string("density")); - this->mass_ = volume_ * mass_density_; + scalar_properties_.at(mpm::properties::Scalar::Mass) = + this->volume() * this->mass_density(); } //! Map particle mass and momentum to nodes template void mpm::Particle::map_mass_momentum_to_nodes() noexcept { // Check if particle mass is set - assert(mass_ != std::numeric_limits::max()); + assert(this->mass() != std::numeric_limits::max()); // Map mass and momentum to nodes for (unsigned i = 0; i < nodes_.size(); ++i) { nodes_[i]->update_mass(true, mpm::ParticlePhase::Solid, - mass_ * shapefn_[i]); + this->mass() * shapefn_[i]); nodes_[i]->update_momentum(true, mpm::ParticlePhase::Solid, - mass_ * shapefn_[i] * velocity_); + this->mass() * shapefn_[i] * velocity_); } } @@ -516,14 +526,14 @@ void mpm::Particle::map_mass_momentum_to_nodes() noexcept { template void mpm::Particle::map_multimaterial_mass_momentum_to_nodes() noexcept { // Check if particle mass is set - assert(mass_ != std::numeric_limits::max()); + assert(this->mass() != std::numeric_limits::max()); // Unit 1x1 Eigen matrix to be used with scalar quantities Eigen::Matrix nodal_mass; // Map mass and momentum to nodal property taking into account the material id for (unsigned i = 0; i < nodes_.size(); ++i) { - nodal_mass(0, 0) = mass_ * shapefn_[i]; + nodal_mass(0, 0) = this->mass() * shapefn_[i]; nodes_[i]->update_property(true, "masses", nodal_mass, material_id_, 1); nodes_[i]->update_property(true, "momenta", velocity_ * nodal_mass, material_id_, Tdim); @@ -534,12 +544,12 @@ void mpm::Particle::map_multimaterial_mass_momentum_to_nodes() noexcept { template void mpm::Particle::map_multimaterial_displacements_to_nodes() noexcept { // Check if particle mass is set - assert(mass_ != std::numeric_limits::max()); + assert(this->mass() != std::numeric_limits::max()); // Map displacements to nodal property and divide it by the respective // nodal-material mass for (unsigned i = 0; i < nodes_.size(); ++i) { - const auto& displacement = mass_ * shapefn_[i] * displacement_; + const auto& displacement = this->mass() * shapefn_[i] * displacement_; nodes_[i]->update_property(true, "displacements", displacement, material_id_, Tdim); } @@ -550,13 +560,14 @@ template void mpm::Particle< Tdim>::map_multimaterial_domain_gradients_to_nodes() noexcept { // Check if particle volume is set - assert(volume_ != std::numeric_limits::max()); + assert(this->volume() != std::numeric_limits::max()); // Map domain gradients to nodal property. The domain gradients is defined as // the gradient of the particle volume for (unsigned i = 0; i < nodes_.size(); ++i) { Eigen::Matrix gradient; - for (unsigned j = 0; j < Tdim; ++j) gradient[j] = volume_ * dn_dx_(i, j); + for (unsigned j = 0; j < Tdim; ++j) + gradient[j] = this->volume() * dn_dx_(i, j); nodes_[i]->update_property(true, "domain_gradients", gradient, material_id_, Tdim); } @@ -656,7 +667,7 @@ void mpm::Particle::map_body_force(const VectorDim& pgravity) noexcept { // Compute nodal body forces for (unsigned i = 0; i < nodes_.size(); ++i) nodes_[i]->update_external_force(true, mpm::ParticlePhase::Solid, - (pgravity * mass_ * shapefn_(i))); + (pgravity * this->mass() * shapefn_(i))); } //! Map internal force @@ -666,7 +677,7 @@ inline void mpm::Particle<1>::map_internal_force() noexcept { for (unsigned i = 0; i < nodes_.size(); ++i) { // Compute force: -pstress * volume Eigen::Matrix force; - force[0] = -1. * dn_dx_(i, 0) * volume_ * stress_[0]; + force[0] = -1. * dn_dx_(i, 0) * this->volume() * stress_[0]; nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Solid, force); } @@ -682,7 +693,7 @@ inline void mpm::Particle<2>::map_internal_force() noexcept { force[0] = dn_dx_(i, 0) * stress_[0] + dn_dx_(i, 1) * stress_[3]; force[1] = dn_dx_(i, 1) * stress_[1] + dn_dx_(i, 0) * stress_[3]; - force *= -1. * this->volume_; + force *= -1. * this->volume(); nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Solid, force); } @@ -704,7 +715,7 @@ inline void mpm::Particle<3>::map_internal_force() noexcept { force[2] = dn_dx_(i, 2) * stress_[2] + dn_dx_(i, 1) * stress_[4] + dn_dx_(i, 0) * stress_[5]; - force *= -1. * this->volume_; + force *= -1. * this->volume(); nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Solid, force); } @@ -725,12 +736,12 @@ bool mpm::Particle::assign_traction(unsigned direction, double traction) { bool status = false; try { if (direction >= Tdim || - this->volume_ == std::numeric_limits::max()) { + this->volume() == std::numeric_limits::max()) { throw std::runtime_error( "Particle traction property: volume / direction is invalid"); } // Assign traction - traction_(direction) = traction * this->volume_ / this->size_(direction); + traction_(direction) = traction * this->volume() / this->size_(direction); status = true; this->set_traction_ = true; } catch (std::exception& exception) { @@ -791,17 +802,17 @@ void mpm::Particle::compute_updated_position( template bool mpm::Particle::map_pressure_to_nodes() noexcept { // Mass is initialized - assert(mass_ != std::numeric_limits::max()); + assert(this->mass() != std::numeric_limits::max()); bool status = false; // Check if particle mass is set and state variable pressure is found - if (mass_ != std::numeric_limits::max() && + if (this->mass() != std::numeric_limits::max() && (state_variables_.find("pressure") != state_variables_.end())) { // Map particle pressure to nodes for (unsigned i = 0; i < nodes_.size(); ++i) nodes_[i]->update_mass_pressure( mpm::ParticlePhase::Solid, - shapefn_[i] * mass_ * state_variables_["pressure"]); + shapefn_[i] * this->mass() * state_variables_["pressure"]); status = true; } diff --git a/tests/particle_test.cc b/tests/particle_test.cc index 0dfe49a8d..64f835b80 100644 --- a/tests/particle_test.cc +++ b/tests/particle_test.cc @@ -157,10 +157,10 @@ TEST_CASE("Particle is checked for 1D case", "[particle][1D]") { } // Check mass - REQUIRE(particle->mass() == Approx(0.0).epsilon(Tolerance)); - double mass = 100.5; - particle->assign_mass(mass); REQUIRE(particle->mass() == Approx(100.5).epsilon(Tolerance)); + double mass = 201.0; + particle->assign_mass(mass); + REQUIRE(particle->mass() == Approx(201.0).epsilon(Tolerance)); // Check stress Eigen::Matrix stress; @@ -1252,10 +1252,10 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { } // Check mass - REQUIRE(particle->mass() == Approx(0.0).epsilon(Tolerance)); - double mass = 100.5; - particle->assign_mass(mass); REQUIRE(particle->mass() == Approx(100.5).epsilon(Tolerance)); + double mass = 201.0; + particle->assign_mass(mass); + REQUIRE(particle->mass() == Approx(201.0).epsilon(Tolerance)); // Check stress Eigen::Matrix stress; From 0a6ac168b24006f9c35a5c9d21d5d00effca6107 Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 8 Jul 2020 16:34:26 -0700 Subject: [PATCH 007/175] :wrench: modify compute_mass function --- include/mesh.tcc | 2 +- include/particles/particle.h | 3 --- include/particles/particle.tcc | 13 ------------- include/particles/particle_base.h | 3 --- include/particles/particle_functions.tcc | 10 ++++++---- include/solvers/mpm_explicit.tcc | 4 +++- tests/particle_cell_crossing_test.cc | 10 ++++++---- tests/particle_test.cc | 22 ++++++++-------------- 8 files changed, 24 insertions(+), 43 deletions(-) diff --git a/include/mesh.tcc b/include/mesh.tcc index 0379a344b..3f03363c8 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1752,7 +1752,7 @@ void mpm::Mesh::inject_particles(double current_time) { } for (auto particle : injected_particles) { particle->compute_volume(); - particle->compute_mass(); + mpm::particle::compute_mass(particle); } } } diff --git a/include/particles/particle.h b/include/particles/particle.h index 1b692ca97..1dc76319f 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -135,9 +135,6 @@ class Particle : public ParticleBase { return this->scalar_property(mpm::properties::Scalar::MassDensity); } - //! Compute mass as volume * density - void compute_mass() noexcept override; - //! Map particle mass and momentum to nodes void map_mass_momentum_to_nodes() noexcept override; diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index 5eb9cdf72..1218cbab2 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -494,19 +494,6 @@ void mpm::Particle::update_volume() noexcept { (1. + dvolumetric_strain_); } -// Compute mass of particle -template -void mpm::Particle::compute_mass() noexcept { - // Check if particle volume is set and material ptr is valid - assert(this->volume() != std::numeric_limits::max() && - material_ != nullptr); - // Mass = volume of particle * mass_density - scalar_properties_.at(mpm::properties::Scalar::MassDensity) = - material_->template property(std::string("density")); - scalar_properties_.at(mpm::properties::Scalar::Mass) = - this->volume() * this->mass_density(); -} - //! Map particle mass and momentum to nodes template void mpm::Particle::map_mass_momentum_to_nodes() noexcept { diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index dcf9ec042..71f6269fb 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -181,9 +181,6 @@ class ParticleBase { //! Return mass density virtual double mass_density() const = 0; - //! Compute mass of particle - virtual void compute_mass() noexcept = 0; - //! Map particle mass and momentum to nodes virtual void map_mass_momentum_to_nodes() noexcept = 0; diff --git a/include/particles/particle_functions.tcc b/include/particles/particle_functions.tcc index 0a5a71f4c..0cd83e5ee 100644 --- a/include/particles/particle_functions.tcc +++ b/include/particles/particle_functions.tcc @@ -7,11 +7,13 @@ void compute_mass(std::shared_ptr> particle) noexcept { assert(particle->volume() != std::numeric_limits::max() && particle->material() != nullptr); // Mass = volume of particle * mass_density - auto density = - (particle->material())->template property(std::string("density")); + particle->update_scalar_property( + mpm::properties::Scalar::MassDensity, false, + particle->material()->template property(std::string("density"))); // Update particle mass - particle->update_scalar_property(mpm::properties::Scalar::Mass, false, - particle->volume() * density); + particle->update_scalar_property( + mpm::properties::Scalar::Mass, false, + particle->volume() * particle->mass_density()); } } // namespace particle } // namespace mpm diff --git a/include/solvers/mpm_explicit.tcc b/include/solvers/mpm_explicit.tcc index 05ddf36c2..b8bddad5b 100644 --- a/include/solvers/mpm_explicit.tcc +++ b/include/solvers/mpm_explicit.tcc @@ -122,7 +122,9 @@ bool mpm::MPMExplicit::solve() { // Compute mass mesh_->iterate_over_particles( - std::bind(&mpm::ParticleBase::compute_mass, std::placeholders::_1)); + [](std::shared_ptr> ptr) { + return mpm::particle::compute_mass(ptr); + }); // Check point resume if (resume) this->checkpoint_resume(); diff --git a/tests/particle_cell_crossing_test.cc b/tests/particle_cell_crossing_test.cc index 05ca405fe..cd084d8f6 100644 --- a/tests/particle_cell_crossing_test.cc +++ b/tests/particle_cell_crossing_test.cc @@ -169,8 +169,9 @@ TEST_CASE("Particle cell crossing is checked for 2D case", &mpm::ParticleBase::compute_volume, std::placeholders::_1)); // Compute mass - mesh->iterate_over_particles( - std::bind(&mpm::ParticleBase::compute_mass, std::placeholders::_1)); + mesh->iterate_over_particles([](std::shared_ptr> ptr) { + return mpm::particle::compute_mass(ptr); + }); // Initialise nodes mesh->iterate_over_nodes( @@ -425,8 +426,9 @@ TEST_CASE("Particle cell crossing is checked for 3D case", &mpm::ParticleBase::compute_volume, std::placeholders::_1)); // Compute mass - mesh->iterate_over_particles( - std::bind(&mpm::ParticleBase::compute_mass, std::placeholders::_1)); + mesh->iterate_over_particles([](std::shared_ptr> ptr) { + return mpm::particle::compute_mass(ptr); + }); // Initialise nodes mesh->iterate_over_nodes( diff --git a/tests/particle_test.cc b/tests/particle_test.cc index 64f835b80..f864a553f 100644 --- a/tests/particle_test.cc +++ b/tests/particle_test.cc @@ -734,9 +734,6 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { Factory, unsigned, const Json&>::instance()->create( "LinearElastic2D", std::move(mid), jmaterial); - // Check compute mass before material and volume - // TODO Assert: REQUIRE(particle->compute_mass() == false); - // Test compute stress before material assignment // TODO Assert: REQUIRE(particle->compute_stress() == false); @@ -750,7 +747,7 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { REQUIRE_NOTHROW(particle->compute_volume()); // Compute mass - REQUIRE_NOTHROW(particle->compute_mass()); + REQUIRE_NOTHROW(mpm::particle::compute_mass(particle)); // Mass REQUIRE(particle->mass() == Approx(1000.).epsilon(Tolerance)); // Compute mass function @@ -777,7 +774,7 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { for (unsigned i = 0; i < velocity.size(); ++i) REQUIRE(particle->velocity()(i) == Approx(i).epsilon(Tolerance)); - REQUIRE_NOTHROW(particle->compute_mass()); + REQUIRE_NOTHROW(mpm::particle::compute_mass(particle)); REQUIRE_NOTHROW(particle->map_mass_momentum_to_nodes()); // TODO Assert: REQUIRE(particle->map_pressure_to_nodes() == false); @@ -1073,7 +1070,7 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { REQUIRE_NOTHROW(particle->compute_volume()); // Compute mass - REQUIRE_NOTHROW(particle->compute_mass()); + REQUIRE_NOTHROW(mpm::particle::compute_mass(particle)); // Mass REQUIRE(particle->mass() == Approx(1000.).epsilon(Tolerance)); @@ -1095,7 +1092,7 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { for (unsigned i = 0; i < velocity.size(); ++i) REQUIRE(particle->velocity()(i) == Approx(i).epsilon(Tolerance)); - REQUIRE_NOTHROW(particle->compute_mass()); + REQUIRE_NOTHROW(mpm::particle::compute_mass(particle)); REQUIRE_NOTHROW(particle->map_mass_momentum_to_nodes()); // Check volumetric strain at centroid @@ -2008,9 +2005,6 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { Factory, unsigned, const Json&>::instance()->create( "LinearElastic3D", std::move(mid), jmaterial); - // Check compute mass before material and volume - // TODO Assert: REQUIRE(particle->compute_mass() == false); - // Test compute stress before material assignment // TODO Assert: REQUIRE(particle->compute_stress() == false); @@ -2024,7 +2018,7 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { REQUIRE_NOTHROW(particle->compute_volume()); // Compute mass - REQUIRE_NOTHROW(particle->compute_mass()); + REQUIRE_NOTHROW(mpm::particle::compute_mass(particle)); // Mass REQUIRE(particle->mass() == Approx(8000.).epsilon(Tolerance)); @@ -2047,7 +2041,7 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { for (unsigned i = 0; i < velocity.size(); ++i) REQUIRE(particle->velocity()(i) == Approx(i).epsilon(Tolerance)); - REQUIRE_NOTHROW(particle->compute_mass()); + REQUIRE_NOTHROW(mpm::particle::compute_mass(particle)); REQUIRE_NOTHROW(particle->map_mass_momentum_to_nodes()); // TODO Assert: REQUIRE(particle->map_pressure_to_nodes() == false); @@ -2337,7 +2331,7 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { REQUIRE_NOTHROW(particle->compute_volume()); // Compute mass - REQUIRE_NOTHROW(particle->compute_mass()); + REQUIRE_NOTHROW(mpm::particle::compute_mass(particle)); // Mass REQUIRE(particle->mass() == Approx(8000.).epsilon(Tolerance)); @@ -2359,7 +2353,7 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { for (unsigned i = 0; i < velocity.size(); ++i) REQUIRE(particle->velocity()(i) == Approx(i).epsilon(Tolerance)); - REQUIRE_NOTHROW(particle->compute_mass()); + REQUIRE_NOTHROW(mpm::particle::compute_mass(particle)); REQUIRE_NOTHROW(particle->map_mass_momentum_to_nodes()); // Check volumetric strain at centroid From adfd93f29227f8cecbdbd95dd1279e1b365bedf6 Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 8 Jul 2020 17:02:04 -0700 Subject: [PATCH 008/175] :wrench: refactor particle velocity and displacement --- include/particles/particle.h | 12 +++++------ include/particles/particle.tcc | 38 +++++++++++++++++++++------------- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/include/particles/particle.h b/include/particles/particle.h index 1dc76319f..ad347ba00 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -215,10 +215,14 @@ class Particle : public ParticleBase { bool assign_velocity(const VectorDim& velocity) override; //! Return velocity of the particle - VectorDim velocity() const override { return velocity_; } + VectorDim velocity() const override { + return this->vector_property(mpm::properties::Vector::Velocity); + } //! Return displacement of the particle - VectorDim displacement() const override { return displacement_; } + VectorDim displacement() const override { + return this->vector_property(mpm::properties::Vector::Displacement); + } //! Assign traction to the particle //! \param[in] direction Index corresponding to the direction of traction @@ -337,10 +341,6 @@ class Particle : public ParticleBase { Eigen::Matrix strain_rate_; //! dstrains Eigen::Matrix dstrain_; - //! Velocity - Eigen::Matrix velocity_; - //! Displacement - Eigen::Matrix displacement_; //! Particle velocity constraints std::map particle_velocity_constraints_; //! Set traction diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index 1218cbab2..cead6c73a 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -59,13 +59,16 @@ bool mpm::Particle::initialise_particle(const HDF5Particle& particle) { displacement << particle.displacement_x, particle.displacement_y, particle.displacement_z; // Initialise displacement - for (unsigned i = 0; i < Tdim; ++i) this->displacement_(i) = displacement(i); + for (unsigned i = 0; i < Tdim; ++i) + vector_properties_.at(mpm::properties::Vector::Displacement)(i) = + displacement(i); // Velocity Eigen::Vector3d velocity; velocity << particle.velocity_x, particle.velocity_y, particle.velocity_z; // Initialise velocity - for (unsigned i = 0; i < Tdim; ++i) this->velocity_(i) = velocity(i); + for (unsigned i = 0; i < Tdim; ++i) + vector_properties_.at(mpm::properties::Vector::Velocity)(i) = velocity(i); // Stress this->stress_[0] = particle.stress_xx; @@ -143,11 +146,11 @@ mpm::HDF5Particle mpm::Particle::hdf5() const { Eigen::Vector3d displacement; displacement.setZero(); - for (unsigned j = 0; j < Tdim; ++j) displacement[j] = this->displacement_[j]; + for (unsigned j = 0; j < Tdim; ++j) displacement[j] = this->displacement()[j]; Eigen::Vector3d velocity; velocity.setZero(); - for (unsigned j = 0; j < Tdim; ++j) velocity[j] = this->velocity_[j]; + for (unsigned j = 0; j < Tdim; ++j) velocity[j] = this->velocity()[j]; // Particle local size Eigen::Vector3d nsize; @@ -224,7 +227,6 @@ mpm::HDF5Particle mpm::Particle::hdf5() const { // Initialise particle properties template void mpm::Particle::initialise() { - displacement_.setZero(); dstrain_.setZero(); natural_size_.setZero(); set_traction_ = false; @@ -233,7 +235,6 @@ void mpm::Particle::initialise() { strain_.setZero(); stress_.setZero(); traction_.setZero(); - velocity_.setZero(); volumetric_strain_centroid_ = 0.; // Initialize scalar properties @@ -244,6 +245,12 @@ void mpm::Particle::initialise() { scalar_properties_.emplace(std::make_pair( mpm::properties::Scalar::Volume, std::numeric_limits::max())); + // Initialize vector properties + vector_properties_.emplace( + std::make_pair(mpm::properties::Vector::Displacement, VectorDim::Zero())); + vector_properties_.emplace( + std::make_pair(mpm::properties::Vector::Velocity, VectorDim::Zero())); + // Initialize vector data properties this->properties_["stresses"] = [&]() { return stress(); }; this->properties_["strains"] = [&]() { return strain(); }; @@ -505,7 +512,7 @@ void mpm::Particle::map_mass_momentum_to_nodes() noexcept { nodes_[i]->update_mass(true, mpm::ParticlePhase::Solid, this->mass() * shapefn_[i]); nodes_[i]->update_momentum(true, mpm::ParticlePhase::Solid, - this->mass() * shapefn_[i] * velocity_); + this->mass() * shapefn_[i] * this->velocity()); } } @@ -522,7 +529,7 @@ void mpm::Particle::map_multimaterial_mass_momentum_to_nodes() noexcept { for (unsigned i = 0; i < nodes_.size(); ++i) { nodal_mass(0, 0) = this->mass() * shapefn_[i]; nodes_[i]->update_property(true, "masses", nodal_mass, material_id_, 1); - nodes_[i]->update_property(true, "momenta", velocity_ * nodal_mass, + nodes_[i]->update_property(true, "momenta", this->velocity() * nodal_mass, material_id_, Tdim); } } @@ -536,7 +543,8 @@ void mpm::Particle::map_multimaterial_displacements_to_nodes() noexcept { // Map displacements to nodal property and divide it by the respective // nodal-material mass for (unsigned i = 0; i < nodes_.size(); ++i) { - const auto& displacement = this->mass() * shapefn_[i] * displacement_; + const auto& displacement = + this->mass() * shapefn_[i] * this->displacement(); nodes_[i]->update_property(true, "displacements", displacement, material_id_, Tdim); } @@ -713,7 +721,7 @@ template bool mpm::Particle::assign_velocity( const Eigen::Matrix& velocity) { // Assign velocity - velocity_ = velocity; + vector_properties_.at(mpm::properties::Vector::Velocity) = velocity; return true; } @@ -773,16 +781,18 @@ void mpm::Particle::compute_updated_position( shapefn_[i] * nodes_[i]->acceleration(mpm::ParticlePhase::Solid); // Update particle velocity from interpolated nodal acceleration - this->velocity_ += nodal_acceleration * dt; + vector_properties_.at(mpm::properties::Vector::Velocity) += + nodal_acceleration * dt; } // Update particle velocity using interpolated nodal velocity else - this->velocity_ = nodal_velocity; + vector_properties_.at(mpm::properties::Vector::Velocity) = nodal_velocity; // New position current position + velocity * dt this->coordinates_ += nodal_velocity * dt; // Update displacement (displacement is initialized from zero) - this->displacement_ += nodal_velocity * dt; + vector_properties_.at(mpm::properties::Vector::Displacement) += + nodal_velocity * dt; } //! Map particle pressure to nodes @@ -833,7 +843,7 @@ template void mpm::Particle::apply_particle_velocity_constraints(unsigned dir, double velocity) { // Set particle velocity constraint - this->velocity_(dir) = velocity; + vector_properties_.at(mpm::properties::Vector::Velocity)(dir) = velocity; } //! Return particle tensor data From 2b92b3f059041626218e5213501da208f791aea8 Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 8 Jul 2020 18:14:28 -0700 Subject: [PATCH 009/175] :wrench: refactor nodal mass and volume --- include/node.h | 12 ++++++------ include/node.tcc | 50 ++++++++++++++++++++++++------------------------ 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/include/node.h b/include/node.h index bb875ec36..490386fe5 100644 --- a/include/node.h +++ b/include/node.h @@ -100,7 +100,9 @@ class Node : public NodeBase { //! Return mass at a given node for a given phase //! \param[in] phase Index corresponding to the phase - double mass(unsigned phase) const override { return mass_(phase); } + double mass(unsigned phase) const override { + return this->scalar_property(mpm::properties::Scalar::Mass, phase); + } //! Update volume at the nodes from particle //! \param[in] update A boolean to update (true) or assign (false) @@ -111,7 +113,9 @@ class Node : public NodeBase { //! Return volume at a given node for a given phase //! \param[in] phase Index corresponding to the phase - double volume(unsigned phase) const override { return volume_(phase); } + double volume(unsigned phase) const override { + return this->scalar_property(mpm::properties::Scalar::Volume, phase); + } //! Assign concentrated force to the node //! \param[in] phase Index corresponding to the phase @@ -312,10 +316,6 @@ class Node : public NodeBase { tsl::ordered_map> vector_properties_; - //! Mass - Eigen::Matrix mass_; - //! Volume - Eigen::Matrix volume_; //! External force Eigen::Matrix external_force_; //! Internal force diff --git a/include/node.tcc b/include/node.tcc index 4ed495285..fcce85bb5 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -17,9 +17,14 @@ mpm::Node::Node( // Clear any velocity constraints velocity_constraints_.clear(); concentrated_force_.setZero(); + + // Initialize scalar properties scalar_properties_.emplace( std::make_pair(mpm::properties::Scalar::Mass, Eigen::Matrix::Zero())); + scalar_properties_.emplace( + std::make_pair(mpm::properties::Scalar::Volume, + Eigen::Matrix::Zero())); this->initialise(); } @@ -27,8 +32,6 @@ mpm::Node::Node( //! Initialise nodal properties template void mpm::Node::initialise() noexcept { - mass_.setZero(); - volume_.setZero(); external_force_.setZero(); internal_force_.setZero(); pressure_.setZero(); @@ -39,6 +42,7 @@ void mpm::Node::initialise() noexcept { status_ = false; material_ids_.clear(); scalar_properties_.at(mpm::properties::Scalar::Mass).setZero(); + scalar_properties_.at(mpm::properties::Scalar::Volume).setZero(); } //! Initialise shared pointer to nodal properties pool @@ -98,24 +102,16 @@ Eigen::Matrix mpm::Node::vector_property( template void mpm::Node::update_mass(bool update, unsigned phase, double mass) noexcept { - // Decide to update or assign - const double factor = (update == true) ? 1. : 0.; - - // Update/assign mass - std::lock_guard guard(node_mutex_); - mass_(phase) = (mass_(phase) * factor) + mass; + this->update_scalar_property(mpm::properties::Scalar::Mass, update, phase, + mass); } //! Update volume at the nodes from particle template void mpm::Node::update_volume(bool update, unsigned phase, double volume) noexcept { - // Decide to update or assign - const double factor = (update == true) ? 1. : 0.; - - // Update/assign volume - std::lock_guard guard(node_mutex_); - volume_(phase) = volume_(phase) * factor + volume; + this->update_scalar_property(mpm::properties::Scalar::Volume, update, phase, + volume); } // Assign concentrated force to the node @@ -208,9 +204,9 @@ void mpm::Node::update_mass_pressure( const double tolerance = 1.E-16; // Compute pressure from mass*pressure - if (mass_(phase) > tolerance) { + if (this->mass(phase) > tolerance) { std::lock_guard guard(node_mutex_); - pressure_(phase) += mass_pressure / mass_(phase); + pressure_(phase) += mass_pressure / this->mass(phase); } } @@ -229,8 +225,8 @@ template void mpm::Node::compute_velocity() { const double tolerance = 1.E-16; for (unsigned phase = 0; phase < Tnphases; ++phase) { - if (mass_(phase) > tolerance) { - velocity_.col(phase) = momentum_.col(phase) / mass_(phase); + if (this->mass(phase) > tolerance) { + velocity_.col(phase) = momentum_.col(phase) / this->mass(phase); // Check to see if value is below threshold for (unsigned i = 0; i < velocity_.rows(); ++i) @@ -265,11 +261,11 @@ bool mpm::Node::compute_acceleration_velocity( unsigned phase, double dt) noexcept { bool status = false; const double tolerance = 1.0E-15; - if (mass_(phase) > tolerance) { + if (this->mass(phase) > tolerance) { // acceleration = (unbalaced force / mass) this->acceleration_.col(phase) = (this->external_force_.col(phase) + this->internal_force_.col(phase)) / - this->mass_(phase); + this->mass(phase); // Apply friction constraints this->apply_friction_constraints(dt); @@ -298,14 +294,14 @@ bool mpm::Node::compute_acceleration_velocity_cundall( unsigned phase, double dt, double damping_factor) noexcept { bool status = false; const double tolerance = 1.0E-15; - if (mass_(phase) > tolerance) { + if (this->mass(phase) > tolerance) { // acceleration = (unbalaced force / mass) auto unbalanced_force = this->external_force_.col(phase) + this->internal_force_.col(phase); this->acceleration_.col(phase) = (unbalanced_force - damping_factor * unbalanced_force.norm() * this->velocity_.col(phase).cwiseSign()) / - this->mass_(phase); + this->mass(phase); // Apply friction constraints this->apply_friction_constraints(dt); @@ -621,7 +617,9 @@ void mpm::Nodeproperty("masses", prop_id_, *mitr); // displacement of the center of mass - contact_displacement_ += material_displacement / mass_(0, 0); + contact_displacement_ += + material_displacement / + scalar_properties_.at(mpm::properties::Scalar::Mass)(0, 0); // assign nodal-multimaterial displacement by dividing it by this material's // mass property_handle_->assign_property( @@ -639,8 +637,10 @@ void mpm::Nodeupdate_property("separation_vectors", prop_id_, *mitr, separation_vector, Tdim); } From 336cfe6f5f7dd86dcd8f7af28c561a3c204c0033 Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 8 Jul 2020 19:20:08 -0700 Subject: [PATCH 010/175] :wrench: refactor nodal velocity and acceleration --- include/node.h | 8 +--- include/node.tcc | 120 ++++++++++++++++++++++++++++------------------- 2 files changed, 75 insertions(+), 53 deletions(-) diff --git a/include/node.h b/include/node.h index 490386fe5..37a96a30b 100644 --- a/include/node.h +++ b/include/node.h @@ -193,7 +193,7 @@ class Node : public NodeBase { //! Return velocity at a given node for a given phase //! \param[in] phase Index corresponding to the phase VectorDim velocity(unsigned phase) const override { - return velocity_.col(phase); + return this->vector_property(mpm::properties::Vector::Velocity, phase); } //! Update nodal acceleration @@ -206,7 +206,7 @@ class Node : public NodeBase { //! Return acceleration at a given node for a given phase //! \param[in] phase Index corresponding to the phase VectorDim acceleration(unsigned phase) const override { - return acceleration_.col(phase); + return this->vector_property(mpm::properties::Vector::Acceleration, phase); } //! Compute acceleration and velocity @@ -324,12 +324,8 @@ class Node : public NodeBase { Eigen::Matrix pressure_; //! Displacement Eigen::Matrix contact_displacement_; - //! Velocity - Eigen::Matrix velocity_; //! Momentum Eigen::Matrix momentum_; - //! Acceleration - Eigen::Matrix acceleration_; //! Velocity constraints std::map velocity_constraints_; //! Rotation matrix for general velocity constraints diff --git a/include/node.tcc b/include/node.tcc index fcce85bb5..5abb68a09 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -26,6 +26,14 @@ mpm::Node::Node( std::make_pair(mpm::properties::Scalar::Volume, Eigen::Matrix::Zero())); + // Initialize vector properties + vector_properties_.emplace( + std::make_pair(mpm::properties::Vector::Velocity, + Eigen::Matrix::Zero())); + vector_properties_.emplace( + std::make_pair(mpm::properties::Vector::Acceleration, + Eigen::Matrix::Zero())); + this->initialise(); } @@ -36,13 +44,13 @@ void mpm::Node::initialise() noexcept { internal_force_.setZero(); pressure_.setZero(); contact_displacement_.setZero(); - velocity_.setZero(); momentum_.setZero(); - acceleration_.setZero(); status_ = false; material_ids_.clear(); scalar_properties_.at(mpm::properties::Scalar::Mass).setZero(); scalar_properties_.at(mpm::properties::Scalar::Volume).setZero(); + vector_properties_.at(mpm::properties::Vector::Velocity).setZero(); + vector_properties_.at(mpm::properties::Vector::Acceleration).setZero(); } //! Initialise shared pointer to nodal properties pool @@ -226,12 +234,14 @@ void mpm::Node::compute_velocity() { const double tolerance = 1.E-16; for (unsigned phase = 0; phase < Tnphases; ++phase) { if (this->mass(phase) > tolerance) { - velocity_.col(phase) = momentum_.col(phase) / this->mass(phase); + vector_properties_.at(mpm::properties::Vector::Velocity).col(phase) = + momentum_.col(phase) / this->mass(phase); // Check to see if value is below threshold - for (unsigned i = 0; i < velocity_.rows(); ++i) - if (std::abs(velocity_.col(phase)(i)) < 1.E-15) - velocity_.col(phase)(i) = 0.; + for (unsigned i = 0; i < Tdim; ++i) + if (std::abs(this->velocity(phase)(i)) < 1.E-15) + vector_properties_.at(mpm::properties::Vector::Velocity) + .col(phase)(i) = 0.; } } @@ -245,14 +255,8 @@ template void mpm::Node::update_acceleration( bool update, unsigned phase, const Eigen::Matrix& acceleration) noexcept { - assert(phase < Tnphases); - - // Decide to update or assign - const double factor = (update == true) ? 1. : 0.; - - //! Update/assign acceleration - std::lock_guard guard(node_mutex_); - acceleration_.col(phase) = acceleration_.col(phase) * factor + acceleration; + this->update_vector_property(mpm::properties::Vector::Acceleration, update, + phase, acceleration); } //! Compute acceleration and velocity @@ -263,7 +267,7 @@ bool mpm::Node::compute_acceleration_velocity( const double tolerance = 1.0E-15; if (this->mass(phase) > tolerance) { // acceleration = (unbalaced force / mass) - this->acceleration_.col(phase) = + vector_properties_.at(mpm::properties::Vector::Acceleration).col(phase) = (this->external_force_.col(phase) + this->internal_force_.col(phase)) / this->mass(phase); @@ -271,18 +275,21 @@ bool mpm::Node::compute_acceleration_velocity( this->apply_friction_constraints(dt); // Velocity += acceleration * dt - this->velocity_.col(phase) += this->acceleration_.col(phase) * dt; + vector_properties_.at(mpm::properties::Vector::Velocity).col(phase) += + this->acceleration(phase) * 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(this->velocity(phase)(i)) < tolerance) + vector_properties_.at(mpm::properties::Vector::Velocity).col(phase)(i) = + 0.; for (unsigned i = 0; i < Tdim; ++i) - if (std::abs(acceleration_.col(phase)(i)) < tolerance) - acceleration_.col(phase)(i) = 0.; + if (std::abs(this->acceleration(phase)(i)) < tolerance) + vector_properties_.at(mpm::properties::Vector::Acceleration) + .col(phase)(i) = 0.; status = true; } return status; @@ -298,27 +305,30 @@ bool mpm::Node::compute_acceleration_velocity_cundall( // acceleration = (unbalaced force / mass) auto unbalanced_force = this->external_force_.col(phase) + this->internal_force_.col(phase); - this->acceleration_.col(phase) = + vector_properties_.at(mpm::properties::Vector::Acceleration).col(phase) = (unbalanced_force - damping_factor * unbalanced_force.norm() * - this->velocity_.col(phase).cwiseSign()) / + this->velocity(phase).cwiseSign()) / this->mass(phase); // Apply friction constraints this->apply_friction_constraints(dt); // Velocity += acceleration * dt - this->velocity_.col(phase) += this->acceleration_.col(phase) * dt; + vector_properties_.at(mpm::properties::Vector::Velocity).col(phase) += + this->acceleration(phase) * 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(this->velocity(phase)(i)) < tolerance) + vector_properties_.at(mpm::properties::Vector::Velocity).col(phase)(i) = + 0.; for (unsigned i = 0; i < Tdim; ++i) - if (std::abs(acceleration_.col(phase)(i)) < tolerance) - acceleration_.col(phase)(i) = 0.; + if (std::abs(this->acceleration(phase)(i)) < tolerance) + vector_properties_.at(mpm::properties::Vector::Acceleration) + .col(phase)(i) = 0.; status = true; } return status; @@ -359,9 +369,11 @@ void mpm::Node::apply_velocity_constraints() { if (!generic_boundary_constraints_) { // Velocity constraints are applied on Cartesian boundaries - this->velocity_(direction, phase) = constraint.second; + vector_properties_.at(mpm::properties::Vector::Velocity)( + direction, phase) = constraint.second; // Set acceleration to 0 in direction of velocity constraint - this->acceleration_(direction, phase) = 0.; + vector_properties_.at(mpm::properties::Vector::Acceleration)(direction, + phase) = 0.; } else { // Velocity constraints on general boundaries // Compute inverse rotation matrix @@ -369,15 +381,19 @@ void mpm::Node::apply_velocity_constraints() { rotation_matrix_.inverse(); // Transform to local coordinate Eigen::Matrix local_velocity = - inverse_rotation_matrix * this->velocity_; + inverse_rotation_matrix * + vector_properties_.at(mpm::properties::Vector::Velocity); Eigen::Matrix local_acceleration = - inverse_rotation_matrix * this->acceleration_; + inverse_rotation_matrix * + vector_properties_.at(mpm::properties::Vector::Acceleration); // Apply boundary condition in local coordinate local_velocity(direction, phase) = constraint.second; local_acceleration(direction, phase) = 0.; // Transform back to global coordinate - this->velocity_ = rotation_matrix_ * local_velocity; - this->acceleration_ = rotation_matrix_ * local_acceleration; + vector_properties_.at(mpm::properties::Vector::Velocity) = + rotation_matrix_ * local_velocity; + vector_properties_.at(mpm::properties::Vector::Acceleration) = + rotation_matrix_ * local_acceleration; } } } @@ -433,10 +449,13 @@ void mpm::Node::apply_friction_constraints(double dt) { if (!generic_boundary_constraints_) { // Cartesian case // Normal and tangential acceleration - acc_n = this->acceleration_(dir_n, phase); - acc_t = this->acceleration_(dir_t, phase); + acc_n = vector_properties_.at(mpm::properties::Vector::Acceleration)( + dir_n, phase); + acc_t = vector_properties_.at(mpm::properties::Vector::Acceleration)( + dir_t, phase); // Velocity tangential - vel_t = this->velocity_(dir_t, phase); + vel_t = vector_properties_.at(mpm::properties::Vector::Velocity)(dir_t, + phase); } else { // General case, transform to local coordinate // Compute inverse rotation matrix @@ -444,9 +463,11 @@ void mpm::Node::apply_friction_constraints(double dt) { rotation_matrix_.inverse(); // Transform to local coordinate Eigen::Matrix local_acceleration = - inverse_rotation_matrix * this->acceleration_; + inverse_rotation_matrix * + vector_properties_.at(mpm::properties::Vector::Acceleration); Eigen::Matrix local_velocity = - inverse_rotation_matrix * this->velocity_; + inverse_rotation_matrix * + vector_properties_.at(mpm::properties::Vector::Velocity); // Normal and tangential acceleration acc_n = local_acceleration(dir_n, phase); acc_t = local_acceleration(dir_t, phase); @@ -471,7 +492,8 @@ void mpm::Node::apply_friction_constraints(double dt) { if (!generic_boundary_constraints_) { // Cartesian case - this->acceleration_(dir_t, phase) = acc_t; + vector_properties_.at(mpm::properties::Vector::Acceleration)( + dir_t, phase) = acc_t; } else { // Local acceleration in terms of tangential and normal Eigen::Matrix acc; @@ -479,7 +501,8 @@ void mpm::Node::apply_friction_constraints(double dt) { acc(dir_n, phase) = acc_n; // General case, transform to global coordinate - this->acceleration_.col(phase) = rotation_matrix_ * acc.col(phase); + vector_properties_.at(mpm::properties::Vector::Acceleration) + .col(phase) = rotation_matrix_ * acc.col(phase); } } } else if (Tdim == 3) { @@ -497,16 +520,16 @@ void mpm::Node::apply_friction_constraints(double dt) { Eigen::Matrix acc, vel; if (!generic_boundary_constraints_) { // Cartesian case - acc = this->acceleration_.col(phase); - vel = this->velocity_.col(phase); + acc = this->acceleration(phase); + vel = this->velocity(phase); } else { // General case, transform to local coordinate // Compute inverse rotation matrix const Eigen::Matrix inverse_rotation_matrix = rotation_matrix_.inverse(); // Transform to local coordinate - acc = inverse_rotation_matrix * this->acceleration_.col(phase); - vel = inverse_rotation_matrix * this->velocity_.col(phase); + acc = inverse_rotation_matrix * this->acceleration(phase); + vel = inverse_rotation_matrix * this->velocity(phase); } const auto acc_n = acc(dir_n); @@ -546,10 +569,12 @@ void mpm::Node::apply_friction_constraints(double dt) { if (!generic_boundary_constraints_) { // Cartesian case - this->acceleration_.col(phase) = acc; + vector_properties_.at(mpm::properties::Vector::Acceleration) + .col(phase) = acc; } else { // General case, transform to global coordinate - this->acceleration_.col(phase) = rotation_matrix_ * acc; + vector_properties_.at(mpm::properties::Vector::Acceleration) + .col(phase) = rotation_matrix_ * acc; } } } @@ -596,7 +621,8 @@ void mpm::Node momentum = property_handle_->property("momenta", prop_id_, *mitr, Tdim); const Eigen::Matrix change_in_momenta = - velocity_ * mass - momentum; + vector_properties_.at(mpm::properties::Vector::Velocity) * mass - + momentum; property_handle_->update_property("change_in_momenta", prop_id_, *mitr, change_in_momenta, Tdim); } From 91d5c974b355161dcdf4a8601d612dbf9be69d09 Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 8 Jul 2020 20:11:11 -0700 Subject: [PATCH 011/175] :wrench: refactor nodal momentum, external, and internal forces --- include/node.h | 12 +++-------- include/node.tcc | 54 +++++++++++++++++++----------------------------- 2 files changed, 24 insertions(+), 42 deletions(-) diff --git a/include/node.h b/include/node.h index 37a96a30b..d302d3683 100644 --- a/include/node.h +++ b/include/node.h @@ -142,7 +142,7 @@ class Node : public NodeBase { //! Return external force at a given node for a given phase //! \param[in] phase Index corresponding to the phase VectorDim external_force(unsigned phase) const override { - return external_force_.col(phase); + return this->vector_property(mpm::properties::Vector::ExternalForce, phase); } //! Update internal force (body force / traction force) @@ -155,7 +155,7 @@ class Node : public NodeBase { //! Return internal force at a given node for a given phase //! \param[in] phase Index corresponding to the phase VectorDim internal_force(unsigned phase) const override { - return internal_force_.col(phase); + return this->vector_property(mpm::properties::Vector::InternalForce, phase); } //! Update pressure at the nodes from particle @@ -184,7 +184,7 @@ class Node : public NodeBase { //! Return momentum at a given node for a given phase //! \param[in] phase Index corresponding to the phase VectorDim momentum(unsigned phase) const override { - return momentum_.col(phase); + return this->vector_property(mpm::properties::Vector::Momentum, phase); } //! Compute velocity from the momentum @@ -316,16 +316,10 @@ class Node : public NodeBase { tsl::ordered_map> vector_properties_; - //! External force - Eigen::Matrix external_force_; - //! Internal force - Eigen::Matrix internal_force_; //! Pressure Eigen::Matrix pressure_; //! Displacement Eigen::Matrix contact_displacement_; - //! Momentum - Eigen::Matrix momentum_; //! Velocity constraints std::map velocity_constraints_; //! Rotation matrix for general velocity constraints diff --git a/include/node.tcc b/include/node.tcc index 5abb68a09..49f28e8f4 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -33,6 +33,15 @@ mpm::Node::Node( vector_properties_.emplace( std::make_pair(mpm::properties::Vector::Acceleration, Eigen::Matrix::Zero())); + vector_properties_.emplace( + std::make_pair(mpm::properties::Vector::Momentum, + Eigen::Matrix::Zero())); + vector_properties_.emplace( + std::make_pair(mpm::properties::Vector::ExternalForce, + Eigen::Matrix::Zero())); + vector_properties_.emplace( + std::make_pair(mpm::properties::Vector::InternalForce, + Eigen::Matrix::Zero())); this->initialise(); } @@ -40,17 +49,17 @@ mpm::Node::Node( //! Initialise nodal properties template void mpm::Node::initialise() noexcept { - external_force_.setZero(); - internal_force_.setZero(); pressure_.setZero(); contact_displacement_.setZero(); - momentum_.setZero(); status_ = false; material_ids_.clear(); scalar_properties_.at(mpm::properties::Scalar::Mass).setZero(); scalar_properties_.at(mpm::properties::Scalar::Volume).setZero(); vector_properties_.at(mpm::properties::Vector::Velocity).setZero(); vector_properties_.at(mpm::properties::Vector::Acceleration).setZero(); + vector_properties_.at(mpm::properties::Vector::Momentum).setZero(); + vector_properties_.at(mpm::properties::Vector::ExternalForce).setZero(); + vector_properties_.at(mpm::properties::Vector::InternalForce).setZero(); } //! Initialise shared pointer to nodal properties pool @@ -160,15 +169,8 @@ template void mpm::Node::update_external_force( bool update, unsigned phase, const Eigen::Matrix& force) noexcept { - // Assert - assert(phase < Tnphases); - - // Decide to update or assign - const double factor = (update == true) ? 1. : 0.; - - // Update/assign external force - std::lock_guard guard(node_mutex_); - external_force_.col(phase) = external_force_.col(phase) * factor + force; + this->update_vector_property(mpm::properties::Vector::ExternalForce, update, + phase, force); } //! Update internal force (body force / traction force) @@ -176,15 +178,8 @@ template void mpm::Node::update_internal_force( bool update, unsigned phase, const Eigen::Matrix& force) noexcept { - // Assert - assert(phase < Tnphases); - - // Decide to update or assign - const double factor = (update == true) ? 1. : 0.; - - // Update/assign internal force - std::lock_guard guard(node_mutex_); - internal_force_.col(phase) = internal_force_.col(phase) * factor + force; + this->update_vector_property(mpm::properties::Vector::InternalForce, update, + phase, force); } //! Assign nodal momentum @@ -192,15 +187,8 @@ template void mpm::Node::update_momentum( bool update, unsigned phase, const Eigen::Matrix& momentum) noexcept { - // Assert - assert(phase < Tnphases); - - // Decide to update or assign - const double factor = (update == true) ? 1. : 0.; - - // Update/assign momentum - std::lock_guard guard(node_mutex_); - momentum_.col(phase) = momentum_.col(phase) * factor + momentum; + this->update_vector_property(mpm::properties::Vector::Momentum, update, phase, + momentum); } //! Update pressure at the nodes from particle @@ -235,7 +223,7 @@ void mpm::Node::compute_velocity() { for (unsigned phase = 0; phase < Tnphases; ++phase) { if (this->mass(phase) > tolerance) { vector_properties_.at(mpm::properties::Vector::Velocity).col(phase) = - momentum_.col(phase) / this->mass(phase); + this->momentum(phase) / this->mass(phase); // Check to see if value is below threshold for (unsigned i = 0; i < Tdim; ++i) @@ -268,7 +256,7 @@ bool mpm::Node::compute_acceleration_velocity( if (this->mass(phase) > tolerance) { // acceleration = (unbalaced force / mass) vector_properties_.at(mpm::properties::Vector::Acceleration).col(phase) = - (this->external_force_.col(phase) + this->internal_force_.col(phase)) / + (this->external_force(phase) + this->internal_force(phase)) / this->mass(phase); // Apply friction constraints @@ -304,7 +292,7 @@ bool mpm::Node::compute_acceleration_velocity_cundall( if (this->mass(phase) > tolerance) { // acceleration = (unbalaced force / mass) auto unbalanced_force = - this->external_force_.col(phase) + this->internal_force_.col(phase); + this->external_force(phase) + this->internal_force(phase); vector_properties_.at(mpm::properties::Vector::Acceleration).col(phase) = (unbalanced_force - damping_factor * unbalanced_force.norm() * this->velocity(phase).cwiseSign()) / From 8ed2eb8f4d9273be81ef26674f821252fef2d6ef Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 8 Jul 2020 20:16:43 -0700 Subject: [PATCH 012/175] :wrench: refactor nodal pressure --- include/node.h | 6 +++--- include/node.tcc | 14 +++++++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/include/node.h b/include/node.h index d302d3683..4dee319bc 100644 --- a/include/node.h +++ b/include/node.h @@ -172,7 +172,9 @@ class Node : public NodeBase { //! Return pressure at a given node for a given phase //! \param[in] phase Index corresponding to the phase - double pressure(unsigned phase) const override { return pressure_(phase); } + double pressure(unsigned phase) const override { + return this->scalar_property(mpm::properties::Scalar::Pressure, phase); + } //! Update momentum at the nodes //! \param[in] update A boolean to update (true) or assign (false) @@ -316,8 +318,6 @@ class Node : public NodeBase { tsl::ordered_map> vector_properties_; - //! Pressure - Eigen::Matrix pressure_; //! Displacement Eigen::Matrix contact_displacement_; //! Velocity constraints diff --git a/include/node.tcc b/include/node.tcc index 49f28e8f4..f46f812c8 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -25,6 +25,9 @@ mpm::Node::Node( scalar_properties_.emplace( std::make_pair(mpm::properties::Scalar::Volume, Eigen::Matrix::Zero())); + scalar_properties_.emplace( + std::make_pair(mpm::properties::Scalar::Pressure, + Eigen::Matrix::Zero())); // Initialize vector properties vector_properties_.emplace( @@ -49,12 +52,16 @@ mpm::Node::Node( //! Initialise nodal properties template void mpm::Node::initialise() noexcept { - pressure_.setZero(); contact_displacement_.setZero(); status_ = false; material_ids_.clear(); + + // Initialise nodal scalar properties scalar_properties_.at(mpm::properties::Scalar::Mass).setZero(); scalar_properties_.at(mpm::properties::Scalar::Volume).setZero(); + scalar_properties_.at(mpm::properties::Scalar::Pressure).setZero(); + + // Initialise nodal vector properties vector_properties_.at(mpm::properties::Vector::Velocity).setZero(); vector_properties_.at(mpm::properties::Vector::Acceleration).setZero(); vector_properties_.at(mpm::properties::Vector::Momentum).setZero(); @@ -202,7 +209,8 @@ void mpm::Node::update_mass_pressure( // Compute pressure from mass*pressure if (this->mass(phase) > tolerance) { std::lock_guard guard(node_mutex_); - pressure_(phase) += mass_pressure / this->mass(phase); + scalar_properties_.at(mpm::properties::Scalar::Pressure)(phase) += + mass_pressure / this->mass(phase); } } @@ -212,7 +220,7 @@ void mpm::Node::assign_pressure(unsigned phase, double pressure) { // Compute pressure from mass*pressure std::lock_guard guard(node_mutex_); - pressure_(phase) = pressure; + scalar_properties_.at(mpm::properties::Scalar::Pressure)(phase) = pressure; } //! Compute velocity from momentum From 02911bf8c85b89fe7ad73985e5919b3bb48b28f3 Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 8 Jul 2020 20:17:07 -0700 Subject: [PATCH 013/175] :wrench: Add scalar and vector properties enum --- include/mpm_properties.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/include/mpm_properties.h b/include/mpm_properties.h index cff0edced..69e87dac7 100644 --- a/include/mpm_properties.h +++ b/include/mpm_properties.h @@ -4,9 +4,16 @@ namespace mpm { namespace properties { //! Scalar Properties -enum Scalar : unsigned int { Mass }; +enum Scalar : unsigned int { Mass, Volume, MassDensity, Pressure }; //! Vector Properties -enum Vector : unsigned int { Velocity, Displacement, Acceleration }; +enum Vector : unsigned int { + Displacement, + Velocity, + Acceleration, + Momentum, + ExternalForce, + InternalForce +}; } // namespace properties } // namespace mpm From 0feaf6d0e9437306dda82fd9e391c8c695600372 Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 8 Jul 2020 20:33:58 -0700 Subject: [PATCH 014/175] :wrench: aesthetic clean up order of initialise() --- include/node.tcc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/node.tcc b/include/node.tcc index f46f812c8..37c70e490 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -52,9 +52,7 @@ mpm::Node::Node( //! Initialise nodal properties template void mpm::Node::initialise() noexcept { - contact_displacement_.setZero(); status_ = false; - material_ids_.clear(); // Initialise nodal scalar properties scalar_properties_.at(mpm::properties::Scalar::Mass).setZero(); @@ -67,6 +65,10 @@ void mpm::Node::initialise() noexcept { vector_properties_.at(mpm::properties::Vector::Momentum).setZero(); vector_properties_.at(mpm::properties::Vector::ExternalForce).setZero(); vector_properties_.at(mpm::properties::Vector::InternalForce).setZero(); + + // Initialise variables for contact + material_ids_.clear(); + contact_displacement_.setZero(); } //! Initialise shared pointer to nodal properties pool From bcfb8781a4bb2fef6dd5f79c312e83470fa03f23 Mon Sep 17 00:00:00 2001 From: Nanda Date: Thu, 9 Jul 2020 15:54:46 -0700 Subject: [PATCH 015/175] :wrench: fix particle vector_properties_ size order --- include/particles/particle_base.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 71f6269fb..54fb2e30a 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -336,7 +336,7 @@ class ParticleBase { //! Scalar properties tsl::ordered_map scalar_properties_; //! Vector properties - tsl::ordered_map> + tsl::ordered_map> vector_properties_; }; // ParticleBase class } // namespace mpm From 99b9eead998f3aaee24a039d02b08551f65ef445 Mon Sep 17 00:00:00 2001 From: Nanda Date: Thu, 9 Jul 2020 15:58:36 -0700 Subject: [PATCH 016/175] :dart: add testings for update and return functions --- tests/particle_test.cc | 124 ++++++++++++++++++++++++++++++++--------- 1 file changed, 98 insertions(+), 26 deletions(-) diff --git a/tests/particle_test.cc b/tests/particle_test.cc index f864a553f..b4e297f09 100644 --- a/tests/particle_test.cc +++ b/tests/particle_test.cc @@ -144,24 +144,25 @@ TEST_CASE("Particle is checked for 1D case", "[particle][1D]") { std::shared_ptr> particle = std::make_shared>(id, coords); - // Check scalar properties - SECTION("Check scalar properties") { - // Check mass - REQUIRE(particle->scalar_property(mpm::properties::Scalar::Mass) == - Approx(0.0).epsilon(Tolerance)); - double mass = 100.5; - particle->update_scalar_property(mpm::properties::Scalar::Mass, true, - mass); - REQUIRE(particle->scalar_property(mpm::properties::Scalar::Mass) == - Approx(100.5).epsilon(Tolerance)); - } - // Check mass - REQUIRE(particle->mass() == Approx(100.5).epsilon(Tolerance)); + REQUIRE(particle->mass() == Approx(0.).epsilon(Tolerance)); double mass = 201.0; particle->assign_mass(mass); REQUIRE(particle->mass() == Approx(201.0).epsilon(Tolerance)); + // Check mass using scalar properties + REQUIRE(particle->scalar_property(mpm::properties::Scalar::Mass) == + Approx(201.0).epsilon(Tolerance)); + mass = 100.5; + particle->update_scalar_property(mpm::properties::Scalar::Mass, false, + mass); + REQUIRE(particle->scalar_property(mpm::properties::Scalar::Mass) == + Approx(100.5).epsilon(Tolerance)); + + particle->update_scalar_property(mpm::properties::Scalar::Mass, true, mass); + REQUIRE(particle->scalar_property(mpm::properties::Scalar::Mass) == + Approx(201.).epsilon(Tolerance)); + // Check stress Eigen::Matrix stress; for (unsigned i = 0; i < stress.size(); ++i) stress(i) = 17.51; @@ -181,6 +182,25 @@ TEST_CASE("Particle is checked for 1D case", "[particle][1D]") { for (unsigned i = 0; i < velocity.size(); ++i) REQUIRE(particle->velocity()(i) == Approx(17.51).epsilon(Tolerance)); + // Check velocity using vector properties + for (unsigned i = 0; i < velocity.size(); ++i) + REQUIRE(particle->vector_property(mpm::properties::Vector::Velocity)(i) == + Approx(17.51).epsilon(Tolerance)); + + for (unsigned i = 0; i < velocity.size(); ++i) velocity(i) = 13.88; + + particle->update_vector_property(mpm::properties::Vector::Velocity, false, + velocity); + for (unsigned i = 0; i < velocity.size(); ++i) + REQUIRE(particle->vector_property(mpm::properties::Vector::Velocity)(i) == + Approx(13.88).epsilon(Tolerance)); + + particle->update_vector_property(mpm::properties::Vector::Velocity, true, + velocity); + for (unsigned i = 0; i < velocity.size(); ++i) + REQUIRE(particle->vector_property(mpm::properties::Vector::Velocity)(i) == + Approx(27.76).epsilon(Tolerance)); + // Assign volume REQUIRE(particle->assign_volume(0.0) == false); REQUIRE(particle->assign_volume(-5.0) == false); @@ -1236,24 +1256,25 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { std::shared_ptr> particle = std::make_shared>(id, coords); - // Check scalar properties - SECTION("Check scalar properties") { - // Check mass - REQUIRE(particle->scalar_property(mpm::properties::Scalar::Mass) == - Approx(0.0).epsilon(Tolerance)); - double mass = 100.5; - particle->update_scalar_property(mpm::properties::Scalar::Mass, true, - mass); - REQUIRE(particle->scalar_property(mpm::properties::Scalar::Mass) == - Approx(100.5).epsilon(Tolerance)); - } - // Check mass - REQUIRE(particle->mass() == Approx(100.5).epsilon(Tolerance)); + REQUIRE(particle->mass() == Approx(0.).epsilon(Tolerance)); double mass = 201.0; particle->assign_mass(mass); REQUIRE(particle->mass() == Approx(201.0).epsilon(Tolerance)); + // Check mass using scalar properties + REQUIRE(particle->scalar_property(mpm::properties::Scalar::Mass) == + Approx(201.).epsilon(Tolerance)); + mass = 111.11; + particle->update_scalar_property(mpm::properties::Scalar::Mass, false, + mass); + REQUIRE(particle->scalar_property(mpm::properties::Scalar::Mass) == + Approx(111.11).epsilon(Tolerance)); + + particle->update_scalar_property(mpm::properties::Scalar::Mass, true, mass); + REQUIRE(particle->scalar_property(mpm::properties::Scalar::Mass) == + Approx(222.22).epsilon(Tolerance)); + // Check stress Eigen::Matrix stress; for (unsigned i = 0; i < stress.size(); ++i) stress(i) = 17.52; @@ -1273,6 +1294,25 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { for (unsigned i = 0; i < velocity.size(); ++i) REQUIRE(particle->velocity()(i) == Approx(19.745).epsilon(Tolerance)); + // Check velocity using vector properties + for (unsigned i = 0; i < velocity.size(); ++i) + REQUIRE(particle->vector_property(mpm::properties::Vector::Velocity)(i) == + Approx(19.745).epsilon(Tolerance)); + + for (unsigned i = 0; i < velocity.size(); ++i) velocity(i) = 11.22; + + particle->update_vector_property(mpm::properties::Vector::Velocity, false, + velocity); + for (unsigned i = 0; i < velocity.size(); ++i) + REQUIRE(particle->vector_property(mpm::properties::Vector::Velocity)(i) == + Approx(11.22).epsilon(Tolerance)); + + particle->update_vector_property(mpm::properties::Vector::Velocity, true, + velocity); + for (unsigned i = 0; i < velocity.size(); ++i) + REQUIRE(particle->vector_property(mpm::properties::Vector::Velocity)(i) == + Approx(22.44).epsilon(Tolerance)); + // Assign volume REQUIRE(particle->assign_volume(0.0) == false); REQUIRE(particle->assign_volume(-5.0) == false); @@ -2544,6 +2584,19 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { particle->assign_mass(mass); REQUIRE(particle->mass() == Approx(100.5).epsilon(Tolerance)); + // Check mass using scalar properties + REQUIRE(particle->scalar_property(mpm::properties::Scalar::Mass) == + Approx(100.5).epsilon(Tolerance)); + mass = 111.11; + particle->update_scalar_property(mpm::properties::Scalar::Mass, false, + mass); + REQUIRE(particle->scalar_property(mpm::properties::Scalar::Mass) == + Approx(111.11).epsilon(Tolerance)); + + particle->update_scalar_property(mpm::properties::Scalar::Mass, true, mass); + REQUIRE(particle->scalar_property(mpm::properties::Scalar::Mass) == + Approx(222.22).epsilon(Tolerance)); + // Check stress Eigen::Matrix stress; for (unsigned i = 0; i < stress.size(); ++i) stress(i) = 1.; @@ -2563,6 +2616,25 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { for (unsigned i = 0; i < velocity.size(); ++i) REQUIRE(particle->velocity()(i) == Approx(17.51).epsilon(Tolerance)); + // Check velocity using vector properties + for (unsigned i = 0; i < velocity.size(); ++i) + REQUIRE(particle->vector_property(mpm::properties::Vector::Velocity)(i) == + Approx(17.51).epsilon(Tolerance)); + + for (unsigned i = 0; i < velocity.size(); ++i) velocity(i) = 11.22; + + particle->update_vector_property(mpm::properties::Vector::Velocity, false, + velocity); + for (unsigned i = 0; i < velocity.size(); ++i) + REQUIRE(particle->vector_property(mpm::properties::Vector::Velocity)(i) == + Approx(11.22).epsilon(Tolerance)); + + particle->update_vector_property(mpm::properties::Vector::Velocity, true, + velocity); + for (unsigned i = 0; i < velocity.size(); ++i) + REQUIRE(particle->vector_property(mpm::properties::Vector::Velocity)(i) == + Approx(22.44).epsilon(Tolerance)); + // Assign volume REQUIRE(particle->assign_volume(0.0) == false); REQUIRE(particle->assign_volume(-5.0) == false); From 2f54b90a549494573ae1eb99f6d2b340af5e8623 Mon Sep 17 00:00:00 2001 From: Nanda Date: Thu, 9 Jul 2020 16:14:53 -0700 Subject: [PATCH 017/175] :wrench: add overload functions of mapping --- include/particles/particle_base.h | 17 +++++++++++++++++ include/particles/particle_base.tcc | 23 +++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 54fb2e30a..da5174bd8 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -148,6 +148,14 @@ class ParticleBase { void map_scalar_property_nodes(mpm::properties::Scalar property, bool update, unsigned phase) noexcept; + //! Map an arbitrary scalar value to nodal scalar property + //! \param[in] property Name of the property to update + //! \param[in] update A boolean to update (true) or assign (false) + //! \param[in] phase Index corresponding to the phase + //! \param[in] value Scalar value to be mapped from particle to node + void map_scalar_property_nodes(mpm::properties::Scalar property, bool update, + unsigned phase, double value) noexcept; + //! Return property at a given node for a given phase //! \param[in] phase Index corresponding to the phase double interpolate_scalar_property_nodes(mpm::properties::Scalar property, @@ -173,6 +181,15 @@ class ParticleBase { void map_vector_property_nodes(mpm::properties::Vector property, bool update, unsigned phase) noexcept; + //! Map an arbitrary vector value to nodal vector property + //! \param[in] property Name of the property to update + //! \param[in] update A boolean to update (true) or assign (false) + //! \param[in] phase Index corresponding to the phase + //! \param[in] value Vector value to be mapped from particle to node + void map_vector_property_nodes( + mpm::properties::Vector property, bool update, unsigned phase, + const Eigen::Matrix& value) noexcept; + //! Return property at a given node for a given phase //! \param[in] phase Index corresponding to the phase double interpolate_vector_property_nodes(mpm::properties::Vector property, diff --git a/include/particles/particle_base.tcc b/include/particles/particle_base.tcc index 58f52f426..4a389ee6d 100644 --- a/include/particles/particle_base.tcc +++ b/include/particles/particle_base.tcc @@ -46,6 +46,17 @@ void mpm::ParticleBase::map_scalar_property_nodes( property, update, phase, scalar_properties_.at(property) * shapefn_[i]); } +//! Map an arbitrary scalar value to nodal scalar property +template +void mpm::ParticleBase::map_scalar_property_nodes( + mpm::properties::Scalar property, bool update, unsigned phase, + double value) noexcept { + // Map scalar value to nodes + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->update_scalar_property(property, update, phase, + value * shapefn_[i]); +} + //! Interpolate scalar property from nodes template double mpm::ParticleBase::interpolate_scalar_property_nodes( @@ -86,6 +97,18 @@ void mpm::ParticleBase::map_vector_property_nodes( property, update, phase, vector_properties_.at(property) * shapefn_[i]); } +//! Map an arbitrary vector value to nodal vector property +template +void mpm::ParticleBase::map_vector_property_nodes( + mpm::properties::Vector property, bool update, unsigned phase, + const Eigen::Matrix& value) noexcept { + // TODO: Check assert needed? + // Map vector property to nodes + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->update_vector_property(property, update, phase, + value * shapefn_[i]); +} + //! Interpolate vector property from nodes template double mpm::ParticleBase::interpolate_vector_property_nodes( From 0facda0fc474bd074ad842d0ab99f3a5fc958185 Mon Sep 17 00:00:00 2001 From: Nanda Date: Thu, 9 Jul 2020 16:16:45 -0700 Subject: [PATCH 018/175] :construction: :dart: test nightly benchmarks with refactored particles and nodes --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 57f12f47b..cd3613b44 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -127,7 +127,7 @@ workflows: version: 2 build: jobs: - - gcc + - benchmarks - clang - cppcheck - codecov From 413665457f23634b5c8eb31ed7f1ddcc606b56a8 Mon Sep 17 00:00:00 2001 From: Nanda Date: Thu, 9 Jul 2020 18:30:05 -0700 Subject: [PATCH 019/175] :construction: :dart: refactor map_mass_momentum and tests --- include/particles/particle.h | 3 --- include/particles/particle.tcc | 15 --------------- include/particles/particle_base.h | 3 --- include/particles/particle_functions.tcc | 20 ++++++++++++++++++++ include/solvers/mpm_explicit.tcc | 5 +++-- tests/interface_test.cc | 6 +++--- tests/particle_cell_crossing_test.cc | 12 ++++++------ tests/particle_test.cc | 12 ++++-------- 8 files changed, 36 insertions(+), 40 deletions(-) diff --git a/include/particles/particle.h b/include/particles/particle.h index ad347ba00..0c7c0bfa8 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -135,9 +135,6 @@ class Particle : public ParticleBase { return this->scalar_property(mpm::properties::Scalar::MassDensity); } - //! Map particle mass and momentum to nodes - void map_mass_momentum_to_nodes() noexcept override; - //! Map multimaterial properties to nodes void map_multimaterial_mass_momentum_to_nodes() noexcept override; diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index cead6c73a..c3996f194 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -501,21 +501,6 @@ void mpm::Particle::update_volume() noexcept { (1. + dvolumetric_strain_); } -//! Map particle mass and momentum to nodes -template -void mpm::Particle::map_mass_momentum_to_nodes() noexcept { - // Check if particle mass is set - assert(this->mass() != std::numeric_limits::max()); - - // Map mass and momentum to nodes - for (unsigned i = 0; i < nodes_.size(); ++i) { - nodes_[i]->update_mass(true, mpm::ParticlePhase::Solid, - this->mass() * shapefn_[i]); - nodes_[i]->update_momentum(true, mpm::ParticlePhase::Solid, - this->mass() * shapefn_[i] * this->velocity()); - } -} - //! Map multimaterial properties to nodes template void mpm::Particle::map_multimaterial_mass_momentum_to_nodes() noexcept { diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index da5174bd8..c227e828a 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -198,9 +198,6 @@ class ParticleBase { //! Return mass density virtual double mass_density() const = 0; - //! Map particle mass and momentum to nodes - virtual void map_mass_momentum_to_nodes() noexcept = 0; - //! Map multimaterial properties to nodes virtual void map_multimaterial_mass_momentum_to_nodes() noexcept = 0; diff --git a/include/particles/particle_functions.tcc b/include/particles/particle_functions.tcc index 0cd83e5ee..973bc0f4a 100644 --- a/include/particles/particle_functions.tcc +++ b/include/particles/particle_functions.tcc @@ -1,19 +1,39 @@ // Compute mass of particle namespace mpm { namespace particle { + +// Compute particle mass template void compute_mass(std::shared_ptr> particle) noexcept { // Check if particle volume is set and material ptr is valid assert(particle->volume() != std::numeric_limits::max() && particle->material() != nullptr); + // Mass = volume of particle * mass_density particle->update_scalar_property( mpm::properties::Scalar::MassDensity, false, particle->material()->template property(std::string("density"))); + // Update particle mass particle->update_scalar_property( mpm::properties::Scalar::Mass, false, particle->volume() * particle->mass_density()); } + +//! Map particle mass and momentum to nodes +template +void map_mass_momentum_to_nodes( + std::shared_ptr> particle) noexcept { + // Check if particle mass is set + assert(particle->mass() != std::numeric_limits::max()); + + // Map mass and momentum to nodes + particle->map_scalar_property_nodes(mpm::properties::Scalar::Mass, true, + mpm::ParticlePhase::Solid); + particle->map_vector_property_nodes(mpm::properties::Vector::Momentum, true, + mpm::ParticlePhase::Solid, + particle->mass() * particle->velocity()); +} + } // namespace particle } // namespace mpm diff --git a/include/solvers/mpm_explicit.tcc b/include/solvers/mpm_explicit.tcc index b8bddad5b..1dbdbe60c 100644 --- a/include/solvers/mpm_explicit.tcc +++ b/include/solvers/mpm_explicit.tcc @@ -184,8 +184,9 @@ bool mpm::MPMExplicit::solve() { // Assign mass and momentum to nodes mesh_->iterate_over_particles( - std::bind(&mpm::ParticleBase::map_mass_momentum_to_nodes, - std::placeholders::_1)); + [](std::shared_ptr> ptr) { + return mpm::particle::map_mass_momentum_to_nodes(ptr); + }); #ifdef USE_MPI // Run if there is more than a single MPI task diff --git a/tests/interface_test.cc b/tests/interface_test.cc index cb3b151d7..e9104e799 100644 --- a/tests/interface_test.cc +++ b/tests/interface_test.cc @@ -152,9 +152,9 @@ TEST_CASE("Interface functions are checked", "[interface]") { particle3->map_multimaterial_mass_momentum_to_nodes(); // Map masses and momenta from particles to nodes - particle1->map_mass_momentum_to_nodes(); - particle2->map_mass_momentum_to_nodes(); - particle3->map_mass_momentum_to_nodes(); + mpm::particle::map_mass_momentum_to_nodes(particle1); + mpm::particle::map_mass_momentum_to_nodes(particle2); + mpm::particle::map_mass_momentum_to_nodes(particle3); // Compute velocities at nodes node0->compute_velocity(); diff --git a/tests/particle_cell_crossing_test.cc b/tests/particle_cell_crossing_test.cc index cd084d8f6..ce6acda6e 100644 --- a/tests/particle_cell_crossing_test.cc +++ b/tests/particle_cell_crossing_test.cc @@ -191,9 +191,9 @@ TEST_CASE("Particle cell crossing is checked for 2D case", &mpm::ParticleBase::compute_shapefn, 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)); + mesh->iterate_over_particles([](std::shared_ptr> ptr) { + return mpm::particle::map_mass_momentum_to_nodes(ptr); + }); // Iterate over active nodes to compute acceleratation and velocity mesh->iterate_over_nodes_predicate( @@ -452,9 +452,9 @@ TEST_CASE("Particle cell crossing is checked for 3D case", &mpm::ParticleBase::compute_shapefn, 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)); + mesh->iterate_over_particles([](std::shared_ptr> ptr) { + return mpm::particle::map_mass_momentum_to_nodes(ptr); + }); // Iterate over active nodes to compute acceleratation and velocity mesh->iterate_over_nodes_predicate( diff --git a/tests/particle_test.cc b/tests/particle_test.cc index b4e297f09..4859c6bd6 100644 --- a/tests/particle_test.cc +++ b/tests/particle_test.cc @@ -777,7 +777,6 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { // Map particle mass to nodes particle->assign_mass(std::numeric_limits::max()); - // TODO Assert: REQUIRE_NOTHROW(particle->map_mass_momentum_to_nodes()); // Map particle pressure to nodes // TODO Assert: REQUIRE(particle->map_pressure_to_nodes() == false); @@ -795,7 +794,7 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { REQUIRE(particle->velocity()(i) == Approx(i).epsilon(Tolerance)); REQUIRE_NOTHROW(mpm::particle::compute_mass(particle)); - REQUIRE_NOTHROW(particle->map_mass_momentum_to_nodes()); + REQUIRE_NOTHROW(mpm::particle::map_mass_momentum_to_nodes(particle)); // TODO Assert: REQUIRE(particle->map_pressure_to_nodes() == false); REQUIRE(particle->compute_pressure_smoothing() == false); @@ -1096,7 +1095,6 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { // Map particle mass to nodes particle->assign_mass(std::numeric_limits::max()); - // TODO Assert: REQUIRE(particle->map_mass_momentum_to_nodes() == false); // Map particle pressure to nodes // TODO Assert: REQUIRE(particle->map_pressure_to_nodes() == false); @@ -1113,7 +1111,7 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { REQUIRE(particle->velocity()(i) == Approx(i).epsilon(Tolerance)); REQUIRE_NOTHROW(mpm::particle::compute_mass(particle)); - REQUIRE_NOTHROW(particle->map_mass_momentum_to_nodes()); + REQUIRE_NOTHROW(mpm::particle::map_mass_momentum_to_nodes(particle)); // Check volumetric strain at centroid volumetric_strain = 0.2; @@ -2064,7 +2062,6 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { // Map particle mass to nodes particle->assign_mass(std::numeric_limits::max()); - // TODO Assert: REQUIRE(particle->map_mass_momentum_to_nodes() == false); // Map particle pressure to nodes // TODO Assert: REQUIRE(particle->map_pressure_to_nodes() == false); @@ -2082,7 +2079,7 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { REQUIRE(particle->velocity()(i) == Approx(i).epsilon(Tolerance)); REQUIRE_NOTHROW(mpm::particle::compute_mass(particle)); - REQUIRE_NOTHROW(particle->map_mass_momentum_to_nodes()); + REQUIRE_NOTHROW(mpm::particle::map_mass_momentum_to_nodes(particle)); // TODO Assert: REQUIRE(particle->map_pressure_to_nodes() == false); REQUIRE(particle->compute_pressure_smoothing() == false); @@ -2377,7 +2374,6 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { // Map particle mass to nodes particle->assign_mass(std::numeric_limits::max()); - // TODO Assert: REQUIRE(particle->map_mass_momentum_to_nodes() == false); // Map particle pressure to nodes // TODO Assert: REQUIRE(particle->map_pressure_to_nodes() == false); @@ -2394,7 +2390,7 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { REQUIRE(particle->velocity()(i) == Approx(i).epsilon(Tolerance)); REQUIRE_NOTHROW(mpm::particle::compute_mass(particle)); - REQUIRE_NOTHROW(particle->map_mass_momentum_to_nodes()); + REQUIRE_NOTHROW(mpm::particle::map_mass_momentum_to_nodes(particle)); // Check volumetric strain at centroid volumetric_strain = 0.5; From cb71c90f3c22f835af6798b225a24a883f345dcf Mon Sep 17 00:00:00 2001 From: Nanda Date: Thu, 9 Jul 2020 22:40:47 -0700 Subject: [PATCH 020/175] :construction: :dart: refactor map_body_force and update_volume --- include/particles/particle.h | 7 ------ include/particles/particle.tcc | 24 --------------------- include/particles/particle_base.h | 6 ------ include/particles/particle_functions.tcc | 27 ++++++++++++++++++++++++ include/solvers/mpm_explicit.tcc | 11 ++++++---- tests/particle_test.cc | 12 ++++------- 6 files changed, 38 insertions(+), 49 deletions(-) diff --git a/include/particles/particle.h b/include/particles/particle.h index 0c7c0bfa8..6cf8e5870 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -127,9 +127,6 @@ class Particle : public ParticleBase { //! Compute volume as cell volume / nparticles void compute_volume() noexcept override; - //! Update volume based on centre volumetric strain rate - void update_volume() noexcept override; - //! \param[in] phase Index corresponding to the phase double mass_density() const override { return this->scalar_property(mpm::properties::Scalar::MassDensity); @@ -199,10 +196,6 @@ class Particle : public ParticleBase { //! Return stress of the particle Eigen::Matrix stress() const override { return stress_; } - //! Map body force - //! \param[in] pgravity Gravity of a particle - void map_body_force(const VectorDim& pgravity) noexcept override; - //! Map internal force inline void map_internal_force() noexcept override; diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index c3996f194..af98eadf7 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -486,21 +486,6 @@ void mpm::Particle::compute_volume() noexcept { this->assign_volume(cell_->volume() / cell_->nparticles()); } -// Update volume based on the central strain rate -template -void mpm::Particle::update_volume() noexcept { - // Check if particle has a valid cell ptr and a valid volume - assert(cell_ != nullptr && - this->volume() != std::numeric_limits::max()); - // Compute at centroid - // Strain rate for reduced integration - scalar_properties_.at(mpm::properties::Scalar::Volume) *= - (1. + dvolumetric_strain_); - scalar_properties_.at(mpm::properties::Scalar::MassDensity) = - scalar_properties_.at(mpm::properties::Scalar::MassDensity) / - (1. + dvolumetric_strain_); -} - //! Map multimaterial properties to nodes template void mpm::Particle::map_multimaterial_mass_momentum_to_nodes() noexcept { @@ -641,15 +626,6 @@ void mpm::Particle::compute_stress() noexcept { material_->compute_stress(stress_, dstrain_, this, &state_variables_); } -//! Map body force -template -void mpm::Particle::map_body_force(const VectorDim& pgravity) noexcept { - // Compute nodal body forces - for (unsigned i = 0; i < nodes_.size(); ++i) - nodes_[i]->update_external_force(true, mpm::ParticlePhase::Solid, - (pgravity * this->mass() * shapefn_(i))); -} - //! Map internal force template <> inline void mpm::Particle<1>::map_internal_force() noexcept { diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index c227e828a..7beaeb6bd 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -127,9 +127,6 @@ class ParticleBase { //! Compute volume of particle virtual void compute_volume() noexcept = 0; - //! Update volume based on centre volumetric strain rate - virtual void update_volume() noexcept = 0; - //! Update scalar property at the particle //! \param[in] property Name of the property to update //! \param[in] update A boolean to update (true) or assign (false) @@ -260,9 +257,6 @@ class ParticleBase { //! Return stress virtual Eigen::Matrix stress() const = 0; - //! Map body force - virtual void map_body_force(const VectorDim& pgravity) noexcept = 0; - //! Map internal force virtual void map_internal_force() noexcept = 0; diff --git a/include/particles/particle_functions.tcc b/include/particles/particle_functions.tcc index 973bc0f4a..39d53689a 100644 --- a/include/particles/particle_functions.tcc +++ b/include/particles/particle_functions.tcc @@ -20,6 +20,23 @@ void compute_mass(std::shared_ptr> particle) noexcept { particle->volume() * particle->mass_density()); } +// Update volume based on the central strain rate +template +void update_volume(std::shared_ptr> particle) noexcept { + // Check if particle has a valid cell ptr and a valid volume + assert(particle->cell_ptr() && + particle->volume() != std::numeric_limits::max()); + + // Compute at centroid + // Strain rate for reduced integration + particle->update_scalar_property( + mpm::properties::Scalar::Volume, false, + (particle->volume() * (1. + particle->dvolumetric_strain()))); + particle->update_scalar_property( + mpm::properties::Scalar::MassDensity, false, + (particle->mass_density() / (1. + particle->dvolumetric_strain()))); +} + //! Map particle mass and momentum to nodes template void map_mass_momentum_to_nodes( @@ -35,5 +52,15 @@ void map_mass_momentum_to_nodes( particle->mass() * particle->velocity()); } +//! Map body force to nodes +template +void map_body_force(std::shared_ptr> particle, + const Eigen::Matrix& pgravity) noexcept { + // Compute nodal body forces + particle->map_vector_property_nodes(mpm::properties::Vector::ExternalForce, + true, mpm::ParticlePhase::Solid, + pgravity * particle->mass()); +} + } // namespace particle } // namespace mpm diff --git a/include/solvers/mpm_explicit.tcc b/include/solvers/mpm_explicit.tcc index 1dbdbe60c..286ab6579 100644 --- a/include/solvers/mpm_explicit.tcc +++ b/include/solvers/mpm_explicit.tcc @@ -43,8 +43,10 @@ void mpm::MPMExplicit::compute_stress_strain(unsigned phase) { &mpm::ParticleBase::compute_strain, std::placeholders::_1, dt_)); // Iterate over each particle to update particle volume - mesh_->iterate_over_particles(std::bind( - &mpm::ParticleBase::update_volume, std::placeholders::_1)); + mesh_->iterate_over_particles( + [](std::shared_ptr> ptr) { + return mpm::particle::update_volume(ptr); + }); // Pressure smoothing if (pressure_smoothing_) this->pressure_smoothing(phase); @@ -255,8 +257,9 @@ bool mpm::MPMExplicit::solve() { { // Iterate over each particle to compute nodal body force mesh_->iterate_over_particles( - std::bind(&mpm::ParticleBase::map_body_force, - std::placeholders::_1, this->gravity_)); + [&value = gravity_](std::shared_ptr> ptr) { + return mpm::particle::map_body_force(ptr, value); + }); // Apply particle traction and map to nodes mesh_->apply_traction_on_particles(this->step_ * this->dt_); diff --git a/tests/particle_test.cc b/tests/particle_test.cc index 4859c6bd6..59afcfe1f 100644 --- a/tests/particle_test.cc +++ b/tests/particle_test.cc @@ -711,8 +711,6 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { // TODO Assert: REQUIRE_NOTHROW(particle->compute_updated_position(dt, // true)); Compute volume // TODO Assert: REQUIRE(particle->compute_volume() == false); - // Update volume should fail - // TODO Assert: REQUIRE(particle->update_volume() == false); REQUIRE(particle->assign_cell(cell) == true); REQUIRE(cell->status() == true); @@ -887,7 +885,7 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { // Update volume strain rate REQUIRE(particle->volume() == Approx(1.0).epsilon(Tolerance)); particle->compute_strain(dt); - REQUIRE_NOTHROW(particle->update_volume()); + REQUIRE_NOTHROW(mpm::particle::update_volume(particle)); REQUIRE(particle->volume() == Approx(1.2).epsilon(Tolerance)); // Compute stress @@ -910,7 +908,7 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { Eigen::Matrix gravity; gravity << 0., -9.81; - particle->map_body_force(gravity); + mpm::particle::map_body_force(particle, gravity); // Body force Eigen::Matrix body_force; @@ -2000,8 +1998,6 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { // Compute volume // TODO Assert: REQUIRE(particle->compute_volume() == false); - // Update volume should fail - // TODO Assert: REQUIRE(particle->update_volume() == false); REQUIRE(particle->assign_cell(cell) == true); REQUIRE(cell->status() == true); @@ -2190,7 +2186,7 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { // Update volume strain rate REQUIRE(particle->volume() == Approx(8.0).epsilon(Tolerance)); particle->compute_strain(dt); - REQUIRE_NOTHROW(particle->update_volume()); + REQUIRE_NOTHROW(mpm::particle::update_volume(particle)); REQUIRE(particle->volume() == Approx(12.0).epsilon(Tolerance)); // Compute stress @@ -2213,7 +2209,7 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { Eigen::Matrix gravity; gravity << 0., 0., -9.81; - particle->map_body_force(gravity); + mpm::particle::map_body_force(particle, gravity); // Body force Eigen::Matrix body_force; From 52eb2b3522538de680f12957981303ac998b87f4 Mon Sep 17 00:00:00 2001 From: Nanda Date: Fri, 10 Jul 2020 15:05:24 -0700 Subject: [PATCH 021/175] :construction: :dart: change assign_velocity to void and cleanup --- include/node.tcc | 4 ++-- include/particles/particle.h | 4 +++- include/particles/particle.tcc | 9 --------- include/particles/particle_base.h | 2 +- tests/particle_test.cc | 14 +++++++------- 5 files changed, 13 insertions(+), 20 deletions(-) diff --git a/include/node.tcc b/include/node.tcc index 37c70e490..d3e2cf755 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -89,7 +89,7 @@ void mpm::Node::update_scalar_property( // Decide to update or assign const double factor = (update == true) ? 1. : 0.; - // Update/assign mass + // Update/assign value std::lock_guard guard(node_mutex_); scalar_properties_.at(property)[phase] = (scalar_properties_.at(property)[phase] * factor) + value; @@ -110,7 +110,7 @@ void mpm::Node::update_vector_property( // Decide to update or assign const double factor = (update == true) ? 1. : 0.; - // Update/assign mass + // Update/assign value std::lock_guard guard(node_mutex_); Eigen::Matrix vecvalue = vector_properties_.at(property).col(phase); diff --git a/include/particles/particle.h b/include/particles/particle.h index 6cf8e5870..dbca8af31 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -202,7 +202,9 @@ class Particle : public ParticleBase { //! Assign velocity to the particle //! \param[in] velocity A vector of particle velocity //! \retval status Assignment status - bool assign_velocity(const VectorDim& velocity) override; + void assign_velocity(const VectorDim& velocity) override { + vector_properties_.at(mpm::properties::Vector::Velocity) = velocity; + }; //! Return velocity of the particle VectorDim velocity() const override { diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index af98eadf7..5d1b57e4b 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -677,15 +677,6 @@ inline void mpm::Particle<3>::map_internal_force() noexcept { } } -// Assign velocity to the particle -template -bool mpm::Particle::assign_velocity( - const Eigen::Matrix& velocity) { - // Assign velocity - vector_properties_.at(mpm::properties::Vector::Velocity) = velocity; - return true; -} - // Assign traction to the particle template bool mpm::Particle::assign_traction(unsigned direction, double traction) { diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 7beaeb6bd..15f670cc0 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -267,7 +267,7 @@ class ParticleBase { virtual bool compute_pressure_smoothing() noexcept = 0; //! Assign velocity - virtual bool assign_velocity(const VectorDim& velocity) = 0; + virtual void assign_velocity(const VectorDim& velocity) = 0; //! Return velocity virtual VectorDim velocity() const = 0; diff --git a/tests/particle_test.cc b/tests/particle_test.cc index 59afcfe1f..de05b1dc5 100644 --- a/tests/particle_test.cc +++ b/tests/particle_test.cc @@ -178,7 +178,7 @@ TEST_CASE("Particle is checked for 1D case", "[particle][1D]") { for (unsigned i = 0; i < velocity.size(); ++i) REQUIRE(particle->velocity()(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(particle->assign_velocity(velocity) == true); + particle->assign_velocity(velocity); for (unsigned i = 0; i < velocity.size(); ++i) REQUIRE(particle->velocity()(i) == Approx(17.51).epsilon(Tolerance)); @@ -787,7 +787,7 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { Eigen::VectorXd velocity; velocity.resize(Dim); for (unsigned i = 0; i < velocity.size(); ++i) velocity(i) = i; - REQUIRE(particle->assign_velocity(velocity) == true); + particle->assign_velocity(velocity); for (unsigned i = 0; i < velocity.size(); ++i) REQUIRE(particle->velocity()(i) == Approx(i).epsilon(Tolerance)); @@ -1104,7 +1104,7 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { // Check velocity velocity.resize(Dim); for (unsigned i = 0; i < velocity.size(); ++i) velocity(i) = i; - REQUIRE(particle->assign_velocity(velocity) == true); + particle->assign_velocity(velocity); for (unsigned i = 0; i < velocity.size(); ++i) REQUIRE(particle->velocity()(i) == Approx(i).epsilon(Tolerance)); @@ -1286,7 +1286,7 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { for (unsigned i = 0; i < velocity.size(); ++i) REQUIRE(particle->velocity()(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(particle->assign_velocity(velocity) == true); + particle->assign_velocity(velocity); for (unsigned i = 0; i < velocity.size(); ++i) REQUIRE(particle->velocity()(i) == Approx(19.745).epsilon(Tolerance)); @@ -2070,7 +2070,7 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { Eigen::VectorXd velocity; velocity.resize(Dim); for (unsigned i = 0; i < velocity.size(); ++i) velocity(i) = i; - REQUIRE(particle->assign_velocity(velocity) == true); + particle->assign_velocity(velocity); for (unsigned i = 0; i < velocity.size(); ++i) REQUIRE(particle->velocity()(i) == Approx(i).epsilon(Tolerance)); @@ -2381,7 +2381,7 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { // Check velocity velocity.resize(Dim); for (unsigned i = 0; i < velocity.size(); ++i) velocity(i) = i; - REQUIRE(particle->assign_velocity(velocity) == true); + particle->assign_velocity(velocity); for (unsigned i = 0; i < velocity.size(); ++i) REQUIRE(particle->velocity()(i) == Approx(i).epsilon(Tolerance)); @@ -2604,7 +2604,7 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { for (unsigned i = 0; i < velocity.size(); ++i) REQUIRE(particle->velocity()(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(particle->assign_velocity(velocity) == true); + particle->assign_velocity(velocity); for (unsigned i = 0; i < velocity.size(); ++i) REQUIRE(particle->velocity()(i) == Approx(17.51).epsilon(Tolerance)); From a20a2ab046e6469cc25773f4ddc2dcffd8ece87f Mon Sep 17 00:00:00 2001 From: Nanda Date: Fri, 10 Jul 2020 15:09:47 -0700 Subject: [PATCH 022/175] :dart: revert mass change in particle test --- tests/particle_test.cc | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/particle_test.cc b/tests/particle_test.cc index de05b1dc5..0d5623bc1 100644 --- a/tests/particle_test.cc +++ b/tests/particle_test.cc @@ -145,23 +145,23 @@ TEST_CASE("Particle is checked for 1D case", "[particle][1D]") { std::make_shared>(id, coords); // Check mass - REQUIRE(particle->mass() == Approx(0.).epsilon(Tolerance)); - double mass = 201.0; + REQUIRE(particle->mass() == Approx(0.0).epsilon(Tolerance)); + double mass = 100.5; particle->assign_mass(mass); - REQUIRE(particle->mass() == Approx(201.0).epsilon(Tolerance)); + REQUIRE(particle->mass() == Approx(100.5).epsilon(Tolerance)); // Check mass using scalar properties REQUIRE(particle->scalar_property(mpm::properties::Scalar::Mass) == - Approx(201.0).epsilon(Tolerance)); - mass = 100.5; + Approx(100.5).epsilon(Tolerance)); + mass = 200.5; particle->update_scalar_property(mpm::properties::Scalar::Mass, false, mass); REQUIRE(particle->scalar_property(mpm::properties::Scalar::Mass) == - Approx(100.5).epsilon(Tolerance)); + Approx(200.5).epsilon(Tolerance)); particle->update_scalar_property(mpm::properties::Scalar::Mass, true, mass); REQUIRE(particle->scalar_property(mpm::properties::Scalar::Mass) == - Approx(201.).epsilon(Tolerance)); + Approx(401.).epsilon(Tolerance)); // Check stress Eigen::Matrix stress; @@ -1253,14 +1253,14 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { std::make_shared>(id, coords); // Check mass - REQUIRE(particle->mass() == Approx(0.).epsilon(Tolerance)); - double mass = 201.0; + REQUIRE(particle->mass() == Approx(0.0).epsilon(Tolerance)); + double mass = 100.5; particle->assign_mass(mass); - REQUIRE(particle->mass() == Approx(201.0).epsilon(Tolerance)); + REQUIRE(particle->mass() == Approx(100.5).epsilon(Tolerance)); // Check mass using scalar properties REQUIRE(particle->scalar_property(mpm::properties::Scalar::Mass) == - Approx(201.).epsilon(Tolerance)); + Approx(100.5).epsilon(Tolerance)); mass = 111.11; particle->update_scalar_property(mpm::properties::Scalar::Mass, false, mass); From 0a0cf7b4461f35f769c78b4a84087f8c2219fec8 Mon Sep 17 00:00:00 2001 From: Nanda Date: Fri, 10 Jul 2020 15:29:00 -0700 Subject: [PATCH 023/175] :construction: :dart: add return cell pointer and refactor compute_volume --- include/mesh.tcc | 2 +- include/particles/particle.h | 6 +++--- include/particles/particle.tcc | 9 --------- include/particles/particle_base.h | 6 +++--- include/particles/particle_functions.tcc | 12 ++++++++++++ include/solvers/mpm_base.tcc | 6 ++++-- tests/mesh_test_2d.cc | 5 +++-- tests/mesh_test_3d.cc | 5 +++-- tests/particle_cell_crossing_test.cc | 10 ++++++---- tests/particle_test.cc | 18 +++++++----------- 10 files changed, 42 insertions(+), 37 deletions(-) diff --git a/include/mesh.tcc b/include/mesh.tcc index 3f03363c8..68b64879e 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1751,7 +1751,7 @@ void mpm::Mesh::inject_particles(double current_time) { } } for (auto particle : injected_particles) { - particle->compute_volume(); + mpm::particle::compute_volume(particle); mpm::particle::compute_mass(particle); } } diff --git a/include/particles/particle.h b/include/particles/particle.h index dbca8af31..e9fffc0c4 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -103,6 +103,9 @@ class Particle : public ParticleBase { //! Return cell id Index cell_id() const override { return cell_id_; } + //! Return cell ptr + std::shared_ptr> cell() const override { return cell_; } + //! Return cell ptr status bool cell_ptr() const override { return cell_ != nullptr; } @@ -124,9 +127,6 @@ class Particle : public ParticleBase { //! Return size of particle in natural coordinates VectorDim natural_size() const override { return natural_size_; } - //! Compute volume as cell volume / nparticles - void compute_volume() noexcept override; - //! \param[in] phase Index corresponding to the phase double mass_density() const override { return this->scalar_property(mpm::properties::Scalar::MassDensity); diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index 5d1b57e4b..4a3deb7d2 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -477,15 +477,6 @@ bool mpm::Particle::assign_volume(double volume) { return status; } -// Compute volume of the particle -template -void mpm::Particle::compute_volume() noexcept { - // Check if particle has a valid cell ptr - assert(cell_ != nullptr); - // Volume of the cell / # of particles - this->assign_volume(cell_->volume() / cell_->nparticles()); -} - //! Map multimaterial properties to nodes template void mpm::Particle::map_multimaterial_mass_momentum_to_nodes() noexcept { diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 15f670cc0..c84f24436 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -106,6 +106,9 @@ class ParticleBase { //! Return cell id virtual Index cell_id() const = 0; + //! Return cell ptr + virtual std::shared_ptr> cell() const = 0; + //! Return cell ptr status virtual bool cell_ptr() const = 0; @@ -124,9 +127,6 @@ class ParticleBase { //! Return size of particle in natural coordinates virtual VectorDim natural_size() const = 0; - //! Compute volume of particle - virtual void compute_volume() noexcept = 0; - //! Update scalar property at the particle //! \param[in] property Name of the property to update //! \param[in] update A boolean to update (true) or assign (false) diff --git a/include/particles/particle_functions.tcc b/include/particles/particle_functions.tcc index 39d53689a..a8f35bd28 100644 --- a/include/particles/particle_functions.tcc +++ b/include/particles/particle_functions.tcc @@ -20,6 +20,18 @@ void compute_mass(std::shared_ptr> particle) noexcept { particle->volume() * particle->mass_density()); } +// Compute volume of the particle +template +void compute_volume( + std::shared_ptr> particle) noexcept { + // Check if particle has a valid cell ptr + assert(particle->cell_ptr()); + + // Volume of the cell / # of particles + particle->assign_volume(particle->cell()->volume() / + particle->cell()->nparticles()); +} + // Update volume based on the central strain rate template void update_volume(std::shared_ptr> particle) noexcept { diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index 47e5dcd0a..c9393b68f 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -300,8 +300,10 @@ bool mpm::MPMBase::initialise_particles() { auto particles_volume_begin = std::chrono::steady_clock::now(); // Compute volume - mesh_->iterate_over_particles(std::bind( - &mpm::ParticleBase::compute_volume, std::placeholders::_1)); + mesh_->iterate_over_particles( + [](std::shared_ptr> ptr) { + return mpm::particle::compute_volume(ptr); + }); // Read and assign particles volumes this->particles_volumes(mesh_props, particle_io); diff --git a/tests/mesh_test_2d.cc b/tests/mesh_test_2d.cc index 7b564bd94..0f44d1d7e 100644 --- a/tests/mesh_test_2d.cc +++ b/tests/mesh_test_2d.cc @@ -966,8 +966,9 @@ TEST_CASE("Mesh is checked for 2D case", "[mesh][2D]") { // Compute volume mesh->iterate_over_particles( - std::bind(&mpm::ParticleBase::compute_volume, - std::placeholders::_1)); + [](std::shared_ptr> ptr) { + return mpm::particle::compute_volume(ptr); + }); mesh->apply_traction_on_particles(10); } diff --git a/tests/mesh_test_3d.cc b/tests/mesh_test_3d.cc index 56d05b503..9805fbea5 100644 --- a/tests/mesh_test_3d.cc +++ b/tests/mesh_test_3d.cc @@ -1061,8 +1061,9 @@ TEST_CASE("Mesh is checked for 3D case", "[mesh][3D]") { // Compute volume mesh->iterate_over_particles( - std::bind(&mpm::ParticleBase::compute_volume, - std::placeholders::_1)); + [](std::shared_ptr> ptr) { + return mpm::particle::compute_volume(ptr); + }); mesh->apply_traction_on_particles(10); } diff --git a/tests/particle_cell_crossing_test.cc b/tests/particle_cell_crossing_test.cc index ce6acda6e..3699ccb31 100644 --- a/tests/particle_cell_crossing_test.cc +++ b/tests/particle_cell_crossing_test.cc @@ -165,8 +165,9 @@ TEST_CASE("Particle cell crossing is checked for 2D case", material)); // Compute volume - mesh->iterate_over_particles(std::bind( - &mpm::ParticleBase::compute_volume, std::placeholders::_1)); + mesh->iterate_over_particles([](std::shared_ptr> ptr) { + return mpm::particle::compute_volume(ptr); + }); // Compute mass mesh->iterate_over_particles([](std::shared_ptr> ptr) { @@ -422,8 +423,9 @@ TEST_CASE("Particle cell crossing is checked for 3D case", material)); // Compute volume - mesh->iterate_over_particles(std::bind( - &mpm::ParticleBase::compute_volume, std::placeholders::_1)); + mesh->iterate_over_particles([](std::shared_ptr> ptr) { + return mpm::particle::compute_volume(ptr); + }); // Compute mass mesh->iterate_over_particles([](std::shared_ptr> ptr) { diff --git a/tests/particle_test.cc b/tests/particle_test.cc index 0d5623bc1..b6d32e942 100644 --- a/tests/particle_test.cc +++ b/tests/particle_test.cc @@ -709,8 +709,7 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { // REQUIRE_NOTHROW(particle->compute_updated_position(dt) == false); // Compute updated particle location from nodal velocity should fail // TODO Assert: REQUIRE_NOTHROW(particle->compute_updated_position(dt, - // true)); Compute volume - // TODO Assert: REQUIRE(particle->compute_volume() == false); + // true)); REQUIRE(particle->assign_cell(cell) == true); REQUIRE(cell->status() == true); @@ -729,7 +728,7 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { // Check volume REQUIRE(particle->volume() == Approx(2.0).epsilon(Tolerance)); // Compute volume - REQUIRE_NOTHROW(particle->compute_volume()); + REQUIRE_NOTHROW(mpm::particle::compute_volume(particle)); // Check volume REQUIRE(particle->volume() == Approx(1.0).epsilon(Tolerance)); @@ -762,7 +761,7 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { REQUIRE(particle->material_id() == 1); // Compute volume - REQUIRE_NOTHROW(particle->compute_volume()); + REQUIRE_NOTHROW(mpm::particle::compute_volume(particle)); // Compute mass REQUIRE_NOTHROW(mpm::particle::compute_mass(particle)); @@ -1084,7 +1083,7 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { REQUIRE(particle->assign_material(material1) == true); // Compute volume - REQUIRE_NOTHROW(particle->compute_volume()); + REQUIRE_NOTHROW(mpm::particle::compute_volume(particle)); // Compute mass REQUIRE_NOTHROW(mpm::particle::compute_mass(particle)); @@ -1996,9 +1995,6 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { // TODO Assert: REQUIRE_NOTHROW(particle->compute_updated_position(dt, // true)); - // Compute volume - // TODO Assert: REQUIRE(particle->compute_volume() == false); - REQUIRE(particle->assign_cell(cell) == true); REQUIRE(cell->status() == true); REQUIRE(particle->cell_id() == 10); @@ -2016,7 +2012,7 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { // Check volume REQUIRE(particle->volume() == Approx(2.0).epsilon(Tolerance)); // Compute volume - REQUIRE_NOTHROW(particle->compute_volume()); + REQUIRE_NOTHROW(mpm::particle::compute_volume(particle)); // Check volume REQUIRE(particle->volume() == Approx(8.0).epsilon(Tolerance)); @@ -2049,7 +2045,7 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { REQUIRE(particle->material_id() == 0); // Compute volume - REQUIRE_NOTHROW(particle->compute_volume()); + REQUIRE_NOTHROW(mpm::particle::compute_volume(particle)); // Compute mass REQUIRE_NOTHROW(mpm::particle::compute_mass(particle)); @@ -2361,7 +2357,7 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { REQUIRE(particle->assign_material(material1) == true); // Compute volume - REQUIRE_NOTHROW(particle->compute_volume()); + REQUIRE_NOTHROW(mpm::particle::compute_volume(particle)); // Compute mass REQUIRE_NOTHROW(mpm::particle::compute_mass(particle)); From fe0f9bfbd4f2de2a3c2c32997576212ffb41d1f4 Mon Sep 17 00:00:00 2001 From: Nanda Date: Fri, 10 Jul 2020 15:32:23 -0700 Subject: [PATCH 024/175] :wrench: add assert in return and update scalar and vector properties --- include/node.tcc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/node.tcc b/include/node.tcc index d3e2cf755..680f9b8e5 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -86,6 +86,9 @@ template void mpm::Node::update_scalar_property( mpm::properties::Scalar property, bool update, unsigned phase, double value) noexcept { + // Assert phase + assert(phase < Tnphases); + // Decide to update or assign const double factor = (update == true) ? 1. : 0.; @@ -99,6 +102,8 @@ void mpm::Node::update_scalar_property( template double mpm::Node::scalar_property( mpm::properties::Scalar property, unsigned phase) const { + // Assert phase + assert(phase < Tnphases); return scalar_properties_.at(property)[phase]; } @@ -107,6 +112,9 @@ template void mpm::Node::update_vector_property( mpm::properties::Vector property, bool update, unsigned phase, const Eigen::Matrix& value) noexcept { + // Assert phase + assert(phase < Tnphases); + // Decide to update or assign const double factor = (update == true) ? 1. : 0.; @@ -121,6 +129,8 @@ void mpm::Node::update_vector_property( template Eigen::Matrix mpm::Node::vector_property( mpm::properties::Vector property, unsigned phase) const { + // Assert phase + assert(phase < Tnphases); return vector_properties_.at(property).col(phase); } From b6937094b3bf733b67ff7c151603801e4a816c37 Mon Sep 17 00:00:00 2001 From: Nanda Date: Fri, 10 Jul 2020 15:44:44 -0700 Subject: [PATCH 025/175] :construction: :dart: return set traction and refactor map traction --- include/mesh.tcc | 6 ++++-- include/particles/particle.h | 4 ++-- include/particles/particle.tcc | 11 ----------- include/particles/particle_base.h | 4 ++-- include/particles/particle_functions.tcc | 12 ++++++++++++ tests/particle_test.cc | 8 ++++---- 6 files changed, 24 insertions(+), 21 deletions(-) diff --git a/include/mesh.tcc b/include/mesh.tcc index 68b64879e..be5c037dc 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1202,8 +1202,10 @@ void mpm::Mesh::apply_traction_on_particles(double current_time) { std::placeholders::_1, dir, traction)); } if (!particle_tractions_.empty()) { - this->iterate_over_particles(std::bind( - &mpm::ParticleBase::map_traction_force, std::placeholders::_1)); + this->iterate_over_particles( + [](std::shared_ptr> ptr) { + return mpm::particle::map_traction_force(ptr); + }); } } diff --git a/include/particles/particle.h b/include/particles/particle.h index e9fffc0c4..4bbae8d6d 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -226,8 +226,8 @@ class Particle : public ParticleBase { //! \param[in] phase Index corresponding to the phase VectorDim traction() const override { return traction_; } - //! Map traction force - void map_traction_force() noexcept override; + //! Return set traction bool + bool set_traction() const override { return set_traction_; } //! Compute updated position of the particle //! \param[in] dt Analysis time step diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index 4a3deb7d2..859f751d9 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -689,17 +689,6 @@ bool mpm::Particle::assign_traction(unsigned direction, double traction) { return status; } -//! Map traction force -template -void mpm::Particle::map_traction_force() noexcept { - if (this->set_traction_) { - // Map particle traction forces to nodes - for (unsigned i = 0; i < nodes_.size(); ++i) - nodes_[i]->update_external_force(true, mpm::ParticlePhase::Solid, - (shapefn_[i] * traction_)); - } -} - // Compute updated position of the particle template void mpm::Particle::compute_updated_position( diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index c84f24436..9b421202c 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -281,8 +281,8 @@ class ParticleBase { //! Return traction virtual VectorDim traction() const = 0; - //! Map traction force - virtual void map_traction_force() noexcept = 0; + //! Return set traction bool + virtual bool set_traction() const = 0; //! Compute updated position virtual void compute_updated_position( diff --git a/include/particles/particle_functions.tcc b/include/particles/particle_functions.tcc index a8f35bd28..66feba4b9 100644 --- a/include/particles/particle_functions.tcc +++ b/include/particles/particle_functions.tcc @@ -74,5 +74,17 @@ void map_body_force(std::shared_ptr> particle, pgravity * particle->mass()); } +//! Map traction force +template +void map_traction_force( + std::shared_ptr> particle) noexcept { + if (particle->set_traction()) { + // Map particle traction forces to nodes + particle->map_vector_property_nodes(mpm::properties::Vector::ExternalForce, + true, mpm::ParticlePhase::Solid, + particle->traction()); + } +} + } // namespace particle } // namespace mpm diff --git a/tests/particle_test.cc b/tests/particle_test.cc index b6d32e942..46a219242 100644 --- a/tests/particle_test.cc +++ b/tests/particle_test.cc @@ -936,7 +936,7 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { // Assign traction to particle particle->assign_traction(direction, mfunction->value(current_time) * traction); - particle->map_traction_force(); + mpm::particle::map_traction_force(particle); // Traction force Eigen::Matrix traction_force; @@ -959,7 +959,7 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { particle->assign_traction(direction, -traction * mfunction->value(current_time)); // Map traction force - particle->map_traction_force(); + mpm::particle::map_traction_force(particle); // Check nodal external force for (unsigned i = 0; i < traction_force.rows(); ++i) for (unsigned j = 0; j < traction_force.cols(); ++j) @@ -2237,7 +2237,7 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { particle->assign_traction(direction, mfunction->value(current_time) * traction); // Map traction force - particle->map_traction_force(); + mpm::particle::map_traction_force(particle); // Traction force Eigen::Matrix traction_force; @@ -2264,7 +2264,7 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { particle->assign_traction(direction, mfunction->value(current_time) * -traction); // Map traction force - particle->map_traction_force(); + mpm::particle::map_traction_force(particle); // Check nodal external force for (unsigned i = 0; i < traction_force.rows(); ++i) for (unsigned j = 0; j < traction_force.cols(); ++j) From 5fc100e83b5b2003df756723d89b6f8d7d7e5f3a Mon Sep 17 00:00:00 2001 From: Nanda Date: Sat, 11 Jul 2020 19:32:26 -0700 Subject: [PATCH 026/175] :construction: :dart: refactor pressure smoothing --- include/mpm_properties.h | 8 +++++++- include/node.h | 3 +++ include/node.tcc | 22 ++++++++++++++++++++++ include/node_base.h | 3 +++ include/particles/particle.h | 3 --- include/particles/particle.tcc | 21 --------------------- include/particles/particle_base.h | 3 --- include/particles/particle_functions.tcc | 16 ++++++++++++++++ include/solvers/mpm_explicit.tcc | 13 ++++++++++--- tests/particle_test.cc | 18 ++---------------- 10 files changed, 63 insertions(+), 47 deletions(-) diff --git a/include/mpm_properties.h b/include/mpm_properties.h index 69e87dac7..4e3568667 100644 --- a/include/mpm_properties.h +++ b/include/mpm_properties.h @@ -4,7 +4,13 @@ namespace mpm { namespace properties { //! Scalar Properties -enum Scalar : unsigned int { Mass, Volume, MassDensity, Pressure }; +enum Scalar : unsigned int { + Mass, + Volume, + MassDensity, + MassPressure, + Pressure +}; //! Vector Properties enum Vector : unsigned int { Displacement, diff --git a/include/node.h b/include/node.h index 4dee319bc..de78f18a7 100644 --- a/include/node.h +++ b/include/node.h @@ -164,6 +164,9 @@ class Node : public NodeBase { void update_mass_pressure(unsigned phase, double mass_pressure) noexcept override; + //! Compute pressure from the mass pressure + virtual void compute_pressure() override; + //! Assign pressure at the nodes from particle //! \param[in] update A boolean to update (true) or assign (false) //! \param[in] phase Index corresponding to the phase diff --git a/include/node.tcc b/include/node.tcc index 680f9b8e5..6bc4ae264 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -25,6 +25,9 @@ mpm::Node::Node( scalar_properties_.emplace( std::make_pair(mpm::properties::Scalar::Volume, Eigen::Matrix::Zero())); + scalar_properties_.emplace( + std::make_pair(mpm::properties::Scalar::MassPressure, + Eigen::Matrix::Zero())); scalar_properties_.emplace( std::make_pair(mpm::properties::Scalar::Pressure, Eigen::Matrix::Zero())); @@ -57,6 +60,7 @@ void mpm::Node::initialise() noexcept { // Initialise nodal scalar properties scalar_properties_.at(mpm::properties::Scalar::Mass).setZero(); scalar_properties_.at(mpm::properties::Scalar::Volume).setZero(); + scalar_properties_.at(mpm::properties::Scalar::MassPressure).setZero(); scalar_properties_.at(mpm::properties::Scalar::Pressure).setZero(); // Initialise nodal vector properties @@ -226,6 +230,24 @@ void mpm::Node::update_mass_pressure( } } +//! Compute pressure from mass pressure +//! pressure = mass pressure / mass +template +void mpm::Node::compute_pressure() { + const double tolerance = 1.E-16; + for (unsigned phase = 0; phase < Tnphases; ++phase) { + if (this->mass(phase) > tolerance) { + scalar_properties_.at(mpm::properties::Scalar::Pressure)(phase) = + scalar_properties_.at(mpm::properties::Scalar::MassPressure)(phase) / + this->mass(phase); + + // Check to see if value is below threshold + if (std::abs(this->pressure(phase)) < 1.E-15) + scalar_properties_.at(mpm::properties::Scalar::Pressure)(phase) = 0.; + } + } +} + //! Assign pressure at the nodes from particle template void mpm::Node::assign_pressure(unsigned phase, diff --git a/include/node_base.h b/include/node_base.h index 7e696235d..d85080058 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -163,6 +163,9 @@ class NodeBase { virtual void update_mass_pressure(unsigned phase, double mass_pressure) noexcept = 0; + //! Compute pressure from the mass pressure + virtual void compute_pressure() = 0; + //! Assign pressure at the nodes from particle //! \param[in] update A boolean to update (true) or assign (false) //! \param[in] phase Index corresponding to the phase diff --git a/include/particles/particle.h b/include/particles/particle.h index 4bbae8d6d..ca84fb21b 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -244,9 +244,6 @@ class Particle : public ParticleBase { : std::numeric_limits::quiet_NaN(); } - //! Map particle pressure to nodes - bool map_pressure_to_nodes() noexcept override; - //! Compute pressure smoothing of the particle based on nodal pressure //! $$\hat{p}_p = \sum_{i = 1}^{n_n} N_i(x_p) p_i$$ bool compute_pressure_smoothing() noexcept override; diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index 859f751d9..fc3bd2313 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -727,27 +727,6 @@ void mpm::Particle::compute_updated_position( nodal_velocity * dt; } -//! Map particle pressure to nodes -template -bool mpm::Particle::map_pressure_to_nodes() noexcept { - // Mass is initialized - assert(this->mass() != std::numeric_limits::max()); - - bool status = false; - // Check if particle mass is set and state variable pressure is found - if (this->mass() != std::numeric_limits::max() && - (state_variables_.find("pressure") != state_variables_.end())) { - // Map particle pressure to nodes - for (unsigned i = 0; i < nodes_.size(); ++i) - nodes_[i]->update_mass_pressure( - mpm::ParticlePhase::Solid, - shapefn_[i] * this->mass() * state_variables_["pressure"]); - - status = true; - } - return status; -} - // Compute pressure smoothing of the particle based on nodal pressure template bool mpm::Particle::compute_pressure_smoothing() noexcept { diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 9b421202c..25101ec42 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -260,9 +260,6 @@ class ParticleBase { //! Map internal force virtual void map_internal_force() noexcept = 0; - //! Map particle pressure to nodes - virtual bool map_pressure_to_nodes() noexcept = 0; - //! Compute pressure smoothing of the particle based on nodal pressure virtual bool compute_pressure_smoothing() noexcept = 0; diff --git a/include/particles/particle_functions.tcc b/include/particles/particle_functions.tcc index 66feba4b9..b5dd74e74 100644 --- a/include/particles/particle_functions.tcc +++ b/include/particles/particle_functions.tcc @@ -64,6 +64,22 @@ void map_mass_momentum_to_nodes( particle->mass() * particle->velocity()); } +//! Map particle pressure to nodes +template +void map_mass_pressure_to_nodes( + std::shared_ptr> particle) noexcept { + // Mass is initialized + assert(particle->mass() != std::numeric_limits::max()); + + // Check if state variable pressure is found + if (particle->pressure() != std::numeric_limits::quiet_NaN()) { + // Map particle pressure to nodes + particle->map_scalar_property_nodes( + mpm::properties::Scalar::MassPressure, true, mpm::ParticlePhase::Solid, + particle->mass() * particle->pressure()); + } +} + //! Map body force to nodes template void map_body_force(std::shared_ptr> particle, diff --git a/include/solvers/mpm_explicit.tcc b/include/solvers/mpm_explicit.tcc index 286ab6579..2fcd60001 100644 --- a/include/solvers/mpm_explicit.tcc +++ b/include/solvers/mpm_explicit.tcc @@ -9,9 +9,16 @@ mpm::MPMExplicit::MPMExplicit(const std::shared_ptr& io) //! 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)); + // Assign mass pressure to nodes + mesh_->iterate_over_particles( + [](std::shared_ptr> ptr) { + return mpm::particle::map_mass_pressure_to_nodes(ptr); + }); + + // Compute nodal pressure + mesh_->iterate_over_nodes_predicate( + std::bind(&mpm::NodeBase::compute_pressure, std::placeholders::_1), + std::bind(&mpm::NodeBase::status, std::placeholders::_1)); #ifdef USE_MPI int mpi_size = 1; diff --git a/tests/particle_test.cc b/tests/particle_test.cc index 46a219242..6bcc8eb4e 100644 --- a/tests/particle_test.cc +++ b/tests/particle_test.cc @@ -775,9 +775,6 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { // Map particle mass to nodes particle->assign_mass(std::numeric_limits::max()); - // Map particle pressure to nodes - // TODO Assert: REQUIRE(particle->map_pressure_to_nodes() == false); - // Assign mass to nodes REQUIRE(particle->compute_reference_location() == true); REQUIRE_NOTHROW(particle->compute_shapefn()); @@ -793,7 +790,6 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { REQUIRE_NOTHROW(mpm::particle::compute_mass(particle)); REQUIRE_NOTHROW(mpm::particle::map_mass_momentum_to_nodes(particle)); - // TODO Assert: REQUIRE(particle->map_pressure_to_nodes() == false); REQUIRE(particle->compute_pressure_smoothing() == false); // Values of nodal mass @@ -1093,9 +1089,6 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { // Map particle mass to nodes particle->assign_mass(std::numeric_limits::max()); - // Map particle pressure to nodes - // TODO Assert: REQUIRE(particle->map_pressure_to_nodes() == false); - // Assign mass to nodes REQUIRE(particle->compute_reference_location() == true); REQUIRE_NOTHROW(particle->compute_shapefn()); @@ -1122,7 +1115,7 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { particle->pressure() == Approx(-8333333.333333333 * volumetric_strain).epsilon(Tolerance)); - REQUIRE_NOTHROW(particle->map_pressure_to_nodes()); + REQUIRE_NOTHROW(mpm::particle::map_mass_pressure_to_nodes(particle)); REQUIRE(particle->compute_pressure_smoothing() == true); } @@ -2055,9 +2048,6 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { // Map particle mass to nodes particle->assign_mass(std::numeric_limits::max()); - // Map particle pressure to nodes - // TODO Assert: REQUIRE(particle->map_pressure_to_nodes() == false); - // Assign mass to nodes REQUIRE(particle->compute_reference_location() == true); REQUIRE_NOTHROW(particle->compute_shapefn()); @@ -2073,7 +2063,6 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { REQUIRE_NOTHROW(mpm::particle::compute_mass(particle)); REQUIRE_NOTHROW(mpm::particle::map_mass_momentum_to_nodes(particle)); - // TODO Assert: REQUIRE(particle->map_pressure_to_nodes() == false); REQUIRE(particle->compute_pressure_smoothing() == false); // Values of nodal mass @@ -2367,9 +2356,6 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { // Map particle mass to nodes particle->assign_mass(std::numeric_limits::max()); - // Map particle pressure to nodes - // TODO Assert: REQUIRE(particle->map_pressure_to_nodes() == false); - // Assign mass to nodes REQUIRE(particle->compute_reference_location() == true); REQUIRE_NOTHROW(particle->compute_shapefn()); @@ -2396,7 +2382,7 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { particle->pressure() == Approx(-8333333.333333333 * volumetric_strain).epsilon(Tolerance)); - REQUIRE_NOTHROW(particle->map_pressure_to_nodes()); + REQUIRE_NOTHROW(mpm::particle::map_mass_pressure_to_nodes(particle)); REQUIRE(particle->compute_pressure_smoothing() == true); } From bfee43aead5248d8e72c6fc14968679106ba1bd5 Mon Sep 17 00:00:00 2001 From: Nanda Date: Sat, 11 Jul 2020 19:44:40 -0700 Subject: [PATCH 027/175] :construction: change assign pressure to update pressure --- include/node.h | 5 +++-- include/node.tcc | 8 ++++---- include/node_base.h | 5 +++-- include/solvers/mpm_explicit.tcc | 4 ++-- tests/node_test.cc | 15 ++++++--------- 5 files changed, 18 insertions(+), 19 deletions(-) diff --git a/include/node.h b/include/node.h index de78f18a7..7c826037a 100644 --- a/include/node.h +++ b/include/node.h @@ -170,8 +170,9 @@ class Node : public NodeBase { //! Assign pressure at the nodes from particle //! \param[in] update A boolean to update (true) or assign (false) //! \param[in] phase Index corresponding to the phase - //! \param[in] mass_pressure Product of mass x pressure of a particle - void assign_pressure(unsigned phase, double mass_pressure) override; + //! \param[in] pressure Pressure of a particle + virtual void update_pressure(bool update, unsigned phase, + double pressure) override; //! Return pressure at a given node for a given phase //! \param[in] phase Index corresponding to the phase diff --git a/include/node.tcc b/include/node.tcc index 6bc4ae264..0a6cabf11 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -250,11 +250,11 @@ void mpm::Node::compute_pressure() { //! Assign pressure at the nodes from particle template -void mpm::Node::assign_pressure(unsigned phase, +void mpm::Node::update_pressure(bool update, + unsigned phase, double pressure) { - // Compute pressure from mass*pressure - std::lock_guard guard(node_mutex_); - scalar_properties_.at(mpm::properties::Scalar::Pressure)(phase) = pressure; + this->update_scalar_property(mpm::properties::Scalar::Pressure, update, phase, + pressure); } //! Compute velocity from momentum diff --git a/include/node_base.h b/include/node_base.h index d85080058..a117979c7 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -169,8 +169,9 @@ class NodeBase { //! Assign pressure at the nodes from particle //! \param[in] update A boolean to update (true) or assign (false) //! \param[in] phase Index corresponding to the phase - //! \param[in] mass_pressure Product of mass x pressure of a particle - virtual void assign_pressure(unsigned phase, double mass_pressure) = 0; + //! \param[in] pressure Pressure of a particle + virtual void update_pressure(bool update, unsigned phase, + double pressure) = 0; //! Return pressure at a given node for a given phase //! \param[in] phase Index corresponding to the phase diff --git a/include/solvers/mpm_explicit.tcc b/include/solvers/mpm_explicit.tcc index 2fcd60001..b9b44ca7b 100644 --- a/include/solvers/mpm_explicit.tcc +++ b/include/solvers/mpm_explicit.tcc @@ -31,8 +31,8 @@ void mpm::MPMExplicit::pressure_smoothing(unsigned phase) { // 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)); + std::bind(&mpm::NodeBase::update_pressure, std::placeholders::_1, + false, phase, std::placeholders::_2)); } #endif diff --git a/tests/node_test.cc b/tests/node_test.cc index 3cc92d2a5..6eae5374e 100644 --- a/tests/node_test.cc +++ b/tests/node_test.cc @@ -147,7 +147,7 @@ TEST_CASE("Node is checked for 1D case", "[node][1D]") { REQUIRE(node->pressure(Nphase) == Approx(2001.4).epsilon(Tolerance)); // Assign pressure to 1000 pressure = 1000.; - node->assign_pressure(Nphase, pressure); + REQUIRE_NOTHROW(node->update_pressure(false, Nphase, pressure)); REQUIRE(node->pressure(Nphase) == Approx(1000.0).epsilon(Tolerance)); // Assign mass to 0 mass = 0.; @@ -155,8 +155,7 @@ TEST_CASE("Node is checked for 1D case", "[node][1D]") { REQUIRE(node->mass(Nphase) == Approx(0.0).epsilon(Tolerance)); // Try to update pressure to 2000, should throw and keep to 1000. pressure = 1000.; - const double pmass = 1.5; - node->assign_pressure(Nphase, pressure); + node->update_pressure(false, Nphase, pressure); REQUIRE(node->pressure(Nphase) == Approx(1000.0).epsilon(Tolerance)); } @@ -614,7 +613,7 @@ TEST_CASE("Node is checked for 2D case", "[node][2D]") { REQUIRE(node->pressure(Nphase) == Approx(2001.4).epsilon(Tolerance)); // Assign pressure to 1000 pressure = 1000.; - node->assign_pressure(Nphase, pressure); + REQUIRE_NOTHROW(node->update_pressure(false, Nphase, pressure)); REQUIRE(node->pressure(Nphase) == Approx(1000.0).epsilon(Tolerance)); // Assign mass to 0 mass = 0.; @@ -622,8 +621,7 @@ TEST_CASE("Node is checked for 2D case", "[node][2D]") { REQUIRE(node->mass(Nphase) == Approx(0.0).epsilon(Tolerance)); // Try to update pressure to 2000, should throw and keep to 1000. pressure = 1000.; - const double pmass = 1.5; - node->assign_pressure(Nphase, pressure); + node->update_pressure(false, Nphase, pressure); REQUIRE(node->pressure(Nphase) == Approx(1000.0).epsilon(Tolerance)); } @@ -1218,7 +1216,7 @@ TEST_CASE("Node is checked for 3D case", "[node][3D]") { REQUIRE(node->pressure(Nphase) == Approx(2001.4).epsilon(Tolerance)); // Assign pressure to 1000 pressure = 1000.; - node->assign_pressure(Nphase, pressure); + REQUIRE_NOTHROW(node->update_pressure(false, Nphase, pressure)); REQUIRE(node->pressure(Nphase) == Approx(1000.0).epsilon(Tolerance)); // Assign mass to 0 mass = 0.; @@ -1226,8 +1224,7 @@ TEST_CASE("Node is checked for 3D case", "[node][3D]") { REQUIRE(node->mass(Nphase) == Approx(0.0).epsilon(Tolerance)); // Try to update pressure to 2000, should throw and keep to 1000. pressure = 1000.; - const double pmass = 1.5; - node->assign_pressure(Nphase, pressure); + node->update_pressure(false, Nphase, pressure); REQUIRE(node->pressure(Nphase) == Approx(1000.0).epsilon(Tolerance)); } From 2727d3442a305aad36faf3b0dffa07e06afad650 Mon Sep 17 00:00:00 2001 From: Nanda Date: Sat, 11 Jul 2020 20:03:36 -0700 Subject: [PATCH 028/175] :construction: :dart: refactor update_mass_pressure --- include/node.h | 3 ++- include/node.tcc | 14 +++---------- include/node_base.h | 3 ++- tests/node_test.cc | 48 +++++++++++++++++++++++++++++++++------------ 4 files changed, 43 insertions(+), 25 deletions(-) diff --git a/include/node.h b/include/node.h index 7c826037a..099c2dbae 100644 --- a/include/node.h +++ b/include/node.h @@ -159,9 +159,10 @@ class Node : public NodeBase { } //! Update pressure at the nodes from particle + //! \param[in] update A boolean to update (true) or assign (false) //! \param[in] phase Index corresponding to the phase //! \param[in] mass_pressure Product of mass x pressure of a particle - void update_mass_pressure(unsigned phase, + void update_mass_pressure(bool update, unsigned phase, double mass_pressure) noexcept override; //! Compute pressure from the mass pressure diff --git a/include/node.tcc b/include/node.tcc index 0a6cabf11..54ae7f6d4 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -217,17 +217,9 @@ void mpm::Node::update_momentum( //! Update pressure at the nodes from particle template void mpm::Node::update_mass_pressure( - unsigned phase, double mass_pressure) noexcept { - // Assert - assert(phase < Tnphases); - - const double tolerance = 1.E-16; - // Compute pressure from mass*pressure - if (this->mass(phase) > tolerance) { - std::lock_guard guard(node_mutex_); - scalar_properties_.at(mpm::properties::Scalar::Pressure)(phase) += - mass_pressure / this->mass(phase); - } + bool update, unsigned phase, double mass_pressure) noexcept { + this->update_scalar_property(mpm::properties::Scalar::MassPressure, update, + phase, mass_pressure); } //! Compute pressure from mass pressure diff --git a/include/node_base.h b/include/node_base.h index a117979c7..7ae912b01 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -158,9 +158,10 @@ class NodeBase { virtual VectorDim internal_force(unsigned phase) const = 0; //! Update pressure at the nodes from particle + //! \param[in] update A boolean to update (true) or assign (false) //! \param[in] phase Index corresponding to the phase //! \param[in] mass_pressure Product of mass x pressure of a particle - virtual void update_mass_pressure(unsigned phase, + virtual void update_mass_pressure(bool update, unsigned phase, double mass_pressure) noexcept = 0; //! Compute pressure from the mass pressure diff --git a/tests/node_test.cc b/tests/node_test.cc index 6eae5374e..db41277af 100644 --- a/tests/node_test.cc +++ b/tests/node_test.cc @@ -140,10 +140,14 @@ TEST_CASE("Node is checked for 1D case", "[node][1D]") { REQUIRE(node->pressure(Nphase) == Approx(0.0).epsilon(Tolerance)); double pressure = 1000.7; // Update pressure to 1000.7 - REQUIRE_NOTHROW(node->update_mass_pressure(Nphase, mass * pressure)); + REQUIRE_NOTHROW( + node->update_mass_pressure(false, Nphase, mass * pressure)); + node->compute_pressure(); REQUIRE(node->pressure(Nphase) == Approx(1000.7).epsilon(Tolerance)); // Update pressure to 2001.4 - REQUIRE_NOTHROW(node->update_mass_pressure(Nphase, mass * pressure)); + REQUIRE_NOTHROW( + node->update_mass_pressure(true, Nphase, mass * pressure)); + node->compute_pressure(); REQUIRE(node->pressure(Nphase) == Approx(2001.4).epsilon(Tolerance)); // Assign pressure to 1000 pressure = 1000.; @@ -153,10 +157,14 @@ TEST_CASE("Node is checked for 1D case", "[node][1D]") { mass = 0.; REQUIRE_NOTHROW(node->update_mass(false, Nphase, mass)); REQUIRE(node->mass(Nphase) == Approx(0.0).epsilon(Tolerance)); - // Try to update pressure to 2000, should throw and keep to 1000. + // Try to update pressure, should throw and keep to 1000. pressure = 1000.; - node->update_pressure(false, Nphase, pressure); + node->update_mass_pressure(false, Nphase, pressure); + node->compute_pressure(); REQUIRE(node->pressure(Nphase) == Approx(1000.0).epsilon(Tolerance)); + // Update pressure to 2000. + REQUIRE_NOTHROW(node->update_pressure(true, Nphase, pressure)); + REQUIRE(node->pressure(Nphase) == Approx(2000.0).epsilon(Tolerance)); } SECTION("Check external force") { @@ -606,10 +614,14 @@ TEST_CASE("Node is checked for 2D case", "[node][2D]") { REQUIRE(node->pressure(Nphase) == Approx(0.0).epsilon(Tolerance)); double pressure = 1000.7; // Update pressure to 1000.7 - REQUIRE_NOTHROW(node->update_mass_pressure(Nphase, mass * pressure)); + REQUIRE_NOTHROW( + node->update_mass_pressure(false, Nphase, mass * pressure)); + node->compute_pressure(); REQUIRE(node->pressure(Nphase) == Approx(1000.7).epsilon(Tolerance)); // Update pressure to 2001.4 - REQUIRE_NOTHROW(node->update_mass_pressure(Nphase, mass * pressure)); + REQUIRE_NOTHROW( + node->update_mass_pressure(true, Nphase, mass * pressure)); + node->compute_pressure(); REQUIRE(node->pressure(Nphase) == Approx(2001.4).epsilon(Tolerance)); // Assign pressure to 1000 pressure = 1000.; @@ -619,10 +631,14 @@ TEST_CASE("Node is checked for 2D case", "[node][2D]") { mass = 0.; REQUIRE_NOTHROW(node->update_mass(false, Nphase, mass)); REQUIRE(node->mass(Nphase) == Approx(0.0).epsilon(Tolerance)); - // Try to update pressure to 2000, should throw and keep to 1000. + // Try to update pressure, should throw and keep to 1000. pressure = 1000.; - node->update_pressure(false, Nphase, pressure); + node->update_mass_pressure(false, Nphase, pressure); + node->compute_pressure(); REQUIRE(node->pressure(Nphase) == Approx(1000.0).epsilon(Tolerance)); + // Update pressure to 2000. + REQUIRE_NOTHROW(node->update_pressure(true, Nphase, pressure)); + REQUIRE(node->pressure(Nphase) == Approx(2000.0).epsilon(Tolerance)); } SECTION("Check volume") { @@ -1209,10 +1225,14 @@ TEST_CASE("Node is checked for 3D case", "[node][3D]") { REQUIRE(node->pressure(Nphase) == Approx(0.0).epsilon(Tolerance)); double pressure = 1000.7; // Update pressure to 1000.7 - REQUIRE_NOTHROW(node->update_mass_pressure(Nphase, mass * pressure)); + REQUIRE_NOTHROW( + node->update_mass_pressure(false, Nphase, mass * pressure)); + node->compute_pressure(); REQUIRE(node->pressure(Nphase) == Approx(1000.7).epsilon(Tolerance)); // Update pressure to 2001.4 - REQUIRE_NOTHROW(node->update_mass_pressure(Nphase, mass * pressure)); + REQUIRE_NOTHROW( + node->update_mass_pressure(true, Nphase, mass * pressure)); + node->compute_pressure(); REQUIRE(node->pressure(Nphase) == Approx(2001.4).epsilon(Tolerance)); // Assign pressure to 1000 pressure = 1000.; @@ -1222,10 +1242,14 @@ TEST_CASE("Node is checked for 3D case", "[node][3D]") { mass = 0.; REQUIRE_NOTHROW(node->update_mass(false, Nphase, mass)); REQUIRE(node->mass(Nphase) == Approx(0.0).epsilon(Tolerance)); - // Try to update pressure to 2000, should throw and keep to 1000. + // Try to update pressure, should throw and keep to 1000. pressure = 1000.; - node->update_pressure(false, Nphase, pressure); + node->update_mass_pressure(false, Nphase, pressure); + node->compute_pressure(); REQUIRE(node->pressure(Nphase) == Approx(1000.0).epsilon(Tolerance)); + // Update pressure to 2000. + REQUIRE_NOTHROW(node->update_pressure(true, Nphase, pressure)); + REQUIRE(node->pressure(Nphase) == Approx(2000.0).epsilon(Tolerance)); } SECTION("Check external force") { From f9602fd9a953ab2f9409eb59a698a8ee185b120c Mon Sep 17 00:00:00 2001 From: Nanda Date: Sat, 11 Jul 2020 20:39:48 -0700 Subject: [PATCH 029/175] :wrench: fix return value of interpolate vector properties --- include/particles/particle_base.h | 10 ++++++---- include/particles/particle_base.tcc | 7 +++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 25101ec42..46384b794 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -153,7 +153,8 @@ class ParticleBase { void map_scalar_property_nodes(mpm::properties::Scalar property, bool update, unsigned phase, double value) noexcept; - //! Return property at a given node for a given phase + //! Return an interpolation of scalar property in particle from nodes + //! \param[in] property Name of the property to update //! \param[in] phase Index corresponding to the phase double interpolate_scalar_property_nodes(mpm::properties::Scalar property, unsigned phase) const; @@ -187,10 +188,11 @@ class ParticleBase { mpm::properties::Vector property, bool update, unsigned phase, const Eigen::Matrix& value) noexcept; - //! Return property at a given node for a given phase + //! Return an interpolation of vector property in particle from nodes + //! \param[in] property Name of the property to update //! \param[in] phase Index corresponding to the phase - double interpolate_vector_property_nodes(mpm::properties::Vector property, - unsigned phase) const; + Eigen::Matrix interpolate_vector_property_nodes( + mpm::properties::Vector property, unsigned phase) const; //! Return mass density virtual double mass_density() const = 0; diff --git a/include/particles/particle_base.tcc b/include/particles/particle_base.tcc index 4a389ee6d..f67c45ebf 100644 --- a/include/particles/particle_base.tcc +++ b/include/particles/particle_base.tcc @@ -90,7 +90,6 @@ Eigen::Matrix mpm::ParticleBase::vector_property( template void mpm::ParticleBase::map_vector_property_nodes( mpm::properties::Vector property, bool update, unsigned phase) noexcept { - // TODO: Check assert needed? // Map vector property to nodes for (unsigned i = 0; i < nodes_.size(); ++i) nodes_[i]->update_vector_property( @@ -102,7 +101,6 @@ template void mpm::ParticleBase::map_vector_property_nodes( mpm::properties::Vector property, bool update, unsigned phase, const Eigen::Matrix& value) noexcept { - // TODO: Check assert needed? // Map vector property to nodes for (unsigned i = 0; i < nodes_.size(); ++i) nodes_[i]->update_vector_property(property, update, phase, @@ -111,8 +109,9 @@ void mpm::ParticleBase::map_vector_property_nodes( //! Interpolate vector property from nodes template -double mpm::ParticleBase::interpolate_vector_property_nodes( - mpm::properties::Vector property, unsigned phase) const { +Eigen::Matrix + mpm::ParticleBase::interpolate_vector_property_nodes( + mpm::properties::Vector property, unsigned phase) const { Eigen::Matrix value = Eigen::Matrix::Zero(); // Interpolate vector property from nodes for (unsigned i = 0; i < nodes_.size(); ++i) From a3ee6845fa89c2fcd579e0a164e8d052ea62f1ca Mon Sep 17 00:00:00 2001 From: Nanda Date: Sat, 11 Jul 2020 20:41:20 -0700 Subject: [PATCH 030/175] :construction: :dart: use interpolate functions in particle --- include/particles/particle.tcc | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index fc3bd2313..9499bd73f 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -696,21 +696,14 @@ void mpm::Particle::compute_updated_position( // Check if particle has a valid cell ptr assert(cell_ != nullptr); // Get interpolated nodal velocity - Eigen::Matrix nodal_velocity = - Eigen::Matrix::Zero(); - - for (unsigned i = 0; i < nodes_.size(); ++i) - nodal_velocity += - shapefn_[i] * nodes_[i]->velocity(mpm::ParticlePhase::Solid); + const auto& nodal_velocity = this->interpolate_vector_property_nodes( + mpm::properties::Vector::Velocity, mpm::ParticlePhase::Solid); // Acceleration update if (!velocity_update) { // Get interpolated nodal acceleration - Eigen::Matrix nodal_acceleration = - Eigen::Matrix::Zero(); - for (unsigned i = 0; i < nodes_.size(); ++i) - nodal_acceleration += - shapefn_[i] * nodes_[i]->acceleration(mpm::ParticlePhase::Solid); + const auto& nodal_acceleration = this->interpolate_vector_property_nodes( + mpm::properties::Vector::Acceleration, mpm::ParticlePhase::Solid); // Update particle velocity from interpolated nodal acceleration vector_properties_.at(mpm::properties::Vector::Velocity) += @@ -722,6 +715,7 @@ void mpm::Particle::compute_updated_position( // New position current position + velocity * dt this->coordinates_ += nodal_velocity * dt; + // Update displacement (displacement is initialized from zero) vector_properties_.at(mpm::properties::Vector::Displacement) += nodal_velocity * dt; @@ -737,13 +731,8 @@ bool mpm::Particle::compute_pressure_smoothing() noexcept { // Check if particle has a valid cell ptr if (cell_ != nullptr && (state_variables_.find("pressure") != state_variables_.end())) { - - double pressure = 0.; - // Update particle pressure to interpolated nodal pressure - for (unsigned i = 0; i < this->nodes_.size(); ++i) - pressure += shapefn_[i] * nodes_[i]->pressure(mpm::ParticlePhase::Solid); - - state_variables_["pressure"] = pressure; + state_variables_["pressure"] = this->interpolate_scalar_property_nodes( + mpm::properties::Scalar::Pressure, mpm::ParticlePhase::Solid); status = true; } return status; From 45aa3ba30d382b707a8ec18c28866bd6dbbdcc9f Mon Sep 17 00:00:00 2001 From: Nanda Date: Sun, 12 Jul 2020 20:34:32 -0700 Subject: [PATCH 031/175] :construction: refactor pressure smoothing interpolation --- include/particles/particle.h | 12 ++++++++---- include/particles/particle.tcc | 17 ----------------- include/particles/particle_base.h | 6 +++--- include/particles/particle_functions.tcc | 15 +++++++++++++++ include/solvers/mpm_explicit.tcc | 5 +++-- 5 files changed, 29 insertions(+), 26 deletions(-) diff --git a/include/particles/particle.h b/include/particles/particle.h index ca84fb21b..e45adc107 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -235,6 +235,14 @@ class Particle : public ParticleBase { void compute_updated_position(double dt, bool velocity_update = false) noexcept override; + //! Assign a state variable + //! \param[in] var State variable + //! \param[in] value State variable to be assigned + void assign_state_variable(const std::string& var, double value) override { + if (state_variables_.find(var) != state_variables_.end()) + state_variables_.at(var) = value; + } + //! Return a state variable //! \param[in] var State variable //! \retval Quantity of the state history variable @@ -244,10 +252,6 @@ class Particle : public ParticleBase { : std::numeric_limits::quiet_NaN(); } - //! Compute pressure smoothing of the particle based on nodal pressure - //! $$\hat{p}_p = \sum_{i = 1}^{n_n} N_i(x_p) p_i$$ - bool compute_pressure_smoothing() noexcept override; - //! Return pressure of the particles double pressure() const override { return (state_variables_.find("pressure") != state_variables_.end()) diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index 9499bd73f..98ca378f9 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -721,23 +721,6 @@ void mpm::Particle::compute_updated_position( nodal_velocity * dt; } -// Compute pressure smoothing of the particle based on nodal pressure -template -bool mpm::Particle::compute_pressure_smoothing() noexcept { - // Assert - assert(cell_ != nullptr); - - bool status = false; - // Check if particle has a valid cell ptr - if (cell_ != nullptr && - (state_variables_.find("pressure") != state_variables_.end())) { - state_variables_["pressure"] = this->interpolate_scalar_property_nodes( - mpm::properties::Scalar::Pressure, mpm::ParticlePhase::Solid); - status = true; - } - return status; -} - //! Apply particle velocity constraints template void mpm::Particle::apply_particle_velocity_constraints(unsigned dir, diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 46384b794..231dbcb40 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -262,9 +262,6 @@ class ParticleBase { //! Map internal force virtual void map_internal_force() noexcept = 0; - //! Compute pressure smoothing of the particle based on nodal pressure - virtual bool compute_pressure_smoothing() noexcept = 0; - //! Assign velocity virtual void assign_velocity(const VectorDim& velocity) = 0; @@ -287,6 +284,9 @@ class ParticleBase { virtual void compute_updated_position( double dt, bool velocity_update = false) noexcept = 0; + //! Return a state variable + virtual void assign_state_variable(const std::string& var, double value) = 0; + //! Return a state variable virtual double state_variable(const std::string& var) const = 0; diff --git a/include/particles/particle_functions.tcc b/include/particles/particle_functions.tcc index b5dd74e74..7134f0c89 100644 --- a/include/particles/particle_functions.tcc +++ b/include/particles/particle_functions.tcc @@ -102,5 +102,20 @@ void map_traction_force( } } +// Compute pressure smoothing of the particle based on nodal pressure +template +void compute_pressure_smoothing( + std::shared_ptr> particle) noexcept { + // Assert + assert(particle->cell_ptr()); + + // Check if particle has pressure + if (particle->pressure() != std::numeric_limits::quiet_NaN()) { + double pressure = particle->interpolate_scalar_property_nodes( + mpm::properties::Scalar::Pressure, mpm::ParticlePhase::Solid); + particle->assign_state_variable("pressure", pressure); + } +} + } // namespace particle } // namespace mpm diff --git a/include/solvers/mpm_explicit.tcc b/include/solvers/mpm_explicit.tcc index b9b44ca7b..0b097bb32 100644 --- a/include/solvers/mpm_explicit.tcc +++ b/include/solvers/mpm_explicit.tcc @@ -38,8 +38,9 @@ void mpm::MPMExplicit::pressure_smoothing(unsigned phase) { // Smooth pressure over particles mesh_->iterate_over_particles( - std::bind(&mpm::ParticleBase::compute_pressure_smoothing, - std::placeholders::_1)); + [](std::shared_ptr> ptr) { + return mpm::particle::compute_pressure_smoothing(ptr); + }); } //! MPM Explicit compute stress strain From 212505e6af1f698a93c26867a930259cde745e55 Mon Sep 17 00:00:00 2001 From: Nanda Date: Sun, 12 Jul 2020 20:34:47 -0700 Subject: [PATCH 032/175] :dart: fix and add pressure mapping test --- tests/particle_test.cc | 66 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 6 deletions(-) diff --git a/tests/particle_test.cc b/tests/particle_test.cc index 6bcc8eb4e..21e5ad332 100644 --- a/tests/particle_test.cc +++ b/tests/particle_test.cc @@ -790,8 +790,6 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { REQUIRE_NOTHROW(mpm::particle::compute_mass(particle)); REQUIRE_NOTHROW(mpm::particle::map_mass_momentum_to_nodes(particle)); - REQUIRE(particle->compute_pressure_smoothing() == false); - // Values of nodal mass std::array nodal_mass{562.5, 187.5, 62.5, 187.5}; // Check nodal mass @@ -1075,6 +1073,9 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { Factory, unsigned, const Json&>::instance() ->create("Newtonian2D", std::move(mid1), jmaterial1); + // Reset nodal properties + for (const auto& node : nodes) node->initialise(); + // Assign material properties REQUIRE(particle->assign_material(material1) == true); @@ -1115,8 +1116,38 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { particle->pressure() == Approx(-8333333.333333333 * volumetric_strain).epsilon(Tolerance)); + // Check return and assign state variable + REQUIRE( + particle->state_variable("pressure") == + Approx(-8333333.333333333 * volumetric_strain).epsilon(Tolerance)); + + REQUIRE_NOTHROW(particle->assign_state_variable( + "pressure", -8333333.333333333 * volumetric_strain)); + + // Check pressure smoothing REQUIRE_NOTHROW(mpm::particle::map_mass_pressure_to_nodes(particle)); - REQUIRE(particle->compute_pressure_smoothing() == true); + for (const auto& node : nodes) node->compute_pressure(); + REQUIRE_NOTHROW(mpm::particle::compute_pressure_smoothing(particle)); + REQUIRE( + particle->pressure() == + Approx(-8333333.333333333 * volumetric_strain).epsilon(Tolerance)); + + // Assign pressure equal to 1.0, we expect its smoothed value is also 1.0 + REQUIRE_NOTHROW(particle->assign_state_variable("pressure", 1.0)); + REQUIRE(particle->pressure() == Approx(1.0).epsilon(Tolerance)); + + for (const auto& node : nodes) + node->update_scalar_property(mpm::properties::Scalar::MassPressure, + false, 0, 0.0); + REQUIRE_NOTHROW(mpm::particle::map_mass_pressure_to_nodes(particle)); + for (const auto& node : nodes) { + REQUIRE( + node->scalar_property(mpm::properties::Scalar::MassPressure, 0) == + node->scalar_property(mpm::properties::Scalar::Mass, 0)); + node->compute_pressure(); + } + REQUIRE_NOTHROW(mpm::particle::compute_pressure_smoothing(particle)); + REQUIRE(particle->pressure() == Approx(1.0).epsilon(Tolerance)); } SECTION("Particle assign state variables") { @@ -2063,8 +2094,6 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { REQUIRE_NOTHROW(mpm::particle::compute_mass(particle)); REQUIRE_NOTHROW(mpm::particle::map_mass_momentum_to_nodes(particle)); - REQUIRE(particle->compute_pressure_smoothing() == false); - // Values of nodal mass std::array nodal_mass{125., 375., 1125., 375., 375., 1125., 3375., 1125.}; @@ -2382,8 +2411,33 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { particle->pressure() == Approx(-8333333.333333333 * volumetric_strain).epsilon(Tolerance)); + // Check return and assign state variable + REQUIRE( + particle->state_variable("pressure") == + Approx(-8333333.333333333 * volumetric_strain).epsilon(Tolerance)); + + REQUIRE_NOTHROW(particle->assign_state_variable( + "pressure", -8333333.333333333 * volumetric_strain)); + + // Check pressure smoothing + REQUIRE_NOTHROW(mpm::particle::map_mass_pressure_to_nodes(particle)); + for (const auto& node : nodes) node->compute_pressure(); + REQUIRE_NOTHROW(mpm::particle::compute_pressure_smoothing(particle)); + REQUIRE(particle->pressure() == + Approx(-2083333.3333333333).epsilon(Tolerance)); + + // Assign pressure equal to 1.0, we expect its smoothed value is 0.5 as + // the nodal mass is mapped twice in this case + REQUIRE_NOTHROW(particle->assign_state_variable("pressure", 1.0)); + REQUIRE(particle->pressure() == Approx(1.0).epsilon(Tolerance)); + + for (const auto& node : nodes) + node->update_scalar_property(mpm::properties::Scalar::MassPressure, + false, 0, 0.0); REQUIRE_NOTHROW(mpm::particle::map_mass_pressure_to_nodes(particle)); - REQUIRE(particle->compute_pressure_smoothing() == true); + for (const auto& node : nodes) node->compute_pressure(); + REQUIRE_NOTHROW(mpm::particle::compute_pressure_smoothing(particle)); + REQUIRE(particle->pressure() == Approx(0.5).epsilon(Tolerance)); } SECTION("Particle assign state variables") { From 1251bd7f326e652318ff22590cf187ad19dc286e Mon Sep 17 00:00:00 2001 From: Nanda Date: Sun, 12 Jul 2020 20:39:05 -0700 Subject: [PATCH 033/175] :construction: add TODO notes in particle.tcc --- include/particles/particle.tcc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index 98ca378f9..d7e740876 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -478,6 +478,7 @@ bool mpm::Particle::assign_volume(double volume) { } //! Map multimaterial properties to nodes +// TODO: Contact function to be refactored template void mpm::Particle::map_multimaterial_mass_momentum_to_nodes() noexcept { // Check if particle mass is set @@ -496,6 +497,7 @@ void mpm::Particle::map_multimaterial_mass_momentum_to_nodes() noexcept { } //! Map multimaterial displacements to nodes +// TODO: Contact function to be refactored template void mpm::Particle::map_multimaterial_displacements_to_nodes() noexcept { // Check if particle mass is set @@ -512,6 +514,7 @@ void mpm::Particle::map_multimaterial_displacements_to_nodes() noexcept { } //! Map multimaterial domain gradients to nodes +// TODO: Contact function to be refactored template void mpm::Particle< Tdim>::map_multimaterial_domain_gradients_to_nodes() noexcept { @@ -722,6 +725,8 @@ void mpm::Particle::compute_updated_position( } //! Apply particle velocity constraints +// TODO: revisit constraint application in vector properties, should assign +// direction template void mpm::Particle::apply_particle_velocity_constraints(unsigned dir, double velocity) { @@ -736,6 +741,7 @@ Eigen::VectorXd mpm::Particle::tensor_data(const std::string& property) { } //! Assign material id of this particle to nodes +// TODO: Contact function to be refactored template void mpm::Particle::append_material_id_to_nodes() const { for (unsigned i = 0; i < nodes_.size(); ++i) From 27ea5d6f14588c9986c9bd027cbfa385ee3f4bae Mon Sep 17 00:00:00 2001 From: Nanda Date: Sun, 12 Jul 2020 20:52:06 -0700 Subject: [PATCH 034/175] :dart: add test for assign and return scalar and vector property --- tests/node_test.cc | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/node_test.cc b/tests/node_test.cc index db41277af..9bd3584c7 100644 --- a/tests/node_test.cc +++ b/tests/node_test.cc @@ -134,6 +134,16 @@ TEST_CASE("Node is checked for 1D case", "[node][1D]") { mass = 100.; REQUIRE_NOTHROW(node->update_mass(false, Nphase, mass)); REQUIRE(node->mass(Nphase) == Approx(100.0).epsilon(Tolerance)); + // Assign mass to 200 using scalar property update true + REQUIRE_NOTHROW(node->update_scalar_property(mpm::properties::Scalar::Mass, + true, Nphase, mass)); + REQUIRE(node->scalar_property(mpm::properties::Scalar::Mass, Nphase) == + Approx(200.0).epsilon(Tolerance)); + // Assign mass to 100 using scalar property update false + REQUIRE_NOTHROW(node->update_scalar_property(mpm::properties::Scalar::Mass, + false, Nphase, mass)); + REQUIRE(node->scalar_property(mpm::properties::Scalar::Mass, Nphase) == + Approx(100.0).epsilon(Tolerance)); SECTION("Check nodal pressure") { // Check pressure @@ -268,6 +278,22 @@ TEST_CASE("Node is checked for 1D case", "[node][1D]") { for (unsigned i = 0; i < force.size(); ++i) REQUIRE(node->internal_force(Nphase)(i) == Approx(10.).epsilon(Tolerance)); + + // Assign force to 20 using vector property update true + REQUIRE_NOTHROW(node->update_vector_property( + mpm::properties::Vector::InternalForce, true, Nphase, force)); + for (unsigned i = 0; i < force.size(); ++i) + REQUIRE(node->vector_property(mpm::properties::Vector::InternalForce, + Nphase)(i) == + Approx(20.).epsilon(Tolerance)); + + // Assign force to 10 using vector property update false + REQUIRE_NOTHROW(node->update_vector_property( + mpm::properties::Vector::InternalForce, false, Nphase, force)); + for (unsigned i = 0; i < force.size(); ++i) + REQUIRE(node->vector_property(mpm::properties::Vector::InternalForce, + Nphase)(i) == + Approx(10.).epsilon(Tolerance)); } SECTION("Check compute acceleration and velocity") { From ae339f1a80790e21997fd3ea8171515c0e950a85 Mon Sep 17 00:00:00 2001 From: Nanda Date: Mon, 13 Jul 2020 09:56:18 -0700 Subject: [PATCH 035/175] :wrench: 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 faabd0398..15ec41886 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -813,8 +813,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 7491c3429a5b419faebad2c726c9919573e964d7 Mon Sep 17 00:00:00 2001 From: Tianchi Date: Mon, 13 Jul 2020 15:51:29 -0700 Subject: [PATCH 036/175] Add twophase explicit logger --- include/io/logger.h | 3 +++ include/mesh.tcc | 18 ++++++++++++++++++ src/io/logger.cc | 5 +++++ 3 files changed, 26 insertions(+) diff --git a/include/io/logger.h b/include/io/logger.h index 082a0e874..6d2b152d2 100644 --- a/include/io/logger.h +++ b/include/io/logger.h @@ -41,6 +41,9 @@ struct Logger { // Create a logger for MPM Explicit USL static const std::shared_ptr mpm_explicit_usl_logger; + + // Create a logger for MPM Explicit + static const std::shared_ptr mpm_explicit_twophase_logger; }; } // namespace mpm diff --git a/include/mesh.tcc b/include/mesh.tcc index ef9a33d8f..be8d7ec73 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1690,6 +1690,15 @@ bool mpm::Mesh::generate_particles(const std::shared_ptr& io, // Particle set id unsigned pset_id = generator["pset_id"].template get(); status = this->read_particles_file(io, generator, pset_id); + // Assign liquid material for twophase particle + if (generator["particle_type"] == "P2D2PHASE") { + // Liquid material + auto liquid_material = materials_.at(generator["liquid_material_id"]); + // Assign liquid material + iterate_over_particle_set( + pset_id, std::bind(&mpm::ParticleBase::assign_liquid_material, + std::placeholders::_1, liquid_material)); + } } // Generate material points at the Gauss location in all cells @@ -1708,6 +1717,15 @@ bool mpm::Mesh::generate_particles(const std::shared_ptr& io, unsigned pset_id = generator["pset_id"].template get(); status = this->generate_material_points(nparticles_dir, particle_type, material_id, cset_id, pset_id); + // Assign liquid material for twophase particle + if (particle_type == "P2D2PHASE") { + // Liquid material + auto liquid_material = materials_.at(generator["liquid_material_id"]); + // Assign liquid material + iterate_over_particle_set( + pset_id, std::bind(&mpm::ParticleBase::assign_liquid_material, + std::placeholders::_1, liquid_material)); + } } // Generate material points at the Gauss location in all cells diff --git a/src/io/logger.cc b/src/io/logger.cc index 82e2b262c..16e804077 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 Explicit TwoPhase +const std::shared_ptr + mpm::Logger::mpm_explicit_twophase_logger = + spdlog::stdout_color_st("MPMExplicitTwoPhase"); \ No newline at end of file From f34b64c2aa25cde88ca3ce8170c8bfbe403cbb5a Mon Sep 17 00:00:00 2001 From: Nanda Date: Mon, 13 Jul 2020 18:20:20 -0700 Subject: [PATCH 037/175] :wrench: remove virtual in initialise particle --- include/particles/particle.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/particles/particle.h b/include/particles/particle.h index e45adc107..06ece14dc 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -55,7 +55,7 @@ class Particle : public ParticleBase { //! \param[in] particle HDF5 data of particle //! \param[in] material Material associated with the particle //! \retval status Status of reading HDF5 particle - virtual bool initialise_particle( + bool initialise_particle( const HDF5Particle& particle, const std::shared_ptr>& material) override; From 164491fd7f5c7ef09536405aeb2ae0d5fd8947ea Mon Sep 17 00:00:00 2001 From: Nanda Date: Mon, 13 Jul 2020 20:44:16 -0700 Subject: [PATCH 038/175] :dart: :construction_worker: revert benchmarks to gcc --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index cd3613b44..57f12f47b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -127,7 +127,7 @@ workflows: version: 2 build: jobs: - - benchmarks + - gcc - clang - cppcheck - codecov From 3d35f450f71d6d69b979379795462aecf5e96cf7 Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 14 Jul 2020 10:35:26 -0700 Subject: [PATCH 039/175] :wrench: modify explanation as suggested --- include/node.h | 2 ++ include/node_base.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/include/node.h b/include/node.h index 099c2dbae..79dfe271f 100644 --- a/include/node.h +++ b/include/node.h @@ -74,6 +74,7 @@ class Node : public NodeBase { unsigned phase, double value) noexcept override; //! Return property at a given node for a given phase + //! \param[in] property Name of the property to return //! \param[in] phase Index corresponding to the phase double scalar_property(mpm::properties::Scalar property, unsigned phase) const override; @@ -88,6 +89,7 @@ class Node : public NodeBase { const Eigen::Matrix& value) noexcept override; //! Return property at a given node for a given phase + //! \param[in] property Name of the property to return //! \param[in] phase Index corresponding to the phase virtual Eigen::Matrix vector_property( mpm::properties::Vector property, unsigned phase) const override; diff --git a/include/node_base.h b/include/node_base.h index 7ae912b01..018dc31fc 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -82,6 +82,7 @@ class NodeBase { double value) noexcept = 0; //! Return property at a given node for a given phase + //! \param[in] property Name of the property to return //! \param[in] phase Index corresponding to the phase virtual double scalar_property(mpm::properties::Scalar property, unsigned phase) const = 0; @@ -96,6 +97,7 @@ class NodeBase { const Eigen::Matrix& value) noexcept = 0; //! Return property at a given node for a given phase + //! \param[in] property Name of the property to return //! \param[in] phase Index corresponding to the phase virtual Eigen::Matrix vector_property( mpm::properties::Vector property, unsigned phase) const = 0; From deb54a7f29411cd2b060c95885ce101b636d7879 Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 14 Jul 2020 17:25:44 -0700 Subject: [PATCH 040/175] :construction: :dart: some minor corrections and test addition --- include/particles/particle.h | 10 +++++++--- include/particles/particle_base.h | 4 +++- tests/mpm_explicit_usf_test.cc | 18 ++++++++++++++++++ tests/particle_test.cc | 8 ++++---- 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/include/particles/particle.h b/include/particles/particle.h index 06ece14dc..b0b20b255 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -127,7 +127,7 @@ class Particle : public ParticleBase { //! Return size of particle in natural coordinates VectorDim natural_size() const override { return natural_size_; } - //! \param[in] phase Index corresponding to the phase + //! Return mass density double mass_density() const override { return this->scalar_property(mpm::properties::Scalar::MassDensity); } @@ -143,7 +143,6 @@ class Particle : public ParticleBase { //! Assign nodal mass to particles //! \param[in] mass Mass from the particles in a cell - //! \retval status Assignment status void assign_mass(double mass) override { scalar_properties_.at(mpm::properties::Scalar::Mass) = mass; } @@ -201,7 +200,6 @@ class Particle : public ParticleBase { //! Assign velocity to the particle //! \param[in] velocity A vector of particle velocity - //! \retval status Assignment status void assign_velocity(const VectorDim& velocity) override { vector_properties_.at(mpm::properties::Vector::Velocity) = velocity; }; @@ -252,6 +250,12 @@ class Particle : public ParticleBase { : std::numeric_limits::quiet_NaN(); } + //! Assign a state variable + //! \param[in] value Particle pressure to be assigned + void assign_pressure(double pressure) override { + this->assign_state_variable("pressure", pressure); + } + //! Return pressure of the particles double pressure() const override { return (state_variables_.find("pressure") != state_variables_.end()) diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 231dbcb40..fb119bc2a 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -211,7 +211,6 @@ class ParticleBase { const std::shared_ptr>& material) = 0; //! Return material - //! \retval material Pointer to a material virtual std::shared_ptr> material() const = 0; //! Return material id @@ -232,6 +231,9 @@ class ParticleBase { //! Return mass virtual double mass() const = 0; + //! Assign pressure + virtual void assign_pressure(double pressure) = 0; + //! Return pressure virtual double pressure() const = 0; diff --git a/tests/mpm_explicit_usf_test.cc b/tests/mpm_explicit_usf_test.cc index 89062396f..3d7b6de49 100644 --- a/tests/mpm_explicit_usf_test.cc +++ b/tests/mpm_explicit_usf_test.cc @@ -85,6 +85,15 @@ TEST_CASE("MPM 2D Explicit implementation is checked", // Solve REQUIRE(mpm->solve() == true); } + + SECTION("Check pressure smoothing") { + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit MPM + auto mpm = std::make_unique>(std::move(io)); + // Pressure smoothing + REQUIRE_NOTHROW(mpm->pressure_smoothing(0)); + } } // Check MPM Explicit @@ -162,4 +171,13 @@ TEST_CASE("MPM 3D Explicit implementation is checked", // Solve REQUIRE(mpm->solve() == true); } + + SECTION("Check pressure smoothing") { + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit MPM + auto mpm = std::make_unique>(std::move(io)); + // Pressure smoothing + REQUIRE_NOTHROW(mpm->pressure_smoothing(0)); + } } diff --git a/tests/particle_test.cc b/tests/particle_test.cc index 21e5ad332..3663d2889 100644 --- a/tests/particle_test.cc +++ b/tests/particle_test.cc @@ -1121,8 +1121,8 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { particle->state_variable("pressure") == Approx(-8333333.333333333 * volumetric_strain).epsilon(Tolerance)); - REQUIRE_NOTHROW(particle->assign_state_variable( - "pressure", -8333333.333333333 * volumetric_strain)); + REQUIRE_NOTHROW( + particle->assign_pressure(-8333333.333333333 * volumetric_strain)); // Check pressure smoothing REQUIRE_NOTHROW(mpm::particle::map_mass_pressure_to_nodes(particle)); @@ -2416,8 +2416,8 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { particle->state_variable("pressure") == Approx(-8333333.333333333 * volumetric_strain).epsilon(Tolerance)); - REQUIRE_NOTHROW(particle->assign_state_variable( - "pressure", -8333333.333333333 * volumetric_strain)); + REQUIRE_NOTHROW( + particle->assign_pressure(-8333333.333333333 * volumetric_strain)); // Check pressure smoothing REQUIRE_NOTHROW(mpm::particle::map_mass_pressure_to_nodes(particle)); From fcfcf871ab47404f23978f5bc2c54b587ee098af Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Fri, 17 Jul 2020 14:45:24 -0500 Subject: [PATCH 041/175] :hammer: Improve performance with vector --- include/mpm_properties.h | 22 ++++---- include/node.h | 7 +-- include/node.tcc | 90 ++++++++++++++++++------------- include/particles/particle.tcc | 21 ++++---- include/particles/particle_base.h | 5 +- 5 files changed, 80 insertions(+), 65 deletions(-) diff --git a/include/mpm_properties.h b/include/mpm_properties.h index 4e3568667..f3aea193e 100644 --- a/include/mpm_properties.h +++ b/include/mpm_properties.h @@ -5,20 +5,20 @@ namespace mpm { namespace properties { //! Scalar Properties enum Scalar : unsigned int { - Mass, - Volume, - MassDensity, - MassPressure, - Pressure + Mass = 0, + Volume = 1, + MassDensity = 2, + MassPressure = 3, + Pressure = 4 }; //! Vector Properties enum Vector : unsigned int { - Displacement, - Velocity, - Acceleration, - Momentum, - ExternalForce, - InternalForce + Displacement = 0, + Velocity = 1, + Acceleration = 2, + Momentum = 3, + ExternalForce = 4, + InternalForce = 5 }; } // namespace properties } // namespace mpm diff --git a/include/node.h b/include/node.h index 79dfe271f..a49d36741 100644 --- a/include/node.h +++ b/include/node.h @@ -319,12 +319,9 @@ class Node : public NodeBase { //! Status bool status_{false}; //! Scalar properties - tsl::ordered_map> - scalar_properties_; + std::vector> scalar_properties_; //! Vector properties - tsl::ordered_map> - vector_properties_; + std::vector> vector_properties_; //! Displacement Eigen::Matrix contact_displacement_; //! Velocity constraints diff --git a/include/node.tcc b/include/node.tcc index 54ae7f6d4..7d3051e47 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -19,35 +19,38 @@ mpm::Node::Node( concentrated_force_.setZero(); // Initialize scalar properties - scalar_properties_.emplace( - std::make_pair(mpm::properties::Scalar::Mass, - Eigen::Matrix::Zero())); - scalar_properties_.emplace( - std::make_pair(mpm::properties::Scalar::Volume, - Eigen::Matrix::Zero())); - scalar_properties_.emplace( - std::make_pair(mpm::properties::Scalar::MassPressure, - Eigen::Matrix::Zero())); - scalar_properties_.emplace( - std::make_pair(mpm::properties::Scalar::Pressure, - Eigen::Matrix::Zero())); + scalar_properties_.reserve(5); + // Mass + scalar_properties_.emplace_back(Eigen::Matrix::Zero()); + // Volume + scalar_properties_.emplace_back(Eigen::Matrix::Zero()); + // MassDensity + scalar_properties_.emplace_back(Eigen::Matrix::Zero()); + // MassPressure + scalar_properties_.emplace_back(Eigen::Matrix::Zero()); + // Pressure + scalar_properties_.emplace_back(Eigen::Matrix::Zero()); // Initialize vector properties - vector_properties_.emplace( - std::make_pair(mpm::properties::Vector::Velocity, - Eigen::Matrix::Zero())); - vector_properties_.emplace( - std::make_pair(mpm::properties::Vector::Acceleration, - Eigen::Matrix::Zero())); - vector_properties_.emplace( - std::make_pair(mpm::properties::Vector::Momentum, - Eigen::Matrix::Zero())); - vector_properties_.emplace( - std::make_pair(mpm::properties::Vector::ExternalForce, - Eigen::Matrix::Zero())); - vector_properties_.emplace( - std::make_pair(mpm::properties::Vector::InternalForce, - Eigen::Matrix::Zero())); + vector_properties_.resize(6); + // Displacement + vector_properties_.emplace_back( + Eigen::Matrix::Zero()); + // Velocity + vector_properties_.emplace_back( + Eigen::Matrix::Zero()); + // Acceleration + vector_properties_.emplace_back( + Eigen::Matrix::Zero()); + // Momentum + vector_properties_.emplace_back( + Eigen::Matrix::Zero()); + // ExternalForce + vector_properties_.emplace_back( + Eigen::Matrix::Zero()); + // InternalForce + vector_properties_.emplace_back( + Eigen::Matrix::Zero()); this->initialise(); } @@ -58,17 +61,32 @@ void mpm::Node::initialise() noexcept { status_ = false; // Initialise nodal scalar properties - scalar_properties_.at(mpm::properties::Scalar::Mass).setZero(); - scalar_properties_.at(mpm::properties::Scalar::Volume).setZero(); - scalar_properties_.at(mpm::properties::Scalar::MassPressure).setZero(); - scalar_properties_.at(mpm::properties::Scalar::Pressure).setZero(); + scalar_properties_.resize(5); + scalar_properties_.at(mpm::properties::Scalar::Mass) = + Eigen::Matrix::Zero(); + scalar_properties_.at(mpm::properties::Scalar::Volume) = + Eigen::Matrix::Zero(); + scalar_properties_.at(mpm::properties::Scalar::MassDensity) = + Eigen::Matrix::Zero(); + scalar_properties_.at(mpm::properties::Scalar::MassPressure) = + Eigen::Matrix::Zero(); + scalar_properties_.at(mpm::properties::Scalar::Pressure) = + Eigen::Matrix::Zero(); // Initialise nodal vector properties - vector_properties_.at(mpm::properties::Vector::Velocity).setZero(); - vector_properties_.at(mpm::properties::Vector::Acceleration).setZero(); - vector_properties_.at(mpm::properties::Vector::Momentum).setZero(); - vector_properties_.at(mpm::properties::Vector::ExternalForce).setZero(); - vector_properties_.at(mpm::properties::Vector::InternalForce).setZero(); + vector_properties_.resize(6); + vector_properties_.at(mpm::properties::Vector::Displacement) = + Eigen::Matrix::Zero(); + vector_properties_.at(mpm::properties::Vector::Velocity) = + Eigen::Matrix::Zero(); + vector_properties_.at(mpm::properties::Vector::Acceleration) = + Eigen::Matrix::Zero(); + vector_properties_.at(mpm::properties::Vector::Momentum) = + Eigen::Matrix::Zero(); + vector_properties_.at(mpm::properties::Vector::ExternalForce) = + Eigen::Matrix::Zero(); + vector_properties_.at(mpm::properties::Vector::InternalForce) = + Eigen::Matrix::Zero(); // Initialise variables for contact material_ids_.clear(); diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index 0d5d3c680..2ce5bc060 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -9,6 +9,8 @@ mpm::Particle::Particle(Index id, const VectorDim& coord) nodes_.clear(); // Set material pointer to null material_ = nullptr; + scalar_properties_.resize(3); + vector_properties_.resize(3); // Logger std::string logger = "particle" + std::to_string(Tdim) + "d::" + std::to_string(id); @@ -239,18 +241,17 @@ void mpm::Particle::initialise() { volumetric_strain_centroid_ = 0.; // Initialize scalar properties - scalar_properties_.emplace( - std::make_pair(mpm::properties::Scalar::Mass, double(0.))); - scalar_properties_.emplace( - std::make_pair(mpm::properties::Scalar::MassDensity, double(0.))); - scalar_properties_.emplace(std::make_pair( - mpm::properties::Scalar::Volume, std::numeric_limits::max())); + scalar_properties_.resize(3); + scalar_properties_.at(mpm::properties::Scalar::Mass) = 0.; + scalar_properties_.at(mpm::properties::Scalar::MassDensity) = 0.; + scalar_properties_.at(mpm::properties::Scalar::Volume) = + std::numeric_limits::max(); // Initialize vector properties - vector_properties_.emplace( - std::make_pair(mpm::properties::Vector::Displacement, VectorDim::Zero())); - vector_properties_.emplace( - std::make_pair(mpm::properties::Vector::Velocity, VectorDim::Zero())); + vector_properties_.resize(2); + vector_properties_.at(mpm::properties::Vector::Displacement) = + VectorDim::Zero(); + vector_properties_.at(mpm::properties::Vector::Velocity) = VectorDim::Zero(); // Initialize vector data properties this->properties_["stresses"] = [&]() { return stress(); }; diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index fb119bc2a..3982ea5ee 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -343,10 +343,9 @@ class ParticleBase { //! Shape functions Eigen::VectorXd shapefn_; //! Scalar properties - tsl::ordered_map scalar_properties_; + std::vector scalar_properties_; //! Vector properties - tsl::ordered_map> - vector_properties_; + std::vector> vector_properties_; }; // ParticleBase class } // namespace mpm From 385fccafa0b6eae7b393d3bf1d46b845fea57ff7 Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Sat, 18 Jul 2020 06:46:40 -0500 Subject: [PATCH 042/175] :pencil: AssocVector --- CMakeLists.txt | 4 +- external/assoc_vector.h | 4955 +++++++++++++++++++++++++++++ external/flat | 1 + include/node.h | 5 +- include/node_base.h | 6 + include/particles/particle_base.h | 4 +- 6 files changed, 4968 insertions(+), 7 deletions(-) create mode 100644 external/assoc_vector.h create mode 160000 external/flat diff --git a/CMakeLists.txt b/CMakeLists.txt index 5fc7cfa1d..fc8e2accb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,9 +45,9 @@ option(HALO_EXCHANGE "Enable halo exchange" OFF) set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) # Boost Archive -find_package(Boost REQUIRED COMPONENTS filesystem system) +find_package(Boost REQUIRED COMPONENTS container filesystem system) include_directories(${BOOST_INCLUDE_DIRS}) -link_libraries(${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY}) +link_libraries(${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_CONTAINER_LIBRARY}) # Eigen find_package(Eigen3 REQUIRED) diff --git a/external/assoc_vector.h b/external/assoc_vector.h new file mode 100644 index 000000000..7a3ae766d --- /dev/null +++ b/external/assoc_vector.h @@ -0,0 +1,4955 @@ +/* + * Copyright (C) 2012 £ukasz Czerwiñski + * + * GitHub: https://github.com/wo3kie/AssocVector + * Website: http://www.lukaszczerwinski.pl/assoc_vector.en.html + * + * Distributed under the BSD Software License (see file license) + */ + +#ifndef ASSOC_VECTOR_HPP +#define ASSOC_VECTOR_HPP + +#ifndef __GXX_EXPERIMENTAL_CXX0X__ + #error C++11 is required to run this code, please use AssocVector 1.0.x instead. +#endif + +// includes.begin + +#include +#include +#include +#include + +#include +#include + +// includes.end + +// configuration.begin + +#if ( __GNUC__ >= 4 && __GNUC_MINOR__ >= 8 ) + #define AV_HAS_TRIVIAL_DESTRUCTOR( type ) std::is_trivially_destructible< type >::value + #define AV_MOVE_IF_NOEXCEPT std::move_if_noexcept +#else + #define AV_HAS_TRIVIAL_DESTRUCTOR( type ) __has_trivial_destructor( type ) + #define AV_MOVE_IF_NOEXCEPT std::move +#endif + +// configuration.end + +#ifndef NDEBUG + #define AV_DEBUG +#endif + +#ifdef AV_DEBUG + #define AV_PRECONDITION( condition ) if( (bool)( condition ) == false ){int*i=0;*i=0;} + #define AV_CHECK( condition ) if( (bool)( condition ) == false ){int*i=0;*i=0;} + #define AV_POSTCONDITION( condition ) if( (bool)( condition ) == false ){int*i=0;*i=0;} + #define AV_ERROR() if( (true) ){int*i=0;*i=0;} +#else + #define AV_PRECONDITION( condition ) (void)( 0 ); + #define AV_CHECK( condition ) (void)( 0 ); + #define AV_POSTCONDITION( condition ) (void)( 0 ); + #define AV_ERROR() (void)( 0 ); +#endif + +namespace util +{ + // + // CmpByFirst + // + template< typename _Pair, typename _Cmp > + struct CmpByFirst + { + CmpByFirst( _Cmp const & cmp = _Cmp() ) + : _cmp( cmp ) + { + } + + bool operator()( _Pair const & lhs, _Pair const & rhs )const + { + return _cmp( lhs.first, rhs.first ); + } + + bool operator()( _Pair const & pair, typename _Pair::first_type const & value )const + { + return _cmp( pair.first, value ); + } + + bool operator()( typename _Pair::first_type const & value, _Pair const & pair )const + { + return _cmp( value, pair.first ); + } + + private: + _Cmp _cmp; + }; +} + +namespace util +{ + // + // equal + // + template< + typename _T1 + , typename _T2 + > + inline bool equal( + _T1 const & first + , _T2 const & second + ) + { + if( first < second ){ + return false; + } + + if( second < first ){ + return false; + } + + return true; + } + + // + // less_equal + // + template< + typename _T1 + , typename _T2 + > + inline bool less_equal( + _T1 const & first + , _T2 const & second + ) + { + return ( second < first ) == false; + } +} + +namespace util +{ + // + // is_between + // + template< + typename _T1 + , typename _T2 + > + inline bool is_between( + _T1 const & first + , _T2 const & value + , _T1 const & last + ) + { + AV_PRECONDITION( less_equal( first, last ) ); + + return ( value < first ) == false && ( last < value ) == false; + } +} + +namespace util +{ + // + // destroy_range + // + namespace detail + { + template< bool _HasTrivialDestructor > + struct DestroyRangeImpl + { + }; + + template<> + struct DestroyRangeImpl< true > + { + template< typename _Ptr > + static + void destroy( _Ptr, _Ptr ) + { + } + }; + + template<> + struct DestroyRangeImpl< false > + { + template< typename _Ptr > + static + void destroy( _Ptr first, _Ptr const last ) + { + AV_PRECONDITION( less_equal( first, last ) ); + + typedef typename std::iterator_traits< _Ptr >::value_type T; + + for( /*empty*/ ; first != last ; ++ first ){ + first -> T::~T(); + } + } + }; + } + + template< typename _Ptr > + inline void destroy_range( + _Ptr first + , _Ptr const last + ) + { + typedef typename std::iterator_traits< _Ptr >::value_type T; + + detail::DestroyRangeImpl< AV_HAS_TRIVIAL_DESTRUCTOR( T ) >::destroy( first, last ); + } +} + +namespace util +{ + // + // move + // + template< + typename _InputPtr + , typename _OutputPtr + > + inline void move( + _InputPtr first + , _InputPtr last + , _OutputPtr first2 + ) + { + if( first < first2 ){ + std::move_backward( first, last, first2 + ( last - first ) ); + } + else if( first > first2 ){ + std::move( first, last, first2 ); + } + else{ + // first == first2 -> do nothing + } + } + + template< + typename _InputPtr + , typename _OutputPtr + > + inline void copy( + _InputPtr first + , _InputPtr last + , _OutputPtr first2 + ) + { + if( first < first2 ){ + std::copy_backward( first, last, first2 + ( last - first ) ); + } + else if( first > first2 ){ + std::copy( first, last, first2 ); + } + else{ + // first == first2 -> do nothing + } + } + + + + namespace detail + { + + template< bool _MoveDoesNotThrow > + struct MoveIfNoExcept + { + }; + + template<> + struct MoveIfNoExcept< true > + { + template< + typename _InputPtr + , typename _OutputPtr + > + static + void move( _InputPtr first, _InputPtr const last, _OutputPtr first2 ) + { + move( first, last, first2 ); + } + }; + + template<> + struct MoveIfNoExcept< false > + { + template< + typename _InputPtr + , typename _OutputPtr + > + static + void move( _InputPtr first, _InputPtr const last, _OutputPtr first2 ) + { + copy( first, last, first2 ); + } + }; + } + + template< + typename _InputPtr + , typename _OutputPtr + > + inline void move_if_noexcept( + _InputPtr first + , _InputPtr const last + , _OutputPtr first2 + ) + { + typedef typename std::iterator_traits< _InputPtr >::value_type T; + + detail::MoveIfNoExcept< true >::move( first, last, first2 ); + } + +} + +namespace util +{ + +template< + typename _Iterator + , typename _T + , typename _Cmp +> +_Iterator +last_less_equal( + _Iterator first + , _Iterator last + , _T const & t + , _Cmp cmp +) +{ + AV_PRECONDITION( less_equal( first, last ) ); + + if( first == last ){ + return last; + } + + _Iterator greaterEqual = std::lower_bound( first, last, t, cmp ); + + if( greaterEqual != last ) + { + // lower_bound returns first greater_than/equal_to but we need last less_than + + bool const isEqual = cmp( t, * greaterEqual ) == false; + + if( isEqual ) + { + // that is OK, request item was found + return greaterEqual; + } + } + + if( greaterEqual == first ) + { + // requested item does not exist in container + + // 6 8 10 13 17 19 20 21 22 24 end + // ^ lower_bound( 1 ): + // requested: ^ + + return last; + } + else + { + // we need to go one item backward + + // 6 8 10 13 17 19 20 21 22 24 + // lower_bound( 23 ): ^ + // requested: ^ + + return -- greaterEqual; + } +} + +} + +namespace util +{ + +template< + typename _InputIterator1 + , typename _InputIterator2 + , typename _Cmp +> +bool has_intersection( + _InputIterator1 first1 + , _InputIterator1 const last1 + , _InputIterator2 first2 + , _InputIterator2 const last2 + , _Cmp const & cmp +) +{ + while( first1 != last1 && first2 != last2 ) + { + if( cmp( * first1, * first2 ) ){ + ++first1; + } + else if( cmp( * first2, * first1 ) ){ + ++first2; + } + else{ + return true; + } + } + + return false; +} + +} + +namespace array +{ + // + // I need much more control over Array inside AssocVector than std::vector offers + // + + // C' style array with some useful methods and functions + + // + // Array + // + template< + typename _T + , typename _Alloc = std::allocator< _T > + > + struct ArrayBase + { + struct ArrayImpl + : public _Alloc + { + ArrayImpl( _Alloc const & alloc = _Alloc() ) + : _Alloc( alloc ) + , _data( nullptr ) + , _capacity( 0 ) + , _size( 0 ) + { + } + + ArrayImpl( std::size_t capacity, _Alloc const & alloc = _Alloc() ) + : _Alloc( alloc ) + , _data( capacity ? this->allocate( capacity ) : nullptr ) + , _capacity( capacity ) + , _size( 0 ) + { + AV_PRECONDITION( _capacity < this->max_size() ); + } + + ~ArrayImpl() + { + util::destroy_range( _data, _data + _size ); + + this->deallocate( _data, _capacity ); + } + + void swap( ArrayImpl & other )noexcept + { + std::swap( _data, other._data ); + std::swap( _capacity, other._capacity ); + std::swap( _size, other._size ); + } + + public: + _T * _data; + + std::size_t _capacity; + std::size_t _size; + }; + + typedef _Alloc allocator_type; + + allocator_type + get_allocator() const { + return * static_cast< allocator_type const * >( & this->_impl ); + } + + public: + ArrayBase( _Alloc const & alloc = _Alloc() ) + : _impl( alloc ) + { + } + + ArrayBase( std::size_t capacity, _Alloc const & alloc = _Alloc() ) + : _impl( capacity, alloc ) + { + } + + ~ArrayBase() = default; + + ArrayBase( ArrayBase const & other ) = delete; + ArrayBase( ArrayBase && other ) = delete; + + ArrayBase & operator=( ArrayBase const & other ) = delete; + ArrayBase & operator=( ArrayBase && other ) = delete; + + protected: + ArrayImpl _impl; + }; + + template< + typename _T + , typename _Alloc = std::allocator< _T > + > + struct Array + : protected ArrayBase< _T, _Alloc > + { + private: + typedef ArrayBase< _T, _Alloc > Base; + + public: + using Base::get_allocator; + + public: + typedef _T value_type; + + typedef _T * iterator; + typedef _T const * const_iterator; + + public: + Array( _Alloc const & alloc = _Alloc() ) + : Base( alloc ) + { + } + + Array( std::size_t capacity, _Alloc const & alloc = _Alloc() ) + : Base( capacity, alloc ) + { + } + + Array( Array const & other ) + // In std::vector new vector's capacity is equal to old vector's size. + // Array's capacity is equal to old array's capacity to ensure invariant that: + // sqrt( storage.capacity ) == buffer.capacity + // sqrt( storage.capacity ) == erased.capacity + : Base( other.capacity(), other.get_allocator() ) + { + for( /*empty*/ ; this->_impl._size < other.size() ; ++ this->_impl._size ){ + get_allocator().construct( + this->_impl._data + this->_impl._size + , * ( other._impl._data + this->_impl._size ) + ); + } + } + + Array( Array && other ) + : Base( 0, other.get_allocator() ) + { + this->_impl.swap( other._impl ); + } + + ~Array() = default; + + Array & operator=( Array const & other ) + { + Array temp( other ); + + swap( temp ); + + return * this; + } + + Array & operator=( Array && other ) + { + this->_impl.swap( other._impl ); + + return * this; + } + + void swap( Array & other )noexcept + { + this->_impl.swap( other._impl ); + } + + void reserve( std::size_t capacity ) + { + if( get_allocator().max_size() < capacity ){ + throw std::length_error( "Array::reserve" ); + } + + if( capacity <= getCapacity() ){ + return; + } + + Array< _T, _Alloc > temp( capacity, get_allocator() ); + + std::uninitialized_copy( + std::make_move_iterator( begin() ) + , std::make_move_iterator( end() ) + , temp.begin() + ); + + swap( temp ); + } + + iterator begin()noexcept + { + return getData(); + } + + const_iterator begin()const noexcept + { + return getData(); + } + + const_iterator cbegin()const noexcept + { + return getData(); + } + + iterator end()noexcept + { + return getData() + getSize(); + } + + const_iterator end()const noexcept + { + return getData() + getSize(); + } + + const_iterator cend()const noexcept + { + return getData() + getSize(); + } + + bool empty()const noexcept + { + return getSize() == 0; + } + + bool full()const noexcept + { + return size() == capacity(); + } + + std::size_t size()const noexcept + { + return this->_impl._size; + } + + std::size_t getSize()const noexcept + { + return size(); + } + + void setSize( std::size_t newSize ) noexcept + { + AV_PRECONDITION( getData() != 0 || newSize == 0 ); + + this->_impl._size = newSize; + } + + std::size_t capacity()const noexcept + { + return this->_impl._capacity; + } + + std::size_t getCapacity()const noexcept + { + return capacity(); + } + + value_type & front() noexcept + { + AV_PRECONDITION( getData() != 0 ); + AV_PRECONDITION( empty() == false ); + + return getData()[ 0 ]; + } + + value_type const & front()const noexcept + { + AV_PRECONDITION( getData() != 0 ); + AV_PRECONDITION( empty() == false ); + + return getData()[ 0 ]; + } + + value_type & back() noexcept + { + AV_PRECONDITION( getData() != 0 ); + AV_PRECONDITION( empty() == false ); + + return getData()[ getSize() - 1 ]; + } + + value_type const & back()const noexcept + { + AV_PRECONDITION( getData() != 0 ); + AV_PRECONDITION( empty() == false ); + + return getData()[ getSize() - 1 ]; + } + + _T const * data()const noexcept + { + return this->_impl._data; + } + + _T const * getData()const noexcept + { + return data(); + } + + _T * data() noexcept + { + return this->_impl._data; + } + + _T * getData() noexcept + { + return data(); + } + + value_type & operator[]( std::size_t index ) noexcept + { + AV_PRECONDITION( getData() != 0 ); + AV_PRECONDITION( index < size() ); + + return getData()[ index ]; + } + + value_type const & operator[]( std::size_t index )const noexcept + { + AV_PRECONDITION( getData() != 0 ); + AV_PRECONDITION( index < size() ); + + return getData()[ index ]; + } + + template< typename _T2 > + void + insert( + typename Array< _T >::iterator const pos + , _T2 && t + ) + { + AV_PRECONDITION( util::less_equal( size() + 1, capacity() ) ); + AV_PRECONDITION( util::is_between( begin(), pos, end() ) ); + + iterator const oldEnd = end(); + + get_allocator().construct( end() ); + setSize( getSize() + 1 ); + + if( pos != oldEnd ) + { + util::move( pos, oldEnd, pos + 1 ); + } + + * pos = AV_MOVE_IF_NOEXCEPT( t ); + } + + // Array::push_back is not implemented to ensure invariant that: + // sqrt( storage.capacity ) == buffer.capacity + // sqrt( storage.capacity ) == erased.capacity + template< typename __T2 > + void place_back( __T2 && value ) + { + AV_CHECK( getData() ); + AV_CHECK( capacity() > 0 ); + AV_CHECK( getSize() < capacity() ); + + get_allocator().construct( end(), std::forward< __T2 >( value ) ); + setSize( getSize() + 1 ); + } + + void + erase( typename Array< _T >::iterator pos ) + { + AV_PRECONDITION( empty() == false ); + AV_PRECONDITION( util::less_equal( begin(), pos ) ); + AV_PRECONDITION( pos < end() ); + + util::move( pos + 1, end(), pos ); + get_allocator().destroy( end() - 1 ); + setSize( getSize() - 1 ); + } + + private: + void setCapacity( std::size_t newCapacity ) noexcept + { + AV_PRECONDITION( getData() != 0 || newCapacity == 0 ); + + this->_impl._capacity = newCapacity; + } + + void setData( _T * t ) noexcept + { + this->_impl._data = t; + } + }; +} + +namespace array +{ + template< + typename _Iterator + , typename _T + , typename _Cmp + > + _Iterator + binary_search( + _Iterator first + , _Iterator last + , _T const & t + , _Cmp cmp + ) + { + AV_PRECONDITION( util::less_equal( first, last ) ); + + _Iterator const greaterEqual = std::lower_bound( first, last, t, cmp ); + + if( greaterEqual == last ){ + return last; + } + + bool const isEqual = cmp( t, * greaterEqual ) == false; + + if( isEqual ){ + return greaterEqual; + } + + return last; + } + + template< + typename _T + , typename _T2 + , typename _Cmp + > + std::pair< typename Array< _T >::iterator, bool > + insert_in_sorted( + Array< _T > & array + , _T2 && t + , _Cmp cmp + ) + { + AV_PRECONDITION( util::less_equal( array.size() + 1, array.capacity() ) ); + + typename Array< _T >::iterator const greaterEqual + = std::lower_bound( array.begin(), array.end(), t, cmp ); + + if( greaterEqual != array.end() ) + { + bool const isEqual = cmp( t, * greaterEqual ) == false; + + if( isEqual ){ + return std::make_pair( greaterEqual, false ); + } + } + + array.insert( greaterEqual, std::forward< _T2 >( t ) ); + + return std::make_pair( greaterEqual, true ); + } + + template< typename _T > + void + erase_removed( + array::Array< _T > & storage + , array::Array< typename array::Array< _T >::const_iterator > const & erased + ) + { + AV_PRECONDITION( util::less_equal( erased.size(), storage.size() ) ); + + if( erased.empty() ){ + return; + } + + typedef typename array::Array< _T >::const_iterator StorageConstIterator; + typedef typename array::Array< _T >::iterator StorageIterator; + typedef typename array::Array< StorageConstIterator >::const_iterator ErasedConstIterator; + + StorageIterator currentInStorage = const_cast< StorageIterator >( erased.front() ); + AV_CHECK( util::is_between( storage.begin(), currentInStorage, storage.end() ) ); + + StorageIterator const endInStorage = storage.end(); + + StorageIterator whereInsertInStorage = const_cast< StorageIterator >( erased.front() ); + AV_CHECK( util::is_between( storage.begin(), whereInsertInStorage, storage.end() ) ); + + ErasedConstIterator currentInErased = erased.begin(); + ErasedConstIterator const endInErased = erased.end(); + + while( currentInStorage != endInStorage ) + { + AV_CHECK( util::is_between( storage.begin(), whereInsertInStorage, storage.end() ) ); + + if( + currentInErased != endInErased + && currentInStorage == ( * currentInErased ) + ) + { + ++ currentInStorage; + ++ currentInErased; + } + else + { + ( * whereInsertInStorage ) = AV_MOVE_IF_NOEXCEPT( * currentInStorage ); + + ++ whereInsertInStorage; + ++ currentInStorage; + } + } + + AV_POSTCONDITION( currentInErased == endInErased ); + + storage.setSize( storage.size() - erased.size() ); + } + + template< + typename _T + , typename _Cmp + > + void + move_merge( + array::Array< _T > & storage + , array::Array< _T > & buffer + , _Cmp const & cmp = _Cmp() + ) + { + AV_PRECONDITION( util::less_equal( storage.size() + buffer.size(), storage.capacity() ) ); + + typedef typename array::Array< _T >::iterator Iterator; + + Iterator rWhereInsertInStorage = storage.begin() + storage.size() + buffer.size() - 1; + + Iterator rCurrentInStorage = storage.begin() + storage.size() - 1; + Iterator const rEndInStorage = storage.begin() - 1; + + Iterator rCurrentInBuffer = buffer.begin() + buffer.size() - 1; + Iterator const rEndInBuffer = buffer.begin() - 1; + + std::size_t numberOfItemsToCreateByPlacementNew = buffer.size(); + + while( + rCurrentInBuffer != rEndInBuffer + && numberOfItemsToCreateByPlacementNew != 0 + ) + { + AV_CHECK( rWhereInsertInStorage != 0 ); + AV_CHECK( rCurrentInStorage != 0 ); + AV_CHECK( rCurrentInBuffer != 0 ); + + if( + rCurrentInStorage == rEndInStorage + || cmp( * rCurrentInStorage, * rCurrentInBuffer ) + ) + { + new ( static_cast< void * >( rWhereInsertInStorage ) ) + _T( AV_MOVE_IF_NOEXCEPT( * rCurrentInBuffer ) ); + + -- rCurrentInBuffer; + } + else + { + new ( static_cast< void * >( rWhereInsertInStorage ) ) + _T( AV_MOVE_IF_NOEXCEPT( * rCurrentInStorage ) ); + + -- rCurrentInStorage; + } + + -- numberOfItemsToCreateByPlacementNew; + -- rWhereInsertInStorage; + } + + AV_CHECK( numberOfItemsToCreateByPlacementNew == 0 ); + + while( rCurrentInBuffer != rEndInBuffer ) + { + AV_CHECK( rWhereInsertInStorage != 0 ); + AV_CHECK( rCurrentInStorage != 0 ); + AV_CHECK( rCurrentInBuffer != 0 ); + + if( + rCurrentInStorage == rEndInStorage + || cmp( * rCurrentInStorage, * rCurrentInBuffer ) + ) + { + * rWhereInsertInStorage = AV_MOVE_IF_NOEXCEPT( * rCurrentInBuffer ); + + -- rCurrentInBuffer; + } + else + { + * rWhereInsertInStorage = AV_MOVE_IF_NOEXCEPT( * rCurrentInStorage ); + + -- rCurrentInStorage; + } + + -- rWhereInsertInStorage; + } + + storage.setSize( storage.size() + buffer.size() ); + } +} + +namespace util +{ + +template< + typename _InputPtr1 + , typename _InputPtr2 + , typename _OutputPtr + , typename _Cmp +> +_OutputPtr +move_merge_into_uninitialized( + _InputPtr1 first1 + , _InputPtr1 last1 + , _InputPtr2 first2 + , _InputPtr2 last2 + , _OutputPtr output + , _Cmp cmp = _Cmp() +) +{ + AV_PRECONDITION( util::less_equal( first1, last1 ) ); + AV_PRECONDITION( util::less_equal( first2, last2 ) ); + + while( first1 != last1 && first2 != last2 ) + { + AV_CHECK( first1 != 0 ); + AV_CHECK( first2 != 0 ); + AV_CHECK( output != 0 ); + + if( cmp( * first1, * first2 ) ) + { + new ( static_cast< void * >( output ) ) + typename std::iterator_traits< _OutputPtr >::value_type( std::move( * first1 ) ); + + ++ output; + ++ first1; + } + else + { + new ( static_cast< void * >( output ) ) + typename std::iterator_traits< _OutputPtr >::value_type( std::move( * first2 ) ); + + ++ output; + ++ first2; + } + } + + if( first1 == last1 ){ + return std::uninitialized_copy( + std::make_move_iterator( first2 ) + , std::make_move_iterator( last2 ) + , output + ); + } + + if( first2 == last2 ){ + return std::uninitialized_copy( + std::make_move_iterator( first1 ) + , std::make_move_iterator( last1 ) + , output + ); + } + + return output; +} + +} + +namespace detail +{ + template< typename _Iterator > + bool equal( _Iterator const & lhs, _Iterator const & rhs ) + { + if( lhs.getContainer() != rhs.getContainer() ){ + return false; + } + + // for empty container returns that begin == end + // despite on fact they are not + if( lhs.getContainer()->empty() ){ + return true; + } + + return lhs.getCurrent() == rhs.getCurrent(); + } + + // + // AssocVectorLazyIterator + // + + template< + typename _Iterator + , typename _Container + > + struct AssocVectorLazyIterator + { + public: + typedef typename std::iterator_traits< _Iterator >::pointer pointer_mutable; + + public: + typedef std::bidirectional_iterator_tag iterator_category; + typedef typename std::iterator_traits< _Iterator >::value_type value_type; + typedef typename std::iterator_traits< _Iterator >::difference_type difference_type; + + // make key const + typedef std::pair< + typename value_type::first_type const + , typename value_type::second_type + > & reference; + + // make key const + typedef std::pair< + typename value_type::first_type const + , typename value_type::second_type + > * pointer; + + private: + struct _CurrentInErased + { + _CurrentInErased( typename _Container::_Erased::const_iterator current ) + : _current( current ) + { + } + + _CurrentInErased( _CurrentInErased const & other ) + : _current( other._current ) + { + } + + _CurrentInErased & operator=( _CurrentInErased const & other ) + { + _current = other._current; + + return * this; + } + + _CurrentInErased & operator=( typename _Container::_Erased::const_iterator current ) + { + _current = current; + + return * this; + } + + bool is_end( _Container const * container )const + { + return _current == container->erased().end(); + } + + bool is_not_end( _Container const * container )const + { + return ! is_end( container ); + } + + bool is_begin( _Container const * container )const + { + return _current == container->erased().begin(); + } + + bool is_not_begin( _Container const * container )const + { + return ! is_begin( container ); + } + + void increment( _Container const * container ) + { + AV_PRECONDITION( is_not_end( container ) ); + + ++ _current; + } + + void try_increment( _Container const * container ) + { + if( is_end( container ) ){ + return; + } + + increment( container ); + } + + void decrement( _Container const * container ) + { + AV_PRECONDITION( is_not_begin( container ) ); + + -- _current; + } + + void try_decrement( _Container const * container ) + { + if( is_begin( container ) ){ + return; + } + + decrement( container ); + } + + bool validate( _Container const * container )const + { + bool const result + = util::is_between( + container->erased().begin() + , _current + , container->erased().end() + ); + + if( result ){ + return true; + } + + AV_ERROR(); + + return false; + } + + typename _Container::_Erased::value_type const & + get( _Container const * container )const noexcept + { + AV_PRECONDITION( _current ); + AV_PRECONDITION( is_not_end( container ) ); + AV_PRECONDITION( validate( container ) ); + + return * _current; + } + + typename _Container::_Erased::const_iterator data()const noexcept + { + return _current; + } + + operator bool()const noexcept + { + return _current != 0; + } + + private: + typename _Container::_Erased::const_iterator _current; + }; + + struct _CurrentInBuffer + { + _CurrentInBuffer( pointer_mutable current ) + : _current( current ) + { + } + + _CurrentInBuffer( _CurrentInBuffer const & other ) + : _current( other._current ) + { + } + + _CurrentInBuffer & operator=( _CurrentInBuffer const & other ) + { + _current = other._current; + + return * this; + } + + _CurrentInBuffer & operator=( pointer_mutable current ) + { + _current = current; + + return * this; + } + + bool is_begin( _Container const * container )const + { + return _current == container->buffer().begin(); + } + + bool is_not_begin( _Container const * container )const + { + return ! is_begin( container ); + } + + bool is_end( _Container const * container )const + { + return _current == container->buffer().end(); + } + + bool is_not_end( _Container const * container )const + { + return ! is_end( container ); + } + + void increment( _Container const * container ) + { + AV_PRECONDITION( is_not_end( container ) ); + + ++ _current; + } + + void try_increment( _Container const * container ) + { + if( is_end( container ) ){ + return; + } + + increment( container ); + } + + void decrement( _Container const * container ) + { + AV_PRECONDITION( is_not_begin( container ) ); + + -- _current; + } + + void try_decrement( _Container const * container ) + { + if( is_begin( container ) ){ + return; + } + + decrement( container ); + } + + bool validate( _Container const * container )const + { + bool const result + = util::is_between( + container->buffer().begin() + , _current + , container->buffer().end() + ); + + if( result ){ + return true; + } + + AV_ERROR(); + + return false; + } + + typename _Container::_Storage::value_type const & + get( _Container const * container )const noexcept + { + AV_PRECONDITION( _current ); + AV_PRECONDITION( is_not_end( container ) ); + AV_PRECONDITION( validate( container ) ); + + return * _current; + } + + operator bool()const noexcept + { + return _current != 0; + } + + pointer_mutable data()const noexcept + { + return _current; + } + private: + pointer_mutable _current; + }; + + struct _CurrentInStorage + { + // begin is always set at first not erased item, marked with ^ + // end is always set at the end of container, marked with $ + + // Case 1: no item erased + // storage: ^1 3 5 7$ + // erased : + + // Case 2: item erased from front + // storage: 1 ^3 5 7$ + // erased : 1 + + // Case 3: item erased from back + // storage: ^1 3 5 7$ + // erased : 7 + + // Case 4: item erased from front and back + // storage: 1 ^3 5 7$ + // erased : 1 7 + + _CurrentInStorage( pointer_mutable current ) + : _dir( 1 ) + , _current( current ) + { + } + + _CurrentInStorage( _CurrentInStorage const & other ) + : _dir( other._dir ) + , _current( other._current ) + { + } + + _CurrentInStorage & operator=( _CurrentInStorage const & other ) + { + _dir = other._dir; + _current = other._current; + + return * this; + } + + bool operator==( _CurrentInStorage const & other )const + { + return _current == other._current; + } + + bool operator!=( _CurrentInStorage const & other )const + { + return _current != other._current; + } + + bool operator==( typename _Container::_Erased::value_type inErased )const + { + return _current == inErased; + } + + bool operator!=( typename _Container::_Erased::value_type inErased )const + { + return _current != inErased; + } + + bool is_begin( _Container const * container )const + { + _CurrentInStorage currentInStorage = const_cast< pointer_mutable >( container->storage().begin() ); + _CurrentInErased currentInErased = container->erased().begin(); + + currentInStorage.setOnNotErased( currentInErased, container ); + + return data() == currentInStorage.data(); + } + + bool is_not_begin( _Container const * container )const + { + return ! is_begin( container ); + } + + bool _is_begin( _Container const * container )const + { + return _current == container->storage().begin(); + } + + bool _is_not_begin( _Container const * container )const + { + return ! _is_begin( container ); + } + + bool is_end( _Container const * container )const + { + return _current == container->storage().end(); + } + + bool is_not_end( _Container const * container )const + { + return ! is_end( container ); + } + + void + increment( + _CurrentInErased & currentInErased + , _Container const * container + ) + { + AV_PRECONDITION( is_not_end( container ) ); + + increment( container ); + + if( _dir == -1 ) + { + _dir = 1; + currentInErased.try_increment( container ); + } + + setOnNotErased( currentInErased, container ); + } + + void + try_increment( + _CurrentInErased & currentInErased + , _Container const * container + ) + { + if( is_end( container ) ){ + return; + } + + increment( currentInErased, container ); + } + + void + decrement( + _CurrentInErased & currentInErased + , _Container const * container + ) + { + AV_PRECONDITION( is_not_begin( container ) ); + + decrement( container ); + + if( _dir == 1 ) + { + _dir = -1; + currentInErased.try_decrement( container ); + } + + setOnNotErasedBackward( currentInErased, container ); + } + + void + try_decrement( + _CurrentInErased & currentInErased + , _Container const * container + ) + { + if( _is_begin( container ) ){ + return; + } + + decrement( currentInErased, container ); + } + + void + setOnNotErased( + _CurrentInErased & currentInErased + , _Container const * container + ) + { + if( is_end( container ) ) + { + if( !currentInErased ) + { + currentInErased = container->erased().end(); + } + + return; + } + + if( !currentInErased ) + { + currentInErased = std::lower_bound( + container->erased().begin() + , container->erased().end() + , data() + , std::less< typename _Container::_Storage::const_iterator >() + ); + } + + if( _dir == -1 ) + { + _dir = 1; + currentInErased.try_increment( container ); + } + + while( + is_not_end( container ) + && currentInErased.is_not_end( container ) + && data() == currentInErased.get( container ) + ) + { + increment( container ); + currentInErased.increment( container ); + } + + AV_POSTCONDITION( currentInErased ); + + AV_POSTCONDITION( + ( + is_end( container ) + && currentInErased.is_end( container ) + ) + || currentInErased.is_end( container ) + || *this != currentInErased.get( container ) + ); + } + + void + setOnNotErasedBackward( + _CurrentInErased & currentInErased + , _Container const * container + ) + { + AV_CHECK( is_not_end( container ) ); + + if( _dir == 1 ) + { + _dir = -1; + currentInErased.try_decrement( container ); + } + + while( + is_not_begin( container ) + && currentInErased.is_not_end( container ) + && data() == currentInErased.get( container ) + ) + { + decrement( container ); + currentInErased.try_decrement( container ); + } + + AV_POSTCONDITION( validate( container ) ); + + AV_POSTCONDITION( + currentInErased.is_end( container ) + || *this != currentInErased.get( container ) + ); + } + + operator bool()const noexcept + { + return _current != 0; + } + + bool validate( _Container const * container )const + { + bool const result = util::is_between( + container->storage().begin() + , _current + , container->storage().end() + ); + + if( result ){ + return true; + } + + AV_ERROR(); + + return false; + } + + typename _Container::_Storage::value_type const & + get( _Container const * container )const noexcept + { + AV_PRECONDITION( _current ); + AV_PRECONDITION( is_not_end( container ) ); + + return * _current; + } + + pointer_mutable data()const noexcept + { + return _current; + } + + private: + void increment( _Container const * container ) + { + AV_PRECONDITION( is_not_end( container ) ); + + ++ _current; + } + + void decrement( _Container const * container ) + { + AV_PRECONDITION( is_not_begin( container ) ); + + -- _current; + } + + private: + int _dir; + + pointer_mutable _current; + }; + + struct _Current + { + _Current( pointer_mutable current ) + : _current( current ) + { + } + + _Current( _CurrentInStorage const & inStorage ) + : _current( inStorage.data() ) + { + } + + _Current( _CurrentInBuffer const & inBuffer ) + : _current( inBuffer.data() ) + { + } + + _Current & operator=( _Current const & other ) + { + _current = other._current; + + return * this; + } + + _Current & operator=( _CurrentInStorage const & inStorage ) + { + _current = inStorage.data(); + + return * this; + } + + _Current & operator=( _CurrentInBuffer const & inBuffer ) + { + _current = inBuffer.data(); + + return * this; + } + + bool operator==( _Current const & other )const + { + return _current == other._current; + } + + bool operator==( _CurrentInStorage const & inStorage )const + { + return _current == inStorage.data(); + } + + bool operator==( _CurrentInBuffer const & inBuffer )const + { + return _current == inBuffer.data(); + } + + bool validate( + _CurrentInStorage currentInStorage + , _CurrentInBuffer currentInBuffer + , _Container const * container + )const + { + AV_PRECONDITION( currentInStorage || currentInBuffer ); + AV_PRECONDITION( container != 0 ); + + if( !currentInStorage ) + { + if( _current == currentInBuffer.data() ){ + return true; + } + + AV_ERROR(); + + return false; + } + + if( !currentInBuffer ) + { + if( _current == currentInStorage.data() ){ + return true; + } + + AV_ERROR(); + + return false; + } + + // if 'setLower' does not work 'validateCurrent' does not work as well :O( + bool const result + = _current == getLower( currentInStorage, currentInBuffer, container ).data(); + + if( result ){ + return true; + } + + AV_ERROR(); + + return false; + } + + void setLower( + _CurrentInStorage currentInStorage + , _CurrentInBuffer currentInBuffer + , _Container const * container + ) + { + _current = getLower( currentInStorage, currentInBuffer, container ).data(); + } + + _Current getLower( + _CurrentInStorage currentInStorage + , _CurrentInBuffer currentInBuffer + , _Container const * container + )const + { + AV_CHECK( currentInStorage ); + AV_CHECK( currentInBuffer ); + + if( currentInStorage.is_end( container ) ) + { + if( currentInBuffer.is_end( container ) ){ + return _Current( 0 ); + } + else{ + return _Current( currentInBuffer ); + } + } + else + { + if( currentInBuffer.is_end( container ) ){ + return _Current( currentInStorage ); + } + else + { + if( container->value_comp()( + currentInStorage.get( container ) + , currentInBuffer.get( container ) + ) + ){ + return _Current( currentInStorage ); + } + else{ + return _Current( currentInBuffer ); + } + } + } + } + + operator bool()const noexcept + { + return _current != 0; + } + + typename _Container::_Storage::value_type const & + get( _Container const * container )const noexcept + { + return * _current; + } + + pointer_mutable data()const noexcept + { + return _current; + } + + private: + pointer_mutable _current; + }; + + public: + AssocVectorLazyIterator( + typename _Container::value_compare const & cmp = typename _Container::value_compare() + ) + : _container( 0 ) + + , _currentInStorage( 0 ) + , _currentInBuffer( 0 ) + , _currentInErased( 0 ) + + , _current( 0 ) + { + } + + template< typename _Iter > + AssocVectorLazyIterator( AssocVectorLazyIterator< _Iter, _Container > const & other ) + : _container( other.getContainer() ) + + , _currentInStorage( other.getCurrentInStorage() ) + , _currentInBuffer( other.getCurrentInBuffer() ) + , _currentInErased( other.getCurrentInErased() ) + + , _current( other.getCurrent() ) + { + } + + AssocVectorLazyIterator( + _Container const * container + , pointer_mutable currentInStorage + , pointer_mutable currentInBuffer + , typename _Container::_Erased::const_iterator currentInErased + , pointer_mutable current + ) + : _container( container ) + + , _currentInStorage( currentInStorage ) + , _currentInBuffer( currentInBuffer ) + , _currentInErased( currentInErased ) + + , _current( current ) + { + AV_PRECONDITION( container != 0 ); + AV_PRECONDITION( validate() ); + + if( _currentInStorage && _currentInBuffer && !_currentInErased && !_current ) + { + // not found in storage, insert to buffer + // erase from buffer + find in storage + // lower_bound + // upper_bound + + // _currentInStorage <- fix against '!_currentInErased' + _currentInStorage.setOnNotErased( _currentInErased, _container ); + + // _current <- get it right now + _current.setLower( _currentInStorage, _currentInBuffer, _container ); + } + else + if( _currentInStorage && _currentInBuffer && !_currentInErased && _current ) + { + // not found in storage, found in buffer + // not found in storage, inserted to buffer + // erased from storage's back + + // _currentInStorage <- fix against '!_currentInErased' + _currentInStorage.setOnNotErased( _currentInErased, _container ); + } + else + if( _currentInStorage && _currentInBuffer && _currentInErased && !_current ) + { + // begin iterator + // end iterator + // erase from storage, not merged + find in buffer + // erase from storage, merged + find in buffer + find in storage + + // _currentInStorage <- check against _currentInErased + _currentInStorage.setOnNotErased( _currentInErased, _container ); + + // _current <- get it right now + _current.setLower( _currentInStorage, _currentInBuffer, _container ); + } + else + if( ! _currentInStorage && ! _currentInBuffer && ! _currentInErased && !_current ) + { + // begin iterator on empty AssocVector + // end iterator on empty AssocVector + + // return, do not make validation + return; + } + + AV_POSTCONDITION( _current.validate( _currentInStorage, _currentInBuffer, _container ) ); + AV_POSTCONDITION( _currentInStorage || _currentInBuffer ); + AV_POSTCONDITION( _currentInErased ); + AV_POSTCONDITION( _container != 0 ); + } + + AssocVectorLazyIterator & + operator=( AssocVectorLazyIterator const & other ) + { + _container = other._container; + + _currentInStorage = other._currentInStorage; + _currentInBuffer = other._currentInBuffer; + _currentInErased = other._currentInErased; + + _current = other._current; + + return * this; + } + + bool operator==( AssocVectorLazyIterator const & other )const + { + this->resolveLazyValues(); + other.resolveLazyValues(); + + if( isEmpty() && other.isEmpty() ){ + return getContainer() == other.getContainer(); + } + + AV_PRECONDITION( _current.validate( _currentInStorage, _currentInBuffer, _container ) ); + + return equal( *this, other ); + } + + bool operator!=( AssocVectorLazyIterator const & other )const + { + this->resolveLazyValues(); + other.resolveLazyValues(); + + return ! ( ( * this ) == other ); + } + + AssocVectorLazyIterator & operator++() + { + AV_PRECONDITION( isEmpty() == false ); + + resolveLazyValues(); + + AV_PRECONDITION( _current.validate( _currentInStorage, _currentInBuffer, _container ) ); + + if( _current == _Current( 0 ) ){ + return * this; + } + else if( _current == _currentInStorage ){ + _currentInStorage.try_increment( _currentInErased, _container ); + } + else if( _current == _currentInBuffer ){ + _currentInBuffer.try_increment( _container ); + } + else{ + AV_ERROR(); + } + + _current.setLower( _currentInStorage, _currentInBuffer, _container ); + + AV_POSTCONDITION( _current.validate( _currentInStorage, _currentInBuffer, _container ) ); + + return * this; + } + + AssocVectorLazyIterator operator++( int ) + { + AssocVectorLazyIterator result( * this ); + + ( * this ).operator++(); + + return result; + } + + AssocVectorLazyIterator & operator--() + { + AV_PRECONDITION( isEmpty() == false ); + + resolveLazyValues(); + + AV_PRECONDITION( _current.validate( _currentInStorage, _currentInBuffer, _container ) ); + + if( + _currentInStorage.is_begin( _container ) + && _currentInBuffer.is_begin( _container ) + ) + { + AV_POSTCONDITION( _current.validate( _currentInStorage, _currentInBuffer, _container ) ); + + return * this; + } + + if( _currentInStorage.is_begin( _container ) ) + { + _currentInBuffer.decrement( _container ); + + _current = _currentInBuffer; + + AV_POSTCONDITION( _current.validate( _currentInStorage, _currentInBuffer, _container ) ); + + return * this; + } + + if( _currentInBuffer.is_begin( _container ) ) + { + _currentInStorage.decrement( _currentInErased, _container ); + + _current = _currentInStorage; + + AV_POSTCONDITION( _current.validate( _currentInStorage, _currentInBuffer, _container ) ); + + return * this; + } + + _CurrentInStorage currentInStorage = _currentInStorage; + _CurrentInBuffer currentInBuffer = _currentInBuffer; + + _CurrentInErased currentInErased = _currentInErased; + + currentInStorage.decrement( currentInErased, _container ); + currentInBuffer.decrement( _container ); + + if( + _container->value_comp()( + currentInStorage.get( _container ) + , currentInBuffer.get( _container ) + ) + ) + { + _currentInBuffer = currentInBuffer; + + _current = _currentInBuffer; + } + else + { + _currentInStorage = currentInStorage; + _currentInErased = currentInErased; + + _current = _currentInStorage; + } + + AV_POSTCONDITION( _current.validate( _currentInStorage, _currentInBuffer, _container ) ); + + return * this; + } + + AssocVectorLazyIterator operator--( int ) + { + AssocVectorLazyIterator result( * this ); + + ( * this ).operator--(); + + return result; + } + + reference operator*()const + { + return * get(); + } + + pointer operator->()const + { + return get(); + } + + pointer get()const + { + AV_PRECONDITION( isEmpty() == false ); + AV_PRECONDITION( _current ); + AV_PRECONDITION( _current.validate( _currentInStorage, _currentInBuffer, _container ) ); + + // make key const + // pair< T1, T2 > * -> pair< T1 const, T2 > * + //return reinterpret_cast< pointer >( _current ); + + return + reinterpret_cast< pointer >( + const_cast< void * >( + reinterpret_cast< void const * >( _current.data() ) + ) + ); + } + + // public for copy constructor only : Iterator -> ConstIterator + _Container const * getContainer()const noexcept + { + return _container; + } + + pointer_mutable getCurrentInStorage()const noexcept + { + return _currentInStorage.data(); + } + + pointer_mutable getCurrentInBuffer()const noexcept + { + return _currentInBuffer.data(); + } + + typename _Container::_Erased::const_iterator getCurrentInErased()const noexcept + { + return _currentInErased.data(); + } + + pointer_mutable getCurrent()const noexcept + { + return _current.data(); + } + + private: + bool isEmpty()const + { + if( _currentInStorage ){ + return false; + } + if( _currentInBuffer ){ + return false; + } + if( _currentInErased ){ + return false; + } + if( _current ){ + return false; + } + + return true; + } + + /*const function*/ + static + void + resolveLazyCurrentInBuffer( + _CurrentInBuffer & currentInBuffer + , _Current const current + , _Container const * container + ) + { + if( currentInBuffer ){ + return; + } + + currentInBuffer = const_cast< pointer_mutable >( + std::lower_bound( + container->buffer().begin() + , container->buffer().end() + , current.get( container ) + , container->value_comp() + ) + ); + } + + static + void + resolveLazyCurrentInStorage( + _CurrentInStorage & currentInStorage + , _CurrentInErased & currentInErased + , _Current const current + , _Container const * container + ) + { + if( currentInStorage ){ + return; + } + + currentInStorage = const_cast< pointer_mutable >( + std::lower_bound( + container->storage().begin() + , container->storage().end() + , current.get( container ) + , container->value_comp() + ) + ); + + currentInStorage.setOnNotErased( currentInErased, container ); + } + + void + resolveLazyValues()const + { + resolveLazyCurrentInBuffer( _currentInBuffer, _current, _container ); + resolveLazyCurrentInStorage( _currentInStorage, _currentInErased, _current, _container ); + } + + /*pure function*/ + bool + validate()const + { + if( !_currentInStorage && _currentInBuffer && _currentInErased && _current ) + { + // not found in storage, inserted to buffer, buffer merged to storage + + AV_CHECK( _currentInBuffer.validate( _container ) ); + AV_CHECK( _currentInErased.is_end( _container ) ); + AV_CHECK( _current == _currentInBuffer ); + + // _currentInStorage <- lazy in operator++/operator--/operator==/operator!= + } + else + if( _currentInStorage && !_currentInBuffer && _currentInErased && !_current ) + { + AV_ERROR(); + + return false; + } + else + if( _currentInStorage && !_currentInBuffer && _currentInErased && _current ) + { + // found in storage, not found in erased + + AV_CHECK( _currentInStorage.validate( _container ) ); + AV_CHECK( + std::binary_search( + _container->erased().begin() + , _container->erased().end() + , _currentInStorage.data() + ) == false + ); + AV_CHECK( _currentInErased.validate( _container ) ); + AV_CHECK( _current == _currentInStorage ); + + // _currentInBuffer <- lazy in operator++/operator--/operator==/operator!= + } + else + if( _currentInStorage && _currentInBuffer && !_currentInErased && !_current ) + { + // not found in storage, insert to buffer + // erase from buffer + find in storage + // lower_bound + // upper_bound + + AV_CHECK( _currentInStorage.validate( _container ) ); + AV_CHECK( _currentInBuffer.validate( _container ) ); + + // _currentInStorage <- fix against '!_currentInErased' + // _current <- get it right now + } + else + if( _currentInStorage && _currentInBuffer && !_currentInErased && _current ) + { + // not found in storage, found in buffer + // not found in storage, inserted to buffer + // erased from storage's back + + AV_CHECK( _currentInStorage.validate( _container ) ); + AV_CHECK( _currentInBuffer.validate( _container ) ); + AV_CHECK( _current == _currentInBuffer ); + + // _currentInStorage <- fix against '!_currentInErased' + // _currentInErased <- get it right now + } + else + if( _currentInStorage && _currentInBuffer && _currentInErased && !_current ) + { + // begin iterator + // end iterator + // erase from storage, not merged + find in buffer + // erase from storage, merged + find in buffer + find in storage + + AV_CHECK( _currentInStorage.validate( _container ) ); + AV_CHECK( _currentInBuffer.validate( _container ) ); + AV_CHECK( _currentInErased.validate( _container ) ); + + // _currentInStorage <- check against _currentInErased + // _current <- get it right now + } + else + if( ! _currentInStorage && ! _currentInBuffer && ! _currentInErased && !_current ) + { + // begin iterator on empty AssocVector + // end iterator on empty AssocVector + } + else + { + AV_ERROR(); + + return false; + } + + return true; + } + + private: + _Container const * _container; + + // mutable since lazy values in operator==()const / operator!=()const + mutable _CurrentInStorage _currentInStorage; + mutable _CurrentInBuffer _currentInBuffer; + mutable _CurrentInErased _currentInErased; + + _Current _current; + }; + + template< + typename _Iterator + , typename _Container + > + std::ostream & + operator<<( + std::ostream & out + , AssocVectorLazyIterator< _Iterator, _Container > const & iter + ) + { + out << "S: " << iter.getCurrentInStorage(); + + if( iter.getCurrentInStorage() == 0 ){ + out << " (null)"; + } + else if( iter.getContainer()->storage().end() == iter.getCurrentInStorage() ){ + out << " (end)"; + } + else{ + out << " " << * iter.getCurrentInStorage(); + } + + out << "\nB: " << iter.getCurrentInBuffer(); + + if( iter.getCurrentInBuffer() == 0 ){ + out << " (null)"; + } + else if( iter.getContainer()->buffer().end() == iter.getCurrentInBuffer() ){ + out << " (end)"; + } + else{ + out << " " << * iter.getCurrentInBuffer(); + } + + out << "\nE: " << iter.getCurrentInErased(); + + if( iter.getCurrentInErased() == 0 ){ + out << " (null)"; + } + else if( iter.getContainer()->erased().end() == iter.getCurrentInErased() ){ + out << " (end)"; + } + else{ + AV_CHECK( * iter.getCurrentInErased() ); + + out << " " << * * iter.getCurrentInErased(); + } + + out << "\nC: " << iter.getCurrent(); + + if( iter.getCurrent() == 0 ){ + out << " (null)"; + } + else{ + out << " " << * iter.getCurrent(); + } + + std::flush( out ); + + return out; + } + + // + // _AssocVectorIterator, simplified version of AssocVectorLazyIterator, works with _find and _end + // + template< + typename _Iterator + , typename _Container + > + struct _AssocVectorIterator + { + private: + typedef typename std::iterator_traits< _Iterator >::pointer pointer_mutable; + + public: + typedef typename std::iterator_traits< _Iterator >::value_type value_type; + + // make key const + typedef std::pair< + typename value_type::first_type const + , typename value_type::second_type + > & reference; + + // make key const + typedef std::pair< + typename value_type::first_type const + , typename value_type::second_type + > * pointer; + + public: + _AssocVectorIterator( + typename _Container::value_compare const & cmp = typename _Container::value_compare() + ) + : _current( 0 ) + { + } + + template< typename _Iter > + _AssocVectorIterator( _AssocVectorIterator< _Iter, _Container > const & other ) + : _current( other.getCurrent() ) + { + } + + _AssocVectorIterator( pointer_mutable current ) + : _current( current ) + { + } + + _AssocVectorIterator & + operator=( _AssocVectorIterator const & other ) + { + _current = other._current; + + return * this; + } + + bool operator==( _AssocVectorIterator const & other )const + { + return _current == other.getCurrent(); + } + + bool operator!=( _AssocVectorIterator const & other )const + { + return ! ( ( * this ) == other ); + } + + reference operator*()const + { + AV_PRECONDITION( _current != 0 ); + + return * get(); + } + + pointer operator->()const + { + AV_PRECONDITION( _current != 0 ); + + return get(); + } + + pointer get()const + { + AV_PRECONDITION( _current != 0 ); + + // make key const + // pair< T1, T2 > * -> pair< T1 const, T2 > * + //return reinterpret_cast< pointer >( _current ); + + return + reinterpret_cast< pointer >( + const_cast< void * >( + reinterpret_cast< void const * >( _current ) + ) + ); + } + + operator bool()const noexcept + { + return _current != 0; + } + + // public for copy constructor only : Iterator -> ConstIterator + pointer_mutable getCurrent()const noexcept + { + return _current; + } + + private: + pointer_mutable _current; + }; + + template< + typename _Iterator + , typename _Container + > + std::ostream & operator<<( + std::ostream & out + , _AssocVectorIterator< _Iterator, _Container > const & iter + ) + { + out << "S: " << iter.getCurrent(); + + if( iter.getCurrent() == 0 ){ + out << " (null)(end)"; + } + else{ + out << " " << * iter.get(); + } + + return out; + } + +} // namespace detail + +template< + typename _Key + , typename _Mapped + , typename _Cmp = std::less< _Key > + , typename _Allocator = std::allocator< std::pair< _Key, _Mapped > > +> +struct AssocVector +{ +private: + typedef std::pair< _Key, _Mapped > value_type_mutable; + typedef std::pair< _Key const, _Mapped > value_type_key_const; + +public: + typedef _Key key_type; + typedef _Mapped mapped_type; + + typedef value_type_key_const value_type; + + typedef typename _Allocator::size_type size_type; + typedef typename _Allocator::difference_type difference_type; + + typedef typename _Allocator::pointer pointer; + typedef typename _Allocator::const_pointer const_pointer; + + typedef _Cmp key_compare; + typedef util::CmpByFirst< value_type_mutable, _Cmp > value_compare; + + typedef _Allocator allocator_type; + + typedef mapped_type & reference; + typedef mapped_type const & const_reference; + + typedef detail::AssocVectorLazyIterator< value_type_mutable *, AssocVector > iterator; + typedef detail::AssocVectorLazyIterator< value_type_mutable const *, AssocVector > const_iterator; + + typedef std::reverse_iterator< iterator > reverse_iterator; + typedef std::reverse_iterator< const_iterator > const_reverse_iterator; + + typedef array::Array< value_type_mutable > _Storage; + typedef array::Array< typename _Storage::const_iterator > _Erased; + +#ifdef AV_ENABLE_EXTENSIONS + public: +#else + private: +#endif + + // + // extension, faster, non STL compatible version of iterator, working with _find end _end + // + typedef detail::_AssocVectorIterator< value_type_mutable *, AssocVector > _iterator; + typedef detail::_AssocVectorIterator< value_type_mutable const *, AssocVector > _const_iterator; + +private: + struct _FindOrInsertToBufferResult + { + typename _Storage::iterator _inBuffer; + bool _isInserted; + bool _isReallocated; + }; + + struct _TryRemoveBackResult + { + bool _anyItemRemoved; + bool _erasedItemRemoved; + }; + + struct _FindImplResult + { + typename _Storage::iterator _inStorage; + typename _Storage::iterator _inBuffer; + typename _Erased::iterator _inErased; + typename _Storage::iterator _current; + + bool validate()const + { + return + ( _current == 0 && _inStorage == 0 && _inBuffer == 0 && _inErased == 0 ) + || _inStorage != 0; + } + }; + + struct _InsertImplResult + { + bool _isInserted; + + typename _Storage::iterator _inStorage; + typename _Storage::iterator _inBuffer; + typename _Erased::iterator _inErased; + typename _Storage::iterator _current; + + bool validate()const + { + if( _current == 0 ) + { + AV_ERROR(); + + return false; + } + + if( _inStorage == 0 && ( _inBuffer == 0 || _inErased == 0 ) ) + { + AV_ERROR(); + + return false; + } + + return true; + } + }; + + struct _TryEraseFromStorageResult + { + typename _Erased::iterator _inErased; + bool _isErased; + bool _isMerged; + }; + +public: + // + // constructor + // + explicit + AssocVector( + _Cmp const & cmp = _Cmp() + , _Allocator const & allocator = _Allocator() + ); + + explicit + AssocVector( _Allocator const & allocator ); + + template< typename __InputIterator > + AssocVector( + __InputIterator first + , __InputIterator last + , _Cmp const & cmp = _Cmp() + , _Allocator const & allocator = _Allocator() + ); + + AssocVector( AssocVector< _Key, _Mapped, _Cmp, _Allocator > const & other ); + AssocVector( + AssocVector< _Key, _Mapped, _Cmp, _Allocator > const & other + , _Allocator const & allocator + ); + + AssocVector( AssocVector< _Key, _Mapped, _Cmp, _Allocator > && other ); + AssocVector( + AssocVector< _Key, _Mapped, _Cmp, _Allocator > && other + , _Allocator const & allocator + ); + + AssocVector( + std::initializer_list< value_type > list + , _Cmp const & cmp = _Cmp() + , _Allocator const & allocator = _Allocator() + ); + + // + // destructor + // + inline ~AssocVector(); + + // + // clear + // + inline void clear() noexcept; + + // + // operator= + // + AssocVector & operator=( AssocVector const & other ); + AssocVector & operator=( AssocVector && other ); + + // + // methods + // + void reserve( std::size_t newCapacity ); + void swap( AssocVector & other ) noexcept; + + // + // iterators + // + inline iterator begin(); + inline const_iterator begin()const; + inline const_iterator cbegin()const; + + inline reverse_iterator rbegin(); + inline const_reverse_iterator rbegin()const; + inline const_reverse_iterator crbegin()const; + + inline iterator end(); + inline const_iterator end()const; + inline const_iterator cend()const; + + inline reverse_iterator rend(); + inline const_reverse_iterator rend()const; + inline const_reverse_iterator crend()const; + + // + // size + // + inline bool empty()const noexcept; + inline std::size_t size()const noexcept; + inline std::size_t capacity()const noexcept; + inline std::size_t max_size()const noexcept; + + // + // insert + // + std::pair< iterator, bool > insert( value_type const & value ); + + template< typename __ValueType > + std::pair< iterator, bool > insert( __ValueType && value ); + + iterator insert( const_iterator hint, value_type const & value ); + + template< typename __ValueType > + iterator insert( const_iterator hint, __ValueType && value ); + + template< typename _Iterator > + inline void insert( _Iterator first, _Iterator last ); + + inline void insert( std::initializer_list< value_type > list ); + + // + // emplace + // + template< class... __Args > + std::pair< iterator, bool > emplace( __Args... args ); + + template< class... __Args > + std::pair< iterator, bool > emplace_hint( const_iterator hint, __Args... args ); + + // + // find + // + iterator find( key_type const & k ); + const_iterator find( key_type const & k )const; + + iterator lower_bound( key_type const & k ); + const_iterator lower_bound( key_type const & k )const; + + iterator upper_bound( key_type const & k ); + const_iterator upper_bound( key_type const & k )const; + + std::pair< iterator, iterator > equal_range( key_type const & k ); + std::pair< const_iterator, const_iterator > equal_range( key_type const & k )const; + + // + // count + // + inline std::size_t count( key_type const & k )const; + + // + // operator[] + // + reference operator[]( key_type const & k ); + reference operator[]( key_type && k ); + + // + // at + // + reference at( key_type const & k ); + const_reference at( key_type const & k )const; + + // + // erase + // + std::size_t erase( key_type const & k ); + iterator erase( iterator pos ); + + // + // observers + // + key_compare key_comp()const + { + return _cmp; + } + + value_compare value_comp()const + { + return value_compare( _cmp ); + } + + //allocator_type get_allocator()const + //{ + // return _allocator; + //} + +#ifdef AV_ENABLE_EXTENSIONS + public: +#else + private: +#endif + + // + // extension, flatenize container, enforce merge of _storage with _erased and with _buffer + // + void _merge(); + + // + // extension, faster, non STL compatible version of insert + // + bool _insert( value_type const & value ); + + template< typename __ValueType > + bool _insert( __ValueType && value ); + + // + // extension, faster, non STL compatible version of end, works with _find + // + inline _iterator _end(); + inline _const_iterator _end()const; + + // + // extension, faster, non STL compatible version of find, works with _end + // + _iterator _find( key_type const & k ); + _const_iterator _find( key_type const & k )const; + + // + // extension, faster, non STL compatible version of erase + // + bool _erase( iterator pos ); + +private: + bool validateStorage()const; + bool validateBuffer()const; + bool validateErased()const; + bool validate()const; + + // + // merge + // + void mergeStorageWithBuffer(); + void mergeStorageWithErased(); + + // + // insert + // + template< typename __ValueType > + void pushBack( __ValueType && value ); + + template< typename __ValueType > + bool shouldBePushBack( __ValueType && value )const; + + template< typename __ValueType > + _FindOrInsertToBufferResult + findOrInsertToBuffer( __ValueType && value ); + + // + // insertImpl, function does as little as needed but returns as much data as possible + // + template< typename __ValueType > + _InsertImplResult + insertImpl( __ValueType && value ); + + // + // emplace_impl + // + template< class __Head, class... __Tail > + std::pair< iterator, bool > emplaceImpl( __Head && head, __Tail... tail ); + + // + // erase + // + _TryRemoveBackResult + tryRemoveStorageBack( typename _Storage::iterator pos ); + + // + // tryEraseFromStorage + // + _TryEraseFromStorageResult + tryEraseFromStorage( typename _Storage::iterator pos ); + + // + // isErased + // + bool isErased( typename _Storage::const_iterator iterator )const; + + // + // findImpl, function does as little as needed but returns as much data as possible + // + _FindImplResult + findImpl( key_type const & key ); + + // + // getAllocator (method specialization) + // + //_Allocator getAllocator( _Storage const & ){ return _allocator; } + // + //typename _Allocator::template rebind< typename _Storage::const_iterator >::other + //getAllocator( _Erased const & ) + //{return typename _Allocator::template rebind< typename _Storage::const_iterator >::other( _allocator );} + +public: // public for unit tests only + void dump( int width = -1 )const; + + std::size_t bufferSize()const{ return _buffer.size(); } + std::size_t bufferCapacity()const{ return _buffer.capacity(); } + _Storage const & storage()const{ return _storage; } + + std::size_t storageSize()const{ return _storage.size(); } + std::size_t storageCapacity()const{ return _storage.capacity(); } + _Storage const & buffer()const{ return _buffer; } + + std::size_t erasedSize()const{ return _erased.size(); } + std::size_t erasedCapacity()const{ return _erased.capacity(); } + _Erased const & erased()const{ return _erased; } + + static std::size_t calculateNewBufferCapacity( std::size_t storageSize ); + static std::size_t calculateNewErasedCapacity( std::size_t storageSize ); + static std::size_t calculateNewStorageCapacity( std::size_t storageSize ); + +private: + _Storage _storage; + _Storage _buffer; + _Erased _erased; + + _Cmp _cmp; +}; + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +bool operator==( + AssocVector< _Key, _Mapped, _Cmp, _Allocator > const & lhs + , AssocVector< _Key, _Mapped, _Cmp, _Allocator > const & rhs +) +{ + if( lhs.size() != rhs.size() ){ + return false; + } + + typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_iterator begin = lhs.begin(); + typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_iterator const end = lhs.end(); + + typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_iterator begin2 = rhs.begin(); + + for( /*empty*/ ; begin != end ; ++ begin, ++ begin2 ) + { + if( begin->first != begin2->first ){ + return false; + } + + if( begin->second != begin2->second ){ + return false; + } + } + + return true; +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +bool operator!=( + AssocVector< _Key, _Mapped, _Cmp, _Allocator > const & lhs + , AssocVector< _Key, _Mapped, _Cmp, _Allocator > const & rhs +) +{ + return ! ( lhs == rhs ); +} + +// +// Method Definitions +// + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::AssocVector( + _Cmp const & cmp + , _Allocator const & allocator +) + : _cmp( cmp ) +{ +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::AssocVector( _Allocator const & allocator ) +{ +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +template< + typename __InputIterator +> +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::AssocVector( + __InputIterator first + , __InputIterator last + , _Cmp const & cmp + , _Allocator const & allocator +) + : _cmp( cmp ) +{ + AV_PRECONDITION( std::distance( first, last ) >= 0 ); + + std::size_t const size = std::distance( first, last ); + + if( size > 0 ) + { + reserve( size ); + + for( /*empty*/ ; first != last ; ++ first ){ + insert( * first ); + } + } + + AV_POSTCONDITION( validate() ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::AssocVector( + AssocVector< _Key, _Mapped, _Cmp, _Allocator > const & other +) + : _storage( other._storage ) + , _buffer( other._buffer ) + , _erased( other._erased ) + , _cmp( other._cmp ) +{ +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::AssocVector( + AssocVector< _Key, _Mapped, _Cmp, _Allocator > const & other + , _Allocator const & allocator +) + : _storage( other._storage, allocator ) + , _buffer( other._buffer, allocator ) + , _erased( other._erased, allocator ) + , _cmp( other._cmp, allocator ) +{ +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::AssocVector( + AssocVector< _Key, _Mapped, _Cmp, _Allocator > && other +) + : _storage( std::move( other._storage ) ) + , _buffer( std::move( other._buffer ) ) + , _erased( std::move( other._erased ) ) + , _cmp( other._cmp ) +{ +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::AssocVector( + AssocVector< _Key, _Mapped, _Cmp, _Allocator > && other + , _Allocator const & allocator +) + : _storage( std::move( other._storage ) ) + , _buffer( std::move( other._buffer ) ) + , _erased( std::move( other._erased ) ) + , _cmp( other._cmp ) +{ +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::AssocVector( + std::initializer_list< typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::value_type > list + , _Cmp const & cmp + , _Allocator const & allocator +) + : _cmp( cmp ) +{ + reserve( list.size() ); + + insert( list ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::~AssocVector() +{ +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +void +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::clear() noexcept +{ + util::destroy_range( _storage.begin(), _storage.end() ); + util::destroy_range( _buffer.begin(), _buffer.end() ); + + _storage.setSize( 0 ); + _buffer.setSize( 0 ); + _erased.setSize( 0 ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +AssocVector< _Key, _Mapped, _Cmp, _Allocator > & +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::operator=( AssocVector const & other ) +{ + AssocVector temp( other ); + temp.swap( * this ); + + return * this; +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +AssocVector< _Key, _Mapped, _Cmp, _Allocator > & +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::operator=( AssocVector && other ) +{ + AssocVector temp( std::move( other ) ); + + temp.swap( * this ); + + return * this; +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +void +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::reserve( std::size_t newStorageCapacity ) +{ + if( _storage.get_allocator().max_size() < newStorageCapacity ){ + throw std::length_error( "AssocVector< _K, _M, _C, _A >::reserve" ); + } + + if( util::less_equal( newStorageCapacity, _storage.capacity() ) ){ + return; + } + + {// _erased + if( _erased.empty() == false ){ + mergeStorageWithErased(); + } + + _erased.reserve( calculateNewErasedCapacity( newStorageCapacity ) ); + + AV_CHECK( _erased.empty() ); + } + + std::size_t const newBufferCapacity + = calculateNewBufferCapacity( newStorageCapacity ); + + std::size_t const newStorageSize = _storage.size() + _buffer.size(); + + { + _Storage newStorage( newStorageCapacity, _storage.get_allocator() ); + _Storage newBuffer( newBufferCapacity, _buffer.get_allocator() ); + + util::move_merge_into_uninitialized( + _storage.begin() + , _storage.end() + , _buffer.begin() + , _buffer.end() + , newStorage.begin() + , value_comp() + ); + + newStorage.swap( _storage ); + newBuffer.swap( _buffer ); + }// call newStorage newBuffer destructors + + _storage.setSize( newStorageSize ); + + AV_POSTCONDITION( _buffer.empty() ); + AV_POSTCONDITION( validate() ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::iterator +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::begin() +{ + return iterator( this, _storage.begin(), _buffer.begin(), _erased.begin(), 0 ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::reverse_iterator +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::rbegin() +{ + return reverse_iterator( end() ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_iterator +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::begin()const +{ + return const_iterator( this, _storage.begin(), _buffer.begin(), _erased.begin(), 0 ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_iterator +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::cbegin()const +{ + return begin(); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_reverse_iterator +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::rbegin()const +{ + return const_reverse_iterator( end() ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_reverse_iterator +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::crbegin()const +{ + return rbegin(); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::iterator +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::end() +{ + return iterator( this, _storage.end(), _buffer.end(), _erased.end(), 0 ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::reverse_iterator +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::rend() +{ + return reverse_iterator( begin() ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_iterator +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::end()const +{ + return const_iterator( this, _storage.end(), _buffer.end(), _erased.end(), 0 ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_iterator +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::cend()const +{ + return end(); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_reverse_iterator +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::rend()const +{ + return const_reverse_iterator( begin() ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_reverse_iterator +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::crend()const +{ + return rend(); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::_iterator +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::_end() +{ + return _iterator( 0 ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::_const_iterator +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::_end()const +{ + return _const_iterator( 0 ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +bool +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::empty()const noexcept +{ + return size() == 0; +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +std::size_t +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::size()const noexcept +{ + return _storage.size() + _buffer.size() - _erased.size(); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +std::size_t +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::capacity()const noexcept +{ + return _storage.capacity() + _buffer.capacity(); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +std::size_t +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::max_size()const noexcept +{ + return _storage.get_allocator().max_size(); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +std::pair< typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::iterator, bool > +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::insert( value_type const & value ) +{ + _InsertImplResult const result = insertImpl( value ); + + return std::make_pair( + iterator( + this + , result._inStorage + , result._inBuffer + , result._inErased + , result._current + ) + , result._isInserted + ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +template< + typename __ValueType +> +std::pair< typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::iterator, bool > +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::insert( __ValueType && value ) +{ + _InsertImplResult const result = insertImpl( std::forward< __ValueType >( value ) ); + + return std::make_pair( + iterator( + this + , result._inStorage + , result._inBuffer + , result._inErased + , result._current + ) + , result._isInserted + ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::iterator +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::insert( + typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_iterator hint + , value_type const & value +) +{ + ( void )( hint ); + + _InsertImplResult const result = insertImpl( value ); + + return iterator( + this + , result._inStorage + , result._inBuffer + , result._inErased + , result._current + ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +template< + typename __ValueType +> +typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::iterator +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::insert( + const_iterator hint + , __ValueType && value +) +{ + ( void )( hint ); + + _InsertImplResult const result = insertImpl( std::forward< __ValueType >( value ) ); + + return iterator( + this + , result._inStorage + , result._inBuffer + , result._inErased + , result._current + ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +void +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::insert( + std::initializer_list< value_type > list +) +{ + insert( list.begin(), list.end() ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +bool +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::_insert( value_type const & value ) +{ + return insertImpl( value )._isInserted; +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +template< + typename __ValueType +> +bool +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::_insert( __ValueType && value ) +{ + return insertImpl( std::forward< __ValueType >( value ) )._isInserted; +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +template< + typename __ValueType +> +typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::_InsertImplResult +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::insertImpl( __ValueType && value ) +{ + _Key const & k = value.first; + _Mapped const & m = value.second; + + {//push back to storage + if( shouldBePushBack( value ) ) + { + pushBack( std::forward< __ValueType >( value ) ); + + _InsertImplResult result; + + { + AV_CHECK( _storage.empty() == false ); + + result._inStorage = ( _storage.end() - 1 ); + result._current = ( _storage.end() - 1 ); + } + + result._isInserted = true; + result._inBuffer = 0; + result._inErased = _erased.end(); + + AV_POSTCONDITION( result.validate() ); + AV_POSTCONDITION( validate() ); + + return result; + } + } + + typename _Storage::iterator const greaterEqualInStorage + = std::lower_bound( _storage.begin(), _storage.end(), k, value_comp() ); + + bool const notPresentInStorage + = greaterEqualInStorage == _storage.end() + || key_comp()( k, greaterEqualInStorage->first ); + + {//find or insert to buffer + if( notPresentInStorage ) + { + _FindOrInsertToBufferResult const findOrInsertToBufferResult + = findOrInsertToBuffer( std::forward< __ValueType >( value ) ); + + _InsertImplResult result; + result._isInserted = findOrInsertToBufferResult._isInserted; + + if( findOrInsertToBufferResult._isReallocated ) + { + result._inStorage = 0; + result._inErased = _erased.end(); + } + else + { + result._inStorage = greaterEqualInStorage; + result._inErased = 0; + } + + result._inBuffer = findOrInsertToBufferResult._inBuffer; + result._current = findOrInsertToBufferResult._inBuffer; + + AV_POSTCONDITION( result.validate() ); + AV_POSTCONDITION( validate() ); + + return result; + } + } + + {// check if not erased + typename _Erased::iterator const greaterEqualInErased = std::lower_bound( + _erased.begin() + , _erased.end() + , greaterEqualInStorage + , std::less< typename _Storage::const_iterator >() + ); + + bool const itemNotMarkedAsErased + = greaterEqualInErased == _erased.end() + || std::less< typename _Storage::const_iterator >() + ( greaterEqualInStorage, * greaterEqualInErased ); + + if( itemNotMarkedAsErased ) + {// item is in storage and is not marked as erased + _InsertImplResult result; + result._isInserted = false; + result._inStorage = greaterEqualInStorage; + result._inBuffer = 0; + result._inErased = greaterEqualInErased; + result._current = greaterEqualInStorage; + + AV_POSTCONDITION( result.validate() ); + AV_POSTCONDITION( validate() ); + + return result; + } + else + {// item is in storage but is marked as erased + _erased.erase( greaterEqualInErased ); + + greaterEqualInStorage->second = m; + + _InsertImplResult result; + result._isInserted = true; + result._inStorage = greaterEqualInStorage; + result._inBuffer = 0; + + // greaterEqualInErased is after 'Array::erase' but still valid + result._inErased = greaterEqualInErased; + + result._current = greaterEqualInStorage; + + AV_POSTCONDITION( validate() ); + AV_POSTCONDITION( result.validate() ); + + return result; + } + } +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +template< + typename _Iterator +> +void +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::insert( _Iterator const begin, _Iterator const end ) +{ + for( _Iterator current = begin ; current != end ; ++ current ){ + insert( * current ); + } +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +template< + class... __Args +> +std::pair< typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::iterator, bool > +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::emplace( __Args... args ) +{ + return emplaceImpl( args... ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +template< + class... __Args +> +std::pair< typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::iterator, bool > +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::emplace_hint( const_iterator hint, __Args... args ) +{ + ( void )( hint ); + + return emplaceImpl( args... ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +template< + class __Head + , class... __Tail +> +std::pair< typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::iterator, bool > +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::emplaceImpl( __Head && head, __Tail... tail ) +{ + _InsertImplResult const result + = insertImpl( value_type_mutable( key_type( head ), mapped_type( tail... ) ) ); + + return std::make_pair( + iterator( + this + , result._inStorage + , result._inBuffer + , result._inErased + , result._current + ) + , result._isInserted + ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +template< + typename __ValueType +> +bool +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::shouldBePushBack( __ValueType && value )const +{ + bool pushBackToStorage = false; + + {// should be pushed back + if( _storage.empty() ) + { + if( _buffer.empty() ){ + pushBackToStorage = true; + } + else + { + if( _cmp( _buffer.back().first, value.first ) ){ + pushBackToStorage = true; + } + } + } + else + { + if( _buffer.empty() ) + { + if( _cmp( _storage.back().first, value.first ) ){ + pushBackToStorage = true; + } + } + else + { + if( _cmp( _storage.back().first, value.first ) + && _cmp( _buffer.back().first, value.first ) + ){ + pushBackToStorage = true; + } + } + } + } + + return pushBackToStorage; +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +template< + typename __ValueType +> +void +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::pushBack( __ValueType && value ) +{ + if( _storage.size() != _storage.capacity() ){ + _storage.place_back( std::forward< __ValueType >( value ) ); + + AV_POSTCONDITION( validate() ); + + return; + } + + std::size_t const newStorageCapacity = calculateNewStorageCapacity( _storage.capacity() ); + std::size_t const newBufferCapacity = calculateNewBufferCapacity( newStorageCapacity ); + std::size_t const newErasedCapacity = calculateNewErasedCapacity( newStorageCapacity ); + + if( util::less_equal( newStorageCapacity, _storage.capacity() ) ){ + return; + } + + if( _storage.get_allocator().max_size() < newStorageCapacity ){ + throw std::length_error( "AssocVector::reserve" ); + } + + _Storage newStorage( newStorageCapacity, _storage.get_allocator() ); + _Storage newBuffer( newBufferCapacity, _buffer.get_allocator() ); + _Erased newErased( newErasedCapacity, _erased.get_allocator() ); + + {// may throw + iterator current = begin(); + iterator const end = this->end(); + + while( current != end ) + { + // for '++ current' object has still exist and can not be moved before + typename iterator::pointer_mutable const current_raw_ptr = current.getCurrent(); + + ++ current; + + newStorage.place_back( AV_MOVE_IF_NOEXCEPT( * current_raw_ptr ) ); + } + } + + // may throw an exception in __ValueType copy constructor, not exception safe + newStorage.place_back( std::forward< __ValueType >( value ) ); + + newStorage.swap( _storage ); + newBuffer.swap( _buffer ); + newErased.swap( _erased ); + + AV_POSTCONDITION( _buffer.empty() ); + AV_POSTCONDITION( _erased.empty() ); + + AV_POSTCONDITION( validate() ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::_TryRemoveBackResult +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::tryRemoveStorageBack( + typename _Storage::iterator pos +) +{ + if( pos + 1 != _storage.end() ) + { + _TryRemoveBackResult result; + result._anyItemRemoved = false; + result._erasedItemRemoved = false; + + return result; + } + + _storage.get_allocator().destroy( pos ); + + _storage.setSize( _storage.size() - 1 ); + + if( + _erased.empty() == false + && _erased.back() == pos + ) + { + _erased.setSize( _erased.size() - 1 ); + + _TryRemoveBackResult result; + result._anyItemRemoved = true; + result._erasedItemRemoved = true; + + AV_POSTCONDITION( validate() ); + + return result; + } + + _TryRemoveBackResult result; + result._anyItemRemoved = true; + result._erasedItemRemoved = false; + + AV_POSTCONDITION( validate() ); + + return result; +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::_TryEraseFromStorageResult +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::tryEraseFromStorage( + typename _Storage::iterator pos +) +{ + std::pair< typename _Erased::iterator, bool > const insertInSortedResult + = array::insert_in_sorted( + _erased + , typename _Storage::const_iterator( pos ) + , std::less< typename _Storage::const_iterator >() + ); + + if( _erased.full() ) + { + mergeStorageWithErased(); + + _TryEraseFromStorageResult result; + result._inErased = _erased.end(); + result._isErased = true; + result._isMerged = true; + + AV_POSTCONDITION( validate() ); + + return result; + } + else + { + _TryEraseFromStorageResult result; + result._inErased = insertInSortedResult.first; + result._isErased = insertInSortedResult.second; + result._isMerged = false; + + AV_POSTCONDITION( validate() ); + + return result; + } +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +bool +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::isErased( + typename AssocVector::_Storage::const_iterator iterator +)const +{ + typename _Erased::const_iterator const foundInErased = array::binary_search( + _erased.begin() + , _erased.end() + , iterator + , std::less< typename _Storage::const_iterator >() + ); + + return foundInErased != _erased.end(); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::_FindImplResult +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::findImpl( _Key const & k ) +{ + typename _Storage::iterator const greaterEqualInStorage + = std::lower_bound( _storage.begin(), _storage.end(), k, value_comp() ); + + bool const presentInStorage + = greaterEqualInStorage != _storage.end() + && key_comp()( k, greaterEqualInStorage->first ) == false; + + {// item is in storage, check in erased + if( presentInStorage ) + { + typename _Erased::iterator greaterEqualInErased = std::lower_bound( + _erased.begin() + , _erased.end() + , greaterEqualInStorage + , std::less< typename _Storage::const_iterator >() + ); + + bool const itemNotMarkedAsErased + = greaterEqualInErased == _erased.end() + || std::less< typename _Storage::const_iterator >()( + greaterEqualInStorage + , * greaterEqualInErased + ); + + if( itemNotMarkedAsErased ) + { + _FindImplResult result; + result._inStorage = greaterEqualInStorage; + result._inBuffer = 0; + result._inErased = greaterEqualInErased; + result._current = greaterEqualInStorage; + + AV_POSTCONDITION( result.validate() ); + + return result; + } + else + { + _FindImplResult result; + result._inStorage = 0; + result._inBuffer = 0; + result._inErased = 0; + result._current = 0; + + AV_POSTCONDITION( result.validate() ); + + return result; + } + } + } + + {// check in buffer + typename _Storage::iterator const greaterEqualInBuffer + = std::lower_bound( _buffer.begin(), _buffer.end(), k, value_comp() ); + + bool const presentInBuffer + = greaterEqualInBuffer != _buffer.end() + && key_comp()( k, greaterEqualInBuffer->first ) == false; + + if( presentInBuffer ) + { + _FindImplResult result; + result._inStorage = greaterEqualInStorage; + result._inBuffer = greaterEqualInBuffer; + result._inErased = 0; + result._current = greaterEqualInBuffer; + + AV_POSTCONDITION( result.validate() ); + + return result; + } + else + { + _FindImplResult result; + result._inStorage = 0; + result._inBuffer = 0; + result._inErased = 0; + result._current = 0; + + AV_POSTCONDITION( result.validate() ); + + return result; + } + } +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::iterator +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::find( _Key const & k ) +{ + _FindImplResult const result = findImpl( k ); + + if( result._current == 0 ){ + return end(); + } + else + { + return iterator( + this + , result._inStorage + , result._inBuffer + , result._inErased + , result._current + ); + } +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::reference +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::at( _Key const & k ) +{ + _FindImplResult const result = findImpl( k ); + + if( result._current == 0 ){ + throw std::out_of_range( "AssocVector::at" ); + } + else + { + return result._current->second; + } +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_reference +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::at( _Key const & k )const +{ + typedef AssocVector< _Key, _Mapped, _Cmp, _Allocator > * NonConstThis; + + return const_cast< NonConstThis >( this )->at( k ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_iterator +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::find( _Key const & k )const +{ + typedef AssocVector< _Key, _Mapped, _Cmp, _Allocator > * NonConstThis; + + return const_cast< NonConstThis >( this )->find( k ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::iterator +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::lower_bound( _Key const & k ) +{ + typename _Storage::iterator const greaterEqualInStorage + = std::lower_bound( _storage.begin(), _storage.end(), k, value_comp() ); + + typename _Storage::iterator const greaterEqualInBuffer + = std::lower_bound( _buffer.begin(), _buffer.end(), k, value_comp() ); + + return iterator( this, greaterEqualInStorage, greaterEqualInBuffer, 0, 0 ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_iterator +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::lower_bound( _Key const & k )const +{ + typedef AssocVector< _Key, _Mapped, _Cmp, _Allocator > * NonConstThis; + + return const_cast< NonConstThis >( this )->lower_bound( k ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::iterator +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::upper_bound( _Key const & k ) +{ + typename _Storage::iterator const greaterInStorage + = std::upper_bound( _storage.begin(), _storage.end(), k, value_comp() ); + + typename _Storage::iterator const greaterInBuffer + = std::upper_bound( _buffer.begin(), _buffer.end(), k, value_comp() ); + + return iterator( this, greaterInStorage, greaterInBuffer, 0, 0 ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_iterator +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::upper_bound( _Key const & k )const +{ + typedef AssocVector< _Key, _Mapped, _Cmp, _Allocator > * NonConstThis; + + return const_cast< NonConstThis >( this )->upper_bound( k ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +std::pair< + typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::iterator + , typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::iterator +> +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::equal_range( _Key const & k ) +{ + typename _Storage::iterator const greaterEqualInStorage + = std::lower_bound( _storage.begin(), _storage.end(), k, value_comp() ); + + bool const notPresentInStorage + = greaterEqualInStorage == _storage.end() + || key_comp()( k, greaterEqualInStorage->first ); + + typename _Storage::iterator const greaterEqualInBuffer + = std::lower_bound( _buffer.begin(), _buffer.end(), k, value_comp() ); + + bool const notPresentInBuffer + = greaterEqualInBuffer == _buffer.end() + || key_comp()( k, greaterEqualInBuffer->first ); + + if( notPresentInStorage == false ) + { + return std::make_pair( + iterator( this, greaterEqualInStorage, greaterEqualInBuffer, 0, 0 ) + , iterator( this, greaterEqualInStorage + 1, greaterEqualInBuffer, 0, 0 ) + ); + } + + if( notPresentInBuffer == false ) + { + return std::make_pair( + iterator( this, greaterEqualInStorage, greaterEqualInBuffer, 0, 0 ) + , iterator( this, greaterEqualInStorage, greaterEqualInBuffer + 1, 0, 0 ) + ); + } + + return std::make_pair( + iterator( this, greaterEqualInStorage, greaterEqualInBuffer, 0, 0 ) + , iterator( this, greaterEqualInStorage, greaterEqualInBuffer, 0, 0 ) + ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +std::pair< + typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_iterator + , typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_iterator +> +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::equal_range( _Key const & k )const +{ + typedef AssocVector< _Key, _Mapped, _Cmp, _Allocator > * NonConstThis; + + return const_cast< NonConstThis >( this )->equal_range( k ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::_iterator +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::_find( _Key const & k ) +{ + return _iterator( findImpl( k )._current ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::_const_iterator +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::_find( _Key const & k )const +{ + typedef AssocVector< _Key, _Mapped, _Cmp, _Allocator > * NonConstThis; + + return const_cast< NonConstThis >( this )->_find( k ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +bool +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::validateStorage()const +{ + if( _storage.size() > _storage.capacity() ) + { + AV_ERROR(); + + return false; + } + + if( std::is_sorted( _storage.begin(), _storage.end(), value_comp() ) == false ) + { + AV_ERROR(); + + return false; + } + + return true; +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +bool +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::validateBuffer()const +{ + if( _buffer.size() > _buffer.capacity() ) + { + AV_ERROR(); + + return false; + } + + if( _buffer.empty() ){ + return true; + } + + if( std::is_sorted( _buffer.begin(), _buffer.end(), value_comp() ) == false ) + { + AV_ERROR(); + + return false; + } + + if( + util::has_intersection( + _buffer.begin() + , _buffer.end() + , _storage.begin() + , _storage.end() + , value_comp() + ) + ) + { + AV_ERROR(); + + return false; + } + + return true; +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +bool +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::validateErased()const +{ + if( _erased.size() > _erased.capacity() ) + { + AV_ERROR(); + + return false; + } + + if( _erased.empty() ){ + return true; + } + + if( + std::is_sorted( + _erased.begin() + , _erased.end() + , std::less< typename _Storage::const_iterator >() + ) == false + ) + { + AV_ERROR(); + + return false; + } + + AV_CHECK( _erased.front() >= _storage.begin() ); + AV_CHECK( _erased.back() < _storage.end() ); + + return true; +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +bool +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::validate()const +{ + if( calculateNewBufferCapacity( _storage.capacity() ) != _buffer.capacity() ){ + return false; + } + + if( calculateNewErasedCapacity( _storage.capacity() ) != _erased.capacity() ){ + return false; + } + + return validateStorage() && validateBuffer() && validateErased(); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +void +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::_merge() +{ + if( size() > _storage.capacity() ) + { + reserve( calculateNewStorageCapacity( _storage.capacity() ) ); + + return; + } + + if( _erased.empty() == false ){ + mergeStorageWithErased(); + } + + mergeStorageWithBuffer(); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::reference +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::operator[]( key_type const & k ) +{ + return insert( value_type( k, mapped_type() ) ).first->second; +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::reference +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::operator[]( key_type && k ) +{ + return insert( value_type( std::move( k ), mapped_type() ) ).first->second; +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +std::size_t +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::count( key_type const & k )const +{ + return _find( k ) ? 1 : 0; +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +std::size_t +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::erase( key_type const & k ) +{ + typename _Storage::iterator const foundInStorage + = array::binary_search( _storage.begin(), _storage.end(), k, value_comp() ); + + {//erase from _buffer + if( foundInStorage == _storage.end() ) + { + typename _Storage::iterator const foundInBuffer + = array::binary_search( _buffer.begin(), _buffer.end(), k, value_comp() ); + + if( foundInBuffer == _buffer.end() ) + { + AV_POSTCONDITION( validate() ); + + return 0; + } + else + { + _buffer.erase( foundInBuffer ); + + AV_POSTCONDITION( validate() ); + + return 1; + } + } + } + + {//erase from back + _TryRemoveBackResult const result = tryRemoveStorageBack( foundInStorage ); + + if( result._anyItemRemoved ) + { + if( result._erasedItemRemoved ) + { + AV_POSTCONDITION( validate() ); + + return 0; + } + else + { + AV_POSTCONDITION( validate() ); + + return 1; + } + } + } + + {//erase from _storage + bool const result = tryEraseFromStorage( foundInStorage )._isErased ? 1 : 0; + + AV_POSTCONDITION( validate() ); + + return result; + } +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::iterator +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::erase( iterator pos ) +{ + if( pos == end() ){ + return end(); + } + + // iterator::get converts : pair< T1, T2 > * -> pair< T1 const, T2 > * + // revert real iterator type: pair< T1 const, T2 > * -> pair< T1, T2 > * + value_type_mutable * const posBase = reinterpret_cast< value_type_mutable * >( pos.get() ); + + _Key const key = pos->first; + + {//erase from _buffer + if( util::is_between( _buffer.begin(), posBase, _buffer.end() ) ) + { + _buffer.erase( posBase ); + + typename _Storage::iterator const greaterEqualInStorage + = pos.getCurrentInStorage() + ? pos.getCurrentInStorage() + : std::lower_bound( _storage.begin(), _storage.end(), key, value_comp() ); + + AV_POSTCONDITION( validate() ); + + return iterator( this, greaterEqualInStorage, posBase, 0, 0 ); + } + } + + {//item not present in container + if( util::is_between( _storage.begin(), posBase, _storage.end() ) == false ){ + return end(); + } + } + + {//erase from back + _TryRemoveBackResult const result = tryRemoveStorageBack( posBase ); + + if( result._anyItemRemoved ) + { + typename _Storage::iterator const greaterEqualInBuffer + = pos.getCurrentInBuffer() + ? pos.getCurrentInBuffer() + : std::lower_bound( _buffer.begin(), _buffer.end(), key, value_comp() ); + + if( greaterEqualInBuffer == _buffer.end() ) + { + AV_POSTCONDITION( validate() ); + + return end(); + } + else + { + AV_POSTCONDITION( validate() ); + + return iterator( this, _storage.end(), greaterEqualInBuffer, 0, 0 ); + } + } + } + + {//erase from _storage + _TryEraseFromStorageResult const result = tryEraseFromStorage( posBase ); + + if( result._isErased == false ){ + return end(); + } + + typename _Storage::iterator const greaterEqualInBuffer + = pos.getCurrentInBuffer() + ? pos.getCurrentInBuffer() + : std::lower_bound( _buffer.begin(), _buffer.end(), key, value_comp() ); + + if( result._isMerged == false ) + { + AV_POSTCONDITION( validate() ); + + return iterator( this, posBase + 1, greaterEqualInBuffer, result._inErased + 1, 0 ); + } + + typename _Storage::iterator const greaterEqualInStorage + = std::lower_bound( _storage.begin(), _storage.end(), key, value_comp() ); + + AV_POSTCONDITION( validate() ); + + return iterator( this, greaterEqualInStorage, greaterEqualInBuffer, _erased.end(), 0 ); + } +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +bool +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::_erase( iterator pos ) +{ + // iterator::get converts : pair< T1, T2 > * -> pair< T1 const, T2 > * + // revert real iterator type: pair< T1 const, T2 > * -> pair< T1, T2 > * + value_type_mutable * const posBase = reinterpret_cast< value_type_mutable * >( pos.get() ); + + {//erase from _buffer + if( util::is_between( _buffer.begin(), posBase, _buffer.end() ) ) + { + _buffer.erase( posBase ); + + AV_POSTCONDITION( validate() ); + + return true; + } + } + + {//item not present in container + if( util::is_between( _storage.begin(), posBase, _storage.end() ) == false ){ + return false; + } + } + + {//erase from back + _TryRemoveBackResult const result = tryRemoveStorageBack( posBase ); + + if( result._anyItemRemoved ) + { + AV_POSTCONDITION( validate() ); + + return true; + } + } + + {//erase from _storage + bool const result = tryEraseFromStorage( posBase )._isErased; + + AV_POSTCONDITION( validate() ); + + return result; + } +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +void +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::swap( + AssocVector< _Key, _Mapped, _Cmp, _Allocator > & other +) noexcept +{ + std::swap( _storage, other._storage ); + std::swap( _buffer, other._buffer ); + std::swap( _erased, other._erased ); + + std::swap( _cmp, other._cmp ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +void +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::mergeStorageWithBuffer() +{ + AV_PRECONDITION( _erased.empty() ); + + array::move_merge( _storage, _buffer, value_comp() ); + + util::destroy_range( _buffer.begin(), _buffer.end() ); + + _buffer.setSize( 0 ); + + AV_POSTCONDITION( _buffer.empty() ); + AV_POSTCONDITION( validateStorage() ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +void +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::mergeStorageWithErased() +{ + typename _Storage::iterator const end = _storage.end(); + + array::erase_removed( _storage, _erased ); + + util::destroy_range( _storage.end(), end ); + + _erased.setSize( 0 ); + + AV_POSTCONDITION( _erased.empty() ); + AV_POSTCONDITION( validateStorage() ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +template< + typename __ValueType +> +typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::_FindOrInsertToBufferResult +AssocVector< _Key, _Mapped, _Cmp, _Allocator >::findOrInsertToBuffer( __ValueType && value ) +{ + typename _Storage::iterator const greaterEqualInBuffer + = std::lower_bound( _buffer.begin(), _buffer.end(), value.first, value_comp() ); + + if( greaterEqualInBuffer != _buffer.end() ) + { + bool const isEqual = _cmp( value.first, greaterEqualInBuffer->first ) == false; + + if( isEqual ) + { + _FindOrInsertToBufferResult result; + result._inBuffer = greaterEqualInBuffer; + result._isInserted = false; + result._isReallocated = false; + + return result; + } + } + + if( _buffer.full() ) + { + _merge(); + + AV_CHECK( _buffer.empty() ); + + _buffer.insert( + _buffer.begin() + , value_type_mutable( std::forward< __ValueType >( value ) ) + ); + + _FindOrInsertToBufferResult result; + result._inBuffer = _buffer.begin(); + result._isInserted = true; + result._isReallocated = true; + + AV_POSTCONDITION( validate() ); + + return result; + } + else + { + _buffer.insert( + greaterEqualInBuffer + , value_type_mutable( std::forward< __ValueType >( value ) ) + ); + + _FindOrInsertToBufferResult result; + result._inBuffer = greaterEqualInBuffer; + result._isInserted = true; + result._isReallocated = false; + + AV_POSTCONDITION( validate() ); + + return result; + } +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +std::size_t AssocVector< _Key, _Mapped, _Cmp, _Allocator >::calculateNewBufferCapacity( + std::size_t storageSize +) +{ + return static_cast< std::size_t >( 1.0 * sqrt( storageSize )); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +std::size_t AssocVector< _Key, _Mapped, _Cmp, _Allocator >::calculateNewErasedCapacity( + std::size_t storageSize +) +{ + return calculateNewBufferCapacity( storageSize ); +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +std::size_t AssocVector< _Key, _Mapped, _Cmp, _Allocator >::calculateNewStorageCapacity( + std::size_t storageSize +) +{ + if( storageSize == 0 ){ + return 1; + } + else if( storageSize == 1 ){ + // size=1 size=2 + // capacity=1 capacity=2 + // S:[a] S:[ab] + // B:[b] -> reserve -> B:[ ] + // E:[ ] E:[ ] + + return 4; + } + else{ + return 2 * storageSize; + } +} + +template< + typename _Key + , typename _Mapped + , typename _Cmp + , typename _Allocator +> +void AssocVector< _Key, _Mapped, _Cmp, _Allocator >::dump( int width )const +{ + std::cout << "storage: "; + for( unsigned i = 0 ; i < _storage.size() ; ++ i ) + { + if( i > 0 && width > 0 && ( i % width == 0 ) ){ + std::cout << "\n "; + } + + std::cout << " (" << _storage[i].first << "," << _storage[i].second << ")"; + } + + std::cout << std::endl << "buffer: "; + for( unsigned i = 0 ; i < _buffer.size() ; ++ i ) + { + if( i > 0 && width > 0 && ( i % width == 0 ) ){ + std::cout << "\n "; + } + + std::cout << " (" << _buffer[i].first << "," << _buffer[i].second << ")"; + } + + std::cout << std::endl << "erased: "; + for( unsigned i = 0 ; i < _erased.size() ; ++ i ) + { + if( i > 0 && width > 0 && ( i % width == 0 ) ){ + std::cout << "\n "; + } + + std::cout << " (" << (*_erased[i]).first << "," << (*_erased[i]).second << ")"; + } + + std::cout << "." << std::endl; +} + +#endif diff --git a/external/flat b/external/flat new file mode 160000 index 000000000..2e8d469f7 --- /dev/null +++ b/external/flat @@ -0,0 +1 @@ +Subproject commit 2e8d469f7933cd640c64c6d8e8ba98f6ed9f2efc diff --git a/include/node.h b/include/node.h index 79dfe271f..dba34e5cf 100644 --- a/include/node.h +++ b/include/node.h @@ -319,11 +319,10 @@ class Node : public NodeBase { //! Status bool status_{false}; //! Scalar properties - tsl::ordered_map> + fc::vector_map> scalar_properties_; //! Vector properties - tsl::ordered_map> + fc::vector_map> vector_properties_; //! Displacement Eigen::Matrix contact_displacement_; diff --git a/include/node_base.h b/include/node_base.h index 018dc31fc..8cacffd2e 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -1,15 +1,21 @@ #ifndef MPM_NODE_BASE_H_ #define MPM_NODE_BASE_H_ +#include + #include +#include #include #include #include #include +#include +#include #include #include #include +#include #include #include "data_types.h" diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index fb119bc2a..9eb0dc6e2 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -343,9 +343,9 @@ class ParticleBase { //! Shape functions Eigen::VectorXd shapefn_; //! Scalar properties - tsl::ordered_map scalar_properties_; + fc::vector_map scalar_properties_; //! Vector properties - tsl::ordered_map> + fc::vector_map> vector_properties_; }; // ParticleBase class } // namespace mpm From 86341a6a612843ec242b1a9dc0b708d0e7c401c8 Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Mon, 20 Jul 2020 16:53:38 -0500 Subject: [PATCH 043/175] :fire: Remove unnecessary files --- CMakeLists.txt | 4 +- external/assoc_vector.h | 4955 --------------------------------------- 2 files changed, 2 insertions(+), 4957 deletions(-) delete mode 100644 external/assoc_vector.h diff --git a/CMakeLists.txt b/CMakeLists.txt index fc8e2accb..5fc7cfa1d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,9 +45,9 @@ option(HALO_EXCHANGE "Enable halo exchange" OFF) set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) # Boost Archive -find_package(Boost REQUIRED COMPONENTS container filesystem system) +find_package(Boost REQUIRED COMPONENTS filesystem system) include_directories(${BOOST_INCLUDE_DIRS}) -link_libraries(${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_CONTAINER_LIBRARY}) +link_libraries(${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY}) # Eigen find_package(Eigen3 REQUIRED) diff --git a/external/assoc_vector.h b/external/assoc_vector.h deleted file mode 100644 index 7a3ae766d..000000000 --- a/external/assoc_vector.h +++ /dev/null @@ -1,4955 +0,0 @@ -/* - * Copyright (C) 2012 £ukasz Czerwiñski - * - * GitHub: https://github.com/wo3kie/AssocVector - * Website: http://www.lukaszczerwinski.pl/assoc_vector.en.html - * - * Distributed under the BSD Software License (see file license) - */ - -#ifndef ASSOC_VECTOR_HPP -#define ASSOC_VECTOR_HPP - -#ifndef __GXX_EXPERIMENTAL_CXX0X__ - #error C++11 is required to run this code, please use AssocVector 1.0.x instead. -#endif - -// includes.begin - -#include -#include -#include -#include - -#include -#include - -// includes.end - -// configuration.begin - -#if ( __GNUC__ >= 4 && __GNUC_MINOR__ >= 8 ) - #define AV_HAS_TRIVIAL_DESTRUCTOR( type ) std::is_trivially_destructible< type >::value - #define AV_MOVE_IF_NOEXCEPT std::move_if_noexcept -#else - #define AV_HAS_TRIVIAL_DESTRUCTOR( type ) __has_trivial_destructor( type ) - #define AV_MOVE_IF_NOEXCEPT std::move -#endif - -// configuration.end - -#ifndef NDEBUG - #define AV_DEBUG -#endif - -#ifdef AV_DEBUG - #define AV_PRECONDITION( condition ) if( (bool)( condition ) == false ){int*i=0;*i=0;} - #define AV_CHECK( condition ) if( (bool)( condition ) == false ){int*i=0;*i=0;} - #define AV_POSTCONDITION( condition ) if( (bool)( condition ) == false ){int*i=0;*i=0;} - #define AV_ERROR() if( (true) ){int*i=0;*i=0;} -#else - #define AV_PRECONDITION( condition ) (void)( 0 ); - #define AV_CHECK( condition ) (void)( 0 ); - #define AV_POSTCONDITION( condition ) (void)( 0 ); - #define AV_ERROR() (void)( 0 ); -#endif - -namespace util -{ - // - // CmpByFirst - // - template< typename _Pair, typename _Cmp > - struct CmpByFirst - { - CmpByFirst( _Cmp const & cmp = _Cmp() ) - : _cmp( cmp ) - { - } - - bool operator()( _Pair const & lhs, _Pair const & rhs )const - { - return _cmp( lhs.first, rhs.first ); - } - - bool operator()( _Pair const & pair, typename _Pair::first_type const & value )const - { - return _cmp( pair.first, value ); - } - - bool operator()( typename _Pair::first_type const & value, _Pair const & pair )const - { - return _cmp( value, pair.first ); - } - - private: - _Cmp _cmp; - }; -} - -namespace util -{ - // - // equal - // - template< - typename _T1 - , typename _T2 - > - inline bool equal( - _T1 const & first - , _T2 const & second - ) - { - if( first < second ){ - return false; - } - - if( second < first ){ - return false; - } - - return true; - } - - // - // less_equal - // - template< - typename _T1 - , typename _T2 - > - inline bool less_equal( - _T1 const & first - , _T2 const & second - ) - { - return ( second < first ) == false; - } -} - -namespace util -{ - // - // is_between - // - template< - typename _T1 - , typename _T2 - > - inline bool is_between( - _T1 const & first - , _T2 const & value - , _T1 const & last - ) - { - AV_PRECONDITION( less_equal( first, last ) ); - - return ( value < first ) == false && ( last < value ) == false; - } -} - -namespace util -{ - // - // destroy_range - // - namespace detail - { - template< bool _HasTrivialDestructor > - struct DestroyRangeImpl - { - }; - - template<> - struct DestroyRangeImpl< true > - { - template< typename _Ptr > - static - void destroy( _Ptr, _Ptr ) - { - } - }; - - template<> - struct DestroyRangeImpl< false > - { - template< typename _Ptr > - static - void destroy( _Ptr first, _Ptr const last ) - { - AV_PRECONDITION( less_equal( first, last ) ); - - typedef typename std::iterator_traits< _Ptr >::value_type T; - - for( /*empty*/ ; first != last ; ++ first ){ - first -> T::~T(); - } - } - }; - } - - template< typename _Ptr > - inline void destroy_range( - _Ptr first - , _Ptr const last - ) - { - typedef typename std::iterator_traits< _Ptr >::value_type T; - - detail::DestroyRangeImpl< AV_HAS_TRIVIAL_DESTRUCTOR( T ) >::destroy( first, last ); - } -} - -namespace util -{ - // - // move - // - template< - typename _InputPtr - , typename _OutputPtr - > - inline void move( - _InputPtr first - , _InputPtr last - , _OutputPtr first2 - ) - { - if( first < first2 ){ - std::move_backward( first, last, first2 + ( last - first ) ); - } - else if( first > first2 ){ - std::move( first, last, first2 ); - } - else{ - // first == first2 -> do nothing - } - } - - template< - typename _InputPtr - , typename _OutputPtr - > - inline void copy( - _InputPtr first - , _InputPtr last - , _OutputPtr first2 - ) - { - if( first < first2 ){ - std::copy_backward( first, last, first2 + ( last - first ) ); - } - else if( first > first2 ){ - std::copy( first, last, first2 ); - } - else{ - // first == first2 -> do nothing - } - } - - - - namespace detail - { - - template< bool _MoveDoesNotThrow > - struct MoveIfNoExcept - { - }; - - template<> - struct MoveIfNoExcept< true > - { - template< - typename _InputPtr - , typename _OutputPtr - > - static - void move( _InputPtr first, _InputPtr const last, _OutputPtr first2 ) - { - move( first, last, first2 ); - } - }; - - template<> - struct MoveIfNoExcept< false > - { - template< - typename _InputPtr - , typename _OutputPtr - > - static - void move( _InputPtr first, _InputPtr const last, _OutputPtr first2 ) - { - copy( first, last, first2 ); - } - }; - } - - template< - typename _InputPtr - , typename _OutputPtr - > - inline void move_if_noexcept( - _InputPtr first - , _InputPtr const last - , _OutputPtr first2 - ) - { - typedef typename std::iterator_traits< _InputPtr >::value_type T; - - detail::MoveIfNoExcept< true >::move( first, last, first2 ); - } - -} - -namespace util -{ - -template< - typename _Iterator - , typename _T - , typename _Cmp -> -_Iterator -last_less_equal( - _Iterator first - , _Iterator last - , _T const & t - , _Cmp cmp -) -{ - AV_PRECONDITION( less_equal( first, last ) ); - - if( first == last ){ - return last; - } - - _Iterator greaterEqual = std::lower_bound( first, last, t, cmp ); - - if( greaterEqual != last ) - { - // lower_bound returns first greater_than/equal_to but we need last less_than - - bool const isEqual = cmp( t, * greaterEqual ) == false; - - if( isEqual ) - { - // that is OK, request item was found - return greaterEqual; - } - } - - if( greaterEqual == first ) - { - // requested item does not exist in container - - // 6 8 10 13 17 19 20 21 22 24 end - // ^ lower_bound( 1 ): - // requested: ^ - - return last; - } - else - { - // we need to go one item backward - - // 6 8 10 13 17 19 20 21 22 24 - // lower_bound( 23 ): ^ - // requested: ^ - - return -- greaterEqual; - } -} - -} - -namespace util -{ - -template< - typename _InputIterator1 - , typename _InputIterator2 - , typename _Cmp -> -bool has_intersection( - _InputIterator1 first1 - , _InputIterator1 const last1 - , _InputIterator2 first2 - , _InputIterator2 const last2 - , _Cmp const & cmp -) -{ - while( first1 != last1 && first2 != last2 ) - { - if( cmp( * first1, * first2 ) ){ - ++first1; - } - else if( cmp( * first2, * first1 ) ){ - ++first2; - } - else{ - return true; - } - } - - return false; -} - -} - -namespace array -{ - // - // I need much more control over Array inside AssocVector than std::vector offers - // - - // C' style array with some useful methods and functions - - // - // Array - // - template< - typename _T - , typename _Alloc = std::allocator< _T > - > - struct ArrayBase - { - struct ArrayImpl - : public _Alloc - { - ArrayImpl( _Alloc const & alloc = _Alloc() ) - : _Alloc( alloc ) - , _data( nullptr ) - , _capacity( 0 ) - , _size( 0 ) - { - } - - ArrayImpl( std::size_t capacity, _Alloc const & alloc = _Alloc() ) - : _Alloc( alloc ) - , _data( capacity ? this->allocate( capacity ) : nullptr ) - , _capacity( capacity ) - , _size( 0 ) - { - AV_PRECONDITION( _capacity < this->max_size() ); - } - - ~ArrayImpl() - { - util::destroy_range( _data, _data + _size ); - - this->deallocate( _data, _capacity ); - } - - void swap( ArrayImpl & other )noexcept - { - std::swap( _data, other._data ); - std::swap( _capacity, other._capacity ); - std::swap( _size, other._size ); - } - - public: - _T * _data; - - std::size_t _capacity; - std::size_t _size; - }; - - typedef _Alloc allocator_type; - - allocator_type - get_allocator() const { - return * static_cast< allocator_type const * >( & this->_impl ); - } - - public: - ArrayBase( _Alloc const & alloc = _Alloc() ) - : _impl( alloc ) - { - } - - ArrayBase( std::size_t capacity, _Alloc const & alloc = _Alloc() ) - : _impl( capacity, alloc ) - { - } - - ~ArrayBase() = default; - - ArrayBase( ArrayBase const & other ) = delete; - ArrayBase( ArrayBase && other ) = delete; - - ArrayBase & operator=( ArrayBase const & other ) = delete; - ArrayBase & operator=( ArrayBase && other ) = delete; - - protected: - ArrayImpl _impl; - }; - - template< - typename _T - , typename _Alloc = std::allocator< _T > - > - struct Array - : protected ArrayBase< _T, _Alloc > - { - private: - typedef ArrayBase< _T, _Alloc > Base; - - public: - using Base::get_allocator; - - public: - typedef _T value_type; - - typedef _T * iterator; - typedef _T const * const_iterator; - - public: - Array( _Alloc const & alloc = _Alloc() ) - : Base( alloc ) - { - } - - Array( std::size_t capacity, _Alloc const & alloc = _Alloc() ) - : Base( capacity, alloc ) - { - } - - Array( Array const & other ) - // In std::vector new vector's capacity is equal to old vector's size. - // Array's capacity is equal to old array's capacity to ensure invariant that: - // sqrt( storage.capacity ) == buffer.capacity - // sqrt( storage.capacity ) == erased.capacity - : Base( other.capacity(), other.get_allocator() ) - { - for( /*empty*/ ; this->_impl._size < other.size() ; ++ this->_impl._size ){ - get_allocator().construct( - this->_impl._data + this->_impl._size - , * ( other._impl._data + this->_impl._size ) - ); - } - } - - Array( Array && other ) - : Base( 0, other.get_allocator() ) - { - this->_impl.swap( other._impl ); - } - - ~Array() = default; - - Array & operator=( Array const & other ) - { - Array temp( other ); - - swap( temp ); - - return * this; - } - - Array & operator=( Array && other ) - { - this->_impl.swap( other._impl ); - - return * this; - } - - void swap( Array & other )noexcept - { - this->_impl.swap( other._impl ); - } - - void reserve( std::size_t capacity ) - { - if( get_allocator().max_size() < capacity ){ - throw std::length_error( "Array::reserve" ); - } - - if( capacity <= getCapacity() ){ - return; - } - - Array< _T, _Alloc > temp( capacity, get_allocator() ); - - std::uninitialized_copy( - std::make_move_iterator( begin() ) - , std::make_move_iterator( end() ) - , temp.begin() - ); - - swap( temp ); - } - - iterator begin()noexcept - { - return getData(); - } - - const_iterator begin()const noexcept - { - return getData(); - } - - const_iterator cbegin()const noexcept - { - return getData(); - } - - iterator end()noexcept - { - return getData() + getSize(); - } - - const_iterator end()const noexcept - { - return getData() + getSize(); - } - - const_iterator cend()const noexcept - { - return getData() + getSize(); - } - - bool empty()const noexcept - { - return getSize() == 0; - } - - bool full()const noexcept - { - return size() == capacity(); - } - - std::size_t size()const noexcept - { - return this->_impl._size; - } - - std::size_t getSize()const noexcept - { - return size(); - } - - void setSize( std::size_t newSize ) noexcept - { - AV_PRECONDITION( getData() != 0 || newSize == 0 ); - - this->_impl._size = newSize; - } - - std::size_t capacity()const noexcept - { - return this->_impl._capacity; - } - - std::size_t getCapacity()const noexcept - { - return capacity(); - } - - value_type & front() noexcept - { - AV_PRECONDITION( getData() != 0 ); - AV_PRECONDITION( empty() == false ); - - return getData()[ 0 ]; - } - - value_type const & front()const noexcept - { - AV_PRECONDITION( getData() != 0 ); - AV_PRECONDITION( empty() == false ); - - return getData()[ 0 ]; - } - - value_type & back() noexcept - { - AV_PRECONDITION( getData() != 0 ); - AV_PRECONDITION( empty() == false ); - - return getData()[ getSize() - 1 ]; - } - - value_type const & back()const noexcept - { - AV_PRECONDITION( getData() != 0 ); - AV_PRECONDITION( empty() == false ); - - return getData()[ getSize() - 1 ]; - } - - _T const * data()const noexcept - { - return this->_impl._data; - } - - _T const * getData()const noexcept - { - return data(); - } - - _T * data() noexcept - { - return this->_impl._data; - } - - _T * getData() noexcept - { - return data(); - } - - value_type & operator[]( std::size_t index ) noexcept - { - AV_PRECONDITION( getData() != 0 ); - AV_PRECONDITION( index < size() ); - - return getData()[ index ]; - } - - value_type const & operator[]( std::size_t index )const noexcept - { - AV_PRECONDITION( getData() != 0 ); - AV_PRECONDITION( index < size() ); - - return getData()[ index ]; - } - - template< typename _T2 > - void - insert( - typename Array< _T >::iterator const pos - , _T2 && t - ) - { - AV_PRECONDITION( util::less_equal( size() + 1, capacity() ) ); - AV_PRECONDITION( util::is_between( begin(), pos, end() ) ); - - iterator const oldEnd = end(); - - get_allocator().construct( end() ); - setSize( getSize() + 1 ); - - if( pos != oldEnd ) - { - util::move( pos, oldEnd, pos + 1 ); - } - - * pos = AV_MOVE_IF_NOEXCEPT( t ); - } - - // Array::push_back is not implemented to ensure invariant that: - // sqrt( storage.capacity ) == buffer.capacity - // sqrt( storage.capacity ) == erased.capacity - template< typename __T2 > - void place_back( __T2 && value ) - { - AV_CHECK( getData() ); - AV_CHECK( capacity() > 0 ); - AV_CHECK( getSize() < capacity() ); - - get_allocator().construct( end(), std::forward< __T2 >( value ) ); - setSize( getSize() + 1 ); - } - - void - erase( typename Array< _T >::iterator pos ) - { - AV_PRECONDITION( empty() == false ); - AV_PRECONDITION( util::less_equal( begin(), pos ) ); - AV_PRECONDITION( pos < end() ); - - util::move( pos + 1, end(), pos ); - get_allocator().destroy( end() - 1 ); - setSize( getSize() - 1 ); - } - - private: - void setCapacity( std::size_t newCapacity ) noexcept - { - AV_PRECONDITION( getData() != 0 || newCapacity == 0 ); - - this->_impl._capacity = newCapacity; - } - - void setData( _T * t ) noexcept - { - this->_impl._data = t; - } - }; -} - -namespace array -{ - template< - typename _Iterator - , typename _T - , typename _Cmp - > - _Iterator - binary_search( - _Iterator first - , _Iterator last - , _T const & t - , _Cmp cmp - ) - { - AV_PRECONDITION( util::less_equal( first, last ) ); - - _Iterator const greaterEqual = std::lower_bound( first, last, t, cmp ); - - if( greaterEqual == last ){ - return last; - } - - bool const isEqual = cmp( t, * greaterEqual ) == false; - - if( isEqual ){ - return greaterEqual; - } - - return last; - } - - template< - typename _T - , typename _T2 - , typename _Cmp - > - std::pair< typename Array< _T >::iterator, bool > - insert_in_sorted( - Array< _T > & array - , _T2 && t - , _Cmp cmp - ) - { - AV_PRECONDITION( util::less_equal( array.size() + 1, array.capacity() ) ); - - typename Array< _T >::iterator const greaterEqual - = std::lower_bound( array.begin(), array.end(), t, cmp ); - - if( greaterEqual != array.end() ) - { - bool const isEqual = cmp( t, * greaterEqual ) == false; - - if( isEqual ){ - return std::make_pair( greaterEqual, false ); - } - } - - array.insert( greaterEqual, std::forward< _T2 >( t ) ); - - return std::make_pair( greaterEqual, true ); - } - - template< typename _T > - void - erase_removed( - array::Array< _T > & storage - , array::Array< typename array::Array< _T >::const_iterator > const & erased - ) - { - AV_PRECONDITION( util::less_equal( erased.size(), storage.size() ) ); - - if( erased.empty() ){ - return; - } - - typedef typename array::Array< _T >::const_iterator StorageConstIterator; - typedef typename array::Array< _T >::iterator StorageIterator; - typedef typename array::Array< StorageConstIterator >::const_iterator ErasedConstIterator; - - StorageIterator currentInStorage = const_cast< StorageIterator >( erased.front() ); - AV_CHECK( util::is_between( storage.begin(), currentInStorage, storage.end() ) ); - - StorageIterator const endInStorage = storage.end(); - - StorageIterator whereInsertInStorage = const_cast< StorageIterator >( erased.front() ); - AV_CHECK( util::is_between( storage.begin(), whereInsertInStorage, storage.end() ) ); - - ErasedConstIterator currentInErased = erased.begin(); - ErasedConstIterator const endInErased = erased.end(); - - while( currentInStorage != endInStorage ) - { - AV_CHECK( util::is_between( storage.begin(), whereInsertInStorage, storage.end() ) ); - - if( - currentInErased != endInErased - && currentInStorage == ( * currentInErased ) - ) - { - ++ currentInStorage; - ++ currentInErased; - } - else - { - ( * whereInsertInStorage ) = AV_MOVE_IF_NOEXCEPT( * currentInStorage ); - - ++ whereInsertInStorage; - ++ currentInStorage; - } - } - - AV_POSTCONDITION( currentInErased == endInErased ); - - storage.setSize( storage.size() - erased.size() ); - } - - template< - typename _T - , typename _Cmp - > - void - move_merge( - array::Array< _T > & storage - , array::Array< _T > & buffer - , _Cmp const & cmp = _Cmp() - ) - { - AV_PRECONDITION( util::less_equal( storage.size() + buffer.size(), storage.capacity() ) ); - - typedef typename array::Array< _T >::iterator Iterator; - - Iterator rWhereInsertInStorage = storage.begin() + storage.size() + buffer.size() - 1; - - Iterator rCurrentInStorage = storage.begin() + storage.size() - 1; - Iterator const rEndInStorage = storage.begin() - 1; - - Iterator rCurrentInBuffer = buffer.begin() + buffer.size() - 1; - Iterator const rEndInBuffer = buffer.begin() - 1; - - std::size_t numberOfItemsToCreateByPlacementNew = buffer.size(); - - while( - rCurrentInBuffer != rEndInBuffer - && numberOfItemsToCreateByPlacementNew != 0 - ) - { - AV_CHECK( rWhereInsertInStorage != 0 ); - AV_CHECK( rCurrentInStorage != 0 ); - AV_CHECK( rCurrentInBuffer != 0 ); - - if( - rCurrentInStorage == rEndInStorage - || cmp( * rCurrentInStorage, * rCurrentInBuffer ) - ) - { - new ( static_cast< void * >( rWhereInsertInStorage ) ) - _T( AV_MOVE_IF_NOEXCEPT( * rCurrentInBuffer ) ); - - -- rCurrentInBuffer; - } - else - { - new ( static_cast< void * >( rWhereInsertInStorage ) ) - _T( AV_MOVE_IF_NOEXCEPT( * rCurrentInStorage ) ); - - -- rCurrentInStorage; - } - - -- numberOfItemsToCreateByPlacementNew; - -- rWhereInsertInStorage; - } - - AV_CHECK( numberOfItemsToCreateByPlacementNew == 0 ); - - while( rCurrentInBuffer != rEndInBuffer ) - { - AV_CHECK( rWhereInsertInStorage != 0 ); - AV_CHECK( rCurrentInStorage != 0 ); - AV_CHECK( rCurrentInBuffer != 0 ); - - if( - rCurrentInStorage == rEndInStorage - || cmp( * rCurrentInStorage, * rCurrentInBuffer ) - ) - { - * rWhereInsertInStorage = AV_MOVE_IF_NOEXCEPT( * rCurrentInBuffer ); - - -- rCurrentInBuffer; - } - else - { - * rWhereInsertInStorage = AV_MOVE_IF_NOEXCEPT( * rCurrentInStorage ); - - -- rCurrentInStorage; - } - - -- rWhereInsertInStorage; - } - - storage.setSize( storage.size() + buffer.size() ); - } -} - -namespace util -{ - -template< - typename _InputPtr1 - , typename _InputPtr2 - , typename _OutputPtr - , typename _Cmp -> -_OutputPtr -move_merge_into_uninitialized( - _InputPtr1 first1 - , _InputPtr1 last1 - , _InputPtr2 first2 - , _InputPtr2 last2 - , _OutputPtr output - , _Cmp cmp = _Cmp() -) -{ - AV_PRECONDITION( util::less_equal( first1, last1 ) ); - AV_PRECONDITION( util::less_equal( first2, last2 ) ); - - while( first1 != last1 && first2 != last2 ) - { - AV_CHECK( first1 != 0 ); - AV_CHECK( first2 != 0 ); - AV_CHECK( output != 0 ); - - if( cmp( * first1, * first2 ) ) - { - new ( static_cast< void * >( output ) ) - typename std::iterator_traits< _OutputPtr >::value_type( std::move( * first1 ) ); - - ++ output; - ++ first1; - } - else - { - new ( static_cast< void * >( output ) ) - typename std::iterator_traits< _OutputPtr >::value_type( std::move( * first2 ) ); - - ++ output; - ++ first2; - } - } - - if( first1 == last1 ){ - return std::uninitialized_copy( - std::make_move_iterator( first2 ) - , std::make_move_iterator( last2 ) - , output - ); - } - - if( first2 == last2 ){ - return std::uninitialized_copy( - std::make_move_iterator( first1 ) - , std::make_move_iterator( last1 ) - , output - ); - } - - return output; -} - -} - -namespace detail -{ - template< typename _Iterator > - bool equal( _Iterator const & lhs, _Iterator const & rhs ) - { - if( lhs.getContainer() != rhs.getContainer() ){ - return false; - } - - // for empty container returns that begin == end - // despite on fact they are not - if( lhs.getContainer()->empty() ){ - return true; - } - - return lhs.getCurrent() == rhs.getCurrent(); - } - - // - // AssocVectorLazyIterator - // - - template< - typename _Iterator - , typename _Container - > - struct AssocVectorLazyIterator - { - public: - typedef typename std::iterator_traits< _Iterator >::pointer pointer_mutable; - - public: - typedef std::bidirectional_iterator_tag iterator_category; - typedef typename std::iterator_traits< _Iterator >::value_type value_type; - typedef typename std::iterator_traits< _Iterator >::difference_type difference_type; - - // make key const - typedef std::pair< - typename value_type::first_type const - , typename value_type::second_type - > & reference; - - // make key const - typedef std::pair< - typename value_type::first_type const - , typename value_type::second_type - > * pointer; - - private: - struct _CurrentInErased - { - _CurrentInErased( typename _Container::_Erased::const_iterator current ) - : _current( current ) - { - } - - _CurrentInErased( _CurrentInErased const & other ) - : _current( other._current ) - { - } - - _CurrentInErased & operator=( _CurrentInErased const & other ) - { - _current = other._current; - - return * this; - } - - _CurrentInErased & operator=( typename _Container::_Erased::const_iterator current ) - { - _current = current; - - return * this; - } - - bool is_end( _Container const * container )const - { - return _current == container->erased().end(); - } - - bool is_not_end( _Container const * container )const - { - return ! is_end( container ); - } - - bool is_begin( _Container const * container )const - { - return _current == container->erased().begin(); - } - - bool is_not_begin( _Container const * container )const - { - return ! is_begin( container ); - } - - void increment( _Container const * container ) - { - AV_PRECONDITION( is_not_end( container ) ); - - ++ _current; - } - - void try_increment( _Container const * container ) - { - if( is_end( container ) ){ - return; - } - - increment( container ); - } - - void decrement( _Container const * container ) - { - AV_PRECONDITION( is_not_begin( container ) ); - - -- _current; - } - - void try_decrement( _Container const * container ) - { - if( is_begin( container ) ){ - return; - } - - decrement( container ); - } - - bool validate( _Container const * container )const - { - bool const result - = util::is_between( - container->erased().begin() - , _current - , container->erased().end() - ); - - if( result ){ - return true; - } - - AV_ERROR(); - - return false; - } - - typename _Container::_Erased::value_type const & - get( _Container const * container )const noexcept - { - AV_PRECONDITION( _current ); - AV_PRECONDITION( is_not_end( container ) ); - AV_PRECONDITION( validate( container ) ); - - return * _current; - } - - typename _Container::_Erased::const_iterator data()const noexcept - { - return _current; - } - - operator bool()const noexcept - { - return _current != 0; - } - - private: - typename _Container::_Erased::const_iterator _current; - }; - - struct _CurrentInBuffer - { - _CurrentInBuffer( pointer_mutable current ) - : _current( current ) - { - } - - _CurrentInBuffer( _CurrentInBuffer const & other ) - : _current( other._current ) - { - } - - _CurrentInBuffer & operator=( _CurrentInBuffer const & other ) - { - _current = other._current; - - return * this; - } - - _CurrentInBuffer & operator=( pointer_mutable current ) - { - _current = current; - - return * this; - } - - bool is_begin( _Container const * container )const - { - return _current == container->buffer().begin(); - } - - bool is_not_begin( _Container const * container )const - { - return ! is_begin( container ); - } - - bool is_end( _Container const * container )const - { - return _current == container->buffer().end(); - } - - bool is_not_end( _Container const * container )const - { - return ! is_end( container ); - } - - void increment( _Container const * container ) - { - AV_PRECONDITION( is_not_end( container ) ); - - ++ _current; - } - - void try_increment( _Container const * container ) - { - if( is_end( container ) ){ - return; - } - - increment( container ); - } - - void decrement( _Container const * container ) - { - AV_PRECONDITION( is_not_begin( container ) ); - - -- _current; - } - - void try_decrement( _Container const * container ) - { - if( is_begin( container ) ){ - return; - } - - decrement( container ); - } - - bool validate( _Container const * container )const - { - bool const result - = util::is_between( - container->buffer().begin() - , _current - , container->buffer().end() - ); - - if( result ){ - return true; - } - - AV_ERROR(); - - return false; - } - - typename _Container::_Storage::value_type const & - get( _Container const * container )const noexcept - { - AV_PRECONDITION( _current ); - AV_PRECONDITION( is_not_end( container ) ); - AV_PRECONDITION( validate( container ) ); - - return * _current; - } - - operator bool()const noexcept - { - return _current != 0; - } - - pointer_mutable data()const noexcept - { - return _current; - } - private: - pointer_mutable _current; - }; - - struct _CurrentInStorage - { - // begin is always set at first not erased item, marked with ^ - // end is always set at the end of container, marked with $ - - // Case 1: no item erased - // storage: ^1 3 5 7$ - // erased : - - // Case 2: item erased from front - // storage: 1 ^3 5 7$ - // erased : 1 - - // Case 3: item erased from back - // storage: ^1 3 5 7$ - // erased : 7 - - // Case 4: item erased from front and back - // storage: 1 ^3 5 7$ - // erased : 1 7 - - _CurrentInStorage( pointer_mutable current ) - : _dir( 1 ) - , _current( current ) - { - } - - _CurrentInStorage( _CurrentInStorage const & other ) - : _dir( other._dir ) - , _current( other._current ) - { - } - - _CurrentInStorage & operator=( _CurrentInStorage const & other ) - { - _dir = other._dir; - _current = other._current; - - return * this; - } - - bool operator==( _CurrentInStorage const & other )const - { - return _current == other._current; - } - - bool operator!=( _CurrentInStorage const & other )const - { - return _current != other._current; - } - - bool operator==( typename _Container::_Erased::value_type inErased )const - { - return _current == inErased; - } - - bool operator!=( typename _Container::_Erased::value_type inErased )const - { - return _current != inErased; - } - - bool is_begin( _Container const * container )const - { - _CurrentInStorage currentInStorage = const_cast< pointer_mutable >( container->storage().begin() ); - _CurrentInErased currentInErased = container->erased().begin(); - - currentInStorage.setOnNotErased( currentInErased, container ); - - return data() == currentInStorage.data(); - } - - bool is_not_begin( _Container const * container )const - { - return ! is_begin( container ); - } - - bool _is_begin( _Container const * container )const - { - return _current == container->storage().begin(); - } - - bool _is_not_begin( _Container const * container )const - { - return ! _is_begin( container ); - } - - bool is_end( _Container const * container )const - { - return _current == container->storage().end(); - } - - bool is_not_end( _Container const * container )const - { - return ! is_end( container ); - } - - void - increment( - _CurrentInErased & currentInErased - , _Container const * container - ) - { - AV_PRECONDITION( is_not_end( container ) ); - - increment( container ); - - if( _dir == -1 ) - { - _dir = 1; - currentInErased.try_increment( container ); - } - - setOnNotErased( currentInErased, container ); - } - - void - try_increment( - _CurrentInErased & currentInErased - , _Container const * container - ) - { - if( is_end( container ) ){ - return; - } - - increment( currentInErased, container ); - } - - void - decrement( - _CurrentInErased & currentInErased - , _Container const * container - ) - { - AV_PRECONDITION( is_not_begin( container ) ); - - decrement( container ); - - if( _dir == 1 ) - { - _dir = -1; - currentInErased.try_decrement( container ); - } - - setOnNotErasedBackward( currentInErased, container ); - } - - void - try_decrement( - _CurrentInErased & currentInErased - , _Container const * container - ) - { - if( _is_begin( container ) ){ - return; - } - - decrement( currentInErased, container ); - } - - void - setOnNotErased( - _CurrentInErased & currentInErased - , _Container const * container - ) - { - if( is_end( container ) ) - { - if( !currentInErased ) - { - currentInErased = container->erased().end(); - } - - return; - } - - if( !currentInErased ) - { - currentInErased = std::lower_bound( - container->erased().begin() - , container->erased().end() - , data() - , std::less< typename _Container::_Storage::const_iterator >() - ); - } - - if( _dir == -1 ) - { - _dir = 1; - currentInErased.try_increment( container ); - } - - while( - is_not_end( container ) - && currentInErased.is_not_end( container ) - && data() == currentInErased.get( container ) - ) - { - increment( container ); - currentInErased.increment( container ); - } - - AV_POSTCONDITION( currentInErased ); - - AV_POSTCONDITION( - ( - is_end( container ) - && currentInErased.is_end( container ) - ) - || currentInErased.is_end( container ) - || *this != currentInErased.get( container ) - ); - } - - void - setOnNotErasedBackward( - _CurrentInErased & currentInErased - , _Container const * container - ) - { - AV_CHECK( is_not_end( container ) ); - - if( _dir == 1 ) - { - _dir = -1; - currentInErased.try_decrement( container ); - } - - while( - is_not_begin( container ) - && currentInErased.is_not_end( container ) - && data() == currentInErased.get( container ) - ) - { - decrement( container ); - currentInErased.try_decrement( container ); - } - - AV_POSTCONDITION( validate( container ) ); - - AV_POSTCONDITION( - currentInErased.is_end( container ) - || *this != currentInErased.get( container ) - ); - } - - operator bool()const noexcept - { - return _current != 0; - } - - bool validate( _Container const * container )const - { - bool const result = util::is_between( - container->storage().begin() - , _current - , container->storage().end() - ); - - if( result ){ - return true; - } - - AV_ERROR(); - - return false; - } - - typename _Container::_Storage::value_type const & - get( _Container const * container )const noexcept - { - AV_PRECONDITION( _current ); - AV_PRECONDITION( is_not_end( container ) ); - - return * _current; - } - - pointer_mutable data()const noexcept - { - return _current; - } - - private: - void increment( _Container const * container ) - { - AV_PRECONDITION( is_not_end( container ) ); - - ++ _current; - } - - void decrement( _Container const * container ) - { - AV_PRECONDITION( is_not_begin( container ) ); - - -- _current; - } - - private: - int _dir; - - pointer_mutable _current; - }; - - struct _Current - { - _Current( pointer_mutable current ) - : _current( current ) - { - } - - _Current( _CurrentInStorage const & inStorage ) - : _current( inStorage.data() ) - { - } - - _Current( _CurrentInBuffer const & inBuffer ) - : _current( inBuffer.data() ) - { - } - - _Current & operator=( _Current const & other ) - { - _current = other._current; - - return * this; - } - - _Current & operator=( _CurrentInStorage const & inStorage ) - { - _current = inStorage.data(); - - return * this; - } - - _Current & operator=( _CurrentInBuffer const & inBuffer ) - { - _current = inBuffer.data(); - - return * this; - } - - bool operator==( _Current const & other )const - { - return _current == other._current; - } - - bool operator==( _CurrentInStorage const & inStorage )const - { - return _current == inStorage.data(); - } - - bool operator==( _CurrentInBuffer const & inBuffer )const - { - return _current == inBuffer.data(); - } - - bool validate( - _CurrentInStorage currentInStorage - , _CurrentInBuffer currentInBuffer - , _Container const * container - )const - { - AV_PRECONDITION( currentInStorage || currentInBuffer ); - AV_PRECONDITION( container != 0 ); - - if( !currentInStorage ) - { - if( _current == currentInBuffer.data() ){ - return true; - } - - AV_ERROR(); - - return false; - } - - if( !currentInBuffer ) - { - if( _current == currentInStorage.data() ){ - return true; - } - - AV_ERROR(); - - return false; - } - - // if 'setLower' does not work 'validateCurrent' does not work as well :O( - bool const result - = _current == getLower( currentInStorage, currentInBuffer, container ).data(); - - if( result ){ - return true; - } - - AV_ERROR(); - - return false; - } - - void setLower( - _CurrentInStorage currentInStorage - , _CurrentInBuffer currentInBuffer - , _Container const * container - ) - { - _current = getLower( currentInStorage, currentInBuffer, container ).data(); - } - - _Current getLower( - _CurrentInStorage currentInStorage - , _CurrentInBuffer currentInBuffer - , _Container const * container - )const - { - AV_CHECK( currentInStorage ); - AV_CHECK( currentInBuffer ); - - if( currentInStorage.is_end( container ) ) - { - if( currentInBuffer.is_end( container ) ){ - return _Current( 0 ); - } - else{ - return _Current( currentInBuffer ); - } - } - else - { - if( currentInBuffer.is_end( container ) ){ - return _Current( currentInStorage ); - } - else - { - if( container->value_comp()( - currentInStorage.get( container ) - , currentInBuffer.get( container ) - ) - ){ - return _Current( currentInStorage ); - } - else{ - return _Current( currentInBuffer ); - } - } - } - } - - operator bool()const noexcept - { - return _current != 0; - } - - typename _Container::_Storage::value_type const & - get( _Container const * container )const noexcept - { - return * _current; - } - - pointer_mutable data()const noexcept - { - return _current; - } - - private: - pointer_mutable _current; - }; - - public: - AssocVectorLazyIterator( - typename _Container::value_compare const & cmp = typename _Container::value_compare() - ) - : _container( 0 ) - - , _currentInStorage( 0 ) - , _currentInBuffer( 0 ) - , _currentInErased( 0 ) - - , _current( 0 ) - { - } - - template< typename _Iter > - AssocVectorLazyIterator( AssocVectorLazyIterator< _Iter, _Container > const & other ) - : _container( other.getContainer() ) - - , _currentInStorage( other.getCurrentInStorage() ) - , _currentInBuffer( other.getCurrentInBuffer() ) - , _currentInErased( other.getCurrentInErased() ) - - , _current( other.getCurrent() ) - { - } - - AssocVectorLazyIterator( - _Container const * container - , pointer_mutable currentInStorage - , pointer_mutable currentInBuffer - , typename _Container::_Erased::const_iterator currentInErased - , pointer_mutable current - ) - : _container( container ) - - , _currentInStorage( currentInStorage ) - , _currentInBuffer( currentInBuffer ) - , _currentInErased( currentInErased ) - - , _current( current ) - { - AV_PRECONDITION( container != 0 ); - AV_PRECONDITION( validate() ); - - if( _currentInStorage && _currentInBuffer && !_currentInErased && !_current ) - { - // not found in storage, insert to buffer - // erase from buffer + find in storage - // lower_bound - // upper_bound - - // _currentInStorage <- fix against '!_currentInErased' - _currentInStorage.setOnNotErased( _currentInErased, _container ); - - // _current <- get it right now - _current.setLower( _currentInStorage, _currentInBuffer, _container ); - } - else - if( _currentInStorage && _currentInBuffer && !_currentInErased && _current ) - { - // not found in storage, found in buffer - // not found in storage, inserted to buffer - // erased from storage's back - - // _currentInStorage <- fix against '!_currentInErased' - _currentInStorage.setOnNotErased( _currentInErased, _container ); - } - else - if( _currentInStorage && _currentInBuffer && _currentInErased && !_current ) - { - // begin iterator - // end iterator - // erase from storage, not merged + find in buffer - // erase from storage, merged + find in buffer + find in storage - - // _currentInStorage <- check against _currentInErased - _currentInStorage.setOnNotErased( _currentInErased, _container ); - - // _current <- get it right now - _current.setLower( _currentInStorage, _currentInBuffer, _container ); - } - else - if( ! _currentInStorage && ! _currentInBuffer && ! _currentInErased && !_current ) - { - // begin iterator on empty AssocVector - // end iterator on empty AssocVector - - // return, do not make validation - return; - } - - AV_POSTCONDITION( _current.validate( _currentInStorage, _currentInBuffer, _container ) ); - AV_POSTCONDITION( _currentInStorage || _currentInBuffer ); - AV_POSTCONDITION( _currentInErased ); - AV_POSTCONDITION( _container != 0 ); - } - - AssocVectorLazyIterator & - operator=( AssocVectorLazyIterator const & other ) - { - _container = other._container; - - _currentInStorage = other._currentInStorage; - _currentInBuffer = other._currentInBuffer; - _currentInErased = other._currentInErased; - - _current = other._current; - - return * this; - } - - bool operator==( AssocVectorLazyIterator const & other )const - { - this->resolveLazyValues(); - other.resolveLazyValues(); - - if( isEmpty() && other.isEmpty() ){ - return getContainer() == other.getContainer(); - } - - AV_PRECONDITION( _current.validate( _currentInStorage, _currentInBuffer, _container ) ); - - return equal( *this, other ); - } - - bool operator!=( AssocVectorLazyIterator const & other )const - { - this->resolveLazyValues(); - other.resolveLazyValues(); - - return ! ( ( * this ) == other ); - } - - AssocVectorLazyIterator & operator++() - { - AV_PRECONDITION( isEmpty() == false ); - - resolveLazyValues(); - - AV_PRECONDITION( _current.validate( _currentInStorage, _currentInBuffer, _container ) ); - - if( _current == _Current( 0 ) ){ - return * this; - } - else if( _current == _currentInStorage ){ - _currentInStorage.try_increment( _currentInErased, _container ); - } - else if( _current == _currentInBuffer ){ - _currentInBuffer.try_increment( _container ); - } - else{ - AV_ERROR(); - } - - _current.setLower( _currentInStorage, _currentInBuffer, _container ); - - AV_POSTCONDITION( _current.validate( _currentInStorage, _currentInBuffer, _container ) ); - - return * this; - } - - AssocVectorLazyIterator operator++( int ) - { - AssocVectorLazyIterator result( * this ); - - ( * this ).operator++(); - - return result; - } - - AssocVectorLazyIterator & operator--() - { - AV_PRECONDITION( isEmpty() == false ); - - resolveLazyValues(); - - AV_PRECONDITION( _current.validate( _currentInStorage, _currentInBuffer, _container ) ); - - if( - _currentInStorage.is_begin( _container ) - && _currentInBuffer.is_begin( _container ) - ) - { - AV_POSTCONDITION( _current.validate( _currentInStorage, _currentInBuffer, _container ) ); - - return * this; - } - - if( _currentInStorage.is_begin( _container ) ) - { - _currentInBuffer.decrement( _container ); - - _current = _currentInBuffer; - - AV_POSTCONDITION( _current.validate( _currentInStorage, _currentInBuffer, _container ) ); - - return * this; - } - - if( _currentInBuffer.is_begin( _container ) ) - { - _currentInStorage.decrement( _currentInErased, _container ); - - _current = _currentInStorage; - - AV_POSTCONDITION( _current.validate( _currentInStorage, _currentInBuffer, _container ) ); - - return * this; - } - - _CurrentInStorage currentInStorage = _currentInStorage; - _CurrentInBuffer currentInBuffer = _currentInBuffer; - - _CurrentInErased currentInErased = _currentInErased; - - currentInStorage.decrement( currentInErased, _container ); - currentInBuffer.decrement( _container ); - - if( - _container->value_comp()( - currentInStorage.get( _container ) - , currentInBuffer.get( _container ) - ) - ) - { - _currentInBuffer = currentInBuffer; - - _current = _currentInBuffer; - } - else - { - _currentInStorage = currentInStorage; - _currentInErased = currentInErased; - - _current = _currentInStorage; - } - - AV_POSTCONDITION( _current.validate( _currentInStorage, _currentInBuffer, _container ) ); - - return * this; - } - - AssocVectorLazyIterator operator--( int ) - { - AssocVectorLazyIterator result( * this ); - - ( * this ).operator--(); - - return result; - } - - reference operator*()const - { - return * get(); - } - - pointer operator->()const - { - return get(); - } - - pointer get()const - { - AV_PRECONDITION( isEmpty() == false ); - AV_PRECONDITION( _current ); - AV_PRECONDITION( _current.validate( _currentInStorage, _currentInBuffer, _container ) ); - - // make key const - // pair< T1, T2 > * -> pair< T1 const, T2 > * - //return reinterpret_cast< pointer >( _current ); - - return - reinterpret_cast< pointer >( - const_cast< void * >( - reinterpret_cast< void const * >( _current.data() ) - ) - ); - } - - // public for copy constructor only : Iterator -> ConstIterator - _Container const * getContainer()const noexcept - { - return _container; - } - - pointer_mutable getCurrentInStorage()const noexcept - { - return _currentInStorage.data(); - } - - pointer_mutable getCurrentInBuffer()const noexcept - { - return _currentInBuffer.data(); - } - - typename _Container::_Erased::const_iterator getCurrentInErased()const noexcept - { - return _currentInErased.data(); - } - - pointer_mutable getCurrent()const noexcept - { - return _current.data(); - } - - private: - bool isEmpty()const - { - if( _currentInStorage ){ - return false; - } - if( _currentInBuffer ){ - return false; - } - if( _currentInErased ){ - return false; - } - if( _current ){ - return false; - } - - return true; - } - - /*const function*/ - static - void - resolveLazyCurrentInBuffer( - _CurrentInBuffer & currentInBuffer - , _Current const current - , _Container const * container - ) - { - if( currentInBuffer ){ - return; - } - - currentInBuffer = const_cast< pointer_mutable >( - std::lower_bound( - container->buffer().begin() - , container->buffer().end() - , current.get( container ) - , container->value_comp() - ) - ); - } - - static - void - resolveLazyCurrentInStorage( - _CurrentInStorage & currentInStorage - , _CurrentInErased & currentInErased - , _Current const current - , _Container const * container - ) - { - if( currentInStorage ){ - return; - } - - currentInStorage = const_cast< pointer_mutable >( - std::lower_bound( - container->storage().begin() - , container->storage().end() - , current.get( container ) - , container->value_comp() - ) - ); - - currentInStorage.setOnNotErased( currentInErased, container ); - } - - void - resolveLazyValues()const - { - resolveLazyCurrentInBuffer( _currentInBuffer, _current, _container ); - resolveLazyCurrentInStorage( _currentInStorage, _currentInErased, _current, _container ); - } - - /*pure function*/ - bool - validate()const - { - if( !_currentInStorage && _currentInBuffer && _currentInErased && _current ) - { - // not found in storage, inserted to buffer, buffer merged to storage - - AV_CHECK( _currentInBuffer.validate( _container ) ); - AV_CHECK( _currentInErased.is_end( _container ) ); - AV_CHECK( _current == _currentInBuffer ); - - // _currentInStorage <- lazy in operator++/operator--/operator==/operator!= - } - else - if( _currentInStorage && !_currentInBuffer && _currentInErased && !_current ) - { - AV_ERROR(); - - return false; - } - else - if( _currentInStorage && !_currentInBuffer && _currentInErased && _current ) - { - // found in storage, not found in erased - - AV_CHECK( _currentInStorage.validate( _container ) ); - AV_CHECK( - std::binary_search( - _container->erased().begin() - , _container->erased().end() - , _currentInStorage.data() - ) == false - ); - AV_CHECK( _currentInErased.validate( _container ) ); - AV_CHECK( _current == _currentInStorage ); - - // _currentInBuffer <- lazy in operator++/operator--/operator==/operator!= - } - else - if( _currentInStorage && _currentInBuffer && !_currentInErased && !_current ) - { - // not found in storage, insert to buffer - // erase from buffer + find in storage - // lower_bound - // upper_bound - - AV_CHECK( _currentInStorage.validate( _container ) ); - AV_CHECK( _currentInBuffer.validate( _container ) ); - - // _currentInStorage <- fix against '!_currentInErased' - // _current <- get it right now - } - else - if( _currentInStorage && _currentInBuffer && !_currentInErased && _current ) - { - // not found in storage, found in buffer - // not found in storage, inserted to buffer - // erased from storage's back - - AV_CHECK( _currentInStorage.validate( _container ) ); - AV_CHECK( _currentInBuffer.validate( _container ) ); - AV_CHECK( _current == _currentInBuffer ); - - // _currentInStorage <- fix against '!_currentInErased' - // _currentInErased <- get it right now - } - else - if( _currentInStorage && _currentInBuffer && _currentInErased && !_current ) - { - // begin iterator - // end iterator - // erase from storage, not merged + find in buffer - // erase from storage, merged + find in buffer + find in storage - - AV_CHECK( _currentInStorage.validate( _container ) ); - AV_CHECK( _currentInBuffer.validate( _container ) ); - AV_CHECK( _currentInErased.validate( _container ) ); - - // _currentInStorage <- check against _currentInErased - // _current <- get it right now - } - else - if( ! _currentInStorage && ! _currentInBuffer && ! _currentInErased && !_current ) - { - // begin iterator on empty AssocVector - // end iterator on empty AssocVector - } - else - { - AV_ERROR(); - - return false; - } - - return true; - } - - private: - _Container const * _container; - - // mutable since lazy values in operator==()const / operator!=()const - mutable _CurrentInStorage _currentInStorage; - mutable _CurrentInBuffer _currentInBuffer; - mutable _CurrentInErased _currentInErased; - - _Current _current; - }; - - template< - typename _Iterator - , typename _Container - > - std::ostream & - operator<<( - std::ostream & out - , AssocVectorLazyIterator< _Iterator, _Container > const & iter - ) - { - out << "S: " << iter.getCurrentInStorage(); - - if( iter.getCurrentInStorage() == 0 ){ - out << " (null)"; - } - else if( iter.getContainer()->storage().end() == iter.getCurrentInStorage() ){ - out << " (end)"; - } - else{ - out << " " << * iter.getCurrentInStorage(); - } - - out << "\nB: " << iter.getCurrentInBuffer(); - - if( iter.getCurrentInBuffer() == 0 ){ - out << " (null)"; - } - else if( iter.getContainer()->buffer().end() == iter.getCurrentInBuffer() ){ - out << " (end)"; - } - else{ - out << " " << * iter.getCurrentInBuffer(); - } - - out << "\nE: " << iter.getCurrentInErased(); - - if( iter.getCurrentInErased() == 0 ){ - out << " (null)"; - } - else if( iter.getContainer()->erased().end() == iter.getCurrentInErased() ){ - out << " (end)"; - } - else{ - AV_CHECK( * iter.getCurrentInErased() ); - - out << " " << * * iter.getCurrentInErased(); - } - - out << "\nC: " << iter.getCurrent(); - - if( iter.getCurrent() == 0 ){ - out << " (null)"; - } - else{ - out << " " << * iter.getCurrent(); - } - - std::flush( out ); - - return out; - } - - // - // _AssocVectorIterator, simplified version of AssocVectorLazyIterator, works with _find and _end - // - template< - typename _Iterator - , typename _Container - > - struct _AssocVectorIterator - { - private: - typedef typename std::iterator_traits< _Iterator >::pointer pointer_mutable; - - public: - typedef typename std::iterator_traits< _Iterator >::value_type value_type; - - // make key const - typedef std::pair< - typename value_type::first_type const - , typename value_type::second_type - > & reference; - - // make key const - typedef std::pair< - typename value_type::first_type const - , typename value_type::second_type - > * pointer; - - public: - _AssocVectorIterator( - typename _Container::value_compare const & cmp = typename _Container::value_compare() - ) - : _current( 0 ) - { - } - - template< typename _Iter > - _AssocVectorIterator( _AssocVectorIterator< _Iter, _Container > const & other ) - : _current( other.getCurrent() ) - { - } - - _AssocVectorIterator( pointer_mutable current ) - : _current( current ) - { - } - - _AssocVectorIterator & - operator=( _AssocVectorIterator const & other ) - { - _current = other._current; - - return * this; - } - - bool operator==( _AssocVectorIterator const & other )const - { - return _current == other.getCurrent(); - } - - bool operator!=( _AssocVectorIterator const & other )const - { - return ! ( ( * this ) == other ); - } - - reference operator*()const - { - AV_PRECONDITION( _current != 0 ); - - return * get(); - } - - pointer operator->()const - { - AV_PRECONDITION( _current != 0 ); - - return get(); - } - - pointer get()const - { - AV_PRECONDITION( _current != 0 ); - - // make key const - // pair< T1, T2 > * -> pair< T1 const, T2 > * - //return reinterpret_cast< pointer >( _current ); - - return - reinterpret_cast< pointer >( - const_cast< void * >( - reinterpret_cast< void const * >( _current ) - ) - ); - } - - operator bool()const noexcept - { - return _current != 0; - } - - // public for copy constructor only : Iterator -> ConstIterator - pointer_mutable getCurrent()const noexcept - { - return _current; - } - - private: - pointer_mutable _current; - }; - - template< - typename _Iterator - , typename _Container - > - std::ostream & operator<<( - std::ostream & out - , _AssocVectorIterator< _Iterator, _Container > const & iter - ) - { - out << "S: " << iter.getCurrent(); - - if( iter.getCurrent() == 0 ){ - out << " (null)(end)"; - } - else{ - out << " " << * iter.get(); - } - - return out; - } - -} // namespace detail - -template< - typename _Key - , typename _Mapped - , typename _Cmp = std::less< _Key > - , typename _Allocator = std::allocator< std::pair< _Key, _Mapped > > -> -struct AssocVector -{ -private: - typedef std::pair< _Key, _Mapped > value_type_mutable; - typedef std::pair< _Key const, _Mapped > value_type_key_const; - -public: - typedef _Key key_type; - typedef _Mapped mapped_type; - - typedef value_type_key_const value_type; - - typedef typename _Allocator::size_type size_type; - typedef typename _Allocator::difference_type difference_type; - - typedef typename _Allocator::pointer pointer; - typedef typename _Allocator::const_pointer const_pointer; - - typedef _Cmp key_compare; - typedef util::CmpByFirst< value_type_mutable, _Cmp > value_compare; - - typedef _Allocator allocator_type; - - typedef mapped_type & reference; - typedef mapped_type const & const_reference; - - typedef detail::AssocVectorLazyIterator< value_type_mutable *, AssocVector > iterator; - typedef detail::AssocVectorLazyIterator< value_type_mutable const *, AssocVector > const_iterator; - - typedef std::reverse_iterator< iterator > reverse_iterator; - typedef std::reverse_iterator< const_iterator > const_reverse_iterator; - - typedef array::Array< value_type_mutable > _Storage; - typedef array::Array< typename _Storage::const_iterator > _Erased; - -#ifdef AV_ENABLE_EXTENSIONS - public: -#else - private: -#endif - - // - // extension, faster, non STL compatible version of iterator, working with _find end _end - // - typedef detail::_AssocVectorIterator< value_type_mutable *, AssocVector > _iterator; - typedef detail::_AssocVectorIterator< value_type_mutable const *, AssocVector > _const_iterator; - -private: - struct _FindOrInsertToBufferResult - { - typename _Storage::iterator _inBuffer; - bool _isInserted; - bool _isReallocated; - }; - - struct _TryRemoveBackResult - { - bool _anyItemRemoved; - bool _erasedItemRemoved; - }; - - struct _FindImplResult - { - typename _Storage::iterator _inStorage; - typename _Storage::iterator _inBuffer; - typename _Erased::iterator _inErased; - typename _Storage::iterator _current; - - bool validate()const - { - return - ( _current == 0 && _inStorage == 0 && _inBuffer == 0 && _inErased == 0 ) - || _inStorage != 0; - } - }; - - struct _InsertImplResult - { - bool _isInserted; - - typename _Storage::iterator _inStorage; - typename _Storage::iterator _inBuffer; - typename _Erased::iterator _inErased; - typename _Storage::iterator _current; - - bool validate()const - { - if( _current == 0 ) - { - AV_ERROR(); - - return false; - } - - if( _inStorage == 0 && ( _inBuffer == 0 || _inErased == 0 ) ) - { - AV_ERROR(); - - return false; - } - - return true; - } - }; - - struct _TryEraseFromStorageResult - { - typename _Erased::iterator _inErased; - bool _isErased; - bool _isMerged; - }; - -public: - // - // constructor - // - explicit - AssocVector( - _Cmp const & cmp = _Cmp() - , _Allocator const & allocator = _Allocator() - ); - - explicit - AssocVector( _Allocator const & allocator ); - - template< typename __InputIterator > - AssocVector( - __InputIterator first - , __InputIterator last - , _Cmp const & cmp = _Cmp() - , _Allocator const & allocator = _Allocator() - ); - - AssocVector( AssocVector< _Key, _Mapped, _Cmp, _Allocator > const & other ); - AssocVector( - AssocVector< _Key, _Mapped, _Cmp, _Allocator > const & other - , _Allocator const & allocator - ); - - AssocVector( AssocVector< _Key, _Mapped, _Cmp, _Allocator > && other ); - AssocVector( - AssocVector< _Key, _Mapped, _Cmp, _Allocator > && other - , _Allocator const & allocator - ); - - AssocVector( - std::initializer_list< value_type > list - , _Cmp const & cmp = _Cmp() - , _Allocator const & allocator = _Allocator() - ); - - // - // destructor - // - inline ~AssocVector(); - - // - // clear - // - inline void clear() noexcept; - - // - // operator= - // - AssocVector & operator=( AssocVector const & other ); - AssocVector & operator=( AssocVector && other ); - - // - // methods - // - void reserve( std::size_t newCapacity ); - void swap( AssocVector & other ) noexcept; - - // - // iterators - // - inline iterator begin(); - inline const_iterator begin()const; - inline const_iterator cbegin()const; - - inline reverse_iterator rbegin(); - inline const_reverse_iterator rbegin()const; - inline const_reverse_iterator crbegin()const; - - inline iterator end(); - inline const_iterator end()const; - inline const_iterator cend()const; - - inline reverse_iterator rend(); - inline const_reverse_iterator rend()const; - inline const_reverse_iterator crend()const; - - // - // size - // - inline bool empty()const noexcept; - inline std::size_t size()const noexcept; - inline std::size_t capacity()const noexcept; - inline std::size_t max_size()const noexcept; - - // - // insert - // - std::pair< iterator, bool > insert( value_type const & value ); - - template< typename __ValueType > - std::pair< iterator, bool > insert( __ValueType && value ); - - iterator insert( const_iterator hint, value_type const & value ); - - template< typename __ValueType > - iterator insert( const_iterator hint, __ValueType && value ); - - template< typename _Iterator > - inline void insert( _Iterator first, _Iterator last ); - - inline void insert( std::initializer_list< value_type > list ); - - // - // emplace - // - template< class... __Args > - std::pair< iterator, bool > emplace( __Args... args ); - - template< class... __Args > - std::pair< iterator, bool > emplace_hint( const_iterator hint, __Args... args ); - - // - // find - // - iterator find( key_type const & k ); - const_iterator find( key_type const & k )const; - - iterator lower_bound( key_type const & k ); - const_iterator lower_bound( key_type const & k )const; - - iterator upper_bound( key_type const & k ); - const_iterator upper_bound( key_type const & k )const; - - std::pair< iterator, iterator > equal_range( key_type const & k ); - std::pair< const_iterator, const_iterator > equal_range( key_type const & k )const; - - // - // count - // - inline std::size_t count( key_type const & k )const; - - // - // operator[] - // - reference operator[]( key_type const & k ); - reference operator[]( key_type && k ); - - // - // at - // - reference at( key_type const & k ); - const_reference at( key_type const & k )const; - - // - // erase - // - std::size_t erase( key_type const & k ); - iterator erase( iterator pos ); - - // - // observers - // - key_compare key_comp()const - { - return _cmp; - } - - value_compare value_comp()const - { - return value_compare( _cmp ); - } - - //allocator_type get_allocator()const - //{ - // return _allocator; - //} - -#ifdef AV_ENABLE_EXTENSIONS - public: -#else - private: -#endif - - // - // extension, flatenize container, enforce merge of _storage with _erased and with _buffer - // - void _merge(); - - // - // extension, faster, non STL compatible version of insert - // - bool _insert( value_type const & value ); - - template< typename __ValueType > - bool _insert( __ValueType && value ); - - // - // extension, faster, non STL compatible version of end, works with _find - // - inline _iterator _end(); - inline _const_iterator _end()const; - - // - // extension, faster, non STL compatible version of find, works with _end - // - _iterator _find( key_type const & k ); - _const_iterator _find( key_type const & k )const; - - // - // extension, faster, non STL compatible version of erase - // - bool _erase( iterator pos ); - -private: - bool validateStorage()const; - bool validateBuffer()const; - bool validateErased()const; - bool validate()const; - - // - // merge - // - void mergeStorageWithBuffer(); - void mergeStorageWithErased(); - - // - // insert - // - template< typename __ValueType > - void pushBack( __ValueType && value ); - - template< typename __ValueType > - bool shouldBePushBack( __ValueType && value )const; - - template< typename __ValueType > - _FindOrInsertToBufferResult - findOrInsertToBuffer( __ValueType && value ); - - // - // insertImpl, function does as little as needed but returns as much data as possible - // - template< typename __ValueType > - _InsertImplResult - insertImpl( __ValueType && value ); - - // - // emplace_impl - // - template< class __Head, class... __Tail > - std::pair< iterator, bool > emplaceImpl( __Head && head, __Tail... tail ); - - // - // erase - // - _TryRemoveBackResult - tryRemoveStorageBack( typename _Storage::iterator pos ); - - // - // tryEraseFromStorage - // - _TryEraseFromStorageResult - tryEraseFromStorage( typename _Storage::iterator pos ); - - // - // isErased - // - bool isErased( typename _Storage::const_iterator iterator )const; - - // - // findImpl, function does as little as needed but returns as much data as possible - // - _FindImplResult - findImpl( key_type const & key ); - - // - // getAllocator (method specialization) - // - //_Allocator getAllocator( _Storage const & ){ return _allocator; } - // - //typename _Allocator::template rebind< typename _Storage::const_iterator >::other - //getAllocator( _Erased const & ) - //{return typename _Allocator::template rebind< typename _Storage::const_iterator >::other( _allocator );} - -public: // public for unit tests only - void dump( int width = -1 )const; - - std::size_t bufferSize()const{ return _buffer.size(); } - std::size_t bufferCapacity()const{ return _buffer.capacity(); } - _Storage const & storage()const{ return _storage; } - - std::size_t storageSize()const{ return _storage.size(); } - std::size_t storageCapacity()const{ return _storage.capacity(); } - _Storage const & buffer()const{ return _buffer; } - - std::size_t erasedSize()const{ return _erased.size(); } - std::size_t erasedCapacity()const{ return _erased.capacity(); } - _Erased const & erased()const{ return _erased; } - - static std::size_t calculateNewBufferCapacity( std::size_t storageSize ); - static std::size_t calculateNewErasedCapacity( std::size_t storageSize ); - static std::size_t calculateNewStorageCapacity( std::size_t storageSize ); - -private: - _Storage _storage; - _Storage _buffer; - _Erased _erased; - - _Cmp _cmp; -}; - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -bool operator==( - AssocVector< _Key, _Mapped, _Cmp, _Allocator > const & lhs - , AssocVector< _Key, _Mapped, _Cmp, _Allocator > const & rhs -) -{ - if( lhs.size() != rhs.size() ){ - return false; - } - - typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_iterator begin = lhs.begin(); - typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_iterator const end = lhs.end(); - - typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_iterator begin2 = rhs.begin(); - - for( /*empty*/ ; begin != end ; ++ begin, ++ begin2 ) - { - if( begin->first != begin2->first ){ - return false; - } - - if( begin->second != begin2->second ){ - return false; - } - } - - return true; -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -bool operator!=( - AssocVector< _Key, _Mapped, _Cmp, _Allocator > const & lhs - , AssocVector< _Key, _Mapped, _Cmp, _Allocator > const & rhs -) -{ - return ! ( lhs == rhs ); -} - -// -// Method Definitions -// - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::AssocVector( - _Cmp const & cmp - , _Allocator const & allocator -) - : _cmp( cmp ) -{ -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::AssocVector( _Allocator const & allocator ) -{ -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -template< - typename __InputIterator -> -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::AssocVector( - __InputIterator first - , __InputIterator last - , _Cmp const & cmp - , _Allocator const & allocator -) - : _cmp( cmp ) -{ - AV_PRECONDITION( std::distance( first, last ) >= 0 ); - - std::size_t const size = std::distance( first, last ); - - if( size > 0 ) - { - reserve( size ); - - for( /*empty*/ ; first != last ; ++ first ){ - insert( * first ); - } - } - - AV_POSTCONDITION( validate() ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::AssocVector( - AssocVector< _Key, _Mapped, _Cmp, _Allocator > const & other -) - : _storage( other._storage ) - , _buffer( other._buffer ) - , _erased( other._erased ) - , _cmp( other._cmp ) -{ -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::AssocVector( - AssocVector< _Key, _Mapped, _Cmp, _Allocator > const & other - , _Allocator const & allocator -) - : _storage( other._storage, allocator ) - , _buffer( other._buffer, allocator ) - , _erased( other._erased, allocator ) - , _cmp( other._cmp, allocator ) -{ -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::AssocVector( - AssocVector< _Key, _Mapped, _Cmp, _Allocator > && other -) - : _storage( std::move( other._storage ) ) - , _buffer( std::move( other._buffer ) ) - , _erased( std::move( other._erased ) ) - , _cmp( other._cmp ) -{ -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::AssocVector( - AssocVector< _Key, _Mapped, _Cmp, _Allocator > && other - , _Allocator const & allocator -) - : _storage( std::move( other._storage ) ) - , _buffer( std::move( other._buffer ) ) - , _erased( std::move( other._erased ) ) - , _cmp( other._cmp ) -{ -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::AssocVector( - std::initializer_list< typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::value_type > list - , _Cmp const & cmp - , _Allocator const & allocator -) - : _cmp( cmp ) -{ - reserve( list.size() ); - - insert( list ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::~AssocVector() -{ -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -void -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::clear() noexcept -{ - util::destroy_range( _storage.begin(), _storage.end() ); - util::destroy_range( _buffer.begin(), _buffer.end() ); - - _storage.setSize( 0 ); - _buffer.setSize( 0 ); - _erased.setSize( 0 ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -AssocVector< _Key, _Mapped, _Cmp, _Allocator > & -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::operator=( AssocVector const & other ) -{ - AssocVector temp( other ); - temp.swap( * this ); - - return * this; -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -AssocVector< _Key, _Mapped, _Cmp, _Allocator > & -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::operator=( AssocVector && other ) -{ - AssocVector temp( std::move( other ) ); - - temp.swap( * this ); - - return * this; -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -void -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::reserve( std::size_t newStorageCapacity ) -{ - if( _storage.get_allocator().max_size() < newStorageCapacity ){ - throw std::length_error( "AssocVector< _K, _M, _C, _A >::reserve" ); - } - - if( util::less_equal( newStorageCapacity, _storage.capacity() ) ){ - return; - } - - {// _erased - if( _erased.empty() == false ){ - mergeStorageWithErased(); - } - - _erased.reserve( calculateNewErasedCapacity( newStorageCapacity ) ); - - AV_CHECK( _erased.empty() ); - } - - std::size_t const newBufferCapacity - = calculateNewBufferCapacity( newStorageCapacity ); - - std::size_t const newStorageSize = _storage.size() + _buffer.size(); - - { - _Storage newStorage( newStorageCapacity, _storage.get_allocator() ); - _Storage newBuffer( newBufferCapacity, _buffer.get_allocator() ); - - util::move_merge_into_uninitialized( - _storage.begin() - , _storage.end() - , _buffer.begin() - , _buffer.end() - , newStorage.begin() - , value_comp() - ); - - newStorage.swap( _storage ); - newBuffer.swap( _buffer ); - }// call newStorage newBuffer destructors - - _storage.setSize( newStorageSize ); - - AV_POSTCONDITION( _buffer.empty() ); - AV_POSTCONDITION( validate() ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::iterator -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::begin() -{ - return iterator( this, _storage.begin(), _buffer.begin(), _erased.begin(), 0 ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::reverse_iterator -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::rbegin() -{ - return reverse_iterator( end() ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_iterator -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::begin()const -{ - return const_iterator( this, _storage.begin(), _buffer.begin(), _erased.begin(), 0 ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_iterator -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::cbegin()const -{ - return begin(); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_reverse_iterator -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::rbegin()const -{ - return const_reverse_iterator( end() ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_reverse_iterator -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::crbegin()const -{ - return rbegin(); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::iterator -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::end() -{ - return iterator( this, _storage.end(), _buffer.end(), _erased.end(), 0 ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::reverse_iterator -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::rend() -{ - return reverse_iterator( begin() ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_iterator -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::end()const -{ - return const_iterator( this, _storage.end(), _buffer.end(), _erased.end(), 0 ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_iterator -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::cend()const -{ - return end(); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_reverse_iterator -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::rend()const -{ - return const_reverse_iterator( begin() ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_reverse_iterator -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::crend()const -{ - return rend(); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::_iterator -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::_end() -{ - return _iterator( 0 ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::_const_iterator -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::_end()const -{ - return _const_iterator( 0 ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -bool -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::empty()const noexcept -{ - return size() == 0; -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -std::size_t -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::size()const noexcept -{ - return _storage.size() + _buffer.size() - _erased.size(); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -std::size_t -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::capacity()const noexcept -{ - return _storage.capacity() + _buffer.capacity(); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -std::size_t -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::max_size()const noexcept -{ - return _storage.get_allocator().max_size(); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -std::pair< typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::iterator, bool > -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::insert( value_type const & value ) -{ - _InsertImplResult const result = insertImpl( value ); - - return std::make_pair( - iterator( - this - , result._inStorage - , result._inBuffer - , result._inErased - , result._current - ) - , result._isInserted - ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -template< - typename __ValueType -> -std::pair< typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::iterator, bool > -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::insert( __ValueType && value ) -{ - _InsertImplResult const result = insertImpl( std::forward< __ValueType >( value ) ); - - return std::make_pair( - iterator( - this - , result._inStorage - , result._inBuffer - , result._inErased - , result._current - ) - , result._isInserted - ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::iterator -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::insert( - typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_iterator hint - , value_type const & value -) -{ - ( void )( hint ); - - _InsertImplResult const result = insertImpl( value ); - - return iterator( - this - , result._inStorage - , result._inBuffer - , result._inErased - , result._current - ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -template< - typename __ValueType -> -typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::iterator -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::insert( - const_iterator hint - , __ValueType && value -) -{ - ( void )( hint ); - - _InsertImplResult const result = insertImpl( std::forward< __ValueType >( value ) ); - - return iterator( - this - , result._inStorage - , result._inBuffer - , result._inErased - , result._current - ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -void -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::insert( - std::initializer_list< value_type > list -) -{ - insert( list.begin(), list.end() ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -bool -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::_insert( value_type const & value ) -{ - return insertImpl( value )._isInserted; -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -template< - typename __ValueType -> -bool -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::_insert( __ValueType && value ) -{ - return insertImpl( std::forward< __ValueType >( value ) )._isInserted; -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -template< - typename __ValueType -> -typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::_InsertImplResult -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::insertImpl( __ValueType && value ) -{ - _Key const & k = value.first; - _Mapped const & m = value.second; - - {//push back to storage - if( shouldBePushBack( value ) ) - { - pushBack( std::forward< __ValueType >( value ) ); - - _InsertImplResult result; - - { - AV_CHECK( _storage.empty() == false ); - - result._inStorage = ( _storage.end() - 1 ); - result._current = ( _storage.end() - 1 ); - } - - result._isInserted = true; - result._inBuffer = 0; - result._inErased = _erased.end(); - - AV_POSTCONDITION( result.validate() ); - AV_POSTCONDITION( validate() ); - - return result; - } - } - - typename _Storage::iterator const greaterEqualInStorage - = std::lower_bound( _storage.begin(), _storage.end(), k, value_comp() ); - - bool const notPresentInStorage - = greaterEqualInStorage == _storage.end() - || key_comp()( k, greaterEqualInStorage->first ); - - {//find or insert to buffer - if( notPresentInStorage ) - { - _FindOrInsertToBufferResult const findOrInsertToBufferResult - = findOrInsertToBuffer( std::forward< __ValueType >( value ) ); - - _InsertImplResult result; - result._isInserted = findOrInsertToBufferResult._isInserted; - - if( findOrInsertToBufferResult._isReallocated ) - { - result._inStorage = 0; - result._inErased = _erased.end(); - } - else - { - result._inStorage = greaterEqualInStorage; - result._inErased = 0; - } - - result._inBuffer = findOrInsertToBufferResult._inBuffer; - result._current = findOrInsertToBufferResult._inBuffer; - - AV_POSTCONDITION( result.validate() ); - AV_POSTCONDITION( validate() ); - - return result; - } - } - - {// check if not erased - typename _Erased::iterator const greaterEqualInErased = std::lower_bound( - _erased.begin() - , _erased.end() - , greaterEqualInStorage - , std::less< typename _Storage::const_iterator >() - ); - - bool const itemNotMarkedAsErased - = greaterEqualInErased == _erased.end() - || std::less< typename _Storage::const_iterator >() - ( greaterEqualInStorage, * greaterEqualInErased ); - - if( itemNotMarkedAsErased ) - {// item is in storage and is not marked as erased - _InsertImplResult result; - result._isInserted = false; - result._inStorage = greaterEqualInStorage; - result._inBuffer = 0; - result._inErased = greaterEqualInErased; - result._current = greaterEqualInStorage; - - AV_POSTCONDITION( result.validate() ); - AV_POSTCONDITION( validate() ); - - return result; - } - else - {// item is in storage but is marked as erased - _erased.erase( greaterEqualInErased ); - - greaterEqualInStorage->second = m; - - _InsertImplResult result; - result._isInserted = true; - result._inStorage = greaterEqualInStorage; - result._inBuffer = 0; - - // greaterEqualInErased is after 'Array::erase' but still valid - result._inErased = greaterEqualInErased; - - result._current = greaterEqualInStorage; - - AV_POSTCONDITION( validate() ); - AV_POSTCONDITION( result.validate() ); - - return result; - } - } -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -template< - typename _Iterator -> -void -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::insert( _Iterator const begin, _Iterator const end ) -{ - for( _Iterator current = begin ; current != end ; ++ current ){ - insert( * current ); - } -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -template< - class... __Args -> -std::pair< typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::iterator, bool > -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::emplace( __Args... args ) -{ - return emplaceImpl( args... ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -template< - class... __Args -> -std::pair< typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::iterator, bool > -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::emplace_hint( const_iterator hint, __Args... args ) -{ - ( void )( hint ); - - return emplaceImpl( args... ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -template< - class __Head - , class... __Tail -> -std::pair< typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::iterator, bool > -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::emplaceImpl( __Head && head, __Tail... tail ) -{ - _InsertImplResult const result - = insertImpl( value_type_mutable( key_type( head ), mapped_type( tail... ) ) ); - - return std::make_pair( - iterator( - this - , result._inStorage - , result._inBuffer - , result._inErased - , result._current - ) - , result._isInserted - ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -template< - typename __ValueType -> -bool -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::shouldBePushBack( __ValueType && value )const -{ - bool pushBackToStorage = false; - - {// should be pushed back - if( _storage.empty() ) - { - if( _buffer.empty() ){ - pushBackToStorage = true; - } - else - { - if( _cmp( _buffer.back().first, value.first ) ){ - pushBackToStorage = true; - } - } - } - else - { - if( _buffer.empty() ) - { - if( _cmp( _storage.back().first, value.first ) ){ - pushBackToStorage = true; - } - } - else - { - if( _cmp( _storage.back().first, value.first ) - && _cmp( _buffer.back().first, value.first ) - ){ - pushBackToStorage = true; - } - } - } - } - - return pushBackToStorage; -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -template< - typename __ValueType -> -void -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::pushBack( __ValueType && value ) -{ - if( _storage.size() != _storage.capacity() ){ - _storage.place_back( std::forward< __ValueType >( value ) ); - - AV_POSTCONDITION( validate() ); - - return; - } - - std::size_t const newStorageCapacity = calculateNewStorageCapacity( _storage.capacity() ); - std::size_t const newBufferCapacity = calculateNewBufferCapacity( newStorageCapacity ); - std::size_t const newErasedCapacity = calculateNewErasedCapacity( newStorageCapacity ); - - if( util::less_equal( newStorageCapacity, _storage.capacity() ) ){ - return; - } - - if( _storage.get_allocator().max_size() < newStorageCapacity ){ - throw std::length_error( "AssocVector::reserve" ); - } - - _Storage newStorage( newStorageCapacity, _storage.get_allocator() ); - _Storage newBuffer( newBufferCapacity, _buffer.get_allocator() ); - _Erased newErased( newErasedCapacity, _erased.get_allocator() ); - - {// may throw - iterator current = begin(); - iterator const end = this->end(); - - while( current != end ) - { - // for '++ current' object has still exist and can not be moved before - typename iterator::pointer_mutable const current_raw_ptr = current.getCurrent(); - - ++ current; - - newStorage.place_back( AV_MOVE_IF_NOEXCEPT( * current_raw_ptr ) ); - } - } - - // may throw an exception in __ValueType copy constructor, not exception safe - newStorage.place_back( std::forward< __ValueType >( value ) ); - - newStorage.swap( _storage ); - newBuffer.swap( _buffer ); - newErased.swap( _erased ); - - AV_POSTCONDITION( _buffer.empty() ); - AV_POSTCONDITION( _erased.empty() ); - - AV_POSTCONDITION( validate() ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::_TryRemoveBackResult -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::tryRemoveStorageBack( - typename _Storage::iterator pos -) -{ - if( pos + 1 != _storage.end() ) - { - _TryRemoveBackResult result; - result._anyItemRemoved = false; - result._erasedItemRemoved = false; - - return result; - } - - _storage.get_allocator().destroy( pos ); - - _storage.setSize( _storage.size() - 1 ); - - if( - _erased.empty() == false - && _erased.back() == pos - ) - { - _erased.setSize( _erased.size() - 1 ); - - _TryRemoveBackResult result; - result._anyItemRemoved = true; - result._erasedItemRemoved = true; - - AV_POSTCONDITION( validate() ); - - return result; - } - - _TryRemoveBackResult result; - result._anyItemRemoved = true; - result._erasedItemRemoved = false; - - AV_POSTCONDITION( validate() ); - - return result; -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::_TryEraseFromStorageResult -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::tryEraseFromStorage( - typename _Storage::iterator pos -) -{ - std::pair< typename _Erased::iterator, bool > const insertInSortedResult - = array::insert_in_sorted( - _erased - , typename _Storage::const_iterator( pos ) - , std::less< typename _Storage::const_iterator >() - ); - - if( _erased.full() ) - { - mergeStorageWithErased(); - - _TryEraseFromStorageResult result; - result._inErased = _erased.end(); - result._isErased = true; - result._isMerged = true; - - AV_POSTCONDITION( validate() ); - - return result; - } - else - { - _TryEraseFromStorageResult result; - result._inErased = insertInSortedResult.first; - result._isErased = insertInSortedResult.second; - result._isMerged = false; - - AV_POSTCONDITION( validate() ); - - return result; - } -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -bool -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::isErased( - typename AssocVector::_Storage::const_iterator iterator -)const -{ - typename _Erased::const_iterator const foundInErased = array::binary_search( - _erased.begin() - , _erased.end() - , iterator - , std::less< typename _Storage::const_iterator >() - ); - - return foundInErased != _erased.end(); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::_FindImplResult -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::findImpl( _Key const & k ) -{ - typename _Storage::iterator const greaterEqualInStorage - = std::lower_bound( _storage.begin(), _storage.end(), k, value_comp() ); - - bool const presentInStorage - = greaterEqualInStorage != _storage.end() - && key_comp()( k, greaterEqualInStorage->first ) == false; - - {// item is in storage, check in erased - if( presentInStorage ) - { - typename _Erased::iterator greaterEqualInErased = std::lower_bound( - _erased.begin() - , _erased.end() - , greaterEqualInStorage - , std::less< typename _Storage::const_iterator >() - ); - - bool const itemNotMarkedAsErased - = greaterEqualInErased == _erased.end() - || std::less< typename _Storage::const_iterator >()( - greaterEqualInStorage - , * greaterEqualInErased - ); - - if( itemNotMarkedAsErased ) - { - _FindImplResult result; - result._inStorage = greaterEqualInStorage; - result._inBuffer = 0; - result._inErased = greaterEqualInErased; - result._current = greaterEqualInStorage; - - AV_POSTCONDITION( result.validate() ); - - return result; - } - else - { - _FindImplResult result; - result._inStorage = 0; - result._inBuffer = 0; - result._inErased = 0; - result._current = 0; - - AV_POSTCONDITION( result.validate() ); - - return result; - } - } - } - - {// check in buffer - typename _Storage::iterator const greaterEqualInBuffer - = std::lower_bound( _buffer.begin(), _buffer.end(), k, value_comp() ); - - bool const presentInBuffer - = greaterEqualInBuffer != _buffer.end() - && key_comp()( k, greaterEqualInBuffer->first ) == false; - - if( presentInBuffer ) - { - _FindImplResult result; - result._inStorage = greaterEqualInStorage; - result._inBuffer = greaterEqualInBuffer; - result._inErased = 0; - result._current = greaterEqualInBuffer; - - AV_POSTCONDITION( result.validate() ); - - return result; - } - else - { - _FindImplResult result; - result._inStorage = 0; - result._inBuffer = 0; - result._inErased = 0; - result._current = 0; - - AV_POSTCONDITION( result.validate() ); - - return result; - } - } -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::iterator -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::find( _Key const & k ) -{ - _FindImplResult const result = findImpl( k ); - - if( result._current == 0 ){ - return end(); - } - else - { - return iterator( - this - , result._inStorage - , result._inBuffer - , result._inErased - , result._current - ); - } -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::reference -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::at( _Key const & k ) -{ - _FindImplResult const result = findImpl( k ); - - if( result._current == 0 ){ - throw std::out_of_range( "AssocVector::at" ); - } - else - { - return result._current->second; - } -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_reference -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::at( _Key const & k )const -{ - typedef AssocVector< _Key, _Mapped, _Cmp, _Allocator > * NonConstThis; - - return const_cast< NonConstThis >( this )->at( k ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_iterator -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::find( _Key const & k )const -{ - typedef AssocVector< _Key, _Mapped, _Cmp, _Allocator > * NonConstThis; - - return const_cast< NonConstThis >( this )->find( k ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::iterator -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::lower_bound( _Key const & k ) -{ - typename _Storage::iterator const greaterEqualInStorage - = std::lower_bound( _storage.begin(), _storage.end(), k, value_comp() ); - - typename _Storage::iterator const greaterEqualInBuffer - = std::lower_bound( _buffer.begin(), _buffer.end(), k, value_comp() ); - - return iterator( this, greaterEqualInStorage, greaterEqualInBuffer, 0, 0 ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_iterator -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::lower_bound( _Key const & k )const -{ - typedef AssocVector< _Key, _Mapped, _Cmp, _Allocator > * NonConstThis; - - return const_cast< NonConstThis >( this )->lower_bound( k ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::iterator -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::upper_bound( _Key const & k ) -{ - typename _Storage::iterator const greaterInStorage - = std::upper_bound( _storage.begin(), _storage.end(), k, value_comp() ); - - typename _Storage::iterator const greaterInBuffer - = std::upper_bound( _buffer.begin(), _buffer.end(), k, value_comp() ); - - return iterator( this, greaterInStorage, greaterInBuffer, 0, 0 ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_iterator -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::upper_bound( _Key const & k )const -{ - typedef AssocVector< _Key, _Mapped, _Cmp, _Allocator > * NonConstThis; - - return const_cast< NonConstThis >( this )->upper_bound( k ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -std::pair< - typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::iterator - , typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::iterator -> -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::equal_range( _Key const & k ) -{ - typename _Storage::iterator const greaterEqualInStorage - = std::lower_bound( _storage.begin(), _storage.end(), k, value_comp() ); - - bool const notPresentInStorage - = greaterEqualInStorage == _storage.end() - || key_comp()( k, greaterEqualInStorage->first ); - - typename _Storage::iterator const greaterEqualInBuffer - = std::lower_bound( _buffer.begin(), _buffer.end(), k, value_comp() ); - - bool const notPresentInBuffer - = greaterEqualInBuffer == _buffer.end() - || key_comp()( k, greaterEqualInBuffer->first ); - - if( notPresentInStorage == false ) - { - return std::make_pair( - iterator( this, greaterEqualInStorage, greaterEqualInBuffer, 0, 0 ) - , iterator( this, greaterEqualInStorage + 1, greaterEqualInBuffer, 0, 0 ) - ); - } - - if( notPresentInBuffer == false ) - { - return std::make_pair( - iterator( this, greaterEqualInStorage, greaterEqualInBuffer, 0, 0 ) - , iterator( this, greaterEqualInStorage, greaterEqualInBuffer + 1, 0, 0 ) - ); - } - - return std::make_pair( - iterator( this, greaterEqualInStorage, greaterEqualInBuffer, 0, 0 ) - , iterator( this, greaterEqualInStorage, greaterEqualInBuffer, 0, 0 ) - ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -std::pair< - typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_iterator - , typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::const_iterator -> -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::equal_range( _Key const & k )const -{ - typedef AssocVector< _Key, _Mapped, _Cmp, _Allocator > * NonConstThis; - - return const_cast< NonConstThis >( this )->equal_range( k ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::_iterator -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::_find( _Key const & k ) -{ - return _iterator( findImpl( k )._current ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::_const_iterator -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::_find( _Key const & k )const -{ - typedef AssocVector< _Key, _Mapped, _Cmp, _Allocator > * NonConstThis; - - return const_cast< NonConstThis >( this )->_find( k ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -bool -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::validateStorage()const -{ - if( _storage.size() > _storage.capacity() ) - { - AV_ERROR(); - - return false; - } - - if( std::is_sorted( _storage.begin(), _storage.end(), value_comp() ) == false ) - { - AV_ERROR(); - - return false; - } - - return true; -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -bool -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::validateBuffer()const -{ - if( _buffer.size() > _buffer.capacity() ) - { - AV_ERROR(); - - return false; - } - - if( _buffer.empty() ){ - return true; - } - - if( std::is_sorted( _buffer.begin(), _buffer.end(), value_comp() ) == false ) - { - AV_ERROR(); - - return false; - } - - if( - util::has_intersection( - _buffer.begin() - , _buffer.end() - , _storage.begin() - , _storage.end() - , value_comp() - ) - ) - { - AV_ERROR(); - - return false; - } - - return true; -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -bool -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::validateErased()const -{ - if( _erased.size() > _erased.capacity() ) - { - AV_ERROR(); - - return false; - } - - if( _erased.empty() ){ - return true; - } - - if( - std::is_sorted( - _erased.begin() - , _erased.end() - , std::less< typename _Storage::const_iterator >() - ) == false - ) - { - AV_ERROR(); - - return false; - } - - AV_CHECK( _erased.front() >= _storage.begin() ); - AV_CHECK( _erased.back() < _storage.end() ); - - return true; -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -bool -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::validate()const -{ - if( calculateNewBufferCapacity( _storage.capacity() ) != _buffer.capacity() ){ - return false; - } - - if( calculateNewErasedCapacity( _storage.capacity() ) != _erased.capacity() ){ - return false; - } - - return validateStorage() && validateBuffer() && validateErased(); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -void -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::_merge() -{ - if( size() > _storage.capacity() ) - { - reserve( calculateNewStorageCapacity( _storage.capacity() ) ); - - return; - } - - if( _erased.empty() == false ){ - mergeStorageWithErased(); - } - - mergeStorageWithBuffer(); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::reference -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::operator[]( key_type const & k ) -{ - return insert( value_type( k, mapped_type() ) ).first->second; -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::reference -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::operator[]( key_type && k ) -{ - return insert( value_type( std::move( k ), mapped_type() ) ).first->second; -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -std::size_t -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::count( key_type const & k )const -{ - return _find( k ) ? 1 : 0; -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -std::size_t -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::erase( key_type const & k ) -{ - typename _Storage::iterator const foundInStorage - = array::binary_search( _storage.begin(), _storage.end(), k, value_comp() ); - - {//erase from _buffer - if( foundInStorage == _storage.end() ) - { - typename _Storage::iterator const foundInBuffer - = array::binary_search( _buffer.begin(), _buffer.end(), k, value_comp() ); - - if( foundInBuffer == _buffer.end() ) - { - AV_POSTCONDITION( validate() ); - - return 0; - } - else - { - _buffer.erase( foundInBuffer ); - - AV_POSTCONDITION( validate() ); - - return 1; - } - } - } - - {//erase from back - _TryRemoveBackResult const result = tryRemoveStorageBack( foundInStorage ); - - if( result._anyItemRemoved ) - { - if( result._erasedItemRemoved ) - { - AV_POSTCONDITION( validate() ); - - return 0; - } - else - { - AV_POSTCONDITION( validate() ); - - return 1; - } - } - } - - {//erase from _storage - bool const result = tryEraseFromStorage( foundInStorage )._isErased ? 1 : 0; - - AV_POSTCONDITION( validate() ); - - return result; - } -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::iterator -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::erase( iterator pos ) -{ - if( pos == end() ){ - return end(); - } - - // iterator::get converts : pair< T1, T2 > * -> pair< T1 const, T2 > * - // revert real iterator type: pair< T1 const, T2 > * -> pair< T1, T2 > * - value_type_mutable * const posBase = reinterpret_cast< value_type_mutable * >( pos.get() ); - - _Key const key = pos->first; - - {//erase from _buffer - if( util::is_between( _buffer.begin(), posBase, _buffer.end() ) ) - { - _buffer.erase( posBase ); - - typename _Storage::iterator const greaterEqualInStorage - = pos.getCurrentInStorage() - ? pos.getCurrentInStorage() - : std::lower_bound( _storage.begin(), _storage.end(), key, value_comp() ); - - AV_POSTCONDITION( validate() ); - - return iterator( this, greaterEqualInStorage, posBase, 0, 0 ); - } - } - - {//item not present in container - if( util::is_between( _storage.begin(), posBase, _storage.end() ) == false ){ - return end(); - } - } - - {//erase from back - _TryRemoveBackResult const result = tryRemoveStorageBack( posBase ); - - if( result._anyItemRemoved ) - { - typename _Storage::iterator const greaterEqualInBuffer - = pos.getCurrentInBuffer() - ? pos.getCurrentInBuffer() - : std::lower_bound( _buffer.begin(), _buffer.end(), key, value_comp() ); - - if( greaterEqualInBuffer == _buffer.end() ) - { - AV_POSTCONDITION( validate() ); - - return end(); - } - else - { - AV_POSTCONDITION( validate() ); - - return iterator( this, _storage.end(), greaterEqualInBuffer, 0, 0 ); - } - } - } - - {//erase from _storage - _TryEraseFromStorageResult const result = tryEraseFromStorage( posBase ); - - if( result._isErased == false ){ - return end(); - } - - typename _Storage::iterator const greaterEqualInBuffer - = pos.getCurrentInBuffer() - ? pos.getCurrentInBuffer() - : std::lower_bound( _buffer.begin(), _buffer.end(), key, value_comp() ); - - if( result._isMerged == false ) - { - AV_POSTCONDITION( validate() ); - - return iterator( this, posBase + 1, greaterEqualInBuffer, result._inErased + 1, 0 ); - } - - typename _Storage::iterator const greaterEqualInStorage - = std::lower_bound( _storage.begin(), _storage.end(), key, value_comp() ); - - AV_POSTCONDITION( validate() ); - - return iterator( this, greaterEqualInStorage, greaterEqualInBuffer, _erased.end(), 0 ); - } -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -bool -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::_erase( iterator pos ) -{ - // iterator::get converts : pair< T1, T2 > * -> pair< T1 const, T2 > * - // revert real iterator type: pair< T1 const, T2 > * -> pair< T1, T2 > * - value_type_mutable * const posBase = reinterpret_cast< value_type_mutable * >( pos.get() ); - - {//erase from _buffer - if( util::is_between( _buffer.begin(), posBase, _buffer.end() ) ) - { - _buffer.erase( posBase ); - - AV_POSTCONDITION( validate() ); - - return true; - } - } - - {//item not present in container - if( util::is_between( _storage.begin(), posBase, _storage.end() ) == false ){ - return false; - } - } - - {//erase from back - _TryRemoveBackResult const result = tryRemoveStorageBack( posBase ); - - if( result._anyItemRemoved ) - { - AV_POSTCONDITION( validate() ); - - return true; - } - } - - {//erase from _storage - bool const result = tryEraseFromStorage( posBase )._isErased; - - AV_POSTCONDITION( validate() ); - - return result; - } -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -void -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::swap( - AssocVector< _Key, _Mapped, _Cmp, _Allocator > & other -) noexcept -{ - std::swap( _storage, other._storage ); - std::swap( _buffer, other._buffer ); - std::swap( _erased, other._erased ); - - std::swap( _cmp, other._cmp ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -void -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::mergeStorageWithBuffer() -{ - AV_PRECONDITION( _erased.empty() ); - - array::move_merge( _storage, _buffer, value_comp() ); - - util::destroy_range( _buffer.begin(), _buffer.end() ); - - _buffer.setSize( 0 ); - - AV_POSTCONDITION( _buffer.empty() ); - AV_POSTCONDITION( validateStorage() ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -void -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::mergeStorageWithErased() -{ - typename _Storage::iterator const end = _storage.end(); - - array::erase_removed( _storage, _erased ); - - util::destroy_range( _storage.end(), end ); - - _erased.setSize( 0 ); - - AV_POSTCONDITION( _erased.empty() ); - AV_POSTCONDITION( validateStorage() ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -template< - typename __ValueType -> -typename AssocVector< _Key, _Mapped, _Cmp, _Allocator >::_FindOrInsertToBufferResult -AssocVector< _Key, _Mapped, _Cmp, _Allocator >::findOrInsertToBuffer( __ValueType && value ) -{ - typename _Storage::iterator const greaterEqualInBuffer - = std::lower_bound( _buffer.begin(), _buffer.end(), value.first, value_comp() ); - - if( greaterEqualInBuffer != _buffer.end() ) - { - bool const isEqual = _cmp( value.first, greaterEqualInBuffer->first ) == false; - - if( isEqual ) - { - _FindOrInsertToBufferResult result; - result._inBuffer = greaterEqualInBuffer; - result._isInserted = false; - result._isReallocated = false; - - return result; - } - } - - if( _buffer.full() ) - { - _merge(); - - AV_CHECK( _buffer.empty() ); - - _buffer.insert( - _buffer.begin() - , value_type_mutable( std::forward< __ValueType >( value ) ) - ); - - _FindOrInsertToBufferResult result; - result._inBuffer = _buffer.begin(); - result._isInserted = true; - result._isReallocated = true; - - AV_POSTCONDITION( validate() ); - - return result; - } - else - { - _buffer.insert( - greaterEqualInBuffer - , value_type_mutable( std::forward< __ValueType >( value ) ) - ); - - _FindOrInsertToBufferResult result; - result._inBuffer = greaterEqualInBuffer; - result._isInserted = true; - result._isReallocated = false; - - AV_POSTCONDITION( validate() ); - - return result; - } -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -std::size_t AssocVector< _Key, _Mapped, _Cmp, _Allocator >::calculateNewBufferCapacity( - std::size_t storageSize -) -{ - return static_cast< std::size_t >( 1.0 * sqrt( storageSize )); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -std::size_t AssocVector< _Key, _Mapped, _Cmp, _Allocator >::calculateNewErasedCapacity( - std::size_t storageSize -) -{ - return calculateNewBufferCapacity( storageSize ); -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -std::size_t AssocVector< _Key, _Mapped, _Cmp, _Allocator >::calculateNewStorageCapacity( - std::size_t storageSize -) -{ - if( storageSize == 0 ){ - return 1; - } - else if( storageSize == 1 ){ - // size=1 size=2 - // capacity=1 capacity=2 - // S:[a] S:[ab] - // B:[b] -> reserve -> B:[ ] - // E:[ ] E:[ ] - - return 4; - } - else{ - return 2 * storageSize; - } -} - -template< - typename _Key - , typename _Mapped - , typename _Cmp - , typename _Allocator -> -void AssocVector< _Key, _Mapped, _Cmp, _Allocator >::dump( int width )const -{ - std::cout << "storage: "; - for( unsigned i = 0 ; i < _storage.size() ; ++ i ) - { - if( i > 0 && width > 0 && ( i % width == 0 ) ){ - std::cout << "\n "; - } - - std::cout << " (" << _storage[i].first << "," << _storage[i].second << ")"; - } - - std::cout << std::endl << "buffer: "; - for( unsigned i = 0 ; i < _buffer.size() ; ++ i ) - { - if( i > 0 && width > 0 && ( i % width == 0 ) ){ - std::cout << "\n "; - } - - std::cout << " (" << _buffer[i].first << "," << _buffer[i].second << ")"; - } - - std::cout << std::endl << "erased: "; - for( unsigned i = 0 ; i < _erased.size() ; ++ i ) - { - if( i > 0 && width > 0 && ( i % width == 0 ) ){ - std::cout << "\n "; - } - - std::cout << " (" << (*_erased[i]).first << "," << (*_erased[i]).second << ")"; - } - - std::cout << "." << std::endl; -} - -#endif From c8b65cd007524d9c73fc409192513c56f8d387ea Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Mon, 20 Jul 2020 16:56:01 -0500 Subject: [PATCH 044/175] :fire: Delete flat_map --- external/flat | 1 - 1 file changed, 1 deletion(-) delete mode 160000 external/flat diff --git a/external/flat b/external/flat deleted file mode 160000 index 2e8d469f7..000000000 --- a/external/flat +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2e8d469f7933cd640c64c6d8e8ba98f6ed9f2efc From 542198482d6388351ca21564d881eaa89c21d41f Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Mon, 20 Jul 2020 16:56:58 -0500 Subject: [PATCH 045/175] :pencil: External flat_map --- external/flat/LICENSE_1_0.txt | 23 ++ external/flat/README.md | 65 ++++ external/flat/flat_map.hpp | 251 +++++++++++++ external/flat/flat_multimap.hpp | 133 +++++++ external/flat/flat_multiset.hpp | 117 ++++++ external/flat/flat_set.hpp | 129 +++++++ external/flat/impl/class_def.hpp | 60 +++ external/flat/impl/container_traits.hpp | 25 ++ external/flat/impl/flat_impl.hpp | 470 ++++++++++++++++++++++++ 9 files changed, 1273 insertions(+) create mode 100644 external/flat/LICENSE_1_0.txt create mode 100644 external/flat/README.md create mode 100644 external/flat/flat_map.hpp create mode 100644 external/flat/flat_multimap.hpp create mode 100644 external/flat/flat_multiset.hpp create mode 100644 external/flat/flat_set.hpp create mode 100644 external/flat/impl/class_def.hpp create mode 100644 external/flat/impl/container_traits.hpp create mode 100644 external/flat/impl/flat_impl.hpp diff --git a/external/flat/LICENSE_1_0.txt b/external/flat/LICENSE_1_0.txt new file mode 100644 index 000000000..36b7cd93c --- /dev/null +++ b/external/flat/LICENSE_1_0.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/external/flat/README.md b/external/flat/README.md new file mode 100644 index 000000000..e3b89eab0 --- /dev/null +++ b/external/flat/README.md @@ -0,0 +1,65 @@ +# C++ Flat Containers Library + +Fast+efficient associative containers using sorted arrays, with an interface based on standard containers. + +This was part of a C++ standard proposal and I recommend that you read it for more details: http://pubby.github.io/proposal.html + +#### Container Adaptors +- `fc::flat_map` +- `fc::flat_multimap` +- `fc::flat_set` +- `fc::flat_multiset` + +#### Class Aliases +- `fc::vector_map` +- `fc::vector_multimap` +- `fc::vector_set` +- `fc::vector_multiset` + +#### New Member Functions +- `has` + - `map.has(key)` returns a pointer to key's mapped value if it exists, otherwise returns null. +- `insert` (delayed sort) + - `map.insert(first, last, fc::delay_sort)` performs insertion with a delayed sort optimization. +- Constructors (delayed sort overload) + - Constructs flat container using a delayed sort optimization. +- Constructors (container construct overload) + - Constructs flat container by forwarding arguments to the underlying container member. + +#### What's an adaptor? + +Container adaptors allow you to use any vector-like sequence container for the underlying storage. +`std::vector` is the natural choice, but classes like `boost::small_vector` and `boost::static_vector` are useful too. Because `std::vector` is the most common in usage, aliases are provided for convenience. + +For basic use, just use the `std::vector` aliases. + +#### The public Members: `container` and `underlying` + +The public member `container` allows access to the underlying storage container. Note that it is the user's responsibility to keep the container in a sorted, unique state. + +Likewise, the public member of iterators: `underlying`, allows access to the underlying storage container's iterators. + +*Example: Delayed sort optimization using `.container`* + + std::flat_multiset set; + while(cpu_temperature() < 100) + set.container.push_back(cpu_temperature()); + std::sort(set.begin(), set.end()); + +#### Const Iteration by Default + +For safety reasons, flat container iterators are const by default. To bypass this safety and get non-const iterators, one can either iterate `.container` or take the `.underlying` of the iterator. + +*Example: Modify values in a way that preserves sortedness* + + for(auto& v : set.container) + v *= 2; + +*Example: Same thing but with `.underlying`* + + for(auto it = v.begin(); it != v.end(); ++it) + (*v.underlying) *= 2; + +#### Helper Types + +The directory `include_extra` contains convenience typedefs for use with Boost.Container. diff --git a/external/flat/flat_map.hpp b/external/flat/flat_map.hpp new file mode 100644 index 000000000..7e6ce507c --- /dev/null +++ b/external/flat/flat_map.hpp @@ -0,0 +1,251 @@ +// Copyright Pubby 2016 +// Distributed under the Boost Software License, Version 1.0. +// http://www.boost.org/LICENSE_1_0.txt + +#ifndef LIB_FLAT_FLAT_MAP_HPP +#define LIB_FLAT_FLAT_MAP_HPP + +#include "impl/flat_impl.hpp" + +namespace fc { +namespace impl { + +template +class flat_map_base +: public flat_container_base +{ +#include "impl/container_traits.hpp" + using mapped_type = typename value_type::second_type; + using B = flat_container_base; + D const* self() const { return static_cast(this); } + D* self() { return static_cast(this); } +public: + using value_compare = first_compare; + value_compare value_comp() const { return value_compare(B::key_comp()); } + + using B::insert; + using B::erase; + + // Element access + + mapped_type const* has(key_type const& key) const + { + const_iterator it = self()->find(key); + return it == self()->end() ? nullptr : &it.underlying->second; + } + + mapped_type* has(key_type const& key) + { + iterator it = self()->find(key); + return it == self()->end() ? nullptr : &it.underlying->second; + } + + mapped_type const& at(key_type const& key) const + { + if(mapped_type const* ptr = has(key)) + return *ptr; + throw std::out_of_range("flat_map::at"); + } + + mapped_type& at(key_type const& key) + { + if(mapped_type* ptr = has(key)) + return *ptr; + throw std::out_of_range("flat_map::at"); + } + + mapped_type& operator[](key_type const& key) + { return self()->try_emplace(key).first.underlying->second; } + + mapped_type& operator[](key_type&& key) + { + return self()->try_emplace(std::move(key)).first.underlying->second; + } + + // Modifiers + + std::pair insert(value_type const& value) + { return insert_(value); } + + std::pair insert(value_type&& value) + { return insert_(std::move(value)); } + + template + void insert(InputIt first, InputIt last, delay_sort_t) + { + this->ds_insert_(first, last); + auto it = std::unique( + self()->container.begin(), self()->container.end(), + impl::eq_comp{value_comp()}); + self()->container.erase(it, self()->container.end()); + } + + template + std::pair insert_or_assign(key_type const& key, M&& obj) + { return insert_or_assign_(key, std::forward(obj)); } + + template + std::pair insert_or_assign(key_type&& key, M&& obj) + { return insert_or_assign_(std::move(key), std::forward(obj)); } + + template + std::pair insert_or_assign(const_iterator hint, + key_type const& key, M&& obj) + { return insert_or_assign(key, std::forward(obj)); } + + template + std::pair insert_or_assign(const_iterator hint, + key_type&& key, M&& obj) + { return insert_or_assign(std::move(key), std::forward(obj)); } + + template + std::pair try_emplace(key_type const& key, Args&&... args) + { return try_emplace_(key, std::forward(args)...); } + + template + std::pair try_emplace(key_type&& key, Args&&... args) + { return try_emplace_(std::move(key), std::forward(args)...); } + + template + iterator try_emplace(const_iterator hint, + key_type const& key, Args&&... args) + { return try_emplace_(key, std::forward(args)...).first; } + + template + iterator try_emplace(const_iterator hint, key_type&& key, Args&&... args) + { + return try_emplace_(std::move(key), + std::forward(args)...).first; + } + + size_type erase(key_type const& key) + { + const_iterator it = self()->find(key); + if(it == self()->end()) + return 0; + self()->container.erase(it.underlying); + return 1; + } + + // Lookup + + size_type count(key_type const& key) const + { + return self()->find(key) != self()->end(); + } + +private: + template + std::pair insert_(V&& value) + { + iterator it = self()->lower_bound(value.first); + if(it == self()->end() || self()->value_comp()(value, *it)) + { + it = self()->container.insert(it.underlying, + std::forward(value)); + return std::make_pair(it, true); + } + return std::make_pair(it, false); + } + + template + std::pair insert_or_assign_(K&& key, M&& obj) + { + iterator it = self()->lower_bound(key); + if(it == self()->end() || self()->key_comp()(key, it->first)) + { + it = self()->container.insert(it.underlying, + value_type(std::forward(key), std::forward(obj))); + return std::make_pair(it, true); + } + it.underlying->second = std::forward(obj); + return std::make_pair(it, false); + } + + template + std::pair try_emplace_(K&& key, Args&&... args) + { + iterator it = self()->lower_bound(key); + if(it == self()->end() || self()->key_comp()(key, it->first)) + { + it = self()->container.emplace(it.underlying, + value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(key)), + std::forward_as_tuple(std::forward(args)...))); + return std::make_pair(it, true); + } + return std::make_pair(it, false); + } +}; + +template +class flat_map_base> +: public flat_map_base +{ +#include "impl/container_traits.hpp" + using mapped_type = typename value_type::second_type; + using B = flat_map_base; + D const* self() const { return static_cast(this); } + D* self() { return static_cast(this); } +public: + + using B::insert; + using B::count; + + // Modifiers + + template + std::pair insert(P&& value) + { + iterator it = self()->lower_bound(value.first); + if(it == self()->end() || self()->value_comp()(value, *it)) + { + it = self()->container.insert( + it.underlying, std::forward

(value)); + return std::make_pair(it, true); + } + return std::make_pair(it, false); + } + + // Lookup + + template + size_type count(K const& key) const + { + return self()->find(key) != self()->end(); + } +}; + +} // namespace impl + +template> +class flat_map +: public impl::flat_map_base, + typename Container::value_type::first_type, Container, Compare> +{ +#define FLATNAME flat_map +#define FLATKEY typename Container::value_type::first_type +#include "impl/class_def.hpp" +#undef FLATNAME +#undef FLATKEY +}; + +template> +using vector_map = flat_map>, Compare>; + +template +inline bool operator==(const flat_map& lhs, const flat_map& rhs) +{ + return lhs.container == rhs.container; +} +template +inline bool operator!=(const flat_map& lhs, const flat_map& rhs) +{ + return lhs.container != rhs.container; +} + +} // namespace fc + +#endif diff --git a/external/flat/flat_multimap.hpp b/external/flat/flat_multimap.hpp new file mode 100644 index 000000000..169be155e --- /dev/null +++ b/external/flat/flat_multimap.hpp @@ -0,0 +1,133 @@ +// Copyright Pubby 2016 +// Distributed under the Boost Software License, Version 1.0. +// http://www.boost.org/LICENSE_1_0.txt + +#ifndef LIB_FLAT_FLAT_MULTIMAP_HPP +#define LIB_FLAT_FLAT_MULTIMAP_HPP + +#include "impl/flat_impl.hpp" + +namespace fc { +namespace impl { + +template +class flat_multimap_base +: public flat_container_base +{ +#include "impl/container_traits.hpp" + using mapped_type = typename value_type::second_type; + using B = flat_container_base; + D const* self() const { return static_cast(this); } + D* self() { return static_cast(this); } +public: + using value_compare = first_compare; + value_compare value_comp() const { return value_compare(B::key_comp()); } + + using B::insert; + using B::erase; + + // Modifiers + + iterator insert(value_type const& value) + { + iterator it = self()->upper_bound(value.first); + return self()->container.insert(it.underlying, value); + } + + iterator insert(value_type&& value) + { + iterator it = self()->upper_bound(value.first); + return self()->container.insert(it.underlying, std::move(value)); + } + + template + void insert(InputIt first, InputIt last, delay_sort_t) + { this->ds_insert_(first, last); } + + size_type erase(key_type const& key) + { + auto it_pair = self()->equal_range(key); + std::size_t ret = std::distance(it_pair.first, it_pair.second); + self()->container.erase(it_pair.first.underlying, + it_pair.second.underlying); + return ret; + } + + // Lookup + + size_type count(key_type const& key) const + { + auto it_pair = self()->equal_range(key); + return std::distance(it_pair.first, it_pair.second); + } + +}; + +template +class flat_multimap_base> +: public flat_multimap_base +{ +#include "impl/container_traits.hpp" + using mapped_type = typename value_type::second_type; + using B = flat_multimap_base; + D const* self() const { return static_cast(this); } + D* self() { return static_cast(this); } +public: + + using B::insert; + using B::count; + + // Modifiers + + template + iterator insert(P&& value) + { + iterator it = self()->upper_bound(value.first); + return self()->container.insert(it.underlying, + std::forward

(value)); + } + + // Lookup + + template + size_type count(K const& key) const + { + auto it_pair = self()->equal_range(key); + return std::distance(it_pair.first, it_pair.second); + } +}; + +} // namespace impl + +template> +class flat_multimap +: public impl::flat_multimap_base, + typename Container::value_type::first_type, Container, Compare> +{ +#define FLATNAME flat_multimap +#define FLATKEY typename Container::value_type::first_type +#include "impl/class_def.hpp" +#undef FLATNAME +#undef FLATKEY +}; + +template> +using vector_multimap + = flat_multimap>, Compare>; + +template +inline bool operator==(const flat_multimap& lhs, const flat_multimap& rhs) +{ + return lhs.container == rhs.container; +} +template +inline bool operator!=(const flat_multimap& lhs, const flat_multimap& rhs) +{ + return lhs.container != rhs.container; +} + +} // namespace fc + +#endif diff --git a/external/flat/flat_multiset.hpp b/external/flat/flat_multiset.hpp new file mode 100644 index 000000000..beca937ff --- /dev/null +++ b/external/flat/flat_multiset.hpp @@ -0,0 +1,117 @@ +// Copyright Pubby 2016 +// Distributed under the Boost Software License, Version 1.0. +// http://www.boost.org/LICENSE_1_0.txt + +#ifndef LIB_FLAT_FLAT_MULTISET_HPP +#define LIB_FLAT_FLAT_MULTISET_HPP + +#include "impl/flat_impl.hpp" + +namespace fc { +namespace impl { + +template +class flat_multiset_base +: public flat_container_base +{ +#include "impl/container_traits.hpp" + using B = flat_container_base; + D const* self() const { return static_cast(this); } + D* self() { return static_cast(this); } +public: + using value_compare = Compare; + value_compare value_comp() const { return value_compare(B::key_comp()); } + + using B::insert; + using B::erase; + + // Modifiers + + iterator insert(value_type const& value) + { + iterator it = self()->upper_bound(value); + return self()->container.insert(it.underlying, value); + } + + iterator insert(value_type&& value) + { + iterator it = self()->upper_bound(value); + return self()->container.insert(it.underlying, std::move(value)); + } + + template + void insert(InputIt first, InputIt last, delay_sort_t) + { this->ds_insert_(first, last); } + + size_type erase(key_type const& key) + { + auto it_pair = self()->equal_range(key); + std::size_t ret = std::distance(it_pair.first, it_pair.second); + self()->container.erase(it_pair.first.underlying, + it_pair.second.underlying); + return ret; + } + + // Lookup + + size_type count(key_type const& key) const + { + auto it_pair = self()->equal_range(key); + return std::distance(it_pair.first, it_pair.second); + } +}; + +template +class flat_multiset_base> +: public flat_multiset_base +{ +#include "impl/container_traits.hpp" + using B = flat_multiset_base; + D const* self() const { return static_cast(this); } + D* self() { return static_cast(this); } +public: + using B::count; + + // Lookup + + template + size_type count(K const& key) const + { + auto it_pair = self()->equal_range(key); + return std::distance(it_pair.first, it_pair.second); + } +}; + +} // namespace impl + +template> +class flat_multiset +: public impl::flat_multiset_base, + typename Container::value_type, Container, Compare> +{ +#define FLATNAME flat_multiset +#define FLATKEY typename Container::value_type +#include "impl/class_def.hpp" +#undef FLATNAME +#undef FLATKEY +}; + +template> +using vector_multiset = flat_multiset, Compare>; + +template +inline bool operator==(const flat_multiset& lhs, const flat_multiset& rhs) +{ + return lhs.container == rhs.container; +} +template +inline bool operator!=(const flat_multiset& lhs, const flat_multiset& rhs) +{ + return lhs.container != rhs.container; +} + +} // namespace fc + +#endif diff --git a/external/flat/flat_set.hpp b/external/flat/flat_set.hpp new file mode 100644 index 000000000..7f95049cb --- /dev/null +++ b/external/flat/flat_set.hpp @@ -0,0 +1,129 @@ +// Copyright Pubby 2016 +// Distributed under the Boost Software License, Version 1.0. +// http://www.boost.org/LICENSE_1_0.txt + +#ifndef LIB_FLAT_FLAT_SET_HPP +#define LIB_FLAT_FLAT_SET_HPP + +#include "impl/flat_impl.hpp" + +namespace fc { +namespace impl { + +template +class flat_set_base +: public flat_container_base +{ +#include "impl/container_traits.hpp" + using B = flat_container_base; + D const* self() const { return static_cast(this); } + D* self() { return static_cast(this); } +public: + using value_compare = Compare; + value_compare value_comp() const { return value_compare(B::key_comp()); } + + using B::insert; + using B::erase; + + // Modifiers + + std::pair insert(value_type const& value) + { return insert_(value); } + + std::pair insert(value_type&& value) + { return insert_(std::move(value)); } + + template + void insert(InputIt first, InputIt last, delay_sort_t) + { + this->ds_insert_(first, last); + auto it = std::unique( + self()->container.begin(), self()->container.end(), + impl::eq_comp{value_comp()}); + self()->container.erase(it, self()->container.end()); + } + + size_type erase(key_type const& key) + { + const_iterator it = self()->find(key); + if(it == self()->end()) + return 0; + self()->container.erase(it.underlying); + return 1; + } + + // Lookup + + size_type count(key_type const& key) const + { + return self()->find(key) != self()->end(); + } + +private: + template + std::pair insert_(V&& value) + { + iterator it = self()->lower_bound(value); + if(it == self()->end() || self()->value_comp()(value, *it)) + { + it = self()->container.insert(it.underlying, + std::forward(value)); + return std::make_pair(it, true); + } + return std::make_pair(it, false); + } +}; + +template +class flat_set_base> +: public flat_set_base +{ +#include "impl/container_traits.hpp" + using B = flat_set_base; + D const* self() const { return static_cast(this); } + D* self() { return static_cast(this); } +public: + using B::count; + + // Lookup + + template + size_type count(K const& key) const + { + return self()->find(key) != self()->end(); + } +}; + +} // namespace impl + +template> +class flat_set +: public impl::flat_set_base, + typename Container::value_type, Container, Compare> +{ +#define FLATNAME flat_set +#define FLATKEY typename Container::value_type +#include "impl/class_def.hpp" +#undef FLATNAME +#undef FLATKEY +}; + +template> +using vector_set = flat_set, Compare>; + +template +inline bool operator==(const flat_set& lhs, const flat_set& rhs) +{ + return lhs.container == rhs.container; +} +template +inline bool operator!=(const flat_set& lhs, const flat_set& rhs) +{ + return lhs.container != rhs.container; +} + +} // namespace fc + +#endif diff --git a/external/flat/impl/class_def.hpp b/external/flat/impl/class_def.hpp new file mode 100644 index 000000000..d29e24b2f --- /dev/null +++ b/external/flat/impl/class_def.hpp @@ -0,0 +1,60 @@ +// Copyright Pubby 2016 +// Distributed under the Boost Software License, Version 1.0. +// http://www.boost.org/LICENSE_1_0.txt + +private: + using D = FLATNAME; + using Key = FLATKEY; +public: +#include "container_traits.hpp" + + FLATNAME() = default; + explicit FLATNAME(Compare const& comp) : comp(comp), container() {} + + template + FLATNAME(InputIt first, InputIt last) + : FLATNAME() { this->insert(first, last); } + + template + FLATNAME(InputIt first, InputIt last, Compare const& comp) + : FLATNAME(comp) { this->insert(first, last); } + + template + FLATNAME(InputIt first, InputIt last, delay_sort_t d) + : FLATNAME() { this->insert(first, last, d); } + + template + FLATNAME(InputIt first, InputIt last, Compare const& comp, delay_sort_t d) + : FLATNAME(comp) { this->insert(first, last, d); } + + FLATNAME(FLATNAME const&) = default; + FLATNAME(FLATNAME&&) = default; + + FLATNAME(std::initializer_list ilist) + : FLATNAME() { this->insert(ilist); } + + FLATNAME(std::initializer_list ilist, delay_sort_t d) + : FLATNAME() { this->insert(ilist, d); } + + FLATNAME(std::initializer_list ilist, + Compare const& comp, delay_sort_t d) + : FLATNAME(comp) { this->insert(ilist, d); } + + template + explicit FLATNAME(container_construct_t, Args&&... args) + : container(std::forward(args)...), comp() {} + + template + FLATNAME(Compare const& comp, container_construct_t, Args&&... args) + : container(std::forward(args)...), comp(comp) {} + + FLATNAME& operator=(FLATNAME const&) = default; + FLATNAME& operator=(FLATNAME&&) = default; + FLATNAME& operator=(std::initializer_list ilist) + { this->clear(); this->insert(ilist); return *this; } + + Container container; + Compare comp; + +#undef FLATNAME +#undef FLATKEY diff --git a/external/flat/impl/container_traits.hpp b/external/flat/impl/container_traits.hpp new file mode 100644 index 000000000..31e16423d --- /dev/null +++ b/external/flat/impl/container_traits.hpp @@ -0,0 +1,25 @@ +// Copyright Pubby 2016 +// Distributed under the Boost Software License, Version 1.0. +// http://www.boost.org/LICENSE_1_0.txt + +using container_type = Container; +using key_type = Key; +using size_type = typename container_type::size_type; +using difference_type = typename container_type::difference_type; +using value_type = typename container_type::value_type; +using iterator + = impl::flat_iterator< + typename container_type::iterator, + impl::dummy_iterator>; +using const_iterator + = impl::flat_iterator< + typename container_type::const_iterator, + iterator>; +using reverse_iterator + = impl::flat_iterator< + typename container_type::reverse_iterator, + impl::dummy_iterator>; +using const_reverse_iterator + = impl::flat_iterator< + typename container_type::const_reverse_iterator, + reverse_iterator>; diff --git a/external/flat/impl/flat_impl.hpp b/external/flat/impl/flat_impl.hpp new file mode 100644 index 000000000..2d639620e --- /dev/null +++ b/external/flat/impl/flat_impl.hpp @@ -0,0 +1,470 @@ +// Copyright Pubby 2016 +// Distributed under the Boost Software License, Version 1.0. +// http://www.boost.org/LICENSE_1_0.txt + +#ifndef LIB_FLAT_FLAT_IMPL_HPP +#define LIB_FLAT_FLAT_IMPL_HPP + +#include +#include +#include +#include +#include + +namespace fc { + +struct delay_sort_t {}; +constexpr delay_sort_t delay_sort = {}; + +struct container_construct_t {}; +constexpr container_construct_t container_construct = {}; + +namespace impl { + +template +using transparent_key_t = std::reference_wrapper; + +template +struct eq_comp +{ + template + bool operator()(A const& lhs, B const& rhs) + { return !comp(lhs, rhs) && !comp(rhs, lhs); } + Comp comp; +}; + + +template +struct dummy_iterator +{ + dummy_iterator() = delete; + dummy_iterator(dummy_iterator const&) = delete; + It underlying; +}; + +template::iterator_category> +class flat_iterator; + +template +class flat_iterator +{ + using traits = std::iterator_traits; +public: + using difference_type = typename traits::difference_type; + using value_type = typename traits::value_type const; + using pointer = value_type*; + using reference = value_type&; + using iterator_category = std::random_access_iterator_tag; + + flat_iterator() = default; + flat_iterator(flat_iterator const&) = default; + flat_iterator(flat_iterator&&) = default; + flat_iterator(Convert const& c) : underlying(c.underlying) {} + flat_iterator(Convert&& c) : underlying(std::move(c.underlying)) {} + flat_iterator(It const& underlying) : underlying(underlying) {} + flat_iterator(It&& underlying) : underlying(std::move(underlying)) {} + + flat_iterator& operator=(flat_iterator const& u) = default; + flat_iterator& operator=(flat_iterator&& u) = default; + flat_iterator& operator=(It const& u) + { this->underlying = u; return *this; } + flat_iterator& operator=(It&& u) + { this->underlying = std::move(u); return *this; } + + reference operator*() const { return *underlying; } + pointer operator->() const { return std::addressof(*underlying); } + + flat_iterator& operator++() { ++this->underlying; return *this; } + flat_iterator operator++(int) + { flat_iterator it = *this; ++this->underlying; return it; } + + flat_iterator& operator--() { --this->underlying; return *this; } + flat_iterator operator--(int) + { flat_iterator it = *this; --this->underlying; return it; } + + flat_iterator& operator+=(difference_type d) + { this->underlying += d; return *this; } + flat_iterator& operator-=(difference_type d) + { this->underlying -= d; return *this; } + + flat_iterator operator+(difference_type d) const + { return this->underlying + d; } + flat_iterator operator-(difference_type d) const + { return this->underlying - d; } + + difference_type operator-(flat_iterator const& o) const + { return this->underlying - o.underlying; } + + reference operator[](difference_type d) const { return *(*this + d); } + + auto operator==(flat_iterator const& o) const + { + using namespace std::rel_ops; + return this->underlying == o.underlying; + } + auto operator!=(flat_iterator const& o) const + { + using namespace std::rel_ops; + return this->underlying != o.underlying; + } + auto operator<(flat_iterator const& o) const + { return this->underlying < o.underlying; } + auto operator<=(flat_iterator const& o) const + { return this->underlying <= o.underlying; } + auto operator>(flat_iterator const& o) const + { return this->underlying > o.underlying; } + auto operator>=(flat_iterator const& o) const + { return this->underlying >= o.underlying; } + + It underlying; +}; + +template, typename TransparentKey = void> +struct first_compare +{ + first_compare(const Compare& comp) : + compare(comp) { + } + + bool operator()(Pair const& lhs, Pair const& rhs) const + { + return compare.get()(lhs.first, rhs.first); + } + + bool operator()(typename Pair::first_type const& lhs, Pair const& rhs) const + { + return compare.get()(lhs, rhs.first); + } + + bool operator()(Pair const& lhs, typename Pair::first_type const& rhs) const + { + return compare.get()(lhs.first, rhs); + } + + template + bool operator()(transparent_key_t const& lhs, Pair const& rhs) const + { + return compare.get()(lhs.get(), rhs.first); + } + + template + bool operator()(transparent_key_t const& lhs, typename Pair::first_type const& rhs) const + { + return compare.get()(lhs.get(), rhs); + } + + template + bool operator()(Pair const& lhs, transparent_key_t const& rhs) const + { + return compare.get()(lhs.first, rhs.get()); + } + + template + bool operator()(typename Pair::first_type const& lhs, transparent_key_t const& rhs) const + { + return compare.get()(lhs, rhs.get()); + } + + std::reference_wrapper compare; +}; + +template +class flat_container_base +{ +#include "container_traits.hpp" + D const* self() const { return static_cast(this); } + D* self() { return static_cast(this); } +public: + using key_compare = Compare; + const key_compare &key_comp() const { return self()->comp; } + + // Iterators + + const_iterator cbegin() const + noexcept(noexcept(std::declval().container.cbegin())) + { return self()->container.cbegin(); } + const_iterator begin() const + noexcept(noexcept(std::declval().container.begin())) + { return self()->container.begin(); } + iterator begin() + noexcept(noexcept(std::declval().container.begin())) + { return self()->container.begin(); } + + const_iterator cend() const + noexcept(noexcept(std::declval().container.cend())) + { return self()->container.cend(); } + const_iterator end() const + noexcept(noexcept(std::declval().container.end())) + { return self()->container.end(); } + iterator end() + noexcept(noexcept(std::declval().container.end())) + { return self()->container.end(); } + + const_reverse_iterator crbegin() const + noexcept(noexcept(std::declval().container.crbegin())) + { return self()->container.crbegin(); } + const_reverse_iterator rbegin() const + noexcept(noexcept(std::declval().container.rbegin())) + { return self()->container.rbegin(); } + reverse_iterator rbegin() + noexcept(noexcept(std::declval().container.rbegin())) + { return self()->container.rbegin(); } + + const_reverse_iterator crend() const + noexcept(noexcept(std::declval().container.crend())) + { return self()->container.crend(); } + const_reverse_iterator rend() const + noexcept(noexcept(std::declval().container.rend())) + { return self()->container.rend(); } + reverse_iterator rend() + noexcept(noexcept(std::declval().container.rend())) + { return self()->container.rend(); } + + // Capacity + + bool empty() const + noexcept(noexcept(std::declval().container.empty())) + { return self()->container.empty(); } + + size_type size() const + noexcept(noexcept(std::declval().container.size())) + { return self()->container.size(); } + + // Modifiers + + iterator insert(const_iterator hint, value_type const& value) + { return self()->insert(value).first; } + + iterator insert(const_iterator hint, value_type&& value) + { return self()->insert(std::move(value)).first; } + + template + void insert(InputIt first, InputIt last) + { + for(InputIt it = first; it != last; ++it) + self()->insert(*it); + } + + void insert(std::initializer_list ilist) + { self()->insert(ilist.begin(), ilist.end()); } + + void insert(std::initializer_list ilist, delay_sort_t d) + { self()->insert(ilist.begin(), ilist.end(), d); } + + template + auto emplace(Args&&... args) + { return self()->insert(value_type(std::forward(args)...)); } + + template + auto emplace_hint(const_iterator hint, Args&&... args) + { return self()->insert(value_type(std::forward(args)...)); } + + iterator erase(const_iterator pos) + noexcept(noexcept(std::declval().container.erase(pos.underlying))) + { return self()->container.erase(pos.underlying); } + + iterator erase(const_iterator first, const_iterator last) + noexcept(noexcept(std::declval().container.erase(first.underlying, + last.underlying))) + { return self()->container.erase(first.underlying, last.underlying); } + + void clear() + noexcept(noexcept(std::declval().container.clear())) + { self()->container.clear(); } + + void swap(D& other) + noexcept(D::has_noexcept_swap()) + { + using std::swap; + swap(self()->container, other.container); + } + + // Lookup + + const_iterator find(key_type const& key) const + { + const_iterator it = self()->lower_bound(key); + if(it == self()->end() || self()->value_comp()(key, *it)) + return self()->end(); + return it; + } + + iterator find(key_type const& key) + { + iterator it = self()->lower_bound(key); + if(it == self()->end() || self()->value_comp()(key, *it)) + return self()->end(); + return it; + } + + const_iterator lower_bound(key_type const& key) const + { + return std::lower_bound( + self()->begin(), self()->end(), + key, self()->value_comp()); + } + + iterator lower_bound(key_type const& key) + { + return std::lower_bound( + self()->begin(), self()->end(), + key, self()->value_comp()); + } + + const_iterator upper_bound(key_type const& key) const + { + return std::upper_bound( + self()->begin(), self()->end(), + key, self()->value_comp()); + } + + iterator upper_bound(key_type const& key) + { + return std::upper_bound( + self()->begin(), self()->end(), + key, self()->value_comp()); + } + + std::pair + equal_range(key_type const& key) const + { + return std::equal_range( + self()->begin(), self()->end(), + key, self()->value_comp()); + } + + std::pair equal_range(key_type const& key) + { + return std::equal_range( + self()->begin(), self()->end(), + key, self()->value_comp()); + } + +private: + static constexpr bool has_noexcept_swap() + { + using std::swap; + return noexcept(swap(*static_cast(nullptr), + *static_cast(nullptr))); + } + +protected: + template + void ds_insert_(InputIt first, InputIt last) + { + size_type const i = self()->size(); + for(InputIt it = first; it != last; ++it) + self()->container.push_back(*it); + std::sort( + self()->container.begin()+i, + self()->container.end(), + self()->value_comp()); + std::inplace_merge( + self()->container.begin(), + self()->container.begin()+i, + self()->container.end()); + // Note: Not calling unique here. Do it in the caller. + } +}; + +template +class flat_container_base> +: public flat_container_base +{ +#include "container_traits.hpp" + D const* self() const { return static_cast(this); } + D* self() { return static_cast(this); } + using B = flat_container_base; +public: + + using B::insert; + using B::find; + using B::lower_bound; + using B::upper_bound; + using B::equal_range; + + // Modifiers + + template + iterator insert(const_iterator hint, P&& value) + { return insert(std::forward

(value)).first; } + + // Lookup + + template + const_iterator find(K const& key) const + { + const_iterator it = self()->lower_bound(key); + if (it == self()->end() || self()->value_comp()(std::ref(key), *it)) + return self()->end(); + return it; + } + + template + iterator find(K const& key) + { + iterator it = self()->lower_bound(key); + if (it == self()->end() || self()->value_comp()(std::ref(key), *it)) + return self()->end(); + return it; + } + + template + const_iterator lower_bound(K const& key) const + { + return std::lower_bound( + self()->begin(), self()->end(), + std::ref(key), self()->value_comp()); + } + + template + iterator lower_bound(K const& key) + { + return std::lower_bound( + self()->begin(), self()->end(), + std::ref(key), self()->value_comp()); + } + + template + const_iterator upper_bound(K const& key) const + { + return std::upper_bound( + self()->begin(), self()->end(), + std::ref(key), self()->value_comp()); + } + + template + iterator upper_bound(K const& key) + { + return std::upper_bound( + self()->begin(), self()->end(), + std::ref(key), self()->value_comp()); + } + + template + std::pair + equal_range(K const& key) const + { + return std::equal_range( + self()->begin(), self()->end(), + std::ref(key), self()->value_comp()); + } + + template + std::pair equal_range(K const& key) + { + return std::equal_range( + self()->begin(), self()->end(), + std::ref(key), self()->value_comp()); + } +}; + +} // namespace fc +} // namespace impl + +#endif From 23be1008d6a8747f5078cb9f5748683d02a535bb Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Mon, 20 Jul 2020 17:01:25 -0500 Subject: [PATCH 046/175] :fire: Remove unused includes --- include/node_base.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/include/node_base.h b/include/node_base.h index 8cacffd2e..b5fe54744 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -1,22 +1,16 @@ #ifndef MPM_NODE_BASE_H_ #define MPM_NODE_BASE_H_ -#include - #include -#include #include #include #include #include -#include -#include #include #include #include #include -#include #include "data_types.h" #include "function_base.h" From 222ca55f527e6d16e4d7e98b80ceb3ae4787d295 Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 21 Jul 2020 10:05:32 -0700 Subject: [PATCH 047/175] :wrench: change flat map initialisation --- include/mpm_properties.h | 22 ++++----- include/node.tcc | 81 +++++++++++++++------------------- include/particles/particle.tcc | 21 +++++---- 3 files changed, 57 insertions(+), 67 deletions(-) diff --git a/include/mpm_properties.h b/include/mpm_properties.h index f3aea193e..4e3568667 100644 --- a/include/mpm_properties.h +++ b/include/mpm_properties.h @@ -5,20 +5,20 @@ namespace mpm { namespace properties { //! Scalar Properties enum Scalar : unsigned int { - Mass = 0, - Volume = 1, - MassDensity = 2, - MassPressure = 3, - Pressure = 4 + Mass, + Volume, + MassDensity, + MassPressure, + Pressure }; //! Vector Properties enum Vector : unsigned int { - Displacement = 0, - Velocity = 1, - Acceleration = 2, - Momentum = 3, - ExternalForce = 4, - InternalForce = 5 + Displacement, + Velocity, + Acceleration, + Momentum, + ExternalForce, + InternalForce }; } // namespace properties } // namespace mpm diff --git a/include/node.tcc b/include/node.tcc index 7d3051e47..996f259fc 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -19,38 +19,44 @@ mpm::Node::Node( concentrated_force_.setZero(); // Initialize scalar properties - scalar_properties_.reserve(5); // Mass - scalar_properties_.emplace_back(Eigen::Matrix::Zero()); + scalar_properties_.emplace( + std::make_pair(mpm::properties::Scalar::Mass, + Eigen::Matrix::Zero())); // Volume - scalar_properties_.emplace_back(Eigen::Matrix::Zero()); - // MassDensity - scalar_properties_.emplace_back(Eigen::Matrix::Zero()); + scalar_properties_.emplace( + std::make_pair(mpm::properties::Scalar::Volume, + Eigen::Matrix::Zero())); // MassPressure - scalar_properties_.emplace_back(Eigen::Matrix::Zero()); + scalar_properties_.emplace( + std::make_pair(mpm::properties::Scalar::MassPressure, + Eigen::Matrix::Zero())); // Pressure - scalar_properties_.emplace_back(Eigen::Matrix::Zero()); + scalar_properties_.emplace( + std::make_pair(mpm::properties::Scalar::Pressure, + Eigen::Matrix::Zero())); // Initialize vector properties - vector_properties_.resize(6); - // Displacement - vector_properties_.emplace_back( - Eigen::Matrix::Zero()); // Velocity - vector_properties_.emplace_back( - Eigen::Matrix::Zero()); + vector_properties_.emplace( + std::make_pair(mpm::properties::Vector::Velocity, + Eigen::Matrix::Zero())); // Acceleration - vector_properties_.emplace_back( - Eigen::Matrix::Zero()); + vector_properties_.emplace( + std::make_pair(mpm::properties::Vector::Acceleration, + Eigen::Matrix::Zero())); // Momentum - vector_properties_.emplace_back( - Eigen::Matrix::Zero()); + vector_properties_.emplace( + std::make_pair(mpm::properties::Vector::Momentum, + Eigen::Matrix::Zero())); // ExternalForce - vector_properties_.emplace_back( - Eigen::Matrix::Zero()); + vector_properties_.emplace( + std::make_pair(mpm::properties::Vector::ExternalForce, + Eigen::Matrix::Zero())); // InternalForce - vector_properties_.emplace_back( - Eigen::Matrix::Zero()); + vector_properties_.emplace( + std::make_pair(mpm::properties::Vector::InternalForce, + Eigen::Matrix::Zero())); this->initialise(); } @@ -61,32 +67,17 @@ void mpm::Node::initialise() noexcept { status_ = false; // Initialise nodal scalar properties - scalar_properties_.resize(5); - scalar_properties_.at(mpm::properties::Scalar::Mass) = - Eigen::Matrix::Zero(); - scalar_properties_.at(mpm::properties::Scalar::Volume) = - Eigen::Matrix::Zero(); - scalar_properties_.at(mpm::properties::Scalar::MassDensity) = - Eigen::Matrix::Zero(); - scalar_properties_.at(mpm::properties::Scalar::MassPressure) = - Eigen::Matrix::Zero(); - scalar_properties_.at(mpm::properties::Scalar::Pressure) = - Eigen::Matrix::Zero(); + scalar_properties_.at(mpm::properties::Scalar::Mass).setZero(); + scalar_properties_.at(mpm::properties::Scalar::Volume).setZero(); + scalar_properties_.at(mpm::properties::Scalar::MassPressure).setZero(); + scalar_properties_.at(mpm::properties::Scalar::Pressure).setZero(); // Initialise nodal vector properties - vector_properties_.resize(6); - vector_properties_.at(mpm::properties::Vector::Displacement) = - Eigen::Matrix::Zero(); - vector_properties_.at(mpm::properties::Vector::Velocity) = - Eigen::Matrix::Zero(); - vector_properties_.at(mpm::properties::Vector::Acceleration) = - Eigen::Matrix::Zero(); - vector_properties_.at(mpm::properties::Vector::Momentum) = - Eigen::Matrix::Zero(); - vector_properties_.at(mpm::properties::Vector::ExternalForce) = - Eigen::Matrix::Zero(); - vector_properties_.at(mpm::properties::Vector::InternalForce) = - Eigen::Matrix::Zero(); + vector_properties_.at(mpm::properties::Vector::Velocity).setZero(); + vector_properties_.at(mpm::properties::Vector::Acceleration).setZero(); + vector_properties_.at(mpm::properties::Vector::Momentum).setZero(); + vector_properties_.at(mpm::properties::Vector::ExternalForce).setZero(); + vector_properties_.at(mpm::properties::Vector::InternalForce).setZero(); // Initialise variables for contact material_ids_.clear(); diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index 2ce5bc060..0d5d3c680 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -9,8 +9,6 @@ mpm::Particle::Particle(Index id, const VectorDim& coord) nodes_.clear(); // Set material pointer to null material_ = nullptr; - scalar_properties_.resize(3); - vector_properties_.resize(3); // Logger std::string logger = "particle" + std::to_string(Tdim) + "d::" + std::to_string(id); @@ -241,17 +239,18 @@ void mpm::Particle::initialise() { volumetric_strain_centroid_ = 0.; // Initialize scalar properties - scalar_properties_.resize(3); - scalar_properties_.at(mpm::properties::Scalar::Mass) = 0.; - scalar_properties_.at(mpm::properties::Scalar::MassDensity) = 0.; - scalar_properties_.at(mpm::properties::Scalar::Volume) = - std::numeric_limits::max(); + scalar_properties_.emplace( + std::make_pair(mpm::properties::Scalar::Mass, double(0.))); + scalar_properties_.emplace( + std::make_pair(mpm::properties::Scalar::MassDensity, double(0.))); + scalar_properties_.emplace(std::make_pair( + mpm::properties::Scalar::Volume, std::numeric_limits::max())); // Initialize vector properties - vector_properties_.resize(2); - vector_properties_.at(mpm::properties::Vector::Displacement) = - VectorDim::Zero(); - vector_properties_.at(mpm::properties::Vector::Velocity) = VectorDim::Zero(); + vector_properties_.emplace( + std::make_pair(mpm::properties::Vector::Displacement, VectorDim::Zero())); + vector_properties_.emplace( + std::make_pair(mpm::properties::Vector::Velocity, VectorDim::Zero())); // Initialize vector data properties this->properties_["stresses"] = [&]() { return stress(); }; From da461c310ec3521837dbae3441a08676b73bd693 Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Mon, 20 Jul 2020 16:56:58 -0500 Subject: [PATCH 048/175] :pencil: External flat_map --- external/flat/LICENSE_1_0.txt | 23 ++ external/flat/README.md | 65 ++++ external/flat/flat_map.hpp | 251 +++++++++++++ external/flat/flat_multimap.hpp | 133 +++++++ external/flat/flat_multiset.hpp | 117 ++++++ external/flat/flat_set.hpp | 129 +++++++ external/flat/impl/class_def.hpp | 60 +++ external/flat/impl/container_traits.hpp | 25 ++ external/flat/impl/flat_impl.hpp | 470 ++++++++++++++++++++++++ 9 files changed, 1273 insertions(+) create mode 100644 external/flat/LICENSE_1_0.txt create mode 100644 external/flat/README.md create mode 100644 external/flat/flat_map.hpp create mode 100644 external/flat/flat_multimap.hpp create mode 100644 external/flat/flat_multiset.hpp create mode 100644 external/flat/flat_set.hpp create mode 100644 external/flat/impl/class_def.hpp create mode 100644 external/flat/impl/container_traits.hpp create mode 100644 external/flat/impl/flat_impl.hpp diff --git a/external/flat/LICENSE_1_0.txt b/external/flat/LICENSE_1_0.txt new file mode 100644 index 000000000..36b7cd93c --- /dev/null +++ b/external/flat/LICENSE_1_0.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/external/flat/README.md b/external/flat/README.md new file mode 100644 index 000000000..e3b89eab0 --- /dev/null +++ b/external/flat/README.md @@ -0,0 +1,65 @@ +# C++ Flat Containers Library + +Fast+efficient associative containers using sorted arrays, with an interface based on standard containers. + +This was part of a C++ standard proposal and I recommend that you read it for more details: http://pubby.github.io/proposal.html + +#### Container Adaptors +- `fc::flat_map` +- `fc::flat_multimap` +- `fc::flat_set` +- `fc::flat_multiset` + +#### Class Aliases +- `fc::vector_map` +- `fc::vector_multimap` +- `fc::vector_set` +- `fc::vector_multiset` + +#### New Member Functions +- `has` + - `map.has(key)` returns a pointer to key's mapped value if it exists, otherwise returns null. +- `insert` (delayed sort) + - `map.insert(first, last, fc::delay_sort)` performs insertion with a delayed sort optimization. +- Constructors (delayed sort overload) + - Constructs flat container using a delayed sort optimization. +- Constructors (container construct overload) + - Constructs flat container by forwarding arguments to the underlying container member. + +#### What's an adaptor? + +Container adaptors allow you to use any vector-like sequence container for the underlying storage. +`std::vector` is the natural choice, but classes like `boost::small_vector` and `boost::static_vector` are useful too. Because `std::vector` is the most common in usage, aliases are provided for convenience. + +For basic use, just use the `std::vector` aliases. + +#### The public Members: `container` and `underlying` + +The public member `container` allows access to the underlying storage container. Note that it is the user's responsibility to keep the container in a sorted, unique state. + +Likewise, the public member of iterators: `underlying`, allows access to the underlying storage container's iterators. + +*Example: Delayed sort optimization using `.container`* + + std::flat_multiset set; + while(cpu_temperature() < 100) + set.container.push_back(cpu_temperature()); + std::sort(set.begin(), set.end()); + +#### Const Iteration by Default + +For safety reasons, flat container iterators are const by default. To bypass this safety and get non-const iterators, one can either iterate `.container` or take the `.underlying` of the iterator. + +*Example: Modify values in a way that preserves sortedness* + + for(auto& v : set.container) + v *= 2; + +*Example: Same thing but with `.underlying`* + + for(auto it = v.begin(); it != v.end(); ++it) + (*v.underlying) *= 2; + +#### Helper Types + +The directory `include_extra` contains convenience typedefs for use with Boost.Container. diff --git a/external/flat/flat_map.hpp b/external/flat/flat_map.hpp new file mode 100644 index 000000000..7e6ce507c --- /dev/null +++ b/external/flat/flat_map.hpp @@ -0,0 +1,251 @@ +// Copyright Pubby 2016 +// Distributed under the Boost Software License, Version 1.0. +// http://www.boost.org/LICENSE_1_0.txt + +#ifndef LIB_FLAT_FLAT_MAP_HPP +#define LIB_FLAT_FLAT_MAP_HPP + +#include "impl/flat_impl.hpp" + +namespace fc { +namespace impl { + +template +class flat_map_base +: public flat_container_base +{ +#include "impl/container_traits.hpp" + using mapped_type = typename value_type::second_type; + using B = flat_container_base; + D const* self() const { return static_cast(this); } + D* self() { return static_cast(this); } +public: + using value_compare = first_compare; + value_compare value_comp() const { return value_compare(B::key_comp()); } + + using B::insert; + using B::erase; + + // Element access + + mapped_type const* has(key_type const& key) const + { + const_iterator it = self()->find(key); + return it == self()->end() ? nullptr : &it.underlying->second; + } + + mapped_type* has(key_type const& key) + { + iterator it = self()->find(key); + return it == self()->end() ? nullptr : &it.underlying->second; + } + + mapped_type const& at(key_type const& key) const + { + if(mapped_type const* ptr = has(key)) + return *ptr; + throw std::out_of_range("flat_map::at"); + } + + mapped_type& at(key_type const& key) + { + if(mapped_type* ptr = has(key)) + return *ptr; + throw std::out_of_range("flat_map::at"); + } + + mapped_type& operator[](key_type const& key) + { return self()->try_emplace(key).first.underlying->second; } + + mapped_type& operator[](key_type&& key) + { + return self()->try_emplace(std::move(key)).first.underlying->second; + } + + // Modifiers + + std::pair insert(value_type const& value) + { return insert_(value); } + + std::pair insert(value_type&& value) + { return insert_(std::move(value)); } + + template + void insert(InputIt first, InputIt last, delay_sort_t) + { + this->ds_insert_(first, last); + auto it = std::unique( + self()->container.begin(), self()->container.end(), + impl::eq_comp{value_comp()}); + self()->container.erase(it, self()->container.end()); + } + + template + std::pair insert_or_assign(key_type const& key, M&& obj) + { return insert_or_assign_(key, std::forward(obj)); } + + template + std::pair insert_or_assign(key_type&& key, M&& obj) + { return insert_or_assign_(std::move(key), std::forward(obj)); } + + template + std::pair insert_or_assign(const_iterator hint, + key_type const& key, M&& obj) + { return insert_or_assign(key, std::forward(obj)); } + + template + std::pair insert_or_assign(const_iterator hint, + key_type&& key, M&& obj) + { return insert_or_assign(std::move(key), std::forward(obj)); } + + template + std::pair try_emplace(key_type const& key, Args&&... args) + { return try_emplace_(key, std::forward(args)...); } + + template + std::pair try_emplace(key_type&& key, Args&&... args) + { return try_emplace_(std::move(key), std::forward(args)...); } + + template + iterator try_emplace(const_iterator hint, + key_type const& key, Args&&... args) + { return try_emplace_(key, std::forward(args)...).first; } + + template + iterator try_emplace(const_iterator hint, key_type&& key, Args&&... args) + { + return try_emplace_(std::move(key), + std::forward(args)...).first; + } + + size_type erase(key_type const& key) + { + const_iterator it = self()->find(key); + if(it == self()->end()) + return 0; + self()->container.erase(it.underlying); + return 1; + } + + // Lookup + + size_type count(key_type const& key) const + { + return self()->find(key) != self()->end(); + } + +private: + template + std::pair insert_(V&& value) + { + iterator it = self()->lower_bound(value.first); + if(it == self()->end() || self()->value_comp()(value, *it)) + { + it = self()->container.insert(it.underlying, + std::forward(value)); + return std::make_pair(it, true); + } + return std::make_pair(it, false); + } + + template + std::pair insert_or_assign_(K&& key, M&& obj) + { + iterator it = self()->lower_bound(key); + if(it == self()->end() || self()->key_comp()(key, it->first)) + { + it = self()->container.insert(it.underlying, + value_type(std::forward(key), std::forward(obj))); + return std::make_pair(it, true); + } + it.underlying->second = std::forward(obj); + return std::make_pair(it, false); + } + + template + std::pair try_emplace_(K&& key, Args&&... args) + { + iterator it = self()->lower_bound(key); + if(it == self()->end() || self()->key_comp()(key, it->first)) + { + it = self()->container.emplace(it.underlying, + value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(key)), + std::forward_as_tuple(std::forward(args)...))); + return std::make_pair(it, true); + } + return std::make_pair(it, false); + } +}; + +template +class flat_map_base> +: public flat_map_base +{ +#include "impl/container_traits.hpp" + using mapped_type = typename value_type::second_type; + using B = flat_map_base; + D const* self() const { return static_cast(this); } + D* self() { return static_cast(this); } +public: + + using B::insert; + using B::count; + + // Modifiers + + template + std::pair insert(P&& value) + { + iterator it = self()->lower_bound(value.first); + if(it == self()->end() || self()->value_comp()(value, *it)) + { + it = self()->container.insert( + it.underlying, std::forward

(value)); + return std::make_pair(it, true); + } + return std::make_pair(it, false); + } + + // Lookup + + template + size_type count(K const& key) const + { + return self()->find(key) != self()->end(); + } +}; + +} // namespace impl + +template> +class flat_map +: public impl::flat_map_base, + typename Container::value_type::first_type, Container, Compare> +{ +#define FLATNAME flat_map +#define FLATKEY typename Container::value_type::first_type +#include "impl/class_def.hpp" +#undef FLATNAME +#undef FLATKEY +}; + +template> +using vector_map = flat_map>, Compare>; + +template +inline bool operator==(const flat_map& lhs, const flat_map& rhs) +{ + return lhs.container == rhs.container; +} +template +inline bool operator!=(const flat_map& lhs, const flat_map& rhs) +{ + return lhs.container != rhs.container; +} + +} // namespace fc + +#endif diff --git a/external/flat/flat_multimap.hpp b/external/flat/flat_multimap.hpp new file mode 100644 index 000000000..169be155e --- /dev/null +++ b/external/flat/flat_multimap.hpp @@ -0,0 +1,133 @@ +// Copyright Pubby 2016 +// Distributed under the Boost Software License, Version 1.0. +// http://www.boost.org/LICENSE_1_0.txt + +#ifndef LIB_FLAT_FLAT_MULTIMAP_HPP +#define LIB_FLAT_FLAT_MULTIMAP_HPP + +#include "impl/flat_impl.hpp" + +namespace fc { +namespace impl { + +template +class flat_multimap_base +: public flat_container_base +{ +#include "impl/container_traits.hpp" + using mapped_type = typename value_type::second_type; + using B = flat_container_base; + D const* self() const { return static_cast(this); } + D* self() { return static_cast(this); } +public: + using value_compare = first_compare; + value_compare value_comp() const { return value_compare(B::key_comp()); } + + using B::insert; + using B::erase; + + // Modifiers + + iterator insert(value_type const& value) + { + iterator it = self()->upper_bound(value.first); + return self()->container.insert(it.underlying, value); + } + + iterator insert(value_type&& value) + { + iterator it = self()->upper_bound(value.first); + return self()->container.insert(it.underlying, std::move(value)); + } + + template + void insert(InputIt first, InputIt last, delay_sort_t) + { this->ds_insert_(first, last); } + + size_type erase(key_type const& key) + { + auto it_pair = self()->equal_range(key); + std::size_t ret = std::distance(it_pair.first, it_pair.second); + self()->container.erase(it_pair.first.underlying, + it_pair.second.underlying); + return ret; + } + + // Lookup + + size_type count(key_type const& key) const + { + auto it_pair = self()->equal_range(key); + return std::distance(it_pair.first, it_pair.second); + } + +}; + +template +class flat_multimap_base> +: public flat_multimap_base +{ +#include "impl/container_traits.hpp" + using mapped_type = typename value_type::second_type; + using B = flat_multimap_base; + D const* self() const { return static_cast(this); } + D* self() { return static_cast(this); } +public: + + using B::insert; + using B::count; + + // Modifiers + + template + iterator insert(P&& value) + { + iterator it = self()->upper_bound(value.first); + return self()->container.insert(it.underlying, + std::forward

(value)); + } + + // Lookup + + template + size_type count(K const& key) const + { + auto it_pair = self()->equal_range(key); + return std::distance(it_pair.first, it_pair.second); + } +}; + +} // namespace impl + +template> +class flat_multimap +: public impl::flat_multimap_base, + typename Container::value_type::first_type, Container, Compare> +{ +#define FLATNAME flat_multimap +#define FLATKEY typename Container::value_type::first_type +#include "impl/class_def.hpp" +#undef FLATNAME +#undef FLATKEY +}; + +template> +using vector_multimap + = flat_multimap>, Compare>; + +template +inline bool operator==(const flat_multimap& lhs, const flat_multimap& rhs) +{ + return lhs.container == rhs.container; +} +template +inline bool operator!=(const flat_multimap& lhs, const flat_multimap& rhs) +{ + return lhs.container != rhs.container; +} + +} // namespace fc + +#endif diff --git a/external/flat/flat_multiset.hpp b/external/flat/flat_multiset.hpp new file mode 100644 index 000000000..beca937ff --- /dev/null +++ b/external/flat/flat_multiset.hpp @@ -0,0 +1,117 @@ +// Copyright Pubby 2016 +// Distributed under the Boost Software License, Version 1.0. +// http://www.boost.org/LICENSE_1_0.txt + +#ifndef LIB_FLAT_FLAT_MULTISET_HPP +#define LIB_FLAT_FLAT_MULTISET_HPP + +#include "impl/flat_impl.hpp" + +namespace fc { +namespace impl { + +template +class flat_multiset_base +: public flat_container_base +{ +#include "impl/container_traits.hpp" + using B = flat_container_base; + D const* self() const { return static_cast(this); } + D* self() { return static_cast(this); } +public: + using value_compare = Compare; + value_compare value_comp() const { return value_compare(B::key_comp()); } + + using B::insert; + using B::erase; + + // Modifiers + + iterator insert(value_type const& value) + { + iterator it = self()->upper_bound(value); + return self()->container.insert(it.underlying, value); + } + + iterator insert(value_type&& value) + { + iterator it = self()->upper_bound(value); + return self()->container.insert(it.underlying, std::move(value)); + } + + template + void insert(InputIt first, InputIt last, delay_sort_t) + { this->ds_insert_(first, last); } + + size_type erase(key_type const& key) + { + auto it_pair = self()->equal_range(key); + std::size_t ret = std::distance(it_pair.first, it_pair.second); + self()->container.erase(it_pair.first.underlying, + it_pair.second.underlying); + return ret; + } + + // Lookup + + size_type count(key_type const& key) const + { + auto it_pair = self()->equal_range(key); + return std::distance(it_pair.first, it_pair.second); + } +}; + +template +class flat_multiset_base> +: public flat_multiset_base +{ +#include "impl/container_traits.hpp" + using B = flat_multiset_base; + D const* self() const { return static_cast(this); } + D* self() { return static_cast(this); } +public: + using B::count; + + // Lookup + + template + size_type count(K const& key) const + { + auto it_pair = self()->equal_range(key); + return std::distance(it_pair.first, it_pair.second); + } +}; + +} // namespace impl + +template> +class flat_multiset +: public impl::flat_multiset_base, + typename Container::value_type, Container, Compare> +{ +#define FLATNAME flat_multiset +#define FLATKEY typename Container::value_type +#include "impl/class_def.hpp" +#undef FLATNAME +#undef FLATKEY +}; + +template> +using vector_multiset = flat_multiset, Compare>; + +template +inline bool operator==(const flat_multiset& lhs, const flat_multiset& rhs) +{ + return lhs.container == rhs.container; +} +template +inline bool operator!=(const flat_multiset& lhs, const flat_multiset& rhs) +{ + return lhs.container != rhs.container; +} + +} // namespace fc + +#endif diff --git a/external/flat/flat_set.hpp b/external/flat/flat_set.hpp new file mode 100644 index 000000000..7f95049cb --- /dev/null +++ b/external/flat/flat_set.hpp @@ -0,0 +1,129 @@ +// Copyright Pubby 2016 +// Distributed under the Boost Software License, Version 1.0. +// http://www.boost.org/LICENSE_1_0.txt + +#ifndef LIB_FLAT_FLAT_SET_HPP +#define LIB_FLAT_FLAT_SET_HPP + +#include "impl/flat_impl.hpp" + +namespace fc { +namespace impl { + +template +class flat_set_base +: public flat_container_base +{ +#include "impl/container_traits.hpp" + using B = flat_container_base; + D const* self() const { return static_cast(this); } + D* self() { return static_cast(this); } +public: + using value_compare = Compare; + value_compare value_comp() const { return value_compare(B::key_comp()); } + + using B::insert; + using B::erase; + + // Modifiers + + std::pair insert(value_type const& value) + { return insert_(value); } + + std::pair insert(value_type&& value) + { return insert_(std::move(value)); } + + template + void insert(InputIt first, InputIt last, delay_sort_t) + { + this->ds_insert_(first, last); + auto it = std::unique( + self()->container.begin(), self()->container.end(), + impl::eq_comp{value_comp()}); + self()->container.erase(it, self()->container.end()); + } + + size_type erase(key_type const& key) + { + const_iterator it = self()->find(key); + if(it == self()->end()) + return 0; + self()->container.erase(it.underlying); + return 1; + } + + // Lookup + + size_type count(key_type const& key) const + { + return self()->find(key) != self()->end(); + } + +private: + template + std::pair insert_(V&& value) + { + iterator it = self()->lower_bound(value); + if(it == self()->end() || self()->value_comp()(value, *it)) + { + it = self()->container.insert(it.underlying, + std::forward(value)); + return std::make_pair(it, true); + } + return std::make_pair(it, false); + } +}; + +template +class flat_set_base> +: public flat_set_base +{ +#include "impl/container_traits.hpp" + using B = flat_set_base; + D const* self() const { return static_cast(this); } + D* self() { return static_cast(this); } +public: + using B::count; + + // Lookup + + template + size_type count(K const& key) const + { + return self()->find(key) != self()->end(); + } +}; + +} // namespace impl + +template> +class flat_set +: public impl::flat_set_base, + typename Container::value_type, Container, Compare> +{ +#define FLATNAME flat_set +#define FLATKEY typename Container::value_type +#include "impl/class_def.hpp" +#undef FLATNAME +#undef FLATKEY +}; + +template> +using vector_set = flat_set, Compare>; + +template +inline bool operator==(const flat_set& lhs, const flat_set& rhs) +{ + return lhs.container == rhs.container; +} +template +inline bool operator!=(const flat_set& lhs, const flat_set& rhs) +{ + return lhs.container != rhs.container; +} + +} // namespace fc + +#endif diff --git a/external/flat/impl/class_def.hpp b/external/flat/impl/class_def.hpp new file mode 100644 index 000000000..d29e24b2f --- /dev/null +++ b/external/flat/impl/class_def.hpp @@ -0,0 +1,60 @@ +// Copyright Pubby 2016 +// Distributed under the Boost Software License, Version 1.0. +// http://www.boost.org/LICENSE_1_0.txt + +private: + using D = FLATNAME; + using Key = FLATKEY; +public: +#include "container_traits.hpp" + + FLATNAME() = default; + explicit FLATNAME(Compare const& comp) : comp(comp), container() {} + + template + FLATNAME(InputIt first, InputIt last) + : FLATNAME() { this->insert(first, last); } + + template + FLATNAME(InputIt first, InputIt last, Compare const& comp) + : FLATNAME(comp) { this->insert(first, last); } + + template + FLATNAME(InputIt first, InputIt last, delay_sort_t d) + : FLATNAME() { this->insert(first, last, d); } + + template + FLATNAME(InputIt first, InputIt last, Compare const& comp, delay_sort_t d) + : FLATNAME(comp) { this->insert(first, last, d); } + + FLATNAME(FLATNAME const&) = default; + FLATNAME(FLATNAME&&) = default; + + FLATNAME(std::initializer_list ilist) + : FLATNAME() { this->insert(ilist); } + + FLATNAME(std::initializer_list ilist, delay_sort_t d) + : FLATNAME() { this->insert(ilist, d); } + + FLATNAME(std::initializer_list ilist, + Compare const& comp, delay_sort_t d) + : FLATNAME(comp) { this->insert(ilist, d); } + + template + explicit FLATNAME(container_construct_t, Args&&... args) + : container(std::forward(args)...), comp() {} + + template + FLATNAME(Compare const& comp, container_construct_t, Args&&... args) + : container(std::forward(args)...), comp(comp) {} + + FLATNAME& operator=(FLATNAME const&) = default; + FLATNAME& operator=(FLATNAME&&) = default; + FLATNAME& operator=(std::initializer_list ilist) + { this->clear(); this->insert(ilist); return *this; } + + Container container; + Compare comp; + +#undef FLATNAME +#undef FLATKEY diff --git a/external/flat/impl/container_traits.hpp b/external/flat/impl/container_traits.hpp new file mode 100644 index 000000000..31e16423d --- /dev/null +++ b/external/flat/impl/container_traits.hpp @@ -0,0 +1,25 @@ +// Copyright Pubby 2016 +// Distributed under the Boost Software License, Version 1.0. +// http://www.boost.org/LICENSE_1_0.txt + +using container_type = Container; +using key_type = Key; +using size_type = typename container_type::size_type; +using difference_type = typename container_type::difference_type; +using value_type = typename container_type::value_type; +using iterator + = impl::flat_iterator< + typename container_type::iterator, + impl::dummy_iterator>; +using const_iterator + = impl::flat_iterator< + typename container_type::const_iterator, + iterator>; +using reverse_iterator + = impl::flat_iterator< + typename container_type::reverse_iterator, + impl::dummy_iterator>; +using const_reverse_iterator + = impl::flat_iterator< + typename container_type::const_reverse_iterator, + reverse_iterator>; diff --git a/external/flat/impl/flat_impl.hpp b/external/flat/impl/flat_impl.hpp new file mode 100644 index 000000000..2d639620e --- /dev/null +++ b/external/flat/impl/flat_impl.hpp @@ -0,0 +1,470 @@ +// Copyright Pubby 2016 +// Distributed under the Boost Software License, Version 1.0. +// http://www.boost.org/LICENSE_1_0.txt + +#ifndef LIB_FLAT_FLAT_IMPL_HPP +#define LIB_FLAT_FLAT_IMPL_HPP + +#include +#include +#include +#include +#include + +namespace fc { + +struct delay_sort_t {}; +constexpr delay_sort_t delay_sort = {}; + +struct container_construct_t {}; +constexpr container_construct_t container_construct = {}; + +namespace impl { + +template +using transparent_key_t = std::reference_wrapper; + +template +struct eq_comp +{ + template + bool operator()(A const& lhs, B const& rhs) + { return !comp(lhs, rhs) && !comp(rhs, lhs); } + Comp comp; +}; + + +template +struct dummy_iterator +{ + dummy_iterator() = delete; + dummy_iterator(dummy_iterator const&) = delete; + It underlying; +}; + +template::iterator_category> +class flat_iterator; + +template +class flat_iterator +{ + using traits = std::iterator_traits; +public: + using difference_type = typename traits::difference_type; + using value_type = typename traits::value_type const; + using pointer = value_type*; + using reference = value_type&; + using iterator_category = std::random_access_iterator_tag; + + flat_iterator() = default; + flat_iterator(flat_iterator const&) = default; + flat_iterator(flat_iterator&&) = default; + flat_iterator(Convert const& c) : underlying(c.underlying) {} + flat_iterator(Convert&& c) : underlying(std::move(c.underlying)) {} + flat_iterator(It const& underlying) : underlying(underlying) {} + flat_iterator(It&& underlying) : underlying(std::move(underlying)) {} + + flat_iterator& operator=(flat_iterator const& u) = default; + flat_iterator& operator=(flat_iterator&& u) = default; + flat_iterator& operator=(It const& u) + { this->underlying = u; return *this; } + flat_iterator& operator=(It&& u) + { this->underlying = std::move(u); return *this; } + + reference operator*() const { return *underlying; } + pointer operator->() const { return std::addressof(*underlying); } + + flat_iterator& operator++() { ++this->underlying; return *this; } + flat_iterator operator++(int) + { flat_iterator it = *this; ++this->underlying; return it; } + + flat_iterator& operator--() { --this->underlying; return *this; } + flat_iterator operator--(int) + { flat_iterator it = *this; --this->underlying; return it; } + + flat_iterator& operator+=(difference_type d) + { this->underlying += d; return *this; } + flat_iterator& operator-=(difference_type d) + { this->underlying -= d; return *this; } + + flat_iterator operator+(difference_type d) const + { return this->underlying + d; } + flat_iterator operator-(difference_type d) const + { return this->underlying - d; } + + difference_type operator-(flat_iterator const& o) const + { return this->underlying - o.underlying; } + + reference operator[](difference_type d) const { return *(*this + d); } + + auto operator==(flat_iterator const& o) const + { + using namespace std::rel_ops; + return this->underlying == o.underlying; + } + auto operator!=(flat_iterator const& o) const + { + using namespace std::rel_ops; + return this->underlying != o.underlying; + } + auto operator<(flat_iterator const& o) const + { return this->underlying < o.underlying; } + auto operator<=(flat_iterator const& o) const + { return this->underlying <= o.underlying; } + auto operator>(flat_iterator const& o) const + { return this->underlying > o.underlying; } + auto operator>=(flat_iterator const& o) const + { return this->underlying >= o.underlying; } + + It underlying; +}; + +template, typename TransparentKey = void> +struct first_compare +{ + first_compare(const Compare& comp) : + compare(comp) { + } + + bool operator()(Pair const& lhs, Pair const& rhs) const + { + return compare.get()(lhs.first, rhs.first); + } + + bool operator()(typename Pair::first_type const& lhs, Pair const& rhs) const + { + return compare.get()(lhs, rhs.first); + } + + bool operator()(Pair const& lhs, typename Pair::first_type const& rhs) const + { + return compare.get()(lhs.first, rhs); + } + + template + bool operator()(transparent_key_t const& lhs, Pair const& rhs) const + { + return compare.get()(lhs.get(), rhs.first); + } + + template + bool operator()(transparent_key_t const& lhs, typename Pair::first_type const& rhs) const + { + return compare.get()(lhs.get(), rhs); + } + + template + bool operator()(Pair const& lhs, transparent_key_t const& rhs) const + { + return compare.get()(lhs.first, rhs.get()); + } + + template + bool operator()(typename Pair::first_type const& lhs, transparent_key_t const& rhs) const + { + return compare.get()(lhs, rhs.get()); + } + + std::reference_wrapper compare; +}; + +template +class flat_container_base +{ +#include "container_traits.hpp" + D const* self() const { return static_cast(this); } + D* self() { return static_cast(this); } +public: + using key_compare = Compare; + const key_compare &key_comp() const { return self()->comp; } + + // Iterators + + const_iterator cbegin() const + noexcept(noexcept(std::declval().container.cbegin())) + { return self()->container.cbegin(); } + const_iterator begin() const + noexcept(noexcept(std::declval().container.begin())) + { return self()->container.begin(); } + iterator begin() + noexcept(noexcept(std::declval().container.begin())) + { return self()->container.begin(); } + + const_iterator cend() const + noexcept(noexcept(std::declval().container.cend())) + { return self()->container.cend(); } + const_iterator end() const + noexcept(noexcept(std::declval().container.end())) + { return self()->container.end(); } + iterator end() + noexcept(noexcept(std::declval().container.end())) + { return self()->container.end(); } + + const_reverse_iterator crbegin() const + noexcept(noexcept(std::declval().container.crbegin())) + { return self()->container.crbegin(); } + const_reverse_iterator rbegin() const + noexcept(noexcept(std::declval().container.rbegin())) + { return self()->container.rbegin(); } + reverse_iterator rbegin() + noexcept(noexcept(std::declval().container.rbegin())) + { return self()->container.rbegin(); } + + const_reverse_iterator crend() const + noexcept(noexcept(std::declval().container.crend())) + { return self()->container.crend(); } + const_reverse_iterator rend() const + noexcept(noexcept(std::declval().container.rend())) + { return self()->container.rend(); } + reverse_iterator rend() + noexcept(noexcept(std::declval().container.rend())) + { return self()->container.rend(); } + + // Capacity + + bool empty() const + noexcept(noexcept(std::declval().container.empty())) + { return self()->container.empty(); } + + size_type size() const + noexcept(noexcept(std::declval().container.size())) + { return self()->container.size(); } + + // Modifiers + + iterator insert(const_iterator hint, value_type const& value) + { return self()->insert(value).first; } + + iterator insert(const_iterator hint, value_type&& value) + { return self()->insert(std::move(value)).first; } + + template + void insert(InputIt first, InputIt last) + { + for(InputIt it = first; it != last; ++it) + self()->insert(*it); + } + + void insert(std::initializer_list ilist) + { self()->insert(ilist.begin(), ilist.end()); } + + void insert(std::initializer_list ilist, delay_sort_t d) + { self()->insert(ilist.begin(), ilist.end(), d); } + + template + auto emplace(Args&&... args) + { return self()->insert(value_type(std::forward(args)...)); } + + template + auto emplace_hint(const_iterator hint, Args&&... args) + { return self()->insert(value_type(std::forward(args)...)); } + + iterator erase(const_iterator pos) + noexcept(noexcept(std::declval().container.erase(pos.underlying))) + { return self()->container.erase(pos.underlying); } + + iterator erase(const_iterator first, const_iterator last) + noexcept(noexcept(std::declval().container.erase(first.underlying, + last.underlying))) + { return self()->container.erase(first.underlying, last.underlying); } + + void clear() + noexcept(noexcept(std::declval().container.clear())) + { self()->container.clear(); } + + void swap(D& other) + noexcept(D::has_noexcept_swap()) + { + using std::swap; + swap(self()->container, other.container); + } + + // Lookup + + const_iterator find(key_type const& key) const + { + const_iterator it = self()->lower_bound(key); + if(it == self()->end() || self()->value_comp()(key, *it)) + return self()->end(); + return it; + } + + iterator find(key_type const& key) + { + iterator it = self()->lower_bound(key); + if(it == self()->end() || self()->value_comp()(key, *it)) + return self()->end(); + return it; + } + + const_iterator lower_bound(key_type const& key) const + { + return std::lower_bound( + self()->begin(), self()->end(), + key, self()->value_comp()); + } + + iterator lower_bound(key_type const& key) + { + return std::lower_bound( + self()->begin(), self()->end(), + key, self()->value_comp()); + } + + const_iterator upper_bound(key_type const& key) const + { + return std::upper_bound( + self()->begin(), self()->end(), + key, self()->value_comp()); + } + + iterator upper_bound(key_type const& key) + { + return std::upper_bound( + self()->begin(), self()->end(), + key, self()->value_comp()); + } + + std::pair + equal_range(key_type const& key) const + { + return std::equal_range( + self()->begin(), self()->end(), + key, self()->value_comp()); + } + + std::pair equal_range(key_type const& key) + { + return std::equal_range( + self()->begin(), self()->end(), + key, self()->value_comp()); + } + +private: + static constexpr bool has_noexcept_swap() + { + using std::swap; + return noexcept(swap(*static_cast(nullptr), + *static_cast(nullptr))); + } + +protected: + template + void ds_insert_(InputIt first, InputIt last) + { + size_type const i = self()->size(); + for(InputIt it = first; it != last; ++it) + self()->container.push_back(*it); + std::sort( + self()->container.begin()+i, + self()->container.end(), + self()->value_comp()); + std::inplace_merge( + self()->container.begin(), + self()->container.begin()+i, + self()->container.end()); + // Note: Not calling unique here. Do it in the caller. + } +}; + +template +class flat_container_base> +: public flat_container_base +{ +#include "container_traits.hpp" + D const* self() const { return static_cast(this); } + D* self() { return static_cast(this); } + using B = flat_container_base; +public: + + using B::insert; + using B::find; + using B::lower_bound; + using B::upper_bound; + using B::equal_range; + + // Modifiers + + template + iterator insert(const_iterator hint, P&& value) + { return insert(std::forward

(value)).first; } + + // Lookup + + template + const_iterator find(K const& key) const + { + const_iterator it = self()->lower_bound(key); + if (it == self()->end() || self()->value_comp()(std::ref(key), *it)) + return self()->end(); + return it; + } + + template + iterator find(K const& key) + { + iterator it = self()->lower_bound(key); + if (it == self()->end() || self()->value_comp()(std::ref(key), *it)) + return self()->end(); + return it; + } + + template + const_iterator lower_bound(K const& key) const + { + return std::lower_bound( + self()->begin(), self()->end(), + std::ref(key), self()->value_comp()); + } + + template + iterator lower_bound(K const& key) + { + return std::lower_bound( + self()->begin(), self()->end(), + std::ref(key), self()->value_comp()); + } + + template + const_iterator upper_bound(K const& key) const + { + return std::upper_bound( + self()->begin(), self()->end(), + std::ref(key), self()->value_comp()); + } + + template + iterator upper_bound(K const& key) + { + return std::upper_bound( + self()->begin(), self()->end(), + std::ref(key), self()->value_comp()); + } + + template + std::pair + equal_range(K const& key) const + { + return std::equal_range( + self()->begin(), self()->end(), + std::ref(key), self()->value_comp()); + } + + template + std::pair equal_range(K const& key) + { + return std::equal_range( + self()->begin(), self()->end(), + std::ref(key), self()->value_comp()); + } +}; + +} // namespace fc +} // namespace impl + +#endif From 532aca85f5d3c078ee7554efd3fd6f14a64f74c5 Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 21 Jul 2020 10:19:33 -0700 Subject: [PATCH 049/175] :wrench: add mpm_properties --- include/mpm_properties.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 include/mpm_properties.h diff --git a/include/mpm_properties.h b/include/mpm_properties.h new file mode 100644 index 000000000..c582c8ff4 --- /dev/null +++ b/include/mpm_properties.h @@ -0,0 +1,26 @@ +#ifndef MPM_PROPERTIES_H_ +#define MPM_PROPERTIES_H_ + +namespace mpm { +namespace properties { +//! Scalar Properties +enum Scalar : unsigned int { + Mass, + Volume, + MassDensity, + MassPressure, + Pressure +}; +//! Vector Properties +enum Vector : unsigned int { + Displacement, + Velocity, + Acceleration, + Momentum, + ExternalForce, + InternalForce +}; +} // namespace properties +} // namespace mpm + +#endif // MPM_PROPERTIES_H_ \ No newline at end of file From b017a9948968a1965988ce6c5fe03fee1a84fc46 Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 21 Jul 2020 10:36:17 -0700 Subject: [PATCH 050/175] :wrench: 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 b7870da8f..d3c91d936 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -811,8 +811,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 6de587f0326aa964ecf09d90c5a35c7d899a25e6 Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 21 Jul 2020 10:36:42 -0700 Subject: [PATCH 051/175] :wrench: add functions and container in node --- include/node.h | 35 ++++++++++++++++++++++++++++++ include/node.tcc | 53 +++++++++++++++++++++++++++++++++++++++++++++ include/node_base.h | 32 +++++++++++++++++++++++++++ 3 files changed, 120 insertions(+) diff --git a/include/node.h b/include/node.h index c815a8f78..f7c8e8b0e 100644 --- a/include/node.h +++ b/include/node.h @@ -65,6 +65,35 @@ class Node : public NodeBase { //! Return status bool status() const override { return status_; } + //! Update scalar property at the nodes + //! \param[in] property Name of the property to update + //! \param[in] update A boolean to update (true) or assign (false) + //! \param[in] phase Index corresponding to the phase + //! \param[in] value Property value from the particles in a cell + void update_scalar_property(mpm::properties::Scalar property, bool update, + unsigned phase, double value) noexcept override; + + //! Return property at a given node for a given phase + //! \param[in] property Name of the property to return + //! \param[in] phase Index corresponding to the phase + double scalar_property(mpm::properties::Scalar property, + unsigned phase) const override; + + //! Update vector property at the nodes + //! \param[in] property Name of the property to update + //! \param[in] update A boolean to update (true) or assign (false) + //! \param[in] phase Index corresponding to the phase + //! \param[in] value Property value from the particles in a cell + virtual void update_vector_property( + mpm::properties::Vector property, bool update, unsigned phase, + const Eigen::Matrix& value) noexcept override; + + //! Return property at a given node for a given phase + //! \param[in] property Name of the property to return + //! \param[in] phase Index corresponding to the phase + virtual Eigen::Matrix vector_property( + mpm::properties::Vector property, unsigned phase) const override; + //! Update mass at the nodes from particle //! \param[in] update A boolean to update (true) or assign (false) //! \param[in] phase Index corresponding to the phase @@ -278,6 +307,12 @@ class Node : public NodeBase { unsigned dof_{std::numeric_limits::max()}; //! Status bool status_{false}; + //! Scalar properties + fc::vector_map> + scalar_properties_; + //! Vector properties + fc::vector_map> + vector_properties_; //! Mass Eigen::Matrix mass_; //! Volume diff --git a/include/node.tcc b/include/node.tcc index b120493f1..2b3f2bdc5 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -46,6 +46,59 @@ void mpm::Node::initialise_property_handle( this->prop_id_ = prop_id; } +//! Update scalar property at the nodes from particle +template +void mpm::Node::update_scalar_property( + mpm::properties::Scalar property, bool update, unsigned phase, + double value) noexcept { + // Assert phase + assert(phase < Tnphases); + + // Decide to update or assign + const double factor = (update == true) ? 1. : 0.; + + // Update/assign value + std::lock_guard guard(node_mutex_); + scalar_properties_.at(property)[phase] = + (scalar_properties_.at(property)[phase] * factor) + value; +} + +//! Update scalar property at the nodes from particle +template +double mpm::Node::scalar_property( + mpm::properties::Scalar property, unsigned phase) const { + // Assert phase + assert(phase < Tnphases); + return scalar_properties_.at(property)[phase]; +} + +//! Update vector property at the nodes from particle +template +void mpm::Node::update_vector_property( + mpm::properties::Vector property, bool update, unsigned phase, + const Eigen::Matrix& value) noexcept { + // Assert phase + assert(phase < Tnphases); + + // Decide to update or assign + const double factor = (update == true) ? 1. : 0.; + + // Update/assign value + std::lock_guard guard(node_mutex_); + Eigen::Matrix vecvalue = + vector_properties_.at(property).col(phase); + vector_properties_.at(property).col(phase) = (vecvalue * factor) + value; +} + +//! Update vector property at the nodes from particle +template +Eigen::Matrix mpm::Node::vector_property( + mpm::properties::Vector property, unsigned phase) const { + // Assert phase + assert(phase < Tnphases); + return vector_properties_.at(property).col(phase); +} + //! Update mass at the nodes from particle template void mpm::Node::update_mass(bool update, unsigned phase, diff --git a/include/node_base.h b/include/node_base.h index 17eddfdca..d751d7688 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -10,9 +10,11 @@ #include #include +#include #include "data_types.h" #include "function_base.h" +#include "mpm_properties.h" #include "nodal_properties.h" namespace mpm { @@ -70,6 +72,36 @@ class NodeBase { //! Return status virtual bool status() const = 0; + //! Update scalar property at the nodes + //! \param[in] property Name of the property to update + //! \param[in] update A boolean to update (true) or assign (false) + //! \param[in] phase Index corresponding to the phase + //! \param[in] value Property value from the particles in a cell + virtual void update_scalar_property(mpm::properties::Scalar property, + bool update, unsigned phase, + double value) noexcept = 0; + + //! Return property at a given node for a given phase + //! \param[in] property Name of the property to return + //! \param[in] phase Index corresponding to the phase + virtual double scalar_property(mpm::properties::Scalar property, + unsigned phase) const = 0; + + //! Update vector property at the nodes + //! \param[in] property Name of the property to update + //! \param[in] update A boolean to update (true) or assign (false) + //! \param[in] phase Index corresponding to the phase + //! \param[in] value Property value from the particles in a cell + virtual void update_vector_property( + mpm::properties::Vector property, bool update, unsigned phase, + const Eigen::Matrix& value) noexcept = 0; + + //! Return property at a given node for a given phase + //! \param[in] property Name of the property to return + //! \param[in] phase Index corresponding to the phase + virtual Eigen::Matrix vector_property( + mpm::properties::Vector property, unsigned phase) const = 0; + //! Update mass at the nodes from particle //! \param[in] update A boolean to update (true) or assign (false) //! \param[in] phase Index corresponding to the phase From 9f42d94c06d01eb394694fd3153b562f25b459a3 Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 21 Jul 2020 11:05:04 -0700 Subject: [PATCH 052/175] :wrench: add functions and container in particle --- include/particles/particle.h | 4 +- include/particles/particle_base.h | 74 ++++++++++++++++++++ include/particles/particle_base.tcc | 103 ++++++++++++++++++++++++++++ 3 files changed, 179 insertions(+), 2 deletions(-) diff --git a/include/particles/particle.h b/include/particles/particle.h index f5f02925f..2b20e65fb 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -307,6 +307,8 @@ class Particle : public ParticleBase { using ParticleBase::state_variables_; //! Neighbour particles using ParticleBase::neighbours_; + //! Shape functions + using ParticleBase::shapefn_; //! Volumetric mass density (mass / volume) double mass_density_{0.}; //! Mass @@ -339,8 +341,6 @@ class Particle : public ParticleBase { bool set_traction_{false}; //! Surface Traction (given as a stress; force/area) Eigen::Matrix traction_; - //! Shape functions - Eigen::VectorXd shapefn_; //! dN/dX Eigen::MatrixXd dn_dx_; //! dN/dX at cell centroid diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index d8e006fb3..ced7b4f1f 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -124,6 +124,73 @@ class ParticleBase { //! Return size of particle in natural coordinates virtual VectorDim natural_size() const = 0; + //! Update scalar property at the particle + //! \param[in] property Name of the property to update + //! \param[in] update A boolean to update (true) or assign (false) + //! \param[in] value Property value from the particles in a cell + void update_scalar_property(mpm::properties::Scalar property, bool update, + double value) noexcept; + + //! Return property + //! \param[in] phase Index corresponding to the phase + double scalar_property(mpm::properties::Scalar property) const; + + //! Map scalar property to the nodes + //! \param[in] property Name of the property to update + //! \param[in] update A boolean to update (true) or assign (false) + //! \param[in] phase Index corresponding to the phase + void map_scalar_property_nodes(mpm::properties::Scalar property, bool update, + unsigned phase) noexcept; + + //! Map an arbitrary scalar value to nodal scalar property + //! \param[in] property Name of the property to update + //! \param[in] update A boolean to update (true) or assign (false) + //! \param[in] phase Index corresponding to the phase + //! \param[in] value Scalar value to be mapped from particle to node + void map_scalar_property_nodes(mpm::properties::Scalar property, bool update, + unsigned phase, double value) noexcept; + + //! Return an interpolation of scalar property in particle from nodes + //! \param[in] property Name of the property to update + //! \param[in] phase Index corresponding to the phase + double interpolate_scalar_property_nodes(mpm::properties::Scalar property, + unsigned phase) const; + + //! Update vector property at the particle + //! \param[in] property Name of the property to update + //! \param[in] update A boolean to update (true) or assign (false) + //! \param[in] value Property value from the particles in a cell + void update_vector_property( + mpm::properties::Vector property, bool update, + const Eigen::Matrix& value) noexcept; + + //! Return property + //! \param[in] phase Index corresponding to the phase + Eigen::Matrix vector_property( + mpm::properties::Vector property) const; + + //! Map vector property to the nodes + //! \param[in] property Name of the property to update + //! \param[in] update A boolean to update (true) or assign (false) + //! \param[in] phase Index corresponding to the phase + void map_vector_property_nodes(mpm::properties::Vector property, bool update, + unsigned phase) noexcept; + + //! Map an arbitrary vector value to nodal vector property + //! \param[in] property Name of the property to update + //! \param[in] update A boolean to update (true) or assign (false) + //! \param[in] phase Index corresponding to the phase + //! \param[in] value Vector value to be mapped from particle to node + void map_vector_property_nodes( + mpm::properties::Vector property, bool update, unsigned phase, + const Eigen::Matrix& value) noexcept; + + //! Return an interpolation of vector property in particle from nodes + //! \param[in] property Name of the property to update + //! \param[in] phase Index corresponding to the phase + Eigen::Matrix interpolate_vector_property_nodes( + mpm::properties::Vector property, unsigned phase) const; + //! Compute volume of particle virtual void compute_volume() noexcept = 0; @@ -282,6 +349,13 @@ class ParticleBase { mpm::dense_map state_variables_; //! Vector of particle neighbour ids std::vector neighbours_; + //! Shape functions + Eigen::VectorXd shapefn_; + //! Scalar properties + fc::vector_map scalar_properties_; + //! Vector properties + fc::vector_map> + vector_properties_; }; // ParticleBase class } // namespace mpm diff --git a/include/particles/particle_base.tcc b/include/particles/particle_base.tcc index a75e8ca0b..f67c45ebf 100644 --- a/include/particles/particle_base.tcc +++ b/include/particles/particle_base.tcc @@ -15,3 +15,106 @@ mpm::ParticleBase::ParticleBase(Index id, const VectorDim& coord, : mpm::ParticleBase::ParticleBase(id, coord) { status_ = status; } + +//! Update scalar property at particle +template +void mpm::ParticleBase::update_scalar_property( + mpm::properties::Scalar property, bool update, double value) noexcept { + // Decide to update or assign + const double factor = (update == true) ? 1. : 0.; + scalar_properties_.at(property) = + scalar_properties_.at(property) * factor + value; +} + +//! Update scalar property at particle +template +double mpm::ParticleBase::scalar_property( + mpm::properties::Scalar property) const { + return scalar_properties_.at(property); +} + +//! Map scalar property to nodes +template +void mpm::ParticleBase::map_scalar_property_nodes( + mpm::properties::Scalar property, bool update, unsigned phase) noexcept { + // Check if particle property is set + assert(scalar_properties_.at(property) != std::numeric_limits::max()); + + // Map scalar property to nodes + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->update_scalar_property( + property, update, phase, scalar_properties_.at(property) * shapefn_[i]); +} + +//! Map an arbitrary scalar value to nodal scalar property +template +void mpm::ParticleBase::map_scalar_property_nodes( + mpm::properties::Scalar property, bool update, unsigned phase, + double value) noexcept { + // Map scalar value to nodes + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->update_scalar_property(property, update, phase, + value * shapefn_[i]); +} + +//! Interpolate scalar property from nodes +template +double mpm::ParticleBase::interpolate_scalar_property_nodes( + mpm::properties::Scalar property, unsigned phase) const { + double value = 0.; + // Interpolate scalar property from nodes + for (unsigned i = 0; i < nodes_.size(); ++i) + value += nodes_[i]->scalar_property(property, phase) * shapefn_[i]; + return value; +} + +//! Update vector property at particle +template +void mpm::ParticleBase::update_vector_property( + mpm::properties::Vector property, bool update, + const Eigen::Matrix& value) noexcept { + // Decide to update or assign + const double factor = (update == true) ? 1. : 0.; + vector_properties_.at(property) = + vector_properties_.at(property) * factor + value; +} + +//! Update vector property at particle +template +Eigen::Matrix mpm::ParticleBase::vector_property( + mpm::properties::Vector property) const { + return vector_properties_.at(property); +} + +//! Map vector property to nodes +template +void mpm::ParticleBase::map_vector_property_nodes( + mpm::properties::Vector property, bool update, unsigned phase) noexcept { + // Map vector property to nodes + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->update_vector_property( + property, update, phase, vector_properties_.at(property) * shapefn_[i]); +} + +//! Map an arbitrary vector value to nodal vector property +template +void mpm::ParticleBase::map_vector_property_nodes( + mpm::properties::Vector property, bool update, unsigned phase, + const Eigen::Matrix& value) noexcept { + // Map vector property to nodes + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->update_vector_property(property, update, phase, + value * shapefn_[i]); +} + +//! Interpolate vector property from nodes +template +Eigen::Matrix + mpm::ParticleBase::interpolate_vector_property_nodes( + mpm::properties::Vector property, unsigned phase) const { + Eigen::Matrix value = Eigen::Matrix::Zero(); + // Interpolate vector property from nodes + for (unsigned i = 0; i < nodes_.size(); ++i) + value += nodes_[i]->vector_property(property, phase) * shapefn_[i]; + return value; +} From da1682e4e3332c3f8fc373d39a28951b01063130 Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 21 Jul 2020 12:07:54 -0700 Subject: [PATCH 053/175] :construction: cosmetic changes as suggested --- include/node.h | 2 ++ include/node_base.h | 2 ++ include/particles/particle_base.h | 29 +++++++++++++++++------------ include/particles/particle_base.tcc | 12 ++++++------ 4 files changed, 27 insertions(+), 18 deletions(-) diff --git a/include/node.h b/include/node.h index f7c8e8b0e..19bea7512 100644 --- a/include/node.h +++ b/include/node.h @@ -76,6 +76,7 @@ class Node : public NodeBase { //! Return property at a given node for a given phase //! \param[in] property Name of the property to return //! \param[in] phase Index corresponding to the phase + //! \retval scalar property at the designated phase double scalar_property(mpm::properties::Scalar property, unsigned phase) const override; @@ -91,6 +92,7 @@ class Node : public NodeBase { //! Return property at a given node for a given phase //! \param[in] property Name of the property to return //! \param[in] phase Index corresponding to the phase + //! \retval vector property at the designated phase virtual Eigen::Matrix vector_property( mpm::properties::Vector property, unsigned phase) const override; diff --git a/include/node_base.h b/include/node_base.h index d751d7688..24abdde58 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -84,6 +84,7 @@ class NodeBase { //! Return property at a given node for a given phase //! \param[in] property Name of the property to return //! \param[in] phase Index corresponding to the phase + //! \retval scalar property at the designated phase virtual double scalar_property(mpm::properties::Scalar property, unsigned phase) const = 0; @@ -99,6 +100,7 @@ class NodeBase { //! Return property at a given node for a given phase //! \param[in] property Name of the property to return //! \param[in] phase Index corresponding to the phase + //! \retval vector property at the designated phase virtual Eigen::Matrix vector_property( mpm::properties::Vector property, unsigned phase) const = 0; diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index ced7b4f1f..ab4df0019 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -131,30 +131,33 @@ class ParticleBase { void update_scalar_property(mpm::properties::Scalar property, bool update, double value) noexcept; - //! Return property + //! Return scalar property //! \param[in] phase Index corresponding to the phase + //! \retval scalar property at particle double scalar_property(mpm::properties::Scalar property) const; //! Map scalar property to the nodes //! \param[in] property Name of the property to update //! \param[in] update A boolean to update (true) or assign (false) //! \param[in] phase Index corresponding to the phase - void map_scalar_property_nodes(mpm::properties::Scalar property, bool update, - unsigned phase) noexcept; + void map_scalar_property_to_nodes(mpm::properties::Scalar property, + bool update, unsigned phase) noexcept; //! Map an arbitrary scalar value to nodal scalar property //! \param[in] property Name of the property to update //! \param[in] update A boolean to update (true) or assign (false) //! \param[in] phase Index corresponding to the phase //! \param[in] value Scalar value to be mapped from particle to node - void map_scalar_property_nodes(mpm::properties::Scalar property, bool update, - unsigned phase, double value) noexcept; + void map_scalar_property_to_nodes(mpm::properties::Scalar property, + bool update, unsigned phase, + double value) noexcept; //! Return an interpolation of scalar property in particle from nodes //! \param[in] property Name of the property to update //! \param[in] phase Index corresponding to the phase - double interpolate_scalar_property_nodes(mpm::properties::Scalar property, - unsigned phase) const; + //! \retval interpolated scalar property at particle + double interpolate_scalar_property_from_nodes( + mpm::properties::Scalar property, unsigned phase) const; //! Update vector property at the particle //! \param[in] property Name of the property to update @@ -164,8 +167,9 @@ class ParticleBase { mpm::properties::Vector property, bool update, const Eigen::Matrix& value) noexcept; - //! Return property + //! Return vector property //! \param[in] phase Index corresponding to the phase + //! \retval vector property at particle Eigen::Matrix vector_property( mpm::properties::Vector property) const; @@ -173,22 +177,23 @@ class ParticleBase { //! \param[in] property Name of the property to update //! \param[in] update A boolean to update (true) or assign (false) //! \param[in] phase Index corresponding to the phase - void map_vector_property_nodes(mpm::properties::Vector property, bool update, - unsigned phase) noexcept; + void map_vector_property_to_nodes(mpm::properties::Vector property, + bool update, unsigned phase) noexcept; //! Map an arbitrary vector value to nodal vector property //! \param[in] property Name of the property to update //! \param[in] update A boolean to update (true) or assign (false) //! \param[in] phase Index corresponding to the phase //! \param[in] value Vector value to be mapped from particle to node - void map_vector_property_nodes( + void map_vector_property_to_nodes( mpm::properties::Vector property, bool update, unsigned phase, const Eigen::Matrix& value) noexcept; //! Return an interpolation of vector property in particle from nodes //! \param[in] property Name of the property to update //! \param[in] phase Index corresponding to the phase - Eigen::Matrix interpolate_vector_property_nodes( + //! \retval interpolated vector property at particle + Eigen::Matrix interpolate_vector_property_from_nodes( mpm::properties::Vector property, unsigned phase) const; //! Compute volume of particle diff --git a/include/particles/particle_base.tcc b/include/particles/particle_base.tcc index f67c45ebf..03175fbcb 100644 --- a/include/particles/particle_base.tcc +++ b/include/particles/particle_base.tcc @@ -35,7 +35,7 @@ double mpm::ParticleBase::scalar_property( //! Map scalar property to nodes template -void mpm::ParticleBase::map_scalar_property_nodes( +void mpm::ParticleBase::map_scalar_property_to_nodes( mpm::properties::Scalar property, bool update, unsigned phase) noexcept { // Check if particle property is set assert(scalar_properties_.at(property) != std::numeric_limits::max()); @@ -48,7 +48,7 @@ void mpm::ParticleBase::map_scalar_property_nodes( //! Map an arbitrary scalar value to nodal scalar property template -void mpm::ParticleBase::map_scalar_property_nodes( +void mpm::ParticleBase::map_scalar_property_to_nodes( mpm::properties::Scalar property, bool update, unsigned phase, double value) noexcept { // Map scalar value to nodes @@ -59,7 +59,7 @@ void mpm::ParticleBase::map_scalar_property_nodes( //! Interpolate scalar property from nodes template -double mpm::ParticleBase::interpolate_scalar_property_nodes( +double mpm::ParticleBase::interpolate_scalar_property_from_nodes( mpm::properties::Scalar property, unsigned phase) const { double value = 0.; // Interpolate scalar property from nodes @@ -88,7 +88,7 @@ Eigen::Matrix mpm::ParticleBase::vector_property( //! Map vector property to nodes template -void mpm::ParticleBase::map_vector_property_nodes( +void mpm::ParticleBase::map_vector_property_to_nodes( mpm::properties::Vector property, bool update, unsigned phase) noexcept { // Map vector property to nodes for (unsigned i = 0; i < nodes_.size(); ++i) @@ -98,7 +98,7 @@ void mpm::ParticleBase::map_vector_property_nodes( //! Map an arbitrary vector value to nodal vector property template -void mpm::ParticleBase::map_vector_property_nodes( +void mpm::ParticleBase::map_vector_property_to_nodes( mpm::properties::Vector property, bool update, unsigned phase, const Eigen::Matrix& value) noexcept { // Map vector property to nodes @@ -110,7 +110,7 @@ void mpm::ParticleBase::map_vector_property_nodes( //! Interpolate vector property from nodes template Eigen::Matrix - mpm::ParticleBase::interpolate_vector_property_nodes( + mpm::ParticleBase::interpolate_vector_property_from_nodes( mpm::properties::Vector property, unsigned phase) const { Eigen::Matrix value = Eigen::Matrix::Zero(); // Interpolate vector property from nodes From 3e1f9ff6331c925540d8f3582fb7851b58e39d7b Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 22 Jul 2020 13:51:20 -0700 Subject: [PATCH 054/175] :construction: add boolean property --- include/mpm_properties.h | 2 ++ include/node.h | 13 +++++++++++++ include/node.tcc | 16 ++++++++++++++++ include/node_base.h | 11 +++++++++++ include/particles/particle_base.h | 18 ++++++++++++++++-- include/particles/particle_base.tcc | 14 ++++++++++++++ 6 files changed, 72 insertions(+), 2 deletions(-) diff --git a/include/mpm_properties.h b/include/mpm_properties.h index c582c8ff4..1046c6873 100644 --- a/include/mpm_properties.h +++ b/include/mpm_properties.h @@ -3,6 +3,8 @@ namespace mpm { namespace properties { +//! Boolean Properties +enum Boolean : unsigned int { FreeSurface }; //! Scalar Properties enum Scalar : unsigned int { Mass, diff --git a/include/node.h b/include/node.h index 19bea7512..bc4afd326 100644 --- a/include/node.h +++ b/include/node.h @@ -65,6 +65,17 @@ class Node : public NodeBase { //! Return status bool status() const override { return status_; } + //! Assign boolean property at the nodes + //! \param[in] property Name of the property to assign + //! \param[in] boolean Property boolean (true/false) of the node + void assign_boolean_property(mpm::properties::Boolean property, + bool boolean) noexcept override; + + //! Return boolean property + //! \param[in] property Name of the property to update + //! \retval boolean property at node + bool boolean_property(mpm::properties::Boolean property) const override; + //! Update scalar property at the nodes //! \param[in] property Name of the property to update //! \param[in] update A boolean to update (true) or assign (false) @@ -309,6 +320,8 @@ class Node : public NodeBase { unsigned dof_{std::numeric_limits::max()}; //! Status bool status_{false}; + //! Boolean properties + fc::vector_map boolean_properties_; //! Scalar properties fc::vector_map> scalar_properties_; diff --git a/include/node.tcc b/include/node.tcc index 2b3f2bdc5..c3584b5f0 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -46,6 +46,22 @@ void mpm::Node::initialise_property_handle( this->prop_id_ = prop_id; } +//! Assign boolean property at the nodes +template +void mpm::Node::assign_boolean_property( + mpm::properties::Boolean property, bool boolean) noexcept { + // Update/assign value + std::lock_guard guard(node_mutex_); + boolean_properties_.at(property) = boolean; +} + +//! Return boolean property +template +bool mpm::Node::boolean_property( + mpm::properties::Boolean property) const { + return boolean_properties_.at(property); +} + //! Update scalar property at the nodes from particle template void mpm::Node::update_scalar_property( diff --git a/include/node_base.h b/include/node_base.h index 24abdde58..b0eb77888 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -72,6 +72,17 @@ class NodeBase { //! Return status virtual bool status() const = 0; + //! Assign boolean property at the nodes + //! \param[in] property Name of the property to assign + //! \param[in] boolean Property boolean (true/false) of the node + virtual void assign_boolean_property(mpm::properties::Boolean property, + bool boolean) noexcept = 0; + + //! Return boolean property + //! \param[in] property Name of the property to update + //! \retval boolean property at node + virtual bool boolean_property(mpm::properties::Boolean property) const = 0; + //! Update scalar property at the nodes //! \param[in] property Name of the property to update //! \param[in] update A boolean to update (true) or assign (false) diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index ab4df0019..51a12415d 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -124,6 +124,18 @@ class ParticleBase { //! Return size of particle in natural coordinates virtual VectorDim natural_size() const = 0; + //! Assign boolean property at the particle + //! \param[in] property Name of the property to assign + //! \param[in] boolean Property boolean (true/false) of the particles in a + //! cell + void assign_boolean_property(mpm::properties::Boolean property, + bool boolean) noexcept; + + //! Return boolean property + //! \param[in] property Name of the property to update + //! \retval boolean property at particle + bool boolean_property(mpm::properties::Boolean property) const; + //! Update scalar property at the particle //! \param[in] property Name of the property to update //! \param[in] update A boolean to update (true) or assign (false) @@ -132,7 +144,7 @@ class ParticleBase { double value) noexcept; //! Return scalar property - //! \param[in] phase Index corresponding to the phase + //! \param[in] property Name of the property to return //! \retval scalar property at particle double scalar_property(mpm::properties::Scalar property) const; @@ -168,7 +180,7 @@ class ParticleBase { const Eigen::Matrix& value) noexcept; //! Return vector property - //! \param[in] phase Index corresponding to the phase + //! \param[in] property Name of the property to return //! \retval vector property at particle Eigen::Matrix vector_property( mpm::properties::Vector property) const; @@ -356,6 +368,8 @@ class ParticleBase { std::vector neighbours_; //! Shape functions Eigen::VectorXd shapefn_; + //! Boolean properties + fc::vector_map boolean_properties_; //! Scalar properties fc::vector_map scalar_properties_; //! Vector properties diff --git a/include/particles/particle_base.tcc b/include/particles/particle_base.tcc index 03175fbcb..092340f25 100644 --- a/include/particles/particle_base.tcc +++ b/include/particles/particle_base.tcc @@ -16,6 +16,20 @@ mpm::ParticleBase::ParticleBase(Index id, const VectorDim& coord, status_ = status; } +//! Assign boolean property at the particle +template +void mpm::ParticleBase::assign_boolean_property( + mpm::properties::Boolean property, bool boolean) noexcept { + boolean_properties_.at(property) = boolean; +} + +//! Return boolean property +template +bool mpm::ParticleBase::boolean_property( + mpm::properties::Boolean property) const { + return boolean_properties_.at(property); +} + //! Update scalar property at particle template void mpm::ParticleBase::update_scalar_property( From 47c5f48803327ba2ab587b3b5528a31d2b563c20 Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 22 Jul 2020 15:55:27 -0700 Subject: [PATCH 055/175] :wrench: modify function calls --- include/particles/particle.tcc | 7 ++++--- include/particles/particle_functions.tcc | 26 ++++++++++++------------ 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index 0d5d3c680..58ba73ac8 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -700,14 +700,15 @@ void mpm::Particle::compute_updated_position( // Check if particle has a valid cell ptr assert(cell_ != nullptr); // Get interpolated nodal velocity - const auto& nodal_velocity = this->interpolate_vector_property_nodes( + const auto& nodal_velocity = this->interpolate_vector_property_from_nodes( mpm::properties::Vector::Velocity, mpm::ParticlePhase::Solid); // Acceleration update if (!velocity_update) { // Get interpolated nodal acceleration - const auto& nodal_acceleration = this->interpolate_vector_property_nodes( - mpm::properties::Vector::Acceleration, mpm::ParticlePhase::Solid); + const auto& nodal_acceleration = + this->interpolate_vector_property_from_nodes( + mpm::properties::Vector::Acceleration, mpm::ParticlePhase::Solid); // Update particle velocity from interpolated nodal acceleration vector_properties_.at(mpm::properties::Vector::Velocity) += diff --git a/include/particles/particle_functions.tcc b/include/particles/particle_functions.tcc index 7134f0c89..40646005c 100644 --- a/include/particles/particle_functions.tcc +++ b/include/particles/particle_functions.tcc @@ -57,11 +57,11 @@ void map_mass_momentum_to_nodes( assert(particle->mass() != std::numeric_limits::max()); // Map mass and momentum to nodes - particle->map_scalar_property_nodes(mpm::properties::Scalar::Mass, true, - mpm::ParticlePhase::Solid); - particle->map_vector_property_nodes(mpm::properties::Vector::Momentum, true, - mpm::ParticlePhase::Solid, - particle->mass() * particle->velocity()); + particle->map_scalar_property_to_nodes(mpm::properties::Scalar::Mass, true, + mpm::ParticlePhase::Solid); + particle->map_vector_property_to_nodes( + mpm::properties::Vector::Momentum, true, mpm::ParticlePhase::Solid, + particle->mass() * particle->velocity()); } //! Map particle pressure to nodes @@ -74,7 +74,7 @@ void map_mass_pressure_to_nodes( // Check if state variable pressure is found if (particle->pressure() != std::numeric_limits::quiet_NaN()) { // Map particle pressure to nodes - particle->map_scalar_property_nodes( + particle->map_scalar_property_to_nodes( mpm::properties::Scalar::MassPressure, true, mpm::ParticlePhase::Solid, particle->mass() * particle->pressure()); } @@ -85,9 +85,9 @@ template void map_body_force(std::shared_ptr> particle, const Eigen::Matrix& pgravity) noexcept { // Compute nodal body forces - particle->map_vector_property_nodes(mpm::properties::Vector::ExternalForce, - true, mpm::ParticlePhase::Solid, - pgravity * particle->mass()); + particle->map_vector_property_to_nodes(mpm::properties::Vector::ExternalForce, + true, mpm::ParticlePhase::Solid, + pgravity * particle->mass()); } //! Map traction force @@ -96,9 +96,9 @@ void map_traction_force( std::shared_ptr> particle) noexcept { if (particle->set_traction()) { // Map particle traction forces to nodes - particle->map_vector_property_nodes(mpm::properties::Vector::ExternalForce, - true, mpm::ParticlePhase::Solid, - particle->traction()); + particle->map_vector_property_to_nodes( + mpm::properties::Vector::ExternalForce, true, mpm::ParticlePhase::Solid, + particle->traction()); } } @@ -111,7 +111,7 @@ void compute_pressure_smoothing( // Check if particle has pressure if (particle->pressure() != std::numeric_limits::quiet_NaN()) { - double pressure = particle->interpolate_scalar_property_nodes( + double pressure = particle->interpolate_scalar_property_from_nodes( mpm::properties::Scalar::Pressure, mpm::ParticlePhase::Solid); particle->assign_state_variable("pressure", pressure); } From b8a39327d291f2451fec8e4c353db6d6bf44f819 Mon Sep 17 00:00:00 2001 From: Nanda Date: Fri, 24 Jul 2020 19:45:58 -0700 Subject: [PATCH 056/175] :construction: :dart: add set_traction to boolean_properties and add testing --- include/mpm_properties.h | 2 +- include/particles/particle.h | 5 ----- include/particles/particle.tcc | 7 +++++-- include/particles/particle_base.h | 3 --- include/particles/particle_functions.tcc | 2 +- tests/particle_test.cc | 16 ++++++++++++++++ 6 files changed, 23 insertions(+), 12 deletions(-) diff --git a/include/mpm_properties.h b/include/mpm_properties.h index b280561f1..fa7eddfae 100644 --- a/include/mpm_properties.h +++ b/include/mpm_properties.h @@ -4,7 +4,7 @@ namespace mpm { namespace properties { //! Boolean Properties -enum Boolean : unsigned int { FreeSurface }; +enum Boolean : unsigned int { SetTraction }; //! Scalar Properties enum Scalar : unsigned int { Mass, diff --git a/include/particles/particle.h b/include/particles/particle.h index e254d8dc7..a33e624c8 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -224,9 +224,6 @@ class Particle : public ParticleBase { //! \param[in] phase Index corresponding to the phase VectorDim traction() const override { return traction_; } - //! Return set traction bool - bool set_traction() const override { return set_traction_; } - //! Compute updated position of the particle //! \param[in] dt Analysis time step //! \param[in] velocity_update Update particle velocity from nodal vel @@ -342,8 +339,6 @@ class Particle : public ParticleBase { Eigen::Matrix dstrain_; //! Particle velocity constraints std::map particle_velocity_constraints_; - //! Set traction - bool set_traction_{false}; //! Surface Traction (given as a stress; force/area) Eigen::Matrix traction_; //! dN/dX diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index 58ba73ac8..57f69a061 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -230,7 +230,6 @@ template void mpm::Particle::initialise() { dstrain_.setZero(); natural_size_.setZero(); - set_traction_ = false; size_.setZero(); strain_rate_.setZero(); strain_.setZero(); @@ -238,6 +237,10 @@ void mpm::Particle::initialise() { traction_.setZero(); volumetric_strain_centroid_ = 0.; + // Initialize boolean properties + boolean_properties_.emplace( + std::make_pair(mpm::properties::Boolean::SetTraction, false)); + // Initialize scalar properties scalar_properties_.emplace( std::make_pair(mpm::properties::Scalar::Mass, double(0.))); @@ -685,7 +688,7 @@ bool mpm::Particle::assign_traction(unsigned direction, double traction) { // Assign traction traction_(direction) = traction * this->volume() / this->size_(direction); status = true; - this->set_traction_ = true; + this->assign_boolean_property(mpm::properties::Boolean::SetTraction, true); } 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 9f8a67c2a..c73ed2f3c 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -296,9 +296,6 @@ class ParticleBase { //! Return traction virtual VectorDim traction() const = 0; - //! Return set traction bool - virtual bool set_traction() const = 0; - //! Compute updated position virtual void compute_updated_position( double dt, bool velocity_update = false) noexcept = 0; diff --git a/include/particles/particle_functions.tcc b/include/particles/particle_functions.tcc index 40646005c..f502f96fc 100644 --- a/include/particles/particle_functions.tcc +++ b/include/particles/particle_functions.tcc @@ -94,7 +94,7 @@ void map_body_force(std::shared_ptr> particle, template void map_traction_force( std::shared_ptr> particle) noexcept { - if (particle->set_traction()) { + if (particle->boolean_property(mpm::properties::Boolean::SetTraction)) { // Map particle traction forces to nodes particle->map_vector_property_to_nodes( mpm::properties::Vector::ExternalForce, true, mpm::ParticlePhase::Solid, diff --git a/tests/particle_test.cc b/tests/particle_test.cc index 3663d2889..b8e25107a 100644 --- a/tests/particle_test.cc +++ b/tests/particle_test.cc @@ -234,6 +234,14 @@ TEST_CASE("Particle is checked for 1D case", "[particle][1D]") { else REQUIRE(particle->traction()(i) == Approx(0.).epsilon(Tolerance)); } + + // Check for boolean property assignment and return + REQUIRE(particle->boolean_property(mpm::properties::Boolean::SetTraction) == + true); + particle->assign_boolean_property(mpm::properties::Boolean::SetTraction, + false); + REQUIRE(particle->boolean_property(mpm::properties::Boolean::SetTraction) == + false); } SECTION("Check initialise particle HDF5") { @@ -1368,6 +1376,14 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { else REQUIRE(particle->traction()(i) == Approx(0.).epsilon(Tolerance)); } + + // Check for boolean property assignment and return + REQUIRE(particle->boolean_property(mpm::properties::Boolean::SetTraction) == + true); + particle->assign_boolean_property(mpm::properties::Boolean::SetTraction, + false); + REQUIRE(particle->boolean_property(mpm::properties::Boolean::SetTraction) == + false); } // Check initialise particle from HDF5 file From 68506c12947895371ae62f1ae5e7e2f09786358f Mon Sep 17 00:00:00 2001 From: Nanda Date: Sat, 25 Jul 2020 10:39:08 -0700 Subject: [PATCH 057/175] :wrench: fix particle_function for pressure smoothing --- include/particles/particle_functions.tcc | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/include/particles/particle_functions.tcc b/include/particles/particle_functions.tcc index f502f96fc..fb53fc1ea 100644 --- a/include/particles/particle_functions.tcc +++ b/include/particles/particle_functions.tcc @@ -67,16 +67,17 @@ void map_mass_momentum_to_nodes( //! Map particle pressure to nodes template void map_mass_pressure_to_nodes( - std::shared_ptr> particle) noexcept { + std::shared_ptr> particle, + unsigned phase = mpm::ParticlePhase::Solid) noexcept { // Mass is initialized assert(particle->mass() != std::numeric_limits::max()); // Check if state variable pressure is found - if (particle->pressure() != std::numeric_limits::quiet_NaN()) { + if (particle->pressure(phase) != std::numeric_limits::quiet_NaN()) { // Map particle pressure to nodes particle->map_scalar_property_to_nodes( - mpm::properties::Scalar::MassPressure, true, mpm::ParticlePhase::Solid, - particle->mass() * particle->pressure()); + mpm::properties::Scalar::MassPressure, true, phase, + particle->mass() * particle->pressure(phase)); } } @@ -105,15 +106,16 @@ void map_traction_force( // Compute pressure smoothing of the particle based on nodal pressure template void compute_pressure_smoothing( - std::shared_ptr> particle) noexcept { + std::shared_ptr> particle, + unsigned phase = mpm::ParticlePhase::Solid) noexcept { // Assert assert(particle->cell_ptr()); // Check if particle has pressure - if (particle->pressure() != std::numeric_limits::quiet_NaN()) { + if (particle->pressure(phase) != std::numeric_limits::quiet_NaN()) { double pressure = particle->interpolate_scalar_property_from_nodes( - mpm::properties::Scalar::Pressure, mpm::ParticlePhase::Solid); - particle->assign_state_variable("pressure", pressure); + mpm::properties::Scalar::Pressure, phase); + particle->assign_state_variable("pressure", pressure, phase); } } From 0666b0a345a717d44b257ecfc2e9a1f178ab60d9 Mon Sep 17 00:00:00 2001 From: Nanda Date: Sat, 25 Jul 2020 11:01:25 -0700 Subject: [PATCH 058/175] :construction: :dart: refactor and add test for nodal boolean properties --- include/mpm_properties.h | 2 +- include/node.h | 6 +-- include/node.tcc | 22 ++++++---- tests/node_test.cc | 88 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 105 insertions(+), 13 deletions(-) diff --git a/include/mpm_properties.h b/include/mpm_properties.h index fa7eddfae..170c2bec6 100644 --- a/include/mpm_properties.h +++ b/include/mpm_properties.h @@ -4,7 +4,7 @@ namespace mpm { namespace properties { //! Boolean Properties -enum Boolean : unsigned int { SetTraction }; +enum Boolean : unsigned int { SetTraction, Friction, GenericBC }; //! Scalar Properties enum Scalar : unsigned int { Mass, diff --git a/include/node.h b/include/node.h index f0fa1c065..993abca0b 100644 --- a/include/node.h +++ b/include/node.h @@ -271,7 +271,7 @@ class Node : public NodeBase { void assign_rotation_matrix( const Eigen::Matrix& rotation_matrix) override { rotation_matrix_ = rotation_matrix; - generic_boundary_constraints_ = true; + this->assign_boolean_property(mpm::properties::Boolean::GenericBC, true); } //! Add material id from material points to list of materials in materials_ @@ -348,11 +348,7 @@ class Node : public NodeBase { Eigen::Matrix rotation_matrix_; //! Material ids whose information was passed to this node std::set material_ids_; - //! A general velocity (non-Cartesian/inclined) constraint is specified at the - //! node - bool generic_boundary_constraints_{false}; //! Frictional constraints - bool friction_{false}; std::tuple friction_constraint_; //! Concentrated force Eigen::Matrix concentrated_force_; diff --git a/include/node.tcc b/include/node.tcc index 9b91f7bf4..6fb6f5bad 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -18,6 +18,14 @@ mpm::Node::Node( velocity_constraints_.clear(); concentrated_force_.setZero(); + // Initialize boolean properties + // Friction + boolean_properties_.emplace( + std::make_pair(mpm::properties::Boolean::Friction, false)); + // GenericBC + boolean_properties_.emplace( + std::make_pair(mpm::properties::Boolean::GenericBC, false)); + // Initialize scalar properties // Mass scalar_properties_.emplace( @@ -417,7 +425,7 @@ void mpm::Node::apply_velocity_constraints() { // Phase: Integer value of division (dir / Tdim) const auto phase = static_cast(dir / Tdim); - if (!generic_boundary_constraints_) { + if (!this->boolean_property(mpm::properties::Boolean::GenericBC)) { // Velocity constraints are applied on Cartesian boundaries vector_properties_.at(mpm::properties::Vector::Velocity)( direction, phase) = constraint.second; @@ -460,7 +468,7 @@ bool mpm::Node::assign_friction_constraint( this->friction_constraint_ = std::make_tuple(static_cast(dir), static_cast(sign_n), static_cast(friction)); - this->friction_ = true; + this->assign_boolean_property(mpm::properties::Boolean::Friction, true); } else throw std::runtime_error("Constraint direction is out of bounds"); @@ -474,7 +482,7 @@ bool mpm::Node::assign_friction_constraint( //! Apply friction constraints template void mpm::Node::apply_friction_constraints(double dt) { - if (friction_) { + if (this->boolean_property(mpm::properties::Boolean::Friction)) { auto sign = [](double value) { return (value > 0.) ? 1. : -1.; }; // Set friction constraint @@ -496,7 +504,7 @@ void mpm::Node::apply_friction_constraints(double dt) { // tangential direction to boundary const unsigned dir_t = (Tdim - 1) - dir_n; - if (!generic_boundary_constraints_) { + if (!this->boolean_property(mpm::properties::Boolean::GenericBC)) { // Cartesian case // Normal and tangential acceleration acc_n = vector_properties_.at(mpm::properties::Vector::Acceleration)( @@ -540,7 +548,7 @@ void mpm::Node::apply_friction_constraints(double dt) { acc_t -= sign(acc_t) * mu * std::abs(acc_n); } - if (!generic_boundary_constraints_) { + if (!this->boolean_property(mpm::properties::Boolean::GenericBC)) { // Cartesian case vector_properties_.at(mpm::properties::Vector::Acceleration)( dir_t, phase) = acc_t; @@ -568,7 +576,7 @@ void mpm::Node::apply_friction_constraints(double dt) { const unsigned dir_t1 = dir(dir_n, 1); Eigen::Matrix acc, vel; - if (!generic_boundary_constraints_) { + if (!this->boolean_property(mpm::properties::Boolean::GenericBC)) { // Cartesian case acc = this->acceleration(phase); vel = this->velocity(phase); @@ -617,7 +625,7 @@ void mpm::Node::apply_friction_constraints(double dt) { } } - if (!generic_boundary_constraints_) { + if (!this->boolean_property(mpm::properties::Boolean::GenericBC)) { // Cartesian case vector_properties_.at(mpm::properties::Vector::Acceleration) .col(phase) = acc; diff --git a/tests/node_test.cc b/tests/node_test.cc index 9bd3584c7..3a610136a 100644 --- a/tests/node_test.cc +++ b/tests/node_test.cc @@ -341,12 +341,20 @@ TEST_CASE("Node is checked for 1D case", "[node][1D]") { REQUIRE(node->velocity(Nphase)(i) == Approx(velocity(i)).epsilon(Tolerance)); + // Check boolean properties Friction, should be false + REQUIRE(node->boolean_property(mpm::properties::Boolean::Friction) == + false); + // Apply friction constraints REQUIRE(node->assign_friction_constraint(0, 1., 0.5) == true); // Apply friction constraints REQUIRE(node->assign_friction_constraint(-1, 1., 0.5) == false); REQUIRE(node->assign_friction_constraint(3, 1., 0.5) == false); + // Check boolean properties Friction, should be true + REQUIRE(node->boolean_property(mpm::properties::Boolean::Friction) == + true); + // Test acceleration with constraints acceleration[0] = 0.5 * acceleration[0]; for (unsigned i = 0; i < acceleration.size(); ++i) @@ -979,6 +987,10 @@ TEST_CASE("Node is checked for 2D case", "[node][2D]") { // Apply velocity constraints REQUIRE(node->assign_velocity_constraint(0, -12.5) == true); + // Check boolean properties GenericBC, should be false + REQUIRE(node->boolean_property(mpm::properties::Boolean::GenericBC) == + false); + // Apply rotation matrix with Euler angles alpha = 10 deg, beta = 30 deg Eigen::Matrix euler_angles; euler_angles << 10. * M_PI / 180, 30. * M_PI / 180; @@ -987,6 +999,10 @@ TEST_CASE("Node is checked for 2D case", "[node][2D]") { node->assign_rotation_matrix(rotation_matrix); const auto inverse_rotation_matrix = rotation_matrix.inverse(); + // Check boolean properties GenericBC, should be true + REQUIRE(node->boolean_property(mpm::properties::Boolean::GenericBC) == + true); + // Apply inclined velocity constraints node->apply_velocity_constraints(); @@ -1016,6 +1032,10 @@ TEST_CASE("Node is checked for 2D case", "[node][2D]") { REQUIRE(node->assign_velocity_constraint(0, -12.5) == true); REQUIRE(node->assign_velocity_constraint(1, 7.5) == true); + // Check boolean properties GenericBC, should be false + REQUIRE(node->boolean_property(mpm::properties::Boolean::GenericBC) == + false); + // Apply rotation matrix with Euler angles alpha = -10 deg, beta = 30 // deg Eigen::Matrix euler_angles; @@ -1025,6 +1045,10 @@ TEST_CASE("Node is checked for 2D case", "[node][2D]") { node->assign_rotation_matrix(rotation_matrix); const auto inverse_rotation_matrix = rotation_matrix.inverse(); + // Check boolean properties GenericBC, should be true + REQUIRE(node->boolean_property(mpm::properties::Boolean::GenericBC) == + true); + // Apply inclined velocity constraints node->apply_velocity_constraints(); @@ -1054,11 +1078,19 @@ TEST_CASE("Node is checked for 2D case", "[node][2D]") { } SECTION("Check Cartesian friction constraints") { + // Check boolean properties Friction, should be false + REQUIRE(node->boolean_property(mpm::properties::Boolean::Friction) == + false); + // Apply friction constraints REQUIRE(node->assign_friction_constraint(1, 1, 0.2) == true); // Check out of bounds condition REQUIRE(node->assign_friction_constraint(2, 1, 0.2) == false); + // Check boolean properties Friction, should be true + REQUIRE(node->boolean_property(mpm::properties::Boolean::Friction) == + true); + // Apply friction constraints node->apply_friction_constraints(dt); @@ -1070,9 +1102,21 @@ TEST_CASE("Node is checked for 2D case", "[node][2D]") { } SECTION("Check general friction constraints in 1 direction") { + // Check boolean properties Friction, should be false + REQUIRE(node->boolean_property(mpm::properties::Boolean::Friction) == + false); + // Apply friction constraints REQUIRE(node->assign_friction_constraint(1, 1, 0.2) == true); + // Check boolean properties Friction, should be true + REQUIRE(node->boolean_property(mpm::properties::Boolean::Friction) == + true); + + // Check boolean properties GenericBC, should be false + REQUIRE(node->boolean_property(mpm::properties::Boolean::GenericBC) == + false); + // Apply rotation matrix with Euler angles alpha = 10 deg, beta = 30 deg Eigen::Matrix euler_angles; euler_angles << 10. * M_PI / 180, 30. * M_PI / 180; @@ -1084,6 +1128,10 @@ TEST_CASE("Node is checked for 2D case", "[node][2D]") { // Apply general friction constraints node->apply_friction_constraints(dt); + // Check boolean properties GenericBC, should be true + REQUIRE(node->boolean_property(mpm::properties::Boolean::GenericBC) == + true); + // Check applied constraints on acceleration in the global coordinates acceleration << 4.905579787672637, 4.920772034660430; for (unsigned i = 0; i < Dim; ++i) @@ -1563,6 +1611,10 @@ TEST_CASE("Node is checked for 3D case", "[node][3D]") { REQUIRE(node->assign_velocity_constraint(0, 10.5) == true); REQUIRE(node->assign_velocity_constraint(2, -12.5) == true); + // Check boolean properties GenericBC, should be false + REQUIRE(node->boolean_property(mpm::properties::Boolean::GenericBC) == + false); + // Apply rotation matrix with Euler angles alpha = 10 deg, beta = 20 deg // and gamma = 30 deg Eigen::Matrix euler_angles; @@ -1572,6 +1624,10 @@ TEST_CASE("Node is checked for 3D case", "[node][3D]") { node->assign_rotation_matrix(rotation_matrix); const auto inverse_rotation_matrix = rotation_matrix.inverse(); + // Check boolean properties GenericBC, should be true + REQUIRE(node->boolean_property(mpm::properties::Boolean::GenericBC) == + true); + // Apply constraints node->apply_velocity_constraints(); @@ -1607,6 +1663,10 @@ TEST_CASE("Node is checked for 3D case", "[node][3D]") { REQUIRE(node->assign_velocity_constraint(1, -12.5) == true); REQUIRE(node->assign_velocity_constraint(2, 7.5) == true); + // Check boolean properties GenericBC, should be false + REQUIRE(node->boolean_property(mpm::properties::Boolean::GenericBC) == + false); + // Apply rotation matrix with Euler angles alpha = -10 deg, beta = 20 // deg and gamma = -30 deg Eigen::Matrix euler_angles; @@ -1616,6 +1676,10 @@ TEST_CASE("Node is checked for 3D case", "[node][3D]") { node->assign_rotation_matrix(rotation_matrix); const auto inverse_rotation_matrix = rotation_matrix.inverse(); + // Check boolean properties GenericBC, should be true + REQUIRE(node->boolean_property(mpm::properties::Boolean::GenericBC) == + true); + // Apply constraints node->apply_velocity_constraints(); @@ -1649,11 +1713,19 @@ TEST_CASE("Node is checked for 3D case", "[node][3D]") { } SECTION("Check Cartesian friction constraints") { + // Check boolean properties Friction, should be false + REQUIRE(node->boolean_property(mpm::properties::Boolean::Friction) == + false); + // Apply friction constraints REQUIRE(node->assign_friction_constraint(2, 2, 0.3) == true); // Check out of bounds condition REQUIRE(node->assign_friction_constraint(4, 1, 0.2) == false); + // Check boolean properties Friction, should be true + REQUIRE(node->boolean_property(mpm::properties::Boolean::Friction) == + true); + // Apply constraints node->apply_friction_constraints(dt); @@ -1665,9 +1737,21 @@ TEST_CASE("Node is checked for 3D case", "[node][3D]") { } SECTION("Check general friction constraints in 1 direction") { + // Check boolean properties Friction, should be false + REQUIRE(node->boolean_property(mpm::properties::Boolean::Friction) == + false); + // Apply friction constraints REQUIRE(node->assign_friction_constraint(2, 2, 0.3) == true); + // Check boolean properties Friction, should be true + REQUIRE(node->boolean_property(mpm::properties::Boolean::Friction) == + true); + + // Check boolean properties GenericBC, should be false + REQUIRE(node->boolean_property(mpm::properties::Boolean::GenericBC) == + false); + // Apply rotation matrix with Euler angles alpha = 10 deg, beta = 20 deg // and gamma = 30 deg Eigen::Matrix euler_angles; @@ -1680,6 +1764,10 @@ TEST_CASE("Node is checked for 3D case", "[node][3D]") { // Apply inclined velocity constraints node->apply_friction_constraints(dt); + // Check boolean properties GenericBC, should be true + REQUIRE(node->boolean_property(mpm::properties::Boolean::GenericBC) == + true); + // Check applied constraints on acceleration in the global coordinates acceleration << 4.602895052828914, 4.492575657560740, 4.751301246937935; for (unsigned i = 0; i < Dim; ++i) From 28580013ec2da765069add8a46815515b43558d3 Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Mon, 27 Jul 2020 13:10:52 -0700 Subject: [PATCH 059/175] Modify twophase part based on new structure --- include/mesh.h | 1 + include/mpm_properties.h | 13 +- include/node.h | 10 +- include/node.tcc | 144 ++-- include/node_base.h | 6 - include/particles/particle_base.h | 194 +---- include/particles/particle_functions.tcc | 1 - include/particles/twophase_particle.h | 185 ++--- include/particles/twophase_particle.tcc | 736 ++++++------------ .../particles/twophase_particle_functions.tcc | 268 +++++++ include/solvers/mpm_explicit_twophase.tcc | 179 ++--- 11 files changed, 751 insertions(+), 986 deletions(-) create mode 100644 include/particles/twophase_particle_functions.tcc diff --git a/include/mesh.h b/include/mesh.h index 78496a607..add94d09d 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -41,6 +41,7 @@ using Json = nlohmann::json; #include "particle.h" #include "particle_base.h" #include "traction.h" +#include "twophase_particle.h" #include "vector.h" #include "velocity_constraint.h" diff --git a/include/mpm_properties.h b/include/mpm_properties.h index 4e3568667..d5af683d4 100644 --- a/include/mpm_properties.h +++ b/include/mpm_properties.h @@ -9,7 +9,12 @@ enum Scalar : unsigned int { Volume, MassDensity, MassPressure, - Pressure + Pressure, + //! TwoPhase properties + LiquidMass, + Porosity, + PorePressure, + LiquidMassDensity }; //! Vector Properties enum Vector : unsigned int { @@ -18,7 +23,11 @@ enum Vector : unsigned int { Acceleration, Momentum, ExternalForce, - InternalForce + InternalForce, + //! TwoPhase properties + Permeability, + LiquidVelocity, + DragForce }; } // namespace properties } // namespace mpm diff --git a/include/node.h b/include/node.h index e6a28b8f8..6838052d4 100644 --- a/include/node.h +++ b/include/node.h @@ -160,7 +160,8 @@ class Node : public NodeBase { //! Return drag force coefficient VectorDim drag_force_coefficient() const override { - return drag_force_coefficient_; + return this->vector_property(mpm::properties::Vector::DragForce, + mpm::NodePhase::nSolid); } //! Update pressure at the nodes from particle @@ -170,13 +171,6 @@ class Node : public NodeBase { void update_mass_pressure(bool update, unsigned phase, double mass_pressure) noexcept override; - //! Update drag force coefficient - //! \param[in] update A boolean to update (true) or assign (false) - //! \param[in] drag_force Drag force from the particles in a cell - //! \retval status Update status - bool update_drag_force_coefficient( - bool update, const VectorDim& drag_force_coefficient) override; - //! Compute pressure from the mass pressure virtual void compute_pressure() override; diff --git a/include/node.tcc b/include/node.tcc index 2e119ee30..9ee21854a 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -240,28 +240,6 @@ void mpm::Node::compute_pressure() { } } -//! Update drag force coefficient -template -bool mpm::Node::update_drag_force_coefficient( - bool update, const Eigen::Matrix& drag_force_coefficient) { - bool status = false; - try { - // Decide to update or assign - double factor = 1.0; - if (!update) factor = 0.; - - // Update/assign drag force coefficient - std::lock_guard guard(node_mutex_); - drag_force_coefficient_ = - drag_force_coefficient_ * factor + drag_force_coefficient; - status = true; - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; - } - return status; -} - //! Assign pressure at the nodes from particle template void mpm::Node::update_pressure(bool update, @@ -665,7 +643,9 @@ void mpm::Node momentum = property_handle_->property("momenta", prop_id_, *mitr, Tdim); const Eigen::Matrix change_in_momenta = - vector_properties_.at(mpm::properties::Vector::Velocity) * mass - + vector_properties_.at(mpm::properties::Vector::Velocity) + .col(mpm::NodePhase::nSolid) * + mass - momentum; property_handle_->update_property("change_in_momenta", prop_id_, *mitr, change_in_momenta, Tdim); @@ -722,32 +702,37 @@ bool mpm::Node:: compute_acceleration_velocity_twophase_explicit(double dt) noexcept { bool status = false; const double tolerance = 1.0E-15; - if (mass_(mpm::NodePhase::nSolid) > tolerance && - mass_(mpm::NodePhase::nLiquid) > tolerance) { + if (this->mass(mpm::NodePhase::nSolid) > tolerance && + this->mass(mpm::NodePhase::nLiquid) > tolerance) { // Compute drag force - VectorDim drag_force = drag_force_coefficient_.cwiseProduct( - velocity_.col(mpm::NodePhase::nLiquid) - - velocity_.col(mpm::NodePhase::nSolid)); + VectorDim drag_force = + (vector_properties_.at(mpm::properties::Vector::DragForce)) + .col(mpm::NodePhase::nSolid) + .cwiseProduct(this->velocity(mpm::NodePhase::nLiquid) - + this->velocity(mpm::NodePhase::nSolid)); // Acceleration of pore fluid (momentume balance of fluid phase) - this->acceleration_.col(mpm::NodePhase::nLiquid) = - (this->external_force_.col(mpm::NodePhase::nLiquid) + - this->internal_force_.col(mpm::NodePhase::nLiquid) - drag_force) / - this->mass_(mpm::NodePhase::nLiquid); + vector_properties_.at(mpm::properties::Vector::Acceleration) + .col(mpm::NodePhase::nLiquid) = + (this->external_force(mpm::NodePhase::nLiquid) + + this->internal_force(mpm::NodePhase::nLiquid) - drag_force) / + this->mass(mpm::NodePhase::nLiquid); // Acceleration of solid skeleton (momentume balance of mixture) - this->acceleration_.col(mpm::NodePhase::nSolid) = - (this->external_force_.col(mpm::NodePhase::nMixture) + - this->internal_force_.col(mpm::NodePhase::nMixture) - - this->mass_(mpm::NodePhase::nLiquid) * - this->acceleration_.col(mpm::NodePhase::nLiquid)) / - this->mass_(mpm::NodePhase::nSolid); + vector_properties_.at(mpm::properties::Vector::Acceleration) + .col(mpm::NodePhase::nSolid) = + (this->external_force(mpm::NodePhase::nMixture) + + this->internal_force(mpm::NodePhase::nMixture) - + this->mass(mpm::NodePhase::nLiquid) * + this->acceleration(mpm::NodePhase::nLiquid)) / + this->mass(mpm::NodePhase::nSolid); // Apply friction constraints this->apply_friction_constraints(dt); // Velocity += acceleration * dt - this->velocity_ += this->acceleration_ * dt; + vector_properties_.at(mpm::properties::Vector::Velocity) += + vector_properties_.at(mpm::properties::Vector::Acceleration) * dt; // Apply velocity constraints, which also sets acceleration to 0, // when velocity is set. @@ -755,14 +740,14 @@ bool mpm::Node:: // Set a threshold for (unsigned i = 0; i < Tdim; ++i) { - if (std::abs(velocity_.col(mpm::NodePhase::nSolid)(i)) < tolerance) - velocity_.col(mpm::NodePhase::nSolid)(i) = 0.; - if (std::abs(acceleration_.col(mpm::NodePhase::nSolid)(i)) < tolerance) - acceleration_.col(mpm::NodePhase::nSolid)(i) = 0.; - if (std::abs(velocity_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) - velocity_.col(mpm::NodePhase::nLiquid)(i) = 0.; - if (std::abs(acceleration_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) - acceleration_.col(mpm::NodePhase::nLiquid)(i) = 0.; + if (std::abs(this->velocity(mpm::NodePhase::nSolid)(i)) < tolerance) + this->velocity(mpm::NodePhase::nSolid)(i) = 0.; + if (std::abs(this->acceleration(mpm::NodePhase::nSolid)(i)) < tolerance) + this->acceleration(mpm::NodePhase::nSolid)(i) = 0.; + if (std::abs(this->velocity(mpm::NodePhase::nLiquid)(i)) < tolerance) + this->velocity(mpm::NodePhase::nLiquid)(i) = 0.; + if (std::abs(this->acceleration(mpm::NodePhase::nLiquid)(i)) < tolerance) + this->acceleration(mpm::NodePhase::nLiquid)(i) = 0.; } } return status; @@ -776,42 +761,51 @@ bool mpm::Node:: bool status = false; const double tolerance = 1.0E-15; - if (mass_(mpm::NodePhase::nSolid) > tolerance && - mass_(mpm::NodePhase::nLiquid) > tolerance) { + if (this->mass(mpm::NodePhase::nSolid) > tolerance && + this->mass(mpm::NodePhase::nLiquid) > tolerance) { // Compute drag force - VectorDim drag_force = drag_force_coefficient_.cwiseProduct( - velocity_.col(mpm::NodePhase::nLiquid) - - velocity_.col(mpm::NodePhase::nSolid)); + VectorDim drag_force = + (vector_properties_.at(mpm::properties::Vector::DragForce)) + .col(mpm::NodePhase::nSolid) + .cwiseProduct(this->velocity(mpm::NodePhase::nLiquid) - + this->velocity(mpm::NodePhase::nSolid)); // Unbalanced force of liquid phase auto unbalanced_force_liquid = - this->external_force_.col(mpm::NodePhase::nLiquid) + - this->internal_force_.col(mpm::NodePhase::nLiquid) - drag_force; + this->external_force(mpm::NodePhase::nLiquid) + + this->internal_force(mpm::NodePhase::nLiquid) - drag_force; // Acceleration of liquid phase (momentume balance of fluid phase) - this->acceleration_.col(mpm::NodePhase::nLiquid) = + vector_properties_.at(mpm::properties::Vector::Acceleration) + .col(mpm::NodePhase::nLiquid) = (unbalanced_force_liquid - damping_factor * unbalanced_force_liquid.norm() * - this->velocity_.col(mpm::NodePhase::nLiquid).cwiseSign()) / - this->mass_(mpm::NodePhase::nLiquid); + vector_properties_.at(mpm::properties::Vector::Velocity) + .col(mpm::NodePhase::nLiquid) + .cwiseSign()) / + this->mass(mpm::NodePhase::nLiquid); // Unbalanced force of solid phase auto unbalanced_force_solid = - this->external_force_.col(mpm::NodePhase::nMixture) + - this->internal_force_.col(mpm::NodePhase::nMixture) - - this->mass_(mpm::NodePhase::nLiquid) * - this->acceleration_.col(mpm::NodePhase::nLiquid); + this->external_force(mpm::NodePhase::nMixture) + + this->internal_force(mpm::NodePhase::nMixture) - + this->mass(mpm::NodePhase::nLiquid) * + this->acceleration(mpm::NodePhase::nLiquid); // Acceleration of solid phase (momentume balance of mixture) - this->acceleration_.col(mpm::NodePhase::nSolid) = + vector_properties_.at(mpm::properties::Vector::Acceleration) + .col(mpm::NodePhase::nSolid) = (unbalanced_force_solid - damping_factor * unbalanced_force_solid.norm() * - this->velocity_.col(mpm::NodePhase::nSolid).cwiseSign()) / - this->mass_(mpm::NodePhase::nSolid); + vector_properties_.at(mpm::properties::Vector::Velocity) + .col(mpm::NodePhase::nSolid) + .cwiseSign()) / + this->mass(mpm::NodePhase::nSolid); // Apply friction constraints this->apply_friction_constraints(dt); // Velocity += acceleration * dt - this->velocity_ += this->acceleration_ * dt; + vector_properties_.at(mpm::properties::Vector::Velocity) += + vector_properties_.at(mpm::properties::Vector::Acceleration) * dt; // Apply velocity constraints, which also sets acceleration to 0, // when velocity is set. @@ -819,14 +813,18 @@ bool mpm::Node:: // Set a threshold for (unsigned i = 0; i < Tdim; ++i) { - if (std::abs(velocity_.col(mpm::NodePhase::nSolid)(i)) < tolerance) - velocity_.col(mpm::NodePhase::nSolid)(i) = 0.; - if (std::abs(acceleration_.col(mpm::NodePhase::nSolid)(i)) < tolerance) - acceleration_.col(mpm::NodePhase::nSolid)(i) = 0.; - if (std::abs(velocity_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) - velocity_.col(mpm::NodePhase::nLiquid)(i) = 0.; - if (std::abs(acceleration_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) - acceleration_.col(mpm::NodePhase::nLiquid)(i) = 0.; + if (std::abs(this->velocity(mpm::NodePhase::nSolid)(i)) < tolerance) + vector_properties_.at(mpm::properties::Vector::Velocity) + .col(mpm::NodePhase::nSolid)(i) = 0.; + if (std::abs(this->acceleration(mpm::NodePhase::nSolid)(i)) < tolerance) + vector_properties_.at(mpm::properties::Vector::Acceleration) + .col(mpm::NodePhase::nSolid)(i) = 0.; + if (std::abs(this->velocity(mpm::NodePhase::nLiquid)(i)) < tolerance) + vector_properties_.at(mpm::properties::Vector::Velocity) + .col(mpm::NodePhase::nLiquid)(i) = 0.; + if (std::abs(this->acceleration(mpm::NodePhase::nLiquid)(i)) < tolerance) + vector_properties_.at(mpm::properties::Vector::Acceleration) + .col(mpm::NodePhase::nLiquid)(i) = 0.; } status = true; } diff --git a/include/node_base.h b/include/node_base.h index 438c09875..9a9b83b42 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -175,12 +175,6 @@ class NodeBase { virtual void update_mass_pressure(bool update, unsigned phase, double mass_pressure) noexcept = 0; - //! Update drag force coefficient - //! \param[in] update A boolean to update (true) or assign (false) - //! \param[in] drag_force Drag force from the particles in a cell - //! \retval status Update status - virtual bool update_drag_force_coefficient(bool update, - const VectorDim& drag_force) = 0; //! Compute pressure from the mass pressure virtual void compute_pressure() = 0; diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 6a81ae127..abe6ea5f0 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -20,10 +20,10 @@ class Material; //! Particle phases enum ParticlePhase : unsigned int { - Mixture = 0, Solid = 0, Liquid = 1, - Gas = 2 + Gas = 2, + Mixture = 1 }; //! ParticleBase class @@ -320,60 +320,8 @@ class ParticleBase { //! Return neighbour ids virtual std::vector neighbours() const = 0; - // Twophase particle functions------------------------------------------------ - - //! Assign porosity - virtual bool assign_porosity() { - throw std::runtime_error( - "Calling the base class function " - "(assign_porosity) in " - "ParticleBase:: illegal operation!"); - return false; - }; - - //! Assign particle free surface - virtual bool free_surface() { - throw std::runtime_error( - "Calling the base class function " - "(free_surface) in " - "ParticleBase:: illegal operation!"); - return false; - }; - - //! Assign particle pressure constraints - virtual bool assign_particle_pore_pressure_constraint(double pressure) { - throw std::runtime_error( - "Calling the base class function " - "(assign_particle_pore_pressure_constraint) in " - "ParticleBase:: illegal operation!"); - return false; - }; - - //! Initialise liquid phase - virtual void initialise_liquid_phase() { - throw std::runtime_error( - "Calling the base class function (initialise_liquid_phase) in " - "ParticleBase:: illegal operation!"); - }; - - //! Assign material - //! \param[in] material Pointer to a material - virtual bool assign_liquid_material( - const std::shared_ptr>& material) { - throw std::runtime_error( - "Calling the base class function (assign_liquid_material) in " - "ParticleBase:: illegal operation!"); - return false; - }; - - //! Assign pore pressure - //! \param[in] pressure Pore liquid pressure - virtual void assign_pore_pressure(double pressure) { - throw std::runtime_error( - "Calling the base class function (assign_pore_pressure) in " - "ParticleBase:: illegal operation!"); - }; - + //---------------------------------------------------------------------------- + //! TODO //! Assign liquid traction //! \param[in] direction Index corresponding to the direction of traction //! \param[in] traction Particle traction in specified direction @@ -385,65 +333,12 @@ class ParticleBase { return false; }; - //! Return liquid phase traction - virtual VectorDim liquid_traction() const { - auto error = VectorDim::Zero(); - throw std::runtime_error( - "Calling the base class function (liquid_traction) in " - "ParticleBase:: illegal operation!"); - return error; - }; - - //! Return liquid mass - //! \retval liquid mass Liquid phase mass - virtual double liquid_mass() const { - throw std::runtime_error( - "Calling the base class function (liquid_mass) in " - "ParticleBase:: illegal operation!"); - return 0; - }; - - //! Assign velocity to the particle liquid phase - //! \param[in] velocity A vector of particle liquid phase velocity - //! \retval status Assignment status - virtual bool assign_liquid_velocity(const VectorDim& velocity) { - throw std::runtime_error( - "Calling the base class function (assign_liquid_velocity) in " - "ParticleBase:: illegal operation!"); - return false; - }; - - //! Return velocity of the particle liquid phase - //! \retval liquid velocity Liquid phase velocity - virtual VectorDim liquid_velocity() const { - auto error = VectorDim::Zero(); - throw std::runtime_error( - "Calling the base class function (liquid_velocity) in " - "ParticleBase:: illegal operation!"); - return error; - }; - - //! Return strain of the particle liquid phase - //! \retval liquid strain Liquid phase strain - virtual Eigen::Matrix liquid_strain() const { - auto error = Eigen::Matrix::Zero(); - throw std::runtime_error( - "Calling the base class function (liquid_strain) in " - "ParticleBase:: illegal operation!"); - return error; - }; - - //! Assign pore pressure to nodes - virtual void map_pore_pressure_to_nodes() { - throw std::runtime_error( - "Calling the base class function (map_pore_pressure_to_nodes) in " - "ParticleBase:: illegal operation!"); - }; - - //! Compute pore pressure somoothening by interpolating nodal pressure - virtual bool compute_pore_pressure_smoothing() { + //! Assign material + //! \param[in] material Pointer to a material + virtual bool assign_liquid_material( + const std::shared_ptr>& material) { throw std::runtime_error( - "Calling the base class function (compute_pore_pressure_smoothing) in " + "Calling the base class function (assign_liquid_material) in " "ParticleBase:: illegal operation!"); return false; }; @@ -456,54 +351,10 @@ class ParticleBase { "ParticleBase:: illegal operation!"); }; - //! Return pore pressure - //! \retval pore pressure Pore liquid pressure - virtual double pore_pressure() const { - throw std::runtime_error( - "Calling the base class function (pore_pressure) in " - "ParticleBase:: illegal operation!"); - return 0; - }; - - //! Return free surface status - //! \retval free surface Free surface status - virtual bool free_surface() const { - throw std::runtime_error( - "Calling the base class function (free_surface) in " - "ParticleBase:: illegal operation!"); - return 0; - }; - - //! Return excessive pore pressure - //! \retval excessive pore pressure Excessive pore pressure - virtual double excessive_pore_pressure() const { - throw std::runtime_error( - "Calling the base class function (excessive_pore_pressure) in " - "ParticleBase:: illegal operation!"); - return 0; - }; - - //! Update particle permeability - virtual VectorDim update_permeability() { - auto error = VectorDim::Zero(); - throw std::runtime_error( - "Calling the base class function (update_permeability) in " - "ParticleBase:: illegal operation!"); - return error; - }; - - //! Update porosity - virtual bool update_porosity(double dt) { - throw std::runtime_error( - "Calling the base class function (update_porosity) in " - "ParticleBase:: illegal operation!"); - return false; - }; - - //! Map drag force coefficient - virtual bool map_drag_force_coefficient() { + //! Compute pore pressure somoothening by interpolating nodal pressure + virtual bool compute_pore_pressure_smoothing() { throw std::runtime_error( - "Calling the base class function (map_drag_force_coefficient) in " + "Calling the base class function (compute_pore_pressure_smoothing) in " "ParticleBase:: illegal operation!"); return false; }; @@ -518,26 +369,15 @@ class ParticleBase { return false; }; - //! Apply particle liquid phase velocity constraints - virtual void apply_particle_liquid_velocity_constraints() { - throw std::runtime_error( - "Calling the base class function " - "(apply_particle_liquid_velocity_constraints) in " - "ParticleBase:: illegal operation!"); - }; - - //! Initialise particle pore pressure by watertable - virtual bool initialise_pore_pressure_watertable( - const unsigned dir_v, const unsigned dir_h, - std::map& refernece_points) { + //! Assign particle pressure constraints + virtual bool assign_particle_pore_pressure_constraint(double pressure) { throw std::runtime_error( "Calling the base class function " - "(initialise_pore_pressure_watertable) in " + "(assign_particle_pore_pressure_constraint) in " "ParticleBase:: illegal operation!"); return false; }; - - // --------------------------------------------------------------------------- + //---------------------------------------------------------------------------- protected: //! particleBase id @@ -574,4 +414,4 @@ class ParticleBase { #include "particle_base.tcc" -#endif // MPM_PARTICLEBASE_H__ +#endif // MPM_PARTICLEBASE_H__ \ No newline at end of file diff --git a/include/particles/particle_functions.tcc b/include/particles/particle_functions.tcc index 7134f0c89..f91437f31 100644 --- a/include/particles/particle_functions.tcc +++ b/include/particles/particle_functions.tcc @@ -1,4 +1,3 @@ -// Compute mass of particle namespace mpm { namespace particle { diff --git a/include/particles/twophase_particle.h b/include/particles/twophase_particle.h index 0a5727cbc..aebc7ad52 100644 --- a/include/particles/twophase_particle.h +++ b/include/particles/twophase_particle.h @@ -55,45 +55,12 @@ class TwoPhaseParticle : public mpm::Particle { const HDF5Particle& particle, const std::shared_ptr>& material) override; - //! Initialise liquid phase - void initialise_liquid_phase() override; - //! Retrun particle data as HDF5 //! \retval particle HDF5 data of the particle HDF5Particle hdf5() const override; - //! Assign material - //! \param[in] material Pointer to a material - bool assign_liquid_material( - const std::shared_ptr>& material) override; - - //! Assign porosity - bool assign_porosity() override; - - //! Assign pore pressure - //! \param[in] pressure Pore liquid pressure - void assign_pore_pressure(double pressure) override { - this->pore_pressure_ = pressure; - } - - //! Assign liquid traction - //! \param[in] direction Index corresponding to the direction of traction - //! \param[in] traction Particle traction in specified direction - //! \retval status Assignment status - bool assign_liquid_traction(unsigned direction, double traction) override; - - //! Return liquid phase traction - VectorDim liquid_traction() const { return liquid_traction_; }; - - //! Compute both solid and liquid mass - void compute_mass() noexcept override; - - //! Map particle mass and momentum to nodes (both solid and liquid) - void map_mass_momentum_to_nodes() noexcept override; - - //! Map body force - //! \param[in] pgravity Gravity of a particle - void map_body_force(const VectorDim& pgravity) noexcept override; + //! Initialise properties + void initialise() override; //! Map internal force inline void map_internal_force() noexcept override; @@ -103,59 +70,25 @@ class TwoPhaseParticle : public mpm::Particle { //! Update particle velocity from nodal vel when true void compute_updated_position(double dt, bool velocity_update = false) noexcept override; - - //! Assign velocity to the particle liquid phase - //! \param[in] velocity A vector of particle liquid phase velocity + //------------------------------------------------------------------------------- + //! TODO + //! Assign liquid traction + //! \param[in] direction Index corresponding to the direction of traction + //! \param[in] traction Particle traction in specified direction //! \retval status Assignment status - bool assign_liquid_velocity(const VectorDim& velocity) override; - - //! Return velocity of the particle liquid phase - //! \retval liquid velocity Liquid phase velocity - VectorDim liquid_velocity() const override { return liquid_velocity_; } - - //! Return liquid strain of the particle - Eigen::Matrix liquid_strain() const override { - return liquid_strain_; - } - - //! Return liquid mass - //! \retval liquid mass Liquid phase mass - double liquid_mass() const override { return liquid_mass_; } - - //! Assign pore pressure to nodes - void map_pore_pressure_to_nodes() noexcept override; + bool assign_liquid_traction(unsigned direction, double traction) override; - //! Compute pore pressure somoothening by interpolating nodal pressure - bool compute_pore_pressure_smoothing() noexcept override; + //! Assign material + //! \param[in] material Pointer to a material + bool assign_liquid_material( + const std::shared_ptr>& material) override; //! Compute pore pressure //! \param[in] dt Time step size void compute_pore_pressure(double dt) noexcept override; - //! Return pore pressure - //! \retval pore_pressure Pore pressure - double pore_pressure() const override { return pore_pressure_; } - - //! Return excessive pore pressure - //! \retval excessive pore pressure Excessive pore pressure - double excessive_pore_pressure() const override { - return excessive_pore_pressure_; - } - - //! Return free surface status - //! \retval free surface Free surface status - bool free_surface() const override { return free_surface_; } - - //! Map drag force coefficient - bool map_drag_force_coefficient() override; - - //! Update particle permeability - //! \retval status Update status - VectorDim update_permeability() override; - - //! Update porosity - //! \param[in] dt Analysis time step - bool update_porosity(double dt) override; + //! Compute pore pressure somoothening by interpolating nodal pressure + bool compute_pore_pressure_smoothing() noexcept override; //! Assign particle liquid phase velocity constraints //! Directions can take values between 0 and Dim @@ -165,54 +98,49 @@ class TwoPhaseParticle : public mpm::Particle { bool assign_particle_liquid_velocity_constraint(unsigned dir, double velocity) override; - //! Apply particle liquid phase velocity constraints - void apply_particle_liquid_velocity_constraints() override; - //! Assign particle pressure constraints //! \retval status Assignment status bool assign_particle_pore_pressure_constraint(double pressure) override; - - //! Assign particles initial pore pressure by watertable - bool initialise_pore_pressure_watertable( - const unsigned dir_v, const unsigned dir_h, - std::map& refernece_points); + //------------------------------------------------------------------------------- private: - //! Assign particle permeability - //! \retval status Assignment status - virtual bool assign_permeability(); + //! Compute updated velocity of the particle based on nodal velocity + //! \param[in] dt Analysis time step + //! \retval status Compute status + void compute_updated_liquid_velocity(double dt, + bool velocity_update) noexcept; - //! Compute liquid mass - virtual void compute_liquid_mass() noexcept; + //! Apply particle liquid phase velocity constraints + void apply_particle_liquid_velocity_constraints(); - //! Assign liquid mass and momentum to nodes - virtual void map_liquid_mass_momentum_to_nodes() noexcept; + //! Map liquid phase traction force + void map_liquid_traction_force() noexcept; - //! Map two phase mixture body force - //! \param[in] mixture Identification for Mixture - //! \param[in] pgravity Gravity of the particle - virtual void map_mixture_body_force(unsigned mixture, - const VectorDim& pgravity) noexcept; + //! Return mass of the particle + double liquid_mass() const { + return this->scalar_property(mpm::properties::Scalar::LiquidMass); + } - //! Map liquid body force - //! \param[in] pgravity Gravity of a particle - virtual void map_liquid_body_force(const VectorDim& pgravity) noexcept; + //! Return porosity of the particle + double porosity() const { + return this->scalar_property(mpm::properties::Scalar::Porosity); + } - //! Map liquid phase traction force - virtual void map_liquid_traction_force() noexcept; + //! Return liquid strain of the particle + Eigen::Matrix liquid_strain() const { return liquid_strain_; } - //! Map liquid internal force - virtual void map_liquid_internal_force() noexcept; + //! Return liquid velocity of the particle + VectorDim liquid_velocity() const { + return this->vector_property(mpm::properties::Vector::LiquidVelocity); + } - //! Map two phase mixture internal force - //! \param[in] mixture Identification for Mixture - virtual void map_mixture_internal_force(unsigned mixture) noexcept; + //! Return pore pressure of the particle + double pore_pressure() const { + return this->scalar_property(mpm::properties::Scalar::PorePressure); + } - //! Compute updated velocity of the particle based on nodal velocity - //! \param[in] dt Analysis time step - //! \retval status Compute status - virtual void compute_updated_liquid_velocity(double dt, - bool velocity_update) noexcept; + //! Return free surface status + bool free_surface() const { return free_surface_; } protected: //! coordinates @@ -229,38 +157,22 @@ class TwoPhaseParticle : public mpm::Particle { using Particle::strain_rate_; //! Soil skeleton material using Particle::material_; - //! Particle total volume - using Particle::volume_; - //! Particle mass density - using Particle::mass_density_; //! dN/dX using Particle::dn_dx_; //! dN/dX at cell centroid using Particle::dn_dx_centroid_; - //! Solid mass - using Particle::mass_; //! Set traction using Particle::set_traction_; + //! Scalar properties + using ParticleBase::scalar_properties_; + //! Vector properties + using ParticleBase::vector_properties_; //! Material std::shared_ptr> liquid_material_; //! Liquid material id unsigned liquid_material_id_{std::numeric_limits::max()}; - //! Liquid mass density (bulk density = liquid mass / total volume) - double liquid_mass_density_{0.}; - //! Liquid mass - double liquid_mass_{0.}; - //! Porosity - double porosity_{0.}; - //! Permeability c1 (k = k_p * c1_) - Eigen::Matrix permeability_c1_; - //! Liquid velocity - Eigen::Matrix liquid_velocity_; //! Particle liquid phase velocity constraints std::map liquid_velocity_constraints_; - //! Pore pressure - double pore_pressure_{0.}; - //! Excessive pore pressure - double excessive_pore_pressure_{0.}; //! Free surface bool free_surface_{false}; //! Pore pressure constraint @@ -279,5 +191,6 @@ class TwoPhaseParticle : public mpm::Particle { } // namespace mpm #include "twophase_particle.tcc" +#include "twophase_particle_functions.tcc" #endif // MPM_TWOPHASE_PARTICLE_H__ diff --git a/include/particles/twophase_particle.tcc b/include/particles/twophase_particle.tcc index eb774d291..de57b109f 100644 --- a/include/particles/twophase_particle.tcc +++ b/include/particles/twophase_particle.tcc @@ -2,10 +2,8 @@ template mpm::TwoPhaseParticle::TwoPhaseParticle(Index id, const VectorDim& coord) : mpm::Particle(id, coord) { - // Initialise variables for solid phase - mpm::Particle::initialise(); - // Initialise variables for liquid phase - this->initialise_liquid_phase(); + // Initialise variables for solid phase and liquid phase + this->initialise(); // Clear cell ptr cell_ = nullptr; // Nodes @@ -24,10 +22,8 @@ template mpm::TwoPhaseParticle::TwoPhaseParticle(Index id, const VectorDim& coord, bool status) : mpm::Particle(id, coord, status) { - // Initialise variables for solid phase - mpm::Particle::initialise(); - // Initialise variables for liquid phase - this->initialise_liquid_phase(); + // Initialise variables for solid phase and liquid phase + this->initialise(); // Clear cell ptr cell_ = nullptr; // Nodes @@ -48,20 +44,23 @@ bool mpm::TwoPhaseParticle::initialise_particle( // Derive from particle mpm::Particle::initialise_particle(particle); - // TODO:HDF5 // // Liquid mass - // this->liquid_mass_ = particle.liquid_mass; + // scalar_properties_.at(mpm::properties::Scalar::LiquidMass) = + // particle.liquid_mass; // // Liquid mass Density - // this->liquid_mass_density_ = particle.mass / particle.volume; + // scalar_properties_.at(mpm::properties::Scalar::LiquidMassDensity) = + // particle.mass / particle.volume; // // Pore pressure - // this->pore_pressure_ = particle.pore_pressure; + // scalar_properties_.at(mpm::properties::Scalar::PorePressure) = + // particle.pore_pressure; // // Liquid velocity // Eigen::Vector3d liquid_velocity; // liquid_velocity << particle.liquid_velocity_x, particle.liquid_velocity_y, // particle.liquid_velocity_z; // // Initialise velocity // for (unsigned i = 0; i < Tdim; ++i) - // this->liquid_velocity_(i) = liquid_velocity(i); + // vector_properties_.at(mpm::properties::Vector::LiquidVelocity)(i) = + // liquid_velocity(i); // // Liquid strain // this->liquid_strain_[0] = particle.liquid_strain_xx; // this->liquid_strain_[1] = particle.liquid_strain_yy; @@ -120,7 +119,8 @@ mpm::HDF5Particle mpm::TwoPhaseParticle::hdf5() const { // // Particle liquid mass // particle_data.liquid_mass = this->liquid_mass_; // // Particle pore pressure - // particle_data.pore_pressure = this->pore_pressure_; + // particle_data.pore_pressure = + // scalar_properties_.at(mpm::properties::Scalar::PorePressure); // // Particle liquid velocity // particle_data.liquid_velocity_x = liquid_velocity[0]; // particle_data.liquid_velocity_y = liquid_velocity[1]; @@ -138,19 +138,31 @@ mpm::HDF5Particle mpm::TwoPhaseParticle::hdf5() const { return particle_data; } -// Initialise liquid phase particle properties +//! Initialise particle data from HDF5 template -void mpm::TwoPhaseParticle::initialise_liquid_phase() { - liquid_mass_ = 0.; - pore_pressure_ = 0.; - porosity_ = 0.; - liquid_velocity_.setZero(); +void mpm::TwoPhaseParticle::initialise() { + mpm::Particle::initialise(); liquid_strain_rate_.setZero(); liquid_strain_.setZero(); liquid_traction_.setZero(); - permeability_c1_.setZero(); set_liquid_traction_ = false; + // Initialize scalar properties + scalar_properties_.emplace( + std::make_pair(mpm::properties::Scalar::Porosity, double(0.))); + scalar_properties_.emplace( + std::make_pair(mpm::properties::Scalar::PorePressure, double(0.))); + scalar_properties_.emplace( + std::make_pair(mpm::properties::Scalar::LiquidMass, double(0.))); + scalar_properties_.emplace( + std::make_pair(mpm::properties::Scalar::LiquidMassDensity, double(0.))); + + // Initialize vector properties + vector_properties_.emplace(std::make_pair( + mpm::properties::Vector::LiquidVelocity, VectorDim::Zero())); + vector_properties_.emplace( + std::make_pair(mpm::properties::Vector::Permeability, VectorDim::Zero())); + // Initialize vector data properties this->properties_["liquid_strains"] = [&]() { return liquid_strain(); }; this->properties_["liquid_velocities"] = [&]() { return liquid_velocity(); }; @@ -159,361 +171,61 @@ void mpm::TwoPhaseParticle::initialise_liquid_phase() { // Total pore pressure pore_pressure[0] = this->pore_pressure(); // Excessive pore pressure - pore_pressure[1] = this->excessive_pore_pressure(); + // pore_pressure[1] = this->excessive_pore_pressure(); // Free surface - pore_pressure[2] = this->free_surface(); + // pore_pressure[2] = this->free_surface(); return pore_pressure; }; } -// Assign a liquid material to particle -template -bool mpm::TwoPhaseParticle::assign_liquid_material( - const std::shared_ptr>& material) { - bool status = false; - try { - // Check if material is valid and properties are set - if (material != nullptr) { - liquid_material_ = material; - liquid_material_id_ = liquid_material_->id(); - status = true; - } else { - throw std::runtime_error("Liquid material is undefined!"); - } - - // Assign porosity - this->assign_porosity(); - // Assign permeability - this->assign_permeability(); - - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - } - return status; -} - -//! Assign particle permeability -template -bool mpm::TwoPhaseParticle::assign_permeability() { - bool status = true; - try { - // Check if material ptr is valid - if (material_ != nullptr) { - // Porosity parameter k_p - const double k_p = - std::pow(this->porosity_, 3) / std::pow((1. - this->porosity_), 2); - // Different dimensions permeability - switch (Tdim) { - case (1): { - permeability_c1_(0) = - material_->template property("k_x") / k_p; - break; - } - case (2): { - permeability_c1_(0) = - material_->template property("k_x") / k_p; - permeability_c1_(1) = - material_->template property("k_y") / k_p; - break; - } - default: { - permeability_c1_(0) = - material_->template property("k_x") / k_p; - permeability_c1_(1) = - material_->template property("k_y") / k_p; - permeability_c1_(2) = - material_->template property("k_z") / k_p; - break; - } - } - } else { - throw std::runtime_error( - "Material is invalid, could not assign permeability"); - } - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; - } - return status; -} - -// Assign particle porosity -template -bool mpm::TwoPhaseParticle::assign_porosity() { - bool status = true; - try { - // Check if material ptr is valid - if (material_ != nullptr) { - porosity_ = material_->template property(std::string("porosity")); - // Check if the porosity value is valid - if (porosity_ < 0. || porosity_ > 1.) - throw std::runtime_error( - "Particle porosity is negative or larger than one"); - } else { - throw std::runtime_error( - "Material is invalid, could not assign porosity"); - } - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; - } - return status; -} - -// Assign velocity to the particle liquid phase -template -bool mpm::TwoPhaseParticle::assign_liquid_velocity( - const Eigen::Matrix& velocity) { - bool status = false; - try { - // Assign velocity - liquid_velocity_ = velocity; - status = true; - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; - } - return status; -} - -// Assign traction to the liquid phase -template -bool mpm::TwoPhaseParticle::assign_liquid_traction(unsigned direction, - double traction) { - bool status = false; - try { - if (direction >= Tdim || - this->volume_ == std::numeric_limits::max()) { - throw std::runtime_error( - "Particle liquid traction property: volume / direction is invalid"); - } - // Assign liquid traction - liquid_traction_(direction) = - traction * this->volume_ / this->size_(direction); - status = true; - this->set_liquid_traction_ = true; - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; - } - return status; -} - -// Compute mass of particle (both solid and liquid) -template -void mpm::TwoPhaseParticle::compute_mass() noexcept { - // Compute mass of particle (solid phase) - mpm::Particle::compute_mass(); - // Compute mass of particle (liquid phase) - this->compute_liquid_mass(); -} - -// Compute liquid mass of particle -template -void mpm::TwoPhaseParticle::compute_liquid_mass() noexcept { - // Check if particle volume is set and liquid material ptr is valid - assert(volume_ != std::numeric_limits::max() && - liquid_material_ != nullptr); - - // Mass = volume of particle * bulk_density - this->liquid_mass_density_ = - porosity_ * - liquid_material_->template property(std::string("density")); - this->liquid_mass_ = volume_ * liquid_mass_density_; -} - -//! Map particle mass and momentum to nodes -template -void mpm::TwoPhaseParticle::map_mass_momentum_to_nodes() noexcept { - // Map particle mass and momentum to nodes (solid phase) - mpm::Particle::map_mass_momentum_to_nodes(); - // Map particle mass and momentum to nodes (liquid phase) - this->map_liquid_mass_momentum_to_nodes(); -} - -//! Map liquid mass and momentum to nodes -template -void mpm::TwoPhaseParticle::map_liquid_mass_momentum_to_nodes() noexcept { - // Check if liquid mass is set and positive - assert(liquid_mass_ != std::numeric_limits::max()); - - // Map liquid mass and momentum to nodes - for (unsigned i = 0; i < nodes_.size(); ++i) { - nodes_[i]->update_mass(true, mpm::ParticlePhase::Liquid, - liquid_mass_ * shapefn_[i]); - nodes_[i]->update_momentum(true, mpm::ParticlePhase::Liquid, - liquid_mass_ * shapefn_[i] * liquid_velocity_); - } -} - -//! Compute pore pressure (compressible fluid) -template -void mpm::TwoPhaseParticle::compute_pore_pressure(double dt) noexcept { - // Check if liquid material and cell pointer are set and positive - assert(liquid_material_ != nullptr && cell_ != nullptr); - // Apply free surface - if (this->free_surface()) this->pore_pressure_ = 0.0; - // Compute pore pressure - else { - // get the bulk modulus of liquid - double K = liquid_material_->template property( - std::string("bulk_modulus")); - // Compute strain rate of liquid phase at centroid - auto liquid_strain_rate_centroid = mpm::Particle::compute_strain_rate( - dn_dx_centroid_, mpm::ParticlePhase::Liquid); - // update pressure - this->pore_pressure_ += - -dt * (K / porosity_) * - ((1 - porosity_) * strain_rate_.head(Tdim).sum() + - porosity_ * liquid_strain_rate_centroid.head(Tdim).sum()); - } -} - -//! Map particle pore liquid pressure to nodes -template -void mpm::TwoPhaseParticle::map_pore_pressure_to_nodes() noexcept { - // Check if particle mass is set - assert(liquid_mass_ != std::numeric_limits::max()); - // Map particle liquid mass and pore pressure to nodes - for (unsigned i = 0; i < nodes_.size(); ++i) - nodes_[i]->update_mass_pressure( - mpm::ParticlePhase::Liquid, - shapefn_[i] * liquid_mass_ * pore_pressure_); -} - -// Compute pore liquid pressure smoothing based on nodal pressure -template -bool mpm::TwoPhaseParticle::compute_pore_pressure_smoothing() noexcept { - // Check if particle has a valid cell ptr - assert(cell_ != nullptr); - - bool status = false; - // Check if particle has a valid cell ptr - if (cell_ != nullptr) { - // Apply free surface - if (this->free_surface()) this->pore_pressure_ = 0.0; - // Compute particle pore pressure from nodal values - else { - double pore_pressure = 0; - for (unsigned i = 0; i < nodes_.size(); ++i) - pore_pressure += - shapefn_(i) * nodes_[i]->pressure(mpm::ParticlePhase::Liquid); - // Update pore liquid pressure to interpolated nodal pressure - this->pore_pressure_ = pore_pressure; - } - } - return status; -} - -//! Map body force for both mixture and liquid -template -void mpm::TwoPhaseParticle::map_body_force( - const VectorDim& pgravity) noexcept { - //! Map body force for mixture - this->map_mixture_body_force(mpm::ParticlePhase::Mixture, pgravity); - //! Map body force for liquid - this->map_liquid_body_force(pgravity); -} - -//! Map liquid phase body force -template -void mpm::TwoPhaseParticle::map_liquid_body_force( - const VectorDim& pgravity) noexcept { - // Compute nodal liquid body forces - for (unsigned i = 0; i < nodes_.size(); ++i) - nodes_[i]->update_external_force( - true, mpm::ParticlePhase::Liquid, - (pgravity * this->liquid_mass_ * shapefn_(i))); -} - -//! Map mixture body force -template -void mpm::TwoPhaseParticle::map_mixture_body_force( - unsigned mixture, const VectorDim& pgravity) noexcept { - // Compute nodal mixture body forces - for (unsigned i = 0; i < nodes_.size(); ++i) - nodes_[i]->update_external_force( - true, mixture, - (pgravity * (this->liquid_mass_ + this->mass_) * shapefn_(i))); -} - -//! Map liquid traction force -template -void mpm::TwoPhaseParticle::map_liquid_traction_force() noexcept { - if (this->set_liquid_traction_) { - // Map particle liquid traction forces to nodes - for (unsigned i = 0; i < nodes_.size(); ++i) - nodes_[i]->update_external_force( - true, mpm::ParticlePhase::Liquid, - (-1. * shapefn_[i] * porosity_ * this->liquid_traction_)); - } -} - //! Map both mixture and liquid internal force -template -inline void mpm::TwoPhaseParticle::map_internal_force() noexcept { - //! Map mixture internal force - mpm::TwoPhaseParticle::map_mixture_internal_force( - mpm::ParticlePhase::Mixture); - //! Map liquid internal force - mpm::TwoPhaseParticle::map_liquid_internal_force(); -} - -//! Map liquid phase internal force template <> -void mpm::TwoPhaseParticle<2>::map_liquid_internal_force() noexcept { - // initialise a vector of pore pressure - Eigen::Matrix pressure; - pressure.setZero(); - pressure(0) = -this->pore_pressure_; - pressure(1) = -this->pore_pressure_; - +inline void mpm::TwoPhaseParticle<1>::map_internal_force() noexcept { + // Map mixture internal force + // Initialise a vector of pore pressure + Eigen::Matrix total_stress = this->stress_; + total_stress(0) -= + scalar_properties_.at(mpm::properties::Scalar::PorePressure); // 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) * pressure[0] * this->porosity_; - force[1] = dn_dx_(i, 1) * pressure[1] * this->porosity_; + Eigen::Matrix force; + force[0] = dn_dx_(i, 0) * total_stress[0] + dn_dx_(i, 1) * total_stress[3]; - force *= -1. * this->volume_; + force *= -1. * mpm::Particle<1>::volume(); nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Liquid, force); } -} -template <> -void mpm::TwoPhaseParticle<3>::map_liquid_internal_force() noexcept { - // initialise a vector of pore pressure + // Map liquid internal force + // Initialise a vector of pore pressure Eigen::Matrix pressure; pressure.setZero(); - pressure(0) = -this->pore_pressure_; - pressure(1) = -this->pore_pressure_; - pressure(2) = -this->pore_pressure_; - + pressure(0) = -scalar_properties_.at(mpm::properties::Scalar::PorePressure); + pressure(1) = -scalar_properties_.at(mpm::properties::Scalar::PorePressure); // 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) * pressure[0] * this->porosity_; - force[1] = dn_dx_(i, 1) * pressure[1] * this->porosity_; - force[2] = dn_dx_(i, 2) * pressure[2] * this->porosity_; + Eigen::Matrix force; + force[0] = dn_dx_(i, 0) * pressure[0] * this->porosity(); - force *= -1. * this->volume_; + force *= -1. * mpm::Particle<1>::volume(); nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Liquid, force); } } -//! Map mixture internal force +//! Map both mixture and liquid internal force template <> -void mpm::TwoPhaseParticle<2>::map_mixture_internal_force( - unsigned mixture) noexcept { - // initialise a vector of pore pressure +inline void mpm::TwoPhaseParticle<2>::map_internal_force() noexcept { + // Map mixture internal force + // Initialise a vector of pore pressure Eigen::Matrix total_stress = this->stress_; - total_stress(0) -= this->pore_pressure_; - total_stress(1) -= this->pore_pressure_; - + total_stress(0) -= + scalar_properties_.at(mpm::properties::Scalar::PorePressure); + total_stress(1) -= + scalar_properties_.at(mpm::properties::Scalar::PorePressure); // Compute nodal internal forces for (unsigned i = 0; i < nodes_.size(); ++i) { // Compute force: -pstress * volume @@ -521,21 +233,42 @@ void mpm::TwoPhaseParticle<2>::map_mixture_internal_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_; + force *= -1. * mpm::Particle<2>::volume(); - nodes_[i]->update_internal_force(true, mixture, force); + nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Liquid, force); + } + + // Map liquid internal force + // Initialise a vector of pore pressure + Eigen::Matrix pressure; + pressure.setZero(); + pressure(0) = -scalar_properties_.at(mpm::properties::Scalar::PorePressure); + pressure(1) = -scalar_properties_.at(mpm::properties::Scalar::PorePressure); + // 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) * pressure[0] * this->porosity(); + force[1] = dn_dx_(i, 1) * pressure[1] * this->porosity(); + + force *= -1. * mpm::Particle<2>::volume(); + + nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Liquid, force); } } +//! Map both mixture and liquid internal force template <> -void mpm::TwoPhaseParticle<3>::map_mixture_internal_force( - unsigned mixture) noexcept { - // initialise a vector of pore pressure +inline void mpm::TwoPhaseParticle<3>::map_internal_force() noexcept { + // Map mixture internal force + // Initialise a vector of pore pressure Eigen::Matrix total_stress = this->stress_; - total_stress(0) -= this->pore_pressure_; - total_stress(1) -= this->pore_pressure_; - total_stress(2) -= this->pore_pressure_; - + total_stress(0) -= + scalar_properties_.at(mpm::properties::Scalar::PorePressure); + total_stress(1) -= + scalar_properties_.at(mpm::properties::Scalar::PorePressure); + total_stress(2) -= + scalar_properties_.at(mpm::properties::Scalar::PorePressure); // Compute nodal internal forces for (unsigned i = 0; i < nodes_.size(); ++i) { // Compute force: -pstress * volume @@ -549,78 +282,30 @@ void mpm::TwoPhaseParticle<3>::map_mixture_internal_force( 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_; + force *= -1. * mpm::Particle<3>::volume(); - nodes_[i]->update_internal_force(true, mixture, force); + nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Liquid, force); } -} - -//! Map drag force coefficient -template -bool mpm::TwoPhaseParticle::map_drag_force_coefficient() { - bool status = true; - try { - // Update permeability - auto 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) { - drag_force_coefficient(i) = - porosity_ * porosity_ * 9.81 * - liquid_material_->template property(std::string("density")) / - permeability(i); - } - - // 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; -} + // Map liquid internal force + // Initialise a vector of pore pressure + Eigen::Matrix pressure; + pressure.setZero(); + pressure(0) = -scalar_properties_.at(mpm::properties::Scalar::PorePressure); + pressure(1) = -scalar_properties_.at(mpm::properties::Scalar::PorePressure); + pressure(2) = -scalar_properties_.at(mpm::properties::Scalar::PorePressure); + // 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) * pressure[0] * this->porosity(); + force[1] = dn_dx_(i, 1) * pressure[1] * this->porosity(); + force[2] = dn_dx_(i, 2) * pressure[2] * this->porosity(); -//! Update particle permeability -template -Eigen::Matrix - mpm::TwoPhaseParticle::update_permeability() { - // Initialise permeability - Eigen::Matrix permeability; - permeability.setZero(); - 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 * permeability_c1_; - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - } - return permeability; -} + force *= -1. * mpm::Particle<3>::volume(); -// Update particle porosity -template -bool mpm::TwoPhaseParticle::update_porosity(double dt) { - bool status = true; - try { - // Update particle porosity - this->porosity_ = - 1 - (1 - this->porosity_) / (1 + dt * strain_rate_.head(Tdim).sum()); - // Check if the value is valid - if (this->porosity_ < 0) this->porosity_ = 1E-5; - if (this->porosity_ < 1) this->porosity_ = 1 - 1E-5; - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; + nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Liquid, force); } - return status; } // Compute updated position and velocities @@ -650,7 +335,8 @@ void mpm::TwoPhaseParticle::compute_updated_liquid_velocity( shapefn_(i) * nodes_[i]->acceleration(mpm::ParticlePhase::Liquid); // Update particle velocity from interpolated nodal acceleration - this->liquid_velocity_ += acceleration * dt; + vector_properties_.at(mpm::properties::Vector::LiquidVelocity) += + acceleration * dt; } else { // Get interpolated nodal velocity Eigen::Matrix velocity; @@ -660,13 +346,142 @@ void mpm::TwoPhaseParticle::compute_updated_liquid_velocity( velocity += shapefn_(i) * nodes_[i]->velocity(mpm::ParticlePhase::Liquid); // Update particle velocity to interpolated nodal velocity - this->liquid_velocity_ = velocity; + vector_properties_.at(mpm::properties::Vector::LiquidVelocity) = velocity; } // Apply particle velocity constraints this->apply_particle_liquid_velocity_constraints(); } +//! Apply particle velocity constraints +template +void mpm::TwoPhaseParticle::apply_particle_liquid_velocity_constraints() { + // Set particle velocity constraint + for (const auto& constraint : this->liquid_velocity_constraints_) { + // Direction value in the constraint (0, Dim) + const unsigned dir = constraint.first; + // Direction: dir % Tdim (modulus) + const auto direction = static_cast(dir % Tdim); + vector_properties_.at(mpm::properties::Vector::LiquidVelocity)(direction) = + constraint.second; + } +} + +//! Map liquid traction force +template +void mpm::TwoPhaseParticle::map_liquid_traction_force() noexcept { + if (this->set_liquid_traction_) { + // Map particle liquid traction forces to nodes + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->update_external_force( + true, mpm::ParticlePhase::Liquid, + (-1. * shapefn_[i] * this->porosity() * this->liquid_traction_)); + } +} + +//---------------------------------------------------------------------------- +//! TODO +// Assign traction to the liquid phase +template +bool mpm::TwoPhaseParticle::assign_liquid_traction(unsigned direction, + double traction) { + bool status = false; + try { + if (direction >= Tdim || + mpm::Particle::volume() == std::numeric_limits::max()) { + throw std::runtime_error( + "Particle liquid traction property: volume / direction is invalid"); + } + // Assign liquid traction + liquid_traction_(direction) = + traction * mpm::Particle::volume() / this->size_(direction); + status = true; + this->set_liquid_traction_ = true; + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +//! Assign a liquid material to particle +template +bool mpm::TwoPhaseParticle::assign_liquid_material( + const std::shared_ptr>& material) { + bool status = false; + try { + // Check if material is valid and properties are set + if (material != nullptr) { + liquid_material_ = material; + liquid_material_id_ = liquid_material_->id(); + status = true; + } else { + throw std::runtime_error("Liquid material is undefined!"); + } + // TODO + // Assign porosity + // mpm::twophaseparticle::assign_porosity(); + // Assign permeability + // mpm::twophaseparticle::assign_permeability(); + + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + } + return status; +} + +//! Compute pore pressure (compressible fluid) +template +void mpm::TwoPhaseParticle::compute_pore_pressure(double dt) noexcept { + // Check if liquid material and cell pointer are set and positive + assert(liquid_material_ != nullptr && cell_ != nullptr); + // Apply free surface + if (this->free_surface()) + scalar_properties_.at(mpm::properties::Scalar::PorePressure) = 0.0; + // Compute pore pressure + else { + // get the bulk modulus of liquid + double K = liquid_material_->template property( + std::string("bulk_modulus")); + // Compute strain rate of liquid phase at centroid + auto liquid_strain_rate_centroid = mpm::Particle::compute_strain_rate( + dn_dx_centroid_, mpm::ParticlePhase::Liquid); + // update pressure + scalar_properties_.at(mpm::properties::Scalar::PorePressure) += + -dt * (K / this->scalar_property(mpm::properties::Scalar::Porosity)) * + ((1 - this->scalar_property(mpm::properties::Scalar::Porosity)) * + strain_rate_.head(Tdim).sum() + + this->scalar_property(mpm::properties::Scalar::Porosity) * + liquid_strain_rate_centroid.head(Tdim).sum()); + } +} + +// Compute pore liquid pressure smoothing based on nodal pressure +template +bool mpm::TwoPhaseParticle::compute_pore_pressure_smoothing() noexcept { + // Check if particle has a valid cell ptr + assert(cell_ != nullptr); + + bool status = false; + // Check if particle has a valid cell ptr + if (cell_ != nullptr) { + // Apply free surface + if (this->free_surface()) + scalar_properties_.at(mpm::properties::Scalar::PorePressure) = 0.0; + // Compute particle pore pressure from nodal values + else { + double pore_pressure = 0; + for (unsigned i = 0; i < nodes_.size(); ++i) + pore_pressure += + shapefn_(i) * nodes_[i]->pressure(mpm::ParticlePhase::Liquid); + // Update pore liquid pressure to interpolated nodal pressure + scalar_properties_.at(mpm::properties::Scalar::PorePressure) = + pore_pressure; + } + } + return status; +} + //! Assign particle liquid phase velocity constraint //! Constrain directions can take values between 0 and Dim template @@ -690,20 +505,8 @@ bool mpm::TwoPhaseParticle::assign_particle_liquid_velocity_constraint( return status; } -//! Apply particle velocity constraints -template -void mpm::TwoPhaseParticle::apply_particle_liquid_velocity_constraints() { - // Set particle velocity constraint - for (const auto& constraint : this->liquid_velocity_constraints_) { - // Direction value in the constraint (0, Dim) - const unsigned dir = constraint.first; - // Direction: dir % Tdim (modulus) - const auto direction = static_cast(dir % Tdim); - this->liquid_velocity_(direction) = constraint.second; - } -} - //! Assign particle pressure constraints +//! TODO template bool mpm::TwoPhaseParticle::assign_particle_pore_pressure_constraint( double pressure) { @@ -715,63 +518,4 @@ bool mpm::TwoPhaseParticle::assign_particle_pore_pressure_constraint( status = false; } return status; -} - -//! Initial pore pressure by water table -template -bool mpm::TwoPhaseParticle::initialise_pore_pressure_watertable( - const unsigned dir_v, const unsigned dir_h, - std::map& refernece_points) { - bool status = true; - try { - // Initialise left boundary position (coordinate) and h0 - double left_boundary = std::numeric_limits::lowest(); - double h0_left = 0.; - // Initialise right boundary position (coordinate) and h0 - double right_boundary = std::numeric_limits::max(); - double h0_right = 0.; - // Position and h0 of particle (coordinate) - const double position = this->coordinates_(dir_h); - // Iterate over each refernece_points - for (const auto& refernece_point : refernece_points) { - // Find boundary - if (refernece_point.first > left_boundary && - refernece_point.first <= position) { - // Left boundary position and h0 - left_boundary = refernece_point.first; - h0_left = refernece_point.second; - } else if (refernece_point.first > position && - refernece_point.first <= right_boundary) { - // Right boundary position and h0 - right_boundary = refernece_point.first; - h0_right = refernece_point.second; - } - } - // Check if the boundaries are assigned - if (left_boundary != std::numeric_limits::lowest()) { - // Particle with left and right boundary - if (right_boundary != std::numeric_limits::max()) { - this->pore_pressure_ = - ((h0_right - h0_left) / (right_boundary - left_boundary) * - (position - left_boundary) + - h0_left - this->coordinates_(dir_v)) * - 1000 * 9.81; - } else - // Particle with only left boundary - this->pore_pressure_ = - (h0_left - this->coordinates_(dir_v)) * 1000 * 9.81; - } - // Particle with only right boundary - else if (right_boundary != std::numeric_limits::max()) - this->pore_pressure_ = - (h0_right - this->coordinates_(dir_v)) * 1000 * 9.81; - - else - throw std::runtime_error( - "Particle pore pressure can not be initialised by water table"); - } 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/particles/twophase_particle_functions.tcc b/include/particles/twophase_particle_functions.tcc new file mode 100644 index 000000000..b6151959e --- /dev/null +++ b/include/particles/twophase_particle_functions.tcc @@ -0,0 +1,268 @@ +namespace mpm { +namespace twophaseparticle { + +// Assign particle porosity +template +void assign_porosity(std::shared_ptr> particle) { + // Check if material ptr is valid + if (particle->material() != nullptr) { + double porosity = particle->material()->template property( + std::string("porosity")); + + // Check if the porosity value is valid + if (porosity < 0. || porosity > 1.) + throw std::runtime_error( + "Particle porosity is negative or larger than one"); + + // Update porosity + particle->update_scalar_property(mpm::properties::Scalar::Porosity, false, + porosity); + } else { + throw std::runtime_error("Material is invalid, could not assign porosity"); + } +} + +//! Assign particle permeability +template +void assign_permeability(std::shared_ptr> particle) { + + // Check if material ptr is valid + if (particle->material() != nullptr) { + // Porosity parameter k_p + const double k_p = + std::pow(particle->scalar_property(mpm::properties::Scalar::Porosity), + 3) / + std::pow( + (1. - particle->scalar_property(mpm::properties::Scalar::Porosity)), + 2); + // Initialise permeability vector + Eigen::Matrix permeability; + permeability.setZero(); + + // Different dimensions permeability + switch (Tdim) { + case (1): { + permeability(0) = + particle->material()->template property("k_x") / k_p; + break; + } + case (2): { + permeability(0) = + particle->material()->template property("k_x") / k_p; + permeability(1) = + particle->material()->template property("k_y") / k_p; + + break; + } + default: { + permeability(0) = + particle->material()->template property("k_x") / k_p; + permeability(1) = + particle->material()->template property("k_y") / k_p; + permeability(2) = + particle->material()->template property("k_z") / k_p; + break; + } + } + // Assign permeability vector + particle->update_vector_property(mpm::properties::Vector::Permeability, + false, permeability); + } else { + throw std::runtime_error( + "Material is invalid, could not assign permeability"); + } +} + +// Compute particle mass for two phase +template +void compute_mass(std::shared_ptr> particle) noexcept { + // Check if particle volume is set and material ptr is valid + assert(particle->volume() != std::numeric_limits::max() && + particle->material() != nullptr); + + // Mass = volume of particle * mass_density + // Solid density + particle->update_scalar_property( + mpm::properties::Scalar::MassDensity, false, + particle->material()->template property(std::string("density"))); + + // Update particle solid mass + particle->update_scalar_property( + mpm::properties::Scalar::Mass, false, + (1 - particle->scalar_property(mpm::properties::Scalar::Porosity)) * + particle->volume() * particle->mass_density()); + + // Update particle water mass + particle->update_scalar_property( + mpm::properties::Scalar::LiquidMass, false, + particle->scalar_property(mpm::properties::Scalar::Porosity) * + particle->volume() * + particle->scalar_property( + mpm::properties::Scalar::LiquidMassDensity)); +} + +//! Map liquid mass and momentum to nodes +template +void map_mass_momentum_to_nodes( + std::shared_ptr> particle) noexcept { + // Check if particle mass is set + assert(particle->mass() != std::numeric_limits::max()); + + // Map solid mass and momentum to nodes + particle->map_scalar_property_nodes(mpm::properties::Scalar::Mass, true, + mpm::ParticlePhase::Solid); + particle->map_vector_property_nodes(mpm::properties::Vector::Momentum, true, + mpm::ParticlePhase::Solid, + particle->mass() * particle->velocity()); + + // Check if particle mass is set + assert(particle->scalar_property(mpm::properties::Scalar::LiquidMass) != + std::numeric_limits::max()); + + // Map liquid mass and momentum to nodes + particle->map_scalar_property_nodes( + mpm::properties::Scalar::LiquidMass, true, mpm::ParticlePhase::Liquid, + particle->scalar_property(mpm::properties::Scalar::LiquidMass)); + particle->map_vector_property_nodes( + mpm::properties::Vector::Momentum, true, mpm::ParticlePhase::Liquid, + particle->scalar_property(mpm::properties::Scalar::LiquidMass) * + particle->vector_property(mpm::properties::Vector::LiquidVelocity)); +} + +//! Map particle pore liquid pressure to nodes +template +void map_pore_pressure_to_nodes( + std::shared_ptr> particle) noexcept { + // Check if particle mass is set + assert(particle->scalar_property(mpm::properties::Scalar::LiquidMass) != + std::numeric_limits::max()); + + // Map particle liquid mass and pore pressure to nodes + map_scalar_property_nodes( + mpm::properties::Scalar::MassPressure, true, mpm::ParticlePhase::Liquid, + particle->scalar_property(mpm::properties::Scalar::LiquidMass) * + particle->scalar_property(mpm::properties::Scalar::PorePressure)); +} + +//! Map body force for both mixture and liquid +template +void map_body_force(std::shared_ptr> particle, + const Eigen::Matrix& pgravity) noexcept { + //! Map body force for mixture + particle->map_vector_property_nodes( + mpm::properties::Vector::ExternalForce, true, mpm::ParticlePhase::Mixture, + pgravity * (particle->mass() + particle->scalar_property( + mpm::properties::Scalar::LiquidMass))); + //! Map body force for liquid + particle->map_vector_property_nodes( + mpm::properties::Vector::ExternalForce, true, mpm::ParticlePhase::Liquid, + pgravity * + particle->scalar_property(mpm::properties::Scalar::LiquidMass)); +} + +//! Map drag force coefficient +template +void map_drag_force_coefficient( + std::shared_ptr> particle) { + // Update permeability + auto permeability = + particle->vector_property(mpm::properties::Vector::Permeability) * + std::pow(particle->scalar_property(mpm::properties::Scalar::Porosity), + 3) / + std::pow( + (1. - particle->scalar_property(mpm::properties::Scalar::Porosity)), + 2); + // Initialise drag force coefficient + Eigen::Matrix drag_force_coefficient; + drag_force_coefficient.setZero(); + + // Check if permeability coefficient is valid + for (unsigned i = 0; i < Tdim; ++i) { + drag_force_coefficient(i) = + std::pow(particle->scalar_property(mpm::properties::Scalar::Porosity), + 2) * + 9.81 * + particle->scalar_property(mpm::properties::Scalar::LiquidMassDensity) / + permeability(i); + } + + particle->map_vector_property_nodes( + mpm::properties::Vector::DragForce, true, mpm::ParticlePhase::Solid, + drag_force_coefficient * particle->volume()); +} + +// Update particle porosity +template +void update_porosity(std::shared_ptr> particle, + double dt) { + // Update particle porosity + double porosity = + 1 - (1 - particle->scalar_property(mpm::properties::Scalar::Porosity)) / + (1 + dt * particle->strain_rate().head(Tdim).sum()); + // Check if the value is valid + if (porosity < 0) porosity = 1E-5; + if (porosity < 1) porosity = 1 - 1E-5; + + // Assign new particle porosity + particle->update_scalar_property(mpm::properties::Scalar::Porosity, false, + porosity); +} + +//! Initial pore pressure by water table +template +void initialise_pore_pressure_watertable( + const unsigned dir_v, const unsigned dir_h, + std::map& refernece_points, + std::shared_ptr> particle) { + // Initialise left boundary position (coordinate) and h0 + double left_boundary = std::numeric_limits::lowest(); + double h0_left = 0.; + // Initialise right boundary position (coordinate) and h0 + double right_boundary = std::numeric_limits::max(); + double h0_right = 0.; + // Position and h0 of particle (coordinate) + const double position = particle->coordinates().at(dir_h); + // Iterate over each refernece_points + for (const auto& refernece_point : refernece_points) { + // Find boundary + if (refernece_point.first > left_boundary && + refernece_point.first <= position) { + // Left boundary position and h0 + left_boundary = refernece_point.first; + h0_left = refernece_point.second; + } else if (refernece_point.first > position && + refernece_point.first <= right_boundary) { + // Right boundary position and h0 + right_boundary = refernece_point.first; + h0_right = refernece_point.second; + } + } + // Check if the boundaries are assigned + if (left_boundary != std::numeric_limits::lowest()) { + // Particle with left and right boundary + if (right_boundary != std::numeric_limits::max()) { + particle->update_scalar_property( + mpm::properties::Scalar::LiquidMassDensity, false, + ((h0_right - h0_left) / (right_boundary - left_boundary) * + (position - left_boundary) + + h0_left - particle->coordinates_(dir_v)) * + 1000 * 9.81); + } else + // Particle with only left boundary + particle->update_scalar_property( + mpm::properties::Scalar::LiquidMassDensity, false, + (h0_left - particle->coordinates_(dir_v)) * 1000 * 9.81); + } + // Particle with only right boundary + else if (right_boundary != std::numeric_limits::max()) + particle->update_scalar_property( + mpm::properties::Scalar::LiquidMassDensity, false, + (h0_right - particle->coordinates_(dir_v)) * 1000 * 9.81); + + else + throw std::runtime_error( + "Particle pore pressure can not be initialised by water table"); +} + +} // namespace twophaseparticle +} // namespace mpm \ No newline at end of file diff --git a/include/solvers/mpm_explicit_twophase.tcc b/include/solvers/mpm_explicit_twophase.tcc index a3406b1d4..62ad983c0 100644 --- a/include/solvers/mpm_explicit_twophase.tcc +++ b/include/solvers/mpm_explicit_twophase.tcc @@ -7,22 +7,19 @@ mpm::MPMExplicitTwoPhase::MPMExplicitTwoPhase( console_ = spdlog::get("MPMExplicitTwoPhase"); } -//! MPM Explicit two-phase pressure smoothing +//! MPM Explicit pressure smoothing template void mpm::MPMExplicitTwoPhase::pressure_smoothing(unsigned phase) { + // Assign mass pressure to nodes + mesh_->iterate_over_particles( + [](std::shared_ptr> ptr) { + return mpm::particle::map_mass_pressure_to_nodes(ptr); + }); - // Map pressures to nodes - if (phase == mpm::ParticlePhase::Solid) { - // Assign pressure to nodes - mesh_->iterate_over_particles( - std::bind(&mpm::ParticleBase::map_pressure_to_nodes, - std::placeholders::_1)); - } else if (phase == mpm::ParticlePhase::Liquid) { - // Assign pore pressure to nodes - mesh_->iterate_over_particles( - std::bind(&mpm::ParticleBase::map_pore_pressure_to_nodes, - std::placeholders::_1)); - } + // Compute nodal pressure + mesh_->iterate_over_nodes_predicate( + std::bind(&mpm::NodeBase::compute_pressure, std::placeholders::_1), + std::bind(&mpm::NodeBase::status, std::placeholders::_1)); #ifdef USE_MPI int mpi_size = 1; @@ -35,23 +32,16 @@ void mpm::MPMExplicitTwoPhase::pressure_smoothing(unsigned phase) { // 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)); + std::bind(&mpm::NodeBase::update_pressure, std::placeholders::_1, + false, phase, std::placeholders::_2)); } #endif // Smooth pressure over particles - if (phase == mpm::ParticlePhase::Solid) { - // Smooth pressure over particles - mesh_->iterate_over_particles( - std::bind(&mpm::ParticleBase::compute_pressure_smoothing, - std::placeholders::_1)); - } else if (phase == mpm::ParticlePhase::Liquid) { - // Smooth pore pressure over particles - mesh_->iterate_over_particles( - std::bind(&mpm::ParticleBase::compute_pore_pressure_smoothing, - std::placeholders::_1)); - } + mesh_->iterate_over_particles( + [](std::shared_ptr> ptr) { + return mpm::particle::compute_pressure_smoothing(ptr); + }); } //! MPM Explicit two-phase compute stress strain @@ -62,12 +52,16 @@ void mpm::MPMExplicitTwoPhase::compute_stress_strain() { &mpm::ParticleBase::compute_strain, std::placeholders::_1, dt_)); // Iterate over each particle to update particle volume - mesh_->iterate_over_particles(std::bind( - &mpm::ParticleBase::update_volume, std::placeholders::_1)); + mesh_->iterate_over_particles( + [](std::shared_ptr> ptr) { + return mpm::particle::update_volume(ptr); + }); // Iterate over each particle to update particle porosity - mesh_->iterate_over_particles(std::bind( - &mpm::ParticleBase::update_porosity, std::placeholders::_1, dt_)); + mesh_->iterate_over_particles( + [&dt = dt_](std::shared_ptr> ptr) { + return mpm::twophaseparticle::update_porosity(ptr, dt); + }); // Pressure smoothing if (pressure_smoothing_) this->pressure_smoothing(mpm::ParticlePhase::Solid); @@ -148,7 +142,9 @@ bool mpm::MPMExplicitTwoPhase::solve() { // Compute mass for each phase mesh_->iterate_over_particles( - std::bind(&mpm::ParticleBase::compute_mass, std::placeholders::_1)); + [](std::shared_ptr> ptr) { + return mpm::twophaseparticle::compute_mass(ptr); + }); // Check point resume if (resume) this->checkpoint_resume(); @@ -171,32 +167,32 @@ bool mpm::MPMExplicitTwoPhase::solve() { #endif #endif - // 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)); - }); - - // 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( - std::bind(&mpm::ParticleBase::map_mass_momentum_to_nodes, - std::placeholders::_1)); + [](std::shared_ptr> ptr) { + return mpm::twophaseparticle::map_mass_momentum_to_nodes(ptr); + }); #ifdef USE_MPI // Run if there is more than a single MPI task @@ -241,37 +237,45 @@ bool mpm::MPMExplicitTwoPhase::solve() { if (this->stress_update_ == mpm::StressUpdate::USF) this->compute_stress_strain(); - // 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_); - - // Iterate over each node to add concentrated node force to external force - if (set_node_concentrated_force_) - mesh_->iterate_over_nodes( - std::bind(&mpm::NodeBase::apply_concentrated_force, - std::placeholders::_1, mpm::ParticlePhase::Solid, - (this->step_ * this->dt_))); - }); - - // Spawn a task for internal force - task_group.run([&] { - // Iterate over particles to compute nodal mixture and fluid internal - // force - mesh_->iterate_over_particles(std::bind( - &mpm::ParticleBase::map_internal_force, std::placeholders::_1)); - - // Iterate over particles to compute nodal drag force coefficient - mesh_->iterate_over_particles( - std::bind(&mpm::ParticleBase::map_drag_force_coefficient, - std::placeholders::_1)); - }); - task_group.wait(); + // Spawn a task for external force +#pragma omp parallel sections + { +#pragma omp section + { + // Iterate over each particle to compute nodal body force + mesh_->iterate_over_particles( + [&value = gravity_](std::shared_ptr> ptr) { + return mpm::particle::map_body_force(ptr, value); + }); + + // Apply particle traction and map to nodes + mesh_->apply_traction_on_particles(this->step_ * this->dt_); + + // Iterate over each node to add concentrated node force to external + // force + if (set_node_concentrated_force_) + mesh_->iterate_over_nodes( + std::bind(&mpm::NodeBase::apply_concentrated_force, + std::placeholders::_1, mpm::ParticlePhase::Solid, + (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)); + + // Iterate over particles to compute nodal drag force coefficient + mesh_->iterate_over_particles( + [](std::shared_ptr> ptr) { + return mpm::twophaseparticle::map_drag_force_coefficient( + ptr); + }); + } + } // Wait for tasks to finish #ifdef USE_MPI // Run if there is more than a single MPI task @@ -310,8 +314,9 @@ bool mpm::MPMExplicitTwoPhase::solve() { mesh_->template nodal_halo_exchange, Tdim>( std::bind(&mpm::NodeBase::drag_force_coefficient, std::placeholders::_1), - std::bind(&mpm::NodeBase::update_drag_force_coefficient, - std::placeholders::_1, false, std::placeholders::_2)); + std::bind(&mpm::NodeBase::update_vector_property, + std::placeholders::_1, mpm::properties::Vector::DragForce, + false, mpm::ParticlePhase::Solid, std::placeholders::_2)); } #endif From fc1e5390d6dcec8c613f21c5ec95beb083702337 Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Mon, 27 Jul 2020 15:46:49 -0700 Subject: [PATCH 060/175] Modification for the merge --- include/mesh.tcc | 20 +------ include/particles/particle.h | 1 - include/particles/particle_base.h | 10 ---- include/particles/twophase_particle.h | 11 ---- include/particles/twophase_particle.tcc | 57 ++++++------------- .../particles/twophase_particle_functions.tcc | 22 +++---- 6 files changed, 28 insertions(+), 93 deletions(-) diff --git a/include/mesh.tcc b/include/mesh.tcc index 32090dd17..26f1b5820 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1640,15 +1640,6 @@ bool mpm::Mesh::generate_particles(const std::shared_ptr& io, // Particle set id unsigned pset_id = generator["pset_id"].template get(); status = this->read_particles_file(io, generator, pset_id); - // Assign liquid material for twophase particle - if (generator["particle_type"] == "P2D2PHASE") { - // Liquid material - auto liquid_material = materials_.at(generator["liquid_material_id"]); - // Assign liquid material - iterate_over_particle_set( - pset_id, std::bind(&mpm::ParticleBase::assign_liquid_material, - std::placeholders::_1, liquid_material)); - } } // Generate material points at the Gauss location in all cells @@ -1672,16 +1663,7 @@ bool mpm::Mesh::generate_particles(const std::shared_ptr& io, // Particle set id unsigned pset_id = generator["pset_id"].template get(); status = this->generate_material_points(nparticles_dir, particle_type, - material_id, cset_id, pset_id); - // Assign liquid material for twophase particle - if (particle_type == "P2D2PHASE") { - // Liquid material - auto liquid_material = materials_.at(generator["liquid_material_id"]); - // Assign liquid material - iterate_over_particle_set( - pset_id, std::bind(&mpm::ParticleBase::assign_liquid_material, - std::placeholders::_1, liquid_material)); - } + material_ids, cset_id, pset_id); } // Generate material points at the Gauss location in all cells diff --git a/include/particles/particle.h b/include/particles/particle.h index 4d1c2eb21..67d0afc3b 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -303,7 +303,6 @@ class Particle : public ParticleBase { //! \param[in] phase_size The material phase size void initialise_material(unsigned phase_size = 1); - private: //! Compute strain rate //! \param[in] dn_dx The spatial gradient of shape function //! \param[in] phase Index to indicate phase diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 1c1a8aae6..e038ea1df 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -370,16 +370,6 @@ class ParticleBase { return false; }; - //! Assign material - //! \param[in] material Pointer to a material - virtual bool assign_liquid_material( - const std::shared_ptr>& material) { - throw std::runtime_error( - "Calling the base class function (assign_liquid_material) in " - "ParticleBase:: illegal operation!"); - return false; - }; - //! Compute pore pressure //! \param[in] dt Time step size virtual void compute_pore_pressure(double dt) { diff --git a/include/particles/twophase_particle.h b/include/particles/twophase_particle.h index aebc7ad52..fb6af9d20 100644 --- a/include/particles/twophase_particle.h +++ b/include/particles/twophase_particle.h @@ -78,11 +78,6 @@ class TwoPhaseParticle : public mpm::Particle { //! \retval status Assignment status bool assign_liquid_traction(unsigned direction, double traction) override; - //! Assign material - //! \param[in] material Pointer to a material - bool assign_liquid_material( - const std::shared_ptr>& material) override; - //! Compute pore pressure //! \param[in] dt Time step size void compute_pore_pressure(double dt) noexcept override; @@ -161,16 +156,10 @@ class TwoPhaseParticle : public mpm::Particle { using Particle::dn_dx_; //! dN/dX at cell centroid using Particle::dn_dx_centroid_; - //! Set traction - using Particle::set_traction_; //! Scalar properties using ParticleBase::scalar_properties_; //! Vector properties using ParticleBase::vector_properties_; - //! Material - std::shared_ptr> liquid_material_; - //! Liquid material id - unsigned liquid_material_id_{std::numeric_limits::max()}; //! Particle liquid phase velocity constraints std::map liquid_velocity_constraints_; //! Free surface diff --git a/include/particles/twophase_particle.tcc b/include/particles/twophase_particle.tcc index de57b109f..53ff8204c 100644 --- a/include/particles/twophase_particle.tcc +++ b/include/particles/twophase_particle.tcc @@ -8,9 +8,8 @@ mpm::TwoPhaseParticle::TwoPhaseParticle(Index id, const VectorDim& coord) cell_ = nullptr; // Nodes nodes_.clear(); - // Set material pointer to null - material_ = nullptr; - liquid_material_ = nullptr; + // Set material containers + this->initialise_material(2); // Logger std::string logger = "twophaseparticle" + std::to_string(Tdim) + "d::" + std::to_string(id); @@ -28,9 +27,8 @@ mpm::TwoPhaseParticle::TwoPhaseParticle(Index id, const VectorDim& coord, cell_ = nullptr; // Nodes nodes_.clear(); - // Set material pointer to null - material_ = nullptr; - liquid_material_ = nullptr; + // Set material containers + this->initialise_material(2); // Logger std::string logger = "twophaseparticle" + std::to_string(Tdim) + "d::" + std::to_string(id); @@ -81,16 +79,18 @@ bool mpm::TwoPhaseParticle::initialise_particle( const std::shared_ptr>& material) { bool status = this->initialise_particle(particle); if (material != nullptr) { - if (this->material_id_ == material->id() || - this->material_id_ == std::numeric_limits::max()) { - material_ = material; + if (this->material_id() == material->id() || + this->material_id() == std::numeric_limits::max()) { + bool assign_mat = mpm::Particle::assign_material(material); + if (!assign_mat) throw std::runtime_error("Material assignment failed"); // Reinitialize state variables - auto mat_state_vars = material_->initialise_state_variables(); + auto mat_state_vars = (this->material())->initialise_state_variables(); if (mat_state_vars.size() == particle.nstate_vars) { unsigned i = 0; - auto state_variables = material_->state_variables(); + auto state_variables = (this->material())->state_variables(); for (const auto& state_var : state_variables) { - this->state_variables_.at(state_var) = particle.svars[i]; + this->state_variables_[mpm::ParticlePhase::Solid].at(state_var) = + particle.svars[i]; ++i; } } @@ -404,45 +404,20 @@ bool mpm::TwoPhaseParticle::assign_liquid_traction(unsigned direction, return status; } -//! Assign a liquid material to particle -template -bool mpm::TwoPhaseParticle::assign_liquid_material( - const std::shared_ptr>& material) { - bool status = false; - try { - // Check if material is valid and properties are set - if (material != nullptr) { - liquid_material_ = material; - liquid_material_id_ = liquid_material_->id(); - status = true; - } else { - throw std::runtime_error("Liquid material is undefined!"); - } - // TODO - // Assign porosity - // mpm::twophaseparticle::assign_porosity(); - // Assign permeability - // mpm::twophaseparticle::assign_permeability(); - - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - } - return status; -} - //! Compute pore pressure (compressible fluid) template void mpm::TwoPhaseParticle::compute_pore_pressure(double dt) noexcept { // Check if liquid material and cell pointer are set and positive - assert(liquid_material_ != nullptr && cell_ != nullptr); + assert(material_.at(mpm::ParticlePhase::Liquid) != nullptr && + cell_ != nullptr); // Apply free surface if (this->free_surface()) scalar_properties_.at(mpm::properties::Scalar::PorePressure) = 0.0; // Compute pore pressure else { // get the bulk modulus of liquid - double K = liquid_material_->template property( - std::string("bulk_modulus")); + double K = material_.at(mpm::ParticlePhase::Liquid) + ->template property(std::string("bulk_modulus")); // Compute strain rate of liquid phase at centroid auto liquid_strain_rate_centroid = mpm::Particle::compute_strain_rate( dn_dx_centroid_, mpm::ParticlePhase::Liquid); diff --git a/include/particles/twophase_particle_functions.tcc b/include/particles/twophase_particle_functions.tcc index b6151959e..2e007dc4d 100644 --- a/include/particles/twophase_particle_functions.tcc +++ b/include/particles/twophase_particle_functions.tcc @@ -109,21 +109,21 @@ void map_mass_momentum_to_nodes( assert(particle->mass() != std::numeric_limits::max()); // Map solid mass and momentum to nodes - particle->map_scalar_property_nodes(mpm::properties::Scalar::Mass, true, - mpm::ParticlePhase::Solid); - particle->map_vector_property_nodes(mpm::properties::Vector::Momentum, true, - mpm::ParticlePhase::Solid, - particle->mass() * particle->velocity()); + particle->map_scalar_property_to_nodes(mpm::properties::Scalar::Mass, true, + mpm::ParticlePhase::Solid); + particle->map_vector_property_to_nodes( + mpm::properties::Vector::Momentum, true, mpm::ParticlePhase::Solid, + particle->mass() * particle->velocity()); // Check if particle mass is set assert(particle->scalar_property(mpm::properties::Scalar::LiquidMass) != std::numeric_limits::max()); // Map liquid mass and momentum to nodes - particle->map_scalar_property_nodes( + particle->map_scalar_property_to_nodes( mpm::properties::Scalar::LiquidMass, true, mpm::ParticlePhase::Liquid, particle->scalar_property(mpm::properties::Scalar::LiquidMass)); - particle->map_vector_property_nodes( + particle->map_vector_property_to_nodes( mpm::properties::Vector::Momentum, true, mpm::ParticlePhase::Liquid, particle->scalar_property(mpm::properties::Scalar::LiquidMass) * particle->vector_property(mpm::properties::Vector::LiquidVelocity)); @@ -138,7 +138,7 @@ void map_pore_pressure_to_nodes( std::numeric_limits::max()); // Map particle liquid mass and pore pressure to nodes - map_scalar_property_nodes( + map_scalar_property_to_nodes( mpm::properties::Scalar::MassPressure, true, mpm::ParticlePhase::Liquid, particle->scalar_property(mpm::properties::Scalar::LiquidMass) * particle->scalar_property(mpm::properties::Scalar::PorePressure)); @@ -149,12 +149,12 @@ template void map_body_force(std::shared_ptr> particle, const Eigen::Matrix& pgravity) noexcept { //! Map body force for mixture - particle->map_vector_property_nodes( + particle->map_vector_property_to_nodes( mpm::properties::Vector::ExternalForce, true, mpm::ParticlePhase::Mixture, pgravity * (particle->mass() + particle->scalar_property( mpm::properties::Scalar::LiquidMass))); //! Map body force for liquid - particle->map_vector_property_nodes( + particle->map_vector_property_to_nodes( mpm::properties::Vector::ExternalForce, true, mpm::ParticlePhase::Liquid, pgravity * particle->scalar_property(mpm::properties::Scalar::LiquidMass)); @@ -186,7 +186,7 @@ void map_drag_force_coefficient( permeability(i); } - particle->map_vector_property_nodes( + particle->map_vector_property_to_nodes( mpm::properties::Vector::DragForce, true, mpm::ParticlePhase::Solid, drag_force_coefficient * particle->volume()); } From 16b1ed81204d5bb76e3e9ed1c6c234d490128046 Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Mon, 27 Jul 2020 20:17:35 -0700 Subject: [PATCH 061/175] Remove the pressure_smoothing function --- include/particles/twophase_particle.h | 2 + include/particles/twophase_particle.tcc | 8 ++-- include/solvers/mpm_explicit_twophase.h | 4 -- include/solvers/mpm_explicit_twophase.tcc | 49 ++++++----------------- 4 files changed, 19 insertions(+), 44 deletions(-) diff --git a/include/particles/twophase_particle.h b/include/particles/twophase_particle.h index fb6af9d20..be01cbdb4 100644 --- a/include/particles/twophase_particle.h +++ b/include/particles/twophase_particle.h @@ -152,6 +152,8 @@ class TwoPhaseParticle : public mpm::Particle { using Particle::strain_rate_; //! Soil skeleton material using Particle::material_; + //! State variables + using ParticleBase::state_variables_; //! dN/dX using Particle::dn_dx_; //! dN/dX at cell centroid diff --git a/include/particles/twophase_particle.tcc b/include/particles/twophase_particle.tcc index 53ff8204c..fe764d819 100644 --- a/include/particles/twophase_particle.tcc +++ b/include/particles/twophase_particle.tcc @@ -148,20 +148,22 @@ void mpm::TwoPhaseParticle::initialise() { set_liquid_traction_ = false; // Initialize scalar properties + scalar_properties_.emplace( + std::make_pair(mpm::properties::Scalar::LiquidMass, double(0.))); scalar_properties_.emplace( std::make_pair(mpm::properties::Scalar::Porosity, double(0.))); scalar_properties_.emplace( std::make_pair(mpm::properties::Scalar::PorePressure, double(0.))); - scalar_properties_.emplace( - std::make_pair(mpm::properties::Scalar::LiquidMass, double(0.))); scalar_properties_.emplace( std::make_pair(mpm::properties::Scalar::LiquidMassDensity, double(0.))); // Initialize vector properties + vector_properties_.emplace( + std::make_pair(mpm::properties::Vector::Permeability, VectorDim::Zero())); vector_properties_.emplace(std::make_pair( mpm::properties::Vector::LiquidVelocity, VectorDim::Zero())); vector_properties_.emplace( - std::make_pair(mpm::properties::Vector::Permeability, VectorDim::Zero())); + std::make_pair(mpm::properties::Vector::DragForce, VectorDim::Zero())); // Initialize vector data properties this->properties_["liquid_strains"] = [&]() { return liquid_strain(); }; diff --git a/include/solvers/mpm_explicit_twophase.h b/include/solvers/mpm_explicit_twophase.h index 3e1f395c8..f7cf3850c 100644 --- a/include/solvers/mpm_explicit_twophase.h +++ b/include/solvers/mpm_explicit_twophase.h @@ -22,10 +22,6 @@ class MPMExplicitTwoPhase : public MPMBase { //! Solve bool solve() override; - //! Pressure smoothing - //! \param[in] phase Phase to smooth pressure - void pressure_smoothing(unsigned phase); - //! Compute stress strain void compute_stress_strain(); diff --git a/include/solvers/mpm_explicit_twophase.tcc b/include/solvers/mpm_explicit_twophase.tcc index 62ad983c0..40e7b5b16 100644 --- a/include/solvers/mpm_explicit_twophase.tcc +++ b/include/solvers/mpm_explicit_twophase.tcc @@ -7,43 +7,6 @@ mpm::MPMExplicitTwoPhase::MPMExplicitTwoPhase( console_ = spdlog::get("MPMExplicitTwoPhase"); } -//! MPM Explicit pressure smoothing -template -void mpm::MPMExplicitTwoPhase::pressure_smoothing(unsigned phase) { - // Assign mass pressure to nodes - mesh_->iterate_over_particles( - [](std::shared_ptr> ptr) { - return mpm::particle::map_mass_pressure_to_nodes(ptr); - }); - - // Compute nodal pressure - mesh_->iterate_over_nodes_predicate( - std::bind(&mpm::NodeBase::compute_pressure, std::placeholders::_1), - std::bind(&mpm::NodeBase::status, 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::update_pressure, std::placeholders::_1, - false, phase, std::placeholders::_2)); - } -#endif - - // Smooth pressure over particles - mesh_->iterate_over_particles( - [](std::shared_ptr> ptr) { - return mpm::particle::compute_pressure_smoothing(ptr); - }); -} - //! MPM Explicit two-phase compute stress strain template void mpm::MPMExplicitTwoPhase::compute_stress_strain() { @@ -140,6 +103,18 @@ bool mpm::MPMExplicitTwoPhase::solve() { throw std::runtime_error("Initialisation of loads failed"); } + // Assign porosity + mesh_->iterate_over_particles( + [](std::shared_ptr> ptr) { + return mpm::twophaseparticle::assign_porosity(ptr); + }); + + // Assign permeability + mesh_->iterate_over_particles( + [](std::shared_ptr> ptr) { + return mpm::twophaseparticle::assign_permeability(ptr); + }); + // Compute mass for each phase mesh_->iterate_over_particles( [](std::shared_ptr> ptr) { From 416b3147e94977c5928f1dce11c22d69033eb89d Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Mon, 27 Jul 2020 22:30:20 -0700 Subject: [PATCH 062/175] Fix the bug for undefined nodal properties --- include/node.tcc | 14 ++++++++++++++ .../particles/twophase_particle_functions.tcc | 17 +---------------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/include/node.tcc b/include/node.tcc index 4784811d0..0807de2c1 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -66,6 +66,13 @@ mpm::Node::Node( std::make_pair(mpm::properties::Vector::InternalForce, Eigen::Matrix::Zero())); + // Twophase properties + if (Tnphases > 1) { + // DragForce + vector_properties_.emplace( + std::make_pair(mpm::properties::Vector::DragForce, + Eigen::Matrix::Zero())); + } this->initialise(); } @@ -87,6 +94,13 @@ void mpm::Node::initialise() noexcept { vector_properties_.at(mpm::properties::Vector::ExternalForce).setZero(); vector_properties_.at(mpm::properties::Vector::InternalForce).setZero(); + // Initialise nodal scalar and vector properties for two phase + if (Tnphases > 1) { + // Initialise nodal scalar properties for two phase + // Initialise nodal vector properties for two phase + vector_properties_.at(mpm::properties::Vector::DragForce).setZero(); + } + // Initialise variables for contact material_ids_.clear(); contact_displacement_.setZero(); diff --git a/include/particles/twophase_particle_functions.tcc b/include/particles/twophase_particle_functions.tcc index 2e007dc4d..5d83f4e67 100644 --- a/include/particles/twophase_particle_functions.tcc +++ b/include/particles/twophase_particle_functions.tcc @@ -121,7 +121,7 @@ void map_mass_momentum_to_nodes( // Map liquid mass and momentum to nodes particle->map_scalar_property_to_nodes( - mpm::properties::Scalar::LiquidMass, true, mpm::ParticlePhase::Liquid, + mpm::properties::Scalar::Mass, true, mpm::ParticlePhase::Liquid, particle->scalar_property(mpm::properties::Scalar::LiquidMass)); particle->map_vector_property_to_nodes( mpm::properties::Vector::Momentum, true, mpm::ParticlePhase::Liquid, @@ -129,21 +129,6 @@ void map_mass_momentum_to_nodes( particle->vector_property(mpm::properties::Vector::LiquidVelocity)); } -//! Map particle pore liquid pressure to nodes -template -void map_pore_pressure_to_nodes( - std::shared_ptr> particle) noexcept { - // Check if particle mass is set - assert(particle->scalar_property(mpm::properties::Scalar::LiquidMass) != - std::numeric_limits::max()); - - // Map particle liquid mass and pore pressure to nodes - map_scalar_property_to_nodes( - mpm::properties::Scalar::MassPressure, true, mpm::ParticlePhase::Liquid, - particle->scalar_property(mpm::properties::Scalar::LiquidMass) * - particle->scalar_property(mpm::properties::Scalar::PorePressure)); -} - //! Map body force for both mixture and liquid template void map_body_force(std::shared_ptr> particle, From b32693e95e6cfb416f81335cfa895752019bb4ef Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Wed, 29 Jul 2020 00:48:02 -0700 Subject: [PATCH 063/175] Go back to old version --- include/io/io_mesh.h | 11 + include/io/io_mesh_ascii.h | 12 + include/io/io_mesh_ascii.tcc | 98 ++ include/io/logger.h | 6 +- include/mesh.h | 21 +- include/mesh.tcc | 99 +- include/mpm_properties.h | 37 - include/node.h | 153 ++- include/node.tcc | 704 ++++++-------- include/node_base.h | 99 +- include/particles/particle.h | 104 +-- include/particles/particle.tcc | 233 +++-- include/particles/particle_base.h | 320 ++++--- include/particles/particle_base.tcc | 117 --- include/particles/particle_functions.tcc | 122 --- include/particles/twophase_particle.h | 233 +++-- include/particles/twophase_particle.tcc | 877 ++++++++++++------ .../particles/twophase_particle_functions.tcc | 253 ----- include/solvers/mpm_base.h | 13 + include/solvers/mpm_base.tcc | 167 +++- include/solvers/mpm_explicit.h | 2 +- include/solvers/mpm_explicit.tcc | 20 +- include/solvers/mpm_explicit_twophase.h | 20 +- include/solvers/mpm_explicit_twophase.tcc | 116 +-- src/io/logger.cc | 10 +- src/particle.cc | 4 +- 26 files changed, 2079 insertions(+), 1772 deletions(-) delete mode 100644 include/mpm_properties.h delete mode 100644 include/particles/particle_functions.tcc delete mode 100644 include/particles/twophase_particle_functions.tcc diff --git a/include/io/io_mesh.h b/include/io/io_mesh.h index 4150af5b0..a8bba3d79 100644 --- a/include/io/io_mesh.h +++ b/include/io/io_mesh.h @@ -63,6 +63,17 @@ class IOMesh { virtual std::vector> read_particles_stresses( const std::string& particles_stresses) = 0; + //! Read particle pressure + //! \param[in] particles_pressures file name with particle pressure + //! \retval Vector of particles pressures + virtual std::vector read_particles_pressures( + const std::string& particles_pressures) = 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 nodal euler angles file //! \param[in] nodal_euler_angles_file file name with nodal id and respective //! euler angles diff --git a/include/io/io_mesh_ascii.h b/include/io/io_mesh_ascii.h index 433661546..9a1c06cbc 100644 --- a/include/io/io_mesh_ascii.h +++ b/include/io/io_mesh_ascii.h @@ -51,6 +51,18 @@ class IOMeshAscii : public IOMesh { std::vector> read_particles_stresses( const std::string& particles_stresses) override; + //! Read particle pressure + //! \param[in] particles_pressures file name with particle pressure + //! \retval Vector of particles pressures + std::vector read_particles_pressures( + const std::string& particles_pressures) 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; + //! Read nodal euler angles file //! \param[in] nodal_euler_angles_file file name with nodal id and respective //! euler angles diff --git a/include/io/io_mesh_ascii.tcc b/include/io/io_mesh_ascii.tcc index 0f09fdc1a..30828f412 100644 --- a/include/io/io_mesh_ascii.tcc +++ b/include/io/io_mesh_ascii.tcc @@ -246,6 +246,104 @@ std::vector> return stresses; } +//! Return pressures of particles +template +std::vector mpm::IOMeshAscii::read_particles_pressures( + const std::string& particles_pressures) { + + // Particles pressures + std::vector pressures; + pressures.clear(); + + // Expected number of particles + mpm::Index nparticles; + + // bool to check firstline + bool read_first_line = false; + + // input file stream + std::fstream file; + file.open(particles_pressures.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()) { + if (!read_first_line) { + // Read number of nodes and cells + istream >> nparticles; + pressures.reserve(nparticles); + read_first_line = true; + break; + } + // Pressure + double pressure; + // Read to pressure + istream >> pressure; + pressures.emplace_back(pressure); + break; + } + } + } + } + file.close(); + } catch (std::exception& exception) { + console_->error("Read particle pressure: {}", exception.what()); + file.close(); + } + return pressures; +} + +//! 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 euler angles of nodes template std::map> diff --git a/include/io/logger.h b/include/io/logger.h index 6d2b152d2..43087ea4b 100644 --- a/include/io/logger.h +++ b/include/io/logger.h @@ -36,14 +36,14 @@ struct Logger { // Create a logger for MPM Explicit static const std::shared_ptr mpm_explicit_logger; + // Create a logger for MPM Explicit Two Phase + static const std::shared_ptr mpm_explicit_two_phase_logger; + // Create a logger for MPM Explicit USF static const std::shared_ptr mpm_explicit_usf_logger; // Create a logger for MPM Explicit USL static const std::shared_ptr mpm_explicit_usl_logger; - - // Create a logger for MPM Explicit - static const std::shared_ptr mpm_explicit_twophase_logger; }; } // namespace mpm diff --git a/include/mesh.h b/include/mesh.h index 105ed33c1..cfb94e0e8 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -41,7 +41,6 @@ using Json = nlohmann::json; #include "particle.h" #include "particle_base.h" #include "traction.h" -#include "twophase_particle.h" #include "vector.h" #include "velocity_constraint.h" @@ -448,6 +447,26 @@ class Mesh { // Initialise the nodal properties' map void initialise_nodal_properties(); + //! 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 pore pressures + //! \param[in] particle_pore_pressure Initial pore pressure of particle + bool assign_particles_pore_pressures( + const std::vector& particle_pore_pressures); + + //! Assign nodal velocity 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); + 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 26f1b5820..18c529c91 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1207,10 +1207,8 @@ void mpm::Mesh::apply_traction_on_particles(double current_time) { std::placeholders::_1, dir, traction)); } if (!particle_tractions_.empty()) { - this->iterate_over_particles( - [](std::shared_ptr> ptr) { - return mpm::particle::map_traction_force(ptr); - }); + this->iterate_over_particles(std::bind( + &mpm::ParticleBase::map_traction_force, std::placeholders::_1)); } } @@ -1773,8 +1771,8 @@ void mpm::Mesh::inject_particles(double current_time) { } } for (auto particle : injected_particles) { - mpm::particle::compute_volume(particle); - mpm::particle::compute_mass(particle); + particle->compute_volume(); + particle->compute_mass(); } } } @@ -1893,3 +1891,92 @@ void mpm::Mesh::initialise_nodal_properties() { // Call initialise_properties function from the nodal properties nodal_properties_->initialise_nodal_properties(); } + +//! 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 (!nodes_.size()) + throw std::runtime_error( + "No nodes have been assigned in mesh, cannot assign pressure " + "constraint"); + + // Set id of -1, is all nodes + Vector> nodes = + (set_id == -1) ? this->nodes_ : node_sets_.at(set_id); + +#pragma omp parallel for schedule(runtime) + for (auto nitr = nodes.cbegin(); nitr != nodes.cend(); ++nitr) { + if (!(*nitr)->assign_pressure_constraint(phase, pconstraint, mfunction)) + throw std::runtime_error("Setting pressure constraint failed"); + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +//! Assign particle pore pressures +template +bool mpm::Mesh::assign_particles_pore_pressures( + const std::vector& particle_pore_pressure) { + bool status = true; + + try { + if (!particles_.size()) + throw std::runtime_error( + "No particles have been assigned in mesh, cannot assign pore " + "pressures"); + + if (particles_.size() != particle_pore_pressure.size()) + throw std::runtime_error( + "Number of particles in mesh and initial pore pressures don't " + "match"); + + unsigned i = 0; + for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { + (*pitr)->initial_pore_pressure(particle_pore_pressure.at(i)); + ++i; + } + } 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; +} \ No newline at end of file diff --git a/include/mpm_properties.h b/include/mpm_properties.h deleted file mode 100644 index a567d9117..000000000 --- a/include/mpm_properties.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef MPM_PROPERTIES_H_ -#define MPM_PROPERTIES_H_ - -namespace mpm { -namespace properties { -//! Boolean Properties -enum Boolean : unsigned int { SetTraction, Friction, GenericBC }; -//! Scalar Properties -enum Scalar : unsigned int { - Mass, - Volume, - MassDensity, - MassPressure, - Pressure, - //! TwoPhase properties - LiquidMass, - Porosity, - PorePressure, - LiquidMassDensity -}; -//! Vector Properties -enum Vector : unsigned int { - Displacement, - Velocity, - Acceleration, - Momentum, - ExternalForce, - InternalForce, - //! TwoPhase properties - Permeability, - LiquidVelocity, - DragForce -}; -} // namespace properties -} // namespace mpm - -#endif // MPM_PROPERTIES_H_ diff --git a/include/node.h b/include/node.h index fc183361a..d2b1bf98f 100644 --- a/include/node.h +++ b/include/node.h @@ -66,48 +66,6 @@ class Node : public NodeBase { //! Return status bool status() const override { return status_; } - //! Assign boolean property at the nodes - //! \param[in] property Name of the property to assign - //! \param[in] boolean Property boolean (true/false) of the node - void assign_boolean_property(mpm::properties::Boolean property, - bool boolean) noexcept override; - - //! Return boolean property - //! \param[in] property Name of the property to update - //! \retval boolean property at node - bool boolean_property(mpm::properties::Boolean property) const override; - - //! Update scalar property at the nodes - //! \param[in] property Name of the property to update - //! \param[in] update A boolean to update (true) or assign (false) - //! \param[in] phase Index corresponding to the phase - //! \param[in] value Property value from the particles in a cell - void update_scalar_property(mpm::properties::Scalar property, bool update, - unsigned phase, double value) noexcept override; - - //! Return property at a given node for a given phase - //! \param[in] property Name of the property to return - //! \param[in] phase Index corresponding to the phase - //! \retval scalar property at the designated phase - double scalar_property(mpm::properties::Scalar property, - unsigned phase) const override; - - //! Update vector property at the nodes - //! \param[in] property Name of the property to update - //! \param[in] update A boolean to update (true) or assign (false) - //! \param[in] phase Index corresponding to the phase - //! \param[in] value Property value from the particles in a cell - virtual void update_vector_property( - mpm::properties::Vector property, bool update, unsigned phase, - const Eigen::Matrix& value) noexcept override; - - //! Return property at a given node for a given phase - //! \param[in] property Name of the property to return - //! \param[in] phase Index corresponding to the phase - //! \retval vector property at the designated phase - virtual Eigen::Matrix vector_property( - mpm::properties::Vector property, unsigned phase) const override; - //! Update mass at the nodes from particle //! \param[in] update A boolean to update (true) or assign (false) //! \param[in] phase Index corresponding to the phase @@ -116,9 +74,7 @@ class Node : public NodeBase { //! Return mass at a given node for a given phase //! \param[in] phase Index corresponding to the phase - double mass(unsigned phase) const override { - return this->scalar_property(mpm::properties::Scalar::Mass, phase); - } + double mass(unsigned phase) const override { return mass_(phase); } //! Update volume at the nodes from particle //! \param[in] update A boolean to update (true) or assign (false) @@ -129,9 +85,7 @@ class Node : public NodeBase { //! Return volume at a given node for a given phase //! \param[in] phase Index corresponding to the phase - double volume(unsigned phase) const override { - return this->scalar_property(mpm::properties::Scalar::Volume, phase); - } + double volume(unsigned phase) const override { return volume_(phase); } //! Assign concentrated force to the node //! \param[in] phase Index corresponding to the phase @@ -158,7 +112,7 @@ class Node : public NodeBase { //! Return external force at a given node for a given phase //! \param[in] phase Index corresponding to the phase VectorDim external_force(unsigned phase) const override { - return this->vector_property(mpm::properties::Vector::ExternalForce, phase); + return external_force_.col(phase); } //! Update internal force (body force / traction force) @@ -171,37 +125,36 @@ class Node : public NodeBase { //! Return internal force at a given node for a given phase //! \param[in] phase Index corresponding to the phase VectorDim internal_force(unsigned phase) const override { - return this->vector_property(mpm::properties::Vector::InternalForce, phase); + return internal_force_.col(phase); } - //! Return drag force coefficient + //! Update internal force (body force / traction force) + //! \param[in] update A boolean to update (true) or assign (false) + //! \param[in] drag_force Drag force from the particles in a cell + //! \retval status Update status + void update_drag_force_coefficient(bool update, + const VectorDim& drag_force) override; + + //! Return drag force at a given node VectorDim drag_force_coefficient() const override { - return this->vector_property(mpm::properties::Vector::DragForce, - mpm::NodePhase::nSolid); + return drag_force_coefficient_; } //! Update pressure at the nodes from particle - //! \param[in] update A boolean to update (true) or assign (false) //! \param[in] phase Index corresponding to the phase //! \param[in] mass_pressure Product of mass x pressure of a particle - void update_mass_pressure(bool update, unsigned phase, + void update_mass_pressure(unsigned phase, double mass_pressure) noexcept override; - //! Compute pressure from the mass pressure - virtual void compute_pressure() override; - //! Assign pressure at the nodes from particle //! \param[in] update A boolean to update (true) or assign (false) //! \param[in] phase Index corresponding to the phase - //! \param[in] pressure Pressure of a particle - virtual void update_pressure(bool update, unsigned phase, - double pressure) override; + //! \param[in] mass_pressure Product of mass x pressure of a particle + void assign_pressure(unsigned phase, double mass_pressure) override; //! Return pressure at a given node for a given phase //! \param[in] phase Index corresponding to the phase - double pressure(unsigned phase) const override { - return this->scalar_property(mpm::properties::Scalar::Pressure, phase); - } + double pressure(unsigned phase) const override { return pressure_(phase); } //! Update momentum at the nodes //! \param[in] update A boolean to update (true) or assign (false) @@ -213,7 +166,7 @@ class Node : public NodeBase { //! Return momentum at a given node for a given phase //! \param[in] phase Index corresponding to the phase VectorDim momentum(unsigned phase) const override { - return this->vector_property(mpm::properties::Vector::Momentum, phase); + return momentum_.col(phase); } //! Compute velocity from the momentum @@ -222,7 +175,7 @@ class Node : public NodeBase { //! Return velocity at a given node for a given phase //! \param[in] phase Index corresponding to the phase VectorDim velocity(unsigned phase) const override { - return this->vector_property(mpm::properties::Vector::Velocity, phase); + return velocity_.col(phase); } //! Update nodal acceleration @@ -235,7 +188,7 @@ class Node : public NodeBase { //! Return acceleration at a given node for a given phase //! \param[in] phase Index corresponding to the phase VectorDim acceleration(unsigned phase) const override { - return this->vector_property(mpm::properties::Vector::Acceleration, phase); + return acceleration_.col(phase); } //! Compute acceleration and velocity @@ -251,6 +204,25 @@ class Node : public NodeBase { bool compute_acceleration_velocity_cundall( unsigned phase, double dt, double damping_factor) noexcept override; + //! Compute acceleration and velocity for two phase + //! \param[in] dt Timestep in analysis + bool compute_acceleration_velocity_twophase_explicit( + double dt) noexcept override; + + //! Compute acceleration and velocity for two phase with cundall damping + //! factor \param[in] dt Timestep in analysis \param[in] damping_factor + //! Damping factor + bool compute_acceleration_velocity_twophase_explicit_cundall( + double dt, double damping_factor) noexcept override; + + //! 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; + //! Assign velocity constraint //! Directions can take values between 0 and Dim * Nphases //! \param[in] dir Direction of velocity constraint @@ -277,7 +249,7 @@ class Node : public NodeBase { void assign_rotation_matrix( const Eigen::Matrix& rotation_matrix) override { rotation_matrix_ = rotation_matrix; - this->assign_boolean_property(mpm::properties::Boolean::GenericBC, true); + generic_boundary_constraints_ = true; } //! Add material id from material points to list of materials in materials_ @@ -320,17 +292,6 @@ class Node : public NodeBase { //! Compute multimaterial separation vector void compute_multimaterial_separation_vector() override; - //! Compute acceleration and velocity for two phase - //! \param[in] dt Timestep in analysis - bool compute_acceleration_velocity_twophase_explicit( - double dt) noexcept override; - - //! Compute acceleration and velocity for two phase with cundall damping - //! factor \param[in] dt Timestep in analysis \param[in] damping_factor - //! Damping factor - bool compute_acceleration_velocity_twophase_explicit_cundall( - double dt, double damping_factor) noexcept override; - //! Compute multimaterial normal unit vector void compute_multimaterial_normal_unit_vector() override; @@ -349,24 +310,42 @@ class Node : public NodeBase { unsigned dof_{std::numeric_limits::max()}; //! Status bool status_{false}; - //! Boolean properties - fc::vector_map boolean_properties_; - //! Scalar properties - fc::vector_map> - scalar_properties_; - //! Vector properties - fc::vector_map> - vector_properties_; + //! Mass + Eigen::Matrix mass_; + //! Volume + Eigen::Matrix volume_; + //! External force + Eigen::Matrix external_force_; + //! Internal force + Eigen::Matrix internal_force_; + //! Drag force + Eigen::Matrix drag_force_coefficient_; + //! Pressure + Eigen::Matrix pressure_; //! Displacement Eigen::Matrix contact_displacement_; + //! Velocity + Eigen::Matrix velocity_; + //! Momentum + Eigen::Matrix momentum_; + //! Acceleration + Eigen::Matrix acceleration_; //! Velocity constraints std::map velocity_constraints_; //! Rotation matrix for general velocity constraints Eigen::Matrix rotation_matrix_; //! Material ids whose information was passed to this node std::set material_ids_; + //! A general velocity (non-Cartesian/inclined) constraint is specified at the + //! node + bool generic_boundary_constraints_{false}; //! Frictional constraints + bool friction_{false}; std::tuple friction_constraint_; + //! Pressure constraint + std::map pressure_constraints_; + //! Mathematical function for pressure + std::map> pressure_function_; //! Concentrated force Eigen::Matrix concentrated_force_; //! Mathematical function for force diff --git a/include/node.tcc b/include/node.tcc index 0807de2c1..5868856a8 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -17,93 +17,25 @@ mpm::Node::Node( // Clear any velocity constraints velocity_constraints_.clear(); concentrated_force_.setZero(); - - // Initialize boolean properties - // Friction - boolean_properties_.emplace( - std::make_pair(mpm::properties::Boolean::Friction, false)); - // GenericBC - boolean_properties_.emplace( - std::make_pair(mpm::properties::Boolean::GenericBC, false)); - - // Initialize scalar properties - // Mass - scalar_properties_.emplace( - std::make_pair(mpm::properties::Scalar::Mass, - Eigen::Matrix::Zero())); - // Volume - scalar_properties_.emplace( - std::make_pair(mpm::properties::Scalar::Volume, - Eigen::Matrix::Zero())); - // MassPressure - scalar_properties_.emplace( - std::make_pair(mpm::properties::Scalar::MassPressure, - Eigen::Matrix::Zero())); - // Pressure - scalar_properties_.emplace( - std::make_pair(mpm::properties::Scalar::Pressure, - Eigen::Matrix::Zero())); - - // Initialize vector properties - // Velocity - vector_properties_.emplace( - std::make_pair(mpm::properties::Vector::Velocity, - Eigen::Matrix::Zero())); - // Acceleration - vector_properties_.emplace( - std::make_pair(mpm::properties::Vector::Acceleration, - Eigen::Matrix::Zero())); - // Momentum - vector_properties_.emplace( - std::make_pair(mpm::properties::Vector::Momentum, - Eigen::Matrix::Zero())); - // ExternalForce - vector_properties_.emplace( - std::make_pair(mpm::properties::Vector::ExternalForce, - Eigen::Matrix::Zero())); - // InternalForce - vector_properties_.emplace( - std::make_pair(mpm::properties::Vector::InternalForce, - Eigen::Matrix::Zero())); - - // Twophase properties - if (Tnphases > 1) { - // DragForce - vector_properties_.emplace( - std::make_pair(mpm::properties::Vector::DragForce, - Eigen::Matrix::Zero())); - } this->initialise(); } //! Initialise nodal properties template void mpm::Node::initialise() noexcept { + mass_.setZero(); + volume_.setZero(); + external_force_.setZero(); + internal_force_.setZero(); + pressure_.setZero(); + contact_displacement_.setZero(); + velocity_.setZero(); + momentum_.setZero(); + acceleration_.setZero(); status_ = false; - - // Initialise nodal scalar properties - scalar_properties_.at(mpm::properties::Scalar::Mass).setZero(); - scalar_properties_.at(mpm::properties::Scalar::Volume).setZero(); - scalar_properties_.at(mpm::properties::Scalar::MassPressure).setZero(); - scalar_properties_.at(mpm::properties::Scalar::Pressure).setZero(); - - // Initialise nodal vector properties - vector_properties_.at(mpm::properties::Vector::Velocity).setZero(); - vector_properties_.at(mpm::properties::Vector::Acceleration).setZero(); - vector_properties_.at(mpm::properties::Vector::Momentum).setZero(); - vector_properties_.at(mpm::properties::Vector::ExternalForce).setZero(); - vector_properties_.at(mpm::properties::Vector::InternalForce).setZero(); - - // Initialise nodal scalar and vector properties for two phase - if (Tnphases > 1) { - // Initialise nodal scalar properties for two phase - // Initialise nodal vector properties for two phase - vector_properties_.at(mpm::properties::Vector::DragForce).setZero(); - } - - // Initialise variables for contact material_ids_.clear(); - contact_displacement_.setZero(); + // Specific variables for two phase + drag_force_coefficient_.setZero(); } //! Initialise shared pointer to nodal properties pool @@ -116,94 +48,32 @@ void mpm::Node::initialise_property_handle( this->prop_id_ = prop_id; } -//! Assign boolean property at the nodes -template -void mpm::Node::assign_boolean_property( - mpm::properties::Boolean property, bool boolean) noexcept { - // Update/assign value - node_mutex_.lock(); - boolean_properties_.at(property) = boolean; - node_mutex_.unlock(); -} - -//! Return boolean property -template -bool mpm::Node::boolean_property( - mpm::properties::Boolean property) const { - return boolean_properties_.at(property); -} - -//! Update scalar property at the nodes from particle +//! Update mass at the nodes from particle template -void mpm::Node::update_scalar_property( - mpm::properties::Scalar property, bool update, unsigned phase, - double value) noexcept { - // Assert phase - assert(phase < Tnphases); - +void mpm::Node::update_mass(bool update, unsigned phase, + double mass) noexcept { // Decide to update or assign const double factor = (update == true) ? 1. : 0.; - // Update/assign value + // Update/assign mass node_mutex_.lock(); - scalar_properties_.at(property)[phase] = - (scalar_properties_.at(property)[phase] * factor) + value; + mass_(phase) = (mass_(phase) * factor) + mass; node_mutex_.unlock(); } -//! Update scalar property at the nodes from particle -template -double mpm::Node::scalar_property( - mpm::properties::Scalar property, unsigned phase) const { - // Assert phase - assert(phase < Tnphases); - return scalar_properties_.at(property)[phase]; -} - -//! Update vector property at the nodes from particle +//! Update volume at the nodes from particle template -void mpm::Node::update_vector_property( - mpm::properties::Vector property, bool update, unsigned phase, - const Eigen::Matrix& value) noexcept { - // Assert phase - assert(phase < Tnphases); - +void mpm::Node::update_volume(bool update, unsigned phase, + double volume) noexcept { // Decide to update or assign const double factor = (update == true) ? 1. : 0.; - // Update/assign value + // Update/assign volume node_mutex_.lock(); - Eigen::Matrix vecvalue = - vector_properties_.at(property).col(phase); - vector_properties_.at(property).col(phase) = (vecvalue * factor) + value; + volume_(phase) = volume_(phase) * factor + volume; node_mutex_.unlock(); } -//! Update vector property at the nodes from particle -template -Eigen::Matrix mpm::Node::vector_property( - mpm::properties::Vector property, unsigned phase) const { - // Assert phase - assert(phase < Tnphases); - return vector_properties_.at(property).col(phase); -} - -//! Update mass at the nodes from particle -template -void mpm::Node::update_mass(bool update, unsigned phase, - double mass) noexcept { - this->update_scalar_property(mpm::properties::Scalar::Mass, update, phase, - mass); -} - -//! Update volume at the nodes from particle -template -void mpm::Node::update_volume(bool update, unsigned phase, - double volume) noexcept { - this->update_scalar_property(mpm::properties::Scalar::Volume, update, phase, - volume); -} - // Assign concentrated force to the node template bool mpm::Node::assign_concentrated_force( @@ -242,8 +112,16 @@ template void mpm::Node::update_external_force( bool update, unsigned phase, const Eigen::Matrix& force) noexcept { - this->update_vector_property(mpm::properties::Vector::ExternalForce, update, - phase, force); + // Assert + assert(phase < Tnphases); + + // Decide to update or assign + const double factor = (update == true) ? 1. : 0.; + + // Update/assign external force + node_mutex_.lock(); + external_force_.col(phase) = external_force_.col(phase) * factor + force; + node_mutex_.unlock(); } //! Update internal force (body force / traction force) @@ -251,8 +129,31 @@ template void mpm::Node::update_internal_force( bool update, unsigned phase, const Eigen::Matrix& force) noexcept { - this->update_vector_property(mpm::properties::Vector::InternalForce, update, - phase, force); + // Assert + assert(phase < Tnphases); + + // Decide to update or assign + const double factor = (update == true) ? 1. : 0.; + + // Update/assign internal force + node_mutex_.lock(); + internal_force_.col(phase) = internal_force_.col(phase) * factor + force; + node_mutex_.unlock(); +} + +//! Update drag force coefficient +template +void mpm::Node::update_drag_force_coefficient( + bool update, const Eigen::Matrix& drag_force_coefficient) { + + // Decide to update or assign + const double factor = (update == true) ? 1. : 0.; + + // Update/assign drag force coefficient + node_mutex_.lock(); + drag_force_coefficient_ = + drag_force_coefficient_ * factor + drag_force_coefficient; + node_mutex_.unlock(); } //! Assign nodal momentum @@ -260,43 +161,61 @@ template void mpm::Node::update_momentum( bool update, unsigned phase, const Eigen::Matrix& momentum) noexcept { - this->update_vector_property(mpm::properties::Vector::Momentum, update, phase, - momentum); + // Assert + assert(phase < Tnphases); + + // Decide to update or assign + const double factor = (update == true) ? 1. : 0.; + + // Update/assign momentum + node_mutex_.lock(); + momentum_.col(phase) = momentum_.col(phase) * factor + momentum; + node_mutex_.unlock(); } //! Update pressure at the nodes from particle template void mpm::Node::update_mass_pressure( - bool update, unsigned phase, double mass_pressure) noexcept { - this->update_scalar_property(mpm::properties::Scalar::MassPressure, update, - phase, mass_pressure); -} + unsigned phase, double mass_pressure) noexcept { + // Assert + assert(phase < Tnphases); -//! Compute pressure from mass pressure -//! pressure = mass pressure / mass -template -void mpm::Node::compute_pressure() { const double tolerance = 1.E-16; - for (unsigned phase = 0; phase < Tnphases; ++phase) { - if (this->mass(phase) > tolerance) { - scalar_properties_.at(mpm::properties::Scalar::Pressure)(phase) = - scalar_properties_.at(mpm::properties::Scalar::MassPressure)(phase) / - this->mass(phase); - - // Check to see if value is below threshold - if (std::abs(this->pressure(phase)) < 1.E-15) - scalar_properties_.at(mpm::properties::Scalar::Pressure)(phase) = 0.; + // Compute pressure from mass*pressure + if (mass_(phase) > tolerance) { + node_mutex_.lock(); + pressure_(phase) += mass_pressure / mass_(phase); + node_mutex_.unlock(); + + if (pressure_constraints_.find(phase) != pressure_constraints_.end()) { + // const double scalar = + // (pressure_function_.find(phase) != pressure_function_.end()) + // ? pressure_function_[phase]->value(step * dt) + // : 1.0; + // this->pressure_(phase) = scalar * pressure_constraints_[phase]; + this->pressure_(phase) = pressure_constraints_[phase]; + // if (step > ref_step_ && pressure_constraints_.find(phase + Tnphases) != + // pressure_constraints_.end()) { + // const double scalar_increment = + // (pressure_function_.find(phase + Tnphases) != + // pressure_function_.end()) + // ? pressure_function_[phase + Tnphases]->value(step * dt) + // : 1.0; + // this->pressure_(phase) += + // scalar_increment * pressure_constraints_[phase + Tnphases]; + // } } } } //! Assign pressure at the nodes from particle template -void mpm::Node::update_pressure(bool update, - unsigned phase, +void mpm::Node::assign_pressure(unsigned phase, double pressure) { - this->update_scalar_property(mpm::properties::Scalar::Pressure, update, phase, - pressure); + // Compute pressure from mass*pressure + node_mutex_.lock(); + pressure_(phase) = pressure; + node_mutex_.unlock(); } //! Compute velocity from momentum @@ -305,15 +224,13 @@ template void mpm::Node::compute_velocity() { const double tolerance = 1.E-16; for (unsigned phase = 0; phase < Tnphases; ++phase) { - if (this->mass(phase) > tolerance) { - vector_properties_.at(mpm::properties::Vector::Velocity).col(phase) = - this->momentum(phase) / this->mass(phase); + if (mass_(phase) > tolerance) { + velocity_.col(phase) = momentum_.col(phase) / mass_(phase); // Check to see if value is below threshold - for (unsigned i = 0; i < Tdim; ++i) - if (std::abs(this->velocity(phase)(i)) < 1.E-15) - vector_properties_.at(mpm::properties::Vector::Velocity) - .col(phase)(i) = 0.; + for (unsigned i = 0; i < velocity_.rows(); ++i) + if (std::abs(velocity_.col(phase)(i)) < 1.E-15) + velocity_.col(phase)(i) = 0.; } } @@ -327,8 +244,15 @@ template void mpm::Node::update_acceleration( bool update, unsigned phase, const Eigen::Matrix& acceleration) noexcept { - this->update_vector_property(mpm::properties::Vector::Acceleration, update, - phase, acceleration); + assert(phase < Tnphases); + + // Decide to update or assign + const double factor = (update == true) ? 1. : 0.; + + //! Update/assign acceleration + node_mutex_.lock(); + acceleration_.col(phase) = acceleration_.col(phase) * factor + acceleration; + node_mutex_.unlock(); } //! Compute acceleration and velocity @@ -337,31 +261,28 @@ bool mpm::Node::compute_acceleration_velocity( unsigned phase, double dt) noexcept { bool status = false; const double tolerance = 1.0E-15; - if (this->mass(phase) > tolerance) { + if (mass_(phase) > tolerance) { // acceleration = (unbalaced force / mass) - vector_properties_.at(mpm::properties::Vector::Acceleration).col(phase) = - (this->external_force(phase) + this->internal_force(phase)) / - this->mass(phase); + this->acceleration_.col(phase) = + (this->external_force_.col(phase) + this->internal_force_.col(phase)) / + this->mass_(phase); // Apply friction constraints this->apply_friction_constraints(dt); // Velocity += acceleration * dt - vector_properties_.at(mpm::properties::Vector::Velocity).col(phase) += - this->acceleration(phase) * dt; + this->velocity_.col(phase) += this->acceleration_.col(phase) * 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(this->velocity(phase)(i)) < tolerance) - vector_properties_.at(mpm::properties::Vector::Velocity).col(phase)(i) = - 0.; + if (std::abs(velocity_.col(phase)(i)) < tolerance) + velocity_.col(phase)(i) = 0.; for (unsigned i = 0; i < Tdim; ++i) - if (std::abs(this->acceleration(phase)(i)) < tolerance) - vector_properties_.at(mpm::properties::Vector::Acceleration) - .col(phase)(i) = 0.; + if (std::abs(acceleration_.col(phase)(i)) < tolerance) + acceleration_.col(phase)(i) = 0.; status = true; } return status; @@ -373,39 +294,181 @@ bool mpm::Node::compute_acceleration_velocity_cundall( unsigned phase, double dt, double damping_factor) noexcept { bool status = false; const double tolerance = 1.0E-15; - if (this->mass(phase) > tolerance) { + if (mass_(phase) > tolerance) { // acceleration = (unbalaced force / mass) auto unbalanced_force = - this->external_force(phase) + this->internal_force(phase); - vector_properties_.at(mpm::properties::Vector::Acceleration).col(phase) = + this->external_force_.col(phase) + this->internal_force_.col(phase); + this->acceleration_.col(phase) = (unbalanced_force - damping_factor * unbalanced_force.norm() * - this->velocity(phase).cwiseSign()) / - this->mass(phase); + this->velocity_.col(phase).cwiseSign()) / + this->mass_(phase); // Apply friction constraints this->apply_friction_constraints(dt); // Velocity += acceleration * dt - vector_properties_.at(mpm::properties::Vector::Velocity).col(phase) += - this->acceleration(phase) * dt; + this->velocity_.col(phase) += this->acceleration_.col(phase) * 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(this->velocity(phase)(i)) < tolerance) - vector_properties_.at(mpm::properties::Vector::Velocity).col(phase)(i) = - 0.; + if (std::abs(velocity_.col(phase)(i)) < tolerance) + velocity_.col(phase)(i) = 0.; for (unsigned i = 0; i < Tdim; ++i) - if (std::abs(this->acceleration(phase)(i)) < tolerance) - vector_properties_.at(mpm::properties::Vector::Acceleration) - .col(phase)(i) = 0.; + if (std::abs(acceleration_.col(phase)(i)) < tolerance) + acceleration_.col(phase)(i) = 0.; + status = true; + } + return status; +} + +//! Compute acceleration and velocity for two phase +template +bool mpm::Node:: + compute_acceleration_velocity_twophase_explicit(double dt) noexcept { + bool status = false; + const double tolerance = 1.0E-15; + if (this->mass(mpm::NodePhase::nSolid) > tolerance && + this->mass(mpm::NodePhase::nLiquid) > tolerance) { + // Compute drag force + VectorDim drag_force = drag_force_coefficient_.cwiseProduct( + velocity_.col(mpm::NodePhase::nLiquid) - + velocity_.col(mpm::NodePhase::nSolid)); + + // Acceleration of pore fluid (momentume balance of fluid phase) + this->acceleration_.col(mpm::NodePhase::nLiquid) = + (this->external_force_.col(mpm::NodePhase::nLiquid) + + this->internal_force_.col(mpm::NodePhase::nLiquid) - drag_force) / + this->mass_(mpm::NodePhase::nLiquid); + + // Acceleration of solid skeleton (momentume balance of mixture) + this->acceleration_.col(mpm::NodePhase::nSolid) = + (this->external_force_.col(mpm::NodePhase::nMixture) + + this->internal_force_.col(mpm::NodePhase::nMixture) - + this->mass_(mpm::NodePhase::nLiquid) * + this->acceleration_.col(mpm::NodePhase::nLiquid)) / + this->mass_(mpm::NodePhase::nSolid); + + // Apply friction constraints + this->apply_friction_constraints(dt); + + // Velocity += acceleration * dt + this->velocity_ += this->acceleration_ * 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(mpm::NodePhase::nSolid)(i)) < tolerance) + velocity_.col(mpm::NodePhase::nSolid)(i) = 0.; + if (std::abs(acceleration_.col(mpm::NodePhase::nSolid)(i)) < tolerance) + acceleration_.col(mpm::NodePhase::nSolid)(i) = 0.; + if (std::abs(velocity_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) + velocity_.col(mpm::NodePhase::nLiquid)(i) = 0.; + if (std::abs(acceleration_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) + acceleration_.col(mpm::NodePhase::nLiquid)(i) = 0.; + } + status = true; + } + return status; +} + +//! Compute acceleration and velocity for two phase with damping +template +bool mpm::Node:: + compute_acceleration_velocity_twophase_explicit_cundall( + double dt, double damping_factor) noexcept { + bool status = false; + const double tolerance = 1.0E-15; + + if (this->mass(mpm::NodePhase::nSolid) > tolerance && + this->mass(mpm::NodePhase::nLiquid) > tolerance) { + // Compute drag force + VectorDim drag_force = drag_force_coefficient_.cwiseProduct( + velocity_.col(mpm::NodePhase::nLiquid) - + velocity_.col(mpm::NodePhase::nSolid)); + + // Unbalanced force of liquid phase + auto unbalanced_force_liquid = + this->external_force(mpm::NodePhase::nLiquid) + + this->internal_force(mpm::NodePhase::nLiquid) - drag_force; + // Acceleration of liquid phase (momentume balance of fluid phase) + this->acceleration_.col(mpm::NodePhase::nLiquid) = + (unbalanced_force_liquid - + damping_factor * unbalanced_force_liquid.norm() * + this->velocity_.col(mpm::NodePhase::nLiquid).cwiseSign()) / + this->mass(mpm::NodePhase::nLiquid); + + // Unbalanced force of solid phase + auto unbalanced_force_solid = + this->external_force(mpm::NodePhase::nMixture) + + this->internal_force(mpm::NodePhase::nMixture) - + this->mass(mpm::NodePhase::nLiquid) * + this->acceleration(mpm::NodePhase::nLiquid); + // Acceleration of solid phase (momentume balance of mixture) + this->acceleration_.col(mpm::NodePhase::nSolid) = + (unbalanced_force_solid - + damping_factor * unbalanced_force_solid.norm() * + this->velocity_.col(mpm::NodePhase::nSolid).cwiseSign()) / + this->mass(mpm::NodePhase::nSolid); + + // Apply friction constraints + this->apply_friction_constraints(dt); + + // Velocity += acceleration * dt + this->velocity_ += this->acceleration_ * 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(mpm::NodePhase::nSolid)(i)) < tolerance) + velocity_.col(mpm::NodePhase::nSolid)(i) = 0.; + if (std::abs(acceleration_.col(mpm::NodePhase::nSolid)(i)) < tolerance) + acceleration_.col(mpm::NodePhase::nSolid)(i) = 0.; + if (std::abs(velocity_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) + velocity_.col(mpm::NodePhase::nLiquid)(i) = 0.; + if (std::abs(acceleration_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) + acceleration_.col(mpm::NodePhase::nLiquid)(i) = 0.; + } status = true; } return status; } +//! Assign pressure constraint +template +bool mpm::Node::assign_pressure_constraint( + const unsigned phase, const double pressure, + const std::shared_ptr& function) { + bool status = true; + try { + // Constrain directions can take values between 0 and Tnphases + if (phase < Tnphases * 2) { + 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; +} + //! Assign velocity constraint //! Constrain directions can take values between 0 and Dim * Nphases template @@ -439,13 +502,11 @@ void mpm::Node::apply_velocity_constraints() { // Phase: Integer value of division (dir / Tdim) const auto phase = static_cast(dir / Tdim); - if (!this->boolean_property(mpm::properties::Boolean::GenericBC)) { + if (!generic_boundary_constraints_) { // Velocity constraints are applied on Cartesian boundaries - vector_properties_.at(mpm::properties::Vector::Velocity)( - direction, phase) = constraint.second; + this->velocity_(direction, phase) = constraint.second; // Set acceleration to 0 in direction of velocity constraint - vector_properties_.at(mpm::properties::Vector::Acceleration)(direction, - phase) = 0.; + this->acceleration_(direction, phase) = 0.; } else { // Velocity constraints on general boundaries // Compute inverse rotation matrix @@ -453,19 +514,15 @@ void mpm::Node::apply_velocity_constraints() { rotation_matrix_.inverse(); // Transform to local coordinate Eigen::Matrix local_velocity = - inverse_rotation_matrix * - vector_properties_.at(mpm::properties::Vector::Velocity); + inverse_rotation_matrix * this->velocity_; Eigen::Matrix local_acceleration = - inverse_rotation_matrix * - vector_properties_.at(mpm::properties::Vector::Acceleration); + inverse_rotation_matrix * this->acceleration_; // Apply boundary condition in local coordinate local_velocity(direction, phase) = constraint.second; local_acceleration(direction, phase) = 0.; // Transform back to global coordinate - vector_properties_.at(mpm::properties::Vector::Velocity) = - rotation_matrix_ * local_velocity; - vector_properties_.at(mpm::properties::Vector::Acceleration) = - rotation_matrix_ * local_acceleration; + this->velocity_ = rotation_matrix_ * local_velocity; + this->acceleration_ = rotation_matrix_ * local_acceleration; } } } @@ -482,7 +539,7 @@ bool mpm::Node::assign_friction_constraint( this->friction_constraint_ = std::make_tuple(static_cast(dir), static_cast(sign_n), static_cast(friction)); - this->assign_boolean_property(mpm::properties::Boolean::Friction, true); + this->friction_ = true; } else throw std::runtime_error("Constraint direction is out of bounds"); @@ -496,7 +553,7 @@ bool mpm::Node::assign_friction_constraint( //! Apply friction constraints template void mpm::Node::apply_friction_constraints(double dt) { - if (this->boolean_property(mpm::properties::Boolean::Friction)) { + if (friction_) { auto sign = [](double value) { return (value > 0.) ? 1. : -1.; }; // Set friction constraint @@ -518,16 +575,13 @@ void mpm::Node::apply_friction_constraints(double dt) { // tangential direction to boundary const unsigned dir_t = (Tdim - 1) - dir_n; - if (!this->boolean_property(mpm::properties::Boolean::GenericBC)) { + if (!generic_boundary_constraints_) { // Cartesian case // Normal and tangential acceleration - acc_n = vector_properties_.at(mpm::properties::Vector::Acceleration)( - dir_n, phase); - acc_t = vector_properties_.at(mpm::properties::Vector::Acceleration)( - dir_t, phase); + acc_n = this->acceleration_(dir_n, phase); + acc_t = this->acceleration_(dir_t, phase); // Velocity tangential - vel_t = vector_properties_.at(mpm::properties::Vector::Velocity)(dir_t, - phase); + vel_t = this->velocity_(dir_t, phase); } else { // General case, transform to local coordinate // Compute inverse rotation matrix @@ -535,11 +589,9 @@ void mpm::Node::apply_friction_constraints(double dt) { rotation_matrix_.inverse(); // Transform to local coordinate Eigen::Matrix local_acceleration = - inverse_rotation_matrix * - vector_properties_.at(mpm::properties::Vector::Acceleration); + inverse_rotation_matrix * this->acceleration_; Eigen::Matrix local_velocity = - inverse_rotation_matrix * - vector_properties_.at(mpm::properties::Vector::Velocity); + inverse_rotation_matrix * this->velocity_; // Normal and tangential acceleration acc_n = local_acceleration(dir_n, phase); acc_t = local_acceleration(dir_t, phase); @@ -562,10 +614,9 @@ void mpm::Node::apply_friction_constraints(double dt) { acc_t -= sign(acc_t) * mu * std::abs(acc_n); } - if (!this->boolean_property(mpm::properties::Boolean::GenericBC)) { + if (!generic_boundary_constraints_) { // Cartesian case - vector_properties_.at(mpm::properties::Vector::Acceleration)( - dir_t, phase) = acc_t; + this->acceleration_(dir_t, phase) = acc_t; } else { // Local acceleration in terms of tangential and normal Eigen::Matrix acc; @@ -573,8 +624,7 @@ void mpm::Node::apply_friction_constraints(double dt) { acc(dir_n, phase) = acc_n; // General case, transform to global coordinate - vector_properties_.at(mpm::properties::Vector::Acceleration) - .col(phase) = rotation_matrix_ * acc.col(phase); + this->acceleration_.col(phase) = rotation_matrix_ * acc.col(phase); } } } else if (Tdim == 3) { @@ -590,18 +640,18 @@ void mpm::Node::apply_friction_constraints(double dt) { const unsigned dir_t1 = dir(dir_n, 1); Eigen::Matrix acc, vel; - if (!this->boolean_property(mpm::properties::Boolean::GenericBC)) { + if (!generic_boundary_constraints_) { // Cartesian case - acc = this->acceleration(phase); - vel = this->velocity(phase); + acc = this->acceleration_.col(phase); + vel = this->velocity_.col(phase); } else { // General case, transform to local coordinate // Compute inverse rotation matrix const Eigen::Matrix inverse_rotation_matrix = rotation_matrix_.inverse(); // Transform to local coordinate - acc = inverse_rotation_matrix * this->acceleration(phase); - vel = inverse_rotation_matrix * this->velocity(phase); + acc = inverse_rotation_matrix * this->acceleration_.col(phase); + vel = inverse_rotation_matrix * this->velocity_.col(phase); } const auto acc_n = acc(dir_n); @@ -639,14 +689,12 @@ void mpm::Node::apply_friction_constraints(double dt) { } } - if (!this->boolean_property(mpm::properties::Boolean::GenericBC)) { + if (!generic_boundary_constraints_) { // Cartesian case - vector_properties_.at(mpm::properties::Vector::Acceleration) - .col(phase) = acc; + this->acceleration_.col(phase) = acc; } else { // General case, transform to global coordinate - vector_properties_.at(mpm::properties::Vector::Acceleration) - .col(phase) = rotation_matrix_ * acc; + this->acceleration_.col(phase) = rotation_matrix_ * acc; } } } @@ -696,10 +744,7 @@ void mpm::Node momentum = property_handle_->property("momenta", prop_id_, *mitr, Tdim); const Eigen::Matrix change_in_momenta = - vector_properties_.at(mpm::properties::Vector::Velocity) - .col(mpm::NodePhase::nSolid) * - mass - - momentum; + velocity_.col(mpm::NodePhase::nSolid) * mass - momentum; property_handle_->update_property("change_in_momenta", prop_id_, *mitr, change_in_momenta, Tdim); } @@ -721,9 +766,7 @@ void mpm::Nodeproperty("masses", prop_id_, *mitr); // displacement of the center of mass - contact_displacement_ += - material_displacement / - scalar_properties_.at(mpm::properties::Scalar::Mass)(0, 0); + contact_displacement_ += material_displacement / mass_(0, 0); // assign nodal-multimaterial displacement by dividing it by this material's // mass property_handle_->assign_property( @@ -741,151 +784,14 @@ void mpm::Nodeupdate_property("separation_vectors", prop_id_, *mitr, separation_vector, Tdim); } node_mutex_.unlock(); } -//! Compute acceleration and velocity for two phase -template -bool mpm::Node:: - compute_acceleration_velocity_twophase_explicit(double dt) noexcept { - bool status = false; - const double tolerance = 1.0E-15; - if (this->mass(mpm::NodePhase::nSolid) > tolerance && - this->mass(mpm::NodePhase::nLiquid) > tolerance) { - // Compute drag force - VectorDim drag_force = - (vector_properties_.at(mpm::properties::Vector::DragForce)) - .col(mpm::NodePhase::nSolid) - .cwiseProduct(this->velocity(mpm::NodePhase::nLiquid) - - this->velocity(mpm::NodePhase::nSolid)); - - // Acceleration of pore fluid (momentume balance of fluid phase) - vector_properties_.at(mpm::properties::Vector::Acceleration) - .col(mpm::NodePhase::nLiquid) = - (this->external_force(mpm::NodePhase::nLiquid) + - this->internal_force(mpm::NodePhase::nLiquid) - drag_force) / - this->mass(mpm::NodePhase::nLiquid); - - // Acceleration of solid skeleton (momentume balance of mixture) - vector_properties_.at(mpm::properties::Vector::Acceleration) - .col(mpm::NodePhase::nSolid) = - (this->external_force(mpm::NodePhase::nMixture) + - this->internal_force(mpm::NodePhase::nMixture) - - this->mass(mpm::NodePhase::nLiquid) * - this->acceleration(mpm::NodePhase::nLiquid)) / - this->mass(mpm::NodePhase::nSolid); - - // Apply friction constraints - this->apply_friction_constraints(dt); - - // Velocity += acceleration * dt - vector_properties_.at(mpm::properties::Vector::Velocity) += - vector_properties_.at(mpm::properties::Vector::Acceleration) * 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(this->velocity(mpm::NodePhase::nSolid)(i)) < tolerance) - this->velocity(mpm::NodePhase::nSolid)(i) = 0.; - if (std::abs(this->acceleration(mpm::NodePhase::nSolid)(i)) < tolerance) - this->acceleration(mpm::NodePhase::nSolid)(i) = 0.; - if (std::abs(this->velocity(mpm::NodePhase::nLiquid)(i)) < tolerance) - this->velocity(mpm::NodePhase::nLiquid)(i) = 0.; - if (std::abs(this->acceleration(mpm::NodePhase::nLiquid)(i)) < tolerance) - this->acceleration(mpm::NodePhase::nLiquid)(i) = 0.; - } - } - return status; -} - -//! Compute acceleration and velocity for two phase with damping -template -bool mpm::Node:: - compute_acceleration_velocity_twophase_explicit_cundall( - double dt, double damping_factor) noexcept { - bool status = false; - const double tolerance = 1.0E-15; - - if (this->mass(mpm::NodePhase::nSolid) > tolerance && - this->mass(mpm::NodePhase::nLiquid) > tolerance) { - // Compute drag force - VectorDim drag_force = - (vector_properties_.at(mpm::properties::Vector::DragForce)) - .col(mpm::NodePhase::nSolid) - .cwiseProduct(this->velocity(mpm::NodePhase::nLiquid) - - this->velocity(mpm::NodePhase::nSolid)); - - // Unbalanced force of liquid phase - auto unbalanced_force_liquid = - this->external_force(mpm::NodePhase::nLiquid) + - this->internal_force(mpm::NodePhase::nLiquid) - drag_force; - // Acceleration of liquid phase (momentume balance of fluid phase) - vector_properties_.at(mpm::properties::Vector::Acceleration) - .col(mpm::NodePhase::nLiquid) = - (unbalanced_force_liquid - - damping_factor * unbalanced_force_liquid.norm() * - vector_properties_.at(mpm::properties::Vector::Velocity) - .col(mpm::NodePhase::nLiquid) - .cwiseSign()) / - this->mass(mpm::NodePhase::nLiquid); - - // Unbalanced force of solid phase - auto unbalanced_force_solid = - this->external_force(mpm::NodePhase::nMixture) + - this->internal_force(mpm::NodePhase::nMixture) - - this->mass(mpm::NodePhase::nLiquid) * - this->acceleration(mpm::NodePhase::nLiquid); - // Acceleration of solid phase (momentume balance of mixture) - vector_properties_.at(mpm::properties::Vector::Acceleration) - .col(mpm::NodePhase::nSolid) = - (unbalanced_force_solid - - damping_factor * unbalanced_force_solid.norm() * - vector_properties_.at(mpm::properties::Vector::Velocity) - .col(mpm::NodePhase::nSolid) - .cwiseSign()) / - this->mass(mpm::NodePhase::nSolid); - - // Apply friction constraints - this->apply_friction_constraints(dt); - - // Velocity += acceleration * dt - vector_properties_.at(mpm::properties::Vector::Velocity) += - vector_properties_.at(mpm::properties::Vector::Acceleration) * 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(this->velocity(mpm::NodePhase::nSolid)(i)) < tolerance) - vector_properties_.at(mpm::properties::Vector::Velocity) - .col(mpm::NodePhase::nSolid)(i) = 0.; - if (std::abs(this->acceleration(mpm::NodePhase::nSolid)(i)) < tolerance) - vector_properties_.at(mpm::properties::Vector::Acceleration) - .col(mpm::NodePhase::nSolid)(i) = 0.; - if (std::abs(this->velocity(mpm::NodePhase::nLiquid)(i)) < tolerance) - vector_properties_.at(mpm::properties::Vector::Velocity) - .col(mpm::NodePhase::nLiquid)(i) = 0.; - if (std::abs(this->acceleration(mpm::NodePhase::nLiquid)(i)) < tolerance) - vector_properties_.at(mpm::properties::Vector::Acceleration) - .col(mpm::NodePhase::nLiquid)(i) = 0.; - } - status = true; - } - return status; -} - //! Compute multimaterial normal unit vector template void mpm::Node #include -#include #include "data_types.h" #include "function_base.h" -#include "mpm_properties.h" #include "nodal_properties.h" namespace mpm { -//! Nodal phases +//! Particle phases enum NodePhase : unsigned int { - nMixture = 0, nSolid = 0, nLiquid = 1, - nGas = 2 + nGas = 2, + nMixture = 0 }; //! NodeBase base class for nodes @@ -80,49 +78,6 @@ class NodeBase { //! Return status virtual bool status() const = 0; - //! Assign boolean property at the nodes - //! \param[in] property Name of the property to assign - //! \param[in] boolean Property boolean (true/false) of the node - virtual void assign_boolean_property(mpm::properties::Boolean property, - bool boolean) noexcept = 0; - - //! Return boolean property - //! \param[in] property Name of the property to update - //! \retval boolean property at node - virtual bool boolean_property(mpm::properties::Boolean property) const = 0; - - //! Update scalar property at the nodes - //! \param[in] property Name of the property to update - //! \param[in] update A boolean to update (true) or assign (false) - //! \param[in] phase Index corresponding to the phase - //! \param[in] value Property value from the particles in a cell - virtual void update_scalar_property(mpm::properties::Scalar property, - bool update, unsigned phase, - double value) noexcept = 0; - - //! Return property at a given node for a given phase - //! \param[in] property Name of the property to return - //! \param[in] phase Index corresponding to the phase - //! \retval scalar property at the designated phase - virtual double scalar_property(mpm::properties::Scalar property, - unsigned phase) const = 0; - - //! Update vector property at the nodes - //! \param[in] property Name of the property to update - //! \param[in] update A boolean to update (true) or assign (false) - //! \param[in] phase Index corresponding to the phase - //! \param[in] value Property value from the particles in a cell - virtual void update_vector_property( - mpm::properties::Vector property, bool update, unsigned phase, - const Eigen::Matrix& value) noexcept = 0; - - //! Return property at a given node for a given phase - //! \param[in] property Name of the property to return - //! \param[in] phase Index corresponding to the phase - //! \retval vector property at the designated phase - virtual Eigen::Matrix vector_property( - mpm::properties::Vector property, unsigned phase) const = 0; - //! Update mass at the nodes from particle //! \param[in] update A boolean to update (true) or assign (false) //! \param[in] phase Index corresponding to the phase @@ -180,25 +135,27 @@ class NodeBase { //! \param[in] phase Index corresponding to the phase virtual VectorDim internal_force(unsigned phase) const = 0; - //! Return drag force coefficient + //! Update internal force (body force / traction force) + //! \param[in] update A boolean to update (true) or assign (false) + //! \param[in] drag_force Drag force from the particles in a cell + //! \retval status Update status + virtual void update_drag_force_coefficient(bool update, + const VectorDim& drag_force) = 0; + + //! Return drag force at a given node virtual VectorDim drag_force_coefficient() const = 0; //! Update pressure at the nodes from particle - //! \param[in] update A boolean to update (true) or assign (false) //! \param[in] phase Index corresponding to the phase //! \param[in] mass_pressure Product of mass x pressure of a particle - virtual void update_mass_pressure(bool update, unsigned phase, + virtual void update_mass_pressure(unsigned phase, double mass_pressure) noexcept = 0; - //! Compute pressure from the mass pressure - virtual void compute_pressure() = 0; - //! Assign pressure at the nodes from particle //! \param[in] update A boolean to update (true) or assign (false) //! \param[in] phase Index corresponding to the phase - //! \param[in] pressure Pressure of a particle - virtual void update_pressure(bool update, unsigned phase, - double pressure) = 0; + //! \param[in] mass_pressure Product of mass x pressure of a particle + virtual void assign_pressure(unsigned phase, double mass_pressure) = 0; //! Return pressure at a given node for a given phase //! \param[in] phase Index corresponding to the phase @@ -245,6 +202,24 @@ class NodeBase { virtual bool compute_acceleration_velocity_cundall( unsigned phase, double dt, double damping_factor) noexcept = 0; + //! Compute acceleration and velocity for two phase + //! \param[in] dt Timestep in analysis + virtual bool compute_acceleration_velocity_twophase_explicit( + double dt) noexcept = 0; + + //! Compute acceleration and velocity for two phase with cundall damping + //! \param[in] dt Timestep in analysis + virtual bool compute_acceleration_velocity_twophase_explicit_cundall( + double dt, double damping_factor) noexcept = 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; + //! Assign velocity constraint //! Directions can take values between 0 and Dim * Nphases //! \param[in] dir Direction of velocity constraint @@ -311,16 +286,6 @@ class NodeBase { //! Compute multimaterial separation vector virtual void compute_multimaterial_separation_vector() = 0; - //! Compute acceleration and velocity for two phase - //! \param[in] dt Timestep in analysis - virtual bool compute_acceleration_velocity_twophase_explicit( - double dt) noexcept = 0; - - //! Compute acceleration and velocity for two phase with cundall damping - //! \param[in] dt Timestep in analysis - virtual bool compute_acceleration_velocity_twophase_explicit_cundall( - double dt, double damping_factor) noexcept = 0; - //! Compute multimaterial normal unit vector virtual void compute_multimaterial_normal_unit_vector() = 0; diff --git a/include/particles/particle.h b/include/particles/particle.h index 67d0afc3b..2b0025729 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -55,7 +55,7 @@ class Particle : public ParticleBase { //! \param[in] particle HDF5 data of particle //! \param[in] material Material associated with the particle //! \retval status Status of reading HDF5 particle - bool initialise_particle( + virtual bool initialise_particle( const HDF5Particle& particle, const std::shared_ptr>& material) override; @@ -105,9 +105,6 @@ class Particle : public ParticleBase { //! Return cell id Index cell_id() const override { return cell_id_; } - //! Return cell ptr - std::shared_ptr> cell() const override { return cell_; } - //! Return cell ptr status bool cell_ptr() const override { return cell_ != nullptr; } @@ -122,17 +119,26 @@ class Particle : public ParticleBase { bool assign_volume(double volume) override; //! Return volume - double volume() const override { - return this->scalar_property(mpm::properties::Scalar::Volume); - } + double volume() const override { return volume_; } //! Return size of particle in natural coordinates VectorDim natural_size() const override { return natural_size_; } + //! Compute volume as cell volume / nparticles + void compute_volume() noexcept override; + + //! Update volume based on centre volumetric strain rate + void update_volume() noexcept override; + //! Return mass density - double mass_density() const override { - return this->scalar_property(mpm::properties::Scalar::MassDensity); - } + //! \param[in] phase Index corresponding to the phase + double mass_density() const override { return mass_density_; } + + //! Compute mass as volume * density + void compute_mass() noexcept override; + + //! Map particle mass and momentum to nodes + void map_mass_momentum_to_nodes() noexcept override; //! Map multimaterial properties to nodes void map_multimaterial_mass_momentum_to_nodes() noexcept override; @@ -145,14 +151,11 @@ class Particle : public ParticleBase { //! Assign nodal mass to particles //! \param[in] mass Mass from the particles in a cell - void assign_mass(double mass) override { - scalar_properties_.at(mpm::properties::Scalar::Mass) = mass; - } + //! \retval status Assignment status + void assign_mass(double mass) override { mass_ = mass; } //! Return mass of the particles - double mass() const override { - return this->scalar_property(mpm::properties::Scalar::Mass); - } + double mass() const override { return mass_; } //! Assign material //! \param[in] material Pointer to a material @@ -194,24 +197,23 @@ class Particle : public ParticleBase { //! Return stress of the particle Eigen::Matrix stress() const override { return stress_; } + //! Map body force + //! \param[in] pgravity Gravity of a particle + void map_body_force(const VectorDim& pgravity) noexcept override; + //! Map internal force inline void map_internal_force() noexcept override; //! Assign velocity to the particle //! \param[in] velocity A vector of particle velocity - void assign_velocity(const VectorDim& velocity) override { - vector_properties_.at(mpm::properties::Vector::Velocity) = velocity; - }; + //! \retval status Assignment status + bool assign_velocity(const VectorDim& velocity) override; //! Return velocity of the particle - VectorDim velocity() const override { - return this->vector_property(mpm::properties::Vector::Velocity); - } + VectorDim velocity() const override { return velocity_; } //! Return displacement of the particle - VectorDim displacement() const override { - return this->vector_property(mpm::properties::Vector::Displacement); - } + VectorDim displacement() const override { return displacement_; } //! Assign traction to the particle //! \param[in] direction Index corresponding to the direction of traction @@ -223,23 +225,15 @@ class Particle : public ParticleBase { //! \param[in] phase Index corresponding to the phase VectorDim traction() const override { return traction_; } + //! Map traction force + void map_traction_force() noexcept override; + //! Compute updated position of the particle //! \param[in] dt Analysis time step //! \param[in] velocity_update Update particle velocity from nodal vel void compute_updated_position(double dt, bool velocity_update = false) noexcept 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 @@ -252,13 +246,14 @@ class Particle : public ParticleBase { : std::numeric_limits::quiet_NaN(); } - //! 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); - } + //! Map particle pressure to nodes + bool map_pressure_to_nodes( + unsigned phase = mpm::ParticlePhase::Solid) noexcept override; + + //! Compute pressure smoothing of the particle based on nodal pressure + //! $$\hat{p}_p = \sum_{i = 1}^{n_n} N_i(x_p) p_i$$ + bool compute_pressure_smoothing( + unsigned phase = mpm::ParticlePhase::Solid) noexcept override; //! Return pressure of the particles //! \param[in] phase Index to indicate phase @@ -333,14 +328,12 @@ class Particle : public ParticleBase { using ParticleBase::state_variables_; //! Neighbour particles using ParticleBase::neighbours_; - //! Scalar properties - using ParticleBase::boolean_properties_; - //! Scalar properties - using ParticleBase::scalar_properties_; - //! Vector properties - using ParticleBase::vector_properties_; - //! Shape functions - using ParticleBase::shapefn_; + //! Volumetric mass density (mass / volume) + double mass_density_{0.}; + //! Mass + double mass_{0.}; + //! Volume + double volume_{0.}; //! Size of particle Eigen::Matrix size_; //! Size of particle in natural coordinates @@ -357,10 +350,18 @@ class Particle : public ParticleBase { Eigen::Matrix strain_rate_; //! dstrains Eigen::Matrix dstrain_; + //! Velocity + Eigen::Matrix velocity_; + //! Displacement + Eigen::Matrix displacement_; //! Particle velocity constraints std::map particle_velocity_constraints_; + //! Set traction + bool set_traction_{false}; //! Surface Traction (given as a stress; force/area) Eigen::Matrix traction_; + //! Shape functions + Eigen::VectorXd shapefn_; //! dN/dX Eigen::MatrixXd dn_dx_; //! dN/dX at cell centroid @@ -374,6 +375,5 @@ class Particle : public ParticleBase { } // namespace mpm #include "particle.tcc" -#include "particle_functions.tcc" #endif // MPM_PARTICLE_H__ diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index 5ad4c3da7..c3d945b69 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -37,12 +37,11 @@ bool mpm::Particle::initialise_particle(const HDF5Particle& particle) { // Assign id this->id_ = particle.id; // Mass - scalar_properties_.at(mpm::properties::Scalar::Mass) = particle.mass; + this->mass_ = particle.mass; // Volume - scalar_properties_.at(mpm::properties::Scalar::Volume) = particle.volume; + this->volume_ = particle.volume; // Mass Density - scalar_properties_.at(mpm::properties::Scalar::MassDensity) = - particle.mass / particle.volume; + this->mass_density_ = particle.mass / particle.volume; // Set local size of particle Eigen::Vector3d psize; psize << particle.nsize_x, particle.nsize_y, particle.nsize_z; @@ -60,16 +59,13 @@ bool mpm::Particle::initialise_particle(const HDF5Particle& particle) { displacement << particle.displacement_x, particle.displacement_y, particle.displacement_z; // Initialise displacement - for (unsigned i = 0; i < Tdim; ++i) - vector_properties_.at(mpm::properties::Vector::Displacement)(i) = - displacement(i); + for (unsigned i = 0; i < Tdim; ++i) this->displacement_(i) = displacement(i); // Velocity Eigen::Vector3d velocity; velocity << particle.velocity_x, particle.velocity_y, particle.velocity_z; // Initialise velocity - for (unsigned i = 0; i < Tdim; ++i) - vector_properties_.at(mpm::properties::Vector::Velocity)(i) = velocity(i); + for (unsigned i = 0; i < Tdim; ++i) this->velocity_(i) = velocity(i); // Stress this->stress_[0] = particle.stress_xx; @@ -149,11 +145,11 @@ mpm::HDF5Particle mpm::Particle::hdf5() const { Eigen::Vector3d displacement; displacement.setZero(); - for (unsigned j = 0; j < Tdim; ++j) displacement[j] = this->displacement()[j]; + for (unsigned j = 0; j < Tdim; ++j) displacement[j] = this->displacement_[j]; Eigen::Vector3d velocity; velocity.setZero(); - for (unsigned j = 0; j < Tdim; ++j) velocity[j] = this->velocity()[j]; + for (unsigned j = 0; j < Tdim; ++j) velocity[j] = this->velocity_[j]; // Particle local size Eigen::Vector3d nsize; @@ -233,33 +229,20 @@ mpm::HDF5Particle mpm::Particle::hdf5() const { // Initialise particle properties template void mpm::Particle::initialise() { + displacement_.setZero(); dstrain_.setZero(); + mass_ = 0.; natural_size_.setZero(); + set_traction_ = false; size_.setZero(); strain_rate_.setZero(); strain_.setZero(); stress_.setZero(); traction_.setZero(); + velocity_.setZero(); + volume_ = std::numeric_limits::max(); volumetric_strain_centroid_ = 0.; - // Initialize boolean properties - boolean_properties_.emplace( - std::make_pair(mpm::properties::Boolean::SetTraction, false)); - - // Initialize scalar properties - scalar_properties_.emplace( - std::make_pair(mpm::properties::Scalar::Mass, double(0.))); - scalar_properties_.emplace( - std::make_pair(mpm::properties::Scalar::MassDensity, double(0.))); - scalar_properties_.emplace(std::make_pair( - mpm::properties::Scalar::Volume, std::numeric_limits::max())); - - // Initialize vector properties - vector_properties_.emplace( - std::make_pair(mpm::properties::Vector::Displacement, VectorDim::Zero())); - vector_properties_.emplace( - std::make_pair(mpm::properties::Vector::Velocity, VectorDim::Zero())); - // Initialize vector data properties this->properties_["stresses"] = [&]() { return stress(); }; this->properties_["strains"] = [&]() { return strain(); }; @@ -279,16 +262,16 @@ void mpm::Particle::initialise_material(unsigned phase_size) { std::fill(state_variables_.begin(), state_variables_.end(), mpm::dense_map()); } -//! Assign material state variables from neighbour particle +//! Assign material history variables template bool mpm::Particle::assign_material_state_vars( const mpm::dense_map& state_vars, const std::shared_ptr>& material, unsigned phase) { bool status = false; - if (material != nullptr && this->material() != nullptr && - this->material_id() == material->id()) { + if (material != nullptr && this->material(phase) != nullptr && + this->material_id(phase) == material->id()) { // Clone state variables - auto mat_state_vars = (this->material())->initialise_state_variables(); + auto mat_state_vars = (this->material(phase))->initialise_state_variables(); if (state_variables_[phase].size() == state_vars.size() && mat_state_vars.size() == state_vars.size()) { this->state_variables_[phase] = state_vars; @@ -469,10 +452,10 @@ bool mpm::Particle::assign_volume(double volume) { if (volume <= 0.) throw std::runtime_error("Particle volume cannot be negative"); - scalar_properties_.at(mpm::properties::Scalar::Volume) = volume; + this->volume_ = volume; // Compute size of particle in each direction const double length = - std::pow(this->volume(), static_cast(1. / Tdim)); + std::pow(this->volume_, static_cast(1. / Tdim)); // Set particle size as length on each side this->size_.fill(length); @@ -493,57 +476,99 @@ bool mpm::Particle::assign_volume(double volume) { return status; } +// Compute volume of the particle +template +void mpm::Particle::compute_volume() noexcept { + // Check if particle has a valid cell ptr + assert(cell_ != nullptr); + // Volume of the cell / # of particles + this->assign_volume(cell_->volume() / cell_->nparticles()); +} + +// Update volume based on the central strain rate +template +void mpm::Particle::update_volume() noexcept { + // Check if particle has a valid cell ptr and a valid volume + assert(cell_ != nullptr && volume_ != std::numeric_limits::max()); + // Compute at centroid + // Strain rate for reduced integration + this->volume_ *= (1. + dvolumetric_strain_); + this->mass_density_ = this->mass_density_ / (1. + dvolumetric_strain_); +} + +// Compute mass of particle +template +void mpm::Particle::compute_mass() noexcept { + // Check if particle volume is set and material ptr is valid + assert(volume_ != std::numeric_limits::max() && + this->material() != nullptr); + // Mass = volume of particle * mass_density + this->mass_density_ = + (this->material())->template property(std::string("density")); + this->mass_ = volume_ * mass_density_; +} + +//! Map particle mass and momentum to nodes +template +void mpm::Particle::map_mass_momentum_to_nodes() noexcept { + // Check if particle mass is set + assert(mass_ != std::numeric_limits::max()); + + // Map mass and momentum to nodes + for (unsigned i = 0; i < nodes_.size(); ++i) { + nodes_[i]->update_mass(true, mpm::ParticlePhase::Solid, + mass_ * shapefn_[i]); + nodes_[i]->update_momentum(true, mpm::ParticlePhase::Solid, + mass_ * shapefn_[i] * velocity_); + } +} + //! Map multimaterial properties to nodes -// TODO: Contact function to be refactored template void mpm::Particle::map_multimaterial_mass_momentum_to_nodes() noexcept { // Check if particle mass is set - assert(this->mass() != std::numeric_limits::max()); + assert(mass_ != std::numeric_limits::max()); // Unit 1x1 Eigen matrix to be used with scalar quantities Eigen::Matrix nodal_mass; // Map mass and momentum to nodal property taking into account the material id for (unsigned i = 0; i < nodes_.size(); ++i) { - nodal_mass(0, 0) = this->mass() * shapefn_[i]; + nodal_mass(0, 0) = mass_ * shapefn_[i]; nodes_[i]->update_property(true, "masses", nodal_mass, this->material_id(), 1); - nodes_[i]->update_property(true, "momenta", this->velocity() * nodal_mass, + nodes_[i]->update_property(true, "momenta", velocity_ * nodal_mass, this->material_id(), Tdim); } } //! Map multimaterial displacements to nodes -// TODO: Contact function to be refactored template void mpm::Particle::map_multimaterial_displacements_to_nodes() noexcept { // Check if particle mass is set - assert(this->mass() != std::numeric_limits::max()); + assert(mass_ != std::numeric_limits::max()); // Map displacements to nodal property and divide it by the respective // nodal-material mass for (unsigned i = 0; i < nodes_.size(); ++i) { - const auto& displacement = - this->mass() * shapefn_[i] * this->displacement(); + const auto& displacement = mass_ * shapefn_[i] * displacement_; nodes_[i]->update_property(true, "displacements", displacement, this->material_id(), Tdim); } } //! Map multimaterial domain gradients to nodes -// TODO: Contact function to be refactored template void mpm::Particle< Tdim>::map_multimaterial_domain_gradients_to_nodes() noexcept { // Check if particle volume is set - assert(this->volume() != std::numeric_limits::max()); + assert(volume_ != std::numeric_limits::max()); // Map domain gradients to nodal property. The domain gradients is defined as // the gradient of the particle volume for (unsigned i = 0; i < nodes_.size(); ++i) { Eigen::Matrix gradient; - for (unsigned j = 0; j < Tdim; ++j) - gradient[j] = this->volume() * dn_dx_(i, j); + for (unsigned j = 0; j < Tdim; ++j) gradient[j] = volume_ * dn_dx_(i, j); nodes_[i]->update_property(true, "domain_gradients", gradient, this->material_id(), Tdim); } @@ -639,6 +664,15 @@ void mpm::Particle::compute_stress() noexcept { &state_variables_[mpm::ParticlePhase::Solid]); } +//! Map body force +template +void mpm::Particle::map_body_force(const VectorDim& pgravity) noexcept { + // Compute nodal body forces + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->update_external_force(true, mpm::ParticlePhase::Solid, + (pgravity * mass_ * shapefn_(i))); +} + //! Map internal force template <> inline void mpm::Particle<1>::map_internal_force() noexcept { @@ -646,7 +680,7 @@ inline void mpm::Particle<1>::map_internal_force() noexcept { for (unsigned i = 0; i < nodes_.size(); ++i) { // Compute force: -pstress * volume Eigen::Matrix force; - force[0] = -1. * dn_dx_(i, 0) * this->volume() * stress_[0]; + force[0] = -1. * dn_dx_(i, 0) * volume_ * stress_[0]; nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Solid, force); } @@ -662,7 +696,7 @@ inline void mpm::Particle<2>::map_internal_force() noexcept { force[0] = dn_dx_(i, 0) * stress_[0] + dn_dx_(i, 1) * stress_[3]; force[1] = dn_dx_(i, 1) * stress_[1] + dn_dx_(i, 0) * stress_[3]; - force *= -1. * this->volume(); + force *= -1. * this->volume_; nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Solid, force); } @@ -684,26 +718,35 @@ inline void mpm::Particle<3>::map_internal_force() noexcept { force[2] = dn_dx_(i, 2) * stress_[2] + dn_dx_(i, 1) * stress_[4] + dn_dx_(i, 0) * stress_[5]; - force *= -1. * this->volume(); + force *= -1. * this->volume_; nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Solid, force); } } +// Assign velocity to the particle +template +bool mpm::Particle::assign_velocity( + const Eigen::Matrix& velocity) { + // Assign velocity + velocity_ = velocity; + return true; +} + // Assign traction to the particle template bool mpm::Particle::assign_traction(unsigned direction, double traction) { bool status = false; try { if (direction >= Tdim || - this->volume() == std::numeric_limits::max()) { + this->volume_ == std::numeric_limits::max()) { throw std::runtime_error( "Particle traction property: volume / direction is invalid"); } // Assign traction - traction_(direction) = traction * this->volume() / this->size_(direction); + traction_(direction) = traction * this->volume_ / this->size_(direction); status = true; - this->assign_boolean_property(mpm::properties::Boolean::SetTraction, true); + this->set_traction_ = true; } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); status = false; @@ -711,6 +754,17 @@ bool mpm::Particle::assign_traction(unsigned direction, double traction) { return status; } +//! Map traction force +template +void mpm::Particle::map_traction_force() noexcept { + if (this->set_traction_) { + // Map particle traction forces to nodes + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->update_external_force(true, mpm::ParticlePhase::Solid, + (shapefn_[i] * traction_)); + } +} + // Compute updated position of the particle template void mpm::Particle::compute_updated_position( @@ -718,40 +772,84 @@ void mpm::Particle::compute_updated_position( // Check if particle has a valid cell ptr assert(cell_ != nullptr); // Get interpolated nodal velocity - const auto& nodal_velocity = this->interpolate_vector_property_from_nodes( - mpm::properties::Vector::Velocity, mpm::ParticlePhase::Solid); + Eigen::Matrix nodal_velocity = + Eigen::Matrix::Zero(); + + for (unsigned i = 0; i < nodes_.size(); ++i) + nodal_velocity += + shapefn_[i] * nodes_[i]->velocity(mpm::ParticlePhase::Solid); // Acceleration update if (!velocity_update) { // Get interpolated nodal acceleration - const auto& nodal_acceleration = - this->interpolate_vector_property_from_nodes( - mpm::properties::Vector::Acceleration, mpm::ParticlePhase::Solid); + Eigen::Matrix nodal_acceleration = + Eigen::Matrix::Zero(); + for (unsigned i = 0; i < nodes_.size(); ++i) + nodal_acceleration += + shapefn_[i] * nodes_[i]->acceleration(mpm::ParticlePhase::Solid); // Update particle velocity from interpolated nodal acceleration - vector_properties_.at(mpm::properties::Vector::Velocity) += - nodal_acceleration * dt; + this->velocity_ += nodal_acceleration * dt; } // Update particle velocity using interpolated nodal velocity else - vector_properties_.at(mpm::properties::Vector::Velocity) = nodal_velocity; + this->velocity_ = nodal_velocity; // New position current position + velocity * dt this->coordinates_ += nodal_velocity * dt; - // Update displacement (displacement is initialized from zero) - vector_properties_.at(mpm::properties::Vector::Displacement) += - nodal_velocity * dt; + this->displacement_ += nodal_velocity * dt; +} + +//! Map particle pressure to nodes +template +bool mpm::Particle::map_pressure_to_nodes(unsigned phase) noexcept { + // Mass is initialized + assert(mass_ != std::numeric_limits::max()); + + bool status = false; + // Check if particle mass is set and state variable pressure is found + if (mass_ != std::numeric_limits::max() && + (state_variables_[phase].find("pressure") != + state_variables_[phase].end())) { + // Map particle pressure to nodes + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->update_mass_pressure( + phase, shapefn_[i] * mass_ * state_variables_[phase]["pressure"]); + + status = true; + } + return status; +} + +// Compute pressure smoothing of the particle based on nodal pressure +template +bool mpm::Particle::compute_pressure_smoothing(unsigned phase) noexcept { + // Assert + assert(cell_ != nullptr); + + bool status = false; + // Check if particle has a valid cell ptr + if (cell_ != nullptr && (state_variables_[phase].find("pressure") != + state_variables_[phase].end())) { + + double pressure = 0.; + // Update particle pressure to interpolated nodal pressure + for (unsigned i = 0; i < this->nodes_.size(); ++i) + pressure += shapefn_[i] * nodes_[i]->pressure(phase); + + state_variables_[phase]["pressure"] = pressure; + status = true; + } + return status; } //! Apply particle velocity constraints -// TODO: revisit constraint application in vector properties, should assign -// direction template void mpm::Particle::apply_particle_velocity_constraints(unsigned dir, double velocity) { // Set particle velocity constraint - vector_properties_.at(mpm::properties::Vector::Velocity)(dir) = velocity; + this->velocity_(dir) = velocity; } //! Return particle tensor data @@ -761,7 +859,6 @@ Eigen::VectorXd mpm::Particle::tensor_data(const std::string& property) { } //! Assign material id of this particle to nodes -// TODO: Contact function to be refactored template void mpm::Particle::append_material_id_to_nodes() const { for (unsigned i = 0; i < nodes_.size(); ++i) diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index e038ea1df..667abf1ff 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -23,7 +23,7 @@ enum ParticlePhase : unsigned int { Solid = 0, Liquid = 1, Gas = 2, - Mixture = 1 + Mixture = 0 }; //! ParticleBase class @@ -113,9 +113,6 @@ class ParticleBase { //! Return cell id virtual Index cell_id() const = 0; - //! Return cell ptr - virtual std::shared_ptr> cell() const = 0; - //! Return cell ptr status virtual bool cell_ptr() const = 0; @@ -134,93 +131,21 @@ class ParticleBase { //! Return size of particle in natural coordinates virtual VectorDim natural_size() const = 0; - //! Assign boolean property at the particle - //! \param[in] property Name of the property to assign - //! \param[in] boolean Property boolean (true/false) of the particles in a - //! cell - void assign_boolean_property(mpm::properties::Boolean property, - bool boolean) noexcept; - - //! Return boolean property - //! \param[in] property Name of the property to update - //! \retval boolean property at particle - bool boolean_property(mpm::properties::Boolean property) const; - - //! Update scalar property at the particle - //! \param[in] property Name of the property to update - //! \param[in] update A boolean to update (true) or assign (false) - //! \param[in] value Property value from the particles in a cell - void update_scalar_property(mpm::properties::Scalar property, bool update, - double value) noexcept; - - //! Return scalar property - //! \param[in] property Name of the property to return - //! \retval scalar property at particle - double scalar_property(mpm::properties::Scalar property) const; - - //! Map scalar property to the nodes - //! \param[in] property Name of the property to update - //! \param[in] update A boolean to update (true) or assign (false) - //! \param[in] phase Index corresponding to the phase - void map_scalar_property_to_nodes(mpm::properties::Scalar property, - bool update, unsigned phase) noexcept; - - //! Map an arbitrary scalar value to nodal scalar property - //! \param[in] property Name of the property to update - //! \param[in] update A boolean to update (true) or assign (false) - //! \param[in] phase Index corresponding to the phase - //! \param[in] value Scalar value to be mapped from particle to node - void map_scalar_property_to_nodes(mpm::properties::Scalar property, - bool update, unsigned phase, - double value) noexcept; - - //! Return an interpolation of scalar property in particle from nodes - //! \param[in] property Name of the property to update - //! \param[in] phase Index corresponding to the phase - //! \retval interpolated scalar property at particle - double interpolate_scalar_property_from_nodes( - mpm::properties::Scalar property, unsigned phase) const; - - //! Update vector property at the particle - //! \param[in] property Name of the property to update - //! \param[in] update A boolean to update (true) or assign (false) - //! \param[in] value Property value from the particles in a cell - void update_vector_property( - mpm::properties::Vector property, bool update, - const Eigen::Matrix& value) noexcept; - - //! Return vector property - //! \param[in] property Name of the property to return - //! \retval vector property at particle - Eigen::Matrix vector_property( - mpm::properties::Vector property) const; - - //! Map vector property to the nodes - //! \param[in] property Name of the property to update - //! \param[in] update A boolean to update (true) or assign (false) - //! \param[in] phase Index corresponding to the phase - void map_vector_property_to_nodes(mpm::properties::Vector property, - bool update, unsigned phase) noexcept; - - //! Map an arbitrary vector value to nodal vector property - //! \param[in] property Name of the property to update - //! \param[in] update A boolean to update (true) or assign (false) - //! \param[in] phase Index corresponding to the phase - //! \param[in] value Vector value to be mapped from particle to node - void map_vector_property_to_nodes( - mpm::properties::Vector property, bool update, unsigned phase, - const Eigen::Matrix& value) noexcept; - - //! Return an interpolation of vector property in particle from nodes - //! \param[in] property Name of the property to update - //! \param[in] phase Index corresponding to the phase - //! \retval interpolated vector property at particle - Eigen::Matrix interpolate_vector_property_from_nodes( - mpm::properties::Vector property, unsigned phase) const; + //! Compute volume of particle + virtual void compute_volume() noexcept = 0; + + //! Update volume based on centre volumetric strain rate + virtual void update_volume() noexcept = 0; //! Return mass density virtual double mass_density() const = 0; + //! Compute mass of particle + virtual void compute_mass() noexcept = 0; + + //! Map particle mass and momentum to nodes + virtual void map_mass_momentum_to_nodes() noexcept = 0; + //! Map multimaterial properties to nodes virtual void map_multimaterial_mass_momentum_to_nodes() noexcept = 0; @@ -254,16 +179,6 @@ 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; } @@ -279,10 +194,6 @@ 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; @@ -310,11 +221,22 @@ class ParticleBase { //! Return stress virtual Eigen::Matrix stress() const = 0; + //! Map body force + virtual void map_body_force(const VectorDim& pgravity) noexcept = 0; + //! Map internal force virtual void map_internal_force() noexcept = 0; + //! Map particle pressure to nodes + virtual bool map_pressure_to_nodes( + unsigned phase = mpm::ParticlePhase::Solid) noexcept = 0; + + //! Compute pressure smoothing of the particle based on nodal pressure + virtual bool compute_pressure_smoothing( + unsigned phase = mpm::ParticlePhase::Solid) noexcept = 0; + //! Assign velocity - virtual void assign_velocity(const VectorDim& velocity) = 0; + virtual bool assign_velocity(const VectorDim& velocity) = 0; //! Return velocity virtual VectorDim velocity() const = 0; @@ -328,10 +250,18 @@ class ParticleBase { //! Return traction virtual VectorDim traction() const = 0; + //! Map traction force + virtual void map_traction_force() noexcept = 0; + //! Compute updated position 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 @@ -357,8 +287,48 @@ class ParticleBase { //! Return neighbour ids virtual std::vector neighbours() const = 0; - //---------------------------------------------------------------------------- - //! TODO + //! Update porosity + //! \param[in] dt Analysis time step + virtual bool update_porosity(double dt) { + throw std::runtime_error( + "Calling the base class function (update_porosity) in " + "ParticleBase:: illegal operation!"); + return false; + }; + + //! Initial pore pressure + virtual void initial_pore_pressure(double pore_pressure) { + throw std::runtime_error( + "Calling the base class function " + "(initial_pore_pressure) in " + "ParticleBase:: illegal operation!"); + }; + + //! Assign particle pressure constraints + virtual bool assign_particle_pore_pressure_constraint(double pressure) { + throw std::runtime_error( + "Calling the base class function " + "(assign_particle_pore_pressure_constraint) in " + "ParticleBase:: illegal operation!"); + return 0; + }; + + //! Assign saturation degree + virtual bool assign_saturation_degree() { + throw std::runtime_error( + "Calling the base class function (assign_saturation_degree) in " + "ParticleBase:: illegal operation!"); + return 0; + }; + + //! Assign pore pressure + //! \param[in] pressure Pore liquid pressure + virtual void assign_pore_pressure(double pressure) { + throw std::runtime_error( + "Calling the base class function (assign_pore_pressure) in " + "ParticleBase:: illegal operation!"); + }; + //! Assign liquid traction //! \param[in] direction Index corresponding to the direction of traction //! \param[in] traction Particle traction in specified direction @@ -367,7 +337,72 @@ class ParticleBase { throw std::runtime_error( "Calling the base class function (assign_liquid_traction) in " "ParticleBase:: illegal operation!"); - return false; + return 0; + }; + + //! Return liquid phase traction + virtual VectorDim liquid_traction() const { + auto error = VectorDim::Zero(); + throw std::runtime_error( + "Calling the base class function (liquid_traction) in " + "ParticleBase:: illegal operation!"); + return error; + }; + + //! Return mixture traction + virtual VectorDim mixture_traction() const { + auto error = VectorDim::Zero(); + throw std::runtime_error( + "Calling the base class function (mixture_traction) in " + "ParticleBase:: illegal operation!"); + return error; + }; + + //! Return liquid mass + //! \retval liquid mass Liquid phase mass + virtual double liquid_mass() const { + throw std::runtime_error( + "Calling the base class function (liquid_mass) in " + "ParticleBase:: illegal operation!"); + return 0; + }; + + //! Assign velocity to the particle liquid phase + //! \param[in] velocity A vector of particle liquid phase velocity + //! \retval status Assignment status + virtual bool assign_liquid_velocity(const VectorDim& velocity) { + throw std::runtime_error( + "Calling the base class function (assign_liquid_velocity) in " + "ParticleBase:: illegal operation!"); + return 0; + }; + + //! Return velocity of the particle liquid phase + //! \retval liquid velocity Liquid phase velocity + virtual VectorDim liquid_velocity() const { + auto error = VectorDim::Zero(); + throw std::runtime_error( + "Calling the base class function (liquid_velocity) in " + "ParticleBase:: illegal operation!"); + return error; + }; + + //! Return strain of the particle liquid phase + //! \retval liquid strain Liquid phase strain + virtual Eigen::Matrix liquid_strain() const { + auto error = Eigen::Matrix::Zero(); + throw std::runtime_error( + "Calling the base class function (liquid_strain) in " + "ParticleBase:: illegal operation!"); + return error; + }; + + //! Compute pore pressure somoothening by interpolating nodal pressure + virtual bool compute_pore_pressure_smoothing() { + throw std::runtime_error( + "Calling the base class function (compute_pore_pressure_smoothing) in " + "ParticleBase:: illegal operation!"); + return 0; }; //! Compute pore pressure @@ -378,33 +413,81 @@ class ParticleBase { "ParticleBase:: illegal operation!"); }; - //! Compute pore pressure somoothening by interpolating nodal pressure - virtual bool compute_pore_pressure_smoothing() { + //! Return liquid pore pressure + //! \retval pore pressure Pore liquid pressure + virtual double pore_pressure() const { throw std::runtime_error( - "Calling the base class function (compute_pore_pressure_smoothing) in " + "Calling the base class function (pore_pressure) in " "ParticleBase:: illegal operation!"); - return false; + return 0; + }; + + //! Update particle permeability + virtual bool update_permeability() { + throw std::runtime_error( + "Calling the base class function (update_permeability) in " + "ParticleBase:: illegal operation!"); + return 0; + }; + + //! Map drag force coefficient + virtual bool map_drag_force_coefficient() { + throw std::runtime_error( + "Calling the base class function (map_drag_force_coefficient) in " + "ParticleBase:: illegal operation!"); + return 0; }; //! Assign particle liquid phase velocity constraints + //! Directions can take values between 0 and Dim + //! \param[in] dir Direction of particle velocity constraint + //! \param[in] velocity Applied particle liquid phase velocity constraint + //! \retval status Assignment status virtual bool assign_particle_liquid_velocity_constraint(unsigned dir, double velocity) { throw std::runtime_error( "Calling the base class function " "(assign_particle_liquid_velocity_constraint) in " "ParticleBase:: illegal operation!"); + return 0; + }; + + //! Apply particle liquid phase velocity constraints + virtual void apply_particle_liquid_velocity_constraints() { + throw std::runtime_error( + "Calling the base class function " + "(apply_particle_liquid_velocity_constraints) in " + "ParticleBase:: illegal operation!"); + }; + + //! Initialise particle pore pressure by watertable + virtual bool initialise_pore_pressure_watertable( + const unsigned dir_v, const unsigned dir_h, + std::map& refernece_points) { + throw std::runtime_error( + "Calling the base class function " + "(initial_pore_pressure_watertable) in " + "ParticleBase:: illegal operation!"); return false; }; - //! Assign particle pressure constraints - virtual bool assign_particle_pore_pressure_constraint(double pressure) { + //! Initialise particle pore pressure by watertable + virtual bool assign_porosity() { throw std::runtime_error( "Calling the base class function " - "(assign_particle_pore_pressure_constraint) in " + "(assign_porosity) in " + "ParticleBase:: illegal operation!"); + return false; + }; + + //! Initialise particle pore pressure by watertable + virtual bool assign_permeability() { + throw std::runtime_error( + "Calling the base class function " + "(assign_permeability) in " "ParticleBase:: illegal operation!"); return false; }; - //---------------------------------------------------------------------------- protected: //! particleBase id @@ -429,18 +512,9 @@ class ParticleBase { std::vector state_variables_; //! Vector of particle neighbour ids std::vector neighbours_; - //! Shape functions - Eigen::VectorXd shapefn_; - //! Boolean properties - fc::vector_map boolean_properties_; - //! Scalar properties - fc::vector_map scalar_properties_; - //! Vector properties - fc::vector_map> - vector_properties_; }; // ParticleBase class } // namespace mpm #include "particle_base.tcc" -#endif // MPM_PARTICLEBASE_H__ \ No newline at end of file +#endif // MPM_PARTICLEBASE_H__ diff --git a/include/particles/particle_base.tcc b/include/particles/particle_base.tcc index 092340f25..a75e8ca0b 100644 --- a/include/particles/particle_base.tcc +++ b/include/particles/particle_base.tcc @@ -15,120 +15,3 @@ mpm::ParticleBase::ParticleBase(Index id, const VectorDim& coord, : mpm::ParticleBase::ParticleBase(id, coord) { status_ = status; } - -//! Assign boolean property at the particle -template -void mpm::ParticleBase::assign_boolean_property( - mpm::properties::Boolean property, bool boolean) noexcept { - boolean_properties_.at(property) = boolean; -} - -//! Return boolean property -template -bool mpm::ParticleBase::boolean_property( - mpm::properties::Boolean property) const { - return boolean_properties_.at(property); -} - -//! Update scalar property at particle -template -void mpm::ParticleBase::update_scalar_property( - mpm::properties::Scalar property, bool update, double value) noexcept { - // Decide to update or assign - const double factor = (update == true) ? 1. : 0.; - scalar_properties_.at(property) = - scalar_properties_.at(property) * factor + value; -} - -//! Update scalar property at particle -template -double mpm::ParticleBase::scalar_property( - mpm::properties::Scalar property) const { - return scalar_properties_.at(property); -} - -//! Map scalar property to nodes -template -void mpm::ParticleBase::map_scalar_property_to_nodes( - mpm::properties::Scalar property, bool update, unsigned phase) noexcept { - // Check if particle property is set - assert(scalar_properties_.at(property) != std::numeric_limits::max()); - - // Map scalar property to nodes - for (unsigned i = 0; i < nodes_.size(); ++i) - nodes_[i]->update_scalar_property( - property, update, phase, scalar_properties_.at(property) * shapefn_[i]); -} - -//! Map an arbitrary scalar value to nodal scalar property -template -void mpm::ParticleBase::map_scalar_property_to_nodes( - mpm::properties::Scalar property, bool update, unsigned phase, - double value) noexcept { - // Map scalar value to nodes - for (unsigned i = 0; i < nodes_.size(); ++i) - nodes_[i]->update_scalar_property(property, update, phase, - value * shapefn_[i]); -} - -//! Interpolate scalar property from nodes -template -double mpm::ParticleBase::interpolate_scalar_property_from_nodes( - mpm::properties::Scalar property, unsigned phase) const { - double value = 0.; - // Interpolate scalar property from nodes - for (unsigned i = 0; i < nodes_.size(); ++i) - value += nodes_[i]->scalar_property(property, phase) * shapefn_[i]; - return value; -} - -//! Update vector property at particle -template -void mpm::ParticleBase::update_vector_property( - mpm::properties::Vector property, bool update, - const Eigen::Matrix& value) noexcept { - // Decide to update or assign - const double factor = (update == true) ? 1. : 0.; - vector_properties_.at(property) = - vector_properties_.at(property) * factor + value; -} - -//! Update vector property at particle -template -Eigen::Matrix mpm::ParticleBase::vector_property( - mpm::properties::Vector property) const { - return vector_properties_.at(property); -} - -//! Map vector property to nodes -template -void mpm::ParticleBase::map_vector_property_to_nodes( - mpm::properties::Vector property, bool update, unsigned phase) noexcept { - // Map vector property to nodes - for (unsigned i = 0; i < nodes_.size(); ++i) - nodes_[i]->update_vector_property( - property, update, phase, vector_properties_.at(property) * shapefn_[i]); -} - -//! Map an arbitrary vector value to nodal vector property -template -void mpm::ParticleBase::map_vector_property_to_nodes( - mpm::properties::Vector property, bool update, unsigned phase, - const Eigen::Matrix& value) noexcept { - // Map vector property to nodes - for (unsigned i = 0; i < nodes_.size(); ++i) - nodes_[i]->update_vector_property(property, update, phase, - value * shapefn_[i]); -} - -//! Interpolate vector property from nodes -template -Eigen::Matrix - mpm::ParticleBase::interpolate_vector_property_from_nodes( - mpm::properties::Vector property, unsigned phase) const { - Eigen::Matrix value = Eigen::Matrix::Zero(); - // Interpolate vector property from nodes - for (unsigned i = 0; i < nodes_.size(); ++i) - value += nodes_[i]->vector_property(property, phase) * shapefn_[i]; - return value; -} diff --git a/include/particles/particle_functions.tcc b/include/particles/particle_functions.tcc deleted file mode 100644 index 3b654507a..000000000 --- a/include/particles/particle_functions.tcc +++ /dev/null @@ -1,122 +0,0 @@ -namespace mpm { -namespace particle { - -// Compute particle mass -template -void compute_mass(std::shared_ptr> particle) noexcept { - // Check if particle volume is set and material ptr is valid - assert(particle->volume() != std::numeric_limits::max() && - particle->material() != nullptr); - - // Mass = volume of particle * mass_density - particle->update_scalar_property( - mpm::properties::Scalar::MassDensity, false, - particle->material()->template property(std::string("density"))); - - // Update particle mass - particle->update_scalar_property( - mpm::properties::Scalar::Mass, false, - particle->volume() * particle->mass_density()); -} - -// Compute volume of the particle -template -void compute_volume( - std::shared_ptr> particle) noexcept { - // Check if particle has a valid cell ptr - assert(particle->cell_ptr()); - - // Volume of the cell / # of particles - particle->assign_volume(particle->cell()->volume() / - particle->cell()->nparticles()); -} - -// Update volume based on the central strain rate -template -void update_volume(std::shared_ptr> particle) noexcept { - // Check if particle has a valid cell ptr and a valid volume - assert(particle->cell_ptr() && - particle->volume() != std::numeric_limits::max()); - - // Compute at centroid - // Strain rate for reduced integration - particle->update_scalar_property( - mpm::properties::Scalar::Volume, false, - (particle->volume() * (1. + particle->dvolumetric_strain()))); - particle->update_scalar_property( - mpm::properties::Scalar::MassDensity, false, - (particle->mass_density() / (1. + particle->dvolumetric_strain()))); -} - -//! Map particle mass and momentum to nodes -template -void map_mass_momentum_to_nodes( - std::shared_ptr> particle) noexcept { - // Check if particle mass is set - assert(particle->mass() != std::numeric_limits::max()); - - // Map mass and momentum to nodes - particle->map_scalar_property_to_nodes(mpm::properties::Scalar::Mass, true, - mpm::ParticlePhase::Solid); - particle->map_vector_property_to_nodes( - mpm::properties::Vector::Momentum, true, mpm::ParticlePhase::Solid, - particle->mass() * particle->velocity()); -} - -//! Map particle pressure to nodes -template -void map_mass_pressure_to_nodes( - std::shared_ptr> particle, - unsigned phase = mpm::ParticlePhase::Solid) noexcept { - // Mass is initialized - assert(particle->mass() != std::numeric_limits::max()); - - // Check if state variable pressure is found - if (particle->pressure(phase) != std::numeric_limits::quiet_NaN()) { - // Map particle pressure to nodes - particle->map_scalar_property_to_nodes( - mpm::properties::Scalar::MassPressure, true, phase, - particle->mass() * particle->pressure(phase)); - } -} - -//! Map body force to nodes -template -void map_body_force(std::shared_ptr> particle, - const Eigen::Matrix& pgravity) noexcept { - // Compute nodal body forces - particle->map_vector_property_to_nodes(mpm::properties::Vector::ExternalForce, - true, mpm::ParticlePhase::Solid, - pgravity * particle->mass()); -} - -//! Map traction force -template -void map_traction_force( - std::shared_ptr> particle) noexcept { - if (particle->boolean_property(mpm::properties::Boolean::SetTraction)) { - // Map particle traction forces to nodes - particle->map_vector_property_to_nodes( - mpm::properties::Vector::ExternalForce, true, mpm::ParticlePhase::Solid, - particle->traction()); - } -} - -// Compute pressure smoothing of the particle based on nodal pressure -template -void compute_pressure_smoothing( - std::shared_ptr> particle, - unsigned phase = mpm::ParticlePhase::Solid) noexcept { - // Assert - assert(particle->cell_ptr()); - - // Check if particle has pressure - if (particle->pressure(phase) != std::numeric_limits::quiet_NaN()) { - double pressure = particle->interpolate_scalar_property_from_nodes( - mpm::properties::Scalar::Pressure, phase); - particle->assign_state_variable("pressure", pressure, phase); - } -} - -} // namespace particle -} // namespace mpm diff --git a/include/particles/twophase_particle.h b/include/particles/twophase_particle.h index be01cbdb4..cd67ca77b 100644 --- a/include/particles/twophase_particle.h +++ b/include/particles/twophase_particle.h @@ -13,8 +13,8 @@ namespace mpm { //! TwoPhaseParticle class -//! \brief Class that stores the information about twophase particles -//! Derive from particle +//! \brief Class that stores the information about second-phase (water) +//! particles //! \tparam Tdim Dimension template class TwoPhaseParticle : public mpm::Particle { @@ -55,12 +55,52 @@ class TwoPhaseParticle : public mpm::Particle { const HDF5Particle& particle, const std::shared_ptr>& material) override; + //! Initialise liquid phase + void initialise() override; + //! Retrun particle data as HDF5 //! \retval particle HDF5 data of the particle HDF5Particle hdf5() const override; - //! Initialise properties - void initialise() override; + //! Assign saturation degree + bool assign_saturation_degree() override; + + //! Assign pore pressure + //! \param[in] pressure Pore liquid pressure + void assign_pore_pressure(double pressure) override { + this->pore_pressure_ = pressure; + } + + //! Assign liquid traction + //! \param[in] direction Index corresponding to the direction of traction + //! \param[in] traction Particle traction in specified direction + //! \retval status Assignment status + bool assign_liquid_traction(unsigned direction, double traction) override; + + //! Return liquid phase traction + VectorDim liquid_traction() const { return liquid_traction_; }; + + //! Return mixture traction + VectorDim mixture_traction() const { return mixture_traction_; }; + + //! Compute both solid and liquid mass + void compute_mass() noexcept override; + + //! Map particle mass and momentum to nodes (both solid and liquid) + void map_mass_momentum_to_nodes() noexcept override; + + //! Map body force + //! \param[in] pgravity Gravity of a particle + void map_body_force(const VectorDim& pgravity) noexcept override; + + //! Assign traction to the particle + //! \param[in] direction Index corresponding to the direction of traction + //! \param[in] traction Particle traction in specified direction + //! \retval status Assignment status + bool assign_traction(unsigned direction, double traction) override; + + //! Map traction force + void map_traction_force() noexcept override; //! Map internal force inline void map_internal_force() noexcept override; @@ -70,20 +110,42 @@ class TwoPhaseParticle : public mpm::Particle { //! Update particle velocity from nodal vel when true void compute_updated_position(double dt, bool velocity_update = false) noexcept override; - //------------------------------------------------------------------------------- - //! TODO - //! Assign liquid traction - //! \param[in] direction Index corresponding to the direction of traction - //! \param[in] traction Particle traction in specified direction + + //! Assign velocity to the particle liquid phase + //! \param[in] velocity A vector of particle liquid phase velocity //! \retval status Assignment status - bool assign_liquid_traction(unsigned direction, double traction) override; + bool assign_liquid_velocity(const VectorDim& velocity) override; + + //! Return velocity of the particle liquid phase + //! \retval liquid velocity Liquid phase velocity + VectorDim liquid_velocity() const override { return liquid_velocity_; } + + //! Return liquid strain of the particle + Eigen::Matrix liquid_strain() const override { + return liquid_strain_; + } + + //! Return liquid mass + //! \retval liquid mass Liquid phase mass + double liquid_mass() const override { return liquid_mass_; } + + //! Compute pore pressure somoothening by interpolating nodal pressure + bool compute_pore_pressure_smoothing() noexcept override; //! Compute pore pressure //! \param[in] dt Time step size void compute_pore_pressure(double dt) noexcept override; - //! Compute pore pressure somoothening by interpolating nodal pressure - bool compute_pore_pressure_smoothing() noexcept override; + //! Return liquid pore pressure + //! \retval pore pressure Pore liquid pressure + double pore_pressure() const override { return pore_pressure_; } + + //! Map drag force coefficient + bool map_drag_force_coefficient() override; + + //! Update particle permeability + //! \retval status Update status + bool update_permeability() override; //! Assign particle liquid phase velocity constraints //! Directions can take values between 0 and Dim @@ -93,49 +155,86 @@ class TwoPhaseParticle : public mpm::Particle { bool assign_particle_liquid_velocity_constraint(unsigned dir, double velocity) override; + //! Apply particle liquid phase velocity constraints + void apply_particle_liquid_velocity_constraints() override; + //! Assign particle pressure constraints //! \retval status Assignment status bool assign_particle_pore_pressure_constraint(double pressure) override; - //------------------------------------------------------------------------------- - private: - //! Compute updated velocity of the particle based on nodal velocity + //! Initial pore pressure + //! \param[in] pore pressure Initial pore pressure + void initial_pore_pressure(double pore_pressure) override { + this->pore_pressure_ = pore_pressure; + } + + //! Assign particles initial pore pressure by watertable + bool initialise_pore_pressure_watertable( + const unsigned dir_v, const unsigned dir_h, + std::map& refernece_points); + + //! Update porosity //! \param[in] dt Analysis time step - //! \retval status Compute status - void compute_updated_liquid_velocity(double dt, - bool velocity_update) noexcept; + bool update_porosity(double dt) override; - //! Apply particle liquid phase velocity constraints - void apply_particle_liquid_velocity_constraints(); + //! Assign particle permeability + //! \retval status Assignment status + bool assign_permeability() override; - //! Map liquid phase traction force - void map_liquid_traction_force() noexcept; + //! Assign porosity + bool assign_porosity() override; - //! Return mass of the particle - double liquid_mass() const { - return this->scalar_property(mpm::properties::Scalar::LiquidMass); - } + //! Map particle pressure to nodes + bool map_pressure_to_nodes( + unsigned phase = mpm::ParticlePhase::Solid) noexcept override; - //! Return porosity of the particle - double porosity() const { - return this->scalar_property(mpm::properties::Scalar::Porosity); - } + //! Compute pressure smoothing of the particle based on nodal pressure + //! $$\hat{p}_p = \sum_{i = 1}^{n_n} N_i(x_p) p_i$$ + bool compute_pressure_smoothing( + unsigned phase = mpm::ParticlePhase::Solid) noexcept override; - //! Return liquid strain of the particle - Eigen::Matrix liquid_strain() const { return liquid_strain_; } + private: + //! Compute liquid mass + virtual void compute_liquid_mass() noexcept; - //! Return liquid velocity of the particle - VectorDim liquid_velocity() const { - return this->vector_property(mpm::properties::Vector::LiquidVelocity); - } + //! Assign liquid mass and momentum to nodes + virtual void map_liquid_mass_momentum_to_nodes() noexcept; - //! Return pore pressure of the particle - double pore_pressure() const { - return this->scalar_property(mpm::properties::Scalar::PorePressure); - } + //! Map two phase mixture body force + //! \param[in] mixture Identification for Mixture + //! \param[in] pgravity Gravity of the particle + virtual void map_mixture_body_force(unsigned mixture, + const VectorDim& pgravity) noexcept; - //! Return free surface status - bool free_surface() const { return free_surface_; } + //! Map liquid body force + //! \param[in] pgravity Gravity of a particle + virtual void map_liquid_body_force(const VectorDim& pgravity) noexcept; + + //! Assign mixture traction + //! \param[in] direction Index corresponding to the direction of traction + //! \param[in] traction Particle traction in specified direction + //! \retval status Assignment status + virtual bool assign_mixture_traction(unsigned direction, double traction); + + //! Map liquid phase traction force + virtual void map_liquid_traction_force() noexcept; + + //! Map two phase mixture traction force + //! \param[in] mixture Identification for Mixture + virtual void map_mixture_traction_force(unsigned mixture) noexcept; + + //! Map liquid internal force + virtual void map_liquid_internal_force() noexcept; + + //! Map two phase mixture internal force + //! \param[in] mixture Identification for Mixture + virtual void map_mixture_internal_force(unsigned mixture) noexcept; + + //! Compute updated velocity of the particle based on nodal velocity + //! \param[in] dt Analysis time step + //! \retval status Compute status + virtual void compute_updated_liquid_velocity(double dt, + bool velocity_update) noexcept; protected: //! coordinates @@ -144,6 +243,8 @@ class TwoPhaseParticle : public mpm::Particle { using ParticleBase::cell_; //! Nodes using ParticleBase::nodes_; + //! State variables + using ParticleBase::state_variables_; //! Shape functions using Particle::shapefn_; //! Effective stress of soil skeleton @@ -152,36 +253,58 @@ class TwoPhaseParticle : public mpm::Particle { using Particle::strain_rate_; //! Soil skeleton material using Particle::material_; - //! State variables - using ParticleBase::state_variables_; + //! Material id + using ParticleBase::material_id_; + //! Particle total volume + using Particle::volume_; + //! Particle mass density + using Particle::mass_density_; + //! Particle mass for solid phase + using Particle::mass_; //! dN/dX using Particle::dn_dx_; //! dN/dX at cell centroid using Particle::dn_dx_centroid_; - //! Scalar properties - using ParticleBase::scalar_properties_; - //! Vector properties - using ParticleBase::vector_properties_; + + //! Liquid mass + double liquid_mass_; + //! Liquid mass density (bulk density = liquid mass / total volume) + double liquid_mass_density_; + //! Degree of saturation + double liquid_saturation_{1.0}; + //! Material point porosity (volume of voids / total volume) + double porosity_{0.0}; + //! Liquid velocity + Eigen::Matrix liquid_velocity_; //! Particle liquid phase velocity constraints std::map liquid_velocity_constraints_; - //! Free surface - bool free_surface_{false}; //! Pore pressure constraint - double pore_pressure_constraint_{std::numeric_limits::max()}; + double pore_pressure_constraint_{std::numeric_limits::max()}; + //! Pore pressure + double pore_pressure_; //! Set liquid phase traction - bool set_liquid_traction_{false}; + bool set_liquid_traction_; + //! Set mixture traction + bool set_mixture_traction_; //! Traction for liquid phase Eigen::Matrix liquid_traction_; + //! Traction for mixture (soil skeleton + pore liquid) + Eigen::Matrix mixture_traction_; //! Liquid strain rate - Eigen::Matrix liquid_strain_rate_; + Eigen::Matrix liquid_strain_rate_; // delete if not needed //! Liquid strain rate - Eigen::Matrix liquid_strain_; + Eigen::Matrix liquid_strain_; // delete if not needed //! Logger std::unique_ptr console_; + //! Permeability + VectorDim permeability_; + //! Permeability parameter + VectorDim c1_; + //! reference pore pressure + double reference_pore_pressure_{0}; }; // TwoPhaseParticle class } // namespace mpm #include "twophase_particle.tcc" -#include "twophase_particle_functions.tcc" #endif // MPM_TWOPHASE_PARTICLE_H__ diff --git a/include/particles/twophase_particle.tcc b/include/particles/twophase_particle.tcc index fe764d819..e0079c612 100644 --- a/include/particles/twophase_particle.tcc +++ b/include/particles/twophase_particle.tcc @@ -1,8 +1,7 @@ -//! Construct a twophase particle with id and coordinates +//! Construct a two phase particle with id and coordinates template mpm::TwoPhaseParticle::TwoPhaseParticle(Index id, const VectorDim& coord) : mpm::Particle(id, coord) { - // Initialise variables for solid phase and liquid phase this->initialise(); // Clear cell ptr cell_ = nullptr; @@ -20,21 +19,52 @@ mpm::TwoPhaseParticle::TwoPhaseParticle(Index id, const VectorDim& coord) template mpm::TwoPhaseParticle::TwoPhaseParticle(Index id, const VectorDim& coord, bool status) - : mpm::Particle(id, coord, status) { - // Initialise variables for solid phase and liquid phase + : mpm::ParticleBase(id, coord, status) { this->initialise(); - // Clear cell ptr cell_ = nullptr; - // Nodes nodes_.clear(); // Set material containers this->initialise_material(2); - // Logger + //! Logger std::string logger = "twophaseparticle" + std::to_string(Tdim) + "d::" + std::to_string(id); console_ = std::make_unique(logger, mpm::stdout_sink); } +//! Return particle data in HDF5 format +template +// cppcheck-suppress * +mpm::HDF5Particle mpm::TwoPhaseParticle::hdf5() const { + // Derive from particle + auto particle_data = mpm::Particle::hdf5(); + // // Particle liquid velocity + // Eigen::Vector3d liquid_velocity; + // liquid_velocity.setZero(); + // for (unsigned j = 0; j < Tdim; ++j) + // liquid_velocity[j] = this->liquid_velocity_[j]; + // // Particle liquid strain + // Eigen::Matrix liquid_strain = this->liquid_strain_; + // // Particle liquid mass + // particle_data.liquid_mass = this->liquid_mass_; + // Particle pore pressure + particle_data.pressure = this->pore_pressure_; + // // Particle liquid velocity + // particle_data.liquid_velocity_x = liquid_velocity[0]; + // particle_data.liquid_velocity_y = liquid_velocity[1]; + // particle_data.liquid_velocity_z = liquid_velocity[2]; + // // Particle liquid strain + // particle_data.liquid_strain_xx = liquid_strain[0]; + // particle_data.liquid_strain_yy = liquid_strain[1]; + // particle_data.liquid_strain_zz = liquid_strain[2]; + // particle_data.liquid_gamma_xy = liquid_strain[3]; + // particle_data.liquid_gamma_yz = liquid_strain[4]; + // particle_data.liquid_gamma_xz = liquid_strain[5]; + // // Particle liquid material id + // particle_data.liquid_material_id = this->liquid_material_id_; + + return particle_data; +} + //! Initialise particle data from HDF5 template bool mpm::TwoPhaseParticle::initialise_particle( @@ -43,22 +73,21 @@ bool mpm::TwoPhaseParticle::initialise_particle( mpm::Particle::initialise_particle(particle); // // Liquid mass - // scalar_properties_.at(mpm::properties::Scalar::LiquidMass) = - // particle.liquid_mass; + // this->liquid_mass_ = particle.liquid_mass; // // Liquid mass Density - // scalar_properties_.at(mpm::properties::Scalar::LiquidMassDensity) = - // particle.mass / particle.volume; + // this->liquid_mass_density_ = particle.mass / particle.volume; + // // Pore pressure - // scalar_properties_.at(mpm::properties::Scalar::PorePressure) = - // particle.pore_pressure; + // this->pore_pressure_ = particle.pore_pressure; + // // Liquid velocity // Eigen::Vector3d liquid_velocity; // liquid_velocity << particle.liquid_velocity_x, particle.liquid_velocity_y, // particle.liquid_velocity_z; // // Initialise velocity // for (unsigned i = 0; i < Tdim; ++i) - // vector_properties_.at(mpm::properties::Vector::LiquidVelocity)(i) = - // liquid_velocity(i); + // this->liquid_velocity_(i) = liquid_velocity(i); + // // Liquid strain // this->liquid_strain_[0] = particle.liquid_strain_xx; // this->liquid_strain_[1] = particle.liquid_strain_yy; @@ -66,6 +95,7 @@ bool mpm::TwoPhaseParticle::initialise_particle( // this->liquid_strain_[3] = particle.liquid_gamma_xy; // this->liquid_strain_[4] = particle.liquid_gamma_yz; // this->liquid_strain_[5] = particle.liquid_gamma_xz; + // // Liquid material id // this->liquid_material_id_ = particle.liquid_material_id; @@ -73,204 +103,367 @@ bool mpm::TwoPhaseParticle::initialise_particle( } //! Initialise particle data from HDF5 +//! TODO template bool mpm::TwoPhaseParticle::initialise_particle( const HDF5Particle& particle, const std::shared_ptr>& material) { - bool status = this->initialise_particle(particle); - if (material != nullptr) { - if (this->material_id() == material->id() || - this->material_id() == std::numeric_limits::max()) { - bool assign_mat = mpm::Particle::assign_material(material); - if (!assign_mat) throw std::runtime_error("Material assignment failed"); - // Reinitialize state variables - auto mat_state_vars = (this->material())->initialise_state_variables(); - if (mat_state_vars.size() == particle.nstate_vars) { - unsigned i = 0; - auto state_variables = (this->material())->state_variables(); - for (const auto& state_var : state_variables) { - this->state_variables_[mpm::ParticlePhase::Solid].at(state_var) = - particle.svars[i]; - ++i; - } - } - } else { - status = false; - throw std::runtime_error("Material is invalid to assign to particle!"); - } - } + bool status = mpm::Particle::initialise_particle(particle, material); return status; } -//! Return particle data in HDF5 format -template -// cppcheck-suppress * -mpm::HDF5Particle mpm::TwoPhaseParticle::hdf5() const { - // Derive from particle - auto particle_data = mpm::Particle::hdf5(); - // TODO:HDF5 - // // Particle liquid velocity - // Eigen::Vector3d liquid_velocity; - // liquid_velocity.setZero(); - // for (unsigned j = 0; j < Tdim; ++j) - // liquid_velocity[j] = this->liquid_velocity_[j]; - // // Particle liquid strain - // Eigen::Matrix liquid_strain = this->liquid_strain_; - // // Particle liquid mass - // particle_data.liquid_mass = this->liquid_mass_; - // // Particle pore pressure - // particle_data.pore_pressure = - // scalar_properties_.at(mpm::properties::Scalar::PorePressure); - // // Particle liquid velocity - // particle_data.liquid_velocity_x = liquid_velocity[0]; - // particle_data.liquid_velocity_y = liquid_velocity[1]; - // particle_data.liquid_velocity_z = liquid_velocity[2]; - // // Particle liquid strain - // particle_data.liquid_strain_xx = liquid_strain[0]; - // particle_data.liquid_strain_yy = liquid_strain[1]; - // particle_data.liquid_strain_zz = liquid_strain[2]; - // particle_data.liquid_gamma_xy = liquid_strain[3]; - // particle_data.liquid_gamma_yz = liquid_strain[4]; - // particle_data.liquid_gamma_xz = liquid_strain[5]; - // // Particle liquid material id - // particle_data.liquid_material_id = this->liquid_material_id_; - - return particle_data; -} - -//! Initialise particle data from HDF5 +// Initialise liquid phase particle properties template void mpm::TwoPhaseParticle::initialise() { mpm::Particle::initialise(); + liquid_mass_ = 0.; + liquid_velocity_.setZero(); liquid_strain_rate_.setZero(); liquid_strain_.setZero(); - liquid_traction_.setZero(); set_liquid_traction_ = false; - - // Initialize scalar properties - scalar_properties_.emplace( - std::make_pair(mpm::properties::Scalar::LiquidMass, double(0.))); - scalar_properties_.emplace( - std::make_pair(mpm::properties::Scalar::Porosity, double(0.))); - scalar_properties_.emplace( - std::make_pair(mpm::properties::Scalar::PorePressure, double(0.))); - scalar_properties_.emplace( - std::make_pair(mpm::properties::Scalar::LiquidMassDensity, double(0.))); - - // Initialize vector properties - vector_properties_.emplace( - std::make_pair(mpm::properties::Vector::Permeability, VectorDim::Zero())); - vector_properties_.emplace(std::make_pair( - mpm::properties::Vector::LiquidVelocity, VectorDim::Zero())); - vector_properties_.emplace( - std::make_pair(mpm::properties::Vector::DragForce, VectorDim::Zero())); + set_mixture_traction_ = false; + liquid_traction_.setZero(); + pore_pressure_ = 0.; + liquid_saturation_ = 1.; // Initialize vector data properties this->properties_["liquid_strains"] = [&]() { return liquid_strain(); }; this->properties_["liquid_velocities"] = [&]() { return liquid_velocity(); }; this->properties_["pore_pressure"] = [&]() { - Eigen::VectorXd pore_pressure = Eigen::VectorXd::Zero(3); - // Total pore pressure - pore_pressure[0] = this->pore_pressure(); - // Excessive pore pressure - // pore_pressure[1] = this->excessive_pore_pressure(); - // Free surface - // pore_pressure[2] = this->free_surface(); - - return pore_pressure; + Eigen::VectorXd vec_pressure = Eigen::VectorXd::Zero(3); + vec_pressure[0] = this->pore_pressure(); + // FIXME: This is to check free surface particles + // TODO: To be removed somewhere + // vec_pressure[1] = this->free_surface(); + return vec_pressure; }; } -//! Map both mixture and liquid internal force -template <> -inline void mpm::TwoPhaseParticle<1>::map_internal_force() noexcept { - // Map mixture internal force - // Initialise a vector of pore pressure - Eigen::Matrix total_stress = this->stress_; - total_stress(0) -= - scalar_properties_.at(mpm::properties::Scalar::PorePressure); - // Compute nodal internal forces +// Assign degree of saturation to the liquid phase +template +bool mpm::TwoPhaseParticle::assign_saturation_degree() { + bool status = true; + try { + if (this->material(mpm::ParticlePhase::Liquid) != nullptr) { + liquid_saturation_ = + this->material(mpm::ParticlePhase::Liquid) + ->template property(std::string("saturation")); + if (liquid_saturation_ < 0. || liquid_saturation_ > 1.) + throw std::runtime_error( + "Particle saturation degree is negative or larger than one"); + } else { + throw std::runtime_error("Liquid material is invalid"); + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +// Assign velocity to the particle liquid phase +template +bool mpm::TwoPhaseParticle::assign_liquid_velocity( + const Eigen::Matrix& velocity) { + bool status = false; + try { + // Assign velocity + liquid_velocity_ = velocity; + status = true; + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +// Assign traction to the liquid phase +template +bool mpm::TwoPhaseParticle::assign_liquid_traction(unsigned direction, + double traction) { + bool status = false; + try { + if (direction >= Tdim || + this->volume_ == std::numeric_limits::max()) { + throw std::runtime_error( + "Particle liquid traction property: volume / direction is invalid"); + } + // Assign liquid traction + liquid_traction_(direction) = + traction * this->volume_ / this->size_(direction); + status = true; + this->set_liquid_traction_ = true; + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +// Assign traction +template +bool mpm::TwoPhaseParticle::assign_traction(unsigned direction, + double traction) { + bool status = true; + this->assign_mixture_traction(direction, traction); + return status; +} + +// Assign traction to the mixture +template +bool mpm::TwoPhaseParticle::assign_mixture_traction(unsigned direction, + double traction) { + bool status = false; + try { + if (direction >= Tdim || + this->volume_ == std::numeric_limits::max()) { + throw std::runtime_error( + "Particle mixture traction property: volume / direction is invalid"); + } + // Assign mixture traction + mixture_traction_(direction) = + traction * this->volume_ / this->size_(direction); + status = true; + this->set_mixture_traction_ = true; + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +// Compute mass of particle (both solid and fluid) +template +void mpm::TwoPhaseParticle::compute_mass() noexcept { + mpm::Particle::compute_mass(); + this->compute_liquid_mass(); +} + +// Compute fluid mass of particle +template +void mpm::TwoPhaseParticle::compute_liquid_mass() noexcept { + // Check if particle volume is set and liquid material ptr is valid + assert(volume_ != std::numeric_limits::max() && + this->material(mpm::ParticlePhase::Liquid) != nullptr); + + // Mass = volume of particle * bulk_density + this->liquid_mass_density_ = + liquid_saturation_ * porosity_ * + this->material(mpm::ParticlePhase::Liquid) + ->template property(std::string("density")); + this->liquid_mass_ = volume_ * liquid_mass_density_; +} + +//! Map particle mass and momentum to nodes +template +void mpm::TwoPhaseParticle::map_mass_momentum_to_nodes() noexcept { + mpm::Particle::map_mass_momentum_to_nodes(); + this->map_liquid_mass_momentum_to_nodes(); +} + +//! Map liquid mass and momentum to nodes +template +void mpm::TwoPhaseParticle::map_liquid_mass_momentum_to_nodes() noexcept { + // Check if liquid mass is set and positive + assert(liquid_mass_ != std::numeric_limits::max()); + + // Map liquid mass and momentum to nodes 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]; + nodes_[i]->update_mass(true, mpm::ParticlePhase::Liquid, + liquid_mass_ * shapefn_[i]); + nodes_[i]->update_momentum(true, mpm::ParticlePhase::Liquid, + liquid_mass_ * shapefn_[i] * liquid_velocity_); + } +} - force *= -1. * mpm::Particle<1>::volume(); +//! Compute pore pressure +template +void mpm::TwoPhaseParticle::compute_pore_pressure(double dt) noexcept { + // Check if liquid material and cell pointer are set and positive + assert(this->material(mpm::ParticlePhase::Liquid) != nullptr && + cell_ != nullptr); - nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Liquid, force); + // get the bulk modulus of liquid + double K = this->material(mpm::ParticlePhase::Liquid) + ->template property(std::string("bulk_modulus")); + + // Compute at centroid + // get liquid phase strain rate at cell centre + auto liquid_strain_rate_centroid = + this->compute_strain_rate(dn_dx_centroid_, mpm::ParticlePhase::Liquid); + + // update pressure + this->pore_pressure_ += + -dt * (K / porosity_) * + ((1 - porosity_) * strain_rate_.head(Tdim).sum() + + porosity_ * liquid_strain_rate_centroid.head(Tdim).sum()); + + // Apply free surface + // if (this->free_surface()) this->pore_pressure_ = 0.0; +} + +// Compute pore liquid pressure smoothing based on nodal pressure +template +bool mpm::TwoPhaseParticle::compute_pore_pressure_smoothing() noexcept { + // Check if particle has a valid cell ptr + assert(cell_ != nullptr); + + bool status = true; + double pressure = 0; + for (unsigned i = 0; i < nodes_.size(); ++i) + pressure += shapefn_(i) * nodes_[i]->pressure(mpm::ParticlePhase::Liquid); + + // Update pore liquid pressure to interpolated nodal pressure + this->pore_pressure_ = pressure; + // Apply free surface + // if (this->free_surface()) this->pore_pressure_ = 0.0; + return status; +} + +//! Map body force for both mixture and liquid +template +void mpm::TwoPhaseParticle::map_body_force( + const VectorDim& pgravity) noexcept { + this->map_mixture_body_force(mpm::ParticlePhase::Mixture, pgravity); + this->map_liquid_body_force(pgravity); +} + +//! Map liquid phase body force +template +void mpm::TwoPhaseParticle::map_liquid_body_force( + const VectorDim& pgravity) noexcept { + // Compute nodal liquid body forces + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->update_external_force( + true, mpm::ParticlePhase::Liquid, + (pgravity * this->liquid_mass_ * shapefn_(i))); +} + +//! Map mixture body force +template +void mpm::TwoPhaseParticle::map_mixture_body_force( + unsigned mixture, const VectorDim& pgravity) noexcept { + // Compute nodal mixture body forces + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->update_external_force( + true, mixture, + (pgravity * (this->liquid_mass_ + this->mass_) * shapefn_(i))); +} + +//! Map traction force +template +void mpm::TwoPhaseParticle::map_traction_force() noexcept { + this->map_mixture_traction_force(mpm::ParticlePhase::Mixture); +} + +//! Map liquid traction force +template +void mpm::TwoPhaseParticle::map_liquid_traction_force() noexcept { + if (this->set_liquid_traction_) { + // Map particle liquid traction forces to nodes + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->update_external_force( + true, mpm::ParticlePhase::Liquid, + (-1. * shapefn_[i] * porosity_ * this->liquid_traction_)); } +} - // Map liquid internal force - // Initialise a vector of pore pressure +//! Map mixture traction force +template +void mpm::TwoPhaseParticle::map_mixture_traction_force( + unsigned mixture) noexcept { + if (this->set_mixture_traction_) { + // Map particle mixture traction forces to nodes + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->update_external_force(true, mixture, + (shapefn_[i] * this->mixture_traction_)); + } +} + +//! Map both mixture and liquid internal force +template +inline void mpm::TwoPhaseParticle::map_internal_force() noexcept { + mpm::TwoPhaseParticle::map_mixture_internal_force( + mpm::ParticlePhase::Mixture); + mpm::TwoPhaseParticle::map_liquid_internal_force(); +} + +//! Map liquid phase internal force +template <> +void mpm::TwoPhaseParticle<2>::map_liquid_internal_force() noexcept { + // initialise a vector of pore pressure Eigen::Matrix pressure; pressure.setZero(); - pressure(0) = -scalar_properties_.at(mpm::properties::Scalar::PorePressure); - pressure(1) = -scalar_properties_.at(mpm::properties::Scalar::PorePressure); + pressure(0) = -this->pore_pressure_; + pressure(1) = -this->pore_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) * pressure[0] * this->porosity(); + Eigen::Matrix force; + force[0] = dn_dx_(i, 0) * pressure[0] * this->porosity_; + force[1] = dn_dx_(i, 1) * pressure[1] * this->porosity_; - force *= -1. * mpm::Particle<1>::volume(); + force *= -1. * this->volume_; nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Liquid, force); } } -//! Map both mixture and liquid internal force template <> -inline void mpm::TwoPhaseParticle<2>::map_internal_force() noexcept { - // Map mixture internal force - // Initialise a vector of pore pressure - Eigen::Matrix total_stress = this->stress_; - total_stress(0) -= - scalar_properties_.at(mpm::properties::Scalar::PorePressure); - total_stress(1) -= - scalar_properties_.at(mpm::properties::Scalar::PorePressure); +void mpm::TwoPhaseParticle<3>::map_liquid_internal_force() noexcept { + // initialise a vector of pore pressure + Eigen::Matrix pressure; + pressure.setZero(); + pressure(0) = -this->pore_pressure_; + pressure(1) = -this->pore_pressure_; + pressure(2) = -this->pore_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]; + Eigen::Matrix force; + force[0] = dn_dx_(i, 0) * pressure[0] * this->porosity_; + force[1] = dn_dx_(i, 1) * pressure[1] * this->porosity_; + force[2] = dn_dx_(i, 2) * pressure[2] * this->porosity_; - force *= -1. * mpm::Particle<2>::volume(); + force *= -1. * this->volume_; nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Liquid, force); } +} + +//! Map mixture internal force +template <> +void mpm::TwoPhaseParticle<2>::map_mixture_internal_force( + unsigned mixture) noexcept { + // initialise a vector of pore pressure + Eigen::Matrix total_stress = this->stress_; + total_stress(0) -= this->pore_pressure_; + total_stress(1) -= this->pore_pressure_; - // Map liquid internal force - // Initialise a vector of pore pressure - Eigen::Matrix pressure; - pressure.setZero(); - pressure(0) = -scalar_properties_.at(mpm::properties::Scalar::PorePressure); - pressure(1) = -scalar_properties_.at(mpm::properties::Scalar::PorePressure); // 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) * pressure[0] * this->porosity(); - force[1] = dn_dx_(i, 1) * pressure[1] * this->porosity(); + 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. * mpm::Particle<2>::volume(); + force *= -1. * this->volume_; - nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Liquid, force); + nodes_[i]->update_internal_force(true, mixture, force); } } -//! Map both mixture and liquid internal force template <> -inline void mpm::TwoPhaseParticle<3>::map_internal_force() noexcept { - // Map mixture internal force - // Initialise a vector of pore pressure +void mpm::TwoPhaseParticle<3>::map_mixture_internal_force( + unsigned mixture) noexcept { + // initialise a vector of pore pressure Eigen::Matrix total_stress = this->stress_; - total_stress(0) -= - scalar_properties_.at(mpm::properties::Scalar::PorePressure); - total_stress(1) -= - scalar_properties_.at(mpm::properties::Scalar::PorePressure); - total_stress(2) -= - scalar_properties_.at(mpm::properties::Scalar::PorePressure); + total_stress(0) -= this->pore_pressure_; + total_stress(1) -= this->pore_pressure_; + total_stress(2) -= this->pore_pressure_; + // Compute nodal internal forces for (unsigned i = 0; i < nodes_.size(); ++i) { // Compute force: -pstress * volume @@ -284,42 +477,86 @@ inline void mpm::TwoPhaseParticle<3>::map_internal_force() noexcept { 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. * mpm::Particle<3>::volume(); + force *= -1. * this->volume_; - nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Liquid, force); - } - - // Map liquid internal force - // Initialise a vector of pore pressure - Eigen::Matrix pressure; - pressure.setZero(); - pressure(0) = -scalar_properties_.at(mpm::properties::Scalar::PorePressure); - pressure(1) = -scalar_properties_.at(mpm::properties::Scalar::PorePressure); - pressure(2) = -scalar_properties_.at(mpm::properties::Scalar::PorePressure); - // 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) * pressure[0] * this->porosity(); - force[1] = dn_dx_(i, 1) * pressure[1] * this->porosity(); - force[2] = dn_dx_(i, 2) * pressure[2] * this->porosity(); - - force *= -1. * mpm::Particle<3>::volume(); - - nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Liquid, force); + nodes_[i]->update_internal_force(true, mixture, force); } } -// Compute updated position and velocities +// Compute updated position of the particle and kinematics of both solid and +// liquid phase template void mpm::TwoPhaseParticle::compute_updated_position( double dt, bool velocity_update) noexcept { - // Compute updated position mpm::Particle::compute_updated_position(dt, velocity_update); - // Compute updated liquid velocities this->compute_updated_liquid_velocity(dt, velocity_update); } +//! Map particle pressure to nodes +template +bool mpm::TwoPhaseParticle::map_pressure_to_nodes( + unsigned phase) noexcept { + // Mass is initialized + assert(mass_ != std::numeric_limits::max() && + liquid_mass_ != std::numeric_limits::max()); + + bool status = false; + if (phase == mpm::ParticlePhase::Solid) { + // Check if particle mass is set and state variable pressure is found + if (mass_ != std::numeric_limits::max() && + (state_variables_[phase].find("pressure") != + state_variables_[phase].end())) { + // Map particle pressure to nodes + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->update_mass_pressure( + phase, shapefn_[i] * mass_ * state_variables_[phase]["pressure"]); + + status = true; + } + } else { + // Map particle pore pressure to nodes + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->update_mass_pressure( + phase, shapefn_[i] * liquid_mass_ * this->pore_pressure_); + + status = true; + } + return status; +} + +// Compute pressure smoothing of the particle based on nodal pressure +template +bool mpm::TwoPhaseParticle::compute_pressure_smoothing( + unsigned phase) noexcept { + // Assert + assert(cell_ != nullptr); + + bool status = false; + if (phase == mpm::ParticlePhase::Solid) { + // Check if particle has a valid cell ptr + if (cell_ != nullptr && (state_variables_[phase].find("pressure") != + state_variables_[phase].end())) { + + double pressure = 0.; + // Update particle pressure to interpolated nodal pressure + for (unsigned i = 0; i < this->nodes_.size(); ++i) + pressure += shapefn_[i] * nodes_[i]->pressure(phase); + + state_variables_[phase]["pressure"] = pressure; + status = true; + } + } else { + double pressure = 0.; + // Update particle pressure to interpolated nodal pressure + for (unsigned i = 0; i < this->nodes_.size(); ++i) + pressure += shapefn_[i] * nodes_[i]->pressure(phase); + + this->pore_pressure_ = pressure; + status = true; + } + return status; +} + // Compute updated velocity of the liquid phase based on nodal velocity template void mpm::TwoPhaseParticle::compute_updated_liquid_velocity( @@ -337,8 +574,7 @@ void mpm::TwoPhaseParticle::compute_updated_liquid_velocity( shapefn_(i) * nodes_[i]->acceleration(mpm::ParticlePhase::Liquid); // Update particle velocity from interpolated nodal acceleration - vector_properties_.at(mpm::properties::Vector::LiquidVelocity) += - acceleration * dt; + this->liquid_velocity_ += acceleration * dt; } else { // Get interpolated nodal velocity Eigen::Matrix velocity; @@ -348,13 +584,36 @@ void mpm::TwoPhaseParticle::compute_updated_liquid_velocity( velocity += shapefn_(i) * nodes_[i]->velocity(mpm::ParticlePhase::Liquid); // Update particle velocity to interpolated nodal velocity - vector_properties_.at(mpm::properties::Vector::LiquidVelocity) = velocity; + this->liquid_velocity_ = velocity; } // Apply particle velocity constraints this->apply_particle_liquid_velocity_constraints(); } +//! Assign particle liquid phase velocity constraint +//! Constrain directions can take values between 0 and Dim +template +bool mpm::TwoPhaseParticle::assign_particle_liquid_velocity_constraint( + unsigned dir, double velocity) { + bool status = true; + try { + //! Constrain directions can take values between 0 and Dim + if (dir < Tdim) + this->liquid_velocity_constraints_.insert( + std::make_pair(static_cast(dir), + static_cast(velocity))); + else + throw std::runtime_error( + "Particle liquid velocity constraint direction is out of bounds"); + + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + //! Apply particle velocity constraints template void mpm::TwoPhaseParticle::apply_particle_liquid_velocity_constraints() { @@ -364,41 +623,38 @@ void mpm::TwoPhaseParticle::apply_particle_liquid_velocity_constraints() { const unsigned dir = constraint.first; // Direction: dir % Tdim (modulus) const auto direction = static_cast(dir % Tdim); - vector_properties_.at(mpm::properties::Vector::LiquidVelocity)(direction) = - constraint.second; + this->liquid_velocity_(direction) = constraint.second; } } -//! Map liquid traction force +//! Assign particle pressure constraints template -void mpm::TwoPhaseParticle::map_liquid_traction_force() noexcept { - if (this->set_liquid_traction_) { - // Map particle liquid traction forces to nodes - for (unsigned i = 0; i < nodes_.size(); ++i) - nodes_[i]->update_external_force( - true, mpm::ParticlePhase::Liquid, - (-1. * shapefn_[i] * this->porosity() * this->liquid_traction_)); +bool mpm::TwoPhaseParticle::assign_particle_pore_pressure_constraint( + double pressure) { + bool status = true; + try { + this->pore_pressure_constraint_ = pressure; + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; } + return status; } -//---------------------------------------------------------------------------- -//! TODO -// Assign traction to the liquid phase +// Assign porosity to the particle template -bool mpm::TwoPhaseParticle::assign_liquid_traction(unsigned direction, - double traction) { - bool status = false; +bool mpm::TwoPhaseParticle::assign_porosity() { + bool status = true; try { - if (direction >= Tdim || - mpm::Particle::volume() == std::numeric_limits::max()) { - throw std::runtime_error( - "Particle liquid traction property: volume / direction is invalid"); + if (this->material() != nullptr) { + this->porosity_ = + this->material()->template property(std::string("porosity")); + if (porosity_ < 0. || porosity_ > 1.) + throw std::runtime_error( + "Particle porosity is negative or larger than one"); + } else { + throw std::runtime_error("Material is invalid"); } - // Assign liquid traction - liquid_traction_(direction) = - traction * mpm::Particle::volume() / this->size_(direction); - status = true; - this->set_liquid_traction_ = true; } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); status = false; @@ -406,75 +662,155 @@ bool mpm::TwoPhaseParticle::assign_liquid_traction(unsigned direction, return status; } -//! Compute pore pressure (compressible fluid) +//! Assign particle permeability template -void mpm::TwoPhaseParticle::compute_pore_pressure(double dt) noexcept { - // Check if liquid material and cell pointer are set and positive - assert(material_.at(mpm::ParticlePhase::Liquid) != nullptr && - cell_ != nullptr); - // Apply free surface - if (this->free_surface()) - scalar_properties_.at(mpm::properties::Scalar::PorePressure) = 0.0; - // Compute pore pressure - else { - // get the bulk modulus of liquid - double K = material_.at(mpm::ParticlePhase::Liquid) - ->template property(std::string("bulk_modulus")); - // Compute strain rate of liquid phase at centroid - auto liquid_strain_rate_centroid = mpm::Particle::compute_strain_rate( - dn_dx_centroid_, mpm::ParticlePhase::Liquid); - // update pressure - scalar_properties_.at(mpm::properties::Scalar::PorePressure) += - -dt * (K / this->scalar_property(mpm::properties::Scalar::Porosity)) * - ((1 - this->scalar_property(mpm::properties::Scalar::Porosity)) * - strain_rate_.head(Tdim).sum() + - this->scalar_property(mpm::properties::Scalar::Porosity) * - liquid_strain_rate_centroid.head(Tdim).sum()); +bool mpm::TwoPhaseParticle::assign_permeability() { + bool status = true; + try { + // Check if material ptr is valid + if (this->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) = this->material()->template property("k_x"); + c1_(0) = permeability_(0) / k_p; + break; + } + case (2): { + permeability_(0) = this->material()->template property("k_x"); + permeability_(1) = this->material()->template property("k_y"); + c1_(0) = permeability_(0) / k_p; + c1_(1) = permeability_(1) / k_p; + break; + } + default: { + permeability_(0) = this->material()->template property("k_x"); + permeability_(1) = this->material()->template property("k_y"); + permeability_(2) = this->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; } -// Compute pore liquid pressure smoothing based on nodal pressure +//! Update particle permeability template -bool mpm::TwoPhaseParticle::compute_pore_pressure_smoothing() noexcept { - // Check if particle has a valid cell ptr - assert(cell_ != nullptr); +bool mpm::TwoPhaseParticle::update_permeability() { + bool status = true; + try { + // Porosity parameter + const double k_p = + std::pow(this->porosity_, 3) / std::pow((1. - this->porosity_), 2); - bool status = false; - // Check if particle has a valid cell ptr - if (cell_ != nullptr) { - // Apply free surface - if (this->free_surface()) - scalar_properties_.at(mpm::properties::Scalar::PorePressure) = 0.0; - // Compute particle pore pressure from nodal values - else { - double pore_pressure = 0; - for (unsigned i = 0; i < nodes_.size(); ++i) - pore_pressure += - shapefn_(i) * nodes_[i]->pressure(mpm::ParticlePhase::Liquid); - // Update pore liquid pressure to interpolated nodal pressure - scalar_properties_.at(mpm::properties::Scalar::PorePressure) = - pore_pressure; + // 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::TwoPhaseParticle::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 * + this->material(mpm::ParticlePhase::Liquid) + ->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; } -//! Assign particle liquid phase velocity constraint -//! Constrain directions can take values between 0 and Dim +//! Initial pore pressure template -bool mpm::TwoPhaseParticle::assign_particle_liquid_velocity_constraint( - unsigned dir, double velocity) { +bool mpm::TwoPhaseParticle::initialise_pore_pressure_watertable( + const unsigned dir_v, const unsigned dir_h, + std::map& refernece_points) { bool status = true; try { - //! Constrain directions can take values between 0 and Dim - if (dir < Tdim) - this->liquid_velocity_constraints_.insert( - std::make_pair(static_cast(dir), - static_cast(velocity))); + // Initialise left boundary position (coordinate) and h0 + double left_boundary = std::numeric_limits::lowest(); + double h0_left = 0.; + // Initialise right boundary position (coordinate) and h0 + double right_boundary = std::numeric_limits::max(); + double h0_right = 0.; + // Position and h0 of particle (coordinate) + const double position = this->coordinates_(dir_h); + // Iterate over each refernece_points + for (const auto& refernece_point : refernece_points) { + // Find boundary + if (refernece_point.first > left_boundary && + refernece_point.first <= position) { + // Left boundary position and h0 + left_boundary = refernece_point.first; + h0_left = refernece_point.second; + } else if (refernece_point.first > position && + refernece_point.first <= right_boundary) { + // Right boundary position and h0 + right_boundary = refernece_point.first; + h0_right = refernece_point.second; + } + } + + if (left_boundary != std::numeric_limits::lowest()) { + // Particle with left and right boundary + if (right_boundary != std::numeric_limits::max()) { + this->pore_pressure_ = + ((h0_right - h0_left) / (right_boundary - left_boundary) * + (position - left_boundary) + + h0_left - this->coordinates_(dir_v)) * + 1000 * 9.81; + } else + // Particle with only left boundary + this->pore_pressure_ = + (h0_left - this->coordinates_(dir_v)) * 1000 * 9.81; + } + // Particle with only right boundary + else if (right_boundary != std::numeric_limits::max()) + this->pore_pressure_ = + (h0_right - this->coordinates_(dir_v)) * 1000 * 9.81; + else throw std::runtime_error( - "Particle liquid velocity constraint direction is out of bounds"); - + "Particle pore pressure can not be initialised by water table"); } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); status = false; @@ -482,14 +818,21 @@ bool mpm::TwoPhaseParticle::assign_particle_liquid_velocity_constraint( return status; } -//! Assign particle pressure constraints -//! TODO +// Update material point porosity template -bool mpm::TwoPhaseParticle::assign_particle_pore_pressure_constraint( - double pressure) { +bool mpm::TwoPhaseParticle::update_porosity(double dt) { bool status = true; try { - this->pore_pressure_constraint_ = pressure; + // Update particle porosity + const double porosity = + 1 - (1 - this->porosity_) / (1 + dt * strain_rate_.head(Tdim).sum()); + // Check if the value is valid + if (porosity > 0 && porosity < 1) this->porosity_ = porosity; + // Invalid value + else + throw std::runtime_error( + "Invalid porosity, less than zero or greater than one"); + } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); status = false; diff --git a/include/particles/twophase_particle_functions.tcc b/include/particles/twophase_particle_functions.tcc deleted file mode 100644 index 5d83f4e67..000000000 --- a/include/particles/twophase_particle_functions.tcc +++ /dev/null @@ -1,253 +0,0 @@ -namespace mpm { -namespace twophaseparticle { - -// Assign particle porosity -template -void assign_porosity(std::shared_ptr> particle) { - // Check if material ptr is valid - if (particle->material() != nullptr) { - double porosity = particle->material()->template property( - std::string("porosity")); - - // Check if the porosity value is valid - if (porosity < 0. || porosity > 1.) - throw std::runtime_error( - "Particle porosity is negative or larger than one"); - - // Update porosity - particle->update_scalar_property(mpm::properties::Scalar::Porosity, false, - porosity); - } else { - throw std::runtime_error("Material is invalid, could not assign porosity"); - } -} - -//! Assign particle permeability -template -void assign_permeability(std::shared_ptr> particle) { - - // Check if material ptr is valid - if (particle->material() != nullptr) { - // Porosity parameter k_p - const double k_p = - std::pow(particle->scalar_property(mpm::properties::Scalar::Porosity), - 3) / - std::pow( - (1. - particle->scalar_property(mpm::properties::Scalar::Porosity)), - 2); - // Initialise permeability vector - Eigen::Matrix permeability; - permeability.setZero(); - - // Different dimensions permeability - switch (Tdim) { - case (1): { - permeability(0) = - particle->material()->template property("k_x") / k_p; - break; - } - case (2): { - permeability(0) = - particle->material()->template property("k_x") / k_p; - permeability(1) = - particle->material()->template property("k_y") / k_p; - - break; - } - default: { - permeability(0) = - particle->material()->template property("k_x") / k_p; - permeability(1) = - particle->material()->template property("k_y") / k_p; - permeability(2) = - particle->material()->template property("k_z") / k_p; - break; - } - } - // Assign permeability vector - particle->update_vector_property(mpm::properties::Vector::Permeability, - false, permeability); - } else { - throw std::runtime_error( - "Material is invalid, could not assign permeability"); - } -} - -// Compute particle mass for two phase -template -void compute_mass(std::shared_ptr> particle) noexcept { - // Check if particle volume is set and material ptr is valid - assert(particle->volume() != std::numeric_limits::max() && - particle->material() != nullptr); - - // Mass = volume of particle * mass_density - // Solid density - particle->update_scalar_property( - mpm::properties::Scalar::MassDensity, false, - particle->material()->template property(std::string("density"))); - - // Update particle solid mass - particle->update_scalar_property( - mpm::properties::Scalar::Mass, false, - (1 - particle->scalar_property(mpm::properties::Scalar::Porosity)) * - particle->volume() * particle->mass_density()); - - // Update particle water mass - particle->update_scalar_property( - mpm::properties::Scalar::LiquidMass, false, - particle->scalar_property(mpm::properties::Scalar::Porosity) * - particle->volume() * - particle->scalar_property( - mpm::properties::Scalar::LiquidMassDensity)); -} - -//! Map liquid mass and momentum to nodes -template -void map_mass_momentum_to_nodes( - std::shared_ptr> particle) noexcept { - // Check if particle mass is set - assert(particle->mass() != std::numeric_limits::max()); - - // Map solid mass and momentum to nodes - particle->map_scalar_property_to_nodes(mpm::properties::Scalar::Mass, true, - mpm::ParticlePhase::Solid); - particle->map_vector_property_to_nodes( - mpm::properties::Vector::Momentum, true, mpm::ParticlePhase::Solid, - particle->mass() * particle->velocity()); - - // Check if particle mass is set - assert(particle->scalar_property(mpm::properties::Scalar::LiquidMass) != - std::numeric_limits::max()); - - // Map liquid mass and momentum to nodes - particle->map_scalar_property_to_nodes( - mpm::properties::Scalar::Mass, true, mpm::ParticlePhase::Liquid, - particle->scalar_property(mpm::properties::Scalar::LiquidMass)); - particle->map_vector_property_to_nodes( - mpm::properties::Vector::Momentum, true, mpm::ParticlePhase::Liquid, - particle->scalar_property(mpm::properties::Scalar::LiquidMass) * - particle->vector_property(mpm::properties::Vector::LiquidVelocity)); -} - -//! Map body force for both mixture and liquid -template -void map_body_force(std::shared_ptr> particle, - const Eigen::Matrix& pgravity) noexcept { - //! Map body force for mixture - particle->map_vector_property_to_nodes( - mpm::properties::Vector::ExternalForce, true, mpm::ParticlePhase::Mixture, - pgravity * (particle->mass() + particle->scalar_property( - mpm::properties::Scalar::LiquidMass))); - //! Map body force for liquid - particle->map_vector_property_to_nodes( - mpm::properties::Vector::ExternalForce, true, mpm::ParticlePhase::Liquid, - pgravity * - particle->scalar_property(mpm::properties::Scalar::LiquidMass)); -} - -//! Map drag force coefficient -template -void map_drag_force_coefficient( - std::shared_ptr> particle) { - // Update permeability - auto permeability = - particle->vector_property(mpm::properties::Vector::Permeability) * - std::pow(particle->scalar_property(mpm::properties::Scalar::Porosity), - 3) / - std::pow( - (1. - particle->scalar_property(mpm::properties::Scalar::Porosity)), - 2); - // Initialise drag force coefficient - Eigen::Matrix drag_force_coefficient; - drag_force_coefficient.setZero(); - - // Check if permeability coefficient is valid - for (unsigned i = 0; i < Tdim; ++i) { - drag_force_coefficient(i) = - std::pow(particle->scalar_property(mpm::properties::Scalar::Porosity), - 2) * - 9.81 * - particle->scalar_property(mpm::properties::Scalar::LiquidMassDensity) / - permeability(i); - } - - particle->map_vector_property_to_nodes( - mpm::properties::Vector::DragForce, true, mpm::ParticlePhase::Solid, - drag_force_coefficient * particle->volume()); -} - -// Update particle porosity -template -void update_porosity(std::shared_ptr> particle, - double dt) { - // Update particle porosity - double porosity = - 1 - (1 - particle->scalar_property(mpm::properties::Scalar::Porosity)) / - (1 + dt * particle->strain_rate().head(Tdim).sum()); - // Check if the value is valid - if (porosity < 0) porosity = 1E-5; - if (porosity < 1) porosity = 1 - 1E-5; - - // Assign new particle porosity - particle->update_scalar_property(mpm::properties::Scalar::Porosity, false, - porosity); -} - -//! Initial pore pressure by water table -template -void initialise_pore_pressure_watertable( - const unsigned dir_v, const unsigned dir_h, - std::map& refernece_points, - std::shared_ptr> particle) { - // Initialise left boundary position (coordinate) and h0 - double left_boundary = std::numeric_limits::lowest(); - double h0_left = 0.; - // Initialise right boundary position (coordinate) and h0 - double right_boundary = std::numeric_limits::max(); - double h0_right = 0.; - // Position and h0 of particle (coordinate) - const double position = particle->coordinates().at(dir_h); - // Iterate over each refernece_points - for (const auto& refernece_point : refernece_points) { - // Find boundary - if (refernece_point.first > left_boundary && - refernece_point.first <= position) { - // Left boundary position and h0 - left_boundary = refernece_point.first; - h0_left = refernece_point.second; - } else if (refernece_point.first > position && - refernece_point.first <= right_boundary) { - // Right boundary position and h0 - right_boundary = refernece_point.first; - h0_right = refernece_point.second; - } - } - // Check if the boundaries are assigned - if (left_boundary != std::numeric_limits::lowest()) { - // Particle with left and right boundary - if (right_boundary != std::numeric_limits::max()) { - particle->update_scalar_property( - mpm::properties::Scalar::LiquidMassDensity, false, - ((h0_right - h0_left) / (right_boundary - left_boundary) * - (position - left_boundary) + - h0_left - particle->coordinates_(dir_v)) * - 1000 * 9.81); - } else - // Particle with only left boundary - particle->update_scalar_property( - mpm::properties::Scalar::LiquidMassDensity, false, - (h0_left - particle->coordinates_(dir_v)) * 1000 * 9.81); - } - // Particle with only right boundary - else if (right_boundary != std::numeric_limits::max()) - particle->update_scalar_property( - mpm::properties::Scalar::LiquidMassDensity, false, - (h0_right - particle->coordinates_(dir_v)) * 1000 * 9.81); - - else - throw std::runtime_error( - "Particle pore pressure can not be initialised by water table"); -} - -} // namespace twophaseparticle -} // namespace mpm \ No newline at end of file diff --git a/include/solvers/mpm_base.h b/include/solvers/mpm_base.h index ca017f1fc..1bb3aa248 100644 --- a/include/solvers/mpm_base.h +++ b/include/solvers/mpm_base.h @@ -116,6 +116,12 @@ class MPMBase : public MPM { void nodal_frictional_constraints( const Json& mesh_prop, const std::shared_ptr>& mesh_io); + //! Nodal pore pressure constraints + //! \param[in] mesh_prop Mesh properties + //! \param[in] mesh_io Mesh IO handle + void nodal_pore_pressure_constraints( + const Json& mesh_prop, const std::shared_ptr>& mesh_io); + //! Cell entity sets //! \param[in] mesh_prop Mesh properties //! \param[in] check Check duplicates @@ -147,6 +153,13 @@ class MPMBase : public MPM { const Json& mesh_prop, const std::shared_ptr>& particle_io); + // Particles pore pressures + //! \param[in] mesh_prop Mesh properties + //! \param[in] particle_io Particle IO handle + void particles_pore_pressures( + const Json& mesh_prop, + const std::shared_ptr>& particle_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 65d5031da..eb6a1c571 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -184,6 +184,9 @@ bool mpm::MPMBase::initialise_mesh() { // Read and assign friction constraints this->nodal_frictional_constraints(mesh_props, mesh_io); + // Read and assign pore pressure constraints + this->nodal_pore_pressure_constraints(mesh_props, mesh_io); + // Initialise cell auto cells_begin = std::chrono::steady_clock::now(); // Shape function name @@ -300,10 +303,8 @@ bool mpm::MPMBase::initialise_particles() { auto particles_volume_begin = std::chrono::steady_clock::now(); // Compute volume - mesh_->iterate_over_particles( - [](std::shared_ptr> ptr) { - return mpm::particle::compute_volume(ptr); - }); + mesh_->iterate_over_particles(std::bind( + &mpm::ParticleBase::compute_volume, std::placeholders::_1)); // Read and assign particles volumes this->particles_volumes(mesh_props, particle_io); @@ -311,6 +312,9 @@ bool mpm::MPMBase::initialise_particles() { // Read and assign particles stresses this->particles_stresses(mesh_props, particle_io); + // Read and assign particles initial pore pressure + this->particles_pore_pressures(mesh_props, particle_io); + auto particles_volume_end = std::chrono::steady_clock::now(); console_->info("Rank {} Read volume, velocity and stresses: {} ms", mpi_rank, @@ -508,7 +512,8 @@ void mpm::MPMBase::write_vtk(mpm::Index step, mpm::Index max_steps) { #endif //! VTK vector variables - std::vector vtk_vector_data = {"displacements", "velocities"}; + std::vector vtk_vector_data = {"displacements", "velocities", + "pore_pressure"}; // Write VTK attributes for (const auto& attribute : vtk_vector_data) { @@ -906,6 +911,77 @@ void mpm::MPMBase::nodal_frictional_constraints( } } +// Nodal pore pressure constraints (Coupled solid-fluid formulation) +template +void mpm::MPMBase::nodal_pore_pressure_constraints( + const Json& mesh_props, const std::shared_ptr>& mesh_io) { + try { + // Water phase indice + const unsigned phase = mpm::ParticlePhase::Liquid; + // Total phase + const unsigned Tnphases = 2; + + // Read and assign pore pressure constraints + if (mesh_props.find("boundary_conditions") != mesh_props.end() && + mesh_props["boundary_conditions"].find("pore_pressure_constraints") != + mesh_props["boundary_conditions"].end()) { + + // Iterate over pore pressure constraints + for (const auto& constraints : + mesh_props["boundary_conditions"]["pore_pressure_constraints"]) { + // Pore pressure constraint phase indice + unsigned constraint_phase = phase; + + // Check if it is pressure increment constraints + if (constraints.find("increment_boundary") != constraints.end() && + constraints["increment_boundary"]) + constraint_phase += Tnphases; + + // Pore pressure constraints are specified in a file + if (constraints.find("file") != constraints.end()) { + std::string pore_pressure_constraints_file = + constraints.at("file").template get(); + bool ppressure_constraints = mesh_->assign_nodal_pressure_constraints( + constraint_phase, + mesh_io->read_pressure_constraints( + io_->file_name(pore_pressure_constraints_file))); + if (!ppressure_constraints) + throw std::runtime_error( + "Pore 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(); + // Pore Pressure + double pore_pressure = + constraints.at("pore_pressure").template get(); + // Add pore pressure constraint to mesh + mesh_->assign_nodal_pressure_constraint( + pfunction, nset_id, constraint_phase, pore_pressure); + // if (constraint_phase >= Tnphases) { + // // Reference step + // const Index ref_step = + // constraints.at("ref_step").template get(); + // // Add reference step to nodes + // mesh_->assign_nodal_pressure_reference_step(nset_id, ref_step); + // // Insert the ref_step to the vector + // pore_pressure_ref_step_.emplace_back(ref_step); + // } + } + } + } else + throw std::runtime_error("Pore pressure constraints JSON not found"); + + } catch (std::exception& exception) { + console_->warn("#{}: Pore pressure conditions are undefined {} ", __LINE__, + exception.what()); + } +} + //! Cell entity sets template void mpm::MPMBase::cell_entity_sets(const Json& mesh_props, @@ -1049,6 +1125,66 @@ void mpm::MPMBase::particles_stresses( } } +// Particles pore pressures +template +void mpm::MPMBase::particles_pore_pressures( + const Json& mesh_props, + const std::shared_ptr>& particle_io) { + try { + if (mesh_props.find("particles_pore_pressures") != mesh_props.end()) { + // Assign initial pore pressure by file + if (mesh_props["particles_pore_pressures"].find("file") != + mesh_props["particles_pore_pressures"].end()) { + std::string fparticles_pore_pressures = + mesh_props["particles_pore_pressures"]["file"] + .template get(); + if (!io_->file_name(fparticles_pore_pressures).empty()) { + + // Get pore pressures of all particles + const auto all_particles_pore_pressures = + particle_io->read_particles_pressures( + io_->file_name(fparticles_pore_pressures)); + + // Read and assign particles pore pressures + if (!mesh_->assign_particles_pore_pressures( + all_particles_pore_pressures)) + throw std::runtime_error( + "Particles pore pressures are not properly assigned"); + } else + throw std::runtime_error("Particle pore pressures JSON not found"); + + } else { + // Initialise water tables + std::map refernece_points; + // Vertical direction + const unsigned dir_v = mesh_props["particles_pore_pressures"]["dir_v"] + .template get(); + // Horizontal direction + const unsigned dir_h = mesh_props["particles_pore_pressures"]["dir_h"] + .template get(); + // Iterate over water tables + for (const auto& water_table : + mesh_props["particles_pore_pressures"]["water_tables"]) { + // Position coordinate + double position = water_table.at("position").template get(); + // Direction + double h0 = water_table.at("h0").template get(); + // Add refernece points to mesh + refernece_points.insert(std::make_pair( + static_cast(position), static_cast(h0))); + } + // Initialise particles pore pressures by watertable + mesh_->iterate_over_particles(std::bind( + &mpm::ParticleBase::initialise_pore_pressure_watertable, + std::placeholders::_1, dir_v, dir_h, refernece_points)); + } + } + } catch (std::exception& exception) { + console_->warn("#{}: Particle pore pressures are undefined {} ", __LINE__, + exception.what()); + } +} + //! Particle entity sets template void mpm::MPMBase::particle_entity_sets(const Json& mesh_props, @@ -1166,16 +1302,10 @@ void mpm::MPMBase::mpi_domain_decompose(bool initial_step) { //! MPM pressure smoothing template void mpm::MPMBase::pressure_smoothing(unsigned phase) { - // Assign mass pressure to nodes + // Assign pressure to nodes mesh_->iterate_over_particles( - [&phase = phase](std::shared_ptr> ptr) { - return mpm::particle::map_mass_pressure_to_nodes(ptr, phase); - }); - - // Compute nodal pressure - mesh_->iterate_over_nodes_predicate( - std::bind(&mpm::NodeBase::compute_pressure, std::placeholders::_1), - std::bind(&mpm::NodeBase::status, std::placeholders::_1)); + std::bind(&mpm::ParticleBase::map_pressure_to_nodes, + std::placeholders::_1, phase)); #ifdef USE_MPI int mpi_size = 1; @@ -1188,14 +1318,13 @@ void mpm::MPMBase::pressure_smoothing(unsigned phase) { // MPI all reduce nodal pressure mesh_->template nodal_halo_exchange( std::bind(&mpm::NodeBase::pressure, std::placeholders::_1, phase), - std::bind(&mpm::NodeBase::update_pressure, std::placeholders::_1, - false, phase, std::placeholders::_2)); + std::bind(&mpm::NodeBase::assign_pressure, std::placeholders::_1, + phase, std::placeholders::_2)); } #endif // Smooth pressure over particles mesh_->iterate_over_particles( - [&phase = phase](std::shared_ptr> ptr) { - return mpm::particle::compute_pressure_smoothing(ptr, phase); - }); + std::bind(&mpm::ParticleBase::compute_pressure_smoothing, + std::placeholders::_1, phase)); } diff --git a/include/solvers/mpm_explicit.h b/include/solvers/mpm_explicit.h index 2ff65e98e..47ae93446 100644 --- a/include/solvers/mpm_explicit.h +++ b/include/solvers/mpm_explicit.h @@ -35,7 +35,7 @@ class MPMExplicit : public MPMBase { using mpm::MPMBase::step_; //! Number of steps using mpm::MPMBase::nsteps_; - //! Load balance step + //! Number of steps using mpm::MPMBase::nload_balance_steps_; //! Output steps using mpm::MPMBase::output_steps_; diff --git a/include/solvers/mpm_explicit.tcc b/include/solvers/mpm_explicit.tcc index d72a1cede..67261d041 100644 --- a/include/solvers/mpm_explicit.tcc +++ b/include/solvers/mpm_explicit.tcc @@ -14,10 +14,8 @@ void mpm::MPMExplicit::compute_stress_strain(unsigned phase) { &mpm::ParticleBase::compute_strain, std::placeholders::_1, dt_)); // Iterate over each particle to update particle volume - mesh_->iterate_over_particles( - [](std::shared_ptr> ptr) { - return mpm::particle::update_volume(ptr); - }); + mesh_->iterate_over_particles(std::bind( + &mpm::ParticleBase::update_volume, std::placeholders::_1)); // Pressure smoothing if (pressure_smoothing_) this->pressure_smoothing(phase); @@ -95,9 +93,7 @@ bool mpm::MPMExplicit::solve() { // Compute mass mesh_->iterate_over_particles( - [](std::shared_ptr> ptr) { - return mpm::particle::compute_mass(ptr); - }); + std::bind(&mpm::ParticleBase::compute_mass, std::placeholders::_1)); // Check point resume if (resume) this->checkpoint_resume(); @@ -157,9 +153,8 @@ bool mpm::MPMExplicit::solve() { // Assign mass and momentum to nodes mesh_->iterate_over_particles( - [](std::shared_ptr> ptr) { - return mpm::particle::map_mass_momentum_to_nodes(ptr); - }); + std::bind(&mpm::ParticleBase::map_mass_momentum_to_nodes, + std::placeholders::_1)); #ifdef USE_MPI // Run if there is more than a single MPI task @@ -228,9 +223,8 @@ bool mpm::MPMExplicit::solve() { { // Iterate over each particle to compute nodal body force mesh_->iterate_over_particles( - [&value = gravity_](std::shared_ptr> ptr) { - return mpm::particle::map_body_force(ptr, value); - }); + 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_); diff --git a/include/solvers/mpm_explicit_twophase.h b/include/solvers/mpm_explicit_twophase.h index f7cf3850c..1706ee852 100644 --- a/include/solvers/mpm_explicit_twophase.h +++ b/include/solvers/mpm_explicit_twophase.h @@ -5,13 +5,13 @@ #include "graph.h" #endif -#include "mpm_base.h" +#include "solvers/mpm_base.h" namespace mpm { -//! MPMExplicitTwoPhase class -//! \brief A class that implements the fully explicit two phase mpm -//! \details A two-phase explicit MPM +//! MPMExplicit class +//! \brief A class that implements the fully explicit one phase mpm +//! \details A single-phase explicit MPM //! \tparam Tdim Dimension template class MPMExplicitTwoPhase : public MPMBase { @@ -34,7 +34,7 @@ class MPMExplicitTwoPhase : public MPMBase { using mpm::MPMBase::step_; //! Number of steps using mpm::MPMBase::nsteps_; - //! Load balance step + //! Number of steps using mpm::MPMBase::nload_balance_steps_; //! Output steps using mpm::MPMBase::output_steps_; @@ -52,8 +52,6 @@ class MPMExplicitTwoPhase : public MPMBase { using mpm::MPMBase::graph_; #endif - //! Stress update - using mpm::MPMBase::stress_update_; //! velocity update using mpm::MPMBase::velocity_update_; //! Gravity @@ -75,11 +73,13 @@ class MPMExplicitTwoPhase : public MPMBase { //! Pressure smoothing bool pressure_smoothing_{false}; //! Pore pressure smoothing - bool pore_pressure_smoothing_{true}; + bool pore_pressure_smoothing_{false}; + //! Volume tolerance for free surface + double volume_tolerance_{0}; -}; // MPMExplicitTwoPhase class +}; // MPMExplicit class } // namespace mpm #include "mpm_explicit_twophase.tcc" -#endif // MPM_MPM_EXPLICIT_TWOPHASE_H_ +#endif // MPM_MPM_EXPLICIT_H_ diff --git a/include/solvers/mpm_explicit_twophase.tcc b/include/solvers/mpm_explicit_twophase.tcc index 40e7b5b16..dd7953f75 100644 --- a/include/solvers/mpm_explicit_twophase.tcc +++ b/include/solvers/mpm_explicit_twophase.tcc @@ -7,43 +7,35 @@ mpm::MPMExplicitTwoPhase::MPMExplicitTwoPhase( console_ = spdlog::get("MPMExplicitTwoPhase"); } -//! MPM Explicit two-phase compute stress strain +//! MPM Explicit compute stress strain template void mpm::MPMExplicitTwoPhase::compute_stress_strain() { - // Iterate over each particle to calculate strain + // Iterate over each particle to calculate strain of soil_skeleton mesh_->iterate_over_particles(std::bind( &mpm::ParticleBase::compute_strain, std::placeholders::_1, dt_)); - // Iterate over each particle to update particle volume - mesh_->iterate_over_particles( - [](std::shared_ptr> ptr) { - return mpm::particle::update_volume(ptr); - }); - - // Iterate over each particle to update particle porosity - mesh_->iterate_over_particles( - [&dt = dt_](std::shared_ptr> ptr) { - return mpm::twophaseparticle::update_porosity(ptr, dt); - }); - - // Pressure smoothing - if (pressure_smoothing_) this->pressure_smoothing(mpm::ParticlePhase::Solid); - - // Iterate over each particle to compute stress + mesh_->iterate_over_particles(std::bind( + &mpm::ParticleBase::update_volume, std::placeholders::_1)); + // Iterate over each particle to update porosity + mesh_->iterate_over_particles(std::bind( + &mpm::ParticleBase::update_porosity, std::placeholders::_1, dt_)); + // Iterate over each particle to compute stress of soil skeleton mesh_->iterate_over_particles(std::bind( &mpm::ParticleBase::compute_stress, std::placeholders::_1)); + // Pressure smoothing + if (pressure_smoothing_) this->pressure_smoothing(mpm::ParticlePhase::Solid); // Iterate over each particle to compute pore pressure mesh_->iterate_over_particles( std::bind(&mpm::ParticleBase::compute_pore_pressure, std::placeholders::_1, dt_)); - // Pore pressure smoothing - if (pore_pressure_smoothing_) + if (pore_pressure_smoothing_) { this->pressure_smoothing(mpm::ParticlePhase::Liquid); + } } -//! MPM Explicit two-phase solver +//! MPM Explicit solver template bool mpm::MPMExplicitTwoPhase::solve() { bool status = true; @@ -68,14 +60,15 @@ bool mpm::MPMExplicitTwoPhase::solve() { // Pressure smoothing if (analysis_.find("pressure_smoothing") != analysis_.end()) - pressure_smoothing_ = analysis_["pressure_smoothing"].template get(); + pressure_smoothing_ = + analysis_.at("pressure_smoothing").template get(); // Pore pressure smoothing if (analysis_.find("pore_pressure_smoothing") != analysis_.end()) pore_pressure_smoothing_ = - analysis_["pore_pressure_smoothing"].template get(); + analysis_.at("pore_pressure_smoothing").template get(); - // Initialise materials + // Initialise material bool mat_status = this->initialise_materials(); if (!mat_status) { status = false; @@ -100,26 +93,20 @@ bool mpm::MPMExplicitTwoPhase::solve() { bool loading_status = this->initialise_loads(); if (!loading_status) { status = false; - throw std::runtime_error("Initialisation of loads failed"); + throw std::runtime_error("Initialisation of loading failed"); } // Assign porosity - mesh_->iterate_over_particles( - [](std::shared_ptr> ptr) { - return mpm::twophaseparticle::assign_porosity(ptr); - }); + mesh_->iterate_over_particles(std::bind( + &mpm::ParticleBase::assign_porosity, std::placeholders::_1)); // Assign permeability - mesh_->iterate_over_particles( - [](std::shared_ptr> ptr) { - return mpm::twophaseparticle::assign_permeability(ptr); - }); + mesh_->iterate_over_particles(std::bind( + &mpm::ParticleBase::assign_permeability, std::placeholders::_1)); // Compute mass for each phase mesh_->iterate_over_particles( - [](std::shared_ptr> ptr) { - return mpm::twophaseparticle::compute_mass(ptr); - }); + std::bind(&mpm::ParticleBase::compute_mass, std::placeholders::_1)); // Check point resume if (resume) this->checkpoint_resume(); @@ -142,6 +129,9 @@ bool mpm::MPMExplicitTwoPhase::solve() { #endif #endif + // Inject particles + mesh_->inject_particles(this->step_ * this->dt_); + #pragma omp parallel sections { // Spawn a task for initialising nodes and cells @@ -165,9 +155,8 @@ bool mpm::MPMExplicitTwoPhase::solve() { // Assign mass and momentum to nodes mesh_->iterate_over_particles( - [](std::shared_ptr> ptr) { - return mpm::twophaseparticle::map_mass_momentum_to_nodes(ptr); - }); + std::bind(&mpm::ParticleBase::map_mass_momentum_to_nodes, + std::placeholders::_1)); #ifdef USE_MPI // Run if there is more than a single MPI task @@ -197,7 +186,7 @@ bool mpm::MPMExplicitTwoPhase::solve() { std::bind(&mpm::NodeBase::momentum, std::placeholders::_1, mpm::ParticlePhase::Liquid), std::bind(&mpm::NodeBase::update_momentum, - std::placeholders::_1, false, mpm::ParticlePhase::Liquid, + std::placeholders::_1, false, mpm::ParticlePhase::Solid, std::placeholders::_2)); } #endif @@ -219,9 +208,8 @@ bool mpm::MPMExplicitTwoPhase::solve() { { // Iterate over each particle to compute nodal body force mesh_->iterate_over_particles( - [&value = gravity_](std::shared_ptr> ptr) { - return mpm::particle::map_body_force(ptr, value); - }); + 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_); @@ -242,13 +230,14 @@ bool mpm::MPMExplicitTwoPhase::solve() { mesh_->iterate_over_particles( std::bind(&mpm::ParticleBase::map_internal_force, std::placeholders::_1)); + } +#pragma omp section + { // Iterate over particles to compute nodal drag force coefficient mesh_->iterate_over_particles( - [](std::shared_ptr> ptr) { - return mpm::twophaseparticle::map_drag_force_coefficient( - ptr); - }); + std::bind(&mpm::ParticleBase::map_drag_force_coefficient, + std::placeholders::_1)); } } // Wait for tasks to finish @@ -258,40 +247,39 @@ bool mpm::MPMExplicitTwoPhase::solve() { // MPI all reduce external force of mixture mesh_->template nodal_halo_exchange, Tdim>( std::bind(&mpm::NodeBase::external_force, std::placeholders::_1, - mpm::ParticlePhase::Mixture), + mpm::NodePhase::nMixture), std::bind(&mpm::NodeBase::update_external_force, - std::placeholders::_1, false, mpm::ParticlePhase::Mixture, + std::placeholders::_1, false, mpm::NodePhase::nMixture, std::placeholders::_2)); // MPI all reduce external force of pore fluid mesh_->template nodal_halo_exchange, Tdim>( std::bind(&mpm::NodeBase::external_force, std::placeholders::_1, - mpm::ParticlePhase::Liquid), + mpm::NodePhase::nLiquid), std::bind(&mpm::NodeBase::update_external_force, - std::placeholders::_1, false, mpm::ParticlePhase::Liquid, + std::placeholders::_1, false, mpm::NodePhase::nLiquid, std::placeholders::_2)); // MPI all reduce internal force of mixture mesh_->template nodal_halo_exchange, Tdim>( std::bind(&mpm::NodeBase::internal_force, std::placeholders::_1, - mpm::ParticlePhase::Mixture), + mpm::NodePhase::nMixture), std::bind(&mpm::NodeBase::update_internal_force, - std::placeholders::_1, false, mpm::ParticlePhase::Mixture, + std::placeholders::_1, false, mpm::NodePhase::nMixture, std::placeholders::_2)); // MPI all reduce internal force of pore liquid mesh_->template nodal_halo_exchange, Tdim>( std::bind(&mpm::NodeBase::internal_force, std::placeholders::_1, - mpm::ParticlePhase::Liquid), + mpm::NodePhase::nLiquid), std::bind(&mpm::NodeBase::update_internal_force, - std::placeholders::_1, false, mpm::ParticlePhase::Liquid, + std::placeholders::_1, false, mpm::NodePhase::nLiquid, std::placeholders::_2)); // MPI all reduce drag force mesh_->template nodal_halo_exchange, Tdim>( std::bind(&mpm::NodeBase::drag_force_coefficient, std::placeholders::_1), - std::bind(&mpm::NodeBase::update_vector_property, - std::placeholders::_1, mpm::properties::Vector::DragForce, - false, mpm::ParticlePhase::Solid, std::placeholders::_2)); + std::bind(&mpm::NodeBase::update_drag_force_coefficient, + std::placeholders::_1, false, std::placeholders::_2)); } #endif @@ -299,10 +287,11 @@ bool mpm::MPMExplicitTwoPhase::solve() { // active nodes to compute acceleratation and velocity if (damping_type_ == mpm::Damping::Cundall) mesh_->iterate_over_nodes_predicate( - std::bind(&mpm::NodeBase:: - compute_acceleration_velocity_twophase_explicit_cundall, - std::placeholders::_1, this->dt_, damping_factor_), + std::bind(&mpm::NodeBase< + Tdim>::compute_acceleration_velocity_twophase_explicit, + std::placeholders::_1, this->dt_), std::bind(&mpm::NodeBase::status, std::placeholders::_1)); + else mesh_->iterate_over_nodes_predicate( std::bind(&mpm::NodeBase< @@ -315,9 +304,6 @@ bool mpm::MPMExplicitTwoPhase::solve() { std::bind(&mpm::ParticleBase::compute_updated_position, std::placeholders::_1, this->dt_, velocity_update_)); - // Apply particle velocity constraints - mesh_->apply_particle_velocity_constraints(); - // Update Stress Last if (this->stress_update_ == mpm::StressUpdate::USL) this->compute_stress_strain(); @@ -353,7 +339,7 @@ bool mpm::MPMExplicitTwoPhase::solve() { } auto solver_end = std::chrono::steady_clock::now(); console_->info( - "Rank {}, ExplicitTwoPhase {} solver duration: {} ms", mpi_rank, + "Rank {}, Explicit {} solver duration: {} ms", mpi_rank, (this->stress_update_ == mpm::StressUpdate::USL ? "USL" : "USF"), std::chrono::duration_cast(solver_end - solver_begin) diff --git a/src/io/logger.cc b/src/io/logger.cc index 16e804077..652c2aab4 100644 --- a/src/io/logger.cc +++ b/src/io/logger.cc @@ -28,6 +28,11 @@ const std::shared_ptr mpm::Logger::mpm_base_logger = const std::shared_ptr mpm::Logger::mpm_explicit_logger = spdlog::stdout_color_st("MPMExplicit"); +// Create a logger for MPM Explicit Two Phase +const std::shared_ptr + mpm::Logger::mpm_explicit_two_phase_logger = + spdlog::stdout_color_st("MPMExplicitTwoPhase"); + // Create a logger for MPM Explicit USF const std::shared_ptr mpm::Logger::mpm_explicit_usf_logger = spdlog::stdout_color_st("MPMExplicitUSF"); @@ -35,8 +40,3 @@ 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 Explicit TwoPhase -const std::shared_ptr - mpm::Logger::mpm_explicit_twophase_logger = - spdlog::stdout_color_st("MPMExplicitTwoPhase"); \ No newline at end of file diff --git a/src/particle.cc b/src/particle.cc index 7770a8750..d5593d0ab 100644 --- a/src/particle.cc +++ b/src/particle.cc @@ -13,12 +13,12 @@ static Register, mpm::Particle<3>, mpm::Index, const Eigen::Matrix&> particle3d("P3D"); -// Two phase particle2D (2 Dim) +// Second phase particle2D (2 Dim) static Register, mpm::TwoPhaseParticle<2>, mpm::Index, const Eigen::Matrix&> particle2d2phase("P2D2PHASE"); -// Two phase particle3D (3 Dim) +// Second phase particle3D (3 Dim) static Register, mpm::TwoPhaseParticle<3>, mpm::Index, const Eigen::Matrix&> particle3d2phase("P3D2PHASE"); \ No newline at end of file From 46e0b67b12a7ed5e83dffd6c883875de93bf5a17 Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Wed, 29 Jul 2020 00:55:13 -0700 Subject: [PATCH 064/175] Fix some bug in the test --- .gitignore | 1 + tests/interface_test.cc | 6 +- tests/mesh_test_2d.cc | 5 +- tests/mesh_test_3d.cc | 5 +- tests/node_test.cc | 171 ++-------------- tests/particle_cell_crossing_test.cc | 32 ++- tests/particle_test.cc | 289 +++++++-------------------- 7 files changed, 115 insertions(+), 394 deletions(-) diff --git a/.gitignore b/.gitignore index 828560b3a..ee24fee34 100644 --- a/.gitignore +++ b/.gitignore @@ -76,3 +76,4 @@ configure.scan *missing *stamp-h1 benchmarks/ +bin/ diff --git a/tests/interface_test.cc b/tests/interface_test.cc index e9104e799..cb3b151d7 100644 --- a/tests/interface_test.cc +++ b/tests/interface_test.cc @@ -152,9 +152,9 @@ TEST_CASE("Interface functions are checked", "[interface]") { particle3->map_multimaterial_mass_momentum_to_nodes(); // Map masses and momenta from particles to nodes - mpm::particle::map_mass_momentum_to_nodes(particle1); - mpm::particle::map_mass_momentum_to_nodes(particle2); - mpm::particle::map_mass_momentum_to_nodes(particle3); + particle1->map_mass_momentum_to_nodes(); + particle2->map_mass_momentum_to_nodes(); + particle3->map_mass_momentum_to_nodes(); // Compute velocities at nodes node0->compute_velocity(); diff --git a/tests/mesh_test_2d.cc b/tests/mesh_test_2d.cc index eba42e693..c82b04f2e 100644 --- a/tests/mesh_test_2d.cc +++ b/tests/mesh_test_2d.cc @@ -967,9 +967,8 @@ TEST_CASE("Mesh is checked for 2D case", "[mesh][2D]") { // Compute volume mesh->iterate_over_particles( - [](std::shared_ptr> ptr) { - return mpm::particle::compute_volume(ptr); - }); + std::bind(&mpm::ParticleBase::compute_volume, + std::placeholders::_1)); mesh->apply_traction_on_particles(10); } diff --git a/tests/mesh_test_3d.cc b/tests/mesh_test_3d.cc index 85d5d2bca..a6c1db5bb 100644 --- a/tests/mesh_test_3d.cc +++ b/tests/mesh_test_3d.cc @@ -1062,9 +1062,8 @@ TEST_CASE("Mesh is checked for 3D case", "[mesh][3D]") { // Compute volume mesh->iterate_over_particles( - [](std::shared_ptr> ptr) { - return mpm::particle::compute_volume(ptr); - }); + std::bind(&mpm::ParticleBase::compute_volume, + std::placeholders::_1)); mesh->apply_traction_on_particles(10); } diff --git a/tests/node_test.cc b/tests/node_test.cc index 3a610136a..3cc92d2a5 100644 --- a/tests/node_test.cc +++ b/tests/node_test.cc @@ -134,47 +134,30 @@ TEST_CASE("Node is checked for 1D case", "[node][1D]") { mass = 100.; REQUIRE_NOTHROW(node->update_mass(false, Nphase, mass)); REQUIRE(node->mass(Nphase) == Approx(100.0).epsilon(Tolerance)); - // Assign mass to 200 using scalar property update true - REQUIRE_NOTHROW(node->update_scalar_property(mpm::properties::Scalar::Mass, - true, Nphase, mass)); - REQUIRE(node->scalar_property(mpm::properties::Scalar::Mass, Nphase) == - Approx(200.0).epsilon(Tolerance)); - // Assign mass to 100 using scalar property update false - REQUIRE_NOTHROW(node->update_scalar_property(mpm::properties::Scalar::Mass, - false, Nphase, mass)); - REQUIRE(node->scalar_property(mpm::properties::Scalar::Mass, Nphase) == - Approx(100.0).epsilon(Tolerance)); SECTION("Check nodal pressure") { // Check pressure REQUIRE(node->pressure(Nphase) == Approx(0.0).epsilon(Tolerance)); double pressure = 1000.7; // Update pressure to 1000.7 - REQUIRE_NOTHROW( - node->update_mass_pressure(false, Nphase, mass * pressure)); - node->compute_pressure(); + REQUIRE_NOTHROW(node->update_mass_pressure(Nphase, mass * pressure)); REQUIRE(node->pressure(Nphase) == Approx(1000.7).epsilon(Tolerance)); // Update pressure to 2001.4 - REQUIRE_NOTHROW( - node->update_mass_pressure(true, Nphase, mass * pressure)); - node->compute_pressure(); + REQUIRE_NOTHROW(node->update_mass_pressure(Nphase, mass * pressure)); REQUIRE(node->pressure(Nphase) == Approx(2001.4).epsilon(Tolerance)); // Assign pressure to 1000 pressure = 1000.; - REQUIRE_NOTHROW(node->update_pressure(false, Nphase, pressure)); + node->assign_pressure(Nphase, pressure); REQUIRE(node->pressure(Nphase) == Approx(1000.0).epsilon(Tolerance)); // Assign mass to 0 mass = 0.; REQUIRE_NOTHROW(node->update_mass(false, Nphase, mass)); REQUIRE(node->mass(Nphase) == Approx(0.0).epsilon(Tolerance)); - // Try to update pressure, should throw and keep to 1000. + // Try to update pressure to 2000, should throw and keep to 1000. pressure = 1000.; - node->update_mass_pressure(false, Nphase, pressure); - node->compute_pressure(); + const double pmass = 1.5; + node->assign_pressure(Nphase, pressure); REQUIRE(node->pressure(Nphase) == Approx(1000.0).epsilon(Tolerance)); - // Update pressure to 2000. - REQUIRE_NOTHROW(node->update_pressure(true, Nphase, pressure)); - REQUIRE(node->pressure(Nphase) == Approx(2000.0).epsilon(Tolerance)); } SECTION("Check external force") { @@ -278,22 +261,6 @@ TEST_CASE("Node is checked for 1D case", "[node][1D]") { for (unsigned i = 0; i < force.size(); ++i) REQUIRE(node->internal_force(Nphase)(i) == Approx(10.).epsilon(Tolerance)); - - // Assign force to 20 using vector property update true - REQUIRE_NOTHROW(node->update_vector_property( - mpm::properties::Vector::InternalForce, true, Nphase, force)); - for (unsigned i = 0; i < force.size(); ++i) - REQUIRE(node->vector_property(mpm::properties::Vector::InternalForce, - Nphase)(i) == - Approx(20.).epsilon(Tolerance)); - - // Assign force to 10 using vector property update false - REQUIRE_NOTHROW(node->update_vector_property( - mpm::properties::Vector::InternalForce, false, Nphase, force)); - for (unsigned i = 0; i < force.size(); ++i) - REQUIRE(node->vector_property(mpm::properties::Vector::InternalForce, - Nphase)(i) == - Approx(10.).epsilon(Tolerance)); } SECTION("Check compute acceleration and velocity") { @@ -341,20 +308,12 @@ TEST_CASE("Node is checked for 1D case", "[node][1D]") { REQUIRE(node->velocity(Nphase)(i) == Approx(velocity(i)).epsilon(Tolerance)); - // Check boolean properties Friction, should be false - REQUIRE(node->boolean_property(mpm::properties::Boolean::Friction) == - false); - // Apply friction constraints REQUIRE(node->assign_friction_constraint(0, 1., 0.5) == true); // Apply friction constraints REQUIRE(node->assign_friction_constraint(-1, 1., 0.5) == false); REQUIRE(node->assign_friction_constraint(3, 1., 0.5) == false); - // Check boolean properties Friction, should be true - REQUIRE(node->boolean_property(mpm::properties::Boolean::Friction) == - true); - // Test acceleration with constraints acceleration[0] = 0.5 * acceleration[0]; for (unsigned i = 0; i < acceleration.size(); ++i) @@ -648,31 +607,24 @@ TEST_CASE("Node is checked for 2D case", "[node][2D]") { REQUIRE(node->pressure(Nphase) == Approx(0.0).epsilon(Tolerance)); double pressure = 1000.7; // Update pressure to 1000.7 - REQUIRE_NOTHROW( - node->update_mass_pressure(false, Nphase, mass * pressure)); - node->compute_pressure(); + REQUIRE_NOTHROW(node->update_mass_pressure(Nphase, mass * pressure)); REQUIRE(node->pressure(Nphase) == Approx(1000.7).epsilon(Tolerance)); // Update pressure to 2001.4 - REQUIRE_NOTHROW( - node->update_mass_pressure(true, Nphase, mass * pressure)); - node->compute_pressure(); + REQUIRE_NOTHROW(node->update_mass_pressure(Nphase, mass * pressure)); REQUIRE(node->pressure(Nphase) == Approx(2001.4).epsilon(Tolerance)); // Assign pressure to 1000 pressure = 1000.; - REQUIRE_NOTHROW(node->update_pressure(false, Nphase, pressure)); + node->assign_pressure(Nphase, pressure); REQUIRE(node->pressure(Nphase) == Approx(1000.0).epsilon(Tolerance)); // Assign mass to 0 mass = 0.; REQUIRE_NOTHROW(node->update_mass(false, Nphase, mass)); REQUIRE(node->mass(Nphase) == Approx(0.0).epsilon(Tolerance)); - // Try to update pressure, should throw and keep to 1000. + // Try to update pressure to 2000, should throw and keep to 1000. pressure = 1000.; - node->update_mass_pressure(false, Nphase, pressure); - node->compute_pressure(); + const double pmass = 1.5; + node->assign_pressure(Nphase, pressure); REQUIRE(node->pressure(Nphase) == Approx(1000.0).epsilon(Tolerance)); - // Update pressure to 2000. - REQUIRE_NOTHROW(node->update_pressure(true, Nphase, pressure)); - REQUIRE(node->pressure(Nphase) == Approx(2000.0).epsilon(Tolerance)); } SECTION("Check volume") { @@ -987,10 +939,6 @@ TEST_CASE("Node is checked for 2D case", "[node][2D]") { // Apply velocity constraints REQUIRE(node->assign_velocity_constraint(0, -12.5) == true); - // Check boolean properties GenericBC, should be false - REQUIRE(node->boolean_property(mpm::properties::Boolean::GenericBC) == - false); - // Apply rotation matrix with Euler angles alpha = 10 deg, beta = 30 deg Eigen::Matrix euler_angles; euler_angles << 10. * M_PI / 180, 30. * M_PI / 180; @@ -999,10 +947,6 @@ TEST_CASE("Node is checked for 2D case", "[node][2D]") { node->assign_rotation_matrix(rotation_matrix); const auto inverse_rotation_matrix = rotation_matrix.inverse(); - // Check boolean properties GenericBC, should be true - REQUIRE(node->boolean_property(mpm::properties::Boolean::GenericBC) == - true); - // Apply inclined velocity constraints node->apply_velocity_constraints(); @@ -1032,10 +976,6 @@ TEST_CASE("Node is checked for 2D case", "[node][2D]") { REQUIRE(node->assign_velocity_constraint(0, -12.5) == true); REQUIRE(node->assign_velocity_constraint(1, 7.5) == true); - // Check boolean properties GenericBC, should be false - REQUIRE(node->boolean_property(mpm::properties::Boolean::GenericBC) == - false); - // Apply rotation matrix with Euler angles alpha = -10 deg, beta = 30 // deg Eigen::Matrix euler_angles; @@ -1045,10 +985,6 @@ TEST_CASE("Node is checked for 2D case", "[node][2D]") { node->assign_rotation_matrix(rotation_matrix); const auto inverse_rotation_matrix = rotation_matrix.inverse(); - // Check boolean properties GenericBC, should be true - REQUIRE(node->boolean_property(mpm::properties::Boolean::GenericBC) == - true); - // Apply inclined velocity constraints node->apply_velocity_constraints(); @@ -1078,19 +1014,11 @@ TEST_CASE("Node is checked for 2D case", "[node][2D]") { } SECTION("Check Cartesian friction constraints") { - // Check boolean properties Friction, should be false - REQUIRE(node->boolean_property(mpm::properties::Boolean::Friction) == - false); - // Apply friction constraints REQUIRE(node->assign_friction_constraint(1, 1, 0.2) == true); // Check out of bounds condition REQUIRE(node->assign_friction_constraint(2, 1, 0.2) == false); - // Check boolean properties Friction, should be true - REQUIRE(node->boolean_property(mpm::properties::Boolean::Friction) == - true); - // Apply friction constraints node->apply_friction_constraints(dt); @@ -1102,21 +1030,9 @@ TEST_CASE("Node is checked for 2D case", "[node][2D]") { } SECTION("Check general friction constraints in 1 direction") { - // Check boolean properties Friction, should be false - REQUIRE(node->boolean_property(mpm::properties::Boolean::Friction) == - false); - // Apply friction constraints REQUIRE(node->assign_friction_constraint(1, 1, 0.2) == true); - // Check boolean properties Friction, should be true - REQUIRE(node->boolean_property(mpm::properties::Boolean::Friction) == - true); - - // Check boolean properties GenericBC, should be false - REQUIRE(node->boolean_property(mpm::properties::Boolean::GenericBC) == - false); - // Apply rotation matrix with Euler angles alpha = 10 deg, beta = 30 deg Eigen::Matrix euler_angles; euler_angles << 10. * M_PI / 180, 30. * M_PI / 180; @@ -1128,10 +1044,6 @@ TEST_CASE("Node is checked for 2D case", "[node][2D]") { // Apply general friction constraints node->apply_friction_constraints(dt); - // Check boolean properties GenericBC, should be true - REQUIRE(node->boolean_property(mpm::properties::Boolean::GenericBC) == - true); - // Check applied constraints on acceleration in the global coordinates acceleration << 4.905579787672637, 4.920772034660430; for (unsigned i = 0; i < Dim; ++i) @@ -1299,31 +1211,24 @@ TEST_CASE("Node is checked for 3D case", "[node][3D]") { REQUIRE(node->pressure(Nphase) == Approx(0.0).epsilon(Tolerance)); double pressure = 1000.7; // Update pressure to 1000.7 - REQUIRE_NOTHROW( - node->update_mass_pressure(false, Nphase, mass * pressure)); - node->compute_pressure(); + REQUIRE_NOTHROW(node->update_mass_pressure(Nphase, mass * pressure)); REQUIRE(node->pressure(Nphase) == Approx(1000.7).epsilon(Tolerance)); // Update pressure to 2001.4 - REQUIRE_NOTHROW( - node->update_mass_pressure(true, Nphase, mass * pressure)); - node->compute_pressure(); + REQUIRE_NOTHROW(node->update_mass_pressure(Nphase, mass * pressure)); REQUIRE(node->pressure(Nphase) == Approx(2001.4).epsilon(Tolerance)); // Assign pressure to 1000 pressure = 1000.; - REQUIRE_NOTHROW(node->update_pressure(false, Nphase, pressure)); + node->assign_pressure(Nphase, pressure); REQUIRE(node->pressure(Nphase) == Approx(1000.0).epsilon(Tolerance)); // Assign mass to 0 mass = 0.; REQUIRE_NOTHROW(node->update_mass(false, Nphase, mass)); REQUIRE(node->mass(Nphase) == Approx(0.0).epsilon(Tolerance)); - // Try to update pressure, should throw and keep to 1000. + // Try to update pressure to 2000, should throw and keep to 1000. pressure = 1000.; - node->update_mass_pressure(false, Nphase, pressure); - node->compute_pressure(); + const double pmass = 1.5; + node->assign_pressure(Nphase, pressure); REQUIRE(node->pressure(Nphase) == Approx(1000.0).epsilon(Tolerance)); - // Update pressure to 2000. - REQUIRE_NOTHROW(node->update_pressure(true, Nphase, pressure)); - REQUIRE(node->pressure(Nphase) == Approx(2000.0).epsilon(Tolerance)); } SECTION("Check external force") { @@ -1611,10 +1516,6 @@ TEST_CASE("Node is checked for 3D case", "[node][3D]") { REQUIRE(node->assign_velocity_constraint(0, 10.5) == true); REQUIRE(node->assign_velocity_constraint(2, -12.5) == true); - // Check boolean properties GenericBC, should be false - REQUIRE(node->boolean_property(mpm::properties::Boolean::GenericBC) == - false); - // Apply rotation matrix with Euler angles alpha = 10 deg, beta = 20 deg // and gamma = 30 deg Eigen::Matrix euler_angles; @@ -1624,10 +1525,6 @@ TEST_CASE("Node is checked for 3D case", "[node][3D]") { node->assign_rotation_matrix(rotation_matrix); const auto inverse_rotation_matrix = rotation_matrix.inverse(); - // Check boolean properties GenericBC, should be true - REQUIRE(node->boolean_property(mpm::properties::Boolean::GenericBC) == - true); - // Apply constraints node->apply_velocity_constraints(); @@ -1663,10 +1560,6 @@ TEST_CASE("Node is checked for 3D case", "[node][3D]") { REQUIRE(node->assign_velocity_constraint(1, -12.5) == true); REQUIRE(node->assign_velocity_constraint(2, 7.5) == true); - // Check boolean properties GenericBC, should be false - REQUIRE(node->boolean_property(mpm::properties::Boolean::GenericBC) == - false); - // Apply rotation matrix with Euler angles alpha = -10 deg, beta = 20 // deg and gamma = -30 deg Eigen::Matrix euler_angles; @@ -1676,10 +1569,6 @@ TEST_CASE("Node is checked for 3D case", "[node][3D]") { node->assign_rotation_matrix(rotation_matrix); const auto inverse_rotation_matrix = rotation_matrix.inverse(); - // Check boolean properties GenericBC, should be true - REQUIRE(node->boolean_property(mpm::properties::Boolean::GenericBC) == - true); - // Apply constraints node->apply_velocity_constraints(); @@ -1713,19 +1602,11 @@ TEST_CASE("Node is checked for 3D case", "[node][3D]") { } SECTION("Check Cartesian friction constraints") { - // Check boolean properties Friction, should be false - REQUIRE(node->boolean_property(mpm::properties::Boolean::Friction) == - false); - // Apply friction constraints REQUIRE(node->assign_friction_constraint(2, 2, 0.3) == true); // Check out of bounds condition REQUIRE(node->assign_friction_constraint(4, 1, 0.2) == false); - // Check boolean properties Friction, should be true - REQUIRE(node->boolean_property(mpm::properties::Boolean::Friction) == - true); - // Apply constraints node->apply_friction_constraints(dt); @@ -1737,21 +1618,9 @@ TEST_CASE("Node is checked for 3D case", "[node][3D]") { } SECTION("Check general friction constraints in 1 direction") { - // Check boolean properties Friction, should be false - REQUIRE(node->boolean_property(mpm::properties::Boolean::Friction) == - false); - // Apply friction constraints REQUIRE(node->assign_friction_constraint(2, 2, 0.3) == true); - // Check boolean properties Friction, should be true - REQUIRE(node->boolean_property(mpm::properties::Boolean::Friction) == - true); - - // Check boolean properties GenericBC, should be false - REQUIRE(node->boolean_property(mpm::properties::Boolean::GenericBC) == - false); - // Apply rotation matrix with Euler angles alpha = 10 deg, beta = 20 deg // and gamma = 30 deg Eigen::Matrix euler_angles; @@ -1764,10 +1633,6 @@ TEST_CASE("Node is checked for 3D case", "[node][3D]") { // Apply inclined velocity constraints node->apply_friction_constraints(dt); - // Check boolean properties GenericBC, should be true - REQUIRE(node->boolean_property(mpm::properties::Boolean::GenericBC) == - true); - // Check applied constraints on acceleration in the global coordinates acceleration << 4.602895052828914, 4.492575657560740, 4.751301246937935; for (unsigned i = 0; i < Dim; ++i) diff --git a/tests/particle_cell_crossing_test.cc b/tests/particle_cell_crossing_test.cc index c8f616e74..ea3a1eb35 100644 --- a/tests/particle_cell_crossing_test.cc +++ b/tests/particle_cell_crossing_test.cc @@ -165,14 +165,12 @@ TEST_CASE("Particle cell crossing is checked for 2D case", material, mpm::ParticlePhase::Solid)); // Compute volume - mesh->iterate_over_particles([](std::shared_ptr> ptr) { - return mpm::particle::compute_volume(ptr); - }); + mesh->iterate_over_particles(std::bind( + &mpm::ParticleBase::compute_volume, std::placeholders::_1)); // Compute mass - mesh->iterate_over_particles([](std::shared_ptr> ptr) { - return mpm::particle::compute_mass(ptr); - }); + mesh->iterate_over_particles( + std::bind(&mpm::ParticleBase::compute_mass, std::placeholders::_1)); // Initialise nodes mesh->iterate_over_nodes( @@ -192,9 +190,9 @@ TEST_CASE("Particle cell crossing is checked for 2D case", &mpm::ParticleBase::compute_shapefn, std::placeholders::_1)); // Assign mass and momentum to nodes - mesh->iterate_over_particles([](std::shared_ptr> ptr) { - return mpm::particle::map_mass_momentum_to_nodes(ptr); - }); + mesh->iterate_over_particles( + std::bind(&mpm::ParticleBase::map_mass_momentum_to_nodes, + std::placeholders::_1)); // Iterate over active nodes to compute acceleratation and velocity mesh->iterate_over_nodes_predicate( @@ -423,14 +421,12 @@ TEST_CASE("Particle cell crossing is checked for 3D case", material, mpm::ParticlePhase::Solid)); // Compute volume - mesh->iterate_over_particles([](std::shared_ptr> ptr) { - return mpm::particle::compute_volume(ptr); - }); + mesh->iterate_over_particles(std::bind( + &mpm::ParticleBase::compute_volume, std::placeholders::_1)); // Compute mass - mesh->iterate_over_particles([](std::shared_ptr> ptr) { - return mpm::particle::compute_mass(ptr); - }); + mesh->iterate_over_particles( + std::bind(&mpm::ParticleBase::compute_mass, std::placeholders::_1)); // Initialise nodes mesh->iterate_over_nodes( @@ -454,9 +450,9 @@ TEST_CASE("Particle cell crossing is checked for 3D case", &mpm::ParticleBase::compute_shapefn, std::placeholders::_1)); // Assign mass and momentum to nodes - mesh->iterate_over_particles([](std::shared_ptr> ptr) { - return mpm::particle::map_mass_momentum_to_nodes(ptr); - }); + mesh->iterate_over_particles( + std::bind(&mpm::ParticleBase::map_mass_momentum_to_nodes, + std::placeholders::_1)); // Iterate over active nodes to compute acceleratation and velocity mesh->iterate_over_nodes_predicate( diff --git a/tests/particle_test.cc b/tests/particle_test.cc index b8e25107a..0d2656f54 100644 --- a/tests/particle_test.cc +++ b/tests/particle_test.cc @@ -150,19 +150,6 @@ TEST_CASE("Particle is checked for 1D case", "[particle][1D]") { particle->assign_mass(mass); REQUIRE(particle->mass() == Approx(100.5).epsilon(Tolerance)); - // Check mass using scalar properties - REQUIRE(particle->scalar_property(mpm::properties::Scalar::Mass) == - Approx(100.5).epsilon(Tolerance)); - mass = 200.5; - particle->update_scalar_property(mpm::properties::Scalar::Mass, false, - mass); - REQUIRE(particle->scalar_property(mpm::properties::Scalar::Mass) == - Approx(200.5).epsilon(Tolerance)); - - particle->update_scalar_property(mpm::properties::Scalar::Mass, true, mass); - REQUIRE(particle->scalar_property(mpm::properties::Scalar::Mass) == - Approx(401.).epsilon(Tolerance)); - // Check stress Eigen::Matrix stress; for (unsigned i = 0; i < stress.size(); ++i) stress(i) = 17.51; @@ -178,29 +165,10 @@ TEST_CASE("Particle is checked for 1D case", "[particle][1D]") { for (unsigned i = 0; i < velocity.size(); ++i) REQUIRE(particle->velocity()(i) == Approx(0.).epsilon(Tolerance)); - particle->assign_velocity(velocity); + REQUIRE(particle->assign_velocity(velocity) == true); for (unsigned i = 0; i < velocity.size(); ++i) REQUIRE(particle->velocity()(i) == Approx(17.51).epsilon(Tolerance)); - // Check velocity using vector properties - for (unsigned i = 0; i < velocity.size(); ++i) - REQUIRE(particle->vector_property(mpm::properties::Vector::Velocity)(i) == - Approx(17.51).epsilon(Tolerance)); - - for (unsigned i = 0; i < velocity.size(); ++i) velocity(i) = 13.88; - - particle->update_vector_property(mpm::properties::Vector::Velocity, false, - velocity); - for (unsigned i = 0; i < velocity.size(); ++i) - REQUIRE(particle->vector_property(mpm::properties::Vector::Velocity)(i) == - Approx(13.88).epsilon(Tolerance)); - - particle->update_vector_property(mpm::properties::Vector::Velocity, true, - velocity); - for (unsigned i = 0; i < velocity.size(); ++i) - REQUIRE(particle->vector_property(mpm::properties::Vector::Velocity)(i) == - Approx(27.76).epsilon(Tolerance)); - // Assign volume REQUIRE(particle->assign_volume(0.0) == false); REQUIRE(particle->assign_volume(-5.0) == false); @@ -234,14 +202,6 @@ TEST_CASE("Particle is checked for 1D case", "[particle][1D]") { else REQUIRE(particle->traction()(i) == Approx(0.).epsilon(Tolerance)); } - - // Check for boolean property assignment and return - REQUIRE(particle->boolean_property(mpm::properties::Boolean::SetTraction) == - true); - particle->assign_boolean_property(mpm::properties::Boolean::SetTraction, - false); - REQUIRE(particle->boolean_property(mpm::properties::Boolean::SetTraction) == - false); } SECTION("Check initialise particle HDF5") { @@ -658,8 +618,7 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { // Add particle mpm::Index id = 0; coords << 0.75, 0.75; - std::shared_ptr> particle = - std::make_shared>(id, coords); + auto particle = std::make_shared>(id, coords); // Time-step const double dt = 0.1; @@ -717,7 +676,10 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { // REQUIRE_NOTHROW(particle->compute_updated_position(dt) == false); // Compute updated particle location from nodal velocity should fail // TODO Assert: REQUIRE_NOTHROW(particle->compute_updated_position(dt, - // true)); + // true)); Compute volume + // TODO Assert: REQUIRE(particle->compute_volume() == false); + // Update volume should fail + // TODO Assert: REQUIRE(particle->update_volume() == false); REQUIRE(particle->assign_cell(cell) == true); REQUIRE(cell->status() == true); @@ -736,7 +698,7 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { // Check volume REQUIRE(particle->volume() == Approx(2.0).epsilon(Tolerance)); // Compute volume - REQUIRE_NOTHROW(mpm::particle::compute_volume(particle)); + REQUIRE_NOTHROW(particle->compute_volume()); // Check volume REQUIRE(particle->volume() == Approx(1.0).epsilon(Tolerance)); @@ -759,6 +721,9 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { Factory, unsigned, const Json&>::instance()->create( "LinearElastic2D", std::move(mid), jmaterial); + // Check compute mass before material and volume + // TODO Assert: REQUIRE(particle->compute_mass() == false); + // Test compute stress before material assignment // TODO Assert: REQUIRE(particle->compute_stress() == false); @@ -769,19 +734,19 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { REQUIRE(particle->material_id() == 1); // Compute volume - REQUIRE_NOTHROW(mpm::particle::compute_volume(particle)); + REQUIRE_NOTHROW(particle->compute_volume()); // Compute mass - REQUIRE_NOTHROW(mpm::particle::compute_mass(particle)); + REQUIRE_NOTHROW(particle->compute_mass()); // Mass REQUIRE(particle->mass() == Approx(1000.).epsilon(Tolerance)); - // Compute mass function - REQUIRE_NOTHROW(mpm::particle::compute_mass(particle)); - REQUIRE(particle->scalar_property(mpm::properties::Scalar::Mass) == - Approx(1000.).epsilon(Tolerance)); // Map particle mass to nodes particle->assign_mass(std::numeric_limits::max()); + // TODO Assert: REQUIRE_NOTHROW(particle->map_mass_momentum_to_nodes()); + + // Map particle pressure to nodes + // TODO Assert: REQUIRE(particle->map_pressure_to_nodes() == false); // Assign mass to nodes REQUIRE(particle->compute_reference_location() == true); @@ -791,12 +756,15 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { Eigen::VectorXd velocity; velocity.resize(Dim); for (unsigned i = 0; i < velocity.size(); ++i) velocity(i) = i; - particle->assign_velocity(velocity); + REQUIRE(particle->assign_velocity(velocity) == true); for (unsigned i = 0; i < velocity.size(); ++i) REQUIRE(particle->velocity()(i) == Approx(i).epsilon(Tolerance)); - REQUIRE_NOTHROW(mpm::particle::compute_mass(particle)); - REQUIRE_NOTHROW(mpm::particle::map_mass_momentum_to_nodes(particle)); + REQUIRE_NOTHROW(particle->compute_mass()); + REQUIRE_NOTHROW(particle->map_mass_momentum_to_nodes()); + + // TODO Assert: REQUIRE(particle->map_pressure_to_nodes() == false); + REQUIRE(particle->compute_pressure_smoothing() == false); // Values of nodal mass std::array nodal_mass{562.5, 187.5, 62.5, 187.5}; @@ -886,7 +854,7 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { // Update volume strain rate REQUIRE(particle->volume() == Approx(1.0).epsilon(Tolerance)); particle->compute_strain(dt); - REQUIRE_NOTHROW(mpm::particle::update_volume(particle)); + REQUIRE_NOTHROW(particle->update_volume()); REQUIRE(particle->volume() == Approx(1.2).epsilon(Tolerance)); // Compute stress @@ -909,7 +877,7 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { Eigen::Matrix gravity; gravity << 0., -9.81; - mpm::particle::map_body_force(particle, gravity); + particle->map_body_force(gravity); // Body force Eigen::Matrix body_force; @@ -938,7 +906,7 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { // Assign traction to particle particle->assign_traction(direction, mfunction->value(current_time) * traction); - mpm::particle::map_traction_force(particle); + particle->map_traction_force(); // Traction force Eigen::Matrix traction_force; @@ -961,7 +929,7 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { particle->assign_traction(direction, -traction * mfunction->value(current_time)); // Map traction force - mpm::particle::map_traction_force(particle); + particle->map_traction_force(); // Check nodal external force for (unsigned i = 0; i < traction_force.rows(); ++i) for (unsigned j = 0; j < traction_force.cols(); ++j) @@ -1081,22 +1049,23 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { Factory, unsigned, const Json&>::instance() ->create("Newtonian2D", std::move(mid1), jmaterial1); - // Reset nodal properties - for (const auto& node : nodes) node->initialise(); - // Assign material properties REQUIRE(particle->assign_material(material1) == true); // Compute volume - REQUIRE_NOTHROW(mpm::particle::compute_volume(particle)); + REQUIRE_NOTHROW(particle->compute_volume()); // Compute mass - REQUIRE_NOTHROW(mpm::particle::compute_mass(particle)); + REQUIRE_NOTHROW(particle->compute_mass()); // Mass REQUIRE(particle->mass() == Approx(1000.).epsilon(Tolerance)); // Map particle mass to nodes particle->assign_mass(std::numeric_limits::max()); + // TODO Assert: REQUIRE(particle->map_mass_momentum_to_nodes() == false); + + // Map particle pressure to nodes + // TODO Assert: REQUIRE(particle->map_pressure_to_nodes() == false); // Assign mass to nodes REQUIRE(particle->compute_reference_location() == true); @@ -1105,12 +1074,12 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { // Check velocity velocity.resize(Dim); for (unsigned i = 0; i < velocity.size(); ++i) velocity(i) = i; - particle->assign_velocity(velocity); + REQUIRE(particle->assign_velocity(velocity) == true); for (unsigned i = 0; i < velocity.size(); ++i) REQUIRE(particle->velocity()(i) == Approx(i).epsilon(Tolerance)); - REQUIRE_NOTHROW(mpm::particle::compute_mass(particle)); - REQUIRE_NOTHROW(mpm::particle::map_mass_momentum_to_nodes(particle)); + REQUIRE_NOTHROW(particle->compute_mass()); + REQUIRE_NOTHROW(particle->map_mass_momentum_to_nodes()); // Check volumetric strain at centroid volumetric_strain = 0.2; @@ -1124,38 +1093,8 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { particle->pressure() == Approx(-8333333.333333333 * volumetric_strain).epsilon(Tolerance)); - // Check return and assign state variable - REQUIRE( - particle->state_variable("pressure") == - Approx(-8333333.333333333 * volumetric_strain).epsilon(Tolerance)); - - REQUIRE_NOTHROW( - particle->assign_pressure(-8333333.333333333 * volumetric_strain)); - - // Check pressure smoothing - REQUIRE_NOTHROW(mpm::particle::map_mass_pressure_to_nodes(particle)); - for (const auto& node : nodes) node->compute_pressure(); - REQUIRE_NOTHROW(mpm::particle::compute_pressure_smoothing(particle)); - REQUIRE( - particle->pressure() == - Approx(-8333333.333333333 * volumetric_strain).epsilon(Tolerance)); - - // Assign pressure equal to 1.0, we expect its smoothed value is also 1.0 - REQUIRE_NOTHROW(particle->assign_state_variable("pressure", 1.0)); - REQUIRE(particle->pressure() == Approx(1.0).epsilon(Tolerance)); - - for (const auto& node : nodes) - node->update_scalar_property(mpm::properties::Scalar::MassPressure, - false, 0, 0.0); - REQUIRE_NOTHROW(mpm::particle::map_mass_pressure_to_nodes(particle)); - for (const auto& node : nodes) { - REQUIRE( - node->scalar_property(mpm::properties::Scalar::MassPressure, 0) == - node->scalar_property(mpm::properties::Scalar::Mass, 0)); - node->compute_pressure(); - } - REQUIRE_NOTHROW(mpm::particle::compute_pressure_smoothing(particle)); - REQUIRE(particle->pressure() == Approx(1.0).epsilon(Tolerance)); + REQUIRE_NOTHROW(particle->map_pressure_to_nodes()); + REQUIRE(particle->compute_pressure_smoothing() == true); } SECTION("Particle assign state variables") { @@ -1289,19 +1228,6 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { particle->assign_mass(mass); REQUIRE(particle->mass() == Approx(100.5).epsilon(Tolerance)); - // Check mass using scalar properties - REQUIRE(particle->scalar_property(mpm::properties::Scalar::Mass) == - Approx(100.5).epsilon(Tolerance)); - mass = 111.11; - particle->update_scalar_property(mpm::properties::Scalar::Mass, false, - mass); - REQUIRE(particle->scalar_property(mpm::properties::Scalar::Mass) == - Approx(111.11).epsilon(Tolerance)); - - particle->update_scalar_property(mpm::properties::Scalar::Mass, true, mass); - REQUIRE(particle->scalar_property(mpm::properties::Scalar::Mass) == - Approx(222.22).epsilon(Tolerance)); - // Check stress Eigen::Matrix stress; for (unsigned i = 0; i < stress.size(); ++i) stress(i) = 17.52; @@ -1317,29 +1243,10 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { for (unsigned i = 0; i < velocity.size(); ++i) REQUIRE(particle->velocity()(i) == Approx(0.).epsilon(Tolerance)); - particle->assign_velocity(velocity); + REQUIRE(particle->assign_velocity(velocity) == true); for (unsigned i = 0; i < velocity.size(); ++i) REQUIRE(particle->velocity()(i) == Approx(19.745).epsilon(Tolerance)); - // Check velocity using vector properties - for (unsigned i = 0; i < velocity.size(); ++i) - REQUIRE(particle->vector_property(mpm::properties::Vector::Velocity)(i) == - Approx(19.745).epsilon(Tolerance)); - - for (unsigned i = 0; i < velocity.size(); ++i) velocity(i) = 11.22; - - particle->update_vector_property(mpm::properties::Vector::Velocity, false, - velocity); - for (unsigned i = 0; i < velocity.size(); ++i) - REQUIRE(particle->vector_property(mpm::properties::Vector::Velocity)(i) == - Approx(11.22).epsilon(Tolerance)); - - particle->update_vector_property(mpm::properties::Vector::Velocity, true, - velocity); - for (unsigned i = 0; i < velocity.size(); ++i) - REQUIRE(particle->vector_property(mpm::properties::Vector::Velocity)(i) == - Approx(22.44).epsilon(Tolerance)); - // Assign volume REQUIRE(particle->assign_volume(0.0) == false); REQUIRE(particle->assign_volume(-5.0) == false); @@ -1376,14 +1283,6 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { else REQUIRE(particle->traction()(i) == Approx(0.).epsilon(Tolerance)); } - - // Check for boolean property assignment and return - REQUIRE(particle->boolean_property(mpm::properties::Boolean::SetTraction) == - true); - particle->assign_boolean_property(mpm::properties::Boolean::SetTraction, - false); - REQUIRE(particle->boolean_property(mpm::properties::Boolean::SetTraction) == - false); } // Check initialise particle from HDF5 file @@ -2035,6 +1934,11 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { // TODO Assert: REQUIRE_NOTHROW(particle->compute_updated_position(dt, // true)); + // Compute volume + // TODO Assert: REQUIRE(particle->compute_volume() == false); + // Update volume should fail + // TODO Assert: REQUIRE(particle->update_volume() == false); + REQUIRE(particle->assign_cell(cell) == true); REQUIRE(cell->status() == true); REQUIRE(particle->cell_id() == 10); @@ -2052,7 +1956,7 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { // Check volume REQUIRE(particle->volume() == Approx(2.0).epsilon(Tolerance)); // Compute volume - REQUIRE_NOTHROW(mpm::particle::compute_volume(particle)); + REQUIRE_NOTHROW(particle->compute_volume()); // Check volume REQUIRE(particle->volume() == Approx(8.0).epsilon(Tolerance)); @@ -2075,6 +1979,9 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { Factory, unsigned, const Json&>::instance()->create( "LinearElastic3D", std::move(mid), jmaterial); + // Check compute mass before material and volume + // TODO Assert: REQUIRE(particle->compute_mass() == false); + // Test compute stress before material assignment // TODO Assert: REQUIRE(particle->compute_stress() == false); @@ -2085,15 +1992,19 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { REQUIRE(particle->material_id() == 0); // Compute volume - REQUIRE_NOTHROW(mpm::particle::compute_volume(particle)); + REQUIRE_NOTHROW(particle->compute_volume()); // Compute mass - REQUIRE_NOTHROW(mpm::particle::compute_mass(particle)); + REQUIRE_NOTHROW(particle->compute_mass()); // Mass REQUIRE(particle->mass() == Approx(8000.).epsilon(Tolerance)); // Map particle mass to nodes particle->assign_mass(std::numeric_limits::max()); + // TODO Assert: REQUIRE(particle->map_mass_momentum_to_nodes() == false); + + // Map particle pressure to nodes + // TODO Assert: REQUIRE(particle->map_pressure_to_nodes() == false); // Assign mass to nodes REQUIRE(particle->compute_reference_location() == true); @@ -2103,12 +2014,15 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { Eigen::VectorXd velocity; velocity.resize(Dim); for (unsigned i = 0; i < velocity.size(); ++i) velocity(i) = i; - particle->assign_velocity(velocity); + REQUIRE(particle->assign_velocity(velocity) == true); for (unsigned i = 0; i < velocity.size(); ++i) REQUIRE(particle->velocity()(i) == Approx(i).epsilon(Tolerance)); - REQUIRE_NOTHROW(mpm::particle::compute_mass(particle)); - REQUIRE_NOTHROW(mpm::particle::map_mass_momentum_to_nodes(particle)); + REQUIRE_NOTHROW(particle->compute_mass()); + REQUIRE_NOTHROW(particle->map_mass_momentum_to_nodes()); + + // TODO Assert: REQUIRE(particle->map_pressure_to_nodes() == false); + REQUIRE(particle->compute_pressure_smoothing() == false); // Values of nodal mass std::array nodal_mass{125., 375., 1125., 375., @@ -2216,7 +2130,7 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { // Update volume strain rate REQUIRE(particle->volume() == Approx(8.0).epsilon(Tolerance)); particle->compute_strain(dt); - REQUIRE_NOTHROW(mpm::particle::update_volume(particle)); + REQUIRE_NOTHROW(particle->update_volume()); REQUIRE(particle->volume() == Approx(12.0).epsilon(Tolerance)); // Compute stress @@ -2239,7 +2153,7 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { Eigen::Matrix gravity; gravity << 0., 0., -9.81; - mpm::particle::map_body_force(particle, gravity); + particle->map_body_force(gravity); // Body force Eigen::Matrix body_force; @@ -2271,7 +2185,7 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { particle->assign_traction(direction, mfunction->value(current_time) * traction); // Map traction force - mpm::particle::map_traction_force(particle); + particle->map_traction_force(); // Traction force Eigen::Matrix traction_force; @@ -2298,7 +2212,7 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { particle->assign_traction(direction, mfunction->value(current_time) * -traction); // Map traction force - mpm::particle::map_traction_force(particle); + particle->map_traction_force(); // Check nodal external force for (unsigned i = 0; i < traction_force.rows(); ++i) for (unsigned j = 0; j < traction_force.cols(); ++j) @@ -2391,15 +2305,19 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { REQUIRE(particle->assign_material(material1) == true); // Compute volume - REQUIRE_NOTHROW(mpm::particle::compute_volume(particle)); + REQUIRE_NOTHROW(particle->compute_volume()); // Compute mass - REQUIRE_NOTHROW(mpm::particle::compute_mass(particle)); + REQUIRE_NOTHROW(particle->compute_mass()); // Mass REQUIRE(particle->mass() == Approx(8000.).epsilon(Tolerance)); // Map particle mass to nodes particle->assign_mass(std::numeric_limits::max()); + // TODO Assert: REQUIRE(particle->map_mass_momentum_to_nodes() == false); + + // Map particle pressure to nodes + // TODO Assert: REQUIRE(particle->map_pressure_to_nodes() == false); // Assign mass to nodes REQUIRE(particle->compute_reference_location() == true); @@ -2408,12 +2326,12 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { // Check velocity velocity.resize(Dim); for (unsigned i = 0; i < velocity.size(); ++i) velocity(i) = i; - particle->assign_velocity(velocity); + REQUIRE(particle->assign_velocity(velocity) == true); for (unsigned i = 0; i < velocity.size(); ++i) REQUIRE(particle->velocity()(i) == Approx(i).epsilon(Tolerance)); - REQUIRE_NOTHROW(mpm::particle::compute_mass(particle)); - REQUIRE_NOTHROW(mpm::particle::map_mass_momentum_to_nodes(particle)); + REQUIRE_NOTHROW(particle->compute_mass()); + REQUIRE_NOTHROW(particle->map_mass_momentum_to_nodes()); // Check volumetric strain at centroid volumetric_strain = 0.5; @@ -2427,33 +2345,8 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { particle->pressure() == Approx(-8333333.333333333 * volumetric_strain).epsilon(Tolerance)); - // Check return and assign state variable - REQUIRE( - particle->state_variable("pressure") == - Approx(-8333333.333333333 * volumetric_strain).epsilon(Tolerance)); - - REQUIRE_NOTHROW( - particle->assign_pressure(-8333333.333333333 * volumetric_strain)); - - // Check pressure smoothing - REQUIRE_NOTHROW(mpm::particle::map_mass_pressure_to_nodes(particle)); - for (const auto& node : nodes) node->compute_pressure(); - REQUIRE_NOTHROW(mpm::particle::compute_pressure_smoothing(particle)); - REQUIRE(particle->pressure() == - Approx(-2083333.3333333333).epsilon(Tolerance)); - - // Assign pressure equal to 1.0, we expect its smoothed value is 0.5 as - // the nodal mass is mapped twice in this case - REQUIRE_NOTHROW(particle->assign_state_variable("pressure", 1.0)); - REQUIRE(particle->pressure() == Approx(1.0).epsilon(Tolerance)); - - for (const auto& node : nodes) - node->update_scalar_property(mpm::properties::Scalar::MassPressure, - false, 0, 0.0); - REQUIRE_NOTHROW(mpm::particle::map_mass_pressure_to_nodes(particle)); - for (const auto& node : nodes) node->compute_pressure(); - REQUIRE_NOTHROW(mpm::particle::compute_pressure_smoothing(particle)); - REQUIRE(particle->pressure() == Approx(0.5).epsilon(Tolerance)); + REQUIRE_NOTHROW(particle->map_pressure_to_nodes()); + REQUIRE(particle->compute_pressure_smoothing() == true); } SECTION("Particle assign state variables") { @@ -2628,19 +2521,6 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { particle->assign_mass(mass); REQUIRE(particle->mass() == Approx(100.5).epsilon(Tolerance)); - // Check mass using scalar properties - REQUIRE(particle->scalar_property(mpm::properties::Scalar::Mass) == - Approx(100.5).epsilon(Tolerance)); - mass = 111.11; - particle->update_scalar_property(mpm::properties::Scalar::Mass, false, - mass); - REQUIRE(particle->scalar_property(mpm::properties::Scalar::Mass) == - Approx(111.11).epsilon(Tolerance)); - - particle->update_scalar_property(mpm::properties::Scalar::Mass, true, mass); - REQUIRE(particle->scalar_property(mpm::properties::Scalar::Mass) == - Approx(222.22).epsilon(Tolerance)); - // Check stress Eigen::Matrix stress; for (unsigned i = 0; i < stress.size(); ++i) stress(i) = 1.; @@ -2656,29 +2536,10 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { for (unsigned i = 0; i < velocity.size(); ++i) REQUIRE(particle->velocity()(i) == Approx(0.).epsilon(Tolerance)); - particle->assign_velocity(velocity); + REQUIRE(particle->assign_velocity(velocity) == true); for (unsigned i = 0; i < velocity.size(); ++i) REQUIRE(particle->velocity()(i) == Approx(17.51).epsilon(Tolerance)); - // Check velocity using vector properties - for (unsigned i = 0; i < velocity.size(); ++i) - REQUIRE(particle->vector_property(mpm::properties::Vector::Velocity)(i) == - Approx(17.51).epsilon(Tolerance)); - - for (unsigned i = 0; i < velocity.size(); ++i) velocity(i) = 11.22; - - particle->update_vector_property(mpm::properties::Vector::Velocity, false, - velocity); - for (unsigned i = 0; i < velocity.size(); ++i) - REQUIRE(particle->vector_property(mpm::properties::Vector::Velocity)(i) == - Approx(11.22).epsilon(Tolerance)); - - particle->update_vector_property(mpm::properties::Vector::Velocity, true, - velocity); - for (unsigned i = 0; i < velocity.size(); ++i) - REQUIRE(particle->vector_property(mpm::properties::Vector::Velocity)(i) == - Approx(22.44).epsilon(Tolerance)); - // Assign volume REQUIRE(particle->assign_volume(0.0) == false); REQUIRE(particle->assign_volume(-5.0) == false); From 32989ade9d87b5a481bced586a30fedf127701ff Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Wed, 29 Jul 2020 00:59:52 -0700 Subject: [PATCH 065/175] clean up --- .gitignore | 1 - external/flat/LICENSE_1_0.txt | 23 -- external/flat/README.md | 65 ---- external/flat/flat_map.hpp | 251 ------------- external/flat/flat_multimap.hpp | 133 ------- external/flat/flat_multiset.hpp | 117 ------ external/flat/flat_set.hpp | 129 ------- external/flat/impl/class_def.hpp | 60 --- external/flat/impl/container_traits.hpp | 25 -- external/flat/impl/flat_impl.hpp | 470 ------------------------ 10 files changed, 1274 deletions(-) delete mode 100644 external/flat/LICENSE_1_0.txt delete mode 100644 external/flat/README.md delete mode 100644 external/flat/flat_map.hpp delete mode 100644 external/flat/flat_multimap.hpp delete mode 100644 external/flat/flat_multiset.hpp delete mode 100644 external/flat/flat_set.hpp delete mode 100644 external/flat/impl/class_def.hpp delete mode 100644 external/flat/impl/container_traits.hpp delete mode 100644 external/flat/impl/flat_impl.hpp diff --git a/.gitignore b/.gitignore index ee24fee34..828560b3a 100644 --- a/.gitignore +++ b/.gitignore @@ -76,4 +76,3 @@ configure.scan *missing *stamp-h1 benchmarks/ -bin/ diff --git a/external/flat/LICENSE_1_0.txt b/external/flat/LICENSE_1_0.txt deleted file mode 100644 index 36b7cd93c..000000000 --- a/external/flat/LICENSE_1_0.txt +++ /dev/null @@ -1,23 +0,0 @@ -Boost Software License - Version 1.0 - August 17th, 2003 - -Permission is hereby granted, free of charge, to any person or organization -obtaining a copy of the software and accompanying documentation covered by -this license (the "Software") to use, reproduce, display, distribute, -execute, and transmit the Software, and to prepare derivative works of the -Software, and to permit third-parties to whom the Software is furnished to -do so, all subject to the following: - -The copyright notices in the Software and this entire statement, including -the above license grant, this restriction and the following disclaimer, -must be included in all copies of the Software, in whole or in part, and -all derivative works of the Software, unless such copies or derivative -works are solely in the form of machine-executable object code generated by -a source language processor. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT -SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE -FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/external/flat/README.md b/external/flat/README.md deleted file mode 100644 index e3b89eab0..000000000 --- a/external/flat/README.md +++ /dev/null @@ -1,65 +0,0 @@ -# C++ Flat Containers Library - -Fast+efficient associative containers using sorted arrays, with an interface based on standard containers. - -This was part of a C++ standard proposal and I recommend that you read it for more details: http://pubby.github.io/proposal.html - -#### Container Adaptors -- `fc::flat_map` -- `fc::flat_multimap` -- `fc::flat_set` -- `fc::flat_multiset` - -#### Class Aliases -- `fc::vector_map` -- `fc::vector_multimap` -- `fc::vector_set` -- `fc::vector_multiset` - -#### New Member Functions -- `has` - - `map.has(key)` returns a pointer to key's mapped value if it exists, otherwise returns null. -- `insert` (delayed sort) - - `map.insert(first, last, fc::delay_sort)` performs insertion with a delayed sort optimization. -- Constructors (delayed sort overload) - - Constructs flat container using a delayed sort optimization. -- Constructors (container construct overload) - - Constructs flat container by forwarding arguments to the underlying container member. - -#### What's an adaptor? - -Container adaptors allow you to use any vector-like sequence container for the underlying storage. -`std::vector` is the natural choice, but classes like `boost::small_vector` and `boost::static_vector` are useful too. Because `std::vector` is the most common in usage, aliases are provided for convenience. - -For basic use, just use the `std::vector` aliases. - -#### The public Members: `container` and `underlying` - -The public member `container` allows access to the underlying storage container. Note that it is the user's responsibility to keep the container in a sorted, unique state. - -Likewise, the public member of iterators: `underlying`, allows access to the underlying storage container's iterators. - -*Example: Delayed sort optimization using `.container`* - - std::flat_multiset set; - while(cpu_temperature() < 100) - set.container.push_back(cpu_temperature()); - std::sort(set.begin(), set.end()); - -#### Const Iteration by Default - -For safety reasons, flat container iterators are const by default. To bypass this safety and get non-const iterators, one can either iterate `.container` or take the `.underlying` of the iterator. - -*Example: Modify values in a way that preserves sortedness* - - for(auto& v : set.container) - v *= 2; - -*Example: Same thing but with `.underlying`* - - for(auto it = v.begin(); it != v.end(); ++it) - (*v.underlying) *= 2; - -#### Helper Types - -The directory `include_extra` contains convenience typedefs for use with Boost.Container. diff --git a/external/flat/flat_map.hpp b/external/flat/flat_map.hpp deleted file mode 100644 index 7e6ce507c..000000000 --- a/external/flat/flat_map.hpp +++ /dev/null @@ -1,251 +0,0 @@ -// Copyright Pubby 2016 -// Distributed under the Boost Software License, Version 1.0. -// http://www.boost.org/LICENSE_1_0.txt - -#ifndef LIB_FLAT_FLAT_MAP_HPP -#define LIB_FLAT_FLAT_MAP_HPP - -#include "impl/flat_impl.hpp" - -namespace fc { -namespace impl { - -template -class flat_map_base -: public flat_container_base -{ -#include "impl/container_traits.hpp" - using mapped_type = typename value_type::second_type; - using B = flat_container_base; - D const* self() const { return static_cast(this); } - D* self() { return static_cast(this); } -public: - using value_compare = first_compare; - value_compare value_comp() const { return value_compare(B::key_comp()); } - - using B::insert; - using B::erase; - - // Element access - - mapped_type const* has(key_type const& key) const - { - const_iterator it = self()->find(key); - return it == self()->end() ? nullptr : &it.underlying->second; - } - - mapped_type* has(key_type const& key) - { - iterator it = self()->find(key); - return it == self()->end() ? nullptr : &it.underlying->second; - } - - mapped_type const& at(key_type const& key) const - { - if(mapped_type const* ptr = has(key)) - return *ptr; - throw std::out_of_range("flat_map::at"); - } - - mapped_type& at(key_type const& key) - { - if(mapped_type* ptr = has(key)) - return *ptr; - throw std::out_of_range("flat_map::at"); - } - - mapped_type& operator[](key_type const& key) - { return self()->try_emplace(key).first.underlying->second; } - - mapped_type& operator[](key_type&& key) - { - return self()->try_emplace(std::move(key)).first.underlying->second; - } - - // Modifiers - - std::pair insert(value_type const& value) - { return insert_(value); } - - std::pair insert(value_type&& value) - { return insert_(std::move(value)); } - - template - void insert(InputIt first, InputIt last, delay_sort_t) - { - this->ds_insert_(first, last); - auto it = std::unique( - self()->container.begin(), self()->container.end(), - impl::eq_comp{value_comp()}); - self()->container.erase(it, self()->container.end()); - } - - template - std::pair insert_or_assign(key_type const& key, M&& obj) - { return insert_or_assign_(key, std::forward(obj)); } - - template - std::pair insert_or_assign(key_type&& key, M&& obj) - { return insert_or_assign_(std::move(key), std::forward(obj)); } - - template - std::pair insert_or_assign(const_iterator hint, - key_type const& key, M&& obj) - { return insert_or_assign(key, std::forward(obj)); } - - template - std::pair insert_or_assign(const_iterator hint, - key_type&& key, M&& obj) - { return insert_or_assign(std::move(key), std::forward(obj)); } - - template - std::pair try_emplace(key_type const& key, Args&&... args) - { return try_emplace_(key, std::forward(args)...); } - - template - std::pair try_emplace(key_type&& key, Args&&... args) - { return try_emplace_(std::move(key), std::forward(args)...); } - - template - iterator try_emplace(const_iterator hint, - key_type const& key, Args&&... args) - { return try_emplace_(key, std::forward(args)...).first; } - - template - iterator try_emplace(const_iterator hint, key_type&& key, Args&&... args) - { - return try_emplace_(std::move(key), - std::forward(args)...).first; - } - - size_type erase(key_type const& key) - { - const_iterator it = self()->find(key); - if(it == self()->end()) - return 0; - self()->container.erase(it.underlying); - return 1; - } - - // Lookup - - size_type count(key_type const& key) const - { - return self()->find(key) != self()->end(); - } - -private: - template - std::pair insert_(V&& value) - { - iterator it = self()->lower_bound(value.first); - if(it == self()->end() || self()->value_comp()(value, *it)) - { - it = self()->container.insert(it.underlying, - std::forward(value)); - return std::make_pair(it, true); - } - return std::make_pair(it, false); - } - - template - std::pair insert_or_assign_(K&& key, M&& obj) - { - iterator it = self()->lower_bound(key); - if(it == self()->end() || self()->key_comp()(key, it->first)) - { - it = self()->container.insert(it.underlying, - value_type(std::forward(key), std::forward(obj))); - return std::make_pair(it, true); - } - it.underlying->second = std::forward(obj); - return std::make_pair(it, false); - } - - template - std::pair try_emplace_(K&& key, Args&&... args) - { - iterator it = self()->lower_bound(key); - if(it == self()->end() || self()->key_comp()(key, it->first)) - { - it = self()->container.emplace(it.underlying, - value_type(std::piecewise_construct, - std::forward_as_tuple(std::forward(key)), - std::forward_as_tuple(std::forward(args)...))); - return std::make_pair(it, true); - } - return std::make_pair(it, false); - } -}; - -template -class flat_map_base> -: public flat_map_base -{ -#include "impl/container_traits.hpp" - using mapped_type = typename value_type::second_type; - using B = flat_map_base; - D const* self() const { return static_cast(this); } - D* self() { return static_cast(this); } -public: - - using B::insert; - using B::count; - - // Modifiers - - template - std::pair insert(P&& value) - { - iterator it = self()->lower_bound(value.first); - if(it == self()->end() || self()->value_comp()(value, *it)) - { - it = self()->container.insert( - it.underlying, std::forward

(value)); - return std::make_pair(it, true); - } - return std::make_pair(it, false); - } - - // Lookup - - template - size_type count(K const& key) const - { - return self()->find(key) != self()->end(); - } -}; - -} // namespace impl - -template> -class flat_map -: public impl::flat_map_base, - typename Container::value_type::first_type, Container, Compare> -{ -#define FLATNAME flat_map -#define FLATKEY typename Container::value_type::first_type -#include "impl/class_def.hpp" -#undef FLATNAME -#undef FLATKEY -}; - -template> -using vector_map = flat_map>, Compare>; - -template -inline bool operator==(const flat_map& lhs, const flat_map& rhs) -{ - return lhs.container == rhs.container; -} -template -inline bool operator!=(const flat_map& lhs, const flat_map& rhs) -{ - return lhs.container != rhs.container; -} - -} // namespace fc - -#endif diff --git a/external/flat/flat_multimap.hpp b/external/flat/flat_multimap.hpp deleted file mode 100644 index 169be155e..000000000 --- a/external/flat/flat_multimap.hpp +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright Pubby 2016 -// Distributed under the Boost Software License, Version 1.0. -// http://www.boost.org/LICENSE_1_0.txt - -#ifndef LIB_FLAT_FLAT_MULTIMAP_HPP -#define LIB_FLAT_FLAT_MULTIMAP_HPP - -#include "impl/flat_impl.hpp" - -namespace fc { -namespace impl { - -template -class flat_multimap_base -: public flat_container_base -{ -#include "impl/container_traits.hpp" - using mapped_type = typename value_type::second_type; - using B = flat_container_base; - D const* self() const { return static_cast(this); } - D* self() { return static_cast(this); } -public: - using value_compare = first_compare; - value_compare value_comp() const { return value_compare(B::key_comp()); } - - using B::insert; - using B::erase; - - // Modifiers - - iterator insert(value_type const& value) - { - iterator it = self()->upper_bound(value.first); - return self()->container.insert(it.underlying, value); - } - - iterator insert(value_type&& value) - { - iterator it = self()->upper_bound(value.first); - return self()->container.insert(it.underlying, std::move(value)); - } - - template - void insert(InputIt first, InputIt last, delay_sort_t) - { this->ds_insert_(first, last); } - - size_type erase(key_type const& key) - { - auto it_pair = self()->equal_range(key); - std::size_t ret = std::distance(it_pair.first, it_pair.second); - self()->container.erase(it_pair.first.underlying, - it_pair.second.underlying); - return ret; - } - - // Lookup - - size_type count(key_type const& key) const - { - auto it_pair = self()->equal_range(key); - return std::distance(it_pair.first, it_pair.second); - } - -}; - -template -class flat_multimap_base> -: public flat_multimap_base -{ -#include "impl/container_traits.hpp" - using mapped_type = typename value_type::second_type; - using B = flat_multimap_base; - D const* self() const { return static_cast(this); } - D* self() { return static_cast(this); } -public: - - using B::insert; - using B::count; - - // Modifiers - - template - iterator insert(P&& value) - { - iterator it = self()->upper_bound(value.first); - return self()->container.insert(it.underlying, - std::forward

(value)); - } - - // Lookup - - template - size_type count(K const& key) const - { - auto it_pair = self()->equal_range(key); - return std::distance(it_pair.first, it_pair.second); - } -}; - -} // namespace impl - -template> -class flat_multimap -: public impl::flat_multimap_base, - typename Container::value_type::first_type, Container, Compare> -{ -#define FLATNAME flat_multimap -#define FLATKEY typename Container::value_type::first_type -#include "impl/class_def.hpp" -#undef FLATNAME -#undef FLATKEY -}; - -template> -using vector_multimap - = flat_multimap>, Compare>; - -template -inline bool operator==(const flat_multimap& lhs, const flat_multimap& rhs) -{ - return lhs.container == rhs.container; -} -template -inline bool operator!=(const flat_multimap& lhs, const flat_multimap& rhs) -{ - return lhs.container != rhs.container; -} - -} // namespace fc - -#endif diff --git a/external/flat/flat_multiset.hpp b/external/flat/flat_multiset.hpp deleted file mode 100644 index beca937ff..000000000 --- a/external/flat/flat_multiset.hpp +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright Pubby 2016 -// Distributed under the Boost Software License, Version 1.0. -// http://www.boost.org/LICENSE_1_0.txt - -#ifndef LIB_FLAT_FLAT_MULTISET_HPP -#define LIB_FLAT_FLAT_MULTISET_HPP - -#include "impl/flat_impl.hpp" - -namespace fc { -namespace impl { - -template -class flat_multiset_base -: public flat_container_base -{ -#include "impl/container_traits.hpp" - using B = flat_container_base; - D const* self() const { return static_cast(this); } - D* self() { return static_cast(this); } -public: - using value_compare = Compare; - value_compare value_comp() const { return value_compare(B::key_comp()); } - - using B::insert; - using B::erase; - - // Modifiers - - iterator insert(value_type const& value) - { - iterator it = self()->upper_bound(value); - return self()->container.insert(it.underlying, value); - } - - iterator insert(value_type&& value) - { - iterator it = self()->upper_bound(value); - return self()->container.insert(it.underlying, std::move(value)); - } - - template - void insert(InputIt first, InputIt last, delay_sort_t) - { this->ds_insert_(first, last); } - - size_type erase(key_type const& key) - { - auto it_pair = self()->equal_range(key); - std::size_t ret = std::distance(it_pair.first, it_pair.second); - self()->container.erase(it_pair.first.underlying, - it_pair.second.underlying); - return ret; - } - - // Lookup - - size_type count(key_type const& key) const - { - auto it_pair = self()->equal_range(key); - return std::distance(it_pair.first, it_pair.second); - } -}; - -template -class flat_multiset_base> -: public flat_multiset_base -{ -#include "impl/container_traits.hpp" - using B = flat_multiset_base; - D const* self() const { return static_cast(this); } - D* self() { return static_cast(this); } -public: - using B::count; - - // Lookup - - template - size_type count(K const& key) const - { - auto it_pair = self()->equal_range(key); - return std::distance(it_pair.first, it_pair.second); - } -}; - -} // namespace impl - -template> -class flat_multiset -: public impl::flat_multiset_base, - typename Container::value_type, Container, Compare> -{ -#define FLATNAME flat_multiset -#define FLATKEY typename Container::value_type -#include "impl/class_def.hpp" -#undef FLATNAME -#undef FLATKEY -}; - -template> -using vector_multiset = flat_multiset, Compare>; - -template -inline bool operator==(const flat_multiset& lhs, const flat_multiset& rhs) -{ - return lhs.container == rhs.container; -} -template -inline bool operator!=(const flat_multiset& lhs, const flat_multiset& rhs) -{ - return lhs.container != rhs.container; -} - -} // namespace fc - -#endif diff --git a/external/flat/flat_set.hpp b/external/flat/flat_set.hpp deleted file mode 100644 index 7f95049cb..000000000 --- a/external/flat/flat_set.hpp +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright Pubby 2016 -// Distributed under the Boost Software License, Version 1.0. -// http://www.boost.org/LICENSE_1_0.txt - -#ifndef LIB_FLAT_FLAT_SET_HPP -#define LIB_FLAT_FLAT_SET_HPP - -#include "impl/flat_impl.hpp" - -namespace fc { -namespace impl { - -template -class flat_set_base -: public flat_container_base -{ -#include "impl/container_traits.hpp" - using B = flat_container_base; - D const* self() const { return static_cast(this); } - D* self() { return static_cast(this); } -public: - using value_compare = Compare; - value_compare value_comp() const { return value_compare(B::key_comp()); } - - using B::insert; - using B::erase; - - // Modifiers - - std::pair insert(value_type const& value) - { return insert_(value); } - - std::pair insert(value_type&& value) - { return insert_(std::move(value)); } - - template - void insert(InputIt first, InputIt last, delay_sort_t) - { - this->ds_insert_(first, last); - auto it = std::unique( - self()->container.begin(), self()->container.end(), - impl::eq_comp{value_comp()}); - self()->container.erase(it, self()->container.end()); - } - - size_type erase(key_type const& key) - { - const_iterator it = self()->find(key); - if(it == self()->end()) - return 0; - self()->container.erase(it.underlying); - return 1; - } - - // Lookup - - size_type count(key_type const& key) const - { - return self()->find(key) != self()->end(); - } - -private: - template - std::pair insert_(V&& value) - { - iterator it = self()->lower_bound(value); - if(it == self()->end() || self()->value_comp()(value, *it)) - { - it = self()->container.insert(it.underlying, - std::forward(value)); - return std::make_pair(it, true); - } - return std::make_pair(it, false); - } -}; - -template -class flat_set_base> -: public flat_set_base -{ -#include "impl/container_traits.hpp" - using B = flat_set_base; - D const* self() const { return static_cast(this); } - D* self() { return static_cast(this); } -public: - using B::count; - - // Lookup - - template - size_type count(K const& key) const - { - return self()->find(key) != self()->end(); - } -}; - -} // namespace impl - -template> -class flat_set -: public impl::flat_set_base, - typename Container::value_type, Container, Compare> -{ -#define FLATNAME flat_set -#define FLATKEY typename Container::value_type -#include "impl/class_def.hpp" -#undef FLATNAME -#undef FLATKEY -}; - -template> -using vector_set = flat_set, Compare>; - -template -inline bool operator==(const flat_set& lhs, const flat_set& rhs) -{ - return lhs.container == rhs.container; -} -template -inline bool operator!=(const flat_set& lhs, const flat_set& rhs) -{ - return lhs.container != rhs.container; -} - -} // namespace fc - -#endif diff --git a/external/flat/impl/class_def.hpp b/external/flat/impl/class_def.hpp deleted file mode 100644 index d29e24b2f..000000000 --- a/external/flat/impl/class_def.hpp +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright Pubby 2016 -// Distributed under the Boost Software License, Version 1.0. -// http://www.boost.org/LICENSE_1_0.txt - -private: - using D = FLATNAME; - using Key = FLATKEY; -public: -#include "container_traits.hpp" - - FLATNAME() = default; - explicit FLATNAME(Compare const& comp) : comp(comp), container() {} - - template - FLATNAME(InputIt first, InputIt last) - : FLATNAME() { this->insert(first, last); } - - template - FLATNAME(InputIt first, InputIt last, Compare const& comp) - : FLATNAME(comp) { this->insert(first, last); } - - template - FLATNAME(InputIt first, InputIt last, delay_sort_t d) - : FLATNAME() { this->insert(first, last, d); } - - template - FLATNAME(InputIt first, InputIt last, Compare const& comp, delay_sort_t d) - : FLATNAME(comp) { this->insert(first, last, d); } - - FLATNAME(FLATNAME const&) = default; - FLATNAME(FLATNAME&&) = default; - - FLATNAME(std::initializer_list ilist) - : FLATNAME() { this->insert(ilist); } - - FLATNAME(std::initializer_list ilist, delay_sort_t d) - : FLATNAME() { this->insert(ilist, d); } - - FLATNAME(std::initializer_list ilist, - Compare const& comp, delay_sort_t d) - : FLATNAME(comp) { this->insert(ilist, d); } - - template - explicit FLATNAME(container_construct_t, Args&&... args) - : container(std::forward(args)...), comp() {} - - template - FLATNAME(Compare const& comp, container_construct_t, Args&&... args) - : container(std::forward(args)...), comp(comp) {} - - FLATNAME& operator=(FLATNAME const&) = default; - FLATNAME& operator=(FLATNAME&&) = default; - FLATNAME& operator=(std::initializer_list ilist) - { this->clear(); this->insert(ilist); return *this; } - - Container container; - Compare comp; - -#undef FLATNAME -#undef FLATKEY diff --git a/external/flat/impl/container_traits.hpp b/external/flat/impl/container_traits.hpp deleted file mode 100644 index 31e16423d..000000000 --- a/external/flat/impl/container_traits.hpp +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright Pubby 2016 -// Distributed under the Boost Software License, Version 1.0. -// http://www.boost.org/LICENSE_1_0.txt - -using container_type = Container; -using key_type = Key; -using size_type = typename container_type::size_type; -using difference_type = typename container_type::difference_type; -using value_type = typename container_type::value_type; -using iterator - = impl::flat_iterator< - typename container_type::iterator, - impl::dummy_iterator>; -using const_iterator - = impl::flat_iterator< - typename container_type::const_iterator, - iterator>; -using reverse_iterator - = impl::flat_iterator< - typename container_type::reverse_iterator, - impl::dummy_iterator>; -using const_reverse_iterator - = impl::flat_iterator< - typename container_type::const_reverse_iterator, - reverse_iterator>; diff --git a/external/flat/impl/flat_impl.hpp b/external/flat/impl/flat_impl.hpp deleted file mode 100644 index 2d639620e..000000000 --- a/external/flat/impl/flat_impl.hpp +++ /dev/null @@ -1,470 +0,0 @@ -// Copyright Pubby 2016 -// Distributed under the Boost Software License, Version 1.0. -// http://www.boost.org/LICENSE_1_0.txt - -#ifndef LIB_FLAT_FLAT_IMPL_HPP -#define LIB_FLAT_FLAT_IMPL_HPP - -#include -#include -#include -#include -#include - -namespace fc { - -struct delay_sort_t {}; -constexpr delay_sort_t delay_sort = {}; - -struct container_construct_t {}; -constexpr container_construct_t container_construct = {}; - -namespace impl { - -template -using transparent_key_t = std::reference_wrapper; - -template -struct eq_comp -{ - template - bool operator()(A const& lhs, B const& rhs) - { return !comp(lhs, rhs) && !comp(rhs, lhs); } - Comp comp; -}; - - -template -struct dummy_iterator -{ - dummy_iterator() = delete; - dummy_iterator(dummy_iterator const&) = delete; - It underlying; -}; - -template::iterator_category> -class flat_iterator; - -template -class flat_iterator -{ - using traits = std::iterator_traits; -public: - using difference_type = typename traits::difference_type; - using value_type = typename traits::value_type const; - using pointer = value_type*; - using reference = value_type&; - using iterator_category = std::random_access_iterator_tag; - - flat_iterator() = default; - flat_iterator(flat_iterator const&) = default; - flat_iterator(flat_iterator&&) = default; - flat_iterator(Convert const& c) : underlying(c.underlying) {} - flat_iterator(Convert&& c) : underlying(std::move(c.underlying)) {} - flat_iterator(It const& underlying) : underlying(underlying) {} - flat_iterator(It&& underlying) : underlying(std::move(underlying)) {} - - flat_iterator& operator=(flat_iterator const& u) = default; - flat_iterator& operator=(flat_iterator&& u) = default; - flat_iterator& operator=(It const& u) - { this->underlying = u; return *this; } - flat_iterator& operator=(It&& u) - { this->underlying = std::move(u); return *this; } - - reference operator*() const { return *underlying; } - pointer operator->() const { return std::addressof(*underlying); } - - flat_iterator& operator++() { ++this->underlying; return *this; } - flat_iterator operator++(int) - { flat_iterator it = *this; ++this->underlying; return it; } - - flat_iterator& operator--() { --this->underlying; return *this; } - flat_iterator operator--(int) - { flat_iterator it = *this; --this->underlying; return it; } - - flat_iterator& operator+=(difference_type d) - { this->underlying += d; return *this; } - flat_iterator& operator-=(difference_type d) - { this->underlying -= d; return *this; } - - flat_iterator operator+(difference_type d) const - { return this->underlying + d; } - flat_iterator operator-(difference_type d) const - { return this->underlying - d; } - - difference_type operator-(flat_iterator const& o) const - { return this->underlying - o.underlying; } - - reference operator[](difference_type d) const { return *(*this + d); } - - auto operator==(flat_iterator const& o) const - { - using namespace std::rel_ops; - return this->underlying == o.underlying; - } - auto operator!=(flat_iterator const& o) const - { - using namespace std::rel_ops; - return this->underlying != o.underlying; - } - auto operator<(flat_iterator const& o) const - { return this->underlying < o.underlying; } - auto operator<=(flat_iterator const& o) const - { return this->underlying <= o.underlying; } - auto operator>(flat_iterator const& o) const - { return this->underlying > o.underlying; } - auto operator>=(flat_iterator const& o) const - { return this->underlying >= o.underlying; } - - It underlying; -}; - -template, typename TransparentKey = void> -struct first_compare -{ - first_compare(const Compare& comp) : - compare(comp) { - } - - bool operator()(Pair const& lhs, Pair const& rhs) const - { - return compare.get()(lhs.first, rhs.first); - } - - bool operator()(typename Pair::first_type const& lhs, Pair const& rhs) const - { - return compare.get()(lhs, rhs.first); - } - - bool operator()(Pair const& lhs, typename Pair::first_type const& rhs) const - { - return compare.get()(lhs.first, rhs); - } - - template - bool operator()(transparent_key_t const& lhs, Pair const& rhs) const - { - return compare.get()(lhs.get(), rhs.first); - } - - template - bool operator()(transparent_key_t const& lhs, typename Pair::first_type const& rhs) const - { - return compare.get()(lhs.get(), rhs); - } - - template - bool operator()(Pair const& lhs, transparent_key_t const& rhs) const - { - return compare.get()(lhs.first, rhs.get()); - } - - template - bool operator()(typename Pair::first_type const& lhs, transparent_key_t const& rhs) const - { - return compare.get()(lhs, rhs.get()); - } - - std::reference_wrapper compare; -}; - -template -class flat_container_base -{ -#include "container_traits.hpp" - D const* self() const { return static_cast(this); } - D* self() { return static_cast(this); } -public: - using key_compare = Compare; - const key_compare &key_comp() const { return self()->comp; } - - // Iterators - - const_iterator cbegin() const - noexcept(noexcept(std::declval().container.cbegin())) - { return self()->container.cbegin(); } - const_iterator begin() const - noexcept(noexcept(std::declval().container.begin())) - { return self()->container.begin(); } - iterator begin() - noexcept(noexcept(std::declval().container.begin())) - { return self()->container.begin(); } - - const_iterator cend() const - noexcept(noexcept(std::declval().container.cend())) - { return self()->container.cend(); } - const_iterator end() const - noexcept(noexcept(std::declval().container.end())) - { return self()->container.end(); } - iterator end() - noexcept(noexcept(std::declval().container.end())) - { return self()->container.end(); } - - const_reverse_iterator crbegin() const - noexcept(noexcept(std::declval().container.crbegin())) - { return self()->container.crbegin(); } - const_reverse_iterator rbegin() const - noexcept(noexcept(std::declval().container.rbegin())) - { return self()->container.rbegin(); } - reverse_iterator rbegin() - noexcept(noexcept(std::declval().container.rbegin())) - { return self()->container.rbegin(); } - - const_reverse_iterator crend() const - noexcept(noexcept(std::declval().container.crend())) - { return self()->container.crend(); } - const_reverse_iterator rend() const - noexcept(noexcept(std::declval().container.rend())) - { return self()->container.rend(); } - reverse_iterator rend() - noexcept(noexcept(std::declval().container.rend())) - { return self()->container.rend(); } - - // Capacity - - bool empty() const - noexcept(noexcept(std::declval().container.empty())) - { return self()->container.empty(); } - - size_type size() const - noexcept(noexcept(std::declval().container.size())) - { return self()->container.size(); } - - // Modifiers - - iterator insert(const_iterator hint, value_type const& value) - { return self()->insert(value).first; } - - iterator insert(const_iterator hint, value_type&& value) - { return self()->insert(std::move(value)).first; } - - template - void insert(InputIt first, InputIt last) - { - for(InputIt it = first; it != last; ++it) - self()->insert(*it); - } - - void insert(std::initializer_list ilist) - { self()->insert(ilist.begin(), ilist.end()); } - - void insert(std::initializer_list ilist, delay_sort_t d) - { self()->insert(ilist.begin(), ilist.end(), d); } - - template - auto emplace(Args&&... args) - { return self()->insert(value_type(std::forward(args)...)); } - - template - auto emplace_hint(const_iterator hint, Args&&... args) - { return self()->insert(value_type(std::forward(args)...)); } - - iterator erase(const_iterator pos) - noexcept(noexcept(std::declval().container.erase(pos.underlying))) - { return self()->container.erase(pos.underlying); } - - iterator erase(const_iterator first, const_iterator last) - noexcept(noexcept(std::declval().container.erase(first.underlying, - last.underlying))) - { return self()->container.erase(first.underlying, last.underlying); } - - void clear() - noexcept(noexcept(std::declval().container.clear())) - { self()->container.clear(); } - - void swap(D& other) - noexcept(D::has_noexcept_swap()) - { - using std::swap; - swap(self()->container, other.container); - } - - // Lookup - - const_iterator find(key_type const& key) const - { - const_iterator it = self()->lower_bound(key); - if(it == self()->end() || self()->value_comp()(key, *it)) - return self()->end(); - return it; - } - - iterator find(key_type const& key) - { - iterator it = self()->lower_bound(key); - if(it == self()->end() || self()->value_comp()(key, *it)) - return self()->end(); - return it; - } - - const_iterator lower_bound(key_type const& key) const - { - return std::lower_bound( - self()->begin(), self()->end(), - key, self()->value_comp()); - } - - iterator lower_bound(key_type const& key) - { - return std::lower_bound( - self()->begin(), self()->end(), - key, self()->value_comp()); - } - - const_iterator upper_bound(key_type const& key) const - { - return std::upper_bound( - self()->begin(), self()->end(), - key, self()->value_comp()); - } - - iterator upper_bound(key_type const& key) - { - return std::upper_bound( - self()->begin(), self()->end(), - key, self()->value_comp()); - } - - std::pair - equal_range(key_type const& key) const - { - return std::equal_range( - self()->begin(), self()->end(), - key, self()->value_comp()); - } - - std::pair equal_range(key_type const& key) - { - return std::equal_range( - self()->begin(), self()->end(), - key, self()->value_comp()); - } - -private: - static constexpr bool has_noexcept_swap() - { - using std::swap; - return noexcept(swap(*static_cast(nullptr), - *static_cast(nullptr))); - } - -protected: - template - void ds_insert_(InputIt first, InputIt last) - { - size_type const i = self()->size(); - for(InputIt it = first; it != last; ++it) - self()->container.push_back(*it); - std::sort( - self()->container.begin()+i, - self()->container.end(), - self()->value_comp()); - std::inplace_merge( - self()->container.begin(), - self()->container.begin()+i, - self()->container.end()); - // Note: Not calling unique here. Do it in the caller. - } -}; - -template -class flat_container_base> -: public flat_container_base -{ -#include "container_traits.hpp" - D const* self() const { return static_cast(this); } - D* self() { return static_cast(this); } - using B = flat_container_base; -public: - - using B::insert; - using B::find; - using B::lower_bound; - using B::upper_bound; - using B::equal_range; - - // Modifiers - - template - iterator insert(const_iterator hint, P&& value) - { return insert(std::forward

(value)).first; } - - // Lookup - - template - const_iterator find(K const& key) const - { - const_iterator it = self()->lower_bound(key); - if (it == self()->end() || self()->value_comp()(std::ref(key), *it)) - return self()->end(); - return it; - } - - template - iterator find(K const& key) - { - iterator it = self()->lower_bound(key); - if (it == self()->end() || self()->value_comp()(std::ref(key), *it)) - return self()->end(); - return it; - } - - template - const_iterator lower_bound(K const& key) const - { - return std::lower_bound( - self()->begin(), self()->end(), - std::ref(key), self()->value_comp()); - } - - template - iterator lower_bound(K const& key) - { - return std::lower_bound( - self()->begin(), self()->end(), - std::ref(key), self()->value_comp()); - } - - template - const_iterator upper_bound(K const& key) const - { - return std::upper_bound( - self()->begin(), self()->end(), - std::ref(key), self()->value_comp()); - } - - template - iterator upper_bound(K const& key) - { - return std::upper_bound( - self()->begin(), self()->end(), - std::ref(key), self()->value_comp()); - } - - template - std::pair - equal_range(K const& key) const - { - return std::equal_range( - self()->begin(), self()->end(), - std::ref(key), self()->value_comp()); - } - - template - std::pair equal_range(K const& key) - { - return std::equal_range( - self()->begin(), self()->end(), - std::ref(key), self()->value_comp()); - } -}; - -} // namespace fc -} // namespace impl - -#endif From 99882d25a01b40f48baae943e90a6479eddea744 Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Wed, 29 Jul 2020 01:03:09 -0700 Subject: [PATCH 066/175] Clean up --- external/tsl/ordered_hash.h | 1617 ----------------------------------- external/tsl/ordered_map.h | 833 ------------------ external/tsl/ordered_set.h | 688 --------------- 3 files changed, 3138 deletions(-) delete mode 100644 external/tsl/ordered_hash.h delete mode 100644 external/tsl/ordered_map.h delete mode 100644 external/tsl/ordered_set.h diff --git a/external/tsl/ordered_hash.h b/external/tsl/ordered_hash.h deleted file mode 100644 index 46d9b4877..000000000 --- a/external/tsl/ordered_hash.h +++ /dev/null @@ -1,1617 +0,0 @@ -/** - * MIT License - * - * Copyright (c) 2017 Thibaut Goetghebuer-Planchon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef TSL_ORDERED_HASH_H -#define TSL_ORDERED_HASH_H - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/** - * Macros for compatibility with GCC 4.8 - */ -#if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 9)) -# define TSL_OH_NO_CONTAINER_ERASE_CONST_ITERATOR -# define TSL_OH_NO_CONTAINER_EMPLACE_CONST_ITERATOR -#endif - -/** - * Only activate tsl_oh_assert if TSL_DEBUG is defined. - * This way we avoid the performance hit when NDEBUG is not defined with assert as tsl_oh_assert is used a lot - * (people usually compile with "-O3" and not "-O3 -DNDEBUG"). - */ -#ifdef TSL_DEBUG -# define tsl_oh_assert(expr) assert(expr) -#else -# define tsl_oh_assert(expr) (static_cast(0)) -#endif - -/** - * If exceptions are enabled, throw the exception passed in parameter, otherwise call std::terminate. - */ -#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || (defined (_MSC_VER) && defined (_CPPUNWIND))) && !defined(TSL_NO_EXCEPTIONS) -# define TSL_OH_THROW_OR_TERMINATE(ex, msg) throw ex(msg) -#else -# define TSL_OH_NO_EXCEPTIONS -# ifdef NDEBUG -# define TSL_OH_THROW_OR_TERMINATE(ex, msg) std::terminate() -# else -# include -# define TSL_OH_THROW_OR_TERMINATE(ex, msg) do { std::cerr << msg << std::endl; std::terminate(); } while(0) -# endif -#endif - - -namespace tsl { - -namespace detail_ordered_hash { - -template -struct make_void { - using type = void; -}; - -template -struct has_is_transparent: std::false_type { -}; - -template -struct has_is_transparent::type>: std::true_type { -}; - - -template -struct is_vector: std::false_type { -}; - -template -struct is_vector>::value - >::type>: std::true_type { -}; - -// Only available in C++17, we need to be compatible with C++11 -template -const T& clamp( const T& v, const T& lo, const T& hi) { - return std::min(hi, std::max(lo, v)); -} - -template -static T numeric_cast(U value, const char* error_message = "numeric_cast() failed.") { - T ret = static_cast(value); - if(static_cast(ret) != value) { - TSL_OH_THROW_OR_TERMINATE(std::runtime_error, error_message); - } - - const bool is_same_signedness = (std::is_unsigned::value && std::is_unsigned::value) || - (std::is_signed::value && std::is_signed::value); - if(!is_same_signedness && (ret < T{}) != (value < U{})) { - TSL_OH_THROW_OR_TERMINATE(std::runtime_error, error_message); - } - - return ret; -} - - -/** - * Fixed size type used to represent size_type values on serialization. Need to be big enough - * to represent a std::size_t on 32 and 64 bits platforms, and must be the same size on both platforms. - */ -using slz_size_type = std::uint64_t; -static_assert(std::numeric_limits::max() >= std::numeric_limits::max(), - "slz_size_type must be >= std::size_t"); - -template -static T deserialize_value(Deserializer& deserializer) { - // MSVC < 2017 is not conformant, circumvent the problem by removing the template keyword -#if defined (_MSC_VER) && _MSC_VER < 1910 - return deserializer.Deserializer::operator()(); -#else - return deserializer.Deserializer::template operator()(); -#endif -} - - -/** - * Each bucket entry stores an index which is the index in m_values corresponding to the bucket's value - * and a hash (which may be truncated to 32 bits depending on IndexType) corresponding to the hash of the value. - * - * The size of IndexType limits the size of the hash table to std::numeric_limits::max() - 1 elements (-1 due to - * a reserved value used to mark a bucket as empty). - */ -template -class bucket_entry { - static_assert(std::is_unsigned::value, "IndexType must be an unsigned value."); - static_assert(std::numeric_limits::max() <= std::numeric_limits::max(), - "std::numeric_limits::max() must be <= std::numeric_limits::max()."); - -public: - using index_type = IndexType; - using truncated_hash_type = typename std::conditional::max() <= - std::numeric_limits::max(), - std::uint_least32_t, - std::size_t>::type; - - bucket_entry() noexcept: m_index(EMPTY_MARKER_INDEX), m_hash(0) { - } - - bool empty() const noexcept { - return m_index == EMPTY_MARKER_INDEX; - } - - void clear() noexcept { - m_index = EMPTY_MARKER_INDEX; - } - - index_type index() const noexcept { - tsl_oh_assert(!empty()); - return m_index; - } - - index_type& index_ref() noexcept { - tsl_oh_assert(!empty()); - return m_index; - } - - void set_index(index_type index) noexcept { - tsl_oh_assert(index <= max_size()); - - m_index = index; - } - - truncated_hash_type truncated_hash() const noexcept { - tsl_oh_assert(!empty()); - return m_hash; - } - - truncated_hash_type& truncated_hash_ref() noexcept { - tsl_oh_assert(!empty()); - return m_hash; - } - - void set_hash(std::size_t hash) noexcept { - m_hash = truncate_hash(hash); - } - - template - void serialize(Serializer& serializer) const { - const slz_size_type index = m_index; - serializer(index); - - const slz_size_type hash = m_hash; - serializer(hash); - } - - template - static bucket_entry deserialize(Deserializer& deserializer) { - const slz_size_type index = deserialize_value(deserializer); - const slz_size_type hash = deserialize_value(deserializer); - - bucket_entry bentry; - bentry.m_index = numeric_cast(index, "Deserialized index is too big."); - bentry.m_hash = numeric_cast(hash, "Deserialized hash is too big."); - - return bentry; - } - - - - static truncated_hash_type truncate_hash(std::size_t hash) noexcept { - return truncated_hash_type(hash); - } - - static std::size_t max_size() noexcept { - return static_cast(std::numeric_limits::max()) - NB_RESERVED_INDEXES; - } - -private: - static const index_type EMPTY_MARKER_INDEX = std::numeric_limits::max(); - static const std::size_t NB_RESERVED_INDEXES = 1; - - index_type m_index; - truncated_hash_type m_hash; -}; - - - -/** - * Internal common class used by ordered_map and ordered_set. - * - * ValueType is what will be stored by ordered_hash (usually std::pair for map and Key for set). - * - * KeySelect should be a FunctionObject which takes a ValueType in parameter and return a reference to the key. - * - * ValueSelect should be a FunctionObject which takes a ValueType in parameter and return a reference to the value. - * ValueSelect should be void if there is no value (in set for example). - * - * ValueTypeContainer is the container which will be used to store ValueType values. - * Usually a std::deque or std::vector. - * - * - * - * The ordered_hash structure is a hash table which preserves the order of insertion of the elements. - * To do so, it stores the values in the ValueTypeContainer (m_values) using emplace_back at each - * insertion of a new element. Another structure (m_buckets of type std::vector) will - * serve as buckets array for the hash table part. Each bucket stores an index which corresponds to - * the index in m_values where the bucket's value is and the (truncated) hash of this value. An index - * is used instead of a pointer to the value to reduce the size of each bucket entry. - * - * To resolve collisions in the buckets array, the structures use robin hood linear probing with - * backward shift deletion. - */ -template -class ordered_hash: private Hash, private KeyEqual { -private: - template - using has_mapped_type = typename std::integral_constant::value>; - - static_assert(std::is_same::value, - "ValueTypeContainer::value_type != ValueType. " - "Check that the ValueTypeContainer has 'Key' as type for a set or 'std::pair' as type for a map."); - - static_assert(std::is_same::value, - "ValueTypeContainer::allocator_type != Allocator. " - "Check that the allocator for ValueTypeContainer is the same as Allocator."); - - static_assert(std::is_same::value, - "Allocator::value_type != ValueType. " - "Check that the allocator has 'Key' as type for a set or 'std::pair' as type for a map."); - - -public: - template - class ordered_iterator; - - using key_type = typename KeySelect::key_type; - using value_type = ValueType; - using size_type = std::size_t; - using difference_type = std::ptrdiff_t; - using hasher = Hash; - using key_equal = KeyEqual; - using allocator_type = Allocator; - using reference = value_type&; - using const_reference = const value_type&; - using pointer = value_type*; - using const_pointer = const value_type*; - using iterator = ordered_iterator; - using const_iterator = ordered_iterator; - using reverse_iterator = std::reverse_iterator; - using const_reverse_iterator = std::reverse_iterator; - - using values_container_type = ValueTypeContainer; - -public: - template - class ordered_iterator { - friend class ordered_hash; - - private: - using iterator = typename std::conditional::type; - - - ordered_iterator(iterator it) noexcept: m_iterator(it) { - } - - public: - using iterator_category = std::random_access_iterator_tag; - using value_type = const typename ordered_hash::value_type; - using difference_type = typename iterator::difference_type; - using reference = value_type&; - using pointer = value_type*; - - - ordered_iterator() noexcept { - } - - // Copy constructor from iterator to const_iterator. - template::type* = nullptr> - ordered_iterator(const ordered_iterator& other) noexcept: m_iterator(other.m_iterator) { - } - - ordered_iterator(const ordered_iterator& other) = default; - ordered_iterator(ordered_iterator&& other) = default; - ordered_iterator& operator=(const ordered_iterator& other) = default; - ordered_iterator& operator=(ordered_iterator&& other) = default; - - const typename ordered_hash::key_type& key() const { - return KeySelect()(*m_iterator); - } - - template::value && IsConst>::type* = nullptr> - const typename U::value_type& value() const { - return U()(*m_iterator); - } - - template::value && !IsConst>::type* = nullptr> - typename U::value_type& value() { - return U()(*m_iterator); - } - - reference operator*() const { return *m_iterator; } - pointer operator->() const { return m_iterator.operator->(); } - - ordered_iterator& operator++() { ++m_iterator; return *this; } - ordered_iterator& operator--() { --m_iterator; return *this; } - - ordered_iterator operator++(int) { ordered_iterator tmp(*this); ++(*this); return tmp; } - ordered_iterator operator--(int) { ordered_iterator tmp(*this); --(*this); return tmp; } - - reference operator[](difference_type n) const { return m_iterator[n]; } - - ordered_iterator& operator+=(difference_type n) { m_iterator += n; return *this; } - ordered_iterator& operator-=(difference_type n) { m_iterator -= n; return *this; } - - ordered_iterator operator+(difference_type n) { ordered_iterator tmp(*this); tmp += n; return tmp; } - ordered_iterator operator-(difference_type n) { ordered_iterator tmp(*this); tmp -= n; return tmp; } - - friend bool operator==(const ordered_iterator& lhs, const ordered_iterator& rhs) { - return lhs.m_iterator == rhs.m_iterator; - } - - friend bool operator!=(const ordered_iterator& lhs, const ordered_iterator& rhs) { - return lhs.m_iterator != rhs.m_iterator; - } - - friend bool operator<(const ordered_iterator& lhs, const ordered_iterator& rhs) { - return lhs.m_iterator < rhs.m_iterator; - } - - friend bool operator>(const ordered_iterator& lhs, const ordered_iterator& rhs) { - return lhs.m_iterator > rhs.m_iterator; - } - - friend bool operator<=(const ordered_iterator& lhs, const ordered_iterator& rhs) { - return lhs.m_iterator <= rhs.m_iterator; - } - - friend bool operator>=(const ordered_iterator& lhs, const ordered_iterator& rhs) { - return lhs.m_iterator >= rhs.m_iterator; - } - - friend ordered_iterator operator+(difference_type n, const ordered_iterator& it) { - return n + it.m_iterator; - } - - friend difference_type operator-(const ordered_iterator& lhs, const ordered_iterator& rhs) { - return lhs.m_iterator - rhs.m_iterator; - } - - private: - iterator m_iterator; - }; - - -private: - using bucket_entry = tsl::detail_ordered_hash::bucket_entry; - - using buckets_container_allocator = typename - std::allocator_traits::template rebind_alloc; - - using buckets_container_type = std::vector; - - - using truncated_hash_type = typename bucket_entry::truncated_hash_type; - using index_type = typename bucket_entry::index_type; - -public: - ordered_hash(size_type bucket_count, - const Hash& hash, - const KeyEqual& equal, - const Allocator& alloc, - float max_load_factor): Hash(hash), - KeyEqual(equal), - m_buckets_data(alloc), - m_buckets(static_empty_bucket_ptr()), - m_hash_mask(0), - m_values(alloc), - m_grow_on_next_insert(false) - { - if(bucket_count > max_bucket_count()) { - TSL_OH_THROW_OR_TERMINATE(std::length_error, "The map exceeds its maximum size."); - } - - if(bucket_count > 0) { - bucket_count = round_up_to_power_of_two(bucket_count); - - m_buckets_data.resize(bucket_count); - m_buckets = m_buckets_data.data(), - m_hash_mask = bucket_count - 1; - } - - this->max_load_factor(max_load_factor); - } - - ordered_hash(const ordered_hash& other): Hash(other), - KeyEqual(other), - m_buckets_data(other.m_buckets_data), - m_buckets(m_buckets_data.empty()?static_empty_bucket_ptr(): - m_buckets_data.data()), - m_hash_mask(other.m_hash_mask), - m_values(other.m_values), - m_load_threshold(other.m_load_threshold), - m_max_load_factor(other.m_max_load_factor), - m_grow_on_next_insert(other.m_grow_on_next_insert) - { - } - - ordered_hash(ordered_hash&& other) noexcept(std::is_nothrow_move_constructible::value && - std::is_nothrow_move_constructible::value && - std::is_nothrow_move_constructible::value && - std::is_nothrow_move_constructible::value) - : Hash(std::move(static_cast(other))), - KeyEqual(std::move(static_cast(other))), - m_buckets_data(std::move(other.m_buckets_data)), - m_buckets(m_buckets_data.empty()?static_empty_bucket_ptr(): - m_buckets_data.data()), - m_hash_mask(other.m_hash_mask), - m_values(std::move(other.m_values)), - m_load_threshold(other.m_load_threshold), - m_max_load_factor(other.m_max_load_factor), - m_grow_on_next_insert(other.m_grow_on_next_insert) - { - other.m_buckets_data.clear(); - other.m_buckets = static_empty_bucket_ptr(); - other.m_hash_mask = 0; - other.m_values.clear(); - other.m_load_threshold = 0; - other.m_grow_on_next_insert = false; - } - - ordered_hash& operator=(const ordered_hash& other) { - if(&other != this) { - Hash::operator=(other); - KeyEqual::operator=(other); - - m_buckets_data = other.m_buckets_data; - m_buckets = m_buckets_data.empty()?static_empty_bucket_ptr(): - m_buckets_data.data(); - - m_hash_mask = other.m_hash_mask; - m_values = other.m_values; - m_load_threshold = other.m_load_threshold; - m_max_load_factor = other.m_max_load_factor; - m_grow_on_next_insert = other.m_grow_on_next_insert; - } - - return *this; - } - - ordered_hash& operator=(ordered_hash&& other) { - other.swap(*this); - other.clear(); - - return *this; - } - - allocator_type get_allocator() const { - return m_values.get_allocator(); - } - - - /* - * Iterators - */ - iterator begin() noexcept { - return iterator(m_values.begin()); - } - - const_iterator begin() const noexcept { - return cbegin(); - } - - const_iterator cbegin() const noexcept { - return const_iterator(m_values.cbegin()); - } - - iterator end() noexcept { - return iterator(m_values.end()); - } - - const_iterator end() const noexcept { - return cend(); - } - - const_iterator cend() const noexcept { - return const_iterator(m_values.cend()); - } - - - reverse_iterator rbegin() noexcept { - return reverse_iterator(m_values.end()); - } - - const_reverse_iterator rbegin() const noexcept { - return rcbegin(); - } - - const_reverse_iterator rcbegin() const noexcept { - return const_reverse_iterator(m_values.cend()); - } - - reverse_iterator rend() noexcept { - return reverse_iterator(m_values.begin()); - } - - const_reverse_iterator rend() const noexcept { - return rcend(); - } - - const_reverse_iterator rcend() const noexcept { - return const_reverse_iterator(m_values.cbegin()); - } - - - /* - * Capacity - */ - bool empty() const noexcept { - return m_values.empty(); - } - - size_type size() const noexcept { - return m_values.size(); - } - - size_type max_size() const noexcept { - return std::min(bucket_entry::max_size(), m_values.max_size()); - } - - - /* - * Modifiers - */ - void clear() noexcept { - for(auto& bucket: m_buckets_data) { - bucket.clear(); - } - - m_values.clear(); - m_grow_on_next_insert = false; - } - - template - std::pair insert(P&& value) { - return insert_impl(KeySelect()(value), std::forward

(value)); - } - - template - iterator insert_hint(const_iterator hint, P&& value) { - if(hint != cend() && compare_keys(KeySelect()(*hint), KeySelect()(value))) { - return mutable_iterator(hint); - } - - return insert(std::forward

(value)).first; - } - - template - void insert(InputIt first, InputIt last) { - if(std::is_base_of::iterator_category>::value) - { - const auto nb_elements_insert = std::distance(first, last); - const size_type nb_free_buckets = m_load_threshold - size(); - tsl_oh_assert(m_load_threshold >= size()); - - if(nb_elements_insert > 0 && nb_free_buckets < size_type(nb_elements_insert)) { - reserve(size() + size_type(nb_elements_insert)); - } - } - - for(; first != last; ++first) { - insert(*first); - } - } - - - - template - std::pair insert_or_assign(K&& key, M&& value) { - auto it = try_emplace(std::forward(key), std::forward(value)); - if(!it.second) { - it.first.value() = std::forward(value); - } - - return it; - } - - template - iterator insert_or_assign(const_iterator hint, K&& key, M&& obj) { - if(hint != cend() && compare_keys(KeySelect()(*hint), key)) { - auto it = mutable_iterator(hint); - it.value() = std::forward(obj); - - return it; - } - - return insert_or_assign(std::forward(key), std::forward(obj)).first; - } - - - - template - std::pair emplace(Args&&... args) { - return insert(value_type(std::forward(args)...)); - } - - template - iterator emplace_hint(const_iterator hint, Args&&... args) { - return insert_hint(hint, value_type(std::forward(args)...)); - } - - - - template - std::pair try_emplace(K&& key, Args&&... value_args) { - return insert_impl(key, std::piecewise_construct, - std::forward_as_tuple(std::forward(key)), - std::forward_as_tuple(std::forward(value_args)...)); - } - - template - iterator try_emplace_hint(const_iterator hint, K&& key, Args&&... args) { - if(hint != cend() && compare_keys(KeySelect()(*hint), key)) { - return mutable_iterator(hint); - } - - return try_emplace(std::forward(key), std::forward(args)...).first; - } - - - - /** - * Here to avoid `template size_type erase(const K& key)` being used when - * we use an `iterator` instead of a `const_iterator`. - */ - iterator erase(iterator pos) { - return erase(const_iterator(pos)); - } - - iterator erase(const_iterator pos) { - tsl_oh_assert(pos != cend()); - - const std::size_t index_erase = iterator_to_index(pos); - - auto it_bucket = find_key(pos.key(), hash_key(pos.key())); - tsl_oh_assert(it_bucket != m_buckets_data.end()); - - erase_value_from_bucket(it_bucket); - - /* - * One element was removed from m_values, due to the left shift the next element - * is now at the position of the previous element (or end if none). - */ - return begin() + index_erase; - } - - iterator erase(const_iterator first, const_iterator last) { - if(first == last) { - return mutable_iterator(first); - } - - tsl_oh_assert(std::distance(first, last) > 0); - const std::size_t start_index = iterator_to_index(first); - const std::size_t nb_values = std::size_t(std::distance(first, last)); - const std::size_t end_index = start_index + nb_values; - - // Delete all values -#ifdef TSL_OH_NO_CONTAINER_ERASE_CONST_ITERATOR - auto next_it = m_values.erase(mutable_iterator(first).m_iterator, mutable_iterator(last).m_iterator); -#else - auto next_it = m_values.erase(first.m_iterator, last.m_iterator); -#endif - - /* - * Mark the buckets corresponding to the values as empty and do a backward shift. - * - * Also, the erase operation on m_values has shifted all the values on the right of last.m_iterator. - * Adapt the indexes for these values. - */ - std::size_t ibucket = 0; - while(ibucket < m_buckets_data.size()) { - if(m_buckets[ibucket].empty()) { - ibucket++; - } - else if(m_buckets[ibucket].index() >= start_index && m_buckets[ibucket].index() < end_index) { - m_buckets[ibucket].clear(); - backward_shift(ibucket); - // Don't increment ibucket, backward_shift may have replaced current bucket. - } - else if(m_buckets[ibucket].index() >= end_index) { - m_buckets[ibucket].set_index(index_type(m_buckets[ibucket].index() - nb_values)); - ibucket++; - } - else { - ibucket++; - } - } - - return iterator(next_it); - } - - - template - size_type erase(const K& key) { - return erase(key, hash_key(key)); - } - - template - size_type erase(const K& key, std::size_t hash) { - return erase_impl(key, hash); - } - - void swap(ordered_hash& other) { - using std::swap; - - swap(static_cast(*this), static_cast(other)); - swap(static_cast(*this), static_cast(other)); - swap(m_buckets_data, other.m_buckets_data); - swap(m_buckets, other.m_buckets); - swap(m_hash_mask, other.m_hash_mask); - swap(m_values, other.m_values); - swap(m_load_threshold, other.m_load_threshold); - swap(m_max_load_factor, other.m_max_load_factor); - swap(m_grow_on_next_insert, other.m_grow_on_next_insert); - } - - - - - /* - * Lookup - */ - template::value>::type* = nullptr> - typename U::value_type& at(const K& key) { - return at(key, hash_key(key)); - } - - template::value>::type* = nullptr> - typename U::value_type& at(const K& key, std::size_t hash) { - return const_cast(static_cast(this)->at(key, hash)); - } - - template::value>::type* = nullptr> - const typename U::value_type& at(const K& key) const { - return at(key, hash_key(key)); - } - - template::value>::type* = nullptr> - const typename U::value_type& at(const K& key, std::size_t hash) const { - auto it = find(key, hash); - if(it != end()) { - return it.value(); - } - else { - TSL_OH_THROW_OR_TERMINATE(std::out_of_range, "Couldn't find the key."); - } - } - - - template::value>::type* = nullptr> - typename U::value_type& operator[](K&& key) { - return try_emplace(std::forward(key)).first.value(); - } - - - template - size_type count(const K& key) const { - return count(key, hash_key(key)); - } - - template - size_type count(const K& key, std::size_t hash) const { - if(find(key, hash) == cend()) { - return 0; - } - else { - return 1; - } - } - - template - iterator find(const K& key) { - return find(key, hash_key(key)); - } - - template - iterator find(const K& key, std::size_t hash) { - auto it_bucket = find_key(key, hash); - return (it_bucket != m_buckets_data.end())?iterator(m_values.begin() + it_bucket->index()):end(); - } - - template - const_iterator find(const K& key) const { - return find(key, hash_key(key)); - } - - template - const_iterator find(const K& key, std::size_t hash) const { - auto it_bucket = find_key(key, hash); - return (it_bucket != m_buckets_data.cend())?const_iterator(m_values.begin() + it_bucket->index()):end(); - } - - - template - std::pair equal_range(const K& key) { - return equal_range(key, hash_key(key)); - } - - template - std::pair equal_range(const K& key, std::size_t hash) { - iterator it = find(key, hash); - return std::make_pair(it, (it == end())?it:std::next(it)); - } - - template - std::pair equal_range(const K& key) const { - return equal_range(key, hash_key(key)); - } - - template - std::pair equal_range(const K& key, std::size_t hash) const { - const_iterator it = find(key, hash); - return std::make_pair(it, (it == cend())?it:std::next(it)); - } - - - /* - * Bucket interface - */ - size_type bucket_count() const { - return m_buckets_data.size(); - } - - size_type max_bucket_count() const { - return m_buckets_data.max_size(); - } - - /* - * Hash policy - */ - float load_factor() const { - if(bucket_count() == 0) { - return 0; - } - - return float(size())/float(bucket_count()); - } - - float max_load_factor() const { - return m_max_load_factor; - } - - void max_load_factor(float ml) { - m_max_load_factor = clamp(ml, float(MAX_LOAD_FACTOR__MINIMUM), - float(MAX_LOAD_FACTOR__MAXIMUM)); - - m_max_load_factor = ml; - m_load_threshold = size_type(float(bucket_count())*m_max_load_factor); - } - - void rehash(size_type count) { - count = std::max(count, size_type(std::ceil(float(size())/max_load_factor()))); - rehash_impl(count); - } - - void reserve(size_type count) { - reserve_space_for_values(count); - - count = size_type(std::ceil(float(count)/max_load_factor())); - rehash(count); - } - - - /* - * Observers - */ - hasher hash_function() const { - return static_cast(*this); - } - - key_equal key_eq() const { - return static_cast(*this); - } - - - /* - * Other - */ - iterator mutable_iterator(const_iterator pos) { - return iterator(m_values.begin() + iterator_to_index(pos)); - } - - iterator nth(size_type index) { - tsl_oh_assert(index <= size()); - return iterator(m_values.begin() + index); - } - - const_iterator nth(size_type index) const { - tsl_oh_assert(index <= size()); - return const_iterator(m_values.cbegin() + index); - } - - const_reference front() const { - tsl_oh_assert(!empty()); - return m_values.front(); - } - - const_reference back() const { - tsl_oh_assert(!empty()); - return m_values.back(); - } - - const values_container_type& values_container() const noexcept { - return m_values; - } - - template::value>::type* = nullptr> - const typename values_container_type::value_type* data() const noexcept { - return m_values.data(); - } - - template::value>::type* = nullptr> - size_type capacity() const noexcept { - return m_values.capacity(); - } - - void shrink_to_fit() { - m_values.shrink_to_fit(); - } - - - template - std::pair insert_at_position(const_iterator pos, P&& value) { - return insert_at_position_impl(pos.m_iterator, KeySelect()(value), std::forward

(value)); - } - - template - std::pair emplace_at_position(const_iterator pos, Args&&... args) { - return insert_at_position(pos, value_type(std::forward(args)...)); - } - - template - std::pair try_emplace_at_position(const_iterator pos, K&& key, Args&&... value_args) { - return insert_at_position_impl(pos.m_iterator, key, - std::piecewise_construct, - std::forward_as_tuple(std::forward(key)), - std::forward_as_tuple(std::forward(value_args)...)); - } - - - void pop_back() { - tsl_oh_assert(!empty()); - erase(std::prev(end())); - } - - - /** - * Here to avoid `template size_type unordered_erase(const K& key)` being used when - * we use a iterator instead of a const_iterator. - */ - iterator unordered_erase(iterator pos) { - return unordered_erase(const_iterator(pos)); - } - - iterator unordered_erase(const_iterator pos) { - const std::size_t index_erase = iterator_to_index(pos); - unordered_erase(pos.key()); - - /* - * One element was deleted, index_erase now points to the next element as the elements after - * the deleted value were shifted to the left in m_values (will be end() if we deleted the last element). - */ - return begin() + index_erase; - } - - template - size_type unordered_erase(const K& key) { - return unordered_erase(key, hash_key(key)); - } - - template - size_type unordered_erase(const K& key, std::size_t hash) { - auto it_bucket_key = find_key(key, hash); - if(it_bucket_key == m_buckets_data.end()) { - return 0; - } - - /** - * If we are not erasing the last element in m_values, we swap - * the element we are erasing with the last element. We then would - * just have to do a pop_back() in m_values. - */ - if(!compare_keys(key, KeySelect()(back()))) { - auto it_bucket_last_elem = find_key(KeySelect()(back()), hash_key(KeySelect()(back()))); - tsl_oh_assert(it_bucket_last_elem != m_buckets_data.end()); - tsl_oh_assert(it_bucket_last_elem->index() == m_values.size() - 1); - - using std::swap; - swap(m_values[it_bucket_key->index()], m_values[it_bucket_last_elem->index()]); - swap(it_bucket_key->index_ref(), it_bucket_last_elem->index_ref()); - } - - erase_value_from_bucket(it_bucket_key); - - return 1; - } - - template - void serialize(Serializer& serializer) const { - serialize_impl(serializer); - } - - template - void deserialize(Deserializer& deserializer, bool hash_compatible) { - deserialize_impl(deserializer, hash_compatible); - } - - friend bool operator==(const ordered_hash& lhs, const ordered_hash& rhs) { - return lhs.m_values == rhs.m_values; - } - - friend bool operator!=(const ordered_hash& lhs, const ordered_hash& rhs) { - return lhs.m_values != rhs.m_values; - } - - friend bool operator<(const ordered_hash& lhs, const ordered_hash& rhs) { - return lhs.m_values < rhs.m_values; - } - - friend bool operator<=(const ordered_hash& lhs, const ordered_hash& rhs) { - return lhs.m_values <= rhs.m_values; - } - - friend bool operator>(const ordered_hash& lhs, const ordered_hash& rhs) { - return lhs.m_values > rhs.m_values; - } - - friend bool operator>=(const ordered_hash& lhs, const ordered_hash& rhs) { - return lhs.m_values >= rhs.m_values; - } - - -private: - template - std::size_t hash_key(const K& key) const { - return Hash::operator()(key); - } - - template - bool compare_keys(const K1& key1, const K2& key2) const { - return KeyEqual::operator()(key1, key2); - } - - template - typename buckets_container_type::iterator find_key(const K& key, std::size_t hash) { - auto it = static_cast(this)->find_key(key, hash); - return m_buckets_data.begin() + std::distance(m_buckets_data.cbegin(), it); - } - - /** - * Return bucket which has the key 'key' or m_buckets_data.end() if none. - * - * From the bucket_for_hash, search for the value until we either find an empty bucket - * or a bucket which has a value with a distance from its ideal bucket longer - * than the probe length for the value we are looking for. - */ - template - typename buckets_container_type::const_iterator find_key(const K& key, std::size_t hash) const { - for(std::size_t ibucket = bucket_for_hash(hash), dist_from_ideal_bucket = 0; ; - ibucket = next_bucket(ibucket), dist_from_ideal_bucket++) - { - if(m_buckets[ibucket].empty()) { - return m_buckets_data.end(); - } - else if(m_buckets[ibucket].truncated_hash() == bucket_entry::truncate_hash(hash) && - compare_keys(key, KeySelect()(m_values[m_buckets[ibucket].index()]))) - { - return m_buckets_data.begin() + ibucket; - } - else if(dist_from_ideal_bucket > distance_from_ideal_bucket(ibucket)) { - return m_buckets_data.end(); - } - } - } - - void rehash_impl(size_type bucket_count) { - tsl_oh_assert(bucket_count >= size_type(std::ceil(float(size())/max_load_factor()))); - - if(bucket_count > max_bucket_count()) { - TSL_OH_THROW_OR_TERMINATE(std::length_error, "The map exceeds its maximum size."); - } - - if(bucket_count > 0) { - bucket_count = round_up_to_power_of_two(bucket_count); - } - - if(bucket_count == this->bucket_count()) { - return; - } - - - buckets_container_type old_buckets(bucket_count); - m_buckets_data.swap(old_buckets); - m_buckets = m_buckets_data.empty()?static_empty_bucket_ptr(): - m_buckets_data.data(); - // Everything should be noexcept from here. - - m_hash_mask = (bucket_count > 0)?(bucket_count - 1):0; - this->max_load_factor(m_max_load_factor); - m_grow_on_next_insert = false; - - - - for(const bucket_entry& old_bucket: old_buckets) { - if(old_bucket.empty()) { - continue; - } - - truncated_hash_type insert_hash = old_bucket.truncated_hash(); - index_type insert_index = old_bucket.index(); - - for(std::size_t ibucket = bucket_for_hash(insert_hash), dist_from_ideal_bucket = 0; ; - ibucket = next_bucket(ibucket), dist_from_ideal_bucket++) - { - if(m_buckets[ibucket].empty()) { - m_buckets[ibucket].set_index(insert_index); - m_buckets[ibucket].set_hash(insert_hash); - break; - } - - const std::size_t distance = distance_from_ideal_bucket(ibucket); - if(dist_from_ideal_bucket > distance) { - std::swap(insert_index, m_buckets[ibucket].index_ref()); - std::swap(insert_hash, m_buckets[ibucket].truncated_hash_ref()); - dist_from_ideal_bucket = distance; - } - } - } - } - - template::value>::type* = nullptr> - void reserve_space_for_values(size_type count) { - m_values.reserve(count); - } - - template::value>::type* = nullptr> - void reserve_space_for_values(size_type /*count*/) { - } - - /** - * Swap the empty bucket with the values on its right until we cross another empty bucket - * or if the other bucket has a distance_from_ideal_bucket == 0. - */ - void backward_shift(std::size_t empty_ibucket) noexcept { - tsl_oh_assert(m_buckets[empty_ibucket].empty()); - - std::size_t previous_ibucket = empty_ibucket; - for(std::size_t current_ibucket = next_bucket(previous_ibucket); - !m_buckets[current_ibucket].empty() && distance_from_ideal_bucket(current_ibucket) > 0; - previous_ibucket = current_ibucket, current_ibucket = next_bucket(current_ibucket)) - { - std::swap(m_buckets[current_ibucket], m_buckets[previous_ibucket]); - } - } - - void erase_value_from_bucket(typename buckets_container_type::iterator it_bucket) { - tsl_oh_assert(it_bucket != m_buckets_data.end() && !it_bucket->empty()); - - m_values.erase(m_values.begin() + it_bucket->index()); - - /* - * m_values.erase shifted all the values on the right of the erased value, - * shift the indexes by -1 in the buckets array for these values. - */ - if(it_bucket->index() != m_values.size()) { - shift_indexes_in_buckets(it_bucket->index(), -1); - } - - // Mark the bucket as empty and do a backward shift of the values on the right - it_bucket->clear(); - backward_shift(std::size_t(std::distance(m_buckets_data.begin(), it_bucket))); - } - - /** - * Go through each value from [from_ivalue, m_values.size()) in m_values and for each - * bucket corresponding to the value, shift the index by delta. - * - * delta must be equal to 1 or -1. - */ - void shift_indexes_in_buckets(index_type from_ivalue, int delta) noexcept { - tsl_oh_assert(delta == 1 || delta == -1); - - for(std::size_t ivalue = from_ivalue; ivalue < m_values.size(); ivalue++) { - // All the values in m_values have been shifted by delta. Find the bucket corresponding - // to the value m_values[ivalue] - const index_type old_index = static_cast(ivalue - delta); - - std::size_t ibucket = bucket_for_hash(hash_key(KeySelect()(m_values[ivalue]))); - while(m_buckets[ibucket].index() != old_index) { - ibucket = next_bucket(ibucket); - } - - m_buckets[ibucket].set_index(index_type(ivalue)); - } - } - - template - size_type erase_impl(const K& key, std::size_t hash) { - auto it_bucket = find_key(key, hash); - if(it_bucket != m_buckets_data.end()) { - erase_value_from_bucket(it_bucket); - - return 1; - } - else { - return 0; - } - } - - /** - * Insert the element at the end. - */ - template - std::pair insert_impl(const K& key, Args&&... value_type_args) { - const std::size_t hash = hash_key(key); - - std::size_t ibucket = bucket_for_hash(hash); - std::size_t dist_from_ideal_bucket = 0; - - while(!m_buckets[ibucket].empty() && dist_from_ideal_bucket <= distance_from_ideal_bucket(ibucket)) { - if(m_buckets[ibucket].truncated_hash() == bucket_entry::truncate_hash(hash) && - compare_keys(key, KeySelect()(m_values[m_buckets[ibucket].index()]))) - { - return std::make_pair(begin() + m_buckets[ibucket].index(), false); - } - - ibucket = next_bucket(ibucket); - dist_from_ideal_bucket++; - } - - if(size() >= max_size()) { - TSL_OH_THROW_OR_TERMINATE(std::length_error, "We reached the maximum size for the hash table."); - } - - - if(grow_on_high_load()) { - ibucket = bucket_for_hash(hash); - dist_from_ideal_bucket = 0; - } - - - m_values.emplace_back(std::forward(value_type_args)...); - insert_index(ibucket, dist_from_ideal_bucket, - index_type(m_values.size() - 1), bucket_entry::truncate_hash(hash)); - - - return std::make_pair(std::prev(end()), true); - } - - /** - * Insert the element before insert_position. - */ - template - std::pair insert_at_position_impl(typename values_container_type::const_iterator insert_position, - const K& key, Args&&... value_type_args) - { - const std::size_t hash = hash_key(key); - - std::size_t ibucket = bucket_for_hash(hash); - std::size_t dist_from_ideal_bucket = 0; - - while(!m_buckets[ibucket].empty() && dist_from_ideal_bucket <= distance_from_ideal_bucket(ibucket)) { - if(m_buckets[ibucket].truncated_hash() == bucket_entry::truncate_hash(hash) && - compare_keys(key, KeySelect()(m_values[m_buckets[ibucket].index()]))) - { - return std::make_pair(begin() + m_buckets[ibucket].index(), false); - } - - ibucket = next_bucket(ibucket); - dist_from_ideal_bucket++; - } - - if(size() >= max_size()) { - TSL_OH_THROW_OR_TERMINATE(std::length_error, "We reached the maximum size for the hash table."); - } - - - if(grow_on_high_load()) { - ibucket = bucket_for_hash(hash); - dist_from_ideal_bucket = 0; - } - - - const index_type index_insert_position = index_type(std::distance(m_values.cbegin(), insert_position)); - -#ifdef TSL_OH_NO_CONTAINER_EMPLACE_CONST_ITERATOR - m_values.emplace(m_values.begin() + std::distance(m_values.cbegin(), insert_position), std::forward(value_type_args)...); -#else - m_values.emplace(insert_position, std::forward(value_type_args)...); -#endif - - insert_index(ibucket, dist_from_ideal_bucket, - index_insert_position, bucket_entry::truncate_hash(hash)); - - /* - * The insertion didn't happend at the end of the m_values container, - * we need to shift the indexes in m_buckets_data. - */ - if(index_insert_position != m_values.size() - 1) { - shift_indexes_in_buckets(index_insert_position + 1, 1); - } - - return std::make_pair(iterator(m_values.begin() + index_insert_position), true); - } - - void insert_index(std::size_t ibucket, std::size_t dist_from_ideal_bucket, - index_type index_insert, truncated_hash_type hash_insert) noexcept - { - while(!m_buckets[ibucket].empty()) { - const std::size_t distance = distance_from_ideal_bucket(ibucket); - if(dist_from_ideal_bucket > distance) { - std::swap(index_insert, m_buckets[ibucket].index_ref()); - std::swap(hash_insert, m_buckets[ibucket].truncated_hash_ref()); - - dist_from_ideal_bucket = distance; - } - - - ibucket = next_bucket(ibucket); - dist_from_ideal_bucket++; - - - if(dist_from_ideal_bucket > REHASH_ON_HIGH_NB_PROBES__NPROBES && !m_grow_on_next_insert && - load_factor() >= REHASH_ON_HIGH_NB_PROBES__MIN_LOAD_FACTOR) - { - // We don't want to grow the map now as we need this method to be noexcept. - // Do it on next insert. - m_grow_on_next_insert = true; - } - } - - - m_buckets[ibucket].set_index(index_insert); - m_buckets[ibucket].set_hash(hash_insert); - } - - std::size_t distance_from_ideal_bucket(std::size_t ibucket) const noexcept { - const std::size_t ideal_bucket = bucket_for_hash(m_buckets[ibucket].truncated_hash()); - - if(ibucket >= ideal_bucket) { - return ibucket - ideal_bucket; - } - // If the bucket is smaller than the ideal bucket for the value, there was a wrapping at the end of the - // bucket array due to the modulo. - else { - return (bucket_count() + ibucket) - ideal_bucket; - } - } - - std::size_t next_bucket(std::size_t index) const noexcept { - tsl_oh_assert(index < m_buckets_data.size()); - - index++; - return (index < m_buckets_data.size())?index:0; - } - - std::size_t bucket_for_hash(std::size_t hash) const noexcept { - return hash & m_hash_mask; - } - - std::size_t iterator_to_index(const_iterator it) const noexcept { - const auto dist = std::distance(cbegin(), it); - tsl_oh_assert(dist >= 0); - - return std::size_t(dist); - } - - /** - * Return true if the map has been rehashed. - */ - bool grow_on_high_load() { - if(m_grow_on_next_insert || size() >= m_load_threshold) { - rehash_impl(std::max(size_type(1), bucket_count() * 2)); - m_grow_on_next_insert = false; - - return true; - } - else { - return false; - } - } - - template - void serialize_impl(Serializer& serializer) const { - const slz_size_type version = SERIALIZATION_PROTOCOL_VERSION; - serializer(version); - - const slz_size_type nb_elements = m_values.size(); - serializer(nb_elements); - - const slz_size_type bucket_count = m_buckets_data.size(); - serializer(bucket_count); - - const float max_load_factor = m_max_load_factor; - serializer(max_load_factor); - - - for(const value_type& value: m_values) { - serializer(value); - } - - for(const bucket_entry& bucket: m_buckets_data) { - bucket.serialize(serializer); - } - } - - template - void deserialize_impl(Deserializer& deserializer, bool hash_compatible) { - tsl_oh_assert(m_buckets_data.empty()); // Current hash table must be empty - - const slz_size_type version = deserialize_value(deserializer); - // For now we only have one version of the serialization protocol. - // If it doesn't match there is a problem with the file. - if(version != SERIALIZATION_PROTOCOL_VERSION) { - TSL_OH_THROW_OR_TERMINATE(std::runtime_error, "Can't deserialize the ordered_map/set. " - "The protocol version header is invalid."); - } - - const slz_size_type nb_elements = deserialize_value(deserializer); - const slz_size_type bucket_count_ds = deserialize_value(deserializer); - const float max_load_factor = deserialize_value(deserializer); - - if(max_load_factor < MAX_LOAD_FACTOR__MINIMUM || max_load_factor > MAX_LOAD_FACTOR__MAXIMUM) { - TSL_OH_THROW_OR_TERMINATE(std::runtime_error, "Invalid max_load_factor. Check that the serializer " - "and deserializer support floats correctly as they " - "can be converted implicitly to ints."); - } - - - this->max_load_factor(max_load_factor); - - if(bucket_count_ds == 0) { - tsl_oh_assert(nb_elements == 0); - return; - } - - - if(!hash_compatible) { - reserve(numeric_cast(nb_elements, "Deserialized nb_elements is too big.")); - for(slz_size_type el = 0; el < nb_elements; el++) { - insert(deserialize_value(deserializer)); - } - } - else { - m_buckets_data.reserve(numeric_cast(bucket_count_ds, "Deserialized bucket_count is too big.")); - m_buckets = m_buckets_data.data(), - m_hash_mask = m_buckets_data.capacity() - 1; - - reserve_space_for_values(numeric_cast(nb_elements, "Deserialized nb_elements is too big.")); - for(slz_size_type el = 0; el < nb_elements; el++) { - m_values.push_back(deserialize_value(deserializer)); - } - - for(slz_size_type b = 0; b < bucket_count_ds; b++) { - m_buckets_data.push_back(bucket_entry::deserialize(deserializer)); - } - } - } - - static std::size_t round_up_to_power_of_two(std::size_t value) { - if(is_power_of_two(value)) { - return value; - } - - if(value == 0) { - return 1; - } - - --value; - for(std::size_t i = 1; i < sizeof(std::size_t) * CHAR_BIT; i *= 2) { - value |= value >> i; - } - - return value + 1; - } - - static constexpr bool is_power_of_two(std::size_t value) { - return value != 0 && (value & (value - 1)) == 0; - } - - -public: - static const size_type DEFAULT_INIT_BUCKETS_SIZE = 0; - static constexpr float DEFAULT_MAX_LOAD_FACTOR = 0.75f; - -private: - static constexpr float MAX_LOAD_FACTOR__MINIMUM = 0.1f; - static constexpr float MAX_LOAD_FACTOR__MAXIMUM = 0.95f; - - static const size_type REHASH_ON_HIGH_NB_PROBES__NPROBES = 128; - static constexpr float REHASH_ON_HIGH_NB_PROBES__MIN_LOAD_FACTOR = 0.15f; - - /** - * Protocol version currenlty used for serialization. - */ - static const slz_size_type SERIALIZATION_PROTOCOL_VERSION = 1; - - /** - * Return an always valid pointer to an static empty bucket_entry with last_bucket() == true. - */ - bucket_entry* static_empty_bucket_ptr() { - static bucket_entry empty_bucket; - return &empty_bucket; - } - -private: - buckets_container_type m_buckets_data; - - /** - * Points to m_buckets_data.data() if !m_buckets_data.empty() otherwise points to static_empty_bucket_ptr. - * This variable is useful to avoid the cost of checking if m_buckets_data is empty when trying - * to find an element. - * - * TODO Remove m_buckets_data and only use a pointer+size instead of a pointer+vector to save some space in the ordered_hash object. - */ - bucket_entry* m_buckets; - - size_type m_hash_mask; - - values_container_type m_values; - - size_type m_load_threshold; - float m_max_load_factor; - - bool m_grow_on_next_insert; -}; - - -} // end namespace detail_ordered_hash - -} // end namespace tsl - -#endif diff --git a/external/tsl/ordered_map.h b/external/tsl/ordered_map.h deleted file mode 100644 index c8b8b6bb2..000000000 --- a/external/tsl/ordered_map.h +++ /dev/null @@ -1,833 +0,0 @@ -/** - * MIT License - * - * Copyright (c) 2017 Thibaut Goetghebuer-Planchon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef TSL_ORDERED_MAP_H -#define TSL_ORDERED_MAP_H - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ordered_hash.h" - - -namespace tsl { - - -/** - * Implementation of an hash map using open addressing with robin hood with backshift delete to resolve collisions. - * - * The particularity of this hash map is that it remembers the order in which the elements were added and - * provide a way to access the structure which stores these values through the 'values_container()' method. - * The used container is defined by ValueTypeContainer, by default a std::deque is used (grows faster) but - * a std::vector may be used. In this case the map provides a 'data()' method which give a direct access - * to the memory used to store the values (which can be useful to communicate with C API's). - * - * The Key and T must be copy constructible and/or move constructible. To use `unordered_erase` they both - * must be swappable. - * - * The behaviour of the hash map is undefined if the destructor of Key or T throws an exception. - * - * By default the maximum size of a map is limited to 2^32 - 1 values, if needed this can be changed through - * the IndexType template parameter. Using an `uint64_t` will raise this limit to 2^64 - 1 values but each - * bucket will use 16 bytes instead of 8 bytes in addition to the space needed to store the values. - * - * Iterators invalidation: - * - clear, operator=, reserve, rehash: always invalidate the iterators (also invalidate end()). - * - insert, emplace, emplace_hint, operator[]: when a std::vector is used as ValueTypeContainer - * and if size() < capacity(), only end(). - * Otherwise all the iterators are invalidated if an insert occurs. - * - erase, unordered_erase: when a std::vector is used as ValueTypeContainer invalidate the iterator of - * the erased element and all the ones after the erased element (including end()). - * Otherwise all the iterators are invalidated if an erase occurs. - */ -template, - class KeyEqual = std::equal_to, - class Allocator = std::allocator>, - class ValueTypeContainer = std::deque, Allocator>, - class IndexType = std::uint_least32_t> -class ordered_map { -private: - template - using has_is_transparent = tsl::detail_ordered_hash::has_is_transparent; - - class KeySelect { - public: - using key_type = Key; - - const key_type& operator()(const std::pair& key_value) const noexcept { - return key_value.first; - } - - key_type& operator()(std::pair& key_value) noexcept { - return key_value.first; - } - }; - - class ValueSelect { - public: - using value_type = T; - - const value_type& operator()(const std::pair& key_value) const noexcept { - return key_value.second; - } - - value_type& operator()(std::pair& key_value) noexcept { - return key_value.second; - } - }; - - using ht = detail_ordered_hash::ordered_hash, KeySelect, ValueSelect, - Hash, KeyEqual, Allocator, ValueTypeContainer, IndexType>; - -public: - using key_type = typename ht::key_type; - using mapped_type = T; - using value_type = typename ht::value_type; - using size_type = typename ht::size_type; - using difference_type = typename ht::difference_type; - using hasher = typename ht::hasher; - using key_equal = typename ht::key_equal; - using allocator_type = typename ht::allocator_type; - using reference = typename ht::reference; - using const_reference = typename ht::const_reference; - using pointer = typename ht::pointer; - using const_pointer = typename ht::const_pointer; - using iterator = typename ht::iterator; - using const_iterator = typename ht::const_iterator; - using reverse_iterator = typename ht::reverse_iterator; - using const_reverse_iterator = typename ht::const_reverse_iterator; - - using values_container_type = typename ht::values_container_type; - - - /* - * Constructors - */ - ordered_map(): ordered_map(ht::DEFAULT_INIT_BUCKETS_SIZE) { - } - - explicit ordered_map(size_type bucket_count, - const Hash& hash = Hash(), - const KeyEqual& equal = KeyEqual(), - const Allocator& alloc = Allocator()): - m_ht(bucket_count, hash, equal, alloc, ht::DEFAULT_MAX_LOAD_FACTOR) - { - } - - ordered_map(size_type bucket_count, - const Allocator& alloc): ordered_map(bucket_count, Hash(), KeyEqual(), alloc) - { - } - - ordered_map(size_type bucket_count, - const Hash& hash, - const Allocator& alloc): ordered_map(bucket_count, hash, KeyEqual(), alloc) - { - } - - explicit ordered_map(const Allocator& alloc): ordered_map(ht::DEFAULT_INIT_BUCKETS_SIZE, alloc) { - } - - template - ordered_map(InputIt first, InputIt last, - size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE, - const Hash& hash = Hash(), - const KeyEqual& equal = KeyEqual(), - const Allocator& alloc = Allocator()): ordered_map(bucket_count, hash, equal, alloc) - { - insert(first, last); - } - - template - ordered_map(InputIt first, InputIt last, - size_type bucket_count, - const Allocator& alloc): ordered_map(first, last, bucket_count, Hash(), KeyEqual(), alloc) - { - } - - template - ordered_map(InputIt first, InputIt last, - size_type bucket_count, - const Hash& hash, - const Allocator& alloc): ordered_map(first, last, bucket_count, hash, KeyEqual(), alloc) - { - } - - ordered_map(std::initializer_list init, - size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE, - const Hash& hash = Hash(), - const KeyEqual& equal = KeyEqual(), - const Allocator& alloc = Allocator()): - ordered_map(init.begin(), init.end(), bucket_count, hash, equal, alloc) - { - } - - ordered_map(std::initializer_list init, - size_type bucket_count, - const Allocator& alloc): - ordered_map(init.begin(), init.end(), bucket_count, Hash(), KeyEqual(), alloc) - { - } - - ordered_map(std::initializer_list init, - size_type bucket_count, - const Hash& hash, - const Allocator& alloc): - ordered_map(init.begin(), init.end(), bucket_count, hash, KeyEqual(), alloc) - { - } - - - ordered_map& operator=(std::initializer_list ilist) { - m_ht.clear(); - - m_ht.reserve(ilist.size()); - m_ht.insert(ilist.begin(), ilist.end()); - - return *this; - } - - allocator_type get_allocator() const { return m_ht.get_allocator(); } - - - - /* - * Iterators - */ - iterator begin() noexcept { return m_ht.begin(); } - const_iterator begin() const noexcept { return m_ht.begin(); } - const_iterator cbegin() const noexcept { return m_ht.cbegin(); } - - iterator end() noexcept { return m_ht.end(); } - const_iterator end() const noexcept { return m_ht.end(); } - const_iterator cend() const noexcept { return m_ht.cend(); } - - reverse_iterator rbegin() noexcept { return m_ht.rbegin(); } - const_reverse_iterator rbegin() const noexcept { return m_ht.rbegin(); } - const_reverse_iterator rcbegin() const noexcept { return m_ht.rcbegin(); } - - reverse_iterator rend() noexcept { return m_ht.rend(); } - const_reverse_iterator rend() const noexcept { return m_ht.rend(); } - const_reverse_iterator rcend() const noexcept { return m_ht.rcend(); } - - - /* - * Capacity - */ - bool empty() const noexcept { return m_ht.empty(); } - size_type size() const noexcept { return m_ht.size(); } - size_type max_size() const noexcept { return m_ht.max_size(); } - - /* - * Modifiers - */ - void clear() noexcept { m_ht.clear(); } - - - - std::pair insert(const value_type& value) { return m_ht.insert(value); } - - template::value>::type* = nullptr> - std::pair insert(P&& value) { return m_ht.emplace(std::forward

(value)); } - - std::pair insert(value_type&& value) { return m_ht.insert(std::move(value)); } - - - iterator insert(const_iterator hint, const value_type& value) { - return m_ht.insert_hint(hint, value); - } - - template::value>::type* = nullptr> - iterator insert(const_iterator hint, P&& value) { - return m_ht.emplace_hint(hint, std::forward

(value)); - } - - iterator insert(const_iterator hint, value_type&& value) { - return m_ht.insert_hint(hint, std::move(value)); - } - - - template - void insert(InputIt first, InputIt last) { m_ht.insert(first, last); } - void insert(std::initializer_list ilist) { m_ht.insert(ilist.begin(), ilist.end()); } - - - - - template - std::pair insert_or_assign(const key_type& k, M&& obj) { - return m_ht.insert_or_assign(k, std::forward(obj)); - } - - template - std::pair insert_or_assign(key_type&& k, M&& obj) { - return m_ht.insert_or_assign(std::move(k), std::forward(obj)); - } - - - template - iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj) { - return m_ht.insert_or_assign(hint, k, std::forward(obj)); - } - - template - iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj) { - return m_ht.insert_or_assign(hint, std::move(k), std::forward(obj)); - } - - /** - * Due to the way elements are stored, emplace will need to move or copy the key-value once. - * The method is equivalent to insert(value_type(std::forward(args)...)); - * - * Mainly here for compatibility with the std::unordered_map interface. - */ - template - std::pair emplace(Args&&... args) { return m_ht.emplace(std::forward(args)...); } - - /** - * Due to the way elements are stored, emplace_hint will need to move or copy the key-value once. - * The method is equivalent to insert(hint, value_type(std::forward(args)...)); - * - * Mainly here for compatibility with the std::unordered_map interface. - */ - template - iterator emplace_hint(const_iterator hint, Args&&... args) { - return m_ht.emplace_hint(hint, std::forward(args)...); - } - - - - - template - std::pair try_emplace(const key_type& k, Args&&... args) { - return m_ht.try_emplace(k, std::forward(args)...); - } - - template - std::pair try_emplace(key_type&& k, Args&&... args) { - return m_ht.try_emplace(std::move(k), std::forward(args)...); - } - - template - iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args) { - return m_ht.try_emplace_hint(hint, k, std::forward(args)...); - } - - template - iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args) { - return m_ht.try_emplace_hint(hint, std::move(k), std::forward(args)...); - } - - - - - /** - * When erasing an element, the insert order will be preserved and no holes will be present in the container - * returned by 'values_container()'. - * - * The method is in O(n), if the order is not important 'unordered_erase(...)' method is faster with an O(1) - * average complexity. - */ - iterator erase(iterator pos) { return m_ht.erase(pos); } - - /** - * @copydoc erase(iterator pos) - */ - iterator erase(const_iterator pos) { return m_ht.erase(pos); } - - /** - * @copydoc erase(iterator pos) - */ - iterator erase(const_iterator first, const_iterator last) { return m_ht.erase(first, last); } - - /** - * @copydoc erase(iterator pos) - */ - size_type erase(const key_type& key) { return m_ht.erase(key); } - - /** - * @copydoc erase(iterator pos) - * - * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same - * as hash_function()(key). Useful to speed-up the lookup to the value if you already have the hash. - */ - size_type erase(const key_type& key, std::size_t precalculated_hash) { - return m_ht.erase(key, precalculated_hash); - } - - /** - * @copydoc erase(iterator pos) - * - * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. - * If so, K must be hashable and comparable to Key. - */ - template::value>::type* = nullptr> - size_type erase(const K& key) { return m_ht.erase(key); } - - /** - * @copydoc erase(const key_type& key, std::size_t precalculated_hash) - * - * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. - * If so, K must be hashable and comparable to Key. - */ - template::value>::type* = nullptr> - size_type erase(const K& key, std::size_t precalculated_hash) { - return m_ht.erase(key, precalculated_hash); - } - - - - void swap(ordered_map& other) { other.m_ht.swap(m_ht); } - - /* - * Lookup - */ - T& at(const Key& key) { return m_ht.at(key); } - - /** - * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same - * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. - */ - T& at(const Key& key, std::size_t precalculated_hash) { return m_ht.at(key, precalculated_hash); } - - - const T& at(const Key& key) const { return m_ht.at(key); } - - /** - * @copydoc at(const Key& key, std::size_t precalculated_hash) - */ - const T& at(const Key& key, std::size_t precalculated_hash) const { return m_ht.at(key, precalculated_hash); } - - - /** - * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. - * If so, K must be hashable and comparable to Key. - */ - template::value>::type* = nullptr> - T& at(const K& key) { return m_ht.at(key); } - - /** - * @copydoc at(const K& key) - * - * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same - * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. - */ - template::value>::type* = nullptr> - T& at(const K& key, std::size_t precalculated_hash) { return m_ht.at(key, precalculated_hash); } - - /** - * @copydoc at(const K& key) - */ - template::value>::type* = nullptr> - const T& at(const K& key) const { return m_ht.at(key); } - - /** - * @copydoc at(const K& key, std::size_t precalculated_hash) - */ - template::value>::type* = nullptr> - const T& at(const K& key, std::size_t precalculated_hash) const { return m_ht.at(key, precalculated_hash); } - - - - T& operator[](const Key& key) { return m_ht[key]; } - T& operator[](Key&& key) { return m_ht[std::move(key)]; } - - - - size_type count(const Key& key) const { return m_ht.count(key); } - - /** - * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same - * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. - */ - size_type count(const Key& key, std::size_t precalculated_hash) const { - return m_ht.count(key, precalculated_hash); - } - - /** - * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. - * If so, K must be hashable and comparable to Key. - */ - template::value>::type* = nullptr> - size_type count(const K& key) const { return m_ht.count(key); } - - /** - * @copydoc count(const K& key) const - * - * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same - * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. - */ - template::value>::type* = nullptr> - size_type count(const K& key, std::size_t precalculated_hash) const { - return m_ht.count(key, precalculated_hash); - } - - - - iterator find(const Key& key) { return m_ht.find(key); } - - /** - * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same - * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. - */ - iterator find(const Key& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); } - - const_iterator find(const Key& key) const { return m_ht.find(key); } - - /** - * @copydoc find(const Key& key, std::size_t precalculated_hash) - */ - const_iterator find(const Key& key, std::size_t precalculated_hash) const { - return m_ht.find(key, precalculated_hash); - } - - /** - * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. - * If so, K must be hashable and comparable to Key. - */ - template::value>::type* = nullptr> - iterator find(const K& key) { return m_ht.find(key); } - - /** - * @copydoc find(const K& key) - * - * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same - * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. - */ - template::value>::type* = nullptr> - iterator find(const K& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); } - - /** - * @copydoc find(const K& key) - */ - template::value>::type* = nullptr> - const_iterator find(const K& key) const { return m_ht.find(key); } - - /** - * @copydoc find(const K& key) - * - * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same - * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. - */ - template::value>::type* = nullptr> - const_iterator find(const K& key, std::size_t precalculated_hash) const { - return m_ht.find(key, precalculated_hash); - } - - - - std::pair equal_range(const Key& key) { return m_ht.equal_range(key); } - - /** - * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same - * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. - */ - std::pair equal_range(const Key& key, std::size_t precalculated_hash) { - return m_ht.equal_range(key, precalculated_hash); - } - - std::pair equal_range(const Key& key) const { return m_ht.equal_range(key); } - - /** - * @copydoc equal_range(const Key& key, std::size_t precalculated_hash) - */ - std::pair equal_range(const Key& key, std::size_t precalculated_hash) const { - return m_ht.equal_range(key, precalculated_hash); - } - - /** - * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. - * If so, K must be hashable and comparable to Key. - */ - template::value>::type* = nullptr> - std::pair equal_range(const K& key) { return m_ht.equal_range(key); } - - /** - * @copydoc equal_range(const K& key) - * - * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same - * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. - */ - template::value>::type* = nullptr> - std::pair equal_range(const K& key, std::size_t precalculated_hash) { - return m_ht.equal_range(key, precalculated_hash); - } - - /** - * @copydoc equal_range(const K& key) - */ - template::value>::type* = nullptr> - std::pair equal_range(const K& key) const { return m_ht.equal_range(key); } - - /** - * @copydoc equal_range(const K& key, std::size_t precalculated_hash) - */ - template::value>::type* = nullptr> - std::pair equal_range(const K& key, std::size_t precalculated_hash) const { - return m_ht.equal_range(key, precalculated_hash); - } - - - - /* - * Bucket interface - */ - size_type bucket_count() const { return m_ht.bucket_count(); } - size_type max_bucket_count() const { return m_ht.max_bucket_count(); } - - - /* - * Hash policy - */ - float load_factor() const { return m_ht.load_factor(); } - float max_load_factor() const { return m_ht.max_load_factor(); } - void max_load_factor(float ml) { m_ht.max_load_factor(ml); } - - void rehash(size_type count) { m_ht.rehash(count); } - void reserve(size_type count) { m_ht.reserve(count); } - - - /* - * Observers - */ - hasher hash_function() const { return m_ht.hash_function(); } - key_equal key_eq() const { return m_ht.key_eq(); } - - - - /* - * Other - */ - - /** - * Convert a const_iterator to an iterator. - */ - iterator mutable_iterator(const_iterator pos) { - return m_ht.mutable_iterator(pos); - } - - /** - * Requires index <= size(). - * - * Return an iterator to the element at index. Return end() if index == size(). - */ - iterator nth(size_type index) { return m_ht.nth(index); } - - /** - * @copydoc nth(size_type index) - */ - const_iterator nth(size_type index) const { return m_ht.nth(index); } - - - /** - * Return const_reference to the first element. Requires the container to not be empty. - */ - const_reference front() const { return m_ht.front(); } - - /** - * Return const_reference to the last element. Requires the container to not be empty. - */ - const_reference back() const { return m_ht.back(); } - - - /** - * Only available if ValueTypeContainer is a std::vector. Same as calling 'values_container().data()'. - */ - template::value>::type* = nullptr> - const typename values_container_type::value_type* data() const noexcept { return m_ht.data(); } - - /** - * Return the container in which the values are stored. The values are in the same order as the insertion order - * and are contiguous in the structure, no holes (size() == values_container().size()). - */ - const values_container_type& values_container() const noexcept { return m_ht.values_container(); } - - template::value>::type* = nullptr> - size_type capacity() const noexcept { return m_ht.capacity(); } - - void shrink_to_fit() { m_ht.shrink_to_fit(); } - - - - /** - * Insert the value before pos shifting all the elements on the right of pos (including pos) one position - * to the right. - * - * Amortized linear time-complexity in the distance between pos and end(). - */ - std::pair insert_at_position(const_iterator pos, const value_type& value) { - return m_ht.insert_at_position(pos, value); - } - - /** - * @copydoc insert_at_position(const_iterator pos, const value_type& value) - */ - std::pair insert_at_position(const_iterator pos, value_type&& value) { - return m_ht.insert_at_position(pos, std::move(value)); - } - - /** - * @copydoc insert_at_position(const_iterator pos, const value_type& value) - * - * Same as insert_at_position(pos, value_type(std::forward(args)...), mainly - * here for coherence. - */ - template - std::pair emplace_at_position(const_iterator pos, Args&&... args) { - return m_ht.emplace_at_position(pos, std::forward(args)...); - } - - /** - * @copydoc insert_at_position(const_iterator pos, const value_type& value) - */ - template - std::pair try_emplace_at_position(const_iterator pos, const key_type& k, Args&&... args) { - return m_ht.try_emplace_at_position(pos, k, std::forward(args)...); - } - - /** - * @copydoc insert_at_position(const_iterator pos, const value_type& value) - */ - template - std::pair try_emplace_at_position(const_iterator pos, key_type&& k, Args&&... args) { - return m_ht.try_emplace_at_position(pos, std::move(k), std::forward(args)...); - } - - - - void pop_back() { m_ht.pop_back(); } - - /** - * Faster erase operation with an O(1) average complexity but it doesn't preserve the insertion order. - * - * If an erasure occurs, the last element of the map will take the place of the erased element. - */ - iterator unordered_erase(iterator pos) { return m_ht.unordered_erase(pos); } - - /** - * @copydoc unordered_erase(iterator pos) - */ - iterator unordered_erase(const_iterator pos) { return m_ht.unordered_erase(pos); } - - /** - * @copydoc unordered_erase(iterator pos) - */ - size_type unordered_erase(const key_type& key) { return m_ht.unordered_erase(key); } - - /** - * @copydoc unordered_erase(iterator pos) - * - * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same - * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. - */ - size_type unordered_erase(const key_type& key, std::size_t precalculated_hash) { - return m_ht.unordered_erase(key, precalculated_hash); - } - - /** - * @copydoc unordered_erase(iterator pos) - * - * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. - * If so, K must be hashable and comparable to Key. - */ - template::value>::type* = nullptr> - size_type unordered_erase(const K& key) { return m_ht.unordered_erase(key); } - - /** - * @copydoc unordered_erase(const K& key) - * - * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same - * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. - */ - template::value>::type* = nullptr> - size_type unordered_erase(const K& key, std::size_t precalculated_hash) { - return m_ht.unordered_erase(key, precalculated_hash); - } - - /** - * Serialize the map through the `serializer` parameter. - * - * The `serializer` parameter must be a function object that supports the following call: - * - `template void operator()(const U& value);` where the types `std::uint64_t`, `float` and `std::pair` must be supported for U. - * - * The implementation leaves binary compatibility (endianness, IEEE 754 for floats, ...) of the types it serializes - * in the hands of the `Serializer` function object if compatibility is required. - */ - template - void serialize(Serializer& serializer) const { - m_ht.serialize(serializer); - } - - /** - * Deserialize a previously serialized map through the `deserializer` parameter. - * - * The `deserializer` parameter must be a function object that supports the following calls: - * - `template U operator()();` where the types `std::uint64_t`, `float` and `std::pair` must be supported for U. - * - * If the deserialized hash map type is hash compatible with the serialized map, the deserialization process can be - * sped up by setting `hash_compatible` to true. To be hash compatible, the Hash and KeyEqual must behave the same way - * than the ones used on the serialized map. The `std::size_t` must also be of the same size as the one on the platform used - * to serialize the map, the same apply for `IndexType`. If these criteria are not met, the behaviour is undefined with - * `hash_compatible` sets to true. - * - * The behaviour is undefined if the type `Key` and `T` of the `ordered_map` are not the same as the - * types used during serialization. - * - * The implementation leaves binary compatibility (endianness, IEEE 754 for floats, size of int, ...) of the types it - * deserializes in the hands of the `Deserializer` function object if compatibility is required. - */ - template - static ordered_map deserialize(Deserializer& deserializer, bool hash_compatible = false) { - ordered_map map(0); - map.m_ht.deserialize(deserializer, hash_compatible); - - return map; - } - - - - friend bool operator==(const ordered_map& lhs, const ordered_map& rhs) { return lhs.m_ht == rhs.m_ht; } - friend bool operator!=(const ordered_map& lhs, const ordered_map& rhs) { return lhs.m_ht != rhs.m_ht; } - friend bool operator<(const ordered_map& lhs, const ordered_map& rhs) { return lhs.m_ht < rhs.m_ht; } - friend bool operator<=(const ordered_map& lhs, const ordered_map& rhs) { return lhs.m_ht <= rhs.m_ht; } - friend bool operator>(const ordered_map& lhs, const ordered_map& rhs) { return lhs.m_ht > rhs.m_ht; } - friend bool operator>=(const ordered_map& lhs, const ordered_map& rhs) { return lhs.m_ht >= rhs.m_ht; } - - friend void swap(ordered_map& lhs, ordered_map& rhs) { lhs.swap(rhs); } - -private: - ht m_ht; -}; - -} // end namespace tsl - -#endif diff --git a/external/tsl/ordered_set.h b/external/tsl/ordered_set.h deleted file mode 100644 index 0932f54b9..000000000 --- a/external/tsl/ordered_set.h +++ /dev/null @@ -1,688 +0,0 @@ -/** - * MIT License - * - * Copyright (c) 2017 Thibaut Goetghebuer-Planchon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef TSL_ORDERED_SET_H -#define TSL_ORDERED_SET_H - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ordered_hash.h" - - -namespace tsl { - - -/** - * Implementation of an hash set using open addressing with robin hood with backshift delete to resolve collisions. - * - * The particularity of this hash set is that it remembers the order in which the elements were added and - * provide a way to access the structure which stores these values through the 'values_container()' method. - * The used container is defined by ValueTypeContainer, by default a std::deque is used (grows faster) but - * a std::vector may be used. In this case the set provides a 'data()' method which give a direct access - * to the memory used to store the values (which can be useful to communicate with C API's). - * - * The Key must be copy constructible and/or move constructible. To use `unordered_erase` it also must be swappable. - * - * The behaviour of the hash set is undefined if the destructor of Key throws an exception. - * - * By default the maximum size of a set is limited to 2^32 - 1 values, if needed this can be changed through - * the IndexType template parameter. Using an `uint64_t` will raise this limit to 2^64 - 1 values but each - * bucket will use 16 bytes instead of 8 bytes in addition to the space needed to store the values. - * - * Iterators invalidation: - * - clear, operator=, reserve, rehash: always invalidate the iterators (also invalidate end()). - * - insert, emplace, emplace_hint, operator[]: when a std::vector is used as ValueTypeContainer - * and if size() < capacity(), only end(). - * Otherwise all the iterators are invalidated if an insert occurs. - * - erase, unordered_erase: when a std::vector is used as ValueTypeContainer invalidate the iterator of - * the erased element and all the ones after the erased element (including end()). - * Otherwise all the iterators are invalidated if an erase occurs. - */ -template, - class KeyEqual = std::equal_to, - class Allocator = std::allocator, - class ValueTypeContainer = std::deque, - class IndexType = std::uint_least32_t> -class ordered_set { -private: - template - using has_is_transparent = tsl::detail_ordered_hash::has_is_transparent; - - class KeySelect { - public: - using key_type = Key; - - const key_type& operator()(const Key& key) const noexcept { - return key; - } - - key_type& operator()(Key& key) noexcept { - return key; - } - }; - - using ht = detail_ordered_hash::ordered_hash; - -public: - using key_type = typename ht::key_type; - using value_type = typename ht::value_type; - using size_type = typename ht::size_type; - using difference_type = typename ht::difference_type; - using hasher = typename ht::hasher; - using key_equal = typename ht::key_equal; - using allocator_type = typename ht::allocator_type; - using reference = typename ht::reference; - using const_reference = typename ht::const_reference; - using pointer = typename ht::pointer; - using const_pointer = typename ht::const_pointer; - using iterator = typename ht::iterator; - using const_iterator = typename ht::const_iterator; - using reverse_iterator = typename ht::reverse_iterator; - using const_reverse_iterator = typename ht::const_reverse_iterator; - - using values_container_type = typename ht::values_container_type; - - - /* - * Constructors - */ - ordered_set(): ordered_set(ht::DEFAULT_INIT_BUCKETS_SIZE) { - } - - explicit ordered_set(size_type bucket_count, - const Hash& hash = Hash(), - const KeyEqual& equal = KeyEqual(), - const Allocator& alloc = Allocator()): - m_ht(bucket_count, hash, equal, alloc, ht::DEFAULT_MAX_LOAD_FACTOR) - { - } - - ordered_set(size_type bucket_count, - const Allocator& alloc): ordered_set(bucket_count, Hash(), KeyEqual(), alloc) - { - } - - ordered_set(size_type bucket_count, - const Hash& hash, - const Allocator& alloc): ordered_set(bucket_count, hash, KeyEqual(), alloc) - { - } - - explicit ordered_set(const Allocator& alloc): ordered_set(ht::DEFAULT_INIT_BUCKETS_SIZE, alloc) { - } - - template - ordered_set(InputIt first, InputIt last, - size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE, - const Hash& hash = Hash(), - const KeyEqual& equal = KeyEqual(), - const Allocator& alloc = Allocator()): ordered_set(bucket_count, hash, equal, alloc) - { - insert(first, last); - } - - template - ordered_set(InputIt first, InputIt last, - size_type bucket_count, - const Allocator& alloc): ordered_set(first, last, bucket_count, Hash(), KeyEqual(), alloc) - { - } - - template - ordered_set(InputIt first, InputIt last, - size_type bucket_count, - const Hash& hash, - const Allocator& alloc): ordered_set(first, last, bucket_count, hash, KeyEqual(), alloc) - { - } - - ordered_set(std::initializer_list init, - size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE, - const Hash& hash = Hash(), - const KeyEqual& equal = KeyEqual(), - const Allocator& alloc = Allocator()): - ordered_set(init.begin(), init.end(), bucket_count, hash, equal, alloc) - { - } - - ordered_set(std::initializer_list init, - size_type bucket_count, - const Allocator& alloc): - ordered_set(init.begin(), init.end(), bucket_count, Hash(), KeyEqual(), alloc) - { - } - - ordered_set(std::initializer_list init, - size_type bucket_count, - const Hash& hash, - const Allocator& alloc): - ordered_set(init.begin(), init.end(), bucket_count, hash, KeyEqual(), alloc) - { - } - - - ordered_set& operator=(std::initializer_list ilist) { - m_ht.clear(); - - m_ht.reserve(ilist.size()); - m_ht.insert(ilist.begin(), ilist.end()); - - return *this; - } - - allocator_type get_allocator() const { return m_ht.get_allocator(); } - - - /* - * Iterators - */ - iterator begin() noexcept { return m_ht.begin(); } - const_iterator begin() const noexcept { return m_ht.begin(); } - const_iterator cbegin() const noexcept { return m_ht.cbegin(); } - - iterator end() noexcept { return m_ht.end(); } - const_iterator end() const noexcept { return m_ht.end(); } - const_iterator cend() const noexcept { return m_ht.cend(); } - - reverse_iterator rbegin() noexcept { return m_ht.rbegin(); } - const_reverse_iterator rbegin() const noexcept { return m_ht.rbegin(); } - const_reverse_iterator rcbegin() const noexcept { return m_ht.rcbegin(); } - - reverse_iterator rend() noexcept { return m_ht.rend(); } - const_reverse_iterator rend() const noexcept { return m_ht.rend(); } - const_reverse_iterator rcend() const noexcept { return m_ht.rcend(); } - - - /* - * Capacity - */ - bool empty() const noexcept { return m_ht.empty(); } - size_type size() const noexcept { return m_ht.size(); } - size_type max_size() const noexcept { return m_ht.max_size(); } - - /* - * Modifiers - */ - void clear() noexcept { m_ht.clear(); } - - - - std::pair insert(const value_type& value) { return m_ht.insert(value); } - std::pair insert(value_type&& value) { return m_ht.insert(std::move(value)); } - - iterator insert(const_iterator hint, const value_type& value) { - return m_ht.insert_hint(hint, value); - } - - iterator insert(const_iterator hint, value_type&& value) { - return m_ht.insert_hint(hint, std::move(value)); - } - - template - void insert(InputIt first, InputIt last) { m_ht.insert(first, last); } - void insert(std::initializer_list ilist) { m_ht.insert(ilist.begin(), ilist.end()); } - - - - /** - * Due to the way elements are stored, emplace will need to move or copy the key-value once. - * The method is equivalent to insert(value_type(std::forward(args)...)); - * - * Mainly here for compatibility with the std::unordered_map interface. - */ - template - std::pair emplace(Args&&... args) { return m_ht.emplace(std::forward(args)...); } - - /** - * Due to the way elements are stored, emplace_hint will need to move or copy the key-value once. - * The method is equivalent to insert(hint, value_type(std::forward(args)...)); - * - * Mainly here for compatibility with the std::unordered_map interface. - */ - template - iterator emplace_hint(const_iterator hint, Args&&... args) { - return m_ht.emplace_hint(hint, std::forward(args)...); - } - - /** - * When erasing an element, the insert order will be preserved and no holes will be present in the container - * returned by 'values_container()'. - * - * The method is in O(n), if the order is not important 'unordered_erase(...)' method is faster with an O(1) - * average complexity. - */ - iterator erase(iterator pos) { return m_ht.erase(pos); } - - /** - * @copydoc erase(iterator pos) - */ - iterator erase(const_iterator pos) { return m_ht.erase(pos); } - - /** - * @copydoc erase(iterator pos) - */ - iterator erase(const_iterator first, const_iterator last) { return m_ht.erase(first, last); } - - /** - * @copydoc erase(iterator pos) - */ - size_type erase(const key_type& key) { return m_ht.erase(key); } - - /** - * @copydoc erase(iterator pos) - * - * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same - * as hash_function()(key). Useful to speed-up the lookup to the value if you already have the hash. - */ - size_type erase(const key_type& key, std::size_t precalculated_hash) { - return m_ht.erase(key, precalculated_hash); - } - - /** - * @copydoc erase(iterator pos) - * - * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. - * If so, K must be hashable and comparable to Key. - */ - template::value>::type* = nullptr> - size_type erase(const K& key) { return m_ht.erase(key); } - - /** - * @copydoc erase(const key_type& key, std::size_t precalculated_hash) - * - * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. - * If so, K must be hashable and comparable to Key. - */ - template::value>::type* = nullptr> - size_type erase(const K& key, std::size_t precalculated_hash) { - return m_ht.erase(key, precalculated_hash); - } - - - - void swap(ordered_set& other) { other.m_ht.swap(m_ht); } - - /* - * Lookup - */ - size_type count(const Key& key) const { return m_ht.count(key); } - - /** - * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same - * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. - */ - size_type count(const Key& key, std::size_t precalculated_hash) const { - return m_ht.count(key, precalculated_hash); - } - - /** - * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. - * If so, K must be hashable and comparable to Key. - */ - template::value>::type* = nullptr> - size_type count(const K& key) const { return m_ht.count(key); } - - /** - * @copydoc count(const K& key) const - * - * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same - * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. - */ - template::value>::type* = nullptr> - size_type count(const K& key, std::size_t precalculated_hash) const { - return m_ht.count(key, precalculated_hash); - } - - - - - iterator find(const Key& key) { return m_ht.find(key); } - - /** - * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same - * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. - */ - iterator find(const Key& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); } - - const_iterator find(const Key& key) const { return m_ht.find(key); } - - /** - * @copydoc find(const Key& key, std::size_t precalculated_hash) - */ - const_iterator find(const Key& key, std::size_t precalculated_hash) const { - return m_ht.find(key, precalculated_hash); - } - - /** - * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. - * If so, K must be hashable and comparable to Key. - */ - template::value>::type* = nullptr> - iterator find(const K& key) { return m_ht.find(key); } - - /** - * @copydoc find(const K& key) - * - * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same - * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. - */ - template::value>::type* = nullptr> - iterator find(const K& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); } - - /** - * @copydoc find(const K& key) - */ - template::value>::type* = nullptr> - const_iterator find(const K& key) const { return m_ht.find(key); } - - /** - * @copydoc find(const K& key) - * - * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same - * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. - */ - template::value>::type* = nullptr> - const_iterator find(const K& key, std::size_t precalculated_hash) const { - return m_ht.find(key, precalculated_hash); - } - - - - std::pair equal_range(const Key& key) { return m_ht.equal_range(key); } - - /** - * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same - * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. - */ - std::pair equal_range(const Key& key, std::size_t precalculated_hash) { - return m_ht.equal_range(key, precalculated_hash); - } - - std::pair equal_range(const Key& key) const { return m_ht.equal_range(key); } - - /** - * @copydoc equal_range(const Key& key, std::size_t precalculated_hash) - */ - std::pair equal_range(const Key& key, std::size_t precalculated_hash) const { - return m_ht.equal_range(key, precalculated_hash); - } - - /** - * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. - * If so, K must be hashable and comparable to Key. - */ - template::value>::type* = nullptr> - std::pair equal_range(const K& key) { return m_ht.equal_range(key); } - - /** - * @copydoc equal_range(const K& key) - * - * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same - * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. - */ - template::value>::type* = nullptr> - std::pair equal_range(const K& key, std::size_t precalculated_hash) { - return m_ht.equal_range(key, precalculated_hash); - } - - /** - * @copydoc equal_range(const K& key) - */ - template::value>::type* = nullptr> - std::pair equal_range(const K& key) const { return m_ht.equal_range(key); } - - /** - * @copydoc equal_range(const K& key, std::size_t precalculated_hash) - */ - template::value>::type* = nullptr> - std::pair equal_range(const K& key, std::size_t precalculated_hash) const { - return m_ht.equal_range(key, precalculated_hash); - } - - - /* - * Bucket interface - */ - size_type bucket_count() const { return m_ht.bucket_count(); } - size_type max_bucket_count() const { return m_ht.max_bucket_count(); } - - - /* - * Hash policy - */ - float load_factor() const { return m_ht.load_factor(); } - float max_load_factor() const { return m_ht.max_load_factor(); } - void max_load_factor(float ml) { m_ht.max_load_factor(ml); } - - void rehash(size_type count) { m_ht.rehash(count); } - void reserve(size_type count) { m_ht.reserve(count); } - - - /* - * Observers - */ - hasher hash_function() const { return m_ht.hash_function(); } - key_equal key_eq() const { return m_ht.key_eq(); } - - - /* - * Other - */ - - /** - * Convert a const_iterator to an iterator. - */ - iterator mutable_iterator(const_iterator pos) { - return m_ht.mutable_iterator(pos); - } - - /** - * Requires index <= size(). - * - * Return an iterator to the element at index. Return end() if index == size(). - */ - iterator nth(size_type index) { return m_ht.nth(index); } - - /** - * @copydoc nth(size_type index) - */ - const_iterator nth(size_type index) const { return m_ht.nth(index); } - - - /** - * Return const_reference to the first element. Requires the container to not be empty. - */ - const_reference front() const { return m_ht.front(); } - - /** - * Return const_reference to the last element. Requires the container to not be empty. - */ - const_reference back() const { return m_ht.back(); } - - - /** - * Only available if ValueTypeContainer is a std::vector. Same as calling 'values_container().data()'. - */ - template::value>::type* = nullptr> - const typename values_container_type::value_type* data() const noexcept { return m_ht.data(); } - - /** - * Return the container in which the values are stored. The values are in the same order as the insertion order - * and are contiguous in the structure, no holes (size() == values_container().size()). - */ - const values_container_type& values_container() const noexcept { return m_ht.values_container(); } - - template::value>::type* = nullptr> - size_type capacity() const noexcept { return m_ht.capacity(); } - - void shrink_to_fit() { m_ht.shrink_to_fit(); } - - - - /** - * Insert the value before pos shifting all the elements on the right of pos (including pos) one position - * to the right. - * - * Amortized linear time-complexity in the distance between pos and end(). - */ - std::pair insert_at_position(const_iterator pos, const value_type& value) { - return m_ht.insert_at_position(pos, value); - } - - /** - * @copydoc insert_at_position(const_iterator pos, const value_type& value) - */ - std::pair insert_at_position(const_iterator pos, value_type&& value) { - return m_ht.insert_at_position(pos, std::move(value)); - } - - /** - * @copydoc insert_at_position(const_iterator pos, const value_type& value) - * - * Same as insert_at_position(pos, value_type(std::forward(args)...), mainly - * here for coherence. - */ - template - std::pair emplace_at_position(const_iterator pos, Args&&... args) { - return m_ht.emplace_at_position(pos, std::forward(args)...); - } - - - - void pop_back() { m_ht.pop_back(); } - - /** - * Faster erase operation with an O(1) average complexity but it doesn't preserve the insertion order. - * - * If an erasure occurs, the last element of the map will take the place of the erased element. - */ - iterator unordered_erase(iterator pos) { return m_ht.unordered_erase(pos); } - - /** - * @copydoc unordered_erase(iterator pos) - */ - iterator unordered_erase(const_iterator pos) { return m_ht.unordered_erase(pos); } - - /** - * @copydoc unordered_erase(iterator pos) - */ - size_type unordered_erase(const key_type& key) { return m_ht.unordered_erase(key); } - - /** - * @copydoc unordered_erase(iterator pos) - * - * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same - * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. - */ - size_type unordered_erase(const key_type& key, std::size_t precalculated_hash) { - return m_ht.unordered_erase(key, precalculated_hash); - } - - /** - * @copydoc unordered_erase(iterator pos) - * - * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. - * If so, K must be hashable and comparable to Key. - */ - template::value>::type* = nullptr> - size_type unordered_erase(const K& key) { return m_ht.unordered_erase(key); } - - /** - * @copydoc unordered_erase(const K& key) - * - * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same - * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. - */ - template::value>::type* = nullptr> - size_type unordered_erase(const K& key, std::size_t precalculated_hash) { - return m_ht.unordered_erase(key, precalculated_hash); - } - - /** - * Serialize the set through the `serializer` parameter. - * - * The `serializer` parameter must be a function object that supports the following call: - * - `void operator()(const U& value);` where the types `std::uint64_t`, `float` and `Key` must be supported for U. - * - * The implementation leaves binary compatibility (endianness, IEEE 754 for floats, ...) of the types it serializes - * in the hands of the `Serializer` function object if compatibility is required. - */ - template - void serialize(Serializer& serializer) const { - m_ht.serialize(serializer); - } - - /** - * Deserialize a previously serialized set through the `deserializer` parameter. - * - * The `deserializer` parameter must be a function object that supports the following calls: - * - `template U operator()();` where the types `std::uint64_t`, `float` and `Key` must be supported for U. - * - * If the deserialized hash set type is hash compatible with the serialized set, the deserialization process can be - * sped up by setting `hash_compatible` to true. To be hash compatible, the Hash and KeyEqual must behave the same way - * than the ones used on the serialized map. The `std::size_t` must also be of the same size as the one on the platform used - * to serialize the map, the same apply for `IndexType`. If these criteria are not met, the behaviour is undefined with - * `hash_compatible` sets to true. - * - * The behaviour is undefined if the type `Key` of the `ordered_set` is not the same as the - * type used during serialization. - * - * The implementation leaves binary compatibility (endianness, IEEE 754 for floats, size of int, ...) of the types it - * deserializes in the hands of the `Deserializer` function object if compatibility is required. - */ - template - static ordered_set deserialize(Deserializer& deserializer, bool hash_compatible = false) { - ordered_set set(0); - set.m_ht.deserialize(deserializer, hash_compatible); - - return set; - } - - - - friend bool operator==(const ordered_set& lhs, const ordered_set& rhs) { return lhs.m_ht == rhs.m_ht; } - friend bool operator!=(const ordered_set& lhs, const ordered_set& rhs) { return lhs.m_ht != rhs.m_ht; } - friend bool operator<(const ordered_set& lhs, const ordered_set& rhs) { return lhs.m_ht < rhs.m_ht; } - friend bool operator<=(const ordered_set& lhs, const ordered_set& rhs) { return lhs.m_ht <= rhs.m_ht; } - friend bool operator>(const ordered_set& lhs, const ordered_set& rhs) { return lhs.m_ht > rhs.m_ht; } - friend bool operator>=(const ordered_set& lhs, const ordered_set& rhs) { return lhs.m_ht >= rhs.m_ht; } - - friend void swap(ordered_set& lhs, ordered_set& rhs) { lhs.swap(rhs); } - -private: - ht m_ht; -}; - -} // end namespace tsl - -#endif From 6c066c30032196ee335c162ff6715e779d2415b2 Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 28 Jul 2020 14:39:46 -0700 Subject: [PATCH 067/175] :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 2b0025729..2156ad54c 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; @@ -234,6 +224,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 @@ -255,13 +266,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 667abf1ff..3dcb4c5b7 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; @@ -172,6 +162,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( @@ -179,6 +175,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; } @@ -194,6 +200,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; @@ -257,11 +267,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 aa7ddfe28fc8ec330eb1cec0420cad546eaa7778 Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Wed, 29 Jul 2020 13:06:16 -0700 Subject: [PATCH 068/175] Fix the compute mass bug --- include/particles/particle_base.h | 28 ------------ include/particles/twophase_particle.h | 25 ----------- include/particles/twophase_particle.tcc | 58 +++++-------------------- 3 files changed, 10 insertions(+), 101 deletions(-) diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 3dcb4c5b7..fd3bfc73e 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -326,34 +326,6 @@ class ParticleBase { return 0; }; - //! Assign pore pressure - //! \param[in] pressure Pore liquid pressure - virtual void assign_pore_pressure(double pressure) { - throw std::runtime_error( - "Calling the base class function (assign_pore_pressure) in " - "ParticleBase:: illegal operation!"); - }; - - //! Assign liquid traction - //! \param[in] direction Index corresponding to the direction of traction - //! \param[in] traction Particle traction in specified direction - //! \retval status Assignment status - virtual bool assign_liquid_traction(unsigned direction, double traction) { - throw std::runtime_error( - "Calling the base class function (assign_liquid_traction) in " - "ParticleBase:: illegal operation!"); - return 0; - }; - - //! Return liquid phase traction - virtual VectorDim liquid_traction() const { - auto error = VectorDim::Zero(); - throw std::runtime_error( - "Calling the base class function (liquid_traction) in " - "ParticleBase:: illegal operation!"); - return error; - }; - //! Return mixture traction virtual VectorDim mixture_traction() const { auto error = VectorDim::Zero(); diff --git a/include/particles/twophase_particle.h b/include/particles/twophase_particle.h index cd67ca77b..ac22a8857 100644 --- a/include/particles/twophase_particle.h +++ b/include/particles/twophase_particle.h @@ -65,21 +65,6 @@ class TwoPhaseParticle : public mpm::Particle { //! Assign saturation degree bool assign_saturation_degree() override; - //! Assign pore pressure - //! \param[in] pressure Pore liquid pressure - void assign_pore_pressure(double pressure) override { - this->pore_pressure_ = pressure; - } - - //! Assign liquid traction - //! \param[in] direction Index corresponding to the direction of traction - //! \param[in] traction Particle traction in specified direction - //! \retval status Assignment status - bool assign_liquid_traction(unsigned direction, double traction) override; - - //! Return liquid phase traction - VectorDim liquid_traction() const { return liquid_traction_; }; - //! Return mixture traction VectorDim mixture_traction() const { return mixture_traction_; }; @@ -194,9 +179,6 @@ class TwoPhaseParticle : public mpm::Particle { unsigned phase = mpm::ParticlePhase::Solid) noexcept override; private: - //! Compute liquid mass - virtual void compute_liquid_mass() noexcept; - //! Assign liquid mass and momentum to nodes virtual void map_liquid_mass_momentum_to_nodes() noexcept; @@ -216,9 +198,6 @@ class TwoPhaseParticle : public mpm::Particle { //! \retval status Assignment status virtual bool assign_mixture_traction(unsigned direction, double traction); - //! Map liquid phase traction force - virtual void map_liquid_traction_force() noexcept; - //! Map two phase mixture traction force //! \param[in] mixture Identification for Mixture virtual void map_mixture_traction_force(unsigned mixture) noexcept; @@ -282,12 +261,8 @@ class TwoPhaseParticle : public mpm::Particle { double pore_pressure_constraint_{std::numeric_limits::max()}; //! Pore pressure double pore_pressure_; - //! Set liquid phase traction - bool set_liquid_traction_; //! Set mixture traction bool set_mixture_traction_; - //! Traction for liquid phase - Eigen::Matrix liquid_traction_; //! Traction for mixture (soil skeleton + pore liquid) Eigen::Matrix mixture_traction_; //! Liquid strain rate diff --git a/include/particles/twophase_particle.tcc b/include/particles/twophase_particle.tcc index e0079c612..18be09b43 100644 --- a/include/particles/twophase_particle.tcc +++ b/include/particles/twophase_particle.tcc @@ -120,9 +120,7 @@ void mpm::TwoPhaseParticle::initialise() { liquid_velocity_.setZero(); liquid_strain_rate_.setZero(); liquid_strain_.setZero(); - set_liquid_traction_ = false; set_mixture_traction_ = false; - liquid_traction_.setZero(); pore_pressure_ = 0.; liquid_saturation_ = 1.; @@ -177,29 +175,6 @@ bool mpm::TwoPhaseParticle::assign_liquid_velocity( return status; } -// Assign traction to the liquid phase -template -bool mpm::TwoPhaseParticle::assign_liquid_traction(unsigned direction, - double traction) { - bool status = false; - try { - if (direction >= Tdim || - this->volume_ == std::numeric_limits::max()) { - throw std::runtime_error( - "Particle liquid traction property: volume / direction is invalid"); - } - // Assign liquid traction - liquid_traction_(direction) = - traction * this->volume_ / this->size_(direction); - status = true; - this->set_liquid_traction_ = true; - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; - } - return status; -} - // Assign traction template bool mpm::TwoPhaseParticle::assign_traction(unsigned direction, @@ -235,18 +210,17 @@ bool mpm::TwoPhaseParticle::assign_mixture_traction(unsigned direction, // Compute mass of particle (both solid and fluid) template void mpm::TwoPhaseParticle::compute_mass() noexcept { - mpm::Particle::compute_mass(); - this->compute_liquid_mass(); -} - -// Compute fluid mass of particle -template -void mpm::TwoPhaseParticle::compute_liquid_mass() noexcept { - // Check if particle volume is set and liquid material ptr is valid + // Check if particle volume is set and material ptr is valid assert(volume_ != std::numeric_limits::max() && - this->material(mpm::ParticlePhase::Liquid) != nullptr); - - // Mass = volume of particle * bulk_density + this->material() != nullptr && this->material(1) != nullptr); + // Mass = volume of particle * mass_density + // Solid mass + this->mass_density_ = + (this->material())->template property(std::string("density")) * + (1 - this->porosity_); + this->mass_ = volume_ * mass_density_; + + // Liquid mass this->liquid_mass_density_ = liquid_saturation_ * porosity_ * this->material(mpm::ParticlePhase::Liquid) @@ -356,18 +330,6 @@ void mpm::TwoPhaseParticle::map_traction_force() noexcept { this->map_mixture_traction_force(mpm::ParticlePhase::Mixture); } -//! Map liquid traction force -template -void mpm::TwoPhaseParticle::map_liquid_traction_force() noexcept { - if (this->set_liquid_traction_) { - // Map particle liquid traction forces to nodes - for (unsigned i = 0; i < nodes_.size(); ++i) - nodes_[i]->update_external_force( - true, mpm::ParticlePhase::Liquid, - (-1. * shapefn_[i] * porosity_ * this->liquid_traction_)); - } -} - //! Map mixture traction force template void mpm::TwoPhaseParticle::map_mixture_traction_force( From 3e29ecfb482fa1015fe24e749617a2142a1b1339 Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Thu, 30 Jul 2020 11:31:26 -0700 Subject: [PATCH 069/175] Some clean up work --- include/node.h | 64 ++--- include/node.tcc | 322 ++++++++++++------------ include/particles/particle_base.h | 93 +++---- include/particles/twophase_particle.h | 56 ++--- include/particles/twophase_particle.tcc | 105 +++----- 5 files changed, 274 insertions(+), 366 deletions(-) diff --git a/include/node.h b/include/node.h index d2b1bf98f..8be964b0c 100644 --- a/include/node.h +++ b/include/node.h @@ -128,18 +128,6 @@ class Node : public NodeBase { return internal_force_.col(phase); } - //! Update internal force (body force / traction force) - //! \param[in] update A boolean to update (true) or assign (false) - //! \param[in] drag_force Drag force from the particles in a cell - //! \retval status Update status - void update_drag_force_coefficient(bool update, - const VectorDim& drag_force) override; - - //! Return drag force at a given node - VectorDim drag_force_coefficient() const override { - return drag_force_coefficient_; - } - //! Update pressure at the nodes from particle //! \param[in] phase Index corresponding to the phase //! \param[in] mass_pressure Product of mass x pressure of a particle @@ -204,25 +192,6 @@ class Node : public NodeBase { bool compute_acceleration_velocity_cundall( unsigned phase, double dt, double damping_factor) noexcept override; - //! Compute acceleration and velocity for two phase - //! \param[in] dt Timestep in analysis - bool compute_acceleration_velocity_twophase_explicit( - double dt) noexcept override; - - //! Compute acceleration and velocity for two phase with cundall damping - //! factor \param[in] dt Timestep in analysis \param[in] damping_factor - //! Damping factor - bool compute_acceleration_velocity_twophase_explicit_cundall( - double dt, double damping_factor) noexcept override; - - //! 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; - //! Assign velocity constraint //! Directions can take values between 0 and Dim * Nphases //! \param[in] dir Direction of velocity constraint @@ -295,6 +264,39 @@ class Node : public NodeBase { //! Compute multimaterial normal unit vector void compute_multimaterial_normal_unit_vector() override; + //! TwoPhase functions-------------------------------------------------------- + //! Update internal force (body force / traction force) + //! \param[in] update A boolean to update (true) or assign (false) + //! \param[in] drag_force Drag force from the particles in a cell + //! \retval status Update status + void update_drag_force_coefficient(bool update, + const VectorDim& drag_force) override; + + //! Return drag force at a given node + VectorDim drag_force_coefficient() const override { + return drag_force_coefficient_; + } + + //! Compute acceleration and velocity for two phase + //! \param[in] dt Timestep in analysis + bool compute_acceleration_velocity_twophase_explicit( + double dt) noexcept override; + + //! Compute acceleration and velocity for two phase with cundall damping + //! factor \param[in] dt Timestep in analysis \param[in] damping_factor + //! Damping factor + bool compute_acceleration_velocity_twophase_explicit_cundall( + double dt, double damping_factor) noexcept override; + + //! 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; + //---------------------------------------------------------------------------- + private: //! Mutex SpinMutex node_mutex_; diff --git a/include/node.tcc b/include/node.tcc index 5868856a8..3555bce36 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -141,21 +141,6 @@ void mpm::Node::update_internal_force( node_mutex_.unlock(); } -//! Update drag force coefficient -template -void mpm::Node::update_drag_force_coefficient( - bool update, const Eigen::Matrix& drag_force_coefficient) { - - // Decide to update or assign - const double factor = (update == true) ? 1. : 0.; - - // Update/assign drag force coefficient - node_mutex_.lock(); - drag_force_coefficient_ = - drag_force_coefficient_ * factor + drag_force_coefficient; - node_mutex_.unlock(); -} - //! Assign nodal momentum template void mpm::Node::update_momentum( @@ -324,151 +309,6 @@ bool mpm::Node::compute_acceleration_velocity_cundall( return status; } -//! Compute acceleration and velocity for two phase -template -bool mpm::Node:: - compute_acceleration_velocity_twophase_explicit(double dt) noexcept { - bool status = false; - const double tolerance = 1.0E-15; - if (this->mass(mpm::NodePhase::nSolid) > tolerance && - this->mass(mpm::NodePhase::nLiquid) > tolerance) { - // Compute drag force - VectorDim drag_force = drag_force_coefficient_.cwiseProduct( - velocity_.col(mpm::NodePhase::nLiquid) - - velocity_.col(mpm::NodePhase::nSolid)); - - // Acceleration of pore fluid (momentume balance of fluid phase) - this->acceleration_.col(mpm::NodePhase::nLiquid) = - (this->external_force_.col(mpm::NodePhase::nLiquid) + - this->internal_force_.col(mpm::NodePhase::nLiquid) - drag_force) / - this->mass_(mpm::NodePhase::nLiquid); - - // Acceleration of solid skeleton (momentume balance of mixture) - this->acceleration_.col(mpm::NodePhase::nSolid) = - (this->external_force_.col(mpm::NodePhase::nMixture) + - this->internal_force_.col(mpm::NodePhase::nMixture) - - this->mass_(mpm::NodePhase::nLiquid) * - this->acceleration_.col(mpm::NodePhase::nLiquid)) / - this->mass_(mpm::NodePhase::nSolid); - - // Apply friction constraints - this->apply_friction_constraints(dt); - - // Velocity += acceleration * dt - this->velocity_ += this->acceleration_ * 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(mpm::NodePhase::nSolid)(i)) < tolerance) - velocity_.col(mpm::NodePhase::nSolid)(i) = 0.; - if (std::abs(acceleration_.col(mpm::NodePhase::nSolid)(i)) < tolerance) - acceleration_.col(mpm::NodePhase::nSolid)(i) = 0.; - if (std::abs(velocity_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) - velocity_.col(mpm::NodePhase::nLiquid)(i) = 0.; - if (std::abs(acceleration_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) - acceleration_.col(mpm::NodePhase::nLiquid)(i) = 0.; - } - status = true; - } - return status; -} - -//! Compute acceleration and velocity for two phase with damping -template -bool mpm::Node:: - compute_acceleration_velocity_twophase_explicit_cundall( - double dt, double damping_factor) noexcept { - bool status = false; - const double tolerance = 1.0E-15; - - if (this->mass(mpm::NodePhase::nSolid) > tolerance && - this->mass(mpm::NodePhase::nLiquid) > tolerance) { - // Compute drag force - VectorDim drag_force = drag_force_coefficient_.cwiseProduct( - velocity_.col(mpm::NodePhase::nLiquid) - - velocity_.col(mpm::NodePhase::nSolid)); - - // Unbalanced force of liquid phase - auto unbalanced_force_liquid = - this->external_force(mpm::NodePhase::nLiquid) + - this->internal_force(mpm::NodePhase::nLiquid) - drag_force; - // Acceleration of liquid phase (momentume balance of fluid phase) - this->acceleration_.col(mpm::NodePhase::nLiquid) = - (unbalanced_force_liquid - - damping_factor * unbalanced_force_liquid.norm() * - this->velocity_.col(mpm::NodePhase::nLiquid).cwiseSign()) / - this->mass(mpm::NodePhase::nLiquid); - - // Unbalanced force of solid phase - auto unbalanced_force_solid = - this->external_force(mpm::NodePhase::nMixture) + - this->internal_force(mpm::NodePhase::nMixture) - - this->mass(mpm::NodePhase::nLiquid) * - this->acceleration(mpm::NodePhase::nLiquid); - // Acceleration of solid phase (momentume balance of mixture) - this->acceleration_.col(mpm::NodePhase::nSolid) = - (unbalanced_force_solid - - damping_factor * unbalanced_force_solid.norm() * - this->velocity_.col(mpm::NodePhase::nSolid).cwiseSign()) / - this->mass(mpm::NodePhase::nSolid); - - // Apply friction constraints - this->apply_friction_constraints(dt); - - // Velocity += acceleration * dt - this->velocity_ += this->acceleration_ * 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(mpm::NodePhase::nSolid)(i)) < tolerance) - velocity_.col(mpm::NodePhase::nSolid)(i) = 0.; - if (std::abs(acceleration_.col(mpm::NodePhase::nSolid)(i)) < tolerance) - acceleration_.col(mpm::NodePhase::nSolid)(i) = 0.; - if (std::abs(velocity_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) - velocity_.col(mpm::NodePhase::nLiquid)(i) = 0.; - if (std::abs(acceleration_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) - acceleration_.col(mpm::NodePhase::nLiquid)(i) = 0.; - } - status = true; - } - return status; -} - -//! Assign pressure constraint -template -bool mpm::Node::assign_pressure_constraint( - const unsigned phase, const double pressure, - const std::shared_ptr& function) { - bool status = true; - try { - // Constrain directions can take values between 0 and Tnphases - if (phase < Tnphases * 2) { - 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; -} - //! Assign velocity constraint //! Constrain directions can take values between 0 and Dim * Nphases template @@ -812,3 +652,165 @@ void mpm::Node +void mpm::Node::update_drag_force_coefficient( + bool update, const Eigen::Matrix& drag_force_coefficient) { + + // Decide to update or assign + const double factor = (update == true) ? 1. : 0.; + + // Update/assign drag force coefficient + node_mutex_.lock(); + drag_force_coefficient_ = + drag_force_coefficient_ * factor + drag_force_coefficient; + node_mutex_.unlock(); +} + +//! Compute acceleration and velocity for two phase +template +bool mpm::Node:: + compute_acceleration_velocity_twophase_explicit(double dt) noexcept { + bool status = false; + const double tolerance = 1.0E-15; + if (this->mass(mpm::NodePhase::nSolid) > tolerance && + this->mass(mpm::NodePhase::nLiquid) > tolerance) { + // Compute drag force + VectorDim drag_force = drag_force_coefficient_.cwiseProduct( + velocity_.col(mpm::NodePhase::nLiquid) - + velocity_.col(mpm::NodePhase::nSolid)); + + // Acceleration of pore fluid (momentume balance of fluid phase) + this->acceleration_.col(mpm::NodePhase::nLiquid) = + (this->external_force_.col(mpm::NodePhase::nLiquid) + + this->internal_force_.col(mpm::NodePhase::nLiquid) - drag_force) / + this->mass_(mpm::NodePhase::nLiquid); + + // Acceleration of solid skeleton (momentume balance of mixture) + this->acceleration_.col(mpm::NodePhase::nSolid) = + (this->external_force_.col(mpm::NodePhase::nMixture) + + this->internal_force_.col(mpm::NodePhase::nMixture) - + this->mass_(mpm::NodePhase::nLiquid) * + this->acceleration_.col(mpm::NodePhase::nLiquid)) / + this->mass_(mpm::NodePhase::nSolid); + + // Apply friction constraints + this->apply_friction_constraints(dt); + + // Velocity += acceleration * dt + this->velocity_ += this->acceleration_ * 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(mpm::NodePhase::nSolid)(i)) < tolerance) + velocity_.col(mpm::NodePhase::nSolid)(i) = 0.; + if (std::abs(acceleration_.col(mpm::NodePhase::nSolid)(i)) < tolerance) + acceleration_.col(mpm::NodePhase::nSolid)(i) = 0.; + if (std::abs(velocity_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) + velocity_.col(mpm::NodePhase::nLiquid)(i) = 0.; + if (std::abs(acceleration_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) + acceleration_.col(mpm::NodePhase::nLiquid)(i) = 0.; + } + status = true; + } + return status; +} + +//! TwoPhase functions-------------------------------------------------------- +//! Compute acceleration and velocity for two phase with damping +template +bool mpm::Node:: + compute_acceleration_velocity_twophase_explicit_cundall( + double dt, double damping_factor) noexcept { + bool status = false; + const double tolerance = 1.0E-15; + + if (this->mass(mpm::NodePhase::nSolid) > tolerance && + this->mass(mpm::NodePhase::nLiquid) > tolerance) { + // Compute drag force + VectorDim drag_force = drag_force_coefficient_.cwiseProduct( + velocity_.col(mpm::NodePhase::nLiquid) - + velocity_.col(mpm::NodePhase::nSolid)); + + // Unbalanced force of liquid phase + auto unbalanced_force_liquid = + this->external_force(mpm::NodePhase::nLiquid) + + this->internal_force(mpm::NodePhase::nLiquid) - drag_force; + // Acceleration of liquid phase (momentume balance of fluid phase) + this->acceleration_.col(mpm::NodePhase::nLiquid) = + (unbalanced_force_liquid - + damping_factor * unbalanced_force_liquid.norm() * + this->velocity_.col(mpm::NodePhase::nLiquid).cwiseSign()) / + this->mass(mpm::NodePhase::nLiquid); + + // Unbalanced force of solid phase + auto unbalanced_force_solid = + this->external_force(mpm::NodePhase::nMixture) + + this->internal_force(mpm::NodePhase::nMixture) - + this->mass(mpm::NodePhase::nLiquid) * + this->acceleration(mpm::NodePhase::nLiquid); + // Acceleration of solid phase (momentume balance of mixture) + this->acceleration_.col(mpm::NodePhase::nSolid) = + (unbalanced_force_solid - + damping_factor * unbalanced_force_solid.norm() * + this->velocity_.col(mpm::NodePhase::nSolid).cwiseSign()) / + this->mass(mpm::NodePhase::nSolid); + + // Apply friction constraints + this->apply_friction_constraints(dt); + + // Velocity += acceleration * dt + this->velocity_ += this->acceleration_ * 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(mpm::NodePhase::nSolid)(i)) < tolerance) + velocity_.col(mpm::NodePhase::nSolid)(i) = 0.; + if (std::abs(acceleration_.col(mpm::NodePhase::nSolid)(i)) < tolerance) + acceleration_.col(mpm::NodePhase::nSolid)(i) = 0.; + if (std::abs(velocity_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) + velocity_.col(mpm::NodePhase::nLiquid)(i) = 0.; + if (std::abs(acceleration_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) + acceleration_.col(mpm::NodePhase::nLiquid)(i) = 0.; + } + status = true; + } + return status; +} + +//! Assign pressure constraint +template +bool mpm::Node::assign_pressure_constraint( + const unsigned phase, const double pressure, + const std::shared_ptr& function) { + bool status = true; + try { + // Constrain directions can take values between 0 and Tnphases + if (phase < Tnphases * 2) { + 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; +} +//---------------------------------------------------------------------------- \ No newline at end of file diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index fd3bfc73e..f7f8d8bed 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -292,6 +292,7 @@ class ParticleBase { //! Return neighbour ids virtual std::vector neighbours() const = 0; + //! TwoPhase functions-------------------------------------------------------- //! Update porosity //! \param[in] dt Analysis time step virtual bool update_porosity(double dt) { @@ -326,24 +327,6 @@ class ParticleBase { return 0; }; - //! Return mixture traction - virtual VectorDim mixture_traction() const { - auto error = VectorDim::Zero(); - throw std::runtime_error( - "Calling the base class function (mixture_traction) in " - "ParticleBase:: illegal operation!"); - return error; - }; - - //! Return liquid mass - //! \retval liquid mass Liquid phase mass - virtual double liquid_mass() const { - throw std::runtime_error( - "Calling the base class function (liquid_mass) in " - "ParticleBase:: illegal operation!"); - return 0; - }; - //! Assign velocity to the particle liquid phase //! \param[in] velocity A vector of particle liquid phase velocity //! \retval status Assignment status @@ -354,34 +337,6 @@ class ParticleBase { return 0; }; - //! Return velocity of the particle liquid phase - //! \retval liquid velocity Liquid phase velocity - virtual VectorDim liquid_velocity() const { - auto error = VectorDim::Zero(); - throw std::runtime_error( - "Calling the base class function (liquid_velocity) in " - "ParticleBase:: illegal operation!"); - return error; - }; - - //! Return strain of the particle liquid phase - //! \retval liquid strain Liquid phase strain - virtual Eigen::Matrix liquid_strain() const { - auto error = Eigen::Matrix::Zero(); - throw std::runtime_error( - "Calling the base class function (liquid_strain) in " - "ParticleBase:: illegal operation!"); - return error; - }; - - //! Compute pore pressure somoothening by interpolating nodal pressure - virtual bool compute_pore_pressure_smoothing() { - throw std::runtime_error( - "Calling the base class function (compute_pore_pressure_smoothing) in " - "ParticleBase:: illegal operation!"); - return 0; - }; - //! Compute pore pressure //! \param[in] dt Time step size virtual void compute_pore_pressure(double dt) { @@ -390,23 +345,6 @@ class ParticleBase { "ParticleBase:: illegal operation!"); }; - //! Return liquid pore pressure - //! \retval pore pressure Pore liquid pressure - virtual double pore_pressure() const { - throw std::runtime_error( - "Calling the base class function (pore_pressure) in " - "ParticleBase:: illegal operation!"); - return 0; - }; - - //! Update particle permeability - virtual bool update_permeability() { - throw std::runtime_error( - "Calling the base class function (update_permeability) in " - "ParticleBase:: illegal operation!"); - return 0; - }; - //! Map drag force coefficient virtual bool map_drag_force_coefficient() { throw std::runtime_error( @@ -466,6 +404,35 @@ class ParticleBase { return false; }; + //! Return liquid mass + //! \retval liquid mass Liquid phase mass + virtual double liquid_mass() const { + throw std::runtime_error( + "Calling the base class function (liquid_mass) in " + "ParticleBase:: illegal operation!"); + return 0; + }; + + //! Return velocity of the particle liquid phase + //! \retval liquid velocity Liquid phase velocity + virtual VectorDim liquid_velocity() const { + auto error = VectorDim::Zero(); + throw std::runtime_error( + "Calling the base class function (liquid_velocity) in " + "ParticleBase:: illegal operation!"); + return error; + }; + + //! Return liquid pore pressure + //! \retval pore pressure Pore liquid pressure + virtual double pore_pressure() const { + throw std::runtime_error( + "Calling the base class function (pore_pressure) in " + "ParticleBase:: illegal operation!"); + return 0; + }; + //---------------------------------------------------------------------------- + protected: //! particleBase id Index id_{std::numeric_limits::max()}; diff --git a/include/particles/twophase_particle.h b/include/particles/twophase_particle.h index ac22a8857..9e8e19742 100644 --- a/include/particles/twophase_particle.h +++ b/include/particles/twophase_particle.h @@ -65,9 +65,6 @@ class TwoPhaseParticle : public mpm::Particle { //! Assign saturation degree bool assign_saturation_degree() override; - //! Return mixture traction - VectorDim mixture_traction() const { return mixture_traction_; }; - //! Compute both solid and liquid mass void compute_mass() noexcept override; @@ -101,37 +98,13 @@ class TwoPhaseParticle : public mpm::Particle { //! \retval status Assignment status bool assign_liquid_velocity(const VectorDim& velocity) override; - //! Return velocity of the particle liquid phase - //! \retval liquid velocity Liquid phase velocity - VectorDim liquid_velocity() const override { return liquid_velocity_; } - - //! Return liquid strain of the particle - Eigen::Matrix liquid_strain() const override { - return liquid_strain_; - } - - //! Return liquid mass - //! \retval liquid mass Liquid phase mass - double liquid_mass() const override { return liquid_mass_; } - - //! Compute pore pressure somoothening by interpolating nodal pressure - bool compute_pore_pressure_smoothing() noexcept override; - //! Compute pore pressure //! \param[in] dt Time step size void compute_pore_pressure(double dt) noexcept override; - //! Return liquid pore pressure - //! \retval pore pressure Pore liquid pressure - double pore_pressure() const override { return pore_pressure_; } - //! Map drag force coefficient bool map_drag_force_coefficient() override; - //! Update particle permeability - //! \retval status Update status - bool update_permeability() override; - //! Assign particle liquid phase velocity constraints //! Directions can take values between 0 and Dim //! \param[in] dir Direction of particle velocity constraint @@ -178,6 +151,18 @@ class TwoPhaseParticle : public mpm::Particle { bool compute_pressure_smoothing( unsigned phase = mpm::ParticlePhase::Solid) noexcept override; + //! Return velocity of the particle liquid phase + //! \retval liquid velocity Liquid phase velocity + VectorDim liquid_velocity() const override { return liquid_velocity_; } + + //! Return liquid mass + //! \retval liquid mass Liquid phase mass + double liquid_mass() const override { return liquid_mass_; } + + //! Return liquid pore pressure + //! \retval pore pressure Pore liquid pressure + double pore_pressure() const override { return pore_pressure_; } + private: //! Assign liquid mass and momentum to nodes virtual void map_liquid_mass_momentum_to_nodes() noexcept; @@ -236,10 +221,10 @@ class TwoPhaseParticle : public mpm::Particle { using ParticleBase::material_id_; //! Particle total volume using Particle::volume_; - //! Particle mass density - using Particle::mass_density_; //! Particle mass for solid phase using Particle::mass_; + //! Particle mass density + using Particle::mass_density_; //! dN/dX using Particle::dn_dx_; //! dN/dX at cell centroid @@ -261,22 +246,15 @@ class TwoPhaseParticle : public mpm::Particle { double pore_pressure_constraint_{std::numeric_limits::max()}; //! Pore pressure double pore_pressure_; + //! Permeability parameter c1 (k = k_p * c1) + VectorDim permeability_; //! Set mixture traction bool set_mixture_traction_; //! Traction for mixture (soil skeleton + pore liquid) Eigen::Matrix mixture_traction_; - //! Liquid strain rate - Eigen::Matrix liquid_strain_rate_; // delete if not needed - //! Liquid strain rate - Eigen::Matrix liquid_strain_; // delete if not needed //! Logger std::unique_ptr console_; - //! Permeability - VectorDim permeability_; - //! Permeability parameter - VectorDim c1_; - //! reference pore pressure - double reference_pore_pressure_{0}; + }; // TwoPhaseParticle class } // namespace mpm diff --git a/include/particles/twophase_particle.tcc b/include/particles/twophase_particle.tcc index 18be09b43..1bc7dcba5 100644 --- a/include/particles/twophase_particle.tcc +++ b/include/particles/twophase_particle.tcc @@ -42,8 +42,6 @@ mpm::HDF5Particle mpm::TwoPhaseParticle::hdf5() const { // liquid_velocity.setZero(); // for (unsigned j = 0; j < Tdim; ++j) // liquid_velocity[j] = this->liquid_velocity_[j]; - // // Particle liquid strain - // Eigen::Matrix liquid_strain = this->liquid_strain_; // // Particle liquid mass // particle_data.liquid_mass = this->liquid_mass_; // Particle pore pressure @@ -52,13 +50,6 @@ mpm::HDF5Particle mpm::TwoPhaseParticle::hdf5() const { // particle_data.liquid_velocity_x = liquid_velocity[0]; // particle_data.liquid_velocity_y = liquid_velocity[1]; // particle_data.liquid_velocity_z = liquid_velocity[2]; - // // Particle liquid strain - // particle_data.liquid_strain_xx = liquid_strain[0]; - // particle_data.liquid_strain_yy = liquid_strain[1]; - // particle_data.liquid_strain_zz = liquid_strain[2]; - // particle_data.liquid_gamma_xy = liquid_strain[3]; - // particle_data.liquid_gamma_yz = liquid_strain[4]; - // particle_data.liquid_gamma_xz = liquid_strain[5]; // // Particle liquid material id // particle_data.liquid_material_id = this->liquid_material_id_; @@ -88,14 +79,6 @@ bool mpm::TwoPhaseParticle::initialise_particle( // for (unsigned i = 0; i < Tdim; ++i) // this->liquid_velocity_(i) = liquid_velocity(i); - // // Liquid strain - // this->liquid_strain_[0] = particle.liquid_strain_xx; - // this->liquid_strain_[1] = particle.liquid_strain_yy; - // this->liquid_strain_[2] = particle.liquid_strain_zz; - // this->liquid_strain_[3] = particle.liquid_gamma_xy; - // this->liquid_strain_[4] = particle.liquid_gamma_yz; - // this->liquid_strain_[5] = particle.liquid_gamma_xz; - // // Liquid material id // this->liquid_material_id_ = particle.liquid_material_id; @@ -118,14 +101,11 @@ void mpm::TwoPhaseParticle::initialise() { mpm::Particle::initialise(); liquid_mass_ = 0.; liquid_velocity_.setZero(); - liquid_strain_rate_.setZero(); - liquid_strain_.setZero(); set_mixture_traction_ = false; pore_pressure_ = 0.; liquid_saturation_ = 1.; // Initialize vector data properties - this->properties_["liquid_strains"] = [&]() { return liquid_strain(); }; this->properties_["liquid_velocities"] = [&]() { return liquid_velocity(); }; this->properties_["pore_pressure"] = [&]() { Eigen::VectorXd vec_pressure = Eigen::VectorXd::Zero(3); @@ -276,24 +256,6 @@ void mpm::TwoPhaseParticle::compute_pore_pressure(double dt) noexcept { // if (this->free_surface()) this->pore_pressure_ = 0.0; } -// Compute pore liquid pressure smoothing based on nodal pressure -template -bool mpm::TwoPhaseParticle::compute_pore_pressure_smoothing() noexcept { - // Check if particle has a valid cell ptr - assert(cell_ != nullptr); - - bool status = true; - double pressure = 0; - for (unsigned i = 0; i < nodes_.size(); ++i) - pressure += shapefn_(i) * nodes_[i]->pressure(mpm::ParticlePhase::Liquid); - - // Update pore liquid pressure to interpolated nodal pressure - this->pore_pressure_ = pressure; - // Apply free surface - // if (this->free_surface()) this->pore_pressure_ = 0.0; - return status; -} - //! Map body force for both mixture and liquid template void mpm::TwoPhaseParticle::map_body_force( @@ -636,24 +598,39 @@ bool mpm::TwoPhaseParticle::assign_permeability() { std::pow(this->porosity_, 3) / std::pow((1. - this->porosity_), 2); switch (Tdim) { case (1): { - permeability_(0) = this->material()->template property("k_x"); - c1_(0) = permeability_(0) / k_p; + // Check if the permeability is valid + if (this->material()->template property("k_x") < 0) + throw std::runtime_error("Material's permeability is invalid"); + // Assign permeability + permeability_(0) = + this->material()->template property("k_x") / k_p; break; } case (2): { - permeability_(0) = this->material()->template property("k_x"); - permeability_(1) = this->material()->template property("k_y"); - c1_(0) = permeability_(0) / k_p; - c1_(1) = permeability_(1) / k_p; + // Check if the permeability is valid + if (this->material()->template property("k_x") < 0 || + this->material()->template property("k_y") < 0) + throw std::runtime_error("Material's permeability is invalid"); + // Assign permeability + permeability_(0) = + this->material()->template property("k_x") / k_p; + permeability_(1) = + this->material()->template property("k_y") / k_p; break; } default: { - permeability_(0) = this->material()->template property("k_x"); - permeability_(1) = this->material()->template property("k_y"); - permeability_(2) = this->material()->template property("k_z"); - c1_(0) = permeability_(0) / k_p; - c1_(1) = permeability_(1) / k_p; - c1_(2) = permeability_(2) / k_p; + // Check if the permeability is valid + if (this->material()->template property("k_x") < 0 || + this->material()->template property("k_y") < 0 || + this->material()->template property("k_z") < 0) + throw std::runtime_error("Material's permeability is invalid"); + // Assign permeability + permeability_(0) = + this->material()->template property("k_x") / k_p; + permeability_(1) = + this->material()->template property("k_y") / k_p; + permeability_(2) = + this->material()->template property("k_z") / k_p; break; } } @@ -667,46 +644,28 @@ bool mpm::TwoPhaseParticle::assign_permeability() { return status; } -//! Update particle permeability +//! Map drag force template -bool mpm::TwoPhaseParticle::update_permeability() { +bool mpm::TwoPhaseParticle::map_drag_force_coefficient() { 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::TwoPhaseParticle::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.) + if (k_p > 0.) drag_force_coefficient(i) = porosity_ * porosity_ * 9.81 * this->material(mpm::ParticlePhase::Liquid) ->template property(std::string("density")) / - permeability_(i); + (k_p * permeability_(i)); else - throw std::runtime_error("Permeability coefficient is invalid"); + throw std::runtime_error("Porosity coefficient is invalid"); } // Map drag forces from particle to nodes From 974a86d350dc1348a4da9eb5479754ff3727dd77 Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Thu, 30 Jul 2020 11:55:31 -0700 Subject: [PATCH 070/175] Move pressure constraints functions --- include/loads_bcs/constraints.h | 15 ++++++++ include/loads_bcs/constraints.tcc | 50 ++++++++++++++++++++++++++ include/mesh.h | 15 -------- include/mesh.tcc | 60 ------------------------------- include/solvers/mpm_base.tcc | 11 +++--- 5 files changed, 71 insertions(+), 80 deletions(-) diff --git a/include/loads_bcs/constraints.h b/include/loads_bcs/constraints.h index 0efdef6f6..23a01081d 100644 --- a/include/loads_bcs/constraints.h +++ b/include/loads_bcs/constraints.h @@ -48,6 +48,21 @@ class Constraints { const std::vector>& friction_constraints); + //! Assign nodal velocity 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); + private: //! Mesh object std::shared_ptr> mesh_; diff --git a/include/loads_bcs/constraints.tcc b/include/loads_bcs/constraints.tcc index 5813e609f..d8bf667e2 100644 --- a/include/loads_bcs/constraints.tcc +++ b/include/loads_bcs/constraints.tcc @@ -105,3 +105,53 @@ 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, int set_id, + const unsigned phase, const unsigned pconstraint) { + bool status = true; + try { + auto nset = mesh_->nodes(set_id); + if (nset.size() == 0) + throw std::runtime_error( + "Node set is empty for assignment of pressure constraints"); + +#pragma omp parallel for schedule(runtime) + for (auto nitr = nset.cbegin(); nitr != nset.cend(); ++nitr) { + if (!(*nitr)->assign_pressure_constraint(phase, pconstraint, mfunction)) + throw std::runtime_error("Setting 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 + if (!mesh_->node(nid)->assign_pressure_constraint(phase, pressure, + nullptr)) + throw std::runtime_error( + "Nodal pressure constraints assignment failed"); + } + } 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 cfb94e0e8..a94b600ff 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -447,26 +447,11 @@ class Mesh { // Initialise the nodal properties' map void initialise_nodal_properties(); - //! 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 pore pressures //! \param[in] particle_pore_pressure Initial pore pressure of particle bool assign_particles_pore_pressures( const std::vector& particle_pore_pressures); - //! Assign nodal velocity 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); - 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 18c529c91..19cc51129 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1892,34 +1892,6 @@ void mpm::Mesh::initialise_nodal_properties() { nodal_properties_->initialise_nodal_properties(); } -//! 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 (!nodes_.size()) - throw std::runtime_error( - "No nodes have been assigned in mesh, cannot assign pressure " - "constraint"); - - // Set id of -1, is all nodes - Vector> nodes = - (set_id == -1) ? this->nodes_ : node_sets_.at(set_id); - -#pragma omp parallel for schedule(runtime) - for (auto nitr = nodes.cbegin(); nitr != nodes.cend(); ++nitr) { - if (!(*nitr)->assign_pressure_constraint(phase, pconstraint, mfunction)) - throw std::runtime_error("Setting pressure constraint failed"); - } - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; - } - return status; -} - //! Assign particle pore pressures template bool mpm::Mesh::assign_particles_pore_pressures( @@ -1947,36 +1919,4 @@ bool mpm::Mesh::assign_particles_pore_pressures( 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; } \ No newline at end of file diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index eb6a1c571..541b86650 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -941,10 +941,11 @@ void mpm::MPMBase::nodal_pore_pressure_constraints( if (constraints.find("file") != constraints.end()) { std::string pore_pressure_constraints_file = constraints.at("file").template get(); - bool ppressure_constraints = mesh_->assign_nodal_pressure_constraints( - constraint_phase, - mesh_io->read_pressure_constraints( - io_->file_name(pore_pressure_constraints_file))); + bool ppressure_constraints = + constraints_->assign_nodal_pressure_constraints( + constraint_phase, + mesh_io->read_pressure_constraints( + io_->file_name(pore_pressure_constraints_file))); if (!ppressure_constraints) throw std::runtime_error( "Pore pressure constraints are not properly assigned"); @@ -960,7 +961,7 @@ void mpm::MPMBase::nodal_pore_pressure_constraints( double pore_pressure = constraints.at("pore_pressure").template get(); // Add pore pressure constraint to mesh - mesh_->assign_nodal_pressure_constraint( + constraints_->assign_nodal_pressure_constraint( pfunction, nset_id, constraint_phase, pore_pressure); // if (constraint_phase >= Tnphases) { // // Reference step From 5400fd201edef15cdadd4211ada33508e00511dd Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Thu, 30 Jul 2020 12:09:58 -0700 Subject: [PATCH 071/175] Fix the error in the test --- include/solvers/mpm_base.tcc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index 541b86650..a7625295e 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -512,8 +512,7 @@ void mpm::MPMBase::write_vtk(mpm::Index step, mpm::Index max_steps) { #endif //! VTK vector variables - std::vector vtk_vector_data = {"displacements", "velocities", - "pore_pressure"}; + std::vector vtk_vector_data = {"displacements", "velocities"}; // Write VTK attributes for (const auto& attribute : vtk_vector_data) { From 178eff077d2c9386d37443fd2de65e6e1ed328d0 Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Thu, 30 Jul 2020 17:47:38 -0700 Subject: [PATCH 072/175] Add twophase particle test --- CMakeLists.txt | 1 + include/particles/particle_base.h | 40 +- include/particles/twophase_particle.h | 55 +- include/particles/twophase_particle.tcc | 169 +-- include/solvers/mpm_explicit_twophase.tcc | 3 + tests/twophase_particle_test.cc | 1596 +++++++++++++++++++++ 6 files changed, 1703 insertions(+), 161 deletions(-) create mode 100644 tests/twophase_particle_test.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 5fc7cfa1d..4a2703295 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -217,6 +217,7 @@ if(MPM_BUILD_TESTING) ${mpm_SOURCE_DIR}/tests/node_vector_test.cc ${mpm_SOURCE_DIR}/tests/particle_cell_crossing_test.cc ${mpm_SOURCE_DIR}/tests/particle_test.cc + ${mpm_SOURCE_DIR}/tests/twophase_particle_test.cc ${mpm_SOURCE_DIR}/tests/particle_traction_test.cc ${mpm_SOURCE_DIR}/tests/particle_vector_test.cc ${mpm_SOURCE_DIR}/tests/point_in_cell_test.cc diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index f7f8d8bed..7ef799023 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -310,15 +310,6 @@ class ParticleBase { "ParticleBase:: illegal operation!"); }; - //! Assign particle pressure constraints - virtual bool assign_particle_pore_pressure_constraint(double pressure) { - throw std::runtime_error( - "Calling the base class function " - "(assign_particle_pore_pressure_constraint) in " - "ParticleBase:: illegal operation!"); - return 0; - }; - //! Assign saturation degree virtual bool assign_saturation_degree() { throw std::runtime_error( @@ -353,28 +344,6 @@ class ParticleBase { return 0; }; - //! Assign particle liquid phase velocity constraints - //! Directions can take values between 0 and Dim - //! \param[in] dir Direction of particle velocity constraint - //! \param[in] velocity Applied particle liquid phase velocity constraint - //! \retval status Assignment status - virtual bool assign_particle_liquid_velocity_constraint(unsigned dir, - double velocity) { - throw std::runtime_error( - "Calling the base class function " - "(assign_particle_liquid_velocity_constraint) in " - "ParticleBase:: illegal operation!"); - return 0; - }; - - //! Apply particle liquid phase velocity constraints - virtual void apply_particle_liquid_velocity_constraints() { - throw std::runtime_error( - "Calling the base class function " - "(apply_particle_liquid_velocity_constraints) in " - "ParticleBase:: illegal operation!"); - }; - //! Initialise particle pore pressure by watertable virtual bool initialise_pore_pressure_watertable( const unsigned dir_v, const unsigned dir_h, @@ -431,6 +400,15 @@ class ParticleBase { "ParticleBase:: illegal operation!"); return 0; }; + + //! Return porosity + //! \retval porosity Porosity + virtual double porosity() const { + throw std::runtime_error( + "Calling the base class function (porosity) in " + "ParticleBase:: illegal operation!"); + return 0; + }; //---------------------------------------------------------------------------- protected: diff --git a/include/particles/twophase_particle.h b/include/particles/twophase_particle.h index 9e8e19742..e7b514a5f 100644 --- a/include/particles/twophase_particle.h +++ b/include/particles/twophase_particle.h @@ -75,12 +75,6 @@ class TwoPhaseParticle : public mpm::Particle { //! \param[in] pgravity Gravity of a particle void map_body_force(const VectorDim& pgravity) noexcept override; - //! Assign traction to the particle - //! \param[in] direction Index corresponding to the direction of traction - //! \param[in] traction Particle traction in specified direction - //! \retval status Assignment status - bool assign_traction(unsigned direction, double traction) override; - //! Map traction force void map_traction_force() noexcept override; @@ -105,21 +99,6 @@ class TwoPhaseParticle : public mpm::Particle { //! Map drag force coefficient bool map_drag_force_coefficient() override; - //! Assign particle liquid phase velocity constraints - //! Directions can take values between 0 and Dim - //! \param[in] dir Direction of particle velocity constraint - //! \param[in] velocity Applied particle liquid phase velocity constraint - //! \retval status Assignment status - bool assign_particle_liquid_velocity_constraint(unsigned dir, - double velocity) override; - - //! Apply particle liquid phase velocity constraints - void apply_particle_liquid_velocity_constraints() override; - - //! Assign particle pressure constraints - //! \retval status Assignment status - bool assign_particle_pore_pressure_constraint(double pressure) override; - //! Initial pore pressure //! \param[in] pore pressure Initial pore pressure void initial_pore_pressure(double pore_pressure) override { @@ -151,6 +130,12 @@ class TwoPhaseParticle : public mpm::Particle { bool compute_pressure_smoothing( unsigned phase = mpm::ParticlePhase::Solid) noexcept override; + //! Apply particle velocity constraints + //! \param[in] dir Direction of particle velocity constraint + //! \param[in] velocity Applied particle velocity constraint + void apply_particle_velocity_constraints(unsigned dir, + double velocity) override; + //! Return velocity of the particle liquid phase //! \retval liquid velocity Liquid phase velocity VectorDim liquid_velocity() const override { return liquid_velocity_; } @@ -163,6 +148,10 @@ class TwoPhaseParticle : public mpm::Particle { //! \retval pore pressure Pore liquid pressure double pore_pressure() const override { return pore_pressure_; } + //! Reture porosity + //! \retval porosity Porosity + double porosity() const override { return porosity_; } + private: //! Assign liquid mass and momentum to nodes virtual void map_liquid_mass_momentum_to_nodes() noexcept; @@ -177,15 +166,11 @@ class TwoPhaseParticle : public mpm::Particle { //! \param[in] pgravity Gravity of a particle virtual void map_liquid_body_force(const VectorDim& pgravity) noexcept; - //! Assign mixture traction - //! \param[in] direction Index corresponding to the direction of traction - //! \param[in] traction Particle traction in specified direction - //! \retval status Assignment status - virtual bool assign_mixture_traction(unsigned direction, double traction); - //! Map two phase mixture traction force - //! \param[in] mixture Identification for Mixture - virtual void map_mixture_traction_force(unsigned mixture) noexcept; + virtual void map_mixture_traction_force() noexcept; + + //! Map two phase liquid traction force + virtual void map_liquid_traction_force() noexcept; //! Map liquid internal force virtual void map_liquid_internal_force() noexcept; @@ -229,6 +214,12 @@ class TwoPhaseParticle : public mpm::Particle { using Particle::dn_dx_; //! dN/dX at cell centroid using Particle::dn_dx_centroid_; + //! Set traction + using Particle::set_traction_; + //! Surface Traction (given as a stress; force/area) + using Particle::traction_; + //! Particle velocity constraints + using Particle::particle_velocity_constraints_; //! Liquid mass double liquid_mass_; @@ -240,18 +231,12 @@ class TwoPhaseParticle : public mpm::Particle { double porosity_{0.0}; //! Liquid velocity Eigen::Matrix liquid_velocity_; - //! Particle liquid phase velocity constraints - std::map liquid_velocity_constraints_; //! Pore pressure constraint double pore_pressure_constraint_{std::numeric_limits::max()}; //! Pore pressure double pore_pressure_; //! Permeability parameter c1 (k = k_p * c1) VectorDim permeability_; - //! Set mixture traction - bool set_mixture_traction_; - //! Traction for mixture (soil skeleton + pore liquid) - Eigen::Matrix mixture_traction_; //! Logger std::unique_ptr console_; diff --git a/include/particles/twophase_particle.tcc b/include/particles/twophase_particle.tcc index 1bc7dcba5..536645503 100644 --- a/include/particles/twophase_particle.tcc +++ b/include/particles/twophase_particle.tcc @@ -19,7 +19,7 @@ mpm::TwoPhaseParticle::TwoPhaseParticle(Index id, const VectorDim& coord) template mpm::TwoPhaseParticle::TwoPhaseParticle(Index id, const VectorDim& coord, bool status) - : mpm::ParticleBase(id, coord, status) { + : mpm::Particle(id, coord, status) { this->initialise(); cell_ = nullptr; nodes_.clear(); @@ -101,7 +101,6 @@ void mpm::TwoPhaseParticle::initialise() { mpm::Particle::initialise(); liquid_mass_ = 0.; liquid_velocity_.setZero(); - set_mixture_traction_ = false; pore_pressure_ = 0.; liquid_saturation_ = 1.; @@ -155,44 +154,13 @@ bool mpm::TwoPhaseParticle::assign_liquid_velocity( return status; } -// Assign traction -template -bool mpm::TwoPhaseParticle::assign_traction(unsigned direction, - double traction) { - bool status = true; - this->assign_mixture_traction(direction, traction); - return status; -} - -// Assign traction to the mixture -template -bool mpm::TwoPhaseParticle::assign_mixture_traction(unsigned direction, - double traction) { - bool status = false; - try { - if (direction >= Tdim || - this->volume_ == std::numeric_limits::max()) { - throw std::runtime_error( - "Particle mixture traction property: volume / direction is invalid"); - } - // Assign mixture traction - mixture_traction_(direction) = - traction * this->volume_ / this->size_(direction); - status = true; - this->set_mixture_traction_ = true; - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; - } - return status; -} - // Compute mass of particle (both solid and fluid) template void mpm::TwoPhaseParticle::compute_mass() noexcept { // Check if particle volume is set and material ptr is valid assert(volume_ != std::numeric_limits::max() && - this->material() != nullptr && this->material(1) != nullptr); + this->material() != nullptr && + this->material(mpm::ParticlePhase::Liquid) != nullptr); // Mass = volume of particle * mass_density // Solid mass this->mass_density_ = @@ -203,7 +171,7 @@ void mpm::TwoPhaseParticle::compute_mass() noexcept { // Liquid mass this->liquid_mass_density_ = liquid_saturation_ * porosity_ * - this->material(mpm::ParticlePhase::Liquid) + (this->material(mpm::ParticlePhase::Liquid)) ->template property(std::string("density")); this->liquid_mass_ = volume_ * liquid_mass_density_; } @@ -289,21 +257,32 @@ void mpm::TwoPhaseParticle::map_mixture_body_force( //! Map traction force template void mpm::TwoPhaseParticle::map_traction_force() noexcept { - this->map_mixture_traction_force(mpm::ParticlePhase::Mixture); + this->map_mixture_traction_force(); + this->map_liquid_traction_force(); } //! Map mixture traction force template -void mpm::TwoPhaseParticle::map_mixture_traction_force( - unsigned mixture) noexcept { - if (this->set_mixture_traction_) { - // Map particle mixture traction forces to nodes +void mpm::TwoPhaseParticle::map_mixture_traction_force() noexcept { + if (this->set_traction_) { + // Map particle traction forces to nodes for (unsigned i = 0; i < nodes_.size(); ++i) - nodes_[i]->update_external_force(true, mixture, - (shapefn_[i] * this->mixture_traction_)); + nodes_[i]->update_external_force(true, mpm::ParticlePhase::Mixture, + (shapefn_[i] * traction_)); } } +//! Map liquid traction force +template +void mpm::TwoPhaseParticle::map_liquid_traction_force() noexcept { + // if (this->set_traction_) { + // // Map particle traction forces to nodes + // for (unsigned i = 0; i < nodes_.size(); ++i) + // nodes_[i]->update_external_force(true, mpm::ParticlePhase::Mixture, + // (shapefn_[i] * traction_)); + // } +} + //! Map both mixture and liquid internal force template inline void mpm::TwoPhaseParticle::map_internal_force() noexcept { @@ -314,7 +293,27 @@ inline void mpm::TwoPhaseParticle::map_internal_force() noexcept { //! Map liquid phase internal force template <> -void mpm::TwoPhaseParticle<2>::map_liquid_internal_force() noexcept { +inline void mpm::TwoPhaseParticle<1>::map_liquid_internal_force() noexcept { + // initialise a vector of pore pressure + Eigen::Matrix pressure; + pressure.setZero(); + pressure(0) = -this->pore_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) * pressure[0] * this->porosity_; + + force *= -1. * this->volume_; + + nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Liquid, force); + } +} + +//! Map liquid phase internal force +template <> +inline void mpm::TwoPhaseParticle<2>::map_liquid_internal_force() noexcept { // initialise a vector of pore pressure Eigen::Matrix pressure; pressure.setZero(); @@ -335,7 +334,7 @@ void mpm::TwoPhaseParticle<2>::map_liquid_internal_force() noexcept { } template <> -void mpm::TwoPhaseParticle<3>::map_liquid_internal_force() noexcept { +inline void mpm::TwoPhaseParticle<3>::map_liquid_internal_force() noexcept { // initialise a vector of pore pressure Eigen::Matrix pressure; pressure.setZero(); @@ -359,7 +358,27 @@ void mpm::TwoPhaseParticle<3>::map_liquid_internal_force() noexcept { //! Map mixture internal force template <> -void mpm::TwoPhaseParticle<2>::map_mixture_internal_force( +inline void mpm::TwoPhaseParticle<1>::map_mixture_internal_force( + unsigned mixture) noexcept { + // initialise a vector of pore pressure + Eigen::Matrix total_stress = this->stress_; + total_stress(0) -= this->pore_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. * this->volume_; + + nodes_[i]->update_internal_force(true, mixture, force); + } +} + +//! Map mixture internal force +template <> +inline void mpm::TwoPhaseParticle<2>::map_mixture_internal_force( unsigned mixture) noexcept { // initialise a vector of pore pressure Eigen::Matrix total_stress = this->stress_; @@ -380,7 +399,7 @@ void mpm::TwoPhaseParticle<2>::map_mixture_internal_force( } template <> -void mpm::TwoPhaseParticle<3>::map_mixture_internal_force( +inline void mpm::TwoPhaseParticle<3>::map_mixture_internal_force( unsigned mixture) noexcept { // initialise a vector of pore pressure Eigen::Matrix total_stress = this->stress_; @@ -510,59 +529,19 @@ void mpm::TwoPhaseParticle::compute_updated_liquid_velocity( // Update particle velocity to interpolated nodal velocity this->liquid_velocity_ = velocity; } - - // Apply particle velocity constraints - this->apply_particle_liquid_velocity_constraints(); -} - -//! Assign particle liquid phase velocity constraint -//! Constrain directions can take values between 0 and Dim -template -bool mpm::TwoPhaseParticle::assign_particle_liquid_velocity_constraint( - unsigned dir, double velocity) { - bool status = true; - try { - //! Constrain directions can take values between 0 and Dim - if (dir < Tdim) - this->liquid_velocity_constraints_.insert( - std::make_pair(static_cast(dir), - static_cast(velocity))); - else - throw std::runtime_error( - "Particle liquid velocity constraint direction is out of bounds"); - - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; - } - return status; } //! Apply particle velocity constraints template -void mpm::TwoPhaseParticle::apply_particle_liquid_velocity_constraints() { - // Set particle velocity constraint - for (const auto& constraint : this->liquid_velocity_constraints_) { - // Direction value in the constraint (0, Dim) - const unsigned dir = constraint.first; - // Direction: dir % Tdim (modulus) - const auto direction = static_cast(dir % Tdim); - this->liquid_velocity_(direction) = constraint.second; - } -} +void mpm::TwoPhaseParticle::apply_particle_velocity_constraints( + unsigned dir, double velocity) { + // Set particle velocity constraint for solid phase + if (dir < Tdim) + mpm::Particle::apply_particle_velocity_constraints(dir, velocity); -//! Assign particle pressure constraints -template -bool mpm::TwoPhaseParticle::assign_particle_pore_pressure_constraint( - double pressure) { - bool status = true; - try { - this->pore_pressure_constraint_ = pressure; - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; - } - return status; + // Set particle velocity constraint for liquid phase + else + this->liquid_velocity_(static_cast(dir % Tdim)) = velocity; } // Assign porosity to the particle diff --git a/include/solvers/mpm_explicit_twophase.tcc b/include/solvers/mpm_explicit_twophase.tcc index dd7953f75..9df215857 100644 --- a/include/solvers/mpm_explicit_twophase.tcc +++ b/include/solvers/mpm_explicit_twophase.tcc @@ -304,6 +304,9 @@ bool mpm::MPMExplicitTwoPhase::solve() { std::bind(&mpm::ParticleBase::compute_updated_position, std::placeholders::_1, this->dt_, velocity_update_)); + // Apply particle velocity constraints + mesh_->apply_particle_velocity_constraints(); + // Update Stress Last if (this->stress_update_ == mpm::StressUpdate::USL) this->compute_stress_strain(); diff --git a/tests/twophase_particle_test.cc b/tests/twophase_particle_test.cc new file mode 100644 index 000000000..59de4268c --- /dev/null +++ b/tests/twophase_particle_test.cc @@ -0,0 +1,1596 @@ +#include + +#include "catch.hpp" + +#include "cell.h" +#include "element.h" +#include "function_base.h" +#include "hdf5_particle.h" +#include "hexahedron_element.h" +#include "linear_function.h" +#include "material.h" +#include "node.h" +#include "particle.h" +#include "quadrilateral_element.h" +#include "twophase_particle.h" + +//! \brief Check twophase particle class for 1D case +TEST_CASE("TwoPhase Particle is checked for 1D case", + "[twophase_particle][1D]") { + // Dimension + const unsigned Dim = 1; + // Dimension + const unsigned Dof = 1; + // Number of phases + const unsigned Nphases = 2; + // Json property + Json jfunctionproperties; + jfunctionproperties["id"] = 0; + std::vector x_values{{0.0, 0.5, 1.0}}; + std::vector fx_values{{0.0, 1.0, 1.0}}; + jfunctionproperties["xvalues"] = x_values; + jfunctionproperties["fxvalues"] = fx_values; + + // math function + std::shared_ptr mfunction = + std::make_shared(0, jfunctionproperties); + + // Coordinates + Eigen::Matrix coords; + coords.setZero(); + + //! Check for id = 0 + SECTION("TwoPhase Particle id is zero") { + mpm::Index id = 0; + std::shared_ptr> particle = + std::make_shared>(id, coords); + REQUIRE(particle->id() == 0); + REQUIRE(particle->status() == true); + } + + SECTION("TwoPhase Particle id is positive") { + //! Check for id is a positive value + mpm::Index id = std::numeric_limits::max(); + std::shared_ptr> particle = + std::make_shared>(id, coords); + REQUIRE(particle->id() == std::numeric_limits::max()); + REQUIRE(particle->status() == true); + } + + //! Construct with id, coordinates and status + SECTION("TwoPhase Particle with id, coordinates, and status") { + mpm::Index id = 0; + bool status = true; + std::shared_ptr> particle = + std::make_shared>(id, coords, status); + REQUIRE(particle->id() == 0); + REQUIRE(particle->status() == true); + particle->assign_status(false); + REQUIRE(particle->status() == false); + } + + //! Test coordinates function + SECTION("coordinates function is checked") { + mpm::Index id = 0; + const double Tolerance = 1.E-7; + + std::shared_ptr> particle = + std::make_shared>(id, coords); + + // Check for coordinates being zero + auto coordinates = particle->coordinates(); + for (unsigned i = 0; i < coordinates.size(); ++i) + REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + REQUIRE(coordinates.size() == Dim); + + // Check for negative value of coordinates + for (unsigned i = 0; i < coordinates.size(); ++i) + coords(i) = -1. * std::numeric_limits::max(); + particle->assign_coordinates(coords); + coordinates = particle->coordinates(); + for (unsigned i = 0; i < coordinates.size(); ++i) + REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + + REQUIRE(coordinates.size() == Dim); + + // Check for positive value of coordinates + for (unsigned i = 0; i < coordinates.size(); ++i) + coords(i) = std::numeric_limits::max(); + particle->assign_coordinates(coords); + coordinates = particle->coordinates(); + for (unsigned i = 0; i < coordinates.size(); ++i) + REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + + REQUIRE(coordinates.size() == Dim); + } + + //! Test initialise particle stresses + SECTION("TwoPhase Particle with initial stress") { + mpm::Index id = 0; + const double Tolerance = 1.E-7; + bool status = true; + std::shared_ptr> particle = + std::make_shared>(id, coords, status); + Eigen::Matrix stress = + Eigen::Matrix::Constant(5.7); + particle->initial_stress(stress); + REQUIRE(particle->stress().size() == stress.size()); + auto pstress = particle->stress(); + for (unsigned i = 0; i < pstress.size(); ++i) + REQUIRE(pstress[i] == Approx(stress[i]).epsilon(Tolerance)); + + auto pstress_data = particle->tensor_data("stresses"); + for (unsigned i = 0; i < pstress_data.size(); ++i) + REQUIRE(pstress_data[i] == Approx(stress[i]).epsilon(Tolerance)); + } + + //! Test particles velocity constraints + SECTION("TwoPhase Particle with velocity constraints") { + mpm::Index id = 0; + const double Tolerance = 1.E-7; + bool status = true; + std::shared_ptr> particle = + std::make_shared>(id, coords, status); + // Apply constraints for solid phase + particle->apply_particle_velocity_constraints(0, 10.5); + particle->apply_particle_velocity_constraints(1, 20.5); + + // Check apply constraints + REQUIRE(particle->velocity()(0) == Approx(10.5).epsilon(Tolerance)); + REQUIRE(particle->liquid_velocity()(0) == Approx(20.5).epsilon(Tolerance)); + } + + SECTION("Check particle properties") { + mpm::Index id = 0; + const double Tolerance = 1.E-7; + std::shared_ptr> particle = + std::make_shared>(id, coords); + + // Check mass + REQUIRE(particle->mass() == Approx(0.0).epsilon(Tolerance)); + double mass = 100.5; + particle->assign_mass(mass); + REQUIRE(particle->mass() == Approx(100.5).epsilon(Tolerance)); + + // Check stress + Eigen::Matrix stress; + for (unsigned i = 0; i < stress.size(); ++i) stress(i) = 17.51; + + for (unsigned i = 0; i < stress.size(); ++i) + REQUIRE(particle->stress()(i) == Approx(0.).epsilon(Tolerance)); + + // Check velocity + Eigen::VectorXd velocity; + velocity.resize(Dim); + for (unsigned i = 0; i < velocity.size(); ++i) velocity(i) = 17.51; + + for (unsigned i = 0; i < velocity.size(); ++i) + REQUIRE(particle->velocity()(i) == Approx(0.).epsilon(Tolerance)); + + REQUIRE(particle->assign_velocity(velocity) == true); + for (unsigned i = 0; i < velocity.size(); ++i) + REQUIRE(particle->velocity()(i) == Approx(17.51).epsilon(Tolerance)); + + // Assign volume + REQUIRE(particle->assign_volume(0.0) == false); + REQUIRE(particle->assign_volume(-5.0) == false); + REQUIRE(particle->assign_volume(2.0) == true); + // Check volume + REQUIRE(particle->volume() == Approx(2.0).epsilon(Tolerance)); + // Traction + double traction = 65.32; + const unsigned Direction = 0; + // Check traction + for (unsigned i = 0; i < Dim; ++i) + REQUIRE(particle->traction()(i) == Approx(0.).epsilon(Tolerance)); + // Try with a null math fuction ptr + REQUIRE(particle->assign_traction(Direction, traction) == true); + + for (unsigned i = 0; i < Dim; ++i) { + if (i == Direction) + REQUIRE(particle->traction()(i) == Approx(traction).epsilon(Tolerance)); + else + REQUIRE(particle->traction()(i) == Approx(0.).epsilon(Tolerance)); + } + + // Check for incorrect direction + const unsigned wrong_dir = 4; + REQUIRE(particle->assign_traction(wrong_dir, traction) == false); + + // Check again to ensure value hasn't been updated + for (unsigned i = 0; i < Dim; ++i) { + if (i == Direction) + REQUIRE(particle->traction()(i) == Approx(traction).epsilon(Tolerance)); + else + REQUIRE(particle->traction()(i) == Approx(0.).epsilon(Tolerance)); + } + } + + SECTION("Check initialise particle HDF5") { + mpm::Index id = 0; + const double Tolerance = 1.E-7; + std::shared_ptr> particle = + std::make_shared>(id, coords); + + mpm::HDF5Particle h5_particle; + h5_particle.id = 13; + h5_particle.mass = 501.5; + + Eigen::Vector3d coords; + coords << 1., 0., 0.; + h5_particle.coord_x = coords[0]; + h5_particle.coord_y = coords[1]; + h5_particle.coord_z = coords[2]; + + Eigen::Vector3d displacement; + displacement << 0.01, 0.0, 0.0; + h5_particle.displacement_x = displacement[0]; + h5_particle.displacement_y = displacement[1]; + h5_particle.displacement_z = displacement[2]; + + Eigen::Vector3d lsize; + lsize << 0.25, 0.0, 0.0; + h5_particle.nsize_x = lsize[0]; + h5_particle.nsize_y = lsize[1]; + h5_particle.nsize_z = lsize[2]; + + Eigen::Vector3d velocity; + velocity << 1.5, 0., 0.; + h5_particle.velocity_x = velocity[0]; + h5_particle.velocity_y = velocity[1]; + h5_particle.velocity_z = velocity[2]; + + Eigen::Matrix stress; + stress << 11.5, -12.5, 13.5, 14.5, -15.5, 16.5; + h5_particle.stress_xx = stress[0]; + h5_particle.stress_yy = stress[1]; + h5_particle.stress_zz = stress[2]; + h5_particle.tau_xy = stress[3]; + h5_particle.tau_yz = stress[4]; + h5_particle.tau_xz = stress[5]; + + Eigen::Matrix strain; + strain << 0.115, -0.125, 0.135, 0.145, -0.155, 0.165; + h5_particle.strain_xx = strain[0]; + h5_particle.strain_yy = strain[1]; + h5_particle.strain_zz = strain[2]; + h5_particle.gamma_xy = strain[3]; + h5_particle.gamma_yz = strain[4]; + h5_particle.gamma_xz = strain[5]; + + h5_particle.epsilon_v = strain.head(Dim).sum(); + + h5_particle.status = true; + + h5_particle.cell_id = 1; + + h5_particle.volume = 2.; + + h5_particle.material_id = 1; + + // Reinitialise particle from HDF5 data + REQUIRE(particle->initialise_particle(h5_particle) == true); + + // Check particle id + REQUIRE(particle->id() == h5_particle.id); + // Check particle mass + REQUIRE(particle->mass() == h5_particle.mass); + // Check particle volume + REQUIRE(particle->volume() == h5_particle.volume); + // Check particle mass density + REQUIRE(particle->mass_density() == h5_particle.mass / h5_particle.volume); + // Check particle status + REQUIRE(particle->status() == h5_particle.status); + + // Check for coordinates + auto coordinates = particle->coordinates(); + REQUIRE(coordinates.size() == Dim); + for (unsigned i = 0; i < coordinates.size(); ++i) + REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + + // Check for displacement + auto pdisplacement = particle->displacement(); + REQUIRE(pdisplacement.size() == Dim); + for (unsigned i = 0; i < Dim; ++i) + REQUIRE(pdisplacement(i) == Approx(displacement(i)).epsilon(Tolerance)); + + // Check for size + auto size = particle->natural_size(); + REQUIRE(size.size() == Dim); + for (unsigned i = 0; i < size.size(); ++i) + REQUIRE(size(i) == Approx(lsize(i)).epsilon(Tolerance)); + + // Check velocity + auto pvelocity = particle->velocity(); + REQUIRE(pvelocity.size() == Dim); + for (unsigned i = 0; i < Dim; ++i) + REQUIRE(pvelocity(i) == Approx(velocity(i)).epsilon(Tolerance)); + + // Check stress + auto pstress = particle->stress(); + REQUIRE(pstress.size() == stress.size()); + for (unsigned i = 0; i < stress.size(); ++i) + REQUIRE(pstress(i) == Approx(stress(i)).epsilon(Tolerance)); + + // Check strain + auto pstrain = particle->strain(); + REQUIRE(pstrain.size() == strain.size()); + for (unsigned i = 0; i < strain.size(); ++i) + REQUIRE(pstrain(i) == Approx(strain(i)).epsilon(Tolerance)); + + // Check particle volumetric strain centroid + REQUIRE(particle->volumetric_strain_centroid() == h5_particle.epsilon_v); + + // Check cell id + REQUIRE(particle->cell_id() == h5_particle.cell_id); + + // Check material id + REQUIRE(particle->material_id() == h5_particle.material_id); + + // Write Particle HDF5 data + const auto h5_test = particle->hdf5(); + + REQUIRE(h5_particle.id == h5_test.id); + REQUIRE(h5_particle.mass == h5_test.mass); + + REQUIRE(h5_particle.coord_x == Approx(h5_test.coord_x).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_y == Approx(h5_test.coord_y).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_z == Approx(h5_test.coord_z).epsilon(Tolerance)); + + REQUIRE(h5_particle.displacement_x == + Approx(h5_test.displacement_x).epsilon(Tolerance)); + REQUIRE(h5_particle.displacement_y == + Approx(h5_test.displacement_y).epsilon(Tolerance)); + REQUIRE(h5_particle.displacement_z == + Approx(h5_test.displacement_z).epsilon(Tolerance)); + + REQUIRE(h5_particle.nsize_x == h5_test.nsize_x); + REQUIRE(h5_particle.nsize_y == h5_test.nsize_y); + REQUIRE(h5_particle.nsize_z == h5_test.nsize_z); + + REQUIRE(h5_particle.velocity_x == + Approx(h5_test.velocity_x).epsilon(Tolerance)); + REQUIRE(h5_particle.velocity_y == + Approx(h5_test.velocity_y).epsilon(Tolerance)); + REQUIRE(h5_particle.velocity_z == + Approx(h5_test.velocity_z).epsilon(Tolerance)); + + REQUIRE(h5_particle.stress_xx == + Approx(h5_test.stress_xx).epsilon(Tolerance)); + REQUIRE(h5_particle.stress_yy == + Approx(h5_test.stress_yy).epsilon(Tolerance)); + REQUIRE(h5_particle.stress_zz == + Approx(h5_test.stress_zz).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_xy == Approx(h5_test.tau_xy).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_yz == Approx(h5_test.tau_yz).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_xz == Approx(h5_test.tau_xz).epsilon(Tolerance)); + + REQUIRE(h5_particle.strain_xx == + Approx(h5_test.strain_xx).epsilon(Tolerance)); + REQUIRE(h5_particle.strain_yy == + Approx(h5_test.strain_yy).epsilon(Tolerance)); + REQUIRE(h5_particle.strain_zz == + Approx(h5_test.strain_zz).epsilon(Tolerance)); + REQUIRE(h5_particle.gamma_xy == + Approx(h5_test.gamma_xy).epsilon(Tolerance)); + REQUIRE(h5_particle.gamma_yz == + Approx(h5_test.gamma_yz).epsilon(Tolerance)); + REQUIRE(h5_particle.gamma_xz == + Approx(h5_test.gamma_xz).epsilon(Tolerance)); + + REQUIRE(h5_particle.epsilon_v == + Approx(h5_test.epsilon_v).epsilon(Tolerance)); + REQUIRE(h5_particle.status == h5_test.status); + REQUIRE(h5_particle.cell_id == h5_test.cell_id); + REQUIRE(h5_particle.material_id == h5_test.material_id); + } +} + +//! \brief Check twophase particle class for 2D case +TEST_CASE("TwoPhase Particle is checked for 2D case", + "[twophase_particle][2D]") { + // Dimension + const unsigned Dim = 2; + // Degree of freedom + const unsigned Dof = 2; + // Number of nodes per cell + const unsigned Nnodes = 4; + // Number of phases + const unsigned Nphases = 2; + // Tolerance + const double Tolerance = 1.E-7; + // Json property + Json jfunctionproperties; + jfunctionproperties["id"] = 0; + std::vector x_values{{0.0, 0.5, 1.0}}; + std::vector fx_values{{0.0, 1.0, 1.0}}; + jfunctionproperties["xvalues"] = x_values; + jfunctionproperties["fxvalues"] = fx_values; + + // math function + std::shared_ptr mfunction = + std::make_shared(0, jfunctionproperties); + // Coordinates + Eigen::Vector2d coords; + coords.setZero(); + + //! Check for id = 0 + SECTION("TwoPhase Particle id is zero") { + mpm::Index id = 0; + auto particle = std::make_shared>(id, coords); + REQUIRE(particle->id() == 0); + } + + SECTION("TwoPhase Particle id is positive") { + //! Check for id is a positive value + mpm::Index id = std::numeric_limits::max(); + auto particle = std::make_shared>(id, coords); + REQUIRE(particle->id() == std::numeric_limits::max()); + } + + //! Test coordinates function + SECTION("coordinates function is checked") { + mpm::Index id = 0; + auto particle = std::make_shared>(id, coords); + + //! Check for coordinates being zero + auto coordinates = particle->coordinates(); + for (unsigned i = 0; i < coordinates.size(); ++i) + REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + REQUIRE(coordinates.size() == Dim); + + //! Check for negative value of coordinates + for (unsigned i = 0; i < coordinates.size(); ++i) + coords(i) = -1. * std::numeric_limits::max(); + particle->assign_coordinates(coords); + coordinates = particle->coordinates(); + for (unsigned i = 0; i < coordinates.size(); ++i) + REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + + REQUIRE(coordinates.size() == Dim); + + //! Check for positive value of coordinates + for (unsigned i = 0; i < coordinates.size(); ++i) + coords(i) = std::numeric_limits::max(); + particle->assign_coordinates(coords); + coordinates = particle->coordinates(); + for (unsigned i = 0; i < coordinates.size(); ++i) + REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + + REQUIRE(coordinates.size() == Dim); + } + + // Test assign cell to a particle + SECTION("Add a pointer to a cell to particle") { + // Add particle + mpm::Index id = 0; + coords << 0.75, 0.75; + auto particle = std::make_shared>(id, coords); + + // Check particle coordinates + auto coordinates = particle->coordinates(); + for (unsigned i = 0; i < coordinates.size(); ++i) + REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + + // Element + std::shared_ptr> element = + std::make_shared>(); + + // Create cell + auto cell = std::make_shared>(10, Nnodes, element); + // Add nodes to cell + coords << 0.5, 0.5; + std::shared_ptr> node0 = + std::make_shared>(0, coords); + + coords << 1.5, 0.5; + std::shared_ptr> node1 = + std::make_shared>(1, coords); + + coords << 0.5, 1.5; + std::shared_ptr> node2 = + std::make_shared>(3, coords); + + coords << 1.5, 1.5; + std::shared_ptr> node3 = + std::make_shared>(2, coords); + + coords << 0.5, 3.0; + std::shared_ptr> node4 = + std::make_shared>(3, coords); + + coords << 1.5, 3.0; + std::shared_ptr> node5 = + std::make_shared>(2, coords); + + cell->add_node(0, node0); + cell->add_node(1, node1); + cell->add_node(2, node3); + cell->add_node(3, node2); + REQUIRE(cell->nnodes() == 4); + + // Initialise cell properties + cell->initialise(); + + // Check if cell is initialised + REQUIRE(cell->is_initialised() == true); + + // Add cell to particle + REQUIRE(cell->status() == false); + // Check particle cell status + REQUIRE(particle->cell_ptr() == false); + // Assign cell id + REQUIRE(particle->assign_cell_id(10) == true); + // Require cell id + REQUIRE(particle->cell_id() == 10); + // Assign a very large cell id + REQUIRE(particle->assign_cell_id(std::numeric_limits::max()) == + false); + // Require cell id + REQUIRE(particle->cell_id() == 10); + // Assign particle to cell + REQUIRE(particle->assign_cell(cell) == true); + // Local coordinates + Eigen::Vector2d xi; + xi.fill(std::numeric_limits::max()); + // Assign particle to cell + REQUIRE(particle->assign_cell_xi(cell, xi) == false); + // Compute reference location + cell->is_point_in_cell(particle->coordinates(), &xi); + // Assign particle to cell + REQUIRE(particle->assign_cell_xi(cell, xi) == true); + + // Assign cell id again + REQUIRE(particle->assign_cell_id(10) == false); + // Check particle cell status + REQUIRE(particle->cell_ptr() == true); + // Check cell status on addition of particle + REQUIRE(cell->status() == true); + + // Create cell + auto cell2 = std::make_shared>(20, Nnodes, element); + + cell2->add_node(0, node2); + cell2->add_node(1, node3); + cell2->add_node(2, node5); + cell2->add_node(3, node4); + REQUIRE(cell2->nnodes() == 4); + + // Initialise cell2 properties + cell2->initialise(); + + // Check if cell2 is initialised + REQUIRE(cell2->is_initialised() == true); + + // Add cell2 to particle + REQUIRE(cell2->status() == false); + // Assign particle to cell2 + REQUIRE(particle->assign_cell(cell2) == false); + // Check cell2 status for failed addition of particle + REQUIRE(cell2->status() == false); + // Check cell status because this should not have removed the particle + REQUIRE(cell->status() == true); + + // Remove assigned cell + particle->remove_cell(); + REQUIRE(particle->assign_cell(cell) == true); + + // Clear all particle ids + REQUIRE(cell->nparticles() == 1); + cell->clear_particle_ids(); + REQUIRE(cell->nparticles() == 0); + } + + //! Test initialise particle stresses and pore pressure + SECTION("TwoPhase Particle with initial stress") { + mpm::Index id = 0; + const double Tolerance = 1.E-7; + bool status = true; + std::shared_ptr> particle = + std::make_shared>(id, coords, status); + //! Test initialise particle stresses + Eigen::Matrix stress = + Eigen::Matrix::Constant(5.7); + particle->initial_stress(stress); + REQUIRE(particle->stress().size() == stress.size()); + auto pstress = particle->stress(); + for (unsigned i = 0; i < pstress.size(); ++i) + REQUIRE(pstress[i] == Approx(stress[i]).epsilon(Tolerance)); + //! Test initialise particle pore pressure + double pore_pressure = 100000; + particle->initial_pore_pressure(pore_pressure); + REQUIRE(particle->pore_pressure() == pore_pressure); + } + + //! Test particles velocity constraints + SECTION("TwoPhase Particle with velocity constraints") { + mpm::Index id = 0; + const double Tolerance = 1.E-7; + bool status = true; + std::shared_ptr> particle = + std::make_shared>(id, coords, status); + + // Apply constraints + particle->apply_particle_velocity_constraints(0, 10.5); + particle->apply_particle_velocity_constraints(1, -12.5); + particle->apply_particle_velocity_constraints(2, 20.5); + particle->apply_particle_velocity_constraints(3, -22.5); + + // Check apply constraints + REQUIRE(particle->velocity()(0) == Approx(10.5).epsilon(Tolerance)); + REQUIRE(particle->velocity()(1) == Approx(-12.5).epsilon(Tolerance)); + REQUIRE(particle->liquid_velocity()(0) == Approx(20.5).epsilon(Tolerance)); + REQUIRE(particle->liquid_velocity()(1) == Approx(-22.5).epsilon(Tolerance)); + } + + //! Test particle, cell and node functions + SECTION("Test twophase particle, cell and node functions") { + // Add particle + mpm::Index id = 0; + coords << 0.75, 0.75; + auto particle = std::make_shared>(id, coords); + + // Time-step + const double dt = 0.1; + + // Check particle coordinates + auto coordinates = particle->coordinates(); + for (unsigned i = 0; i < coordinates.size(); ++i) + REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + + // Shape function + std::shared_ptr> element = + std::make_shared>(); + + // Create cell + auto cell = std::make_shared>(10, Nnodes, element); + // Add nodes to cell + coords << 0.5, 0.5; + std::shared_ptr> node0 = + std::make_shared>(0, coords); + + coords << 1.5, 0.5; + std::shared_ptr> node1 = + std::make_shared>(1, coords); + + coords << 1.5, 1.5; + std::shared_ptr> node2 = + std::make_shared>(2, coords); + + coords << 0.5, 1.5; + std::shared_ptr> node3 = + std::make_shared>(3, coords); + cell->add_node(0, node0); + cell->add_node(1, node1); + cell->add_node(2, node2); + cell->add_node(3, node3); + REQUIRE(cell->nnodes() == 4); + + std::vector>> nodes; + nodes.emplace_back(node0); + nodes.emplace_back(node1); + nodes.emplace_back(node2); + nodes.emplace_back(node3); + + // Initialise cell properties + cell->initialise(); + + // Add cell to particle + REQUIRE(cell->status() == false); + // Check compute shape functions of a particle + // TODO Assert: REQUIRE_NOTHROW(particle->compute_shapefn()); + // Compute reference location should throw + REQUIRE(particle->compute_reference_location() == false); + // Compute updated particle location should fail + // TODO Assert: + // REQUIRE_NOTHROW(particle->compute_updated_position(dt) == false); + // Compute updated particle location from nodal velocity should fail + // TODO Assert: REQUIRE_NOTHROW(particle->compute_updated_position(dt, + // true)); Compute volume + // TODO Assert: REQUIRE(particle->compute_volume() == false); + // Update volume should fail + // TODO Assert: REQUIRE(particle->update_volume() == false); + + REQUIRE(particle->assign_cell(cell) == true); + REQUIRE(cell->status() == true); + REQUIRE(particle->cell_id() == 10); + + // Check if cell is initialised + REQUIRE(cell->is_initialised() == true); + + // Check compute shape functions of a particle + REQUIRE_NOTHROW(particle->compute_shapefn()); + + // Assign volume + REQUIRE(particle->assign_volume(0.0) == false); + REQUIRE(particle->assign_volume(-5.0) == false); + REQUIRE(particle->assign_volume(2.0) == true); + // Check volume + REQUIRE(particle->volume() == Approx(2.0).epsilon(Tolerance)); + // Compute volume + REQUIRE_NOTHROW(particle->compute_volume()); + // Check volume + REQUIRE(particle->volume() == Approx(1.0).epsilon(Tolerance)); + + // Check reference location + coords << -0.5, -0.5; + REQUIRE(particle->compute_reference_location() == true); + auto ref_coordinates = particle->reference_location(); + for (unsigned i = 0; i < ref_coordinates.size(); ++i) + REQUIRE(ref_coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + + // Assign material + unsigned mid = 1; + // Initialise material + Json jmaterial; + jmaterial["density"] = 1000.; + jmaterial["youngs_modulus"] = 1.0E+7; + jmaterial["poisson_ratio"] = 0.3; + jmaterial["porosity"] = 0.3; + jmaterial["k_x"] = 0.001; + jmaterial["k_y"] = 0.001; + + auto material = + Factory, unsigned, const Json&>::instance()->create( + "LinearElastic2D", std::move(mid), jmaterial); + + // Assign liquid material + unsigned liquid_mid = 2; + // Initialise material + Json jmaterial_liquid; + jmaterial_liquid["density"] = 1000.; + jmaterial_liquid["bulk_modulus"] = 1.0E+9; + jmaterial_liquid["mu"] = 0.3; + jmaterial_liquid["dynamic_viscosity"] = 0.; + + auto liquid_material = + Factory, unsigned, const Json&>::instance()->create( + "Newtonian2D", std::move(liquid_mid), jmaterial_liquid); + + // Check compute mass before material and volume + // TODO Assert: REQUIRE(particle->compute_mass() == false); + + // Test compute stress before material assignment + // TODO Assert: REQUIRE(particle->compute_stress() == false); + + // Assign material properties + REQUIRE(particle->assign_material(material) == true); + REQUIRE(particle->assign_material(liquid_material, + mpm::ParticlePhase::Liquid) == true); + + // Assign porosity + REQUIRE(particle->assign_porosity() == true); + + // Assign permeability + REQUIRE(particle->assign_permeability() == true); + + // Check material id + REQUIRE(particle->material_id() == 1); + REQUIRE(particle->material_id(mpm::ParticlePhase::Liquid) == 2); + + // Compute volume + REQUIRE_NOTHROW(particle->compute_volume()); + + // Compute mass + REQUIRE_NOTHROW(particle->compute_mass()); + // Mass + REQUIRE(particle->mass() == Approx(700.).epsilon(Tolerance)); + REQUIRE(particle->liquid_mass() == Approx(300.).epsilon(Tolerance)); + + // Map particle mass to nodes + particle->assign_mass(std::numeric_limits::max()); + // TODO Assert: REQUIRE_NOTHROW(particle->map_mass_momentum_to_nodes()); + + // Map particle pressure to nodes + // TODO Assert: REQUIRE(particle->map_pressure_to_nodes() == false); + + // Assign mass to nodes + REQUIRE(particle->compute_reference_location() == true); + REQUIRE_NOTHROW(particle->compute_shapefn()); + + // Check velocity + Eigen::VectorXd velocity; + velocity.resize(Dim); + for (unsigned i = 0; i < velocity.size(); ++i) velocity(i) = i; + REQUIRE(particle->assign_velocity(velocity) == true); + REQUIRE(particle->assign_liquid_velocity(velocity) == true); + for (unsigned i = 0; i < velocity.size(); ++i) { + REQUIRE(particle->velocity()(i) == Approx(i).epsilon(Tolerance)); + REQUIRE(particle->liquid_velocity()(i) == Approx(i).epsilon(Tolerance)); + } + + REQUIRE_NOTHROW(particle->compute_mass()); + REQUIRE_NOTHROW(particle->map_mass_momentum_to_nodes()); + + // TODO Assert: REQUIRE(particle->map_pressure_to_nodes() == false); + REQUIRE(particle->compute_pressure_smoothing() == false); + + // Values of nodal mass + std::array nodal_mass{562.5, 187.5, 62.5, 187.5}; + // Check nodal mass + for (unsigned i = 0; i < nodes.size(); ++i) { + // Solid phase + REQUIRE(nodes.at(i)->mass(mpm::NodePhase::nSolid) == + Approx(nodal_mass.at(i) * (1 - particle->porosity())) + .epsilon(Tolerance)); + // Liquid phase + REQUIRE( + nodes.at(i)->mass(mpm::NodePhase::nLiquid) == + Approx(nodal_mass.at(i) * particle->porosity()).epsilon(Tolerance)); + } + + // Compute nodal velocity + for (const auto& node : nodes) node->compute_velocity(); + + // Values of nodal momentum + Eigen::Matrix nodal_momentum; + // clang-format off + nodal_momentum << 0., 562.5, + 0., 187.5, + 0., 62.5, + 0., 187.5; + // clang-format on + // Check nodal momentum + for (unsigned i = 0; i < nodal_momentum.rows(); ++i) + for (unsigned j = 0; j < nodal_momentum.cols(); ++j) { + // Solid phase + REQUIRE(nodes.at(i)->momentum(mpm::NodePhase::nSolid)(j) == + Approx(nodal_momentum(i, j) * (1 - particle->porosity())) + .epsilon(Tolerance)); + // Liquid phase + REQUIRE(nodes.at(i)->momentum(mpm::NodePhase::nLiquid)(j) == + Approx(nodal_momentum(i, j) * particle->porosity()) + .epsilon(Tolerance)); + } + // Values of nodal velocity + Eigen::Matrix nodal_velocity; + // clang-format off + nodal_velocity << 0., 1., + 0., 1., + 0., 1., + 0., 1.; + // clang-format on + // Check nodal velocity + for (unsigned i = 0; i < nodal_velocity.rows(); ++i) + for (unsigned j = 0; j < nodal_velocity.cols(); ++j) + REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::nSolid)(j) == + Approx(nodal_velocity(i, j)).epsilon(Tolerance)); + + // Set momentum to get non-zero strain + // clang-format off + nodal_momentum << 0., 562.5 * 1., + 0., 187.5 * 2., + 0., 62.5 * 3., + 0., 187.5 * 4.; + // clang-format on + for (unsigned i = 0; i < nodes.size(); ++i) { + // Solid phase + REQUIRE_NOTHROW(nodes.at(i)->update_momentum( + false, mpm::NodePhase::nSolid, + nodal_momentum.row(i) * (1 - particle->porosity()))); + // Liquid phase + REQUIRE_NOTHROW(nodes.at(i)->update_momentum( + false, mpm::NodePhase::nLiquid, + nodal_momentum.row(i) * particle->porosity())); + } + + // nodal velocity + // clang-format off + nodal_velocity << 0., 1., + 0., 2., + 0., 3., + 0., 4.; + // clang-format on + // Compute nodal velocity + for (const auto& node : nodes) node->compute_velocity(); + // Check nodal velocity + for (unsigned i = 0; i < nodal_velocity.rows(); ++i) + for (unsigned j = 0; j < nodal_velocity.cols(); ++j) { + // Solid phase + REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::nSolid)(j) == + Approx(nodal_velocity(i, j)).epsilon(Tolerance)); + // Liquid phase + REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::nLiquid)(j) == + Approx(nodal_velocity(i, j)).epsilon(Tolerance)); + } + + // Check pressure + REQUIRE(std::isnan(particle->pressure()) == true); + + // Compute strain + particle->compute_strain(dt); + // Strain + Eigen::Matrix strain; + strain << 0., 0.25, 0., 0.050, 0., 0.; + // Check strains + for (unsigned i = 0; i < strain.rows(); ++i) + REQUIRE(particle->strain()(i) == Approx(strain(i)).epsilon(Tolerance)); + + // Check volumetric strain at centroid + double volumetric_strain = 0.2; + REQUIRE(particle->volumetric_strain_centroid() == + Approx(volumetric_strain).epsilon(Tolerance)); + + // Check updated pressure + const double K = 8333333.333333333; + REQUIRE(std::isnan(particle->pressure()) == true); + + // Update volume strain rate + REQUIRE(particle->volume() == Approx(1.0).epsilon(Tolerance)); + particle->compute_strain(dt); + REQUIRE_NOTHROW(particle->update_volume()); + REQUIRE(particle->volume() == Approx(1.2).epsilon(Tolerance)); + + // Compute stress + REQUIRE_NOTHROW(particle->compute_stress()); + + Eigen::Matrix stress; + // clang-format off + stress << 721153.8461538460 * 2., + 1682692.3076923075 * 2., + 721153.8461538460 * 2., + 96153.8461538462 * 2., + 0.0000000000 * 2., + 0.0000000000 * 2.; + // clang-format on + // Check stress + for (unsigned i = 0; i < stress.rows(); ++i) + REQUIRE(particle->stress()(i) == Approx(stress(i)).epsilon(Tolerance)); + + // Compute pore_pressure + REQUIRE_NOTHROW(particle->compute_pore_pressure(dt)); + // Check pore pressure + REQUIRE(particle->pore_pressure() == + Approx(-783333333.3333334923).epsilon(Tolerance)); + + // Check body force + Eigen::Matrix gravity; + gravity << 0., -9.81; + + particle->map_body_force(gravity); + + // Body force + Eigen::Matrix body_force; + // clang-format off + body_force << 0., -5518.125, + 0., -1839.375, + 0., -613.125, + 0., -1839.375; + // clang-format on + + // Check nodal body force + for (unsigned i = 0; i < body_force.rows(); ++i) + for (unsigned j = 0; j < body_force.cols(); ++j) + REQUIRE(nodes[i]->external_force(mpm::NodePhase::nSolid)[j] == + Approx(body_force(i, j)).epsilon(Tolerance)); + + // Check traction force + double traction = 7.68; + const unsigned direction = 1; + // Assign volume + REQUIRE(particle->assign_volume(0.0) == false); + REQUIRE(particle->assign_volume(-5.0) == false); + REQUIRE(particle->assign_volume(2.0) == true); + // Map traction force + double current_time = 5.0; + // Assign traction to particle + particle->assign_traction(direction, + mfunction->value(current_time) * traction); + particle->map_traction_force(); + + // Traction force + Eigen::Matrix traction_force; + // shapefn * volume / size_(dir) * traction + // clang-format off + traction_force << 0., 0.5625 * 1.414213562 * 7.68, + 0., 0.1875 * 1.414213562 * 7.68, + 0., 0.0625 * 1.414213562 * 7.68, + 0., 0.1875 * 1.414213562 * 7.68; + // clang-format on + // Add previous external body force + traction_force += body_force; + + // Check nodal traction force + for (unsigned i = 0; i < traction_force.rows(); ++i) + for (unsigned j = 0; j < traction_force.cols(); ++j) + REQUIRE(nodes[i]->external_force(mpm::NodePhase::nSolid)[j] == + Approx(traction_force(i, j)).epsilon(Tolerance)); + // Reset traction + particle->assign_traction(direction, + -traction * mfunction->value(current_time)); + // Map traction force + particle->map_traction_force(); + // Check nodal external force + for (unsigned i = 0; i < traction_force.rows(); ++i) + for (unsigned j = 0; j < traction_force.cols(); ++j) + REQUIRE(nodes[i]->external_force(mpm::NodePhase::nSolid)[j] == + Approx(body_force(i, j)).epsilon(Tolerance)); + + // Internal force + Eigen::Matrix internal_force; + // clang-format off + internal_force << 588725961.538461566, 590168269.2307692766, + -588533653.8461539745, 196530448.7179487348, + -196241987.1794872284, -196722756.4102564454, + 196049679.4871795177, -589975961.5384616852; + // clang-format on + + // Map particle internal force + particle->assign_volume(1.0); + particle->map_internal_force(); + + // Check nodal internal force + for (unsigned i = 0; i < internal_force.rows(); ++i) + for (unsigned j = 0; j < internal_force.cols(); ++j) + REQUIRE(nodes[i]->internal_force(mpm::NodePhase::nSolid)[j] == + Approx(internal_force(i, j)).epsilon(Tolerance)); + + // Calculate nodal acceleration and velocity + for (const auto& node : nodes) + node->compute_acceleration_velocity_twophase_explicit(dt); + + // Check nodal velocity + Eigen::Matrix nodal_liquid_velocity; + // clang-format off + nodal_velocity << 104755.7997557998, 105122.1191221001, + -314120.8791208792, 104976.59897558, + -314267.3992673994, -315364.2813663005, + 104609.2796092796, -315216.7612197804; + nodal_liquid_velocity << 104444.4444444445, 104444.4634444445, + -313333.3333333334, 104445.4634444445, + -313333.3333333334, -313331.3143333333, + 104444.4444444445, -313330.3143333334; + // clang-format on + // Check nodal velocity + for (unsigned i = 0; i < nodal_velocity.rows(); ++i) + for (unsigned j = 0; j < nodal_velocity.cols(); ++j) { + // Solid phase + REQUIRE(nodes[i]->velocity(mpm::NodePhase::nSolid)[j] == + Approx(nodal_velocity(i, j)).epsilon(Tolerance)); + // Liquid phase + REQUIRE(nodes[i]->velocity(mpm::NodePhase::nLiquid)[j] == + Approx(nodal_liquid_velocity(i, j)).epsilon(Tolerance)); + } + + // Check nodal acceleration + Eigen::Matrix nodal_acceleration; + Eigen::Matrix nodal_liquid_acceleration; + // clang-format off + nodal_acceleration << 1047557.9975579976, 1051211.1912210013, + -3141208.791208792, 1049745.9897558, + -3142673.9926739936, -3153672.8136630044, + 1046092.7960927964, -3152207.6121978033; + nodal_liquid_acceleration << 1044444.4444444446, 1044434.6344444447, + -3133333.333333334, 1044434.6344444446, + -3133333.333333334, -3133343.1433333335, + 1044444.4444444446, -3133343.1433333335; + // clang-format on + // Check nodal acceleration + for (unsigned i = 0; i < nodal_acceleration.rows(); ++i) + for (unsigned j = 0; j < nodal_acceleration.cols(); ++j) { + // Solid phase + REQUIRE(nodes[i]->acceleration(mpm::NodePhase::nSolid)[j] == + Approx(nodal_acceleration(i, j)).epsilon(Tolerance)); + // Liquid phase + REQUIRE(nodes[i]->acceleration(mpm::NodePhase::nLiquid)[j] == + Approx(nodal_liquid_acceleration(i, j)).epsilon(Tolerance)); + } + // Approx(nodal_velocity(i, j) / dt).epsilon(Tolerance)); + + // Check original particle coordinates + coords << 0.75, 0.75; + coordinates = particle->coordinates(); + for (unsigned i = 0; i < coordinates.size(); ++i) + REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + + // Compute updated particle location + REQUIRE_NOTHROW(particle->compute_updated_position(dt)); + // Check particle velocity + velocity << 0., 0.019; + for (unsigned i = 0; i < velocity.size(); ++i) + REQUIRE(particle->velocity()(i) == + Approx(velocity(i)).epsilon(Tolerance)); + + // Check particle displacement + Eigen::Vector2d displacement; + displacement << 0., 0.0894; + for (unsigned i = 0; i < displacement.size(); ++i) + REQUIRE(particle->displacement()(i) == + Approx(displacement(i)).epsilon(Tolerance)); + + // Updated particle coordinate + coords << 0.75, .8394; + // Check particle coordinates + coordinates = particle->coordinates(); + for (unsigned i = 0; i < coordinates.size(); ++i) + REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + + // Compute updated particle location from nodal velocity + REQUIRE_NOTHROW(particle->compute_updated_position(dt, true)); + // Check particle velocity + velocity << 0., 0.894; + for (unsigned i = 0; i < velocity.size(); ++i) + REQUIRE(particle->velocity()(i) == + Approx(velocity(i)).epsilon(Tolerance)); + + // Check particle displacement + displacement << 0., 0.1788; + for (unsigned i = 0; i < displacement.size(); ++i) + REQUIRE(particle->displacement()(i) == + Approx(displacement(i)).epsilon(Tolerance)); + + // Updated particle coordinate + coords << 0.75, .9288; + // Check particle coordinates + coordinates = particle->coordinates(); + for (unsigned i = 0; i < coordinates.size(); ++i) + REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + + // Update porosity + REQUIRE_NOTHROW(particle->update_porosity(dt)); + + // Check porosity + REQUIRE(particle->porosity() == Approx(0.44).epsilon(Tolerance)); + + SECTION("TwoPhase Particle assign state variables") { + SECTION("Assign state variable fail") { + mid = 0; + Json jmaterial; + jmaterial["density"] = 1000.; + jmaterial["youngs_modulus"] = 1.0E+7; + jmaterial["poisson_ratio"] = 0.3; + jmaterial["softening"] = false; + jmaterial["friction"] = 0.; + jmaterial["dilation"] = 0.; + jmaterial["cohesion"] = 2000.; + jmaterial["residual_friction"] = 0.; + jmaterial["residual_dilation"] = 0.; + jmaterial["residual_cohesion"] = 1000.; + jmaterial["peak_pdstrain"] = 0.; + jmaterial["residual_pdstrain"] = 0.; + jmaterial["tension_cutoff"] = 0.; + + auto mc_material = + Factory, unsigned, const Json&>::instance() + ->create("MohrCoulomb2D", std::move(id), jmaterial); + REQUIRE(mc_material->id() == 0); + + mpm::dense_map state_variables = + mc_material->initialise_state_variables(); + REQUIRE(state_variables.at("phi") == + Approx(jmaterial["friction"]).epsilon(Tolerance)); + REQUIRE(state_variables.at("psi") == + Approx(jmaterial["dilation"]).epsilon(Tolerance)); + REQUIRE(state_variables.at("cohesion") == + Approx(jmaterial["cohesion"]).epsilon(Tolerance)); + REQUIRE(state_variables.at("epsilon") == Approx(0.).epsilon(Tolerance)); + REQUIRE(state_variables.at("rho") == Approx(0.).epsilon(Tolerance)); + REQUIRE(state_variables.at("theta") == Approx(0.).epsilon(Tolerance)); + REQUIRE(state_variables.at("pdstrain") == + Approx(0.).epsilon(Tolerance)); + + SECTION("Assign state variables") { + // Assign material properties + REQUIRE(particle->assign_material(mc_material) == true); + // 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") { + // Assign material + unsigned mid1 = 0; + // Initialise material + Json jmaterial1; + jmaterial1["density"] = 1000.; + jmaterial1["bulk_modulus"] = 8333333.333333333; + jmaterial1["dynamic_viscosity"] = 8.9E-4; + + auto newtonian_material = + Factory, unsigned, const Json&>::instance() + ->create("Newtonian2D", std::move(mid1), jmaterial1); + + // Assign material properties + REQUIRE(particle->assign_material(newtonian_material) == true); + // Assign state variables + REQUIRE(particle->assign_material_state_vars(state_variables, + mc_material) == false); + } + + SECTION("Assign state variables fail on material id") { + // Assign material + unsigned mid1 = 1; + // Initialise material + Json jmaterial1; + jmaterial1["density"] = 1000.; + jmaterial1["bulk_modulus"] = 8333333.333333333; + jmaterial1["dynamic_viscosity"] = 8.9E-4; + + auto newtonian_material = + Factory, unsigned, const Json&>::instance() + ->create("Newtonian2D", std::move(mid1), jmaterial1); + + // Assign material properties + REQUIRE(particle->assign_material(newtonian_material) == true); + // Assign state variables + REQUIRE(particle->assign_material_state_vars(state_variables, + mc_material) == false); + } + } + } + } + + SECTION("Check assign material to particle") { + // Add particle + mpm::Index id = 0; + coords << 0.75, 0.75; + auto particle = std::make_shared>(id, coords); + + unsigned mid = 1; + // Initialise material + Json jmaterial; + jmaterial["density"] = 1000.; + jmaterial["youngs_modulus"] = 1.0E+7; + jmaterial["poisson_ratio"] = 0.3; + + auto material = + Factory, unsigned, const Json&>::instance()->create( + "LinearElastic2D", std::move(mid), jmaterial); + REQUIRE(material->id() == 1); + + // Check if particle can be assigned a material is null + REQUIRE(particle->assign_material(nullptr) == false); + + // Check material id + REQUIRE(particle->material_id() == std::numeric_limits::max()); + + // Assign material to particle + REQUIRE(particle->assign_material(material) == true); + + // Check material id + REQUIRE(particle->material_id() == 1); + } + + SECTION("Check twophase particle properties") { + mpm::Index id = 0; + const double Tolerance = 1.E-7; + std::shared_ptr> particle = + std::make_shared>(id, coords); + + // Check mass + REQUIRE(particle->mass() == Approx(0.0).epsilon(Tolerance)); + double mass = 100.5; + particle->assign_mass(mass); + REQUIRE(particle->mass() == Approx(100.5).epsilon(Tolerance)); + + // Check stress + Eigen::Matrix stress; + for (unsigned i = 0; i < stress.size(); ++i) stress(i) = 17.52; + + for (unsigned i = 0; i < stress.size(); ++i) + REQUIRE(particle->stress()(i) == Approx(0.).epsilon(Tolerance)); + + // Check velocity + Eigen::VectorXd velocity; + velocity.resize(Dim); + for (unsigned i = 0; i < velocity.size(); ++i) velocity(i) = 19.745; + + for (unsigned i = 0; i < velocity.size(); ++i) + REQUIRE(particle->velocity()(i) == Approx(0.).epsilon(Tolerance)); + + REQUIRE(particle->assign_velocity(velocity) == true); + for (unsigned i = 0; i < velocity.size(); ++i) + REQUIRE(particle->velocity()(i) == Approx(19.745).epsilon(Tolerance)); + + // Assign volume + REQUIRE(particle->assign_volume(0.0) == false); + REQUIRE(particle->assign_volume(-5.0) == false); + REQUIRE(particle->assign_volume(2.0) == true); + // Check volume + REQUIRE(particle->volume() == Approx(2.0).epsilon(Tolerance)); + // Traction + double traction = 65.32; + const unsigned Direction = 1; + // Check traction + for (unsigned i = 0; i < Dim; ++i) + REQUIRE(particle->traction()(i) == Approx(0.).epsilon(Tolerance)); + + REQUIRE(particle->assign_traction(Direction, traction) == true); + + // Calculate traction force = traction * volume / spacing + traction *= 2.0 / (std::pow(2.0, 1. / Dim)); + + for (unsigned i = 0; i < Dim; ++i) { + if (i == Direction) + REQUIRE(particle->traction()(i) == Approx(traction).epsilon(Tolerance)); + else + REQUIRE(particle->traction()(i) == Approx(0.).epsilon(Tolerance)); + } + + // Check for incorrect direction + const unsigned wrong_dir = 4; + REQUIRE(particle->assign_traction(wrong_dir, traction) == false); + + // Check again to ensure value hasn't been updated + for (unsigned i = 0; i < Dim; ++i) { + if (i == Direction) + REQUIRE(particle->traction()(i) == Approx(traction).epsilon(Tolerance)); + else + REQUIRE(particle->traction()(i) == Approx(0.).epsilon(Tolerance)); + } + } + + // Check initialise particle from HDF5 file + SECTION("Check initialise particle HDF5") { + mpm::Index id = 0; + const double Tolerance = 1.E-7; + std::shared_ptr> particle = + std::make_shared>(id, coords); + + mpm::HDF5Particle h5_particle; + h5_particle.id = 13; + h5_particle.mass = 501.5; + + Eigen::Vector3d coords; + coords << 1., 2., 0.; + h5_particle.coord_x = coords[0]; + h5_particle.coord_y = coords[1]; + h5_particle.coord_z = coords[2]; + + Eigen::Vector3d displacement; + displacement << 0.01, 0.02, 0.0; + h5_particle.displacement_x = displacement[0]; + h5_particle.displacement_y = displacement[1]; + h5_particle.displacement_z = displacement[2]; + + Eigen::Vector3d lsize; + lsize << 0.25, 0.5, 0.; + h5_particle.nsize_x = lsize[0]; + h5_particle.nsize_y = lsize[1]; + h5_particle.nsize_z = lsize[2]; + + Eigen::Vector3d velocity; + velocity << 1.5, 2.5, 0.0; + h5_particle.velocity_x = velocity[0]; + h5_particle.velocity_y = velocity[1]; + h5_particle.velocity_z = velocity[2]; + + Eigen::Matrix stress; + stress << 11.5, -12.5, 13.5, 14.5, -15.5, 16.5; + h5_particle.stress_xx = stress[0]; + h5_particle.stress_yy = stress[1]; + h5_particle.stress_zz = stress[2]; + h5_particle.tau_xy = stress[3]; + h5_particle.tau_yz = stress[4]; + h5_particle.tau_xz = stress[5]; + + Eigen::Matrix strain; + strain << 0.115, -0.125, 0.135, 0.145, -0.155, 0.165; + h5_particle.strain_xx = strain[0]; + h5_particle.strain_yy = strain[1]; + h5_particle.strain_zz = strain[2]; + h5_particle.gamma_xy = strain[3]; + h5_particle.gamma_yz = strain[4]; + h5_particle.gamma_xz = strain[5]; + + h5_particle.epsilon_v = strain.head(Dim).sum(); + + h5_particle.status = true; + + h5_particle.cell_id = 1; + + h5_particle.volume = 2.; + + h5_particle.material_id = 1; + + // Reinitialise particle from HDF5 data + REQUIRE(particle->initialise_particle(h5_particle) == true); + + // Check particle id + REQUIRE(particle->id() == h5_particle.id); + // Check particle mass + REQUIRE(particle->mass() == h5_particle.mass); + // Check particle volume + REQUIRE(particle->volume() == h5_particle.volume); + // Check particle mass density + REQUIRE(particle->mass_density() == h5_particle.mass / h5_particle.volume); + // Check particle status + REQUIRE(particle->status() == h5_particle.status); + + // Check for coordinates + auto coordinates = particle->coordinates(); + REQUIRE(coordinates.size() == Dim); + for (unsigned i = 0; i < coordinates.size(); ++i) + REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + + // Check for displacement + auto pdisplacement = particle->displacement(); + REQUIRE(pdisplacement.size() == Dim); + for (unsigned i = 0; i < Dim; ++i) + REQUIRE(pdisplacement(i) == Approx(displacement(i)).epsilon(Tolerance)); + + // Check for size + auto size = particle->natural_size(); + REQUIRE(size.size() == Dim); + for (unsigned i = 0; i < size.size(); ++i) + REQUIRE(size(i) == Approx(lsize(i)).epsilon(Tolerance)); + + // Check velocity + auto pvelocity = particle->velocity(); + REQUIRE(pvelocity.size() == Dim); + for (unsigned i = 0; i < Dim; ++i) + REQUIRE(pvelocity(i) == Approx(velocity(i)).epsilon(Tolerance)); + + // Check stress + auto pstress = particle->stress(); + REQUIRE(pstress.size() == stress.size()); + for (unsigned i = 0; i < stress.size(); ++i) + REQUIRE(pstress(i) == Approx(stress(i)).epsilon(Tolerance)); + + // Check strain + auto pstrain = particle->strain(); + REQUIRE(pstrain.size() == strain.size()); + for (unsigned i = 0; i < strain.size(); ++i) + REQUIRE(pstrain(i) == Approx(strain(i)).epsilon(Tolerance)); + + // Check particle volumetric strain centroid + REQUIRE(particle->volumetric_strain_centroid() == h5_particle.epsilon_v); + + // Check cell id + REQUIRE(particle->cell_id() == h5_particle.cell_id); + + // Check material id + REQUIRE(particle->material_id() == h5_particle.material_id); + + // Write Particle HDF5 data + const auto h5_test = particle->hdf5(); + + REQUIRE(h5_particle.id == h5_test.id); + REQUIRE(h5_particle.mass == h5_test.mass); + + REQUIRE(h5_particle.coord_x == Approx(h5_test.coord_x).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_y == Approx(h5_test.coord_y).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_z == Approx(h5_test.coord_z).epsilon(Tolerance)); + + REQUIRE(h5_particle.displacement_x == + Approx(h5_test.displacement_x).epsilon(Tolerance)); + REQUIRE(h5_particle.displacement_y == + Approx(h5_test.displacement_y).epsilon(Tolerance)); + REQUIRE(h5_particle.displacement_z == + Approx(h5_test.displacement_z).epsilon(Tolerance)); + + REQUIRE(h5_particle.nsize_x == h5_test.nsize_x); + REQUIRE(h5_particle.nsize_y == h5_test.nsize_y); + REQUIRE(h5_particle.nsize_z == h5_test.nsize_z); + + REQUIRE(h5_particle.velocity_x == + Approx(h5_test.velocity_x).epsilon(Tolerance)); + REQUIRE(h5_particle.velocity_y == + Approx(h5_test.velocity_y).epsilon(Tolerance)); + REQUIRE(h5_particle.velocity_z == + Approx(h5_test.velocity_z).epsilon(Tolerance)); + + REQUIRE(h5_particle.stress_xx == + Approx(h5_test.stress_xx).epsilon(Tolerance)); + REQUIRE(h5_particle.stress_yy == + Approx(h5_test.stress_yy).epsilon(Tolerance)); + REQUIRE(h5_particle.stress_zz == + Approx(h5_test.stress_zz).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_xy == Approx(h5_test.tau_xy).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_yz == Approx(h5_test.tau_yz).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_xz == Approx(h5_test.tau_xz).epsilon(Tolerance)); + + REQUIRE(h5_particle.strain_xx == + Approx(h5_test.strain_xx).epsilon(Tolerance)); + REQUIRE(h5_particle.strain_yy == + Approx(h5_test.strain_yy).epsilon(Tolerance)); + REQUIRE(h5_particle.strain_zz == + Approx(h5_test.strain_zz).epsilon(Tolerance)); + REQUIRE(h5_particle.gamma_xy == + Approx(h5_test.gamma_xy).epsilon(Tolerance)); + REQUIRE(h5_particle.gamma_yz == + Approx(h5_test.gamma_yz).epsilon(Tolerance)); + REQUIRE(h5_particle.gamma_xz == + Approx(h5_test.gamma_xz).epsilon(Tolerance)); + + REQUIRE(h5_particle.epsilon_v == + Approx(h5_test.epsilon_v).epsilon(Tolerance)); + REQUIRE(h5_particle.status == h5_test.status); + REQUIRE(h5_particle.cell_id == h5_test.cell_id); + REQUIRE(h5_particle.material_id == h5_test.material_id); + } + + // Check twophase particle's material id maping to nodes + SECTION("Check twophase particle's material id maping to nodes") { + // Add particle + mpm::Index id1 = 0; + coords << 0.75, 0.75; + auto particle1 = std::make_shared>(id1, coords); + + // Add particle + mpm::Index id2 = 1; + coords << 0.25, 0.25; + auto particle2 = std::make_shared>(id2, coords); + + // Element + std::shared_ptr> element = + std::make_shared>(); + + // Create cell + auto cell = std::make_shared>(10, Nnodes, element); + // Create vector of nodes and add them to cell + coords << 0., 0.; + std::shared_ptr> node0 = + std::make_shared>(0, coords); + + coords << 1., 0.; + std::shared_ptr> node1 = + std::make_shared>(1, coords); + + coords << 1., 1.; + std::shared_ptr> node2 = + std::make_shared>(3, coords); + + coords << 0., 1.; + std::shared_ptr> node3 = + std::make_shared>(2, coords); + std::vector>> nodes = {node0, node1, + node2, node3}; + + for (int j = 0; j < nodes.size(); ++j) cell->add_node(j, nodes[j]); + + // Initialise cell properties and assign cell to particle + cell->initialise(); + particle1->assign_cell(cell); + particle2->assign_cell(cell); + + // Assign material 1 + unsigned mid1 = 0; + // Initialise material 1 + Json jmaterial1; + jmaterial1["density"] = 1000.; + jmaterial1["youngs_modulus"] = 1.0E+7; + jmaterial1["poisson_ratio"] = 0.3; + + auto material1 = + Factory, unsigned, const Json&>::instance()->create( + "LinearElastic2D", std::move(mid1), jmaterial1); + + particle1->assign_material(material1); + + // Assign material 2 + unsigned mid2 = 1; + // Initialise material 2 + Json jmaterial2; + jmaterial2["density"] = 2000.; + jmaterial2["youngs_modulus"] = 2.0E+7; + jmaterial2["poisson_ratio"] = 0.25; + + auto material2 = + Factory, unsigned, const Json&>::instance()->create( + "LinearElastic2D", std::move(mid2), jmaterial2); + + particle2->assign_material(material2); + + // Append particle's material id to nodes in cell + particle1->append_material_id_to_nodes(); + particle2->append_material_id_to_nodes(); + + // check if the correct amount of material ids were added to node and if + // their indexes are correct + std::vector material_ids = {0, 1}; + for (const auto& node : nodes) { + REQUIRE(node->material_ids().size() == 2); + auto mat_ids = node->material_ids(); + unsigned i = 0; + for (auto mitr = mat_ids.begin(); mitr != mat_ids.end(); ++mitr, ++i) + REQUIRE(*mitr == material_ids.at(i)); + } + } +} \ No newline at end of file From 3da5b254f7b04e425fa5d90e6a39059c1d58f4a6 Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Thu, 30 Jul 2020 23:45:36 -0700 Subject: [PATCH 073/175] Add 3d twophase particle test --- include/node.tcc | 2 +- tests/twophase_particle_test.cc | 1428 ++++++++++++++++++++++++++++++- 2 files changed, 1424 insertions(+), 6 deletions(-) diff --git a/include/node.tcc b/include/node.tcc index 3555bce36..e359a5e4c 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -653,6 +653,7 @@ void mpm::Node void mpm::Node::update_drag_force_coefficient( @@ -721,7 +722,6 @@ bool mpm::Node:: return status; } -//! TwoPhase functions-------------------------------------------------------- //! Compute acceleration and velocity for two phase with damping template bool mpm::Node:: diff --git a/tests/twophase_particle_test.cc b/tests/twophase_particle_test.cc index 59de4268c..7a1acea71 100644 --- a/tests/twophase_particle_test.cc +++ b/tests/twophase_particle_test.cc @@ -104,13 +104,14 @@ TEST_CASE("TwoPhase Particle is checked for 1D case", REQUIRE(coordinates.size() == Dim); } - //! Test initialise particle stresses - SECTION("TwoPhase Particle with initial stress") { + //! Test initialise particle stresses and pore pressure + SECTION("TwoPhase Particle with initial stress and pore pressure") { mpm::Index id = 0; const double Tolerance = 1.E-7; bool status = true; std::shared_ptr> particle = std::make_shared>(id, coords, status); + //! Test initialise particle stresses Eigen::Matrix stress = Eigen::Matrix::Constant(5.7); particle->initial_stress(stress); @@ -122,6 +123,10 @@ TEST_CASE("TwoPhase Particle is checked for 1D case", auto pstress_data = particle->tensor_data("stresses"); for (unsigned i = 0; i < pstress_data.size(); ++i) REQUIRE(pstress_data[i] == Approx(stress[i]).epsilon(Tolerance)); + //! Test initialise particle pore pressure + double pore_pressure = 100000; + particle->initial_pore_pressure(pore_pressure); + REQUIRE(particle->pore_pressure() == pore_pressure); } //! Test particles velocity constraints @@ -582,7 +587,7 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", } //! Test initialise particle stresses and pore pressure - SECTION("TwoPhase Particle with initial stress") { + SECTION("TwoPhase Particle with initial stress and pore pressure") { mpm::Index id = 0; const double Tolerance = 1.E-7; bool status = true; @@ -852,9 +857,14 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", // clang-format on // Check nodal velocity for (unsigned i = 0; i < nodal_velocity.rows(); ++i) - for (unsigned j = 0; j < nodal_velocity.cols(); ++j) + for (unsigned j = 0; j < nodal_velocity.cols(); ++j) { + // Solid phase REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::nSolid)(j) == Approx(nodal_velocity(i, j)).epsilon(Tolerance)); + // Liquid phase + REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::nLiquid)(j) == + Approx(nodal_velocity(i, j)).epsilon(Tolerance)); + } // Set momentum to get non-zero strain // clang-format off @@ -1022,9 +1032,26 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", // Check nodal internal force for (unsigned i = 0; i < internal_force.rows(); ++i) for (unsigned j = 0; j < internal_force.cols(); ++j) - REQUIRE(nodes[i]->internal_force(mpm::NodePhase::nSolid)[j] == + REQUIRE(nodes[i]->internal_force(mpm::NodePhase::nMixture)[j] == Approx(internal_force(i, j)).epsilon(Tolerance)); + // Internal force + Eigen::Matrix drag_force_coefficient; + // clang-format off + drag_force_coefficient << 496631.25, 496631.25, + 165543.75, 165543.75, + 55181.25, 55181.25, + 165543.75, 165543.75; + + // Map drag force coefficient + particle->map_drag_force_coefficient(); + + // Check nodal drag force coefficient + for (unsigned i = 0; i < drag_force_coefficient.rows(); ++i) + for (unsigned j = 0; j < drag_force_coefficient.cols(); ++j) + REQUIRE(nodes[i]->drag_force_coefficient()[j] == + Approx(drag_force_coefficient(i, j)).epsilon(Tolerance)); + // Calculate nodal acceleration and velocity for (const auto& node : nodes) node->compute_acceleration_velocity_twophase_explicit(dt); @@ -1582,6 +1609,1397 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", particle1->append_material_id_to_nodes(); particle2->append_material_id_to_nodes(); + // check if the correct amount of material ids were added to node and if + // their indexes are correct + std::vector material_ids = {0, 1}; + for (const auto& node : nodes) { + REQUIRE(node->material_ids().size() == 2); + auto mat_ids = node->material_ids(); + unsigned i = 0; + for (auto mitr = mat_ids.begin(); mitr != mat_ids.end(); ++mitr, ++i) + REQUIRE(*mitr == material_ids.at(i)); + } + } +} + +//! \brief Check twophase particle class for 3D case +TEST_CASE("TwoPhase Particle is checked for 3D case", + "[twophase_particle][3D]") { + // Dimension + const unsigned Dim = 3; + // Dimension + const unsigned Dof = 6; + // Number of nodes per cell + const unsigned Nnodes = 8; + // Number of phases + const unsigned Nphases = 2; + // Tolerance + const double Tolerance = 1.E-7; + // Json property + Json jfunctionproperties; + jfunctionproperties["id"] = 0; + std::vector x_values{{0.0, 0.5, 1.0}}; + std::vector fx_values{{0.0, 1.0, 1.0}}; + jfunctionproperties["xvalues"] = x_values; + jfunctionproperties["fxvalues"] = fx_values; + + // math function + std::shared_ptr mfunction = + std::make_shared(0, jfunctionproperties); + // Current time for traction force + double current_time = 10.0; + + // Coordinates + Eigen::Vector3d coords; + coords.setZero(); + + //! Check for id = 0 + SECTION("TwoPhase Particle id is zero") { + mpm::Index id = 0; + std::shared_ptr> particle = + std::make_shared>(id, coords); + REQUIRE(particle->id() == 0); + REQUIRE(particle->status() == true); + } + + SECTION("TwoPhase Particle id is positive") { + //! Check for id is a positive value + mpm::Index id = std::numeric_limits::max(); + std::shared_ptr> particle = + std::make_shared>(id, coords); + REQUIRE(particle->id() == std::numeric_limits::max()); + REQUIRE(particle->status() == true); + } + + //! Construct with id, coordinates and status + SECTION("TwoPhase Particle with id, coordinates, and status") { + mpm::Index id = 0; + bool status = true; + std::shared_ptr> particle = + std::make_shared>(id, coords, status); + REQUIRE(particle->id() == 0); + REQUIRE(particle->status() == true); + particle->assign_status(false); + REQUIRE(particle->status() == false); + } + + //! Test coordinates function + SECTION("coordinates function is checked") { + mpm::Index id = 0; + // Create particle + std::shared_ptr> particle = + std::make_shared>(id, coords); + + //! Check for coordinates being zero + auto coordinates = particle->coordinates(); + for (unsigned i = 0; i < coordinates.size(); ++i) + REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + REQUIRE(coordinates.size() == Dim); + + //! Check for negative value of coordinates + for (unsigned i = 0; i < coordinates.size(); ++i) + coords(i) = -1. * std::numeric_limits::max(); + particle->assign_coordinates(coords); + coordinates = particle->coordinates(); + for (unsigned i = 0; i < coordinates.size(); ++i) + REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + + REQUIRE(coordinates.size() == Dim); + + //! Check for positive value of coordinates + for (unsigned i = 0; i < coordinates.size(); ++i) + coords(i) = std::numeric_limits::max(); + particle->assign_coordinates(coords); + coordinates = particle->coordinates(); + for (unsigned i = 0; i < coordinates.size(); ++i) + REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + + REQUIRE(coordinates.size() == Dim); + } + + //! Test assign cell pointer to particle + SECTION("Add a pointer to a cell to particle") { + // Add particle + mpm::Index id = 0; + coords << 1.5, 1.5, 1.5; + std::shared_ptr> particle = + std::make_shared>(id, coords); + + // Check particle coordinates + auto coordinates = particle->coordinates(); + for (unsigned i = 0; i < coordinates.size(); ++i) + REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + + // Assign hexahedron shape function + std::shared_ptr> element = + std::make_shared>(); + + // Create cell + auto cell = std::make_shared>(10, Nnodes, element); + // Add nodes + coords << 0, 0, 0; + std::shared_ptr> node0 = + std::make_shared>(0, coords); + + coords << 2, 0, 0; + std::shared_ptr> node1 = + std::make_shared>(1, coords); + + coords << 2, 2, 0; + std::shared_ptr> node2 = + std::make_shared>(2, coords); + + coords << 0, 2, 0; + std::shared_ptr> node3 = + std::make_shared>(3, coords); + + coords << 0, 0, 2; + std::shared_ptr> node4 = + std::make_shared>(4, coords); + + coords << 2, 0, 2; + std::shared_ptr> node5 = + std::make_shared>(5, coords); + + coords << 2, 2, 2; + std::shared_ptr> node6 = + std::make_shared>(6, coords); + + coords << 0, 2, 2; + std::shared_ptr> node7 = + std::make_shared>(7, coords); + + coords << 0, 0, 4; + std::shared_ptr> node8 = + std::make_shared>(4, coords); + + coords << 2, 0, 4; + std::shared_ptr> node9 = + std::make_shared>(5, coords); + + coords << 2, 2, 4; + std::shared_ptr> node10 = + std::make_shared>(6, coords); + + coords << 0, 2, 4; + std::shared_ptr> node11 = + std::make_shared>(7, coords); + + cell->add_node(0, node0); + cell->add_node(1, node1); + cell->add_node(2, node2); + cell->add_node(3, node3); + cell->add_node(4, node4); + cell->add_node(5, node5); + cell->add_node(6, node6); + cell->add_node(7, node7); + REQUIRE(cell->nnodes() == 8); + + // Initialise cell properties + cell->initialise(); + + // Check if cell is initialised + REQUIRE(cell->is_initialised() == true); + + // Add cell to particle + REQUIRE(cell->status() == false); + // Check particle cell status + REQUIRE(particle->cell_ptr() == false); + // Assign cell id + REQUIRE(particle->assign_cell_id(10) == true); + // Require cell id + REQUIRE(particle->cell_id() == 10); + // Assign a very large cell id + REQUIRE(particle->assign_cell_id(std::numeric_limits::max()) == + false); + // Require cell id + REQUIRE(particle->cell_id() == 10); + // Assign particle to cell + REQUIRE(particle->assign_cell(cell) == true); + // Local coordinates + Eigen::Vector3d xi; + xi.fill(std::numeric_limits::max()); + // Assign particle to cell + REQUIRE(particle->assign_cell_xi(cell, xi) == false); + // Compute reference location + cell->is_point_in_cell(particle->coordinates(), &xi); + // Assign particle to cell + REQUIRE(particle->assign_cell_xi(cell, xi) == true); + + // Assign cell id again + REQUIRE(particle->assign_cell_id(10) == false); + // Check particle cell status + REQUIRE(particle->cell_ptr() == true); + // Check cell status on addition of particle + REQUIRE(cell->status() == true); + + // Create cell + auto cell2 = std::make_shared>(20, Nnodes, element); + + cell2->add_node(0, node4); + cell2->add_node(1, node5); + cell2->add_node(2, node6); + cell2->add_node(3, node7); + cell2->add_node(4, node8); + cell2->add_node(5, node9); + cell2->add_node(6, node10); + cell2->add_node(7, node11); + REQUIRE(cell2->nnodes() == 8); + + // Initialise cell2 properties + cell2->initialise(); + + // Check if cell2 is initialised + REQUIRE(cell2->is_initialised() == true); + + // Add cell2 to particle + REQUIRE(cell2->status() == false); + // Assign particle to cell2 + REQUIRE(particle->assign_cell(cell2) == false); + // Check cell2 status for failed addition of particle + REQUIRE(cell2->status() == false); + // Check cell status because this should not have removed the particle + REQUIRE(cell->status() == true); + + // Remove assigned cell + particle->remove_cell(); + REQUIRE(particle->assign_cell(cell) == true); + + // Clear all particle ids + REQUIRE(cell->nparticles() == 1); + cell->clear_particle_ids(); + REQUIRE(cell->nparticles() == 0); + } + + //! Test initialise twophase particle stresses and pore pressure + SECTION("TwoPhase Particle with initial stress and pore pressure") { + mpm::Index id = 0; + const double Tolerance = 1.E-7; + bool status = true; + std::shared_ptr> particle = + std::make_shared>(id, coords, status); + //! Test initialise particle stresses + Eigen::Matrix stress = + Eigen::Matrix::Constant(5.7); + particle->initial_stress(stress); + REQUIRE(particle->stress().size() == stress.size()); + auto pstress = particle->stress(); + for (unsigned i = 0; i < pstress.size(); ++i) + REQUIRE(pstress[i] == Approx(stress[i]).epsilon(Tolerance)); + //! Test initialise particle pore pressure + double pore_pressure = 100000; + particle->initial_pore_pressure(pore_pressure); + REQUIRE(particle->pore_pressure() == pore_pressure); + } + + //! Test twophase particles velocity constraints + SECTION("TwoPhase Particle with velocity constraints") { + mpm::Index id = 0; + const double Tolerance = 1.E-7; + bool status = true; + std::shared_ptr> particle = + std::make_shared>(id, coords, status); + // Apply constraints + particle->apply_particle_velocity_constraints(0, 10.5); + particle->apply_particle_velocity_constraints(1, -12.5); + particle->apply_particle_velocity_constraints(2, 14.5); + particle->apply_particle_velocity_constraints(3, 20.5); + particle->apply_particle_velocity_constraints(4, -22.5); + particle->apply_particle_velocity_constraints(5, 24.5); + + // Check apply constraints + REQUIRE(particle->velocity()(0) == Approx(10.5).epsilon(Tolerance)); + REQUIRE(particle->velocity()(1) == Approx(-12.5).epsilon(Tolerance)); + REQUIRE(particle->velocity()(2) == Approx(14.5).epsilon(Tolerance)); + REQUIRE(particle->liquid_velocity()(0) == Approx(20.5).epsilon(Tolerance)); + REQUIRE(particle->liquid_velocity()(1) == Approx(-22.5).epsilon(Tolerance)); + REQUIRE(particle->liquid_velocity()(2) == Approx(24.5).epsilon(Tolerance)); + } + + //! Test particle, cell and node functions + SECTION("Test particle, cell and node functions") { + // Add particle + mpm::Index id = 0; + coords << 1.5, 1.5, 1.5; + std::shared_ptr> particle = + std::make_shared>(id, coords); + + // Time-step + const double dt = 0.1; + + // Check particle coordinates + auto coordinates = particle->coordinates(); + for (unsigned i = 0; i < coordinates.size(); ++i) + REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + + // Assign hexahedron shape function + std::shared_ptr> element = + std::make_shared>(); + + // Create cell + auto cell = std::make_shared>(10, Nnodes, element); + // Add nodes + coords << 0, 0, 0; + std::shared_ptr> node0 = + std::make_shared>(0, coords); + + coords << 2, 0, 0; + std::shared_ptr> node1 = + std::make_shared>(1, coords); + + coords << 2, 2, 0; + std::shared_ptr> node2 = + std::make_shared>(2, coords); + + coords << 0, 2, 0; + std::shared_ptr> node3 = + std::make_shared>(3, coords); + + coords << 0, 0, 2; + std::shared_ptr> node4 = + std::make_shared>(4, coords); + + coords << 2, 0, 2; + std::shared_ptr> node5 = + std::make_shared>(5, coords); + + coords << 2, 2, 2; + std::shared_ptr> node6 = + std::make_shared>(6, coords); + + coords << 0, 2, 2; + std::shared_ptr> node7 = + std::make_shared>(7, coords); + + std::vector>> nodes; + nodes.emplace_back(node0); + nodes.emplace_back(node1); + nodes.emplace_back(node2); + nodes.emplace_back(node3); + nodes.emplace_back(node4); + nodes.emplace_back(node5); + nodes.emplace_back(node6); + nodes.emplace_back(node7); + + cell->add_node(0, node0); + cell->add_node(1, node1); + cell->add_node(2, node2); + cell->add_node(3, node3); + cell->add_node(4, node4); + cell->add_node(5, node5); + cell->add_node(6, node6); + cell->add_node(7, node7); + REQUIRE(cell->nnodes() == 8); + + // Initialise cell properties + cell->initialise(); + + // Check if cell is initialised + REQUIRE(cell->is_initialised() == true); + + // Add cell to particle + REQUIRE(cell->status() == false); + // Check compute shape functions of a particle + // TODO Assert: REQUIRE(particle->compute_shapefn() == false); + // Compute reference location should throw + REQUIRE(particle->compute_reference_location() == false); + // Compute updated particle location should fail + // TODO Assert: REQUIRE(particle->compute_updated_position(dt) == false); + // Compute updated particle location from nodal velocity should fail + // TODO Assert: REQUIRE_NOTHROW(particle->compute_updated_position(dt, + // true)); + + // Compute volume + // TODO Assert: REQUIRE(particle->compute_volume() == false); + // Update volume should fail + // TODO Assert: REQUIRE(particle->update_volume() == false); + + REQUIRE(particle->assign_cell(cell) == true); + REQUIRE(cell->status() == true); + REQUIRE(particle->cell_id() == 10); + + // Check if cell is initialised + REQUIRE(cell->is_initialised() == true); + + // Check compute shape functions of a particle + REQUIRE_NOTHROW(particle->compute_shapefn()); + + // Assign volume + REQUIRE(particle->assign_volume(0.0) == false); + REQUIRE(particle->assign_volume(-5.0) == false); + REQUIRE(particle->assign_volume(2.0) == true); + // Check volume + REQUIRE(particle->volume() == Approx(2.0).epsilon(Tolerance)); + // Compute volume + REQUIRE_NOTHROW(particle->compute_volume()); + // Check volume + REQUIRE(particle->volume() == Approx(8.0).epsilon(Tolerance)); + + // Check reference location + coords << 0.5, 0.5, 0.5; + REQUIRE(particle->compute_reference_location() == true); + auto ref_coordinates = particle->reference_location(); + for (unsigned i = 0; i < ref_coordinates.size(); ++i) + REQUIRE(ref_coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + + // Assign material + unsigned mid = 0; + // Initialise material + Json jmaterial; + jmaterial["density"] = 1000.; + jmaterial["youngs_modulus"] = 1.0E+7; + jmaterial["poisson_ratio"] = 0.3; + jmaterial["porosity"] = 0.3; + jmaterial["k_x"] = 0.001; + jmaterial["k_y"] = 0.001; + jmaterial["k_z"] = 0.001; + + auto material = + Factory, unsigned, const Json&>::instance()->create( + "LinearElastic3D", std::move(mid), jmaterial); + + // Assign liquid material + unsigned liquid_mid = 1; + // Initialise material + Json jmaterial_liquid; + jmaterial_liquid["density"] = 1000.; + jmaterial_liquid["bulk_modulus"] = 1.0E+9; + jmaterial_liquid["mu"] = 0.3; + jmaterial_liquid["dynamic_viscosity"] = 0.; + + auto liquid_material = + Factory, unsigned, const Json&>::instance()->create( + "Newtonian3D", std::move(liquid_mid), jmaterial_liquid); + + // Check compute mass before material and volume + // TODO Assert: REQUIRE(particle->compute_mass() == false); + + // Test compute stress before material assignment + // TODO Assert: REQUIRE(particle->compute_stress() == false); + + // Assign material properties + REQUIRE(particle->assign_material(material) == true); + REQUIRE(particle->assign_material(liquid_material, + mpm::ParticlePhase::Liquid) == true); + + // Check material id from particle + REQUIRE(particle->material_id() == 0); + REQUIRE(particle->material_id(mpm::ParticlePhase::Liquid) == 1); + + // Assign porosity + REQUIRE(particle->assign_porosity() == true); + + // Assign permeability + REQUIRE(particle->assign_permeability() == true); + + // Compute volume + REQUIRE_NOTHROW(particle->compute_volume()); + + // Compute mass + REQUIRE_NOTHROW(particle->compute_mass()); + // Mass + REQUIRE(particle->mass() == Approx(5600.).epsilon(Tolerance)); + REQUIRE(particle->liquid_mass() == Approx(2400.).epsilon(Tolerance)); + + // Map particle mass to nodes + particle->assign_mass(std::numeric_limits::max()); + // TODO Assert: REQUIRE(particle->map_mass_momentum_to_nodes() == false); + + // Map particle pressure to nodes + // TODO Assert: REQUIRE(particle->map_pressure_to_nodes() == false); + + // Assign mass to nodes + REQUIRE(particle->compute_reference_location() == true); + REQUIRE_NOTHROW(particle->compute_shapefn()); + + // Check velocity + Eigen::VectorXd velocity; + velocity.resize(Dim); + for (unsigned i = 0; i < velocity.size(); ++i) velocity(i) = i; + REQUIRE(particle->assign_velocity(velocity) == true); + REQUIRE(particle->assign_liquid_velocity(velocity) == true); + for (unsigned i = 0; i < velocity.size(); ++i) { + REQUIRE(particle->velocity()(i) == Approx(i).epsilon(Tolerance)); + REQUIRE(particle->liquid_velocity()(i) == Approx(i).epsilon(Tolerance)); + } + + REQUIRE_NOTHROW(particle->compute_mass()); + REQUIRE_NOTHROW(particle->map_mass_momentum_to_nodes()); + + // TODO Assert: REQUIRE(particle->map_pressure_to_nodes() == false); + REQUIRE(particle->compute_pressure_smoothing() == false); + + // Values of nodal mass + std::array nodal_mass{125., 375., 1125., 375., + 375., 1125., 3375., 1125.}; + // Check nodal mass + for (unsigned i = 0; i < nodes.size(); ++i) { + // Solid phase + REQUIRE(nodes.at(i)->mass(mpm::NodePhase::nSolid) == + Approx(nodal_mass.at(i) * (1 - particle->porosity()))); + // Liquid phase + REQUIRE( + nodes.at(i)->mass(mpm::NodePhase::nLiquid) == + Approx(nodal_mass.at(i) * particle->porosity()).epsilon(Tolerance)); + } + + // Compute nodal velocity + for (const auto& node : nodes) node->compute_velocity(); + + // Values of nodal momentum + Eigen::Matrix nodal_momentum; + // clang-format off + nodal_momentum << 0., 125., 250., + 0., 375., 750., + 0., 1125., 2250., + 0., 375., 750., + 0., 375., 750., + 0., 1125., 2250., + 0., 3375., 6750., + 0., 1125., 2250.; + // clang-format on + + // Check nodal momentum + for (unsigned i = 0; i < nodal_momentum.rows(); ++i) + for (unsigned j = 0; j < nodal_momentum.cols(); ++j) { + // Solid phase + REQUIRE(nodes.at(i)->momentum(mpm::NodePhase::nSolid)(j) == + Approx(nodal_momentum(i, j) * (1 - particle->porosity())) + .epsilon(Tolerance)); + // Liquid phase + REQUIRE(nodes.at(i)->momentum(mpm::NodePhase::nLiquid)(j) == + Approx(nodal_momentum(i, j) * particle->porosity()) + .epsilon(Tolerance)); + } + + // Values of nodal velocity + Eigen::Matrix nodal_velocity; + // clang-format off + nodal_velocity << 0., 1., 2., + 0., 1., 2., + 0., 1., 2., + 0., 1., 2., + 0., 1., 2., + 0., 1., 2., + 0., 1., 2., + 0., 1., 2.; + // clang-format on + // Check nodal velocity + for (unsigned i = 0; i < nodal_velocity.rows(); ++i) + for (unsigned j = 0; j < nodal_velocity.cols(); ++j) { + // Solid phase + REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::nSolid)(j) == + Approx(nodal_velocity(i, j)).epsilon(Tolerance)); + // Liquid phase + REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::nLiquid)(j) == + Approx(nodal_velocity(i, j)).epsilon(Tolerance)); + } + + // Set momentum to get non-zero strain + // clang-format off + nodal_momentum << 0., 125. * 1., 250. * 1., + 0., 375. * 2., 750. * 2., + 0., 1125. * 3., 2250. * 3., + 0., 375. * 4., 750. * 4., + 0., 375. * 5., 750. * 5., + 0., 1125. * 6., 2250. * 6., + 0., 3375. * 7., 6750. * 7., + 0., 1125. * 8., 2250. * 8.; + // clang-format on + for (unsigned i = 0; i < nodes.size(); ++i) { + // Solid phase + REQUIRE_NOTHROW(nodes.at(i)->update_momentum( + false, mpm::NodePhase::nSolid, + nodal_momentum.row(i) * (1 - particle->porosity()))); + // Liquid phase + REQUIRE_NOTHROW(nodes.at(i)->update_momentum( + false, mpm::NodePhase::nLiquid, + nodal_momentum.row(i) * particle->porosity())); + } + + // nodal velocity + // clang-format off + nodal_velocity << 0., 1., 2., + 0., 2., 4., + 0., 3., 6., + 0., 4., 8., + 0., 5., 10., + 0., 6., 12., + 0., 7., 14., + 0., 8., 16.; + // clang-format on + // Compute nodal velocity + for (const auto& node : nodes) node->compute_velocity(); + // Check nodal velocity + for (unsigned i = 0; i < nodal_velocity.rows(); ++i) + for (unsigned j = 0; j < nodal_velocity.cols(); ++j) { + // Solid phase + REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::nSolid)(j) == + Approx(nodal_velocity(i, j)).epsilon(Tolerance)); + // Liquid phase + REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::nLiquid)(j) == + Approx(nodal_velocity(i, j)).epsilon(Tolerance)); + } + + // Check pressure + REQUIRE(std::isnan(particle->pressure()) == true); + + // Compute strain + particle->compute_strain(dt); + // Strain + Eigen::Matrix strain; + strain << 0.00000, 0.07500, 0.40000, -0.02500, 0.35000, -0.05000; + + // Check strains + for (unsigned i = 0; i < strain.rows(); ++i) + REQUIRE(particle->strain()(i) == Approx(strain(i)).epsilon(Tolerance)); + + // Check volumetric strain at centroid + double volumetric_strain = 0.5; + REQUIRE(particle->volumetric_strain_centroid() == + Approx(volumetric_strain).epsilon(Tolerance)); + + // Check updated pressure + REQUIRE(std::isnan(particle->pressure()) == true); + + // Update volume strain rate + REQUIRE(particle->volume() == Approx(8.0).epsilon(Tolerance)); + particle->compute_strain(dt); + REQUIRE_NOTHROW(particle->update_volume()); + REQUIRE(particle->volume() == Approx(12.0).epsilon(Tolerance)); + + // Compute stress + REQUIRE_NOTHROW(particle->compute_stress()); + + Eigen::Matrix stress; + // clang-format off + stress << 2740384.6153846150, + 3317307.6923076920, + 5817307.6923076920, + -96153.8461538463, + 1346153.8461538465, + -192307.6923076927; + // clang-format on + // Check stress + for (unsigned i = 0; i < stress.rows(); ++i) + REQUIRE(particle->stress()(i) == Approx(stress(i)).epsilon(Tolerance)); + + // Compute pore_pressure + REQUIRE_NOTHROW(particle->compute_pore_pressure(dt)); + // Check pore pressure + REQUIRE(particle->pore_pressure() == + Approx(-1608333333.3333332539).epsilon(Tolerance)); + + // Check body force + Eigen::Matrix gravity; + gravity << 0., 0., -9.81; + + particle->map_body_force(gravity); + + // Body force + Eigen::Matrix body_force; + // clang-format off + body_force << 0., 0., -1226.25, + 0., 0., -3678.75, + 0., 0., -11036.25, + 0., 0., -3678.75, + 0., 0., -3678.75, + 0., 0., -11036.25, + 0., 0., -33108.75, + 0., 0., -11036.25; + // clang-format on + + // Check nodal body force + for (unsigned i = 0; i < body_force.rows(); ++i) + for (unsigned j = 0; j < body_force.cols(); ++j) + REQUIRE(nodes[i]->external_force(mpm::NodePhase::nSolid)[j] == + Approx(body_force(i, j)).epsilon(Tolerance)); + + // Check traction force + double traction = 7.68; + const unsigned direction = 2; + // Assign volume + REQUIRE(particle->assign_volume(0.0) == false); + REQUIRE(particle->assign_volume(-5.0) == false); + REQUIRE(particle->assign_volume(2.0) == true); + // Assign traction to particle + particle->assign_traction(direction, + mfunction->value(current_time) * traction); + // Map traction force + particle->map_traction_force(); + + // Traction force + Eigen::Matrix traction_force; + // shapefn * volume / size_(dir) * traction + // clang-format off + traction_force << 0., 0., 0.015625 * 1.587401052 * 7.68, + 0., 0., 0.046875 * 1.587401052 * 7.68, + 0., 0., 0.140625 * 1.587401052 * 7.68, + 0., 0., 0.046875 * 1.587401052 * 7.68, + 0., 0., 0.046875 * 1.587401052 * 7.68, + 0., 0., 0.140625 * 1.587401052 * 7.68, + 0., 0., 0.421875 * 1.587401052 * 7.68, + 0., 0., 0.140625 * 1.587401052 * 7.68; + // clang-format on + // Add previous external body force + traction_force += body_force; + + // Check nodal traction force + for (unsigned i = 0; i < traction_force.rows(); ++i) + for (unsigned j = 0; j < traction_force.cols(); ++j) + REQUIRE(nodes[i]->external_force(mpm::NodePhase::nSolid)[j] == + Approx(traction_force(i, j)).epsilon(Tolerance)); + // Reset traction + particle->assign_traction(direction, + mfunction->value(current_time) * -traction); + // Map traction force + particle->map_traction_force(); + // Check nodal external force + for (unsigned i = 0; i < traction_force.rows(); ++i) + for (unsigned j = 0; j < traction_force.cols(); ++j) + REQUIRE(nodes[i]->external_force(mpm::NodePhase::nSolid)[j] == + Approx(body_force(i, j)).epsilon(Tolerance)); + + // Internal force + Eigen::Matrix internal_force; + // clang-format off + internal_force << 402696314.1025640965, 403225160.2564102411, 403826121.7948717475, + -402984775.6410256028, 1209771634.6153848171, 1211670673.0769231319, + -1208665865.3846151829, -1205637019.2307691574, 3630973557.6923074722, + 1208185096.1538460255, -401975160.2564102411, 1210132211.5384614468, + 1208281249.9999997616, 1208329326.9230768681, -402672275.64102566242, + -1208377403.8461537361, 3625276442.3076920509, -1207439903.8461537361, + -3624266826.9230761528, -3629026442.3076920509, -3634435096.153845787, + 3625132211.5384612083, -1209963942.3076925278, -1212055288.4615385532; + // clang-format on + + // Map particle internal force + particle->assign_volume(8.0); + particle->map_internal_force(); + + // Check nodal internal force + for (unsigned i = 0; i < internal_force.rows(); ++i) + for (unsigned j = 0; j < internal_force.cols(); ++j) + REQUIRE(nodes[i]->internal_force(mpm::NodePhase::nMixture)[j] == + Approx(internal_force(i, j)).epsilon(Tolerance)); + + // Calculate nodal acceleration and velocity + for (const auto& node : nodes) + node->compute_acceleration_velocity(mpm::NodePhase::nSolid, dt); + + // Check nodal velocity + // clang-format off + nodal_velocity << 460224.35897435899824, 460829.75457875471329, 461516.16633699642261, + -153518.00976800979697, 460867.38461538479896, 461591.42641025653575, + -153481.37973137974041, -153093.76434676436475, 461080.60589743591845, + 460260.98901098914212, -153129.39438339442131, 461009.34582417592173, + 460297.61904761905316, 460320.93406593421241, -153390.36357753362972, + -153444.74969474971294, 460358.56410256412346, -153315.10350427351659, + -153408.11965811965638, -153602.58485958489473, -153825.92401709404658, + 460334.24908424913883, -153638.2148962149513, -153897.1840903541306; + // clang-format on + // Check nodal velocity + for (unsigned i = 0; i < nodal_velocity.rows(); ++i) + for (unsigned j = 0; j < nodal_velocity.cols(); ++j) + REQUIRE(nodes[i]->velocity(mpm::NodePhase::nSolid)[j] == + Approx(nodal_velocity(i, j)).epsilon(Tolerance)); + + // Check nodal acceleration + Eigen::Matrix nodal_acceleration; + // clang-format off + nodal_acceleration << 4602243.5897435899824, 4608287.5457875467837, 4615141.6633699638769, + -1535180.0976800979115, 4608653.8461538478732, 4615874.2641025651246, + -1534813.7973137972876, -1530967.643467643531, 4610746.0589743591845, + 4602609.8901098910719, -1531333.9438339441549, 4610013.4582417588681, + 4602976.1904761902988, 4603159.3406593417749, -1534003.6357753362972, + -1534447.4969474971294, 4603525.6410256410018, -1533271.0350427350495, + -1534081.1965811965056, -1536095.8485958487727, -1538399.2401709402911, + 4603342.4908424913883, -1536462.1489621493965, -1539131.840903541306; + // clang-format on + // Check nodal acceleration + for (unsigned i = 0; i < nodal_acceleration.rows(); ++i) + for (unsigned j = 0; j < nodal_acceleration.cols(); ++j) + REQUIRE(nodes[i]->acceleration(mpm::NodePhase::nSolid)[j] == + Approx(nodal_acceleration(i, j)).epsilon(Tolerance)); + + // Approx(nodal_velocity(i, j) / dt).epsilon(Tolerance)); + + // Check original particle coordinates + coords << 1.5, 1.5, 1.5; + coordinates = particle->coordinates(); + for (unsigned i = 0; i < coordinates.size(); ++i) + REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + + SECTION("Particle pressure smoothing") { + // Assign material + unsigned mid1 = 0; + // Initialise material + Json jmaterial1; + jmaterial1["density"] = 1000.; + jmaterial1["bulk_modulus"] = 8333333.333333333; + jmaterial1["dynamic_viscosity"] = 8.9E-4; + + auto material1 = + Factory, unsigned, const Json&>::instance() + ->create("Newtonian3D", std::move(mid1), jmaterial1); + + // Assign material properties + REQUIRE(particle->assign_material(material1) == true); + + // Compute volume + REQUIRE_NOTHROW(particle->compute_volume()); + + // Compute mass + REQUIRE_NOTHROW(particle->compute_mass()); + // Mass + REQUIRE(particle->mass() == Approx(5600.).epsilon(Tolerance)); + REQUIRE(particle->liquid_mass() == Approx(2400.).epsilon(Tolerance)); + + // Map particle mass to nodes + particle->assign_mass(std::numeric_limits::max()); + // TODO Assert: REQUIRE(particle->map_mass_momentum_to_nodes() == false); + + // Map particle pressure to nodes + // TODO Assert: REQUIRE(particle->map_pressure_to_nodes() == false); + + // Assign mass to nodes + REQUIRE(particle->compute_reference_location() == true); + REQUIRE_NOTHROW(particle->compute_shapefn()); + + // Check velocity + velocity.resize(Dim); + for (unsigned i = 0; i < velocity.size(); ++i) velocity(i) = i; + REQUIRE(particle->assign_velocity(velocity) == true); + for (unsigned i = 0; i < velocity.size(); ++i) + REQUIRE(particle->velocity()(i) == Approx(i).epsilon(Tolerance)); + + REQUIRE_NOTHROW(particle->compute_mass()); + REQUIRE_NOTHROW(particle->map_mass_momentum_to_nodes()); + + // Check volumetric strain at centroid + volumetric_strain = 0.5; + REQUIRE(particle->dvolumetric_strain() == + Approx(volumetric_strain).epsilon(Tolerance)); + + // Compute stress + REQUIRE_NOTHROW(particle->compute_stress()); + + REQUIRE( + particle->pressure() == + Approx(-8333333.333333333 * volumetric_strain).epsilon(Tolerance)); + + REQUIRE_NOTHROW(particle->map_pressure_to_nodes()); + REQUIRE(particle->compute_pressure_smoothing() == true); + } + + SECTION("Particle assign state variables") { + SECTION("Assign state variable fail") { + mid = 0; + Json jmaterial; + jmaterial["density"] = 1000.; + jmaterial["youngs_modulus"] = 1.0E+7; + jmaterial["poisson_ratio"] = 0.3; + jmaterial["softening"] = false; + jmaterial["friction"] = 0.; + jmaterial["dilation"] = 0.; + jmaterial["cohesion"] = 2000.; + jmaterial["residual_friction"] = 0.; + jmaterial["residual_dilation"] = 0.; + jmaterial["residual_cohesion"] = 1000.; + jmaterial["peak_pdstrain"] = 0.; + jmaterial["residual_pdstrain"] = 0.; + jmaterial["tension_cutoff"] = 0.; + + auto mc_material = + Factory, unsigned, const Json&>::instance() + ->create("MohrCoulomb3D", std::move(id), jmaterial); + REQUIRE(mc_material->id() == 0); + + mpm::dense_map state_variables = + mc_material->initialise_state_variables(); + REQUIRE(state_variables.at("phi") == + Approx(jmaterial["friction"]).epsilon(Tolerance)); + REQUIRE(state_variables.at("psi") == + Approx(jmaterial["dilation"]).epsilon(Tolerance)); + REQUIRE(state_variables.at("cohesion") == + Approx(jmaterial["cohesion"]).epsilon(Tolerance)); + REQUIRE(state_variables.at("epsilon") == Approx(0.).epsilon(Tolerance)); + REQUIRE(state_variables.at("rho") == Approx(0.).epsilon(Tolerance)); + REQUIRE(state_variables.at("theta") == Approx(0.).epsilon(Tolerance)); + REQUIRE(state_variables.at("pdstrain") == + Approx(0.).epsilon(Tolerance)); + + SECTION("Assign state variables") { + // Assign material properties + REQUIRE(particle->assign_material(mc_material) == true); + // 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") { + // Assign material + unsigned mid1 = 0; + // Initialise material + Json jmaterial1; + jmaterial1["density"] = 1000.; + jmaterial1["bulk_modulus"] = 8333333.333333333; + jmaterial1["dynamic_viscosity"] = 8.9E-4; + + auto newtonian_material = + Factory, unsigned, const Json&>::instance() + ->create("Newtonian3D", std::move(mid1), jmaterial1); + + // Assign material properties + REQUIRE(particle->assign_material(newtonian_material) == true); + // Assign state variables + REQUIRE(particle->assign_material_state_vars(state_variables, + mc_material) == false); + } + + SECTION("Assign state variables fail on material id") { + // Assign material + unsigned mid1 = 1; + // Initialise material + Json jmaterial1; + jmaterial1["density"] = 1000.; + jmaterial1["bulk_modulus"] = 8333333.333333333; + jmaterial1["dynamic_viscosity"] = 8.9E-4; + + auto newtonian_material = + Factory, unsigned, const Json&>::instance() + ->create("Newtonian3D", std::move(mid1), jmaterial1); + + // Assign material properties + REQUIRE(particle->assign_material(newtonian_material) == true); + // Assign state variables + REQUIRE(particle->assign_material_state_vars(state_variables, + mc_material) == false); + } + } + } + + // Compute updated particle location + REQUIRE_NOTHROW(particle->compute_updated_position(dt)); + // Check particle velocity + velocity << 0., 1., 0.5985714286; + for (unsigned i = 0; i < velocity.size(); ++i) + REQUIRE(particle->velocity()(i) == + Approx(velocity(i)).epsilon(Tolerance)); + + // Check particle displacement + Eigen::Vector3d displacement; + displacement << 0.0, 0.5875, 1.0348571429; + for (unsigned i = 0; i < displacement.size(); ++i) + REQUIRE(particle->displacement()(i) == + Approx(displacement(i)).epsilon(Tolerance)); + + // Updated particle coordinate + coords << 1.5, 2.0875, 2.5348571429; + // Check particle coordinates + coordinates = particle->coordinates(); + for (unsigned i = 0; i < coordinates.size(); ++i) + REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + + // Compute updated particle location based on nodal velocity + REQUIRE_NOTHROW(particle->compute_updated_position(dt, true)); + // Check particle velocity + velocity << 0., 5.875, 10.3485714286; + for (unsigned i = 0; i < velocity.size(); ++i) + REQUIRE(particle->velocity()(i) == + Approx(velocity(i)).epsilon(Tolerance)); + + // Check particle displacement + displacement << 0.0, 1.175, 2.0697142857; + for (unsigned i = 0; i < displacement.size(); ++i) + REQUIRE(particle->displacement()(i) == + Approx(displacement(i)).epsilon(Tolerance)); + + // Updated particle coordinate + coords << 1.5, 2.675, 3.5697142857; + // Check particle coordinates + coordinates = particle->coordinates(); + for (unsigned i = 0; i < coordinates.size(); ++i) + REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + } + + SECTION("Check assign material to particle") { + // Add particle + mpm::Index id = 0; + coords << 0.75, 0.75, 0.75; + auto particle = std::make_shared>(id, coords); + + unsigned mid = 1; + // Initialise material + Json jmaterial; + jmaterial["density"] = 1000.; + jmaterial["youngs_modulus"] = 1.0E+7; + jmaterial["poisson_ratio"] = 0.3; + + auto material = + Factory, unsigned, const Json&>::instance()->create( + "LinearElastic3D", std::move(mid), jmaterial); + REQUIRE(material->id() == 1); + + // Check if particle can be assigned a null material + REQUIRE(particle->assign_material(nullptr) == false); + // Check material id + REQUIRE(particle->material_id() == std::numeric_limits::max()); + + // Assign material to particle + REQUIRE(particle->assign_material(material) == true); + // Check material id + REQUIRE(particle->material_id() == 1); + } + + SECTION("Check particle properties") { + mpm::Index id = 0; + const double Tolerance = 1.E-7; + std::shared_ptr> particle = + std::make_shared>(id, coords); + + // Check mass + REQUIRE(particle->mass() == Approx(0.0).epsilon(Tolerance)); + double mass = 100.5; + particle->assign_mass(mass); + REQUIRE(particle->mass() == Approx(100.5).epsilon(Tolerance)); + + // Check stress + Eigen::Matrix stress; + for (unsigned i = 0; i < stress.size(); ++i) stress(i) = 1.; + + for (unsigned i = 0; i < stress.size(); ++i) + REQUIRE(particle->stress()(i) == Approx(0.).epsilon(Tolerance)); + + // Check velocity + Eigen::VectorXd velocity; + velocity.resize(Dim); + for (unsigned i = 0; i < velocity.size(); ++i) velocity(i) = 17.51; + + for (unsigned i = 0; i < velocity.size(); ++i) + REQUIRE(particle->velocity()(i) == Approx(0.).epsilon(Tolerance)); + + REQUIRE(particle->assign_velocity(velocity) == true); + for (unsigned i = 0; i < velocity.size(); ++i) + REQUIRE(particle->velocity()(i) == Approx(17.51).epsilon(Tolerance)); + + // Assign volume + REQUIRE(particle->assign_volume(0.0) == false); + REQUIRE(particle->assign_volume(-5.0) == false); + REQUIRE(particle->assign_volume(2.0) == true); + // Check volume + REQUIRE(particle->volume() == Approx(2.0).epsilon(Tolerance)); + // Traction + double traction = 65.32; + const unsigned Direction = 1; + // Check traction + for (unsigned i = 0; i < Dim; ++i) + REQUIRE(particle->traction()(i) == Approx(0.).epsilon(Tolerance)); + + REQUIRE(particle->assign_traction(Direction, traction) == true); + + // Calculate traction force = traction * volume / spacing + traction *= 2.0 / (std::pow(2.0, 1. / Dim)); + + for (unsigned i = 0; i < Dim; ++i) { + if (i == Direction) + REQUIRE(particle->traction()(i) == Approx(traction).epsilon(Tolerance)); + else + REQUIRE(particle->traction()(i) == Approx(0.).epsilon(Tolerance)); + } + + // Check for incorrect direction + const unsigned wrong_dir = 4; + REQUIRE(particle->assign_traction(wrong_dir, traction) == false); + + // Check again to ensure value hasn't been updated + for (unsigned i = 0; i < Dim; ++i) { + if (i == Direction) + REQUIRE(particle->traction()(i) == Approx(traction).epsilon(Tolerance)); + else + REQUIRE(particle->traction()(i) == Approx(0.).epsilon(Tolerance)); + } + } + + // Check initialise particle from HDF5 file + SECTION("Check initialise particle HDF5") { + mpm::Index id = 0; + const double Tolerance = 1.E-7; + std::shared_ptr> particle = + std::make_shared>(id, coords); + + mpm::HDF5Particle h5_particle; + h5_particle.id = 13; + h5_particle.mass = 501.5; + + Eigen::Vector3d coords; + coords << 1., 2., 3.; + h5_particle.coord_x = coords[0]; + h5_particle.coord_y = coords[1]; + h5_particle.coord_z = coords[2]; + + Eigen::Vector3d displacement; + displacement << 0.01, 0.02, 0.03; + h5_particle.displacement_x = displacement[0]; + h5_particle.displacement_y = displacement[1]; + h5_particle.displacement_z = displacement[2]; + + Eigen::Vector3d lsize; + lsize << 0.25, 0.5, 0.75; + h5_particle.nsize_x = lsize[0]; + h5_particle.nsize_y = lsize[1]; + h5_particle.nsize_z = lsize[2]; + + Eigen::Vector3d velocity; + velocity << 1.5, 2.5, 3.5; + h5_particle.velocity_x = velocity[0]; + h5_particle.velocity_y = velocity[1]; + h5_particle.velocity_z = velocity[2]; + + Eigen::Matrix stress; + stress << 11.5, -12.5, 13.5, 14.5, -15.5, 16.5; + h5_particle.stress_xx = stress[0]; + h5_particle.stress_yy = stress[1]; + h5_particle.stress_zz = stress[2]; + h5_particle.tau_xy = stress[3]; + h5_particle.tau_yz = stress[4]; + h5_particle.tau_xz = stress[5]; + + Eigen::Matrix strain; + strain << 0.115, -0.125, 0.135, 0.145, -0.155, 0.165; + h5_particle.strain_xx = strain[0]; + h5_particle.strain_yy = strain[1]; + h5_particle.strain_zz = strain[2]; + h5_particle.gamma_xy = strain[3]; + h5_particle.gamma_yz = strain[4]; + h5_particle.gamma_xz = strain[5]; + + h5_particle.epsilon_v = strain.head(Dim).sum(); + + h5_particle.status = true; + + h5_particle.cell_id = 1; + + h5_particle.volume = 2.; + + h5_particle.material_id = 1; + + // Reinitialise particle from HDF5 data + REQUIRE(particle->initialise_particle(h5_particle) == true); + + // Check particle id + REQUIRE(particle->id() == h5_particle.id); + // Check particle mass + REQUIRE(particle->mass() == h5_particle.mass); + // Check particle volume + REQUIRE(particle->volume() == h5_particle.volume); + // Check particle mass density + REQUIRE(particle->mass_density() == h5_particle.mass / h5_particle.volume); + // Check particle status + REQUIRE(particle->status() == h5_particle.status); + + // Check for coordinates + auto coordinates = particle->coordinates(); + REQUIRE(coordinates.size() == Dim); + for (unsigned i = 0; i < coordinates.size(); ++i) + REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + REQUIRE(coordinates.size() == Dim); + + // Check for displacement + auto pdisplacement = particle->displacement(); + REQUIRE(pdisplacement.size() == Dim); + for (unsigned i = 0; i < Dim; ++i) + REQUIRE(pdisplacement(i) == Approx(displacement(i)).epsilon(Tolerance)); + + // Check for size + auto size = particle->natural_size(); + REQUIRE(size.size() == Dim); + for (unsigned i = 0; i < size.size(); ++i) + REQUIRE(size(i) == Approx(lsize(i)).epsilon(Tolerance)); + + // Check velocity + auto pvelocity = particle->velocity(); + REQUIRE(pvelocity.size() == Dim); + for (unsigned i = 0; i < Dim; ++i) + REQUIRE(pvelocity(i) == Approx(velocity(i)).epsilon(Tolerance)); + + // Check stress + auto pstress = particle->stress(); + REQUIRE(pstress.size() == stress.size()); + for (unsigned i = 0; i < stress.size(); ++i) + REQUIRE(pstress(i) == Approx(stress(i)).epsilon(Tolerance)); + + // Check strain + auto pstrain = particle->strain(); + REQUIRE(pstrain.size() == strain.size()); + for (unsigned i = 0; i < strain.size(); ++i) + REQUIRE(pstrain(i) == Approx(strain(i)).epsilon(Tolerance)); + + // Check particle volumetric strain centroid + REQUIRE(particle->volumetric_strain_centroid() == h5_particle.epsilon_v); + + // Check cell id + REQUIRE(particle->cell_id() == h5_particle.cell_id); + + // Check material id + REQUIRE(particle->material_id() == h5_particle.material_id); + + // Write Particle HDF5 data + const auto h5_test = particle->hdf5(); + + REQUIRE(h5_particle.id == h5_test.id); + REQUIRE(h5_particle.mass == h5_test.mass); + + REQUIRE(h5_particle.coord_x == Approx(h5_test.coord_x).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_y == Approx(h5_test.coord_y).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_z == Approx(h5_test.coord_z).epsilon(Tolerance)); + + REQUIRE(h5_particle.displacement_x == + Approx(h5_test.displacement_x).epsilon(Tolerance)); + REQUIRE(h5_particle.displacement_y == + Approx(h5_test.displacement_y).epsilon(Tolerance)); + REQUIRE(h5_particle.displacement_z == + Approx(h5_test.displacement_z).epsilon(Tolerance)); + + REQUIRE(h5_particle.nsize_x == h5_test.nsize_x); + REQUIRE(h5_particle.nsize_y == h5_test.nsize_y); + REQUIRE(h5_particle.nsize_z == h5_test.nsize_z); + + REQUIRE(h5_particle.velocity_x == + Approx(h5_test.velocity_x).epsilon(Tolerance)); + REQUIRE(h5_particle.velocity_y == + Approx(h5_test.velocity_y).epsilon(Tolerance)); + REQUIRE(h5_particle.velocity_z == + Approx(h5_test.velocity_z).epsilon(Tolerance)); + + REQUIRE(h5_particle.stress_xx == + Approx(h5_test.stress_xx).epsilon(Tolerance)); + REQUIRE(h5_particle.stress_yy == + Approx(h5_test.stress_yy).epsilon(Tolerance)); + REQUIRE(h5_particle.stress_zz == + Approx(h5_test.stress_zz).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_xy == Approx(h5_test.tau_xy).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_yz == Approx(h5_test.tau_yz).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_xz == Approx(h5_test.tau_xz).epsilon(Tolerance)); + + REQUIRE(h5_particle.strain_xx == + Approx(h5_test.strain_xx).epsilon(Tolerance)); + REQUIRE(h5_particle.strain_yy == + Approx(h5_test.strain_yy).epsilon(Tolerance)); + REQUIRE(h5_particle.strain_zz == + Approx(h5_test.strain_zz).epsilon(Tolerance)); + REQUIRE(h5_particle.gamma_xy == + Approx(h5_test.gamma_xy).epsilon(Tolerance)); + REQUIRE(h5_particle.gamma_yz == + Approx(h5_test.gamma_yz).epsilon(Tolerance)); + REQUIRE(h5_particle.gamma_xz == + Approx(h5_test.gamma_xz).epsilon(Tolerance)); + + REQUIRE(h5_particle.epsilon_v == + Approx(h5_test.epsilon_v).epsilon(Tolerance)); + REQUIRE(h5_particle.status == h5_test.status); + REQUIRE(h5_particle.cell_id == h5_test.cell_id); + REQUIRE(h5_particle.material_id == h5_test.material_id); + } + + // Check particle's material id maping to nodes + SECTION("Check particle's material id maping to nodes") { + // Add particle + mpm::Index id1 = 0; + coords << 1.5, 1.5, 1.5; + auto particle1 = std::make_shared>(id1, coords); + + // Add particle + mpm::Index id2 = 1; + coords << 0.5, 0.5, 0.5; + auto particle2 = std::make_shared>(id2, coords); + + // Element + std::shared_ptr> element = + std::make_shared>(); + + // Create cell + auto cell = std::make_shared>(10, Nnodes, element); + // Create vector of nodes and add them to cell + coords << 0, 0, 0; + std::shared_ptr> node0 = + std::make_shared>(0, coords); + + coords << 2, 0, 0; + std::shared_ptr> node1 = + std::make_shared>(1, coords); + + coords << 2, 2, 0; + std::shared_ptr> node2 = + std::make_shared>(2, coords); + + coords << 0, 2, 0; + std::shared_ptr> node3 = + std::make_shared>(3, coords); + + coords << 0, 0, 2; + std::shared_ptr> node4 = + std::make_shared>(4, coords); + + coords << 2, 0, 2; + std::shared_ptr> node5 = + std::make_shared>(5, coords); + + coords << 2, 2, 2; + std::shared_ptr> node6 = + std::make_shared>(6, coords); + + coords << 0, 2, 2; + std::shared_ptr> node7 = + std::make_shared>(7, coords); + std::vector>> nodes = { + node0, node1, node2, node3, node4, node5, node6, node7}; + + for (int j = 0; j < nodes.size(); ++j) cell->add_node(j, nodes[j]); + + // Initialise cell properties and assign cell to particle + cell->initialise(); + particle1->assign_cell(cell); + particle2->assign_cell(cell); + + // Assign material 1 + unsigned mid1 = 0; + // Initialise material 1 + Json jmaterial1; + jmaterial1["density"] = 1000.; + jmaterial1["youngs_modulus"] = 1.0E+7; + jmaterial1["poisson_ratio"] = 0.3; + + auto material1 = + Factory, unsigned, const Json&>::instance()->create( + "LinearElastic3D", std::move(mid1), jmaterial1); + + particle1->assign_material(material1); + + // Assign material 2 + unsigned mid2 = 1; + // Initialise material 2 + Json jmaterial2; + jmaterial2["density"] = 2000.; + jmaterial2["youngs_modulus"] = 2.0E+7; + jmaterial2["poisson_ratio"] = 0.25; + + auto material2 = + Factory, unsigned, const Json&>::instance()->create( + "LinearElastic3D", std::move(mid2), jmaterial2); + + particle2->assign_material(material2); + + // Append particle's material id to nodes in cell + particle1->append_material_id_to_nodes(); + particle2->append_material_id_to_nodes(); + // check if the correct amount of material ids were added to node and if // their indexes are correct std::vector material_ids = {0, 1}; From c69843fe0144ed8c9dbb34a60a000275907d4ed7 Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Fri, 31 Jul 2020 14:04:46 -0700 Subject: [PATCH 074/175] Add twophase_node --- include/io/io_mesh.h | 10 +- include/io/io_mesh_ascii.h | 10 +- include/io/io_mesh_ascii.tcc | 48 +++----- include/mesh.h | 3 +- include/mesh.tcc | 18 +-- include/node.h | 13 +- include/node.tcc | 164 +------------------------- include/particles/particle_base.h | 6 +- include/particles/twophase_particle.h | 4 +- include/solvers/mpm_base.tcc | 36 +++--- include/twophase_node.tcc | 159 +++++++++++++++++++++++++ src/node.cc | 4 +- tests/twophase_particle_test.cc | 6 +- 13 files changed, 235 insertions(+), 246 deletions(-) create mode 100644 include/twophase_node.tcc diff --git a/include/io/io_mesh.h b/include/io/io_mesh.h index a8bba3d79..339839983 100644 --- a/include/io/io_mesh.h +++ b/include/io/io_mesh.h @@ -63,11 +63,11 @@ class IOMesh { virtual std::vector> read_particles_stresses( const std::string& particles_stresses) = 0; - //! Read particle pressure - //! \param[in] particles_pressures file name with particle pressure - //! \retval Vector of particles pressures - virtual std::vector read_particles_pressures( - const std::string& particles_pressures) = 0; + //! Read particle scalar properties + //! \param[in] scalar_file file name with particle scalar properties + //! \retval Vector of particles scalar properties + virtual std::vector> + read_particles_scalar_properties(const std::string& scalar_file) = 0; //! Read pressure constraints file //! \param[in] pressure_constraints_files file name with pressure constraints diff --git a/include/io/io_mesh_ascii.h b/include/io/io_mesh_ascii.h index 9a1c06cbc..e1b6031f9 100644 --- a/include/io/io_mesh_ascii.h +++ b/include/io/io_mesh_ascii.h @@ -51,11 +51,11 @@ class IOMeshAscii : public IOMesh { std::vector> read_particles_stresses( const std::string& particles_stresses) override; - //! Read particle pressure - //! \param[in] particles_pressures file name with particle pressure - //! \retval Vector of particles pressures - std::vector read_particles_pressures( - const std::string& particles_pressures) override; + //! Read particle scalar properties + //! \param[in] scalar_file file name with particle scalar properties + //! \retval Vector of particles scalar properties + std::vector> read_particles_scalar_properties( + const std::string& scalar_file) override; //! Read pressure constraints file //! \param[in] pressure_constraints_files file name with pressure diff --git a/include/io/io_mesh_ascii.tcc b/include/io/io_mesh_ascii.tcc index 30828f412..14bba7ea2 100644 --- a/include/io/io_mesh_ascii.tcc +++ b/include/io/io_mesh_ascii.tcc @@ -246,24 +246,19 @@ std::vector> return stresses; } -//! Return pressures of particles +//! Return particles scalar properties template -std::vector mpm::IOMeshAscii::read_particles_pressures( - const std::string& particles_pressures) { - - // Particles pressures - std::vector pressures; - pressures.clear(); - - // Expected number of particles - mpm::Index nparticles; +std::vector> + mpm::IOMeshAscii::read_particles_scalar_properties( + const std::string& scalar_file) { - // bool to check firstline - bool read_first_line = false; + // Particles scalar properties + std::vector> scalar_properties; + scalar_properties.clear(); // input file stream std::fstream file; - file.open(particles_pressures.c_str(), std::ios::in); + file.open(scalar_file.c_str(), std::ios::in); try { if (file.is_open() && file.good()) { @@ -276,29 +271,24 @@ std::vector mpm::IOMeshAscii::read_particles_pressures( if ((line.find('#') == std::string::npos) && (line.find('!') == std::string::npos) && (line != "")) { while (istream.good()) { - if (!read_first_line) { - // Read number of nodes and cells - istream >> nparticles; - pressures.reserve(nparticles); - read_first_line = true; - break; - } - // Pressure - double pressure; - // Read to pressure - istream >> pressure; - pressures.emplace_back(pressure); - break; + // ID + mpm::Index id; + // Scalar + double scalar; + // Read stream + istream >> id >> scalar; + scalar_properties.emplace_back(std::make_tuple(id, scalar)); } } } + file.close(); } - file.close(); } catch (std::exception& exception) { - console_->error("Read particle pressure: {}", exception.what()); + console_->error("Read particle {} #{}: {}\n", __FILE__, __LINE__, + exception.what()); file.close(); } - return pressures; + return scalar_properties; } //! Read pressure constraints file diff --git a/include/mesh.h b/include/mesh.h index a94b600ff..9e34fc3d5 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -450,7 +450,8 @@ class Mesh { //! Assign particles pore pressures //! \param[in] particle_pore_pressure Initial pore pressure of particle bool assign_particles_pore_pressures( - const std::vector& particle_pore_pressures); + const std::vector>& + particle_pore_pressures); private: // Read particles from file diff --git a/include/mesh.tcc b/include/mesh.tcc index 19cc51129..bc984ba74 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1895,7 +1895,8 @@ void mpm::Mesh::initialise_nodal_properties() { //! Assign particle pore pressures template bool mpm::Mesh::assign_particles_pore_pressures( - const std::vector& particle_pore_pressure) { + const std::vector>& + particle_pore_pressures) { bool status = true; try { @@ -1904,15 +1905,14 @@ bool mpm::Mesh::assign_particles_pore_pressures( "No particles have been assigned in mesh, cannot assign pore " "pressures"); - if (particles_.size() != particle_pore_pressure.size()) - throw std::runtime_error( - "Number of particles in mesh and initial pore pressures don't " - "match"); + for (const auto& particle_pore_pressure : particle_pore_pressures) { + // Particle id + mpm::Index pid = std::get<0>(particle_pore_pressure); + // Pore pressure + double pore_pressure = std::get<1>(particle_pore_pressure); - unsigned i = 0; - for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { - (*pitr)->initial_pore_pressure(particle_pore_pressure.at(i)); - ++i; + if (map_particles_.find(pid) != map_particles_.end()) + map_particles_[pid]->assign_pore_pressure(pore_pressure); } } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); diff --git a/include/node.h b/include/node.h index 8be964b0c..bedd57d8b 100644 --- a/include/node.h +++ b/include/node.h @@ -272,18 +272,13 @@ class Node : public NodeBase { void update_drag_force_coefficient(bool update, const VectorDim& drag_force) override; - //! Return drag force at a given node - VectorDim drag_force_coefficient() const override { - return drag_force_coefficient_; - } - //! Compute acceleration and velocity for two phase //! \param[in] dt Timestep in analysis bool compute_acceleration_velocity_twophase_explicit( double dt) noexcept override; //! Compute acceleration and velocity for two phase with cundall damping - //! factor \param[in] dt Timestep in analysis \param[in] damping_factor + //! \param[in] dt Timestep in analysis \param[in] damping_factor //! Damping factor bool compute_acceleration_velocity_twophase_explicit_cundall( double dt, double damping_factor) noexcept override; @@ -295,6 +290,11 @@ class Node : public NodeBase { bool assign_pressure_constraint( const unsigned phase, const double pressure, const std::shared_ptr& function) override; + + //! Return drag force at a given node + VectorDim drag_force_coefficient() const override { + return drag_force_coefficient_; + } //---------------------------------------------------------------------------- private: @@ -362,5 +362,6 @@ class Node : public NodeBase { } // namespace mpm #include "node.tcc" +#include "twophase_node.tcc" #endif // MPM_NODE_H_ diff --git a/include/node.tcc b/include/node.tcc index e359a5e4c..45da13e2c 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -651,166 +651,4 @@ void mpm::Node -void mpm::Node::update_drag_force_coefficient( - bool update, const Eigen::Matrix& drag_force_coefficient) { - - // Decide to update or assign - const double factor = (update == true) ? 1. : 0.; - - // Update/assign drag force coefficient - node_mutex_.lock(); - drag_force_coefficient_ = - drag_force_coefficient_ * factor + drag_force_coefficient; - node_mutex_.unlock(); -} - -//! Compute acceleration and velocity for two phase -template -bool mpm::Node:: - compute_acceleration_velocity_twophase_explicit(double dt) noexcept { - bool status = false; - const double tolerance = 1.0E-15; - if (this->mass(mpm::NodePhase::nSolid) > tolerance && - this->mass(mpm::NodePhase::nLiquid) > tolerance) { - // Compute drag force - VectorDim drag_force = drag_force_coefficient_.cwiseProduct( - velocity_.col(mpm::NodePhase::nLiquid) - - velocity_.col(mpm::NodePhase::nSolid)); - - // Acceleration of pore fluid (momentume balance of fluid phase) - this->acceleration_.col(mpm::NodePhase::nLiquid) = - (this->external_force_.col(mpm::NodePhase::nLiquid) + - this->internal_force_.col(mpm::NodePhase::nLiquid) - drag_force) / - this->mass_(mpm::NodePhase::nLiquid); - - // Acceleration of solid skeleton (momentume balance of mixture) - this->acceleration_.col(mpm::NodePhase::nSolid) = - (this->external_force_.col(mpm::NodePhase::nMixture) + - this->internal_force_.col(mpm::NodePhase::nMixture) - - this->mass_(mpm::NodePhase::nLiquid) * - this->acceleration_.col(mpm::NodePhase::nLiquid)) / - this->mass_(mpm::NodePhase::nSolid); - - // Apply friction constraints - this->apply_friction_constraints(dt); - - // Velocity += acceleration * dt - this->velocity_ += this->acceleration_ * 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(mpm::NodePhase::nSolid)(i)) < tolerance) - velocity_.col(mpm::NodePhase::nSolid)(i) = 0.; - if (std::abs(acceleration_.col(mpm::NodePhase::nSolid)(i)) < tolerance) - acceleration_.col(mpm::NodePhase::nSolid)(i) = 0.; - if (std::abs(velocity_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) - velocity_.col(mpm::NodePhase::nLiquid)(i) = 0.; - if (std::abs(acceleration_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) - acceleration_.col(mpm::NodePhase::nLiquid)(i) = 0.; - } - status = true; - } - return status; -} - -//! Compute acceleration and velocity for two phase with damping -template -bool mpm::Node:: - compute_acceleration_velocity_twophase_explicit_cundall( - double dt, double damping_factor) noexcept { - bool status = false; - const double tolerance = 1.0E-15; - - if (this->mass(mpm::NodePhase::nSolid) > tolerance && - this->mass(mpm::NodePhase::nLiquid) > tolerance) { - // Compute drag force - VectorDim drag_force = drag_force_coefficient_.cwiseProduct( - velocity_.col(mpm::NodePhase::nLiquid) - - velocity_.col(mpm::NodePhase::nSolid)); - - // Unbalanced force of liquid phase - auto unbalanced_force_liquid = - this->external_force(mpm::NodePhase::nLiquid) + - this->internal_force(mpm::NodePhase::nLiquid) - drag_force; - // Acceleration of liquid phase (momentume balance of fluid phase) - this->acceleration_.col(mpm::NodePhase::nLiquid) = - (unbalanced_force_liquid - - damping_factor * unbalanced_force_liquid.norm() * - this->velocity_.col(mpm::NodePhase::nLiquid).cwiseSign()) / - this->mass(mpm::NodePhase::nLiquid); - - // Unbalanced force of solid phase - auto unbalanced_force_solid = - this->external_force(mpm::NodePhase::nMixture) + - this->internal_force(mpm::NodePhase::nMixture) - - this->mass(mpm::NodePhase::nLiquid) * - this->acceleration(mpm::NodePhase::nLiquid); - // Acceleration of solid phase (momentume balance of mixture) - this->acceleration_.col(mpm::NodePhase::nSolid) = - (unbalanced_force_solid - - damping_factor * unbalanced_force_solid.norm() * - this->velocity_.col(mpm::NodePhase::nSolid).cwiseSign()) / - this->mass(mpm::NodePhase::nSolid); - - // Apply friction constraints - this->apply_friction_constraints(dt); - - // Velocity += acceleration * dt - this->velocity_ += this->acceleration_ * 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(mpm::NodePhase::nSolid)(i)) < tolerance) - velocity_.col(mpm::NodePhase::nSolid)(i) = 0.; - if (std::abs(acceleration_.col(mpm::NodePhase::nSolid)(i)) < tolerance) - acceleration_.col(mpm::NodePhase::nSolid)(i) = 0.; - if (std::abs(velocity_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) - velocity_.col(mpm::NodePhase::nLiquid)(i) = 0.; - if (std::abs(acceleration_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) - acceleration_.col(mpm::NodePhase::nLiquid)(i) = 0.; - } - status = true; - } - return status; -} - -//! Assign pressure constraint -template -bool mpm::Node::assign_pressure_constraint( - const unsigned phase, const double pressure, - const std::shared_ptr& function) { - bool status = true; - try { - // Constrain directions can take values between 0 and Tnphases - if (phase < Tnphases * 2) { - 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; -} -//---------------------------------------------------------------------------- \ No newline at end of file +} \ No newline at end of file diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 7ef799023..afd793073 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -302,11 +302,11 @@ class ParticleBase { return false; }; - //! Initial pore pressure - virtual void initial_pore_pressure(double pore_pressure) { + //! Assign pore pressure + virtual void assign_pore_pressure(double pore_pressure) { throw std::runtime_error( "Calling the base class function " - "(initial_pore_pressure) in " + "(assign_pore_pressure) in " "ParticleBase:: illegal operation!"); }; diff --git a/include/particles/twophase_particle.h b/include/particles/twophase_particle.h index e7b514a5f..ca94b87d1 100644 --- a/include/particles/twophase_particle.h +++ b/include/particles/twophase_particle.h @@ -99,9 +99,9 @@ class TwoPhaseParticle : public mpm::Particle { //! Map drag force coefficient bool map_drag_force_coefficient() override; - //! Initial pore pressure + //! Assign pore pressure //! \param[in] pore pressure Initial pore pressure - void initial_pore_pressure(double pore_pressure) override { + void assign_pore_pressure(double pore_pressure) override { this->pore_pressure_ = pore_pressure; } diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index a7625295e..9aa43d237 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -316,11 +316,12 @@ bool mpm::MPMBase::initialise_particles() { this->particles_pore_pressures(mesh_props, particle_io); auto particles_volume_end = std::chrono::steady_clock::now(); - console_->info("Rank {} Read volume, velocity and stresses: {} ms", - mpi_rank, - std::chrono::duration_cast( - particles_volume_end - particles_volume_begin) - .count()); + console_->info( + "Rank {} Read volume, velocity stresses and pore pressure: {} ms", + mpi_rank, + std::chrono::duration_cast( + particles_volume_end - particles_volume_begin) + .count()); // Particle entity sets auto particles_sets_begin = std::chrono::steady_clock::now(); @@ -1132,28 +1133,24 @@ void mpm::MPMBase::particles_pore_pressures( const std::shared_ptr>& particle_io) { try { if (mesh_props.find("particles_pore_pressures") != mesh_props.end()) { + // Get generator type + const std::string type = mesh_props["particles_pore_pressures"]["type"] + .template get(); // Assign initial pore pressure by file - if (mesh_props["particles_pore_pressures"].find("file") != - mesh_props["particles_pore_pressures"].end()) { + if (type == "file") { std::string fparticles_pore_pressures = - mesh_props["particles_pore_pressures"]["file"] + mesh_props["particles_pore_pressures"]["location"] .template get(); if (!io_->file_name(fparticles_pore_pressures).empty()) { - - // Get pore pressures of all particles - const auto all_particles_pore_pressures = - particle_io->read_particles_pressures( - io_->file_name(fparticles_pore_pressures)); - // Read and assign particles pore pressures if (!mesh_->assign_particles_pore_pressures( - all_particles_pore_pressures)) + particle_io->read_particles_scalar_properties( + io_->file_name(fparticles_pore_pressures)))) throw std::runtime_error( "Particles pore pressures are not properly assigned"); } else throw std::runtime_error("Particle pore pressures JSON not found"); - - } else { + } else if (type == "water_table") { // Initialise water tables std::map refernece_points; // Vertical direction @@ -1177,7 +1174,10 @@ void mpm::MPMBase::particles_pore_pressures( mesh_->iterate_over_particles(std::bind( &mpm::ParticleBase::initialise_pore_pressure_watertable, std::placeholders::_1, dir_v, dir_h, refernece_points)); - } + } else + throw std::runtime_error( + "Particle pore pressures generator type is not properly " + "specified"); } } catch (std::exception& exception) { console_->warn("#{}: Particle pore pressures are undefined {} ", __LINE__, diff --git a/include/twophase_node.tcc b/include/twophase_node.tcc new file mode 100644 index 000000000..147e23ef3 --- /dev/null +++ b/include/twophase_node.tcc @@ -0,0 +1,159 @@ +//! Update drag force coefficient +template +void mpm::Node::update_drag_force_coefficient( + bool update, const Eigen::Matrix& drag_force_coefficient) { + + // Decide to update or assign + const double factor = (update == true) ? 1. : 0.; + + // Update/assign drag force coefficient + node_mutex_.lock(); + drag_force_coefficient_ = + drag_force_coefficient_ * factor + drag_force_coefficient; + node_mutex_.unlock(); +} + +//! Compute acceleration and velocity for two phase +template +bool mpm::Node:: + compute_acceleration_velocity_twophase_explicit(double dt) noexcept { + bool status = false; + const double tolerance = 1.0E-15; + if (this->mass(mpm::NodePhase::nSolid) > tolerance && + this->mass(mpm::NodePhase::nLiquid) > tolerance) { + // Compute drag force + VectorDim drag_force = drag_force_coefficient_.cwiseProduct( + velocity_.col(mpm::NodePhase::nLiquid) - + velocity_.col(mpm::NodePhase::nSolid)); + + // Acceleration of pore fluid (momentume balance of fluid phase) + this->acceleration_.col(mpm::NodePhase::nLiquid) = + (this->external_force_.col(mpm::NodePhase::nLiquid) + + this->internal_force_.col(mpm::NodePhase::nLiquid) - drag_force) / + this->mass_(mpm::NodePhase::nLiquid); + + // Acceleration of solid skeleton (momentume balance of mixture) + this->acceleration_.col(mpm::NodePhase::nSolid) = + (this->external_force_.col(mpm::NodePhase::nMixture) + + this->internal_force_.col(mpm::NodePhase::nMixture) - + this->mass_(mpm::NodePhase::nLiquid) * + this->acceleration_.col(mpm::NodePhase::nLiquid)) / + this->mass_(mpm::NodePhase::nSolid); + + // Apply friction constraints + this->apply_friction_constraints(dt); + + // Velocity += acceleration * dt + this->velocity_ += this->acceleration_ * 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(mpm::NodePhase::nSolid)(i)) < tolerance) + velocity_.col(mpm::NodePhase::nSolid)(i) = 0.; + if (std::abs(acceleration_.col(mpm::NodePhase::nSolid)(i)) < tolerance) + acceleration_.col(mpm::NodePhase::nSolid)(i) = 0.; + if (std::abs(velocity_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) + velocity_.col(mpm::NodePhase::nLiquid)(i) = 0.; + if (std::abs(acceleration_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) + acceleration_.col(mpm::NodePhase::nLiquid)(i) = 0.; + } + status = true; + } + return status; +} + +//! Compute acceleration and velocity for two phase with damping +template +bool mpm::Node:: + compute_acceleration_velocity_twophase_explicit_cundall( + double dt, double damping_factor) noexcept { + bool status = false; + const double tolerance = 1.0E-15; + + if (this->mass(mpm::NodePhase::nSolid) > tolerance && + this->mass(mpm::NodePhase::nLiquid) > tolerance) { + // Compute drag force + VectorDim drag_force = drag_force_coefficient_.cwiseProduct( + velocity_.col(mpm::NodePhase::nLiquid) - + velocity_.col(mpm::NodePhase::nSolid)); + + // Unbalanced force of liquid phase + auto unbalanced_force_liquid = + this->external_force(mpm::NodePhase::nLiquid) + + this->internal_force(mpm::NodePhase::nLiquid) - drag_force; + // Acceleration of liquid phase (momentume balance of fluid phase) + this->acceleration_.col(mpm::NodePhase::nLiquid) = + (unbalanced_force_liquid - + damping_factor * unbalanced_force_liquid.norm() * + this->velocity_.col(mpm::NodePhase::nLiquid).cwiseSign()) / + this->mass(mpm::NodePhase::nLiquid); + + // Unbalanced force of solid phase + auto unbalanced_force_solid = + this->external_force(mpm::NodePhase::nMixture) + + this->internal_force(mpm::NodePhase::nMixture) - + this->mass(mpm::NodePhase::nLiquid) * + this->acceleration(mpm::NodePhase::nLiquid); + // Acceleration of solid phase (momentume balance of mixture) + this->acceleration_.col(mpm::NodePhase::nSolid) = + (unbalanced_force_solid - + damping_factor * unbalanced_force_solid.norm() * + this->velocity_.col(mpm::NodePhase::nSolid).cwiseSign()) / + this->mass(mpm::NodePhase::nSolid); + + // Apply friction constraints + this->apply_friction_constraints(dt); + + // Velocity += acceleration * dt + this->velocity_ += this->acceleration_ * 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(mpm::NodePhase::nSolid)(i)) < tolerance) + velocity_.col(mpm::NodePhase::nSolid)(i) = 0.; + if (std::abs(acceleration_.col(mpm::NodePhase::nSolid)(i)) < tolerance) + acceleration_.col(mpm::NodePhase::nSolid)(i) = 0.; + if (std::abs(velocity_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) + velocity_.col(mpm::NodePhase::nLiquid)(i) = 0.; + if (std::abs(acceleration_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) + acceleration_.col(mpm::NodePhase::nLiquid)(i) = 0.; + } + status = true; + } + return status; +} + +//! Assign pressure constraint +template +bool mpm::Node::assign_pressure_constraint( + const unsigned phase, const double pressure, + const std::shared_ptr& function) { + bool status = true; + try { + // Constrain directions can take values between 0 and Tnphases + if (phase < Tnphases * 2) { + 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; +} \ No newline at end of file diff --git a/src/node.cc b/src/node.cc index fda6589bc..ea93ebb86 100644 --- a/src/node.cc +++ b/src/node.cc @@ -15,9 +15,9 @@ static Register, mpm::Node<3, 3, 1>, mpm::Index, // Node2D (2 DoF, 2 Phase) static Register, mpm::Node<2, 2, 2>, mpm::Index, const Eigen::Matrix&> - node2d2phase("N2D2PHASE"); + node2d2phase("N2D2P"); // Node3D (3 DoF, 2 Phase) static Register, mpm::Node<3, 3, 2>, mpm::Index, const Eigen::Matrix&> - node3d2phase("N3D2PHASE"); \ No newline at end of file + node3d2phase("N3D2P"); \ No newline at end of file diff --git a/tests/twophase_particle_test.cc b/tests/twophase_particle_test.cc index 7a1acea71..95a98b320 100644 --- a/tests/twophase_particle_test.cc +++ b/tests/twophase_particle_test.cc @@ -125,7 +125,7 @@ TEST_CASE("TwoPhase Particle is checked for 1D case", REQUIRE(pstress_data[i] == Approx(stress[i]).epsilon(Tolerance)); //! Test initialise particle pore pressure double pore_pressure = 100000; - particle->initial_pore_pressure(pore_pressure); + particle->assign_pore_pressure(pore_pressure); REQUIRE(particle->pore_pressure() == pore_pressure); } @@ -603,7 +603,7 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", REQUIRE(pstress[i] == Approx(stress[i]).epsilon(Tolerance)); //! Test initialise particle pore pressure double pore_pressure = 100000; - particle->initial_pore_pressure(pore_pressure); + particle->assign_pore_pressure(pore_pressure); REQUIRE(particle->pore_pressure() == pore_pressure); } @@ -1888,7 +1888,7 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", REQUIRE(pstress[i] == Approx(stress[i]).epsilon(Tolerance)); //! Test initialise particle pore pressure double pore_pressure = 100000; - particle->initial_pore_pressure(pore_pressure); + particle->assign_pore_pressure(pore_pressure); REQUIRE(particle->pore_pressure() == pore_pressure); } From 6b1a3ce0083ef06dfb306bc59f5af33bc1ef00b9 Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Fri, 31 Jul 2020 22:58:44 -0700 Subject: [PATCH 075/175] Fix the bug in reading pore pressure constraints --- include/loads_bcs/constraints.tcc | 2 +- include/solvers/mpm_base.tcc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/loads_bcs/constraints.tcc b/include/loads_bcs/constraints.tcc index d8bf667e2..cb2d960f2 100644 --- a/include/loads_bcs/constraints.tcc +++ b/include/loads_bcs/constraints.tcc @@ -135,7 +135,7 @@ template bool mpm::Constraints::assign_nodal_pressure_constraints( const unsigned phase, const std::vector>& pressure_constraints) { - bool status = false; + bool status = true; try { for (const auto& pressure_constraint : pressure_constraints) { // Node id diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index 9aa43d237..7a48ac1c8 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -978,7 +978,7 @@ void mpm::MPMBase::nodal_pore_pressure_constraints( throw std::runtime_error("Pore pressure constraints JSON not found"); } catch (std::exception& exception) { - console_->warn("#{}: Pore pressure conditions are undefined {} ", __LINE__, + console_->warn("#{}: Pore pressure constraints are undefined {} ", __LINE__, exception.what()); } } From a015f4f146f8776db98092d17434657e17adf598 Mon Sep 17 00:00:00 2001 From: Nanda Date: Sat, 1 Aug 2020 13:13:15 -0700 Subject: [PATCH 076/175] :construction: add free_surface detection --- CMakeLists.txt | 1 + include/cell.h | 26 ++ include/cell.tcc | 22 +- include/mesh.h | 44 +++ include/mesh.tcc | 390 ++++++++++++++++++++++ include/node.h | 19 ++ include/node.tcc | 20 ++ include/node_base.h | 13 + include/particles/particle.h | 32 ++ include/particles/particle.tcc | 27 ++ include/particles/particle_base.h | 19 ++ include/particles/twophase_particle.tcc | 9 +- include/solvers/mpm_explicit_twophase.h | 2 + include/solvers/mpm_explicit_twophase.tcc | 24 ++ include/utilities/radial_basis_function.h | 308 +++++++++++++++++ 15 files changed, 951 insertions(+), 5 deletions(-) create mode 100644 include/utilities/radial_basis_function.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a2703295..746b9af95 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -142,6 +142,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/cell.h b/include/cell.h index 2380b7d3d..ddee2e5ac 100644 --- a/include/cell.h +++ b/include/cell.h @@ -217,6 +217,28 @@ class Cell { //! Return previous mpi rank unsigned previous_mpirank() 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 + //! \param[in] 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 @@ -264,6 +286,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 05f839dab..c5ebc3381 100644 --- a/include/cell.tcc +++ b/include/cell.tcc @@ -412,7 +412,7 @@ inline Eigen::Matrix mpm::Cell<2>::local_coordinates_point( if (indices.size() == 3) { // 2 0 // |\ - // | \ + // | \ // c | \ b // | \ // | \ @@ -844,3 +844,23 @@ template inline unsigned mpm::Cell::previous_mpirank() const { return this->previous_mpirank_; } + +//! 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 9e34fc3d5..ca330d0be 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -40,6 +40,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" @@ -249,6 +250,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 @@ -441,6 +448,43 @@ class Mesh { //! Inject particles 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( + 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(); + + //! Get free surface cell set + std::set free_surface_cells(); + + //! Get free surface particle set + std::set free_surface_particles(); + // Create the nodal properties' map void create_nodal_properties(); diff --git a/include/mesh.tcc b/include/mesh.tcc index bc984ba74..19eae2bbe 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1022,6 +1022,16 @@ void mpm::Mesh::iterate_over_particles(Toper oper) { oper(*pitr); } +//! Iterate over particles +template +template +void mpm::Mesh::iterate_over_particles_predicate(Toper oper, Tpred pred) { +#pragma omp parallel for schedule(runtime) + for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { + if (pred(*pitr)) oper(*pitr); + } +} + //! Iterate over particle set template template @@ -1885,6 +1895,386 @@ void mpm::Mesh::create_nodal_properties() { } } +//! Compute free surface cells, nodes, and particles +template +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 + 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)); + + // 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(); + ++citr) { + // Cell contains particles + if ((*citr)->status()) { + bool candidate_cell = false; + const auto& node_id = (*citr)->nodes_id(); + if ((*citr)->volume_fraction() < volume_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); + } + } + } + } + } + + // Assign free surface cell + if (candidate_cell) { + (*citr)->assign_free_surface(true); + free_surface_candidate_cells.insert((*citr)->id()); + } + } + } + + // Compute particle neighbours for particles at candidate cells + std::vector free_surface_candidate_particles_first; + 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_first.insert( + free_surface_candidate_particles_first.end(), particle_ids.begin(), + 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_first) { + const auto& particle = map_particles_[p_id]; + status = particle->compute_free_surface_by_density(); + if (status) free_surface_candidate_particles_second.insert(p_id); + } + + // Find free surface particles through geometry + for (const auto p_id : free_surface_candidate_particles_second) { + // Initialize renormalization matrix + Eigen::Matrix renormalization_matrix_inv; + renormalization_matrix_inv.setZero(); + + // Loop over neighbours + 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 VectorDim kernel_gradient = + mpm::RadialBasisFunction::gradient(smoothing_length, + -rel_coord, "gaussian"); + + // Inverse of renormalization matrix B + renormalization_matrix_inv += + (particle->mass() / particle->mass_density()) * kernel_gradient * + rel_coord.transpose(); + } + + // 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 = true; + else if (lambda > 0.2 && lambda <= 0.75) + secondary_check = true; + else + interior = true; + + // Compute numerical normal vector + VectorDim normal; + normal.setZero(); + if (!interior) { + 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; + + // Compute kernel gradient + 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 = -renormalization_matrix_inv.inverse() * temporary_vec; + if (normal.norm() > std::numeric_limits::epsilon()) + normal.normalize(); + else + normal.setZero(); + } + + // 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) { + particle->assign_free_surface(true); + particle->assign_normal(normal); + } + } + } 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 + 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); + } + } 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); + } + } + } + } + } + + // Assign free surface cell + if (cell_at_interface) + (*citr)->assign_free_surface(cell_at_interface); + } + } + } + + // 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 + 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); + } + } + + } 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; +} + // Initialise the nodal properties' map template void mpm::Mesh::initialise_nodal_properties() { diff --git a/include/node.h b/include/node.h index bedd57d8b..258ed6516 100644 --- a/include/node.h +++ b/include/node.h @@ -245,6 +245,21 @@ class Node : public NodeBase { //! Set ghost id void ghost_id(Index gid) override { ghost_id_ = gid; } + //! 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; + + //! 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_; } + //! Update nodal property at the nodes from particle //! \param[in] update A boolean to update (true) or assign (false) //! \param[in] property Property name @@ -358,6 +373,10 @@ class Node : public NodeBase { std::unique_ptr console_; //! MPI ranks std::set mpi_ranks_; + //! Interpolated density + Eigen::Matrix density_; + //! Free surface + bool free_surface_{false}; }; // Node class } // namespace mpm diff --git a/include/node.tcc b/include/node.tcc index 45da13e2c..53e66d3d0 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -32,6 +32,7 @@ void mpm::Node::initialise() noexcept { velocity_.setZero(); momentum_.setZero(); acceleration_.setZero(); + free_surface_ = false; status_ = false; material_ids_.clear(); // Specific variables for two phase @@ -558,6 +559,25 @@ bool mpm::Node::mpi_rank(unsigned rank) { return status.second; } +//! Compute mass density (Z. Wiezckowski, 2004) +//! density = mass / lumped volume +template +void mpm::Node::compute_density() { + 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"); + } +} + //! Update nodal property at the nodes from particle template void mpm::Node::update_property( diff --git a/include/node_base.h b/include/node_base.h index 48e41c783..20c3fff6d 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -270,6 +270,19 @@ class NodeBase { //! Set ghost id virtual void ghost_id(Index gid) = 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; + + //! Assign free surface + virtual void assign_free_surface(bool free_surface) = 0; + + //! Return free surface bool + virtual bool free_surface() = 0; + //! Update nodal property at the nodes from particle //! \param[in] update A boolean to update (true) or assign (false) //! \param[in] property Property name diff --git a/include/particles/particle.h b/include/particles/particle.h index 2156ad54c..b423a6193 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -111,6 +111,14 @@ class Particle : public ParticleBase { //! Return volume double volume() const override { return volume_; } + //! Return the approximate particle diameter + double diameter() const override { + 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 VectorDim natural_size() const override { return natural_size_; } @@ -294,6 +302,26 @@ 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 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; }; + + //! Return normal vector + VectorDim normal() override { return normal_; }; + //! Return the number of neighbour particles unsigned nneighbours() const override { return neighbours_.size(); }; @@ -372,6 +400,10 @@ class Particle : public ParticleBase { Eigen::Matrix displacement_; //! Particle velocity constraints std::map particle_velocity_constraints_; + //! Free surface + bool free_surface_{false}; + //! Free surface + Eigen::Matrix normal_; //! Set traction bool set_traction_{false}; //! Surface Traction (given as a stress; force/area) diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index c3d945b69..31b316eea 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -240,6 +240,7 @@ void mpm::Particle::initialise() { stress_.setZero(); traction_.setZero(); velocity_.setZero(); + normal_.setZero(); volume_ = std::numeric_limits::max(); volumetric_strain_centroid_ = 0.; @@ -248,6 +249,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(); }; } //! Initialise particle material container @@ -839,6 +841,10 @@ bool mpm::Particle::compute_pressure_smoothing(unsigned phase) noexcept { pressure += shapefn_[i] * nodes_[i]->pressure(phase); state_variables_[phase]["pressure"] = pressure; + + // If free_surface particle, overwrite pressure to zero + if (free_surface_) state_variables_[phase]["pressure"] = 0.0; + status = true; } return status; @@ -865,6 +871,27 @@ void mpm::Particle::append_material_id_to_nodes() const { nodes_[i]->append_material_id(this->material_id()); } +//! Compute free surface in particle level by density ratio comparison +template +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) { + // 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_) <= density_ratio_tolerance) + status = true; + } + 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 afd793073..2f09570b9 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -118,6 +118,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; @@ -281,6 +284,22 @@ 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 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; + + //! Return normal vector + virtual VectorDim normal() = 0; + //! Return the number of neighbour particles virtual unsigned nneighbours() const = 0; diff --git a/include/particles/twophase_particle.tcc b/include/particles/twophase_particle.tcc index 536645503..777f32e8e 100644 --- a/include/particles/twophase_particle.tcc +++ b/include/particles/twophase_particle.tcc @@ -109,9 +109,6 @@ void mpm::TwoPhaseParticle::initialise() { this->properties_["pore_pressure"] = [&]() { Eigen::VectorXd vec_pressure = Eigen::VectorXd::Zero(3); vec_pressure[0] = this->pore_pressure(); - // FIXME: This is to check free surface particles - // TODO: To be removed somewhere - // vec_pressure[1] = this->free_surface(); return vec_pressure; }; } @@ -221,7 +218,7 @@ void mpm::TwoPhaseParticle::compute_pore_pressure(double dt) noexcept { porosity_ * liquid_strain_rate_centroid.head(Tdim).sum()); // Apply free surface - // if (this->free_surface()) this->pore_pressure_ = 0.0; + if (this->free_surface()) this->pore_pressure_ = 0.0; } //! Map body force for both mixture and liquid @@ -495,6 +492,10 @@ bool mpm::TwoPhaseParticle::compute_pressure_smoothing( pressure += shapefn_[i] * nodes_[i]->pressure(phase); this->pore_pressure_ = pressure; + + // Apply free surface + if (this->free_surface()) this->pore_pressure_ = 0.0; + status = true; } return status; diff --git a/include/solvers/mpm_explicit_twophase.h b/include/solvers/mpm_explicit_twophase.h index 1706ee852..5e3c1413d 100644 --- a/include/solvers/mpm_explicit_twophase.h +++ b/include/solvers/mpm_explicit_twophase.h @@ -76,6 +76,8 @@ class MPMExplicitTwoPhase : public MPMBase { bool pore_pressure_smoothing_{false}; //! Volume tolerance for free surface double volume_tolerance_{0}; + //! Free surface detection type + std::string free_surface_detection_; }; // MPMExplicit class } // namespace mpm diff --git a/include/solvers/mpm_explicit_twophase.tcc b/include/solvers/mpm_explicit_twophase.tcc index 9df215857..dad6a5a38 100644 --- a/include/solvers/mpm_explicit_twophase.tcc +++ b/include/solvers/mpm_explicit_twophase.tcc @@ -68,6 +68,12 @@ bool mpm::MPMExplicitTwoPhase::solve() { pore_pressure_smoothing_ = analysis_.at("pore_pressure_smoothing").template get(); + // 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(); + // Initialise material bool mat_status = this->initialise_materials(); if (!mat_status) { @@ -191,6 +197,24 @@ bool mpm::MPMExplicitTwoPhase::solve() { } #endif + // TODO: Parallel free-surface computation is not yet implemented + // Compute free surface cells, nodes, and particles + mesh_->compute_free_surface(free_surface_detection_, volume_tolerance_); + + // 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::assign_pressure, + std::placeholders::_1, 0.0, mpm::ParticlePhase::Liquid), + 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( std::bind(&mpm::NodeBase::compute_velocity, diff --git a/include/utilities/radial_basis_function.h b/include/utilities/radial_basis_function.h new file mode 100644 index 000000000..d872a2097 --- /dev/null +++ b/include/utilities/radial_basis_function.h @@ -0,0 +1,308 @@ +#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; +} + +//! 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) { + + // 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.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.0 * 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; +} + +//! 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(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; +} + +//! 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(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 *= 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, + const std::string type = "cubic_spline") { + 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(smoothing_length, + norm_distance); + } else if (type == "super_gaussian") { + return mpm::RadialBasisFunction::super_gaussian(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\"."); + } +} + +//! General Radial Basis Function Kernel call +template +Eigen::Matrix gradient( + const double smoothing_length, + const Eigen::Matrix& relative_distance, + const std::string type = "cubic_spline") { + + // 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 +#endif \ No newline at end of file From 9fe7d02d81e1e4228218ca2de91a95798d49cff5 Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Sat, 1 Aug 2020 14:36:17 -0700 Subject: [PATCH 077/175] Move pore pressure into state_variables --- include/particles/particle.h | 7 +- include/particles/particle.tcc | 18 ++++ include/particles/particle_base.h | 2 +- include/particles/twophase_particle.h | 14 +-- include/particles/twophase_particle.tcc | 131 ++++++++++-------------- 5 files changed, 81 insertions(+), 91 deletions(-) diff --git a/include/particles/particle.h b/include/particles/particle.h index b423a6193..dabfaec46 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -246,12 +246,9 @@ class Particle : public ParticleBase { //! \param[in] var State variable //! \param[in] value State variable to be assigned //! \param[in] phase Index to indicate phase - void assign_state_variable( + bool 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; - } + unsigned phase = mpm::ParticlePhase::Solid) override; //! Return a state variable //! \param[in] var State variable diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index 31b316eea..911e24c18 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -283,6 +283,24 @@ bool mpm::Particle::assign_material_state_vars( return status; } +//! Assign a state variable +template +bool mpm::Particle::assign_state_variable(const std::string& var, + double value, unsigned phase) { + bool status = true; + try { + if (state_variables_[phase].find(var) != state_variables_[phase].end()) + state_variables_[phase].at(var) = value; + else { + throw std::runtime_error(var + "cannot be found in state variables!"); + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + // Assign a cell to particle template bool mpm::Particle::assign_cell( diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 2f09570b9..cf82da22b 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -179,7 +179,7 @@ class ParticleBase { } //! Assign a state variable - virtual void assign_state_variable( + virtual bool assign_state_variable( const std::string& var, double value, unsigned phase = mpm::ParticlePhase::Solid) = 0; diff --git a/include/particles/twophase_particle.h b/include/particles/twophase_particle.h index ca94b87d1..2117543f6 100644 --- a/include/particles/twophase_particle.h +++ b/include/particles/twophase_particle.h @@ -102,7 +102,8 @@ class TwoPhaseParticle : public mpm::Particle { //! Assign pore pressure //! \param[in] pore pressure Initial pore pressure void assign_pore_pressure(double pore_pressure) override { - this->pore_pressure_ = pore_pressure; + this->assign_state_variable("pressure", pore_pressure, + mpm::ParticlePhase::Liquid); } //! Assign particles initial pore pressure by watertable @@ -125,11 +126,6 @@ class TwoPhaseParticle : public mpm::Particle { bool map_pressure_to_nodes( unsigned phase = mpm::ParticlePhase::Solid) noexcept override; - //! Compute pressure smoothing of the particle based on nodal pressure - //! $$\hat{p}_p = \sum_{i = 1}^{n_n} N_i(x_p) p_i$$ - bool compute_pressure_smoothing( - unsigned phase = mpm::ParticlePhase::Solid) noexcept override; - //! Apply particle velocity constraints //! \param[in] dir Direction of particle velocity constraint //! \param[in] velocity Applied particle velocity constraint @@ -146,7 +142,9 @@ class TwoPhaseParticle : public mpm::Particle { //! Return liquid pore pressure //! \retval pore pressure Pore liquid pressure - double pore_pressure() const override { return pore_pressure_; } + double pore_pressure() const override { + return this->state_variables_[mpm::ParticlePhase::Liquid].at("pressure"); + } //! Reture porosity //! \retval porosity Porosity @@ -233,8 +231,6 @@ class TwoPhaseParticle : public mpm::Particle { Eigen::Matrix liquid_velocity_; //! Pore pressure constraint double pore_pressure_constraint_{std::numeric_limits::max()}; - //! Pore pressure - double pore_pressure_; //! Permeability parameter c1 (k = k_p * c1) VectorDim permeability_; //! Logger diff --git a/include/particles/twophase_particle.tcc b/include/particles/twophase_particle.tcc index 777f32e8e..2a850b8c1 100644 --- a/include/particles/twophase_particle.tcc +++ b/include/particles/twophase_particle.tcc @@ -45,13 +45,27 @@ mpm::HDF5Particle mpm::TwoPhaseParticle::hdf5() const { // // Particle liquid mass // particle_data.liquid_mass = this->liquid_mass_; // Particle pore pressure - particle_data.pressure = this->pore_pressure_; + // particle_data.pressure = this->pore_pressure_; // // Particle liquid velocity // particle_data.liquid_velocity_x = liquid_velocity[0]; // particle_data.liquid_velocity_y = liquid_velocity[1]; // particle_data.liquid_velocity_z = liquid_velocity[2]; // // Particle liquid material id // particle_data.liquid_material_id = this->liquid_material_id_; + if (this->material(mpm::ParticlePhase::Liquid) != nullptr) { + particle_data.nstate_vars = + state_variables_[mpm::ParticlePhase::Liquid].size(); + if (state_variables_[mpm::ParticlePhase::Liquid].size() > 20) + throw std::runtime_error("# of state variables cannot be more than 20"); + unsigned i = 0; + auto state_variables = + (this->material(mpm::ParticlePhase::Liquid))->state_variables(); + for (const auto& state_var : state_variables) { + particle_data.svars[i] = + state_variables_[mpm::ParticlePhase::Liquid].at(state_var); + ++i; + } + } return particle_data; } @@ -101,7 +115,6 @@ void mpm::TwoPhaseParticle::initialise() { mpm::Particle::initialise(); liquid_mass_ = 0.; liquid_velocity_.setZero(); - pore_pressure_ = 0.; liquid_saturation_ = 1.; // Initialize vector data properties @@ -212,13 +225,14 @@ void mpm::TwoPhaseParticle::compute_pore_pressure(double dt) noexcept { this->compute_strain_rate(dn_dx_centroid_, mpm::ParticlePhase::Liquid); // update pressure - this->pore_pressure_ += + this->state_variables_[mpm::ParticlePhase::Liquid].at("pressure") += -dt * (K / porosity_) * ((1 - porosity_) * strain_rate_.head(Tdim).sum() + porosity_ * liquid_strain_rate_centroid.head(Tdim).sum()); // Apply free surface - if (this->free_surface()) this->pore_pressure_ = 0.0; + if (this->free_surface()) + this->assign_state_variable("pressure", 0., mpm::ParticlePhase::Liquid); } //! Map body force for both mixture and liquid @@ -294,7 +308,7 @@ inline void mpm::TwoPhaseParticle<1>::map_liquid_internal_force() noexcept { // initialise a vector of pore pressure Eigen::Matrix pressure; pressure.setZero(); - pressure(0) = -this->pore_pressure_; + pressure(0) = -this->state_variable("pressure", mpm::ParticlePhase::Liquid); // Compute nodal internal forces for (unsigned i = 0; i < nodes_.size(); ++i) { @@ -314,8 +328,8 @@ inline void mpm::TwoPhaseParticle<2>::map_liquid_internal_force() noexcept { // initialise a vector of pore pressure Eigen::Matrix pressure; pressure.setZero(); - pressure(0) = -this->pore_pressure_; - pressure(1) = -this->pore_pressure_; + pressure(0) = -this->state_variable("pressure", mpm::ParticlePhase::Liquid); + pressure(1) = -this->state_variable("pressure", mpm::ParticlePhase::Liquid); // Compute nodal internal forces for (unsigned i = 0; i < nodes_.size(); ++i) { @@ -335,9 +349,9 @@ inline void mpm::TwoPhaseParticle<3>::map_liquid_internal_force() noexcept { // initialise a vector of pore pressure Eigen::Matrix pressure; pressure.setZero(); - pressure(0) = -this->pore_pressure_; - pressure(1) = -this->pore_pressure_; - pressure(2) = -this->pore_pressure_; + pressure(0) = -this->state_variable("pressure", mpm::ParticlePhase::Liquid); + pressure(1) = -this->state_variable("pressure", mpm::ParticlePhase::Liquid); + pressure(2) = -this->state_variable("pressure", mpm::ParticlePhase::Liquid); // Compute nodal internal forces for (unsigned i = 0; i < nodes_.size(); ++i) { @@ -359,7 +373,8 @@ inline void mpm::TwoPhaseParticle<1>::map_mixture_internal_force( unsigned mixture) noexcept { // initialise a vector of pore pressure Eigen::Matrix total_stress = this->stress_; - total_stress(0) -= this->pore_pressure_; + total_stress(0) -= + this->state_variable("pressure", mpm::ParticlePhase::Liquid); // Compute nodal internal forces for (unsigned i = 0; i < nodes_.size(); ++i) { @@ -379,8 +394,10 @@ inline void mpm::TwoPhaseParticle<2>::map_mixture_internal_force( unsigned mixture) noexcept { // initialise a vector of pore pressure Eigen::Matrix total_stress = this->stress_; - total_stress(0) -= this->pore_pressure_; - total_stress(1) -= this->pore_pressure_; + total_stress(0) -= + this->state_variable("pressure", mpm::ParticlePhase::Liquid); + total_stress(1) -= + this->state_variable("pressure", mpm::ParticlePhase::Liquid); // Compute nodal internal forces for (unsigned i = 0; i < nodes_.size(); ++i) { @@ -400,9 +417,12 @@ inline void mpm::TwoPhaseParticle<3>::map_mixture_internal_force( unsigned mixture) noexcept { // initialise a vector of pore pressure Eigen::Matrix total_stress = this->stress_; - total_stress(0) -= this->pore_pressure_; - total_stress(1) -= this->pore_pressure_; - total_stress(2) -= this->pore_pressure_; + total_stress(0) -= + this->state_variable("pressure", mpm::ParticlePhase::Liquid); + total_stress(1) -= + this->state_variable("pressure", mpm::ParticlePhase::Liquid); + total_stress(2) -= + this->state_variable("pressure", mpm::ParticlePhase::Liquid); // Compute nodal internal forces for (unsigned i = 0; i < nodes_.size(); ++i) { @@ -437,64 +457,18 @@ template bool mpm::TwoPhaseParticle::map_pressure_to_nodes( unsigned phase) noexcept { // Mass is initialized - assert(mass_ != std::numeric_limits::max() && - liquid_mass_ != std::numeric_limits::max()); + assert(liquid_mass_ != std::numeric_limits::max()); bool status = false; - if (phase == mpm::ParticlePhase::Solid) { - // Check if particle mass is set and state variable pressure is found - if (mass_ != std::numeric_limits::max() && - (state_variables_[phase].find("pressure") != - state_variables_[phase].end())) { - // Map particle pressure to nodes - for (unsigned i = 0; i < nodes_.size(); ++i) - nodes_[i]->update_mass_pressure( - phase, shapefn_[i] * mass_ * state_variables_[phase]["pressure"]); - - status = true; - } - } else { - // Map particle pore pressure to nodes + // Check if particle liquid mass is set and state variable pressure is found + if (liquid_mass_ != std::numeric_limits::max() && + (state_variables_[phase].find("pressure") != + state_variables_[phase].end())) { + // Map particle pressure to nodes for (unsigned i = 0; i < nodes_.size(); ++i) nodes_[i]->update_mass_pressure( - phase, shapefn_[i] * liquid_mass_ * this->pore_pressure_); - - status = true; - } - return status; -} - -// Compute pressure smoothing of the particle based on nodal pressure -template -bool mpm::TwoPhaseParticle::compute_pressure_smoothing( - unsigned phase) noexcept { - // Assert - assert(cell_ != nullptr); - - bool status = false; - if (phase == mpm::ParticlePhase::Solid) { - // Check if particle has a valid cell ptr - if (cell_ != nullptr && (state_variables_[phase].find("pressure") != - state_variables_[phase].end())) { - - double pressure = 0.; - // Update particle pressure to interpolated nodal pressure - for (unsigned i = 0; i < this->nodes_.size(); ++i) - pressure += shapefn_[i] * nodes_[i]->pressure(phase); - - state_variables_[phase]["pressure"] = pressure; - status = true; - } - } else { - double pressure = 0.; - // Update particle pressure to interpolated nodal pressure - for (unsigned i = 0; i < this->nodes_.size(); ++i) - pressure += shapefn_[i] * nodes_[i]->pressure(phase); - - this->pore_pressure_ = pressure; - - // Apply free surface - if (this->free_surface()) this->pore_pressure_ = 0.0; + phase, + shapefn_[i] * liquid_mass_ * state_variables_[phase]["pressure"]); status = true; } @@ -691,27 +665,32 @@ bool mpm::TwoPhaseParticle::initialise_pore_pressure_watertable( } } + // Initialise pore pressure + double pore_pressure = 0; + if (left_boundary != std::numeric_limits::lowest()) { // Particle with left and right boundary if (right_boundary != std::numeric_limits::max()) { - this->pore_pressure_ = + pore_pressure = ((h0_right - h0_left) / (right_boundary - left_boundary) * (position - left_boundary) + h0_left - this->coordinates_(dir_v)) * 1000 * 9.81; } else // Particle with only left boundary - this->pore_pressure_ = - (h0_left - this->coordinates_(dir_v)) * 1000 * 9.81; + pore_pressure = (h0_left - this->coordinates_(dir_v)) * 1000 * 9.81; + } // Particle with only right boundary else if (right_boundary != std::numeric_limits::max()) - this->pore_pressure_ = - (h0_right - this->coordinates_(dir_v)) * 1000 * 9.81; - + pore_pressure = (h0_right - this->coordinates_(dir_v)) * 1000 * 9.81; else throw std::runtime_error( "Particle pore pressure can not be initialised by water table"); + + // Assign pore pressure + this->assign_state_variable("pressure", pore_pressure, + mpm::ParticlePhase::Liquid); } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); status = false; From 966d51a305d383a9ce4a9bdca787f426ddf2f7ee Mon Sep 17 00:00:00 2001 From: Nanda Date: Sat, 1 Aug 2020 15:22:26 -0700 Subject: [PATCH 078/175] :wrench: modify map_pressure_to_nodes in twophase --- include/particles/twophase_particle.tcc | 27 +++++++++++++++---------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/include/particles/twophase_particle.tcc b/include/particles/twophase_particle.tcc index 2a850b8c1..76d7c8ca8 100644 --- a/include/particles/twophase_particle.tcc +++ b/include/particles/twophase_particle.tcc @@ -460,17 +460,22 @@ bool mpm::TwoPhaseParticle::map_pressure_to_nodes( assert(liquid_mass_ != std::numeric_limits::max()); bool status = false; - // Check if particle liquid mass is set and state variable pressure is found - if (liquid_mass_ != std::numeric_limits::max() && - (state_variables_[phase].find("pressure") != - state_variables_[phase].end())) { - // Map particle pressure to nodes - for (unsigned i = 0; i < nodes_.size(); ++i) - nodes_[i]->update_mass_pressure( - phase, - shapefn_[i] * liquid_mass_ * state_variables_[phase]["pressure"]); - - status = true; + // If phase is Solid, use the default map_pressure_to_nodes + if (phase == mpm::ParticlePhase::Solid) + status = mpm::Particle::map_pressure_to_nodes(phase); + else { + // Check if particle liquid mass is set and state variable pressure is found + if (liquid_mass_ != std::numeric_limits::max() && + (state_variables_[phase].find("pressure") != + state_variables_[phase].end())) { + // Map particle pressure to nodes + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->update_mass_pressure( + phase, + shapefn_[i] * liquid_mass_ * state_variables_[phase]["pressure"]); + + status = true; + } } return status; } From 56bc7769bffdef2b49e6003ce41e8cabbc090711 Mon Sep 17 00:00:00 2001 From: Nanda Date: Sat, 1 Aug 2020 15:23:03 -0700 Subject: [PATCH 079/175] :construction: revert back assign state vars to void, though keeping throw --- include/mesh.h | 4 ++++ include/particles/particle.h | 2 +- include/particles/particle.tcc | 18 +++++------------- include/particles/particle_base.h | 2 +- 4 files changed, 11 insertions(+), 15 deletions(-) diff --git a/include/mesh.h b/include/mesh.h index ca330d0be..c12d6e2c1 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -477,12 +477,16 @@ class Mesh { double volume_tolerance = std::numeric_limits::epsilon()); //! Get free surface node set + //! \retval id_set Set of free surface node ids std::set free_surface_nodes(); //! Get free surface cell set + //! \retval id_set Set of free surface cell ids std::set free_surface_cells(); //! Get free surface particle set + //! \retval status Status of compute_free_surface + //! \retval id_set Set of free surface particle ids std::set free_surface_particles(); // Create the nodal properties' map diff --git a/include/particles/particle.h b/include/particles/particle.h index dabfaec46..5b419396a 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -246,7 +246,7 @@ class Particle : public ParticleBase { //! \param[in] var State variable //! \param[in] value State variable to be assigned //! \param[in] phase Index to indicate phase - bool assign_state_variable( + void assign_state_variable( const std::string& var, double value, unsigned phase = mpm::ParticlePhase::Solid) override; diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index 911e24c18..05afce62a 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -285,20 +285,12 @@ bool mpm::Particle::assign_material_state_vars( //! Assign a state variable template -bool mpm::Particle::assign_state_variable(const std::string& var, +void mpm::Particle::assign_state_variable(const std::string& var, double value, unsigned phase) { - bool status = true; - try { - if (state_variables_[phase].find(var) != state_variables_[phase].end()) - state_variables_[phase].at(var) = value; - else { - throw std::runtime_error(var + "cannot be found in state variables!"); - } - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; - } - return status; + if (state_variables_[phase].find(var) != state_variables_[phase].end()) + state_variables_[phase].at(var) = value; + else + throw std::runtime_error(var + " cannot be found in state variables!"); } // Assign a cell to particle diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index cf82da22b..2f09570b9 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -179,7 +179,7 @@ class ParticleBase { } //! Assign a state variable - virtual bool assign_state_variable( + virtual void assign_state_variable( const std::string& var, double value, unsigned phase = mpm::ParticlePhase::Solid) = 0; From bff49ecf29240e4aef3891a37e56e39a8d666739 Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Sat, 1 Aug 2020 17:45:33 -0700 Subject: [PATCH 080/175] Fix the test --- include/particles/particle.tcc | 7 +++++-- tests/particle_test.cc | 4 ++-- tests/twophase_particle_test.cc | 4 ++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index 05afce62a..fe28add5b 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -289,8 +289,11 @@ void mpm::Particle::assign_state_variable(const std::string& var, double value, unsigned phase) { if (state_variables_[phase].find(var) != state_variables_[phase].end()) state_variables_[phase].at(var) = value; - else - throw std::runtime_error(var + " cannot be found in state variables!"); + else { + state_variables_[phase].insert(std::make_pair(var, value)); + console_->warn(var + + " cannot be found in state variables! Initialise it now"); + } } // Assign a cell to particle diff --git a/tests/particle_test.cc b/tests/particle_test.cc index 1e80c0a7a..729e43184 100644 --- a/tests/particle_test.cc +++ b/tests/particle_test.cc @@ -1145,7 +1145,7 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { 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); + REQUIRE(std::isnan(particle->pressure()) == false); } SECTION("Assign state variables fail on state variables size") { @@ -2403,7 +2403,7 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { 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); + REQUIRE(std::isnan(particle->pressure()) == false); } SECTION("Assign state variables fail on state variables size") { diff --git a/tests/twophase_particle_test.cc b/tests/twophase_particle_test.cc index 95a98b320..b16c9c10c 100644 --- a/tests/twophase_particle_test.cc +++ b/tests/twophase_particle_test.cc @@ -1207,7 +1207,7 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", 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); + REQUIRE(std::isnan(particle->pressure()) == false); } SECTION("Assign state variables fail on state variables size") { @@ -2540,7 +2540,7 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", 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); + REQUIRE(std::isnan(particle->pressure()) == false); } SECTION("Assign state variables fail on state variables size") { From feaa3d1eed90856b4a1d470da37e61c9e78c849a Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Sat, 1 Aug 2020 18:16:01 -0700 Subject: [PATCH 081/175] Remove the assign_pore_pressure --- include/mesh.tcc | 3 ++- include/particles/particle.tcc | 7 ++----- include/particles/particle_base.h | 8 ------- include/particles/twophase_particle.h | 7 ------- tests/particle_test.cc | 6 ++---- tests/twophase_particle_test.cc | 30 +++++++-------------------- 6 files changed, 14 insertions(+), 47 deletions(-) diff --git a/include/mesh.tcc b/include/mesh.tcc index 19eae2bbe..c0a53c2ab 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -2302,7 +2302,8 @@ bool mpm::Mesh::assign_particles_pore_pressures( double pore_pressure = std::get<1>(particle_pore_pressure); if (map_particles_.find(pid) != map_particles_.end()) - map_particles_[pid]->assign_pore_pressure(pore_pressure); + map_particles_[pid]->assign_pressure(pore_pressure, + mpm::ParticlePhase::Liquid); } } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index fe28add5b..05afce62a 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -289,11 +289,8 @@ void mpm::Particle::assign_state_variable(const std::string& var, double value, unsigned phase) { if (state_variables_[phase].find(var) != state_variables_[phase].end()) state_variables_[phase].at(var) = value; - else { - state_variables_[phase].insert(std::make_pair(var, value)); - console_->warn(var + - " cannot be found in state variables! Initialise it now"); - } + else + throw std::runtime_error(var + " cannot be found in state variables!"); } // Assign a cell to particle diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 2f09570b9..a26f99d57 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -321,14 +321,6 @@ class ParticleBase { return false; }; - //! Assign pore pressure - virtual void assign_pore_pressure(double pore_pressure) { - throw std::runtime_error( - "Calling the base class function " - "(assign_pore_pressure) in " - "ParticleBase:: illegal operation!"); - }; - //! Assign saturation degree virtual bool assign_saturation_degree() { throw std::runtime_error( diff --git a/include/particles/twophase_particle.h b/include/particles/twophase_particle.h index 2117543f6..8b617c775 100644 --- a/include/particles/twophase_particle.h +++ b/include/particles/twophase_particle.h @@ -99,13 +99,6 @@ class TwoPhaseParticle : public mpm::Particle { //! Map drag force coefficient bool map_drag_force_coefficient() override; - //! Assign pore pressure - //! \param[in] pore pressure Initial pore pressure - void assign_pore_pressure(double pore_pressure) override { - this->assign_state_variable("pressure", pore_pressure, - mpm::ParticlePhase::Liquid); - } - //! Assign particles initial pore pressure by watertable bool initialise_pore_pressure_watertable( const unsigned dir_v, const unsigned dir_h, diff --git a/tests/particle_test.cc b/tests/particle_test.cc index 729e43184..fc4e951a7 100644 --- a/tests/particle_test.cc +++ b/tests/particle_test.cc @@ -1144,8 +1144,7 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { 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()) == false); + REQUIRE(std::isnan(particle->pressure()) == true); } SECTION("Assign state variables fail on state variables size") { @@ -2402,8 +2401,7 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { 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()) == false); + REQUIRE(std::isnan(particle->pressure()) == true); } SECTION("Assign state variables fail on state variables size") { diff --git a/tests/twophase_particle_test.cc b/tests/twophase_particle_test.cc index b16c9c10c..06bc0aeb0 100644 --- a/tests/twophase_particle_test.cc +++ b/tests/twophase_particle_test.cc @@ -104,8 +104,8 @@ TEST_CASE("TwoPhase Particle is checked for 1D case", REQUIRE(coordinates.size() == Dim); } - //! Test initialise particle stresses and pore pressure - SECTION("TwoPhase Particle with initial stress and pore pressure") { + //! Test initialise particle stresses + SECTION("TwoPhase Particle with initial stress") { mpm::Index id = 0; const double Tolerance = 1.E-7; bool status = true; @@ -123,10 +123,6 @@ TEST_CASE("TwoPhase Particle is checked for 1D case", auto pstress_data = particle->tensor_data("stresses"); for (unsigned i = 0; i < pstress_data.size(); ++i) REQUIRE(pstress_data[i] == Approx(stress[i]).epsilon(Tolerance)); - //! Test initialise particle pore pressure - double pore_pressure = 100000; - particle->assign_pore_pressure(pore_pressure); - REQUIRE(particle->pore_pressure() == pore_pressure); } //! Test particles velocity constraints @@ -586,8 +582,8 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", REQUIRE(cell->nparticles() == 0); } - //! Test initialise particle stresses and pore pressure - SECTION("TwoPhase Particle with initial stress and pore pressure") { + //! Test initialise particle stresses + SECTION("TwoPhase Particle with initial stress") { mpm::Index id = 0; const double Tolerance = 1.E-7; bool status = true; @@ -601,10 +597,6 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", auto pstress = particle->stress(); for (unsigned i = 0; i < pstress.size(); ++i) REQUIRE(pstress[i] == Approx(stress[i]).epsilon(Tolerance)); - //! Test initialise particle pore pressure - double pore_pressure = 100000; - particle->assign_pore_pressure(pore_pressure); - REQUIRE(particle->pore_pressure() == pore_pressure); } //! Test particles velocity constraints @@ -1206,8 +1198,7 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", 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()) == false); + REQUIRE(std::isnan(particle->pressure()) == true); } SECTION("Assign state variables fail on state variables size") { @@ -1871,8 +1862,8 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", REQUIRE(cell->nparticles() == 0); } - //! Test initialise twophase particle stresses and pore pressure - SECTION("TwoPhase Particle with initial stress and pore pressure") { + //! Test initialise twophase particle stresses + SECTION("TwoPhase Particle with initial stress") { mpm::Index id = 0; const double Tolerance = 1.E-7; bool status = true; @@ -1886,10 +1877,6 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", auto pstress = particle->stress(); for (unsigned i = 0; i < pstress.size(); ++i) REQUIRE(pstress[i] == Approx(stress[i]).epsilon(Tolerance)); - //! Test initialise particle pore pressure - double pore_pressure = 100000; - particle->assign_pore_pressure(pore_pressure); - REQUIRE(particle->pore_pressure() == pore_pressure); } //! Test twophase particles velocity constraints @@ -2539,8 +2526,7 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", 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()) == false); + REQUIRE(std::isnan(particle->pressure()) == true); } SECTION("Assign state variables fail on state variables size") { From a118f4d520aa6fc730ae544d3f20a882195dfd43 Mon Sep 17 00:00:00 2001 From: Nanda Date: Sat, 1 Aug 2020 18:20:32 -0700 Subject: [PATCH 082/175] :wrench: add an option to do free surface or not --- include/solvers/mpm_explicit_twophase.h | 8 ++-- include/solvers/mpm_explicit_twophase.tcc | 48 +++++++++++++++-------- 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/include/solvers/mpm_explicit_twophase.h b/include/solvers/mpm_explicit_twophase.h index 5e3c1413d..36613bc3f 100644 --- a/include/solvers/mpm_explicit_twophase.h +++ b/include/solvers/mpm_explicit_twophase.h @@ -74,10 +74,12 @@ class MPMExplicitTwoPhase : public MPMBase { bool pressure_smoothing_{false}; //! Pore pressure smoothing bool pore_pressure_smoothing_{false}; - //! Volume tolerance for free surface - double volume_tolerance_{0}; + //! Compute free surface + bool free_surface_detection_; //! Free surface detection type - std::string free_surface_detection_; + std::string fs_detection_type; + //! Volume tolerance for free surface + double volume_tolerance_{0.}; }; // MPMExplicit class } // namespace mpm diff --git a/include/solvers/mpm_explicit_twophase.tcc b/include/solvers/mpm_explicit_twophase.tcc index dad6a5a38..438c19b07 100644 --- a/include/solvers/mpm_explicit_twophase.tcc +++ b/include/solvers/mpm_explicit_twophase.tcc @@ -68,11 +68,23 @@ bool mpm::MPMExplicitTwoPhase::solve() { pore_pressure_smoothing_ = analysis_.at("pore_pressure_smoothing").template get(); - // Get method to detect free surface detection - free_surface_detection_ = "density"; - if (analysis_["free_surface_detection"].contains("type")) + free_surface_detection_ = false; + if (analysis_.find("free_surface_detection") != analysis_.end()) { free_surface_detection_ = - analysis_["free_surface_detection"]["type"].template get(); + analysis_["free_surface_detection"]["free_surface_detection"] + .template get(); + if (free_surface_detection_) { + // Get method to detect free surface detection + fs_detection_type = "density"; + if (analysis_["free_surface_detection"].contains("type")) + fs_detection_type = analysis_["free_surface_detection"]["type"] + .template get(); + // Get volume tolerance for free surface + volume_tolerance_ = + analysis_["free_surface_detection"]["volume_tolerance"] + .template get(); + } + } // Initialise material bool mat_status = this->initialise_materials(); @@ -197,23 +209,25 @@ bool mpm::MPMExplicitTwoPhase::solve() { } #endif - // TODO: Parallel free-surface computation is not yet implemented // Compute free surface cells, nodes, and particles - mesh_->compute_free_surface(free_surface_detection_, volume_tolerance_); + if (free_surface_detection_) { + // TODO: Parallel free-surface computation is not yet implemented + mesh_->compute_free_surface(fs_detection_type, volume_tolerance_); - // Spawn a task for initializing pressure at free surface + // 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::assign_pressure, - std::placeholders::_1, 0.0, mpm::ParticlePhase::Liquid), - std::bind(&mpm::ParticleBase::free_surface, - std::placeholders::_1)); - } - } // Wait to complete +#pragma omp section + { + // Assign initial pressure for all free-surface particle + mesh_->iterate_over_particles_predicate( + std::bind(&mpm::ParticleBase::assign_pressure, + std::placeholders::_1, 0.0, mpm::ParticlePhase::Liquid), + 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( From 284a0dd562f89dffd5a19d1e17adaae1766f2f08 Mon Sep 17 00:00:00 2001 From: Nanda Date: Sat, 1 Aug 2020 18:29:21 -0700 Subject: [PATCH 083/175] :dart: :construction: add REQUIRE_THROWS in assign pressure --- tests/particle_test.cc | 2 ++ tests/twophase_particle_test.cc | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tests/particle_test.cc b/tests/particle_test.cc index fc4e951a7..265e1e56d 100644 --- a/tests/particle_test.cc +++ b/tests/particle_test.cc @@ -1144,6 +1144,7 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { 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_THROWS(particle->assign_pressure(1000)); REQUIRE(std::isnan(particle->pressure()) == true); } @@ -2401,6 +2402,7 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { 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_THROWS(particle->assign_pressure(1000)); REQUIRE(std::isnan(particle->pressure()) == true); } diff --git a/tests/twophase_particle_test.cc b/tests/twophase_particle_test.cc index 06bc0aeb0..3857027fd 100644 --- a/tests/twophase_particle_test.cc +++ b/tests/twophase_particle_test.cc @@ -1198,6 +1198,7 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", 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_THROWS(particle->assign_pressure(1000)); REQUIRE(std::isnan(particle->pressure()) == true); } @@ -2526,6 +2527,7 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", 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_THROWS(particle->assign_pressure(1000)); REQUIRE(std::isnan(particle->pressure()) == true); } From cbd3ef96cb2bb6326dec854035d70f3279301771 Mon Sep 17 00:00:00 2001 From: Nanda Date: Sat, 1 Aug 2020 18:55:55 -0700 Subject: [PATCH 084/175] :wrench: fix free surface detection input --- include/solvers/mpm_explicit_twophase.h | 4 +--- include/solvers/mpm_explicit_twophase.tcc | 29 ++++++++++------------- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/include/solvers/mpm_explicit_twophase.h b/include/solvers/mpm_explicit_twophase.h index 36613bc3f..c3598b845 100644 --- a/include/solvers/mpm_explicit_twophase.h +++ b/include/solvers/mpm_explicit_twophase.h @@ -75,9 +75,7 @@ class MPMExplicitTwoPhase : public MPMBase { //! Pore pressure smoothing bool pore_pressure_smoothing_{false}; //! Compute free surface - bool free_surface_detection_; - //! Free surface detection type - std::string fs_detection_type; + std::string free_surface_detection_; //! Volume tolerance for free surface double volume_tolerance_{0.}; diff --git a/include/solvers/mpm_explicit_twophase.tcc b/include/solvers/mpm_explicit_twophase.tcc index 438c19b07..8e95f7ba0 100644 --- a/include/solvers/mpm_explicit_twophase.tcc +++ b/include/solvers/mpm_explicit_twophase.tcc @@ -68,22 +68,17 @@ bool mpm::MPMExplicitTwoPhase::solve() { pore_pressure_smoothing_ = analysis_.at("pore_pressure_smoothing").template get(); - free_surface_detection_ = false; + // Free surface detection + free_surface_detection_ = "none"; if (analysis_.find("free_surface_detection") != analysis_.end()) { - free_surface_detection_ = - analysis_["free_surface_detection"]["free_surface_detection"] - .template get(); - if (free_surface_detection_) { - // Get method to detect free surface detection - fs_detection_type = "density"; - if (analysis_["free_surface_detection"].contains("type")) - fs_detection_type = analysis_["free_surface_detection"]["type"] - .template get(); - // Get volume tolerance for free surface - volume_tolerance_ = - analysis_["free_surface_detection"]["volume_tolerance"] - .template get(); - } + // 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(); } // Initialise material @@ -210,9 +205,9 @@ bool mpm::MPMExplicitTwoPhase::solve() { #endif // Compute free surface cells, nodes, and particles - if (free_surface_detection_) { + if (free_surface_detection_ != "none") { // TODO: Parallel free-surface computation is not yet implemented - mesh_->compute_free_surface(fs_detection_type, volume_tolerance_); + mesh_->compute_free_surface(free_surface_detection_, volume_tolerance_); // Spawn a task for initializing pressure at free surface #pragma omp parallel sections From 82d8ab022d6508bed29c6b7380d7f6b9cc463e77 Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Sun, 2 Aug 2020 22:55:17 -0700 Subject: [PATCH 085/175] Delete pore_pressure() --- include/particles/particle_base.h | 11 +---------- include/particles/twophase_particle.h | 8 +------- include/particles/twophase_particle.tcc | 8 ++++---- include/solvers/mpm_base.tcc | 6 +++--- tests/twophase_particle_test.cc | 4 ++-- 5 files changed, 11 insertions(+), 26 deletions(-) diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index a26f99d57..685eb6b05 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -358,7 +358,7 @@ class ParticleBase { //! Initialise particle pore pressure by watertable virtual bool initialise_pore_pressure_watertable( const unsigned dir_v, const unsigned dir_h, - std::map& refernece_points) { + std::map& reference_points) { throw std::runtime_error( "Calling the base class function " "(initial_pore_pressure_watertable) in " @@ -403,15 +403,6 @@ class ParticleBase { return error; }; - //! Return liquid pore pressure - //! \retval pore pressure Pore liquid pressure - virtual double pore_pressure() const { - throw std::runtime_error( - "Calling the base class function (pore_pressure) in " - "ParticleBase:: illegal operation!"); - return 0; - }; - //! Return porosity //! \retval porosity Porosity virtual double porosity() const { diff --git a/include/particles/twophase_particle.h b/include/particles/twophase_particle.h index 8b617c775..632c7f1f2 100644 --- a/include/particles/twophase_particle.h +++ b/include/particles/twophase_particle.h @@ -102,7 +102,7 @@ class TwoPhaseParticle : public mpm::Particle { //! Assign particles initial pore pressure by watertable bool initialise_pore_pressure_watertable( const unsigned dir_v, const unsigned dir_h, - std::map& refernece_points); + std::map& reference_points); //! Update porosity //! \param[in] dt Analysis time step @@ -133,12 +133,6 @@ class TwoPhaseParticle : public mpm::Particle { //! \retval liquid mass Liquid phase mass double liquid_mass() const override { return liquid_mass_; } - //! Return liquid pore pressure - //! \retval pore pressure Pore liquid pressure - double pore_pressure() const override { - return this->state_variables_[mpm::ParticlePhase::Liquid].at("pressure"); - } - //! Reture porosity //! \retval porosity Porosity double porosity() const override { return porosity_; } diff --git a/include/particles/twophase_particle.tcc b/include/particles/twophase_particle.tcc index 76d7c8ca8..5a88920a7 100644 --- a/include/particles/twophase_particle.tcc +++ b/include/particles/twophase_particle.tcc @@ -121,7 +121,7 @@ void mpm::TwoPhaseParticle::initialise() { this->properties_["liquid_velocities"] = [&]() { return liquid_velocity(); }; this->properties_["pore_pressure"] = [&]() { Eigen::VectorXd vec_pressure = Eigen::VectorXd::Zero(3); - vec_pressure[0] = this->pore_pressure(); + vec_pressure[0] = this->pressure(mpm::ParticlePhase::Liquid); return vec_pressure; }; } @@ -643,7 +643,7 @@ bool mpm::TwoPhaseParticle::map_drag_force_coefficient() { template bool mpm::TwoPhaseParticle::initialise_pore_pressure_watertable( const unsigned dir_v, const unsigned dir_h, - std::map& refernece_points) { + std::map& reference_points) { bool status = true; try { // Initialise left boundary position (coordinate) and h0 @@ -654,8 +654,8 @@ bool mpm::TwoPhaseParticle::initialise_pore_pressure_watertable( double h0_right = 0.; // Position and h0 of particle (coordinate) const double position = this->coordinates_(dir_h); - // Iterate over each refernece_points - for (const auto& refernece_point : refernece_points) { + // Iterate over each reference_points + for (const auto& refernece_point : reference_points) { // Find boundary if (refernece_point.first > left_boundary && refernece_point.first <= position) { diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index 7a48ac1c8..6be9689de 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -1152,7 +1152,7 @@ void mpm::MPMBase::particles_pore_pressures( throw std::runtime_error("Particle pore pressures JSON not found"); } else if (type == "water_table") { // Initialise water tables - std::map refernece_points; + std::map reference_points; // Vertical direction const unsigned dir_v = mesh_props["particles_pore_pressures"]["dir_v"] .template get(); @@ -1167,13 +1167,13 @@ void mpm::MPMBase::particles_pore_pressures( // Direction double h0 = water_table.at("h0").template get(); // Add refernece points to mesh - refernece_points.insert(std::make_pair( + reference_points.insert(std::make_pair( static_cast(position), static_cast(h0))); } // Initialise particles pore pressures by watertable mesh_->iterate_over_particles(std::bind( &mpm::ParticleBase::initialise_pore_pressure_watertable, - std::placeholders::_1, dir_v, dir_h, refernece_points)); + std::placeholders::_1, dir_v, dir_h, reference_points)); } else throw std::runtime_error( "Particle pore pressures generator type is not properly " diff --git a/tests/twophase_particle_test.cc b/tests/twophase_particle_test.cc index 3857027fd..a1a672c6c 100644 --- a/tests/twophase_particle_test.cc +++ b/tests/twophase_particle_test.cc @@ -942,7 +942,7 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", // Compute pore_pressure REQUIRE_NOTHROW(particle->compute_pore_pressure(dt)); // Check pore pressure - REQUIRE(particle->pore_pressure() == + REQUIRE(particle->pressure(mpm::ParticlePhase::Liquid) == Approx(-783333333.3333334923).epsilon(Tolerance)); // Check body force @@ -2275,7 +2275,7 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", // Compute pore_pressure REQUIRE_NOTHROW(particle->compute_pore_pressure(dt)); // Check pore pressure - REQUIRE(particle->pore_pressure() == + REQUIRE(particle->pressure(mpm::ParticlePhase::Liquid) == Approx(-1608333333.3333332539).epsilon(Tolerance)); // Check body force From ed844c906108a95161d21a67c44894b2367b8bb8 Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Mon, 3 Aug 2020 15:24:47 -0700 Subject: [PATCH 086/175] Fix the nodal pressure constraints --- include/node.h | 4 +-- include/node.tcc | 23 ++++---------- include/node_base.h | 4 +-- include/particles/particle.h | 4 +-- include/particles/particle.tcc | 6 ++-- include/particles/particle_base.h | 5 +-- include/particles/twophase_particle.h | 4 +-- include/particles/twophase_particle.tcc | 25 ++++++++++----- include/solvers/mpm_base.h | 4 +-- include/solvers/mpm_base.tcc | 41 +++++++++---------------- 10 files changed, 55 insertions(+), 65 deletions(-) diff --git a/include/node.h b/include/node.h index 258ed6516..22fc0dfbd 100644 --- a/include/node.h +++ b/include/node.h @@ -131,8 +131,8 @@ class Node : public NodeBase { //! Update pressure at the nodes from particle //! \param[in] phase Index corresponding to the phase //! \param[in] mass_pressure Product of mass x pressure of a particle - void update_mass_pressure(unsigned phase, - double mass_pressure) noexcept override; + void update_mass_pressure(unsigned phase, double mass_pressure, double dt = 0, + Index step = 0) noexcept override; //! Assign pressure at the nodes from particle //! \param[in] update A boolean to update (true) or assign (false) diff --git a/include/node.tcc b/include/node.tcc index 53e66d3d0..d299f2724 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -162,7 +162,7 @@ void mpm::Node::update_momentum( //! Update pressure at the nodes from particle template void mpm::Node::update_mass_pressure( - unsigned phase, double mass_pressure) noexcept { + unsigned phase, double mass_pressure, double dt, Index step) noexcept { // Assert assert(phase < Tnphases); @@ -174,22 +174,11 @@ void mpm::Node::update_mass_pressure( node_mutex_.unlock(); if (pressure_constraints_.find(phase) != pressure_constraints_.end()) { - // const double scalar = - // (pressure_function_.find(phase) != pressure_function_.end()) - // ? pressure_function_[phase]->value(step * dt) - // : 1.0; - // this->pressure_(phase) = scalar * pressure_constraints_[phase]; - this->pressure_(phase) = pressure_constraints_[phase]; - // if (step > ref_step_ && pressure_constraints_.find(phase + Tnphases) != - // pressure_constraints_.end()) { - // const double scalar_increment = - // (pressure_function_.find(phase + Tnphases) != - // pressure_function_.end()) - // ? pressure_function_[phase + Tnphases]->value(step * dt) - // : 1.0; - // this->pressure_(phase) += - // scalar_increment * pressure_constraints_[phase + Tnphases]; - // } + const double scalar = + (pressure_function_.find(phase) != pressure_function_.end()) + ? pressure_function_[phase]->value(step * dt) + : 1.0; + this->pressure_(phase) = scalar * pressure_constraints_[phase]; } } } diff --git a/include/node_base.h b/include/node_base.h index 20c3fff6d..31636a441 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -148,8 +148,8 @@ class NodeBase { //! Update pressure at the nodes from particle //! \param[in] phase Index corresponding to the phase //! \param[in] mass_pressure Product of mass x pressure of a particle - virtual void update_mass_pressure(unsigned phase, - double mass_pressure) noexcept = 0; + virtual void update_mass_pressure(unsigned phase, double mass_pressure, + double dt = 0, Index step = 0) noexcept = 0; //! Assign pressure at the nodes from particle //! \param[in] update A boolean to update (true) or assign (false) diff --git a/include/particles/particle.h b/include/particles/particle.h index 5b419396a..d05c7dc52 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -263,8 +263,8 @@ class Particle : public ParticleBase { } //! Map particle pressure to nodes - bool map_pressure_to_nodes( - unsigned phase = mpm::ParticlePhase::Solid) noexcept override; + bool map_pressure_to_nodes(unsigned phase = mpm::ParticlePhase::Solid, + double dt = 0, Index step = 0) noexcept override; //! Compute pressure smoothing of the particle based on nodal pressure //! $$\hat{p}_p = \sum_{i = 1}^{n_n} N_i(x_p) p_i$$ diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index 05afce62a..f7668d010 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -815,7 +815,8 @@ void mpm::Particle::compute_updated_position( //! Map particle pressure to nodes template -bool mpm::Particle::map_pressure_to_nodes(unsigned phase) noexcept { +bool mpm::Particle::map_pressure_to_nodes(unsigned phase, double dt, + Index step) noexcept { // Mass is initialized assert(mass_ != std::numeric_limits::max()); @@ -827,7 +828,8 @@ bool mpm::Particle::map_pressure_to_nodes(unsigned phase) noexcept { // Map particle pressure to nodes for (unsigned i = 0; i < nodes_.size(); ++i) nodes_[i]->update_mass_pressure( - phase, shapefn_[i] * mass_ * state_variables_[phase]["pressure"]); + phase, shapefn_[i] * mass_ * state_variables_[phase]["pressure"], dt, + step); status = true; } diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 685eb6b05..1230106e9 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -241,8 +241,9 @@ class ParticleBase { virtual void map_internal_force() noexcept = 0; //! Map particle pressure to nodes - virtual bool map_pressure_to_nodes( - unsigned phase = mpm::ParticlePhase::Solid) noexcept = 0; + virtual bool map_pressure_to_nodes(unsigned phase = mpm::ParticlePhase::Solid, + double dt = 0, + Index step = 0) noexcept = 0; //! Compute pressure smoothing of the particle based on nodal pressure virtual bool compute_pressure_smoothing( diff --git a/include/particles/twophase_particle.h b/include/particles/twophase_particle.h index 632c7f1f2..7a9316977 100644 --- a/include/particles/twophase_particle.h +++ b/include/particles/twophase_particle.h @@ -116,8 +116,8 @@ class TwoPhaseParticle : public mpm::Particle { bool assign_porosity() override; //! Map particle pressure to nodes - bool map_pressure_to_nodes( - unsigned phase = mpm::ParticlePhase::Solid) noexcept override; + bool map_pressure_to_nodes(unsigned phase = mpm::ParticlePhase::Solid, + double dt = 0, Index step = 0) noexcept override; //! Apply particle velocity constraints //! \param[in] dir Direction of particle velocity constraint diff --git a/include/particles/twophase_particle.tcc b/include/particles/twophase_particle.tcc index 5a88920a7..fd79830e8 100644 --- a/include/particles/twophase_particle.tcc +++ b/include/particles/twophase_particle.tcc @@ -454,15 +454,16 @@ void mpm::TwoPhaseParticle::compute_updated_position( //! Map particle pressure to nodes template -bool mpm::TwoPhaseParticle::map_pressure_to_nodes( - unsigned phase) noexcept { +bool mpm::TwoPhaseParticle::map_pressure_to_nodes(unsigned phase, + double dt, + Index step) noexcept { // Mass is initialized assert(liquid_mass_ != std::numeric_limits::max()); bool status = false; // If phase is Solid, use the default map_pressure_to_nodes if (phase == mpm::ParticlePhase::Solid) - status = mpm::Particle::map_pressure_to_nodes(phase); + status = mpm::Particle::map_pressure_to_nodes(phase, dt, step); else { // Check if particle liquid mass is set and state variable pressure is found if (liquid_mass_ != std::numeric_limits::max() && @@ -472,7 +473,8 @@ bool mpm::TwoPhaseParticle::map_pressure_to_nodes( for (unsigned i = 0; i < nodes_.size(); ++i) nodes_[i]->update_mass_pressure( phase, - shapefn_[i] * liquid_mass_ * state_variables_[phase]["pressure"]); + shapefn_[i] * liquid_mass_ * state_variables_[phase]["pressure"], + dt, step); status = true; } @@ -680,15 +682,24 @@ bool mpm::TwoPhaseParticle::initialise_pore_pressure_watertable( ((h0_right - h0_left) / (right_boundary - left_boundary) * (position - left_boundary) + h0_left - this->coordinates_(dir_v)) * - 1000 * 9.81; + (this->material(mpm::ParticlePhase::Liquid)) + ->template property(std::string("density")) * + 9.81; } else // Particle with only left boundary - pore_pressure = (h0_left - this->coordinates_(dir_v)) * 1000 * 9.81; + pore_pressure = + (h0_left - this->coordinates_(dir_v)) * + (this->material(mpm::ParticlePhase::Liquid)) + ->template property(std::string("density")) * + 9.81; } // Particle with only right boundary else if (right_boundary != std::numeric_limits::max()) - pore_pressure = (h0_right - this->coordinates_(dir_v)) * 1000 * 9.81; + pore_pressure = (h0_right - this->coordinates_(dir_v)) * + (this->material(mpm::ParticlePhase::Liquid)) + ->template property(std::string("density")) * + 9.81; else throw std::runtime_error( "Particle pore pressure can not be initialised by water table"); diff --git a/include/solvers/mpm_base.h b/include/solvers/mpm_base.h index 1bb3aa248..e6dd771c3 100644 --- a/include/solvers/mpm_base.h +++ b/include/solvers/mpm_base.h @@ -116,10 +116,10 @@ class MPMBase : public MPM { void nodal_frictional_constraints( const Json& mesh_prop, const std::shared_ptr>& mesh_io); - //! Nodal pore pressure constraints + //! Nodal pressure constraints //! \param[in] mesh_prop Mesh properties //! \param[in] mesh_io Mesh IO handle - void nodal_pore_pressure_constraints( + void nodal_pressure_constraints( const Json& mesh_prop, const std::shared_ptr>& mesh_io); //! Cell entity sets diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index 6be9689de..e64e0352b 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -185,7 +185,7 @@ bool mpm::MPMBase::initialise_mesh() { this->nodal_frictional_constraints(mesh_props, mesh_io); // Read and assign pore pressure constraints - this->nodal_pore_pressure_constraints(mesh_props, mesh_io); + this->nodal_pressure_constraints(mesh_props, mesh_io); // Initialise cell auto cells_begin = std::chrono::steady_clock::now(); @@ -911,31 +911,27 @@ void mpm::MPMBase::nodal_frictional_constraints( } } -// Nodal pore pressure constraints (Coupled solid-fluid formulation) +// Nodal pressure constraints template -void mpm::MPMBase::nodal_pore_pressure_constraints( +void mpm::MPMBase::nodal_pressure_constraints( const Json& mesh_props, const std::shared_ptr>& mesh_io) { try { - // Water phase indice - const unsigned phase = mpm::ParticlePhase::Liquid; - // Total phase + // TODO: Get the total phases const unsigned Tnphases = 2; - // Read and assign pore pressure constraints if (mesh_props.find("boundary_conditions") != mesh_props.end() && - mesh_props["boundary_conditions"].find("pore_pressure_constraints") != + mesh_props["boundary_conditions"].find("pressure_constraints") != mesh_props["boundary_conditions"].end()) { // Iterate over pore pressure constraints for (const auto& constraints : - mesh_props["boundary_conditions"]["pore_pressure_constraints"]) { + mesh_props["boundary_conditions"]["pressure_constraints"]) { // Pore pressure constraint phase indice - unsigned constraint_phase = phase; + unsigned constraint_phase = constraints["phase"]; - // Check if it is pressure increment constraints - if (constraints.find("increment_boundary") != constraints.end() && - constraints["increment_boundary"]) - constraint_phase += Tnphases; + if (constraint_phase >= Tnphases) + throw std::runtime_error( + "Phase for nodal pressure constraints is not properly assigned"); // Pore pressure constraints are specified in a file if (constraints.find("file") != constraints.end()) { @@ -963,23 +959,14 @@ void mpm::MPMBase::nodal_pore_pressure_constraints( // Add pore pressure constraint to mesh constraints_->assign_nodal_pressure_constraint( pfunction, nset_id, constraint_phase, pore_pressure); - // if (constraint_phase >= Tnphases) { - // // Reference step - // const Index ref_step = - // constraints.at("ref_step").template get(); - // // Add reference step to nodes - // mesh_->assign_nodal_pressure_reference_step(nset_id, ref_step); - // // Insert the ref_step to the vector - // pore_pressure_ref_step_.emplace_back(ref_step); - // } } } } else - throw std::runtime_error("Pore pressure constraints JSON not found"); + throw std::runtime_error("Pressure constraints JSON not found"); } catch (std::exception& exception) { - console_->warn("#{}: Pore pressure constraints are undefined {} ", __LINE__, - exception.what()); + console_->warn("#{}: Nodal pressure constraints are undefined {} ", + __LINE__, exception.what()); } } @@ -1305,7 +1292,7 @@ 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, phase)); + std::placeholders::_1, phase, this->dt_, this->step_)); #ifdef USE_MPI int mpi_size = 1; From 3cad6b3c5f5ade27feced07b1196ba0df0390014 Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Tue, 4 Aug 2020 00:21:01 -0700 Subject: [PATCH 087/175] Add twophase_node test --- CMakeLists.txt | 1 + tests/node_test.cc | 6 - tests/twophase_node_test.cc | 2518 +++++++++++++++++++++++++++++++++++ 3 files changed, 2519 insertions(+), 6 deletions(-) create mode 100644 tests/twophase_node_test.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 746b9af95..70c44c6da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -215,6 +215,7 @@ if(MPM_BUILD_TESTING) ${mpm_SOURCE_DIR}/tests/nodal_properties_test.cc ${mpm_SOURCE_DIR}/tests/node_map_test.cc ${mpm_SOURCE_DIR}/tests/node_test.cc + ${mpm_SOURCE_DIR}/tests/twophase_node_test.cc ${mpm_SOURCE_DIR}/tests/node_vector_test.cc ${mpm_SOURCE_DIR}/tests/particle_cell_crossing_test.cc ${mpm_SOURCE_DIR}/tests/particle_test.cc diff --git a/tests/node_test.cc b/tests/node_test.cc index 3cc92d2a5..27dc531e5 100644 --- a/tests/node_test.cc +++ b/tests/node_test.cc @@ -154,8 +154,6 @@ TEST_CASE("Node is checked for 1D case", "[node][1D]") { REQUIRE_NOTHROW(node->update_mass(false, Nphase, mass)); REQUIRE(node->mass(Nphase) == Approx(0.0).epsilon(Tolerance)); // Try to update pressure to 2000, should throw and keep to 1000. - pressure = 1000.; - const double pmass = 1.5; node->assign_pressure(Nphase, pressure); REQUIRE(node->pressure(Nphase) == Approx(1000.0).epsilon(Tolerance)); } @@ -621,8 +619,6 @@ TEST_CASE("Node is checked for 2D case", "[node][2D]") { REQUIRE_NOTHROW(node->update_mass(false, Nphase, mass)); REQUIRE(node->mass(Nphase) == Approx(0.0).epsilon(Tolerance)); // Try to update pressure to 2000, should throw and keep to 1000. - pressure = 1000.; - const double pmass = 1.5; node->assign_pressure(Nphase, pressure); REQUIRE(node->pressure(Nphase) == Approx(1000.0).epsilon(Tolerance)); } @@ -1225,8 +1221,6 @@ TEST_CASE("Node is checked for 3D case", "[node][3D]") { REQUIRE_NOTHROW(node->update_mass(false, Nphase, mass)); REQUIRE(node->mass(Nphase) == Approx(0.0).epsilon(Tolerance)); // Try to update pressure to 2000, should throw and keep to 1000. - pressure = 1000.; - const double pmass = 1.5; node->assign_pressure(Nphase, pressure); REQUIRE(node->pressure(Nphase) == Approx(1000.0).epsilon(Tolerance)); } diff --git a/tests/twophase_node_test.cc b/tests/twophase_node_test.cc new file mode 100644 index 000000000..91cccb4e2 --- /dev/null +++ b/tests/twophase_node_test.cc @@ -0,0 +1,2518 @@ +#include +#include +#include + +#include "Eigen/Dense" +#include "catch.hpp" + +#include "function_base.h" +#include "geometry.h" +#include "node.h" + +// Check node class for 1D case +TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2P]") { + const unsigned Dim = 1; + const unsigned Dof = 1; + const unsigned Nphases = 2; + Eigen::Matrix coords; + coords.setZero(); + + // Check for id = 0 + SECTION("Node id is zero") { + mpm::Index id = 0; + std::shared_ptr> node = + std::make_shared>(id, coords); + REQUIRE(node->id() == 0); + } + + // Check for id is a positive value + SECTION("Node id is positive") { + mpm::Index id = std::numeric_limits::max(); + std::shared_ptr> node = + std::make_shared>(id, coords); + REQUIRE(node->id() == std::numeric_limits::max()); + } + + // Check for degrees of freedom + SECTION("Check degrees of freedom") { + mpm::Index id = 0; + std::shared_ptr> node = + std::make_shared>(id, coords); + REQUIRE(node->dof() == 1); + } + + // Check status + SECTION("Check status") { + mpm::Index id = 0; + std::shared_ptr> node = + std::make_shared>(id, coords); + REQUIRE(node->status() == false); + node->assign_status(true); + REQUIRE(node->status() == true); + } + + SECTION("Boundary ghost id") { + mpm::Index id = 0; + std::shared_ptr> node = + std::make_shared>(id, coords); + node->ghost_id(5); + REQUIRE(node->ghost_id() == 5); + } + + // Check MPI Rank + SECTION("Check MPI Rank") { + mpm::Index id = 0; + std::shared_ptr> node = + std::make_shared>(id, coords); + REQUIRE(node->id() == 0); + + // Assign MPI ranks + node->mpi_rank(0); + node->mpi_rank(0); + node->mpi_rank(1); + + std::set ranks = node->mpi_ranks(); + REQUIRE(ranks.size() == 2); + std::vector mpi_ranks = {0, 1}; + unsigned i = 0; + for (auto it = ranks.begin(); it != ranks.end(); ++it, ++i) + REQUIRE(*it == mpi_ranks.at(i)); + } + + // Test coordinates function + SECTION("coordinates function is checked") { + mpm::Index id = 0; + const double Tolerance = 1.E-7; + + std::shared_ptr> node = + std::make_shared>(id, coords); + + // Check for coordinates being zero + auto coordinates = node->coordinates(); + for (unsigned i = 0; i < coordinates.size(); ++i) + REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + REQUIRE(coordinates.size() == Dim); + + // Check for negative value of coordinates + for (unsigned i = 0; i < coordinates.size(); ++i) + coords(i) = -1. * std::numeric_limits::max(); + node->assign_coordinates(coords); + coordinates = node->coordinates(); + for (unsigned i = 0; i < coordinates.size(); ++i) + REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + + REQUIRE(coordinates.size() == Dim); + + // Check for positive value of coordinates + for (unsigned i = 0; i < coordinates.size(); ++i) + coords(i) = std::numeric_limits::max(); + node->assign_coordinates(coords); + coordinates = node->coordinates(); + for (unsigned i = 0; i < coordinates.size(); ++i) + REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + + REQUIRE(coordinates.size() == Dim); + } + + SECTION("Check nodal properties") { + mpm::Index id = 0; + const double Tolerance = 1.E-7; + std::shared_ptr> node = + std::make_shared>(id, coords); + + // Check mass + REQUIRE(node->mass(mpm::NodePhase::nSolid) == + Approx(0.0).epsilon(Tolerance)); + REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + Approx(0.0).epsilon(Tolerance)); + double solid_mass = 100.5; + double liquid_mass = 200.5; + // Update mass to 100.5 and 200.5 + REQUIRE_NOTHROW( + node->update_mass(true, mpm::NodePhase::nSolid, solid_mass)); + REQUIRE_NOTHROW( + node->update_mass(true, mpm::NodePhase::nLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::nSolid) == + Approx(100.5).epsilon(Tolerance)); + REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + Approx(200.5).epsilon(Tolerance)); + // Update mass to 201 and 401 + REQUIRE_NOTHROW( + node->update_mass(true, mpm::NodePhase::nSolid, solid_mass)); + REQUIRE_NOTHROW( + node->update_mass(true, mpm::NodePhase::nLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::nSolid) == + Approx(201.0).epsilon(Tolerance)); + REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + Approx(401.0).epsilon(Tolerance)); + // Assign mass to 100 and 200 + solid_mass = 100.; + liquid_mass = 200.; + REQUIRE_NOTHROW( + node->update_mass(false, mpm::NodePhase::nSolid, solid_mass)); + REQUIRE_NOTHROW( + node->update_mass(false, mpm::NodePhase::nLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::nSolid) == + Approx(100.0).epsilon(Tolerance)); + REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + Approx(200.0).epsilon(Tolerance)); + + SECTION("Check nodal pressure") { + // Check pressure + REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + Approx(0.0).epsilon(Tolerance)); + REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + Approx(0.0).epsilon(Tolerance)); + double pressure = 1000.7; + double pore_pressure = 2000.7; + // Update pressure to 1000.7 and 2000.7 + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nSolid, + solid_mass * pressure)); + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nLiquid, + liquid_mass * pore_pressure)); + REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + Approx(1000.7).epsilon(Tolerance)); + REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + Approx(2000.7).epsilon(Tolerance)); + // Update pressure to 2001.4 and 4001.4 + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nSolid, + solid_mass * pressure)); + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nLiquid, + liquid_mass * pore_pressure)); + REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + Approx(2001.4).epsilon(Tolerance)); + REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + Approx(4001.4).epsilon(Tolerance)); + // Assign pressure to 1000 and 2000 + pressure = 1000.; + pore_pressure = 2000.; + node->assign_pressure(mpm::NodePhase::nSolid, pressure); + node->assign_pressure(mpm::NodePhase::nLiquid, pore_pressure); + REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + Approx(1000.0).epsilon(Tolerance)); + REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + Approx(2000.0).epsilon(Tolerance)); + // Assign mass to 0 + solid_mass = 0.; + liquid_mass = 0.; + REQUIRE_NOTHROW( + node->update_mass(false, mpm::NodePhase::nSolid, solid_mass)); + REQUIRE_NOTHROW( + node->update_mass(false, mpm::NodePhase::nLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::nSolid) == + Approx(0.0).epsilon(Tolerance)); + REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + Approx(0.0).epsilon(Tolerance)); + // Try to update pressure to 2000, should throw and keep to 1000. + node->assign_pressure(mpm::NodePhase::nSolid, pressure); + node->assign_pressure(mpm::NodePhase::nLiquid, pore_pressure); + REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + Approx(1000.0).epsilon(Tolerance)); + REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + Approx(2000.0).epsilon(Tolerance)); + } + + SECTION("Check external force") { + // Create a force vector + Eigen::Matrix force; + for (unsigned i = 0; i < force.size(); ++i) force(i) = 10.; + + // Check current external force is zero + for (unsigned i = 0; i < force.size(); ++i) { + REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + Approx(0.).epsilon(Tolerance)); + REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + Approx(0.).epsilon(Tolerance)); + } + + // Update force to 10.0 + REQUIRE_NOTHROW( + node->update_external_force(true, mpm::NodePhase::nMixture, force)); + REQUIRE_NOTHROW(node->update_external_force(true, mpm::NodePhase::nLiquid, + 0.5 * force)); + for (unsigned i = 0; i < force.size(); ++i) { + REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + Approx(10.).epsilon(Tolerance)); + REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + Approx(5.).epsilon(Tolerance)); + } + + // Update force to 20.0 + REQUIRE_NOTHROW( + node->update_external_force(true, mpm::NodePhase::nMixture, force)); + REQUIRE_NOTHROW(node->update_external_force(true, mpm::NodePhase::nLiquid, + 0.5 * force)); + for (unsigned i = 0; i < force.size(); ++i) { + REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + Approx(20.).epsilon(Tolerance)); + REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + Approx(10.).epsilon(Tolerance)); + } + + // Assign force as 10.0 + REQUIRE_NOTHROW( + node->update_external_force(false, mpm::NodePhase::nMixture, force)); + REQUIRE_NOTHROW(node->update_external_force( + false, mpm::NodePhase::nLiquid, 0.5 * force)); + for (unsigned i = 0; i < force.size(); ++i) { + REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + Approx(10.).epsilon(Tolerance)); + REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + Approx(5.).epsilon(Tolerance)); + } + + SECTION("Check concentrated force") { + // Set external force to zero + force.setZero(); + REQUIRE_NOTHROW(node->update_external_force( + false, mpm::NodePhase::nMixture, force)); + + // concentrated force + std::shared_ptr ffunction = nullptr; + double concentrated_force = 65.32; + const unsigned Direction = 0; + // Check external force + for (unsigned i = 0; i < Dim; ++i) + REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + Approx(0.).epsilon(Tolerance)); + + REQUIRE(node->assign_concentrated_force(mpm::NodePhase::nMixture, + Direction, concentrated_force, + ffunction) == true); + + double current_time = 0.0; + node->apply_concentrated_force(mpm::NodePhase::nMixture, current_time); + + for (unsigned i = 0; i < Dim; ++i) { + if (i == Direction) + REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + Approx(concentrated_force).epsilon(Tolerance)); + else + REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + Approx(0.).epsilon(Tolerance)); + } + + // Check for incorrect direction / phase + const unsigned wrong_dir = 4; + REQUIRE(node->assign_concentrated_force(mpm::NodePhase::nMixture, + wrong_dir, concentrated_force, + ffunction) == false); + + // Check again to ensure value hasn't been updated + for (unsigned i = 0; i < Dim; ++i) { + if (i == Direction) + REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + Approx(concentrated_force).epsilon(Tolerance)); + else + REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + Approx(0.).epsilon(Tolerance)); + } + } + } + + SECTION("Check internal force") { + // Create a force vector + Eigen::Matrix force; + for (unsigned i = 0; i < force.size(); ++i) force(i) = 10.; + + // Check current internal force is zero + for (unsigned i = 0; i < force.size(); ++i) { + REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + Approx(0.).epsilon(Tolerance)); + REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + Approx(0.).epsilon(Tolerance)); + } + + // Update force to 10.0 + REQUIRE_NOTHROW( + node->update_internal_force(true, mpm::NodePhase::nMixture, force)); + REQUIRE_NOTHROW(node->update_internal_force(true, mpm::NodePhase::nLiquid, + 0.5 * force)); + for (unsigned i = 0; i < force.size(); ++i) { + REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + Approx(10.).epsilon(Tolerance)); + REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + Approx(5.).epsilon(Tolerance)); + } + + // Update force to 20.0 + REQUIRE_NOTHROW( + node->update_internal_force(true, mpm::NodePhase::nMixture, force)); + REQUIRE_NOTHROW(node->update_internal_force(true, mpm::NodePhase::nLiquid, + 0.5 * force)); + for (unsigned i = 0; i < force.size(); ++i) { + REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + Approx(20.).epsilon(Tolerance)); + REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + Approx(10.).epsilon(Tolerance)); + } + + // Assign force as 10.0 + REQUIRE_NOTHROW( + node->update_internal_force(false, mpm::NodePhase::nMixture, force)); + REQUIRE_NOTHROW(node->update_internal_force( + false, mpm::NodePhase::nLiquid, 0.5 * force)); + for (unsigned i = 0; i < force.size(); ++i) { + REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + Approx(10.).epsilon(Tolerance)); + REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + Approx(5.).epsilon(Tolerance)); + } + } + + SECTION("Check drag force coefficient") { + // Create a force vector + Eigen::Matrix drag_force_coefficient; + for (unsigned i = 0; i < drag_force_coefficient.size(); ++i) + drag_force_coefficient(i) = 10.; + + // Check current drag force coefficient is zero + for (unsigned i = 0; i < drag_force_coefficient.size(); ++i) + REQUIRE(node->drag_force_coefficient()(i) == + Approx(0.).epsilon(Tolerance)); + + // Update drag force coefficient to 10.0 + REQUIRE_NOTHROW( + node->update_drag_force_coefficient(true, drag_force_coefficient)); + + for (unsigned i = 0; i < drag_force_coefficient.size(); ++i) + REQUIRE(node->drag_force_coefficient()(i) == + Approx(10.).epsilon(Tolerance)); + + // Update force to 20.0 + REQUIRE_NOTHROW( + node->update_drag_force_coefficient(true, drag_force_coefficient)); + + for (unsigned i = 0; i < drag_force_coefficient.size(); ++i) + REQUIRE(node->drag_force_coefficient()(i) == + Approx(20.).epsilon(Tolerance)); + + // Assign force as 10.0 + REQUIRE_NOTHROW( + node->update_drag_force_coefficient(false, drag_force_coefficient)); + for (unsigned i = 0; i < drag_force_coefficient.size(); ++i) + REQUIRE(node->drag_force_coefficient()(i) == + Approx(10.).epsilon(Tolerance)); + } + + SECTION("Check compute acceleration and velocity") { + // Time step + const double dt = 0.1; + + // Nodal mass + double solid_mass = 100.; + double liquid_mass = 100.; + // Update mass to 100.5 + REQUIRE_NOTHROW( + node->update_mass(false, mpm::NodePhase::nSolid, solid_mass)); + REQUIRE(node->mass(mpm::NodePhase::nSolid) == + Approx(solid_mass).epsilon(Tolerance)); + + // Check internal force + // Create a force vector + Eigen::Matrix force; + for (unsigned i = 0; i < force.size(); ++i) force(i) = 10. * i; + // Update force to 10.0 + REQUIRE_NOTHROW( + node->update_internal_force(false, mpm::NodePhase::nMixture, force)); + REQUIRE_NOTHROW(node->update_internal_force( + false, mpm::NodePhase::nLiquid, 0.5 * force)); + // Internal force + for (unsigned i = 0; i < force.size(); ++i) { + REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + Approx(force(i)).epsilon(Tolerance)); + REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + Approx(0.5 * force(i)).epsilon(Tolerance)); + } + + // External force + for (unsigned i = 0; i < force.size(); ++i) force(i) = 5. * i; + // Update force to 10.0 + REQUIRE_NOTHROW( + node->update_external_force(false, mpm::NodePhase::nMixture, force)); + REQUIRE_NOTHROW(node->update_external_force( + false, mpm::NodePhase::nLiquid, 0.5 * force)); + for (unsigned i = 0; i < force.size(); ++i) { + REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + Approx(force(i)).epsilon(Tolerance)); + REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + Approx(0.5 * force(i)).epsilon(Tolerance)); + } + + // Drag force + Eigen::Matrix drag_force_coefficient; + for (unsigned i = 0; i < drag_force_coefficient.size(); ++i) + drag_force_coefficient(i) = 5. * i; + // Update force to 10.0 + REQUIRE_NOTHROW( + node->update_drag_force_coefficient(false, drag_force_coefficient)); + for (unsigned i = 0; i < force.size(); ++i) + REQUIRE(node->drag_force_coefficient()(i) == + Approx(drag_force_coefficient(i)).epsilon(Tolerance)); + + REQUIRE(node->compute_acceleration_velocity_twophase_explicit(dt) == + true); + + // Check acceleration + Eigen::Matrix liquid_acceleration; + liquid_acceleration << 0.; + Eigen::Matrix solid_acceleration; + solid_acceleration << 0.; + + for (unsigned i = 0; i < solid_acceleration.size(); ++i) { + REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + Approx(solid_acceleration(i)).epsilon(Tolerance)); + REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + Approx(liquid_acceleration(i)).epsilon(Tolerance)); + } + + // Check velocity + Eigen::Matrix solid_velocity = solid_acceleration * dt; + Eigen::Matrix liquid_velocity = liquid_acceleration * dt; + for (unsigned i = 0; i < solid_velocity.size(); ++i) { + REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + Approx(solid_velocity(i)).epsilon(Tolerance)); + REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + Approx(liquid_velocity(i)).epsilon(Tolerance)); + } + + // Apply friction constraints + REQUIRE(node->assign_friction_constraint(0, 1., 0.5) == true); + // Apply friction constraints + REQUIRE(node->assign_friction_constraint(-1, 1., 0.5) == false); + REQUIRE(node->assign_friction_constraint(3, 1., 0.5) == false); + + // Test acceleration with constraints + solid_acceleration[0] = 0.5 * solid_acceleration[0]; + liquid_acceleration[0] = 0.5 * liquid_acceleration[0]; + for (unsigned i = 0; i < solid_acceleration.size(); ++i) { + REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + Approx(solid_acceleration(i)).epsilon(Tolerance)); + REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + Approx(liquid_acceleration(i)).epsilon(Tolerance)); + } + + // Apply cundall damping when calculating acceleration + REQUIRE(node->compute_acceleration_velocity_twophase_explicit_cundall( + dt, 0.05) == true); + + // Test acceleration with cundall damping + solid_acceleration[0] = 0.; + liquid_acceleration[0] = 0.; + for (unsigned i = 0; i < solid_acceleration.size(); ++i) { + REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + Approx(solid_acceleration(i)).epsilon(Tolerance)); + REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + Approx(liquid_acceleration(i)).epsilon(Tolerance)); + } + + // Apply velocity constraints + REQUIRE(node->assign_velocity_constraint(0, 10.5) == true); + REQUIRE(node->assign_velocity_constraint(1, 10.5) == true); + REQUIRE(node->compute_acceleration_velocity_twophase_explicit(dt) == + true); + + // Test velocity with constraints + solid_velocity[0] = 10.5; + liquid_velocity[0] = 10.5; + for (unsigned i = 0; i < solid_velocity.size(); ++i) { + REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + Approx(solid_velocity(i)).epsilon(Tolerance)); + REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + Approx(liquid_velocity(i)).epsilon(Tolerance)); + } + + // Test acceleration with constraints + solid_acceleration[0] = 0.; + liquid_acceleration[0] = 0.; + for (unsigned i = 0; i < solid_acceleration.size(); ++i) { + REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + Approx(solid_acceleration(i)).epsilon(Tolerance)); + REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + Approx(liquid_acceleration(i)).epsilon(Tolerance)); + } + + // Exception check when mass is zero + // Update mass to 0. + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nSolid, 0.)); + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nLiquid, 0.)); + REQUIRE(node->mass(mpm::NodePhase::nSolid) == + Approx(0.).epsilon(Tolerance)); + REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + Approx(0.).epsilon(Tolerance)); + REQUIRE(node->compute_acceleration_velocity_twophase_explicit(dt) == + false); + } + + SECTION("Check momentum and velocity") { + // Check momentum + Eigen::Matrix momentum; + for (unsigned i = 0; i < momentum.size(); ++i) momentum(i) = 10.; + + // Check initial momentum + for (unsigned i = 0; i < momentum.size(); ++i) { + REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + Approx(0.).epsilon(Tolerance)); + REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + Approx(0.).epsilon(Tolerance)); + } + + // Check update momentum to 10 + REQUIRE_NOTHROW( + node->update_momentum(true, mpm::NodePhase::nSolid, momentum)); + REQUIRE_NOTHROW( + node->update_momentum(true, mpm::NodePhase::nLiquid, momentum)); + for (unsigned i = 0; i < momentum.size(); ++i) { + REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + Approx(10.).epsilon(Tolerance)); + REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + Approx(10.).epsilon(Tolerance)); + } + + // Check update momentum to 20 + REQUIRE_NOTHROW( + node->update_momentum(true, mpm::NodePhase::nSolid, momentum)); + REQUIRE_NOTHROW( + node->update_momentum(true, mpm::NodePhase::nLiquid, momentum)); + for (unsigned i = 0; i < momentum.size(); ++i) { + REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + Approx(20.).epsilon(Tolerance)); + REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + Approx(20.).epsilon(Tolerance)); + } + + // Check assign momentum to 10 + REQUIRE_NOTHROW( + node->update_momentum(false, mpm::NodePhase::nSolid, momentum)); + REQUIRE_NOTHROW( + node->update_momentum(false, mpm::NodePhase::nLiquid, momentum)); + for (unsigned i = 0; i < momentum.size(); ++i) { + REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + Approx(10.).epsilon(Tolerance)); + REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + Approx(10.).epsilon(Tolerance)); + } + + // Check zero velocity + for (unsigned i = 0; i < Dim; ++i) { + REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + Approx(0.).epsilon(Tolerance)); + REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + Approx(0.).epsilon(Tolerance)); + } + + // Check mass + double mass = 0.; + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nSolid, mass)); + REQUIRE(node->mass(mpm::NodePhase::nSolid) == + Approx(0.0).epsilon(Tolerance)); + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nLiquid, mass)); + REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + Approx(0.0).epsilon(Tolerance)); + // Compute and check velocity this should throw zero mass + node->compute_velocity(); + + mass = 100.; + // Update mass to 100. + REQUIRE_NOTHROW(node->update_mass(true, mpm::NodePhase::nSolid, mass)); + REQUIRE(node->mass(mpm::NodePhase::nSolid) == + Approx(100.).epsilon(Tolerance)); + REQUIRE_NOTHROW(node->update_mass(true, mpm::NodePhase::nLiquid, mass)); + REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + Approx(100.).epsilon(Tolerance)); + + // Compute and check velocity + node->compute_velocity(); + for (unsigned i = 0; i < Dim; ++i) { + REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + Approx(0.1).epsilon(Tolerance)); + REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + Approx(0.1).epsilon(Tolerance)); + } + + // Apply velocity constraints + REQUIRE(node->assign_velocity_constraint(0, 10.5) == true); + // Check out of bounds condition + REQUIRE(node->assign_velocity_constraint(1, 10.5) == true); + + // Check velocity before constraints + Eigen::Matrix velocity; + velocity << 0.1; + for (unsigned i = 0; i < velocity.size(); ++i) { + REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + Approx(velocity(i)).epsilon(Tolerance)); + REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + Approx(velocity(i)).epsilon(Tolerance)); + } + + // Apply constraints + node->apply_velocity_constraints(); + + // Check apply constraints + velocity << 10.5; + for (unsigned i = 0; i < velocity.size(); ++i) { + REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + Approx(velocity(i)).epsilon(Tolerance)); + REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + Approx(velocity(i)).epsilon(Tolerance)); + } + } + + SECTION("Check acceleration") { + // Check acceleration + Eigen::Matrix acceleration; + for (unsigned i = 0; i < acceleration.size(); ++i) acceleration(i) = 5.; + + for (unsigned i = 0; i < acceleration.size(); ++i) { + REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + Approx(0.).epsilon(Tolerance)); + REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + Approx(0.).epsilon(Tolerance)); + } + + REQUIRE_NOTHROW(node->update_acceleration(true, mpm::NodePhase::nSolid, + acceleration)); + REQUIRE_NOTHROW(node->update_acceleration(true, mpm::NodePhase::nLiquid, + 0.5 * acceleration)); + + for (unsigned i = 0; i < acceleration.size(); ++i) { + REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + Approx(5.).epsilon(Tolerance)); + REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + Approx(2.5).epsilon(Tolerance)); + } + + // Apply velocity constraints + REQUIRE(node->assign_velocity_constraint(0, 10.5) == true); + // Check out of bounds condition + REQUIRE(node->assign_velocity_constraint(1, 12.5) == true); + + // Check acceleration before constraints + acceleration.resize(Dim); + acceleration << 5.; + for (unsigned i = 0; i < acceleration.size(); ++i) { + REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + Approx(acceleration(i)).epsilon(Tolerance)); + REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + Approx(0.5 * acceleration(i)).epsilon(Tolerance)); + } + + // Apply constraints + node->apply_velocity_constraints(); + + // Check apply constraints + acceleration << 0.0; + for (unsigned i = 0; i < acceleration.size(); ++i) { + REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + Approx(acceleration(i)).epsilon(Tolerance)); + REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + Approx(acceleration(i)).epsilon(Tolerance)); + } + } + + SECTION("Check node material ids") { + // Add material to nodes + node->append_material_id(0); + node->append_material_id(1); + node->append_material_id(4); + node->append_material_id(0); + node->append_material_id(2); + + // Check size of material_ids + REQUIRE(node->material_ids().size() == 4); + + // Check elements of material_ids + std::vector material_ids = {0, 1, 2, 4}; + auto mat_ids = node->material_ids(); + unsigned i = 0; + for (auto mitr = mat_ids.begin(); mitr != mat_ids.end(); ++mitr, ++i) + REQUIRE(*mitr == material_ids.at(i)); + } + } +} + +// \brief Check node class for 2D case +TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2P]") { + const unsigned Dim = 2; + const unsigned Dof = 2; + const unsigned Nphases = 2; + + Eigen::Vector2d coords; + coords.setZero(); + + // Check for id = 0 + SECTION("Node id is zero") { + mpm::Index id = 0; + std::shared_ptr> node = + std::make_shared>(id, coords); + REQUIRE(node->id() == 0); + } + + // Check for id is a positive value + SECTION("Node id is positive") { + mpm::Index id = std::numeric_limits::max(); + std::shared_ptr> node = + std::make_shared>(id, coords); + REQUIRE(node->id() == std::numeric_limits::max()); + } + + // Check for degrees of freedom + SECTION("Check degrees of freedom") { + mpm::Index id = 0; + std::shared_ptr> node = + std::make_shared>(id, coords); + REQUIRE(node->dof() == 2); + } + + // Check status + SECTION("Check status") { + mpm::Index id = 0; + std::shared_ptr> node = + std::make_shared>(id, coords); + REQUIRE(node->status() == false); + node->assign_status(true); + REQUIRE(node->status() == true); + } + + SECTION("Boundary ghost id") { + mpm::Index id = 0; + std::shared_ptr> node = + std::make_shared>(id, coords); + node->ghost_id(5); + REQUIRE(node->ghost_id() == 5); + } + + // Check MPI Rank + SECTION("Check MPI Rank") { + mpm::Index id = 0; + std::shared_ptr> node = + std::make_shared>(id, coords); + REQUIRE(node->id() == 0); + + // Assign MPI ranks + node->mpi_rank(0); + node->mpi_rank(0); + node->mpi_rank(1); + + std::set ranks = node->mpi_ranks(); + REQUIRE(ranks.size() == 2); + std::vector mpi_ranks = {0, 1}; + unsigned i = 0; + for (auto it = ranks.begin(); it != ranks.end(); ++it, ++i) + REQUIRE(*it == mpi_ranks.at(i)); + } + + // Test coordinates function + SECTION("coordinates function is checked") { + mpm::Index id = 0; + const double Tolerance = 1.E-7; + + std::shared_ptr> node = + std::make_shared>(id, coords); + + // Check for coordinates being zero + auto coordinates = node->coordinates(); + for (unsigned i = 0; i < coordinates.size(); ++i) + REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + REQUIRE(coordinates.size() == Dim); + + // Check for negative value of coordinates + for (unsigned i = 0; i < coordinates.size(); ++i) + coords(i) = -1. * std::numeric_limits::max(); + node->assign_coordinates(coords); + coordinates = node->coordinates(); + for (unsigned i = 0; i < coordinates.size(); ++i) + REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + + REQUIRE(coordinates.size() == Dim); + + // Check for positive value of coordinates + for (unsigned i = 0; i < coordinates.size(); ++i) + coords(i) = std::numeric_limits::max(); + node->assign_coordinates(coords); + coordinates = node->coordinates(); + for (unsigned i = 0; i < coordinates.size(); ++i) + REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + + REQUIRE(coordinates.size() == Dim); + } + + SECTION("Check nodal properties") { + mpm::Index id = 0; + const double Tolerance = 1.E-7; + std::shared_ptr> node = + std::make_shared>(id, coords); + + // Check mass + REQUIRE(node->mass(mpm::NodePhase::nSolid) == + Approx(0.0).epsilon(Tolerance)); + REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + Approx(0.0).epsilon(Tolerance)); + double solid_mass = 100.5; + double liquid_mass = 200.5; + // Update mass to 100.5 and 200.5 + REQUIRE_NOTHROW( + node->update_mass(true, mpm::NodePhase::nSolid, solid_mass)); + REQUIRE_NOTHROW( + node->update_mass(true, mpm::NodePhase::nLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::nSolid) == + Approx(100.5).epsilon(Tolerance)); + REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + Approx(200.5).epsilon(Tolerance)); + // Update mass to 201 and 401 + REQUIRE_NOTHROW( + node->update_mass(true, mpm::NodePhase::nSolid, solid_mass)); + REQUIRE_NOTHROW( + node->update_mass(true, mpm::NodePhase::nLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::nSolid) == + Approx(201.0).epsilon(Tolerance)); + REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + Approx(401.0).epsilon(Tolerance)); + // Assign mass to 100 and 200 + solid_mass = 100.; + liquid_mass = 200.; + REQUIRE_NOTHROW( + node->update_mass(false, mpm::NodePhase::nSolid, solid_mass)); + REQUIRE_NOTHROW( + node->update_mass(false, mpm::NodePhase::nLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::nSolid) == + Approx(100.0).epsilon(Tolerance)); + REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + Approx(200.0).epsilon(Tolerance)); + + SECTION("Check nodal pressure") { + // Check pressure + REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + Approx(0.0).epsilon(Tolerance)); + REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + Approx(0.0).epsilon(Tolerance)); + double pressure = 1000.7; + double pore_pressure = 2000.7; + // Update pressure to 1000.7 and 2000.7 + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nSolid, + solid_mass * pressure)); + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nLiquid, + liquid_mass * pore_pressure)); + REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + Approx(1000.7).epsilon(Tolerance)); + REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + Approx(2000.7).epsilon(Tolerance)); + // Update pressure to 2001.4 and 4001.4 + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nSolid, + solid_mass * pressure)); + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nLiquid, + liquid_mass * pore_pressure)); + REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + Approx(2001.4).epsilon(Tolerance)); + REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + Approx(4001.4).epsilon(Tolerance)); + // Assign pressure to 1000 and 2000 + pressure = 1000.; + pore_pressure = 2000.; + node->assign_pressure(mpm::NodePhase::nSolid, pressure); + node->assign_pressure(mpm::NodePhase::nLiquid, pore_pressure); + REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + Approx(1000.0).epsilon(Tolerance)); + REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + Approx(2000.0).epsilon(Tolerance)); + // Assign mass to 0 + solid_mass = 0.; + liquid_mass = 0.; + REQUIRE_NOTHROW( + node->update_mass(false, mpm::NodePhase::nSolid, solid_mass)); + REQUIRE_NOTHROW( + node->update_mass(false, mpm::NodePhase::nLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::nSolid) == + Approx(0.0).epsilon(Tolerance)); + REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + Approx(0.0).epsilon(Tolerance)); + // Try to update pressure to 2000, should throw and keep to 1000. + node->assign_pressure(mpm::NodePhase::nSolid, pressure); + node->assign_pressure(mpm::NodePhase::nLiquid, pore_pressure); + REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + Approx(1000.0).epsilon(Tolerance)); + REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + Approx(2000.0).epsilon(Tolerance)); + } + + SECTION("Check volume") { + // Check volume + REQUIRE(node->volume(mpm::NodePhase::nMixture) == + Approx(0.0).epsilon(Tolerance)); + double volume = 100.5; + // Update volume to 100.5 + REQUIRE_NOTHROW( + node->update_volume(true, mpm::NodePhase::nMixture, volume)); + REQUIRE(node->volume(mpm::NodePhase::nMixture) == + Approx(100.5).epsilon(Tolerance)); + // Update volume to 201 + REQUIRE_NOTHROW( + node->update_volume(true, mpm::NodePhase::nMixture, volume)); + REQUIRE(node->volume(mpm::NodePhase::nMixture) == + Approx(201.0).epsilon(Tolerance)); + // Assign volume to 100 + volume = 100.; + REQUIRE_NOTHROW( + node->update_volume(false, mpm::NodePhase::nMixture, volume)); + REQUIRE(node->volume(mpm::NodePhase::nMixture) == + Approx(100.0).epsilon(Tolerance)); + } + + SECTION("Check external force") { + // Create a force vector + Eigen::Matrix force; + for (unsigned i = 0; i < force.size(); ++i) force(i) = 10.; + + // Check current external force is zero + for (unsigned i = 0; i < force.size(); ++i) { + REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + Approx(0.).epsilon(Tolerance)); + REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + Approx(0.).epsilon(Tolerance)); + } + + // Update force to 10.0 + REQUIRE_NOTHROW( + node->update_external_force(true, mpm::NodePhase::nMixture, force)); + REQUIRE_NOTHROW(node->update_external_force(true, mpm::NodePhase::nLiquid, + 0.5 * force)); + for (unsigned i = 0; i < force.size(); ++i) { + REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + Approx(10.).epsilon(Tolerance)); + REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + Approx(5.).epsilon(Tolerance)); + } + + // Update force to 20.0 + REQUIRE_NOTHROW( + node->update_external_force(true, mpm::NodePhase::nMixture, force)); + REQUIRE_NOTHROW(node->update_external_force(true, mpm::NodePhase::nLiquid, + 0.5 * force)); + for (unsigned i = 0; i < force.size(); ++i) { + REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + Approx(20.).epsilon(Tolerance)); + REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + Approx(10.).epsilon(Tolerance)); + } + + // Assign force as 10.0 + REQUIRE_NOTHROW( + node->update_external_force(false, mpm::NodePhase::nMixture, force)); + REQUIRE_NOTHROW(node->update_external_force( + false, mpm::NodePhase::nLiquid, 0.5 * force)); + for (unsigned i = 0; i < force.size(); ++i) { + REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + Approx(10.).epsilon(Tolerance)); + REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + Approx(5.).epsilon(Tolerance)); + } + + SECTION("Check concentrated force") { + // Set external force to zero + force.setZero(); + REQUIRE_NOTHROW(node->update_external_force( + false, mpm::NodePhase::nMixture, force)); + + // Concentrated force + std::shared_ptr ffunction = nullptr; + double concentrated_force = 65.32; + const unsigned Direction = 0; + // Check traction + for (unsigned i = 0; i < Dim; ++i) + REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + Approx(0.).epsilon(Tolerance)); + + REQUIRE(node->assign_concentrated_force(mpm::NodePhase::nMixture, + Direction, concentrated_force, + ffunction) == true); + double current_time = 0.0; + node->apply_concentrated_force(mpm::NodePhase::nMixture, current_time); + + for (unsigned i = 0; i < Dim; ++i) { + if (i == Direction) + REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + Approx(concentrated_force).epsilon(Tolerance)); + + else + REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + Approx(0.).epsilon(Tolerance)); + } + + // Check for incorrect direction / phase + const unsigned wrong_dir = 4; + REQUIRE(node->assign_concentrated_force(mpm::NodePhase::nMixture, + wrong_dir, concentrated_force, + ffunction) == false); + + // Check again to ensure value hasn't been updated + for (unsigned i = 0; i < Dim; ++i) { + if (i == Direction) + REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + Approx(concentrated_force).epsilon(Tolerance)); + else + REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + Approx(0.).epsilon(Tolerance)); + } + } + } + + SECTION("Check internal force") { + // Create a force vector + Eigen::Matrix force; + for (unsigned i = 0; i < force.size(); ++i) force(i) = 10.; + + // Check current internal force is zero + for (unsigned i = 0; i < force.size(); ++i) { + REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + Approx(0.).epsilon(Tolerance)); + REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + Approx(0.).epsilon(Tolerance)); + } + + // Update force to 10.0 + REQUIRE_NOTHROW( + node->update_internal_force(true, mpm::NodePhase::nMixture, force)); + REQUIRE_NOTHROW(node->update_internal_force(true, mpm::NodePhase::nLiquid, + 0.5 * force)); + for (unsigned i = 0; i < force.size(); ++i) { + REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + Approx(10.).epsilon(Tolerance)); + REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + Approx(5.).epsilon(Tolerance)); + } + + // Update force to 20.0 + REQUIRE_NOTHROW( + node->update_internal_force(true, mpm::NodePhase::nMixture, force)); + REQUIRE_NOTHROW(node->update_internal_force(true, mpm::NodePhase::nLiquid, + 0.5 * force)); + for (unsigned i = 0; i < force.size(); ++i) { + REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + Approx(20.).epsilon(Tolerance)); + REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + Approx(10.).epsilon(Tolerance)); + } + + // Assign force as 10.0 + REQUIRE_NOTHROW( + node->update_internal_force(false, mpm::NodePhase::nMixture, force)); + REQUIRE_NOTHROW(node->update_internal_force( + false, mpm::NodePhase::nLiquid, 0.5 * force)); + for (unsigned i = 0; i < force.size(); ++i) { + REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + Approx(10.).epsilon(Tolerance)); + REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + Approx(5.).epsilon(Tolerance)); + } + } + + SECTION("Check drag force coefficient") { + // Create a force vector + Eigen::Matrix drag_force_coefficient; + for (unsigned i = 0; i < drag_force_coefficient.size(); ++i) + drag_force_coefficient(i) = 10.; + + // Check current drag force coefficient is zero + for (unsigned i = 0; i < drag_force_coefficient.size(); ++i) + REQUIRE(node->drag_force_coefficient()(i) == + Approx(0.).epsilon(Tolerance)); + + // Update drag force coefficient to 10.0 + REQUIRE_NOTHROW( + node->update_drag_force_coefficient(true, drag_force_coefficient)); + + for (unsigned i = 0; i < drag_force_coefficient.size(); ++i) + REQUIRE(node->drag_force_coefficient()(i) == + Approx(10.).epsilon(Tolerance)); + + // Update force to 20.0 + REQUIRE_NOTHROW( + node->update_drag_force_coefficient(true, drag_force_coefficient)); + + for (unsigned i = 0; i < drag_force_coefficient.size(); ++i) + REQUIRE(node->drag_force_coefficient()(i) == + Approx(20.).epsilon(Tolerance)); + + // Assign force as 10.0 + REQUIRE_NOTHROW( + node->update_drag_force_coefficient(false, drag_force_coefficient)); + for (unsigned i = 0; i < drag_force_coefficient.size(); ++i) + REQUIRE(node->drag_force_coefficient()(i) == + Approx(10.).epsilon(Tolerance)); + } + + SECTION("Check compute acceleration and velocity") { + // Time step + const double dt = 0.1; + + // Nodal mass + double solid_mass = 100.; + double liquid_mass = 100.; + // Update mass to 100. + REQUIRE_NOTHROW( + node->update_mass(false, mpm::NodePhase::nSolid, solid_mass)); + REQUIRE_NOTHROW( + node->update_mass(false, mpm::NodePhase::nLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::nSolid) == + Approx(solid_mass).epsilon(Tolerance)); + REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + Approx(liquid_mass).epsilon(Tolerance)); + + // Check internal force + // Create a force vector + Eigen::Matrix force; + for (unsigned i = 0; i < force.size(); ++i) force(i) = 10. * i; + // Update force to 10.0 + REQUIRE_NOTHROW( + node->update_internal_force(false, mpm::NodePhase::nMixture, force)); + REQUIRE_NOTHROW(node->update_internal_force( + false, mpm::NodePhase::nLiquid, 0.5 * force)); + // Internal force + for (unsigned i = 0; i < force.size(); ++i) { + REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + Approx(force(i)).epsilon(Tolerance)); + REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + Approx(0.5 * force(i)).epsilon(Tolerance)); + } + + // External force + for (unsigned i = 0; i < force.size(); ++i) force(i) = 5. * i; + // Update force to 10.0 + REQUIRE_NOTHROW( + node->update_external_force(false, mpm::NodePhase::nMixture, force)); + REQUIRE_NOTHROW(node->update_external_force( + false, mpm::NodePhase::nLiquid, 0.5 * force)); + for (unsigned i = 0; i < force.size(); ++i) { + REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + Approx(force(i)).epsilon(Tolerance)); + REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + Approx(0.5 * force(i)).epsilon(Tolerance)); + } + + // Drag force + Eigen::Matrix drag_force_coefficient; + for (unsigned i = 0; i < drag_force_coefficient.size(); ++i) + drag_force_coefficient(i) = 5. * i; + // Update force to 10.0 + REQUIRE_NOTHROW( + node->update_drag_force_coefficient(false, drag_force_coefficient)); + for (unsigned i = 0; i < force.size(); ++i) + REQUIRE(node->drag_force_coefficient()(i) == + Approx(drag_force_coefficient(i)).epsilon(Tolerance)); + + REQUIRE(node->compute_acceleration_velocity_twophase_explicit(dt) == + true); + + // Check acceleration + Eigen::Matrix liquid_acceleration; + liquid_acceleration << 0., 0.075; + Eigen::Matrix solid_acceleration; + solid_acceleration << 0., 0.075; + + for (unsigned i = 0; i < solid_acceleration.size(); ++i) { + REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + Approx(solid_acceleration(i)).epsilon(Tolerance)); + REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + Approx(liquid_acceleration(i)).epsilon(Tolerance)); + } + + // Check velocity + Eigen::Matrix solid_velocity = solid_acceleration * dt; + Eigen::Matrix liquid_velocity = liquid_acceleration * dt; + for (unsigned i = 0; i < solid_velocity.size(); ++i) { + REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + Approx(solid_velocity(i)).epsilon(Tolerance)); + REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + Approx(liquid_velocity(i)).epsilon(Tolerance)); + } + + // Apply velocity constraints + REQUIRE(node->assign_velocity_constraint(0, 10.5) == true); + REQUIRE(node->assign_velocity_constraint(1, 0.03) == true); + REQUIRE(node->assign_velocity_constraint(2, 20.5) == true); + REQUIRE(node->assign_velocity_constraint(3, 1.03) == true); + REQUIRE(node->compute_acceleration_velocity_twophase_explicit(dt) == + true); + + // Test velocity with constraints + solid_velocity << 10.5, 0.03; + liquid_velocity << 20.5, 1.03; + for (unsigned i = 0; i < solid_velocity.size(); ++i) { + REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + Approx(solid_velocity(i)).epsilon(Tolerance)); + REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + Approx(liquid_velocity(i)).epsilon(Tolerance)); + } + + // Test acceleration with constraints + solid_acceleration.setZero(); + liquid_acceleration.setZero(); + for (unsigned i = 0; i < solid_acceleration.size(); ++i) { + REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + Approx(solid_acceleration(i)).epsilon(Tolerance)); + REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + Approx(liquid_acceleration(i)).epsilon(Tolerance)); + } + + // Apply cundall damping when calculating acceleration + REQUIRE(node->compute_acceleration_velocity_twophase_explicit_cundall( + dt, 0.05) == true); + + // Test acceleration with cundall damping + solid_acceleration << 0., 0.; + liquid_acceleration << 0., 0.; + for (unsigned i = 0; i < solid_acceleration.size(); ++i) { + REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + Approx(solid_acceleration(i)).epsilon(Tolerance)); + REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + Approx(liquid_acceleration(i)).epsilon(Tolerance)); + } + + // Exception check when mass is zero + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nSolid, 0.)); + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nLiquid, 0.)); + REQUIRE(node->mass(mpm::NodePhase::nSolid) == + Approx(0.).epsilon(Tolerance)); + REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + Approx(0.).epsilon(Tolerance)); + REQUIRE(node->compute_acceleration_velocity_twophase_explicit(dt) == + false); + } + + SECTION("Check momentum, velocity and acceleration") { + // Time step + const double dt = 0.1; + + // Check momentum + Eigen::Matrix momentum; + for (unsigned i = 0; i < momentum.size(); ++i) momentum(i) = 10.; + + // Check initial momentum + for (unsigned i = 0; i < momentum.size(); ++i) { + REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + Approx(0.).epsilon(Tolerance)); + REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + Approx(0.).epsilon(Tolerance)); + } + + // Check update momentum to 10 + REQUIRE_NOTHROW( + node->update_momentum(true, mpm::NodePhase::nSolid, momentum)); + REQUIRE_NOTHROW( + node->update_momentum(true, mpm::NodePhase::nLiquid, momentum)); + for (unsigned i = 0; i < momentum.size(); ++i) { + REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + Approx(10.).epsilon(Tolerance)); + REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + Approx(10.).epsilon(Tolerance)); + } + + // Check update momentum to 20 + REQUIRE_NOTHROW( + node->update_momentum(true, mpm::NodePhase::nSolid, momentum)); + REQUIRE_NOTHROW( + node->update_momentum(true, mpm::NodePhase::nLiquid, momentum)); + for (unsigned i = 0; i < momentum.size(); ++i) { + REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + Approx(20.).epsilon(Tolerance)); + REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + Approx(20.).epsilon(Tolerance)); + } + + // Check assign momentum to 10 + REQUIRE_NOTHROW( + node->update_momentum(false, mpm::NodePhase::nSolid, momentum)); + REQUIRE_NOTHROW( + node->update_momentum(false, mpm::NodePhase::nLiquid, momentum)); + for (unsigned i = 0; i < momentum.size(); ++i) { + REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + Approx(10.).epsilon(Tolerance)); + REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + Approx(10.).epsilon(Tolerance)); + } + + // Check zero velocity + for (unsigned i = 0; i < Dim; ++i) { + REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + Approx(0.).epsilon(Tolerance)); + REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + Approx(0.).epsilon(Tolerance)); + } + + // Check mass + double mass = 0.; + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nSolid, mass)); + REQUIRE(node->mass(mpm::NodePhase::nSolid) == + Approx(0.0).epsilon(Tolerance)); + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nLiquid, mass)); + REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + Approx(0.0).epsilon(Tolerance)); + // Compute and check velocity this should throw zero mass + node->compute_velocity(); + + mass = 100.; + // Update mass to 100.5 + REQUIRE_NOTHROW(node->update_mass(true, mpm::NodePhase::nSolid, mass)); + REQUIRE(node->mass(mpm::NodePhase::nSolid) == + Approx(100.).epsilon(Tolerance)); + REQUIRE_NOTHROW(node->update_mass(true, mpm::NodePhase::nLiquid, mass)); + REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + Approx(100.).epsilon(Tolerance)); + + // Compute and check velocity + node->compute_velocity(); + for (unsigned i = 0; i < Dim; ++i) { + REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + Approx(0.1).epsilon(Tolerance)); + REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + Approx(0.1).epsilon(Tolerance)); + } + + // Check acceleration + Eigen::Matrix acceleration; + for (unsigned i = 0; i < acceleration.size(); ++i) acceleration(i) = 5.; + + for (unsigned i = 0; i < acceleration.size(); ++i) { + REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + Approx(0.).epsilon(Tolerance)); + REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + Approx(0.).epsilon(Tolerance)); + } + + REQUIRE_NOTHROW(node->update_acceleration(true, mpm::NodePhase::nSolid, + acceleration)); + REQUIRE_NOTHROW(node->update_acceleration(true, mpm::NodePhase::nLiquid, + acceleration)); + for (unsigned i = 0; i < acceleration.size(); ++i) { + REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + Approx(5.).epsilon(Tolerance)); + REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + Approx(5.).epsilon(Tolerance)); + } + + // Check if exception is handled + Eigen::Matrix acceleration_bad; + for (unsigned i = 0; i < acceleration_bad.size(); ++i) + acceleration_bad(i) = 10.; + + // Check velocity before constraints + Eigen::Matrix velocity; + velocity << 0.1, 0.1; + for (unsigned i = 0; i < velocity.size(); ++i) { + REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + Approx(velocity(i)).epsilon(Tolerance)); + REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + Approx(velocity(i)).epsilon(Tolerance)); + } + + // Check acceleration before constraints + acceleration << 5., 5.; + for (unsigned i = 0; i < acceleration.size(); ++i) { + REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + Approx(acceleration(i)).epsilon(Tolerance)); + REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + Approx(acceleration(i)).epsilon(Tolerance)); + } + + SECTION("Check Cartesian velocity constraints") { + // Apply velocity constraints + REQUIRE(node->assign_velocity_constraint(0, -12.5) == true); + // Check out of bounds condition + REQUIRE(node->assign_velocity_constraint(2, -12.5) == true); + + // Apply constraints + node->apply_velocity_constraints(); + + // Check apply constraints + velocity << -12.5, 0.1; + for (unsigned i = 0; i < velocity.size(); ++i) { + REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + Approx(velocity(i)).epsilon(Tolerance)); + REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + Approx(velocity(i)).epsilon(Tolerance)); + } + + acceleration << 0., 5.; + for (unsigned i = 0; i < acceleration.size(); ++i) { + REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + Approx(acceleration(i)).epsilon(Tolerance)); + REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + Approx(acceleration(i)).epsilon(Tolerance)); + } + } + + SECTION("Check general velocity constraints in 1 direction") { + // Apply velocity constraints + REQUIRE(node->assign_velocity_constraint(0, -12.5) == true); + REQUIRE(node->assign_velocity_constraint(2, -12.5) == true); + + // Apply rotation matrix with Euler angles alpha = 10 deg, beta + // = 30 deg + Eigen::Matrix euler_angles; + euler_angles << 10. * M_PI / 180, 30. * M_PI / 180; + const auto rotation_matrix = + mpm::geometry::rotation_matrix(euler_angles); + node->assign_rotation_matrix(rotation_matrix); + const auto inverse_rotation_matrix = rotation_matrix.inverse(); + + // Apply inclined velocity constraints + node->apply_velocity_constraints(); + + // Check applied velocity constraints in the global coordinates + velocity << -9.583478335521184, -8.025403099849004; + for (unsigned i = 0; i < Dim; ++i) { + REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + Approx(velocity(i)).epsilon(Tolerance)); + REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + Approx(velocity(i)).epsilon(Tolerance)); + } + + // Check that the velocity is as specified in local coordinate + REQUIRE((inverse_rotation_matrix * + node->velocity(mpm::NodePhase::nSolid))(0) == + Approx(-12.5).epsilon(Tolerance)); + REQUIRE((inverse_rotation_matrix * + node->velocity(mpm::NodePhase::nLiquid))(0) == + Approx(-12.5).epsilon(Tolerance)); + + // Check applied constraints on acceleration in the global coordinates + acceleration << -0.396139826697847, 0.472101061636807; + for (unsigned i = 0; i < Dim; ++i) { + REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + Approx(acceleration(i)).epsilon(Tolerance)); + REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + Approx(acceleration(i)).epsilon(Tolerance)); + } + + // Check that the acceleration is 0 in local coordinate + REQUIRE((inverse_rotation_matrix * + node->acceleration(mpm::NodePhase::nSolid))(0) == + Approx(0).epsilon(Tolerance)); + REQUIRE((inverse_rotation_matrix * + node->acceleration(mpm::NodePhase::nLiquid))(0) == + Approx(0).epsilon(Tolerance)); + } + + SECTION("Check general velocity constraints in all directions") { + // Apply velocity constraints + REQUIRE(node->assign_velocity_constraint(0, -12.5) == true); + REQUIRE(node->assign_velocity_constraint(1, 7.5) == true); + REQUIRE(node->assign_velocity_constraint(2, -12.5) == true); + REQUIRE(node->assign_velocity_constraint(3, 7.5) == true); + + // Apply rotation matrix with Euler angles alpha = -10 deg, beta = 30 + // deg + Eigen::Matrix euler_angles; + euler_angles << -10. * M_PI / 180, 30. * M_PI / 180; + const auto rotation_matrix = + mpm::geometry::rotation_matrix(euler_angles); + node->assign_rotation_matrix(rotation_matrix); + const auto inverse_rotation_matrix = rotation_matrix.inverse(); + + // Apply inclined velocity constraints + node->apply_velocity_constraints(); + + // Check applied velocity constraints in the global coordinates + velocity << -14.311308834766370, 2.772442864323454; + for (unsigned i = 0; i < Dim; ++i) { + REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + Approx(velocity(i)).epsilon(Tolerance)); + REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + Approx(velocity(i)).epsilon(Tolerance)); + } + + // Check that the velocity is as specified in local coordinate + REQUIRE((inverse_rotation_matrix * + node->velocity(mpm::NodePhase::nSolid))(0) == + Approx(-12.5).epsilon(Tolerance)); + REQUIRE((inverse_rotation_matrix * + node->velocity(mpm::NodePhase::nSolid))(1) == + Approx(7.5).epsilon(Tolerance)); + REQUIRE((inverse_rotation_matrix * + node->velocity(mpm::NodePhase::nLiquid))(0) == + Approx(-12.5).epsilon(Tolerance)); + REQUIRE((inverse_rotation_matrix * + node->velocity(mpm::NodePhase::nLiquid))(1) == + Approx(7.5).epsilon(Tolerance)); + + // Check applied constraints on acceleration in the global coordinates + acceleration << 0, 0; + for (unsigned i = 0; i < Dim; ++i) { + REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + Approx(acceleration(i)).epsilon(Tolerance)); + REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + Approx(acceleration(i)).epsilon(Tolerance)); + } + + // Check that the acceleration is 0 in local coordinate + REQUIRE((inverse_rotation_matrix * + node->acceleration(mpm::NodePhase::nSolid))(0) == + Approx(0).epsilon(Tolerance)); + REQUIRE((inverse_rotation_matrix * + node->acceleration(mpm::NodePhase::nSolid))(1) == + Approx(0).epsilon(Tolerance)); + REQUIRE((inverse_rotation_matrix * + node->acceleration(mpm::NodePhase::nLiquid))(0) == + Approx(0).epsilon(Tolerance)); + REQUIRE((inverse_rotation_matrix * + node->acceleration(mpm::NodePhase::nLiquid))(1) == + Approx(0).epsilon(Tolerance)); + } + + SECTION("Check Cartesian friction constraints") { + // Apply friction constraints + REQUIRE(node->assign_friction_constraint(1, 1, 0.2) == true); + // Check out of bounds condition + REQUIRE(node->assign_friction_constraint(2, 1, 0.2) == false); + + // Apply friction constraints + node->apply_friction_constraints(dt); + + // Check apply constraints + acceleration << 4., 5.; + for (unsigned i = 0; i < acceleration.size(); ++i) + REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + Approx(acceleration(i)).epsilon(Tolerance)); + } + + SECTION("Check general friction constraints in 1 direction") { + // Apply friction constraints + REQUIRE(node->assign_friction_constraint(1, 1, 0.2) == true); + + // Apply rotation matrix with Euler angles alpha = 10 deg, beta = 30 deg + Eigen::Matrix euler_angles; + euler_angles << 10. * M_PI / 180, 30. * M_PI / 180; + const auto rotation_matrix = + mpm::geometry::rotation_matrix(euler_angles); + node->assign_rotation_matrix(rotation_matrix); + const auto inverse_rotation_matrix = rotation_matrix.inverse(); + + // Apply general friction constraints + node->apply_friction_constraints(dt); + + // Check applied constraints on acceleration in the global coordinates + acceleration << 4.905579787672637, 4.920772034660430; + for (unsigned i = 0; i < Dim; ++i) + REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + Approx(acceleration(i)).epsilon(Tolerance)); + + // Check the acceleration in local coordinate + acceleration << 6.920903430595146, 0.616284167162194; + for (unsigned i = 0; i < Dim; ++i) + REQUIRE((inverse_rotation_matrix * + node->acceleration(mpm::NodePhase::nSolid))(i) == + Approx(acceleration(i)).epsilon(Tolerance)); + } + } + + SECTION("Check node material ids") { + // Add material to nodes + node->append_material_id(0); + node->append_material_id(1); + node->append_material_id(4); + node->append_material_id(0); + node->append_material_id(2); + + // Check size of material_ids + REQUIRE(node->material_ids().size() == 4); + + // Check elements of material_ids + std::vector material_ids = {0, 1, 2, 4}; + auto mat_ids = node->material_ids(); + unsigned i = 0; + for (auto mitr = mat_ids.begin(); mitr != mat_ids.end(); ++mitr, ++i) + REQUIRE(*mitr == material_ids.at(i)); + } + } +} + +// \brief Check node class for 3D case +TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2P]") { + const unsigned Dim = 3; + const unsigned Dof = 3; + const unsigned Nphases = 2; + + Eigen::Vector3d coords; + coords.setZero(); + + // Check for id = 0 + SECTION("Node id is zero") { + mpm::Index id = 0; + std::shared_ptr> node = + std::make_shared>(id, coords); + REQUIRE(node->id() == 0); + } + + // Check for id is a positive value + SECTION("Node id is positive") { + mpm::Index id = std::numeric_limits::max(); + std::shared_ptr> node = + std::make_shared>(id, coords); + REQUIRE(node->id() == std::numeric_limits::max()); + } + + // Check for degrees of freedom + SECTION("Check degrees of freedom") { + mpm::Index id = 0; + std::shared_ptr> node = + std::make_shared>(id, coords); + REQUIRE(node->dof() == 3); + } + + // Check status + SECTION("Check status") { + mpm::Index id = 0; + std::shared_ptr> node = + std::make_shared>(id, coords); + REQUIRE(node->status() == false); + node->assign_status(true); + REQUIRE(node->status() == true); + } + + SECTION("Boundary ghost id") { + mpm::Index id = 0; + std::shared_ptr> node = + std::make_shared>(id, coords); + node->ghost_id(5); + REQUIRE(node->ghost_id() == 5); + } + + // Check MPI Rank + SECTION("Check MPI Rank") { + mpm::Index id = 0; + std::shared_ptr> node = + std::make_shared>(id, coords); + REQUIRE(node->id() == 0); + + // Assign MPI ranks + node->mpi_rank(0); + node->mpi_rank(0); + node->mpi_rank(1); + + std::set ranks = node->mpi_ranks(); + REQUIRE(ranks.size() == 2); + std::vector mpi_ranks = {0, 1}; + unsigned i = 0; + for (auto it = ranks.begin(); it != ranks.end(); ++it, ++i) + REQUIRE(*it == mpi_ranks.at(i)); + } + + // Test coordinates function + SECTION("coordinates function is checked") { + mpm::Index id = 0; + const double Tolerance = 1.E-7; + + std::shared_ptr> node = + std::make_shared>(id, coords); + + // Check for coordinates being zero + auto coordinates = node->coordinates(); + for (unsigned i = 0; i < coordinates.size(); ++i) + REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + REQUIRE(coordinates.size() == Dim); + + // Check for negative value of coordinates + for (unsigned i = 0; i < coordinates.size(); ++i) + coords(i) = -1. * std::numeric_limits::max(); + node->assign_coordinates(coords); + coordinates = node->coordinates(); + for (unsigned i = 0; i < coordinates.size(); ++i) + REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + + REQUIRE(coordinates.size() == Dim); + + // Check for positive value of coordinates + for (unsigned i = 0; i < coordinates.size(); ++i) + coords(i) = std::numeric_limits::max(); + node->assign_coordinates(coords); + coordinates = node->coordinates(); + for (unsigned i = 0; i < coordinates.size(); ++i) + REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + + REQUIRE(coordinates.size() == Dim); + } + + SECTION("Check nodal properties") { + mpm::Index id = 0; + const double Tolerance = 1.E-7; + std::shared_ptr> node = + std::make_shared>(id, coords); + + // Check mass + REQUIRE(node->mass(mpm::NodePhase::nSolid) == + Approx(0.0).epsilon(Tolerance)); + REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + Approx(0.0).epsilon(Tolerance)); + double solid_mass = 100.5; + double liquid_mass = 200.5; + // Update mass to 100.5 and 200.5 + REQUIRE_NOTHROW( + node->update_mass(true, mpm::NodePhase::nSolid, solid_mass)); + REQUIRE_NOTHROW( + node->update_mass(true, mpm::NodePhase::nLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::nSolid) == + Approx(100.5).epsilon(Tolerance)); + REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + Approx(200.5).epsilon(Tolerance)); + // Update mass to 201 and 401 + REQUIRE_NOTHROW( + node->update_mass(true, mpm::NodePhase::nSolid, solid_mass)); + REQUIRE_NOTHROW( + node->update_mass(true, mpm::NodePhase::nLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::nSolid) == + Approx(201.0).epsilon(Tolerance)); + REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + Approx(401.0).epsilon(Tolerance)); + // Assign mass to 100 and 200 + solid_mass = 100.; + liquid_mass = 200.; + REQUIRE_NOTHROW( + node->update_mass(false, mpm::NodePhase::nSolid, solid_mass)); + REQUIRE_NOTHROW( + node->update_mass(false, mpm::NodePhase::nLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::nSolid) == + Approx(100.0).epsilon(Tolerance)); + REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + Approx(200.0).epsilon(Tolerance)); + + SECTION("Check nodal pressure") { + // Check pressure + REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + Approx(0.0).epsilon(Tolerance)); + REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + Approx(0.0).epsilon(Tolerance)); + double pressure = 1000.7; + double pore_pressure = 2000.7; + // Update pressure to 1000.7 and 2000.7 + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nSolid, + solid_mass * pressure)); + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nLiquid, + liquid_mass * pore_pressure)); + REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + Approx(1000.7).epsilon(Tolerance)); + REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + Approx(2000.7).epsilon(Tolerance)); + // Update pressure to 2001.4 and 4001.4 + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nSolid, + solid_mass * pressure)); + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nLiquid, + liquid_mass * pore_pressure)); + REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + Approx(2001.4).epsilon(Tolerance)); + REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + Approx(4001.4).epsilon(Tolerance)); + // Assign pressure to 1000 and 2000 + pressure = 1000.; + pore_pressure = 2000.; + node->assign_pressure(mpm::NodePhase::nSolid, pressure); + node->assign_pressure(mpm::NodePhase::nLiquid, pore_pressure); + REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + Approx(1000.0).epsilon(Tolerance)); + REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + Approx(2000.0).epsilon(Tolerance)); + // Assign mass to 0 + solid_mass = 0.; + liquid_mass = 0.; + REQUIRE_NOTHROW( + node->update_mass(false, mpm::NodePhase::nSolid, solid_mass)); + REQUIRE_NOTHROW( + node->update_mass(false, mpm::NodePhase::nLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::nSolid) == + Approx(0.0).epsilon(Tolerance)); + REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + Approx(0.0).epsilon(Tolerance)); + // Try to update pressure to 2000, should throw and keep to 1000. + node->assign_pressure(mpm::NodePhase::nSolid, pressure); + node->assign_pressure(mpm::NodePhase::nLiquid, pore_pressure); + REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + Approx(1000.0).epsilon(Tolerance)); + REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + Approx(2000.0).epsilon(Tolerance)); + } + + SECTION("Check external force") { + // Create a force vector + Eigen::Matrix force; + for (unsigned i = 0; i < force.size(); ++i) force(i) = 10.; + + // Check current external force is zero + for (unsigned i = 0; i < force.size(); ++i) { + REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + Approx(0.).epsilon(Tolerance)); + REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + Approx(0.).epsilon(Tolerance)); + } + + // Update force to 10.0 + REQUIRE_NOTHROW( + node->update_external_force(true, mpm::NodePhase::nMixture, force)); + REQUIRE_NOTHROW(node->update_external_force(true, mpm::NodePhase::nLiquid, + 0.5 * force)); + for (unsigned i = 0; i < force.size(); ++i) { + REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + Approx(10.).epsilon(Tolerance)); + REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + Approx(5.).epsilon(Tolerance)); + } + + // Update force to 20.0 + REQUIRE_NOTHROW( + node->update_external_force(true, mpm::NodePhase::nMixture, force)); + REQUIRE_NOTHROW(node->update_external_force(true, mpm::NodePhase::nLiquid, + 0.5 * force)); + for (unsigned i = 0; i < force.size(); ++i) { + REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + Approx(20.).epsilon(Tolerance)); + REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + Approx(10.).epsilon(Tolerance)); + } + + // Assign force as 10.0 + REQUIRE_NOTHROW( + node->update_external_force(false, mpm::NodePhase::nMixture, force)); + REQUIRE_NOTHROW(node->update_external_force( + false, mpm::NodePhase::nLiquid, 0.5 * force)); + for (unsigned i = 0; i < force.size(); ++i) { + REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + Approx(10.).epsilon(Tolerance)); + REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + Approx(5.).epsilon(Tolerance)); + } + + SECTION("Check concentrated force") { + // Set external force to zero + force.setZero(); + REQUIRE_NOTHROW(node->update_external_force( + false, mpm::NodePhase::nMixture, force)); + + // Concentrated force + std::shared_ptr ffunction = nullptr; + double concentrated_force = 65.32; + const unsigned Direction = 0; + // Check traction + for (unsigned i = 0; i < Dim; ++i) + REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + Approx(0.).epsilon(Tolerance)); + + REQUIRE(node->assign_concentrated_force(mpm::NodePhase::nMixture, + Direction, concentrated_force, + ffunction) == true); + double current_time = 0.0; + node->apply_concentrated_force(mpm::NodePhase::nMixture, current_time); + + for (unsigned i = 0; i < Dim; ++i) { + if (i == Direction) + REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + Approx(concentrated_force).epsilon(Tolerance)); + + else + REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + Approx(0.).epsilon(Tolerance)); + } + + // Check for incorrect direction / phase + const unsigned wrong_dir = 4; + REQUIRE(node->assign_concentrated_force(mpm::NodePhase::nMixture, + wrong_dir, concentrated_force, + ffunction) == false); + + // Check again to ensure value hasn't been updated + for (unsigned i = 0; i < Dim; ++i) { + if (i == Direction) + REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + Approx(concentrated_force).epsilon(Tolerance)); + else + REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + Approx(0.).epsilon(Tolerance)); + } + } + } + + SECTION("Check internal force") { + // Create a force vector + Eigen::Matrix force; + for (unsigned i = 0; i < force.size(); ++i) force(i) = 10.; + + // Check current internal force is zero + for (unsigned i = 0; i < force.size(); ++i) { + REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + Approx(0.).epsilon(Tolerance)); + REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + Approx(0.).epsilon(Tolerance)); + } + + // Update force to 10.0 + REQUIRE_NOTHROW( + node->update_internal_force(true, mpm::NodePhase::nMixture, force)); + REQUIRE_NOTHROW(node->update_internal_force(true, mpm::NodePhase::nLiquid, + 0.5 * force)); + for (unsigned i = 0; i < force.size(); ++i) { + REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + Approx(10.).epsilon(Tolerance)); + REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + Approx(5.).epsilon(Tolerance)); + } + + // Update force to 20.0 + REQUIRE_NOTHROW( + node->update_internal_force(true, mpm::NodePhase::nMixture, force)); + REQUIRE_NOTHROW(node->update_internal_force(true, mpm::NodePhase::nLiquid, + 0.5 * force)); + for (unsigned i = 0; i < force.size(); ++i) { + REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + Approx(20.).epsilon(Tolerance)); + REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + Approx(10.).epsilon(Tolerance)); + } + + // Assign force as 10.0 + REQUIRE_NOTHROW( + node->update_internal_force(false, mpm::NodePhase::nMixture, force)); + REQUIRE_NOTHROW(node->update_internal_force( + false, mpm::NodePhase::nLiquid, 0.5 * force)); + for (unsigned i = 0; i < force.size(); ++i) { + REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + Approx(10.).epsilon(Tolerance)); + REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + Approx(5.).epsilon(Tolerance)); + } + } + + SECTION("Check drag force coefficient") { + // Create a force vector + Eigen::Matrix drag_force_coefficient; + for (unsigned i = 0; i < drag_force_coefficient.size(); ++i) + drag_force_coefficient(i) = 10.; + + // Check current drag force coefficient is zero + for (unsigned i = 0; i < drag_force_coefficient.size(); ++i) + REQUIRE(node->drag_force_coefficient()(i) == + Approx(0.).epsilon(Tolerance)); + + // Update drag force coefficient to 10.0 + REQUIRE_NOTHROW( + node->update_drag_force_coefficient(true, drag_force_coefficient)); + + for (unsigned i = 0; i < drag_force_coefficient.size(); ++i) + REQUIRE(node->drag_force_coefficient()(i) == + Approx(10.).epsilon(Tolerance)); + + // Update force to 20.0 + REQUIRE_NOTHROW( + node->update_drag_force_coefficient(true, drag_force_coefficient)); + + for (unsigned i = 0; i < drag_force_coefficient.size(); ++i) + REQUIRE(node->drag_force_coefficient()(i) == + Approx(20.).epsilon(Tolerance)); + + // Assign force as 10.0 + REQUIRE_NOTHROW( + node->update_drag_force_coefficient(false, drag_force_coefficient)); + for (unsigned i = 0; i < drag_force_coefficient.size(); ++i) + REQUIRE(node->drag_force_coefficient()(i) == + Approx(10.).epsilon(Tolerance)); + } + + SECTION("Check compute acceleration and velocity") { + // Time step + const double dt = 0.1; + + // Nodal mass + double solid_mass = 100.; + double liquid_mass = 100.; + // Update mass to 100. + REQUIRE_NOTHROW( + node->update_mass(false, mpm::NodePhase::nSolid, solid_mass)); + REQUIRE_NOTHROW( + node->update_mass(false, mpm::NodePhase::nLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::nSolid) == + Approx(solid_mass).epsilon(Tolerance)); + REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + Approx(liquid_mass).epsilon(Tolerance)); + + // Check internal force + // Create a force vector + Eigen::Matrix force; + for (unsigned i = 0; i < force.size(); ++i) force(i) = 10. * i; + // Update force to 10.0 + REQUIRE_NOTHROW( + node->update_internal_force(false, mpm::NodePhase::nMixture, force)); + REQUIRE_NOTHROW(node->update_internal_force( + false, mpm::NodePhase::nLiquid, 0.5 * force)); + // Internal force + for (unsigned i = 0; i < force.size(); ++i) { + REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + Approx(force(i)).epsilon(Tolerance)); + REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + Approx(0.5 * force(i)).epsilon(Tolerance)); + } + + // External force + for (unsigned i = 0; i < force.size(); ++i) force(i) = 5. * i; + // Update force to 10.0 + REQUIRE_NOTHROW( + node->update_external_force(false, mpm::NodePhase::nMixture, force)); + REQUIRE_NOTHROW(node->update_external_force( + false, mpm::NodePhase::nLiquid, 0.5 * force)); + for (unsigned i = 0; i < force.size(); ++i) { + REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + Approx(force(i)).epsilon(Tolerance)); + REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + Approx(0.5 * force(i)).epsilon(Tolerance)); + } + + // Drag force + Eigen::Matrix drag_force_coefficient; + for (unsigned i = 0; i < drag_force_coefficient.size(); ++i) + drag_force_coefficient(i) = 5. * i; + // Update force to 10.0 + REQUIRE_NOTHROW( + node->update_drag_force_coefficient(false, drag_force_coefficient)); + for (unsigned i = 0; i < force.size(); ++i) + REQUIRE(node->drag_force_coefficient()(i) == + Approx(drag_force_coefficient(i)).epsilon(Tolerance)); + + REQUIRE(node->compute_acceleration_velocity_twophase_explicit(dt) == + true); + + // Check acceleration + Eigen::Matrix solid_acceleration; + solid_acceleration << 0., 0.075, 0.15; + Eigen::Matrix liquid_acceleration; + liquid_acceleration << 0., 0.075, 0.15; + + // Check acceleration + for (unsigned i = 0; i < solid_acceleration.size(); ++i) { + REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + Approx(solid_acceleration(i)).epsilon(Tolerance)); + REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + Approx(liquid_acceleration(i)).epsilon(Tolerance)); + } + + // Check velocity + Eigen::Matrix solid_velocity = solid_acceleration * dt; + Eigen::Matrix liquid_velocity = liquid_acceleration * dt; + for (unsigned i = 0; i < solid_velocity.size(); ++i) { + REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + Approx(solid_velocity(i)).epsilon(Tolerance)); + REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + Approx(liquid_velocity(i)).epsilon(Tolerance)); + } + + // Apply velocity constraints + REQUIRE(node->assign_velocity_constraint(0, 10.5) == true); + REQUIRE(node->assign_velocity_constraint(1, 0.03) == true); + REQUIRE(node->assign_velocity_constraint(2, 5.13) == true); + REQUIRE(node->assign_velocity_constraint(3, 20.5) == true); + REQUIRE(node->assign_velocity_constraint(4, 1.03) == true); + REQUIRE(node->assign_velocity_constraint(5, 7.13) == true); + REQUIRE(node->compute_acceleration_velocity_twophase_explicit(dt) == + true); + + // Test velocity with constraints + solid_velocity << 10.5, 0.03, 5.13; + liquid_velocity << 20.5, 1.03, 7.13; + for (unsigned i = 0; i < solid_velocity.size(); ++i) { + REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + Approx(solid_velocity(i)).epsilon(Tolerance)); + REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + Approx(liquid_velocity(i)).epsilon(Tolerance)); + } + + // Test acceleration with constraints + solid_acceleration.setZero(); + liquid_acceleration.setZero(); + for (unsigned i = 0; i < solid_acceleration.size(); ++i) { + REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + Approx(solid_acceleration(i)).epsilon(Tolerance)); + REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + Approx(liquid_acceleration(i)).epsilon(Tolerance)); + } + + // Apply cundall damping when calculating acceleration + REQUIRE(node->compute_acceleration_velocity_twophase_explicit_cundall( + dt, 0.05) == true); + + // Test acceleration with cundall damping + solid_acceleration << 0., 0., 0.; + liquid_acceleration << 0., 0., 0.; + for (unsigned i = 0; i < solid_acceleration.size(); ++i) { + REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + Approx(solid_acceleration(i)).epsilon(Tolerance)); + REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + Approx(liquid_acceleration(i)).epsilon(Tolerance)); + } + + // Apply velocity constraints + REQUIRE(node->assign_velocity_constraint(0, 10.5) == true); + REQUIRE(node->assign_velocity_constraint(1, 20.5) == true); + REQUIRE(node->compute_acceleration_velocity_twophase_explicit(dt) == + true); + + // Exception check when mass is zero + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nSolid, 0.)); + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nLiquid, 0.)); + REQUIRE(node->mass(mpm::NodePhase::nSolid) == + Approx(0.).epsilon(Tolerance)); + REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + Approx(0.).epsilon(Tolerance)); + REQUIRE(node->compute_acceleration_velocity_twophase_explicit(dt) == + false); + } + + SECTION("Check momentum, velocity and acceleration") { + // Time step + const double dt = 0.1; + + // Check momentum + Eigen::Matrix momentum; + for (unsigned i = 0; i < momentum.size(); ++i) momentum(i) = 10.; + + // Check initial momentum + for (unsigned i = 0; i < momentum.size(); ++i) { + REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + Approx(0.).epsilon(Tolerance)); + REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + Approx(0.).epsilon(Tolerance)); + } + + // Check update momentum to 10 + REQUIRE_NOTHROW( + node->update_momentum(true, mpm::NodePhase::nSolid, momentum)); + REQUIRE_NOTHROW( + node->update_momentum(true, mpm::NodePhase::nLiquid, momentum)); + for (unsigned i = 0; i < momentum.size(); ++i) { + REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + Approx(10.).epsilon(Tolerance)); + REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + Approx(10.).epsilon(Tolerance)); + } + + // Check update momentum to 20 + REQUIRE_NOTHROW( + node->update_momentum(true, mpm::NodePhase::nSolid, momentum)); + REQUIRE_NOTHROW( + node->update_momentum(true, mpm::NodePhase::nLiquid, momentum)); + for (unsigned i = 0; i < momentum.size(); ++i) { + REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + Approx(20.).epsilon(Tolerance)); + REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + Approx(20.).epsilon(Tolerance)); + } + + // Check assign momentum to 10 + REQUIRE_NOTHROW( + node->update_momentum(false, mpm::NodePhase::nSolid, momentum)); + REQUIRE_NOTHROW( + node->update_momentum(false, mpm::NodePhase::nLiquid, momentum)); + for (unsigned i = 0; i < momentum.size(); ++i) { + REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + Approx(10.).epsilon(Tolerance)); + REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + Approx(10.).epsilon(Tolerance)); + } + + // Check zero velocity + for (unsigned i = 0; i < Dim; ++i) { + REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + Approx(0.).epsilon(Tolerance)); + REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + Approx(0.).epsilon(Tolerance)); + } + + // Check mass + double mass = 0.; + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nSolid, mass)); + REQUIRE(node->mass(mpm::NodePhase::nSolid) == + Approx(0.0).epsilon(Tolerance)); + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nLiquid, mass)); + REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + Approx(0.0).epsilon(Tolerance)); + // Compute and check velocity this should throw zero mass + node->compute_velocity(); + + mass = 100.; + // Update mass to 100.5 + REQUIRE_NOTHROW(node->update_mass(true, mpm::NodePhase::nSolid, mass)); + REQUIRE(node->mass(mpm::NodePhase::nSolid) == + Approx(100.).epsilon(Tolerance)); + REQUIRE_NOTHROW(node->update_mass(true, mpm::NodePhase::nLiquid, mass)); + REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + Approx(100.).epsilon(Tolerance)); + + // Check zero velocity + for (unsigned i = 0; i < Dim; ++i) { + REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + Approx(0.).epsilon(Tolerance)); + REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + Approx(0.).epsilon(Tolerance)); + } + + // Compute and check velocity + node->compute_velocity(); + for (unsigned i = 0; i < Dim; ++i) { + REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + Approx(0.1).epsilon(Tolerance)); + REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + Approx(0.1).epsilon(Tolerance)); + } + + // Check acceleration + Eigen::Matrix acceleration; + for (unsigned i = 0; i < acceleration.size(); ++i) acceleration(i) = 5.; + + for (unsigned i = 0; i < acceleration.size(); ++i) { + REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + Approx(0.).epsilon(Tolerance)); + REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + Approx(0.).epsilon(Tolerance)); + } + + REQUIRE_NOTHROW(node->update_acceleration(true, mpm::NodePhase::nSolid, + acceleration)); + REQUIRE_NOTHROW(node->update_acceleration(true, mpm::NodePhase::nLiquid, + acceleration)); + for (unsigned i = 0; i < acceleration.size(); ++i) { + REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + Approx(5.).epsilon(Tolerance)); + REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + Approx(5.).epsilon(Tolerance)); + } + + // Check velocity before constraints + Eigen::Matrix velocity; + velocity << 0.1, 0.1, 0.1; + for (unsigned i = 0; i < velocity.size(); ++i) { + REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + Approx(velocity(i)).epsilon(Tolerance)); + REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + Approx(velocity(i)).epsilon(Tolerance)); + } + + // Check acceleration before constraints + acceleration << 5., 5.; + for (unsigned i = 0; i < acceleration.size(); ++i) { + REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + Approx(acceleration(i)).epsilon(Tolerance)); + REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + Approx(acceleration(i)).epsilon(Tolerance)); + } + SECTION("Check Cartesian velocity constraints") { + // Apply velocity constraints + REQUIRE(node->assign_velocity_constraint(0, -12.5) == true); + // Check out of bounds condition + REQUIRE(node->assign_velocity_constraint(3, -12.5) == true); + + // Apply constraints + node->apply_velocity_constraints(); + + // Check apply constraints + velocity << -12.5, 0.1; + for (unsigned i = 0; i < velocity.size(); ++i) { + REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + Approx(velocity(i)).epsilon(Tolerance)); + REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + Approx(velocity(i)).epsilon(Tolerance)); + } + + acceleration << 0., 5.; + for (unsigned i = 0; i < acceleration.size(); ++i) { + REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + Approx(acceleration(i)).epsilon(Tolerance)); + REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + Approx(acceleration(i)).epsilon(Tolerance)); + } + } + SECTION("Check general velocity constraints in 2 directions") { + // Apply velocity constraints + REQUIRE(node->assign_velocity_constraint(0, -12.5) == true); + REQUIRE(node->assign_velocity_constraint(3, -12.5) == true); + + // Apply rotation matrix with Euler angles alpha = 10 deg, beta + // = 30 deg + Eigen::Matrix euler_angles; + euler_angles << 10. * M_PI / 180, 30. * M_PI / 180; + const auto rotation_matrix = + mpm::geometry::rotation_matrix(euler_angles); + node->assign_rotation_matrix(rotation_matrix); + const auto inverse_rotation_matrix = rotation_matrix.inverse(); + + // Apply inclined velocity constraints + node->apply_velocity_constraints(); + + // Check apply constraints + velocity << -9.5834783355, -8.0254030998, 0.1; + for (unsigned i = 0; i < Dim; ++i) { + REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + Approx(velocity(i)).epsilon(Tolerance)); + REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + Approx(velocity(i)).epsilon(Tolerance)); + } + + // Check that the velocity is as specified in local coordinate + REQUIRE((inverse_rotation_matrix * + node->velocity(mpm::NodePhase::nSolid))(0) == + Approx(-12.5).epsilon(Tolerance)); + REQUIRE((inverse_rotation_matrix * + node->velocity(mpm::NodePhase::nLiquid))(0) == + Approx(-12.5).epsilon(Tolerance)); + + // Check applied constraints on acceleration in the global coordinates + acceleration << -0.3961398267, 0.4721010616, 5.0; + for (unsigned i = 0; i < Dim; ++i) { + REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + Approx(acceleration(i)).epsilon(Tolerance)); + REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + Approx(acceleration(i)).epsilon(Tolerance)); + } + + // Check that the acceleration is 0 in local coordinate + REQUIRE((inverse_rotation_matrix * + node->acceleration(mpm::NodePhase::nSolid))(0) == + Approx(0).epsilon(Tolerance)); + REQUIRE((inverse_rotation_matrix * + node->acceleration(mpm::NodePhase::nLiquid))(0) == + Approx(0).epsilon(Tolerance)); + } + + SECTION("Check general velocity constraints in all directions") { + // Apply velocity constraints + REQUIRE(node->assign_velocity_constraint(0, 10.5) == true); + REQUIRE(node->assign_velocity_constraint(1, -12.5) == true); + REQUIRE(node->assign_velocity_constraint(2, 7.5) == true); + REQUIRE(node->assign_velocity_constraint(3, 10.5) == true); + REQUIRE(node->assign_velocity_constraint(4, -12.5) == true); + REQUIRE(node->assign_velocity_constraint(5, 7.5) == true); + + // Apply rotation matrix with Euler angles alpha = -10 deg, beta = 20, + // deg and gamma = -30 deg + Eigen::Matrix euler_angles; + euler_angles << -10. * M_PI / 180, 20. * M_PI / 180, -30. * M_PI / 180; + const auto rotation_matrix = + mpm::geometry::rotation_matrix(euler_angles); + node->assign_rotation_matrix(rotation_matrix); + const auto inverse_rotation_matrix = rotation_matrix.inverse(); + + // Apply constraints + node->apply_velocity_constraints(); + + // Check apply constraints + velocity << 13.351984588153375, -5.717804716697730, 10.572663655835457; + for (unsigned i = 0; i < Dim; ++i) { + REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + Approx(velocity(i)).epsilon(Tolerance)); + REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + Approx(velocity(i)).epsilon(Tolerance)); + } + + // Check that the velocity is as specified in local coordinate + REQUIRE((inverse_rotation_matrix * + node->velocity(mpm::NodePhase::nSolid))(0) == + Approx(10.5).epsilon(Tolerance)); + REQUIRE((inverse_rotation_matrix * + node->velocity(mpm::NodePhase::nSolid))(1) == + Approx(-12.5).epsilon(Tolerance)); + REQUIRE((inverse_rotation_matrix * + node->velocity(mpm::NodePhase::nSolid))(2) == + Approx(7.5).epsilon(Tolerance)); + REQUIRE((inverse_rotation_matrix * + node->velocity(mpm::NodePhase::nLiquid))(0) == + Approx(10.5).epsilon(Tolerance)); + REQUIRE((inverse_rotation_matrix * + node->velocity(mpm::NodePhase::nLiquid))(1) == + Approx(-12.5).epsilon(Tolerance)); + REQUIRE((inverse_rotation_matrix * + node->velocity(mpm::NodePhase::nLiquid))(2) == + Approx(7.5).epsilon(Tolerance)); + + // Check apply constraints + acceleration << 0, 0, 0; + for (unsigned i = 0; i < Dim; ++i) { + REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + Approx(acceleration(i)).epsilon(Tolerance)); + REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + Approx(acceleration(i)).epsilon(Tolerance)); + } + + // Check that the acceleration is 0 in local coordinate + REQUIRE((inverse_rotation_matrix * + node->acceleration(mpm::NodePhase::nSolid))(0) == + Approx(0).epsilon(Tolerance)); + REQUIRE((inverse_rotation_matrix * + node->acceleration(mpm::NodePhase::nSolid))(1) == + Approx(0).epsilon(Tolerance)); + REQUIRE((inverse_rotation_matrix * + node->acceleration(mpm::NodePhase::nLiquid))(0) == + Approx(0).epsilon(Tolerance)); + REQUIRE((inverse_rotation_matrix * + node->acceleration(mpm::NodePhase::nLiquid))(1) == + Approx(0).epsilon(Tolerance)); + } + + SECTION("Check Cartesian friction constraints") { + // Apply friction constraints + REQUIRE(node->assign_friction_constraint(2, 2, 0.3) == true); + // Check out of bounds condition + REQUIRE(node->assign_friction_constraint(4, 1, 0.2) == false); + + // Apply constraints + node->apply_friction_constraints(dt); + + // Check apply constraints + acceleration << 3.939339828220179, 3.939339828220179, 5.; + for (unsigned i = 0; i < acceleration.size(); ++i) + REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + Approx(acceleration(i)).epsilon(Tolerance)); + } + + SECTION("Check general friction constraints in 1 direction") { + // Apply friction constraints + REQUIRE(node->assign_friction_constraint(2, 2, 0.3) == true); + + // Apply rotation matrix with Euler angles alpha = 10 deg, beta = 20 deg + // and gamma = 30 deg + Eigen::Matrix euler_angles; + euler_angles << 10. * M_PI / 180, 20. * M_PI / 180, 30. * M_PI / 180; + const auto rotation_matrix = + mpm::geometry::rotation_matrix(euler_angles); + node->assign_rotation_matrix(rotation_matrix); + const auto inverse_rotation_matrix = rotation_matrix.inverse(); + + // Apply inclined velocity constraints + node->apply_friction_constraints(dt); + + // Check applied constraints on acceleration in the global coordinates + acceleration << 4.602895052828914, 4.492575657560740, 4.751301246937935; + for (unsigned i = 0; i < Dim; ++i) + REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + Approx(acceleration(i)).epsilon(Tolerance)); + + // Check the acceleration in local coordinate + acceleration << 6.878925666702865, 3.365244416454818, 2.302228080558999; + for (unsigned i = 0; i < Dim; ++i) + REQUIRE((inverse_rotation_matrix * + node->acceleration(mpm::NodePhase::nSolid))(i) == + Approx(acceleration(i)).epsilon(Tolerance)); + } + } + + SECTION("Check node material ids") { + // Add material to nodes + node->append_material_id(0); + node->append_material_id(1); + node->append_material_id(4); + node->append_material_id(0); + node->append_material_id(2); + + // Check size of material_ids + REQUIRE(node->material_ids().size() == 4); + + // Check elements of material_ids + std::vector material_ids = {0, 1, 2, 4}; + auto mat_ids = node->material_ids(); + unsigned i = 0; + for (auto mitr = mat_ids.begin(); mitr != mat_ids.end(); ++mitr, ++i) + REQUIRE(*mitr == material_ids.at(i)); + } + } +} From 196136644b68e3a72900b8ece38d22b3d31b1a23 Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 4 Aug 2020 01:02:25 -0700 Subject: [PATCH 088/175] :construction: :dart: categorize tests --- CMakeLists.txt | 28 +++++++++---------- tests/{ => nodes}/nodal_properties_test.cc | 0 tests/{ => nodes}/node_map_test.cc | 0 tests/{ => nodes}/node_test.cc | 0 tests/{ => nodes}/node_vector_test.cc | 0 tests/{ => nodes}/twophase_node_test.cc | 0 .../particle_cell_crossing_test.cc | 0 tests/{ => particles}/particle_test.cc | 0 .../{ => particles}/particle_traction_test.cc | 0 tests/{ => particles}/particle_vector_test.cc | 0 .../{ => particles}/twophase_particle_test.cc | 0 tests/{ => solvers}/mpm_explicit_usf_test.cc | 0 .../mpm_explicit_usf_unitcell_test.cc | 0 tests/{ => solvers}/mpm_explicit_usl_test.cc | 0 .../mpm_explicit_usl_unitcell_test.cc | 0 15 files changed, 14 insertions(+), 14 deletions(-) rename tests/{ => nodes}/nodal_properties_test.cc (100%) rename tests/{ => nodes}/node_map_test.cc (100%) rename tests/{ => nodes}/node_test.cc (100%) rename tests/{ => nodes}/node_vector_test.cc (100%) rename tests/{ => nodes}/twophase_node_test.cc (100%) rename tests/{ => particles}/particle_cell_crossing_test.cc (100%) rename tests/{ => particles}/particle_test.cc (100%) rename tests/{ => particles}/particle_traction_test.cc (100%) rename tests/{ => particles}/particle_vector_test.cc (100%) rename tests/{ => particles}/twophase_particle_test.cc (100%) rename tests/{ => solvers}/mpm_explicit_usf_test.cc (100%) rename tests/{ => solvers}/mpm_explicit_usf_unitcell_test.cc (100%) rename tests/{ => solvers}/mpm_explicit_usl_test.cc (100%) rename tests/{ => solvers}/mpm_explicit_usl_unitcell_test.cc (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 70c44c6da..13d728ce7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -208,21 +208,21 @@ if(MPM_BUILD_TESTING) ${mpm_SOURCE_DIR}/tests/mesh_test_3d.cc ${mpm_SOURCE_DIR}/tests/mpi_particle_test.cc ${mpm_SOURCE_DIR}/tests/mpi_transfer_particle_test.cc - ${mpm_SOURCE_DIR}/tests/mpm_explicit_usf_test.cc - ${mpm_SOURCE_DIR}/tests/mpm_explicit_usf_unitcell_test.cc - ${mpm_SOURCE_DIR}/tests/mpm_explicit_usl_test.cc - ${mpm_SOURCE_DIR}/tests/mpm_explicit_usl_unitcell_test.cc - ${mpm_SOURCE_DIR}/tests/nodal_properties_test.cc - ${mpm_SOURCE_DIR}/tests/node_map_test.cc - ${mpm_SOURCE_DIR}/tests/node_test.cc - ${mpm_SOURCE_DIR}/tests/twophase_node_test.cc - ${mpm_SOURCE_DIR}/tests/node_vector_test.cc - ${mpm_SOURCE_DIR}/tests/particle_cell_crossing_test.cc - ${mpm_SOURCE_DIR}/tests/particle_test.cc - ${mpm_SOURCE_DIR}/tests/twophase_particle_test.cc - ${mpm_SOURCE_DIR}/tests/particle_traction_test.cc - ${mpm_SOURCE_DIR}/tests/particle_vector_test.cc + ${mpm_SOURCE_DIR}/tests/nodes/nodal_properties_test.cc + ${mpm_SOURCE_DIR}/tests/nodes/node_map_test.cc + ${mpm_SOURCE_DIR}/tests/nodes/node_test.cc + ${mpm_SOURCE_DIR}/tests/nodes/twophase_node_test.cc + ${mpm_SOURCE_DIR}/tests/nodes/node_vector_test.cc + ${mpm_SOURCE_DIR}/tests/particles/particle_cell_crossing_test.cc + ${mpm_SOURCE_DIR}/tests/particles/particle_test.cc + ${mpm_SOURCE_DIR}/tests/particles/twophase_particle_test.cc + ${mpm_SOURCE_DIR}/tests/particles/particle_traction_test.cc + ${mpm_SOURCE_DIR}/tests/particles/particle_vector_test.cc ${mpm_SOURCE_DIR}/tests/point_in_cell_test.cc + ${mpm_SOURCE_DIR}/tests/solvers/mpm_explicit_usf_test.cc + ${mpm_SOURCE_DIR}/tests/solvers/mpm_explicit_usf_unitcell_test.cc + ${mpm_SOURCE_DIR}/tests/solvers/mpm_explicit_usl_test.cc + ${mpm_SOURCE_DIR}/tests/solvers/mpm_explicit_usl_unitcell_test.cc ) add_executable(mpmtest ${mpm_src} ${test_src}) add_test(NAME mpmtest COMMAND $) diff --git a/tests/nodal_properties_test.cc b/tests/nodes/nodal_properties_test.cc similarity index 100% rename from tests/nodal_properties_test.cc rename to tests/nodes/nodal_properties_test.cc diff --git a/tests/node_map_test.cc b/tests/nodes/node_map_test.cc similarity index 100% rename from tests/node_map_test.cc rename to tests/nodes/node_map_test.cc diff --git a/tests/node_test.cc b/tests/nodes/node_test.cc similarity index 100% rename from tests/node_test.cc rename to tests/nodes/node_test.cc diff --git a/tests/node_vector_test.cc b/tests/nodes/node_vector_test.cc similarity index 100% rename from tests/node_vector_test.cc rename to tests/nodes/node_vector_test.cc diff --git a/tests/twophase_node_test.cc b/tests/nodes/twophase_node_test.cc similarity index 100% rename from tests/twophase_node_test.cc rename to tests/nodes/twophase_node_test.cc diff --git a/tests/particle_cell_crossing_test.cc b/tests/particles/particle_cell_crossing_test.cc similarity index 100% rename from tests/particle_cell_crossing_test.cc rename to tests/particles/particle_cell_crossing_test.cc diff --git a/tests/particle_test.cc b/tests/particles/particle_test.cc similarity index 100% rename from tests/particle_test.cc rename to tests/particles/particle_test.cc diff --git a/tests/particle_traction_test.cc b/tests/particles/particle_traction_test.cc similarity index 100% rename from tests/particle_traction_test.cc rename to tests/particles/particle_traction_test.cc diff --git a/tests/particle_vector_test.cc b/tests/particles/particle_vector_test.cc similarity index 100% rename from tests/particle_vector_test.cc rename to tests/particles/particle_vector_test.cc diff --git a/tests/twophase_particle_test.cc b/tests/particles/twophase_particle_test.cc similarity index 100% rename from tests/twophase_particle_test.cc rename to tests/particles/twophase_particle_test.cc diff --git a/tests/mpm_explicit_usf_test.cc b/tests/solvers/mpm_explicit_usf_test.cc similarity index 100% rename from tests/mpm_explicit_usf_test.cc rename to tests/solvers/mpm_explicit_usf_test.cc diff --git a/tests/mpm_explicit_usf_unitcell_test.cc b/tests/solvers/mpm_explicit_usf_unitcell_test.cc similarity index 100% rename from tests/mpm_explicit_usf_unitcell_test.cc rename to tests/solvers/mpm_explicit_usf_unitcell_test.cc diff --git a/tests/mpm_explicit_usl_test.cc b/tests/solvers/mpm_explicit_usl_test.cc similarity index 100% rename from tests/mpm_explicit_usl_test.cc rename to tests/solvers/mpm_explicit_usl_test.cc diff --git a/tests/mpm_explicit_usl_unitcell_test.cc b/tests/solvers/mpm_explicit_usl_unitcell_test.cc similarity index 100% rename from tests/mpm_explicit_usl_unitcell_test.cc rename to tests/solvers/mpm_explicit_usl_unitcell_test.cc From cae6cfed24377b33f42ebde63ad1e7c73a3dcdba Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Tue, 4 Aug 2020 10:39:02 -0700 Subject: [PATCH 089/175] Fix bug in twophase_node test --- tests/twophase_node_test.cc | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/tests/twophase_node_test.cc b/tests/twophase_node_test.cc index 91cccb4e2..672e73a04 100644 --- a/tests/twophase_node_test.cc +++ b/tests/twophase_node_test.cc @@ -2290,7 +2290,7 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2P]") { } // Check acceleration before constraints - acceleration << 5., 5.; + acceleration << 5., 5., 5.; for (unsigned i = 0; i < acceleration.size(); ++i) { REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); @@ -2307,7 +2307,7 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2P]") { node->apply_velocity_constraints(); // Check apply constraints - velocity << -12.5, 0.1; + velocity << -12.5, 0.1, 0.1; for (unsigned i = 0; i < velocity.size(); ++i) { REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == Approx(velocity(i)).epsilon(Tolerance)); @@ -2315,7 +2315,7 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2P]") { Approx(velocity(i)).epsilon(Tolerance)); } - acceleration << 0., 5.; + acceleration << 0., 5., 5.; for (unsigned i = 0; i < acceleration.size(); ++i) { REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); @@ -2326,12 +2326,14 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2P]") { SECTION("Check general velocity constraints in 2 directions") { // Apply velocity constraints REQUIRE(node->assign_velocity_constraint(0, -12.5) == true); + REQUIRE(node->assign_velocity_constraint(1, 7.5) == true); REQUIRE(node->assign_velocity_constraint(3, -12.5) == true); + REQUIRE(node->assign_velocity_constraint(4, 7.5) == true); // Apply rotation matrix with Euler angles alpha = 10 deg, beta // = 30 deg Eigen::Matrix euler_angles; - euler_angles << 10. * M_PI / 180, 30. * M_PI / 180; + euler_angles << 10. * M_PI / 180, 20. * M_PI / 180, 30. * M_PI / 180; const auto rotation_matrix = mpm::geometry::rotation_matrix(euler_angles); node->assign_rotation_matrix(rotation_matrix); @@ -2341,7 +2343,7 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2P]") { node->apply_velocity_constraints(); // Check apply constraints - velocity << -9.5834783355, -8.0254030998, 0.1; + velocity << -14.5068204271, -0.1432759442, 1.4260971922; for (unsigned i = 0; i < Dim; ++i) { REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == Approx(velocity(i)).epsilon(Tolerance)); @@ -2353,12 +2355,18 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2P]") { REQUIRE((inverse_rotation_matrix * node->velocity(mpm::NodePhase::nSolid))(0) == Approx(-12.5).epsilon(Tolerance)); + REQUIRE((inverse_rotation_matrix * + node->velocity(mpm::NodePhase::nSolid))(1) == + Approx(7.5).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * node->velocity(mpm::NodePhase::nLiquid))(0) == Approx(-12.5).epsilon(Tolerance)); + REQUIRE((inverse_rotation_matrix * + node->velocity(mpm::NodePhase::nLiquid))(1) == + Approx(7.5).epsilon(Tolerance)); // Check applied constraints on acceleration in the global coordinates - acceleration << -0.3961398267, 0.4721010616, 5.0; + acceleration << 0.1998888554, -1.1336260315, 1.9937880031; for (unsigned i = 0; i < Dim; ++i) { REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); @@ -2370,9 +2378,15 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2P]") { REQUIRE((inverse_rotation_matrix * node->acceleration(mpm::NodePhase::nSolid))(0) == Approx(0).epsilon(Tolerance)); + REQUIRE((inverse_rotation_matrix * + node->acceleration(mpm::NodePhase::nSolid))(1) == + Approx(0).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * node->acceleration(mpm::NodePhase::nLiquid))(0) == Approx(0).epsilon(Tolerance)); + REQUIRE((inverse_rotation_matrix * + node->acceleration(mpm::NodePhase::nLiquid))(1) == + Approx(0).epsilon(Tolerance)); } SECTION("Check general velocity constraints in all directions") { From d6681a8d6df45b5554bba3b72ddfc00b762c5483 Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Tue, 4 Aug 2020 23:09:20 -0700 Subject: [PATCH 090/175] Inpute gravity in initialise pore pressure --- include/particles/particle_base.h | 2 +- include/particles/twophase_particle.h | 7 ++++++- include/particles/twophase_particle.tcc | 11 +++++++---- include/solvers/mpm_base.tcc | 3 ++- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 1230106e9..9551a9d28 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -358,7 +358,7 @@ class ParticleBase { //! Initialise particle pore pressure by watertable virtual bool initialise_pore_pressure_watertable( - const unsigned dir_v, const unsigned dir_h, + const unsigned dir_v, const unsigned dir_h, VectorDim& gravity, std::map& reference_points) { throw std::runtime_error( "Calling the base class function " diff --git a/include/particles/twophase_particle.h b/include/particles/twophase_particle.h index 7a9316977..9a6bcb9d6 100644 --- a/include/particles/twophase_particle.h +++ b/include/particles/twophase_particle.h @@ -100,8 +100,13 @@ class TwoPhaseParticle : public mpm::Particle { bool map_drag_force_coefficient() override; //! Assign particles initial pore pressure by watertable + //! \param[in] dir_v Vertical direction (Gravity direction) of the watertable + //! \param[in] dir_h Horizontal direction of the watertable + //! \param[in] gravity Gravity vector + //! \param[in] reference_points + //! (Horizontal coordinate of borehole + height of 0 pore pressure) bool initialise_pore_pressure_watertable( - const unsigned dir_v, const unsigned dir_h, + const unsigned dir_v, const unsigned dir_h, VectorDim& gravity, std::map& reference_points); //! Update porosity diff --git a/include/particles/twophase_particle.tcc b/include/particles/twophase_particle.tcc index fd79830e8..17bcfb504 100644 --- a/include/particles/twophase_particle.tcc +++ b/include/particles/twophase_particle.tcc @@ -644,7 +644,7 @@ bool mpm::TwoPhaseParticle::map_drag_force_coefficient() { //! Initial pore pressure template bool mpm::TwoPhaseParticle::initialise_pore_pressure_watertable( - const unsigned dir_v, const unsigned dir_h, + const unsigned dir_v, const unsigned dir_h, VectorDim& gravity, std::map& reference_points) { bool status = true; try { @@ -684,14 +684,14 @@ bool mpm::TwoPhaseParticle::initialise_pore_pressure_watertable( h0_left - this->coordinates_(dir_v)) * (this->material(mpm::ParticlePhase::Liquid)) ->template property(std::string("density")) * - 9.81; + (-gravity(dir_v)); } else // Particle with only left boundary pore_pressure = (h0_left - this->coordinates_(dir_v)) * (this->material(mpm::ParticlePhase::Liquid)) ->template property(std::string("density")) * - 9.81; + (-gravity(dir_v)); } // Particle with only right boundary @@ -699,11 +699,14 @@ bool mpm::TwoPhaseParticle::initialise_pore_pressure_watertable( pore_pressure = (h0_right - this->coordinates_(dir_v)) * (this->material(mpm::ParticlePhase::Liquid)) ->template property(std::string("density")) * - 9.81; + (-gravity(dir_v)); else throw std::runtime_error( "Particle pore pressure can not be initialised by water table"); + // Check negative pore pressure + if (pore_pressure < 0) pore_pressure = 0; + // Assign pore pressure this->assign_state_variable("pressure", pore_pressure, mpm::ParticlePhase::Liquid); diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index b4bf34099..9d874c6ac 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -1200,7 +1200,8 @@ void mpm::MPMBase::particles_pore_pressures( // Initialise particles pore pressures by watertable mesh_->iterate_over_particles(std::bind( &mpm::ParticleBase::initialise_pore_pressure_watertable, - std::placeholders::_1, dir_v, dir_h, reference_points)); + std::placeholders::_1, dir_v, dir_h, this->gravity_, + reference_points)); } else throw std::runtime_error( "Particle pore pressures generator type is not properly " From b70e28dd6cf6be000b96c063482b3b53beaaf417 Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 5 Aug 2020 10:34:58 -0700 Subject: [PATCH 091/175] :construction: remove pore_pressure from tensor data and cleanup --- include/particles/twophase_particle.tcc | 23 +++++++++-------------- include/solvers/mpm_base.tcc | 2 +- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/include/particles/twophase_particle.tcc b/include/particles/twophase_particle.tcc index 17bcfb504..67f33b7a2 100644 --- a/include/particles/twophase_particle.tcc +++ b/include/particles/twophase_particle.tcc @@ -119,11 +119,6 @@ void mpm::TwoPhaseParticle::initialise() { // Initialize vector data properties this->properties_["liquid_velocities"] = [&]() { return liquid_velocity(); }; - this->properties_["pore_pressure"] = [&]() { - Eigen::VectorXd vec_pressure = Eigen::VectorXd::Zero(3); - vec_pressure[0] = this->pressure(mpm::ParticlePhase::Liquid); - return vec_pressure; - }; } // Assign degree of saturation to the liquid phase @@ -657,18 +652,18 @@ bool mpm::TwoPhaseParticle::initialise_pore_pressure_watertable( // Position and h0 of particle (coordinate) const double position = this->coordinates_(dir_h); // Iterate over each reference_points - for (const auto& refernece_point : reference_points) { + for (const auto& reference_point : reference_points) { // Find boundary - if (refernece_point.first > left_boundary && - refernece_point.first <= position) { + if (reference_point.first > left_boundary && + reference_point.first <= position) { // Left boundary position and h0 - left_boundary = refernece_point.first; - h0_left = refernece_point.second; - } else if (refernece_point.first > position && - refernece_point.first <= right_boundary) { + left_boundary = reference_point.first; + h0_left = reference_point.second; + } else if (reference_point.first > position && + reference_point.first <= right_boundary) { // Right boundary position and h0 - right_boundary = refernece_point.first; - h0_right = refernece_point.second; + right_boundary = reference_point.first; + h0_right = reference_point.second; } } diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index 9d874c6ac..e7cee7fae 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -1193,7 +1193,7 @@ void mpm::MPMBase::particles_pore_pressures( double position = water_table.at("position").template get(); // Direction double h0 = water_table.at("h0").template get(); - // Add refernece points to mesh + // Add reference points to mesh reference_points.insert(std::make_pair( static_cast(position), static_cast(h0))); } From a853aac79c414b834046151c8659f4b59f3c2e96 Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Wed, 5 Aug 2020 13:26:05 -0700 Subject: [PATCH 092/175] Add liquid traction --- include/particles/particle_base.h | 3 +- include/particles/twophase_particle.h | 14 ++++- include/particles/twophase_particle.tcc | 71 +++++++++++++++-------- tests/particles/twophase_particle_test.cc | 4 +- 4 files changed, 62 insertions(+), 30 deletions(-) diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 9551a9d28..2f1d1f266 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -315,11 +315,10 @@ class ParticleBase { //! TwoPhase functions-------------------------------------------------------- //! Update porosity //! \param[in] dt Analysis time step - virtual bool update_porosity(double dt) { + virtual void update_porosity(double dt) { throw std::runtime_error( "Calling the base class function (update_porosity) in " "ParticleBase:: illegal operation!"); - return false; }; //! Assign saturation degree diff --git a/include/particles/twophase_particle.h b/include/particles/twophase_particle.h index 9a6bcb9d6..3e82c738d 100644 --- a/include/particles/twophase_particle.h +++ b/include/particles/twophase_particle.h @@ -111,7 +111,7 @@ class TwoPhaseParticle : public mpm::Particle { //! Update porosity //! \param[in] dt Analysis time step - bool update_porosity(double dt) override; + void update_porosity(double dt) override; //! Assign particle permeability //! \retval status Assignment status @@ -130,6 +130,12 @@ class TwoPhaseParticle : public mpm::Particle { void apply_particle_velocity_constraints(unsigned dir, double velocity) override; + //! Assign traction to the particle + //! \param[in] direction Index corresponding to the direction of traction + //! \param[in] traction Particle traction in specified direction + //! \retval status Assignment status + bool assign_traction(unsigned direction, double traction) override; + //! Return velocity of the particle liquid phase //! \retval liquid velocity Liquid phase velocity VectorDim liquid_velocity() const override { return liquid_velocity_; } @@ -208,6 +214,8 @@ class TwoPhaseParticle : public mpm::Particle { using Particle::set_traction_; //! Surface Traction (given as a stress; force/area) using Particle::traction_; + //! Size of particle + using Particle::size_; //! Particle velocity constraints using Particle::particle_velocity_constraints_; @@ -219,6 +227,10 @@ class TwoPhaseParticle : public mpm::Particle { double liquid_saturation_{1.0}; //! Material point porosity (volume of voids / total volume) double porosity_{0.0}; + //! Set liquid traction + bool set_liquid_traction_{false}; + //! Liquid traction + Eigen::Matrix liquid_traction_; //! Liquid velocity Eigen::Matrix liquid_velocity_; //! Pore pressure constraint diff --git a/include/particles/twophase_particle.tcc b/include/particles/twophase_particle.tcc index 67f33b7a2..dda7c3faa 100644 --- a/include/particles/twophase_particle.tcc +++ b/include/particles/twophase_particle.tcc @@ -115,6 +115,8 @@ void mpm::TwoPhaseParticle::initialise() { mpm::Particle::initialise(); liquid_mass_ = 0.; liquid_velocity_.setZero(); + set_liquid_traction_ = false; + liquid_traction_.setZero(); liquid_saturation_ = 1.; // Initialize vector data properties @@ -263,30 +265,26 @@ void mpm::TwoPhaseParticle::map_mixture_body_force( //! Map traction force template void mpm::TwoPhaseParticle::map_traction_force() noexcept { - this->map_mixture_traction_force(); - this->map_liquid_traction_force(); + if (this->set_traction_) this->map_mixture_traction_force(); + if (this->set_liquid_traction_) this->map_liquid_traction_force(); } //! Map mixture traction force template void mpm::TwoPhaseParticle::map_mixture_traction_force() noexcept { - if (this->set_traction_) { - // Map particle traction forces to nodes - for (unsigned i = 0; i < nodes_.size(); ++i) - nodes_[i]->update_external_force(true, mpm::ParticlePhase::Mixture, - (shapefn_[i] * traction_)); - } + // Map particle traction forces to nodes + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->update_external_force(true, mpm::ParticlePhase::Mixture, + (shapefn_[i] * traction_)); } //! Map liquid traction force template void mpm::TwoPhaseParticle::map_liquid_traction_force() noexcept { - // if (this->set_traction_) { - // // Map particle traction forces to nodes - // for (unsigned i = 0; i < nodes_.size(); ++i) - // nodes_[i]->update_external_force(true, mpm::ParticlePhase::Mixture, - // (shapefn_[i] * traction_)); - // } + // Map particle liquid traction forces to nodes + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->update_external_force(true, mpm::ParticlePhase::Liquid, + (shapefn_[i] * liquid_traction_)); } //! Map both mixture and liquid internal force @@ -714,19 +712,42 @@ bool mpm::TwoPhaseParticle::initialise_pore_pressure_watertable( // Update material point porosity template -bool mpm::TwoPhaseParticle::update_porosity(double dt) { - bool status = true; +void mpm::TwoPhaseParticle::update_porosity(double dt) { + // Update particle porosity + const double porosity = + 1 - (1 - this->porosity_) / (1 + dt * strain_rate_.head(Tdim).sum()); + // Check if the value is valid + if (porosity < 0.) + this->porosity_ = 1.E-5; + else if (porosity > 1.) + this->porosity_ = 1 - 1.E-5; + else + this->porosity_ = porosity; +} + +// Assign traction to the particle +template +bool mpm::TwoPhaseParticle::assign_traction(unsigned direction, + double traction) { + bool status = false; try { - // Update particle porosity - const double porosity = - 1 - (1 - this->porosity_) / (1 + dt * strain_rate_.head(Tdim).sum()); - // Check if the value is valid - if (porosity > 0 && porosity < 1) this->porosity_ = porosity; - // Invalid value - else + if (direction >= Tdim * 2 || + this->volume_ == std::numeric_limits::max()) { throw std::runtime_error( - "Invalid porosity, less than zero or greater than one"); - + "Particle traction property: volume / direction is invalid"); + } + // Assign mixture traction + if (direction < Tdim) { + this->set_traction_ = true; + traction_(direction) = traction * this->volume_ / this->size_(direction); + } + // Assign liquid traction + else { + this->set_liquid_traction_ = true; + liquid_traction_(direction - Tdim) = + traction * this->volume_ / this->size_(direction - Tdim); + } + status = true; } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); status = false; diff --git a/tests/particles/twophase_particle_test.cc b/tests/particles/twophase_particle_test.cc index a1a672c6c..c53a660a1 100644 --- a/tests/particles/twophase_particle_test.cc +++ b/tests/particles/twophase_particle_test.cc @@ -195,7 +195,7 @@ TEST_CASE("TwoPhase Particle is checked for 1D case", } // Check for incorrect direction - const unsigned wrong_dir = 4; + const unsigned wrong_dir = 2; REQUIRE(particle->assign_traction(wrong_dir, traction) == false); // Check again to ensure value hasn't been updated @@ -2703,7 +2703,7 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", } // Check for incorrect direction - const unsigned wrong_dir = 4; + const unsigned wrong_dir = 6; REQUIRE(particle->assign_traction(wrong_dir, traction) == false); // Check again to ensure value hasn't been updated From afc5b15ecb6fc39cd5984ca794b1e1c9eac4aefc Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Wed, 5 Aug 2020 14:25:19 -0700 Subject: [PATCH 093/175] Modify the apply pressure constraint --- include/node.h | 11 ++++++-- include/node.tcc | 36 +++++++++++++++---------- include/node_base.h | 11 ++++++-- include/particles/particle.h | 4 +-- include/particles/particle.tcc | 6 ++--- include/particles/particle_base.h | 5 ++-- include/particles/twophase_particle.h | 4 +-- include/particles/twophase_particle.tcc | 10 +++---- include/solvers/mpm_base.tcc | 8 +++++- 9 files changed, 59 insertions(+), 36 deletions(-) diff --git a/include/node.h b/include/node.h index 22fc0dfbd..eee74a764 100644 --- a/include/node.h +++ b/include/node.h @@ -131,8 +131,15 @@ class Node : public NodeBase { //! Update pressure at the nodes from particle //! \param[in] phase Index corresponding to the phase //! \param[in] mass_pressure Product of mass x pressure of a particle - void update_mass_pressure(unsigned phase, double mass_pressure, double dt = 0, - Index step = 0) noexcept override; + void update_mass_pressure(unsigned phase, + double mass_pressure) noexcept override; + + //! Apply pressure constraint + //! \param[in] phase Index corresponding to the phase + //! \param[in] dt Timestep in analysis + //! \param[in] step Step in analysis + void apply_pressure_constraint(unsigned phase, double dt = 0, + Index step = 0) noexcept override; //! Assign pressure at the nodes from particle //! \param[in] update A boolean to update (true) or assign (false) diff --git a/include/node.tcc b/include/node.tcc index d299f2724..354df76e0 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -162,7 +162,7 @@ void mpm::Node::update_momentum( //! Update pressure at the nodes from particle template void mpm::Node::update_mass_pressure( - unsigned phase, double mass_pressure, double dt, Index step) noexcept { + unsigned phase, double mass_pressure) noexcept { // Assert assert(phase < Tnphases); @@ -172,14 +172,22 @@ void mpm::Node::update_mass_pressure( node_mutex_.lock(); pressure_(phase) += mass_pressure / mass_(phase); node_mutex_.unlock(); + } +} - if (pressure_constraints_.find(phase) != pressure_constraints_.end()) { - const double scalar = - (pressure_function_.find(phase) != pressure_function_.end()) - ? pressure_function_[phase]->value(step * dt) - : 1.0; - this->pressure_(phase) = scalar * pressure_constraints_[phase]; - } +//! Apply pressure constraint +template +void mpm::Node::apply_pressure_constraint( + unsigned phase, double dt, Index step) noexcept { + // Assert + assert(phase < Tnphases); + + if (pressure_constraints_.find(phase) != pressure_constraints_.end()) { + const double scalar = + (pressure_function_.find(phase) != pressure_function_.end()) + ? pressure_function_[phase]->value(step * dt) + : 1.0; + this->pressure_(phase) = scalar * pressure_constraints_[phase]; } } @@ -584,8 +592,8 @@ void mpm::Node::update_property( template void mpm::Node::compute_multimaterial_change_in_momentum() { - // iterate over all materials in the material_ids set and update the change in - // momentum + // iterate over all materials in the material_ids set and update the change + // in momentum node_mutex_.lock(); for (auto mitr = material_ids_.begin(); mitr != material_ids_.end(); ++mitr) { const Eigen::Matrix mass = @@ -605,8 +613,8 @@ template void mpm::Node::compute_multimaterial_separation_vector() { // iterate over all materials in the material_ids set, update the - // displacements and calculate the displacement of the center of mass for this - // node + // displacements and calculate the displacement of the center of mass for + // this node node_mutex_.lock(); for (auto mitr = material_ids_.begin(); mitr != material_ids_.end(); ++mitr) { const auto& material_displacement = @@ -616,8 +624,8 @@ void mpm::Nodeassign_property( "displacements", prop_id_, *mitr, material_displacement / material_mass(0, 0), Tdim); diff --git a/include/node_base.h b/include/node_base.h index 31636a441..baae25e1a 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -148,8 +148,15 @@ class NodeBase { //! Update pressure at the nodes from particle //! \param[in] phase Index corresponding to the phase //! \param[in] mass_pressure Product of mass x pressure of a particle - virtual void update_mass_pressure(unsigned phase, double mass_pressure, - double dt = 0, Index step = 0) noexcept = 0; + virtual void update_mass_pressure(unsigned phase, + double mass_pressure) noexcept = 0; + + //! Apply pressure constraint + //! \param[in] phase Index corresponding to the phase + //! \param[in] dt Timestep in analysis + //! \param[in] step Step in analysis + virtual void apply_pressure_constraint(unsigned phase, double dt = 0, + Index step = 0) noexcept = 0; //! Assign pressure at the nodes from particle //! \param[in] update A boolean to update (true) or assign (false) diff --git a/include/particles/particle.h b/include/particles/particle.h index d05c7dc52..5b419396a 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -263,8 +263,8 @@ class Particle : public ParticleBase { } //! Map particle pressure to nodes - bool map_pressure_to_nodes(unsigned phase = mpm::ParticlePhase::Solid, - double dt = 0, Index step = 0) noexcept override; + bool map_pressure_to_nodes( + unsigned phase = mpm::ParticlePhase::Solid) noexcept override; //! Compute pressure smoothing of the particle based on nodal pressure //! $$\hat{p}_p = \sum_{i = 1}^{n_n} N_i(x_p) p_i$$ diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index f7668d010..05afce62a 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -815,8 +815,7 @@ void mpm::Particle::compute_updated_position( //! Map particle pressure to nodes template -bool mpm::Particle::map_pressure_to_nodes(unsigned phase, double dt, - Index step) noexcept { +bool mpm::Particle::map_pressure_to_nodes(unsigned phase) noexcept { // Mass is initialized assert(mass_ != std::numeric_limits::max()); @@ -828,8 +827,7 @@ bool mpm::Particle::map_pressure_to_nodes(unsigned phase, double dt, // Map particle pressure to nodes for (unsigned i = 0; i < nodes_.size(); ++i) nodes_[i]->update_mass_pressure( - phase, shapefn_[i] * mass_ * state_variables_[phase]["pressure"], dt, - step); + phase, shapefn_[i] * mass_ * state_variables_[phase]["pressure"]); status = true; } diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 2f1d1f266..c6cdfdcae 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -241,9 +241,8 @@ class ParticleBase { virtual void map_internal_force() noexcept = 0; //! Map particle pressure to nodes - virtual bool map_pressure_to_nodes(unsigned phase = mpm::ParticlePhase::Solid, - double dt = 0, - Index step = 0) noexcept = 0; + virtual bool map_pressure_to_nodes( + unsigned phase = mpm::ParticlePhase::Solid) noexcept = 0; //! Compute pressure smoothing of the particle based on nodal pressure virtual bool compute_pressure_smoothing( diff --git a/include/particles/twophase_particle.h b/include/particles/twophase_particle.h index 3e82c738d..24e6e525f 100644 --- a/include/particles/twophase_particle.h +++ b/include/particles/twophase_particle.h @@ -121,8 +121,8 @@ class TwoPhaseParticle : public mpm::Particle { bool assign_porosity() override; //! Map particle pressure to nodes - bool map_pressure_to_nodes(unsigned phase = mpm::ParticlePhase::Solid, - double dt = 0, Index step = 0) noexcept override; + bool map_pressure_to_nodes( + unsigned phase = mpm::ParticlePhase::Solid) noexcept override; //! Apply particle velocity constraints //! \param[in] dir Direction of particle velocity constraint diff --git a/include/particles/twophase_particle.tcc b/include/particles/twophase_particle.tcc index dda7c3faa..373acbe72 100644 --- a/include/particles/twophase_particle.tcc +++ b/include/particles/twophase_particle.tcc @@ -447,16 +447,15 @@ void mpm::TwoPhaseParticle::compute_updated_position( //! Map particle pressure to nodes template -bool mpm::TwoPhaseParticle::map_pressure_to_nodes(unsigned phase, - double dt, - Index step) noexcept { +bool mpm::TwoPhaseParticle::map_pressure_to_nodes( + unsigned phase) noexcept { // Mass is initialized assert(liquid_mass_ != std::numeric_limits::max()); bool status = false; // If phase is Solid, use the default map_pressure_to_nodes if (phase == mpm::ParticlePhase::Solid) - status = mpm::Particle::map_pressure_to_nodes(phase, dt, step); + status = mpm::Particle::map_pressure_to_nodes(phase); else { // Check if particle liquid mass is set and state variable pressure is found if (liquid_mass_ != std::numeric_limits::max() && @@ -466,8 +465,7 @@ bool mpm::TwoPhaseParticle::map_pressure_to_nodes(unsigned phase, for (unsigned i = 0; i < nodes_.size(); ++i) nodes_[i]->update_mass_pressure( phase, - shapefn_[i] * liquid_mass_ * state_variables_[phase]["pressure"], - dt, step); + shapefn_[i] * liquid_mass_ * state_variables_[phase]["pressure"]); status = true; } diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index e7cee7fae..4a65e06fe 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -1333,7 +1333,13 @@ 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, phase, this->dt_, this->step_)); + std::placeholders::_1, phase)); + + // Apply pressure constraint + mesh_->iterate_over_nodes_predicate( + std::bind(&mpm::NodeBase::apply_pressure_constraint, + std::placeholders::_1, phase, this->dt_, this->step_), + std::bind(&mpm::NodeBase::status, std::placeholders::_1)); #ifdef USE_MPI int mpi_size = 1; From c6f4d7b123417163e232e49412c2445526b11e5f Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Wed, 5 Aug 2020 14:42:14 -0700 Subject: [PATCH 094/175] Some clean up --- include/particles/twophase_particle.tcc | 29 ++++++++++++------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/include/particles/twophase_particle.tcc b/include/particles/twophase_particle.tcc index 373acbe72..f0ffe7e8f 100644 --- a/include/particles/twophase_particle.tcc +++ b/include/particles/twophase_particle.tcc @@ -37,27 +37,29 @@ template mpm::HDF5Particle mpm::TwoPhaseParticle::hdf5() const { // Derive from particle auto particle_data = mpm::Particle::hdf5(); - // // Particle liquid velocity - // Eigen::Vector3d liquid_velocity; - // liquid_velocity.setZero(); - // for (unsigned j = 0; j < Tdim; ++j) - // liquid_velocity[j] = this->liquid_velocity_[j]; // // Particle liquid mass // particle_data.liquid_mass = this->liquid_mass_; - // Particle pore pressure - // particle_data.pressure = this->pore_pressure_; + // // Particle liquid velocity // particle_data.liquid_velocity_x = liquid_velocity[0]; // particle_data.liquid_velocity_y = liquid_velocity[1]; // particle_data.liquid_velocity_z = liquid_velocity[2]; + // // Particle liquid material id - // particle_data.liquid_material_id = this->liquid_material_id_; + // particle_data.liquid_material_id = + // this->material_id_(mpm::ParticlePhase::Liquid); + if (this->material(mpm::ParticlePhase::Liquid) != nullptr) { + if ((state_variables_[mpm::ParticlePhase::Solid].size() + + state_variables_[mpm::ParticlePhase::Liquid].size()) > 20) + throw std::runtime_error("# of state variables cannot be more than 20"); + // Assign number of state variables particle_data.nstate_vars = + state_variables_[mpm::ParticlePhase::Solid].size() + state_variables_[mpm::ParticlePhase::Liquid].size(); - if (state_variables_[mpm::ParticlePhase::Liquid].size() > 20) - throw std::runtime_error("# of state variables cannot be more than 20"); - unsigned i = 0; + // First id + unsigned i = state_variables_[mpm::ParticlePhase::Solid].size(); + // Liquid state variables auto state_variables = (this->material(mpm::ParticlePhase::Liquid))->state_variables(); for (const auto& state_var : state_variables) { @@ -80,10 +82,7 @@ bool mpm::TwoPhaseParticle::initialise_particle( // // Liquid mass // this->liquid_mass_ = particle.liquid_mass; // // Liquid mass Density - // this->liquid_mass_density_ = particle.mass / particle.volume; - - // // Pore pressure - // this->pore_pressure_ = particle.pore_pressure; + // this->liquid_mass_density_ = particle.liquid_mass / particle.volume; // // Liquid velocity // Eigen::Vector3d liquid_velocity; From 52f5e0db60c77ddaacdefb7fd53d2f2479db67e5 Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Wed, 5 Aug 2020 15:59:31 -0700 Subject: [PATCH 095/175] Add test for watertable --- tests/particles/twophase_particle_test.cc | 129 +++++++++++++++++++++- 1 file changed, 128 insertions(+), 1 deletion(-) diff --git a/tests/particles/twophase_particle_test.cc b/tests/particles/twophase_particle_test.cc index c53a660a1..20c3e4631 100644 --- a/tests/particles/twophase_particle_test.cc +++ b/tests/particles/twophase_particle_test.cc @@ -599,6 +599,62 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", REQUIRE(pstress[i] == Approx(stress[i]).epsilon(Tolerance)); } + // !Test initialise particle pore pressure + SECTION("TwoPhase Particle with initial pore pressure") { + mpm::Index id = 0; + const double Tolerance = 1.E-7; + bool status = true; + coords << 0.1, 0.2; + std::shared_ptr> particle = + std::make_shared>(id, coords, status); + // Assign liquid material + unsigned liquid_mid = 0; + // Initialise material + Json jmaterial_liquid; + jmaterial_liquid["density"] = 1000.; + jmaterial_liquid["bulk_modulus"] = 1.0E+9; + jmaterial_liquid["mu"] = 0.3; + jmaterial_liquid["dynamic_viscosity"] = 0.; + + auto liquid_material = + Factory, unsigned, const Json&>::instance()->create( + "Newtonian2D", std::move(liquid_mid), jmaterial_liquid); + + REQUIRE(particle->assign_material(liquid_material, + mpm::ParticlePhase::Liquid) == true); + + Eigen::Matrix gravity; + gravity << 0., -9.81; + // Test only lefe boundary + std::map reference_points; + reference_points.insert(std::make_pair( + static_cast(0.), static_cast(0.5))); + //! Test initialise pore pressure by water table + REQUIRE(particle->initialise_pore_pressure_watertable(1, 0, gravity, + reference_points)); + REQUIRE(particle->pressure(mpm::ParticlePhase::Liquid) == + Approx(2943).epsilon(Tolerance)); + + // Test only right boundary + reference_points.erase(0.); + reference_points.insert(std::make_pair( + static_cast(1.), static_cast(0.7))); + //! Test initialise pore pressure by water table + REQUIRE(particle->initialise_pore_pressure_watertable(1, 0, gravity, + reference_points)); + REQUIRE(particle->pressure(mpm::ParticlePhase::Liquid) == + Approx(4905).epsilon(Tolerance)); + + // Test both left and right boundaries + reference_points.insert(std::make_pair( + static_cast(0.), static_cast(0.5))); + //! Test initialise pore pressure by water table + REQUIRE(particle->initialise_pore_pressure_watertable(1, 0, gravity, + reference_points)); + REQUIRE(particle->pressure(mpm::ParticlePhase::Liquid) == + Approx(3139.2).epsilon(Tolerance)); + } + //! Test particles velocity constraints SECTION("TwoPhase Particle with velocity constraints") { mpm::Index id = 0; @@ -1863,7 +1919,7 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", REQUIRE(cell->nparticles() == 0); } - //! Test initialise twophase particle stresses + //! Test initialise particle stresses SECTION("TwoPhase Particle with initial stress") { mpm::Index id = 0; const double Tolerance = 1.E-7; @@ -1880,6 +1936,77 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", REQUIRE(pstress[i] == Approx(stress[i]).epsilon(Tolerance)); } + // !Test initialise particle pore pressure + SECTION("TwoPhase Particle with initial pore pressure") { + mpm::Index id = 0; + const double Tolerance = 1.E-7; + bool status = true; + coords << 0.1, 0.2, 0.3; + std::shared_ptr> particle = + std::make_shared>(id, coords, status); + // Assign liquid material + unsigned liquid_mid = 0; + // Initialise material + Json jmaterial_liquid; + jmaterial_liquid["density"] = 1000.; + jmaterial_liquid["bulk_modulus"] = 1.0E+9; + jmaterial_liquid["mu"] = 0.3; + jmaterial_liquid["dynamic_viscosity"] = 0.; + + auto liquid_material = + Factory, unsigned, const Json&>::instance()->create( + "Newtonian3D", std::move(liquid_mid), jmaterial_liquid); + + REQUIRE(particle->assign_material(liquid_material, + mpm::ParticlePhase::Liquid) == true); + + Eigen::Matrix gravity; + gravity << 0., -9.81, 0; + // Test only lefe boundary + std::map reference_points; + reference_points.insert(std::make_pair( + static_cast(0.), static_cast(0.5))); + //! Test initialise pore pressure by water table with x-interpolation + REQUIRE(particle->initialise_pore_pressure_watertable(1, 0, gravity, + reference_points)); + REQUIRE(particle->pressure(mpm::ParticlePhase::Liquid) == + Approx(2943).epsilon(Tolerance)); + //! Test initialise pore pressure by water table with z-interpolation + REQUIRE(particle->initialise_pore_pressure_watertable(1, 2, gravity, + reference_points)); + REQUIRE(particle->pressure(mpm::ParticlePhase::Liquid) == + Approx(2943).epsilon(Tolerance)); + + // Test only right boundary + reference_points.erase(0.); + reference_points.insert(std::make_pair( + static_cast(1.), static_cast(0.7))); + //! Test initialise pore pressure by water table x-interpolation + REQUIRE(particle->initialise_pore_pressure_watertable(1, 0, gravity, + reference_points)); + REQUIRE(particle->pressure(mpm::ParticlePhase::Liquid) == + Approx(4905).epsilon(Tolerance)); + //! Test initialise pore pressure by water table with z-interpolation + REQUIRE(particle->initialise_pore_pressure_watertable(1, 2, gravity, + reference_points)); + REQUIRE(particle->pressure(mpm::ParticlePhase::Liquid) == + Approx(4905).epsilon(Tolerance)); + + // Test both left and right boundaries + reference_points.insert(std::make_pair( + static_cast(0.), static_cast(0.5))); + //! Test initialise pore pressure by water table x-interpolation + REQUIRE(particle->initialise_pore_pressure_watertable(1, 0, gravity, + reference_points)); + REQUIRE(particle->pressure(mpm::ParticlePhase::Liquid) == + Approx(3139.2).epsilon(Tolerance)); + //! Test initialise pore pressure by water table with z-interpolation + REQUIRE(particle->initialise_pore_pressure_watertable(1, 2, gravity, + reference_points)); + REQUIRE(particle->pressure(mpm::ParticlePhase::Liquid) == + Approx(3531.6).epsilon(Tolerance)); + } + //! Test twophase particles velocity constraints SECTION("TwoPhase Particle with velocity constraints") { mpm::Index id = 0; From 8b09a3c3ce2b408e9db00dbd1e8239c4823c6af5 Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Wed, 5 Aug 2020 21:40:27 -0700 Subject: [PATCH 096/175] Add solver test --- .gitignore | 1 + CMakeLists.txt | 4 + tests/include/write_mesh_particles.h | 5 + tests/include/write_mesh_particles_unitcell.h | 5 + tests/io/write_mesh_particles.cc | 127 ++++++++++++ tests/io/write_mesh_particles_unitcell.cc | 120 +++++++++++ .../solvers/mpm_explicit_twophase_usf_test.cc | 191 ++++++++++++++++++ ...mpm_explicit_twophase_usf_unitcell_test.cc | 119 +++++++++++ .../solvers/mpm_explicit_twophase_usl_test.cc | 191 ++++++++++++++++++ ...mpm_explicit_twophase_usl_unitcell_test.cc | 119 +++++++++++ 10 files changed, 882 insertions(+) create mode 100644 tests/solvers/mpm_explicit_twophase_usf_test.cc create mode 100644 tests/solvers/mpm_explicit_twophase_usf_unitcell_test.cc create mode 100644 tests/solvers/mpm_explicit_twophase_usl_test.cc create mode 100644 tests/solvers/mpm_explicit_twophase_usl_unitcell_test.cc diff --git a/.gitignore b/.gitignore index 828560b3a..ee24fee34 100644 --- a/.gitignore +++ b/.gitignore @@ -76,3 +76,4 @@ configure.scan *missing *stamp-h1 benchmarks/ +bin/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 13d728ce7..d141ff1a8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -223,6 +223,10 @@ if(MPM_BUILD_TESTING) ${mpm_SOURCE_DIR}/tests/solvers/mpm_explicit_usf_unitcell_test.cc ${mpm_SOURCE_DIR}/tests/solvers/mpm_explicit_usl_test.cc ${mpm_SOURCE_DIR}/tests/solvers/mpm_explicit_usl_unitcell_test.cc + ${mpm_SOURCE_DIR}/tests/solvers/mpm_explicit_twophase_usf_test.cc + ${mpm_SOURCE_DIR}/tests/solvers/mpm_explicit_twophase_usf_unitcell_test.cc + ${mpm_SOURCE_DIR}/tests/solvers/mpm_explicit_twophase_usl_test.cc + ${mpm_SOURCE_DIR}/tests/solvers/mpm_explicit_twophase_usl_unitcell_test.cc ) add_executable(mpmtest ${mpm_src} ${test_src}) add_test(NAME mpmtest COMMAND $) diff --git a/tests/include/write_mesh_particles.h b/tests/include/write_mesh_particles.h index f2ea265c4..53d3bff38 100644 --- a/tests/include/write_mesh_particles.h +++ b/tests/include/write_mesh_particles.h @@ -8,6 +8,11 @@ namespace mpm_test { bool write_json(unsigned dim, bool resume, const std::string& analysis, const std::string& stress_update, const std::string& file_name); +// Write JSON Configuration file for twophase +bool write_json_twophase(unsigned dim, bool resume, const std::string& analysis, + const std::string& stress_update, + const std::string& file_name); + // Write JSON Entity Set bool write_entity_set(); diff --git a/tests/include/write_mesh_particles_unitcell.h b/tests/include/write_mesh_particles_unitcell.h index a7b1abfbb..9a7de9d60 100644 --- a/tests/include/write_mesh_particles_unitcell.h +++ b/tests/include/write_mesh_particles_unitcell.h @@ -9,6 +9,11 @@ bool write_json_unitcell(unsigned dim, const std::string& analysis, const std::string& stress_update, const std::string& file_name); +// Write JSON Configuration file for two-phase +bool write_json_unitcell_twophase(unsigned dim, const std::string& analysis, + const std::string& stress_update, + const std::string& file_name); + // Write Mesh file in 2D bool write_mesh_2d_unitcell(); // Write particles file in 2D diff --git a/tests/io/write_mesh_particles.cc b/tests/io/write_mesh_particles.cc index 555d5abb5..68b58abef 100644 --- a/tests/io/write_mesh_particles.cc +++ b/tests/io/write_mesh_particles.cc @@ -113,6 +113,133 @@ bool write_json(unsigned dim, bool resume, const std::string& analysis, return true; } +// Write JSON Configuration file for twophase +bool write_json_twophase(unsigned dim, bool resume, const std::string& analysis, + const std::string& stress_update, + const std::string& file_name) { + // Make json object with input files + // 2D + std::string dimension = "2d"; + auto particle_type = "P2D2PHASE"; + auto node_type = "N2D2P"; + auto cell_type = "ED2Q4"; + auto io_type = "Ascii2D"; + std::string material = "LinearElastic2D"; + std::string liquid_material = "Newtonian2D"; + std::vector gravity{{0., -9.81}}; + std::vector material_id{{0, 2}}; + std::vector xvalues{{0.0, 0.5, 1.0}}; + std::vector fxvalues{{0.0, 1.0, 1.0}}; + + // 3D + if (dim == 3) { + dimension = "3d"; + particle_type = "P3D2PHASE"; + node_type = "N3D2P"; + cell_type = "ED3H8"; + io_type = "Ascii3D"; + material = "LinearElastic3D"; + liquid_material = "Newtonian3D"; + gravity.clear(); + gravity = {0., 0., -9.81}; + } + + Json json_file = { + {"title", "Example JSON Input for MPM"}, + {"mesh", + {{"mesh", "mesh-" + dimension + ".txt"}, + {"entity_sets", "entity_sets_0.json"}, + {"io_type", io_type}, + {"check_duplicates", true}, + {"isoparametric", false}, + {"node_type", node_type}, + {"boundary_conditions", + {{"velocity_constraints", {{"file", "velocity-constraints.txt"}}}, + {"friction_constraints", {{"file", "friction-constraints.txt"}}}}}, + {"cell_type", cell_type}}}, + {"particles", + {{{"group_id", 0}, + {"generator", + {{"type", "file"}, + {"material_id", material_id}, + {"pset_id", 0}, + {"io_type", io_type}, + {"particle_type", particle_type}, + {"check_duplicates", true}, + {"location", "particles-" + dimension + ".txt"}}}}}}, + {"materials", + {{{"id", 0}, + {"type", material}, + {"density", 1000.}, + {"youngs_modulus", 1.0E+8}, + {"poisson_ratio", 0.495}, + {"porosity", 0.3}, + {"k_x", 0.001}, + {"k_y", 0.001}, + {"k_z", 0.001}}, + {{"id", 1}, + {"type", material}, + {"density", 2300.}, + {"youngs_modulus", 1.5E+6}, + {"poisson_ratio", 0.25}, + {"porosity", 0.3}, + {"k_x", 0.001}, + {"k_y", 0.001}, + {"k_z", 0.001}}, + {{"id", 2}, + {"type", liquid_material}, + {"density", 2300.}, + {"bulk_modulus", 1.E+9}, + {"mu", 0.3}, + {"dynamic_viscosity", 0.}}}}, + {"material_sets", + {{{"material_id", 1}, {"phase_id", 0}, {"pset_id", 2}}}}, + {"external_loading_conditions", + {{"gravity", gravity}, + {"particle_surface_traction", + {{{"math_function_id", 0}, + {"pset_id", -1}, + {"dir", 1}, + {"traction", 10.5}}}}, + {"concentrated_nodal_forces", + {{{"math_function_id", 0}, + {"nset_id", -1}, + {"dir", 1}, + {"force", 10.5}}}}}}, + {"math_functions", + {{{"id", 0}, + {"type", "Linear"}, + {"xvalues", xvalues}, + {"fxvalues", fxvalues}}}}, + {"analysis", + {{"type", analysis}, + {"stress_update", stress_update}, + {"locate_particles", true}, + {"dt", 0.0001}, + {"uuid", file_name + "-" + dimension}, + {"nsteps", 10}, + {"boundary_friction", 0.5}, + {"resume", + {{"resume", resume}, + {"uuid", file_name + "-" + dimension}, + {"step", 5}}}, + {"damping", {{"type", "Cundall"}, {"damping_ratio", 0.02}}}, + {"newmark", {{"newmark", true}, {"gamma", 0.5}, {"beta", 0.25}}}}}, + {"post_processing", + {{"path", "results/"}, + {"vtk", {{"stresses", "strains", "velocity"}}}, + {"vtk_statevars", {{"pdstrain"}}}, + {"output_steps", 5}}}}; + + // Dump JSON as an input file to be read + std::ofstream file; + file.open((file_name + "-" + dimension + ".json").c_str()); + file << json_file.dump(2); + file.close(); + + return true; +} + // Write JSON Entity Set bool write_entity_set() { // JSON Entity Sets diff --git a/tests/io/write_mesh_particles_unitcell.cc b/tests/io/write_mesh_particles_unitcell.cc index 3767f52b1..32b804f9e 100644 --- a/tests/io/write_mesh_particles_unitcell.cc +++ b/tests/io/write_mesh_particles_unitcell.cc @@ -108,6 +108,126 @@ bool write_json_unitcell(unsigned dim, const std::string& analysis, return true; } +// Write JSON Configuration file for two-phase +bool write_json_unitcell_twophase(unsigned dim, const std::string& analysis, + const std::string& stress_update, + const std::string& file_name) { + // Make json object with input files + // 2D + std::string dimension = "2d"; + auto particle_type = "P2D2PHASE"; + auto node_type = "N2D2P"; + auto cell_type = "ED2Q4"; + auto io_type = "Ascii2D"; + std::string material = "LinearElastic2D"; + std::string liquid_material = "Newtonian2D"; + std::vector material_id{{1, 2}}; + std::vector gravity{{0., -9.81}}; + std::vector xvalues{{0.0, 0.5, 1.0}}; + std::vector fxvalues{{0.0, 1.0, 1.0}}; + + // 3D + if (dim == 3) { + dimension = "3d"; + particle_type = "P3D2PHASE"; + node_type = "N3D2P"; + cell_type = "ED3H8"; + io_type = "Ascii3D"; + material = "LinearElastic3D"; + liquid_material = "Newtonian3D"; + gravity.clear(); + gravity = {0., 0., -9.81}; + } + + Json json_file = { + {"title", "Example JSON Input for MPM"}, + {"mesh", + {{"mesh", "mesh-" + dimension + "-unitcell.txt"}, + {"io_type", io_type}, + {"isoparametric", false}, + {"node_type", node_type}, + {"boundary_conditions", + {{"velocity_constraints", {{"file", "velocity-constraints.txt"}}}, + {"friction_constraints", {{"file", "friction-constraints.txt"}}}}}, + {"cell_type", cell_type}}}, + {"particles", + {{{"group_id", 0}, + {"generator", + {{"type", "file"}, + {"io_type", io_type}, + {"material_id", material_id}, + {"pset_id", 0}, + {"particle_type", particle_type}, + {"check_duplicates", true}, + {"location", "particles-" + dimension + "-unitcell.txt"}}}}}}, + {"materials", + {{{"id", 0}, + {"type", material}, + {"density", 1000.}, + {"youngs_modulus", 1.0E+8}, + {"poisson_ratio", 0.495}, + {"k_x", 0.001}, + {"k_y", 0.001}, + {"k_z", 0.001}}, + {{"id", 1}, + {"type", material}, + {"density", 2300.}, + {"youngs_modulus", 1.5E+6}, + {"poisson_ratio", 0.25}, + {"k_x", 0.001}, + {"k_y", 0.001}, + {"k_z", 0.001}}, + {{"id", 2}, + {"type", liquid_material}, + {"density", 2300.}, + {"bulk_modulus", 1.E+9}, + {"mu", 0.3}, + {"dynamic_viscosity", 0.}}}}, + {"external_loading_conditions", + {{"gravity", gravity}, + {"particle_surface_traction", + {{{"math_function_id", 0}, + {"pset_id", -1}, + {"dir", 1}, + {"traction", 10.5}}}}, + {"concentrated_nodal_forces", + {{{"math_function_id", 0}, + {"nset_id", -1}, + {"dir", 1}, + {"force", 10.5}}}}}}, + {"math_functions", + {{{"id", 0}, + {"type", "Linear"}, + {"xvalues", xvalues}, + {"fxvalues", fxvalues}}}}, + {"math_functions", + {{{"id", 0}, + {"type", "Linear"}, + {"xvalues", xvalues}, + {"fxvalues", fxvalues}}}}, + {"analysis", + {{"type", analysis}, + {"stress_update", stress_update}, + {"locate_particles", true}, + {"dt", 0.0001}, + {"nsteps", 10}, + {"boundary_friction", 0.5}, + {"damping", {{"type", "Cundall"}, {"damping_ratio", 0.02}}}, + {"newmark", {{"newmark", true}, {"gamma", 0.5}, {"beta", 0.25}}}}}, + {"post_processing", + {{"path", "results/"}, + {"vtk_statevars", {{"pdstrain"}}}, + {"output_steps", 10}}}}; + + // Dump JSON as an input file to be read + std::ofstream file; + file.open((file_name + "-" + dimension + "-unitcell.json").c_str()); + file << json_file.dump(2); + file.close(); + + return true; +} + // Write Mesh file in 2D bool write_mesh_2d_unitcell() { // Dimension diff --git a/tests/solvers/mpm_explicit_twophase_usf_test.cc b/tests/solvers/mpm_explicit_twophase_usf_test.cc new file mode 100644 index 000000000..1a3fc92bd --- /dev/null +++ b/tests/solvers/mpm_explicit_twophase_usf_test.cc @@ -0,0 +1,191 @@ +#include "catch.hpp" + +//! Alias for JSON +#include "json.hpp" +using Json = nlohmann::json; + +#include "mpm_explicit_twophase.h" +#include "write_mesh_particles.h" + +// Check MPM Explicit +TEST_CASE("MPM 2D Explicit TwoPhase implementation is checked", + "[MPM][2D][Explicit][USF][2Phase]") { + // Dimension + const unsigned Dim = 2; + + // Write JSON file + const std::string fname = "mpm-explicit-twophase-usf"; + const std::string analysis = "MPMExplicitTwoPhase2D"; + const std::string stress_update = "usf"; + bool resume = false; + REQUIRE(mpm_test::write_json_twophase(2, resume, analysis, stress_update, + fname) == true); + + // Write JSON Entity Sets file + REQUIRE(mpm_test::write_entity_set() == true); + + // Write Mesh + REQUIRE(mpm_test::write_mesh_2d() == true); + + // Write Particles + REQUIRE(mpm_test::write_particles_2d() == true); + + // Assign argc and argv to input arguments of MPM + int argc = 5; + // clang-format off + char* argv[] = {(char*)"./mpm", + (char*)"-f", (char*)"./", + (char*)"-i", (char*)"mpm-explicit-twophase-usf-2d.json"}; + // clang-format on + + SECTION("Check initialisation") { + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit MPM + auto mpm = std::make_unique>(std::move(io)); + + // Initialise materials + REQUIRE(mpm->initialise_materials() == true); + // Initialise mesh + REQUIRE(mpm->initialise_mesh() == true); + // Initialise particles + REQUIRE(mpm->initialise_particles() == true); + + // Initialise external loading + REQUIRE(mpm->initialise_loads() == true); + + // Renitialise materials + REQUIRE(mpm->initialise_materials() == false); + } + + SECTION("Check solver") { + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit MPM + auto mpm = std::make_unique>(std::move(io)); + // Solve + REQUIRE(mpm->solve() == true); + // Test check point restart + REQUIRE(mpm->checkpoint_resume() == false); + } + + SECTION("Check resume") { + // Write JSON file + const std::string fname = "mpm-explicit-twophase-usf"; + const std::string analysis = "MPMExplicitTwoPhase2D"; + const std::string stress_update = "usf"; + bool resume = true; + REQUIRE(mpm_test::write_json_twophase(2, resume, analysis, stress_update, + fname) == true); + + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit MPM + auto mpm = std::make_unique>(std::move(io)); + + // Test check point restart + REQUIRE(mpm->checkpoint_resume() == true); + // Solve + REQUIRE(mpm->solve() == true); + } + + SECTION("Check pressure smoothing") { + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit MPM + auto mpm = std::make_unique>(std::move(io)); + // Pressure smoothing + REQUIRE_NOTHROW(mpm->pressure_smoothing(mpm::ParticlePhase::Solid)); + REQUIRE_NOTHROW(mpm->pressure_smoothing(mpm::ParticlePhase::Liquid)); + } +} + +// Check MPM Explicit +TEST_CASE("MPM 3D Explicit TwoPhase implementation is checked", + "[MPM][3D][Explicit][USF][2Phase]") { + // Dimension + const unsigned Dim = 3; + + // Write JSON file + const std::string fname = "mpm-explicit-twophase-usf"; + const std::string analysis = "MPMExplicitTwoPhase3D"; + const std::string stress_update = "usf"; + const bool resume = false; + REQUIRE(mpm_test::write_json_twophase(3, resume, analysis, stress_update, + fname) == true); + + // Write JSON Entity Sets file + REQUIRE(mpm_test::write_entity_set() == true); + + // Write Mesh + REQUIRE(mpm_test::write_mesh_3d() == true); + + // Write Particles + REQUIRE(mpm_test::write_particles_3d() == true); + + // Assign argc and argv to input arguments of MPM + int argc = 5; + // clang-format off + char* argv[] = {(char*)"./mpm", + (char*)"-f", (char*)"./", + (char*)"-i", (char*)"mpm-explicit-twophase-usf-3d.json"}; + // clang-format on + + SECTION("Check initialisation") { + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit MPM + auto mpm = std::make_unique>(std::move(io)); + + // Initialise materials + REQUIRE(mpm->initialise_materials() == true); + // Initialise mesh + REQUIRE(mpm->initialise_mesh() == true); + // Initialise particles + REQUIRE(mpm->initialise_particles() == true); + + // Renitialise materials + REQUIRE(mpm->initialise_materials() == false); + } + + SECTION("Check solver") { + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit MPM + auto mpm = std::make_unique>(std::move(io)); + // Solve + REQUIRE(mpm->solve() == true); + // Test check point restart + REQUIRE(mpm->checkpoint_resume() == false); + } + + SECTION("Check resume") { + // Write JSON file + const std::string fname = "mpm-explicit-twophase-usf"; + const std::string analysis = "MPMExplicitTwoPhase3D"; + const std::string stress_update = "usf"; + bool resume = true; + REQUIRE(mpm_test::write_json_twophase(3, resume, analysis, stress_update, + fname) == true); + + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit MPM + auto mpm = std::make_unique>(std::move(io)); + + // Test check point restart + REQUIRE(mpm->checkpoint_resume() == true); + // Solve + REQUIRE(mpm->solve() == true); + } + + SECTION("Check pressure smoothing") { + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit MPM + auto mpm = std::make_unique>(std::move(io)); + // Pressure smoothing + REQUIRE_NOTHROW(mpm->pressure_smoothing(mpm::ParticlePhase::Solid)); + REQUIRE_NOTHROW(mpm->pressure_smoothing(mpm::ParticlePhase::Liquid)); + } +} diff --git a/tests/solvers/mpm_explicit_twophase_usf_unitcell_test.cc b/tests/solvers/mpm_explicit_twophase_usf_unitcell_test.cc new file mode 100644 index 000000000..690c60828 --- /dev/null +++ b/tests/solvers/mpm_explicit_twophase_usf_unitcell_test.cc @@ -0,0 +1,119 @@ +#include "catch.hpp" + +//! Alias for JSON +#include "json.hpp" +using Json = nlohmann::json; + +#include "mpm_explicit_twophase.h" +#include "write_mesh_particles_unitcell.h" + +// Check MPM Explicit USF +TEST_CASE("MPM 2D Explicit TwoPhase USF implementation is checked in unitcells", + "[MPM][2D][USF][Explicit][2Phase][unitcell]") { + // Dimension + const unsigned Dim = 2; + + // Write JSON file + const std::string fname = "mpm-explicit-twophase-usf"; + const std::string analysis = "MPMExplicitTwoPhase2D"; + const std::string stress_update = "usf"; + REQUIRE(mpm_test::write_json_unitcell_twophase(2, analysis, stress_update, + fname) == true); + + // Write Mesh + REQUIRE(mpm_test::write_mesh_2d_unitcell() == true); + + // Write Particles + REQUIRE(mpm_test::write_particles_2d_unitcell() == true); + + // Assign argc and argv to input arguments of MPM + int argc = 5; + // clang-format off + char* argv[] = {(char*)"./mpm", + (char*)"-f", (char*)"./", + (char*)"-i", (char*)"mpm-explicit-twophase-usf-2d-unitcell.json"}; + // clang-format on + + SECTION("Check initialisation") { + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit MPM + auto mpm = std::make_unique>(std::move(io)); + + // Initialise materials + REQUIRE(mpm->initialise_materials() == true); + + // Initialise mesh and particles + REQUIRE(mpm->initialise_mesh() == true); + REQUIRE(mpm->initialise_particles() == true); + + // Initialise external loading + REQUIRE(mpm->initialise_loads() == true); + + // Renitialise materials + REQUIRE(mpm->initialise_materials() == false); + } + + SECTION("Check solver") { + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit MPM + auto mpm = std::make_unique>(std::move(io)); + // Solve + REQUIRE(mpm->solve() == true); + } +} + +// Check MPM Explicit +TEST_CASE("MPM 3D Explicit TwoPhase USF implementation is checked in unitcells", + "[MPM][3D][Explicit][USF][2Phase][unitcell]") { + // Dimension + const unsigned Dim = 3; + + // Write JSON file + const std::string fname = "mpm-explicit-twophase-usf"; + const std::string analysis = "MPMExplicitTwoPhase3D"; + const std::string stress_update = "usf"; + REQUIRE(mpm_test::write_json_unitcell_twophase(3, analysis, stress_update, + fname) == true); + + // Write Mesh + REQUIRE(mpm_test::write_mesh_3d_unitcell() == true); + + // Write Particles + REQUIRE(mpm_test::write_particles_3d_unitcell() == true); + + // Assign argc and argv to input arguments of MPM + int argc = 5; + // clang-format off + char* argv[] = {(char*)"./mpm", + (char*)"-f", (char*)"./", + (char*)"-i", (char*)"mpm-explicit-twophase-usf-3d-unitcell.json"}; + // clang-format on + + SECTION("Check initialisation") { + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit MPM + auto mpm = std::make_unique>(std::move(io)); + + // Initialise materials + REQUIRE(mpm->initialise_materials() == true); + + // Initialise mesh and particles + REQUIRE(mpm->initialise_mesh() == true); + REQUIRE(mpm->initialise_particles() == true); + + // Renitialise materials + REQUIRE(mpm->initialise_materials() == false); + } + + SECTION("Check solver") { + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit MPM + auto mpm = std::make_unique>(std::move(io)); + // Solve + REQUIRE(mpm->solve() == true); + } +} diff --git a/tests/solvers/mpm_explicit_twophase_usl_test.cc b/tests/solvers/mpm_explicit_twophase_usl_test.cc new file mode 100644 index 000000000..38ceec438 --- /dev/null +++ b/tests/solvers/mpm_explicit_twophase_usl_test.cc @@ -0,0 +1,191 @@ +#include "catch.hpp" + +//! Alias for JSON +#include "json.hpp" +using Json = nlohmann::json; + +#include "mpm_explicit_twophase.h" +#include "write_mesh_particles.h" + +// Check MPM Explicit +TEST_CASE("MPM 2D Explicit USL TwoPhase implementation is checked", + "[MPM][2D][Explicit][USL][2Phase]") { + // Dimension + const unsigned Dim = 2; + + // Write JSON file + const std::string fname = "mpm-explicit-twophase-usl"; + const std::string analysis = "MPMExplicitTwoPhase2D"; + const std::string stress_update = "usl"; + bool resume = false; + REQUIRE(mpm_test::write_json_twophase(2, resume, analysis, stress_update, + fname) == true); + + // Write JSON Entity Sets file + REQUIRE(mpm_test::write_entity_set() == true); + + // Write Mesh + REQUIRE(mpm_test::write_mesh_2d() == true); + + // Write Particles + REQUIRE(mpm_test::write_particles_2d() == true); + + // Assign argc and argv to input arguments of MPM + int argc = 5; + // clang-format off + char* argv[] = {(char*)"./mpm", + (char*)"-f", (char*)"./", + (char*)"-i", (char*)"mpm-explicit-twophase-usl-2d.json"}; + // clang-format on + + SECTION("Check initialisation") { + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit MPM + auto mpm = std::make_unique>(std::move(io)); + + // Initialise materials + REQUIRE(mpm->initialise_materials() == true); + // Initialise mesh + REQUIRE(mpm->initialise_mesh() == true); + // Initialise particles + REQUIRE(mpm->initialise_particles() == true); + + // Initialise external loading + REQUIRE(mpm->initialise_loads() == true); + + // Renitialise materials + REQUIRE(mpm->initialise_materials() == false); + } + + SECTION("Check solver") { + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit MPM + auto mpm = std::make_unique>(std::move(io)); + // Solve + REQUIRE(mpm->solve() == true); + // Test check point restart + REQUIRE(mpm->checkpoint_resume() == false); + } + + SECTION("Check resume") { + // Write JSON file + const std::string fname = "mpm-explicit-twophase-usl"; + const std::string analysis = "MPMExplicitTwoPhase2D"; + const std::string stress_update = "usl"; + bool resume = true; + REQUIRE(mpm_test::write_json_twophase(2, resume, analysis, stress_update, + fname) == true); + + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit MPM + auto mpm = std::make_unique>(std::move(io)); + + // Test check point restart + REQUIRE(mpm->checkpoint_resume() == true); + // Solve + REQUIRE(mpm->solve() == true); + } + + SECTION("Check pressure smoothing") { + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit MPM + auto mpm = std::make_unique>(std::move(io)); + // Pressure smoothing + REQUIRE_NOTHROW(mpm->pressure_smoothing(mpm::ParticlePhase::Solid)); + REQUIRE_NOTHROW(mpm->pressure_smoothing(mpm::ParticlePhase::Liquid)); + } +} + +// Check MPM Explicit +TEST_CASE("MPM 3D Explicit USL TwoPhase implementation is checked", + "[MPM][3D][Explicit][USL][2Phase]") { + // Dimension + const unsigned Dim = 3; + + // Write JSON file + const std::string fname = "mpm-explicit-twophase-usl"; + const std::string analysis = "MPMExplicitTwoPhase3D"; + const std::string stress_update = "usl"; + const bool resume = false; + REQUIRE(mpm_test::write_json_twophase(3, resume, analysis, stress_update, + fname) == true); + + // Write JSON Entity Sets file + REQUIRE(mpm_test::write_entity_set() == true); + + // Write Mesh + REQUIRE(mpm_test::write_mesh_3d() == true); + + // Write Particles + REQUIRE(mpm_test::write_particles_3d() == true); + + // Assign argc and argv to input arguments of MPM + int argc = 5; + // clang-format off + char* argv[] = {(char*)"./mpm", + (char*)"-f", (char*)"./", + (char*)"-i", (char*)"mpm-explicit-twophase-usl-3d.json"}; + // clang-format on + + SECTION("Check initialisation") { + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit MPM + auto mpm = std::make_unique>(std::move(io)); + + // Initialise materials + REQUIRE(mpm->initialise_materials() == true); + // Initialise mesh + REQUIRE(mpm->initialise_mesh() == true); + // Initialise particles + REQUIRE(mpm->initialise_particles() == true); + + // Renitialise materials + REQUIRE(mpm->initialise_materials() == false); + } + + SECTION("Check solver") { + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit MPM + auto mpm = std::make_unique>(std::move(io)); + // Solve + REQUIRE(mpm->solve() == true); + // Test check point restart + REQUIRE(mpm->checkpoint_resume() == false); + } + + SECTION("Check resume") { + // Write JSON file + const std::string fname = "mpm-explicit-twophase-usl"; + const std::string analysis = "MPMExplicitTwoPhase3D"; + const std::string stress_update = "usl"; + bool resume = true; + REQUIRE(mpm_test::write_json_twophase(3, resume, analysis, stress_update, + fname) == true); + + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit MPM + auto mpm = std::make_unique>(std::move(io)); + + // Test check point restart + REQUIRE(mpm->checkpoint_resume() == true); + // Solve + REQUIRE(mpm->solve() == true); + } + + SECTION("Check pressure smoothing") { + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit MPM + auto mpm = std::make_unique>(std::move(io)); + // Pressure smoothing + REQUIRE_NOTHROW(mpm->pressure_smoothing(mpm::ParticlePhase::Solid)); + REQUIRE_NOTHROW(mpm->pressure_smoothing(mpm::ParticlePhase::Liquid)); + } +} diff --git a/tests/solvers/mpm_explicit_twophase_usl_unitcell_test.cc b/tests/solvers/mpm_explicit_twophase_usl_unitcell_test.cc new file mode 100644 index 000000000..2b7e769d1 --- /dev/null +++ b/tests/solvers/mpm_explicit_twophase_usl_unitcell_test.cc @@ -0,0 +1,119 @@ +#include "catch.hpp" + +//! Alias for JSON +#include "json.hpp" +using Json = nlohmann::json; + +#include "mpm_explicit_twophase.h" +#include "write_mesh_particles_unitcell.h" + +// Check MPM Explicit USL +TEST_CASE("MPM 2D Explicit TwoPhase USL implementation is checked in unitcells", + "[MPM][2D][USL][Explicit][2Phase][unitcell]") { + // Dimension + const unsigned Dim = 2; + + // Write JSON file + const std::string fname = "mpm-explicit-twophase-usl"; + const std::string analysis = "MPMExplicitTwoPhase2D"; + const std::string stress_update = "usl"; + REQUIRE(mpm_test::write_json_unitcell_twophase(2, analysis, stress_update, + fname) == true); + + // Write Mesh + REQUIRE(mpm_test::write_mesh_2d_unitcell() == true); + + // Write Particles + REQUIRE(mpm_test::write_particles_2d_unitcell() == true); + + // Assign argc and argv to input arguments of MPM + int argc = 5; + // clang-format off + char* argv[] = {(char*)"./mpm", + (char*)"-f", (char*)"./", + (char*)"-i", (char*)"mpm-explicit-twophase-usl-2d-unitcell.json"}; + // clang-format on + + SECTION("Check initialisation") { + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit MPM + auto mpm = std::make_unique>(std::move(io)); + + // Initialise materials + REQUIRE(mpm->initialise_materials() == true); + + // Initialise mesh and particles + REQUIRE(mpm->initialise_mesh() == true); + REQUIRE(mpm->initialise_particles() == true); + + // Initialise external loading + REQUIRE(mpm->initialise_loads() == true); + + // Renitialise materials + REQUIRE(mpm->initialise_materials() == false); + } + + SECTION("Check solver") { + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit MPM + auto mpm = std::make_unique>(std::move(io)); + // Solve + REQUIRE(mpm->solve() == true); + } +} + +// Check MPM Explicit +TEST_CASE("MPM 3D Explicit TwoPhase USL implementation is checked in unitcells", + "[MPM][3D][Explicit][USL][2Phase][unitcell]") { + // Dimension + const unsigned Dim = 3; + + // Write JSON file + const std::string fname = "mpm-explicit-twophase-usl"; + const std::string analysis = "MPMExplicitTwoPhase3D"; + const std::string stress_update = "usl"; + REQUIRE(mpm_test::write_json_unitcell_twophase(3, analysis, stress_update, + fname) == true); + + // Write Mesh + REQUIRE(mpm_test::write_mesh_3d_unitcell() == true); + + // Write Particles + REQUIRE(mpm_test::write_particles_3d_unitcell() == true); + + // Assign argc and argv to input arguments of MPM + int argc = 5; + // clang-format off + char* argv[] = {(char*)"./mpm", + (char*)"-f", (char*)"./", + (char*)"-i", (char*)"mpm-explicit-twophase-usl-3d-unitcell.json"}; + // clang-format on + + SECTION("Check initialisation") { + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit MPM + auto mpm = std::make_unique>(std::move(io)); + + // Initialise materials + REQUIRE(mpm->initialise_materials() == true); + + // Initialise mesh and particles + REQUIRE(mpm->initialise_mesh() == true); + REQUIRE(mpm->initialise_particles() == true); + + // Renitialise materials + REQUIRE(mpm->initialise_materials() == false); + } + + SECTION("Check solver") { + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit MPM + auto mpm = std::make_unique>(std::move(io)); + // Solve + REQUIRE(mpm->solve() == true); + } +} From 48298d7943bfcef71937706720a9e03a131a33c3 Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Wed, 5 Aug 2020 22:07:10 -0700 Subject: [PATCH 097/175] Modify two_phase node test --- include/node.h | 16 ++++----- include/node.tcc | 27 ++++++++++++++++ include/twophase_node.tcc | 27 ---------------- tests/nodes/node_test.cc | 36 +++++++++++++++++++++ tests/nodes/twophase_node_test.cc | 54 +++++++++++++++++++++++++++++++ 5 files changed, 125 insertions(+), 35 deletions(-) diff --git a/include/node.h b/include/node.h index eee74a764..ac1d672ed 100644 --- a/include/node.h +++ b/include/node.h @@ -134,6 +134,14 @@ class Node : public NodeBase { void update_mass_pressure(unsigned phase, double mass_pressure) noexcept override; + //! 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; + //! Apply pressure constraint //! \param[in] phase Index corresponding to the phase //! \param[in] dt Timestep in analysis @@ -305,14 +313,6 @@ class Node : public NodeBase { bool compute_acceleration_velocity_twophase_explicit_cundall( double dt, double damping_factor) noexcept override; - //! 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; - //! Return drag force at a given node VectorDim drag_force_coefficient() const override { return drag_force_coefficient_; diff --git a/include/node.tcc b/include/node.tcc index 354df76e0..4b5ad4857 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -175,6 +175,33 @@ void mpm::Node::update_mass_pressure( } } +//! Assign pressure constraint +template +bool mpm::Node::assign_pressure_constraint( + const unsigned phase, const double pressure, + const std::shared_ptr& function) { + bool status = true; + try { + // Constrain directions can take values between 0 and Tnphases + if (phase < Tnphases * 2) { + 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; +} + //! Apply pressure constraint template void mpm::Node::apply_pressure_constraint( diff --git a/include/twophase_node.tcc b/include/twophase_node.tcc index 147e23ef3..9bb4d7950 100644 --- a/include/twophase_node.tcc +++ b/include/twophase_node.tcc @@ -129,31 +129,4 @@ bool mpm::Node:: status = true; } return status; -} - -//! Assign pressure constraint -template -bool mpm::Node::assign_pressure_constraint( - const unsigned phase, const double pressure, - const std::shared_ptr& function) { - bool status = true; - try { - // Constrain directions can take values between 0 and Tnphases - if (phase < Tnphases * 2) { - 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; } \ No newline at end of file diff --git a/tests/nodes/node_test.cc b/tests/nodes/node_test.cc index 27dc531e5..7552300eb 100644 --- a/tests/nodes/node_test.cc +++ b/tests/nodes/node_test.cc @@ -156,6 +156,18 @@ TEST_CASE("Node is checked for 1D case", "[node][1D]") { // Try to update pressure to 2000, should throw and keep to 1000. node->assign_pressure(Nphase, pressure); REQUIRE(node->pressure(Nphase) == Approx(1000.0).epsilon(Tolerance)); + // Check pressure constraints + SECTION("Check nodal pressure constraints") { + // Check assign pressure constraint + REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::nSolid, 8000, + nullptr) == true); + // Check apply pressure constraint + REQUIRE_NOTHROW( + node->apply_pressure_constraint(mpm::NodePhase::nSolid)); + // Check pressure + REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + Approx(8000).epsilon(Tolerance)); + } } SECTION("Check external force") { @@ -621,6 +633,18 @@ TEST_CASE("Node is checked for 2D case", "[node][2D]") { // Try to update pressure to 2000, should throw and keep to 1000. node->assign_pressure(Nphase, pressure); REQUIRE(node->pressure(Nphase) == Approx(1000.0).epsilon(Tolerance)); + // Check pressure constraints + SECTION("Check nodal pressure constraints") { + // Check assign pressure constraint + REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::nSolid, 8000, + nullptr) == true); + // Check apply pressure constraint + REQUIRE_NOTHROW( + node->apply_pressure_constraint(mpm::NodePhase::nSolid)); + // Check pressure + REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + Approx(8000).epsilon(Tolerance)); + } } SECTION("Check volume") { @@ -1223,6 +1247,18 @@ TEST_CASE("Node is checked for 3D case", "[node][3D]") { // Try to update pressure to 2000, should throw and keep to 1000. node->assign_pressure(Nphase, pressure); REQUIRE(node->pressure(Nphase) == Approx(1000.0).epsilon(Tolerance)); + // Check pressure constraints + SECTION("Check nodal pressure constraints") { + // Check assign pressure constraint + REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::nSolid, 8000, + nullptr) == true); + // Check apply pressure constraint + REQUIRE_NOTHROW( + node->apply_pressure_constraint(mpm::NodePhase::nSolid)); + // Check pressure + REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + Approx(8000).epsilon(Tolerance)); + } } SECTION("Check external force") { diff --git a/tests/nodes/twophase_node_test.cc b/tests/nodes/twophase_node_test.cc index 672e73a04..9a329094e 100644 --- a/tests/nodes/twophase_node_test.cc +++ b/tests/nodes/twophase_node_test.cc @@ -210,6 +210,24 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2P]") { Approx(1000.0).epsilon(Tolerance)); REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == Approx(2000.0).epsilon(Tolerance)); + // Check pressure constraints + SECTION("Check nodal pressure constraints") { + // Check assign pressure constraint + REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::nSolid, 8000, + nullptr) == true); + REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::nLiquid, 7000, + nullptr) == true); + // Check apply pressure constraint + REQUIRE_NOTHROW( + node->apply_pressure_constraint(mpm::NodePhase::nSolid)); + REQUIRE_NOTHROW( + node->apply_pressure_constraint(mpm::NodePhase::nLiquid)); + // Check pressure + REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + Approx(8000).epsilon(Tolerance)); + REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + Approx(7000).epsilon(Tolerance)); + } } SECTION("Check external force") { @@ -933,6 +951,24 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2P]") { Approx(1000.0).epsilon(Tolerance)); REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == Approx(2000.0).epsilon(Tolerance)); + // Check pressure constraints + SECTION("Check nodal pressure constraints") { + // Check assign pressure constraint + REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::nSolid, 8000, + nullptr) == true); + REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::nLiquid, 7000, + nullptr) == true); + // Check apply pressure constraint + REQUIRE_NOTHROW( + node->apply_pressure_constraint(mpm::NodePhase::nSolid)); + REQUIRE_NOTHROW( + node->apply_pressure_constraint(mpm::NodePhase::nLiquid)); + // Check pressure + REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + Approx(8000).epsilon(Tolerance)); + REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + Approx(7000).epsilon(Tolerance)); + } } SECTION("Check volume") { @@ -1828,6 +1864,24 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2P]") { Approx(1000.0).epsilon(Tolerance)); REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == Approx(2000.0).epsilon(Tolerance)); + // Check pressure constraints + SECTION("Check nodal pressure constraints") { + // Check assign pressure constraint + REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::nSolid, 8000, + nullptr) == true); + REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::nLiquid, 7000, + nullptr) == true); + // Check apply pressure constraint + REQUIRE_NOTHROW( + node->apply_pressure_constraint(mpm::NodePhase::nSolid)); + REQUIRE_NOTHROW( + node->apply_pressure_constraint(mpm::NodePhase::nLiquid)); + // Check pressure + REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + Approx(8000).epsilon(Tolerance)); + REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + Approx(7000).epsilon(Tolerance)); + } } SECTION("Check external force") { From cde881d046eba4142bec1ecae600aea8187e0cdb Mon Sep 17 00:00:00 2001 From: Nanda Date: Fri, 7 Aug 2020 19:13:15 -0700 Subject: [PATCH 098/175] :wrench: :dart: fix write json in test --- tests/io/write_mesh_particles.cc | 2 +- tests/io/write_mesh_particles_unitcell.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/io/write_mesh_particles.cc b/tests/io/write_mesh_particles.cc index 19f283e40..c086fca71 100644 --- a/tests/io/write_mesh_particles.cc +++ b/tests/io/write_mesh_particles.cc @@ -228,7 +228,7 @@ bool write_json_twophase(unsigned dim, bool resume, const std::string& analysis, {"post_processing", {{"path", "results/"}, {"vtk", {{"stresses", "strains", "velocity"}}}, - {"vtk_statevars", {{"pdstrain"}}}, + {"vtk_statevars", {{{"phase_id", 0}, {"statevars", {"pdstrain"}}}}}, {"output_steps", 5}}}}; // Dump JSON as an input file to be read diff --git a/tests/io/write_mesh_particles_unitcell.cc b/tests/io/write_mesh_particles_unitcell.cc index b297cd191..80ded0e06 100644 --- a/tests/io/write_mesh_particles_unitcell.cc +++ b/tests/io/write_mesh_particles_unitcell.cc @@ -216,7 +216,7 @@ bool write_json_unitcell_twophase(unsigned dim, const std::string& analysis, {"newmark", {{"newmark", true}, {"gamma", 0.5}, {"beta", 0.25}}}}}, {"post_processing", {{"path", "results/"}, - {"vtk_statevars", {{"pdstrain"}}}, + {"vtk_statevars", {{{"phase_id", 0}, {"statevars", {"pdstrain"}}}}}, {"output_steps", 10}}}}; // Dump JSON as an input file to be read From 7cb30f9918dcc49936a352f3a4b1987c4911d667 Mon Sep 17 00:00:00 2001 From: Nanda Date: Mon, 10 Aug 2020 19:36:06 -0700 Subject: [PATCH 099/175] :wrench: bug fix in MPI transfer --- include/solvers/mpm_explicit_twophase.tcc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/solvers/mpm_explicit_twophase.tcc b/include/solvers/mpm_explicit_twophase.tcc index 8e95f7ba0..dd5e8793e 100644 --- a/include/solvers/mpm_explicit_twophase.tcc +++ b/include/solvers/mpm_explicit_twophase.tcc @@ -16,15 +16,15 @@ void mpm::MPMExplicitTwoPhase::compute_stress_strain() { // Iterate over each particle to update particle volume mesh_->iterate_over_particles(std::bind( &mpm::ParticleBase::update_volume, std::placeholders::_1)); - // Iterate over each particle to update porosity - mesh_->iterate_over_particles(std::bind( - &mpm::ParticleBase::update_porosity, std::placeholders::_1, dt_)); // Iterate over each particle to compute stress of soil skeleton mesh_->iterate_over_particles(std::bind( &mpm::ParticleBase::compute_stress, std::placeholders::_1)); // Pressure smoothing if (pressure_smoothing_) this->pressure_smoothing(mpm::ParticlePhase::Solid); + // Iterate over each particle to update porosity + mesh_->iterate_over_particles(std::bind( + &mpm::ParticleBase::update_porosity, std::placeholders::_1, dt_)); // Iterate over each particle to compute pore pressure mesh_->iterate_over_particles( std::bind(&mpm::ParticleBase::compute_pore_pressure, @@ -199,7 +199,7 @@ bool mpm::MPMExplicitTwoPhase::solve() { std::bind(&mpm::NodeBase::momentum, std::placeholders::_1, mpm::ParticlePhase::Liquid), std::bind(&mpm::NodeBase::update_momentum, - std::placeholders::_1, false, mpm::ParticlePhase::Solid, + std::placeholders::_1, false, mpm::ParticlePhase::Liquid, std::placeholders::_2)); } #endif From 01c999c667c9f17b5456a431a60c3bbd51dd3cb0 Mon Sep 17 00:00:00 2001 From: Nanda Date: Mon, 10 Aug 2020 19:48:47 -0700 Subject: [PATCH 100/175] :wrench: bug fix for damping, test is failing --- include/solvers/mpm_explicit_twophase.tcc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/include/solvers/mpm_explicit_twophase.tcc b/include/solvers/mpm_explicit_twophase.tcc index dd5e8793e..4a14a1e0e 100644 --- a/include/solvers/mpm_explicit_twophase.tcc +++ b/include/solvers/mpm_explicit_twophase.tcc @@ -320,11 +320,10 @@ bool mpm::MPMExplicitTwoPhase::solve() { // active nodes to compute acceleratation and velocity if (damping_type_ == mpm::Damping::Cundall) mesh_->iterate_over_nodes_predicate( - std::bind(&mpm::NodeBase< - Tdim>::compute_acceleration_velocity_twophase_explicit, - std::placeholders::_1, this->dt_), + std::bind(&mpm::NodeBase:: + compute_acceleration_velocity_twophase_explicit_cundall, + std::placeholders::_1, this->dt_, damping_factor_), std::bind(&mpm::NodeBase::status, std::placeholders::_1)); - else mesh_->iterate_over_nodes_predicate( std::bind(&mpm::NodeBase< From becdfaa74bc95724f677aea8fdccb4ff09f227ee Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Tue, 11 Aug 2020 14:12:47 -0700 Subject: [PATCH 101/175] Change the input names for pressure constraints --- include/solvers/mpm_base.tcc | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index a4c910f48..89a764ef4 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -984,16 +984,16 @@ void mpm::MPMBase::nodal_pressure_constraints( try { // TODO: Get the total phases const unsigned Tnphases = 2; - // Read and assign pore pressure constraints + // 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 pore pressure constraints + // Iterate over pressure constraints for (const auto& constraints : mesh_props["boundary_conditions"]["pressure_constraints"]) { // Pore pressure constraint phase indice - unsigned constraint_phase = constraints["phase"]; + unsigned constraint_phase = constraints["phase_id"]; if (constraint_phase >= Tnphases) throw std::runtime_error( @@ -1001,13 +1001,13 @@ void mpm::MPMBase::nodal_pressure_constraints( // Pore pressure constraints are specified in a file if (constraints.find("file") != constraints.end()) { - std::string pore_pressure_constraints_file = + std::string pressure_constraints_file = constraints.at("file").template get(); bool ppressure_constraints = constraints_->assign_nodal_pressure_constraints( constraint_phase, mesh_io->read_pressure_constraints( - io_->file_name(pore_pressure_constraints_file))); + io_->file_name(pressure_constraints_file))); if (!ppressure_constraints) throw std::runtime_error( "Pore pressure constraints are not properly assigned"); @@ -1019,12 +1019,11 @@ void mpm::MPMBase::nodal_pressure_constraints( constraints.at("math_function_id").template get()); // Set id int nset_id = constraints.at("nset_id").template get(); - // Pore Pressure - double pore_pressure = - constraints.at("pore_pressure").template get(); - // Add pore pressure constraint to mesh + // Pressure + double pressure = constraints.at("pressure").template get(); + // Add pressure constraint to mesh constraints_->assign_nodal_pressure_constraint( - pfunction, nset_id, constraint_phase, pore_pressure); + pfunction, nset_id, constraint_phase, pressure); } } } else From eff342fdfef6787b6bdc40ceef5229577c921872 Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Tue, 11 Aug 2020 15:14:36 -0700 Subject: [PATCH 102/175] Fix the test bug of "damping" --- tests/io/io_test.cc | 2 +- tests/io/write_mesh_particles.cc | 4 ++-- tests/io/write_mesh_particles_unitcell.cc | 6 ++++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/io/io_test.cc b/tests/io/io_test.cc index 9deb96f0e..97aa97776 100644 --- a/tests/io/io_test.cc +++ b/tests/io/io_test.cc @@ -41,7 +41,7 @@ TEST_CASE("IO is checked for input parsing", "[IO][JSON]") { {{"type", "MPMExplicitUSF3D"}, {"dt", 0.001}, {"nsteps", 1000}, - {"damping", {{"type", "Cundall"}, {"damping_ratio", 0.02}}}, + {"damping", {{"type", "Cundall"}, {"damping_factor", 0.02}}}, {"newmark", {{"newmark", true}, {"gamma", 0.5}, {"beta", 0.25}}}}}, {"post_processing", {{"path", "results/"}, {"output_steps", 10}}}}; diff --git a/tests/io/write_mesh_particles.cc b/tests/io/write_mesh_particles.cc index 531cfe961..9d5711aad 100644 --- a/tests/io/write_mesh_particles.cc +++ b/tests/io/write_mesh_particles.cc @@ -96,7 +96,7 @@ bool write_json(unsigned dim, bool resume, const std::string& analysis, {{"resume", resume}, {"uuid", file_name + "-" + dimension}, {"step", 5}}}, - {"damping", {{"type", "Cundall"}, {"damping_ratio", 0.02}}}, + {"damping", {{"type", "Cundall"}, {"damping_factor", 0.02}}}, {"newmark", {{"newmark", true}, {"gamma", 0.5}, {"beta", 0.25}}}}}, {"post_processing", {{"path", "results/"}, @@ -223,7 +223,7 @@ bool write_json_twophase(unsigned dim, bool resume, const std::string& analysis, {{"resume", resume}, {"uuid", file_name + "-" + dimension}, {"step", 5}}}, - {"damping", {{"type", "Cundall"}, {"damping_ratio", 0.02}}}, + {"damping", {{"type", "Cundall"}, {"damping_factor", 0.02}}}, {"newmark", {{"newmark", true}, {"gamma", 0.5}, {"beta", 0.25}}}}}, {"post_processing", {{"path", "results/"}, diff --git a/tests/io/write_mesh_particles_unitcell.cc b/tests/io/write_mesh_particles_unitcell.cc index ae80946f6..a875aa875 100644 --- a/tests/io/write_mesh_particles_unitcell.cc +++ b/tests/io/write_mesh_particles_unitcell.cc @@ -92,7 +92,7 @@ bool write_json_unitcell(unsigned dim, const std::string& analysis, {"dt", 0.001}, {"nsteps", 10}, {"boundary_friction", 0.5}, - {"damping", {{"type", "Cundall"}, {"damping_ratio", 0.02}}}, + {"damping", {{"type", "Cundall"}, {"damping_factor", 0.02}}}, {"newmark", {{"newmark", true}, {"gamma", 0.5}, {"beta", 0.25}}}}}, {"post_processing", {{"path", "results/"}, @@ -169,6 +169,7 @@ bool write_json_unitcell_twophase(unsigned dim, const std::string& analysis, {"density", 1000.}, {"youngs_modulus", 1.0E+8}, {"poisson_ratio", 0.495}, + {"porosity", 0.3}, {"k_x", 0.001}, {"k_y", 0.001}, {"k_z", 0.001}}, @@ -177,6 +178,7 @@ bool write_json_unitcell_twophase(unsigned dim, const std::string& analysis, {"density", 2300.}, {"youngs_modulus", 1.5E+6}, {"poisson_ratio", 0.25}, + {"porosity", 0.3}, {"k_x", 0.001}, {"k_y", 0.001}, {"k_z", 0.001}}, @@ -215,7 +217,7 @@ bool write_json_unitcell_twophase(unsigned dim, const std::string& analysis, {"dt", 0.0001}, {"nsteps", 10}, {"boundary_friction", 0.5}, - {"damping", {{"type", "Cundall"}, {"damping_ratio", 0.02}}}, + {"damping", {{"type", "Cundall"}, {"damping_factor", 0.02}}}, {"newmark", {{"newmark", true}, {"gamma", 0.5}, {"beta", 0.25}}}}}, {"post_processing", {{"path", "results/"}, From 7f2f40dadf3675f8d5d008ee5f88f880ee503841 Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 11 Aug 2020 15:54:38 -0700 Subject: [PATCH 103/175] :wrench: :dart: fix test category --- tests/nodes/twophase_node_test.cc | 6 +++--- tests/particles/twophase_particle_test.cc | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/nodes/twophase_node_test.cc b/tests/nodes/twophase_node_test.cc index 9a329094e..d4cbc7f61 100644 --- a/tests/nodes/twophase_node_test.cc +++ b/tests/nodes/twophase_node_test.cc @@ -10,7 +10,7 @@ #include "node.h" // Check node class for 1D case -TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2P]") { +TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { const unsigned Dim = 1; const unsigned Dof = 1; const unsigned Nphases = 2; @@ -750,7 +750,7 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2P]") { } // \brief Check node class for 2D case -TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2P]") { +TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { const unsigned Dim = 2; const unsigned Dof = 2; const unsigned Nphases = 2; @@ -1663,7 +1663,7 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2P]") { } // \brief Check node class for 3D case -TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2P]") { +TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { const unsigned Dim = 3; const unsigned Dof = 3; const unsigned Nphases = 2; diff --git a/tests/particles/twophase_particle_test.cc b/tests/particles/twophase_particle_test.cc index 20c3e4631..ad8429ed0 100644 --- a/tests/particles/twophase_particle_test.cc +++ b/tests/particles/twophase_particle_test.cc @@ -16,7 +16,7 @@ //! \brief Check twophase particle class for 1D case TEST_CASE("TwoPhase Particle is checked for 1D case", - "[twophase_particle][1D]") { + "[particle][1D][2Phase]") { // Dimension const unsigned Dim = 1; // Dimension @@ -389,7 +389,7 @@ TEST_CASE("TwoPhase Particle is checked for 1D case", //! \brief Check twophase particle class for 2D case TEST_CASE("TwoPhase Particle is checked for 2D case", - "[twophase_particle][2D]") { + "[particle][2D][2Phase]") { // Dimension const unsigned Dim = 2; // Degree of freedom @@ -1672,7 +1672,7 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", //! \brief Check twophase particle class for 3D case TEST_CASE("TwoPhase Particle is checked for 3D case", - "[twophase_particle][3D]") { + "[particle][3D][2Phase]") { // Dimension const unsigned Dim = 3; // Dimension From 55a5eed43c6e36c725bc789ef1b62fad415ccfd9 Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Tue, 11 Aug 2020 17:00:06 -0700 Subject: [PATCH 104/175] Fix the bug for damping --- include/twophase_node.tcc | 12 ++++++------ tests/nodes/twophase_node_test.cc | 4 ++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/include/twophase_node.tcc b/include/twophase_node.tcc index 9bb4d7950..3d153a0eb 100644 --- a/include/twophase_node.tcc +++ b/include/twophase_node.tcc @@ -83,8 +83,8 @@ bool mpm::Node:: // Unbalanced force of liquid phase auto unbalanced_force_liquid = - this->external_force(mpm::NodePhase::nLiquid) + - this->internal_force(mpm::NodePhase::nLiquid) - drag_force; + this->external_force_.col(mpm::NodePhase::nLiquid) + + this->internal_force_.col(mpm::NodePhase::nLiquid) - drag_force; // Acceleration of liquid phase (momentume balance of fluid phase) this->acceleration_.col(mpm::NodePhase::nLiquid) = (unbalanced_force_liquid - @@ -94,10 +94,10 @@ bool mpm::Node:: // Unbalanced force of solid phase auto unbalanced_force_solid = - this->external_force(mpm::NodePhase::nMixture) + - this->internal_force(mpm::NodePhase::nMixture) - - this->mass(mpm::NodePhase::nLiquid) * - this->acceleration(mpm::NodePhase::nLiquid); + this->external_force_.col(mpm::NodePhase::nMixture) + + this->internal_force_.col(mpm::NodePhase::nMixture) - + this->mass_(mpm::NodePhase::nLiquid) * + this->acceleration_.col(mpm::NodePhase::nLiquid); // Acceleration of solid phase (momentume balance of mixture) this->acceleration_.col(mpm::NodePhase::nSolid) = (unbalanced_force_solid - diff --git a/tests/nodes/twophase_node_test.cc b/tests/nodes/twophase_node_test.cc index d4cbc7f61..eebb0182c 100644 --- a/tests/nodes/twophase_node_test.cc +++ b/tests/nodes/twophase_node_test.cc @@ -425,6 +425,10 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { node->update_mass(false, mpm::NodePhase::nSolid, solid_mass)); REQUIRE(node->mass(mpm::NodePhase::nSolid) == Approx(solid_mass).epsilon(Tolerance)); + REQUIRE_NOTHROW( + node->update_mass(false, mpm::NodePhase::nLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + Approx(liquid_mass).epsilon(Tolerance)); // Check internal force // Create a force vector From be2bbb97d7de246087fb48692f43c8726b2b44b4 Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Tue, 11 Aug 2020 18:25:43 -0700 Subject: [PATCH 105/175] Correct the files names --- CMakeLists.txt | 4 ++-- include/node.h | 2 +- include/{twophase_node.tcc => node_twophase.tcc} | 0 .../{twophase_particle.h => particle_twophase.h} | 8 ++++---- .../{twophase_particle.tcc => particle_twophase.tcc} | 0 src/particle.cc | 2 +- .../{twophase_node_test.cc => node_twophase_test.cc} | 0 ...wophase_particle_test.cc => particle_twophase_test.cc} | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) rename include/{twophase_node.tcc => node_twophase.tcc} (100%) rename include/particles/{twophase_particle.h => particle_twophase.h} (98%) rename include/particles/{twophase_particle.tcc => particle_twophase.tcc} (100%) rename tests/nodes/{twophase_node_test.cc => node_twophase_test.cc} (100%) rename tests/particles/{twophase_particle_test.cc => particle_twophase_test.cc} (99%) diff --git a/CMakeLists.txt b/CMakeLists.txt index d141ff1a8..38d4b934d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -211,11 +211,11 @@ if(MPM_BUILD_TESTING) ${mpm_SOURCE_DIR}/tests/nodes/nodal_properties_test.cc ${mpm_SOURCE_DIR}/tests/nodes/node_map_test.cc ${mpm_SOURCE_DIR}/tests/nodes/node_test.cc - ${mpm_SOURCE_DIR}/tests/nodes/twophase_node_test.cc + ${mpm_SOURCE_DIR}/tests/nodes/node_twophase_test.cc ${mpm_SOURCE_DIR}/tests/nodes/node_vector_test.cc ${mpm_SOURCE_DIR}/tests/particles/particle_cell_crossing_test.cc ${mpm_SOURCE_DIR}/tests/particles/particle_test.cc - ${mpm_SOURCE_DIR}/tests/particles/twophase_particle_test.cc + ${mpm_SOURCE_DIR}/tests/particles/particle_twophase_test.cc ${mpm_SOURCE_DIR}/tests/particles/particle_traction_test.cc ${mpm_SOURCE_DIR}/tests/particles/particle_vector_test.cc ${mpm_SOURCE_DIR}/tests/point_in_cell_test.cc diff --git a/include/node.h b/include/node.h index ac1d672ed..f3fee8da9 100644 --- a/include/node.h +++ b/include/node.h @@ -388,6 +388,6 @@ class Node : public NodeBase { } // namespace mpm #include "node.tcc" -#include "twophase_node.tcc" +#include "node_twophase.tcc" #endif // MPM_NODE_H_ diff --git a/include/twophase_node.tcc b/include/node_twophase.tcc similarity index 100% rename from include/twophase_node.tcc rename to include/node_twophase.tcc diff --git a/include/particles/twophase_particle.h b/include/particles/particle_twophase.h similarity index 98% rename from include/particles/twophase_particle.h rename to include/particles/particle_twophase.h index 24e6e525f..931a6acf7 100644 --- a/include/particles/twophase_particle.h +++ b/include/particles/particle_twophase.h @@ -1,5 +1,5 @@ -#ifndef MPM_TWOPHASE_PARTICLE_H_ -#define MPM_TWOPHASE_PARTICLE_H_ +#ifndef MPM_PARTICLE_TWOPHASE_H_ +#define MPM_PARTICLE_TWOPHASE_H_ #include #include @@ -243,6 +243,6 @@ class TwoPhaseParticle : public mpm::Particle { }; // TwoPhaseParticle class } // namespace mpm -#include "twophase_particle.tcc" +#include "particle_twophase.tcc" -#endif // MPM_TWOPHASE_PARTICLE_H__ +#endif // MPM_PARTICLE_TWOPHASE_H__ diff --git a/include/particles/twophase_particle.tcc b/include/particles/particle_twophase.tcc similarity index 100% rename from include/particles/twophase_particle.tcc rename to include/particles/particle_twophase.tcc diff --git a/src/particle.cc b/src/particle.cc index d5593d0ab..16bfa2e0c 100644 --- a/src/particle.cc +++ b/src/particle.cc @@ -1,7 +1,7 @@ #include "particle.h" #include "factory.h" #include "particle_base.h" -#include "twophase_particle.h" +#include "particle_twophase.h" // Particle2D (2 Dim) static Register, mpm::Particle<2>, mpm::Index, diff --git a/tests/nodes/twophase_node_test.cc b/tests/nodes/node_twophase_test.cc similarity index 100% rename from tests/nodes/twophase_node_test.cc rename to tests/nodes/node_twophase_test.cc diff --git a/tests/particles/twophase_particle_test.cc b/tests/particles/particle_twophase_test.cc similarity index 99% rename from tests/particles/twophase_particle_test.cc rename to tests/particles/particle_twophase_test.cc index ad8429ed0..77990ebc6 100644 --- a/tests/particles/twophase_particle_test.cc +++ b/tests/particles/particle_twophase_test.cc @@ -11,8 +11,8 @@ #include "material.h" #include "node.h" #include "particle.h" +#include "particle_twophase.h" #include "quadrilateral_element.h" -#include "twophase_particle.h" //! \brief Check twophase particle class for 1D case TEST_CASE("TwoPhase Particle is checked for 1D case", From 304f54a4cfc12b8f2ce4153b64f3a6bdd14079cd Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 11 Aug 2020 18:52:47 -0700 Subject: [PATCH 106/175] :wrench: modify some free-surface functions as suggested --- include/cell.h | 10 ++++------ include/cell.tcc | 25 +++++++++++-------------- include/mesh.h | 2 +- include/mesh.tcc | 2 +- 4 files changed, 17 insertions(+), 22 deletions(-) diff --git a/include/cell.h b/include/cell.h index ddee2e5ac..b68005f3c 100644 --- a/include/cell.h +++ b/include/cell.h @@ -223,21 +223,19 @@ class Cell { //! Return free surface bool //! \retval free_surface_ indicating free surface cell - bool free_surface() { return free_surface_; }; + bool free_surface() const { 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; - }; + void assign_volume_fraction(double volume_fraction); //! Return cell volume fraction //! \retval volume_fraction_ cell volume fraction - double volume_fraction() { return volume_fraction_; }; + double volume_fraction() const { return volume_fraction_; }; //! Map cell volume to the nodes //! \param[in] phase to map volume - bool map_cell_volume_to_nodes(unsigned phase); + void map_cell_volume_to_nodes(unsigned phase); private: //! Approximately check if a point is in a cell diff --git a/include/cell.tcc b/include/cell.tcc index c5ebc3381..21dda7353 100644 --- a/include/cell.tcc +++ b/include/cell.tcc @@ -845,22 +845,19 @@ inline unsigned mpm::Cell::previous_mpirank() const { return this->previous_mpirank_; } -//! Map cell volume to nodes +//! Assign volume traction to node 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(); +void mpm::Cell::assign_volume_fraction(double volume_fraction) { + volume_fraction_ = volume_fraction; +} - for (unsigned i = 0; i < nodes_.size(); ++i) { - nodes_[i]->update_volume(true, phase, volume_ / nnodes_); - } +//! Map cell volume to nodes +template +void mpm::Cell::map_cell_volume_to_nodes(unsigned phase) { + // Check if cell volume is set + if (volume_ == std::numeric_limits::lowest()) this->compute_volume(); - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; + for (unsigned i = 0; i < nodes_.size(); ++i) { + nodes_[i]->update_volume(true, phase, volume_ / nnodes_); } - return status; } diff --git a/include/mesh.h b/include/mesh.h index 8bfcd79a9..a7a071a36 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -468,7 +468,7 @@ class Mesh { //! \param[in] volume_tolerance for volume_fraction approach //! \retval status Status of compute_free_surface bool compute_free_surface( - std::string method, + const std::string& method, double volume_tolerance = std::numeric_limits::epsilon()); //! Compute free surface by density method diff --git a/include/mesh.tcc b/include/mesh.tcc index ceca3f8e6..417d02017 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1922,7 +1922,7 @@ void mpm::Mesh::create_nodal_properties() { //! Compute free surface cells, nodes, and particles template -bool mpm::Mesh::compute_free_surface(std::string method, +bool mpm::Mesh::compute_free_surface(const std::string& method, double volume_tolerance) { if (method == "density") { return this->compute_free_surface_by_density(volume_tolerance); From 98b7763326bd6c1bc597c7c5304b3f02dbf84cd4 Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 11 Aug 2020 23:19:39 -0700 Subject: [PATCH 107/175] :wrench::fire: add hdf5 data structure for twophase --- CMakeLists.txt | 1 + include/hdf5_particle_twophase.h | 49 +++++++ include/mpi_datatypes_twophase.h | 141 ++++++++++++++++++ src/hdf5_particle_twophase.cc | 242 +++++++++++++++++++++++++++++++ 4 files changed, 433 insertions(+) create mode 100644 include/hdf5_particle_twophase.h create mode 100644 include/mpi_datatypes_twophase.h create mode 100644 src/hdf5_particle_twophase.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 38d4b934d..5e3f9d1c2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -157,6 +157,7 @@ SET(mpm_src ${mpm_SOURCE_DIR}/src/functions/sin_function.cc ${mpm_SOURCE_DIR}/src/geometry.cc ${mpm_SOURCE_DIR}/src/hdf5_particle.cc + ${mpm_SOURCE_DIR}/src/hdf5_particle_twophase.cc ${mpm_SOURCE_DIR}/src/io/io.cc ${mpm_SOURCE_DIR}/src/io/io_mesh.cc ${mpm_SOURCE_DIR}/src/io/logger.cc diff --git a/include/hdf5_particle_twophase.h b/include/hdf5_particle_twophase.h new file mode 100644 index 000000000..cb8d6940f --- /dev/null +++ b/include/hdf5_particle_twophase.h @@ -0,0 +1,49 @@ +#ifndef MPM_HDF5_TWOPHASE_H_ +#define MPM_HDF5_TWOPHASE_H_ + +// HDF5 Particle +#include "hdf5_particle.h" + +namespace mpm { +// Define a struct of particle +typedef struct HDF5ParticleTwoPhase : HDF5Particle { + // Liquid Mass + double liquid_mass; + // Liquid Velocity + double liquid_velocity_x, liquid_velocity_y, liquid_velocity_z; + // Porosity + double porosity; + // Liquid Saturation + double liquid_saturation; + // Material id + unsigned liquid_material_id; + // Number of state variables + unsigned nliquid_state_vars; + // State variables (init to zero) + double liquid_svars[5] = {0}; +} HDF5ParticleTwoPhase; + +namespace hdf5 { +namespace particletwophase { +const hsize_t NFIELDS = 66; + +const size_t dst_size = sizeof(HDF5ParticleTwoPhase); + +// Destination offset +extern const size_t dst_offset[NFIELDS]; + +// Destination size +extern const size_t dst_sizes[NFIELDS]; + +// Define particle field information +extern const char* field_names[NFIELDS]; + +// Initialize field types +extern const hid_t field_type[NFIELDS]; + +} // namespace particletwophase +} // namespace hdf5 + +} // namespace mpm + +#endif // MPM_HDF5_TWOPHASE_H_ diff --git a/include/mpi_datatypes_twophase.h b/include/mpi_datatypes_twophase.h new file mode 100644 index 000000000..f24f4a894 --- /dev/null +++ b/include/mpi_datatypes_twophase.h @@ -0,0 +1,141 @@ +#ifndef MPM_MPI_HDF5_PARTICLE_TWOPHASE_H_ +#define MPM_MPI_HDF5_PARTICLE_TWOPHASE_H_ + +// Offset macro +#include + +// MPI +#ifdef USE_MPI +#include "mpi.h" + +#include "hdf5_particle_twophase.h" +#include "mpi_datatypes.h" + +namespace mpm { +//! Initialize MPI particle data types +inline MPI_Datatype register_mpi_particle_type( + const HDF5ParticleTwoPhase& particle) { + // Number of blocks to create + const unsigned nblocks = 43; + // Array containing the length of each block + int lengths[nblocks] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 20, 1, 1, 1, 1, 1, 1, 1, 1, 5}; + // Array containing the displacement for each block, expressed in bytes. The + // displacement is the distance between the start of the MPI datatype created + // and the start of the block + const MPI_Aint displacements[nblocks] = { + // Solid phase + offsetof(HDF5ParticleTwoPhase, id), // id + offsetof(HDF5ParticleTwoPhase, mass), // mass + offsetof(HDF5ParticleTwoPhase, volume), // volume + offsetof(HDF5ParticleTwoPhase, pressure), // pressure + offsetof(HDF5ParticleTwoPhase, coord_x), // coord_x + offsetof(HDF5ParticleTwoPhase, coord_y), // coord_y + offsetof(HDF5ParticleTwoPhase, coord_z), // coord_z + offsetof(HDF5ParticleTwoPhase, displacement_x), // disp_x + offsetof(HDF5ParticleTwoPhase, displacement_y), // disp_y + offsetof(HDF5ParticleTwoPhase, displacement_z), // disp_z + offsetof(HDF5ParticleTwoPhase, nsize_x), // nsize_x + offsetof(HDF5ParticleTwoPhase, nsize_y), // nsize_y + offsetof(HDF5ParticleTwoPhase, nsize_z), // nsize_z + offsetof(HDF5ParticleTwoPhase, velocity_x), // vel_x + offsetof(HDF5ParticleTwoPhase, velocity_y), // vel_y + offsetof(HDF5ParticleTwoPhase, velocity_z), // vel_z + offsetof(HDF5ParticleTwoPhase, stress_xx), // stress_xx + offsetof(HDF5ParticleTwoPhase, stress_yy), // stress_yy + offsetof(HDF5ParticleTwoPhase, stress_zz), // stress_zz + offsetof(HDF5ParticleTwoPhase, tau_xy), // tau_xy + offsetof(HDF5ParticleTwoPhase, tau_yz), // tau_yz + offsetof(HDF5ParticleTwoPhase, tau_xz), // tau_xz + offsetof(HDF5ParticleTwoPhase, strain_xx), // strain_xx + offsetof(HDF5ParticleTwoPhase, strain_yy), // strain_yy + offsetof(HDF5ParticleTwoPhase, strain_zz), // strain_zz + offsetof(HDF5ParticleTwoPhase, gamma_xy), // gamma_xy + offsetof(HDF5ParticleTwoPhase, gamma_yz), // gamma_yz + offsetof(HDF5ParticleTwoPhase, gamma_xz), // gamma_xz + offsetof(HDF5ParticleTwoPhase, epsilon_v), // epsv + offsetof(HDF5ParticleTwoPhase, cell_id), // cellid + offsetof(HDF5ParticleTwoPhase, status), // status + offsetof(HDF5ParticleTwoPhase, material_id), // material_id + offsetof(HDF5ParticleTwoPhase, nstate_vars), // nstate_vars + offsetof(HDF5ParticleTwoPhase, svars), // state_vars + // Fluid phase + offsetof(HDF5ParticleTwoPhase, liquid_mass), // liquid_mass + offsetof(HDF5ParticleTwoPhase, liquid_velocity_x), // liquid_vel_x + offsetof(HDF5ParticleTwoPhase, liquid_velocity_y), // liquid_vel_y + offsetof(HDF5ParticleTwoPhase, liquid_velocity_z), // liquid_vel_z + offsetof(HDF5ParticleTwoPhase, porosity), // porosity + offsetof(HDF5ParticleTwoPhase, liquid_saturation), // liquid_saturation + offsetof(HDF5ParticleTwoPhase, liquid_material_id), // liquid_material_id + offsetof(HDF5ParticleTwoPhase, nliquid_state_vars), // nliquid_state_vars + offsetof(HDF5ParticleTwoPhase, liquid_svars) // liquid_state_vars + }; + + // Array containing the MPI datatypes to replicate to make each block. + MPI_Datatype types[nblocks] = { + // Solid phase + MPI_UNSIGNED_LONG_LONG, // id + MPI_DOUBLE, // mass + MPI_DOUBLE, // volume + MPI_DOUBLE, // pressure + MPI_DOUBLE, // coord_x + MPI_DOUBLE, // coord_y + MPI_DOUBLE, // coord_z + MPI_DOUBLE, // disp_x + MPI_DOUBLE, // disp_y + MPI_DOUBLE, // disp_z + MPI_DOUBLE, // nsize_x + MPI_DOUBLE, // nsize_y + MPI_DOUBLE, // nsize_z + MPI_DOUBLE, // vel_x + MPI_DOUBLE, // vel_y + MPI_DOUBLE, // vel_z + MPI_DOUBLE, // stress_xx + MPI_DOUBLE, // stress_yy + MPI_DOUBLE, // stress_zz + MPI_DOUBLE, // tau_xx + MPI_DOUBLE, // tau_yy + MPI_DOUBLE, // tau_zz + MPI_DOUBLE, // strain_xx + MPI_DOUBLE, // strain_yy + MPI_DOUBLE, // strain_zz + MPI_DOUBLE, // gamma_xy + MPI_DOUBLE, // gamma_yz + MPI_DOUBLE, // gamma_zx + MPI_DOUBLE, // epsv + MPI_UNSIGNED_LONG_LONG, // cell_id + MPI_C_BOOL, // status + MPI_UNSIGNED, // material_id + MPI_UNSIGNED, // nstate_vars + MPI_DOUBLE, // state variables + // Fluid phase + MPI_DOUBLE, // liquid_mass + MPI_DOUBLE, // liquid_velocity_x + MPI_DOUBLE, // liquid_velocity_y + MPI_DOUBLE, // liquid_velocity_z + MPI_DOUBLE, // porosity + MPI_DOUBLE, // liquid_saturation + MPI_UNSIGNED, // liquid_material_id + MPI_UNSIGNED, // nliquid_state_vars + MPI_DOUBLE, // liquid_svars + }; + + // Create the Particle datatype + MPI_Datatype MPIParticle; + + // Create particle data types + MPI_Type_create_struct(nblocks, lengths, displacements, types, &MPIParticle); + MPI_Type_commit(&MPIParticle); + return MPIParticle; +} + +//! Deregister MPI particle data type +inline void deregister_mpi_particle_type(MPI_Datatype& particle_type) { + MPI_Type_free(&particle_type); +} +} // namespace mpm + +#endif // MPI + +#endif // MPM_MPI_HDF5_PARTICLE_TWOPHASE_H_ diff --git a/src/hdf5_particle_twophase.cc b/src/hdf5_particle_twophase.cc new file mode 100644 index 000000000..ed994cd68 --- /dev/null +++ b/src/hdf5_particle_twophase.cc @@ -0,0 +1,242 @@ +#include "hdf5_particle_twophase.h" +namespace mpm { +namespace hdf5 { +namespace particletwophase { +const size_t dst_offset[NFIELDS] = { + // Solid phase + HOFFSET(HDF5ParticleTwoPhase, id), + HOFFSET(HDF5ParticleTwoPhase, mass), + HOFFSET(HDF5ParticleTwoPhase, volume), + HOFFSET(HDF5ParticleTwoPhase, pressure), + HOFFSET(HDF5ParticleTwoPhase, coord_x), + HOFFSET(HDF5ParticleTwoPhase, coord_y), + HOFFSET(HDF5ParticleTwoPhase, coord_z), + HOFFSET(HDF5ParticleTwoPhase, displacement_x), + HOFFSET(HDF5ParticleTwoPhase, displacement_y), + HOFFSET(HDF5ParticleTwoPhase, displacement_z), + HOFFSET(HDF5ParticleTwoPhase, nsize_x), + HOFFSET(HDF5ParticleTwoPhase, nsize_y), + HOFFSET(HDF5ParticleTwoPhase, nsize_z), + HOFFSET(HDF5ParticleTwoPhase, velocity_x), + HOFFSET(HDF5ParticleTwoPhase, velocity_y), + HOFFSET(HDF5ParticleTwoPhase, velocity_z), + HOFFSET(HDF5ParticleTwoPhase, stress_xx), + HOFFSET(HDF5ParticleTwoPhase, stress_yy), + HOFFSET(HDF5ParticleTwoPhase, stress_zz), + HOFFSET(HDF5ParticleTwoPhase, tau_xy), + HOFFSET(HDF5ParticleTwoPhase, tau_yz), + HOFFSET(HDF5ParticleTwoPhase, tau_xz), + HOFFSET(HDF5ParticleTwoPhase, strain_xx), + HOFFSET(HDF5ParticleTwoPhase, strain_yy), + HOFFSET(HDF5ParticleTwoPhase, strain_zz), + HOFFSET(HDF5ParticleTwoPhase, gamma_xy), + HOFFSET(HDF5ParticleTwoPhase, gamma_yz), + HOFFSET(HDF5ParticleTwoPhase, gamma_xz), + HOFFSET(HDF5ParticleTwoPhase, epsilon_v), + HOFFSET(HDF5ParticleTwoPhase, status), + HOFFSET(HDF5ParticleTwoPhase, cell_id), + HOFFSET(HDF5ParticleTwoPhase, material_id), + HOFFSET(HDF5ParticleTwoPhase, nstate_vars), + HOFFSET(HDF5ParticleTwoPhase, svars[0]), + HOFFSET(HDF5ParticleTwoPhase, svars[1]), + HOFFSET(HDF5ParticleTwoPhase, svars[2]), + HOFFSET(HDF5ParticleTwoPhase, svars[3]), + HOFFSET(HDF5ParticleTwoPhase, svars[4]), + HOFFSET(HDF5ParticleTwoPhase, svars[5]), + HOFFSET(HDF5ParticleTwoPhase, svars[6]), + HOFFSET(HDF5ParticleTwoPhase, svars[7]), + HOFFSET(HDF5ParticleTwoPhase, svars[8]), + HOFFSET(HDF5ParticleTwoPhase, svars[9]), + HOFFSET(HDF5ParticleTwoPhase, svars[10]), + HOFFSET(HDF5ParticleTwoPhase, svars[11]), + HOFFSET(HDF5ParticleTwoPhase, svars[12]), + HOFFSET(HDF5ParticleTwoPhase, svars[13]), + HOFFSET(HDF5ParticleTwoPhase, svars[14]), + HOFFSET(HDF5ParticleTwoPhase, svars[15]), + HOFFSET(HDF5ParticleTwoPhase, svars[16]), + HOFFSET(HDF5ParticleTwoPhase, svars[17]), + HOFFSET(HDF5ParticleTwoPhase, svars[18]), + HOFFSET(HDF5ParticleTwoPhase, svars[19]), + // Fluid phase + HOFFSET(HDF5ParticleTwoPhase, liquid_mass), + HOFFSET(HDF5ParticleTwoPhase, liquid_velocity_x), + HOFFSET(HDF5ParticleTwoPhase, liquid_velocity_y), + HOFFSET(HDF5ParticleTwoPhase, liquid_velocity_z), + HOFFSET(HDF5ParticleTwoPhase, porosity), + HOFFSET(HDF5ParticleTwoPhase, liquid_saturation), + HOFFSET(HDF5ParticleTwoPhase, liquid_material_id), + HOFFSET(HDF5ParticleTwoPhase, nliquid_state_vars), + HOFFSET(HDF5ParticleTwoPhase, liquid_svars[0]), + HOFFSET(HDF5ParticleTwoPhase, liquid_svars[1]), + HOFFSET(HDF5ParticleTwoPhase, liquid_svars[2]), + HOFFSET(HDF5ParticleTwoPhase, liquid_svars[3]), + HOFFSET(HDF5ParticleTwoPhase, liquid_svars[4]), +}; + +// Get size of particletwophase +HDF5ParticleTwoPhase particle; +const size_t dst_sizes[NFIELDS] = { + // Solid phase + sizeof(particle.id), + sizeof(particle.mass), + sizeof(particle.volume), + sizeof(particle.pressure), + sizeof(particle.coord_x), + sizeof(particle.coord_y), + sizeof(particle.coord_z), + sizeof(particle.displacement_x), + sizeof(particle.displacement_y), + sizeof(particle.displacement_z), + sizeof(particle.nsize_x), + sizeof(particle.nsize_y), + sizeof(particle.nsize_z), + sizeof(particle.velocity_x), + sizeof(particle.velocity_y), + sizeof(particle.velocity_z), + sizeof(particle.stress_xx), + sizeof(particle.stress_yy), + sizeof(particle.stress_zz), + sizeof(particle.tau_xy), + sizeof(particle.tau_yz), + sizeof(particle.tau_xz), + sizeof(particle.strain_xx), + sizeof(particle.strain_yy), + sizeof(particle.strain_zz), + sizeof(particle.gamma_xy), + sizeof(particle.gamma_yz), + sizeof(particle.gamma_xz), + sizeof(particle.epsilon_v), + sizeof(particle.status), + sizeof(particle.cell_id), + sizeof(particle.material_id), + sizeof(particle.nstate_vars), + sizeof(particle.svars[0]), + sizeof(particle.svars[1]), + sizeof(particle.svars[2]), + sizeof(particle.svars[3]), + sizeof(particle.svars[4]), + sizeof(particle.svars[5]), + sizeof(particle.svars[6]), + sizeof(particle.svars[7]), + sizeof(particle.svars[8]), + sizeof(particle.svars[9]), + sizeof(particle.svars[10]), + sizeof(particle.svars[11]), + sizeof(particle.svars[12]), + sizeof(particle.svars[13]), + sizeof(particle.svars[14]), + sizeof(particle.svars[15]), + sizeof(particle.svars[16]), + sizeof(particle.svars[17]), + sizeof(particle.svars[18]), + sizeof(particle.svars[19]), + // Fluid phase + sizeof(particle.liquid_mass), + sizeof(particle.liquid_velocity_x), + sizeof(particle.liquid_velocity_y), + sizeof(particle.liquid_velocity_z), + sizeof(particle.porosity), + sizeof(particle.liquid_saturation), + sizeof(particle.liquid_material_id), + sizeof(particle.nliquid_state_vars), + sizeof(particle.liquid_svars[0]), + sizeof(particle.liquid_svars[1]), + sizeof(particle.liquid_svars[2]), + sizeof(particle.liquid_svars[3]), + sizeof(particle.liquid_svars[4]), +}; + +// Define particletwophase field information +const char* field_names[NFIELDS] = { + // Solid phase + "id", + "mass", + "volume", + "pressure", + "coord_x", + "coord_y", + "coord_z", + "displacement_x", + "displacement_y", + "displacement_z", + "nsize_x", + "nsize_y", + "nsize_z", + "velocity_x", + "velocity_y", + "velocity_z", + "stress_xx", + "stress_yy", + "stress_zz", + "tau_xy", + "tau_yz", + "tau_xz", + "strain_xx", + "strain_yy", + "strain_zz", + "gamma_xy", + "gamma_yz", + "gamma_xz", + "epsilon_v", + "status", + "cell_id", + "material_id", + "nstate_vars", + "svars_0", + "svars_1", + "svars_2", + "svars_3", + "svars_4", + "svars_5", + "svars_6", + "svars_7", + "svars_8", + "svars_9", + "svars_10", + "svars_11", + "svars_12", + "svars_13", + "svars_14", + "svars_15", + "svars_16", + "svars_17", + "svars_18", + "svars_19", + // Fluid phase + "liquid_mass", + "liquid_velocity_x", + "liquid_velocity_y", + "liquid_velocity_z", + "porosity", + "liquid_saturation", + "liquid_material_id", + "nliquid_state_vars", + "liquid_svars_0", + "liquid_svars_1", + "liquid_svars_2", + "liquid_svars_3", + "liquid_svars_4", +}; + +// Initialize field types +const hid_t field_type[NFIELDS] = { + H5T_NATIVE_LLONG, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, + H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, + H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, + H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, + H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, + H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, + H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, + H5T_NATIVE_DOUBLE, H5T_NATIVE_HBOOL, H5T_NATIVE_LLONG, H5T_NATIVE_UINT, + H5T_NATIVE_UINT, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, + H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, + H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, + H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, + H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, + H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, + H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, H5T_NATIVE_UINT, + H5T_NATIVE_UINT, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, + H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE}; +} // namespace particletwophase +} // namespace hdf5 +} // namespace mpm From 311be05fcfae53f4f7cf494e465d51f3b11052a3 Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 12 Aug 2020 11:32:30 -0700 Subject: [PATCH 108/175] :wrench::art: cleanup typo --- tests/mpi_particle_test.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/mpi_particle_test.cc b/tests/mpi_particle_test.cc index 833324092..4e8e7762b 100644 --- a/tests/mpi_particle_test.cc +++ b/tests/mpi_particle_test.cc @@ -292,17 +292,17 @@ TEST_CASE("MPI HDF5 Particle is checked", "[particle][mpi][hdf5]") { const auto h5_send = particle->hdf5(); // Send MPI particle - MPI_Datatype paritcle_type = mpm::register_mpi_particle_type(h5_send); - MPI_Send(&h5_send, 1, paritcle_type, receiver, 0, MPI_COMM_WORLD); - mpm::deregister_mpi_particle_type(paritcle_type); + MPI_Datatype particle_type = mpm::register_mpi_particle_type(h5_send); + MPI_Send(&h5_send, 1, particle_type, receiver, 0, MPI_COMM_WORLD); + mpm::deregister_mpi_particle_type(particle_type); } if (mpi_rank == receiver) { // Receive the messid struct mpm::HDF5Particle received; - MPI_Datatype paritcle_type = mpm::register_mpi_particle_type(received); - MPI_Recv(&received, 1, paritcle_type, sender, 0, MPI_COMM_WORLD, + MPI_Datatype particle_type = mpm::register_mpi_particle_type(received); + MPI_Recv(&received, 1, particle_type, sender, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - mpm::deregister_mpi_particle_type(paritcle_type); + mpm::deregister_mpi_particle_type(particle_type); // Received particle std::shared_ptr> rparticle = From 708c6d0b8982408984f91dcbc4e1d1508f19edba Mon Sep 17 00:00:00 2001 From: Nanda Date: Thu, 13 Aug 2020 11:32:37 -0700 Subject: [PATCH 109/175] :wrench: hdf5 output and initialization in twophase --- include/particles/particle_base.h | 31 +++++ include/particles/particle_twophase.h | 16 +-- include/particles/particle_twophase.tcc | 157 +++++++++++++++++------- 3 files changed, 153 insertions(+), 51 deletions(-) diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 4e7f7aaf8..fa18edea8 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -10,6 +10,7 @@ #include "data_types.h" #include "function_base.h" #include "hdf5_particle.h" +#include "hdf5_particle_twophase.h" #include "material.h" namespace mpm { @@ -322,6 +323,36 @@ class ParticleBase { virtual std::vector neighbours() const = 0; //! TwoPhase functions-------------------------------------------------------- + //! Initialise particle HDF5 data for twophase + //! \param[in] particle HDF5 data of twophase particle + //! \retval status Status of reading HDF5 twophase particle + virtual bool initialise_particle(const HDF5ParticleTwoPhase& particle) { + throw std::runtime_error( + "Calling the base class function (initialise_particle) in " + "ParticleBase:: illegal operation!"); + }; + + //! Initialise particle HDF5 data and material + //! \param[in] particle HDF5 data of particle + //! \param[in] material Material associated with the particle + //! \retval status Status of reading HDF5 particle + virtual bool initialise_particle( + const HDF5ParticleTwoPhase& particle, + const std::shared_ptr>& solid_material, + const std::shared_ptr>& liquid_material) { + throw std::runtime_error( + "Calling the base class function (initialise_particle) in " + "ParticleBase:: illegal operation!"); + }; + + //! Return particle data as HDF5 for twophase particle + //! \retval particle HDF5 data of twophase particle + virtual HDF5ParticleTwoPhase hdf5_twophase() const { + throw std::runtime_error( + "Calling the base class function (hdf5) in " + "ParticleBase:: illegal operation!"); + }; + //! Update porosity //! \param[in] dt Analysis time step virtual void update_porosity(double dt) { diff --git a/include/particles/particle_twophase.h b/include/particles/particle_twophase.h index 931a6acf7..a7ab88eff 100644 --- a/include/particles/particle_twophase.h +++ b/include/particles/particle_twophase.h @@ -45,22 +45,24 @@ class TwoPhaseParticle : public mpm::Particle { //! Initialise particle from HDF5 data //! \param[in] particle HDF5 data of particle //! \retval status Status of reading HDF5 particle - bool initialise_particle(const HDF5Particle& particle) override; + bool initialise_particle(const HDF5ParticleTwoPhase& particle) override; //! Initialise particle HDF5 data and material //! \param[in] particle HDF5 data of particle - //! \param[in] material Material associated with the particle + //! \param[in] solid_material Solid material associated with the particle + //! \param[in] liquid_material Liquid material associated with the particle //! \retval status Status of reading HDF5 particle bool initialise_particle( - const HDF5Particle& particle, - const std::shared_ptr>& material) override; + const HDF5ParticleTwoPhase& particle, + const std::shared_ptr>& solid_material, + const std::shared_ptr>& liquid_material) override; - //! Initialise liquid phase + //! Initialise particle liquid phase on top of the regular solid phase void initialise() override; - //! Retrun particle data as HDF5 + //! Retrun particle twophase data as HDF5 //! \retval particle HDF5 data of the particle - HDF5Particle hdf5() const override; + HDF5ParticleTwoPhase hdf5_twophase() const override; //! Assign saturation degree bool assign_saturation_degree() override; diff --git a/include/particles/particle_twophase.tcc b/include/particles/particle_twophase.tcc index 598557d82..a1b8666ac 100644 --- a/include/particles/particle_twophase.tcc +++ b/include/particles/particle_twophase.tcc @@ -34,36 +34,44 @@ mpm::TwoPhaseParticle::TwoPhaseParticle(Index id, const VectorDim& coord, //! Return particle data in HDF5 format template // cppcheck-suppress * -mpm::HDF5Particle mpm::TwoPhaseParticle::hdf5() const { +mpm::HDF5ParticleTwoPhase mpm::TwoPhaseParticle::hdf5_twophase() const { // Derive from particle - auto particle_data = mpm::Particle::hdf5(); - // // Particle liquid mass - // particle_data.liquid_mass = this->liquid_mass_; + auto solid_particle_data = mpm::Particle::hdf5(); + mpm::HDF5ParticleTwoPhase particle_data; + static_cast(particle_data) = solid_particle_data; - // // Particle liquid velocity - // particle_data.liquid_velocity_x = liquid_velocity[0]; - // particle_data.liquid_velocity_y = liquid_velocity[1]; - // particle_data.liquid_velocity_z = liquid_velocity[2]; + // Particle liquid mass + particle_data.liquid_mass = this->liquid_mass_; - // // Particle liquid material id - // particle_data.liquid_material_id = - // this->material_id_(mpm::ParticlePhase::Liquid); + // Particle liquid velocity + Eigen::Vector3d liquid_velocity; + liquid_velocity.setZero(); + for (unsigned j = 0; j < Tdim; ++j) + liquid_velocity[j] = this->liquid_velocity_[j]; + particle_data.liquid_velocity_x = liquid_velocity[0]; + particle_data.liquid_velocity_y = liquid_velocity[1]; + particle_data.liquid_velocity_z = liquid_velocity[2]; + + // Particle porosity and saturation + particle_data.porosity = this->porosity_; + particle_data.liquid_saturation = this->liquid_saturation_; + + // Particle liquid material id + particle_data.liquid_material_id = + this->material_id(mpm::ParticlePhase::Liquid); + + // Write state variables if (this->material(mpm::ParticlePhase::Liquid) != nullptr) { - if ((state_variables_[mpm::ParticlePhase::Solid].size() + - state_variables_[mpm::ParticlePhase::Liquid].size()) > 20) - throw std::runtime_error("# of state variables cannot be more than 20"); - // Assign number of state variables - particle_data.nstate_vars = - state_variables_[mpm::ParticlePhase::Solid].size() + + particle_data.nliquid_state_vars = state_variables_[mpm::ParticlePhase::Liquid].size(); - // First id - unsigned i = state_variables_[mpm::ParticlePhase::Solid].size(); - // Liquid state variables + if (state_variables_[mpm::ParticlePhase::Liquid].size() > 5) + throw std::runtime_error("# of state variables cannot be more than 5"); + unsigned i = 0; auto state_variables = (this->material(mpm::ParticlePhase::Liquid))->state_variables(); for (const auto& state_var : state_variables) { - particle_data.svars[i] = + particle_data.liquid_svars[i] = state_variables_[mpm::ParticlePhase::Liquid].at(state_var); ++i; } @@ -75,36 +83,97 @@ mpm::HDF5Particle mpm::TwoPhaseParticle::hdf5() const { //! Initialise particle data from HDF5 template bool mpm::TwoPhaseParticle::initialise_particle( - const HDF5Particle& particle) { - // Derive from particle - mpm::Particle::initialise_particle(particle); - - // // Liquid mass - // this->liquid_mass_ = particle.liquid_mass; - // // Liquid mass Density - // this->liquid_mass_density_ = particle.liquid_mass / particle.volume; + const HDF5ParticleTwoPhase& particle) { + // Initialise solid phase + mpm::HDF5Particle solid_particle = particle; + bool status = mpm::Particle::initialise_particle(solid_particle); - // // Liquid velocity - // Eigen::Vector3d liquid_velocity; - // liquid_velocity << particle.liquid_velocity_x, particle.liquid_velocity_y, - // particle.liquid_velocity_z; - // // Initialise velocity - // for (unsigned i = 0; i < Tdim; ++i) - // this->liquid_velocity_(i) = liquid_velocity(i); - - // // Liquid material id - // this->liquid_material_id_ = particle.liquid_material_id; + // Liquid mass + this->liquid_mass_ = particle.liquid_mass; + // Liquid mass Density + this->liquid_mass_density_ = particle.liquid_mass / particle.volume; + + // Liquid velocity + Eigen::Vector3d liquid_velocity; + liquid_velocity << particle.liquid_velocity_x, particle.liquid_velocity_y, + particle.liquid_velocity_z; + // Initialise velocity + for (unsigned i = 0; i < Tdim; ++i) + this->liquid_velocity_(i) = liquid_velocity(i); + + // Particle porosity and saturation + this->porosity_ = particle.porosity; + this->liquid_saturation_ = particle.liquid_saturation; + this->assign_permeability(); + + // Liquid material id + this->material_id_[mpm::ParticlePhase::Liquid] = particle.liquid_material_id; - return true; + return status; } //! Initialise particle data from HDF5 -//! TODO template bool mpm::TwoPhaseParticle::initialise_particle( - const HDF5Particle& particle, - const std::shared_ptr>& material) { - bool status = mpm::Particle::initialise_particle(particle, material); + const HDF5ParticleTwoPhase& particle, + const std::shared_ptr>& solid_material, + const std::shared_ptr>& liquid_material) { + bool status = this->initialise_particle(particle); + + // Solid Phase + if (solid_material != nullptr) { + if (this->material_id(mpm::ParticlePhase::Solid) == solid_material->id() || + this->material_id(mpm::ParticlePhase::Solid) == + std::numeric_limits::max()) { + bool assign_mat = + this->assign_material(solid_material, mpm::ParticlePhase::Solid); + if (!assign_mat) throw std::runtime_error("Material assignment failed"); + // Reinitialize state variables + auto mat_state_vars = (this->material(mpm::ParticlePhase::Solid)) + ->initialise_state_variables(); + if (mat_state_vars.size() == particle.nstate_vars) { + unsigned i = 0; + auto state_variables = + (this->material(mpm::ParticlePhase::Solid))->state_variables(); + for (const auto& state_var : state_variables) { + this->state_variables_[mpm::ParticlePhase::Solid].at(state_var) = + particle.svars[i]; + ++i; + } + } + } else { + status = false; + throw std::runtime_error("Material is invalid to assign to particle!"); + } + } + + // Fluid Phase + if (liquid_material != nullptr) { + if (this->material_id(mpm::ParticlePhase::Liquid) == + liquid_material->id() || + this->material_id(mpm::ParticlePhase::Liquid) == + std::numeric_limits::max()) { + bool assign_mat = + this->assign_material(liquid_material, mpm::ParticlePhase::Liquid); + if (!assign_mat) throw std::runtime_error("Material assignment failed"); + // Reinitialize state variables + auto mat_state_vars = (this->material(mpm::ParticlePhase::Liquid)) + ->initialise_state_variables(); + if (mat_state_vars.size() == particle.nliquid_state_vars) { + unsigned i = 0; + auto state_variables = + (this->material(mpm::ParticlePhase::Liquid))->state_variables(); + for (const auto& state_var : state_variables) { + this->state_variables_[mpm::ParticlePhase::Solid].at(state_var) = + particle.liquid_svars[i]; + ++i; + } + } + } else { + status = false; + throw std::runtime_error("Material is invalid to assign to particle!"); + } + } return status; } From ae45f5dea11bcfdd629f55f6e8e30f3968a55f8a Mon Sep 17 00:00:00 2001 From: Nanda Date: Thu, 13 Aug 2020 11:32:47 -0700 Subject: [PATCH 110/175] :dart: hdf5 twophase particle tested --- tests/particles/particle_twophase_test.cc | 150 +++++++++++++++++++++- 1 file changed, 144 insertions(+), 6 deletions(-) diff --git a/tests/particles/particle_twophase_test.cc b/tests/particles/particle_twophase_test.cc index 77990ebc6..b5e394a4a 100644 --- a/tests/particles/particle_twophase_test.cc +++ b/tests/particles/particle_twophase_test.cc @@ -213,7 +213,7 @@ TEST_CASE("TwoPhase Particle is checked for 1D case", std::shared_ptr> particle = std::make_shared>(id, coords); - mpm::HDF5Particle h5_particle; + mpm::HDF5ParticleTwoPhase h5_particle; h5_particle.id = 13; h5_particle.mass = 501.5; @@ -269,6 +269,20 @@ TEST_CASE("TwoPhase Particle is checked for 1D case", h5_particle.material_id = 1; + h5_particle.liquid_mass = 100.1; + + Eigen::Vector3d liquid_velocity; + liquid_velocity << 5.5, 0., 0.; + h5_particle.liquid_velocity_x = liquid_velocity[0]; + h5_particle.liquid_velocity_y = liquid_velocity[1]; + h5_particle.liquid_velocity_z = liquid_velocity[2]; + + h5_particle.porosity = 0.33; + + h5_particle.liquid_saturation = 1.; + + h5_particle.liquid_material_id = 2; + // Reinitialise particle from HDF5 data REQUIRE(particle->initialise_particle(h5_particle) == true); @@ -328,8 +342,25 @@ TEST_CASE("TwoPhase Particle is checked for 1D case", // Check material id REQUIRE(particle->material_id() == h5_particle.material_id); + // Check liquid mass + REQUIRE(particle->liquid_mass() == h5_particle.liquid_mass); + + // Check liquid velocity + auto pliquid_velocity = particle->liquid_velocity(); + REQUIRE(pliquid_velocity.size() == Dim); + for (unsigned i = 0; i < Dim; ++i) + REQUIRE(pliquid_velocity(i) == + Approx(liquid_velocity(i)).epsilon(Tolerance)); + + // Check porosity + REQUIRE(particle->porosity() == h5_particle.porosity); + + // Check liquid material id + REQUIRE(particle->material_id(mpm::ParticlePhase::Liquid) == + h5_particle.liquid_material_id); + // Write Particle HDF5 data - const auto h5_test = particle->hdf5(); + const auto h5_test = particle->hdf5_twophase(); REQUIRE(h5_particle.id == h5_test.id); REQUIRE(h5_particle.mass == h5_test.mass); @@ -384,6 +415,21 @@ TEST_CASE("TwoPhase Particle is checked for 1D case", REQUIRE(h5_particle.status == h5_test.status); REQUIRE(h5_particle.cell_id == h5_test.cell_id); REQUIRE(h5_particle.material_id == h5_test.material_id); + + REQUIRE(h5_particle.liquid_mass == + Approx(h5_test.liquid_mass).epsilon(Tolerance)); + REQUIRE(h5_particle.liquid_velocity_x == + Approx(h5_test.liquid_velocity_x).epsilon(Tolerance)); + REQUIRE(h5_particle.liquid_velocity_y == + Approx(h5_test.liquid_velocity_y).epsilon(Tolerance)); + REQUIRE(h5_particle.liquid_velocity_z == + Approx(h5_test.liquid_velocity_z).epsilon(Tolerance)); + REQUIRE(h5_particle.porosity == + Approx(h5_test.porosity).epsilon(Tolerance)); + REQUIRE(h5_particle.liquid_saturation == + Approx(h5_test.liquid_saturation).epsilon(Tolerance)); + REQUIRE(h5_particle.liquid_material_id == + Approx(h5_test.liquid_material_id).epsilon(Tolerance)); } } @@ -1408,7 +1454,7 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", std::shared_ptr> particle = std::make_shared>(id, coords); - mpm::HDF5Particle h5_particle; + mpm::HDF5ParticleTwoPhase h5_particle; h5_particle.id = 13; h5_particle.mass = 501.5; @@ -1464,6 +1510,20 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", h5_particle.material_id = 1; + h5_particle.liquid_mass = 100.1; + + Eigen::Vector3d liquid_velocity; + liquid_velocity << 5.5, 2.1, 0.; + h5_particle.liquid_velocity_x = liquid_velocity[0]; + h5_particle.liquid_velocity_y = liquid_velocity[1]; + h5_particle.liquid_velocity_z = liquid_velocity[2]; + + h5_particle.porosity = 0.33; + + h5_particle.liquid_saturation = 1.; + + h5_particle.liquid_material_id = 2; + // Reinitialise particle from HDF5 data REQUIRE(particle->initialise_particle(h5_particle) == true); @@ -1523,8 +1583,25 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", // Check material id REQUIRE(particle->material_id() == h5_particle.material_id); + // Check liquid mass + REQUIRE(particle->liquid_mass() == h5_particle.liquid_mass); + + // Check liquid velocity + auto pliquid_velocity = particle->liquid_velocity(); + REQUIRE(pliquid_velocity.size() == Dim); + for (unsigned i = 0; i < Dim; ++i) + REQUIRE(pliquid_velocity(i) == + Approx(liquid_velocity(i)).epsilon(Tolerance)); + + // Check porosity + REQUIRE(particle->porosity() == h5_particle.porosity); + + // Check liquid material id + REQUIRE(particle->material_id(mpm::ParticlePhase::Liquid) == + h5_particle.liquid_material_id); + // Write Particle HDF5 data - const auto h5_test = particle->hdf5(); + const auto h5_test = particle->hdf5_twophase(); REQUIRE(h5_particle.id == h5_test.id); REQUIRE(h5_particle.mass == h5_test.mass); @@ -1579,6 +1656,21 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", REQUIRE(h5_particle.status == h5_test.status); REQUIRE(h5_particle.cell_id == h5_test.cell_id); REQUIRE(h5_particle.material_id == h5_test.material_id); + + REQUIRE(h5_particle.liquid_mass == + Approx(h5_test.liquid_mass).epsilon(Tolerance)); + REQUIRE(h5_particle.liquid_velocity_x == + Approx(h5_test.liquid_velocity_x).epsilon(Tolerance)); + REQUIRE(h5_particle.liquid_velocity_y == + Approx(h5_test.liquid_velocity_y).epsilon(Tolerance)); + REQUIRE(h5_particle.liquid_velocity_z == + Approx(h5_test.liquid_velocity_z).epsilon(Tolerance)); + REQUIRE(h5_particle.porosity == + Approx(h5_test.porosity).epsilon(Tolerance)); + REQUIRE(h5_particle.liquid_saturation == + Approx(h5_test.liquid_saturation).epsilon(Tolerance)); + REQUIRE(h5_particle.liquid_material_id == + Approx(h5_test.liquid_material_id).epsilon(Tolerance)); } // Check twophase particle's material id maping to nodes @@ -2849,7 +2941,7 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", std::shared_ptr> particle = std::make_shared>(id, coords); - mpm::HDF5Particle h5_particle; + mpm::HDF5ParticleTwoPhase h5_particle; h5_particle.id = 13; h5_particle.mass = 501.5; @@ -2905,6 +2997,20 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", h5_particle.material_id = 1; + h5_particle.liquid_mass = 100.1; + + Eigen::Vector3d liquid_velocity; + liquid_velocity << 5.5, 3.12, 2.1; + h5_particle.liquid_velocity_x = liquid_velocity[0]; + h5_particle.liquid_velocity_y = liquid_velocity[1]; + h5_particle.liquid_velocity_z = liquid_velocity[2]; + + h5_particle.porosity = 0.33; + + h5_particle.liquid_saturation = 1.; + + h5_particle.liquid_material_id = 2; + // Reinitialise particle from HDF5 data REQUIRE(particle->initialise_particle(h5_particle) == true); @@ -2965,8 +3071,25 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", // Check material id REQUIRE(particle->material_id() == h5_particle.material_id); + // Check liquid mass + REQUIRE(particle->liquid_mass() == h5_particle.liquid_mass); + + // Check liquid velocity + auto pliquid_velocity = particle->liquid_velocity(); + REQUIRE(pliquid_velocity.size() == Dim); + for (unsigned i = 0; i < Dim; ++i) + REQUIRE(pliquid_velocity(i) == + Approx(liquid_velocity(i)).epsilon(Tolerance)); + + // Check porosity + REQUIRE(particle->porosity() == h5_particle.porosity); + + // Check liquid material id + REQUIRE(particle->material_id(mpm::ParticlePhase::Liquid) == + h5_particle.liquid_material_id); + // Write Particle HDF5 data - const auto h5_test = particle->hdf5(); + const auto h5_test = particle->hdf5_twophase(); REQUIRE(h5_particle.id == h5_test.id); REQUIRE(h5_particle.mass == h5_test.mass); @@ -3021,6 +3144,21 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", REQUIRE(h5_particle.status == h5_test.status); REQUIRE(h5_particle.cell_id == h5_test.cell_id); REQUIRE(h5_particle.material_id == h5_test.material_id); + + REQUIRE(h5_particle.liquid_mass == + Approx(h5_test.liquid_mass).epsilon(Tolerance)); + REQUIRE(h5_particle.liquid_velocity_x == + Approx(h5_test.liquid_velocity_x).epsilon(Tolerance)); + REQUIRE(h5_particle.liquid_velocity_y == + Approx(h5_test.liquid_velocity_y).epsilon(Tolerance)); + REQUIRE(h5_particle.liquid_velocity_z == + Approx(h5_test.liquid_velocity_z).epsilon(Tolerance)); + REQUIRE(h5_particle.porosity == + Approx(h5_test.porosity).epsilon(Tolerance)); + REQUIRE(h5_particle.liquid_saturation == + Approx(h5_test.liquid_saturation).epsilon(Tolerance)); + REQUIRE(h5_particle.liquid_material_id == + Approx(h5_test.liquid_material_id).epsilon(Tolerance)); } // Check particle's material id maping to nodes From 656f384614bbe02e96cd282b07ad1f3ffcdeb9ac Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Thu, 13 Aug 2020 16:59:20 -0700 Subject: [PATCH 111/175] Correct the error in "assign_permeability" --- include/io/io_mesh_ascii.tcc | 1 - include/particles/particle_twophase.tcc | 11 +++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/include/io/io_mesh_ascii.tcc b/include/io/io_mesh_ascii.tcc index 14bba7ea2..d2fcce4ef 100644 --- a/include/io/io_mesh_ascii.tcc +++ b/include/io/io_mesh_ascii.tcc @@ -254,7 +254,6 @@ std::vector> // Particles scalar properties std::vector> scalar_properties; - scalar_properties.clear(); // input file stream std::fstream file; diff --git a/include/particles/particle_twophase.tcc b/include/particles/particle_twophase.tcc index 598557d82..78a472165 100644 --- a/include/particles/particle_twophase.tcc +++ b/include/particles/particle_twophase.tcc @@ -546,9 +546,16 @@ bool mpm::TwoPhaseParticle::assign_permeability() { try { // Check if material ptr is valid if (this->material() != nullptr) { + // Get initial porosity + double porosity = + this->material()->template property(std::string("porosity")); + if (porosity < 0. || porosity > 1.) + throw std::runtime_error( + "Particle porosity is negative or larger than one, can not assign " + "permeability"); // Porosity parameter - const double k_p = - std::pow(this->porosity_, 3) / std::pow((1. - this->porosity_), 2); + const double k_p = std::pow(porosity, 3) / std::pow((1. - porosity), 2); + // Initial permeability switch (Tdim) { case (1): { // Check if the permeability is valid From c68fbd584dd16cd10f481f8239598ad9213503b0 Mon Sep 17 00:00:00 2001 From: Nanda Date: Thu, 13 Aug 2020 17:41:16 -0700 Subject: [PATCH 112/175] :wrench: add mpi_data_twophase to mesh --- include/mesh.h | 1 + include/mpi_datatypes_twophase.h | 6 ------ 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/include/mesh.h b/include/mesh.h index a7a071a36..26cf45b53 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -36,6 +36,7 @@ using Json = nlohmann::json; #include "logger.h" #include "material.h" #include "mpi_datatypes.h" +#include "mpi_datatypes_twophase.h" #include "nodal_properties.h" #include "node.h" #include "particle.h" diff --git a/include/mpi_datatypes_twophase.h b/include/mpi_datatypes_twophase.h index f24f4a894..95d76426a 100644 --- a/include/mpi_datatypes_twophase.h +++ b/include/mpi_datatypes_twophase.h @@ -9,7 +9,6 @@ #include "mpi.h" #include "hdf5_particle_twophase.h" -#include "mpi_datatypes.h" namespace mpm { //! Initialize MPI particle data types @@ -129,11 +128,6 @@ inline MPI_Datatype register_mpi_particle_type( MPI_Type_commit(&MPIParticle); return MPIParticle; } - -//! Deregister MPI particle data type -inline void deregister_mpi_particle_type(MPI_Datatype& particle_type) { - MPI_Type_free(&particle_type); -} } // namespace mpm #endif // MPI From 8bb993b0b313c6b66c271dfe209eba0daaa6fa69 Mon Sep 17 00:00:00 2001 From: Nanda Date: Thu, 13 Aug 2020 17:59:07 -0700 Subject: [PATCH 113/175] :construction: :dart: add particle twophase mpi data transfer test --- CMakeLists.txt | 1 + tests/mpi_particle_twophase_test.cc | 512 ++++++++++++++++++++++++++++ 2 files changed, 513 insertions(+) create mode 100644 tests/mpi_particle_twophase_test.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e3f9d1c2..530b54c00 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -208,6 +208,7 @@ if(MPM_BUILD_TESTING) ${mpm_SOURCE_DIR}/tests/mesh_test_2d.cc ${mpm_SOURCE_DIR}/tests/mesh_test_3d.cc ${mpm_SOURCE_DIR}/tests/mpi_particle_test.cc + ${mpm_SOURCE_DIR}/tests/mpi_particle_twophase_test.cc ${mpm_SOURCE_DIR}/tests/mpi_transfer_particle_test.cc ${mpm_SOURCE_DIR}/tests/nodes/nodal_properties_test.cc ${mpm_SOURCE_DIR}/tests/nodes/node_map_test.cc diff --git a/tests/mpi_particle_twophase_test.cc b/tests/mpi_particle_twophase_test.cc new file mode 100644 index 000000000..4752c8dfa --- /dev/null +++ b/tests/mpi_particle_twophase_test.cc @@ -0,0 +1,512 @@ +#include + +#include "catch.hpp" + +#include "data_types.h" +#include "hdf5_particle.h" +#include "material.h" +#include "mpi_datatypes.h" +#include "mpi_datatypes_twophase.h" +#include "particle.h" +#include "particle_twophase.h" + +#ifdef USE_MPI +//! \brief Check particle class for 1D case +TEST_CASE("MPI HDF5 TwoPhase Particle is checked", + "[particle][mpi][hdf5][2Phase]") { + // Dimension + const unsigned Dim = 3; + // Tolerance + const double Tolerance = 1.E-7; + + // Check MPI transfer of HDF5 Particle + SECTION("MPI HDF5 TwoPhase Particle") { + mpm::Index id = 0; + + mpm::HDF5ParticleTwoPhase h5_particle; + h5_particle.id = 13; + h5_particle.mass = 501.5; + + h5_particle.pressure = 125.75; + + Eigen::Vector3d coords; + coords << 1., 2., 3.; + h5_particle.coord_x = coords[0]; + h5_particle.coord_y = coords[1]; + h5_particle.coord_z = coords[2]; + + Eigen::Vector3d displacement; + displacement << 0.01, 0.02, 0.03; + h5_particle.displacement_x = displacement[0]; + h5_particle.displacement_y = displacement[1]; + h5_particle.displacement_z = displacement[2]; + + Eigen::Vector3d lsize; + lsize << 0.25, 0.5, 0.75; + h5_particle.nsize_x = lsize[0]; + h5_particle.nsize_y = lsize[1]; + h5_particle.nsize_z = lsize[2]; + + Eigen::Vector3d velocity; + velocity << 1.5, 2.5, 3.5; + h5_particle.velocity_x = velocity[0]; + h5_particle.velocity_y = velocity[1]; + h5_particle.velocity_z = velocity[2]; + + Eigen::Matrix stress; + stress << 11.5, -12.5, 13.5, 14.5, -15.5, 16.5; + h5_particle.stress_xx = stress[0]; + h5_particle.stress_yy = stress[1]; + h5_particle.stress_zz = stress[2]; + h5_particle.tau_xy = stress[3]; + h5_particle.tau_yz = stress[4]; + h5_particle.tau_xz = stress[5]; + + Eigen::Matrix strain; + strain << 0.115, -0.125, 0.135, 0.145, -0.155, 0.165; + h5_particle.strain_xx = strain[0]; + h5_particle.strain_yy = strain[1]; + h5_particle.strain_zz = strain[2]; + h5_particle.gamma_xy = strain[3]; + h5_particle.gamma_yz = strain[4]; + h5_particle.gamma_xz = strain[5]; + + h5_particle.epsilon_v = strain.head(Dim).sum(); + + h5_particle.status = true; + + h5_particle.cell_id = 1; + + h5_particle.volume = 2.; + + h5_particle.material_id = 1; + + h5_particle.nstate_vars = 0; + + for (unsigned i = 0; i < h5_particle.nstate_vars; ++i) + h5_particle.svars[i] = 0.; + + h5_particle.liquid_mass = 100.1; + + Eigen::Vector3d liquid_velocity; + liquid_velocity << 5.5, 2.1, 4.2; + h5_particle.liquid_velocity_x = liquid_velocity[0]; + h5_particle.liquid_velocity_y = liquid_velocity[1]; + h5_particle.liquid_velocity_z = liquid_velocity[2]; + + h5_particle.porosity = 0.33; + + h5_particle.liquid_saturation = 1.; + + h5_particle.liquid_material_id = 2; + + h5_particle.nliquid_state_vars = 1; + + for (unsigned i = 0; i < h5_particle.nliquid_state_vars; ++i) + h5_particle.liquid_svars[i] = 0.; + + // Check send and receive particle with HDF5 + SECTION("Check send and receive particle with HDF5") { + // Get number of MPI ranks + int mpi_size; + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + + // If on same rank + int sender = 0; + int receiver = 0; + // Get rank and do the corresponding job for mpi size == 2 + if (mpi_size == 2) receiver = 1; + + int mpi_rank; + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + // Send particle + if (mpi_rank == sender) { + // Initialize MPI datatypes + MPI_Datatype particle_type = + mpm::register_mpi_particle_type(h5_particle); + MPI_Send(&h5_particle, 1, particle_type, receiver, 0, MPI_COMM_WORLD); + mpm::deregister_mpi_particle_type(particle_type); + } + + // Receive particle + if (mpi_rank == receiver) { + // Receive the messid + struct mpm::HDF5ParticleTwoPhase received; + MPI_Datatype particle_type = mpm::register_mpi_particle_type(received); + MPI_Recv(&received, 1, particle_type, sender, 0, MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + mpm::deregister_mpi_particle_type(particle_type); + + REQUIRE(h5_particle.id == received.id); + REQUIRE(h5_particle.mass == received.mass); + REQUIRE(h5_particle.pressure == + Approx(received.pressure).epsilon(Tolerance)); + REQUIRE(h5_particle.volume == + Approx(received.volume).epsilon(Tolerance)); + + REQUIRE(h5_particle.coord_x == + Approx(received.coord_x).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_y == + Approx(received.coord_y).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_z == + Approx(received.coord_z).epsilon(Tolerance)); + + REQUIRE(h5_particle.displacement_x == + Approx(received.displacement_x).epsilon(Tolerance)); + REQUIRE(h5_particle.displacement_y == + Approx(received.displacement_y).epsilon(Tolerance)); + REQUIRE(h5_particle.displacement_z == + Approx(received.displacement_z).epsilon(Tolerance)); + + REQUIRE(h5_particle.nsize_x == received.nsize_x); + REQUIRE(h5_particle.nsize_y == received.nsize_y); + REQUIRE(h5_particle.nsize_z == received.nsize_z); + + REQUIRE(h5_particle.velocity_x == + Approx(received.velocity_x).epsilon(Tolerance)); + REQUIRE(h5_particle.velocity_y == + Approx(received.velocity_y).epsilon(Tolerance)); + REQUIRE(h5_particle.velocity_z == + Approx(received.velocity_z).epsilon(Tolerance)); + + REQUIRE(h5_particle.stress_xx == + Approx(received.stress_xx).epsilon(Tolerance)); + REQUIRE(h5_particle.stress_yy == + Approx(received.stress_yy).epsilon(Tolerance)); + REQUIRE(h5_particle.stress_zz == + Approx(received.stress_zz).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_xy == + Approx(received.tau_xy).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_yz == + Approx(received.tau_yz).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_xz == + Approx(received.tau_xz).epsilon(Tolerance)); + + REQUIRE(h5_particle.strain_xx == + Approx(received.strain_xx).epsilon(Tolerance)); + REQUIRE(h5_particle.strain_yy == + Approx(received.strain_yy).epsilon(Tolerance)); + REQUIRE(h5_particle.strain_zz == + Approx(received.strain_zz).epsilon(Tolerance)); + REQUIRE(h5_particle.gamma_xy == + Approx(received.gamma_xy).epsilon(Tolerance)); + REQUIRE(h5_particle.gamma_yz == + Approx(received.gamma_yz).epsilon(Tolerance)); + REQUIRE(h5_particle.gamma_xz == + Approx(received.gamma_xz).epsilon(Tolerance)); + + REQUIRE(h5_particle.epsilon_v == + Approx(received.epsilon_v).epsilon(Tolerance)); + REQUIRE(h5_particle.status == received.status); + + REQUIRE(h5_particle.cell_id == received.cell_id); + REQUIRE(h5_particle.material_id == received.cell_id); + + REQUIRE(h5_particle.nstate_vars == received.nstate_vars); + for (unsigned i = 0; i < h5_particle.nstate_vars; ++i) + REQUIRE(h5_particle.svars[i] == + Approx(received.svars[i]).epsilon(Tolerance)); + + REQUIRE(h5_particle.liquid_mass == + Approx(received.liquid_mass).epsilon(Tolerance)); + REQUIRE(h5_particle.liquid_velocity_x == + Approx(received.liquid_velocity_x).epsilon(Tolerance)); + REQUIRE(h5_particle.liquid_velocity_y == + Approx(received.liquid_velocity_y).epsilon(Tolerance)); + REQUIRE(h5_particle.liquid_velocity_z == + Approx(received.liquid_velocity_z).epsilon(Tolerance)); + REQUIRE(h5_particle.porosity == + Approx(received.porosity).epsilon(Tolerance)); + REQUIRE(h5_particle.liquid_saturation == + Approx(received.liquid_saturation).epsilon(Tolerance)); + REQUIRE(h5_particle.liquid_material_id == + Approx(received.liquid_material_id).epsilon(Tolerance)); + + REQUIRE(h5_particle.nliquid_state_vars == received.nliquid_state_vars); + for (unsigned i = 0; i < h5_particle.nliquid_state_vars; ++i) + REQUIRE(h5_particle.liquid_svars[i] == + Approx(received.liquid_svars[i]).epsilon(Tolerance)); + } + } + + // Check initialise particle from HDF5 file + SECTION("Check initialise particle with HDF5 across MPI processes") { + // Get number of MPI ranks + int mpi_size; + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + + int mpi_rank; + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + // If on same rank + int sender = 0; + int receiver = 0; + + // Get rank and do the corresponding job for mpi size == 2 + if (mpi_size == 2) receiver = 1; + + // Initial particle coordinates + Eigen::Matrix pcoordinates; + pcoordinates.setZero(); + + if (mpi_rank == sender) { + // Create and initialzie particle with HDF5 data + std::shared_ptr> particle = + std::make_shared>(id, pcoordinates); + + // Assign material + unsigned solid_mid = 1; + unsigned liquid_mid = 2; + // Initialise material + Json jsolid_material; + Json jliquid_material; + jsolid_material["density"] = 1000.; + jsolid_material["youngs_modulus"] = 1.0E+7; + jsolid_material["poisson_ratio"] = 0.3; + jsolid_material["porosity"] = 0.3; + jsolid_material["k_x"] = 0.001; + jsolid_material["k_y"] = 0.001; + jsolid_material["k_z"] = 0.001; + jliquid_material["density"] = 1000.; + jliquid_material["bulk_modulus"] = 2.0E9; + jliquid_material["dynamic_viscosity"] = 8.90E-4; + + auto solid_material = + Factory, unsigned, const Json&>::instance() + ->create("LinearElastic3D", std::move(solid_mid), + jsolid_material); + auto liquid_material = + Factory, unsigned, const Json&>::instance() + ->create("Newtonian3D", std::move(liquid_mid), + jliquid_material); + + // Reinitialise particle from HDF5 data + REQUIRE(particle->initialise_particle(h5_particle, solid_material, + liquid_material) == true); + + // Check particle id + REQUIRE(particle->id() == h5_particle.id); + // Check particle mass + REQUIRE(particle->mass() == h5_particle.mass); + // Check particle volume + REQUIRE(particle->volume() == h5_particle.volume); + // Check particle mass density + REQUIRE(particle->mass_density() == + h5_particle.mass / h5_particle.volume); + // Check particle status + REQUIRE(particle->status() == h5_particle.status); + + // Check for coordinates + auto coordinates = particle->coordinates(); + REQUIRE(coordinates.size() == Dim); + for (unsigned i = 0; i < coordinates.size(); ++i) + REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + REQUIRE(coordinates.size() == Dim); + + // Check for displacement + auto pdisplacement = particle->displacement(); + REQUIRE(pdisplacement.size() == Dim); + for (unsigned i = 0; i < Dim; ++i) + REQUIRE(pdisplacement(i) == + Approx(displacement(i)).epsilon(Tolerance)); + + // Check for size + auto size = particle->natural_size(); + REQUIRE(size.size() == Dim); + for (unsigned i = 0; i < size.size(); ++i) + REQUIRE(size(i) == Approx(lsize(i)).epsilon(Tolerance)); + + // Check velocity + auto pvelocity = particle->velocity(); + REQUIRE(pvelocity.size() == Dim); + for (unsigned i = 0; i < Dim; ++i) + REQUIRE(pvelocity(i) == Approx(velocity(i)).epsilon(Tolerance)); + + // Check stress + auto pstress = particle->stress(); + REQUIRE(pstress.size() == stress.size()); + for (unsigned i = 0; i < stress.size(); ++i) + REQUIRE(pstress(i) == Approx(stress(i)).epsilon(Tolerance)); + + // Check strain + auto pstrain = particle->strain(); + REQUIRE(pstrain.size() == strain.size()); + for (unsigned i = 0; i < strain.size(); ++i) + REQUIRE(pstrain(i) == Approx(strain(i)).epsilon(Tolerance)); + + // Check particle volumetric strain centroid + REQUIRE(particle->volumetric_strain_centroid() == + h5_particle.epsilon_v); + + // Check cell id + REQUIRE(particle->cell_id() == h5_particle.cell_id); + + // Check material id + REQUIRE(particle->material_id() == h5_particle.material_id); + + // Check liquid mass + REQUIRE(particle->liquid_mass() == h5_particle.liquid_mass); + + // Check liquid velocity + auto pliquid_velocity = particle->liquid_velocity(); + REQUIRE(pliquid_velocity.size() == Dim); + for (unsigned i = 0; i < Dim; ++i) + REQUIRE(pliquid_velocity(i) == + Approx(liquid_velocity(i)).epsilon(Tolerance)); + + // Check porosity + REQUIRE(particle->porosity() == h5_particle.porosity); + + // Check liquid material id + REQUIRE(particle->material_id(mpm::ParticlePhase::Liquid) == + h5_particle.liquid_material_id); + + // Write Particle HDF5 data + const auto h5_send = particle->hdf5_twophase(); + + // Send MPI particle + MPI_Datatype particle_type = mpm::register_mpi_particle_type(h5_send); + MPI_Send(&h5_send, 1, particle_type, receiver, 0, MPI_COMM_WORLD); + mpm::deregister_mpi_particle_type(particle_type); + } + if (mpi_rank == receiver) { + // Receive the messid + struct mpm::HDF5ParticleTwoPhase received; + MPI_Datatype particle_type = mpm::register_mpi_particle_type(received); + MPI_Recv(&received, 1, particle_type, sender, 0, MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + mpm::deregister_mpi_particle_type(particle_type); + + // Received particle + std::shared_ptr> rparticle = + std::make_shared>(id, pcoordinates); + + // Assign material + unsigned solid_mid = 1; + unsigned liquid_mid = 2; + // Initialise material + Json jsolid_material; + Json jliquid_material; + jsolid_material["density"] = 1000.; + jsolid_material["youngs_modulus"] = 1.0E+7; + jsolid_material["poisson_ratio"] = 0.3; + jsolid_material["porosity"] = 0.3; + jsolid_material["k_x"] = 0.001; + jsolid_material["k_y"] = 0.001; + jsolid_material["k_z"] = 0.001; + jliquid_material["density"] = 1000.; + jliquid_material["bulk_modulus"] = 2.0E9; + jliquid_material["dynamic_viscosity"] = 8.90E-4; + + auto solid_material = + Factory, unsigned, const Json&>::instance() + ->create("LinearElastic3D", std::move(solid_mid), + jsolid_material); + auto liquid_material = + Factory, unsigned, const Json&>::instance() + ->create("Newtonian3D", std::move(liquid_mid), + jliquid_material); + + // Reinitialise particle from HDF5 data + REQUIRE(rparticle->initialise_particle(received, solid_material, + liquid_material) == true); + + // Check particle id + REQUIRE(rparticle->id() == h5_particle.id); + // Check particle mass + REQUIRE(rparticle->mass() == h5_particle.mass); + // Check particle volume + REQUIRE(rparticle->volume() == h5_particle.volume); + // Check particle mass density + REQUIRE(rparticle->mass_density() == + h5_particle.mass / h5_particle.volume); + // Check particle status + REQUIRE(rparticle->status() == h5_particle.status); + + // Check for coordinates + auto coordinates = rparticle->coordinates(); + REQUIRE(coordinates.size() == Dim); + for (unsigned i = 0; i < coordinates.size(); ++i) + REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + REQUIRE(coordinates.size() == Dim); + + // Check for displacement + auto pdisplacement = rparticle->displacement(); + REQUIRE(pdisplacement.size() == Dim); + for (unsigned i = 0; i < Dim; ++i) + REQUIRE(pdisplacement(i) == + Approx(displacement(i)).epsilon(Tolerance)); + + // Check for size + auto size = rparticle->natural_size(); + REQUIRE(size.size() == Dim); + for (unsigned i = 0; i < size.size(); ++i) + REQUIRE(size(i) == Approx(lsize(i)).epsilon(Tolerance)); + + // Check velocity + auto pvelocity = rparticle->velocity(); + REQUIRE(pvelocity.size() == Dim); + for (unsigned i = 0; i < Dim; ++i) + REQUIRE(pvelocity(i) == Approx(velocity(i)).epsilon(Tolerance)); + + // Check stress + auto pstress = rparticle->stress(); + REQUIRE(pstress.size() == stress.size()); + for (unsigned i = 0; i < stress.size(); ++i) + REQUIRE(pstress(i) == Approx(stress(i)).epsilon(Tolerance)); + + // Check strain + auto pstrain = rparticle->strain(); + REQUIRE(pstrain.size() == strain.size()); + for (unsigned i = 0; i < strain.size(); ++i) + REQUIRE(pstrain(i) == Approx(strain(i)).epsilon(Tolerance)); + + // Check particle volumetric strain centroid + REQUIRE(rparticle->volumetric_strain_centroid() == + h5_particle.epsilon_v); + + // Check cell id + REQUIRE(rparticle->cell_id() == h5_particle.cell_id); + + // Check material id + REQUIRE(rparticle->material_id() == h5_particle.material_id); + + // Get Particle HDF5 data + const auto h5_received = rparticle->hdf5_twophase(); + // State variables + REQUIRE(h5_received.nstate_vars == h5_particle.nstate_vars); + // State variables + for (unsigned i = 0; i < h5_particle.nstate_vars; ++i) + REQUIRE(h5_received.svars[i] == + Approx(h5_particle.svars[i]).epsilon(Tolerance)); + + // Check liquid mass + REQUIRE(rparticle->liquid_mass() == h5_particle.liquid_mass); + + // Check liquid velocity + auto pliquid_velocity = rparticle->liquid_velocity(); + REQUIRE(pliquid_velocity.size() == Dim); + for (unsigned i = 0; i < Dim; ++i) + REQUIRE(pliquid_velocity(i) == + Approx(liquid_velocity(i)).epsilon(Tolerance)); + + // Check porosity + REQUIRE(rparticle->porosity() == h5_particle.porosity); + + // Check liquid material id + REQUIRE(rparticle->material_id(mpm::ParticlePhase::Liquid) == + h5_particle.liquid_material_id); + + // Liquid state variables + REQUIRE(h5_received.nliquid_state_vars == + h5_particle.nliquid_state_vars); + // Liquid state variables + for (unsigned i = 0; i < h5_particle.nliquid_state_vars; ++i) + REQUIRE(h5_received.liquid_svars[i] == + Approx(h5_particle.liquid_svars[i]).epsilon(Tolerance)); + } + } + } +} +#endif // MPI From 783c17eacb57d2b9358c36c1403b85edd3c43e48 Mon Sep 17 00:00:00 2001 From: Nanda Date: Thu, 13 Aug 2020 17:59:26 -0700 Subject: [PATCH 114/175] :wrench: fix bug in initiating liquid state variables --- include/particles/particle_twophase.tcc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/particles/particle_twophase.tcc b/include/particles/particle_twophase.tcc index 78f4df26f..ea6185c4f 100644 --- a/include/particles/particle_twophase.tcc +++ b/include/particles/particle_twophase.tcc @@ -164,7 +164,7 @@ bool mpm::TwoPhaseParticle::initialise_particle( auto state_variables = (this->material(mpm::ParticlePhase::Liquid))->state_variables(); for (const auto& state_var : state_variables) { - this->state_variables_[mpm::ParticlePhase::Solid].at(state_var) = + this->state_variables_[mpm::ParticlePhase::Liquid].at(state_var) = particle.liquid_svars[i]; ++i; } From b208bf41928c72ca6f478bae11e31a556eb19cfe Mon Sep 17 00:00:00 2001 From: Nanda Date: Thu, 13 Aug 2020 18:39:37 -0700 Subject: [PATCH 115/175] :wrench: modify assign permeability and material() call --- include/particles/particle_twophase.tcc | 65 +++++++++++-------------- 1 file changed, 29 insertions(+), 36 deletions(-) diff --git a/include/particles/particle_twophase.tcc b/include/particles/particle_twophase.tcc index ea6185c4f..d498363bf 100644 --- a/include/particles/particle_twophase.tcc +++ b/include/particles/particle_twophase.tcc @@ -184,6 +184,7 @@ void mpm::TwoPhaseParticle::initialise() { liquid_mass_ = 0.; liquid_velocity_.setZero(); set_liquid_traction_ = false; + permeability_.setZero(); liquid_traction_.setZero(); liquid_saturation_ = 1.; @@ -236,12 +237,13 @@ template void mpm::TwoPhaseParticle::compute_mass() noexcept { // Check if particle volume is set and material ptr is valid assert(volume_ != std::numeric_limits::max() && - this->material() != nullptr && + this->material(mpm::ParticlePhase::Solid) != nullptr && this->material(mpm::ParticlePhase::Liquid) != nullptr); // Mass = volume of particle * mass_density // Solid mass this->mass_density_ = - (this->material())->template property(std::string("density")) * + (this->material(mpm::ParticlePhase::Solid)) + ->template property(std::string("density")) * (1 - this->porosity_); this->mass_ = volume_ * mass_density_; @@ -592,9 +594,10 @@ template bool mpm::TwoPhaseParticle::assign_porosity() { bool status = true; try { - if (this->material() != nullptr) { + if (this->material(mpm::ParticlePhase::Solid) != nullptr) { this->porosity_ = - this->material()->template property(std::string("porosity")); + this->material(mpm::ParticlePhase::Solid) + ->template property(std::string("porosity")); if (porosity_ < 0. || porosity_ > 1.) throw std::runtime_error( "Particle porosity is negative or larger than one"); @@ -614,54 +617,44 @@ bool mpm::TwoPhaseParticle::assign_permeability() { bool status = true; try { // Check if material ptr is valid - if (this->material() != nullptr) { + if (this->material(mpm::ParticlePhase::Solid) != nullptr) { // Get initial porosity double porosity = - this->material()->template property(std::string("porosity")); + this->material(mpm::ParticlePhase::Solid) + ->template property(std::string("porosity")); if (porosity < 0. || porosity > 1.) throw std::runtime_error( "Particle porosity is negative or larger than one, can not assign " "permeability"); // Porosity parameter const double k_p = std::pow(porosity, 3) / std::pow((1. - porosity), 2); - // Initial permeability + // Assign permeability switch (Tdim) { - case (1): { + case (3): // Check if the permeability is valid - if (this->material()->template property("k_x") < 0) + if (this->material(mpm::ParticlePhase::Solid) + ->template property("k_z") < 0) throw std::runtime_error("Material's permeability is invalid"); - // Assign permeability - permeability_(0) = - this->material()->template property("k_x") / k_p; - break; - } - case (2): { + permeability_(2) = this->material(mpm::ParticlePhase::Solid) + ->template property("k_z") / + k_p; + case (2): // Check if the permeability is valid - if (this->material()->template property("k_x") < 0 || - this->material()->template property("k_y") < 0) + if (this->material(mpm::ParticlePhase::Solid) + ->template property("k_y") < 0) throw std::runtime_error("Material's permeability is invalid"); - // Assign permeability - permeability_(0) = - this->material()->template property("k_x") / k_p; - permeability_(1) = - this->material()->template property("k_y") / k_p; - break; - } - default: { + permeability_(1) = this->material(mpm::ParticlePhase::Solid) + ->template property("k_y") / + k_p; + case (1): // Check if the permeability is valid - if (this->material()->template property("k_x") < 0 || - this->material()->template property("k_y") < 0 || - this->material()->template property("k_z") < 0) + if (this->material(mpm::ParticlePhase::Solid) + ->template property("k_x") < 0) throw std::runtime_error("Material's permeability is invalid"); // Assign permeability - permeability_(0) = - this->material()->template property("k_x") / k_p; - permeability_(1) = - this->material()->template property("k_y") / k_p; - permeability_(2) = - this->material()->template property("k_z") / k_p; - break; - } + permeability_(0) = this->material(mpm::ParticlePhase::Solid) + ->template property("k_x") / + k_p; } } else { throw std::runtime_error("Material is invalid"); From 29aeb9c1fed66341ad7375584bbb04e90529edc1 Mon Sep 17 00:00:00 2001 From: Nanda Date: Fri, 14 Aug 2020 19:40:09 -0700 Subject: [PATCH 116/175] :wrench: :art: modify cmake list to deactivate HDF5 offsetof warnings --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 530b54c00..6d6bcab5f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,6 +71,7 @@ if (HDF5_FOUND) include_directories(${HDF5_INCLUDE_DIRS}) link_libraries(${HDF5_LIBRARIES} ${HDF5_HL_LIBRARIES} ${HDF5_CXX_HL_LIBRARIES}) add_definitions(${HDF5_DEFINITIONS}) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-invalid-offsetof") endif() # OpenMP From 6ac4a1be58da0d9b624bb00a00fc43c91c565456 Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Mon, 17 Aug 2020 13:25:36 -0700 Subject: [PATCH 117/175] Add warning information for particle pore pressure --- include/solvers/mpm_base.tcc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index 89a764ef4..56a98a05f 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -1231,7 +1231,9 @@ void mpm::MPMBase::particles_pore_pressures( throw std::runtime_error( "Particle pore pressures generator type is not properly " "specified"); - } + } else + throw std::runtime_error("Particle pore pressure JSON not found"); + } catch (std::exception& exception) { console_->warn("#{}: Particle pore pressures are undefined {} ", __LINE__, exception.what()); From 617efba372e48403a9acba279fb722fb7120e830 Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 18 Aug 2020 12:47:01 -0700 Subject: [PATCH 118/175] :wrench: modify initialise_particle --- include/particles/particle_base.h | 2 +- include/particles/particle_twophase.h | 2 +- include/particles/particle_twophase.tcc | 13 +++++++------ 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index fa18edea8..6bfb6613c 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -337,7 +337,7 @@ class ParticleBase { //! \param[in] material Material associated with the particle //! \retval status Status of reading HDF5 particle virtual bool initialise_particle( - const HDF5ParticleTwoPhase& particle, + HDF5Particle& particle, const std::shared_ptr>& solid_material, const std::shared_ptr>& liquid_material) { throw std::runtime_error( diff --git a/include/particles/particle_twophase.h b/include/particles/particle_twophase.h index a7ab88eff..a5360ac78 100644 --- a/include/particles/particle_twophase.h +++ b/include/particles/particle_twophase.h @@ -53,7 +53,7 @@ class TwoPhaseParticle : public mpm::Particle { //! \param[in] liquid_material Liquid material associated with the particle //! \retval status Status of reading HDF5 particle bool initialise_particle( - const HDF5ParticleTwoPhase& particle, + HDF5Particle& particle, const std::shared_ptr>& solid_material, const std::shared_ptr>& liquid_material) override; diff --git a/include/particles/particle_twophase.tcc b/include/particles/particle_twophase.tcc index d498363bf..aeaf5b8e6 100644 --- a/include/particles/particle_twophase.tcc +++ b/include/particles/particle_twophase.tcc @@ -115,10 +115,11 @@ bool mpm::TwoPhaseParticle::initialise_particle( //! Initialise particle data from HDF5 template bool mpm::TwoPhaseParticle::initialise_particle( - const HDF5ParticleTwoPhase& particle, + HDF5Particle& particle, const std::shared_ptr>& solid_material, const std::shared_ptr>& liquid_material) { - bool status = this->initialise_particle(particle); + auto twophase_particle = reinterpret_cast(&particle); + bool status = this->initialise_particle(*twophase_particle); // Solid Phase if (solid_material != nullptr) { @@ -131,13 +132,13 @@ bool mpm::TwoPhaseParticle::initialise_particle( // Reinitialize state variables auto mat_state_vars = (this->material(mpm::ParticlePhase::Solid)) ->initialise_state_variables(); - if (mat_state_vars.size() == particle.nstate_vars) { + if (mat_state_vars.size() == twophase_particle->nstate_vars) { unsigned i = 0; auto state_variables = (this->material(mpm::ParticlePhase::Solid))->state_variables(); for (const auto& state_var : state_variables) { this->state_variables_[mpm::ParticlePhase::Solid].at(state_var) = - particle.svars[i]; + twophase_particle->svars[i]; ++i; } } @@ -159,13 +160,13 @@ bool mpm::TwoPhaseParticle::initialise_particle( // Reinitialize state variables auto mat_state_vars = (this->material(mpm::ParticlePhase::Liquid)) ->initialise_state_variables(); - if (mat_state_vars.size() == particle.nliquid_state_vars) { + if (mat_state_vars.size() == twophase_particle->nliquid_state_vars) { unsigned i = 0; auto state_variables = (this->material(mpm::ParticlePhase::Liquid))->state_variables(); for (const auto& state_var : state_variables) { this->state_variables_[mpm::ParticlePhase::Liquid].at(state_var) = - particle.liquid_svars[i]; + twophase_particle->liquid_svars[i]; ++i; } } From 288b8aade022ea240a84b6bf5c26f1067c5ef8f9 Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 18 Aug 2020 15:40:42 -0700 Subject: [PATCH 119/175] :construction: change hdf5 output --- include/particles/particle_base.h | 8 - include/particles/particle_twophase.h | 2 +- include/particles/particle_twophase.tcc | 2 +- tests/mpi_particle_twophase_test.cc | 23 ++- tests/particles/particle_twophase_test.cc | 231 +++++++++++----------- 5 files changed, 134 insertions(+), 132 deletions(-) diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 6bfb6613c..3eb44d3a2 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -345,14 +345,6 @@ class ParticleBase { "ParticleBase:: illegal operation!"); }; - //! Return particle data as HDF5 for twophase particle - //! \retval particle HDF5 data of twophase particle - virtual HDF5ParticleTwoPhase hdf5_twophase() const { - throw std::runtime_error( - "Calling the base class function (hdf5) in " - "ParticleBase:: illegal operation!"); - }; - //! Update porosity //! \param[in] dt Analysis time step virtual void update_porosity(double dt) { diff --git a/include/particles/particle_twophase.h b/include/particles/particle_twophase.h index a5360ac78..59fd5af9a 100644 --- a/include/particles/particle_twophase.h +++ b/include/particles/particle_twophase.h @@ -62,7 +62,7 @@ class TwoPhaseParticle : public mpm::Particle { //! Retrun particle twophase data as HDF5 //! \retval particle HDF5 data of the particle - HDF5ParticleTwoPhase hdf5_twophase() const override; + HDF5Particle hdf5() const override; //! Assign saturation degree bool assign_saturation_degree() override; diff --git a/include/particles/particle_twophase.tcc b/include/particles/particle_twophase.tcc index aeaf5b8e6..512f66ac1 100644 --- a/include/particles/particle_twophase.tcc +++ b/include/particles/particle_twophase.tcc @@ -34,7 +34,7 @@ mpm::TwoPhaseParticle::TwoPhaseParticle(Index id, const VectorDim& coord, //! Return particle data in HDF5 format template // cppcheck-suppress * -mpm::HDF5ParticleTwoPhase mpm::TwoPhaseParticle::hdf5_twophase() const { +mpm::HDF5Particle mpm::TwoPhaseParticle::hdf5() const { // Derive from particle auto solid_particle_data = mpm::Particle::hdf5(); mpm::HDF5ParticleTwoPhase particle_data; diff --git a/tests/mpi_particle_twophase_test.cc b/tests/mpi_particle_twophase_test.cc index 4752c8dfa..54855b155 100644 --- a/tests/mpi_particle_twophase_test.cc +++ b/tests/mpi_particle_twophase_test.cc @@ -363,11 +363,15 @@ TEST_CASE("MPI HDF5 TwoPhase Particle is checked", h5_particle.liquid_material_id); // Write Particle HDF5 data - const auto h5_send = particle->hdf5_twophase(); + auto h5_send = particle->hdf5(); + auto h5_twophase_send = + reinterpret_cast(&h5_send); // Send MPI particle - MPI_Datatype particle_type = mpm::register_mpi_particle_type(h5_send); - MPI_Send(&h5_send, 1, particle_type, receiver, 0, MPI_COMM_WORLD); + MPI_Datatype particle_type = + mpm::register_mpi_particle_type(*h5_twophase_send); + MPI_Send(&(*h5_twophase_send), 1, particle_type, receiver, 0, + MPI_COMM_WORLD); mpm::deregister_mpi_particle_type(particle_type); } if (mpi_rank == receiver) { @@ -473,12 +477,15 @@ TEST_CASE("MPI HDF5 TwoPhase Particle is checked", REQUIRE(rparticle->material_id() == h5_particle.material_id); // Get Particle HDF5 data - const auto h5_received = rparticle->hdf5_twophase(); + auto h5_received = rparticle->hdf5(); + auto h5_twophase_received = + reinterpret_cast(&h5_received); + // State variables - REQUIRE(h5_received.nstate_vars == h5_particle.nstate_vars); + REQUIRE(h5_twophase_received->nstate_vars == h5_particle.nstate_vars); // State variables for (unsigned i = 0; i < h5_particle.nstate_vars; ++i) - REQUIRE(h5_received.svars[i] == + REQUIRE(h5_twophase_received->svars[i] == Approx(h5_particle.svars[i]).epsilon(Tolerance)); // Check liquid mass @@ -499,11 +506,11 @@ TEST_CASE("MPI HDF5 TwoPhase Particle is checked", h5_particle.liquid_material_id); // Liquid state variables - REQUIRE(h5_received.nliquid_state_vars == + REQUIRE(h5_twophase_received->nliquid_state_vars == h5_particle.nliquid_state_vars); // Liquid state variables for (unsigned i = 0; i < h5_particle.nliquid_state_vars; ++i) - REQUIRE(h5_received.liquid_svars[i] == + REQUIRE(h5_twophase_received->liquid_svars[i] == Approx(h5_particle.liquid_svars[i]).epsilon(Tolerance)); } } diff --git a/tests/particles/particle_twophase_test.cc b/tests/particles/particle_twophase_test.cc index b5e394a4a..283dd8316 100644 --- a/tests/particles/particle_twophase_test.cc +++ b/tests/particles/particle_twophase_test.cc @@ -360,76 +360,77 @@ TEST_CASE("TwoPhase Particle is checked for 1D case", h5_particle.liquid_material_id); // Write Particle HDF5 data - const auto h5_test = particle->hdf5_twophase(); + auto h5_test_temp = particle->hdf5(); + auto h5_test = reinterpret_cast(&h5_test_temp); - REQUIRE(h5_particle.id == h5_test.id); - REQUIRE(h5_particle.mass == h5_test.mass); + REQUIRE(h5_particle.id == h5_test->id); + REQUIRE(h5_particle.mass == h5_test->mass); - REQUIRE(h5_particle.coord_x == Approx(h5_test.coord_x).epsilon(Tolerance)); - REQUIRE(h5_particle.coord_y == Approx(h5_test.coord_y).epsilon(Tolerance)); - REQUIRE(h5_particle.coord_z == Approx(h5_test.coord_z).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_x == Approx(h5_test->coord_x).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_y == Approx(h5_test->coord_y).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_z == Approx(h5_test->coord_z).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_x == - Approx(h5_test.displacement_x).epsilon(Tolerance)); + Approx(h5_test->displacement_x).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_y == - Approx(h5_test.displacement_y).epsilon(Tolerance)); + Approx(h5_test->displacement_y).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_z == - Approx(h5_test.displacement_z).epsilon(Tolerance)); + Approx(h5_test->displacement_z).epsilon(Tolerance)); - REQUIRE(h5_particle.nsize_x == h5_test.nsize_x); - REQUIRE(h5_particle.nsize_y == h5_test.nsize_y); - REQUIRE(h5_particle.nsize_z == h5_test.nsize_z); + REQUIRE(h5_particle.nsize_x == h5_test->nsize_x); + REQUIRE(h5_particle.nsize_y == h5_test->nsize_y); + REQUIRE(h5_particle.nsize_z == h5_test->nsize_z); REQUIRE(h5_particle.velocity_x == - Approx(h5_test.velocity_x).epsilon(Tolerance)); + Approx(h5_test->velocity_x).epsilon(Tolerance)); REQUIRE(h5_particle.velocity_y == - Approx(h5_test.velocity_y).epsilon(Tolerance)); + Approx(h5_test->velocity_y).epsilon(Tolerance)); REQUIRE(h5_particle.velocity_z == - Approx(h5_test.velocity_z).epsilon(Tolerance)); + Approx(h5_test->velocity_z).epsilon(Tolerance)); REQUIRE(h5_particle.stress_xx == - Approx(h5_test.stress_xx).epsilon(Tolerance)); + Approx(h5_test->stress_xx).epsilon(Tolerance)); REQUIRE(h5_particle.stress_yy == - Approx(h5_test.stress_yy).epsilon(Tolerance)); + Approx(h5_test->stress_yy).epsilon(Tolerance)); REQUIRE(h5_particle.stress_zz == - Approx(h5_test.stress_zz).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_xy == Approx(h5_test.tau_xy).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_yz == Approx(h5_test.tau_yz).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_xz == Approx(h5_test.tau_xz).epsilon(Tolerance)); + Approx(h5_test->stress_zz).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_xy == Approx(h5_test->tau_xy).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_yz == Approx(h5_test->tau_yz).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_xz == Approx(h5_test->tau_xz).epsilon(Tolerance)); REQUIRE(h5_particle.strain_xx == - Approx(h5_test.strain_xx).epsilon(Tolerance)); + Approx(h5_test->strain_xx).epsilon(Tolerance)); REQUIRE(h5_particle.strain_yy == - Approx(h5_test.strain_yy).epsilon(Tolerance)); + Approx(h5_test->strain_yy).epsilon(Tolerance)); REQUIRE(h5_particle.strain_zz == - Approx(h5_test.strain_zz).epsilon(Tolerance)); + Approx(h5_test->strain_zz).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_xy == - Approx(h5_test.gamma_xy).epsilon(Tolerance)); + Approx(h5_test->gamma_xy).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_yz == - Approx(h5_test.gamma_yz).epsilon(Tolerance)); + Approx(h5_test->gamma_yz).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_xz == - Approx(h5_test.gamma_xz).epsilon(Tolerance)); + Approx(h5_test->gamma_xz).epsilon(Tolerance)); REQUIRE(h5_particle.epsilon_v == - Approx(h5_test.epsilon_v).epsilon(Tolerance)); - REQUIRE(h5_particle.status == h5_test.status); - REQUIRE(h5_particle.cell_id == h5_test.cell_id); - REQUIRE(h5_particle.material_id == h5_test.material_id); + Approx(h5_test->epsilon_v).epsilon(Tolerance)); + REQUIRE(h5_particle.status == h5_test->status); + REQUIRE(h5_particle.cell_id == h5_test->cell_id); + REQUIRE(h5_particle.material_id == h5_test->material_id); REQUIRE(h5_particle.liquid_mass == - Approx(h5_test.liquid_mass).epsilon(Tolerance)); + Approx(h5_test->liquid_mass).epsilon(Tolerance)); REQUIRE(h5_particle.liquid_velocity_x == - Approx(h5_test.liquid_velocity_x).epsilon(Tolerance)); + Approx(h5_test->liquid_velocity_x).epsilon(Tolerance)); REQUIRE(h5_particle.liquid_velocity_y == - Approx(h5_test.liquid_velocity_y).epsilon(Tolerance)); + Approx(h5_test->liquid_velocity_y).epsilon(Tolerance)); REQUIRE(h5_particle.liquid_velocity_z == - Approx(h5_test.liquid_velocity_z).epsilon(Tolerance)); + Approx(h5_test->liquid_velocity_z).epsilon(Tolerance)); REQUIRE(h5_particle.porosity == - Approx(h5_test.porosity).epsilon(Tolerance)); + Approx(h5_test->porosity).epsilon(Tolerance)); REQUIRE(h5_particle.liquid_saturation == - Approx(h5_test.liquid_saturation).epsilon(Tolerance)); + Approx(h5_test->liquid_saturation).epsilon(Tolerance)); REQUIRE(h5_particle.liquid_material_id == - Approx(h5_test.liquid_material_id).epsilon(Tolerance)); + Approx(h5_test->liquid_material_id).epsilon(Tolerance)); } } @@ -1601,76 +1602,77 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", h5_particle.liquid_material_id); // Write Particle HDF5 data - const auto h5_test = particle->hdf5_twophase(); + auto h5_test_temp = particle->hdf5(); + auto h5_test = reinterpret_cast(&h5_test_temp); - REQUIRE(h5_particle.id == h5_test.id); - REQUIRE(h5_particle.mass == h5_test.mass); + REQUIRE(h5_particle.id == h5_test->id); + REQUIRE(h5_particle.mass == h5_test->mass); - REQUIRE(h5_particle.coord_x == Approx(h5_test.coord_x).epsilon(Tolerance)); - REQUIRE(h5_particle.coord_y == Approx(h5_test.coord_y).epsilon(Tolerance)); - REQUIRE(h5_particle.coord_z == Approx(h5_test.coord_z).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_x == Approx(h5_test->coord_x).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_y == Approx(h5_test->coord_y).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_z == Approx(h5_test->coord_z).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_x == - Approx(h5_test.displacement_x).epsilon(Tolerance)); + Approx(h5_test->displacement_x).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_y == - Approx(h5_test.displacement_y).epsilon(Tolerance)); + Approx(h5_test->displacement_y).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_z == - Approx(h5_test.displacement_z).epsilon(Tolerance)); + Approx(h5_test->displacement_z).epsilon(Tolerance)); - REQUIRE(h5_particle.nsize_x == h5_test.nsize_x); - REQUIRE(h5_particle.nsize_y == h5_test.nsize_y); - REQUIRE(h5_particle.nsize_z == h5_test.nsize_z); + REQUIRE(h5_particle.nsize_x == h5_test->nsize_x); + REQUIRE(h5_particle.nsize_y == h5_test->nsize_y); + REQUIRE(h5_particle.nsize_z == h5_test->nsize_z); REQUIRE(h5_particle.velocity_x == - Approx(h5_test.velocity_x).epsilon(Tolerance)); + Approx(h5_test->velocity_x).epsilon(Tolerance)); REQUIRE(h5_particle.velocity_y == - Approx(h5_test.velocity_y).epsilon(Tolerance)); + Approx(h5_test->velocity_y).epsilon(Tolerance)); REQUIRE(h5_particle.velocity_z == - Approx(h5_test.velocity_z).epsilon(Tolerance)); + Approx(h5_test->velocity_z).epsilon(Tolerance)); REQUIRE(h5_particle.stress_xx == - Approx(h5_test.stress_xx).epsilon(Tolerance)); + Approx(h5_test->stress_xx).epsilon(Tolerance)); REQUIRE(h5_particle.stress_yy == - Approx(h5_test.stress_yy).epsilon(Tolerance)); + Approx(h5_test->stress_yy).epsilon(Tolerance)); REQUIRE(h5_particle.stress_zz == - Approx(h5_test.stress_zz).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_xy == Approx(h5_test.tau_xy).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_yz == Approx(h5_test.tau_yz).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_xz == Approx(h5_test.tau_xz).epsilon(Tolerance)); + Approx(h5_test->stress_zz).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_xy == Approx(h5_test->tau_xy).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_yz == Approx(h5_test->tau_yz).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_xz == Approx(h5_test->tau_xz).epsilon(Tolerance)); REQUIRE(h5_particle.strain_xx == - Approx(h5_test.strain_xx).epsilon(Tolerance)); + Approx(h5_test->strain_xx).epsilon(Tolerance)); REQUIRE(h5_particle.strain_yy == - Approx(h5_test.strain_yy).epsilon(Tolerance)); + Approx(h5_test->strain_yy).epsilon(Tolerance)); REQUIRE(h5_particle.strain_zz == - Approx(h5_test.strain_zz).epsilon(Tolerance)); + Approx(h5_test->strain_zz).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_xy == - Approx(h5_test.gamma_xy).epsilon(Tolerance)); + Approx(h5_test->gamma_xy).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_yz == - Approx(h5_test.gamma_yz).epsilon(Tolerance)); + Approx(h5_test->gamma_yz).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_xz == - Approx(h5_test.gamma_xz).epsilon(Tolerance)); + Approx(h5_test->gamma_xz).epsilon(Tolerance)); REQUIRE(h5_particle.epsilon_v == - Approx(h5_test.epsilon_v).epsilon(Tolerance)); - REQUIRE(h5_particle.status == h5_test.status); - REQUIRE(h5_particle.cell_id == h5_test.cell_id); - REQUIRE(h5_particle.material_id == h5_test.material_id); + Approx(h5_test->epsilon_v).epsilon(Tolerance)); + REQUIRE(h5_particle.status == h5_test->status); + REQUIRE(h5_particle.cell_id == h5_test->cell_id); + REQUIRE(h5_particle.material_id == h5_test->material_id); REQUIRE(h5_particle.liquid_mass == - Approx(h5_test.liquid_mass).epsilon(Tolerance)); + Approx(h5_test->liquid_mass).epsilon(Tolerance)); REQUIRE(h5_particle.liquid_velocity_x == - Approx(h5_test.liquid_velocity_x).epsilon(Tolerance)); + Approx(h5_test->liquid_velocity_x).epsilon(Tolerance)); REQUIRE(h5_particle.liquid_velocity_y == - Approx(h5_test.liquid_velocity_y).epsilon(Tolerance)); + Approx(h5_test->liquid_velocity_y).epsilon(Tolerance)); REQUIRE(h5_particle.liquid_velocity_z == - Approx(h5_test.liquid_velocity_z).epsilon(Tolerance)); + Approx(h5_test->liquid_velocity_z).epsilon(Tolerance)); REQUIRE(h5_particle.porosity == - Approx(h5_test.porosity).epsilon(Tolerance)); + Approx(h5_test->porosity).epsilon(Tolerance)); REQUIRE(h5_particle.liquid_saturation == - Approx(h5_test.liquid_saturation).epsilon(Tolerance)); + Approx(h5_test->liquid_saturation).epsilon(Tolerance)); REQUIRE(h5_particle.liquid_material_id == - Approx(h5_test.liquid_material_id).epsilon(Tolerance)); + Approx(h5_test->liquid_material_id).epsilon(Tolerance)); } // Check twophase particle's material id maping to nodes @@ -3089,76 +3091,77 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", h5_particle.liquid_material_id); // Write Particle HDF5 data - const auto h5_test = particle->hdf5_twophase(); + auto h5_test_temp = particle->hdf5(); + auto h5_test = reinterpret_cast(&h5_test_temp); - REQUIRE(h5_particle.id == h5_test.id); - REQUIRE(h5_particle.mass == h5_test.mass); + REQUIRE(h5_particle.id == h5_test->id); + REQUIRE(h5_particle.mass == h5_test->mass); - REQUIRE(h5_particle.coord_x == Approx(h5_test.coord_x).epsilon(Tolerance)); - REQUIRE(h5_particle.coord_y == Approx(h5_test.coord_y).epsilon(Tolerance)); - REQUIRE(h5_particle.coord_z == Approx(h5_test.coord_z).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_x == Approx(h5_test->coord_x).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_y == Approx(h5_test->coord_y).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_z == Approx(h5_test->coord_z).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_x == - Approx(h5_test.displacement_x).epsilon(Tolerance)); + Approx(h5_test->displacement_x).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_y == - Approx(h5_test.displacement_y).epsilon(Tolerance)); + Approx(h5_test->displacement_y).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_z == - Approx(h5_test.displacement_z).epsilon(Tolerance)); + Approx(h5_test->displacement_z).epsilon(Tolerance)); - REQUIRE(h5_particle.nsize_x == h5_test.nsize_x); - REQUIRE(h5_particle.nsize_y == h5_test.nsize_y); - REQUIRE(h5_particle.nsize_z == h5_test.nsize_z); + REQUIRE(h5_particle.nsize_x == h5_test->nsize_x); + REQUIRE(h5_particle.nsize_y == h5_test->nsize_y); + REQUIRE(h5_particle.nsize_z == h5_test->nsize_z); REQUIRE(h5_particle.velocity_x == - Approx(h5_test.velocity_x).epsilon(Tolerance)); + Approx(h5_test->velocity_x).epsilon(Tolerance)); REQUIRE(h5_particle.velocity_y == - Approx(h5_test.velocity_y).epsilon(Tolerance)); + Approx(h5_test->velocity_y).epsilon(Tolerance)); REQUIRE(h5_particle.velocity_z == - Approx(h5_test.velocity_z).epsilon(Tolerance)); + Approx(h5_test->velocity_z).epsilon(Tolerance)); REQUIRE(h5_particle.stress_xx == - Approx(h5_test.stress_xx).epsilon(Tolerance)); + Approx(h5_test->stress_xx).epsilon(Tolerance)); REQUIRE(h5_particle.stress_yy == - Approx(h5_test.stress_yy).epsilon(Tolerance)); + Approx(h5_test->stress_yy).epsilon(Tolerance)); REQUIRE(h5_particle.stress_zz == - Approx(h5_test.stress_zz).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_xy == Approx(h5_test.tau_xy).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_yz == Approx(h5_test.tau_yz).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_xz == Approx(h5_test.tau_xz).epsilon(Tolerance)); + Approx(h5_test->stress_zz).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_xy == Approx(h5_test->tau_xy).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_yz == Approx(h5_test->tau_yz).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_xz == Approx(h5_test->tau_xz).epsilon(Tolerance)); REQUIRE(h5_particle.strain_xx == - Approx(h5_test.strain_xx).epsilon(Tolerance)); + Approx(h5_test->strain_xx).epsilon(Tolerance)); REQUIRE(h5_particle.strain_yy == - Approx(h5_test.strain_yy).epsilon(Tolerance)); + Approx(h5_test->strain_yy).epsilon(Tolerance)); REQUIRE(h5_particle.strain_zz == - Approx(h5_test.strain_zz).epsilon(Tolerance)); + Approx(h5_test->strain_zz).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_xy == - Approx(h5_test.gamma_xy).epsilon(Tolerance)); + Approx(h5_test->gamma_xy).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_yz == - Approx(h5_test.gamma_yz).epsilon(Tolerance)); + Approx(h5_test->gamma_yz).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_xz == - Approx(h5_test.gamma_xz).epsilon(Tolerance)); + Approx(h5_test->gamma_xz).epsilon(Tolerance)); REQUIRE(h5_particle.epsilon_v == - Approx(h5_test.epsilon_v).epsilon(Tolerance)); - REQUIRE(h5_particle.status == h5_test.status); - REQUIRE(h5_particle.cell_id == h5_test.cell_id); - REQUIRE(h5_particle.material_id == h5_test.material_id); + Approx(h5_test->epsilon_v).epsilon(Tolerance)); + REQUIRE(h5_particle.status == h5_test->status); + REQUIRE(h5_particle.cell_id == h5_test->cell_id); + REQUIRE(h5_particle.material_id == h5_test->material_id); REQUIRE(h5_particle.liquid_mass == - Approx(h5_test.liquid_mass).epsilon(Tolerance)); + Approx(h5_test->liquid_mass).epsilon(Tolerance)); REQUIRE(h5_particle.liquid_velocity_x == - Approx(h5_test.liquid_velocity_x).epsilon(Tolerance)); + Approx(h5_test->liquid_velocity_x).epsilon(Tolerance)); REQUIRE(h5_particle.liquid_velocity_y == - Approx(h5_test.liquid_velocity_y).epsilon(Tolerance)); + Approx(h5_test->liquid_velocity_y).epsilon(Tolerance)); REQUIRE(h5_particle.liquid_velocity_z == - Approx(h5_test.liquid_velocity_z).epsilon(Tolerance)); + Approx(h5_test->liquid_velocity_z).epsilon(Tolerance)); REQUIRE(h5_particle.porosity == - Approx(h5_test.porosity).epsilon(Tolerance)); + Approx(h5_test->porosity).epsilon(Tolerance)); REQUIRE(h5_particle.liquid_saturation == - Approx(h5_test.liquid_saturation).epsilon(Tolerance)); + Approx(h5_test->liquid_saturation).epsilon(Tolerance)); REQUIRE(h5_particle.liquid_material_id == - Approx(h5_test.liquid_material_id).epsilon(Tolerance)); + Approx(h5_test->liquid_material_id).epsilon(Tolerance)); } // Check particle's material id maping to nodes From ec91bc0bbc42b5eb97ad5665a1f03ddcf7965e99 Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Wed, 19 Aug 2020 06:43:05 -0500 Subject: [PATCH 120/175] :hammer: Use void* to return particle POD --- include/hdf5_particle.h | 1 + include/particles/particle.h | 4 + include/particles/particle.tcc | 8 + include/particles/particle_base.h | 4 + include/particles/particle_twophase.h | 2 + include/particles/particle_twophase.tcc | 193 +++++++++++++++++++++- tests/particles/particle_twophase_test.cc | 9 +- 7 files changed, 215 insertions(+), 6 deletions(-) diff --git a/include/hdf5_particle.h b/include/hdf5_particle.h index b5ebd54d5..70e1a8988 100644 --- a/include/hdf5_particle.h +++ b/include/hdf5_particle.h @@ -44,6 +44,7 @@ typedef struct HDF5Particle { unsigned nstate_vars; // State variables (init to zero) double svars[20] = {0}; + virtual ~HDF5Particle() = default; } HDF5Particle; namespace hdf5 { diff --git a/include/particles/particle.h b/include/particles/particle.h index b7f906bf5..891ea3eb6 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -63,6 +63,10 @@ class Particle : public ParticleBase { //! \retval particle HDF5 data of the particle HDF5Particle hdf5() const override; + //! Retrun particle data as HDF5 + //! \retval particle HDF5 data of the particle + void* hdf5_ptr() override; + //! Initialise properties void initialise() override; diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index 0c6a2c452..5c696fb54 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -132,6 +132,14 @@ bool mpm::Particle::initialise_particle( return status; } +//! Return particle data in HDF5 format +template +// cppcheck-suppress * +void* mpm::Particle::hdf5_ptr() { + mpm::HDF5Particle particle_data; + return &particle_data; +} + //! Return particle data in HDF5 format template // cppcheck-suppress * diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 3eb44d3a2..66e2eb886 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -74,6 +74,10 @@ class ParticleBase { //! \retval particle HDF5 data of the particle virtual HDF5Particle hdf5() const = 0; + //! Retrun particle data as HDF5 + //! \retval particle HDF5 data of the particle + virtual void* hdf5_ptr() = 0; + //! Return id of the particleBase Index id() const { return id_; } diff --git a/include/particles/particle_twophase.h b/include/particles/particle_twophase.h index 59fd5af9a..a6c38b67f 100644 --- a/include/particles/particle_twophase.h +++ b/include/particles/particle_twophase.h @@ -64,6 +64,8 @@ class TwoPhaseParticle : public mpm::Particle { //! \retval particle HDF5 data of the particle HDF5Particle hdf5() const override; + void* hdf5_ptr() override; + //! Assign saturation degree bool assign_saturation_degree() override; diff --git a/include/particles/particle_twophase.tcc b/include/particles/particle_twophase.tcc index 512f66ac1..a9e9cc45f 100644 --- a/include/particles/particle_twophase.tcc +++ b/include/particles/particle_twophase.tcc @@ -36,9 +36,78 @@ template // cppcheck-suppress * mpm::HDF5Particle mpm::TwoPhaseParticle::hdf5() const { // Derive from particle - auto solid_particle_data = mpm::Particle::hdf5(); + // auto solid_particle_data = mpm::Particle::hdf5(); mpm::HDF5ParticleTwoPhase particle_data; - static_cast(particle_data) = solid_particle_data; + // static_cast(particle_data) = solid_particle_data; + + Eigen::Vector3d coordinates; + coordinates.setZero(); + for (unsigned j = 0; j < Tdim; ++j) coordinates[j] = this->coordinates_[j]; + + Eigen::Vector3d displacement; + displacement.setZero(); + for (unsigned j = 0; j < Tdim; ++j) displacement[j] = this->displacement_[j]; + + Eigen::Vector3d velocity; + velocity.setZero(); + for (unsigned j = 0; j < Tdim; ++j) velocity[j] = this->velocity_[j]; + + // Particle local size + Eigen::Vector3d nsize; + nsize.setZero(); + Eigen::VectorXd size = this->natural_size(); + for (unsigned j = 0; j < Tdim; ++j) nsize[j] = size[j]; + + Eigen::Matrix stress = this->stress_; + + Eigen::Matrix strain = this->strain_; + + particle_data.id = this->id(); + particle_data.mass = this->mass(); + particle_data.volume = this->volume(); + particle_data.pressure = + (state_variables_[mpm::ParticlePhase::Solid].find("pressure") != + state_variables_[mpm::ParticlePhase::Solid].end()) + ? state_variables_[mpm::ParticlePhase::Solid].at("pressure") + : 0.; + + particle_data.coord_x = coordinates[0]; + particle_data.coord_y = coordinates[1]; + particle_data.coord_z = coordinates[2]; + + particle_data.displacement_x = displacement[0]; + particle_data.displacement_y = displacement[1]; + particle_data.displacement_z = displacement[2]; + + particle_data.nsize_x = nsize[0]; + particle_data.nsize_y = nsize[1]; + particle_data.nsize_z = nsize[2]; + + particle_data.velocity_x = velocity[0]; + particle_data.velocity_y = velocity[1]; + particle_data.velocity_z = velocity[2]; + + particle_data.stress_xx = stress[0]; + particle_data.stress_yy = stress[1]; + particle_data.stress_zz = stress[2]; + particle_data.tau_xy = stress[3]; + particle_data.tau_yz = stress[4]; + particle_data.tau_xz = stress[5]; + + particle_data.strain_xx = strain[0]; + particle_data.strain_yy = strain[1]; + particle_data.strain_zz = strain[2]; + particle_data.gamma_xy = strain[3]; + particle_data.gamma_yz = strain[4]; + particle_data.gamma_xz = strain[5]; + + particle_data.epsilon_v = this->volumetric_strain_centroid_; + + particle_data.status = this->status(); + + particle_data.cell_id = this->cell_id(); + + particle_data.material_id = this->material_id(); // Particle liquid mass particle_data.liquid_mass = this->liquid_mass_; @@ -80,6 +149,124 @@ mpm::HDF5Particle mpm::TwoPhaseParticle::hdf5() const { return particle_data; } +//! Return particle data in HDF5 format +template +// cppcheck-suppress * +void* mpm::TwoPhaseParticle::hdf5_ptr() { + // Derive from particle + // auto solid_particle_data = mpm::Particle::hdf5(); + mpm::HDF5ParticleTwoPhase* particle_data = new HDF5ParticleTwoPhase(); + // static_cast(particle_data) = solid_particle_data; + + Eigen::Vector3d coordinates; + coordinates.setZero(); + for (unsigned j = 0; j < Tdim; ++j) coordinates[j] = this->coordinates_[j]; + + Eigen::Vector3d displacement; + displacement.setZero(); + for (unsigned j = 0; j < Tdim; ++j) displacement[j] = this->displacement_[j]; + + Eigen::Vector3d velocity; + velocity.setZero(); + for (unsigned j = 0; j < Tdim; ++j) velocity[j] = this->velocity_[j]; + + // Particle local size + Eigen::Vector3d nsize; + nsize.setZero(); + Eigen::VectorXd size = this->natural_size(); + for (unsigned j = 0; j < Tdim; ++j) nsize[j] = size[j]; + + Eigen::Matrix stress = this->stress_; + + Eigen::Matrix strain = this->strain_; + + particle_data->id = this->id(); + particle_data->mass = this->mass(); + particle_data->volume = this->volume(); + particle_data->pressure = + (state_variables_[mpm::ParticlePhase::Solid].find("pressure") != + state_variables_[mpm::ParticlePhase::Solid].end()) + ? state_variables_[mpm::ParticlePhase::Solid].at("pressure") + : 0.; + + particle_data->coord_x = coordinates[0]; + particle_data->coord_y = coordinates[1]; + particle_data->coord_z = coordinates[2]; + + particle_data->displacement_x = displacement[0]; + particle_data->displacement_y = displacement[1]; + particle_data->displacement_z = displacement[2]; + + particle_data->nsize_x = nsize[0]; + particle_data->nsize_y = nsize[1]; + particle_data->nsize_z = nsize[2]; + + particle_data->velocity_x = velocity[0]; + particle_data->velocity_y = velocity[1]; + particle_data->velocity_z = velocity[2]; + + particle_data->stress_xx = stress[0]; + particle_data->stress_yy = stress[1]; + particle_data->stress_zz = stress[2]; + particle_data->tau_xy = stress[3]; + particle_data->tau_yz = stress[4]; + particle_data->tau_xz = stress[5]; + + particle_data->strain_xx = strain[0]; + particle_data->strain_yy = strain[1]; + particle_data->strain_zz = strain[2]; + particle_data->gamma_xy = strain[3]; + particle_data->gamma_yz = strain[4]; + particle_data->gamma_xz = strain[5]; + + particle_data->epsilon_v = this->volumetric_strain_centroid_; + + particle_data->status = this->status(); + + particle_data->cell_id = this->cell_id(); + + particle_data->material_id = this->material_id(); + + // Particle liquid mass + particle_data->liquid_mass = this->liquid_mass_; + + // Particle liquid velocity + Eigen::Vector3d liquid_velocity; + liquid_velocity.setZero(); + for (unsigned j = 0; j < Tdim; ++j) + liquid_velocity[j] = this->liquid_velocity_[j]; + + particle_data->liquid_velocity_x = liquid_velocity[0]; + particle_data->liquid_velocity_y = liquid_velocity[1]; + particle_data->liquid_velocity_z = liquid_velocity[2]; + + // Particle porosity and saturation + particle_data->porosity = this->porosity_; + particle_data->liquid_saturation = this->liquid_saturation_; + + // Particle liquid material id + particle_data->liquid_material_id = + this->material_id(mpm::ParticlePhase::Liquid); + + // Write state variables + if (this->material(mpm::ParticlePhase::Liquid) != nullptr) { + particle_data->nliquid_state_vars = + state_variables_[mpm::ParticlePhase::Liquid].size(); + if (state_variables_[mpm::ParticlePhase::Liquid].size() > 5) + throw std::runtime_error("# of state variables cannot be more than 5"); + unsigned i = 0; + auto state_variables = + (this->material(mpm::ParticlePhase::Liquid))->state_variables(); + for (const auto& state_var : state_variables) { + particle_data->liquid_svars[i] = + state_variables_[mpm::ParticlePhase::Liquid].at(state_var); + ++i; + } + } + + return particle_data; +} + //! Initialise particle data from HDF5 template bool mpm::TwoPhaseParticle::initialise_particle( @@ -822,4 +1009,4 @@ bool mpm::TwoPhaseParticle::assign_traction(unsigned direction, status = false; } return status; -} \ No newline at end of file +} diff --git a/tests/particles/particle_twophase_test.cc b/tests/particles/particle_twophase_test.cc index 283dd8316..e806bf549 100644 --- a/tests/particles/particle_twophase_test.cc +++ b/tests/particles/particle_twophase_test.cc @@ -360,8 +360,11 @@ TEST_CASE("TwoPhase Particle is checked for 1D case", h5_particle.liquid_material_id); // Write Particle HDF5 data - auto h5_test_temp = particle->hdf5(); - auto h5_test = reinterpret_cast(&h5_test_temp); + // mpm::HDF5Particle h5_test_temp = particle->hdf5(); + mpm::HDF5ParticleTwoPhase* h5_test = + reinterpret_cast(particle->hdf5_ptr()); + // auto h5_test = + // reinterpret_cast(&h5_test_temp); REQUIRE(h5_particle.id == h5_test->id); REQUIRE(h5_particle.mass == h5_test->mass); @@ -3267,4 +3270,4 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", REQUIRE(*mitr == material_ids.at(i)); } } -} \ No newline at end of file +} From 5af4700f9821784a099cd2f3a9b8a6b2c81bea58 Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Wed, 19 Aug 2020 07:02:21 -0500 Subject: [PATCH 121/175] :hammer: Use std::shared_ptr to handle PODs --- include/particles/particle.h | 2 +- include/particles/particle.tcc | 6 +++--- include/particles/particle_base.h | 2 +- include/particles/particle_twophase.h | 2 +- include/particles/particle_twophase.tcc | 4 ++-- tests/particles/particle_twophase_test.cc | 18 ++++++++++++------ 6 files changed, 20 insertions(+), 14 deletions(-) diff --git a/include/particles/particle.h b/include/particles/particle.h index 891ea3eb6..2ba6d03dc 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -65,7 +65,7 @@ class Particle : public ParticleBase { //! Retrun particle data as HDF5 //! \retval particle HDF5 data of the particle - void* hdf5_ptr() override; + std::shared_ptr hdf5_ptr() override; //! Initialise properties void initialise() override; diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index 5c696fb54..3c3e43676 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -135,9 +135,9 @@ bool mpm::Particle::initialise_particle( //! Return particle data in HDF5 format template // cppcheck-suppress * -void* mpm::Particle::hdf5_ptr() { - mpm::HDF5Particle particle_data; - return &particle_data; +std::shared_ptr mpm::Particle::hdf5_ptr() { + auto particle_data = std::make_shared(); + return particle_data; } //! Return particle data in HDF5 format diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 66e2eb886..e988482dc 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -76,7 +76,7 @@ class ParticleBase { //! Retrun particle data as HDF5 //! \retval particle HDF5 data of the particle - virtual void* hdf5_ptr() = 0; + virtual std::shared_ptr hdf5_ptr() = 0; //! Return id of the particleBase Index id() const { return id_; } diff --git a/include/particles/particle_twophase.h b/include/particles/particle_twophase.h index a6c38b67f..0035990a9 100644 --- a/include/particles/particle_twophase.h +++ b/include/particles/particle_twophase.h @@ -64,7 +64,7 @@ class TwoPhaseParticle : public mpm::Particle { //! \retval particle HDF5 data of the particle HDF5Particle hdf5() const override; - void* hdf5_ptr() override; + std::shared_ptr hdf5_ptr() override; //! Assign saturation degree bool assign_saturation_degree() override; diff --git a/include/particles/particle_twophase.tcc b/include/particles/particle_twophase.tcc index a9e9cc45f..43ad6479e 100644 --- a/include/particles/particle_twophase.tcc +++ b/include/particles/particle_twophase.tcc @@ -152,10 +152,10 @@ mpm::HDF5Particle mpm::TwoPhaseParticle::hdf5() const { //! Return particle data in HDF5 format template // cppcheck-suppress * -void* mpm::TwoPhaseParticle::hdf5_ptr() { +std::shared_ptr mpm::TwoPhaseParticle::hdf5_ptr() { // Derive from particle // auto solid_particle_data = mpm::Particle::hdf5(); - mpm::HDF5ParticleTwoPhase* particle_data = new HDF5ParticleTwoPhase(); + auto particle_data = std::make_shared(); // static_cast(particle_data) = solid_particle_data; Eigen::Vector3d coordinates; diff --git a/tests/particles/particle_twophase_test.cc b/tests/particles/particle_twophase_test.cc index e806bf549..83e9af71d 100644 --- a/tests/particles/particle_twophase_test.cc +++ b/tests/particles/particle_twophase_test.cc @@ -361,8 +361,8 @@ TEST_CASE("TwoPhase Particle is checked for 1D case", // Write Particle HDF5 data // mpm::HDF5Particle h5_test_temp = particle->hdf5(); - mpm::HDF5ParticleTwoPhase* h5_test = - reinterpret_cast(particle->hdf5_ptr()); + auto h5_test = std::static_pointer_cast( + particle->hdf5_ptr()); // auto h5_test = // reinterpret_cast(&h5_test_temp); @@ -1605,8 +1605,11 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", h5_particle.liquid_material_id); // Write Particle HDF5 data - auto h5_test_temp = particle->hdf5(); - auto h5_test = reinterpret_cast(&h5_test_temp); + // auto h5_test_temp = particle->hdf5(); + // auto h5_test = + // reinterpret_cast(&h5_test_temp); + auto h5_test = std::static_pointer_cast( + particle->hdf5_ptr()); REQUIRE(h5_particle.id == h5_test->id); REQUIRE(h5_particle.mass == h5_test->mass); @@ -3094,8 +3097,11 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", h5_particle.liquid_material_id); // Write Particle HDF5 data - auto h5_test_temp = particle->hdf5(); - auto h5_test = reinterpret_cast(&h5_test_temp); + // auto h5_test_temp = particle->hdf5(); + // auto h5_test = + // reinterpret_cast(&h5_test_temp); + auto h5_test = std::static_pointer_cast( + particle->hdf5_ptr()); REQUIRE(h5_particle.id == h5_test->id); REQUIRE(h5_particle.mass == h5_test->mass); From dc2ec429fa2e10262cd5752396d81c1ca15e3d7e Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 19 Aug 2020 23:04:39 -0700 Subject: [PATCH 122/175] :pencil: :construction: cleanup hdf5_ptr() --- include/particles/particle.h | 4 +- include/particles/particle.tcc | 88 ++++++++++++++++++++++- include/particles/particle_base.h | 4 +- include/particles/particle_twophase.h | 2 + include/particles/particle_twophase.tcc | 21 ++++-- tests/particles/particle_twophase_test.cc | 9 --- 6 files changed, 110 insertions(+), 18 deletions(-) diff --git a/include/particles/particle.h b/include/particles/particle.h index 2ba6d03dc..e86f7e1ae 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -63,8 +63,8 @@ class Particle : public ParticleBase { //! \retval particle HDF5 data of the particle HDF5Particle hdf5() const override; - //! Retrun particle data as HDF5 - //! \retval particle HDF5 data of the particle + //! Return particle data as HDF5 pointer + //! \retval particle HDF5 pointer of the particle std::shared_ptr hdf5_ptr() override; //! Initialise properties diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index 3c3e43676..66321fe68 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -132,11 +132,97 @@ bool mpm::Particle::initialise_particle( return status; } -//! Return particle data in HDF5 format +//! Return particle data as HDF5 pointer template // cppcheck-suppress * std::shared_ptr mpm::Particle::hdf5_ptr() { + // Initialise particle data auto particle_data = std::make_shared(); + + Eigen::Vector3d coordinates; + coordinates.setZero(); + for (unsigned j = 0; j < Tdim; ++j) coordinates[j] = this->coordinates_[j]; + + Eigen::Vector3d displacement; + displacement.setZero(); + for (unsigned j = 0; j < Tdim; ++j) displacement[j] = this->displacement_[j]; + + Eigen::Vector3d velocity; + velocity.setZero(); + for (unsigned j = 0; j < Tdim; ++j) velocity[j] = this->velocity_[j]; + + // Particle local size + Eigen::Vector3d nsize; + nsize.setZero(); + Eigen::VectorXd size = this->natural_size(); + for (unsigned j = 0; j < Tdim; ++j) nsize[j] = size[j]; + + Eigen::Matrix stress = this->stress_; + + Eigen::Matrix strain = this->strain_; + + particle_data->id = this->id(); + particle_data->mass = this->mass(); + particle_data->volume = this->volume(); + particle_data->pressure = + (state_variables_[mpm::ParticlePhase::Solid].find("pressure") != + state_variables_[mpm::ParticlePhase::Solid].end()) + ? state_variables_[mpm::ParticlePhase::Solid].at("pressure") + : 0.; + + particle_data->coord_x = coordinates[0]; + particle_data->coord_y = coordinates[1]; + particle_data->coord_z = coordinates[2]; + + particle_data->displacement_x = displacement[0]; + particle_data->displacement_y = displacement[1]; + particle_data->displacement_z = displacement[2]; + + particle_data->nsize_x = nsize[0]; + particle_data->nsize_y = nsize[1]; + particle_data->nsize_z = nsize[2]; + + particle_data->velocity_x = velocity[0]; + particle_data->velocity_y = velocity[1]; + particle_data->velocity_z = velocity[2]; + + particle_data->stress_xx = stress[0]; + particle_data->stress_yy = stress[1]; + particle_data->stress_zz = stress[2]; + particle_data->tau_xy = stress[3]; + particle_data->tau_yz = stress[4]; + particle_data->tau_xz = stress[5]; + + particle_data->strain_xx = strain[0]; + particle_data->strain_yy = strain[1]; + particle_data->strain_zz = strain[2]; + particle_data->gamma_xy = strain[3]; + particle_data->gamma_yz = strain[4]; + particle_data->gamma_xz = strain[5]; + + particle_data->epsilon_v = this->volumetric_strain_centroid_; + + particle_data->status = this->status(); + + particle_data->cell_id = this->cell_id(); + + particle_data->material_id = this->material_id(); + + // Write state variables + if (this->material() != nullptr) { + particle_data->nstate_vars = + state_variables_[mpm::ParticlePhase::Solid].size(); + if (state_variables_[mpm::ParticlePhase::Solid].size() > 20) + throw std::runtime_error("# of state variables cannot be more than 20"); + unsigned i = 0; + auto state_variables = (this->material())->state_variables(); + for (const auto& state_var : state_variables) { + particle_data->svars[i] = + state_variables_[mpm::ParticlePhase::Solid].at(state_var); + ++i; + } + } + return particle_data; } diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index e988482dc..3ff94e086 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -74,8 +74,8 @@ class ParticleBase { //! \retval particle HDF5 data of the particle virtual HDF5Particle hdf5() const = 0; - //! Retrun particle data as HDF5 - //! \retval particle HDF5 data of the particle + //! Return particle data as HDF5 pointer + //! \retval particle HDF5 pointer of the particle virtual std::shared_ptr hdf5_ptr() = 0; //! Return id of the particleBase diff --git a/include/particles/particle_twophase.h b/include/particles/particle_twophase.h index 0035990a9..0185f28a1 100644 --- a/include/particles/particle_twophase.h +++ b/include/particles/particle_twophase.h @@ -64,6 +64,8 @@ class TwoPhaseParticle : public mpm::Particle { //! \retval particle HDF5 data of the particle HDF5Particle hdf5() const override; + //! Return particle data as HDF5 pointer + //! \retval particle HDF5 pointer of the particle std::shared_ptr hdf5_ptr() override; //! Assign saturation degree diff --git a/include/particles/particle_twophase.tcc b/include/particles/particle_twophase.tcc index 43ad6479e..12b114158 100644 --- a/include/particles/particle_twophase.tcc +++ b/include/particles/particle_twophase.tcc @@ -149,14 +149,12 @@ mpm::HDF5Particle mpm::TwoPhaseParticle::hdf5() const { return particle_data; } -//! Return particle data in HDF5 format +//! Return particle data as HDF5 pointer template // cppcheck-suppress * std::shared_ptr mpm::TwoPhaseParticle::hdf5_ptr() { - // Derive from particle - // auto solid_particle_data = mpm::Particle::hdf5(); + // Initialise particle_data auto particle_data = std::make_shared(); - // static_cast(particle_data) = solid_particle_data; Eigen::Vector3d coordinates; coordinates.setZero(); @@ -227,6 +225,21 @@ std::shared_ptr mpm::TwoPhaseParticle::hdf5_ptr() { particle_data->material_id = this->material_id(); + // Write state variables + if (this->material() != nullptr) { + particle_data->nstate_vars = + state_variables_[mpm::ParticlePhase::Solid].size(); + if (state_variables_[mpm::ParticlePhase::Solid].size() > 20) + throw std::runtime_error("# of state variables cannot be more than 20"); + unsigned i = 0; + auto state_variables = (this->material())->state_variables(); + for (const auto& state_var : state_variables) { + particle_data->svars[i] = + state_variables_[mpm::ParticlePhase::Solid].at(state_var); + ++i; + } + } + // Particle liquid mass particle_data->liquid_mass = this->liquid_mass_; diff --git a/tests/particles/particle_twophase_test.cc b/tests/particles/particle_twophase_test.cc index 83e9af71d..06c3be269 100644 --- a/tests/particles/particle_twophase_test.cc +++ b/tests/particles/particle_twophase_test.cc @@ -360,11 +360,8 @@ TEST_CASE("TwoPhase Particle is checked for 1D case", h5_particle.liquid_material_id); // Write Particle HDF5 data - // mpm::HDF5Particle h5_test_temp = particle->hdf5(); auto h5_test = std::static_pointer_cast( particle->hdf5_ptr()); - // auto h5_test = - // reinterpret_cast(&h5_test_temp); REQUIRE(h5_particle.id == h5_test->id); REQUIRE(h5_particle.mass == h5_test->mass); @@ -1605,9 +1602,6 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", h5_particle.liquid_material_id); // Write Particle HDF5 data - // auto h5_test_temp = particle->hdf5(); - // auto h5_test = - // reinterpret_cast(&h5_test_temp); auto h5_test = std::static_pointer_cast( particle->hdf5_ptr()); @@ -3097,9 +3091,6 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", h5_particle.liquid_material_id); // Write Particle HDF5 data - // auto h5_test_temp = particle->hdf5(); - // auto h5_test = - // reinterpret_cast(&h5_test_temp); auto h5_test = std::static_pointer_cast( particle->hdf5_ptr()); From 4806e093f11120ccab75235ea9825075c6289ff1 Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 19 Aug 2020 23:44:57 -0700 Subject: [PATCH 123/175] :construction: :dart: remove hdf5() and replace completely to hdf5_ptr() --- include/mesh.tcc | 22 ++- include/particles/particle.h | 4 - include/particles/particle.tcc | 94 ------------ include/particles/particle_base.h | 4 - include/particles/particle_twophase.h | 4 - include/particles/particle_twophase.tcc | 118 --------------- tests/mpi_particle_test.cc | 16 +- tests/mpi_particle_twophase_test.cc | 14 +- tests/particles/particle_test.cc | 189 ++++++++++++------------ 9 files changed, 129 insertions(+), 336 deletions(-) diff --git a/include/mesh.tcc b/include/mesh.tcc index f92ab4b00..7785dff75 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -718,7 +718,9 @@ void mpm::Mesh::transfer_halo_particles() { // delete particle for (auto& id : particle_ids) { // Append to vector of particles - h5_particles.emplace_back(map_particles_[id]->hdf5()); + auto hdf5_ptr = std::static_pointer_cast( + map_particles_[id]->hdf5_ptr()); + h5_particles.emplace_back(*hdf5_ptr); // Particles to be removed from the current rank remove_pids.emplace_back(id); } @@ -825,7 +827,9 @@ void mpm::Mesh::transfer_nonrank_particles( // delete particle for (auto& id : particle_ids) { // Append to vector of particles - h5_particles.emplace_back(map_particles_[id]->hdf5()); + auto hdf5_ptr = std::static_pointer_cast( + map_particles_[id]->hdf5_ptr()); + h5_particles.emplace_back(*hdf5_ptr); // Particles to be removed from the current rank remove_pids.emplace_back(id); } @@ -1398,8 +1402,11 @@ bool mpm::Mesh::write_particles_hdf5(unsigned phase, std::vector particle_data; // = new HDF5Particle[nparticles]; particle_data.reserve(nparticles); - for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) - particle_data.emplace_back((*pitr)->hdf5()); + for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { + auto hdf5_ptr = + std::static_pointer_cast((*pitr)->hdf5_ptr()); + particle_data.emplace_back(*hdf5_ptr); + } // Calculate the size and the offsets of our struct members in memory const hsize_t NRECORDS = nparticles; @@ -1492,8 +1499,11 @@ std::vector mpm::Mesh::particles_hdf5() const { std::vector particles_hdf5; particles_hdf5.reserve(nparticles); - for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) - particles_hdf5.emplace_back((*pitr)->hdf5()); + for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { + auto hdf5_ptr = + std::static_pointer_cast((*pitr)->hdf5_ptr()); + particles_hdf5.emplace_back(*hdf5_ptr); + } return particles_hdf5; } diff --git a/include/particles/particle.h b/include/particles/particle.h index e86f7e1ae..f67198df6 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -59,10 +59,6 @@ class Particle : public ParticleBase { const HDF5Particle& particle, const std::shared_ptr>& material) override; - //! Retrun particle data as HDF5 - //! \retval particle HDF5 data of the particle - HDF5Particle hdf5() const override; - //! Return particle data as HDF5 pointer //! \retval particle HDF5 pointer of the particle std::shared_ptr hdf5_ptr() override; diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index 66321fe68..de0f23eb8 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -226,100 +226,6 @@ std::shared_ptr mpm::Particle::hdf5_ptr() { return particle_data; } -//! Return particle data in HDF5 format -template -// cppcheck-suppress * -mpm::HDF5Particle mpm::Particle::hdf5() const { - - mpm::HDF5Particle particle_data; - - Eigen::Vector3d coordinates; - coordinates.setZero(); - for (unsigned j = 0; j < Tdim; ++j) coordinates[j] = this->coordinates_[j]; - - Eigen::Vector3d displacement; - displacement.setZero(); - for (unsigned j = 0; j < Tdim; ++j) displacement[j] = this->displacement_[j]; - - Eigen::Vector3d velocity; - velocity.setZero(); - for (unsigned j = 0; j < Tdim; ++j) velocity[j] = this->velocity_[j]; - - // Particle local size - Eigen::Vector3d nsize; - nsize.setZero(); - Eigen::VectorXd size = this->natural_size(); - for (unsigned j = 0; j < Tdim; ++j) nsize[j] = size[j]; - - Eigen::Matrix stress = this->stress_; - - Eigen::Matrix strain = this->strain_; - - particle_data.id = this->id(); - particle_data.mass = this->mass(); - particle_data.volume = this->volume(); - particle_data.pressure = - (state_variables_[mpm::ParticlePhase::Solid].find("pressure") != - state_variables_[mpm::ParticlePhase::Solid].end()) - ? state_variables_[mpm::ParticlePhase::Solid].at("pressure") - : 0.; - - particle_data.coord_x = coordinates[0]; - particle_data.coord_y = coordinates[1]; - particle_data.coord_z = coordinates[2]; - - particle_data.displacement_x = displacement[0]; - particle_data.displacement_y = displacement[1]; - particle_data.displacement_z = displacement[2]; - - particle_data.nsize_x = nsize[0]; - particle_data.nsize_y = nsize[1]; - particle_data.nsize_z = nsize[2]; - - particle_data.velocity_x = velocity[0]; - particle_data.velocity_y = velocity[1]; - particle_data.velocity_z = velocity[2]; - - particle_data.stress_xx = stress[0]; - particle_data.stress_yy = stress[1]; - particle_data.stress_zz = stress[2]; - particle_data.tau_xy = stress[3]; - particle_data.tau_yz = stress[4]; - particle_data.tau_xz = stress[5]; - - particle_data.strain_xx = strain[0]; - particle_data.strain_yy = strain[1]; - particle_data.strain_zz = strain[2]; - particle_data.gamma_xy = strain[3]; - particle_data.gamma_yz = strain[4]; - particle_data.gamma_xz = strain[5]; - - particle_data.epsilon_v = this->volumetric_strain_centroid_; - - particle_data.status = this->status(); - - particle_data.cell_id = this->cell_id(); - - particle_data.material_id = this->material_id(); - - // Write state variables - if (this->material() != nullptr) { - particle_data.nstate_vars = - state_variables_[mpm::ParticlePhase::Solid].size(); - if (state_variables_[mpm::ParticlePhase::Solid].size() > 20) - throw std::runtime_error("# of state variables cannot be more than 20"); - unsigned i = 0; - auto state_variables = (this->material())->state_variables(); - for (const auto& state_var : state_variables) { - particle_data.svars[i] = - state_variables_[mpm::ParticlePhase::Solid].at(state_var); - ++i; - } - } - - return particle_data; -} - // Initialise particle properties template void mpm::Particle::initialise() { diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 3ff94e086..9eae340cf 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -70,10 +70,6 @@ class ParticleBase { const HDF5Particle& particle, const std::shared_ptr>& material) = 0; - //! Retrun particle data as HDF5 - //! \retval particle HDF5 data of the particle - virtual HDF5Particle hdf5() const = 0; - //! Return particle data as HDF5 pointer //! \retval particle HDF5 pointer of the particle virtual std::shared_ptr hdf5_ptr() = 0; diff --git a/include/particles/particle_twophase.h b/include/particles/particle_twophase.h index 0185f28a1..c189dc5b8 100644 --- a/include/particles/particle_twophase.h +++ b/include/particles/particle_twophase.h @@ -60,10 +60,6 @@ class TwoPhaseParticle : public mpm::Particle { //! Initialise particle liquid phase on top of the regular solid phase void initialise() override; - //! Retrun particle twophase data as HDF5 - //! \retval particle HDF5 data of the particle - HDF5Particle hdf5() const override; - //! Return particle data as HDF5 pointer //! \retval particle HDF5 pointer of the particle std::shared_ptr hdf5_ptr() override; diff --git a/include/particles/particle_twophase.tcc b/include/particles/particle_twophase.tcc index 12b114158..bebdea798 100644 --- a/include/particles/particle_twophase.tcc +++ b/include/particles/particle_twophase.tcc @@ -31,124 +31,6 @@ mpm::TwoPhaseParticle::TwoPhaseParticle(Index id, const VectorDim& coord, console_ = std::make_unique(logger, mpm::stdout_sink); } -//! Return particle data in HDF5 format -template -// cppcheck-suppress * -mpm::HDF5Particle mpm::TwoPhaseParticle::hdf5() const { - // Derive from particle - // auto solid_particle_data = mpm::Particle::hdf5(); - mpm::HDF5ParticleTwoPhase particle_data; - // static_cast(particle_data) = solid_particle_data; - - Eigen::Vector3d coordinates; - coordinates.setZero(); - for (unsigned j = 0; j < Tdim; ++j) coordinates[j] = this->coordinates_[j]; - - Eigen::Vector3d displacement; - displacement.setZero(); - for (unsigned j = 0; j < Tdim; ++j) displacement[j] = this->displacement_[j]; - - Eigen::Vector3d velocity; - velocity.setZero(); - for (unsigned j = 0; j < Tdim; ++j) velocity[j] = this->velocity_[j]; - - // Particle local size - Eigen::Vector3d nsize; - nsize.setZero(); - Eigen::VectorXd size = this->natural_size(); - for (unsigned j = 0; j < Tdim; ++j) nsize[j] = size[j]; - - Eigen::Matrix stress = this->stress_; - - Eigen::Matrix strain = this->strain_; - - particle_data.id = this->id(); - particle_data.mass = this->mass(); - particle_data.volume = this->volume(); - particle_data.pressure = - (state_variables_[mpm::ParticlePhase::Solid].find("pressure") != - state_variables_[mpm::ParticlePhase::Solid].end()) - ? state_variables_[mpm::ParticlePhase::Solid].at("pressure") - : 0.; - - particle_data.coord_x = coordinates[0]; - particle_data.coord_y = coordinates[1]; - particle_data.coord_z = coordinates[2]; - - particle_data.displacement_x = displacement[0]; - particle_data.displacement_y = displacement[1]; - particle_data.displacement_z = displacement[2]; - - particle_data.nsize_x = nsize[0]; - particle_data.nsize_y = nsize[1]; - particle_data.nsize_z = nsize[2]; - - particle_data.velocity_x = velocity[0]; - particle_data.velocity_y = velocity[1]; - particle_data.velocity_z = velocity[2]; - - particle_data.stress_xx = stress[0]; - particle_data.stress_yy = stress[1]; - particle_data.stress_zz = stress[2]; - particle_data.tau_xy = stress[3]; - particle_data.tau_yz = stress[4]; - particle_data.tau_xz = stress[5]; - - particle_data.strain_xx = strain[0]; - particle_data.strain_yy = strain[1]; - particle_data.strain_zz = strain[2]; - particle_data.gamma_xy = strain[3]; - particle_data.gamma_yz = strain[4]; - particle_data.gamma_xz = strain[5]; - - particle_data.epsilon_v = this->volumetric_strain_centroid_; - - particle_data.status = this->status(); - - particle_data.cell_id = this->cell_id(); - - particle_data.material_id = this->material_id(); - - // Particle liquid mass - particle_data.liquid_mass = this->liquid_mass_; - - // Particle liquid velocity - Eigen::Vector3d liquid_velocity; - liquid_velocity.setZero(); - for (unsigned j = 0; j < Tdim; ++j) - liquid_velocity[j] = this->liquid_velocity_[j]; - - particle_data.liquid_velocity_x = liquid_velocity[0]; - particle_data.liquid_velocity_y = liquid_velocity[1]; - particle_data.liquid_velocity_z = liquid_velocity[2]; - - // Particle porosity and saturation - particle_data.porosity = this->porosity_; - particle_data.liquid_saturation = this->liquid_saturation_; - - // Particle liquid material id - particle_data.liquid_material_id = - this->material_id(mpm::ParticlePhase::Liquid); - - // Write state variables - if (this->material(mpm::ParticlePhase::Liquid) != nullptr) { - particle_data.nliquid_state_vars = - state_variables_[mpm::ParticlePhase::Liquid].size(); - if (state_variables_[mpm::ParticlePhase::Liquid].size() > 5) - throw std::runtime_error("# of state variables cannot be more than 5"); - unsigned i = 0; - auto state_variables = - (this->material(mpm::ParticlePhase::Liquid))->state_variables(); - for (const auto& state_var : state_variables) { - particle_data.liquid_svars[i] = - state_variables_[mpm::ParticlePhase::Liquid].at(state_var); - ++i; - } - } - - return particle_data; -} - //! Return particle data as HDF5 pointer template // cppcheck-suppress * diff --git a/tests/mpi_particle_test.cc b/tests/mpi_particle_test.cc index 4e8e7762b..5a919963e 100644 --- a/tests/mpi_particle_test.cc +++ b/tests/mpi_particle_test.cc @@ -289,11 +289,14 @@ TEST_CASE("MPI HDF5 Particle is checked", "[particle][mpi][hdf5]") { REQUIRE(particle->material_id() == h5_particle.material_id); // Write Particle HDF5 data - const auto h5_send = particle->hdf5(); + auto h5_send_ptr = + std::static_pointer_cast(particle->hdf5_ptr()); // Send MPI particle - MPI_Datatype particle_type = mpm::register_mpi_particle_type(h5_send); - MPI_Send(&h5_send, 1, particle_type, receiver, 0, MPI_COMM_WORLD); + MPI_Datatype particle_type = + mpm::register_mpi_particle_type(*h5_send_ptr); + MPI_Send(&(*h5_send_ptr), 1, particle_type, receiver, 0, + MPI_COMM_WORLD); mpm::deregister_mpi_particle_type(particle_type); } if (mpi_rank == receiver) { @@ -384,12 +387,13 @@ TEST_CASE("MPI HDF5 Particle is checked", "[particle][mpi][hdf5]") { REQUIRE(rparticle->material_id() == h5_particle.material_id); // Get Particle HDF5 data - const auto h5_received = rparticle->hdf5(); + auto h5_received = + std::static_pointer_cast(rparticle->hdf5_ptr()); // State variables - REQUIRE(h5_received.nstate_vars == h5_particle.nstate_vars); + REQUIRE(h5_received->nstate_vars == h5_particle.nstate_vars); // State variables for (unsigned i = 0; i < h5_particle.nstate_vars; ++i) - REQUIRE(h5_received.svars[i] == + REQUIRE(h5_received->svars[i] == Approx(h5_particle.svars[i]).epsilon(Tolerance)); } } diff --git a/tests/mpi_particle_twophase_test.cc b/tests/mpi_particle_twophase_test.cc index 54855b155..3130bb56d 100644 --- a/tests/mpi_particle_twophase_test.cc +++ b/tests/mpi_particle_twophase_test.cc @@ -363,14 +363,14 @@ TEST_CASE("MPI HDF5 TwoPhase Particle is checked", h5_particle.liquid_material_id); // Write Particle HDF5 data - auto h5_send = particle->hdf5(); - auto h5_twophase_send = - reinterpret_cast(&h5_send); + auto h5_twophase_send_ptr = + std::static_pointer_cast( + particle->hdf5_ptr()); // Send MPI particle MPI_Datatype particle_type = - mpm::register_mpi_particle_type(*h5_twophase_send); - MPI_Send(&(*h5_twophase_send), 1, particle_type, receiver, 0, + mpm::register_mpi_particle_type(*h5_twophase_send_ptr); + MPI_Send(&(*h5_twophase_send_ptr), 1, particle_type, receiver, 0, MPI_COMM_WORLD); mpm::deregister_mpi_particle_type(particle_type); } @@ -477,9 +477,9 @@ TEST_CASE("MPI HDF5 TwoPhase Particle is checked", REQUIRE(rparticle->material_id() == h5_particle.material_id); // Get Particle HDF5 data - auto h5_received = rparticle->hdf5(); auto h5_twophase_received = - reinterpret_cast(&h5_received); + std::static_pointer_cast( + rparticle->hdf5_ptr()); // State variables REQUIRE(h5_twophase_received->nstate_vars == h5_particle.nstate_vars); diff --git a/tests/particles/particle_test.cc b/tests/particles/particle_test.cc index fc533e26b..37d651c8f 100644 --- a/tests/particles/particle_test.cc +++ b/tests/particles/particle_test.cc @@ -378,61 +378,62 @@ TEST_CASE("Particle is checked for 1D case", "[particle][1D]") { REQUIRE(particle->material_id() == h5_particle.material_id); // Write Particle HDF5 data - const auto h5_test = particle->hdf5(); + auto h5_test = + std::static_pointer_cast(particle->hdf5_ptr()); - REQUIRE(h5_particle.id == h5_test.id); - REQUIRE(h5_particle.mass == h5_test.mass); + REQUIRE(h5_particle.id == h5_test->id); + REQUIRE(h5_particle.mass == h5_test->mass); - REQUIRE(h5_particle.coord_x == Approx(h5_test.coord_x).epsilon(Tolerance)); - REQUIRE(h5_particle.coord_y == Approx(h5_test.coord_y).epsilon(Tolerance)); - REQUIRE(h5_particle.coord_z == Approx(h5_test.coord_z).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_x == Approx(h5_test->coord_x).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_y == Approx(h5_test->coord_y).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_z == Approx(h5_test->coord_z).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_x == - Approx(h5_test.displacement_x).epsilon(Tolerance)); + Approx(h5_test->displacement_x).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_y == - Approx(h5_test.displacement_y).epsilon(Tolerance)); + Approx(h5_test->displacement_y).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_z == - Approx(h5_test.displacement_z).epsilon(Tolerance)); + Approx(h5_test->displacement_z).epsilon(Tolerance)); - REQUIRE(h5_particle.nsize_x == h5_test.nsize_x); - REQUIRE(h5_particle.nsize_y == h5_test.nsize_y); - REQUIRE(h5_particle.nsize_z == h5_test.nsize_z); + REQUIRE(h5_particle.nsize_x == h5_test->nsize_x); + REQUIRE(h5_particle.nsize_y == h5_test->nsize_y); + REQUIRE(h5_particle.nsize_z == h5_test->nsize_z); REQUIRE(h5_particle.velocity_x == - Approx(h5_test.velocity_x).epsilon(Tolerance)); + Approx(h5_test->velocity_x).epsilon(Tolerance)); REQUIRE(h5_particle.velocity_y == - Approx(h5_test.velocity_y).epsilon(Tolerance)); + Approx(h5_test->velocity_y).epsilon(Tolerance)); REQUIRE(h5_particle.velocity_z == - Approx(h5_test.velocity_z).epsilon(Tolerance)); + Approx(h5_test->velocity_z).epsilon(Tolerance)); REQUIRE(h5_particle.stress_xx == - Approx(h5_test.stress_xx).epsilon(Tolerance)); + Approx(h5_test->stress_xx).epsilon(Tolerance)); REQUIRE(h5_particle.stress_yy == - Approx(h5_test.stress_yy).epsilon(Tolerance)); + Approx(h5_test->stress_yy).epsilon(Tolerance)); REQUIRE(h5_particle.stress_zz == - Approx(h5_test.stress_zz).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_xy == Approx(h5_test.tau_xy).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_yz == Approx(h5_test.tau_yz).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_xz == Approx(h5_test.tau_xz).epsilon(Tolerance)); + Approx(h5_test->stress_zz).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_xy == Approx(h5_test->tau_xy).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_yz == Approx(h5_test->tau_yz).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_xz == Approx(h5_test->tau_xz).epsilon(Tolerance)); REQUIRE(h5_particle.strain_xx == - Approx(h5_test.strain_xx).epsilon(Tolerance)); + Approx(h5_test->strain_xx).epsilon(Tolerance)); REQUIRE(h5_particle.strain_yy == - Approx(h5_test.strain_yy).epsilon(Tolerance)); + Approx(h5_test->strain_yy).epsilon(Tolerance)); REQUIRE(h5_particle.strain_zz == - Approx(h5_test.strain_zz).epsilon(Tolerance)); + Approx(h5_test->strain_zz).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_xy == - Approx(h5_test.gamma_xy).epsilon(Tolerance)); + Approx(h5_test->gamma_xy).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_yz == - Approx(h5_test.gamma_yz).epsilon(Tolerance)); + Approx(h5_test->gamma_yz).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_xz == - Approx(h5_test.gamma_xz).epsilon(Tolerance)); + Approx(h5_test->gamma_xz).epsilon(Tolerance)); REQUIRE(h5_particle.epsilon_v == - Approx(h5_test.epsilon_v).epsilon(Tolerance)); - REQUIRE(h5_particle.status == h5_test.status); - REQUIRE(h5_particle.cell_id == h5_test.cell_id); - REQUIRE(h5_particle.material_id == h5_test.material_id); + Approx(h5_test->epsilon_v).epsilon(Tolerance)); + REQUIRE(h5_particle.status == h5_test->status); + REQUIRE(h5_particle.cell_id == h5_test->cell_id); + REQUIRE(h5_particle.material_id == h5_test->material_id); } } @@ -1522,61 +1523,62 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { REQUIRE(particle->material_id() == h5_particle.material_id); // Write Particle HDF5 data - const auto h5_test = particle->hdf5(); + auto h5_test = + std::static_pointer_cast(particle->hdf5_ptr()); - REQUIRE(h5_particle.id == h5_test.id); - REQUIRE(h5_particle.mass == h5_test.mass); + REQUIRE(h5_particle.id == h5_test->id); + REQUIRE(h5_particle.mass == h5_test->mass); - REQUIRE(h5_particle.coord_x == Approx(h5_test.coord_x).epsilon(Tolerance)); - REQUIRE(h5_particle.coord_y == Approx(h5_test.coord_y).epsilon(Tolerance)); - REQUIRE(h5_particle.coord_z == Approx(h5_test.coord_z).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_x == Approx(h5_test->coord_x).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_y == Approx(h5_test->coord_y).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_z == Approx(h5_test->coord_z).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_x == - Approx(h5_test.displacement_x).epsilon(Tolerance)); + Approx(h5_test->displacement_x).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_y == - Approx(h5_test.displacement_y).epsilon(Tolerance)); + Approx(h5_test->displacement_y).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_z == - Approx(h5_test.displacement_z).epsilon(Tolerance)); + Approx(h5_test->displacement_z).epsilon(Tolerance)); - REQUIRE(h5_particle.nsize_x == h5_test.nsize_x); - REQUIRE(h5_particle.nsize_y == h5_test.nsize_y); - REQUIRE(h5_particle.nsize_z == h5_test.nsize_z); + REQUIRE(h5_particle.nsize_x == h5_test->nsize_x); + REQUIRE(h5_particle.nsize_y == h5_test->nsize_y); + REQUIRE(h5_particle.nsize_z == h5_test->nsize_z); REQUIRE(h5_particle.velocity_x == - Approx(h5_test.velocity_x).epsilon(Tolerance)); + Approx(h5_test->velocity_x).epsilon(Tolerance)); REQUIRE(h5_particle.velocity_y == - Approx(h5_test.velocity_y).epsilon(Tolerance)); + Approx(h5_test->velocity_y).epsilon(Tolerance)); REQUIRE(h5_particle.velocity_z == - Approx(h5_test.velocity_z).epsilon(Tolerance)); + Approx(h5_test->velocity_z).epsilon(Tolerance)); REQUIRE(h5_particle.stress_xx == - Approx(h5_test.stress_xx).epsilon(Tolerance)); + Approx(h5_test->stress_xx).epsilon(Tolerance)); REQUIRE(h5_particle.stress_yy == - Approx(h5_test.stress_yy).epsilon(Tolerance)); + Approx(h5_test->stress_yy).epsilon(Tolerance)); REQUIRE(h5_particle.stress_zz == - Approx(h5_test.stress_zz).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_xy == Approx(h5_test.tau_xy).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_yz == Approx(h5_test.tau_yz).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_xz == Approx(h5_test.tau_xz).epsilon(Tolerance)); + Approx(h5_test->stress_zz).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_xy == Approx(h5_test->tau_xy).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_yz == Approx(h5_test->tau_yz).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_xz == Approx(h5_test->tau_xz).epsilon(Tolerance)); REQUIRE(h5_particle.strain_xx == - Approx(h5_test.strain_xx).epsilon(Tolerance)); + Approx(h5_test->strain_xx).epsilon(Tolerance)); REQUIRE(h5_particle.strain_yy == - Approx(h5_test.strain_yy).epsilon(Tolerance)); + Approx(h5_test->strain_yy).epsilon(Tolerance)); REQUIRE(h5_particle.strain_zz == - Approx(h5_test.strain_zz).epsilon(Tolerance)); + Approx(h5_test->strain_zz).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_xy == - Approx(h5_test.gamma_xy).epsilon(Tolerance)); + Approx(h5_test->gamma_xy).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_yz == - Approx(h5_test.gamma_yz).epsilon(Tolerance)); + Approx(h5_test->gamma_yz).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_xz == - Approx(h5_test.gamma_xz).epsilon(Tolerance)); + Approx(h5_test->gamma_xz).epsilon(Tolerance)); REQUIRE(h5_particle.epsilon_v == - Approx(h5_test.epsilon_v).epsilon(Tolerance)); - REQUIRE(h5_particle.status == h5_test.status); - REQUIRE(h5_particle.cell_id == h5_test.cell_id); - REQUIRE(h5_particle.material_id == h5_test.material_id); + Approx(h5_test->epsilon_v).epsilon(Tolerance)); + REQUIRE(h5_particle.status == h5_test->status); + REQUIRE(h5_particle.cell_id == h5_test->cell_id); + REQUIRE(h5_particle.material_id == h5_test->material_id); } // Check particle's material id maping to nodes @@ -2878,61 +2880,62 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { REQUIRE(particle->material_id() == h5_particle.material_id); // Write Particle HDF5 data - const auto h5_test = particle->hdf5(); + auto h5_test = + std::static_pointer_cast(particle->hdf5_ptr()); - REQUIRE(h5_particle.id == h5_test.id); - REQUIRE(h5_particle.mass == h5_test.mass); + REQUIRE(h5_particle.id == h5_test->id); + REQUIRE(h5_particle.mass == h5_test->mass); - REQUIRE(h5_particle.coord_x == Approx(h5_test.coord_x).epsilon(Tolerance)); - REQUIRE(h5_particle.coord_y == Approx(h5_test.coord_y).epsilon(Tolerance)); - REQUIRE(h5_particle.coord_z == Approx(h5_test.coord_z).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_x == Approx(h5_test->coord_x).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_y == Approx(h5_test->coord_y).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_z == Approx(h5_test->coord_z).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_x == - Approx(h5_test.displacement_x).epsilon(Tolerance)); + Approx(h5_test->displacement_x).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_y == - Approx(h5_test.displacement_y).epsilon(Tolerance)); + Approx(h5_test->displacement_y).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_z == - Approx(h5_test.displacement_z).epsilon(Tolerance)); + Approx(h5_test->displacement_z).epsilon(Tolerance)); - REQUIRE(h5_particle.nsize_x == h5_test.nsize_x); - REQUIRE(h5_particle.nsize_y == h5_test.nsize_y); - REQUIRE(h5_particle.nsize_z == h5_test.nsize_z); + REQUIRE(h5_particle.nsize_x == h5_test->nsize_x); + REQUIRE(h5_particle.nsize_y == h5_test->nsize_y); + REQUIRE(h5_particle.nsize_z == h5_test->nsize_z); REQUIRE(h5_particle.velocity_x == - Approx(h5_test.velocity_x).epsilon(Tolerance)); + Approx(h5_test->velocity_x).epsilon(Tolerance)); REQUIRE(h5_particle.velocity_y == - Approx(h5_test.velocity_y).epsilon(Tolerance)); + Approx(h5_test->velocity_y).epsilon(Tolerance)); REQUIRE(h5_particle.velocity_z == - Approx(h5_test.velocity_z).epsilon(Tolerance)); + Approx(h5_test->velocity_z).epsilon(Tolerance)); REQUIRE(h5_particle.stress_xx == - Approx(h5_test.stress_xx).epsilon(Tolerance)); + Approx(h5_test->stress_xx).epsilon(Tolerance)); REQUIRE(h5_particle.stress_yy == - Approx(h5_test.stress_yy).epsilon(Tolerance)); + Approx(h5_test->stress_yy).epsilon(Tolerance)); REQUIRE(h5_particle.stress_zz == - Approx(h5_test.stress_zz).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_xy == Approx(h5_test.tau_xy).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_yz == Approx(h5_test.tau_yz).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_xz == Approx(h5_test.tau_xz).epsilon(Tolerance)); + Approx(h5_test->stress_zz).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_xy == Approx(h5_test->tau_xy).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_yz == Approx(h5_test->tau_yz).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_xz == Approx(h5_test->tau_xz).epsilon(Tolerance)); REQUIRE(h5_particle.strain_xx == - Approx(h5_test.strain_xx).epsilon(Tolerance)); + Approx(h5_test->strain_xx).epsilon(Tolerance)); REQUIRE(h5_particle.strain_yy == - Approx(h5_test.strain_yy).epsilon(Tolerance)); + Approx(h5_test->strain_yy).epsilon(Tolerance)); REQUIRE(h5_particle.strain_zz == - Approx(h5_test.strain_zz).epsilon(Tolerance)); + Approx(h5_test->strain_zz).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_xy == - Approx(h5_test.gamma_xy).epsilon(Tolerance)); + Approx(h5_test->gamma_xy).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_yz == - Approx(h5_test.gamma_yz).epsilon(Tolerance)); + Approx(h5_test->gamma_yz).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_xz == - Approx(h5_test.gamma_xz).epsilon(Tolerance)); + Approx(h5_test->gamma_xz).epsilon(Tolerance)); REQUIRE(h5_particle.epsilon_v == - Approx(h5_test.epsilon_v).epsilon(Tolerance)); - REQUIRE(h5_particle.status == h5_test.status); - REQUIRE(h5_particle.cell_id == h5_test.cell_id); - REQUIRE(h5_particle.material_id == h5_test.material_id); + Approx(h5_test->epsilon_v).epsilon(Tolerance)); + REQUIRE(h5_particle.status == h5_test->status); + REQUIRE(h5_particle.cell_id == h5_test->cell_id); + REQUIRE(h5_particle.material_id == h5_test->material_id); } // Check particle's material id maping to nodes From 65d579eb2d356f0dfc7eb11ce13c99f0d455f4d0 Mon Sep 17 00:00:00 2001 From: Nanda Date: Thu, 20 Aug 2020 00:56:50 -0700 Subject: [PATCH 124/175] :construction: change initialise_particle input arguments --- include/mesh.tcc | 19 +++-- include/particles/particle.h | 6 +- include/particles/particle.tcc | 16 ++-- include/particles/particle_base.h | 28 +------ include/particles/particle_twophase.h | 5 +- include/particles/particle_twophase.tcc | 30 +++---- tests/mpi_particle_test.cc | 8 +- tests/mpi_particle_twophase_test.cc | 12 ++- .../solvers/mpm_explicit_twophase_usf_test.cc | 78 ++++++++++--------- .../solvers/mpm_explicit_twophase_usl_test.cc | 78 ++++++++++--------- 10 files changed, 140 insertions(+), 140 deletions(-) diff --git a/include/mesh.tcc b/include/mesh.tcc index 7785dff75..fc5f56524 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -771,7 +771,7 @@ void mpm::Mesh::transfer_halo_particles() { mpm::deregister_mpi_particle_type(particle_type); // Iterate through n number of received particles - for (const auto& rparticle : recv_particles) { + for (auto& rparticle : recv_particles) { mpm::Index id = 0; // Initial particle coordinates Eigen::Matrix pcoordinates; @@ -781,9 +781,10 @@ void mpm::Mesh::transfer_halo_particles() { auto received_particle = std::make_shared>(id, pcoordinates); // Get material - auto material = materials_.at(rparticle.material_id); + std::vector>> materials; + materials.emplace_back(materials_.at(rparticle.material_id)); // Reinitialise particle from HDF5 data - received_particle->initialise_particle(rparticle, material); + received_particle->initialise_particle(rparticle, materials); // Add particle to mesh this->add_particle(received_particle, true); @@ -883,7 +884,7 @@ void mpm::Mesh::transfer_nonrank_particles( mpm::deregister_mpi_particle_type(particle_type); // Iterate through n number of received particles - for (const auto& rparticle : recv_particles) { + for (auto& rparticle : recv_particles) { mpm::Index id = 0; // Initial particle coordinates Eigen::Matrix pcoordinates; @@ -893,9 +894,10 @@ void mpm::Mesh::transfer_nonrank_particles( auto received_particle = std::make_shared>(id, pcoordinates); // Get material - auto material = materials_.at(rparticle.material_id); + std::vector>> materials; + materials.emplace_back(materials_.at(rparticle.material_id)); // Reinitialise particle from HDF5 data - received_particle->initialise_particle(rparticle, material); + received_particle->initialise_particle(rparticle, materials); // Add particle to mesh this->add_particle(received_particle, true); @@ -1469,9 +1471,10 @@ bool mpm::Mesh::read_particles_hdf5(unsigned phase, if (i < nrecords) { HDF5Particle particle = dst_buf[i]; // Get particle's material from list of materials - auto material = materials_.at(particle.material_id); + std::vector>> materials; + materials.emplace_back(materials_.at(particle.material_id)); // Initialise particle with HDF5 data - (*pitr)->initialise_particle(particle, material); + (*pitr)->initialise_particle(particle, materials); // Add particle to map map_particles_.insert(particle.id, *pitr); particles.add(*pitr); diff --git a/include/particles/particle.h b/include/particles/particle.h index f67198df6..9a4d84be5 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -49,15 +49,15 @@ class Particle : public ParticleBase { //! Initialise particle from HDF5 data //! \param[in] particle HDF5 data of particle //! \retval status Status of reading HDF5 particle - bool initialise_particle(const HDF5Particle& particle) override; + bool initialise_particle(HDF5Particle& particle) override; //! Initialise particle HDF5 data and material //! \param[in] particle HDF5 data of particle //! \param[in] material Material associated with the particle //! \retval status Status of reading HDF5 particle virtual bool initialise_particle( - const HDF5Particle& particle, - const std::shared_ptr>& material) override; + HDF5Particle& particle, + const std::vector>>& materials) override; //! Return particle data as HDF5 pointer //! \retval particle HDF5 pointer of the particle diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index de0f23eb8..decabf937 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -32,7 +32,7 @@ mpm::Particle::Particle(Index id, const VectorDim& coord, bool status) //! Initialise particle data from HDF5 template -bool mpm::Particle::initialise_particle(const HDF5Particle& particle) { +bool mpm::Particle::initialise_particle(HDF5Particle& particle) { // Assign id this->id_ = particle.id; @@ -105,13 +105,17 @@ bool mpm::Particle::initialise_particle(const HDF5Particle& particle) { //! Initialise particle data from HDF5 template bool mpm::Particle::initialise_particle( - const HDF5Particle& particle, - const std::shared_ptr>& material) { + HDF5Particle& particle, + const std::vector>>& materials) { bool status = this->initialise_particle(particle); - if (material != nullptr) { - if (this->material_id() == material->id() || + + assert(materials.size() == 1); + + if (materials.at(mpm::ParticlePhase::Solid) != nullptr) { + if (this->material_id() == materials.at(mpm::ParticlePhase::Solid)->id() || this->material_id() == std::numeric_limits::max()) { - bool assign_mat = this->assign_material(material); + bool assign_mat = + this->assign_material(materials.at(mpm::ParticlePhase::Solid)); if (!assign_mat) throw std::runtime_error("Material assignment failed"); // Reinitialize state variables auto mat_state_vars = (this->material())->initialise_state_variables(); diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 9eae340cf..4cd52e3a1 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -60,15 +60,15 @@ class ParticleBase { //! Initialise particle HDF5 data //! \param[in] particle HDF5 data of particle //! \retval status Status of reading HDF5 particle - virtual bool initialise_particle(const HDF5Particle& particle) = 0; + virtual bool initialise_particle(HDF5Particle& particle) = 0; //! Initialise particle HDF5 data and material //! \param[in] particle HDF5 data of particle //! \param[in] material Material associated with the particle //! \retval status Status of reading HDF5 particle virtual bool initialise_particle( - const HDF5Particle& particle, - const std::shared_ptr>& material) = 0; + HDF5Particle& particle, + const std::vector>>& materials) = 0; //! Return particle data as HDF5 pointer //! \retval particle HDF5 pointer of the particle @@ -323,28 +323,6 @@ class ParticleBase { virtual std::vector neighbours() const = 0; //! TwoPhase functions-------------------------------------------------------- - //! Initialise particle HDF5 data for twophase - //! \param[in] particle HDF5 data of twophase particle - //! \retval status Status of reading HDF5 twophase particle - virtual bool initialise_particle(const HDF5ParticleTwoPhase& particle) { - throw std::runtime_error( - "Calling the base class function (initialise_particle) in " - "ParticleBase:: illegal operation!"); - }; - - //! Initialise particle HDF5 data and material - //! \param[in] particle HDF5 data of particle - //! \param[in] material Material associated with the particle - //! \retval status Status of reading HDF5 particle - virtual bool initialise_particle( - HDF5Particle& particle, - const std::shared_ptr>& solid_material, - const std::shared_ptr>& liquid_material) { - throw std::runtime_error( - "Calling the base class function (initialise_particle) in " - "ParticleBase:: illegal operation!"); - }; - //! Update porosity //! \param[in] dt Analysis time step virtual void update_porosity(double dt) { diff --git a/include/particles/particle_twophase.h b/include/particles/particle_twophase.h index c189dc5b8..83675ac07 100644 --- a/include/particles/particle_twophase.h +++ b/include/particles/particle_twophase.h @@ -45,7 +45,7 @@ class TwoPhaseParticle : public mpm::Particle { //! Initialise particle from HDF5 data //! \param[in] particle HDF5 data of particle //! \retval status Status of reading HDF5 particle - bool initialise_particle(const HDF5ParticleTwoPhase& particle) override; + bool initialise_particle(HDF5Particle& particle) override; //! Initialise particle HDF5 data and material //! \param[in] particle HDF5 data of particle @@ -54,8 +54,7 @@ class TwoPhaseParticle : public mpm::Particle { //! \retval status Status of reading HDF5 particle bool initialise_particle( HDF5Particle& particle, - const std::shared_ptr>& solid_material, - const std::shared_ptr>& liquid_material) override; + const std::vector>>& materials) override; //! Initialise particle liquid phase on top of the regular solid phase void initialise() override; diff --git a/include/particles/particle_twophase.tcc b/include/particles/particle_twophase.tcc index bebdea798..b85b22e94 100644 --- a/include/particles/particle_twophase.tcc +++ b/include/particles/particle_twophase.tcc @@ -164,32 +164,33 @@ std::shared_ptr mpm::TwoPhaseParticle::hdf5_ptr() { //! Initialise particle data from HDF5 template -bool mpm::TwoPhaseParticle::initialise_particle( - const HDF5ParticleTwoPhase& particle) { +bool mpm::TwoPhaseParticle::initialise_particle(HDF5Particle& particle) { // Initialise solid phase - mpm::HDF5Particle solid_particle = particle; - bool status = mpm::Particle::initialise_particle(solid_particle); + bool status = mpm::Particle::initialise_particle(particle); + auto twophase_particle = reinterpret_cast(&particle); // Liquid mass - this->liquid_mass_ = particle.liquid_mass; + this->liquid_mass_ = twophase_particle->liquid_mass; // Liquid mass Density - this->liquid_mass_density_ = particle.liquid_mass / particle.volume; + this->liquid_mass_density_ = twophase_particle->liquid_mass / particle.volume; // Liquid velocity Eigen::Vector3d liquid_velocity; - liquid_velocity << particle.liquid_velocity_x, particle.liquid_velocity_y, - particle.liquid_velocity_z; + liquid_velocity << twophase_particle->liquid_velocity_x, + twophase_particle->liquid_velocity_y, + twophase_particle->liquid_velocity_z; // Initialise velocity for (unsigned i = 0; i < Tdim; ++i) this->liquid_velocity_(i) = liquid_velocity(i); // Particle porosity and saturation - this->porosity_ = particle.porosity; - this->liquid_saturation_ = particle.liquid_saturation; + this->porosity_ = twophase_particle->porosity; + this->liquid_saturation_ = twophase_particle->liquid_saturation; this->assign_permeability(); // Liquid material id - this->material_id_[mpm::ParticlePhase::Liquid] = particle.liquid_material_id; + this->material_id_[mpm::ParticlePhase::Liquid] = + twophase_particle->liquid_material_id; return status; } @@ -198,12 +199,14 @@ bool mpm::TwoPhaseParticle::initialise_particle( template bool mpm::TwoPhaseParticle::initialise_particle( HDF5Particle& particle, - const std::shared_ptr>& solid_material, - const std::shared_ptr>& liquid_material) { + const std::vector>>& materials) { auto twophase_particle = reinterpret_cast(&particle); bool status = this->initialise_particle(*twophase_particle); + assert(materials.size() == 2); + // Solid Phase + const auto& solid_material = materials.at(mpm::ParticlePhase::Solid); if (solid_material != nullptr) { if (this->material_id(mpm::ParticlePhase::Solid) == solid_material->id() || this->material_id(mpm::ParticlePhase::Solid) == @@ -231,6 +234,7 @@ bool mpm::TwoPhaseParticle::initialise_particle( } // Fluid Phase + const auto& liquid_material = materials.at(mpm::ParticlePhase::Liquid); if (liquid_material != nullptr) { if (this->material_id(mpm::ParticlePhase::Liquid) == liquid_material->id() || diff --git a/tests/mpi_particle_test.cc b/tests/mpi_particle_test.cc index 5a919963e..d1bfbdaf6 100644 --- a/tests/mpi_particle_test.cc +++ b/tests/mpi_particle_test.cc @@ -224,9 +224,11 @@ TEST_CASE("MPI HDF5 Particle is checked", "[particle][mpi][hdf5]") { auto material = Factory, unsigned, const Json&>::instance() ->create("LinearElastic3D", std::move(mid), jmaterial); + std::vector>> materials; + materials.emplace_back(material); // Reinitialise particle from HDF5 data - REQUIRE(particle->initialise_particle(h5_particle, material) == true); + REQUIRE(particle->initialise_particle(h5_particle, materials) == true); // Check particle id REQUIRE(particle->id() == h5_particle.id); @@ -322,9 +324,11 @@ TEST_CASE("MPI HDF5 Particle is checked", "[particle][mpi][hdf5]") { auto material = Factory, unsigned, const Json&>::instance() ->create("LinearElastic3D", std::move(mid), jmaterial); + std::vector>> materials; + materials.emplace_back(material); // Reinitialise particle from HDF5 data - REQUIRE(rparticle->initialise_particle(received, material) == true); + REQUIRE(rparticle->initialise_particle(received, materials) == true); // Check particle id REQUIRE(rparticle->id() == h5_particle.id); diff --git a/tests/mpi_particle_twophase_test.cc b/tests/mpi_particle_twophase_test.cc index 3130bb56d..54e9b2313 100644 --- a/tests/mpi_particle_twophase_test.cc +++ b/tests/mpi_particle_twophase_test.cc @@ -280,10 +280,12 @@ TEST_CASE("MPI HDF5 TwoPhase Particle is checked", Factory, unsigned, const Json&>::instance() ->create("Newtonian3D", std::move(liquid_mid), jliquid_material); + std::vector>> materials; + materials.emplace_back(solid_material); + materials.emplace_back(liquid_material); // Reinitialise particle from HDF5 data - REQUIRE(particle->initialise_particle(h5_particle, solid_material, - liquid_material) == true); + REQUIRE(particle->initialise_particle(h5_particle, materials) == true); // Check particle id REQUIRE(particle->id() == h5_particle.id); @@ -411,10 +413,12 @@ TEST_CASE("MPI HDF5 TwoPhase Particle is checked", Factory, unsigned, const Json&>::instance() ->create("Newtonian3D", std::move(liquid_mid), jliquid_material); + std::vector>> materials; + materials.emplace_back(solid_material); + materials.emplace_back(liquid_material); // Reinitialise particle from HDF5 data - REQUIRE(rparticle->initialise_particle(received, solid_material, - liquid_material) == true); + REQUIRE(rparticle->initialise_particle(received, materials) == true); // Check particle id REQUIRE(rparticle->id() == h5_particle.id); diff --git a/tests/solvers/mpm_explicit_twophase_usf_test.cc b/tests/solvers/mpm_explicit_twophase_usf_test.cc index 1a3fc92bd..9b25c85aa 100644 --- a/tests/solvers/mpm_explicit_twophase_usf_test.cc +++ b/tests/solvers/mpm_explicit_twophase_usf_test.cc @@ -69,25 +69,26 @@ TEST_CASE("MPM 2D Explicit TwoPhase implementation is checked", REQUIRE(mpm->checkpoint_resume() == false); } - SECTION("Check resume") { - // Write JSON file - const std::string fname = "mpm-explicit-twophase-usf"; - const std::string analysis = "MPMExplicitTwoPhase2D"; - const std::string stress_update = "usf"; - bool resume = true; - REQUIRE(mpm_test::write_json_twophase(2, resume, analysis, stress_update, - fname) == true); - - // Create an IO object - auto io = std::make_unique(argc, argv); - // Run explicit MPM - auto mpm = std::make_unique>(std::move(io)); - - // Test check point restart - REQUIRE(mpm->checkpoint_resume() == true); - // Solve - REQUIRE(mpm->solve() == true); - } + // SECTION("Check resume") { + // // Write JSON file + // const std::string fname = "mpm-explicit-twophase-usf"; + // const std::string analysis = "MPMExplicitTwoPhase2D"; + // const std::string stress_update = "usf"; + // bool resume = true; + // REQUIRE(mpm_test::write_json_twophase(2, resume, analysis, stress_update, + // fname) == true); + + // // Create an IO object + // auto io = std::make_unique(argc, argv); + // // Run explicit MPM + // auto mpm = + // std::make_unique>(std::move(io)); + + // // Test check point restart + // REQUIRE(mpm->checkpoint_resume() == true); + // // Solve + // REQUIRE(mpm->solve() == true); + // } SECTION("Check pressure smoothing") { // Create an IO object @@ -159,25 +160,26 @@ TEST_CASE("MPM 3D Explicit TwoPhase implementation is checked", REQUIRE(mpm->checkpoint_resume() == false); } - SECTION("Check resume") { - // Write JSON file - const std::string fname = "mpm-explicit-twophase-usf"; - const std::string analysis = "MPMExplicitTwoPhase3D"; - const std::string stress_update = "usf"; - bool resume = true; - REQUIRE(mpm_test::write_json_twophase(3, resume, analysis, stress_update, - fname) == true); - - // Create an IO object - auto io = std::make_unique(argc, argv); - // Run explicit MPM - auto mpm = std::make_unique>(std::move(io)); - - // Test check point restart - REQUIRE(mpm->checkpoint_resume() == true); - // Solve - REQUIRE(mpm->solve() == true); - } + // SECTION("Check resume") { + // // Write JSON file + // const std::string fname = "mpm-explicit-twophase-usf"; + // const std::string analysis = "MPMExplicitTwoPhase3D"; + // const std::string stress_update = "usf"; + // bool resume = true; + // REQUIRE(mpm_test::write_json_twophase(3, resume, analysis, stress_update, + // fname) == true); + + // // Create an IO object + // auto io = std::make_unique(argc, argv); + // // Run explicit MPM + // auto mpm = + // std::make_unique>(std::move(io)); + + // // Test check point restart + // REQUIRE(mpm->checkpoint_resume() == true); + // // Solve + // REQUIRE(mpm->solve() == true); + // } SECTION("Check pressure smoothing") { // Create an IO object diff --git a/tests/solvers/mpm_explicit_twophase_usl_test.cc b/tests/solvers/mpm_explicit_twophase_usl_test.cc index 38ceec438..94b52732c 100644 --- a/tests/solvers/mpm_explicit_twophase_usl_test.cc +++ b/tests/solvers/mpm_explicit_twophase_usl_test.cc @@ -69,25 +69,26 @@ TEST_CASE("MPM 2D Explicit USL TwoPhase implementation is checked", REQUIRE(mpm->checkpoint_resume() == false); } - SECTION("Check resume") { - // Write JSON file - const std::string fname = "mpm-explicit-twophase-usl"; - const std::string analysis = "MPMExplicitTwoPhase2D"; - const std::string stress_update = "usl"; - bool resume = true; - REQUIRE(mpm_test::write_json_twophase(2, resume, analysis, stress_update, - fname) == true); - - // Create an IO object - auto io = std::make_unique(argc, argv); - // Run explicit MPM - auto mpm = std::make_unique>(std::move(io)); - - // Test check point restart - REQUIRE(mpm->checkpoint_resume() == true); - // Solve - REQUIRE(mpm->solve() == true); - } + // SECTION("Check resume") { + // // Write JSON file + // const std::string fname = "mpm-explicit-twophase-usl"; + // const std::string analysis = "MPMExplicitTwoPhase2D"; + // const std::string stress_update = "usl"; + // bool resume = true; + // REQUIRE(mpm_test::write_json_twophase(2, resume, analysis, stress_update, + // fname) == true); + + // // Create an IO object + // auto io = std::make_unique(argc, argv); + // // Run explicit MPM + // auto mpm = + // std::make_unique>(std::move(io)); + + // // Test check point restart + // REQUIRE(mpm->checkpoint_resume() == true); + // // Solve + // REQUIRE(mpm->solve() == true); + // } SECTION("Check pressure smoothing") { // Create an IO object @@ -159,25 +160,26 @@ TEST_CASE("MPM 3D Explicit USL TwoPhase implementation is checked", REQUIRE(mpm->checkpoint_resume() == false); } - SECTION("Check resume") { - // Write JSON file - const std::string fname = "mpm-explicit-twophase-usl"; - const std::string analysis = "MPMExplicitTwoPhase3D"; - const std::string stress_update = "usl"; - bool resume = true; - REQUIRE(mpm_test::write_json_twophase(3, resume, analysis, stress_update, - fname) == true); - - // Create an IO object - auto io = std::make_unique(argc, argv); - // Run explicit MPM - auto mpm = std::make_unique>(std::move(io)); - - // Test check point restart - REQUIRE(mpm->checkpoint_resume() == true); - // Solve - REQUIRE(mpm->solve() == true); - } + // SECTION("Check resume") { + // // Write JSON file + // const std::string fname = "mpm-explicit-twophase-usl"; + // const std::string analysis = "MPMExplicitTwoPhase3D"; + // const std::string stress_update = "usl"; + // bool resume = true; + // REQUIRE(mpm_test::write_json_twophase(3, resume, analysis, stress_update, + // fname) == true); + + // // Create an IO object + // auto io = std::make_unique(argc, argv); + // // Run explicit MPM + // auto mpm = + // std::make_unique>(std::move(io)); + + // // Test check point restart + // REQUIRE(mpm->checkpoint_resume() == true); + // // Solve + // REQUIRE(mpm->solve() == true); + // } SECTION("Check pressure smoothing") { // Create an IO object From 174c5d00ce5e2d0806556c357aa7f6046012f6a2 Mon Sep 17 00:00:00 2001 From: Nanda Date: Thu, 20 Aug 2020 10:07:51 -0700 Subject: [PATCH 125/175] :construction: :wrench: :dart: modify two phase explicit solver and its testings for mpm_scheme --- include/solvers/mpm_explicit_twophase.tcc | 41 +++++-------------- tests/include/write_mesh_particles.h | 2 +- tests/include/write_mesh_particles_unitcell.h | 2 +- tests/io/write_mesh_particles.cc | 9 ++-- tests/io/write_mesh_particles_unitcell.cc | 8 ++-- .../solvers/mpm_explicit_twophase_usf_test.cc | 34 +++++++-------- ...mpm_explicit_twophase_usf_unitcell_test.cc | 26 ++++++------ .../solvers/mpm_explicit_twophase_usl_test.cc | 34 +++++++-------- ...mpm_explicit_twophase_usl_unitcell_test.cc | 26 ++++++------ 9 files changed, 81 insertions(+), 101 deletions(-) diff --git a/include/solvers/mpm_explicit_twophase.tcc b/include/solvers/mpm_explicit_twophase.tcc index 4a14a1e0e..6922e8e72 100644 --- a/include/solvers/mpm_explicit_twophase.tcc +++ b/include/solvers/mpm_explicit_twophase.tcc @@ -82,32 +82,16 @@ bool mpm::MPMExplicitTwoPhase::solve() { } // Initialise material - bool mat_status = this->initialise_materials(); - if (!mat_status) { - status = false; - throw std::runtime_error("Initialisation of materials failed"); - } + this->initialise_materials(); // Initialise mesh - bool mesh_status = this->initialise_mesh(); - if (!mesh_status) { - status = false; - throw std::runtime_error("Initialisation of mesh failed"); - } + this->initialise_mesh(); // Initialise particles - bool particle_status = this->initialise_particles(); - if (!particle_status) { - status = false; - throw std::runtime_error("Initialisation of particles failed"); - } + this->initialise_particles(); // Initialise loading conditions - bool loading_status = this->initialise_loads(); - if (!loading_status) { - status = false; - throw std::runtime_error("Initialisation of loading failed"); - } + this->initialise_loads(); // Assign porosity mesh_->iterate_over_particles(std::bind( @@ -231,8 +215,7 @@ bool mpm::MPMExplicitTwoPhase::solve() { std::bind(&mpm::NodeBase::status, std::placeholders::_1)); // Update stress first - if (this->stress_update_ == mpm::StressUpdate::USF) - this->compute_stress_strain(); + if (this->stress_update_ == "usf") this->compute_stress_strain(); // Spawn a task for external force #pragma omp parallel sections @@ -340,8 +323,7 @@ bool mpm::MPMExplicitTwoPhase::solve() { mesh_->apply_particle_velocity_constraints(); // Update Stress Last - if (this->stress_update_ == mpm::StressUpdate::USL) - this->compute_stress_strain(); + if (this->stress_update_ == "usl") this->compute_stress_strain(); // Locate particles auto unlocatable_particles = mesh_->locate_particles_mesh(); @@ -373,12 +355,11 @@ bool mpm::MPMExplicitTwoPhase::solve() { } } auto solver_end = std::chrono::steady_clock::now(); - console_->info( - "Rank {}, Explicit {} solver duration: {} ms", mpi_rank, - (this->stress_update_ == mpm::StressUpdate::USL ? "USL" : "USF"), - std::chrono::duration_cast(solver_end - - solver_begin) - .count()); + console_->info("Rank {}, Explicit {} solver duration: {} ms", mpi_rank, + (this->stress_update_ == "usl" ? "USL" : "USF"), + std::chrono::duration_cast( + solver_end - solver_begin) + .count()); return status; } \ No newline at end of file diff --git a/tests/include/write_mesh_particles.h b/tests/include/write_mesh_particles.h index f4b1b707a..4457abb60 100644 --- a/tests/include/write_mesh_particles.h +++ b/tests/include/write_mesh_particles.h @@ -10,7 +10,7 @@ bool write_json(unsigned dim, bool resume, const std::string& analysis, // Write JSON Configuration file for twophase bool write_json_twophase(unsigned dim, bool resume, const std::string& analysis, - const std::string& stress_update, + const std::string& mpm_scheme, const std::string& file_name); // Write JSON Entity Set diff --git a/tests/include/write_mesh_particles_unitcell.h b/tests/include/write_mesh_particles_unitcell.h index 85ddd7824..677e05c7d 100644 --- a/tests/include/write_mesh_particles_unitcell.h +++ b/tests/include/write_mesh_particles_unitcell.h @@ -11,7 +11,7 @@ bool write_json_unitcell(unsigned dim, const std::string& analysis, // Write JSON Configuration file for two-phase bool write_json_unitcell_twophase(unsigned dim, const std::string& analysis, - const std::string& stress_update, + const std::string& mpm_scheme, const std::string& file_name); // Write Mesh file in 2D diff --git a/tests/io/write_mesh_particles.cc b/tests/io/write_mesh_particles.cc index 9d5711aad..c7f5daeec 100644 --- a/tests/io/write_mesh_particles.cc +++ b/tests/io/write_mesh_particles.cc @@ -4,8 +4,7 @@ namespace mpm_test { // Write JSON Configuration file bool write_json(unsigned dim, bool resume, const std::string& analysis, - const std::string& stress_update, - const std::string& file_name) { + const std::string& mpm_scheme, const std::string& file_name) { // Make json object with input files // 2D std::string dimension = "2d"; @@ -86,7 +85,7 @@ bool write_json(unsigned dim, bool resume, const std::string& analysis, {"fxvalues", fxvalues}}}}, {"analysis", {{"type", analysis}, - {"stress_update", stress_update}, + {"mpm_scheme", mpm_scheme}, {"locate_particles", true}, {"dt", 0.001}, {"uuid", file_name + "-" + dimension}, @@ -115,7 +114,7 @@ bool write_json(unsigned dim, bool resume, const std::string& analysis, // Write JSON Configuration file for twophase bool write_json_twophase(unsigned dim, bool resume, const std::string& analysis, - const std::string& stress_update, + const std::string& mpm_scheme, const std::string& file_name) { // Make json object with input files // 2D @@ -213,7 +212,7 @@ bool write_json_twophase(unsigned dim, bool resume, const std::string& analysis, {"fxvalues", fxvalues}}}}, {"analysis", {{"type", analysis}, - {"stress_update", stress_update}, + {"mpm_scheme", mpm_scheme}, {"locate_particles", true}, {"dt", 0.0001}, {"uuid", file_name + "-" + dimension}, diff --git a/tests/io/write_mesh_particles_unitcell.cc b/tests/io/write_mesh_particles_unitcell.cc index a875aa875..c09acec6b 100644 --- a/tests/io/write_mesh_particles_unitcell.cc +++ b/tests/io/write_mesh_particles_unitcell.cc @@ -4,7 +4,7 @@ namespace mpm_test { // Write JSON Configuration file bool write_json_unitcell(unsigned dim, const std::string& analysis, - const std::string& stress_update, + const std::string& mpm_scheme, const std::string& file_name) { // Make json object with input files // 2D @@ -87,7 +87,7 @@ bool write_json_unitcell(unsigned dim, const std::string& analysis, {"fxvalues", fxvalues}}}}, {"analysis", {{"type", analysis}, - {"stress_update", stress_update}, + {"mpm_scheme", mpm_scheme}, {"locate_particles", true}, {"dt", 0.001}, {"nsteps", 10}, @@ -113,7 +113,7 @@ bool write_json_unitcell(unsigned dim, const std::string& analysis, // Write JSON Configuration file for two-phase bool write_json_unitcell_twophase(unsigned dim, const std::string& analysis, - const std::string& stress_update, + const std::string& mpm_scheme, const std::string& file_name) { // Make json object with input files // 2D @@ -212,7 +212,7 @@ bool write_json_unitcell_twophase(unsigned dim, const std::string& analysis, {"fxvalues", fxvalues}}}}, {"analysis", {{"type", analysis}, - {"stress_update", stress_update}, + {"mpm_scheme", mpm_scheme}, {"locate_particles", true}, {"dt", 0.0001}, {"nsteps", 10}, diff --git a/tests/solvers/mpm_explicit_twophase_usf_test.cc b/tests/solvers/mpm_explicit_twophase_usf_test.cc index 9b25c85aa..c46565544 100644 --- a/tests/solvers/mpm_explicit_twophase_usf_test.cc +++ b/tests/solvers/mpm_explicit_twophase_usf_test.cc @@ -16,9 +16,9 @@ TEST_CASE("MPM 2D Explicit TwoPhase implementation is checked", // Write JSON file const std::string fname = "mpm-explicit-twophase-usf"; const std::string analysis = "MPMExplicitTwoPhase2D"; - const std::string stress_update = "usf"; + const std::string mpm_scheme = "usf"; bool resume = false; - REQUIRE(mpm_test::write_json_twophase(2, resume, analysis, stress_update, + REQUIRE(mpm_test::write_json_twophase(2, resume, analysis, mpm_scheme, fname) == true); // Write JSON Entity Sets file @@ -45,17 +45,17 @@ TEST_CASE("MPM 2D Explicit TwoPhase implementation is checked", auto mpm = std::make_unique>(std::move(io)); // Initialise materials - REQUIRE(mpm->initialise_materials() == true); + REQUIRE_NOTHROW(mpm->initialise_materials()); // Initialise mesh - REQUIRE(mpm->initialise_mesh() == true); + REQUIRE_NOTHROW(mpm->initialise_mesh()); // Initialise particles - REQUIRE(mpm->initialise_particles() == true); + REQUIRE_NOTHROW(mpm->initialise_particles()); // Initialise external loading - REQUIRE(mpm->initialise_loads() == true); + REQUIRE_NOTHROW(mpm->initialise_loads()); // Renitialise materials - REQUIRE(mpm->initialise_materials() == false); + REQUIRE_THROWS(mpm->initialise_materials()); } SECTION("Check solver") { @@ -73,9 +73,9 @@ TEST_CASE("MPM 2D Explicit TwoPhase implementation is checked", // // Write JSON file // const std::string fname = "mpm-explicit-twophase-usf"; // const std::string analysis = "MPMExplicitTwoPhase2D"; - // const std::string stress_update = "usf"; + // const std::string mpm_scheme = "usf"; // bool resume = true; - // REQUIRE(mpm_test::write_json_twophase(2, resume, analysis, stress_update, + // REQUIRE(mpm_test::write_json_twophase(2, resume, analysis, mpm_scheme, // fname) == true); // // Create an IO object @@ -110,9 +110,9 @@ TEST_CASE("MPM 3D Explicit TwoPhase implementation is checked", // Write JSON file const std::string fname = "mpm-explicit-twophase-usf"; const std::string analysis = "MPMExplicitTwoPhase3D"; - const std::string stress_update = "usf"; + const std::string mpm_scheme = "usf"; const bool resume = false; - REQUIRE(mpm_test::write_json_twophase(3, resume, analysis, stress_update, + REQUIRE(mpm_test::write_json_twophase(3, resume, analysis, mpm_scheme, fname) == true); // Write JSON Entity Sets file @@ -139,14 +139,14 @@ TEST_CASE("MPM 3D Explicit TwoPhase implementation is checked", auto mpm = std::make_unique>(std::move(io)); // Initialise materials - REQUIRE(mpm->initialise_materials() == true); + REQUIRE_NOTHROW(mpm->initialise_materials()); // Initialise mesh - REQUIRE(mpm->initialise_mesh() == true); + REQUIRE_NOTHROW(mpm->initialise_mesh()); // Initialise particles - REQUIRE(mpm->initialise_particles() == true); + REQUIRE_NOTHROW(mpm->initialise_particles()); // Renitialise materials - REQUIRE(mpm->initialise_materials() == false); + REQUIRE_THROWS(mpm->initialise_materials()); } SECTION("Check solver") { @@ -164,9 +164,9 @@ TEST_CASE("MPM 3D Explicit TwoPhase implementation is checked", // // Write JSON file // const std::string fname = "mpm-explicit-twophase-usf"; // const std::string analysis = "MPMExplicitTwoPhase3D"; - // const std::string stress_update = "usf"; + // const std::string mpm_scheme = "usf"; // bool resume = true; - // REQUIRE(mpm_test::write_json_twophase(3, resume, analysis, stress_update, + // REQUIRE(mpm_test::write_json_twophase(3, resume, analysis, mpm_scheme, // fname) == true); // // Create an IO object diff --git a/tests/solvers/mpm_explicit_twophase_usf_unitcell_test.cc b/tests/solvers/mpm_explicit_twophase_usf_unitcell_test.cc index 690c60828..57c3252b8 100644 --- a/tests/solvers/mpm_explicit_twophase_usf_unitcell_test.cc +++ b/tests/solvers/mpm_explicit_twophase_usf_unitcell_test.cc @@ -16,8 +16,8 @@ TEST_CASE("MPM 2D Explicit TwoPhase USF implementation is checked in unitcells", // Write JSON file const std::string fname = "mpm-explicit-twophase-usf"; const std::string analysis = "MPMExplicitTwoPhase2D"; - const std::string stress_update = "usf"; - REQUIRE(mpm_test::write_json_unitcell_twophase(2, analysis, stress_update, + const std::string mpm_scheme = "usf"; + REQUIRE(mpm_test::write_json_unitcell_twophase(2, analysis, mpm_scheme, fname) == true); // Write Mesh @@ -41,17 +41,17 @@ TEST_CASE("MPM 2D Explicit TwoPhase USF implementation is checked in unitcells", auto mpm = std::make_unique>(std::move(io)); // Initialise materials - REQUIRE(mpm->initialise_materials() == true); + REQUIRE_NOTHROW(mpm->initialise_materials()); // Initialise mesh and particles - REQUIRE(mpm->initialise_mesh() == true); - REQUIRE(mpm->initialise_particles() == true); + REQUIRE_NOTHROW(mpm->initialise_mesh()); + REQUIRE_NOTHROW(mpm->initialise_particles()); // Initialise external loading - REQUIRE(mpm->initialise_loads() == true); + REQUIRE_NOTHROW(mpm->initialise_loads()); // Renitialise materials - REQUIRE(mpm->initialise_materials() == false); + REQUIRE_THROWS(mpm->initialise_materials()); } SECTION("Check solver") { @@ -73,8 +73,8 @@ TEST_CASE("MPM 3D Explicit TwoPhase USF implementation is checked in unitcells", // Write JSON file const std::string fname = "mpm-explicit-twophase-usf"; const std::string analysis = "MPMExplicitTwoPhase3D"; - const std::string stress_update = "usf"; - REQUIRE(mpm_test::write_json_unitcell_twophase(3, analysis, stress_update, + const std::string mpm_scheme = "usf"; + REQUIRE(mpm_test::write_json_unitcell_twophase(3, analysis, mpm_scheme, fname) == true); // Write Mesh @@ -98,14 +98,14 @@ TEST_CASE("MPM 3D Explicit TwoPhase USF implementation is checked in unitcells", auto mpm = std::make_unique>(std::move(io)); // Initialise materials - REQUIRE(mpm->initialise_materials() == true); + REQUIRE_NOTHROW(mpm->initialise_materials()); // Initialise mesh and particles - REQUIRE(mpm->initialise_mesh() == true); - REQUIRE(mpm->initialise_particles() == true); + REQUIRE_NOTHROW(mpm->initialise_mesh()); + REQUIRE_NOTHROW(mpm->initialise_particles()); // Renitialise materials - REQUIRE(mpm->initialise_materials() == false); + REQUIRE_THROWS(mpm->initialise_materials()); } SECTION("Check solver") { diff --git a/tests/solvers/mpm_explicit_twophase_usl_test.cc b/tests/solvers/mpm_explicit_twophase_usl_test.cc index 94b52732c..b039b17f3 100644 --- a/tests/solvers/mpm_explicit_twophase_usl_test.cc +++ b/tests/solvers/mpm_explicit_twophase_usl_test.cc @@ -16,9 +16,9 @@ TEST_CASE("MPM 2D Explicit USL TwoPhase implementation is checked", // Write JSON file const std::string fname = "mpm-explicit-twophase-usl"; const std::string analysis = "MPMExplicitTwoPhase2D"; - const std::string stress_update = "usl"; + const std::string mpm_scheme = "usl"; bool resume = false; - REQUIRE(mpm_test::write_json_twophase(2, resume, analysis, stress_update, + REQUIRE(mpm_test::write_json_twophase(2, resume, analysis, mpm_scheme, fname) == true); // Write JSON Entity Sets file @@ -45,17 +45,17 @@ TEST_CASE("MPM 2D Explicit USL TwoPhase implementation is checked", auto mpm = std::make_unique>(std::move(io)); // Initialise materials - REQUIRE(mpm->initialise_materials() == true); + REQUIRE_NOTHROW(mpm->initialise_materials()); // Initialise mesh - REQUIRE(mpm->initialise_mesh() == true); + REQUIRE_NOTHROW(mpm->initialise_mesh()); // Initialise particles - REQUIRE(mpm->initialise_particles() == true); + REQUIRE_NOTHROW(mpm->initialise_particles()); // Initialise external loading - REQUIRE(mpm->initialise_loads() == true); + REQUIRE_NOTHROW(mpm->initialise_loads()); // Renitialise materials - REQUIRE(mpm->initialise_materials() == false); + REQUIRE_THROWS(mpm->initialise_materials()); } SECTION("Check solver") { @@ -73,9 +73,9 @@ TEST_CASE("MPM 2D Explicit USL TwoPhase implementation is checked", // // Write JSON file // const std::string fname = "mpm-explicit-twophase-usl"; // const std::string analysis = "MPMExplicitTwoPhase2D"; - // const std::string stress_update = "usl"; + // const std::string mpm_scheme = "usl"; // bool resume = true; - // REQUIRE(mpm_test::write_json_twophase(2, resume, analysis, stress_update, + // REQUIRE(mpm_test::write_json_twophase(2, resume, analysis, mpm_scheme, // fname) == true); // // Create an IO object @@ -110,9 +110,9 @@ TEST_CASE("MPM 3D Explicit USL TwoPhase implementation is checked", // Write JSON file const std::string fname = "mpm-explicit-twophase-usl"; const std::string analysis = "MPMExplicitTwoPhase3D"; - const std::string stress_update = "usl"; + const std::string mpm_scheme = "usl"; const bool resume = false; - REQUIRE(mpm_test::write_json_twophase(3, resume, analysis, stress_update, + REQUIRE(mpm_test::write_json_twophase(3, resume, analysis, mpm_scheme, fname) == true); // Write JSON Entity Sets file @@ -139,14 +139,14 @@ TEST_CASE("MPM 3D Explicit USL TwoPhase implementation is checked", auto mpm = std::make_unique>(std::move(io)); // Initialise materials - REQUIRE(mpm->initialise_materials() == true); + REQUIRE_NOTHROW(mpm->initialise_materials()); // Initialise mesh - REQUIRE(mpm->initialise_mesh() == true); + REQUIRE_NOTHROW(mpm->initialise_mesh()); // Initialise particles - REQUIRE(mpm->initialise_particles() == true); + REQUIRE_NOTHROW(mpm->initialise_particles()); // Renitialise materials - REQUIRE(mpm->initialise_materials() == false); + REQUIRE_THROWS(mpm->initialise_materials()); } SECTION("Check solver") { @@ -164,9 +164,9 @@ TEST_CASE("MPM 3D Explicit USL TwoPhase implementation is checked", // // Write JSON file // const std::string fname = "mpm-explicit-twophase-usl"; // const std::string analysis = "MPMExplicitTwoPhase3D"; - // const std::string stress_update = "usl"; + // const std::string mpm_scheme = "usl"; // bool resume = true; - // REQUIRE(mpm_test::write_json_twophase(3, resume, analysis, stress_update, + // REQUIRE(mpm_test::write_json_twophase(3, resume, analysis, mpm_scheme, // fname) == true); // // Create an IO object diff --git a/tests/solvers/mpm_explicit_twophase_usl_unitcell_test.cc b/tests/solvers/mpm_explicit_twophase_usl_unitcell_test.cc index 2b7e769d1..7a8671399 100644 --- a/tests/solvers/mpm_explicit_twophase_usl_unitcell_test.cc +++ b/tests/solvers/mpm_explicit_twophase_usl_unitcell_test.cc @@ -16,8 +16,8 @@ TEST_CASE("MPM 2D Explicit TwoPhase USL implementation is checked in unitcells", // Write JSON file const std::string fname = "mpm-explicit-twophase-usl"; const std::string analysis = "MPMExplicitTwoPhase2D"; - const std::string stress_update = "usl"; - REQUIRE(mpm_test::write_json_unitcell_twophase(2, analysis, stress_update, + const std::string mpm_scheme = "usl"; + REQUIRE(mpm_test::write_json_unitcell_twophase(2, analysis, mpm_scheme, fname) == true); // Write Mesh @@ -41,17 +41,17 @@ TEST_CASE("MPM 2D Explicit TwoPhase USL implementation is checked in unitcells", auto mpm = std::make_unique>(std::move(io)); // Initialise materials - REQUIRE(mpm->initialise_materials() == true); + REQUIRE_NOTHROW(mpm->initialise_materials()); // Initialise mesh and particles - REQUIRE(mpm->initialise_mesh() == true); - REQUIRE(mpm->initialise_particles() == true); + REQUIRE_NOTHROW(mpm->initialise_mesh()); + REQUIRE_NOTHROW(mpm->initialise_particles()); // Initialise external loading - REQUIRE(mpm->initialise_loads() == true); + REQUIRE_NOTHROW(mpm->initialise_loads()); // Renitialise materials - REQUIRE(mpm->initialise_materials() == false); + REQUIRE_THROWS(mpm->initialise_materials()); } SECTION("Check solver") { @@ -73,8 +73,8 @@ TEST_CASE("MPM 3D Explicit TwoPhase USL implementation is checked in unitcells", // Write JSON file const std::string fname = "mpm-explicit-twophase-usl"; const std::string analysis = "MPMExplicitTwoPhase3D"; - const std::string stress_update = "usl"; - REQUIRE(mpm_test::write_json_unitcell_twophase(3, analysis, stress_update, + const std::string mpm_scheme = "usl"; + REQUIRE(mpm_test::write_json_unitcell_twophase(3, analysis, mpm_scheme, fname) == true); // Write Mesh @@ -98,14 +98,14 @@ TEST_CASE("MPM 3D Explicit TwoPhase USL implementation is checked in unitcells", auto mpm = std::make_unique>(std::move(io)); // Initialise materials - REQUIRE(mpm->initialise_materials() == true); + REQUIRE_NOTHROW(mpm->initialise_materials()); // Initialise mesh and particles - REQUIRE(mpm->initialise_mesh() == true); - REQUIRE(mpm->initialise_particles() == true); + REQUIRE_NOTHROW(mpm->initialise_mesh()); + REQUIRE_NOTHROW(mpm->initialise_particles()); // Renitialise materials - REQUIRE(mpm->initialise_materials() == false); + REQUIRE_THROWS(mpm->initialise_materials()); } SECTION("Check solver") { From 1571da3c4a769e6715f4d5217543351e41c3c876 Mon Sep 17 00:00:00 2001 From: Nanda Date: Thu, 20 Aug 2020 14:37:26 -0700 Subject: [PATCH 126/175] :wrench: fix conflict with serialize refactoring --- CMakeLists.txt | 1 + include/mpi_datatypes_twophase.h | 135 ----- src/particle.cc | 6 +- tests/mpi_particle_twophase_test.cc | 523 ----------------- .../particle_serialize_deserialize_test.cc | 0 ...cle_serialize_deserialize_twophase_test.cc | 526 ++++++++++++++++++ 6 files changed, 531 insertions(+), 660 deletions(-) delete mode 100644 include/mpi_datatypes_twophase.h delete mode 100644 tests/mpi_particle_twophase_test.cc rename tests/{ => particles}/particle_serialize_deserialize_test.cc (100%) create mode 100644 tests/particles/particle_serialize_deserialize_twophase_test.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index c8c08e632..85a7f5183 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -223,6 +223,7 @@ if(MPM_BUILD_TESTING) ${mpm_SOURCE_DIR}/tests/particles/particle_traction_test.cc ${mpm_SOURCE_DIR}/tests/particles/particle_vector_test.cc ${mpm_SOURCE_DIR}/tests/particles/particle_serialize_deserialize_test.cc + ${mpm_SOURCE_DIR}/tests/particles/particle_serialize_deserialize_twophase_test.cc ${mpm_SOURCE_DIR}/tests/point_in_cell_test.cc ${mpm_SOURCE_DIR}/tests/solvers/mpm_explicit_usf_test.cc ${mpm_SOURCE_DIR}/tests/solvers/mpm_explicit_usf_unitcell_test.cc diff --git a/include/mpi_datatypes_twophase.h b/include/mpi_datatypes_twophase.h deleted file mode 100644 index 95d76426a..000000000 --- a/include/mpi_datatypes_twophase.h +++ /dev/null @@ -1,135 +0,0 @@ -#ifndef MPM_MPI_HDF5_PARTICLE_TWOPHASE_H_ -#define MPM_MPI_HDF5_PARTICLE_TWOPHASE_H_ - -// Offset macro -#include - -// MPI -#ifdef USE_MPI -#include "mpi.h" - -#include "hdf5_particle_twophase.h" - -namespace mpm { -//! Initialize MPI particle data types -inline MPI_Datatype register_mpi_particle_type( - const HDF5ParticleTwoPhase& particle) { - // Number of blocks to create - const unsigned nblocks = 43; - // Array containing the length of each block - int lengths[nblocks] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 20, 1, 1, 1, 1, 1, 1, 1, 1, 5}; - // Array containing the displacement for each block, expressed in bytes. The - // displacement is the distance between the start of the MPI datatype created - // and the start of the block - const MPI_Aint displacements[nblocks] = { - // Solid phase - offsetof(HDF5ParticleTwoPhase, id), // id - offsetof(HDF5ParticleTwoPhase, mass), // mass - offsetof(HDF5ParticleTwoPhase, volume), // volume - offsetof(HDF5ParticleTwoPhase, pressure), // pressure - offsetof(HDF5ParticleTwoPhase, coord_x), // coord_x - offsetof(HDF5ParticleTwoPhase, coord_y), // coord_y - offsetof(HDF5ParticleTwoPhase, coord_z), // coord_z - offsetof(HDF5ParticleTwoPhase, displacement_x), // disp_x - offsetof(HDF5ParticleTwoPhase, displacement_y), // disp_y - offsetof(HDF5ParticleTwoPhase, displacement_z), // disp_z - offsetof(HDF5ParticleTwoPhase, nsize_x), // nsize_x - offsetof(HDF5ParticleTwoPhase, nsize_y), // nsize_y - offsetof(HDF5ParticleTwoPhase, nsize_z), // nsize_z - offsetof(HDF5ParticleTwoPhase, velocity_x), // vel_x - offsetof(HDF5ParticleTwoPhase, velocity_y), // vel_y - offsetof(HDF5ParticleTwoPhase, velocity_z), // vel_z - offsetof(HDF5ParticleTwoPhase, stress_xx), // stress_xx - offsetof(HDF5ParticleTwoPhase, stress_yy), // stress_yy - offsetof(HDF5ParticleTwoPhase, stress_zz), // stress_zz - offsetof(HDF5ParticleTwoPhase, tau_xy), // tau_xy - offsetof(HDF5ParticleTwoPhase, tau_yz), // tau_yz - offsetof(HDF5ParticleTwoPhase, tau_xz), // tau_xz - offsetof(HDF5ParticleTwoPhase, strain_xx), // strain_xx - offsetof(HDF5ParticleTwoPhase, strain_yy), // strain_yy - offsetof(HDF5ParticleTwoPhase, strain_zz), // strain_zz - offsetof(HDF5ParticleTwoPhase, gamma_xy), // gamma_xy - offsetof(HDF5ParticleTwoPhase, gamma_yz), // gamma_yz - offsetof(HDF5ParticleTwoPhase, gamma_xz), // gamma_xz - offsetof(HDF5ParticleTwoPhase, epsilon_v), // epsv - offsetof(HDF5ParticleTwoPhase, cell_id), // cellid - offsetof(HDF5ParticleTwoPhase, status), // status - offsetof(HDF5ParticleTwoPhase, material_id), // material_id - offsetof(HDF5ParticleTwoPhase, nstate_vars), // nstate_vars - offsetof(HDF5ParticleTwoPhase, svars), // state_vars - // Fluid phase - offsetof(HDF5ParticleTwoPhase, liquid_mass), // liquid_mass - offsetof(HDF5ParticleTwoPhase, liquid_velocity_x), // liquid_vel_x - offsetof(HDF5ParticleTwoPhase, liquid_velocity_y), // liquid_vel_y - offsetof(HDF5ParticleTwoPhase, liquid_velocity_z), // liquid_vel_z - offsetof(HDF5ParticleTwoPhase, porosity), // porosity - offsetof(HDF5ParticleTwoPhase, liquid_saturation), // liquid_saturation - offsetof(HDF5ParticleTwoPhase, liquid_material_id), // liquid_material_id - offsetof(HDF5ParticleTwoPhase, nliquid_state_vars), // nliquid_state_vars - offsetof(HDF5ParticleTwoPhase, liquid_svars) // liquid_state_vars - }; - - // Array containing the MPI datatypes to replicate to make each block. - MPI_Datatype types[nblocks] = { - // Solid phase - MPI_UNSIGNED_LONG_LONG, // id - MPI_DOUBLE, // mass - MPI_DOUBLE, // volume - MPI_DOUBLE, // pressure - MPI_DOUBLE, // coord_x - MPI_DOUBLE, // coord_y - MPI_DOUBLE, // coord_z - MPI_DOUBLE, // disp_x - MPI_DOUBLE, // disp_y - MPI_DOUBLE, // disp_z - MPI_DOUBLE, // nsize_x - MPI_DOUBLE, // nsize_y - MPI_DOUBLE, // nsize_z - MPI_DOUBLE, // vel_x - MPI_DOUBLE, // vel_y - MPI_DOUBLE, // vel_z - MPI_DOUBLE, // stress_xx - MPI_DOUBLE, // stress_yy - MPI_DOUBLE, // stress_zz - MPI_DOUBLE, // tau_xx - MPI_DOUBLE, // tau_yy - MPI_DOUBLE, // tau_zz - MPI_DOUBLE, // strain_xx - MPI_DOUBLE, // strain_yy - MPI_DOUBLE, // strain_zz - MPI_DOUBLE, // gamma_xy - MPI_DOUBLE, // gamma_yz - MPI_DOUBLE, // gamma_zx - MPI_DOUBLE, // epsv - MPI_UNSIGNED_LONG_LONG, // cell_id - MPI_C_BOOL, // status - MPI_UNSIGNED, // material_id - MPI_UNSIGNED, // nstate_vars - MPI_DOUBLE, // state variables - // Fluid phase - MPI_DOUBLE, // liquid_mass - MPI_DOUBLE, // liquid_velocity_x - MPI_DOUBLE, // liquid_velocity_y - MPI_DOUBLE, // liquid_velocity_z - MPI_DOUBLE, // porosity - MPI_DOUBLE, // liquid_saturation - MPI_UNSIGNED, // liquid_material_id - MPI_UNSIGNED, // nliquid_state_vars - MPI_DOUBLE, // liquid_svars - }; - - // Create the Particle datatype - MPI_Datatype MPIParticle; - - // Create particle data types - MPI_Type_create_struct(nblocks, lengths, displacements, types, &MPIParticle); - MPI_Type_commit(&MPIParticle); - return MPIParticle; -} -} // namespace mpm - -#endif // MPI - -#endif // MPM_MPI_HDF5_PARTICLE_TWOPHASE_H_ diff --git a/src/particle.cc b/src/particle.cc index a565edd22..a3071b477 100644 --- a/src/particle.cc +++ b/src/particle.cc @@ -5,8 +5,10 @@ namespace mpm { // ParticleType -std::map ParticleType = {{"P2D", 0}, {"P3D", 1}}; -std::map ParticleTypeName = {{0, "P2D"}, {1, "P3D"}}; +std::map ParticleType = { + {"P2D", 0}, {"P3D", 1}, {"P2D2PHASE", 2}, {"P3D2PHASE", 3}}; +std::map ParticleTypeName = { + {0, "P2D"}, {1, "P3D"}, {2, "P2D2PHASE"}, {3, "P3D2PHASE"}}; } // namespace mpm // Particle2D (2 Dim) diff --git a/tests/mpi_particle_twophase_test.cc b/tests/mpi_particle_twophase_test.cc deleted file mode 100644 index 54e9b2313..000000000 --- a/tests/mpi_particle_twophase_test.cc +++ /dev/null @@ -1,523 +0,0 @@ -#include - -#include "catch.hpp" - -#include "data_types.h" -#include "hdf5_particle.h" -#include "material.h" -#include "mpi_datatypes.h" -#include "mpi_datatypes_twophase.h" -#include "particle.h" -#include "particle_twophase.h" - -#ifdef USE_MPI -//! \brief Check particle class for 1D case -TEST_CASE("MPI HDF5 TwoPhase Particle is checked", - "[particle][mpi][hdf5][2Phase]") { - // Dimension - const unsigned Dim = 3; - // Tolerance - const double Tolerance = 1.E-7; - - // Check MPI transfer of HDF5 Particle - SECTION("MPI HDF5 TwoPhase Particle") { - mpm::Index id = 0; - - mpm::HDF5ParticleTwoPhase h5_particle; - h5_particle.id = 13; - h5_particle.mass = 501.5; - - h5_particle.pressure = 125.75; - - Eigen::Vector3d coords; - coords << 1., 2., 3.; - h5_particle.coord_x = coords[0]; - h5_particle.coord_y = coords[1]; - h5_particle.coord_z = coords[2]; - - Eigen::Vector3d displacement; - displacement << 0.01, 0.02, 0.03; - h5_particle.displacement_x = displacement[0]; - h5_particle.displacement_y = displacement[1]; - h5_particle.displacement_z = displacement[2]; - - Eigen::Vector3d lsize; - lsize << 0.25, 0.5, 0.75; - h5_particle.nsize_x = lsize[0]; - h5_particle.nsize_y = lsize[1]; - h5_particle.nsize_z = lsize[2]; - - Eigen::Vector3d velocity; - velocity << 1.5, 2.5, 3.5; - h5_particle.velocity_x = velocity[0]; - h5_particle.velocity_y = velocity[1]; - h5_particle.velocity_z = velocity[2]; - - Eigen::Matrix stress; - stress << 11.5, -12.5, 13.5, 14.5, -15.5, 16.5; - h5_particle.stress_xx = stress[0]; - h5_particle.stress_yy = stress[1]; - h5_particle.stress_zz = stress[2]; - h5_particle.tau_xy = stress[3]; - h5_particle.tau_yz = stress[4]; - h5_particle.tau_xz = stress[5]; - - Eigen::Matrix strain; - strain << 0.115, -0.125, 0.135, 0.145, -0.155, 0.165; - h5_particle.strain_xx = strain[0]; - h5_particle.strain_yy = strain[1]; - h5_particle.strain_zz = strain[2]; - h5_particle.gamma_xy = strain[3]; - h5_particle.gamma_yz = strain[4]; - h5_particle.gamma_xz = strain[5]; - - h5_particle.epsilon_v = strain.head(Dim).sum(); - - h5_particle.status = true; - - h5_particle.cell_id = 1; - - h5_particle.volume = 2.; - - h5_particle.material_id = 1; - - h5_particle.nstate_vars = 0; - - for (unsigned i = 0; i < h5_particle.nstate_vars; ++i) - h5_particle.svars[i] = 0.; - - h5_particle.liquid_mass = 100.1; - - Eigen::Vector3d liquid_velocity; - liquid_velocity << 5.5, 2.1, 4.2; - h5_particle.liquid_velocity_x = liquid_velocity[0]; - h5_particle.liquid_velocity_y = liquid_velocity[1]; - h5_particle.liquid_velocity_z = liquid_velocity[2]; - - h5_particle.porosity = 0.33; - - h5_particle.liquid_saturation = 1.; - - h5_particle.liquid_material_id = 2; - - h5_particle.nliquid_state_vars = 1; - - for (unsigned i = 0; i < h5_particle.nliquid_state_vars; ++i) - h5_particle.liquid_svars[i] = 0.; - - // Check send and receive particle with HDF5 - SECTION("Check send and receive particle with HDF5") { - // Get number of MPI ranks - int mpi_size; - MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); - - // If on same rank - int sender = 0; - int receiver = 0; - // Get rank and do the corresponding job for mpi size == 2 - if (mpi_size == 2) receiver = 1; - - int mpi_rank; - MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); - - // Send particle - if (mpi_rank == sender) { - // Initialize MPI datatypes - MPI_Datatype particle_type = - mpm::register_mpi_particle_type(h5_particle); - MPI_Send(&h5_particle, 1, particle_type, receiver, 0, MPI_COMM_WORLD); - mpm::deregister_mpi_particle_type(particle_type); - } - - // Receive particle - if (mpi_rank == receiver) { - // Receive the messid - struct mpm::HDF5ParticleTwoPhase received; - MPI_Datatype particle_type = mpm::register_mpi_particle_type(received); - MPI_Recv(&received, 1, particle_type, sender, 0, MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - mpm::deregister_mpi_particle_type(particle_type); - - REQUIRE(h5_particle.id == received.id); - REQUIRE(h5_particle.mass == received.mass); - REQUIRE(h5_particle.pressure == - Approx(received.pressure).epsilon(Tolerance)); - REQUIRE(h5_particle.volume == - Approx(received.volume).epsilon(Tolerance)); - - REQUIRE(h5_particle.coord_x == - Approx(received.coord_x).epsilon(Tolerance)); - REQUIRE(h5_particle.coord_y == - Approx(received.coord_y).epsilon(Tolerance)); - REQUIRE(h5_particle.coord_z == - Approx(received.coord_z).epsilon(Tolerance)); - - REQUIRE(h5_particle.displacement_x == - Approx(received.displacement_x).epsilon(Tolerance)); - REQUIRE(h5_particle.displacement_y == - Approx(received.displacement_y).epsilon(Tolerance)); - REQUIRE(h5_particle.displacement_z == - Approx(received.displacement_z).epsilon(Tolerance)); - - REQUIRE(h5_particle.nsize_x == received.nsize_x); - REQUIRE(h5_particle.nsize_y == received.nsize_y); - REQUIRE(h5_particle.nsize_z == received.nsize_z); - - REQUIRE(h5_particle.velocity_x == - Approx(received.velocity_x).epsilon(Tolerance)); - REQUIRE(h5_particle.velocity_y == - Approx(received.velocity_y).epsilon(Tolerance)); - REQUIRE(h5_particle.velocity_z == - Approx(received.velocity_z).epsilon(Tolerance)); - - REQUIRE(h5_particle.stress_xx == - Approx(received.stress_xx).epsilon(Tolerance)); - REQUIRE(h5_particle.stress_yy == - Approx(received.stress_yy).epsilon(Tolerance)); - REQUIRE(h5_particle.stress_zz == - Approx(received.stress_zz).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_xy == - Approx(received.tau_xy).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_yz == - Approx(received.tau_yz).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_xz == - Approx(received.tau_xz).epsilon(Tolerance)); - - REQUIRE(h5_particle.strain_xx == - Approx(received.strain_xx).epsilon(Tolerance)); - REQUIRE(h5_particle.strain_yy == - Approx(received.strain_yy).epsilon(Tolerance)); - REQUIRE(h5_particle.strain_zz == - Approx(received.strain_zz).epsilon(Tolerance)); - REQUIRE(h5_particle.gamma_xy == - Approx(received.gamma_xy).epsilon(Tolerance)); - REQUIRE(h5_particle.gamma_yz == - Approx(received.gamma_yz).epsilon(Tolerance)); - REQUIRE(h5_particle.gamma_xz == - Approx(received.gamma_xz).epsilon(Tolerance)); - - REQUIRE(h5_particle.epsilon_v == - Approx(received.epsilon_v).epsilon(Tolerance)); - REQUIRE(h5_particle.status == received.status); - - REQUIRE(h5_particle.cell_id == received.cell_id); - REQUIRE(h5_particle.material_id == received.cell_id); - - REQUIRE(h5_particle.nstate_vars == received.nstate_vars); - for (unsigned i = 0; i < h5_particle.nstate_vars; ++i) - REQUIRE(h5_particle.svars[i] == - Approx(received.svars[i]).epsilon(Tolerance)); - - REQUIRE(h5_particle.liquid_mass == - Approx(received.liquid_mass).epsilon(Tolerance)); - REQUIRE(h5_particle.liquid_velocity_x == - Approx(received.liquid_velocity_x).epsilon(Tolerance)); - REQUIRE(h5_particle.liquid_velocity_y == - Approx(received.liquid_velocity_y).epsilon(Tolerance)); - REQUIRE(h5_particle.liquid_velocity_z == - Approx(received.liquid_velocity_z).epsilon(Tolerance)); - REQUIRE(h5_particle.porosity == - Approx(received.porosity).epsilon(Tolerance)); - REQUIRE(h5_particle.liquid_saturation == - Approx(received.liquid_saturation).epsilon(Tolerance)); - REQUIRE(h5_particle.liquid_material_id == - Approx(received.liquid_material_id).epsilon(Tolerance)); - - REQUIRE(h5_particle.nliquid_state_vars == received.nliquid_state_vars); - for (unsigned i = 0; i < h5_particle.nliquid_state_vars; ++i) - REQUIRE(h5_particle.liquid_svars[i] == - Approx(received.liquid_svars[i]).epsilon(Tolerance)); - } - } - - // Check initialise particle from HDF5 file - SECTION("Check initialise particle with HDF5 across MPI processes") { - // Get number of MPI ranks - int mpi_size; - MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); - - int mpi_rank; - MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); - - // If on same rank - int sender = 0; - int receiver = 0; - - // Get rank and do the corresponding job for mpi size == 2 - if (mpi_size == 2) receiver = 1; - - // Initial particle coordinates - Eigen::Matrix pcoordinates; - pcoordinates.setZero(); - - if (mpi_rank == sender) { - // Create and initialzie particle with HDF5 data - std::shared_ptr> particle = - std::make_shared>(id, pcoordinates); - - // Assign material - unsigned solid_mid = 1; - unsigned liquid_mid = 2; - // Initialise material - Json jsolid_material; - Json jliquid_material; - jsolid_material["density"] = 1000.; - jsolid_material["youngs_modulus"] = 1.0E+7; - jsolid_material["poisson_ratio"] = 0.3; - jsolid_material["porosity"] = 0.3; - jsolid_material["k_x"] = 0.001; - jsolid_material["k_y"] = 0.001; - jsolid_material["k_z"] = 0.001; - jliquid_material["density"] = 1000.; - jliquid_material["bulk_modulus"] = 2.0E9; - jliquid_material["dynamic_viscosity"] = 8.90E-4; - - auto solid_material = - Factory, unsigned, const Json&>::instance() - ->create("LinearElastic3D", std::move(solid_mid), - jsolid_material); - auto liquid_material = - Factory, unsigned, const Json&>::instance() - ->create("Newtonian3D", std::move(liquid_mid), - jliquid_material); - std::vector>> materials; - materials.emplace_back(solid_material); - materials.emplace_back(liquid_material); - - // Reinitialise particle from HDF5 data - REQUIRE(particle->initialise_particle(h5_particle, materials) == true); - - // Check particle id - REQUIRE(particle->id() == h5_particle.id); - // Check particle mass - REQUIRE(particle->mass() == h5_particle.mass); - // Check particle volume - REQUIRE(particle->volume() == h5_particle.volume); - // Check particle mass density - REQUIRE(particle->mass_density() == - h5_particle.mass / h5_particle.volume); - // Check particle status - REQUIRE(particle->status() == h5_particle.status); - - // Check for coordinates - auto coordinates = particle->coordinates(); - REQUIRE(coordinates.size() == Dim); - for (unsigned i = 0; i < coordinates.size(); ++i) - REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); - REQUIRE(coordinates.size() == Dim); - - // Check for displacement - auto pdisplacement = particle->displacement(); - REQUIRE(pdisplacement.size() == Dim); - for (unsigned i = 0; i < Dim; ++i) - REQUIRE(pdisplacement(i) == - Approx(displacement(i)).epsilon(Tolerance)); - - // Check for size - auto size = particle->natural_size(); - REQUIRE(size.size() == Dim); - for (unsigned i = 0; i < size.size(); ++i) - REQUIRE(size(i) == Approx(lsize(i)).epsilon(Tolerance)); - - // Check velocity - auto pvelocity = particle->velocity(); - REQUIRE(pvelocity.size() == Dim); - for (unsigned i = 0; i < Dim; ++i) - REQUIRE(pvelocity(i) == Approx(velocity(i)).epsilon(Tolerance)); - - // Check stress - auto pstress = particle->stress(); - REQUIRE(pstress.size() == stress.size()); - for (unsigned i = 0; i < stress.size(); ++i) - REQUIRE(pstress(i) == Approx(stress(i)).epsilon(Tolerance)); - - // Check strain - auto pstrain = particle->strain(); - REQUIRE(pstrain.size() == strain.size()); - for (unsigned i = 0; i < strain.size(); ++i) - REQUIRE(pstrain(i) == Approx(strain(i)).epsilon(Tolerance)); - - // Check particle volumetric strain centroid - REQUIRE(particle->volumetric_strain_centroid() == - h5_particle.epsilon_v); - - // Check cell id - REQUIRE(particle->cell_id() == h5_particle.cell_id); - - // Check material id - REQUIRE(particle->material_id() == h5_particle.material_id); - - // Check liquid mass - REQUIRE(particle->liquid_mass() == h5_particle.liquid_mass); - - // Check liquid velocity - auto pliquid_velocity = particle->liquid_velocity(); - REQUIRE(pliquid_velocity.size() == Dim); - for (unsigned i = 0; i < Dim; ++i) - REQUIRE(pliquid_velocity(i) == - Approx(liquid_velocity(i)).epsilon(Tolerance)); - - // Check porosity - REQUIRE(particle->porosity() == h5_particle.porosity); - - // Check liquid material id - REQUIRE(particle->material_id(mpm::ParticlePhase::Liquid) == - h5_particle.liquid_material_id); - - // Write Particle HDF5 data - auto h5_twophase_send_ptr = - std::static_pointer_cast( - particle->hdf5_ptr()); - - // Send MPI particle - MPI_Datatype particle_type = - mpm::register_mpi_particle_type(*h5_twophase_send_ptr); - MPI_Send(&(*h5_twophase_send_ptr), 1, particle_type, receiver, 0, - MPI_COMM_WORLD); - mpm::deregister_mpi_particle_type(particle_type); - } - if (mpi_rank == receiver) { - // Receive the messid - struct mpm::HDF5ParticleTwoPhase received; - MPI_Datatype particle_type = mpm::register_mpi_particle_type(received); - MPI_Recv(&received, 1, particle_type, sender, 0, MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - mpm::deregister_mpi_particle_type(particle_type); - - // Received particle - std::shared_ptr> rparticle = - std::make_shared>(id, pcoordinates); - - // Assign material - unsigned solid_mid = 1; - unsigned liquid_mid = 2; - // Initialise material - Json jsolid_material; - Json jliquid_material; - jsolid_material["density"] = 1000.; - jsolid_material["youngs_modulus"] = 1.0E+7; - jsolid_material["poisson_ratio"] = 0.3; - jsolid_material["porosity"] = 0.3; - jsolid_material["k_x"] = 0.001; - jsolid_material["k_y"] = 0.001; - jsolid_material["k_z"] = 0.001; - jliquid_material["density"] = 1000.; - jliquid_material["bulk_modulus"] = 2.0E9; - jliquid_material["dynamic_viscosity"] = 8.90E-4; - - auto solid_material = - Factory, unsigned, const Json&>::instance() - ->create("LinearElastic3D", std::move(solid_mid), - jsolid_material); - auto liquid_material = - Factory, unsigned, const Json&>::instance() - ->create("Newtonian3D", std::move(liquid_mid), - jliquid_material); - std::vector>> materials; - materials.emplace_back(solid_material); - materials.emplace_back(liquid_material); - - // Reinitialise particle from HDF5 data - REQUIRE(rparticle->initialise_particle(received, materials) == true); - - // Check particle id - REQUIRE(rparticle->id() == h5_particle.id); - // Check particle mass - REQUIRE(rparticle->mass() == h5_particle.mass); - // Check particle volume - REQUIRE(rparticle->volume() == h5_particle.volume); - // Check particle mass density - REQUIRE(rparticle->mass_density() == - h5_particle.mass / h5_particle.volume); - // Check particle status - REQUIRE(rparticle->status() == h5_particle.status); - - // Check for coordinates - auto coordinates = rparticle->coordinates(); - REQUIRE(coordinates.size() == Dim); - for (unsigned i = 0; i < coordinates.size(); ++i) - REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); - REQUIRE(coordinates.size() == Dim); - - // Check for displacement - auto pdisplacement = rparticle->displacement(); - REQUIRE(pdisplacement.size() == Dim); - for (unsigned i = 0; i < Dim; ++i) - REQUIRE(pdisplacement(i) == - Approx(displacement(i)).epsilon(Tolerance)); - - // Check for size - auto size = rparticle->natural_size(); - REQUIRE(size.size() == Dim); - for (unsigned i = 0; i < size.size(); ++i) - REQUIRE(size(i) == Approx(lsize(i)).epsilon(Tolerance)); - - // Check velocity - auto pvelocity = rparticle->velocity(); - REQUIRE(pvelocity.size() == Dim); - for (unsigned i = 0; i < Dim; ++i) - REQUIRE(pvelocity(i) == Approx(velocity(i)).epsilon(Tolerance)); - - // Check stress - auto pstress = rparticle->stress(); - REQUIRE(pstress.size() == stress.size()); - for (unsigned i = 0; i < stress.size(); ++i) - REQUIRE(pstress(i) == Approx(stress(i)).epsilon(Tolerance)); - - // Check strain - auto pstrain = rparticle->strain(); - REQUIRE(pstrain.size() == strain.size()); - for (unsigned i = 0; i < strain.size(); ++i) - REQUIRE(pstrain(i) == Approx(strain(i)).epsilon(Tolerance)); - - // Check particle volumetric strain centroid - REQUIRE(rparticle->volumetric_strain_centroid() == - h5_particle.epsilon_v); - - // Check cell id - REQUIRE(rparticle->cell_id() == h5_particle.cell_id); - - // Check material id - REQUIRE(rparticle->material_id() == h5_particle.material_id); - - // Get Particle HDF5 data - auto h5_twophase_received = - std::static_pointer_cast( - rparticle->hdf5_ptr()); - - // State variables - REQUIRE(h5_twophase_received->nstate_vars == h5_particle.nstate_vars); - // State variables - for (unsigned i = 0; i < h5_particle.nstate_vars; ++i) - REQUIRE(h5_twophase_received->svars[i] == - Approx(h5_particle.svars[i]).epsilon(Tolerance)); - - // Check liquid mass - REQUIRE(rparticle->liquid_mass() == h5_particle.liquid_mass); - - // Check liquid velocity - auto pliquid_velocity = rparticle->liquid_velocity(); - REQUIRE(pliquid_velocity.size() == Dim); - for (unsigned i = 0; i < Dim; ++i) - REQUIRE(pliquid_velocity(i) == - Approx(liquid_velocity(i)).epsilon(Tolerance)); - - // Check porosity - REQUIRE(rparticle->porosity() == h5_particle.porosity); - - // Check liquid material id - REQUIRE(rparticle->material_id(mpm::ParticlePhase::Liquid) == - h5_particle.liquid_material_id); - - // Liquid state variables - REQUIRE(h5_twophase_received->nliquid_state_vars == - h5_particle.nliquid_state_vars); - // Liquid state variables - for (unsigned i = 0; i < h5_particle.nliquid_state_vars; ++i) - REQUIRE(h5_twophase_received->liquid_svars[i] == - Approx(h5_particle.liquid_svars[i]).epsilon(Tolerance)); - } - } - } -} -#endif // MPI diff --git a/tests/particle_serialize_deserialize_test.cc b/tests/particles/particle_serialize_deserialize_test.cc similarity index 100% rename from tests/particle_serialize_deserialize_test.cc rename to tests/particles/particle_serialize_deserialize_test.cc diff --git a/tests/particles/particle_serialize_deserialize_twophase_test.cc b/tests/particles/particle_serialize_deserialize_twophase_test.cc new file mode 100644 index 000000000..bbfd916e6 --- /dev/null +++ b/tests/particles/particle_serialize_deserialize_twophase_test.cc @@ -0,0 +1,526 @@ +// #include + +// #include "catch.hpp" + +// #include "data_types.h" +// #include "hdf5_particle.h" +// #include "material.h" +// #include "particle.h" +// #include "particle_twophase.h" + +// #ifdef USE_MPI +// //! \brief Check particle class for 1D case +// TEST_CASE("MPI HDF5 TwoPhase Particle is checked", +// "[particle][mpi][hdf5][2Phase]") { +// // Dimension +// const unsigned Dim = 3; +// // Tolerance +// const double Tolerance = 1.E-7; + +// // Check MPI transfer of HDF5 Particle +// SECTION("MPI HDF5 TwoPhase Particle") { +// mpm::Index id = 0; + +// mpm::HDF5ParticleTwoPhase h5_particle; +// h5_particle.id = 13; +// h5_particle.mass = 501.5; + +// h5_particle.pressure = 125.75; + +// Eigen::Vector3d coords; +// coords << 1., 2., 3.; +// h5_particle.coord_x = coords[0]; +// h5_particle.coord_y = coords[1]; +// h5_particle.coord_z = coords[2]; + +// Eigen::Vector3d displacement; +// displacement << 0.01, 0.02, 0.03; +// h5_particle.displacement_x = displacement[0]; +// h5_particle.displacement_y = displacement[1]; +// h5_particle.displacement_z = displacement[2]; + +// Eigen::Vector3d lsize; +// lsize << 0.25, 0.5, 0.75; +// h5_particle.nsize_x = lsize[0]; +// h5_particle.nsize_y = lsize[1]; +// h5_particle.nsize_z = lsize[2]; + +// Eigen::Vector3d velocity; +// velocity << 1.5, 2.5, 3.5; +// h5_particle.velocity_x = velocity[0]; +// h5_particle.velocity_y = velocity[1]; +// h5_particle.velocity_z = velocity[2]; + +// Eigen::Matrix stress; +// stress << 11.5, -12.5, 13.5, 14.5, -15.5, 16.5; +// h5_particle.stress_xx = stress[0]; +// h5_particle.stress_yy = stress[1]; +// h5_particle.stress_zz = stress[2]; +// h5_particle.tau_xy = stress[3]; +// h5_particle.tau_yz = stress[4]; +// h5_particle.tau_xz = stress[5]; + +// Eigen::Matrix strain; +// strain << 0.115, -0.125, 0.135, 0.145, -0.155, 0.165; +// h5_particle.strain_xx = strain[0]; +// h5_particle.strain_yy = strain[1]; +// h5_particle.strain_zz = strain[2]; +// h5_particle.gamma_xy = strain[3]; +// h5_particle.gamma_yz = strain[4]; +// h5_particle.gamma_xz = strain[5]; + +// h5_particle.epsilon_v = strain.head(Dim).sum(); + +// h5_particle.status = true; + +// h5_particle.cell_id = 1; + +// h5_particle.volume = 2.; + +// h5_particle.material_id = 1; + +// h5_particle.nstate_vars = 0; + +// for (unsigned i = 0; i < h5_particle.nstate_vars; ++i) +// h5_particle.svars[i] = 0.; + +// h5_particle.liquid_mass = 100.1; + +// Eigen::Vector3d liquid_velocity; +// liquid_velocity << 5.5, 2.1, 4.2; +// h5_particle.liquid_velocity_x = liquid_velocity[0]; +// h5_particle.liquid_velocity_y = liquid_velocity[1]; +// h5_particle.liquid_velocity_z = liquid_velocity[2]; + +// h5_particle.porosity = 0.33; + +// h5_particle.liquid_saturation = 1.; + +// h5_particle.liquid_material_id = 2; + +// h5_particle.nliquid_state_vars = 1; + +// for (unsigned i = 0; i < h5_particle.nliquid_state_vars; ++i) +// h5_particle.liquid_svars[i] = 0.; + +// // Check send and receive particle with HDF5 +// SECTION("Check send and receive particle with HDF5") { +// // Get number of MPI ranks +// int mpi_size; +// MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + +// // If on same rank +// int sender = 0; +// int receiver = 0; +// // Get rank and do the corresponding job for mpi size == 2 +// if (mpi_size == 2) receiver = 1; + +// int mpi_rank; +// MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + +// // Send particle +// if (mpi_rank == sender) { +// // Initialize MPI datatypes +// MPI_Datatype particle_type = +// mpm::register_mpi_particle_type(h5_particle); +// MPI_Send(&h5_particle, 1, particle_type, receiver, 0, +// MPI_COMM_WORLD); mpm::deregister_mpi_particle_type(particle_type); +// } + +// // Receive particle +// if (mpi_rank == receiver) { +// // Receive the messid +// struct mpm::HDF5ParticleTwoPhase received; +// MPI_Datatype particle_type = +// mpm::register_mpi_particle_type(received); MPI_Recv(&received, 1, +// particle_type, sender, 0, MPI_COMM_WORLD, +// MPI_STATUS_IGNORE); +// mpm::deregister_mpi_particle_type(particle_type); + +// REQUIRE(h5_particle.id == received.id); +// REQUIRE(h5_particle.mass == received.mass); +// REQUIRE(h5_particle.pressure == +// Approx(received.pressure).epsilon(Tolerance)); +// REQUIRE(h5_particle.volume == +// Approx(received.volume).epsilon(Tolerance)); + +// REQUIRE(h5_particle.coord_x == +// Approx(received.coord_x).epsilon(Tolerance)); +// REQUIRE(h5_particle.coord_y == +// Approx(received.coord_y).epsilon(Tolerance)); +// REQUIRE(h5_particle.coord_z == +// Approx(received.coord_z).epsilon(Tolerance)); + +// REQUIRE(h5_particle.displacement_x == +// Approx(received.displacement_x).epsilon(Tolerance)); +// REQUIRE(h5_particle.displacement_y == +// Approx(received.displacement_y).epsilon(Tolerance)); +// REQUIRE(h5_particle.displacement_z == +// Approx(received.displacement_z).epsilon(Tolerance)); + +// REQUIRE(h5_particle.nsize_x == received.nsize_x); +// REQUIRE(h5_particle.nsize_y == received.nsize_y); +// REQUIRE(h5_particle.nsize_z == received.nsize_z); + +// REQUIRE(h5_particle.velocity_x == +// Approx(received.velocity_x).epsilon(Tolerance)); +// REQUIRE(h5_particle.velocity_y == +// Approx(received.velocity_y).epsilon(Tolerance)); +// REQUIRE(h5_particle.velocity_z == +// Approx(received.velocity_z).epsilon(Tolerance)); + +// REQUIRE(h5_particle.stress_xx == +// Approx(received.stress_xx).epsilon(Tolerance)); +// REQUIRE(h5_particle.stress_yy == +// Approx(received.stress_yy).epsilon(Tolerance)); +// REQUIRE(h5_particle.stress_zz == +// Approx(received.stress_zz).epsilon(Tolerance)); +// REQUIRE(h5_particle.tau_xy == +// Approx(received.tau_xy).epsilon(Tolerance)); +// REQUIRE(h5_particle.tau_yz == +// Approx(received.tau_yz).epsilon(Tolerance)); +// REQUIRE(h5_particle.tau_xz == +// Approx(received.tau_xz).epsilon(Tolerance)); + +// REQUIRE(h5_particle.strain_xx == +// Approx(received.strain_xx).epsilon(Tolerance)); +// REQUIRE(h5_particle.strain_yy == +// Approx(received.strain_yy).epsilon(Tolerance)); +// REQUIRE(h5_particle.strain_zz == +// Approx(received.strain_zz).epsilon(Tolerance)); +// REQUIRE(h5_particle.gamma_xy == +// Approx(received.gamma_xy).epsilon(Tolerance)); +// REQUIRE(h5_particle.gamma_yz == +// Approx(received.gamma_yz).epsilon(Tolerance)); +// REQUIRE(h5_particle.gamma_xz == +// Approx(received.gamma_xz).epsilon(Tolerance)); + +// REQUIRE(h5_particle.epsilon_v == +// Approx(received.epsilon_v).epsilon(Tolerance)); +// REQUIRE(h5_particle.status == received.status); + +// REQUIRE(h5_particle.cell_id == received.cell_id); +// REQUIRE(h5_particle.material_id == received.cell_id); + +// REQUIRE(h5_particle.nstate_vars == received.nstate_vars); +// for (unsigned i = 0; i < h5_particle.nstate_vars; ++i) +// REQUIRE(h5_particle.svars[i] == +// Approx(received.svars[i]).epsilon(Tolerance)); + +// REQUIRE(h5_particle.liquid_mass == +// Approx(received.liquid_mass).epsilon(Tolerance)); +// REQUIRE(h5_particle.liquid_velocity_x == +// Approx(received.liquid_velocity_x).epsilon(Tolerance)); +// REQUIRE(h5_particle.liquid_velocity_y == +// Approx(received.liquid_velocity_y).epsilon(Tolerance)); +// REQUIRE(h5_particle.liquid_velocity_z == +// Approx(received.liquid_velocity_z).epsilon(Tolerance)); +// REQUIRE(h5_particle.porosity == +// Approx(received.porosity).epsilon(Tolerance)); +// REQUIRE(h5_particle.liquid_saturation == +// Approx(received.liquid_saturation).epsilon(Tolerance)); +// REQUIRE(h5_particle.liquid_material_id == +// Approx(received.liquid_material_id).epsilon(Tolerance)); + +// REQUIRE(h5_particle.nliquid_state_vars == +// received.nliquid_state_vars); for (unsigned i = 0; i < +// h5_particle.nliquid_state_vars; ++i) +// REQUIRE(h5_particle.liquid_svars[i] == +// Approx(received.liquid_svars[i]).epsilon(Tolerance)); +// } +// } + +// // Check initialise particle from HDF5 file +// SECTION("Check initialise particle with HDF5 across MPI processes") { +// // Get number of MPI ranks +// int mpi_size; +// MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + +// int mpi_rank; +// MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + +// // If on same rank +// int sender = 0; +// int receiver = 0; + +// // Get rank and do the corresponding job for mpi size == 2 +// if (mpi_size == 2) receiver = 1; + +// // Initial particle coordinates +// Eigen::Matrix pcoordinates; +// pcoordinates.setZero(); + +// if (mpi_rank == sender) { +// // Create and initialzie particle with HDF5 data +// std::shared_ptr> particle = +// std::make_shared>(id, pcoordinates); + +// // Assign material +// unsigned solid_mid = 1; +// unsigned liquid_mid = 2; +// // Initialise material +// Json jsolid_material; +// Json jliquid_material; +// jsolid_material["density"] = 1000.; +// jsolid_material["youngs_modulus"] = 1.0E+7; +// jsolid_material["poisson_ratio"] = 0.3; +// jsolid_material["porosity"] = 0.3; +// jsolid_material["k_x"] = 0.001; +// jsolid_material["k_y"] = 0.001; +// jsolid_material["k_z"] = 0.001; +// jliquid_material["density"] = 1000.; +// jliquid_material["bulk_modulus"] = 2.0E9; +// jliquid_material["dynamic_viscosity"] = 8.90E-4; + +// auto solid_material = +// Factory, unsigned, const Json&>::instance() +// ->create("LinearElastic3D", std::move(solid_mid), +// jsolid_material); +// auto liquid_material = +// Factory, unsigned, const Json&>::instance() +// ->create("Newtonian3D", std::move(liquid_mid), +// jliquid_material); +// std::vector>> materials; +// materials.emplace_back(solid_material); +// materials.emplace_back(liquid_material); + +// // Reinitialise particle from HDF5 data +// REQUIRE(particle->initialise_particle(h5_particle, materials) == +// true); + +// // Check particle id +// REQUIRE(particle->id() == h5_particle.id); +// // Check particle mass +// REQUIRE(particle->mass() == h5_particle.mass); +// // Check particle volume +// REQUIRE(particle->volume() == h5_particle.volume); +// // Check particle mass density +// REQUIRE(particle->mass_density() == +// h5_particle.mass / h5_particle.volume); +// // Check particle status +// REQUIRE(particle->status() == h5_particle.status); + +// // Check for coordinates +// auto coordinates = particle->coordinates(); +// REQUIRE(coordinates.size() == Dim); +// for (unsigned i = 0; i < coordinates.size(); ++i) +// REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); +// REQUIRE(coordinates.size() == Dim); + +// // Check for displacement +// auto pdisplacement = particle->displacement(); +// REQUIRE(pdisplacement.size() == Dim); +// for (unsigned i = 0; i < Dim; ++i) +// REQUIRE(pdisplacement(i) == +// Approx(displacement(i)).epsilon(Tolerance)); + +// // Check for size +// auto size = particle->natural_size(); +// REQUIRE(size.size() == Dim); +// for (unsigned i = 0; i < size.size(); ++i) +// REQUIRE(size(i) == Approx(lsize(i)).epsilon(Tolerance)); + +// // Check velocity +// auto pvelocity = particle->velocity(); +// REQUIRE(pvelocity.size() == Dim); +// for (unsigned i = 0; i < Dim; ++i) +// REQUIRE(pvelocity(i) == Approx(velocity(i)).epsilon(Tolerance)); + +// // Check stress +// auto pstress = particle->stress(); +// REQUIRE(pstress.size() == stress.size()); +// for (unsigned i = 0; i < stress.size(); ++i) +// REQUIRE(pstress(i) == Approx(stress(i)).epsilon(Tolerance)); + +// // Check strain +// auto pstrain = particle->strain(); +// REQUIRE(pstrain.size() == strain.size()); +// for (unsigned i = 0; i < strain.size(); ++i) +// REQUIRE(pstrain(i) == Approx(strain(i)).epsilon(Tolerance)); + +// // Check particle volumetric strain centroid +// REQUIRE(particle->volumetric_strain_centroid() == +// h5_particle.epsilon_v); + +// // Check cell id +// REQUIRE(particle->cell_id() == h5_particle.cell_id); + +// // Check material id +// REQUIRE(particle->material_id() == h5_particle.material_id); + +// // Check liquid mass +// REQUIRE(particle->liquid_mass() == h5_particle.liquid_mass); + +// // Check liquid velocity +// auto pliquid_velocity = particle->liquid_velocity(); +// REQUIRE(pliquid_velocity.size() == Dim); +// for (unsigned i = 0; i < Dim; ++i) +// REQUIRE(pliquid_velocity(i) == +// Approx(liquid_velocity(i)).epsilon(Tolerance)); + +// // Check porosity +// REQUIRE(particle->porosity() == h5_particle.porosity); + +// // Check liquid material id +// REQUIRE(particle->material_id(mpm::ParticlePhase::Liquid) == +// h5_particle.liquid_material_id); + +// // Write Particle HDF5 data +// auto h5_twophase_send_ptr = +// std::static_pointer_cast( +// particle->hdf5_ptr()); + +// // Send MPI particle +// MPI_Datatype particle_type = +// mpm::register_mpi_particle_type(*h5_twophase_send_ptr); +// MPI_Send(&(*h5_twophase_send_ptr), 1, particle_type, receiver, 0, +// MPI_COMM_WORLD); +// mpm::deregister_mpi_particle_type(particle_type); +// } +// if (mpi_rank == receiver) { +// // Receive the messid +// struct mpm::HDF5ParticleTwoPhase received; +// MPI_Datatype particle_type = +// mpm::register_mpi_particle_type(received); MPI_Recv(&received, 1, +// particle_type, sender, 0, MPI_COMM_WORLD, +// MPI_STATUS_IGNORE); +// mpm::deregister_mpi_particle_type(particle_type); + +// // Received particle +// std::shared_ptr> rparticle = +// std::make_shared>(id, pcoordinates); + +// // Assign material +// unsigned solid_mid = 1; +// unsigned liquid_mid = 2; +// // Initialise material +// Json jsolid_material; +// Json jliquid_material; +// jsolid_material["density"] = 1000.; +// jsolid_material["youngs_modulus"] = 1.0E+7; +// jsolid_material["poisson_ratio"] = 0.3; +// jsolid_material["porosity"] = 0.3; +// jsolid_material["k_x"] = 0.001; +// jsolid_material["k_y"] = 0.001; +// jsolid_material["k_z"] = 0.001; +// jliquid_material["density"] = 1000.; +// jliquid_material["bulk_modulus"] = 2.0E9; +// jliquid_material["dynamic_viscosity"] = 8.90E-4; + +// auto solid_material = +// Factory, unsigned, const Json&>::instance() +// ->create("LinearElastic3D", std::move(solid_mid), +// jsolid_material); +// auto liquid_material = +// Factory, unsigned, const Json&>::instance() +// ->create("Newtonian3D", std::move(liquid_mid), +// jliquid_material); +// std::vector>> materials; +// materials.emplace_back(solid_material); +// materials.emplace_back(liquid_material); + +// // Reinitialise particle from HDF5 data +// REQUIRE(rparticle->initialise_particle(received, materials) == true); + +// // Check particle id +// REQUIRE(rparticle->id() == h5_particle.id); +// // Check particle mass +// REQUIRE(rparticle->mass() == h5_particle.mass); +// // Check particle volume +// REQUIRE(rparticle->volume() == h5_particle.volume); +// // Check particle mass density +// REQUIRE(rparticle->mass_density() == +// h5_particle.mass / h5_particle.volume); +// // Check particle status +// REQUIRE(rparticle->status() == h5_particle.status); + +// // Check for coordinates +// auto coordinates = rparticle->coordinates(); +// REQUIRE(coordinates.size() == Dim); +// for (unsigned i = 0; i < coordinates.size(); ++i) +// REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); +// REQUIRE(coordinates.size() == Dim); + +// // Check for displacement +// auto pdisplacement = rparticle->displacement(); +// REQUIRE(pdisplacement.size() == Dim); +// for (unsigned i = 0; i < Dim; ++i) +// REQUIRE(pdisplacement(i) == +// Approx(displacement(i)).epsilon(Tolerance)); + +// // Check for size +// auto size = rparticle->natural_size(); +// REQUIRE(size.size() == Dim); +// for (unsigned i = 0; i < size.size(); ++i) +// REQUIRE(size(i) == Approx(lsize(i)).epsilon(Tolerance)); + +// // Check velocity +// auto pvelocity = rparticle->velocity(); +// REQUIRE(pvelocity.size() == Dim); +// for (unsigned i = 0; i < Dim; ++i) +// REQUIRE(pvelocity(i) == Approx(velocity(i)).epsilon(Tolerance)); + +// // Check stress +// auto pstress = rparticle->stress(); +// REQUIRE(pstress.size() == stress.size()); +// for (unsigned i = 0; i < stress.size(); ++i) +// REQUIRE(pstress(i) == Approx(stress(i)).epsilon(Tolerance)); + +// // Check strain +// auto pstrain = rparticle->strain(); +// REQUIRE(pstrain.size() == strain.size()); +// for (unsigned i = 0; i < strain.size(); ++i) +// REQUIRE(pstrain(i) == Approx(strain(i)).epsilon(Tolerance)); + +// // Check particle volumetric strain centroid +// REQUIRE(rparticle->volumetric_strain_centroid() == +// h5_particle.epsilon_v); + +// // Check cell id +// REQUIRE(rparticle->cell_id() == h5_particle.cell_id); + +// // Check material id +// REQUIRE(rparticle->material_id() == h5_particle.material_id); + +// // Get Particle HDF5 data +// auto h5_twophase_received = +// std::static_pointer_cast( +// rparticle->hdf5_ptr()); + +// // State variables +// REQUIRE(h5_twophase_received->nstate_vars == +// h5_particle.nstate_vars); +// // State variables +// for (unsigned i = 0; i < h5_particle.nstate_vars; ++i) +// REQUIRE(h5_twophase_received->svars[i] == +// Approx(h5_particle.svars[i]).epsilon(Tolerance)); + +// // Check liquid mass +// REQUIRE(rparticle->liquid_mass() == h5_particle.liquid_mass); + +// // Check liquid velocity +// auto pliquid_velocity = rparticle->liquid_velocity(); +// REQUIRE(pliquid_velocity.size() == Dim); +// for (unsigned i = 0; i < Dim; ++i) +// REQUIRE(pliquid_velocity(i) == +// Approx(liquid_velocity(i)).epsilon(Tolerance)); + +// // Check porosity +// REQUIRE(rparticle->porosity() == h5_particle.porosity); + +// // Check liquid material id +// REQUIRE(rparticle->material_id(mpm::ParticlePhase::Liquid) == +// h5_particle.liquid_material_id); + +// // Liquid state variables +// REQUIRE(h5_twophase_received->nliquid_state_vars == +// h5_particle.nliquid_state_vars); +// // Liquid state variables +// for (unsigned i = 0; i < h5_particle.nliquid_state_vars; ++i) +// REQUIRE(h5_twophase_received->liquid_svars[i] == +// Approx(h5_particle.liquid_svars[i]).epsilon(Tolerance)); +// } +// } +// } +// } +// #endif // MPI From 594aa681b91a2c7e909ac4dd6bc3d6a39ce176e8 Mon Sep 17 00:00:00 2001 From: Nanda Date: Fri, 21 Aug 2020 01:30:00 -0700 Subject: [PATCH 127/175] :construction: some modification of deserialize and serialize functions in particle and cleanups --- include/hdf5_particle.h | 1 + include/particles/particle.h | 2 +- include/particles/particle.tcc | 35 +++++++++++++++++++++++----------- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/include/hdf5_particle.h b/include/hdf5_particle.h index 70e1a8988..88489f232 100644 --- a/include/hdf5_particle.h +++ b/include/hdf5_particle.h @@ -44,6 +44,7 @@ typedef struct HDF5Particle { unsigned nstate_vars; // State variables (init to zero) double svars[20] = {0}; + // Destructor virtual ~HDF5Particle() = default; } HDF5Particle; diff --git a/include/particles/particle.h b/include/particles/particle.h index 2f495c39e..a991ade78 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -374,7 +374,7 @@ class Particle : public ParticleBase { //! Compute pack size //! \retval pack size of serialized object - int compute_pack_size() const; + virtual int compute_pack_size() const; protected: //! particle id diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index 65af90639..6b5568d3c 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -1018,8 +1018,8 @@ std::vector mpm::Particle::serialize() { unsigned nmaterials = material_id_.size(); MPI_Pack(&nmaterials, 1, MPI_UNSIGNED, data_ptr, data.size(), &position, MPI_COMM_WORLD); - MPI_Pack(&material_id_[0], 1, MPI_UNSIGNED, data_ptr, data.size(), &position, - MPI_COMM_WORLD); + MPI_Pack(&material_id_[mpm::ParticlePhase::Solid], 1, MPI_UNSIGNED, data_ptr, + data.size(), &position, MPI_COMM_WORLD); // ID MPI_Pack(&id_, 1, MPI_UNSIGNED_LONG_LONG, data_ptr, data.size(), &position, @@ -1076,9 +1076,10 @@ std::vector mpm::Particle::serialize() { MPI_COMM_WORLD); // state variables - if (this->material() != nullptr) { + if (this->material(mpm::ParticlePhase::Solid) != nullptr) { std::vector svars; - auto state_variables = (this->material())->state_variables(); + auto state_variables = + (this->material(mpm::ParticlePhase::Solid))->state_variables(); for (const auto& state_var : state_variables) svars.emplace_back( state_variables_[mpm::ParticlePhase::Solid].at(state_var)); @@ -1101,16 +1102,24 @@ void mpm::Particle::deserialize( #ifdef USE_MPI // Type - int type = ParticleType.at(this->type()); + int type; MPI_Unpack(data_ptr, data.size(), &position, &type, 1, MPI_INT, MPI_COMM_WORLD); + if (type != ParticleType.at(this->type())) + throw std::runtime_error("Deserialize particle(): particle type mismatch"); + // material id int nmaterials = 0; MPI_Unpack(data_ptr, data.size(), &position, &nmaterials, 1, MPI_UNSIGNED, MPI_COMM_WORLD); + if (nmaterials != materials.size()) + throw std::runtime_error( + "Deserialize particle(): nmaterials mismatch with the input materials " + "size"); - MPI_Unpack(data_ptr, data.size(), &position, &material_id_[0], 1, - MPI_UNSIGNED, MPI_COMM_WORLD); + MPI_Unpack(data_ptr, data.size(), &position, + &material_id_[mpm::ParticlePhase::Solid], 1, MPI_UNSIGNED, + MPI_COMM_WORLD); // ID MPI_Unpack(data_ptr, data.size(), &position, &id_, 1, MPI_UNSIGNED_LONG_LONG, @@ -1156,8 +1165,10 @@ void mpm::Particle::deserialize( MPI_COMM_WORLD); // Assign materials - if (material_id_[0] == materials.at(0)->id()) { - bool assign_mat = this->assign_material(materials.at(0)); + if (material_id_[mpm::ParticlePhase::Solid] == + materials.at(mpm::ParticlePhase::Solid)->id()) { + bool assign_mat = + this->assign_material(materials.at(mpm::ParticlePhase::Solid)); if (!assign_mat) throw std::runtime_error("Material assignment failed"); } @@ -1173,10 +1184,12 @@ void mpm::Particle::deserialize( MPI_DOUBLE, MPI_COMM_WORLD); // Reinitialize state variables - auto mat_state_vars = (this->material())->initialise_state_variables(); + auto mat_state_vars = (this->material(mpm::ParticlePhase::Solid)) + ->initialise_state_variables(); if (mat_state_vars.size() == nstate_vars) { unsigned i = 0; - auto state_variables = (this->material())->state_variables(); + auto state_variables = + (this->material(mpm::ParticlePhase::Solid))->state_variables(); for (const auto& state_var : state_variables) { this->state_variables_[mpm::ParticlePhase::Solid].at(state_var) = svars[i]; From 2b6cf4bc300b254a81d866c08e4f2d489bda7dc3 Mon Sep 17 00:00:00 2001 From: Nanda Date: Fri, 21 Aug 2020 01:31:51 -0700 Subject: [PATCH 128/175] :construction: add serialize and deserialize in twophase particle --- include/hdf5_particle_twophase.h | 2 + include/particles/particle_twophase.h | 23 ++ include/particles/particle_twophase.tcc | 337 ++++++++++++++++++++++++ 3 files changed, 362 insertions(+) diff --git a/include/hdf5_particle_twophase.h b/include/hdf5_particle_twophase.h index cb8d6940f..7e91780d0 100644 --- a/include/hdf5_particle_twophase.h +++ b/include/hdf5_particle_twophase.h @@ -21,6 +21,8 @@ typedef struct HDF5ParticleTwoPhase : HDF5Particle { unsigned nliquid_state_vars; // State variables (init to zero) double liquid_svars[5] = {0}; + // Destructor + virtual ~HDF5ParticleTwoPhase() = default; } HDF5ParticleTwoPhase; namespace hdf5 { diff --git a/include/particles/particle_twophase.h b/include/particles/particle_twophase.h index 83675ac07..ea7ac81ae 100644 --- a/include/particles/particle_twophase.h +++ b/include/particles/particle_twophase.h @@ -149,6 +149,27 @@ class TwoPhaseParticle : public mpm::Particle { //! \retval porosity Porosity double porosity() const override { return porosity_; } + //! Type of particle + std::string type() const override { + return (Tdim == 2) ? "P2D2PHASE" : "P3D2PHASE"; + } + + //! Serialize + //! \retval buffer Serialized buffer data + std::vector serialize() override; + + //! Deserialize + //! \param[in] buffer Serialized buffer data + //! \param[in] material Particle material pointers + void deserialize( + const std::vector& buffer, + std::vector>>& materials) override; + + protected: + //! Compute pack size + //! \retval pack size of serialized object + int compute_pack_size() const override; + private: //! Assign liquid mass and momentum to nodes virtual void map_liquid_mass_momentum_to_nodes() noexcept; @@ -219,6 +240,8 @@ class TwoPhaseParticle : public mpm::Particle { using Particle::size_; //! Particle velocity constraints using Particle::particle_velocity_constraints_; + //! Size of particle + using Particle::pack_size_; //! Liquid mass double liquid_mass_; diff --git a/include/particles/particle_twophase.tcc b/include/particles/particle_twophase.tcc index b85b22e94..08328dc64 100644 --- a/include/particles/particle_twophase.tcc +++ b/include/particles/particle_twophase.tcc @@ -909,3 +909,340 @@ bool mpm::TwoPhaseParticle::assign_traction(unsigned direction, } return status; } + +//! Compute size of serialized particle data +template +int mpm::TwoPhaseParticle::compute_pack_size() const { + int total_size = mpm::Particle::compute_pack_size(); + int partial_size; +#ifdef USE_MPI + // material id for liquid phase + MPI_Pack_size(1, MPI_UNSIGNED, MPI_COMM_WORLD, &partial_size); + total_size += partial_size; + + // liquid mass + MPI_Pack_size(1, MPI_DOUBLE, MPI_COMM_WORLD, &partial_size); + total_size += partial_size; + + // liquid velocity + MPI_Pack_size(Tdim, MPI_DOUBLE, MPI_COMM_WORLD, &partial_size); + total_size += partial_size; + + // porosity, liquid saturation + MPI_Pack_size(2 * 1, MPI_DOUBLE, MPI_COMM_WORLD, &partial_size); + total_size += partial_size; + + // nliquid state variables + unsigned nliquid_state_vars = + state_variables_[mpm::ParticlePhase::Liquid].size(); + MPI_Pack_size(1, MPI_UNSIGNED, MPI_COMM_WORLD, &partial_size); + total_size += partial_size; + + // liquid state variables + MPI_Pack_size(nliquid_state_vars, MPI_DOUBLE, MPI_COMM_WORLD, &partial_size); + total_size += partial_size; +#endif + return total_size; +} + +//! Serialize particle data +template +std::vector mpm::TwoPhaseParticle::serialize() { + // Compute pack size + if (pack_size_ == 0) pack_size_ = this->compute_pack_size(); + // Initialize data buffer + std::vector data; + data.resize(pack_size_); + uint8_t* data_ptr = &data[0]; + int position = 0; + +#ifdef USE_MPI + // Type + int type = ParticleType.at(this->type()); + MPI_Pack(&type, 1, MPI_INT, data_ptr, data.size(), &position, MPI_COMM_WORLD); + + // Material ID + unsigned nmaterials = material_id_.size(); + MPI_Pack(&nmaterials, 1, MPI_UNSIGNED, data_ptr, data.size(), &position, + MPI_COMM_WORLD); + MPI_Pack(&material_id_[mpm::ParticlePhase::Solid], 1, MPI_UNSIGNED, data_ptr, + data.size(), &position, MPI_COMM_WORLD); + MPI_Pack(&material_id_[mpm::ParticlePhase::Liquid], 1, MPI_UNSIGNED, data_ptr, + data.size(), &position, MPI_COMM_WORLD); + + // ID + MPI_Pack(&this->id_, 1, MPI_UNSIGNED_LONG_LONG, data_ptr, data.size(), + &position, MPI_COMM_WORLD); + + // Solid Phase + // Mass + MPI_Pack(&mass_, 1, MPI_DOUBLE, data_ptr, data.size(), &position, + MPI_COMM_WORLD); + // Volume + MPI_Pack(&volume_, 1, MPI_DOUBLE, data_ptr, data.size(), &position, + MPI_COMM_WORLD); + // Pressure + double pressure = + (state_variables_[mpm::ParticlePhase::Solid].find("pressure") != + state_variables_[mpm::ParticlePhase::Solid].end()) + ? state_variables_[mpm::ParticlePhase::Solid].at("pressure") + : 0.; + MPI_Pack(&pressure, 1, MPI_DOUBLE, data_ptr, data.size(), &position, + MPI_COMM_WORLD); + + // Coordinates + MPI_Pack(coordinates_.data(), Tdim, MPI_DOUBLE, data_ptr, data.size(), + &position, MPI_COMM_WORLD); + // Displacement + MPI_Pack(this->displacement_.data(), Tdim, MPI_DOUBLE, data_ptr, data.size(), + &position, MPI_COMM_WORLD); + // Natural size + MPI_Pack(this->natural_size_.data(), Tdim, MPI_DOUBLE, data_ptr, data.size(), + &position, MPI_COMM_WORLD); + // Velocity + MPI_Pack(this->velocity_.data(), Tdim, MPI_DOUBLE, data_ptr, data.size(), + &position, MPI_COMM_WORLD); + // Stress + MPI_Pack(stress_.data(), 6, MPI_DOUBLE, data_ptr, data.size(), &position, + MPI_COMM_WORLD); + // Strain + MPI_Pack(this->strain_.data(), 6, MPI_DOUBLE, data_ptr, data.size(), + &position, MPI_COMM_WORLD); + + // epsv + MPI_Pack(&this->volumetric_strain_centroid_, 1, MPI_DOUBLE, data_ptr, + data.size(), &position, MPI_COMM_WORLD); + + // Cell id + MPI_Pack(&this->cell_id_, 1, MPI_UNSIGNED_LONG_LONG, data_ptr, data.size(), + &position, MPI_COMM_WORLD); + + // Status + MPI_Pack(&this->status_, 1, MPI_C_BOOL, data_ptr, data.size(), &position, + MPI_COMM_WORLD); + + // nstate variables + unsigned nstate_vars = state_variables_[mpm::ParticlePhase::Solid].size(); + MPI_Pack(&nstate_vars, 1, MPI_UNSIGNED, data_ptr, data.size(), &position, + MPI_COMM_WORLD); + + // state variables + if (this->material(mpm::ParticlePhase::Solid) != nullptr) { + std::vector svars; + auto state_variables = + (this->material(mpm::ParticlePhase::Solid))->state_variables(); + for (const auto& state_var : state_variables) + svars.emplace_back( + state_variables_[mpm::ParticlePhase::Solid].at(state_var)); + + // Write state vars + MPI_Pack(&svars[0], nstate_vars, MPI_DOUBLE, data_ptr, data.size(), + &position, MPI_COMM_WORLD); + } + + // Liquid Phase + // Mass + MPI_Pack(&liquid_mass_, 1, MPI_DOUBLE, data_ptr, data.size(), &position, + MPI_COMM_WORLD); + // Velocity + MPI_Pack(liquid_velocity_.data(), Tdim, MPI_DOUBLE, data_ptr, data.size(), + &position, MPI_COMM_WORLD); + // Porosity + MPI_Pack(&porosity_, 1, MPI_DOUBLE, data_ptr, data.size(), &position, + MPI_COMM_WORLD); + // Liquid Saturation + MPI_Pack(&liquid_saturation_, 1, MPI_DOUBLE, data_ptr, data.size(), &position, + MPI_COMM_WORLD); + + // nstate variables + unsigned nliquid_state_vars = + state_variables_[mpm::ParticlePhase::Liquid].size(); + MPI_Pack(&nliquid_state_vars, 1, MPI_UNSIGNED, data_ptr, data.size(), + &position, MPI_COMM_WORLD); + + // state variables + if (this->material(mpm::ParticlePhase::Liquid) != nullptr) { + std::vector svars; + auto state_variables = + (this->material(mpm::ParticlePhase::Liquid))->state_variables(); + for (const auto& state_var : state_variables) + svars.emplace_back( + state_variables_[mpm::ParticlePhase::Liquid].at(state_var)); + + // Write state vars + MPI_Pack(&svars[0], nliquid_state_vars, MPI_DOUBLE, data_ptr, data.size(), + &position, MPI_COMM_WORLD); + } +#endif + return data; +} + +//! Deserialize particle data +template +void mpm::TwoPhaseParticle::deserialize( + const std::vector& data, + std::vector>>& materials) { + uint8_t* data_ptr = const_cast(&data[0]); + int position = 0; + +#ifdef USE_MPI + // Type + int type; + MPI_Unpack(data_ptr, data.size(), &position, &type, 1, MPI_INT, + MPI_COMM_WORLD); + if (type != ParticleType.at(this->type())) + throw std::runtime_error("Deserialize particle(): particle type mismatch"); + + // nmaterials + int nmaterials = 0; + MPI_Unpack(data_ptr, data.size(), &position, &nmaterials, 1, MPI_UNSIGNED, + MPI_COMM_WORLD); + if (nmaterials != materials.size()) + throw std::runtime_error( + "Deserialize particle(): nmaterials mismatch with the input materials " + "size"); + + // Material ID + MPI_Unpack(data_ptr, data.size(), &position, + &material_id_[mpm::ParticlePhase::Solid], 1, MPI_UNSIGNED, + MPI_COMM_WORLD); + MPI_Unpack(data_ptr, data.size(), &position, + &material_id_[mpm::ParticlePhase::Liquid], 1, MPI_UNSIGNED, + MPI_COMM_WORLD); + + // ID + MPI_Unpack(data_ptr, data.size(), &position, &this->id_, 1, + MPI_UNSIGNED_LONG_LONG, MPI_COMM_WORLD); + + // Solid Phase + // mass + MPI_Unpack(data_ptr, data.size(), &position, &mass_, 1, MPI_DOUBLE, + MPI_COMM_WORLD); + // volume + MPI_Unpack(data_ptr, data.size(), &position, &volume_, 1, MPI_DOUBLE, + MPI_COMM_WORLD); + // pressure + double pressure; + MPI_Unpack(data_ptr, data.size(), &position, &pressure, 1, MPI_DOUBLE, + MPI_COMM_WORLD); + this->assign_pressure(pressure); + + // Coordinates + MPI_Unpack(data_ptr, data.size(), &position, coordinates_.data(), Tdim, + MPI_DOUBLE, MPI_COMM_WORLD); + // Displacement + MPI_Unpack(data_ptr, data.size(), &position, this->displacement_.data(), Tdim, + MPI_DOUBLE, MPI_COMM_WORLD); + // Natural size + MPI_Unpack(data_ptr, data.size(), &position, this->natural_size_.data(), Tdim, + MPI_DOUBLE, MPI_COMM_WORLD); + // Velocity + MPI_Unpack(data_ptr, data.size(), &position, this->velocity_.data(), Tdim, + MPI_DOUBLE, MPI_COMM_WORLD); + // Stress + MPI_Unpack(data_ptr, data.size(), &position, stress_.data(), 6, MPI_DOUBLE, + MPI_COMM_WORLD); + // Strain + MPI_Unpack(data_ptr, data.size(), &position, this->strain_.data(), 6, + MPI_DOUBLE, MPI_COMM_WORLD); + + // epsv + MPI_Unpack(data_ptr, data.size(), &position, + &this->volumetric_strain_centroid_, 1, MPI_DOUBLE, MPI_COMM_WORLD); + // cell id + MPI_Unpack(data_ptr, data.size(), &position, &this->cell_id_, 1, + MPI_UNSIGNED_LONG_LONG, MPI_COMM_WORLD); + // status + MPI_Unpack(data_ptr, data.size(), &position, &this->status_, 1, MPI_C_BOOL, + MPI_COMM_WORLD); + + // Assign materials + if (material_id_[mpm::ParticlePhase::Solid] == + materials.at(mpm::ParticlePhase::Solid)->id()) { + bool assign_mat = + this->assign_material(materials.at(mpm::ParticlePhase::Solid)); + if (!assign_mat) throw std::runtime_error("Material assignment failed"); + } + + // nstate vars + unsigned nstate_vars; + MPI_Unpack(data_ptr, data.size(), &position, &nstate_vars, 1, MPI_UNSIGNED, + MPI_COMM_WORLD); + + if (nstate_vars > 0) { + std::vector svars; + svars.reserve(nstate_vars); + MPI_Unpack(data_ptr, data.size(), &position, &svars, nstate_vars, + MPI_DOUBLE, MPI_COMM_WORLD); + + // Reinitialize state variables + auto mat_state_vars = (this->material(mpm::ParticlePhase::Solid)) + ->initialise_state_variables(); + if (mat_state_vars.size() == nstate_vars) { + unsigned i = 0; + auto state_variables = + (this->material(mpm::ParticlePhase::Solid))->state_variables(); + for (const auto& state_var : state_variables) { + this->state_variables_[mpm::ParticlePhase::Solid].at(state_var) = + svars[i]; + ++i; + } + } else + throw std::runtime_error( + "Deserialize particle(): state_vars size mismatch"); + } + + // Liquid Phase + // liquid mass + MPI_Unpack(data_ptr, data.size(), &position, &liquid_mass_, 1, MPI_DOUBLE, + MPI_COMM_WORLD); + // Liquid velocity + MPI_Unpack(data_ptr, data.size(), &position, liquid_velocity_.data(), Tdim, + MPI_DOUBLE, MPI_COMM_WORLD); + // porosity + MPI_Unpack(data_ptr, data.size(), &position, &porosity_, 1, MPI_DOUBLE, + MPI_COMM_WORLD); + // liquid Saturation + MPI_Unpack(data_ptr, data.size(), &position, &liquid_saturation_, 1, + MPI_DOUBLE, MPI_COMM_WORLD); + + // Assign permeability + this->assign_permeability(); + + // Assign liquid materials + if (material_id_[mpm::ParticlePhase::Liquid] == + materials.at(mpm::ParticlePhase::Liquid)->id()) { + bool assign_mat = + this->assign_material(materials.at(mpm::ParticlePhase::Liquid)); + if (!assign_mat) throw std::runtime_error("Material assignment failed"); + } + + // nliquid state vars + unsigned nliquid_state_vars; + MPI_Unpack(data_ptr, data.size(), &position, &nliquid_state_vars, 1, + MPI_UNSIGNED, MPI_COMM_WORLD); + + if (nliquid_state_vars > 0) { + std::vector svars; + svars.reserve(nliquid_state_vars); + MPI_Unpack(data_ptr, data.size(), &position, &svars, nliquid_state_vars, + MPI_DOUBLE, MPI_COMM_WORLD); + + // Reinitialize state variables + auto mat_state_vars = (this->material(mpm::ParticlePhase::Liquid)) + ->initialise_state_variables(); + if (mat_state_vars.size() == nliquid_state_vars) { + unsigned i = 0; + auto state_variables = + (this->material(mpm::ParticlePhase::Liquid))->state_variables(); + for (const auto& state_var : state_variables) { + this->state_variables_[mpm::ParticlePhase::Liquid].at(state_var) = + svars[i]; + ++i; + } + } else + throw std::runtime_error( + "Deserialize particle(): liquid_state_vars size mismatch"); + } +#endif +} \ No newline at end of file From c602ced4cb3263515eb70548f94dfc5eb7a046c0 Mon Sep 17 00:00:00 2001 From: Nanda Date: Sat, 22 Aug 2020 00:21:20 -0700 Subject: [PATCH 129/175] :construction: :dart: fix bugs in particle_twophase SD and create testing --- include/particles/particle_twophase.tcc | 9 +- ...cle_serialize_deserialize_twophase_test.cc | 770 ++++++------------ 2 files changed, 248 insertions(+), 531 deletions(-) diff --git a/include/particles/particle_twophase.tcc b/include/particles/particle_twophase.tcc index 08328dc64..480f8fa0f 100644 --- a/include/particles/particle_twophase.tcc +++ b/include/particles/particle_twophase.tcc @@ -1125,7 +1125,6 @@ void mpm::TwoPhaseParticle::deserialize( double pressure; MPI_Unpack(data_ptr, data.size(), &position, &pressure, 1, MPI_DOUBLE, MPI_COMM_WORLD); - this->assign_pressure(pressure); // Coordinates MPI_Unpack(data_ptr, data.size(), &position, coordinates_.data(), Tdim, @@ -1159,8 +1158,8 @@ void mpm::TwoPhaseParticle::deserialize( // Assign materials if (material_id_[mpm::ParticlePhase::Solid] == materials.at(mpm::ParticlePhase::Solid)->id()) { - bool assign_mat = - this->assign_material(materials.at(mpm::ParticlePhase::Solid)); + bool assign_mat = this->assign_material( + materials.at(mpm::ParticlePhase::Solid), mpm::ParticlePhase::Solid); if (!assign_mat) throw std::runtime_error("Material assignment failed"); } @@ -1212,8 +1211,8 @@ void mpm::TwoPhaseParticle::deserialize( // Assign liquid materials if (material_id_[mpm::ParticlePhase::Liquid] == materials.at(mpm::ParticlePhase::Liquid)->id()) { - bool assign_mat = - this->assign_material(materials.at(mpm::ParticlePhase::Liquid)); + bool assign_mat = this->assign_material( + materials.at(mpm::ParticlePhase::Liquid), mpm::ParticlePhase::Liquid); if (!assign_mat) throw std::runtime_error("Material assignment failed"); } diff --git a/tests/particles/particle_serialize_deserialize_twophase_test.cc b/tests/particles/particle_serialize_deserialize_twophase_test.cc index bbfd916e6..e822dd1ee 100644 --- a/tests/particles/particle_serialize_deserialize_twophase_test.cc +++ b/tests/particles/particle_serialize_deserialize_twophase_test.cc @@ -1,526 +1,244 @@ -// #include - -// #include "catch.hpp" - -// #include "data_types.h" -// #include "hdf5_particle.h" -// #include "material.h" -// #include "particle.h" -// #include "particle_twophase.h" - -// #ifdef USE_MPI -// //! \brief Check particle class for 1D case -// TEST_CASE("MPI HDF5 TwoPhase Particle is checked", -// "[particle][mpi][hdf5][2Phase]") { -// // Dimension -// const unsigned Dim = 3; -// // Tolerance -// const double Tolerance = 1.E-7; - -// // Check MPI transfer of HDF5 Particle -// SECTION("MPI HDF5 TwoPhase Particle") { -// mpm::Index id = 0; - -// mpm::HDF5ParticleTwoPhase h5_particle; -// h5_particle.id = 13; -// h5_particle.mass = 501.5; - -// h5_particle.pressure = 125.75; - -// Eigen::Vector3d coords; -// coords << 1., 2., 3.; -// h5_particle.coord_x = coords[0]; -// h5_particle.coord_y = coords[1]; -// h5_particle.coord_z = coords[2]; - -// Eigen::Vector3d displacement; -// displacement << 0.01, 0.02, 0.03; -// h5_particle.displacement_x = displacement[0]; -// h5_particle.displacement_y = displacement[1]; -// h5_particle.displacement_z = displacement[2]; - -// Eigen::Vector3d lsize; -// lsize << 0.25, 0.5, 0.75; -// h5_particle.nsize_x = lsize[0]; -// h5_particle.nsize_y = lsize[1]; -// h5_particle.nsize_z = lsize[2]; - -// Eigen::Vector3d velocity; -// velocity << 1.5, 2.5, 3.5; -// h5_particle.velocity_x = velocity[0]; -// h5_particle.velocity_y = velocity[1]; -// h5_particle.velocity_z = velocity[2]; - -// Eigen::Matrix stress; -// stress << 11.5, -12.5, 13.5, 14.5, -15.5, 16.5; -// h5_particle.stress_xx = stress[0]; -// h5_particle.stress_yy = stress[1]; -// h5_particle.stress_zz = stress[2]; -// h5_particle.tau_xy = stress[3]; -// h5_particle.tau_yz = stress[4]; -// h5_particle.tau_xz = stress[5]; - -// Eigen::Matrix strain; -// strain << 0.115, -0.125, 0.135, 0.145, -0.155, 0.165; -// h5_particle.strain_xx = strain[0]; -// h5_particle.strain_yy = strain[1]; -// h5_particle.strain_zz = strain[2]; -// h5_particle.gamma_xy = strain[3]; -// h5_particle.gamma_yz = strain[4]; -// h5_particle.gamma_xz = strain[5]; - -// h5_particle.epsilon_v = strain.head(Dim).sum(); - -// h5_particle.status = true; - -// h5_particle.cell_id = 1; - -// h5_particle.volume = 2.; - -// h5_particle.material_id = 1; - -// h5_particle.nstate_vars = 0; - -// for (unsigned i = 0; i < h5_particle.nstate_vars; ++i) -// h5_particle.svars[i] = 0.; - -// h5_particle.liquid_mass = 100.1; - -// Eigen::Vector3d liquid_velocity; -// liquid_velocity << 5.5, 2.1, 4.2; -// h5_particle.liquid_velocity_x = liquid_velocity[0]; -// h5_particle.liquid_velocity_y = liquid_velocity[1]; -// h5_particle.liquid_velocity_z = liquid_velocity[2]; - -// h5_particle.porosity = 0.33; - -// h5_particle.liquid_saturation = 1.; - -// h5_particle.liquid_material_id = 2; - -// h5_particle.nliquid_state_vars = 1; - -// for (unsigned i = 0; i < h5_particle.nliquid_state_vars; ++i) -// h5_particle.liquid_svars[i] = 0.; - -// // Check send and receive particle with HDF5 -// SECTION("Check send and receive particle with HDF5") { -// // Get number of MPI ranks -// int mpi_size; -// MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); - -// // If on same rank -// int sender = 0; -// int receiver = 0; -// // Get rank and do the corresponding job for mpi size == 2 -// if (mpi_size == 2) receiver = 1; - -// int mpi_rank; -// MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); - -// // Send particle -// if (mpi_rank == sender) { -// // Initialize MPI datatypes -// MPI_Datatype particle_type = -// mpm::register_mpi_particle_type(h5_particle); -// MPI_Send(&h5_particle, 1, particle_type, receiver, 0, -// MPI_COMM_WORLD); mpm::deregister_mpi_particle_type(particle_type); -// } - -// // Receive particle -// if (mpi_rank == receiver) { -// // Receive the messid -// struct mpm::HDF5ParticleTwoPhase received; -// MPI_Datatype particle_type = -// mpm::register_mpi_particle_type(received); MPI_Recv(&received, 1, -// particle_type, sender, 0, MPI_COMM_WORLD, -// MPI_STATUS_IGNORE); -// mpm::deregister_mpi_particle_type(particle_type); - -// REQUIRE(h5_particle.id == received.id); -// REQUIRE(h5_particle.mass == received.mass); -// REQUIRE(h5_particle.pressure == -// Approx(received.pressure).epsilon(Tolerance)); -// REQUIRE(h5_particle.volume == -// Approx(received.volume).epsilon(Tolerance)); - -// REQUIRE(h5_particle.coord_x == -// Approx(received.coord_x).epsilon(Tolerance)); -// REQUIRE(h5_particle.coord_y == -// Approx(received.coord_y).epsilon(Tolerance)); -// REQUIRE(h5_particle.coord_z == -// Approx(received.coord_z).epsilon(Tolerance)); - -// REQUIRE(h5_particle.displacement_x == -// Approx(received.displacement_x).epsilon(Tolerance)); -// REQUIRE(h5_particle.displacement_y == -// Approx(received.displacement_y).epsilon(Tolerance)); -// REQUIRE(h5_particle.displacement_z == -// Approx(received.displacement_z).epsilon(Tolerance)); - -// REQUIRE(h5_particle.nsize_x == received.nsize_x); -// REQUIRE(h5_particle.nsize_y == received.nsize_y); -// REQUIRE(h5_particle.nsize_z == received.nsize_z); - -// REQUIRE(h5_particle.velocity_x == -// Approx(received.velocity_x).epsilon(Tolerance)); -// REQUIRE(h5_particle.velocity_y == -// Approx(received.velocity_y).epsilon(Tolerance)); -// REQUIRE(h5_particle.velocity_z == -// Approx(received.velocity_z).epsilon(Tolerance)); - -// REQUIRE(h5_particle.stress_xx == -// Approx(received.stress_xx).epsilon(Tolerance)); -// REQUIRE(h5_particle.stress_yy == -// Approx(received.stress_yy).epsilon(Tolerance)); -// REQUIRE(h5_particle.stress_zz == -// Approx(received.stress_zz).epsilon(Tolerance)); -// REQUIRE(h5_particle.tau_xy == -// Approx(received.tau_xy).epsilon(Tolerance)); -// REQUIRE(h5_particle.tau_yz == -// Approx(received.tau_yz).epsilon(Tolerance)); -// REQUIRE(h5_particle.tau_xz == -// Approx(received.tau_xz).epsilon(Tolerance)); - -// REQUIRE(h5_particle.strain_xx == -// Approx(received.strain_xx).epsilon(Tolerance)); -// REQUIRE(h5_particle.strain_yy == -// Approx(received.strain_yy).epsilon(Tolerance)); -// REQUIRE(h5_particle.strain_zz == -// Approx(received.strain_zz).epsilon(Tolerance)); -// REQUIRE(h5_particle.gamma_xy == -// Approx(received.gamma_xy).epsilon(Tolerance)); -// REQUIRE(h5_particle.gamma_yz == -// Approx(received.gamma_yz).epsilon(Tolerance)); -// REQUIRE(h5_particle.gamma_xz == -// Approx(received.gamma_xz).epsilon(Tolerance)); - -// REQUIRE(h5_particle.epsilon_v == -// Approx(received.epsilon_v).epsilon(Tolerance)); -// REQUIRE(h5_particle.status == received.status); - -// REQUIRE(h5_particle.cell_id == received.cell_id); -// REQUIRE(h5_particle.material_id == received.cell_id); - -// REQUIRE(h5_particle.nstate_vars == received.nstate_vars); -// for (unsigned i = 0; i < h5_particle.nstate_vars; ++i) -// REQUIRE(h5_particle.svars[i] == -// Approx(received.svars[i]).epsilon(Tolerance)); - -// REQUIRE(h5_particle.liquid_mass == -// Approx(received.liquid_mass).epsilon(Tolerance)); -// REQUIRE(h5_particle.liquid_velocity_x == -// Approx(received.liquid_velocity_x).epsilon(Tolerance)); -// REQUIRE(h5_particle.liquid_velocity_y == -// Approx(received.liquid_velocity_y).epsilon(Tolerance)); -// REQUIRE(h5_particle.liquid_velocity_z == -// Approx(received.liquid_velocity_z).epsilon(Tolerance)); -// REQUIRE(h5_particle.porosity == -// Approx(received.porosity).epsilon(Tolerance)); -// REQUIRE(h5_particle.liquid_saturation == -// Approx(received.liquid_saturation).epsilon(Tolerance)); -// REQUIRE(h5_particle.liquid_material_id == -// Approx(received.liquid_material_id).epsilon(Tolerance)); - -// REQUIRE(h5_particle.nliquid_state_vars == -// received.nliquid_state_vars); for (unsigned i = 0; i < -// h5_particle.nliquid_state_vars; ++i) -// REQUIRE(h5_particle.liquid_svars[i] == -// Approx(received.liquid_svars[i]).epsilon(Tolerance)); -// } -// } - -// // Check initialise particle from HDF5 file -// SECTION("Check initialise particle with HDF5 across MPI processes") { -// // Get number of MPI ranks -// int mpi_size; -// MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); - -// int mpi_rank; -// MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); - -// // If on same rank -// int sender = 0; -// int receiver = 0; - -// // Get rank and do the corresponding job for mpi size == 2 -// if (mpi_size == 2) receiver = 1; - -// // Initial particle coordinates -// Eigen::Matrix pcoordinates; -// pcoordinates.setZero(); - -// if (mpi_rank == sender) { -// // Create and initialzie particle with HDF5 data -// std::shared_ptr> particle = -// std::make_shared>(id, pcoordinates); - -// // Assign material -// unsigned solid_mid = 1; -// unsigned liquid_mid = 2; -// // Initialise material -// Json jsolid_material; -// Json jliquid_material; -// jsolid_material["density"] = 1000.; -// jsolid_material["youngs_modulus"] = 1.0E+7; -// jsolid_material["poisson_ratio"] = 0.3; -// jsolid_material["porosity"] = 0.3; -// jsolid_material["k_x"] = 0.001; -// jsolid_material["k_y"] = 0.001; -// jsolid_material["k_z"] = 0.001; -// jliquid_material["density"] = 1000.; -// jliquid_material["bulk_modulus"] = 2.0E9; -// jliquid_material["dynamic_viscosity"] = 8.90E-4; - -// auto solid_material = -// Factory, unsigned, const Json&>::instance() -// ->create("LinearElastic3D", std::move(solid_mid), -// jsolid_material); -// auto liquid_material = -// Factory, unsigned, const Json&>::instance() -// ->create("Newtonian3D", std::move(liquid_mid), -// jliquid_material); -// std::vector>> materials; -// materials.emplace_back(solid_material); -// materials.emplace_back(liquid_material); - -// // Reinitialise particle from HDF5 data -// REQUIRE(particle->initialise_particle(h5_particle, materials) == -// true); - -// // Check particle id -// REQUIRE(particle->id() == h5_particle.id); -// // Check particle mass -// REQUIRE(particle->mass() == h5_particle.mass); -// // Check particle volume -// REQUIRE(particle->volume() == h5_particle.volume); -// // Check particle mass density -// REQUIRE(particle->mass_density() == -// h5_particle.mass / h5_particle.volume); -// // Check particle status -// REQUIRE(particle->status() == h5_particle.status); - -// // Check for coordinates -// auto coordinates = particle->coordinates(); -// REQUIRE(coordinates.size() == Dim); -// for (unsigned i = 0; i < coordinates.size(); ++i) -// REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); -// REQUIRE(coordinates.size() == Dim); - -// // Check for displacement -// auto pdisplacement = particle->displacement(); -// REQUIRE(pdisplacement.size() == Dim); -// for (unsigned i = 0; i < Dim; ++i) -// REQUIRE(pdisplacement(i) == -// Approx(displacement(i)).epsilon(Tolerance)); - -// // Check for size -// auto size = particle->natural_size(); -// REQUIRE(size.size() == Dim); -// for (unsigned i = 0; i < size.size(); ++i) -// REQUIRE(size(i) == Approx(lsize(i)).epsilon(Tolerance)); - -// // Check velocity -// auto pvelocity = particle->velocity(); -// REQUIRE(pvelocity.size() == Dim); -// for (unsigned i = 0; i < Dim; ++i) -// REQUIRE(pvelocity(i) == Approx(velocity(i)).epsilon(Tolerance)); - -// // Check stress -// auto pstress = particle->stress(); -// REQUIRE(pstress.size() == stress.size()); -// for (unsigned i = 0; i < stress.size(); ++i) -// REQUIRE(pstress(i) == Approx(stress(i)).epsilon(Tolerance)); - -// // Check strain -// auto pstrain = particle->strain(); -// REQUIRE(pstrain.size() == strain.size()); -// for (unsigned i = 0; i < strain.size(); ++i) -// REQUIRE(pstrain(i) == Approx(strain(i)).epsilon(Tolerance)); - -// // Check particle volumetric strain centroid -// REQUIRE(particle->volumetric_strain_centroid() == -// h5_particle.epsilon_v); - -// // Check cell id -// REQUIRE(particle->cell_id() == h5_particle.cell_id); - -// // Check material id -// REQUIRE(particle->material_id() == h5_particle.material_id); - -// // Check liquid mass -// REQUIRE(particle->liquid_mass() == h5_particle.liquid_mass); - -// // Check liquid velocity -// auto pliquid_velocity = particle->liquid_velocity(); -// REQUIRE(pliquid_velocity.size() == Dim); -// for (unsigned i = 0; i < Dim; ++i) -// REQUIRE(pliquid_velocity(i) == -// Approx(liquid_velocity(i)).epsilon(Tolerance)); - -// // Check porosity -// REQUIRE(particle->porosity() == h5_particle.porosity); - -// // Check liquid material id -// REQUIRE(particle->material_id(mpm::ParticlePhase::Liquid) == -// h5_particle.liquid_material_id); - -// // Write Particle HDF5 data -// auto h5_twophase_send_ptr = -// std::static_pointer_cast( -// particle->hdf5_ptr()); - -// // Send MPI particle -// MPI_Datatype particle_type = -// mpm::register_mpi_particle_type(*h5_twophase_send_ptr); -// MPI_Send(&(*h5_twophase_send_ptr), 1, particle_type, receiver, 0, -// MPI_COMM_WORLD); -// mpm::deregister_mpi_particle_type(particle_type); -// } -// if (mpi_rank == receiver) { -// // Receive the messid -// struct mpm::HDF5ParticleTwoPhase received; -// MPI_Datatype particle_type = -// mpm::register_mpi_particle_type(received); MPI_Recv(&received, 1, -// particle_type, sender, 0, MPI_COMM_WORLD, -// MPI_STATUS_IGNORE); -// mpm::deregister_mpi_particle_type(particle_type); - -// // Received particle -// std::shared_ptr> rparticle = -// std::make_shared>(id, pcoordinates); - -// // Assign material -// unsigned solid_mid = 1; -// unsigned liquid_mid = 2; -// // Initialise material -// Json jsolid_material; -// Json jliquid_material; -// jsolid_material["density"] = 1000.; -// jsolid_material["youngs_modulus"] = 1.0E+7; -// jsolid_material["poisson_ratio"] = 0.3; -// jsolid_material["porosity"] = 0.3; -// jsolid_material["k_x"] = 0.001; -// jsolid_material["k_y"] = 0.001; -// jsolid_material["k_z"] = 0.001; -// jliquid_material["density"] = 1000.; -// jliquid_material["bulk_modulus"] = 2.0E9; -// jliquid_material["dynamic_viscosity"] = 8.90E-4; - -// auto solid_material = -// Factory, unsigned, const Json&>::instance() -// ->create("LinearElastic3D", std::move(solid_mid), -// jsolid_material); -// auto liquid_material = -// Factory, unsigned, const Json&>::instance() -// ->create("Newtonian3D", std::move(liquid_mid), -// jliquid_material); -// std::vector>> materials; -// materials.emplace_back(solid_material); -// materials.emplace_back(liquid_material); - -// // Reinitialise particle from HDF5 data -// REQUIRE(rparticle->initialise_particle(received, materials) == true); - -// // Check particle id -// REQUIRE(rparticle->id() == h5_particle.id); -// // Check particle mass -// REQUIRE(rparticle->mass() == h5_particle.mass); -// // Check particle volume -// REQUIRE(rparticle->volume() == h5_particle.volume); -// // Check particle mass density -// REQUIRE(rparticle->mass_density() == -// h5_particle.mass / h5_particle.volume); -// // Check particle status -// REQUIRE(rparticle->status() == h5_particle.status); - -// // Check for coordinates -// auto coordinates = rparticle->coordinates(); -// REQUIRE(coordinates.size() == Dim); -// for (unsigned i = 0; i < coordinates.size(); ++i) -// REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); -// REQUIRE(coordinates.size() == Dim); - -// // Check for displacement -// auto pdisplacement = rparticle->displacement(); -// REQUIRE(pdisplacement.size() == Dim); -// for (unsigned i = 0; i < Dim; ++i) -// REQUIRE(pdisplacement(i) == -// Approx(displacement(i)).epsilon(Tolerance)); - -// // Check for size -// auto size = rparticle->natural_size(); -// REQUIRE(size.size() == Dim); -// for (unsigned i = 0; i < size.size(); ++i) -// REQUIRE(size(i) == Approx(lsize(i)).epsilon(Tolerance)); - -// // Check velocity -// auto pvelocity = rparticle->velocity(); -// REQUIRE(pvelocity.size() == Dim); -// for (unsigned i = 0; i < Dim; ++i) -// REQUIRE(pvelocity(i) == Approx(velocity(i)).epsilon(Tolerance)); - -// // Check stress -// auto pstress = rparticle->stress(); -// REQUIRE(pstress.size() == stress.size()); -// for (unsigned i = 0; i < stress.size(); ++i) -// REQUIRE(pstress(i) == Approx(stress(i)).epsilon(Tolerance)); - -// // Check strain -// auto pstrain = rparticle->strain(); -// REQUIRE(pstrain.size() == strain.size()); -// for (unsigned i = 0; i < strain.size(); ++i) -// REQUIRE(pstrain(i) == Approx(strain(i)).epsilon(Tolerance)); - -// // Check particle volumetric strain centroid -// REQUIRE(rparticle->volumetric_strain_centroid() == -// h5_particle.epsilon_v); - -// // Check cell id -// REQUIRE(rparticle->cell_id() == h5_particle.cell_id); - -// // Check material id -// REQUIRE(rparticle->material_id() == h5_particle.material_id); - -// // Get Particle HDF5 data -// auto h5_twophase_received = -// std::static_pointer_cast( -// rparticle->hdf5_ptr()); - -// // State variables -// REQUIRE(h5_twophase_received->nstate_vars == -// h5_particle.nstate_vars); -// // State variables -// for (unsigned i = 0; i < h5_particle.nstate_vars; ++i) -// REQUIRE(h5_twophase_received->svars[i] == -// Approx(h5_particle.svars[i]).epsilon(Tolerance)); - -// // Check liquid mass -// REQUIRE(rparticle->liquid_mass() == h5_particle.liquid_mass); - -// // Check liquid velocity -// auto pliquid_velocity = rparticle->liquid_velocity(); -// REQUIRE(pliquid_velocity.size() == Dim); -// for (unsigned i = 0; i < Dim; ++i) -// REQUIRE(pliquid_velocity(i) == -// Approx(liquid_velocity(i)).epsilon(Tolerance)); - -// // Check porosity -// REQUIRE(rparticle->porosity() == h5_particle.porosity); - -// // Check liquid material id -// REQUIRE(rparticle->material_id(mpm::ParticlePhase::Liquid) == -// h5_particle.liquid_material_id); - -// // Liquid state variables -// REQUIRE(h5_twophase_received->nliquid_state_vars == -// h5_particle.nliquid_state_vars); -// // Liquid state variables -// for (unsigned i = 0; i < h5_particle.nliquid_state_vars; ++i) -// REQUIRE(h5_twophase_received->liquid_svars[i] == -// Approx(h5_particle.liquid_svars[i]).epsilon(Tolerance)); -// } -// } -// } -// } -// #endif // MPI +#include + +#include "catch.hpp" + +#include "data_types.h" +#include "hdf5_particle_twophase.h" +#include "material.h" +#include "particle.h" +#include "particle_twophase.h" + +//! \brief Check particle class for serialization and deserialization +TEST_CASE("Twophase particle is checked for serialization and deserialization", + "[particle][3D][serialize][2Phase]") { + // Dimension + const unsigned Dim = 3; + // Dimension + const unsigned Dof = 3; + // Number of phases + const unsigned Nphases = 2; + // Phase + const unsigned phase = 0; + + // Check initialise particle from HDF5 file + SECTION("Check initialise particle HDF5") { + mpm::Index id = 0; + const double Tolerance = 1.E-7; + // Coordinates + Eigen::Matrix pcoords; + pcoords.setZero(); + + std::shared_ptr> particle = + std::make_shared>(id, pcoords); + + mpm::HDF5ParticleTwoPhase h5_particle; + h5_particle.id = 13; + h5_particle.mass = 501.5; + + Eigen::Vector3d coords; + coords << 1., 2., 0.; + h5_particle.coord_x = coords[0]; + h5_particle.coord_y = coords[1]; + h5_particle.coord_z = coords[2]; + + Eigen::Vector3d displacement; + displacement << 0.01, 0.02, 0.0; + h5_particle.displacement_x = displacement[0]; + h5_particle.displacement_y = displacement[1]; + h5_particle.displacement_z = displacement[2]; + + Eigen::Vector3d lsize; + lsize << 0.25, 0.5, 0.; + h5_particle.nsize_x = lsize[0]; + h5_particle.nsize_y = lsize[1]; + h5_particle.nsize_z = lsize[2]; + + Eigen::Vector3d velocity; + velocity << 1.5, 2.5, 0.0; + h5_particle.velocity_x = velocity[0]; + h5_particle.velocity_y = velocity[1]; + h5_particle.velocity_z = velocity[2]; + + Eigen::Matrix stress; + stress << 11.5, -12.5, 13.5, 14.5, -15.5, 16.5; + h5_particle.stress_xx = stress[0]; + h5_particle.stress_yy = stress[1]; + h5_particle.stress_zz = stress[2]; + h5_particle.tau_xy = stress[3]; + h5_particle.tau_yz = stress[4]; + h5_particle.tau_xz = stress[5]; + + Eigen::Matrix strain; + strain << 0.115, -0.125, 0.135, 0.145, -0.155, 0.165; + h5_particle.strain_xx = strain[0]; + h5_particle.strain_yy = strain[1]; + h5_particle.strain_zz = strain[2]; + h5_particle.gamma_xy = strain[3]; + h5_particle.gamma_yz = strain[4]; + h5_particle.gamma_xz = strain[5]; + + h5_particle.epsilon_v = strain.head(Dim).sum(); + + h5_particle.status = true; + + h5_particle.cell_id = 1; + + h5_particle.volume = 2.; + + h5_particle.material_id = 1; + + h5_particle.nstate_vars = 0; + + for (unsigned i = 0; i < h5_particle.nstate_vars; ++i) + h5_particle.svars[i] = 0.; + + h5_particle.liquid_mass = 100.1; + + Eigen::Vector3d liquid_velocity; + liquid_velocity << 5.5, 2.1, 4.2; + h5_particle.liquid_velocity_x = liquid_velocity[0]; + h5_particle.liquid_velocity_y = liquid_velocity[1]; + h5_particle.liquid_velocity_z = liquid_velocity[2]; + + h5_particle.porosity = 0.33; + + h5_particle.liquid_saturation = 1.; + + h5_particle.liquid_material_id = 2; + + h5_particle.nliquid_state_vars = 1; + + for (unsigned i = 0; i < h5_particle.nliquid_state_vars; ++i) + h5_particle.liquid_svars[i] = 0.; + + // Reinitialise particle from HDF5 data + REQUIRE(particle->initialise_particle(h5_particle) == true); + + // Assign material + unsigned solid_mid = 1; + unsigned liquid_mid = 2; + // Initialise material + Json jsolid_material; + Json jliquid_material; + jsolid_material["density"] = 1000.; + jsolid_material["youngs_modulus"] = 1.0E+7; + jsolid_material["poisson_ratio"] = 0.3; + jsolid_material["porosity"] = 0.3; + jsolid_material["k_x"] = 0.001; + jsolid_material["k_y"] = 0.001; + jsolid_material["k_z"] = 0.001; + jliquid_material["density"] = 1000.; + jliquid_material["bulk_modulus"] = 2.0E9; + jliquid_material["dynamic_viscosity"] = 8.90E-4; + + auto solid_material = + Factory, unsigned, const Json&>::instance()->create( + "LinearElastic3D", std::move(solid_mid), jsolid_material); + auto liquid_material = + Factory, unsigned, const Json&>::instance()->create( + "Newtonian3D", std::move(liquid_mid), jliquid_material); + std::vector>> materials; + materials.emplace_back(solid_material); + materials.emplace_back(liquid_material); + + // Serialize particle + auto buffer = particle->serialize(); + REQUIRE(buffer.size() > 0); + + // Deserialize particle + std::shared_ptr> rparticle = + std::make_shared>(id, pcoords); + + REQUIRE_NOTHROW(rparticle->deserialize(buffer, materials)); + + // Check particle id + REQUIRE(particle->id() == particle->id()); + // Check particle mass + REQUIRE(particle->mass() == rparticle->mass()); + // Check particle volume + REQUIRE(particle->volume() == rparticle->volume()); + // Check particle status + REQUIRE(particle->status() == rparticle->status()); + + // Check for coordinates + auto coordinates = rparticle->coordinates(); + REQUIRE(coordinates.size() == Dim); + for (unsigned i = 0; i < coordinates.size(); ++i) + REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + + // Check for displacement + auto pdisplacement = rparticle->displacement(); + REQUIRE(pdisplacement.size() == Dim); + for (unsigned i = 0; i < Dim; ++i) + REQUIRE(pdisplacement(i) == Approx(displacement(i)).epsilon(Tolerance)); + + // Check for size + auto size = rparticle->natural_size(); + REQUIRE(size.size() == Dim); + for (unsigned i = 0; i < size.size(); ++i) + REQUIRE(size(i) == Approx(lsize(i)).epsilon(Tolerance)); + + // Check velocity + auto pvelocity = rparticle->velocity(); + REQUIRE(pvelocity.size() == Dim); + for (unsigned i = 0; i < Dim; ++i) + REQUIRE(pvelocity(i) == Approx(velocity(i)).epsilon(Tolerance)); + + // Check stress + auto pstress = rparticle->stress(); + REQUIRE(pstress.size() == stress.size()); + for (unsigned i = 0; i < stress.size(); ++i) + REQUIRE(pstress(i) == Approx(stress(i)).epsilon(Tolerance)); + + // Check strain + auto pstrain = rparticle->strain(); + REQUIRE(pstrain.size() == strain.size()); + for (unsigned i = 0; i < strain.size(); ++i) + REQUIRE(pstrain(i) == Approx(strain(i)).epsilon(Tolerance)); + + // Check particle volumetric strain centroid + REQUIRE(particle->volumetric_strain_centroid() == + rparticle->volumetric_strain_centroid()); + + // Check cell id + REQUIRE(particle->cell_id() == rparticle->cell_id()); + + // Check material id + REQUIRE(particle->material_id() == rparticle->material_id()); + + // Check liquid mass + REQUIRE(particle->liquid_mass() == rparticle->liquid_mass()); + + // Check liquid velocity + auto pliquid_velocity = rparticle->liquid_velocity(); + REQUIRE(pliquid_velocity.size() == Dim); + for (unsigned i = 0; i < Dim; ++i) + REQUIRE(pliquid_velocity(i) == + Approx(liquid_velocity(i)).epsilon(Tolerance)); + + // Check porosity + REQUIRE(particle->porosity() == rparticle->porosity()); + + // Check liquid material id + REQUIRE(particle->material_id(mpm::ParticlePhase::Liquid) == + rparticle->material_id(mpm::ParticlePhase::Liquid)); + + SECTION("Performance benchmarks") { + // Number of iterations + unsigned niterations = 1000; + + // Serialization benchmarks + auto serialize_start = std::chrono::steady_clock::now(); + for (unsigned i = 0; i < niterations; ++i) { + // Serialize particle + auto buffer = particle->serialize(); + // Deserialize particle + std::shared_ptr> rparticle = + std::make_shared>(id, pcoords); + + REQUIRE_NOTHROW(rparticle->deserialize(buffer, materials)); + } + auto serialize_end = std::chrono::steady_clock::now(); + } + } +} From a4dfb7601ecfa9cedc7161c72fa051e27fb849de Mon Sep 17 00:00:00 2001 From: Nanda Date: Sat, 22 Aug 2020 18:25:17 -0700 Subject: [PATCH 130/175] :wrench: change if throw to assert --- include/particles/particle_twophase.tcc | 76 ++++++++++++------------- 1 file changed, 36 insertions(+), 40 deletions(-) diff --git a/include/particles/particle_twophase.tcc b/include/particles/particle_twophase.tcc index 480f8fa0f..ba155ee5c 100644 --- a/include/particles/particle_twophase.tcc +++ b/include/particles/particle_twophase.tcc @@ -1090,17 +1090,13 @@ void mpm::TwoPhaseParticle::deserialize( int type; MPI_Unpack(data_ptr, data.size(), &position, &type, 1, MPI_INT, MPI_COMM_WORLD); - if (type != ParticleType.at(this->type())) - throw std::runtime_error("Deserialize particle(): particle type mismatch"); + assert(type == ParticleType.at(this->type())); // nmaterials int nmaterials = 0; MPI_Unpack(data_ptr, data.size(), &position, &nmaterials, 1, MPI_UNSIGNED, MPI_COMM_WORLD); - if (nmaterials != materials.size()) - throw std::runtime_error( - "Deserialize particle(): nmaterials mismatch with the input materials " - "size"); + assert(nmaterials == materials.size()); // Material ID MPI_Unpack(data_ptr, data.size(), &position, @@ -1156,12 +1152,13 @@ void mpm::TwoPhaseParticle::deserialize( MPI_COMM_WORLD); // Assign materials - if (material_id_[mpm::ParticlePhase::Solid] == - materials.at(mpm::ParticlePhase::Solid)->id()) { - bool assign_mat = this->assign_material( - materials.at(mpm::ParticlePhase::Solid), mpm::ParticlePhase::Solid); - if (!assign_mat) throw std::runtime_error("Material assignment failed"); - } + assert(material_id_[mpm::ParticlePhase::Solid] == + materials.at(mpm::ParticlePhase::Solid)->id()); + bool assign_mat = this->assign_material( + materials.at(mpm::ParticlePhase::Solid), mpm::ParticlePhase::Solid); + if (!assign_mat) + throw std::runtime_error( + "deserialize particle(): Solid material assignment failed"); // nstate vars unsigned nstate_vars; @@ -1177,18 +1174,17 @@ void mpm::TwoPhaseParticle::deserialize( // Reinitialize state variables auto mat_state_vars = (this->material(mpm::ParticlePhase::Solid)) ->initialise_state_variables(); - if (mat_state_vars.size() == nstate_vars) { - unsigned i = 0; - auto state_variables = - (this->material(mpm::ParticlePhase::Solid))->state_variables(); - for (const auto& state_var : state_variables) { - this->state_variables_[mpm::ParticlePhase::Solid].at(state_var) = - svars[i]; - ++i; - } - } else + if (mat_state_vars.size() != nstate_vars) throw std::runtime_error( - "Deserialize particle(): state_vars size mismatch"); + "Deserialize particle(): Solid phase state_vars size mismatch"); + unsigned i = 0; + auto state_variables = + (this->material(mpm::ParticlePhase::Solid))->state_variables(); + for (const auto& state_var : state_variables) { + this->state_variables_[mpm::ParticlePhase::Solid].at(state_var) = + svars[i]; + ++i; + } } // Liquid Phase @@ -1209,12 +1205,13 @@ void mpm::TwoPhaseParticle::deserialize( this->assign_permeability(); // Assign liquid materials - if (material_id_[mpm::ParticlePhase::Liquid] == - materials.at(mpm::ParticlePhase::Liquid)->id()) { - bool assign_mat = this->assign_material( - materials.at(mpm::ParticlePhase::Liquid), mpm::ParticlePhase::Liquid); - if (!assign_mat) throw std::runtime_error("Material assignment failed"); - } + assert(material_id_[mpm::ParticlePhase::Liquid] == + materials.at(mpm::ParticlePhase::Liquid)->id()); + assign_mat = this->assign_material(materials.at(mpm::ParticlePhase::Liquid), + mpm::ParticlePhase::Liquid); + if (!assign_mat) + throw std::runtime_error( + "deserialize particle(): Liquid material assignment failed"); // nliquid state vars unsigned nliquid_state_vars; @@ -1230,18 +1227,17 @@ void mpm::TwoPhaseParticle::deserialize( // Reinitialize state variables auto mat_state_vars = (this->material(mpm::ParticlePhase::Liquid)) ->initialise_state_variables(); - if (mat_state_vars.size() == nliquid_state_vars) { - unsigned i = 0; - auto state_variables = - (this->material(mpm::ParticlePhase::Liquid))->state_variables(); - for (const auto& state_var : state_variables) { - this->state_variables_[mpm::ParticlePhase::Liquid].at(state_var) = - svars[i]; - ++i; - } - } else + if (mat_state_vars.size() == nliquid_state_vars) throw std::runtime_error( - "Deserialize particle(): liquid_state_vars size mismatch"); + "Deserialize particle(): Liquid phase state_vars size mismatch"); + unsigned i = 0; + auto state_variables = + (this->material(mpm::ParticlePhase::Liquid))->state_variables(); + for (const auto& state_var : state_variables) { + this->state_variables_[mpm::ParticlePhase::Liquid].at(state_var) = + svars[i]; + ++i; + } } #endif } \ No newline at end of file From 6992ada48abec1af53a5b34304d7d6af1b13ce2f Mon Sep 17 00:00:00 2001 From: Nanda Date: Sun, 23 Aug 2020 20:19:19 -0700 Subject: [PATCH 131/175] :construction: add particle_types_ and modify write_hdf5() --- include/mesh.h | 14 ++++++++++++-- include/mesh.tcc | 14 ++++++++------ include/solvers/mpm_base.h | 2 ++ include/solvers/mpm_base.tcc | 19 ++++++++++++------- tests/mesh_test_2d.cc | 3 ++- tests/mesh_test_3d.cc | 3 ++- 6 files changed, 38 insertions(+), 17 deletions(-) diff --git a/include/mesh.h b/include/mesh.h index 68d21a85b..36cdcaf4c 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -238,6 +238,15 @@ class Mesh { //! Number of particles in the mesh mpm::Index nparticles() const { return particles_.size(); } + //! Number of particles in the mesh with specific type + //! \param[in] particle particle_type A string denoting particle type + mpm::Index nparticles(const std::string& particle_type) const { + mpm::Index counter = 0; + for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) + if ((*pitr)->type() == particle_type) counter++; + return counter; + } + //! Locate particles in a cell //! Iterate over all cells in a mesh to find the cell in which particles //! are located. @@ -396,10 +405,11 @@ class Mesh { void find_ghost_boundary_cells(); //! Write HDF5 particles - //! \param[in] phase Index corresponding to the phase //! \param[in] filename Name of HDF5 file to write particles data + //! \param[in] particle_type Name of particle type to write //! \retval status Status of writing HDF5 output - bool write_particles_hdf5(unsigned phase, const std::string& filename); + bool write_particles_hdf5(const std::string& filename, + const std::string& particle_type); //! Read HDF5 particles //! \param[in] phase Index corresponding to the phase diff --git a/include/mesh.tcc b/include/mesh.tcc index 0b94c89f3..e43528569 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1437,17 +1437,19 @@ std::vector> mpm::Mesh::particles_cells() //! Write particles to HDF5 template -bool mpm::Mesh::write_particles_hdf5(unsigned phase, - const std::string& filename) { - const unsigned nparticles = this->nparticles(); +bool mpm::Mesh::write_particles_hdf5(const std::string& filename, + const std::string& particle_type) { + const unsigned nparticles = this->nparticles(particle_type); std::vector particle_data; // = new HDF5Particle[nparticles]; particle_data.reserve(nparticles); for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { - auto hdf5_ptr = - std::static_pointer_cast((*pitr)->hdf5_ptr()); - particle_data.emplace_back(*hdf5_ptr); + if ((*pitr)->type() == particle_type) { + auto hdf5_ptr = + std::static_pointer_cast((*pitr)->hdf5_ptr()); + particle_data.emplace_back(*hdf5_ptr); + } } // Calculate the size and the offsets of our struct members in memory diff --git a/include/solvers/mpm_base.h b/include/solvers/mpm_base.h index 592956898..2426aaeac 100644 --- a/include/solvers/mpm_base.h +++ b/include/solvers/mpm_base.h @@ -209,6 +209,8 @@ class MPMBase : public MPM { std::shared_ptr> mesh_; //! Constraints object std::shared_ptr> constraints_; + //! Particle types + std::set particle_types_; //! Materials std::map>> materials_; //! Mathematical functions diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index af2c10f45..f8c63a552 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -306,6 +306,10 @@ void mpm::MPMBase::initialise_particles() { if (!gen_status) std::runtime_error( "mpm::base::init_particles() Generate particles failed"); + // Gather particle types + auto particle_type = + json_particle["generator"]["particle_type"].template get(); + particle_types_.insert(particle_type); } auto particles_gen_end = std::chrono::steady_clock::now(); @@ -487,15 +491,16 @@ bool mpm::MPMBase::checkpoint_resume() { //! Write HDF5 files template void mpm::MPMBase::write_hdf5(mpm::Index step, mpm::Index max_steps) { - // Write input geometry to vtk file - std::string attribute = "particles"; - std::string extension = ".h5"; + for (const std::string& p_type : particle_types_) { + // Write input geometry to vtk file + std::string attribute = "particles" + p_type; + std::string extension = ".h5"; - auto particles_file = - io_->output_file(attribute, extension, uuid_, step, max_steps).string(); + auto particles_file = + io_->output_file(attribute, extension, uuid_, step, max_steps).string(); - const unsigned phase = 0; - mesh_->write_particles_hdf5(phase, particles_file); + mesh_->write_particles_hdf5(particles_file, p_type); + } } #ifdef USE_VTK diff --git a/tests/mesh_test_2d.cc b/tests/mesh_test_2d.cc index eedc61044..195c1bb9e 100644 --- a/tests/mesh_test_2d.cc +++ b/tests/mesh_test_2d.cc @@ -906,7 +906,8 @@ TEST_CASE("Mesh is checked for 2D case", "[mesh][2D]") { // Test HDF5 SECTION("Write particles HDF5") { - REQUIRE(mesh->write_particles_hdf5(0, "particles-2d.h5") == true); + REQUIRE(mesh->write_particles_hdf5("particles-2d.h5", + particle_type) == true); auto phdf5 = mesh->particles_hdf5(); REQUIRE(phdf5.size() == mesh->nparticles()); diff --git a/tests/mesh_test_3d.cc b/tests/mesh_test_3d.cc index 06f4e0cf2..081c63bf4 100644 --- a/tests/mesh_test_3d.cc +++ b/tests/mesh_test_3d.cc @@ -1001,7 +1001,8 @@ TEST_CASE("Mesh is checked for 3D case", "[mesh][3D]") { } // Test HDF5 SECTION("Write particles HDF5") { - REQUIRE(mesh->write_particles_hdf5(0, "particles-3d.h5") == true); + REQUIRE(mesh->write_particles_hdf5("particles-3d.h5", + particle_type) == true); auto phdf5 = mesh->particles_hdf5(); REQUIRE(phdf5.size() == mesh->nparticles()); From 8b7f384fb3ed6dce959be65ec690cce34d9a0457 Mon Sep 17 00:00:00 2001 From: Nanda Date: Mon, 24 Aug 2020 16:33:48 -0700 Subject: [PATCH 132/175] :construction: chang read_hdf5 --- include/mesh.h | 5 +- include/mesh.tcc | 123 ++++++++++++++++++++++------------- include/solvers/mpm_base.tcc | 5 +- 3 files changed, 81 insertions(+), 52 deletions(-) diff --git a/include/mesh.h b/include/mesh.h index 36cdcaf4c..fafe61d38 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -412,10 +412,11 @@ class Mesh { const std::string& particle_type); //! Read HDF5 particles - //! \param[in] phase Index corresponding to the phase //! \param[in] filename Name of HDF5 file to write particles data + //! \param[in] particle_types set of particle types to write //! \retval status Status of reading HDF5 output - bool read_particles_hdf5(unsigned phase, const std::string& filename); + bool read_particles_hdf5(const std::string& filename, + const std::set& particle_types); //! Return HDF5 particles //! \retval particles_hdf5 Vector of HDF5 particles diff --git a/include/mesh.tcc b/include/mesh.tcc index e43528569..d129f993d 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1455,8 +1455,6 @@ bool mpm::Mesh::write_particles_hdf5(const std::string& filename, // Calculate the size and the offsets of our struct members in memory const hsize_t NRECORDS = nparticles; - const hsize_t NFIELDS = mpm::hdf5::particle::NFIELDS; - hid_t file_id; hsize_t chunk_size = 10000; int* fill_data = NULL; @@ -1466,12 +1464,24 @@ bool mpm::Mesh::write_particles_hdf5(const std::string& filename, file_id = H5Fcreate(filename.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); - // make a table - H5TBmake_table( - "Table Title", file_id, "table", NFIELDS, NRECORDS, - mpm::hdf5::particle::dst_size, mpm::hdf5::particle::field_names, - mpm::hdf5::particle::dst_offset, mpm::hdf5::particle::field_type, - chunk_size, fill_data, compress, particle_data.data()); + if (particle_type == "P2D" || particle_type == "P3D") { + const hsize_t NFIELDS = mpm::hdf5::particle::NFIELDS; + // make a table + H5TBmake_table( + "Table Title", file_id, "table", NFIELDS, NRECORDS, + mpm::hdf5::particle::dst_size, mpm::hdf5::particle::field_names, + mpm::hdf5::particle::dst_offset, mpm::hdf5::particle::field_type, + chunk_size, fill_data, compress, particle_data.data()); + } else if (particle_type == "P2D2PHASE" || particle_type == "P3D2PHASE") { + const hsize_t NFIELDS = mpm::hdf5::particletwophase::NFIELDS; + // make a table + H5TBmake_table("Table Title", file_id, "table", NFIELDS, NRECORDS, + mpm::hdf5::particletwophase::dst_size, + mpm::hdf5::particletwophase::field_names, + mpm::hdf5::particletwophase::dst_offset, + mpm::hdf5::particletwophase::field_type, chunk_size, + fill_data, compress, particle_data.data()); + } H5Fclose(file_id); return true; @@ -1479,52 +1489,73 @@ bool mpm::Mesh::write_particles_hdf5(const std::string& filename, //! Write particles to HDF5 template -bool mpm::Mesh::read_particles_hdf5(unsigned phase, - const std::string& filename) { - - // Create a new file using default properties. - hid_t file_id = H5Fopen(filename.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT); - // Throw an error if file can't be found - if (file_id < 0) throw std::runtime_error("HDF5 particle file is not found"); - - // Calculate the size and the offsets of our struct members in memory - hsize_t nrecords = 0; - hsize_t nfields = 0; - H5TBget_table_info(file_id, "table", &nfields, &nrecords); - - if (nfields != mpm::hdf5::particle::NFIELDS) - throw std::runtime_error("HDF5 table has incorrect number of fields"); - - std::vector dst_buf; - dst_buf.reserve(nrecords); - // Read the table - H5TBread_table(file_id, "table", mpm::hdf5::particle::dst_size, - mpm::hdf5::particle::dst_offset, - mpm::hdf5::particle::dst_sizes, dst_buf.data()); - +bool mpm::Mesh::read_particles_hdf5( + const std::string& filename, const std::set& particle_types) { // Vector of particles Vector> particles; // Clear map of particles map_particles_.clear(); - unsigned i = 0; - for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { - if (i < nrecords) { - HDF5Particle particle = dst_buf[i]; - // Get particle's material from list of materials - std::vector>> materials; - materials.emplace_back(materials_.at(particle.material_id)); - // Initialise particle with HDF5 data - (*pitr)->initialise_particle(particle, materials); - // Add particle to map - map_particles_.insert(particle.id, *pitr); - particles.add(*pitr); - ++i; + for (const std::string& particle_type : particle_types) { + // Create a new file using default properties. + const std::string new_file_name = filename + particle_type; + hid_t file_id = H5Fopen(new_file_name.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT); + // Throw an error if file can't be found + if (file_id < 0) + throw std::runtime_error("HDF5 particle file is not found"); + + // Calculate the size and the offsets of our struct members in memory + hsize_t nrecords = 0; + hsize_t nfields = 0; + H5TBget_table_info(file_id, "table", &nfields, &nrecords); + + std::vector dst_buf; + dst_buf.reserve(nrecords); + + if (particle_type == "P2D" || particle_type == "P3D") { + if (nfields != mpm::hdf5::particle::NFIELDS) + throw std::runtime_error("HDF5 table has incorrect number of fields"); + // Read the table + H5TBread_table(file_id, "table", mpm::hdf5::particle::dst_size, + mpm::hdf5::particle::dst_offset, + mpm::hdf5::particle::dst_sizes, dst_buf.data()); + } else if (particle_type == "P2D2PHASE" || particle_type == "P3D2PHASE") { + if (nfields != mpm::hdf5::particletwophase::NFIELDS) + throw std::runtime_error("HDF5 table has incorrect number of fields"); + // Read the table + H5TBread_table(file_id, "table", mpm::hdf5::particletwophase::dst_size, + mpm::hdf5::particletwophase::dst_offset, + mpm::hdf5::particletwophase::dst_sizes, dst_buf.data()); + } + + unsigned i = 0; + for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { + if (i < nrecords && (*pitr)->type() == particle_type) { + HDF5Particle particle = dst_buf[i]; + // Get particle's material from list of materials + std::vector>> materials; + materials.emplace_back(materials_.at(particle.material_id)); + + // Append more materials for twophase particles + if (particle_type == "P2D2PHASE" || particle_type == "P3D2PHASE") { + auto twophase_particle = + reinterpret_cast(&particle); + materials.emplace_back( + materials_.at(twophase_particle->liquid_material_id)); + } + + // Initialise particle with HDF5 data + (*pitr)->initialise_particle(particle, materials); + // Add particle to map + map_particles_.insert(particle.id, *pitr); + particles.add(*pitr); + ++i; + } } + // close the file + H5Fclose(file_id); } - // close the file - H5Fclose(file_id); // Overwrite particles container this->particles_ = particles; diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index f8c63a552..07ed2da92 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -437,9 +437,6 @@ template bool mpm::MPMBase::checkpoint_resume() { bool checkpoint = true; try { - // TODO: Set phase - const unsigned phase = 0; - int mpi_rank = 0; #ifdef USE_MPI MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); @@ -462,7 +459,7 @@ bool mpm::MPMBase::checkpoint_resume() { .string(); // Load particle information from file - mesh_->read_particles_hdf5(phase, particles_file); + mesh_->read_particles_hdf5(particles_file, particle_types_); // Clear all particle ids mesh_->iterate_over_cells( From 78a0e5ac56e6d064027662b13ce20b8c4b808b60 Mon Sep 17 00:00:00 2001 From: Nanda Date: Mon, 24 Aug 2020 16:42:45 -0700 Subject: [PATCH 133/175] :dart: reactivate resume test --- .../solvers/mpm_explicit_twophase_usf_test.cc | 78 +++++++++---------- .../solvers/mpm_explicit_twophase_usl_test.cc | 78 +++++++++---------- 2 files changed, 76 insertions(+), 80 deletions(-) diff --git a/tests/solvers/mpm_explicit_twophase_usf_test.cc b/tests/solvers/mpm_explicit_twophase_usf_test.cc index c46565544..f98535f7d 100644 --- a/tests/solvers/mpm_explicit_twophase_usf_test.cc +++ b/tests/solvers/mpm_explicit_twophase_usf_test.cc @@ -69,26 +69,25 @@ TEST_CASE("MPM 2D Explicit TwoPhase implementation is checked", REQUIRE(mpm->checkpoint_resume() == false); } - // SECTION("Check resume") { - // // Write JSON file - // const std::string fname = "mpm-explicit-twophase-usf"; - // const std::string analysis = "MPMExplicitTwoPhase2D"; - // const std::string mpm_scheme = "usf"; - // bool resume = true; - // REQUIRE(mpm_test::write_json_twophase(2, resume, analysis, mpm_scheme, - // fname) == true); - - // // Create an IO object - // auto io = std::make_unique(argc, argv); - // // Run explicit MPM - // auto mpm = - // std::make_unique>(std::move(io)); - - // // Test check point restart - // REQUIRE(mpm->checkpoint_resume() == true); - // // Solve - // REQUIRE(mpm->solve() == true); - // } + SECTION("Check resume") { + // Write JSON file + const std::string fname = "mpm-explicit-twophase-usf"; + const std::string analysis = "MPMExplicitTwoPhase2D"; + const std::string mpm_scheme = "usf"; + bool resume = true; + REQUIRE(mpm_test::write_json_twophase(2, resume, analysis, mpm_scheme, + fname) == true); + + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit MPM + auto mpm = std::make_unique>(std::move(io)); + + // Test check point restart + REQUIRE(mpm->checkpoint_resume() == true); + // Solve + REQUIRE(mpm->solve() == true); + } SECTION("Check pressure smoothing") { // Create an IO object @@ -160,26 +159,25 @@ TEST_CASE("MPM 3D Explicit TwoPhase implementation is checked", REQUIRE(mpm->checkpoint_resume() == false); } - // SECTION("Check resume") { - // // Write JSON file - // const std::string fname = "mpm-explicit-twophase-usf"; - // const std::string analysis = "MPMExplicitTwoPhase3D"; - // const std::string mpm_scheme = "usf"; - // bool resume = true; - // REQUIRE(mpm_test::write_json_twophase(3, resume, analysis, mpm_scheme, - // fname) == true); - - // // Create an IO object - // auto io = std::make_unique(argc, argv); - // // Run explicit MPM - // auto mpm = - // std::make_unique>(std::move(io)); - - // // Test check point restart - // REQUIRE(mpm->checkpoint_resume() == true); - // // Solve - // REQUIRE(mpm->solve() == true); - // } + SECTION("Check resume") { + // Write JSON file + const std::string fname = "mpm-explicit-twophase-usf"; + const std::string analysis = "MPMExplicitTwoPhase3D"; + const std::string mpm_scheme = "usf"; + bool resume = true; + REQUIRE(mpm_test::write_json_twophase(3, resume, analysis, mpm_scheme, + fname) == true); + + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit MPM + auto mpm = std::make_unique>(std::move(io)); + + // Test check point restart + REQUIRE(mpm->checkpoint_resume() == true); + // Solve + REQUIRE(mpm->solve() == true); + } SECTION("Check pressure smoothing") { // Create an IO object diff --git a/tests/solvers/mpm_explicit_twophase_usl_test.cc b/tests/solvers/mpm_explicit_twophase_usl_test.cc index b039b17f3..2b8330032 100644 --- a/tests/solvers/mpm_explicit_twophase_usl_test.cc +++ b/tests/solvers/mpm_explicit_twophase_usl_test.cc @@ -69,26 +69,25 @@ TEST_CASE("MPM 2D Explicit USL TwoPhase implementation is checked", REQUIRE(mpm->checkpoint_resume() == false); } - // SECTION("Check resume") { - // // Write JSON file - // const std::string fname = "mpm-explicit-twophase-usl"; - // const std::string analysis = "MPMExplicitTwoPhase2D"; - // const std::string mpm_scheme = "usl"; - // bool resume = true; - // REQUIRE(mpm_test::write_json_twophase(2, resume, analysis, mpm_scheme, - // fname) == true); - - // // Create an IO object - // auto io = std::make_unique(argc, argv); - // // Run explicit MPM - // auto mpm = - // std::make_unique>(std::move(io)); - - // // Test check point restart - // REQUIRE(mpm->checkpoint_resume() == true); - // // Solve - // REQUIRE(mpm->solve() == true); - // } + SECTION("Check resume") { + // Write JSON file + const std::string fname = "mpm-explicit-twophase-usl"; + const std::string analysis = "MPMExplicitTwoPhase2D"; + const std::string mpm_scheme = "usl"; + bool resume = true; + REQUIRE(mpm_test::write_json_twophase(2, resume, analysis, mpm_scheme, + fname) == true); + + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit MPM + auto mpm = std::make_unique>(std::move(io)); + + // Test check point restart + REQUIRE(mpm->checkpoint_resume() == true); + // Solve + REQUIRE(mpm->solve() == true); + } SECTION("Check pressure smoothing") { // Create an IO object @@ -160,26 +159,25 @@ TEST_CASE("MPM 3D Explicit USL TwoPhase implementation is checked", REQUIRE(mpm->checkpoint_resume() == false); } - // SECTION("Check resume") { - // // Write JSON file - // const std::string fname = "mpm-explicit-twophase-usl"; - // const std::string analysis = "MPMExplicitTwoPhase3D"; - // const std::string mpm_scheme = "usl"; - // bool resume = true; - // REQUIRE(mpm_test::write_json_twophase(3, resume, analysis, mpm_scheme, - // fname) == true); - - // // Create an IO object - // auto io = std::make_unique(argc, argv); - // // Run explicit MPM - // auto mpm = - // std::make_unique>(std::move(io)); - - // // Test check point restart - // REQUIRE(mpm->checkpoint_resume() == true); - // // Solve - // REQUIRE(mpm->solve() == true); - // } + SECTION("Check resume") { + // Write JSON file + const std::string fname = "mpm-explicit-twophase-usl"; + const std::string analysis = "MPMExplicitTwoPhase3D"; + const std::string mpm_scheme = "usl"; + bool resume = true; + REQUIRE(mpm_test::write_json_twophase(3, resume, analysis, mpm_scheme, + fname) == true); + + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit MPM + auto mpm = std::make_unique>(std::move(io)); + + // Test check point restart + REQUIRE(mpm->checkpoint_resume() == true); + // Solve + REQUIRE(mpm->solve() == true); + } SECTION("Check pressure smoothing") { // Create an IO object From c91984195c9b527be9ff801a6eeb8ed8fca64bb8 Mon Sep 17 00:00:00 2001 From: Nanda Date: Mon, 24 Aug 2020 21:16:19 -0700 Subject: [PATCH 134/175] :construction: renaming HDF5Particle as PODParticle --- include/hdf5_particle.h | 8 +- include/hdf5_particle_twophase.h | 8 +- include/io/partio_writer.h | 2 +- include/mesh.h | 2 +- include/mesh.tcc | 16 +-- include/particles/particle.h | 4 +- include/particles/particle.tcc | 6 +- include/particles/particle_base.h | 4 +- include/particles/particle_twophase.h | 4 +- include/particles/particle_twophase.tcc | 10 +- src/hdf5_particle.cc | 108 +++++++------- src/hdf5_particle_twophase.cc | 134 +++++++++--------- src/io/partio_writer.cc | 2 +- .../particle_serialize_deserialize_test.cc | 2 +- ...cle_serialize_deserialize_twophase_test.cc | 2 +- tests/particles/particle_test.cc | 12 +- tests/particles/particle_twophase_test.cc | 12 +- 17 files changed, 168 insertions(+), 168 deletions(-) diff --git a/include/hdf5_particle.h b/include/hdf5_particle.h index 88489f232..07044a2f5 100644 --- a/include/hdf5_particle.h +++ b/include/hdf5_particle.h @@ -9,7 +9,7 @@ namespace mpm { // Define a struct of particle -typedef struct HDF5Particle { +typedef struct PODParticle { // Index mpm::Index id; // Mass @@ -45,14 +45,14 @@ typedef struct HDF5Particle { // State variables (init to zero) double svars[20] = {0}; // Destructor - virtual ~HDF5Particle() = default; -} HDF5Particle; + virtual ~PODParticle() = default; +} PODParticle; namespace hdf5 { namespace particle { const hsize_t NFIELDS = 53; -const size_t dst_size = sizeof(HDF5Particle); +const size_t dst_size = sizeof(PODParticle); // Destination offset extern const size_t dst_offset[NFIELDS]; diff --git a/include/hdf5_particle_twophase.h b/include/hdf5_particle_twophase.h index 7e91780d0..cdf61092c 100644 --- a/include/hdf5_particle_twophase.h +++ b/include/hdf5_particle_twophase.h @@ -6,7 +6,7 @@ namespace mpm { // Define a struct of particle -typedef struct HDF5ParticleTwoPhase : HDF5Particle { +typedef struct PODParticleTwoPhase : PODParticle { // Liquid Mass double liquid_mass; // Liquid Velocity @@ -22,14 +22,14 @@ typedef struct HDF5ParticleTwoPhase : HDF5Particle { // State variables (init to zero) double liquid_svars[5] = {0}; // Destructor - virtual ~HDF5ParticleTwoPhase() = default; -} HDF5ParticleTwoPhase; + virtual ~PODParticleTwoPhase() = default; +} PODParticleTwoPhase; namespace hdf5 { namespace particletwophase { const hsize_t NFIELDS = 66; -const size_t dst_size = sizeof(HDF5ParticleTwoPhase); +const size_t dst_size = sizeof(PODParticleTwoPhase); // Destination offset extern const size_t dst_offset[NFIELDS]; diff --git a/include/io/partio_writer.h b/include/io/partio_writer.h index a15d97c12..e91f14f9b 100644 --- a/include/io/partio_writer.h +++ b/include/io/partio_writer.h @@ -15,7 +15,7 @@ namespace mpm::partio { //! \param[in] filename Mesh VTP file //! \param[in] particles HDF5 particles bool write_particles(const std::string& filename, - const std::vector& particles); + const std::vector& particles); } // namespace mpm::partio diff --git a/include/mesh.h b/include/mesh.h index fafe61d38..18cafc9e0 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -420,7 +420,7 @@ class Mesh { //! Return HDF5 particles //! \retval particles_hdf5 Vector of HDF5 particles - std::vector particles_hdf5() const; + std::vector particles_hdf5() const; //! Return nodal coordinates std::vector> nodal_coordinates() const; diff --git a/include/mesh.tcc b/include/mesh.tcc index d129f993d..f48e3d554 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1441,13 +1441,13 @@ bool mpm::Mesh::write_particles_hdf5(const std::string& filename, const std::string& particle_type) { const unsigned nparticles = this->nparticles(particle_type); - std::vector particle_data; // = new HDF5Particle[nparticles]; + std::vector particle_data; // = new PODParticle[nparticles]; particle_data.reserve(nparticles); for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { if ((*pitr)->type() == particle_type) { auto hdf5_ptr = - std::static_pointer_cast((*pitr)->hdf5_ptr()); + std::static_pointer_cast((*pitr)->hdf5_ptr()); particle_data.emplace_back(*hdf5_ptr); } } @@ -1510,7 +1510,7 @@ bool mpm::Mesh::read_particles_hdf5( hsize_t nfields = 0; H5TBget_table_info(file_id, "table", &nfields, &nrecords); - std::vector dst_buf; + std::vector dst_buf; dst_buf.reserve(nrecords); if (particle_type == "P2D" || particle_type == "P3D") { @@ -1532,7 +1532,7 @@ bool mpm::Mesh::read_particles_hdf5( unsigned i = 0; for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { if (i < nrecords && (*pitr)->type() == particle_type) { - HDF5Particle particle = dst_buf[i]; + PODParticle particle = dst_buf[i]; // Get particle's material from list of materials std::vector>> materials; materials.emplace_back(materials_.at(particle.material_id)); @@ -1540,7 +1540,7 @@ bool mpm::Mesh::read_particles_hdf5( // Append more materials for twophase particles if (particle_type == "P2D2PHASE" || particle_type == "P3D2PHASE") { auto twophase_particle = - reinterpret_cast(&particle); + reinterpret_cast(&particle); materials.emplace_back( materials_.at(twophase_particle->liquid_material_id)); } @@ -1569,15 +1569,15 @@ bool mpm::Mesh::read_particles_hdf5( //! Write particles to HDF5 template -std::vector mpm::Mesh::particles_hdf5() const { +std::vector mpm::Mesh::particles_hdf5() const { const unsigned nparticles = this->nparticles(); - std::vector particles_hdf5; + std::vector particles_hdf5; particles_hdf5.reserve(nparticles); for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { auto hdf5_ptr = - std::static_pointer_cast((*pitr)->hdf5_ptr()); + std::static_pointer_cast((*pitr)->hdf5_ptr()); particles_hdf5.emplace_back(*hdf5_ptr); } diff --git a/include/particles/particle.h b/include/particles/particle.h index a991ade78..a158b38a0 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -49,14 +49,14 @@ class Particle : public ParticleBase { //! Initialise particle from HDF5 data //! \param[in] particle HDF5 data of particle //! \retval status Status of reading HDF5 particle - bool initialise_particle(HDF5Particle& particle) override; + bool initialise_particle(PODParticle& particle) override; //! Initialise particle HDF5 data and material //! \param[in] particle HDF5 data of particle //! \param[in] material Material associated with the particle //! \retval status Status of reading HDF5 particle virtual bool initialise_particle( - HDF5Particle& particle, + PODParticle& particle, const std::vector>>& materials) override; //! Return particle data as HDF5 pointer diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index 75ca6ad9c..cdee4bbb9 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -32,7 +32,7 @@ mpm::Particle::Particle(Index id, const VectorDim& coord, bool status) //! Initialise particle data from HDF5 template -bool mpm::Particle::initialise_particle(HDF5Particle& particle) { +bool mpm::Particle::initialise_particle(PODParticle& particle) { // Assign id this->id_ = particle.id; @@ -105,7 +105,7 @@ bool mpm::Particle::initialise_particle(HDF5Particle& particle) { //! Initialise particle data from HDF5 template bool mpm::Particle::initialise_particle( - HDF5Particle& particle, + PODParticle& particle, const std::vector>>& materials) { bool status = this->initialise_particle(particle); @@ -141,7 +141,7 @@ template // cppcheck-suppress * std::shared_ptr mpm::Particle::hdf5_ptr() { // Initialise particle data - auto particle_data = std::make_shared(); + auto particle_data = std::make_shared(); Eigen::Vector3d coordinates; coordinates.setZero(); diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 15c331c84..9cb676355 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -69,14 +69,14 @@ class ParticleBase { //! Initialise particle HDF5 data //! \param[in] particle HDF5 data of particle //! \retval status Status of reading HDF5 particle - virtual bool initialise_particle(HDF5Particle& particle) = 0; + virtual bool initialise_particle(PODParticle& particle) = 0; //! Initialise particle HDF5 data and material //! \param[in] particle HDF5 data of particle //! \param[in] material Material associated with the particle //! \retval status Status of reading HDF5 particle virtual bool initialise_particle( - HDF5Particle& particle, + PODParticle& particle, const std::vector>>& materials) = 0; //! Return particle data as HDF5 pointer diff --git a/include/particles/particle_twophase.h b/include/particles/particle_twophase.h index ea7ac81ae..28c8cde38 100644 --- a/include/particles/particle_twophase.h +++ b/include/particles/particle_twophase.h @@ -45,7 +45,7 @@ class TwoPhaseParticle : public mpm::Particle { //! Initialise particle from HDF5 data //! \param[in] particle HDF5 data of particle //! \retval status Status of reading HDF5 particle - bool initialise_particle(HDF5Particle& particle) override; + bool initialise_particle(PODParticle& particle) override; //! Initialise particle HDF5 data and material //! \param[in] particle HDF5 data of particle @@ -53,7 +53,7 @@ class TwoPhaseParticle : public mpm::Particle { //! \param[in] liquid_material Liquid material associated with the particle //! \retval status Status of reading HDF5 particle bool initialise_particle( - HDF5Particle& particle, + PODParticle& particle, const std::vector>>& materials) override; //! Initialise particle liquid phase on top of the regular solid phase diff --git a/include/particles/particle_twophase.tcc b/include/particles/particle_twophase.tcc index ba155ee5c..0ee3e3418 100644 --- a/include/particles/particle_twophase.tcc +++ b/include/particles/particle_twophase.tcc @@ -36,7 +36,7 @@ template // cppcheck-suppress * std::shared_ptr mpm::TwoPhaseParticle::hdf5_ptr() { // Initialise particle_data - auto particle_data = std::make_shared(); + auto particle_data = std::make_shared(); Eigen::Vector3d coordinates; coordinates.setZero(); @@ -164,10 +164,10 @@ std::shared_ptr mpm::TwoPhaseParticle::hdf5_ptr() { //! Initialise particle data from HDF5 template -bool mpm::TwoPhaseParticle::initialise_particle(HDF5Particle& particle) { +bool mpm::TwoPhaseParticle::initialise_particle(PODParticle& particle) { // Initialise solid phase bool status = mpm::Particle::initialise_particle(particle); - auto twophase_particle = reinterpret_cast(&particle); + auto twophase_particle = reinterpret_cast(&particle); // Liquid mass this->liquid_mass_ = twophase_particle->liquid_mass; @@ -198,9 +198,9 @@ bool mpm::TwoPhaseParticle::initialise_particle(HDF5Particle& particle) { //! Initialise particle data from HDF5 template bool mpm::TwoPhaseParticle::initialise_particle( - HDF5Particle& particle, + PODParticle& particle, const std::vector>>& materials) { - auto twophase_particle = reinterpret_cast(&particle); + auto twophase_particle = reinterpret_cast(&particle); bool status = this->initialise_particle(*twophase_particle); assert(materials.size() == 2); diff --git a/src/hdf5_particle.cc b/src/hdf5_particle.cc index 0b42b19a5..141bd1e45 100644 --- a/src/hdf5_particle.cc +++ b/src/hdf5_particle.cc @@ -3,63 +3,63 @@ namespace mpm { namespace hdf5 { namespace particle { const size_t dst_offset[NFIELDS] = { - HOFFSET(HDF5Particle, id), - HOFFSET(HDF5Particle, mass), - HOFFSET(HDF5Particle, volume), - HOFFSET(HDF5Particle, pressure), - HOFFSET(HDF5Particle, coord_x), - HOFFSET(HDF5Particle, coord_y), - HOFFSET(HDF5Particle, coord_z), - HOFFSET(HDF5Particle, displacement_x), - HOFFSET(HDF5Particle, displacement_y), - HOFFSET(HDF5Particle, displacement_z), - HOFFSET(HDF5Particle, nsize_x), - HOFFSET(HDF5Particle, nsize_y), - HOFFSET(HDF5Particle, nsize_z), - HOFFSET(HDF5Particle, velocity_x), - HOFFSET(HDF5Particle, velocity_y), - HOFFSET(HDF5Particle, velocity_z), - HOFFSET(HDF5Particle, stress_xx), - HOFFSET(HDF5Particle, stress_yy), - HOFFSET(HDF5Particle, stress_zz), - HOFFSET(HDF5Particle, tau_xy), - HOFFSET(HDF5Particle, tau_yz), - HOFFSET(HDF5Particle, tau_xz), - HOFFSET(HDF5Particle, strain_xx), - HOFFSET(HDF5Particle, strain_yy), - HOFFSET(HDF5Particle, strain_zz), - HOFFSET(HDF5Particle, gamma_xy), - HOFFSET(HDF5Particle, gamma_yz), - HOFFSET(HDF5Particle, gamma_xz), - HOFFSET(HDF5Particle, epsilon_v), - HOFFSET(HDF5Particle, status), - HOFFSET(HDF5Particle, cell_id), - HOFFSET(HDF5Particle, material_id), - HOFFSET(HDF5Particle, nstate_vars), - HOFFSET(HDF5Particle, svars[0]), - HOFFSET(HDF5Particle, svars[1]), - HOFFSET(HDF5Particle, svars[2]), - HOFFSET(HDF5Particle, svars[3]), - HOFFSET(HDF5Particle, svars[4]), - HOFFSET(HDF5Particle, svars[5]), - HOFFSET(HDF5Particle, svars[6]), - HOFFSET(HDF5Particle, svars[7]), - HOFFSET(HDF5Particle, svars[8]), - HOFFSET(HDF5Particle, svars[9]), - HOFFSET(HDF5Particle, svars[10]), - HOFFSET(HDF5Particle, svars[11]), - HOFFSET(HDF5Particle, svars[12]), - HOFFSET(HDF5Particle, svars[13]), - HOFFSET(HDF5Particle, svars[14]), - HOFFSET(HDF5Particle, svars[15]), - HOFFSET(HDF5Particle, svars[16]), - HOFFSET(HDF5Particle, svars[17]), - HOFFSET(HDF5Particle, svars[18]), - HOFFSET(HDF5Particle, svars[19]), + HOFFSET(PODParticle, id), + HOFFSET(PODParticle, mass), + HOFFSET(PODParticle, volume), + HOFFSET(PODParticle, pressure), + HOFFSET(PODParticle, coord_x), + HOFFSET(PODParticle, coord_y), + HOFFSET(PODParticle, coord_z), + HOFFSET(PODParticle, displacement_x), + HOFFSET(PODParticle, displacement_y), + HOFFSET(PODParticle, displacement_z), + HOFFSET(PODParticle, nsize_x), + HOFFSET(PODParticle, nsize_y), + HOFFSET(PODParticle, nsize_z), + HOFFSET(PODParticle, velocity_x), + HOFFSET(PODParticle, velocity_y), + HOFFSET(PODParticle, velocity_z), + HOFFSET(PODParticle, stress_xx), + HOFFSET(PODParticle, stress_yy), + HOFFSET(PODParticle, stress_zz), + HOFFSET(PODParticle, tau_xy), + HOFFSET(PODParticle, tau_yz), + HOFFSET(PODParticle, tau_xz), + HOFFSET(PODParticle, strain_xx), + HOFFSET(PODParticle, strain_yy), + HOFFSET(PODParticle, strain_zz), + HOFFSET(PODParticle, gamma_xy), + HOFFSET(PODParticle, gamma_yz), + HOFFSET(PODParticle, gamma_xz), + HOFFSET(PODParticle, epsilon_v), + HOFFSET(PODParticle, status), + HOFFSET(PODParticle, cell_id), + HOFFSET(PODParticle, material_id), + HOFFSET(PODParticle, nstate_vars), + HOFFSET(PODParticle, svars[0]), + HOFFSET(PODParticle, svars[1]), + HOFFSET(PODParticle, svars[2]), + HOFFSET(PODParticle, svars[3]), + HOFFSET(PODParticle, svars[4]), + HOFFSET(PODParticle, svars[5]), + HOFFSET(PODParticle, svars[6]), + HOFFSET(PODParticle, svars[7]), + HOFFSET(PODParticle, svars[8]), + HOFFSET(PODParticle, svars[9]), + HOFFSET(PODParticle, svars[10]), + HOFFSET(PODParticle, svars[11]), + HOFFSET(PODParticle, svars[12]), + HOFFSET(PODParticle, svars[13]), + HOFFSET(PODParticle, svars[14]), + HOFFSET(PODParticle, svars[15]), + HOFFSET(PODParticle, svars[16]), + HOFFSET(PODParticle, svars[17]), + HOFFSET(PODParticle, svars[18]), + HOFFSET(PODParticle, svars[19]), }; // Get size of particle -HDF5Particle particle; +PODParticle particle; const size_t dst_sizes[NFIELDS] = { sizeof(particle.id), sizeof(particle.mass), diff --git a/src/hdf5_particle_twophase.cc b/src/hdf5_particle_twophase.cc index ed994cd68..525e7e457 100644 --- a/src/hdf5_particle_twophase.cc +++ b/src/hdf5_particle_twophase.cc @@ -4,77 +4,77 @@ namespace hdf5 { namespace particletwophase { const size_t dst_offset[NFIELDS] = { // Solid phase - HOFFSET(HDF5ParticleTwoPhase, id), - HOFFSET(HDF5ParticleTwoPhase, mass), - HOFFSET(HDF5ParticleTwoPhase, volume), - HOFFSET(HDF5ParticleTwoPhase, pressure), - HOFFSET(HDF5ParticleTwoPhase, coord_x), - HOFFSET(HDF5ParticleTwoPhase, coord_y), - HOFFSET(HDF5ParticleTwoPhase, coord_z), - HOFFSET(HDF5ParticleTwoPhase, displacement_x), - HOFFSET(HDF5ParticleTwoPhase, displacement_y), - HOFFSET(HDF5ParticleTwoPhase, displacement_z), - HOFFSET(HDF5ParticleTwoPhase, nsize_x), - HOFFSET(HDF5ParticleTwoPhase, nsize_y), - HOFFSET(HDF5ParticleTwoPhase, nsize_z), - HOFFSET(HDF5ParticleTwoPhase, velocity_x), - HOFFSET(HDF5ParticleTwoPhase, velocity_y), - HOFFSET(HDF5ParticleTwoPhase, velocity_z), - HOFFSET(HDF5ParticleTwoPhase, stress_xx), - HOFFSET(HDF5ParticleTwoPhase, stress_yy), - HOFFSET(HDF5ParticleTwoPhase, stress_zz), - HOFFSET(HDF5ParticleTwoPhase, tau_xy), - HOFFSET(HDF5ParticleTwoPhase, tau_yz), - HOFFSET(HDF5ParticleTwoPhase, tau_xz), - HOFFSET(HDF5ParticleTwoPhase, strain_xx), - HOFFSET(HDF5ParticleTwoPhase, strain_yy), - HOFFSET(HDF5ParticleTwoPhase, strain_zz), - HOFFSET(HDF5ParticleTwoPhase, gamma_xy), - HOFFSET(HDF5ParticleTwoPhase, gamma_yz), - HOFFSET(HDF5ParticleTwoPhase, gamma_xz), - HOFFSET(HDF5ParticleTwoPhase, epsilon_v), - HOFFSET(HDF5ParticleTwoPhase, status), - HOFFSET(HDF5ParticleTwoPhase, cell_id), - HOFFSET(HDF5ParticleTwoPhase, material_id), - HOFFSET(HDF5ParticleTwoPhase, nstate_vars), - HOFFSET(HDF5ParticleTwoPhase, svars[0]), - HOFFSET(HDF5ParticleTwoPhase, svars[1]), - HOFFSET(HDF5ParticleTwoPhase, svars[2]), - HOFFSET(HDF5ParticleTwoPhase, svars[3]), - HOFFSET(HDF5ParticleTwoPhase, svars[4]), - HOFFSET(HDF5ParticleTwoPhase, svars[5]), - HOFFSET(HDF5ParticleTwoPhase, svars[6]), - HOFFSET(HDF5ParticleTwoPhase, svars[7]), - HOFFSET(HDF5ParticleTwoPhase, svars[8]), - HOFFSET(HDF5ParticleTwoPhase, svars[9]), - HOFFSET(HDF5ParticleTwoPhase, svars[10]), - HOFFSET(HDF5ParticleTwoPhase, svars[11]), - HOFFSET(HDF5ParticleTwoPhase, svars[12]), - HOFFSET(HDF5ParticleTwoPhase, svars[13]), - HOFFSET(HDF5ParticleTwoPhase, svars[14]), - HOFFSET(HDF5ParticleTwoPhase, svars[15]), - HOFFSET(HDF5ParticleTwoPhase, svars[16]), - HOFFSET(HDF5ParticleTwoPhase, svars[17]), - HOFFSET(HDF5ParticleTwoPhase, svars[18]), - HOFFSET(HDF5ParticleTwoPhase, svars[19]), + HOFFSET(PODParticleTwoPhase, id), + HOFFSET(PODParticleTwoPhase, mass), + HOFFSET(PODParticleTwoPhase, volume), + HOFFSET(PODParticleTwoPhase, pressure), + HOFFSET(PODParticleTwoPhase, coord_x), + HOFFSET(PODParticleTwoPhase, coord_y), + HOFFSET(PODParticleTwoPhase, coord_z), + HOFFSET(PODParticleTwoPhase, displacement_x), + HOFFSET(PODParticleTwoPhase, displacement_y), + HOFFSET(PODParticleTwoPhase, displacement_z), + HOFFSET(PODParticleTwoPhase, nsize_x), + HOFFSET(PODParticleTwoPhase, nsize_y), + HOFFSET(PODParticleTwoPhase, nsize_z), + HOFFSET(PODParticleTwoPhase, velocity_x), + HOFFSET(PODParticleTwoPhase, velocity_y), + HOFFSET(PODParticleTwoPhase, velocity_z), + HOFFSET(PODParticleTwoPhase, stress_xx), + HOFFSET(PODParticleTwoPhase, stress_yy), + HOFFSET(PODParticleTwoPhase, stress_zz), + HOFFSET(PODParticleTwoPhase, tau_xy), + HOFFSET(PODParticleTwoPhase, tau_yz), + HOFFSET(PODParticleTwoPhase, tau_xz), + HOFFSET(PODParticleTwoPhase, strain_xx), + HOFFSET(PODParticleTwoPhase, strain_yy), + HOFFSET(PODParticleTwoPhase, strain_zz), + HOFFSET(PODParticleTwoPhase, gamma_xy), + HOFFSET(PODParticleTwoPhase, gamma_yz), + HOFFSET(PODParticleTwoPhase, gamma_xz), + HOFFSET(PODParticleTwoPhase, epsilon_v), + HOFFSET(PODParticleTwoPhase, status), + HOFFSET(PODParticleTwoPhase, cell_id), + HOFFSET(PODParticleTwoPhase, material_id), + HOFFSET(PODParticleTwoPhase, nstate_vars), + HOFFSET(PODParticleTwoPhase, svars[0]), + HOFFSET(PODParticleTwoPhase, svars[1]), + HOFFSET(PODParticleTwoPhase, svars[2]), + HOFFSET(PODParticleTwoPhase, svars[3]), + HOFFSET(PODParticleTwoPhase, svars[4]), + HOFFSET(PODParticleTwoPhase, svars[5]), + HOFFSET(PODParticleTwoPhase, svars[6]), + HOFFSET(PODParticleTwoPhase, svars[7]), + HOFFSET(PODParticleTwoPhase, svars[8]), + HOFFSET(PODParticleTwoPhase, svars[9]), + HOFFSET(PODParticleTwoPhase, svars[10]), + HOFFSET(PODParticleTwoPhase, svars[11]), + HOFFSET(PODParticleTwoPhase, svars[12]), + HOFFSET(PODParticleTwoPhase, svars[13]), + HOFFSET(PODParticleTwoPhase, svars[14]), + HOFFSET(PODParticleTwoPhase, svars[15]), + HOFFSET(PODParticleTwoPhase, svars[16]), + HOFFSET(PODParticleTwoPhase, svars[17]), + HOFFSET(PODParticleTwoPhase, svars[18]), + HOFFSET(PODParticleTwoPhase, svars[19]), // Fluid phase - HOFFSET(HDF5ParticleTwoPhase, liquid_mass), - HOFFSET(HDF5ParticleTwoPhase, liquid_velocity_x), - HOFFSET(HDF5ParticleTwoPhase, liquid_velocity_y), - HOFFSET(HDF5ParticleTwoPhase, liquid_velocity_z), - HOFFSET(HDF5ParticleTwoPhase, porosity), - HOFFSET(HDF5ParticleTwoPhase, liquid_saturation), - HOFFSET(HDF5ParticleTwoPhase, liquid_material_id), - HOFFSET(HDF5ParticleTwoPhase, nliquid_state_vars), - HOFFSET(HDF5ParticleTwoPhase, liquid_svars[0]), - HOFFSET(HDF5ParticleTwoPhase, liquid_svars[1]), - HOFFSET(HDF5ParticleTwoPhase, liquid_svars[2]), - HOFFSET(HDF5ParticleTwoPhase, liquid_svars[3]), - HOFFSET(HDF5ParticleTwoPhase, liquid_svars[4]), + HOFFSET(PODParticleTwoPhase, liquid_mass), + HOFFSET(PODParticleTwoPhase, liquid_velocity_x), + HOFFSET(PODParticleTwoPhase, liquid_velocity_y), + HOFFSET(PODParticleTwoPhase, liquid_velocity_z), + HOFFSET(PODParticleTwoPhase, porosity), + HOFFSET(PODParticleTwoPhase, liquid_saturation), + HOFFSET(PODParticleTwoPhase, liquid_material_id), + HOFFSET(PODParticleTwoPhase, nliquid_state_vars), + HOFFSET(PODParticleTwoPhase, liquid_svars[0]), + HOFFSET(PODParticleTwoPhase, liquid_svars[1]), + HOFFSET(PODParticleTwoPhase, liquid_svars[2]), + HOFFSET(PODParticleTwoPhase, liquid_svars[3]), + HOFFSET(PODParticleTwoPhase, liquid_svars[4]), }; // Get size of particletwophase -HDF5ParticleTwoPhase particle; +PODParticleTwoPhase particle; const size_t dst_sizes[NFIELDS] = { // Solid phase sizeof(particle.id), diff --git a/src/io/partio_writer.cc b/src/io/partio_writer.cc index 9685ecada..854d9e23a 100644 --- a/src/io/partio_writer.cc +++ b/src/io/partio_writer.cc @@ -4,7 +4,7 @@ // Write particles bool mpm::partio::write_particles( const std::string& filename, - const std::vector& particles) { + const std::vector& particles) { bool status = false; if (!particles.empty()) { diff --git a/tests/particles/particle_serialize_deserialize_test.cc b/tests/particles/particle_serialize_deserialize_test.cc index e8e74dfe6..2e6c71290 100644 --- a/tests/particles/particle_serialize_deserialize_test.cc +++ b/tests/particles/particle_serialize_deserialize_test.cc @@ -38,7 +38,7 @@ TEST_CASE("Particle is checked for serialization and deserialization", std::shared_ptr> particle = std::make_shared>(id, pcoords); - mpm::HDF5Particle h5_particle; + mpm::PODParticle h5_particle; h5_particle.id = 13; h5_particle.mass = 501.5; diff --git a/tests/particles/particle_serialize_deserialize_twophase_test.cc b/tests/particles/particle_serialize_deserialize_twophase_test.cc index e822dd1ee..c982b8548 100644 --- a/tests/particles/particle_serialize_deserialize_twophase_test.cc +++ b/tests/particles/particle_serialize_deserialize_twophase_test.cc @@ -31,7 +31,7 @@ TEST_CASE("Twophase particle is checked for serialization and deserialization", std::shared_ptr> particle = std::make_shared>(id, pcoords); - mpm::HDF5ParticleTwoPhase h5_particle; + mpm::PODParticleTwoPhase h5_particle; h5_particle.id = 13; h5_particle.mass = 501.5; diff --git a/tests/particles/particle_test.cc b/tests/particles/particle_test.cc index 37d651c8f..f2dda213e 100644 --- a/tests/particles/particle_test.cc +++ b/tests/particles/particle_test.cc @@ -262,7 +262,7 @@ TEST_CASE("Particle is checked for 1D case", "[particle][1D]") { std::shared_ptr> particle = std::make_shared>(id, coords); - mpm::HDF5Particle h5_particle; + mpm::PODParticle h5_particle; h5_particle.id = 13; h5_particle.mass = 501.5; @@ -379,7 +379,7 @@ TEST_CASE("Particle is checked for 1D case", "[particle][1D]") { // Write Particle HDF5 data auto h5_test = - std::static_pointer_cast(particle->hdf5_ptr()); + std::static_pointer_cast(particle->hdf5_ptr()); REQUIRE(h5_particle.id == h5_test->id); REQUIRE(h5_particle.mass == h5_test->mass); @@ -1407,7 +1407,7 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { std::shared_ptr> particle = std::make_shared>(id, coords); - mpm::HDF5Particle h5_particle; + mpm::PODParticle h5_particle; h5_particle.id = 13; h5_particle.mass = 501.5; @@ -1524,7 +1524,7 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { // Write Particle HDF5 data auto h5_test = - std::static_pointer_cast(particle->hdf5_ptr()); + std::static_pointer_cast(particle->hdf5_ptr()); REQUIRE(h5_particle.id == h5_test->id); REQUIRE(h5_particle.mass == h5_test->mass); @@ -2763,7 +2763,7 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { std::shared_ptr> particle = std::make_shared>(id, coords); - mpm::HDF5Particle h5_particle; + mpm::PODParticle h5_particle; h5_particle.id = 13; h5_particle.mass = 501.5; @@ -2881,7 +2881,7 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { // Write Particle HDF5 data auto h5_test = - std::static_pointer_cast(particle->hdf5_ptr()); + std::static_pointer_cast(particle->hdf5_ptr()); REQUIRE(h5_particle.id == h5_test->id); REQUIRE(h5_particle.mass == h5_test->mass); diff --git a/tests/particles/particle_twophase_test.cc b/tests/particles/particle_twophase_test.cc index 06c3be269..11c19afd9 100644 --- a/tests/particles/particle_twophase_test.cc +++ b/tests/particles/particle_twophase_test.cc @@ -213,7 +213,7 @@ TEST_CASE("TwoPhase Particle is checked for 1D case", std::shared_ptr> particle = std::make_shared>(id, coords); - mpm::HDF5ParticleTwoPhase h5_particle; + mpm::PODParticleTwoPhase h5_particle; h5_particle.id = 13; h5_particle.mass = 501.5; @@ -360,7 +360,7 @@ TEST_CASE("TwoPhase Particle is checked for 1D case", h5_particle.liquid_material_id); // Write Particle HDF5 data - auto h5_test = std::static_pointer_cast( + auto h5_test = std::static_pointer_cast( particle->hdf5_ptr()); REQUIRE(h5_particle.id == h5_test->id); @@ -1455,7 +1455,7 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", std::shared_ptr> particle = std::make_shared>(id, coords); - mpm::HDF5ParticleTwoPhase h5_particle; + mpm::PODParticleTwoPhase h5_particle; h5_particle.id = 13; h5_particle.mass = 501.5; @@ -1602,7 +1602,7 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", h5_particle.liquid_material_id); // Write Particle HDF5 data - auto h5_test = std::static_pointer_cast( + auto h5_test = std::static_pointer_cast( particle->hdf5_ptr()); REQUIRE(h5_particle.id == h5_test->id); @@ -2943,7 +2943,7 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", std::shared_ptr> particle = std::make_shared>(id, coords); - mpm::HDF5ParticleTwoPhase h5_particle; + mpm::PODParticleTwoPhase h5_particle; h5_particle.id = 13; h5_particle.mass = 501.5; @@ -3091,7 +3091,7 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", h5_particle.liquid_material_id); // Write Particle HDF5 data - auto h5_test = std::static_pointer_cast( + auto h5_test = std::static_pointer_cast( particle->hdf5_ptr()); REQUIRE(h5_particle.id == h5_test->id); From 2a2a1a8fdc2be7d51e89a4c7777ab5622c26f96e Mon Sep 17 00:00:00 2001 From: Nanda Date: Mon, 24 Aug 2020 23:32:38 -0700 Subject: [PATCH 135/175] :wrench: fix hdf5_ptr casting --- include/mesh.tcc | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/include/mesh.tcc b/include/mesh.tcc index f48e3d554..184ca262b 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1446,9 +1446,15 @@ bool mpm::Mesh::write_particles_hdf5(const std::string& filename, for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { if ((*pitr)->type() == particle_type) { - auto hdf5_ptr = - std::static_pointer_cast((*pitr)->hdf5_ptr()); - particle_data.emplace_back(*hdf5_ptr); + if (particle_type == "P2D" || particle_type == "P3D") { + auto hdf5_ptr = + std::static_pointer_cast((*pitr)->hdf5_ptr()); + particle_data.emplace_back(*hdf5_ptr); + } else if (particle_type == "P2D2PHASE" || particle_type == "P3D2PHASE") { + auto hdf5_ptr = std::static_pointer_cast( + (*pitr)->hdf5_ptr()); + particle_data.emplace_back(*hdf5_ptr); + } } } From 80b28176d0d8438f14d5a14541e4b83c16d49fc3 Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 25 Aug 2020 10:07:30 -0700 Subject: [PATCH 136/175] :wrench: change hdf5 naming to pod --- CMakeLists.txt | 5 +- include/io/partio_writer.h | 2 +- include/mesh.h | 2 +- include/mesh.tcc | 57 ++++++++++--------- include/particles/particle.h | 2 +- include/particles/particle.tcc | 2 +- include/particles/particle_base.h | 6 +- include/particles/particle_twophase.h | 2 +- include/particles/particle_twophase.tcc | 2 +- .../pod_particles/pod_particle.h} | 10 ++-- .../pod_particles/pod_particle_twophase.h} | 12 ++-- src/{hdf5_particle.cc => pod_particle.cc} | 6 +- ...e_twophase.cc => pod_particle_twophase.cc} | 6 +- tests/graph_test.cc | 2 +- tests/interface_test.cc | 2 +- tests/mpi_transfer_particle_test.cc | 2 +- .../particles/particle_cell_crossing_test.cc | 2 +- .../particle_serialize_deserialize_test.cc | 2 +- ...cle_serialize_deserialize_twophase_test.cc | 2 +- tests/particles/particle_test.cc | 11 ++-- tests/particles/particle_twophase_test.cc | 14 ++--- 21 files changed, 77 insertions(+), 74 deletions(-) rename include/{hdf5_particle.h => particles/pod_particles/pod_particle.h} (93%) rename include/{hdf5_particle_twophase.h => particles/pod_particles/pod_particle_twophase.h} (86%) rename src/{hdf5_particle.cc => pod_particle.cc} (98%) rename src/{hdf5_particle_twophase.cc => pod_particle_twophase.cc} (99%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 85a7f5183..a3138d916 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -143,6 +143,7 @@ include_directories(BEFORE ${mpm_SOURCE_DIR}/include/loads_bcs/ ${mpm_SOURCE_DIR}/include/materials/ ${mpm_SOURCE_DIR}/include/particles/ + ${mpm_SOURCE_DIR}/include/particles/pod_particles ${mpm_SOURCE_DIR}/include/solvers/ ${mpm_SOURCE_DIR}/include/solvers/mpm_scheme/ ${mpm_SOURCE_DIR}/include/utilities/ @@ -159,8 +160,8 @@ SET(mpm_src ${mpm_SOURCE_DIR}/src/functions/linear_function.cc ${mpm_SOURCE_DIR}/src/functions/sin_function.cc ${mpm_SOURCE_DIR}/src/geometry.cc - ${mpm_SOURCE_DIR}/src/hdf5_particle.cc - ${mpm_SOURCE_DIR}/src/hdf5_particle_twophase.cc + ${mpm_SOURCE_DIR}/src/pod_particle.cc + ${mpm_SOURCE_DIR}/src/pod_particle_twophase.cc ${mpm_SOURCE_DIR}/src/io/io.cc ${mpm_SOURCE_DIR}/src/io/io_mesh.cc ${mpm_SOURCE_DIR}/src/io/logger.cc diff --git a/include/io/partio_writer.h b/include/io/partio_writer.h index e91f14f9b..65008746a 100644 --- a/include/io/partio_writer.h +++ b/include/io/partio_writer.h @@ -7,7 +7,7 @@ #include #include "data_types.h" -#include "hdf5_particle.h" +#include "pod_particle.h" namespace mpm::partio { diff --git a/include/mesh.h b/include/mesh.h index 18cafc9e0..0e18d372f 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -30,7 +30,6 @@ using Json = nlohmann::json; #include "function_base.h" #include "generators/injection.h" #include "geometry.h" -#include "hdf5_particle.h" #include "io.h" #include "io_mesh.h" #include "logger.h" @@ -39,6 +38,7 @@ using Json = nlohmann::json; #include "node.h" #include "particle.h" #include "particle_base.h" +#include "pod_particle.h" #include "radial_basis_function.h" #include "traction.h" #include "vector.h" diff --git a/include/mesh.tcc b/include/mesh.tcc index 184ca262b..d4f2ee3fb 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1441,19 +1441,21 @@ bool mpm::Mesh::write_particles_hdf5(const std::string& filename, const std::string& particle_type) { const unsigned nparticles = this->nparticles(particle_type); - std::vector particle_data; // = new PODParticle[nparticles]; + // FIXME: PODParticle type does not work for twophase particle + std::vector particle_data; particle_data.reserve(nparticles); for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { if ((*pitr)->type() == particle_type) { + // TODO: Think a better way to separate static_pointer_cast of PODParticle + // or PODParticleTwoPhase if (particle_type == "P2D" || particle_type == "P3D") { - auto hdf5_ptr = - std::static_pointer_cast((*pitr)->hdf5_ptr()); - particle_data.emplace_back(*hdf5_ptr); + auto pod = std::static_pointer_cast((*pitr)->pod()); + particle_data.emplace_back(*pod); } else if (particle_type == "P2D2PHASE" || particle_type == "P3D2PHASE") { - auto hdf5_ptr = std::static_pointer_cast( - (*pitr)->hdf5_ptr()); - particle_data.emplace_back(*hdf5_ptr); + auto pod = + std::static_pointer_cast((*pitr)->pod()); + particle_data.emplace_back(*pod); } } } @@ -1470,22 +1472,23 @@ bool mpm::Mesh::write_particles_hdf5(const std::string& filename, file_id = H5Fcreate(filename.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + // TODO: Think a better way to access mpm::pod::particle namespaces if (particle_type == "P2D" || particle_type == "P3D") { - const hsize_t NFIELDS = mpm::hdf5::particle::NFIELDS; + const hsize_t NFIELDS = mpm::pod::particle::NFIELDS; // make a table H5TBmake_table( "Table Title", file_id, "table", NFIELDS, NRECORDS, - mpm::hdf5::particle::dst_size, mpm::hdf5::particle::field_names, - mpm::hdf5::particle::dst_offset, mpm::hdf5::particle::field_type, + mpm::pod::particle::dst_size, mpm::pod::particle::field_names, + mpm::pod::particle::dst_offset, mpm::pod::particle::field_type, chunk_size, fill_data, compress, particle_data.data()); } else if (particle_type == "P2D2PHASE" || particle_type == "P3D2PHASE") { - const hsize_t NFIELDS = mpm::hdf5::particletwophase::NFIELDS; + const hsize_t NFIELDS = mpm::pod::particletwophase::NFIELDS; // make a table H5TBmake_table("Table Title", file_id, "table", NFIELDS, NRECORDS, - mpm::hdf5::particletwophase::dst_size, - mpm::hdf5::particletwophase::field_names, - mpm::hdf5::particletwophase::dst_offset, - mpm::hdf5::particletwophase::field_type, chunk_size, + mpm::pod::particletwophase::dst_size, + mpm::pod::particletwophase::field_names, + mpm::pod::particletwophase::dst_offset, + mpm::pod::particletwophase::field_type, chunk_size, fill_data, compress, particle_data.data()); } @@ -1505,6 +1508,7 @@ bool mpm::Mesh::read_particles_hdf5( for (const std::string& particle_type : particle_types) { // Create a new file using default properties. + // FIXME: new_file_name is not appropriate const std::string new_file_name = filename + particle_type; hid_t file_id = H5Fopen(new_file_name.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT); // Throw an error if file can't be found @@ -1519,20 +1523,21 @@ bool mpm::Mesh::read_particles_hdf5( std::vector dst_buf; dst_buf.reserve(nrecords); + // TODO: Think a better way to access mpm::pod::particle namespaces if (particle_type == "P2D" || particle_type == "P3D") { - if (nfields != mpm::hdf5::particle::NFIELDS) + if (nfields != mpm::pod::particle::NFIELDS) throw std::runtime_error("HDF5 table has incorrect number of fields"); // Read the table - H5TBread_table(file_id, "table", mpm::hdf5::particle::dst_size, - mpm::hdf5::particle::dst_offset, - mpm::hdf5::particle::dst_sizes, dst_buf.data()); + H5TBread_table(file_id, "table", mpm::pod::particle::dst_size, + mpm::pod::particle::dst_offset, + mpm::pod::particle::dst_sizes, dst_buf.data()); } else if (particle_type == "P2D2PHASE" || particle_type == "P3D2PHASE") { - if (nfields != mpm::hdf5::particletwophase::NFIELDS) + if (nfields != mpm::pod::particletwophase::NFIELDS) throw std::runtime_error("HDF5 table has incorrect number of fields"); // Read the table - H5TBread_table(file_id, "table", mpm::hdf5::particletwophase::dst_size, - mpm::hdf5::particletwophase::dst_offset, - mpm::hdf5::particletwophase::dst_sizes, dst_buf.data()); + H5TBread_table(file_id, "table", mpm::pod::particletwophase::dst_size, + mpm::pod::particletwophase::dst_offset, + mpm::pod::particletwophase::dst_sizes, dst_buf.data()); } unsigned i = 0; @@ -1543,6 +1548,7 @@ bool mpm::Mesh::read_particles_hdf5( std::vector>> materials; materials.emplace_back(materials_.at(particle.material_id)); + // TODO: Think a better way to access more than one material id // Append more materials for twophase particles if (particle_type == "P2D2PHASE" || particle_type == "P3D2PHASE") { auto twophase_particle = @@ -1582,9 +1588,8 @@ std::vector mpm::Mesh::particles_hdf5() const { particles_hdf5.reserve(nparticles); for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { - auto hdf5_ptr = - std::static_pointer_cast((*pitr)->hdf5_ptr()); - particles_hdf5.emplace_back(*hdf5_ptr); + auto pod = std::static_pointer_cast((*pitr)->pod()); + particles_hdf5.emplace_back(*pod); } return particles_hdf5; diff --git a/include/particles/particle.h b/include/particles/particle.h index a158b38a0..24b43823a 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -61,7 +61,7 @@ class Particle : public ParticleBase { //! Return particle data as HDF5 pointer //! \retval particle HDF5 pointer of the particle - std::shared_ptr hdf5_ptr() override; + std::shared_ptr pod() override; //! Initialise properties void initialise() override; diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index cdee4bbb9..fc8a23a6f 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -139,7 +139,7 @@ bool mpm::Particle::initialise_particle( //! Return particle data as HDF5 pointer template // cppcheck-suppress * -std::shared_ptr mpm::Particle::hdf5_ptr() { +std::shared_ptr mpm::Particle::pod() { // Initialise particle data auto particle_data = std::make_shared(); diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 9cb676355..fe7eef33a 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -14,9 +14,9 @@ #include "cell.h" #include "data_types.h" #include "function_base.h" -#include "hdf5_particle.h" -#include "hdf5_particle_twophase.h" #include "material.h" +#include "pod_particle.h" +#include "pod_particle_twophase.h" namespace mpm { @@ -81,7 +81,7 @@ class ParticleBase { //! Return particle data as HDF5 pointer //! \retval particle HDF5 pointer of the particle - virtual std::shared_ptr hdf5_ptr() = 0; + virtual std::shared_ptr pod() = 0; //! Return id of the particleBase Index id() const { return id_; } diff --git a/include/particles/particle_twophase.h b/include/particles/particle_twophase.h index 28c8cde38..f3521cfd7 100644 --- a/include/particles/particle_twophase.h +++ b/include/particles/particle_twophase.h @@ -61,7 +61,7 @@ class TwoPhaseParticle : public mpm::Particle { //! Return particle data as HDF5 pointer //! \retval particle HDF5 pointer of the particle - std::shared_ptr hdf5_ptr() override; + std::shared_ptr pod() override; //! Assign saturation degree bool assign_saturation_degree() override; diff --git a/include/particles/particle_twophase.tcc b/include/particles/particle_twophase.tcc index 0ee3e3418..9147a1e33 100644 --- a/include/particles/particle_twophase.tcc +++ b/include/particles/particle_twophase.tcc @@ -34,7 +34,7 @@ mpm::TwoPhaseParticle::TwoPhaseParticle(Index id, const VectorDim& coord, //! Return particle data as HDF5 pointer template // cppcheck-suppress * -std::shared_ptr mpm::TwoPhaseParticle::hdf5_ptr() { +std::shared_ptr mpm::TwoPhaseParticle::pod() { // Initialise particle_data auto particle_data = std::make_shared(); diff --git a/include/hdf5_particle.h b/include/particles/pod_particles/pod_particle.h similarity index 93% rename from include/hdf5_particle.h rename to include/particles/pod_particles/pod_particle.h index 07044a2f5..9a7e3ba5b 100644 --- a/include/hdf5_particle.h +++ b/include/particles/pod_particles/pod_particle.h @@ -1,5 +1,5 @@ -#ifndef MPM_HDF5_H_ -#define MPM_HDF5_H_ +#ifndef MPM_POD_H_ +#define MPM_POD_H_ // HDF5 #include "hdf5.h" @@ -48,7 +48,7 @@ typedef struct PODParticle { virtual ~PODParticle() = default; } PODParticle; -namespace hdf5 { +namespace pod { namespace particle { const hsize_t NFIELDS = 53; @@ -67,8 +67,8 @@ extern const char* field_names[NFIELDS]; extern const hid_t field_type[NFIELDS]; } // namespace particle -} // namespace hdf5 +} // namespace pod } // namespace mpm -#endif // MPM_HDF5_H_ +#endif // MPM_POD_H_ diff --git a/include/hdf5_particle_twophase.h b/include/particles/pod_particles/pod_particle_twophase.h similarity index 86% rename from include/hdf5_particle_twophase.h rename to include/particles/pod_particles/pod_particle_twophase.h index cdf61092c..5906b09b8 100644 --- a/include/hdf5_particle_twophase.h +++ b/include/particles/pod_particles/pod_particle_twophase.h @@ -1,8 +1,8 @@ -#ifndef MPM_HDF5_TWOPHASE_H_ -#define MPM_HDF5_TWOPHASE_H_ +#ifndef MPM_POD_TWOPHASE_H_ +#define MPM_POD_TWOPHASE_H_ // HDF5 Particle -#include "hdf5_particle.h" +#include "pod_particle.h" namespace mpm { // Define a struct of particle @@ -25,7 +25,7 @@ typedef struct PODParticleTwoPhase : PODParticle { virtual ~PODParticleTwoPhase() = default; } PODParticleTwoPhase; -namespace hdf5 { +namespace pod { namespace particletwophase { const hsize_t NFIELDS = 66; @@ -44,8 +44,8 @@ extern const char* field_names[NFIELDS]; extern const hid_t field_type[NFIELDS]; } // namespace particletwophase -} // namespace hdf5 +} // namespace pod } // namespace mpm -#endif // MPM_HDF5_TWOPHASE_H_ +#endif // MPM_POD_TWOPHASE_H_ diff --git a/src/hdf5_particle.cc b/src/pod_particle.cc similarity index 98% rename from src/hdf5_particle.cc rename to src/pod_particle.cc index 141bd1e45..603a8f2af 100644 --- a/src/hdf5_particle.cc +++ b/src/pod_particle.cc @@ -1,6 +1,6 @@ -#include "hdf5_particle.h" +#include "pod_particle.h" namespace mpm { -namespace hdf5 { +namespace pod { namespace particle { const size_t dst_offset[NFIELDS] = { HOFFSET(PODParticle, id), @@ -190,5 +190,5 @@ const hid_t field_type[NFIELDS] = { H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE}; } // namespace particle -} // namespace hdf5 +} // namespace pod } // namespace mpm diff --git a/src/hdf5_particle_twophase.cc b/src/pod_particle_twophase.cc similarity index 99% rename from src/hdf5_particle_twophase.cc rename to src/pod_particle_twophase.cc index 525e7e457..dff757246 100644 --- a/src/hdf5_particle_twophase.cc +++ b/src/pod_particle_twophase.cc @@ -1,6 +1,6 @@ -#include "hdf5_particle_twophase.h" +#include "pod_particle_twophase.h" namespace mpm { -namespace hdf5 { +namespace pod { namespace particletwophase { const size_t dst_offset[NFIELDS] = { // Solid phase @@ -238,5 +238,5 @@ const hid_t field_type[NFIELDS] = { H5T_NATIVE_UINT, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE}; } // namespace particletwophase -} // namespace hdf5 +} // namespace pod } // namespace mpm diff --git a/tests/graph_test.cc b/tests/graph_test.cc index 25baaf7bb..511bafc21 100644 --- a/tests/graph_test.cc +++ b/tests/graph_test.cc @@ -11,12 +11,12 @@ #include "data_types.h" #include "element.h" #include "graph.h" -#include "hdf5_particle.h" #include "hexahedron_element.h" #include "material.h" #include "mesh.h" #include "node.h" #include "particle.h" +#include "pod_particle.h" #include "quadrilateral_element.h" #include "vector.h" diff --git a/tests/interface_test.cc b/tests/interface_test.cc index cb3b151d7..fa5eb7959 100644 --- a/tests/interface_test.cc +++ b/tests/interface_test.cc @@ -7,12 +7,12 @@ #include "cell.h" #include "element.h" #include "function_base.h" -#include "hdf5_particle.h" #include "hexahedron_element.h" #include "linear_function.h" #include "material.h" #include "node.h" #include "particle.h" +#include "pod_particle.h" #include "quadrilateral_element.h" //! \brief Check interface functions diff --git a/tests/mpi_transfer_particle_test.cc b/tests/mpi_transfer_particle_test.cc index f4aa60fb5..1914cb720 100644 --- a/tests/mpi_transfer_particle_test.cc +++ b/tests/mpi_transfer_particle_test.cc @@ -6,12 +6,12 @@ #include "data_types.h" #include "element.h" #include "graph.h" -#include "hdf5_particle.h" #include "hexahedron_element.h" #include "material.h" #include "mesh.h" #include "node.h" #include "particle.h" +#include "pod_particle.h" #include "quadrilateral_element.h" #ifdef USE_MPI diff --git a/tests/particles/particle_cell_crossing_test.cc b/tests/particles/particle_cell_crossing_test.cc index ea3a1eb35..5da542e5d 100644 --- a/tests/particles/particle_cell_crossing_test.cc +++ b/tests/particles/particle_cell_crossing_test.cc @@ -4,12 +4,12 @@ #include "cell.h" #include "element.h" -#include "hdf5_particle.h" #include "hexahedron_element.h" #include "material.h" #include "mesh.h" #include "node.h" #include "particle.h" +#include "pod_particle.h" #include "quadrilateral_element.h" //! \brief Check particle cell crossing for 2D case diff --git a/tests/particles/particle_serialize_deserialize_test.cc b/tests/particles/particle_serialize_deserialize_test.cc index 2e6c71290..90291e613 100644 --- a/tests/particles/particle_serialize_deserialize_test.cc +++ b/tests/particles/particle_serialize_deserialize_test.cc @@ -7,12 +7,12 @@ #include "data_types.h" #include "element.h" #include "function_base.h" -#include "hdf5_particle.h" #include "hexahedron_element.h" #include "linear_function.h" #include "material.h" #include "node.h" #include "particle.h" +#include "pod_particle.h" #include "quadrilateral_element.h" //! \brief Check particle class for serialization and deserialization diff --git a/tests/particles/particle_serialize_deserialize_twophase_test.cc b/tests/particles/particle_serialize_deserialize_twophase_test.cc index c982b8548..5ec35d74e 100644 --- a/tests/particles/particle_serialize_deserialize_twophase_test.cc +++ b/tests/particles/particle_serialize_deserialize_twophase_test.cc @@ -3,10 +3,10 @@ #include "catch.hpp" #include "data_types.h" -#include "hdf5_particle_twophase.h" #include "material.h" #include "particle.h" #include "particle_twophase.h" +#include "pod_particle_twophase.h" //! \brief Check particle class for serialization and deserialization TEST_CASE("Twophase particle is checked for serialization and deserialization", diff --git a/tests/particles/particle_test.cc b/tests/particles/particle_test.cc index f2dda213e..84f6f2ae5 100644 --- a/tests/particles/particle_test.cc +++ b/tests/particles/particle_test.cc @@ -5,12 +5,12 @@ #include "cell.h" #include "element.h" #include "function_base.h" -#include "hdf5_particle.h" #include "hexahedron_element.h" #include "linear_function.h" #include "material.h" #include "node.h" #include "particle.h" +#include "pod_particle.h" #include "quadrilateral_element.h" //! \brief Check particle class for 1D case @@ -378,8 +378,7 @@ TEST_CASE("Particle is checked for 1D case", "[particle][1D]") { REQUIRE(particle->material_id() == h5_particle.material_id); // Write Particle HDF5 data - auto h5_test = - std::static_pointer_cast(particle->hdf5_ptr()); + auto h5_test = std::static_pointer_cast(particle->pod()); REQUIRE(h5_particle.id == h5_test->id); REQUIRE(h5_particle.mass == h5_test->mass); @@ -1523,8 +1522,7 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { REQUIRE(particle->material_id() == h5_particle.material_id); // Write Particle HDF5 data - auto h5_test = - std::static_pointer_cast(particle->hdf5_ptr()); + auto h5_test = std::static_pointer_cast(particle->pod()); REQUIRE(h5_particle.id == h5_test->id); REQUIRE(h5_particle.mass == h5_test->mass); @@ -2880,8 +2878,7 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { REQUIRE(particle->material_id() == h5_particle.material_id); // Write Particle HDF5 data - auto h5_test = - std::static_pointer_cast(particle->hdf5_ptr()); + auto h5_test = std::static_pointer_cast(particle->pod()); REQUIRE(h5_particle.id == h5_test->id); REQUIRE(h5_particle.mass == h5_test->mass); diff --git a/tests/particles/particle_twophase_test.cc b/tests/particles/particle_twophase_test.cc index 11c19afd9..d7600071d 100644 --- a/tests/particles/particle_twophase_test.cc +++ b/tests/particles/particle_twophase_test.cc @@ -5,13 +5,13 @@ #include "cell.h" #include "element.h" #include "function_base.h" -#include "hdf5_particle.h" #include "hexahedron_element.h" #include "linear_function.h" #include "material.h" #include "node.h" #include "particle.h" #include "particle_twophase.h" +#include "pod_particle.h" #include "quadrilateral_element.h" //! \brief Check twophase particle class for 1D case @@ -360,8 +360,8 @@ TEST_CASE("TwoPhase Particle is checked for 1D case", h5_particle.liquid_material_id); // Write Particle HDF5 data - auto h5_test = std::static_pointer_cast( - particle->hdf5_ptr()); + auto h5_test = + std::static_pointer_cast(particle->pod()); REQUIRE(h5_particle.id == h5_test->id); REQUIRE(h5_particle.mass == h5_test->mass); @@ -1602,8 +1602,8 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", h5_particle.liquid_material_id); // Write Particle HDF5 data - auto h5_test = std::static_pointer_cast( - particle->hdf5_ptr()); + auto h5_test = + std::static_pointer_cast(particle->pod()); REQUIRE(h5_particle.id == h5_test->id); REQUIRE(h5_particle.mass == h5_test->mass); @@ -3091,8 +3091,8 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", h5_particle.liquid_material_id); // Write Particle HDF5 data - auto h5_test = std::static_pointer_cast( - particle->hdf5_ptr()); + auto h5_test = + std::static_pointer_cast(particle->pod()); REQUIRE(h5_particle.id == h5_test->id); REQUIRE(h5_particle.mass == h5_test->mass); From f7c0af9e46c95b9b548f6ce6fa9e8490f7b3cf6c Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 25 Aug 2020 10:17:43 -0700 Subject: [PATCH 137/175] :pencil: cleanup documentation and comments --- include/particles/particle.h | 20 ++++++++--------- include/particles/particle.tcc | 6 ++--- include/particles/particle_base.h | 18 +++++++-------- include/particles/particle_twophase.h | 19 ++++++++-------- include/particles/particle_twophase.tcc | 6 ++--- .../pod_particles/pod_particle_twophase.h | 2 +- .../particle_serialize_deserialize_test.cc | 6 ++--- ...cle_serialize_deserialize_twophase_test.cc | 6 ++--- tests/particles/particle_test.cc | 22 +++++++++---------- tests/particles/particle_twophase_test.cc | 22 +++++++++---------- 10 files changed, 63 insertions(+), 64 deletions(-) diff --git a/include/particles/particle.h b/include/particles/particle.h index 24b43823a..46144d7f6 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -46,21 +46,21 @@ class Particle : public ParticleBase { //! Delete assignment operator Particle& operator=(const Particle&) = delete; - //! Initialise particle from HDF5 data - //! \param[in] particle HDF5 data of particle - //! \retval status Status of reading HDF5 particle + //! Initialise particle from POD data + //! \param[in] particle POD data of particle + //! \retval status Status of reading POD particle bool initialise_particle(PODParticle& particle) override; - //! Initialise particle HDF5 data and material - //! \param[in] particle HDF5 data of particle - //! \param[in] material Material associated with the particle - //! \retval status Status of reading HDF5 particle + //! Initialise particle POD data and material + //! \param[in] particle POD data of particle + //! \param[in] materials Material associated with the particle arranged in vector + //! \retval status Status of reading POD particle virtual bool initialise_particle( PODParticle& particle, const std::vector>>& materials) override; - //! Return particle data as HDF5 pointer - //! \retval particle HDF5 pointer of the particle + //! Return particle data as POD + //! \retval particle POD of the particle std::shared_ptr pod() override; //! Initialise properties @@ -236,7 +236,7 @@ class Particle : public ParticleBase { //! \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 + //! \retval status Status of assigning material state variables bool assign_material_state_vars( const mpm::dense_map& state_vars, const std::shared_ptr>& material, diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index fc8a23a6f..330ab5182 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -30,7 +30,7 @@ mpm::Particle::Particle(Index id, const VectorDim& coord, bool status) console_ = std::make_unique(logger, mpm::stdout_sink); } -//! Initialise particle data from HDF5 +//! Initialise particle data from POD template bool mpm::Particle::initialise_particle(PODParticle& particle) { @@ -102,7 +102,7 @@ bool mpm::Particle::initialise_particle(PODParticle& particle) { return true; } -//! Initialise particle data from HDF5 +//! Initialise particle data from POD template bool mpm::Particle::initialise_particle( PODParticle& particle, @@ -136,7 +136,7 @@ bool mpm::Particle::initialise_particle( return status; } -//! Return particle data as HDF5 pointer +//! Return particle data as POD template // cppcheck-suppress * std::shared_ptr mpm::Particle::pod() { diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index fe7eef33a..19ce6d351 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -66,21 +66,21 @@ class ParticleBase { //! Delete assignement operator ParticleBase& operator=(const ParticleBase&) = delete; - //! Initialise particle HDF5 data - //! \param[in] particle HDF5 data of particle - //! \retval status Status of reading HDF5 particle + //! Initialise particle POD data + //! \param[in] particle POD data of particle + //! \retval status Status of reading POD particle virtual bool initialise_particle(PODParticle& particle) = 0; - //! Initialise particle HDF5 data and material - //! \param[in] particle HDF5 data of particle - //! \param[in] material Material associated with the particle - //! \retval status Status of reading HDF5 particle + //! Initialise particle POD data and material + //! \param[in] particle POD data of particle + //! \param[in] materials Material associated with the particle arranged in vector + //! \retval status Status of reading POD particle virtual bool initialise_particle( PODParticle& particle, const std::vector>>& materials) = 0; - //! Return particle data as HDF5 pointer - //! \retval particle HDF5 pointer of the particle + //! Return particle data as POD + //! \retval particle POD of the particle virtual std::shared_ptr pod() = 0; //! Return id of the particleBase diff --git a/include/particles/particle_twophase.h b/include/particles/particle_twophase.h index f3521cfd7..e0d7b4b52 100644 --- a/include/particles/particle_twophase.h +++ b/include/particles/particle_twophase.h @@ -42,16 +42,15 @@ class TwoPhaseParticle : public mpm::Particle { //! Delete assignment operator TwoPhaseParticle& operator=(const TwoPhaseParticle&) = delete; - //! Initialise particle from HDF5 data - //! \param[in] particle HDF5 data of particle - //! \retval status Status of reading HDF5 particle + //! Initialise particle from POD data + //! \param[in] particle POD data of particle + //! \retval status Status of reading POD particle bool initialise_particle(PODParticle& particle) override; - //! Initialise particle HDF5 data and material - //! \param[in] particle HDF5 data of particle - //! \param[in] solid_material Solid material associated with the particle - //! \param[in] liquid_material Liquid material associated with the particle - //! \retval status Status of reading HDF5 particle + //! Initialise particle POD data and material + //! \param[in] particle POD data of particle + //! \param[in] materials Material associated with the particle arranged in vector + //! \retval status Status of reading POD particle bool initialise_particle( PODParticle& particle, const std::vector>>& materials) override; @@ -59,8 +58,8 @@ class TwoPhaseParticle : public mpm::Particle { //! Initialise particle liquid phase on top of the regular solid phase void initialise() override; - //! Return particle data as HDF5 pointer - //! \retval particle HDF5 pointer of the particle + //! Return particle data as POD + //! \retval particle POD of the particle std::shared_ptr pod() override; //! Assign saturation degree diff --git a/include/particles/particle_twophase.tcc b/include/particles/particle_twophase.tcc index 9147a1e33..26209f76d 100644 --- a/include/particles/particle_twophase.tcc +++ b/include/particles/particle_twophase.tcc @@ -31,7 +31,7 @@ mpm::TwoPhaseParticle::TwoPhaseParticle(Index id, const VectorDim& coord, console_ = std::make_unique(logger, mpm::stdout_sink); } -//! Return particle data as HDF5 pointer +//! Return particle data as POD template // cppcheck-suppress * std::shared_ptr mpm::TwoPhaseParticle::pod() { @@ -162,7 +162,7 @@ std::shared_ptr mpm::TwoPhaseParticle::pod() { return particle_data; } -//! Initialise particle data from HDF5 +//! Initialise particle data from POD template bool mpm::TwoPhaseParticle::initialise_particle(PODParticle& particle) { // Initialise solid phase @@ -195,7 +195,7 @@ bool mpm::TwoPhaseParticle::initialise_particle(PODParticle& particle) { return status; } -//! Initialise particle data from HDF5 +//! Initialise particle data from POD template bool mpm::TwoPhaseParticle::initialise_particle( PODParticle& particle, diff --git a/include/particles/pod_particles/pod_particle_twophase.h b/include/particles/pod_particles/pod_particle_twophase.h index 5906b09b8..9b840bc82 100644 --- a/include/particles/pod_particles/pod_particle_twophase.h +++ b/include/particles/pod_particles/pod_particle_twophase.h @@ -1,7 +1,7 @@ #ifndef MPM_POD_TWOPHASE_H_ #define MPM_POD_TWOPHASE_H_ -// HDF5 Particle +// POD Particle #include "pod_particle.h" namespace mpm { diff --git a/tests/particles/particle_serialize_deserialize_test.cc b/tests/particles/particle_serialize_deserialize_test.cc index 90291e613..c6ed179b1 100644 --- a/tests/particles/particle_serialize_deserialize_test.cc +++ b/tests/particles/particle_serialize_deserialize_test.cc @@ -27,8 +27,8 @@ TEST_CASE("Particle is checked for serialization and deserialization", // Phase const unsigned phase = 0; - // Check initialise particle from HDF5 file - SECTION("Check initialise particle HDF5") { + // Check initialise particle from POD file + SECTION("Check initialise particle POD") { mpm::Index id = 0; const double Tolerance = 1.E-7; // Coordinates @@ -94,7 +94,7 @@ TEST_CASE("Particle is checked for serialization and deserialization", h5_particle.material_id = 1; - // Reinitialise particle from HDF5 data + // Reinitialise particle from POD data REQUIRE(particle->initialise_particle(h5_particle) == true); // Initialise material diff --git a/tests/particles/particle_serialize_deserialize_twophase_test.cc b/tests/particles/particle_serialize_deserialize_twophase_test.cc index 5ec35d74e..5e54644d8 100644 --- a/tests/particles/particle_serialize_deserialize_twophase_test.cc +++ b/tests/particles/particle_serialize_deserialize_twophase_test.cc @@ -20,8 +20,8 @@ TEST_CASE("Twophase particle is checked for serialization and deserialization", // Phase const unsigned phase = 0; - // Check initialise particle from HDF5 file - SECTION("Check initialise particle HDF5") { + // Check initialise particle from POD file + SECTION("Check initialise particle POD") { mpm::Index id = 0; const double Tolerance = 1.E-7; // Coordinates @@ -111,7 +111,7 @@ TEST_CASE("Twophase particle is checked for serialization and deserialization", for (unsigned i = 0; i < h5_particle.nliquid_state_vars; ++i) h5_particle.liquid_svars[i] = 0.; - // Reinitialise particle from HDF5 data + // Reinitialise particle from POD data REQUIRE(particle->initialise_particle(h5_particle) == true); // Assign material diff --git a/tests/particles/particle_test.cc b/tests/particles/particle_test.cc index 84f6f2ae5..6ce062a56 100644 --- a/tests/particles/particle_test.cc +++ b/tests/particles/particle_test.cc @@ -256,7 +256,7 @@ TEST_CASE("Particle is checked for 1D case", "[particle][1D]") { } } - SECTION("Check initialise particle HDF5") { + SECTION("Check initialise particle POD") { mpm::Index id = 0; const double Tolerance = 1.E-7; std::shared_ptr> particle = @@ -318,7 +318,7 @@ TEST_CASE("Particle is checked for 1D case", "[particle][1D]") { h5_particle.material_id = 1; - // Reinitialise particle from HDF5 data + // Reinitialise particle from POD data REQUIRE(particle->initialise_particle(h5_particle) == true); // Check particle id @@ -377,7 +377,7 @@ TEST_CASE("Particle is checked for 1D case", "[particle][1D]") { // Check material id REQUIRE(particle->material_id() == h5_particle.material_id); - // Write Particle HDF5 data + // Write Particle POD data auto h5_test = std::static_pointer_cast(particle->pod()); REQUIRE(h5_particle.id == h5_test->id); @@ -1399,8 +1399,8 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { } } - // Check initialise particle from HDF5 file - SECTION("Check initialise particle HDF5") { + // Check initialise particle from POD file + SECTION("Check initialise particle POD") { mpm::Index id = 0; const double Tolerance = 1.E-7; std::shared_ptr> particle = @@ -1462,7 +1462,7 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { h5_particle.material_id = 1; - // Reinitialise particle from HDF5 data + // Reinitialise particle from POD data REQUIRE(particle->initialise_particle(h5_particle) == true); // Check particle id @@ -1521,7 +1521,7 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { // Check material id REQUIRE(particle->material_id() == h5_particle.material_id); - // Write Particle HDF5 data + // Write Particle POD data auto h5_test = std::static_pointer_cast(particle->pod()); REQUIRE(h5_particle.id == h5_test->id); @@ -2754,8 +2754,8 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { } } - // Check initialise particle from HDF5 file - SECTION("Check initialise particle HDF5") { + // Check initialise particle from POD file + SECTION("Check initialise particle POD") { mpm::Index id = 0; const double Tolerance = 1.E-7; std::shared_ptr> particle = @@ -2817,7 +2817,7 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { h5_particle.material_id = 1; - // Reinitialise particle from HDF5 data + // Reinitialise particle from POD data REQUIRE(particle->initialise_particle(h5_particle) == true); // Check particle id @@ -2877,7 +2877,7 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { // Check material id REQUIRE(particle->material_id() == h5_particle.material_id); - // Write Particle HDF5 data + // Write Particle POD data auto h5_test = std::static_pointer_cast(particle->pod()); REQUIRE(h5_particle.id == h5_test->id); diff --git a/tests/particles/particle_twophase_test.cc b/tests/particles/particle_twophase_test.cc index d7600071d..d4608f296 100644 --- a/tests/particles/particle_twophase_test.cc +++ b/tests/particles/particle_twophase_test.cc @@ -207,7 +207,7 @@ TEST_CASE("TwoPhase Particle is checked for 1D case", } } - SECTION("Check initialise particle HDF5") { + SECTION("Check initialise particle POD") { mpm::Index id = 0; const double Tolerance = 1.E-7; std::shared_ptr> particle = @@ -283,7 +283,7 @@ TEST_CASE("TwoPhase Particle is checked for 1D case", h5_particle.liquid_material_id = 2; - // Reinitialise particle from HDF5 data + // Reinitialise particle from POD data REQUIRE(particle->initialise_particle(h5_particle) == true); // Check particle id @@ -359,7 +359,7 @@ TEST_CASE("TwoPhase Particle is checked for 1D case", REQUIRE(particle->material_id(mpm::ParticlePhase::Liquid) == h5_particle.liquid_material_id); - // Write Particle HDF5 data + // Write Particle POD data auto h5_test = std::static_pointer_cast(particle->pod()); @@ -1448,8 +1448,8 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", } } - // Check initialise particle from HDF5 file - SECTION("Check initialise particle HDF5") { + // Check initialise particle from POD file + SECTION("Check initialise particle POD") { mpm::Index id = 0; const double Tolerance = 1.E-7; std::shared_ptr> particle = @@ -1525,7 +1525,7 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", h5_particle.liquid_material_id = 2; - // Reinitialise particle from HDF5 data + // Reinitialise particle from POD data REQUIRE(particle->initialise_particle(h5_particle) == true); // Check particle id @@ -1601,7 +1601,7 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", REQUIRE(particle->material_id(mpm::ParticlePhase::Liquid) == h5_particle.liquid_material_id); - // Write Particle HDF5 data + // Write Particle POD data auto h5_test = std::static_pointer_cast(particle->pod()); @@ -2936,8 +2936,8 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", } } - // Check initialise particle from HDF5 file - SECTION("Check initialise particle HDF5") { + // Check initialise particle from POD file + SECTION("Check initialise particle POD") { mpm::Index id = 0; const double Tolerance = 1.E-7; std::shared_ptr> particle = @@ -3013,7 +3013,7 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", h5_particle.liquid_material_id = 2; - // Reinitialise particle from HDF5 data + // Reinitialise particle from POD data REQUIRE(particle->initialise_particle(h5_particle) == true); // Check particle id @@ -3090,7 +3090,7 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", REQUIRE(particle->material_id(mpm::ParticlePhase::Liquid) == h5_particle.liquid_material_id); - // Write Particle HDF5 data + // Write Particle POD data auto h5_test = std::static_pointer_cast(particle->pod()); From 5eebcf3c3c7b9bfb0d0d9467547cb22780865b3d Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 25 Aug 2020 10:35:40 -0700 Subject: [PATCH 138/175] :pencil: change naming h5_test to pod_test --- include/mesh.tcc | 2 +- include/particles/particle.h | 3 +- include/particles/particle_base.h | 3 +- include/particles/particle_twophase.h | 3 +- tests/particles/particle_test.cc | 195 +++++++++--------- tests/particles/particle_twophase_test.cc | 237 +++++++++++----------- 6 files changed, 232 insertions(+), 211 deletions(-) diff --git a/include/mesh.tcc b/include/mesh.tcc index d4f2ee3fb..9ef90abea 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1523,7 +1523,7 @@ bool mpm::Mesh::read_particles_hdf5( std::vector dst_buf; dst_buf.reserve(nrecords); - // TODO: Think a better way to access mpm::pod::particle namespaces + // TODO: Think a better way to access mpm::pod::particle namespaces if (particle_type == "P2D" || particle_type == "P3D") { if (nfields != mpm::pod::particle::NFIELDS) throw std::runtime_error("HDF5 table has incorrect number of fields"); diff --git a/include/particles/particle.h b/include/particles/particle.h index 46144d7f6..6fd3862d0 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -53,7 +53,8 @@ class Particle : public ParticleBase { //! Initialise particle POD data and material //! \param[in] particle POD data of particle - //! \param[in] materials Material associated with the particle arranged in vector + //! \param[in] materials Material associated with the particle arranged in a + //! vector //! \retval status Status of reading POD particle virtual bool initialise_particle( PODParticle& particle, diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 19ce6d351..9b8d7223e 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -73,7 +73,8 @@ class ParticleBase { //! Initialise particle POD data and material //! \param[in] particle POD data of particle - //! \param[in] materials Material associated with the particle arranged in vector + //! \param[in] materials Material associated with the particle arranged in a + //! vector //! \retval status Status of reading POD particle virtual bool initialise_particle( PODParticle& particle, diff --git a/include/particles/particle_twophase.h b/include/particles/particle_twophase.h index e0d7b4b52..94705cb67 100644 --- a/include/particles/particle_twophase.h +++ b/include/particles/particle_twophase.h @@ -49,7 +49,8 @@ class TwoPhaseParticle : public mpm::Particle { //! Initialise particle POD data and material //! \param[in] particle POD data of particle - //! \param[in] materials Material associated with the particle arranged in vector + //! \param[in] materials Material associated with the particle arranged in a + //! vector //! \retval status Status of reading POD particle bool initialise_particle( PODParticle& particle, diff --git a/tests/particles/particle_test.cc b/tests/particles/particle_test.cc index 6ce062a56..e39afe425 100644 --- a/tests/particles/particle_test.cc +++ b/tests/particles/particle_test.cc @@ -378,61 +378,64 @@ TEST_CASE("Particle is checked for 1D case", "[particle][1D]") { REQUIRE(particle->material_id() == h5_particle.material_id); // Write Particle POD data - auto h5_test = std::static_pointer_cast(particle->pod()); + auto pod_test = std::static_pointer_cast(particle->pod()); - REQUIRE(h5_particle.id == h5_test->id); - REQUIRE(h5_particle.mass == h5_test->mass); + REQUIRE(h5_particle.id == pod_test->id); + REQUIRE(h5_particle.mass == pod_test->mass); - REQUIRE(h5_particle.coord_x == Approx(h5_test->coord_x).epsilon(Tolerance)); - REQUIRE(h5_particle.coord_y == Approx(h5_test->coord_y).epsilon(Tolerance)); - REQUIRE(h5_particle.coord_z == Approx(h5_test->coord_z).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_x == + Approx(pod_test->coord_x).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_y == + Approx(pod_test->coord_y).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_z == + Approx(pod_test->coord_z).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_x == - Approx(h5_test->displacement_x).epsilon(Tolerance)); + Approx(pod_test->displacement_x).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_y == - Approx(h5_test->displacement_y).epsilon(Tolerance)); + Approx(pod_test->displacement_y).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_z == - Approx(h5_test->displacement_z).epsilon(Tolerance)); + Approx(pod_test->displacement_z).epsilon(Tolerance)); - REQUIRE(h5_particle.nsize_x == h5_test->nsize_x); - REQUIRE(h5_particle.nsize_y == h5_test->nsize_y); - REQUIRE(h5_particle.nsize_z == h5_test->nsize_z); + REQUIRE(h5_particle.nsize_x == pod_test->nsize_x); + REQUIRE(h5_particle.nsize_y == pod_test->nsize_y); + REQUIRE(h5_particle.nsize_z == pod_test->nsize_z); REQUIRE(h5_particle.velocity_x == - Approx(h5_test->velocity_x).epsilon(Tolerance)); + Approx(pod_test->velocity_x).epsilon(Tolerance)); REQUIRE(h5_particle.velocity_y == - Approx(h5_test->velocity_y).epsilon(Tolerance)); + Approx(pod_test->velocity_y).epsilon(Tolerance)); REQUIRE(h5_particle.velocity_z == - Approx(h5_test->velocity_z).epsilon(Tolerance)); + Approx(pod_test->velocity_z).epsilon(Tolerance)); REQUIRE(h5_particle.stress_xx == - Approx(h5_test->stress_xx).epsilon(Tolerance)); + Approx(pod_test->stress_xx).epsilon(Tolerance)); REQUIRE(h5_particle.stress_yy == - Approx(h5_test->stress_yy).epsilon(Tolerance)); + Approx(pod_test->stress_yy).epsilon(Tolerance)); REQUIRE(h5_particle.stress_zz == - Approx(h5_test->stress_zz).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_xy == Approx(h5_test->tau_xy).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_yz == Approx(h5_test->tau_yz).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_xz == Approx(h5_test->tau_xz).epsilon(Tolerance)); + Approx(pod_test->stress_zz).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_xy == Approx(pod_test->tau_xy).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_yz == Approx(pod_test->tau_yz).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_xz == Approx(pod_test->tau_xz).epsilon(Tolerance)); REQUIRE(h5_particle.strain_xx == - Approx(h5_test->strain_xx).epsilon(Tolerance)); + Approx(pod_test->strain_xx).epsilon(Tolerance)); REQUIRE(h5_particle.strain_yy == - Approx(h5_test->strain_yy).epsilon(Tolerance)); + Approx(pod_test->strain_yy).epsilon(Tolerance)); REQUIRE(h5_particle.strain_zz == - Approx(h5_test->strain_zz).epsilon(Tolerance)); + Approx(pod_test->strain_zz).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_xy == - Approx(h5_test->gamma_xy).epsilon(Tolerance)); + Approx(pod_test->gamma_xy).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_yz == - Approx(h5_test->gamma_yz).epsilon(Tolerance)); + Approx(pod_test->gamma_yz).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_xz == - Approx(h5_test->gamma_xz).epsilon(Tolerance)); + Approx(pod_test->gamma_xz).epsilon(Tolerance)); REQUIRE(h5_particle.epsilon_v == - Approx(h5_test->epsilon_v).epsilon(Tolerance)); - REQUIRE(h5_particle.status == h5_test->status); - REQUIRE(h5_particle.cell_id == h5_test->cell_id); - REQUIRE(h5_particle.material_id == h5_test->material_id); + Approx(pod_test->epsilon_v).epsilon(Tolerance)); + REQUIRE(h5_particle.status == pod_test->status); + REQUIRE(h5_particle.cell_id == pod_test->cell_id); + REQUIRE(h5_particle.material_id == pod_test->material_id); } } @@ -1522,61 +1525,64 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { REQUIRE(particle->material_id() == h5_particle.material_id); // Write Particle POD data - auto h5_test = std::static_pointer_cast(particle->pod()); + auto pod_test = std::static_pointer_cast(particle->pod()); - REQUIRE(h5_particle.id == h5_test->id); - REQUIRE(h5_particle.mass == h5_test->mass); + REQUIRE(h5_particle.id == pod_test->id); + REQUIRE(h5_particle.mass == pod_test->mass); - REQUIRE(h5_particle.coord_x == Approx(h5_test->coord_x).epsilon(Tolerance)); - REQUIRE(h5_particle.coord_y == Approx(h5_test->coord_y).epsilon(Tolerance)); - REQUIRE(h5_particle.coord_z == Approx(h5_test->coord_z).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_x == + Approx(pod_test->coord_x).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_y == + Approx(pod_test->coord_y).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_z == + Approx(pod_test->coord_z).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_x == - Approx(h5_test->displacement_x).epsilon(Tolerance)); + Approx(pod_test->displacement_x).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_y == - Approx(h5_test->displacement_y).epsilon(Tolerance)); + Approx(pod_test->displacement_y).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_z == - Approx(h5_test->displacement_z).epsilon(Tolerance)); + Approx(pod_test->displacement_z).epsilon(Tolerance)); - REQUIRE(h5_particle.nsize_x == h5_test->nsize_x); - REQUIRE(h5_particle.nsize_y == h5_test->nsize_y); - REQUIRE(h5_particle.nsize_z == h5_test->nsize_z); + REQUIRE(h5_particle.nsize_x == pod_test->nsize_x); + REQUIRE(h5_particle.nsize_y == pod_test->nsize_y); + REQUIRE(h5_particle.nsize_z == pod_test->nsize_z); REQUIRE(h5_particle.velocity_x == - Approx(h5_test->velocity_x).epsilon(Tolerance)); + Approx(pod_test->velocity_x).epsilon(Tolerance)); REQUIRE(h5_particle.velocity_y == - Approx(h5_test->velocity_y).epsilon(Tolerance)); + Approx(pod_test->velocity_y).epsilon(Tolerance)); REQUIRE(h5_particle.velocity_z == - Approx(h5_test->velocity_z).epsilon(Tolerance)); + Approx(pod_test->velocity_z).epsilon(Tolerance)); REQUIRE(h5_particle.stress_xx == - Approx(h5_test->stress_xx).epsilon(Tolerance)); + Approx(pod_test->stress_xx).epsilon(Tolerance)); REQUIRE(h5_particle.stress_yy == - Approx(h5_test->stress_yy).epsilon(Tolerance)); + Approx(pod_test->stress_yy).epsilon(Tolerance)); REQUIRE(h5_particle.stress_zz == - Approx(h5_test->stress_zz).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_xy == Approx(h5_test->tau_xy).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_yz == Approx(h5_test->tau_yz).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_xz == Approx(h5_test->tau_xz).epsilon(Tolerance)); + Approx(pod_test->stress_zz).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_xy == Approx(pod_test->tau_xy).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_yz == Approx(pod_test->tau_yz).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_xz == Approx(pod_test->tau_xz).epsilon(Tolerance)); REQUIRE(h5_particle.strain_xx == - Approx(h5_test->strain_xx).epsilon(Tolerance)); + Approx(pod_test->strain_xx).epsilon(Tolerance)); REQUIRE(h5_particle.strain_yy == - Approx(h5_test->strain_yy).epsilon(Tolerance)); + Approx(pod_test->strain_yy).epsilon(Tolerance)); REQUIRE(h5_particle.strain_zz == - Approx(h5_test->strain_zz).epsilon(Tolerance)); + Approx(pod_test->strain_zz).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_xy == - Approx(h5_test->gamma_xy).epsilon(Tolerance)); + Approx(pod_test->gamma_xy).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_yz == - Approx(h5_test->gamma_yz).epsilon(Tolerance)); + Approx(pod_test->gamma_yz).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_xz == - Approx(h5_test->gamma_xz).epsilon(Tolerance)); + Approx(pod_test->gamma_xz).epsilon(Tolerance)); REQUIRE(h5_particle.epsilon_v == - Approx(h5_test->epsilon_v).epsilon(Tolerance)); - REQUIRE(h5_particle.status == h5_test->status); - REQUIRE(h5_particle.cell_id == h5_test->cell_id); - REQUIRE(h5_particle.material_id == h5_test->material_id); + Approx(pod_test->epsilon_v).epsilon(Tolerance)); + REQUIRE(h5_particle.status == pod_test->status); + REQUIRE(h5_particle.cell_id == pod_test->cell_id); + REQUIRE(h5_particle.material_id == pod_test->material_id); } // Check particle's material id maping to nodes @@ -2878,61 +2884,64 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { REQUIRE(particle->material_id() == h5_particle.material_id); // Write Particle POD data - auto h5_test = std::static_pointer_cast(particle->pod()); + auto pod_test = std::static_pointer_cast(particle->pod()); - REQUIRE(h5_particle.id == h5_test->id); - REQUIRE(h5_particle.mass == h5_test->mass); + REQUIRE(h5_particle.id == pod_test->id); + REQUIRE(h5_particle.mass == pod_test->mass); - REQUIRE(h5_particle.coord_x == Approx(h5_test->coord_x).epsilon(Tolerance)); - REQUIRE(h5_particle.coord_y == Approx(h5_test->coord_y).epsilon(Tolerance)); - REQUIRE(h5_particle.coord_z == Approx(h5_test->coord_z).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_x == + Approx(pod_test->coord_x).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_y == + Approx(pod_test->coord_y).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_z == + Approx(pod_test->coord_z).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_x == - Approx(h5_test->displacement_x).epsilon(Tolerance)); + Approx(pod_test->displacement_x).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_y == - Approx(h5_test->displacement_y).epsilon(Tolerance)); + Approx(pod_test->displacement_y).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_z == - Approx(h5_test->displacement_z).epsilon(Tolerance)); + Approx(pod_test->displacement_z).epsilon(Tolerance)); - REQUIRE(h5_particle.nsize_x == h5_test->nsize_x); - REQUIRE(h5_particle.nsize_y == h5_test->nsize_y); - REQUIRE(h5_particle.nsize_z == h5_test->nsize_z); + REQUIRE(h5_particle.nsize_x == pod_test->nsize_x); + REQUIRE(h5_particle.nsize_y == pod_test->nsize_y); + REQUIRE(h5_particle.nsize_z == pod_test->nsize_z); REQUIRE(h5_particle.velocity_x == - Approx(h5_test->velocity_x).epsilon(Tolerance)); + Approx(pod_test->velocity_x).epsilon(Tolerance)); REQUIRE(h5_particle.velocity_y == - Approx(h5_test->velocity_y).epsilon(Tolerance)); + Approx(pod_test->velocity_y).epsilon(Tolerance)); REQUIRE(h5_particle.velocity_z == - Approx(h5_test->velocity_z).epsilon(Tolerance)); + Approx(pod_test->velocity_z).epsilon(Tolerance)); REQUIRE(h5_particle.stress_xx == - Approx(h5_test->stress_xx).epsilon(Tolerance)); + Approx(pod_test->stress_xx).epsilon(Tolerance)); REQUIRE(h5_particle.stress_yy == - Approx(h5_test->stress_yy).epsilon(Tolerance)); + Approx(pod_test->stress_yy).epsilon(Tolerance)); REQUIRE(h5_particle.stress_zz == - Approx(h5_test->stress_zz).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_xy == Approx(h5_test->tau_xy).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_yz == Approx(h5_test->tau_yz).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_xz == Approx(h5_test->tau_xz).epsilon(Tolerance)); + Approx(pod_test->stress_zz).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_xy == Approx(pod_test->tau_xy).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_yz == Approx(pod_test->tau_yz).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_xz == Approx(pod_test->tau_xz).epsilon(Tolerance)); REQUIRE(h5_particle.strain_xx == - Approx(h5_test->strain_xx).epsilon(Tolerance)); + Approx(pod_test->strain_xx).epsilon(Tolerance)); REQUIRE(h5_particle.strain_yy == - Approx(h5_test->strain_yy).epsilon(Tolerance)); + Approx(pod_test->strain_yy).epsilon(Tolerance)); REQUIRE(h5_particle.strain_zz == - Approx(h5_test->strain_zz).epsilon(Tolerance)); + Approx(pod_test->strain_zz).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_xy == - Approx(h5_test->gamma_xy).epsilon(Tolerance)); + Approx(pod_test->gamma_xy).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_yz == - Approx(h5_test->gamma_yz).epsilon(Tolerance)); + Approx(pod_test->gamma_yz).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_xz == - Approx(h5_test->gamma_xz).epsilon(Tolerance)); + Approx(pod_test->gamma_xz).epsilon(Tolerance)); REQUIRE(h5_particle.epsilon_v == - Approx(h5_test->epsilon_v).epsilon(Tolerance)); - REQUIRE(h5_particle.status == h5_test->status); - REQUIRE(h5_particle.cell_id == h5_test->cell_id); - REQUIRE(h5_particle.material_id == h5_test->material_id); + Approx(pod_test->epsilon_v).epsilon(Tolerance)); + REQUIRE(h5_particle.status == pod_test->status); + REQUIRE(h5_particle.cell_id == pod_test->cell_id); + REQUIRE(h5_particle.material_id == pod_test->material_id); } // Check particle's material id maping to nodes diff --git a/tests/particles/particle_twophase_test.cc b/tests/particles/particle_twophase_test.cc index d4608f296..58d71ee69 100644 --- a/tests/particles/particle_twophase_test.cc +++ b/tests/particles/particle_twophase_test.cc @@ -360,77 +360,80 @@ TEST_CASE("TwoPhase Particle is checked for 1D case", h5_particle.liquid_material_id); // Write Particle POD data - auto h5_test = + auto pod_test = std::static_pointer_cast(particle->pod()); - REQUIRE(h5_particle.id == h5_test->id); - REQUIRE(h5_particle.mass == h5_test->mass); + REQUIRE(h5_particle.id == pod_test->id); + REQUIRE(h5_particle.mass == pod_test->mass); - REQUIRE(h5_particle.coord_x == Approx(h5_test->coord_x).epsilon(Tolerance)); - REQUIRE(h5_particle.coord_y == Approx(h5_test->coord_y).epsilon(Tolerance)); - REQUIRE(h5_particle.coord_z == Approx(h5_test->coord_z).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_x == + Approx(pod_test->coord_x).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_y == + Approx(pod_test->coord_y).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_z == + Approx(pod_test->coord_z).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_x == - Approx(h5_test->displacement_x).epsilon(Tolerance)); + Approx(pod_test->displacement_x).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_y == - Approx(h5_test->displacement_y).epsilon(Tolerance)); + Approx(pod_test->displacement_y).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_z == - Approx(h5_test->displacement_z).epsilon(Tolerance)); + Approx(pod_test->displacement_z).epsilon(Tolerance)); - REQUIRE(h5_particle.nsize_x == h5_test->nsize_x); - REQUIRE(h5_particle.nsize_y == h5_test->nsize_y); - REQUIRE(h5_particle.nsize_z == h5_test->nsize_z); + REQUIRE(h5_particle.nsize_x == pod_test->nsize_x); + REQUIRE(h5_particle.nsize_y == pod_test->nsize_y); + REQUIRE(h5_particle.nsize_z == pod_test->nsize_z); REQUIRE(h5_particle.velocity_x == - Approx(h5_test->velocity_x).epsilon(Tolerance)); + Approx(pod_test->velocity_x).epsilon(Tolerance)); REQUIRE(h5_particle.velocity_y == - Approx(h5_test->velocity_y).epsilon(Tolerance)); + Approx(pod_test->velocity_y).epsilon(Tolerance)); REQUIRE(h5_particle.velocity_z == - Approx(h5_test->velocity_z).epsilon(Tolerance)); + Approx(pod_test->velocity_z).epsilon(Tolerance)); REQUIRE(h5_particle.stress_xx == - Approx(h5_test->stress_xx).epsilon(Tolerance)); + Approx(pod_test->stress_xx).epsilon(Tolerance)); REQUIRE(h5_particle.stress_yy == - Approx(h5_test->stress_yy).epsilon(Tolerance)); + Approx(pod_test->stress_yy).epsilon(Tolerance)); REQUIRE(h5_particle.stress_zz == - Approx(h5_test->stress_zz).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_xy == Approx(h5_test->tau_xy).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_yz == Approx(h5_test->tau_yz).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_xz == Approx(h5_test->tau_xz).epsilon(Tolerance)); + Approx(pod_test->stress_zz).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_xy == Approx(pod_test->tau_xy).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_yz == Approx(pod_test->tau_yz).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_xz == Approx(pod_test->tau_xz).epsilon(Tolerance)); REQUIRE(h5_particle.strain_xx == - Approx(h5_test->strain_xx).epsilon(Tolerance)); + Approx(pod_test->strain_xx).epsilon(Tolerance)); REQUIRE(h5_particle.strain_yy == - Approx(h5_test->strain_yy).epsilon(Tolerance)); + Approx(pod_test->strain_yy).epsilon(Tolerance)); REQUIRE(h5_particle.strain_zz == - Approx(h5_test->strain_zz).epsilon(Tolerance)); + Approx(pod_test->strain_zz).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_xy == - Approx(h5_test->gamma_xy).epsilon(Tolerance)); + Approx(pod_test->gamma_xy).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_yz == - Approx(h5_test->gamma_yz).epsilon(Tolerance)); + Approx(pod_test->gamma_yz).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_xz == - Approx(h5_test->gamma_xz).epsilon(Tolerance)); + Approx(pod_test->gamma_xz).epsilon(Tolerance)); REQUIRE(h5_particle.epsilon_v == - Approx(h5_test->epsilon_v).epsilon(Tolerance)); - REQUIRE(h5_particle.status == h5_test->status); - REQUIRE(h5_particle.cell_id == h5_test->cell_id); - REQUIRE(h5_particle.material_id == h5_test->material_id); + Approx(pod_test->epsilon_v).epsilon(Tolerance)); + REQUIRE(h5_particle.status == pod_test->status); + REQUIRE(h5_particle.cell_id == pod_test->cell_id); + REQUIRE(h5_particle.material_id == pod_test->material_id); REQUIRE(h5_particle.liquid_mass == - Approx(h5_test->liquid_mass).epsilon(Tolerance)); + Approx(pod_test->liquid_mass).epsilon(Tolerance)); REQUIRE(h5_particle.liquid_velocity_x == - Approx(h5_test->liquid_velocity_x).epsilon(Tolerance)); + Approx(pod_test->liquid_velocity_x).epsilon(Tolerance)); REQUIRE(h5_particle.liquid_velocity_y == - Approx(h5_test->liquid_velocity_y).epsilon(Tolerance)); + Approx(pod_test->liquid_velocity_y).epsilon(Tolerance)); REQUIRE(h5_particle.liquid_velocity_z == - Approx(h5_test->liquid_velocity_z).epsilon(Tolerance)); + Approx(pod_test->liquid_velocity_z).epsilon(Tolerance)); REQUIRE(h5_particle.porosity == - Approx(h5_test->porosity).epsilon(Tolerance)); + Approx(pod_test->porosity).epsilon(Tolerance)); REQUIRE(h5_particle.liquid_saturation == - Approx(h5_test->liquid_saturation).epsilon(Tolerance)); + Approx(pod_test->liquid_saturation).epsilon(Tolerance)); REQUIRE(h5_particle.liquid_material_id == - Approx(h5_test->liquid_material_id).epsilon(Tolerance)); + Approx(pod_test->liquid_material_id).epsilon(Tolerance)); } } @@ -1602,77 +1605,80 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", h5_particle.liquid_material_id); // Write Particle POD data - auto h5_test = + auto pod_test = std::static_pointer_cast(particle->pod()); - REQUIRE(h5_particle.id == h5_test->id); - REQUIRE(h5_particle.mass == h5_test->mass); + REQUIRE(h5_particle.id == pod_test->id); + REQUIRE(h5_particle.mass == pod_test->mass); - REQUIRE(h5_particle.coord_x == Approx(h5_test->coord_x).epsilon(Tolerance)); - REQUIRE(h5_particle.coord_y == Approx(h5_test->coord_y).epsilon(Tolerance)); - REQUIRE(h5_particle.coord_z == Approx(h5_test->coord_z).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_x == + Approx(pod_test->coord_x).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_y == + Approx(pod_test->coord_y).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_z == + Approx(pod_test->coord_z).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_x == - Approx(h5_test->displacement_x).epsilon(Tolerance)); + Approx(pod_test->displacement_x).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_y == - Approx(h5_test->displacement_y).epsilon(Tolerance)); + Approx(pod_test->displacement_y).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_z == - Approx(h5_test->displacement_z).epsilon(Tolerance)); + Approx(pod_test->displacement_z).epsilon(Tolerance)); - REQUIRE(h5_particle.nsize_x == h5_test->nsize_x); - REQUIRE(h5_particle.nsize_y == h5_test->nsize_y); - REQUIRE(h5_particle.nsize_z == h5_test->nsize_z); + REQUIRE(h5_particle.nsize_x == pod_test->nsize_x); + REQUIRE(h5_particle.nsize_y == pod_test->nsize_y); + REQUIRE(h5_particle.nsize_z == pod_test->nsize_z); REQUIRE(h5_particle.velocity_x == - Approx(h5_test->velocity_x).epsilon(Tolerance)); + Approx(pod_test->velocity_x).epsilon(Tolerance)); REQUIRE(h5_particle.velocity_y == - Approx(h5_test->velocity_y).epsilon(Tolerance)); + Approx(pod_test->velocity_y).epsilon(Tolerance)); REQUIRE(h5_particle.velocity_z == - Approx(h5_test->velocity_z).epsilon(Tolerance)); + Approx(pod_test->velocity_z).epsilon(Tolerance)); REQUIRE(h5_particle.stress_xx == - Approx(h5_test->stress_xx).epsilon(Tolerance)); + Approx(pod_test->stress_xx).epsilon(Tolerance)); REQUIRE(h5_particle.stress_yy == - Approx(h5_test->stress_yy).epsilon(Tolerance)); + Approx(pod_test->stress_yy).epsilon(Tolerance)); REQUIRE(h5_particle.stress_zz == - Approx(h5_test->stress_zz).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_xy == Approx(h5_test->tau_xy).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_yz == Approx(h5_test->tau_yz).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_xz == Approx(h5_test->tau_xz).epsilon(Tolerance)); + Approx(pod_test->stress_zz).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_xy == Approx(pod_test->tau_xy).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_yz == Approx(pod_test->tau_yz).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_xz == Approx(pod_test->tau_xz).epsilon(Tolerance)); REQUIRE(h5_particle.strain_xx == - Approx(h5_test->strain_xx).epsilon(Tolerance)); + Approx(pod_test->strain_xx).epsilon(Tolerance)); REQUIRE(h5_particle.strain_yy == - Approx(h5_test->strain_yy).epsilon(Tolerance)); + Approx(pod_test->strain_yy).epsilon(Tolerance)); REQUIRE(h5_particle.strain_zz == - Approx(h5_test->strain_zz).epsilon(Tolerance)); + Approx(pod_test->strain_zz).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_xy == - Approx(h5_test->gamma_xy).epsilon(Tolerance)); + Approx(pod_test->gamma_xy).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_yz == - Approx(h5_test->gamma_yz).epsilon(Tolerance)); + Approx(pod_test->gamma_yz).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_xz == - Approx(h5_test->gamma_xz).epsilon(Tolerance)); + Approx(pod_test->gamma_xz).epsilon(Tolerance)); REQUIRE(h5_particle.epsilon_v == - Approx(h5_test->epsilon_v).epsilon(Tolerance)); - REQUIRE(h5_particle.status == h5_test->status); - REQUIRE(h5_particle.cell_id == h5_test->cell_id); - REQUIRE(h5_particle.material_id == h5_test->material_id); + Approx(pod_test->epsilon_v).epsilon(Tolerance)); + REQUIRE(h5_particle.status == pod_test->status); + REQUIRE(h5_particle.cell_id == pod_test->cell_id); + REQUIRE(h5_particle.material_id == pod_test->material_id); REQUIRE(h5_particle.liquid_mass == - Approx(h5_test->liquid_mass).epsilon(Tolerance)); + Approx(pod_test->liquid_mass).epsilon(Tolerance)); REQUIRE(h5_particle.liquid_velocity_x == - Approx(h5_test->liquid_velocity_x).epsilon(Tolerance)); + Approx(pod_test->liquid_velocity_x).epsilon(Tolerance)); REQUIRE(h5_particle.liquid_velocity_y == - Approx(h5_test->liquid_velocity_y).epsilon(Tolerance)); + Approx(pod_test->liquid_velocity_y).epsilon(Tolerance)); REQUIRE(h5_particle.liquid_velocity_z == - Approx(h5_test->liquid_velocity_z).epsilon(Tolerance)); + Approx(pod_test->liquid_velocity_z).epsilon(Tolerance)); REQUIRE(h5_particle.porosity == - Approx(h5_test->porosity).epsilon(Tolerance)); + Approx(pod_test->porosity).epsilon(Tolerance)); REQUIRE(h5_particle.liquid_saturation == - Approx(h5_test->liquid_saturation).epsilon(Tolerance)); + Approx(pod_test->liquid_saturation).epsilon(Tolerance)); REQUIRE(h5_particle.liquid_material_id == - Approx(h5_test->liquid_material_id).epsilon(Tolerance)); + Approx(pod_test->liquid_material_id).epsilon(Tolerance)); } // Check twophase particle's material id maping to nodes @@ -3091,77 +3097,80 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", h5_particle.liquid_material_id); // Write Particle POD data - auto h5_test = + auto pod_test = std::static_pointer_cast(particle->pod()); - REQUIRE(h5_particle.id == h5_test->id); - REQUIRE(h5_particle.mass == h5_test->mass); + REQUIRE(h5_particle.id == pod_test->id); + REQUIRE(h5_particle.mass == pod_test->mass); - REQUIRE(h5_particle.coord_x == Approx(h5_test->coord_x).epsilon(Tolerance)); - REQUIRE(h5_particle.coord_y == Approx(h5_test->coord_y).epsilon(Tolerance)); - REQUIRE(h5_particle.coord_z == Approx(h5_test->coord_z).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_x == + Approx(pod_test->coord_x).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_y == + Approx(pod_test->coord_y).epsilon(Tolerance)); + REQUIRE(h5_particle.coord_z == + Approx(pod_test->coord_z).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_x == - Approx(h5_test->displacement_x).epsilon(Tolerance)); + Approx(pod_test->displacement_x).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_y == - Approx(h5_test->displacement_y).epsilon(Tolerance)); + Approx(pod_test->displacement_y).epsilon(Tolerance)); REQUIRE(h5_particle.displacement_z == - Approx(h5_test->displacement_z).epsilon(Tolerance)); + Approx(pod_test->displacement_z).epsilon(Tolerance)); - REQUIRE(h5_particle.nsize_x == h5_test->nsize_x); - REQUIRE(h5_particle.nsize_y == h5_test->nsize_y); - REQUIRE(h5_particle.nsize_z == h5_test->nsize_z); + REQUIRE(h5_particle.nsize_x == pod_test->nsize_x); + REQUIRE(h5_particle.nsize_y == pod_test->nsize_y); + REQUIRE(h5_particle.nsize_z == pod_test->nsize_z); REQUIRE(h5_particle.velocity_x == - Approx(h5_test->velocity_x).epsilon(Tolerance)); + Approx(pod_test->velocity_x).epsilon(Tolerance)); REQUIRE(h5_particle.velocity_y == - Approx(h5_test->velocity_y).epsilon(Tolerance)); + Approx(pod_test->velocity_y).epsilon(Tolerance)); REQUIRE(h5_particle.velocity_z == - Approx(h5_test->velocity_z).epsilon(Tolerance)); + Approx(pod_test->velocity_z).epsilon(Tolerance)); REQUIRE(h5_particle.stress_xx == - Approx(h5_test->stress_xx).epsilon(Tolerance)); + Approx(pod_test->stress_xx).epsilon(Tolerance)); REQUIRE(h5_particle.stress_yy == - Approx(h5_test->stress_yy).epsilon(Tolerance)); + Approx(pod_test->stress_yy).epsilon(Tolerance)); REQUIRE(h5_particle.stress_zz == - Approx(h5_test->stress_zz).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_xy == Approx(h5_test->tau_xy).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_yz == Approx(h5_test->tau_yz).epsilon(Tolerance)); - REQUIRE(h5_particle.tau_xz == Approx(h5_test->tau_xz).epsilon(Tolerance)); + Approx(pod_test->stress_zz).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_xy == Approx(pod_test->tau_xy).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_yz == Approx(pod_test->tau_yz).epsilon(Tolerance)); + REQUIRE(h5_particle.tau_xz == Approx(pod_test->tau_xz).epsilon(Tolerance)); REQUIRE(h5_particle.strain_xx == - Approx(h5_test->strain_xx).epsilon(Tolerance)); + Approx(pod_test->strain_xx).epsilon(Tolerance)); REQUIRE(h5_particle.strain_yy == - Approx(h5_test->strain_yy).epsilon(Tolerance)); + Approx(pod_test->strain_yy).epsilon(Tolerance)); REQUIRE(h5_particle.strain_zz == - Approx(h5_test->strain_zz).epsilon(Tolerance)); + Approx(pod_test->strain_zz).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_xy == - Approx(h5_test->gamma_xy).epsilon(Tolerance)); + Approx(pod_test->gamma_xy).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_yz == - Approx(h5_test->gamma_yz).epsilon(Tolerance)); + Approx(pod_test->gamma_yz).epsilon(Tolerance)); REQUIRE(h5_particle.gamma_xz == - Approx(h5_test->gamma_xz).epsilon(Tolerance)); + Approx(pod_test->gamma_xz).epsilon(Tolerance)); REQUIRE(h5_particle.epsilon_v == - Approx(h5_test->epsilon_v).epsilon(Tolerance)); - REQUIRE(h5_particle.status == h5_test->status); - REQUIRE(h5_particle.cell_id == h5_test->cell_id); - REQUIRE(h5_particle.material_id == h5_test->material_id); + Approx(pod_test->epsilon_v).epsilon(Tolerance)); + REQUIRE(h5_particle.status == pod_test->status); + REQUIRE(h5_particle.cell_id == pod_test->cell_id); + REQUIRE(h5_particle.material_id == pod_test->material_id); REQUIRE(h5_particle.liquid_mass == - Approx(h5_test->liquid_mass).epsilon(Tolerance)); + Approx(pod_test->liquid_mass).epsilon(Tolerance)); REQUIRE(h5_particle.liquid_velocity_x == - Approx(h5_test->liquid_velocity_x).epsilon(Tolerance)); + Approx(pod_test->liquid_velocity_x).epsilon(Tolerance)); REQUIRE(h5_particle.liquid_velocity_y == - Approx(h5_test->liquid_velocity_y).epsilon(Tolerance)); + Approx(pod_test->liquid_velocity_y).epsilon(Tolerance)); REQUIRE(h5_particle.liquid_velocity_z == - Approx(h5_test->liquid_velocity_z).epsilon(Tolerance)); + Approx(pod_test->liquid_velocity_z).epsilon(Tolerance)); REQUIRE(h5_particle.porosity == - Approx(h5_test->porosity).epsilon(Tolerance)); + Approx(pod_test->porosity).epsilon(Tolerance)); REQUIRE(h5_particle.liquid_saturation == - Approx(h5_test->liquid_saturation).epsilon(Tolerance)); + Approx(pod_test->liquid_saturation).epsilon(Tolerance)); REQUIRE(h5_particle.liquid_material_id == - Approx(h5_test->liquid_material_id).epsilon(Tolerance)); + Approx(pod_test->liquid_material_id).epsilon(Tolerance)); } // Check particle's material id maping to nodes From 0ace4064621fbcf0f736e6ed4831ed5cb4892112 Mon Sep 17 00:00:00 2001 From: Nanda Date: Sat, 12 Sep 2020 20:12:20 +0700 Subject: [PATCH 139/175] :construction: :wrench: add write hdf5 twophase --- include/mesh.h | 9 ++- include/mesh.tcc | 83 +++++++++++++---------- include/particles/particle_twophase.h | 4 +- include/solvers/mpm.h | 3 + include/solvers/mpm_base.h | 3 + include/solvers/mpm_base.tcc | 28 +++++--- include/solvers/mpm_explicit_twophase.tcc | 2 +- tests/mesh_test_2d.cc | 3 +- tests/mesh_test_3d.cc | 3 +- 9 files changed, 86 insertions(+), 52 deletions(-) diff --git a/include/mesh.h b/include/mesh.h index 0e18d372f..5972fa3c9 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -406,10 +406,8 @@ class Mesh { //! Write HDF5 particles //! \param[in] filename Name of HDF5 file to write particles data - //! \param[in] particle_type Name of particle type to write //! \retval status Status of writing HDF5 output - bool write_particles_hdf5(const std::string& filename, - const std::string& particle_type); + bool write_particles_hdf5(const std::string& filename); //! Read HDF5 particles //! \param[in] filename Name of HDF5 file to write particles data @@ -418,6 +416,11 @@ class Mesh { bool read_particles_hdf5(const std::string& filename, const std::set& particle_types); + //! Write HDF5 particles for two-phase-one-point particle + //! \param[in] filename Name of HDF5 file to write particles data + //! \retval status Status of writing HDF5 output + bool write_particles_hdf5_twophase(const std::string& filename); + //! Return HDF5 particles //! \retval particles_hdf5 Vector of HDF5 particles std::vector particles_hdf5() const; diff --git a/include/mesh.tcc b/include/mesh.tcc index 9ef90abea..9bf272b67 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1437,31 +1437,20 @@ std::vector> mpm::Mesh::particles_cells() //! Write particles to HDF5 template -bool mpm::Mesh::write_particles_hdf5(const std::string& filename, - const std::string& particle_type) { - const unsigned nparticles = this->nparticles(particle_type); +bool mpm::Mesh::write_particles_hdf5(const std::string& filename) { + const unsigned nparticles = this->nparticles(); - // FIXME: PODParticle type does not work for twophase particle std::vector particle_data; particle_data.reserve(nparticles); for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { - if ((*pitr)->type() == particle_type) { - // TODO: Think a better way to separate static_pointer_cast of PODParticle - // or PODParticleTwoPhase - if (particle_type == "P2D" || particle_type == "P3D") { - auto pod = std::static_pointer_cast((*pitr)->pod()); - particle_data.emplace_back(*pod); - } else if (particle_type == "P2D2PHASE" || particle_type == "P3D2PHASE") { - auto pod = - std::static_pointer_cast((*pitr)->pod()); - particle_data.emplace_back(*pod); - } - } + auto pod = std::static_pointer_cast((*pitr)->pod()); + particle_data.emplace_back(*pod); } // Calculate the size and the offsets of our struct members in memory const hsize_t NRECORDS = nparticles; + const hsize_t NFIELDS = mpm::pod::particle::NFIELDS; hid_t file_id; hsize_t chunk_size = 10000; @@ -1472,26 +1461,52 @@ bool mpm::Mesh::write_particles_hdf5(const std::string& filename, file_id = H5Fcreate(filename.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); - // TODO: Think a better way to access mpm::pod::particle namespaces - if (particle_type == "P2D" || particle_type == "P3D") { - const hsize_t NFIELDS = mpm::pod::particle::NFIELDS; - // make a table - H5TBmake_table( - "Table Title", file_id, "table", NFIELDS, NRECORDS, - mpm::pod::particle::dst_size, mpm::pod::particle::field_names, - mpm::pod::particle::dst_offset, mpm::pod::particle::field_type, - chunk_size, fill_data, compress, particle_data.data()); - } else if (particle_type == "P2D2PHASE" || particle_type == "P3D2PHASE") { - const hsize_t NFIELDS = mpm::pod::particletwophase::NFIELDS; - // make a table - H5TBmake_table("Table Title", file_id, "table", NFIELDS, NRECORDS, - mpm::pod::particletwophase::dst_size, - mpm::pod::particletwophase::field_names, - mpm::pod::particletwophase::dst_offset, - mpm::pod::particletwophase::field_type, chunk_size, - fill_data, compress, particle_data.data()); + // make a table + H5TBmake_table("Table Title", file_id, "table", NFIELDS, NRECORDS, + mpm::pod::particle::dst_size, mpm::pod::particle::field_names, + mpm::pod::particle::dst_offset, mpm::pod::particle::field_type, + chunk_size, fill_data, compress, particle_data.data()); + + H5Fclose(file_id); + return true; +} + +//! Write particles to HDF5 for two-phase particle +template +bool mpm::Mesh::write_particles_hdf5_twophase( + const std::string& filename) { + const unsigned nparticles = this->nparticles(); + + std::vector particle_data; + particle_data.reserve(nparticles); + + for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { + auto pod = + std::static_pointer_cast((*pitr)->pod()); + particle_data.emplace_back(*pod); } + // Calculate the size and the offsets of our struct members in memory + const hsize_t NRECORDS = nparticles; + const hsize_t NFIELDS = mpm::pod::particletwophase::NFIELDS; + + hid_t file_id; + hsize_t chunk_size = 10000; + int* fill_data = NULL; + int compress = 0; + + // Create a new file using default properties. + file_id = + H5Fcreate(filename.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + + // make a table + H5TBmake_table("Table Title", file_id, "table", NFIELDS, NRECORDS, + mpm::pod::particletwophase::dst_size, + mpm::pod::particletwophase::field_names, + mpm::pod::particletwophase::dst_offset, + mpm::pod::particletwophase::field_type, chunk_size, fill_data, + compress, particle_data.data()); + H5Fclose(file_id); return true; } diff --git a/include/particles/particle_twophase.h b/include/particles/particle_twophase.h index 94705cb67..141880117 100644 --- a/include/particles/particle_twophase.h +++ b/include/particles/particle_twophase.h @@ -218,9 +218,9 @@ class TwoPhaseParticle : public mpm::Particle { using Particle::stress_; //! Soil skeleton strain rate using Particle::strain_rate_; - //! Soil skeleton material + //! Materials using Particle::material_; - //! Material id + //! Material ids using ParticleBase::material_id_; //! Particle total volume using Particle::volume_; diff --git a/include/solvers/mpm.h b/include/solvers/mpm.h index 070917dd2..7ccf9e16f 100644 --- a/include/solvers/mpm.h +++ b/include/solvers/mpm.h @@ -67,6 +67,9 @@ class MPM { //! Write HDF5 files virtual void write_hdf5(mpm::Index step, mpm::Index max_steps) = 0; + //! Write HDF5 files for twophase particles + virtual void write_hdf5_twophase(mpm::Index step, mpm::Index max_steps) = 0; + #ifdef USE_VTK //! Write VTK files virtual void write_vtk(mpm::Index step, mpm::Index max_steps) = 0; diff --git a/include/solvers/mpm_base.h b/include/solvers/mpm_base.h index 2426aaeac..7c4b27eeb 100644 --- a/include/solvers/mpm_base.h +++ b/include/solvers/mpm_base.h @@ -84,6 +84,9 @@ class MPMBase : public MPM { //! Write HDF5 files void write_hdf5(mpm::Index step, mpm::Index max_steps) override; + //! Write HDF5 files for twophase particles + void write_hdf5_twophase(mpm::Index step, mpm::Index max_steps) override; + //! Domain decomposition //! \param[in] initial_step Start of simulation or later steps void mpi_domain_decompose(bool initial_step = false) override; diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index 07ed2da92..efac91c11 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -488,16 +488,28 @@ bool mpm::MPMBase::checkpoint_resume() { //! Write HDF5 files template void mpm::MPMBase::write_hdf5(mpm::Index step, mpm::Index max_steps) { - for (const std::string& p_type : particle_types_) { - // Write input geometry to vtk file - std::string attribute = "particles" + p_type; - std::string extension = ".h5"; + // Write input geometry to vtk file + std::string attribute = "particles"; + std::string extension = ".h5"; - auto particles_file = - io_->output_file(attribute, extension, uuid_, step, max_steps).string(); + auto particles_file = + io_->output_file(attribute, extension, uuid_, step, max_steps).string(); - mesh_->write_particles_hdf5(particles_file, p_type); - } + mesh_->write_particles_hdf5(particles_file); +} + +//! Write HDF5 files for twophase particles +template +void mpm::MPMBase::write_hdf5_twophase(mpm::Index step, + mpm::Index max_steps) { + // Write input geometry to vtk file + std::string attribute = "twophaseparticles"; + std::string extension = ".h5"; + + auto particles_file = + io_->output_file(attribute, extension, uuid_, step, max_steps).string(); + + mesh_->write_particles_hdf5_twophase(particles_file); } #ifdef USE_VTK diff --git a/include/solvers/mpm_explicit_twophase.tcc b/include/solvers/mpm_explicit_twophase.tcc index 6922e8e72..141afbc32 100644 --- a/include/solvers/mpm_explicit_twophase.tcc +++ b/include/solvers/mpm_explicit_twophase.tcc @@ -343,7 +343,7 @@ bool mpm::MPMExplicitTwoPhase::solve() { if (step_ % output_steps_ == 0) { // HDF5 outputs - this->write_hdf5(this->step_, this->nsteps_); + this->write_hdf5_twophase(this->step_, this->nsteps_); #ifdef USE_VTK // VTK outputs this->write_vtk(this->step_, this->nsteps_); diff --git a/tests/mesh_test_2d.cc b/tests/mesh_test_2d.cc index 195c1bb9e..60badad1a 100644 --- a/tests/mesh_test_2d.cc +++ b/tests/mesh_test_2d.cc @@ -906,8 +906,7 @@ TEST_CASE("Mesh is checked for 2D case", "[mesh][2D]") { // Test HDF5 SECTION("Write particles HDF5") { - REQUIRE(mesh->write_particles_hdf5("particles-2d.h5", - particle_type) == true); + REQUIRE(mesh->write_particles_hdf5("particles-2d.h5") == true); auto phdf5 = mesh->particles_hdf5(); REQUIRE(phdf5.size() == mesh->nparticles()); diff --git a/tests/mesh_test_3d.cc b/tests/mesh_test_3d.cc index 081c63bf4..e04f86f8c 100644 --- a/tests/mesh_test_3d.cc +++ b/tests/mesh_test_3d.cc @@ -1001,8 +1001,7 @@ TEST_CASE("Mesh is checked for 3D case", "[mesh][3D]") { } // Test HDF5 SECTION("Write particles HDF5") { - REQUIRE(mesh->write_particles_hdf5("particles-3d.h5", - particle_type) == true); + REQUIRE(mesh->write_particles_hdf5("particles-3d.h5") == true); auto phdf5 = mesh->particles_hdf5(); REQUIRE(phdf5.size() == mesh->nparticles()); From 20055060b8756c73d040c5c457d4ac50b859b16f Mon Sep 17 00:00:00 2001 From: Nanda Date: Sat, 12 Sep 2020 21:18:44 +0700 Subject: [PATCH 140/175] :construction::wrench: add function to read particle hdf5 with specific type --- include/mesh.h | 22 ++-- include/mesh.tcc | 167 +++++++++++++++++++----------- include/particles/particle_base.h | 1 + include/solvers/mpm_base.tcc | 18 ++-- src/particle.cc | 5 + 5 files changed, 140 insertions(+), 73 deletions(-) diff --git a/include/mesh.h b/include/mesh.h index 5972fa3c9..9f7c785f5 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -409,17 +409,27 @@ class Mesh { //! \retval status Status of writing HDF5 output bool write_particles_hdf5(const std::string& filename); - //! Read HDF5 particles + //! Write HDF5 particles for two-phase-one-point particle //! \param[in] filename Name of HDF5 file to write particles data - //! \param[in] particle_types set of particle types to write + //! \retval status Status of writing HDF5 output + bool write_particles_hdf5_twophase(const std::string& filename); + + //! Read HDF5 particles with type name + //! \param[in] filename Name of HDF5 file to write particles data + //! \param[in] typename Name of particle type name //! \retval status Status of reading HDF5 output bool read_particles_hdf5(const std::string& filename, - const std::set& particle_types); + const std::string& type_name); - //! Write HDF5 particles for two-phase-one-point particle + //! Read HDF5 particles //! \param[in] filename Name of HDF5 file to write particles data - //! \retval status Status of writing HDF5 output - bool write_particles_hdf5_twophase(const std::string& filename); + //! \retval status Status of reading HDF5 output + bool read_particles_hdf5(const std::string& filename); + + //! Read HDF5 particles for twophase particle + //! \param[in] filename Name of HDF5 file to write particles data + //! \retval status Status of reading HDF5 output + bool read_particles_hdf5_twophase(const std::string& filename); //! Return HDF5 particles //! \retval particles_hdf5 Vector of HDF5 particles diff --git a/include/mesh.tcc b/include/mesh.tcc index 9bf272b67..8f642a654 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1511,78 +1511,127 @@ bool mpm::Mesh::write_particles_hdf5_twophase( return true; } +//! Write particles to HDF5 with type name +template +bool mpm::Mesh::read_particles_hdf5(const std::string& filename, + const std::string& type_name) { + bool status = false; + if (type_name == "particles") + status = this->read_particles_hdf5(filename); + else if (type_name == "twophase_particles") + status = this->read_particles_hdf5_twophase(filename); + return status; +} + //! Write particles to HDF5 template -bool mpm::Mesh::read_particles_hdf5( - const std::string& filename, const std::set& particle_types) { +bool mpm::Mesh::read_particles_hdf5(const std::string& filename) { // Vector of particles Vector> particles; // Clear map of particles map_particles_.clear(); - for (const std::string& particle_type : particle_types) { - // Create a new file using default properties. - // FIXME: new_file_name is not appropriate - const std::string new_file_name = filename + particle_type; - hid_t file_id = H5Fopen(new_file_name.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT); - // Throw an error if file can't be found - if (file_id < 0) - throw std::runtime_error("HDF5 particle file is not found"); - - // Calculate the size and the offsets of our struct members in memory - hsize_t nrecords = 0; - hsize_t nfields = 0; - H5TBget_table_info(file_id, "table", &nfields, &nrecords); - - std::vector dst_buf; - dst_buf.reserve(nrecords); - - // TODO: Think a better way to access mpm::pod::particle namespaces - if (particle_type == "P2D" || particle_type == "P3D") { - if (nfields != mpm::pod::particle::NFIELDS) - throw std::runtime_error("HDF5 table has incorrect number of fields"); - // Read the table - H5TBread_table(file_id, "table", mpm::pod::particle::dst_size, - mpm::pod::particle::dst_offset, - mpm::pod::particle::dst_sizes, dst_buf.data()); - } else if (particle_type == "P2D2PHASE" || particle_type == "P3D2PHASE") { - if (nfields != mpm::pod::particletwophase::NFIELDS) - throw std::runtime_error("HDF5 table has incorrect number of fields"); - // Read the table - H5TBread_table(file_id, "table", mpm::pod::particletwophase::dst_size, - mpm::pod::particletwophase::dst_offset, - mpm::pod::particletwophase::dst_sizes, dst_buf.data()); + // Create a new file using default properties. + const std::string new_file_name = filename; + hid_t file_id = H5Fopen(new_file_name.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT); + // Throw an error if file can't be found + if (file_id < 0) throw std::runtime_error("HDF5 particle file is not found"); + + // Calculate the size and the offsets of our struct members in memory + hsize_t nrecords = 0; + hsize_t nfields = 0; + H5TBget_table_info(file_id, "table", &nfields, &nrecords); + + std::vector dst_buf; + dst_buf.reserve(nrecords); + + if (nfields != mpm::pod::particle::NFIELDS) + throw std::runtime_error("HDF5 table has incorrect number of fields"); + // Read the table + H5TBread_table(file_id, "table", mpm::pod::particle::dst_size, + mpm::pod::particle::dst_offset, mpm::pod::particle::dst_sizes, + dst_buf.data()); + + unsigned i = 0; + for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { + if (i < nrecords) { + PODParticle particle = dst_buf[i]; + // Get particle's material from list of materials + std::vector>> materials; + materials.emplace_back(materials_.at(particle.material_id)); + + // Initialise particle with HDF5 data + (*pitr)->initialise_particle(particle, materials); + // Add particle to map + map_particles_.insert(particle.id, *pitr); + particles.add(*pitr); + ++i; } + } + // close the file + H5Fclose(file_id); - unsigned i = 0; - for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { - if (i < nrecords && (*pitr)->type() == particle_type) { - PODParticle particle = dst_buf[i]; - // Get particle's material from list of materials - std::vector>> materials; - materials.emplace_back(materials_.at(particle.material_id)); - - // TODO: Think a better way to access more than one material id - // Append more materials for twophase particles - if (particle_type == "P2D2PHASE" || particle_type == "P3D2PHASE") { - auto twophase_particle = - reinterpret_cast(&particle); - materials.emplace_back( - materials_.at(twophase_particle->liquid_material_id)); - } + // Overwrite particles container + this->particles_ = particles; - // Initialise particle with HDF5 data - (*pitr)->initialise_particle(particle, materials); - // Add particle to map - map_particles_.insert(particle.id, *pitr); - particles.add(*pitr); - ++i; - } + // Remove associated cell for the particle + for (auto citr = this->cells_.cbegin(); citr != this->cells_.cend(); ++citr) + (*citr)->clear_particle_ids(); + + return true; +} + +//! Write particles to HDF5 for twophase particles +template +bool mpm::Mesh::read_particles_hdf5_twophase( + const std::string& filename) { + // Vector of particles + Vector> particles; + + // Clear map of particles + map_particles_.clear(); + + // Create a new file using default properties. + const std::string new_file_name = filename; + hid_t file_id = H5Fopen(new_file_name.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT); + // Throw an error if file can't be found + if (file_id < 0) throw std::runtime_error("HDF5 particle file is not found"); + + // Calculate the size and the offsets of our struct members in memory + hsize_t nrecords = 0; + hsize_t nfields = 0; + H5TBget_table_info(file_id, "table", &nfields, &nrecords); + + std::vector dst_buf; + dst_buf.reserve(nrecords); + + if (nfields != mpm::pod::particletwophase::NFIELDS) + throw std::runtime_error("HDF5 table has incorrect number of fields"); + // Read the table + H5TBread_table(file_id, "table", mpm::pod::particletwophase::dst_size, + mpm::pod::particletwophase::dst_offset, + mpm::pod::particletwophase::dst_sizes, dst_buf.data()); + + unsigned i = 0; + for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { + if (i < nrecords) { + PODParticleTwoPhase particle = dst_buf[i]; + // Get particle's material from list of materials + std::vector>> materials; + materials.emplace_back(materials_.at(particle.material_id)); + materials.emplace_back(materials_.at(particle.liquid_material_id)); + + // Initialise particle with HDF5 data + (*pitr)->initialise_particle(particle, materials); + // Add particle to map + map_particles_.insert(particle.id, *pitr); + particles.add(*pitr); + ++i; } - // close the file - H5Fclose(file_id); } + // close the file + H5Fclose(file_id); // Overwrite particles container this->particles_ = particles; diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 9b8d7223e..942f61349 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -35,6 +35,7 @@ enum ParticlePhase : unsigned int { //! Particle type extern std::map ParticleType; extern std::map ParticleTypeName; +extern std::map ParticleHDF5TypeName; //! ParticleBase class //! \brief Base class that stores the information about particleBases diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index efac91c11..e00b27911 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -451,15 +451,17 @@ bool mpm::MPMBase::checkpoint_resume() { this->step_ = analysis_["resume"]["step"].template get(); // Input particle h5 file for resume - std::string attribute = "particles"; - std::string extension = ".h5"; + for (const auto ptype : particle_types_) { + std::string attribute = mpm::ParticleHDF5TypeName.at(ptype); + std::string extension = ".h5"; - auto particles_file = - io_->output_file(attribute, extension, uuid_, step_, this->nsteps_) - .string(); + auto particles_file = + io_->output_file(attribute, extension, uuid_, step_, this->nsteps_) + .string(); - // Load particle information from file - mesh_->read_particles_hdf5(particles_file, particle_types_); + // Load particle information from file + mesh_->read_particles_hdf5(particles_file, attribute); + } // Clear all particle ids mesh_->iterate_over_cells( @@ -503,7 +505,7 @@ template void mpm::MPMBase::write_hdf5_twophase(mpm::Index step, mpm::Index max_steps) { // Write input geometry to vtk file - std::string attribute = "twophaseparticles"; + std::string attribute = "twophase_particles"; std::string extension = ".h5"; auto particles_file = diff --git a/src/particle.cc b/src/particle.cc index a3071b477..b75d15b00 100644 --- a/src/particle.cc +++ b/src/particle.cc @@ -9,6 +9,11 @@ std::map ParticleType = { {"P2D", 0}, {"P3D", 1}, {"P2D2PHASE", 2}, {"P3D2PHASE", 3}}; std::map ParticleTypeName = { {0, "P2D"}, {1, "P3D"}, {2, "P2D2PHASE"}, {3, "P3D2PHASE"}}; +std::map ParticleHDF5TypeName = { + {"P2D", "particles"}, + {"P3D", "particles"}, + {"P2D2PHASE", "twophase_particles"}, + {"P3D2PHASE", "twophase_particles"}}; } // namespace mpm // Particle2D (2 Dim) From c0ffa57448ce7037f3a83df6da1a45d3e47aef7c Mon Sep 17 00:00:00 2001 From: Nanda Date: Sun, 13 Sep 2020 14:00:58 +0700 Subject: [PATCH 141/175] :wrench: change format back to original read --- include/mesh.tcc | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/include/mesh.tcc b/include/mesh.tcc index 8f642a654..85a751a84 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1526,15 +1526,9 @@ bool mpm::Mesh::read_particles_hdf5(const std::string& filename, //! Write particles to HDF5 template bool mpm::Mesh::read_particles_hdf5(const std::string& filename) { - // Vector of particles - Vector> particles; - - // Clear map of particles - map_particles_.clear(); // Create a new file using default properties. - const std::string new_file_name = filename; - hid_t file_id = H5Fopen(new_file_name.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT); + hid_t file_id = H5Fopen(filename.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT); // Throw an error if file can't be found if (file_id < 0) throw std::runtime_error("HDF5 particle file is not found"); @@ -1543,16 +1537,22 @@ bool mpm::Mesh::read_particles_hdf5(const std::string& filename) { hsize_t nfields = 0; H5TBget_table_info(file_id, "table", &nfields, &nrecords); - std::vector dst_buf; - dst_buf.reserve(nrecords); - if (nfields != mpm::pod::particle::NFIELDS) throw std::runtime_error("HDF5 table has incorrect number of fields"); + + std::vector dst_buf; + dst_buf.reserve(nrecords); // Read the table H5TBread_table(file_id, "table", mpm::pod::particle::dst_size, mpm::pod::particle::dst_offset, mpm::pod::particle::dst_sizes, dst_buf.data()); + // Vector of particles + Vector> particles; + + // Clear map of particles + map_particles_.clear(); + unsigned i = 0; for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { if (i < nrecords) { @@ -1586,15 +1586,9 @@ bool mpm::Mesh::read_particles_hdf5(const std::string& filename) { template bool mpm::Mesh::read_particles_hdf5_twophase( const std::string& filename) { - // Vector of particles - Vector> particles; - - // Clear map of particles - map_particles_.clear(); // Create a new file using default properties. - const std::string new_file_name = filename; - hid_t file_id = H5Fopen(new_file_name.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT); + hid_t file_id = H5Fopen(filename.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT); // Throw an error if file can't be found if (file_id < 0) throw std::runtime_error("HDF5 particle file is not found"); @@ -1603,16 +1597,22 @@ bool mpm::Mesh::read_particles_hdf5_twophase( hsize_t nfields = 0; H5TBget_table_info(file_id, "table", &nfields, &nrecords); - std::vector dst_buf; - dst_buf.reserve(nrecords); - if (nfields != mpm::pod::particletwophase::NFIELDS) throw std::runtime_error("HDF5 table has incorrect number of fields"); + + std::vector dst_buf; + dst_buf.reserve(nrecords); // Read the table H5TBread_table(file_id, "table", mpm::pod::particletwophase::dst_size, mpm::pod::particletwophase::dst_offset, mpm::pod::particletwophase::dst_sizes, dst_buf.data()); + // Vector of particles + Vector> particles; + + // Clear map of particles + map_particles_.clear(); + unsigned i = 0; for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { if (i < nrecords) { From 37428ed9fd4e9f688765edd6abe77a10e62cf67d Mon Sep 17 00:00:00 2001 From: Nanda Date: Mon, 28 Sep 2020 19:08:03 +0700 Subject: [PATCH 142/175] :wrench: :dart: add density and svars fix in twophase deserialization --- include/particles/particle_twophase.tcc | 10 ++++++++-- .../particle_serialize_deserialize_twophase_test.cc | 2 ++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/include/particles/particle_twophase.tcc b/include/particles/particle_twophase.tcc index 26209f76d..8d08e0524 100644 --- a/include/particles/particle_twophase.tcc +++ b/include/particles/particle_twophase.tcc @@ -1117,6 +1117,9 @@ void mpm::TwoPhaseParticle::deserialize( // volume MPI_Unpack(data_ptr, data.size(), &position, &volume_, 1, MPI_DOUBLE, MPI_COMM_WORLD); + // mass density + this->mass_density_ = mass_ / volume_; + // pressure double pressure; MPI_Unpack(data_ptr, data.size(), &position, &pressure, 1, MPI_DOUBLE, @@ -1168,7 +1171,7 @@ void mpm::TwoPhaseParticle::deserialize( if (nstate_vars > 0) { std::vector svars; svars.reserve(nstate_vars); - MPI_Unpack(data_ptr, data.size(), &position, &svars, nstate_vars, + MPI_Unpack(data_ptr, data.size(), &position, &svars[0], nstate_vars, MPI_DOUBLE, MPI_COMM_WORLD); // Reinitialize state variables @@ -1191,6 +1194,9 @@ void mpm::TwoPhaseParticle::deserialize( // liquid mass MPI_Unpack(data_ptr, data.size(), &position, &liquid_mass_, 1, MPI_DOUBLE, MPI_COMM_WORLD); + // Liquid mass Density + this->liquid_mass_density_ = liquid_mass_ / volume_; + // Liquid velocity MPI_Unpack(data_ptr, data.size(), &position, liquid_velocity_.data(), Tdim, MPI_DOUBLE, MPI_COMM_WORLD); @@ -1221,7 +1227,7 @@ void mpm::TwoPhaseParticle::deserialize( if (nliquid_state_vars > 0) { std::vector svars; svars.reserve(nliquid_state_vars); - MPI_Unpack(data_ptr, data.size(), &position, &svars, nliquid_state_vars, + MPI_Unpack(data_ptr, data.size(), &position, &svars[0], nliquid_state_vars, MPI_DOUBLE, MPI_COMM_WORLD); // Reinitialize state variables diff --git a/tests/particles/particle_serialize_deserialize_twophase_test.cc b/tests/particles/particle_serialize_deserialize_twophase_test.cc index 5e54644d8..d851c6c4d 100644 --- a/tests/particles/particle_serialize_deserialize_twophase_test.cc +++ b/tests/particles/particle_serialize_deserialize_twophase_test.cc @@ -157,6 +157,8 @@ TEST_CASE("Twophase particle is checked for serialization and deserialization", REQUIRE(particle->mass() == rparticle->mass()); // Check particle volume REQUIRE(particle->volume() == rparticle->volume()); + // Check particle mass density + REQUIRE(particle->mass_density() == rparticle->mass_density()); // Check particle status REQUIRE(particle->status() == rparticle->status()); From b69d846e549540d54b90d944ad7467b8a531b848 Mon Sep 17 00:00:00 2001 From: Nanda Date: Mon, 28 Sep 2020 21:38:56 +0700 Subject: [PATCH 143/175] :wrench: fix check non equal --- include/particles/particle_twophase.tcc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/particles/particle_twophase.tcc b/include/particles/particle_twophase.tcc index 8d08e0524..42ac0658e 100644 --- a/include/particles/particle_twophase.tcc +++ b/include/particles/particle_twophase.tcc @@ -1233,7 +1233,7 @@ void mpm::TwoPhaseParticle::deserialize( // Reinitialize state variables auto mat_state_vars = (this->material(mpm::ParticlePhase::Liquid)) ->initialise_state_variables(); - if (mat_state_vars.size() == nliquid_state_vars) + if (mat_state_vars.size() != nliquid_state_vars) throw std::runtime_error( "Deserialize particle(): Liquid phase state_vars size mismatch"); unsigned i = 0; From d05373f7e868de66385627020559ed067c5d6706 Mon Sep 17 00:00:00 2001 From: Nanda Date: Mon, 28 Sep 2020 21:39:39 +0700 Subject: [PATCH 144/175] :wrench: :construction: :dart: modify 2phase serialization test --- ...cle_serialize_deserialize_twophase_test.cc | 67 +++++++++++-------- 1 file changed, 39 insertions(+), 28 deletions(-) diff --git a/tests/particles/particle_serialize_deserialize_twophase_test.cc b/tests/particles/particle_serialize_deserialize_twophase_test.cc index d851c6c4d..6c5504e7a 100644 --- a/tests/particles/particle_serialize_deserialize_twophase_test.cc +++ b/tests/particles/particle_serialize_deserialize_twophase_test.cc @@ -31,6 +31,33 @@ TEST_CASE("Twophase particle is checked for serialization and deserialization", std::shared_ptr> particle = std::make_shared>(id, pcoords); + // Assign material + unsigned solid_mid = 1; + unsigned liquid_mid = 2; + // Initialise material + Json jsolid_material; + Json jliquid_material; + jsolid_material["density"] = 1000.; + jsolid_material["youngs_modulus"] = 1.0E+7; + jsolid_material["poisson_ratio"] = 0.3; + jsolid_material["porosity"] = 0.3; + jsolid_material["k_x"] = 0.001; + jsolid_material["k_y"] = 0.001; + jsolid_material["k_z"] = 0.001; + jliquid_material["density"] = 1000.; + jliquid_material["bulk_modulus"] = 2.0E9; + jliquid_material["dynamic_viscosity"] = 8.90E-4; + + auto solid_material = + Factory, unsigned, const Json&>::instance()->create( + "LinearElastic3D", std::move(solid_mid), jsolid_material); + auto liquid_material = + Factory, unsigned, const Json&>::instance()->create( + "Newtonian3D", std::move(liquid_mid), jliquid_material); + std::vector>> materials; + materials.emplace_back(solid_material); + materials.emplace_back(liquid_material); + mpm::PODParticleTwoPhase h5_particle; h5_particle.id = 13; h5_particle.mass = 501.5; @@ -112,34 +139,7 @@ TEST_CASE("Twophase particle is checked for serialization and deserialization", h5_particle.liquid_svars[i] = 0.; // Reinitialise particle from POD data - REQUIRE(particle->initialise_particle(h5_particle) == true); - - // Assign material - unsigned solid_mid = 1; - unsigned liquid_mid = 2; - // Initialise material - Json jsolid_material; - Json jliquid_material; - jsolid_material["density"] = 1000.; - jsolid_material["youngs_modulus"] = 1.0E+7; - jsolid_material["poisson_ratio"] = 0.3; - jsolid_material["porosity"] = 0.3; - jsolid_material["k_x"] = 0.001; - jsolid_material["k_y"] = 0.001; - jsolid_material["k_z"] = 0.001; - jliquid_material["density"] = 1000.; - jliquid_material["bulk_modulus"] = 2.0E9; - jliquid_material["dynamic_viscosity"] = 8.90E-4; - - auto solid_material = - Factory, unsigned, const Json&>::instance()->create( - "LinearElastic3D", std::move(solid_mid), jsolid_material); - auto liquid_material = - Factory, unsigned, const Json&>::instance()->create( - "Newtonian3D", std::move(liquid_mid), jliquid_material); - std::vector>> materials; - materials.emplace_back(solid_material); - materials.emplace_back(liquid_material); + REQUIRE(particle->initialise_particle(h5_particle, materials) == true); // Serialize particle auto buffer = particle->serialize(); @@ -225,6 +225,17 @@ TEST_CASE("Twophase particle is checked for serialization and deserialization", REQUIRE(particle->material_id(mpm::ParticlePhase::Liquid) == rparticle->material_id(mpm::ParticlePhase::Liquid)); + // Check state variables + for (unsigned phase = 0; phase < materials.size(); phase++) { + REQUIRE(particle->state_variables(phase).size() == + rparticle->state_variables(phase).size()); + auto state_variables = materials[phase]->state_variables(); + for (const auto& state_var : state_variables) { + REQUIRE(particle->state_variable(state_var, phase) == + rparticle->state_variable(state_var, phase)); + } + } + SECTION("Performance benchmarks") { // Number of iterations unsigned niterations = 1000; From 2149eaf3ef3436f892ddfaaa66e46345b9512c24 Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 29 Sep 2020 17:31:23 +0700 Subject: [PATCH 145/175] :wrench: add mpi barrier after transfer halo particles --- include/solvers/mpm_explicit_twophase.tcc | 1 + 1 file changed, 1 insertion(+) diff --git a/include/solvers/mpm_explicit_twophase.tcc b/include/solvers/mpm_explicit_twophase.tcc index 141afbc32..3dbf9d186 100644 --- a/include/solvers/mpm_explicit_twophase.tcc +++ b/include/solvers/mpm_explicit_twophase.tcc @@ -338,6 +338,7 @@ bool mpm::MPMExplicitTwoPhase::solve() { #ifdef USE_MPI #ifdef USE_GRAPH_PARTITIONING mesh_->transfer_halo_particles(); + MPI_Barrier(MPI_COMM_WORLD); #endif #endif From e24d2f10d2e69f386c11735cca4032d85446cfaf Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 6 Oct 2020 00:38:25 +0700 Subject: [PATCH 146/175] :wrench: :construction: modify map mixture --- include/particles/particle_twophase.h | 39 +++++-- include/particles/particle_twophase.tcc | 133 ++++++++++------------ include/solvers/mpm_explicit_twophase.tcc | 16 +-- 3 files changed, 98 insertions(+), 90 deletions(-) diff --git a/include/particles/particle_twophase.h b/include/particles/particle_twophase.h index 141880117..44eba3c05 100644 --- a/include/particles/particle_twophase.h +++ b/include/particles/particle_twophase.h @@ -194,8 +194,7 @@ class TwoPhaseParticle : public mpm::Particle { virtual void map_liquid_internal_force() noexcept; //! Map two phase mixture internal force - //! \param[in] mixture Identification for Mixture - virtual void map_mixture_internal_force(unsigned mixture) noexcept; + virtual void map_mixture_internal_force() noexcept; //! Compute updated velocity of the particle based on nodal velocity //! \param[in] dt Analysis time step @@ -204,34 +203,50 @@ class TwoPhaseParticle : public mpm::Particle { bool velocity_update) noexcept; protected: + //! particle id + using ParticleBase::id_; //! coordinates using ParticleBase::coordinates_; + //! Status + using ParticleBase::status_; //! Cell using ParticleBase::cell_; + //! Cell id + using ParticleBase::cell_id_; //! Nodes using ParticleBase::nodes_; //! State variables using ParticleBase::state_variables_; //! Shape functions using Particle::shapefn_; - //! Effective stress of soil skeleton - using Particle::stress_; - //! Soil skeleton strain rate - using Particle::strain_rate_; + //! dN/dX + using Particle::dn_dx_; + //! dN/dX at cell centroid + using Particle::dn_dx_centroid_; + //! Size of particle in natural coordinates + using Particle::natural_size_; //! Materials using Particle::material_; //! Material ids using ParticleBase::material_id_; - //! Particle total volume - using Particle::volume_; //! Particle mass for solid phase using Particle::mass_; + //! Particle total volume + using Particle::volume_; //! Particle mass density using Particle::mass_density_; - //! dN/dX - using Particle::dn_dx_; - //! dN/dX at cell centroid - using Particle::dn_dx_centroid_; + //! Displacement + using Particle::displacement_; + //! Velocity + using Particle::velocity_; + //! Effective stress of soil skeleton + using Particle::stress_; + //! Solid skeleton strains + using Particle::strain_; + //! Volumetric strain at centroid + using Particle::volumetric_strain_centroid_; + //! Soil skeleton strain rate + using Particle::strain_rate_; //! Set traction using Particle::set_traction_; //! Surface Traction (given as a stress; force/area) diff --git a/include/particles/particle_twophase.tcc b/include/particles/particle_twophase.tcc index 42ac0658e..b580ea4f5 100644 --- a/include/particles/particle_twophase.tcc +++ b/include/particles/particle_twophase.tcc @@ -449,24 +449,22 @@ void mpm::TwoPhaseParticle::map_liquid_traction_force() noexcept { //! Map both mixture and liquid internal force template inline void mpm::TwoPhaseParticle::map_internal_force() noexcept { - mpm::TwoPhaseParticle::map_mixture_internal_force( - mpm::ParticlePhase::Mixture); + mpm::TwoPhaseParticle::map_mixture_internal_force(); mpm::TwoPhaseParticle::map_liquid_internal_force(); } //! Map liquid phase internal force template <> inline void mpm::TwoPhaseParticle<1>::map_liquid_internal_force() noexcept { - // initialise a vector of pore pressure - Eigen::Matrix pressure; - pressure.setZero(); - pressure(0) = -this->state_variable("pressure", mpm::ParticlePhase::Liquid); + // pore pressure + const double pressure = + -this->state_variable("pressure", mpm::ParticlePhase::Liquid); // 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) * pressure[0] * this->porosity_; + force[0] = dn_dx_(i, 0) * pressure * this->porosity_; force *= -1. * this->volume_; @@ -477,18 +475,16 @@ inline void mpm::TwoPhaseParticle<1>::map_liquid_internal_force() noexcept { //! Map liquid phase internal force template <> inline void mpm::TwoPhaseParticle<2>::map_liquid_internal_force() noexcept { - // initialise a vector of pore pressure - Eigen::Matrix pressure; - pressure.setZero(); - pressure(0) = -this->state_variable("pressure", mpm::ParticlePhase::Liquid); - pressure(1) = -this->state_variable("pressure", mpm::ParticlePhase::Liquid); + // pore pressure + const double pressure = + -this->state_variable("pressure", mpm::ParticlePhase::Liquid); // 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) * pressure[0] * this->porosity_; - force[1] = dn_dx_(i, 1) * pressure[1] * this->porosity_; + force[0] = dn_dx_(i, 0) * pressure * this->porosity_; + force[1] = dn_dx_(i, 1) * pressure * this->porosity_; force *= -1. * this->volume_; @@ -498,20 +494,17 @@ inline void mpm::TwoPhaseParticle<2>::map_liquid_internal_force() noexcept { template <> inline void mpm::TwoPhaseParticle<3>::map_liquid_internal_force() noexcept { - // initialise a vector of pore pressure - Eigen::Matrix pressure; - pressure.setZero(); - pressure(0) = -this->state_variable("pressure", mpm::ParticlePhase::Liquid); - pressure(1) = -this->state_variable("pressure", mpm::ParticlePhase::Liquid); - pressure(2) = -this->state_variable("pressure", mpm::ParticlePhase::Liquid); + // pore pressure + const double pressure = + -this->state_variable("pressure", mpm::ParticlePhase::Liquid); // 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) * pressure[0] * this->porosity_; - force[1] = dn_dx_(i, 1) * pressure[1] * this->porosity_; - force[2] = dn_dx_(i, 2) * pressure[2] * this->porosity_; + force[0] = dn_dx_(i, 0) * pressure * this->porosity_; + force[1] = dn_dx_(i, 1) * pressure * this->porosity_; + force[2] = dn_dx_(i, 2) * pressure * this->porosity_; force *= -1. * this->volume_; @@ -521,12 +514,13 @@ inline void mpm::TwoPhaseParticle<3>::map_liquid_internal_force() noexcept { //! Map mixture internal force template <> -inline void mpm::TwoPhaseParticle<1>::map_mixture_internal_force( - unsigned mixture) noexcept { - // initialise a vector of pore pressure +inline void mpm::TwoPhaseParticle<1>::map_mixture_internal_force() noexcept { + // pore pressure + const double pressure = + -this->state_variable("pressure", mpm::ParticlePhase::Liquid); + // total stress Eigen::Matrix total_stress = this->stress_; - total_stress(0) -= - this->state_variable("pressure", mpm::ParticlePhase::Liquid); + total_stress(0) += pressure; // Compute nodal internal forces for (unsigned i = 0; i < nodes_.size(); ++i) { @@ -536,20 +530,20 @@ inline void mpm::TwoPhaseParticle<1>::map_mixture_internal_force( force *= -1. * this->volume_; - nodes_[i]->update_internal_force(true, mixture, force); + nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Mixture, force); } } //! Map mixture internal force template <> -inline void mpm::TwoPhaseParticle<2>::map_mixture_internal_force( - unsigned mixture) noexcept { - // initialise a vector of pore pressure +inline void mpm::TwoPhaseParticle<2>::map_mixture_internal_force() noexcept { + // pore pressure + const double pressure = + -this->state_variable("pressure", mpm::ParticlePhase::Liquid); + // total stress Eigen::Matrix total_stress = this->stress_; - total_stress(0) -= - this->state_variable("pressure", mpm::ParticlePhase::Liquid); - total_stress(1) -= - this->state_variable("pressure", mpm::ParticlePhase::Liquid); + total_stress(0) += pressure; + total_stress(1) += pressure; // Compute nodal internal forces for (unsigned i = 0; i < nodes_.size(); ++i) { @@ -560,21 +554,20 @@ inline void mpm::TwoPhaseParticle<2>::map_mixture_internal_force( force *= -1. * this->volume_; - nodes_[i]->update_internal_force(true, mixture, force); + nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Mixture, force); } } template <> -inline void mpm::TwoPhaseParticle<3>::map_mixture_internal_force( - unsigned mixture) noexcept { - // initialise a vector of pore pressure +inline void mpm::TwoPhaseParticle<3>::map_mixture_internal_force() noexcept { + // pore pressure + const double pressure = + -this->state_variable("pressure", mpm::ParticlePhase::Liquid); + // total stress Eigen::Matrix total_stress = this->stress_; - total_stress(0) -= - this->state_variable("pressure", mpm::ParticlePhase::Liquid); - total_stress(1) -= - this->state_variable("pressure", mpm::ParticlePhase::Liquid); - total_stress(2) -= - this->state_variable("pressure", mpm::ParticlePhase::Liquid); + total_stress(0) += pressure; + total_stress(1) += pressure; + total_stress(2) += pressure; // Compute nodal internal forces for (unsigned i = 0; i < nodes_.size(); ++i) { @@ -591,7 +584,7 @@ inline void mpm::TwoPhaseParticle<3>::map_mixture_internal_force( force *= -1. * this->volume_; - nodes_[i]->update_internal_force(true, mixture, force); + nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Mixture, force); } } @@ -971,8 +964,8 @@ std::vector mpm::TwoPhaseParticle::serialize() { data.size(), &position, MPI_COMM_WORLD); // ID - MPI_Pack(&this->id_, 1, MPI_UNSIGNED_LONG_LONG, data_ptr, data.size(), - &position, MPI_COMM_WORLD); + MPI_Pack(&id_, 1, MPI_UNSIGNED_LONG_LONG, data_ptr, data.size(), &position, + MPI_COMM_WORLD); // Solid Phase // Mass @@ -994,31 +987,31 @@ std::vector mpm::TwoPhaseParticle::serialize() { MPI_Pack(coordinates_.data(), Tdim, MPI_DOUBLE, data_ptr, data.size(), &position, MPI_COMM_WORLD); // Displacement - MPI_Pack(this->displacement_.data(), Tdim, MPI_DOUBLE, data_ptr, data.size(), + MPI_Pack(displacement_.data(), Tdim, MPI_DOUBLE, data_ptr, data.size(), &position, MPI_COMM_WORLD); // Natural size - MPI_Pack(this->natural_size_.data(), Tdim, MPI_DOUBLE, data_ptr, data.size(), + MPI_Pack(natural_size_.data(), Tdim, MPI_DOUBLE, data_ptr, data.size(), &position, MPI_COMM_WORLD); // Velocity - MPI_Pack(this->velocity_.data(), Tdim, MPI_DOUBLE, data_ptr, data.size(), - &position, MPI_COMM_WORLD); + MPI_Pack(velocity_.data(), Tdim, MPI_DOUBLE, data_ptr, data.size(), &position, + MPI_COMM_WORLD); // Stress MPI_Pack(stress_.data(), 6, MPI_DOUBLE, data_ptr, data.size(), &position, MPI_COMM_WORLD); // Strain - MPI_Pack(this->strain_.data(), 6, MPI_DOUBLE, data_ptr, data.size(), - &position, MPI_COMM_WORLD); + MPI_Pack(strain_.data(), 6, MPI_DOUBLE, data_ptr, data.size(), &position, + MPI_COMM_WORLD); // epsv - MPI_Pack(&this->volumetric_strain_centroid_, 1, MPI_DOUBLE, data_ptr, - data.size(), &position, MPI_COMM_WORLD); + MPI_Pack(&volumetric_strain_centroid_, 1, MPI_DOUBLE, data_ptr, data.size(), + &position, MPI_COMM_WORLD); // Cell id - MPI_Pack(&this->cell_id_, 1, MPI_UNSIGNED_LONG_LONG, data_ptr, data.size(), + MPI_Pack(&cell_id_, 1, MPI_UNSIGNED_LONG_LONG, data_ptr, data.size(), &position, MPI_COMM_WORLD); // Status - MPI_Pack(&this->status_, 1, MPI_C_BOOL, data_ptr, data.size(), &position, + MPI_Pack(&status_, 1, MPI_C_BOOL, data_ptr, data.size(), &position, MPI_COMM_WORLD); // nstate variables @@ -1107,8 +1100,8 @@ void mpm::TwoPhaseParticle::deserialize( MPI_COMM_WORLD); // ID - MPI_Unpack(data_ptr, data.size(), &position, &this->id_, 1, - MPI_UNSIGNED_LONG_LONG, MPI_COMM_WORLD); + MPI_Unpack(data_ptr, data.size(), &position, &id_, 1, MPI_UNSIGNED_LONG_LONG, + MPI_COMM_WORLD); // Solid Phase // mass @@ -1129,29 +1122,29 @@ void mpm::TwoPhaseParticle::deserialize( MPI_Unpack(data_ptr, data.size(), &position, coordinates_.data(), Tdim, MPI_DOUBLE, MPI_COMM_WORLD); // Displacement - MPI_Unpack(data_ptr, data.size(), &position, this->displacement_.data(), Tdim, + MPI_Unpack(data_ptr, data.size(), &position, displacement_.data(), Tdim, MPI_DOUBLE, MPI_COMM_WORLD); // Natural size - MPI_Unpack(data_ptr, data.size(), &position, this->natural_size_.data(), Tdim, + MPI_Unpack(data_ptr, data.size(), &position, natural_size_.data(), Tdim, MPI_DOUBLE, MPI_COMM_WORLD); // Velocity - MPI_Unpack(data_ptr, data.size(), &position, this->velocity_.data(), Tdim, + MPI_Unpack(data_ptr, data.size(), &position, velocity_.data(), Tdim, MPI_DOUBLE, MPI_COMM_WORLD); // Stress MPI_Unpack(data_ptr, data.size(), &position, stress_.data(), 6, MPI_DOUBLE, MPI_COMM_WORLD); // Strain - MPI_Unpack(data_ptr, data.size(), &position, this->strain_.data(), 6, - MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(data_ptr, data.size(), &position, strain_.data(), 6, MPI_DOUBLE, + MPI_COMM_WORLD); // epsv - MPI_Unpack(data_ptr, data.size(), &position, - &this->volumetric_strain_centroid_, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(data_ptr, data.size(), &position, &volumetric_strain_centroid_, 1, + MPI_DOUBLE, MPI_COMM_WORLD); // cell id - MPI_Unpack(data_ptr, data.size(), &position, &this->cell_id_, 1, + MPI_Unpack(data_ptr, data.size(), &position, &cell_id_, 1, MPI_UNSIGNED_LONG_LONG, MPI_COMM_WORLD); // status - MPI_Unpack(data_ptr, data.size(), &position, &this->status_, 1, MPI_C_BOOL, + MPI_Unpack(data_ptr, data.size(), &position, &status_, 1, MPI_C_BOOL, MPI_COMM_WORLD); // Assign materials diff --git a/include/solvers/mpm_explicit_twophase.tcc b/include/solvers/mpm_explicit_twophase.tcc index 3dbf9d186..debb780db 100644 --- a/include/solvers/mpm_explicit_twophase.tcc +++ b/include/solvers/mpm_explicit_twophase.tcc @@ -161,29 +161,29 @@ bool mpm::MPMExplicitTwoPhase::solve() { // MPI all reduce nodal mass for solid phase mesh_->template nodal_halo_exchange( std::bind(&mpm::NodeBase::mass, std::placeholders::_1, - mpm::ParticlePhase::Solid), + mpm::NodePhase::nSolid), std::bind(&mpm::NodeBase::update_mass, std::placeholders::_1, - false, mpm::ParticlePhase::Solid, std::placeholders::_2)); + false, mpm::NodePhase::nSolid, std::placeholders::_2)); // MPI all reduce nodal momentum for solid phase mesh_->template nodal_halo_exchange, Tdim>( std::bind(&mpm::NodeBase::momentum, std::placeholders::_1, - mpm::ParticlePhase::Solid), + mpm::NodePhase::nSolid), std::bind(&mpm::NodeBase::update_momentum, - std::placeholders::_1, false, mpm::ParticlePhase::Solid, + std::placeholders::_1, false, mpm::NodePhase::nSolid, std::placeholders::_2)); // MPI all reduce nodal mass for liquid phase mesh_->template nodal_halo_exchange( std::bind(&mpm::NodeBase::mass, std::placeholders::_1, - mpm::ParticlePhase::Liquid), + mpm::NodePhase::nLiquid), std::bind(&mpm::NodeBase::update_mass, std::placeholders::_1, - false, mpm::ParticlePhase::Liquid, std::placeholders::_2)); + false, mpm::NodePhase::nLiquid, std::placeholders::_2)); // MPI all reduce nodal momentum for liquid phase mesh_->template nodal_halo_exchange, Tdim>( std::bind(&mpm::NodeBase::momentum, std::placeholders::_1, - mpm::ParticlePhase::Liquid), + mpm::NodePhase::nLiquid), std::bind(&mpm::NodeBase::update_momentum, - std::placeholders::_1, false, mpm::ParticlePhase::Liquid, + std::placeholders::_1, false, mpm::NodePhase::nLiquid, std::placeholders::_2)); } #endif From 2a741deeec38da3a7066ef6297f84cdca041377a Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 6 Oct 2020 02:00:56 +0700 Subject: [PATCH 147/175] :construction: :dart: modify solver as suggested and add test for nparticles --- include/cell.h | 4 +++- include/cell.tcc | 6 ------ include/mesh.h | 7 +------ include/mesh.tcc | 16 ++++++++++++++-- tests/mesh_test_2d.cc | 3 +++ tests/mesh_test_3d.cc | 3 +++ 6 files changed, 24 insertions(+), 15 deletions(-) diff --git a/include/cell.h b/include/cell.h index b68005f3c..fef479738 100644 --- a/include/cell.h +++ b/include/cell.h @@ -227,7 +227,9 @@ class Cell { //! Assign volume traction to node //! \param[in] volume_fraction cell volume fraction - void assign_volume_fraction(double volume_fraction); + void assign_volume_fraction(double volume_fraction) { + volume_fraction_ = volume_fraction; + }; //! Return cell volume fraction //! \retval volume_fraction_ cell volume fraction diff --git a/include/cell.tcc b/include/cell.tcc index 21dda7353..adfd1e379 100644 --- a/include/cell.tcc +++ b/include/cell.tcc @@ -845,12 +845,6 @@ inline unsigned mpm::Cell::previous_mpirank() const { return this->previous_mpirank_; } -//! Assign volume traction to node -template -void mpm::Cell::assign_volume_fraction(double volume_fraction) { - volume_fraction_ = volume_fraction; -} - //! Map cell volume to nodes template void mpm::Cell::map_cell_volume_to_nodes(unsigned phase) { diff --git a/include/mesh.h b/include/mesh.h index 9f7c785f5..00869f585 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -240,12 +240,7 @@ class Mesh { //! Number of particles in the mesh with specific type //! \param[in] particle particle_type A string denoting particle type - mpm::Index nparticles(const std::string& particle_type) const { - mpm::Index counter = 0; - for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) - if ((*pitr)->type() == particle_type) counter++; - return counter; - } + mpm::Index nparticles(const std::string& particle_type) const; //! Locate particles in a cell //! Iterate over all cells in a mesh to find the cell in which particles diff --git a/include/mesh.tcc b/include/mesh.tcc index bc6e29722..b2da78871 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -420,6 +420,16 @@ void mpm::Mesh::find_ghost_boundary_cells() { #endif } +//! Number of particles in the mesh with specific type +template +mpm::Index mpm::Mesh::nparticles(const std::string& particle_type) const { + return std::count_if( + particles_.cbegin(), particles_.cend(), + [&ptype = particle_type](std::shared_ptr> ptr) { + return (ptr)->type() == ptype; + }); +} + //! Find ncells in rank template mpm::Index mpm::Mesh::ncells_rank(bool active_cells) { @@ -2052,7 +2062,8 @@ void mpm::Mesh::create_nodal_properties() { // Initialise the shared pointer to nodal properties nodal_properties_ = std::make_shared(); - // Check if nodes_ and materials_is empty and throw runtime error if they are + // Check if nodes_ and materials_is empty and throw runtime error if they + // are if (nodes_.size() != 0 && materials_.size() != 0) { // Compute number of rows in nodal properties for vector entities const unsigned nrows = nodes_.size() * Tdim; @@ -2091,7 +2102,8 @@ bool mpm::Mesh::compute_free_surface(const std::string& method, return this->compute_free_surface_by_geometry(volume_tolerance); } else { console_->info( - "The selected free-surface computation method: {}\n is not available. " + "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); diff --git a/tests/mesh_test_2d.cc b/tests/mesh_test_2d.cc index 60badad1a..435c4edb4 100644 --- a/tests/mesh_test_2d.cc +++ b/tests/mesh_test_2d.cc @@ -187,6 +187,7 @@ TEST_CASE("Mesh is checked for 2D case", "[mesh][2D]") { REQUIRE(mesh->status() == true); // Check number of particles in mesh REQUIRE(mesh->nparticles() == 2); + REQUIRE(mesh->nparticles("P2D") == 2); // Update coordinates Eigen::Vector2d coordinates; @@ -217,11 +218,13 @@ TEST_CASE("Mesh is checked for 2D case", "[mesh][2D]") { REQUIRE(mesh->remove_particle(particle2) == true); // Check number of particles in mesh REQUIRE(mesh->nparticles() == 1); + REQUIRE(mesh->nparticles("P2D") == 1); // Remove all non-rank particles in mesh mesh->remove_all_nonrank_particles(); // Check number of particles in mesh REQUIRE(mesh->nparticles() == 0); + REQUIRE(mesh->nparticles("P2D") == 0); // Add and use remove all particles REQUIRE(mesh->add_particle(particle1) == true); diff --git a/tests/mesh_test_3d.cc b/tests/mesh_test_3d.cc index e04f86f8c..4f67f0ba0 100644 --- a/tests/mesh_test_3d.cc +++ b/tests/mesh_test_3d.cc @@ -198,11 +198,13 @@ TEST_CASE("Mesh is checked for 3D case", "[mesh][3D]") { REQUIRE(mesh->status() == true); // Check number of particles in mesh REQUIRE(mesh->nparticles() == 2); + REQUIRE(mesh->nparticles("P3D") == 2); // Remove particle 2 and check REQUIRE(mesh->remove_particle(particle2) == true); // Check number of particles in mesh REQUIRE(mesh->nparticles() == 1); + REQUIRE(mesh->nparticles("P3D") == 1); int mpi_size; MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); @@ -225,6 +227,7 @@ TEST_CASE("Mesh is checked for 3D case", "[mesh][3D]") { mesh->remove_all_nonrank_particles(); // Check number of particles in mesh REQUIRE(mesh->nparticles() == 0); + REQUIRE(mesh->nparticles("P3D") == 0); // Add and use remove all particles REQUIRE(mesh->add_particle(particle1) == true); From 7f962259b413381b5ccb77433fad79f16a606d67 Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 6 Oct 2020 23:54:56 +0700 Subject: [PATCH 148/175] :construction: modify as suggested --- include/io/io_mesh_ascii.tcc | 8 ++++---- include/particles/particle_twophase.tcc | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/io/io_mesh_ascii.tcc b/include/io/io_mesh_ascii.tcc index d2fcce4ef..eb2124e4c 100644 --- a/include/io/io_mesh_ascii.tcc +++ b/include/io/io_mesh_ascii.tcc @@ -269,11 +269,11 @@ std::vector> // ignore comment lines (# or !) or blank lines if ((line.find('#') == std::string::npos) && (line.find('!') == std::string::npos) && (line != "")) { + // ID + mpm::Index id; + // Scalar + double scalar; while (istream.good()) { - // ID - mpm::Index id; - // Scalar - double scalar; // Read stream istream >> id >> scalar; scalar_properties.emplace_back(std::make_tuple(id, scalar)); diff --git a/include/particles/particle_twophase.tcc b/include/particles/particle_twophase.tcc index b580ea4f5..35275f7b8 100644 --- a/include/particles/particle_twophase.tcc +++ b/include/particles/particle_twophase.tcc @@ -759,13 +759,13 @@ bool mpm::TwoPhaseParticle::map_drag_force_coefficient() { drag_force_coefficient.setZero(); // Check if permeability coefficient is valid + const double liquid_unit_weight = + 9.81 * this->material(mpm::ParticlePhase::Liquid) + ->template property(std::string("density")); for (unsigned i = 0; i < Tdim; ++i) { if (k_p > 0.) - drag_force_coefficient(i) = - porosity_ * porosity_ * 9.81 * - this->material(mpm::ParticlePhase::Liquid) - ->template property(std::string("density")) / - (k_p * permeability_(i)); + drag_force_coefficient(i) = porosity_ * porosity_ * liquid_unit_weight / + (k_p * permeability_(i)); else throw std::runtime_error("Porosity coefficient is invalid"); } From 974764aa6a9784f5cc4814cfe8fd7bb47ea1ba1c Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 20 Oct 2020 15:48:19 +0700 Subject: [PATCH 149/175] :dart: :construction: radial basis function test --- CMakeLists.txt | 1 + include/utilities/radial_basis_function.h | 108 ++-- tests/functions/radial_basis_function_test.cc | 539 ++++++++++++++++++ 3 files changed, 590 insertions(+), 58 deletions(-) create mode 100644 tests/functions/radial_basis_function_test.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index a3138d916..d93ef69f7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -195,6 +195,7 @@ if(MPM_BUILD_TESTING) ${mpm_SOURCE_DIR}/tests/elements/triangle_quadrature_test.cc ${mpm_SOURCE_DIR}/tests/functions/linear_function_test.cc ${mpm_SOURCE_DIR}/tests/functions/sin_function_test.cc + ${mpm_SOURCE_DIR}/tests/functions/radial_basis_function_test.cc ${mpm_SOURCE_DIR}/tests/graph_test.cc ${mpm_SOURCE_DIR}/tests/interface_test.cc ${mpm_SOURCE_DIR}/tests/io/io_mesh_ascii_test.cc diff --git a/include/utilities/radial_basis_function.h b/include/utilities/radial_basis_function.h index d872a2097..134bca5ca 100644 --- a/include/utilities/radial_basis_function.h +++ b/include/utilities/radial_basis_function.h @@ -10,12 +10,15 @@ namespace mpm { // Namespace for radial basis function handling +// NOTES: only accessible through function kernel() and gradient() namespace RadialBasisFunction { +// Private functions +namespace { //! 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(double smoothing_length, double norm_distance) { // Assign multiplier depends on dimension double multiplier; @@ -43,8 +46,7 @@ double cubic_spline(const double smoothing_length, const double norm_distance) { //! Cubic Spline Radial Basis Function derivative //! Source: Monaghan, 1985; Monaghan, 1992 template -double cubic_spline_derivative(const double smoothing_length, - const double norm_distance) { +double cubic_spline_derivative(double smoothing_length, double norm_distance) { // Assign multiplier depends on dimension double multiplier; @@ -71,8 +73,7 @@ double cubic_spline_derivative(const double smoothing_length, //! Quintic Spline Radial Basis Function //! Source: Liu, 2010 template -double quintic_spline(const double smoothing_length, - const double norm_distance) { +double quintic_spline(double smoothing_length, double norm_distance) { // Assign multiplier depends on dimension double multiplier; @@ -104,8 +105,8 @@ double quintic_spline(const double smoothing_length, //! Quintic Spline Radial Basis Function derivative //! Source: Liu, 2010 template -double quintic_spline_derivative(const double smoothing_length, - const double norm_distance) { +double quintic_spline_derivative(double smoothing_length, + double norm_distance) { // Assign multiplier depends on dimension double multiplier; @@ -137,21 +138,20 @@ double quintic_spline_derivative(const double smoothing_length, //! Gaussian Kernel //! Source: Liu, 2010 template -double gaussian(const double smoothing_length, const double norm_distance) { +double gaussian(double smoothing_length, 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); + if (Tdim == 2 || Tdim == 3) + multiplier = + 1.0 / std::pow((std::sqrt(M_PI) * smoothing_length), int(Tdim)); 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) + if (radius >= 0.0 && radius <= 3.0) basis_function *= std::exp(-std::pow(radius, 2)); else basis_function = 0.0; @@ -162,15 +162,13 @@ double gaussian(const double smoothing_length, const double norm_distance) { //! Gaussian Kernel derivative //! Source: Liu, 2010 template -double gaussian_derivative(const double smoothing_length, - const double norm_distance) { +double gaussian_derivative(double smoothing_length, 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); + if (Tdim == 2 || Tdim == 3) + multiplier = + 1.0 / std::pow((std::sqrt(M_PI) * smoothing_length), int(Tdim)); else throw std::runtime_error("Tdim is invalid"); @@ -188,24 +186,22 @@ double gaussian_derivative(const double smoothing_length, //! Super Gaussian Kernel //! Source: Monaghan, 1992 template -double super_gaussian(const double smoothing_length, - const double norm_distance) { +double super_gaussian(double smoothing_length, 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); + if (Tdim == 2 || Tdim == 3) + multiplier = + 1.0 / std::pow((std::sqrt(M_PI) * smoothing_length), int(Tdim)); 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 *= radius * (2.0 * radius * radius - (double)Tdim - 4.0) * - std::exp(-std::pow(radius, 2)); + if (radius >= 0.0 && radius <= 3.0) + basis_function *= std::exp(-std::pow(radius, 2)) * + (double(Tdim) / 2. + 1. - radius * radius); else basis_function = 0.0; @@ -215,46 +211,46 @@ double super_gaussian(const double smoothing_length, //! Super Gaussian Kernel derivative //! Source: Monaghan, 1992 template -double super_gaussian_derivative(const double smoothing_length, - const double norm_distance) { +double super_gaussian_derivative(double smoothing_length, + 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); + if (Tdim == 2 || Tdim == 3) + multiplier = + 1.0 / std::pow((std::sqrt(M_PI) * smoothing_length), int(Tdim)); 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); + if (radius >= 0.0 && radius <= 3.0) + dw_dr *= std::exp(-std::pow(radius, 2)) * radius * + (-(double)Tdim + 2. * radius * radius - 4.); else dw_dr = 0.0; return dw_dr; } +} // namespace + //! General Radial Basis Function Kernel call template -double kernel(const double smoothing_length, const double norm_distance, - const std::string type = "cubic_spline") { +double kernel(double smoothing_length, double norm_distance, + const std::string& type = "cubic_spline") { + // Norm distance should be positive + assert(norm_distance >= 0.0); + if (type == "cubic_spline") { - return mpm::RadialBasisFunction::cubic_spline(smoothing_length, - norm_distance); + return cubic_spline(smoothing_length, norm_distance); } else if (type == "quintic_spline") { - return mpm::RadialBasisFunction::quintic_spline(smoothing_length, - norm_distance); + return quintic_spline(smoothing_length, norm_distance); } else if (type == "gaussian") { - return mpm::RadialBasisFunction::gaussian(smoothing_length, - norm_distance); + return gaussian(smoothing_length, norm_distance); } else if (type == "super_gaussian") { - return mpm::RadialBasisFunction::super_gaussian(smoothing_length, - norm_distance); + return super_gaussian(smoothing_length, norm_distance); } else { throw std::runtime_error( "RadialBasisFunction kernel type is invalid. Available types are: " @@ -266,25 +262,21 @@ double kernel(const double smoothing_length, const double norm_distance, //! General Radial Basis Function Kernel call template Eigen::Matrix gradient( - const double smoothing_length, + double smoothing_length, const Eigen::Matrix& relative_distance, - const std::string type = "cubic_spline") { + const std::string& type = "cubic_spline") { // 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); + dw_dr = cubic_spline_derivative(smoothing_length, norm_distance); } else if (type == "quintic_spline") { - dw_dr = mpm::RadialBasisFunction::quintic_spline_derivative( - smoothing_length, norm_distance); + dw_dr = quintic_spline_derivative(smoothing_length, norm_distance); } else if (type == "gaussian") { - dw_dr = mpm::RadialBasisFunction::gaussian_derivative( - smoothing_length, norm_distance); + dw_dr = gaussian_derivative(smoothing_length, norm_distance); } else if (type == "super_gaussian") { - dw_dr = mpm::RadialBasisFunction::super_gaussian_derivative( - smoothing_length, norm_distance); + dw_dr = super_gaussian_derivative(smoothing_length, norm_distance); } else { throw std::runtime_error( "RadialBasisFunction gradient type is invalid. Available types are: " @@ -294,7 +286,7 @@ Eigen::Matrix gradient( // Gradient = dw_dr * r / ||r|| / h Eigen::Matrix gradient = relative_distance; - if (norm_distance > 1.e-12) + if (norm_distance > std::numeric_limits::epsilon()) gradient *= dw_dr / (norm_distance * smoothing_length); else gradient *= 0.0; diff --git a/tests/functions/radial_basis_function_test.cc b/tests/functions/radial_basis_function_test.cc new file mode 100644 index 000000000..e522cad3c --- /dev/null +++ b/tests/functions/radial_basis_function_test.cc @@ -0,0 +1,539 @@ +#include +#include + +#include "Eigen/Dense" +#include "catch.hpp" + +#include "radial_basis_function.h" + +TEST_CASE("Radial basis function 2D", "[RBF][2D]") { + // Dimension + const unsigned Dim = 2; + // Tolerance + const double Tolerance = 1.E-7; + + SECTION("Kernel 2D") { + // Initialize variables + double smoothing_length, norm_distance; + std::string type; + + // Check error: wrong type name + type = "test_error"; + smoothing_length = 1.0; + norm_distance = 1.0; + REQUIRE_THROWS(mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type)); + + // Check error: wrong dimension + REQUIRE_THROWS(mpm::RadialBasisFunction::kernel<1>( + smoothing_length, norm_distance, "cubic_spline")); + REQUIRE_THROWS(mpm::RadialBasisFunction::kernel<1>( + smoothing_length, norm_distance, "quintic_spline")); + REQUIRE_THROWS(mpm::RadialBasisFunction::kernel<1>( + smoothing_length, norm_distance, "gaussian")); + REQUIRE_THROWS(mpm::RadialBasisFunction::kernel<1>( + smoothing_length, norm_distance, "super_gaussian")); + + // Cubic Spline + type = "cubic_spline"; + norm_distance = 3.0; + double kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.0).epsilon(Tolerance)); + + norm_distance = 2.0; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.0).epsilon(Tolerance)); + + norm_distance = 1.5; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.014210262776062).epsilon(Tolerance)); + + norm_distance = 1.0; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.113682102208497).epsilon(Tolerance)); + + norm_distance = 0.5; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.326836043849428).epsilon(Tolerance)); + + norm_distance = 0.0; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.454728408833987).epsilon(Tolerance)); + + // Quintic Spline + type = "quintic_spline"; + norm_distance = 5.0; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.0).epsilon(Tolerance)); + + norm_distance = 3.0; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.0).epsilon(Tolerance)); + + norm_distance = 2.5; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(2.08100082494633E-05).epsilon(Tolerance)); + + norm_distance = 2.0; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.000665920263983).epsilon(Tolerance)); + + norm_distance = 1.5; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.004931971955123).epsilon(Tolerance)); + + norm_distance = 1.0; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.017313926863554).epsilon(Tolerance)); + + norm_distance = 0.5; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.035002433875597).epsilon(Tolerance)); + + norm_distance = 0.0; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.043950737422867).epsilon(Tolerance)); + + // Gaussian + type = "gaussian"; + norm_distance = 3.0 + Tolerance; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.0).epsilon(Tolerance)); + + norm_distance = 3.0; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(3.92825606927949E-05).epsilon(Tolerance)); + + norm_distance = 1.5; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.033549615174147).epsilon(Tolerance)); + + norm_distance = 0.0; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.318309886183791).epsilon(Tolerance)); + + // Super Gaussian + type = "super_gaussian"; + norm_distance = 3.0 + Tolerance; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.0).epsilon(Tolerance)); + + norm_distance = 3.0; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(-0.00027497792485).epsilon(Tolerance)); + + norm_distance = 1.5; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(-0.008387403793537).epsilon(Tolerance)); + + norm_distance = 0.0; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.636619772367581).epsilon(Tolerance)); + } + + SECTION("Gradient 2D") { + // Initialize variables + double smoothing_length; + Eigen::Matrix relative_distance; + std::string type; + + // Check error: wrong type name + type = "test_error"; + smoothing_length = 1.0; + relative_distance.setZero(); + REQUIRE_THROWS(mpm::RadialBasisFunction::gradient( + smoothing_length, relative_distance, type)); + + // Check error: wrong dimension + Eigen::Matrix error_mat; + error_mat.setZero(); + REQUIRE_THROWS(mpm::RadialBasisFunction::gradient<1>( + smoothing_length, error_mat, "cubic_spline")); + REQUIRE_THROWS(mpm::RadialBasisFunction::gradient<1>( + smoothing_length, error_mat, "quintic_spline")); + REQUIRE_THROWS(mpm::RadialBasisFunction::gradient<1>( + smoothing_length, error_mat, "gaussian")); + REQUIRE_THROWS(mpm::RadialBasisFunction::gradient<1>( + smoothing_length, error_mat, "super_gaussian")); + + // Cubic Spline + type = "cubic_spline"; + relative_distance.setZero(); + Eigen::Matrix gradient = + mpm::RadialBasisFunction::gradient(smoothing_length, + relative_distance, type); + for (unsigned i = 0; i < gradient.size(); ++i) + REQUIRE(gradient(i) == Approx(0.0).epsilon(Tolerance)); + + relative_distance << 0.5, -0.5; + gradient = mpm::RadialBasisFunction::gradient(smoothing_length, + relative_distance, type); + + REQUIRE(gradient(0) == Approx(-0.320358379080714).epsilon(Tolerance)); + REQUIRE(gradient(1) == Approx(0.320358379080714).epsilon(Tolerance)); + + relative_distance << 1.0, -0.5; + gradient = mpm::RadialBasisFunction::gradient(smoothing_length, + relative_distance, type); + + REQUIRE(gradient(0) == Approx(-0.237280496186688).epsilon(Tolerance)); + REQUIRE(gradient(1) == Approx(0.118640248093344).epsilon(Tolerance)); + + relative_distance << 1.5, 1.5; + gradient = mpm::RadialBasisFunction::gradient(smoothing_length, + relative_distance, type); + for (unsigned i = 0; i < gradient.size(); ++i) + REQUIRE(gradient(i) == Approx(0.0).epsilon(Tolerance)); + + // Quintic Spline + type = "quintic_spline"; + relative_distance.setZero(); + gradient = mpm::RadialBasisFunction::gradient(smoothing_length, + relative_distance, type); + for (unsigned i = 0; i < gradient.size(); ++i) + REQUIRE(gradient(i) == Approx(0.0).epsilon(Tolerance)); + + relative_distance << 0.5, -0.5; + gradient = mpm::RadialBasisFunction::gradient(smoothing_length, + relative_distance, type); + + REQUIRE(gradient(0) == Approx(-0.025863567099382).epsilon(Tolerance)); + REQUIRE(gradient(1) == Approx(0.025863567099382).epsilon(Tolerance)); + + relative_distance << 1.0, -0.5; + gradient = mpm::RadialBasisFunction::gradient(smoothing_length, + relative_distance, type); + + REQUIRE(gradient(0) == Approx(-0.026546314385505).epsilon(Tolerance)); + REQUIRE(gradient(1) == Approx(0.013273157192753).epsilon(Tolerance)); + + relative_distance << -1.9, 1.3; + gradient = mpm::RadialBasisFunction::gradient(smoothing_length, + relative_distance, type); + + REQUIRE(gradient(0) == Approx(0.000651627282552).epsilon(Tolerance)); + REQUIRE(gradient(1) == Approx(-0.000445850245957).epsilon(Tolerance)); + + relative_distance << 2.5, 3.5; + gradient = mpm::RadialBasisFunction::gradient(smoothing_length, + relative_distance, type); + for (unsigned i = 0; i < gradient.size(); ++i) + REQUIRE(gradient(i) == Approx(0.0).epsilon(Tolerance)); + + // Gaussian + type = "gaussian"; + relative_distance.setZero(); + gradient = mpm::RadialBasisFunction::gradient(smoothing_length, + relative_distance, type); + for (unsigned i = 0; i < gradient.size(); ++i) + REQUIRE(gradient(i) == Approx(0.0).epsilon(Tolerance)); + + relative_distance << -1.9, 1.3; + gradient = mpm::RadialBasisFunction::gradient(smoothing_length, + relative_distance, type); + + REQUIRE(gradient(0) == Approx(0.00603772001586).epsilon(Tolerance)); + REQUIRE(gradient(1) == Approx(-0.004131071589799).epsilon(Tolerance)); + + relative_distance << 2.5, 3.5; + gradient = mpm::RadialBasisFunction::gradient(smoothing_length, + relative_distance, type); + for (unsigned i = 0; i < gradient.size(); ++i) + REQUIRE(gradient(i) == Approx(0.0).epsilon(Tolerance)); + + // Super Gaussian + type = "super_gaussian"; + relative_distance.setZero(); + gradient = mpm::RadialBasisFunction::gradient(smoothing_length, + relative_distance, type); + for (unsigned i = 0; i < gradient.size(); ++i) + REQUIRE(gradient(i) == Approx(0.0).epsilon(Tolerance)); + + relative_distance << -1.9, 1.3; + gradient = mpm::RadialBasisFunction::gradient(smoothing_length, + relative_distance, type); + + REQUIRE(gradient(0) == Approx(-0.013886756036479).epsilon(Tolerance)); + REQUIRE(gradient(1) == Approx(0.009501464656538).epsilon(Tolerance)); + + relative_distance << 2.5, 3.5; + gradient = mpm::RadialBasisFunction::gradient(smoothing_length, + relative_distance, type); + for (unsigned i = 0; i < gradient.size(); ++i) + REQUIRE(gradient(i) == Approx(0.0).epsilon(Tolerance)); + } +} + +TEST_CASE("Radial basis function 3D", "[RBF][3D]") { + // Dimension + const unsigned Dim = 3; + // Tolerance + const double Tolerance = 1.E-9; + + SECTION("Kernel 3D") { + // Initialize variables + double smoothing_length, norm_distance; + std::string type; + + // Cubic Spline + type = "cubic_spline"; + smoothing_length = 1.0; + norm_distance = 3.0; + double kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.0).epsilon(Tolerance)); + + norm_distance = 2.0; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.0).epsilon(Tolerance)); + + norm_distance = 1.5; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.009947183943243).epsilon(Tolerance)); + + norm_distance = 1.0; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.079577471545948).epsilon(Tolerance)); + + norm_distance = 0.5; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.2287852306946).epsilon(Tolerance)); + + norm_distance = 0.0; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.318309886183791).epsilon(Tolerance)); + + // Quintic Spline + type = "quintic_spline"; + norm_distance = 5.0; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.0).epsilon(Tolerance)); + + norm_distance = 3.0; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.0).epsilon(Tolerance)); + + norm_distance = 2.5; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(8.31240998042629E-05).epsilon(Tolerance)); + + norm_distance = 2.0; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.002659971193736).epsilon(Tolerance)); + + norm_distance = 1.5; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.01970041165361).epsilon(Tolerance)); + + norm_distance = 1.0; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.069159251037147).epsilon(Tolerance)); + + norm_distance = 0.5; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.13981473587077).epsilon(Tolerance)); + + norm_distance = 0.0; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.175558098786603).epsilon(Tolerance)); + + // Gaussian + type = "gaussian"; + norm_distance = 3.0 + Tolerance; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.0).epsilon(Tolerance)); + + norm_distance = 3.0; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(2.21628115579574E-05).epsilon(Tolerance)); + + norm_distance = 1.5; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.018928343413289).epsilon(Tolerance)); + + norm_distance = 0.0; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.179587122125167).epsilon(Tolerance)); + + // Super Gaussian + type = "super_gaussian"; + norm_distance = 3.0 + Tolerance; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.0).epsilon(Tolerance)); + + norm_distance = 3.0; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(-0.000144058275127).epsilon(Tolerance)); + + norm_distance = 1.5; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.004732085853322).epsilon(Tolerance)); + + norm_distance = 0.0; + kernel = mpm::RadialBasisFunction::kernel(smoothing_length, + norm_distance, type); + REQUIRE(kernel == Approx(0.448967805312916).epsilon(Tolerance)); + } + + SECTION("Gradient 3D") { + // Initialize variables + double smoothing_length = 1.0; + Eigen::Matrix relative_distance; + std::string type; + + // Cubic Spline + type = "cubic_spline"; + relative_distance.setZero(); + Eigen::Matrix gradient = + mpm::RadialBasisFunction::gradient(smoothing_length, + relative_distance, type); + for (unsigned i = 0; i < gradient.size(); ++i) + REQUIRE(gradient(i) == Approx(0.0).epsilon(Tolerance)); + + relative_distance << 0.5, -0.4, 0.1; + gradient = mpm::RadialBasisFunction::gradient(smoothing_length, + relative_distance, type); + + REQUIRE(gradient(0) == Approx(-0.245390397939789).epsilon(Tolerance)); + REQUIRE(gradient(1) == Approx(0.196312318351831).epsilon(Tolerance)); + REQUIRE(gradient(2) == Approx(-0.049078079587958).epsilon(Tolerance)); + + relative_distance << 1.0, -0.6, 0.3; + gradient = mpm::RadialBasisFunction::gradient(smoothing_length, + relative_distance, type); + + REQUIRE(gradient(0) == Approx(-0.1255681536468).epsilon(Tolerance)); + REQUIRE(gradient(1) == Approx(0.07534089218808).epsilon(Tolerance)); + REQUIRE(gradient(2) == Approx(-0.03767044609404).epsilon(Tolerance)); + + relative_distance << 1.5, 1.5, 2.0; + gradient = mpm::RadialBasisFunction::gradient(smoothing_length, + relative_distance, type); + for (unsigned i = 0; i < gradient.size(); ++i) + REQUIRE(gradient(i) == Approx(0.0).epsilon(Tolerance)); + + // Quintic Spline + type = "quintic_spline"; + relative_distance.setZero(); + gradient = mpm::RadialBasisFunction::gradient(smoothing_length, + relative_distance, type); + for (unsigned i = 0; i < gradient.size(); ++i) + REQUIRE(gradient(i) == Approx(0.0).epsilon(Tolerance)); + + relative_distance << 0.5, -0.5, 0.2; + gradient = mpm::RadialBasisFunction::gradient(smoothing_length, + relative_distance, type); + + REQUIRE(gradient(0) == Approx(-0.099803272175507).epsilon(Tolerance)); + REQUIRE(gradient(1) == Approx(0.099803272175507).epsilon(Tolerance)); + REQUIRE(gradient(2) == Approx(-0.039921308870203).epsilon(Tolerance)); + + relative_distance << 0.5, -0.5, 1.3; + gradient = mpm::RadialBasisFunction::gradient(smoothing_length, + relative_distance, type); + + REQUIRE(gradient(0) == Approx(-0.022021780742007).epsilon(Tolerance)); + REQUIRE(gradient(1) == Approx(0.022021780742007).epsilon(Tolerance)); + REQUIRE(gradient(2) == Approx(-0.057256629929218).epsilon(Tolerance)); + + relative_distance << -1.9, 1.3, 1.8; + gradient = mpm::RadialBasisFunction::gradient(smoothing_length, + relative_distance, type); + + REQUIRE(gradient(0) == Approx(3.14726383394464E-07).epsilon(Tolerance)); + REQUIRE(gradient(1) == Approx(-2.15339104427791E-07).epsilon(Tolerance)); + REQUIRE(gradient(2) == Approx(-2.98161836900018E-07).epsilon(Tolerance)); + + relative_distance << 2.5, 3.5, 3.5; + gradient = mpm::RadialBasisFunction::gradient(smoothing_length, + relative_distance, type); + for (unsigned i = 0; i < gradient.size(); ++i) + REQUIRE(gradient(i) == Approx(0.0).epsilon(Tolerance)); + + // Gaussian + type = "gaussian"; + relative_distance.setZero(); + gradient = mpm::RadialBasisFunction::gradient(smoothing_length, + relative_distance, type); + for (unsigned i = 0; i < gradient.size(); ++i) + REQUIRE(gradient(i) == Approx(0.0).epsilon(Tolerance)); + + relative_distance << -1.9, 1.3, 1.0; + gradient = mpm::RadialBasisFunction::gradient(smoothing_length, + relative_distance, type); + + REQUIRE(gradient(0) == Approx(0.001253151422955).epsilon(Tolerance)); + REQUIRE(gradient(1) == Approx(-0.000857419394653).epsilon(Tolerance)); + REQUIRE(gradient(2) == Approx(-0.000659553380503).epsilon(Tolerance)); + + relative_distance << 2.5, 3.5, 3.5; + gradient = mpm::RadialBasisFunction::gradient(smoothing_length, + relative_distance, type); + for (unsigned i = 0; i < gradient.size(); ++i) + REQUIRE(gradient(i) == Approx(0.0).epsilon(Tolerance)); + + // Super Gaussian + type = "super_gaussian"; + relative_distance.setZero(); + gradient = mpm::RadialBasisFunction::gradient(smoothing_length, + relative_distance, type); + for (unsigned i = 0; i < gradient.size(); ++i) + REQUIRE(gradient(i) == Approx(0.0).epsilon(Tolerance)); + + relative_distance << -1.9, 1.3, 1.0; + gradient = mpm::RadialBasisFunction::gradient(smoothing_length, + relative_distance, type); + + REQUIRE(gradient(0) == Approx(-0.003508823984274).epsilon(Tolerance)); + REQUIRE(gradient(1) == Approx(0.00240077430503).epsilon(Tolerance)); + REQUIRE(gradient(2) == Approx(0.001846749465407).epsilon(Tolerance)); + + relative_distance << 2.5, 3.5, 3.5; + gradient = mpm::RadialBasisFunction::gradient(smoothing_length, + relative_distance, type); + for (unsigned i = 0; i < gradient.size(); ++i) + REQUIRE(gradient(i) == Approx(0.0).epsilon(Tolerance)); + } +} From 33f5e972067c9153df77d58cc2af581047c89940 Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 21 Oct 2020 15:20:52 +0700 Subject: [PATCH 150/175] :construction: :dart: add 2D free surface detection test --- CMakeLists.txt | 1 + tests/mesh_free_surface_test.cc | 985 ++++++++++++++++++++++++++++++++ 2 files changed, 986 insertions(+) create mode 100644 tests/mesh_free_surface_test.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index d93ef69f7..87f33bb06 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -210,6 +210,7 @@ if(MPM_BUILD_TESTING) ${mpm_SOURCE_DIR}/tests/materials/newtonian_test.cc ${mpm_SOURCE_DIR}/tests/materials/norsand_test.cc ${mpm_SOURCE_DIR}/tests/materials/material_utility_test.cc + ${mpm_SOURCE_DIR}/tests/mesh_free_surface_test.cc ${mpm_SOURCE_DIR}/tests/mesh_neighbours_test.cc ${mpm_SOURCE_DIR}/tests/mesh_test_2d.cc ${mpm_SOURCE_DIR}/tests/mesh_test_3d.cc diff --git a/tests/mesh_free_surface_test.cc b/tests/mesh_free_surface_test.cc new file mode 100644 index 000000000..2c79ef01b --- /dev/null +++ b/tests/mesh_free_surface_test.cc @@ -0,0 +1,985 @@ +#include +#include + +#include "Eigen/Dense" +#include "catch.hpp" + +#include "cell.h" +#include "element.h" +#include "factory.h" +#include "hexahedron_element.h" +#include "hexahedron_quadrature.h" +#include "material.h" +#include "mesh.h" +#include "node.h" +#include "quadrilateral_element.h" +#include "quadrilateral_quadrature.h" + +TEST_CASE("Mesh free surface 2D", "[MeshCell][2D][free_surface]") { + // Dimension + const unsigned Dim = 2; + // Degrees of freedom + const unsigned Dof = 2; + // Number of phases + const unsigned Nphases = 1; + // Number of nodes per cell + const unsigned Nnodes = 4; + // Tolerance + const double Tolerance = 1.E-7; + + // Initialise material + Json jmaterial; + jmaterial["density"] = 1000.; + jmaterial["bulk_modulus"] = 8333333.333333333; + jmaterial["dynamic_viscosity"] = 8.9E-4; + auto material = + Factory, unsigned, const Json&>::instance()->create( + "Newtonian2D", std::move(0), jmaterial); + + auto mesh = std::make_shared>(0); + // Check mesh is active + REQUIRE(mesh->status() == false); + + // Coordinates + Eigen::Vector2d coords; + + coords << 0., 0.; + std::shared_ptr> node0 = + std::make_shared>(0, coords); + REQUIRE(mesh->add_node(node0) == true); + + coords << 2., 0.; + std::shared_ptr> node1 = + std::make_shared>(1, coords); + REQUIRE(mesh->add_node(node1) == true); + + coords << 4., 0.; + std::shared_ptr> node2 = + std::make_shared>(2, coords); + REQUIRE(mesh->add_node(node2) == true); + + coords << 6., 0.; + std::shared_ptr> node3 = + std::make_shared>(3, coords); + REQUIRE(mesh->add_node(node3) == true); + + coords << 8., 0.; + std::shared_ptr> node4 = + std::make_shared>(4, coords); + REQUIRE(mesh->add_node(node4) == true); + + coords << 10., 0.; + std::shared_ptr> node5 = + std::make_shared>(5, coords); + REQUIRE(mesh->add_node(node5) == true); + + coords << 0., 2.; + std::shared_ptr> node6 = + std::make_shared>(6, coords); + REQUIRE(mesh->add_node(node6) == true); + + coords << 2., 2.; + std::shared_ptr> node7 = + std::make_shared>(7, coords); + REQUIRE(mesh->add_node(node7) == true); + + coords << 4., 2.; + std::shared_ptr> node8 = + std::make_shared>(8, coords); + REQUIRE(mesh->add_node(node8) == true); + + coords << 6., 2.; + std::shared_ptr> node9 = + std::make_shared>(9, coords); + REQUIRE(mesh->add_node(node9) == true); + + coords << 8., 2.; + std::shared_ptr> node10 = + std::make_shared>(10, coords); + REQUIRE(mesh->add_node(node10) == true); + + coords << 10., 2.; + std::shared_ptr> node11 = + std::make_shared>(11, coords); + REQUIRE(mesh->add_node(node11) == true); + + coords << 0., 4.; + std::shared_ptr> node12 = + std::make_shared>(12, coords); + REQUIRE(mesh->add_node(node12) == true); + + coords << 2., 4.; + std::shared_ptr> node13 = + std::make_shared>(13, coords); + REQUIRE(mesh->add_node(node13) == true); + + coords << 4., 4.; + std::shared_ptr> node14 = + std::make_shared>(14, coords); + REQUIRE(mesh->add_node(node14) == true); + + coords << 6., 4.; + std::shared_ptr> node15 = + std::make_shared>(15, coords); + REQUIRE(mesh->add_node(node15) == true); + + coords << 8., 4.; + std::shared_ptr> node16 = + std::make_shared>(16, coords); + REQUIRE(mesh->add_node(node16) == true); + + coords << 10., 4.; + std::shared_ptr> node17 = + std::make_shared>(17, coords); + REQUIRE(mesh->add_node(node17) == true); + + coords << 0., 6.; + std::shared_ptr> node18 = + std::make_shared>(18, coords); + REQUIRE(mesh->add_node(node18) == true); + + coords << 2., 6.; + std::shared_ptr> node19 = + std::make_shared>(19, coords); + REQUIRE(mesh->add_node(node19) == true); + + coords << 4., 6.; + std::shared_ptr> node20 = + std::make_shared>(20, coords); + REQUIRE(mesh->add_node(node20) == true); + + coords << 6., 6.; + std::shared_ptr> node21 = + std::make_shared>(21, coords); + REQUIRE(mesh->add_node(node21) == true); + + coords << 8., 6.; + std::shared_ptr> node22 = + std::make_shared>(22, coords); + REQUIRE(mesh->add_node(node22) == true); + + coords << 10., 6.; + std::shared_ptr> node23 = + std::make_shared>(23, coords); + REQUIRE(mesh->add_node(node23) == true); + + coords << 0., 8.; + std::shared_ptr> node24 = + std::make_shared>(24, coords); + REQUIRE(mesh->add_node(node24) == true); + + coords << 2., 8.; + std::shared_ptr> node25 = + std::make_shared>(25, coords); + REQUIRE(mesh->add_node(node25) == true); + + coords << 4., 8.; + std::shared_ptr> node26 = + std::make_shared>(26, coords); + REQUIRE(mesh->add_node(node26) == true); + + coords << 6., 8.; + std::shared_ptr> node27 = + std::make_shared>(27, coords); + REQUIRE(mesh->add_node(node27) == true); + + coords << 8., 8.; + std::shared_ptr> node28 = + std::make_shared>(28, coords); + REQUIRE(mesh->add_node(node28) == true); + + coords << 10., 8.; + std::shared_ptr> node29 = + std::make_shared>(29, coords); + REQUIRE(mesh->add_node(node29) == true); + + coords << 0., 10.; + std::shared_ptr> node30 = + std::make_shared>(30, coords); + REQUIRE(mesh->add_node(node30) == true); + + coords << 2., 10.; + std::shared_ptr> node31 = + std::make_shared>(31, coords); + REQUIRE(mesh->add_node(node31) == true); + + coords << 4., 10.; + std::shared_ptr> node32 = + std::make_shared>(32, coords); + REQUIRE(mesh->add_node(node32) == true); + + coords << 6., 10.; + std::shared_ptr> node33 = + std::make_shared>(33, coords); + REQUIRE(mesh->add_node(node33) == true); + + coords << 8., 10.; + std::shared_ptr> node34 = + std::make_shared>(34, coords); + REQUIRE(mesh->add_node(node34) == true); + + coords << 10., 10.; + std::shared_ptr> node35 = + std::make_shared>(35, coords); + REQUIRE(mesh->add_node(node35) == true); + + // 4-noded quadrilateral shape functions + std::shared_ptr> element = + Factory>::instance()->create("ED2Q4"); + + mpm::Index id = 0; + auto cell0 = std::make_shared>(id, Nnodes, element); + + REQUIRE(cell0->add_node(0, node0) == true); + REQUIRE(cell0->add_node(1, node1) == true); + REQUIRE(cell0->add_node(2, node7) == true); + REQUIRE(cell0->add_node(3, node6) == true); + REQUIRE(cell0->nnodes() == 4); + + // Initialise cell and to mesh + REQUIRE(cell0->initialise() == true); + REQUIRE(mesh->add_cell(cell0) == true); + + id = 1; + auto cell1 = std::make_shared>(id, Nnodes, element); + + REQUIRE(cell1->add_node(0, node1) == true); + REQUIRE(cell1->add_node(1, node2) == true); + REQUIRE(cell1->add_node(2, node8) == true); + REQUIRE(cell1->add_node(3, node7) == true); + REQUIRE(cell1->nnodes() == 4); + + // Initialise cell and add to mesh + REQUIRE(cell1->initialise() == true); + REQUIRE(mesh->add_cell(cell1) == true); + + id = 2; + auto cell2 = std::make_shared>(id, Nnodes, element); + + REQUIRE(cell2->add_node(0, node2) == true); + REQUIRE(cell2->add_node(1, node3) == true); + REQUIRE(cell2->add_node(2, node9) == true); + REQUIRE(cell2->add_node(3, node8) == true); + REQUIRE(cell2->nnodes() == 4); + + // Initialise cell and add to mesh + REQUIRE(cell2->initialise() == true); + REQUIRE(mesh->add_cell(cell2) == true); + + id = 3; + auto cell3 = std::make_shared>(id, Nnodes, element); + + REQUIRE(cell3->add_node(0, node3) == true); + REQUIRE(cell3->add_node(1, node4) == true); + REQUIRE(cell3->add_node(2, node10) == true); + REQUIRE(cell3->add_node(3, node9) == true); + REQUIRE(cell3->nnodes() == 4); + + // Initialise cell and add to mesh + REQUIRE(cell3->initialise() == true); + REQUIRE(mesh->add_cell(cell3) == true); + + id = 4; + auto cell4 = std::make_shared>(id, Nnodes, element); + + REQUIRE(cell4->add_node(0, node4) == true); + REQUIRE(cell4->add_node(1, node5) == true); + REQUIRE(cell4->add_node(2, node11) == true); + REQUIRE(cell4->add_node(3, node10) == true); + REQUIRE(cell4->nnodes() == 4); + + // Initialise cell and add to mesh + REQUIRE(cell4->initialise() == true); + REQUIRE(mesh->add_cell(cell4) == true); + + id = 5; + auto cell5 = std::make_shared>(id, Nnodes, element); + + REQUIRE(cell5->add_node(0, node6) == true); + REQUIRE(cell5->add_node(1, node7) == true); + REQUIRE(cell5->add_node(2, node13) == true); + REQUIRE(cell5->add_node(3, node12) == true); + REQUIRE(cell5->nnodes() == 4); + + // Initialise cell and add to mesh + REQUIRE(cell5->initialise() == true); + REQUIRE(mesh->add_cell(cell5) == true); + + id = 6; + auto cell6 = std::make_shared>(id, Nnodes, element); + + REQUIRE(cell6->add_node(0, node7) == true); + REQUIRE(cell6->add_node(1, node8) == true); + REQUIRE(cell6->add_node(2, node14) == true); + REQUIRE(cell6->add_node(3, node13) == true); + REQUIRE(cell6->nnodes() == 4); + + // Initialise cell and add to mesh + REQUIRE(cell6->initialise() == true); + REQUIRE(mesh->add_cell(cell6) == true); + + id = 7; + auto cell7 = std::make_shared>(id, Nnodes, element); + + REQUIRE(cell7->add_node(0, node8) == true); + REQUIRE(cell7->add_node(1, node9) == true); + REQUIRE(cell7->add_node(2, node15) == true); + REQUIRE(cell7->add_node(3, node14) == true); + REQUIRE(cell7->nnodes() == 4); + + // Initialise cell and add to mesh + REQUIRE(cell7->initialise() == true); + REQUIRE(mesh->add_cell(cell7) == true); + + id = 8; + auto cell8 = std::make_shared>(id, Nnodes, element); + + REQUIRE(cell8->add_node(0, node9) == true); + REQUIRE(cell8->add_node(1, node10) == true); + REQUIRE(cell8->add_node(2, node16) == true); + REQUIRE(cell8->add_node(3, node15) == true); + REQUIRE(cell8->nnodes() == 4); + + // Initialise cell and add to mesh + REQUIRE(cell8->initialise() == true); + REQUIRE(mesh->add_cell(cell8) == true); + + id = 9; + auto cell9 = std::make_shared>(id, Nnodes, element); + + REQUIRE(cell9->add_node(0, node10) == true); + REQUIRE(cell9->add_node(1, node11) == true); + REQUIRE(cell9->add_node(2, node17) == true); + REQUIRE(cell9->add_node(3, node16) == true); + REQUIRE(cell9->nnodes() == 4); + + // Initialise cell and add to mesh + REQUIRE(cell9->initialise() == true); + REQUIRE(mesh->add_cell(cell9) == true); + + id = 10; + auto cell10 = std::make_shared>(id, Nnodes, element); + + REQUIRE(cell10->add_node(0, node12) == true); + REQUIRE(cell10->add_node(1, node13) == true); + REQUIRE(cell10->add_node(2, node19) == true); + REQUIRE(cell10->add_node(3, node18) == true); + REQUIRE(cell10->nnodes() == 4); + + // Initialise cell and add to mesh + REQUIRE(cell10->initialise() == true); + REQUIRE(mesh->add_cell(cell10) == true); + + id = 11; + auto cell11 = std::make_shared>(id, Nnodes, element); + + REQUIRE(cell11->add_node(0, node13) == true); + REQUIRE(cell11->add_node(1, node14) == true); + REQUIRE(cell11->add_node(2, node20) == true); + REQUIRE(cell11->add_node(3, node19) == true); + REQUIRE(cell11->nnodes() == 4); + + // Initialise cell and add to mesh + REQUIRE(cell11->initialise() == true); + REQUIRE(mesh->add_cell(cell11) == true); + + id = 12; + auto cell12 = std::make_shared>(id, Nnodes, element); + + REQUIRE(cell12->add_node(0, node14) == true); + REQUIRE(cell12->add_node(1, node15) == true); + REQUIRE(cell12->add_node(2, node21) == true); + REQUIRE(cell12->add_node(3, node20) == true); + REQUIRE(cell12->nnodes() == 4); + + // Initialise cell and add to mesh + REQUIRE(cell12->initialise() == true); + REQUIRE(mesh->add_cell(cell12) == true); + + id = 13; + auto cell13 = std::make_shared>(id, Nnodes, element); + + REQUIRE(cell13->add_node(0, node15) == true); + REQUIRE(cell13->add_node(1, node16) == true); + REQUIRE(cell13->add_node(2, node22) == true); + REQUIRE(cell13->add_node(3, node21) == true); + REQUIRE(cell13->nnodes() == 4); + + // Initialise cell and add to mesh + REQUIRE(cell13->initialise() == true); + REQUIRE(mesh->add_cell(cell13) == true); + + id = 14; + auto cell14 = std::make_shared>(id, Nnodes, element); + + REQUIRE(cell14->add_node(0, node16) == true); + REQUIRE(cell14->add_node(1, node17) == true); + REQUIRE(cell14->add_node(2, node23) == true); + REQUIRE(cell14->add_node(3, node22) == true); + REQUIRE(cell14->nnodes() == 4); + + // Initialise cell and add to mesh + REQUIRE(cell14->initialise() == true); + REQUIRE(mesh->add_cell(cell14) == true); + + id = 15; + auto cell15 = std::make_shared>(id, Nnodes, element); + + REQUIRE(cell15->add_node(0, node18) == true); + REQUIRE(cell15->add_node(1, node19) == true); + REQUIRE(cell15->add_node(2, node25) == true); + REQUIRE(cell15->add_node(3, node24) == true); + REQUIRE(cell15->nnodes() == 4); + + // Initialise cell and add to mesh + REQUIRE(cell15->initialise() == true); + REQUIRE(mesh->add_cell(cell15) == true); + + id = 16; + auto cell16 = std::make_shared>(id, Nnodes, element); + + REQUIRE(cell16->add_node(0, node19) == true); + REQUIRE(cell16->add_node(1, node20) == true); + REQUIRE(cell16->add_node(2, node26) == true); + REQUIRE(cell16->add_node(3, node25) == true); + REQUIRE(cell16->nnodes() == 4); + + // Initialise cell and add to mesh + REQUIRE(cell16->initialise() == true); + REQUIRE(mesh->add_cell(cell16) == true); + + id = 17; + auto cell17 = std::make_shared>(id, Nnodes, element); + + REQUIRE(cell17->add_node(0, node20) == true); + REQUIRE(cell17->add_node(1, node21) == true); + REQUIRE(cell17->add_node(2, node27) == true); + REQUIRE(cell17->add_node(3, node26) == true); + REQUIRE(cell17->nnodes() == 4); + + // Initialise cell and add to mesh + REQUIRE(cell17->initialise() == true); + REQUIRE(mesh->add_cell(cell17) == true); + + id = 18; + auto cell18 = std::make_shared>(id, Nnodes, element); + + REQUIRE(cell18->add_node(0, node21) == true); + REQUIRE(cell18->add_node(1, node22) == true); + REQUIRE(cell18->add_node(2, node28) == true); + REQUIRE(cell18->add_node(3, node27) == true); + REQUIRE(cell18->nnodes() == 4); + + // Initialise cell and add to mesh + REQUIRE(cell18->initialise() == true); + REQUIRE(mesh->add_cell(cell18) == true); + + id = 19; + auto cell19 = std::make_shared>(id, Nnodes, element); + + REQUIRE(cell19->add_node(0, node22) == true); + REQUIRE(cell19->add_node(1, node23) == true); + REQUIRE(cell19->add_node(2, node29) == true); + REQUIRE(cell19->add_node(3, node28) == true); + REQUIRE(cell19->nnodes() == 4); + + // Initialise cell and add to mesh + REQUIRE(cell19->initialise() == true); + REQUIRE(mesh->add_cell(cell19) == true); + + id = 20; + auto cell20 = std::make_shared>(id, Nnodes, element); + + REQUIRE(cell20->add_node(0, node24) == true); + REQUIRE(cell20->add_node(1, node25) == true); + REQUIRE(cell20->add_node(2, node31) == true); + REQUIRE(cell20->add_node(3, node30) == true); + REQUIRE(cell20->nnodes() == 4); + + // Initialise cell and add to mesh + REQUIRE(cell20->initialise() == true); + REQUIRE(mesh->add_cell(cell20) == true); + + id = 21; + auto cell21 = std::make_shared>(id, Nnodes, element); + + REQUIRE(cell21->add_node(0, node25) == true); + REQUIRE(cell21->add_node(1, node26) == true); + REQUIRE(cell21->add_node(2, node32) == true); + REQUIRE(cell21->add_node(3, node31) == true); + REQUIRE(cell21->nnodes() == 4); + + // Initialise cell and add to mesh + REQUIRE(cell21->initialise() == true); + REQUIRE(mesh->add_cell(cell21) == true); + + id = 22; + auto cell22 = std::make_shared>(id, Nnodes, element); + + REQUIRE(cell22->add_node(0, node26) == true); + REQUIRE(cell22->add_node(1, node27) == true); + REQUIRE(cell22->add_node(2, node33) == true); + REQUIRE(cell22->add_node(3, node32) == true); + REQUIRE(cell22->nnodes() == 4); + + // Initialise cell and add to mesh + REQUIRE(cell22->initialise() == true); + REQUIRE(mesh->add_cell(cell22) == true); + + id = 23; + auto cell23 = std::make_shared>(id, Nnodes, element); + + REQUIRE(cell23->add_node(0, node27) == true); + REQUIRE(cell23->add_node(1, node28) == true); + REQUIRE(cell23->add_node(2, node34) == true); + REQUIRE(cell23->add_node(3, node33) == true); + REQUIRE(cell23->nnodes() == 4); + + // Initialise cell and add to mesh + REQUIRE(cell23->initialise() == true); + REQUIRE(mesh->add_cell(cell23) == true); + + id = 24; + auto cell24 = std::make_shared>(id, Nnodes, element); + + REQUIRE(cell24->add_node(0, node28) == true); + REQUIRE(cell24->add_node(1, node29) == true); + REQUIRE(cell24->add_node(2, node35) == true); + REQUIRE(cell24->add_node(3, node34) == true); + REQUIRE(cell24->nnodes() == 4); + + // Initialise cell and add to mesh + REQUIRE(cell24->initialise() == true); + REQUIRE(mesh->add_cell(cell24) == true); + + // Find cell neighbours + mesh->find_cell_neighbours(); + + std::shared_ptr> particle0, particle1, particle2, + particle3, particle4, particle5, particle6, particle7, particle8, + particle9, particle10, particle11, particle12, particle13, particle14, + particle15; + + coords << 3.5, 3.5; + particle0 = std::make_shared>(0, coords); + REQUIRE(mesh->add_particle(particle0, false) == true); + + coords << 4.5, 3.5; + particle1 = std::make_shared>(1, coords); + REQUIRE(mesh->add_particle(particle1, false) == true); + + coords << 5.5, 3.5; + particle2 = std::make_shared>(2, coords); + REQUIRE(mesh->add_particle(particle2, false) == true); + + coords << 6.5, 3.5; + particle3 = std::make_shared>(3, coords); + REQUIRE(mesh->add_particle(particle3, false) == true); + + coords << 3.5, 4.5; + particle4 = std::make_shared>(4, coords); + REQUIRE(mesh->add_particle(particle4, false) == true); + + coords << 4.5, 4.5; + particle5 = std::make_shared>(5, coords); + REQUIRE(mesh->add_particle(particle5, false) == true); + + coords << 5.5, 4.5; + particle6 = std::make_shared>(6, coords); + REQUIRE(mesh->add_particle(particle6, false) == true); + + coords << 6.5, 4.5; + particle7 = std::make_shared>(7, coords); + REQUIRE(mesh->add_particle(particle7, false) == true); + + coords << 3.5, 5.5; + particle8 = std::make_shared>(8, coords); + REQUIRE(mesh->add_particle(particle8, false) == true); + + coords << 4.5, 5.5; + particle9 = std::make_shared>(9, coords); + REQUIRE(mesh->add_particle(particle9, false) == true); + + coords << 5.5, 5.5; + particle10 = std::make_shared>(10, coords); + REQUIRE(mesh->add_particle(particle10, false) == true); + + coords << 6.5, 5.5; + particle11 = std::make_shared>(11, coords); + REQUIRE(mesh->add_particle(particle11, false) == true); + + coords << 3.5, 6.5; + particle12 = std::make_shared>(12, coords); + REQUIRE(mesh->add_particle(particle12, false) == true); + + coords << 4.5, 6.5; + particle13 = std::make_shared>(13, coords); + REQUIRE(mesh->add_particle(particle13, false) == true); + + coords << 5.5, 6.5; + particle14 = std::make_shared>(14, coords); + REQUIRE(mesh->add_particle(particle14, false) == true); + + coords << 6.5, 6.5; + particle15 = std::make_shared>(15, coords); + REQUIRE(mesh->add_particle(particle15, false) == true); + + // Assign material to particles + mesh->iterate_over_particles( + std::bind(&mpm::ParticleBase::assign_material, std::placeholders::_1, + material, 0)); + + // Locate particles in a mesh + auto particles = mesh->locate_particles_mesh(); + + // Should find all particles in mesh + REQUIRE(particles.size() == 0); + + // Check particles inside cells + REQUIRE(cell0->nparticles() == 0); + REQUIRE(cell1->nparticles() == 0); + REQUIRE(cell2->nparticles() == 0); + REQUIRE(cell3->nparticles() == 0); + REQUIRE(cell4->nparticles() == 0); + REQUIRE(cell5->nparticles() == 0); + REQUIRE(cell6->nparticles() == 1); + REQUIRE(cell7->nparticles() == 2); + REQUIRE(cell8->nparticles() == 1); + REQUIRE(cell9->nparticles() == 0); + REQUIRE(cell10->nparticles() == 0); + REQUIRE(cell11->nparticles() == 2); + REQUIRE(cell12->nparticles() == 4); + REQUIRE(cell13->nparticles() == 2); + REQUIRE(cell14->nparticles() == 0); + REQUIRE(cell15->nparticles() == 0); + REQUIRE(cell16->nparticles() == 1); + REQUIRE(cell17->nparticles() == 2); + REQUIRE(cell18->nparticles() == 1); + REQUIRE(cell19->nparticles() == 0); + REQUIRE(cell20->nparticles() == 0); + REQUIRE(cell21->nparticles() == 0); + REQUIRE(cell22->nparticles() == 0); + REQUIRE(cell23->nparticles() == 0); + REQUIRE(cell24->nparticles() == 0); + + // Find particle neighbours + mesh->find_particle_neighbours(); + + // Check particle neighbours + REQUIRE(particle0->nneighbours() == 8); + REQUIRE(particle1->nneighbours() == 11); + REQUIRE(particle2->nneighbours() == 11); + REQUIRE(particle3->nneighbours() == 8); + REQUIRE(particle4->nneighbours() == 11); + REQUIRE(particle5->nneighbours() == 15); + REQUIRE(particle6->nneighbours() == 15); + REQUIRE(particle7->nneighbours() == 11); + REQUIRE(particle8->nneighbours() == 11); + REQUIRE(particle9->nneighbours() == 15); + REQUIRE(particle10->nneighbours() == 15); + REQUIRE(particle11->nneighbours() == 11); + REQUIRE(particle12->nneighbours() == 8); + REQUIRE(particle13->nneighbours() == 11); + REQUIRE(particle14->nneighbours() == 11); + REQUIRE(particle15->nneighbours() == 8); + + // Initialise particle variables + // Assign particle volume + mesh->iterate_over_particles(std::bind(&mpm::ParticleBase::assign_volume, + std::placeholders::_1, 1.)); + + // Compute mass + mesh->iterate_over_particles( + std::bind(&mpm::ParticleBase::compute_mass, std::placeholders::_1)); + + // 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)); + + // 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 + mesh->iterate_over_particles( + std::bind(&mpm::ParticleBase::map_mass_momentum_to_nodes, + std::placeholders::_1)); + + SECTION("Mesh check initial condition") { + + // Check cell free surface + REQUIRE(cell0->free_surface() == false); + REQUIRE(cell1->free_surface() == false); + REQUIRE(cell2->free_surface() == false); + REQUIRE(cell3->free_surface() == false); + REQUIRE(cell4->free_surface() == false); + REQUIRE(cell5->free_surface() == false); + REQUIRE(cell6->free_surface() == false); + REQUIRE(cell7->free_surface() == false); + REQUIRE(cell8->free_surface() == false); + REQUIRE(cell9->free_surface() == false); + REQUIRE(cell10->free_surface() == false); + REQUIRE(cell11->free_surface() == false); + REQUIRE(cell12->free_surface() == false); + REQUIRE(cell13->free_surface() == false); + REQUIRE(cell14->free_surface() == false); + REQUIRE(cell15->free_surface() == false); + REQUIRE(cell16->free_surface() == false); + REQUIRE(cell17->free_surface() == false); + REQUIRE(cell18->free_surface() == false); + REQUIRE(cell19->free_surface() == false); + REQUIRE(cell20->free_surface() == false); + REQUIRE(cell21->free_surface() == false); + REQUIRE(cell22->free_surface() == false); + REQUIRE(cell23->free_surface() == false); + REQUIRE(cell24->free_surface() == false); + + // Check cell status + REQUIRE(cell0->status() == false); + REQUIRE(cell1->status() == false); + REQUIRE(cell2->status() == false); + REQUIRE(cell3->status() == false); + REQUIRE(cell4->status() == false); + REQUIRE(cell5->status() == false); + REQUIRE(cell6->status() == true); + REQUIRE(cell7->status() == true); + REQUIRE(cell8->status() == true); + REQUIRE(cell9->status() == false); + REQUIRE(cell10->status() == false); + REQUIRE(cell11->status() == true); + REQUIRE(cell12->status() == true); + REQUIRE(cell13->status() == true); + REQUIRE(cell14->status() == false); + REQUIRE(cell15->status() == false); + REQUIRE(cell16->status() == true); + REQUIRE(cell17->status() == true); + REQUIRE(cell18->status() == true); + REQUIRE(cell19->status() == false); + REQUIRE(cell20->status() == false); + REQUIRE(cell21->status() == false); + REQUIRE(cell22->status() == false); + REQUIRE(cell23->status() == false); + REQUIRE(cell24->status() == false); + + // Check node free surface + REQUIRE(node0->free_surface() == false); + REQUIRE(node1->free_surface() == false); + REQUIRE(node2->free_surface() == false); + REQUIRE(node3->free_surface() == false); + REQUIRE(node4->free_surface() == false); + REQUIRE(node5->free_surface() == false); + REQUIRE(node6->free_surface() == false); + REQUIRE(node7->free_surface() == false); + REQUIRE(node8->free_surface() == false); + REQUIRE(node9->free_surface() == false); + REQUIRE(node10->free_surface() == false); + REQUIRE(node11->free_surface() == false); + REQUIRE(node12->free_surface() == false); + REQUIRE(node13->free_surface() == false); + REQUIRE(node14->free_surface() == false); + REQUIRE(node15->free_surface() == false); + REQUIRE(node16->free_surface() == false); + REQUIRE(node17->free_surface() == false); + REQUIRE(node18->free_surface() == false); + REQUIRE(node19->free_surface() == false); + REQUIRE(node20->free_surface() == false); + REQUIRE(node21->free_surface() == false); + REQUIRE(node22->free_surface() == false); + REQUIRE(node23->free_surface() == false); + REQUIRE(node24->free_surface() == false); + REQUIRE(node25->free_surface() == false); + REQUIRE(node26->free_surface() == false); + REQUIRE(node27->free_surface() == false); + REQUIRE(node28->free_surface() == false); + REQUIRE(node29->free_surface() == false); + REQUIRE(node30->free_surface() == false); + REQUIRE(node31->free_surface() == false); + REQUIRE(node32->free_surface() == false); + REQUIRE(node33->free_surface() == false); + REQUIRE(node34->free_surface() == false); + REQUIRE(node35->free_surface() == false); + + // Check node status + REQUIRE(node0->status() == false); + REQUIRE(node1->status() == false); + REQUIRE(node2->status() == false); + REQUIRE(node3->status() == false); + REQUIRE(node4->status() == false); + REQUIRE(node5->status() == false); + REQUIRE(node6->status() == false); + REQUIRE(node7->status() == true); + REQUIRE(node8->status() == true); + REQUIRE(node9->status() == true); + REQUIRE(node10->status() == true); + REQUIRE(node11->status() == false); + REQUIRE(node12->status() == false); + REQUIRE(node13->status() == true); + REQUIRE(node14->status() == true); + REQUIRE(node15->status() == true); + REQUIRE(node16->status() == true); + REQUIRE(node17->status() == false); + REQUIRE(node18->status() == false); + REQUIRE(node19->status() == true); + REQUIRE(node20->status() == true); + REQUIRE(node21->status() == true); + REQUIRE(node22->status() == true); + REQUIRE(node23->status() == false); + REQUIRE(node24->status() == false); + REQUIRE(node25->status() == true); + REQUIRE(node26->status() == true); + REQUIRE(node27->status() == true); + REQUIRE(node28->status() == true); + REQUIRE(node29->status() == false); + REQUIRE(node30->status() == false); + REQUIRE(node31->status() == false); + REQUIRE(node32->status() == false); + REQUIRE(node33->status() == false); + REQUIRE(node34->status() == false); + REQUIRE(node35->status() == false); + + // Check particle free surface + REQUIRE(particle0->free_surface() == false); + REQUIRE(particle1->free_surface() == false); + REQUIRE(particle2->free_surface() == false); + REQUIRE(particle3->free_surface() == false); + REQUIRE(particle4->free_surface() == false); + REQUIRE(particle5->free_surface() == false); + REQUIRE(particle6->free_surface() == false); + REQUIRE(particle7->free_surface() == false); + REQUIRE(particle8->free_surface() == false); + REQUIRE(particle9->free_surface() == false); + REQUIRE(particle10->free_surface() == false); + REQUIRE(particle11->free_surface() == false); + REQUIRE(particle12->free_surface() == false); + REQUIRE(particle13->free_surface() == false); + REQUIRE(particle14->free_surface() == false); + REQUIRE(particle15->free_surface() == false); + } + + SECTION("Mesh free surface 2D by density") { + + REQUIRE(mesh->compute_free_surface_by_density(0.25) == true); + + // Check cell volume fraction + REQUIRE(cell0->volume_fraction() == Approx(0.0).epsilon(Tolerance)); + REQUIRE(cell1->volume_fraction() == Approx(0.0).epsilon(Tolerance)); + REQUIRE(cell2->volume_fraction() == Approx(0.0).epsilon(Tolerance)); + REQUIRE(cell3->volume_fraction() == Approx(0.0).epsilon(Tolerance)); + REQUIRE(cell4->volume_fraction() == Approx(0.0).epsilon(Tolerance)); + REQUIRE(cell5->volume_fraction() == Approx(0.0).epsilon(Tolerance)); + REQUIRE(cell6->volume_fraction() == Approx(0.25).epsilon(Tolerance)); + REQUIRE(cell7->volume_fraction() == Approx(0.5).epsilon(Tolerance)); + REQUIRE(cell8->volume_fraction() == Approx(0.25).epsilon(Tolerance)); + REQUIRE(cell9->volume_fraction() == Approx(0.0).epsilon(Tolerance)); + REQUIRE(cell10->volume_fraction() == Approx(0.0).epsilon(Tolerance)); + REQUIRE(cell11->volume_fraction() == Approx(0.5).epsilon(Tolerance)); + REQUIRE(cell12->volume_fraction() == Approx(1.0).epsilon(Tolerance)); + REQUIRE(cell13->volume_fraction() == Approx(0.5).epsilon(Tolerance)); + REQUIRE(cell14->volume_fraction() == Approx(0.0).epsilon(Tolerance)); + REQUIRE(cell15->volume_fraction() == Approx(0.0).epsilon(Tolerance)); + REQUIRE(cell16->volume_fraction() == Approx(0.25).epsilon(Tolerance)); + REQUIRE(cell17->volume_fraction() == Approx(0.5).epsilon(Tolerance)); + REQUIRE(cell18->volume_fraction() == Approx(0.25).epsilon(Tolerance)); + REQUIRE(cell19->volume_fraction() == Approx(0.0).epsilon(Tolerance)); + REQUIRE(cell20->volume_fraction() == Approx(0.0).epsilon(Tolerance)); + REQUIRE(cell21->volume_fraction() == Approx(0.0).epsilon(Tolerance)); + REQUIRE(cell22->volume_fraction() == Approx(0.0).epsilon(Tolerance)); + REQUIRE(cell23->volume_fraction() == Approx(0.0).epsilon(Tolerance)); + REQUIRE(cell24->volume_fraction() == Approx(0.0).epsilon(Tolerance)); + + // Check nodal density for active nodes + REQUIRE(node7->density(0) == Approx(62.5).epsilon(Tolerance)); + REQUIRE(node8->density(0) == Approx(218.75).epsilon(Tolerance)); + REQUIRE(node9->density(0) == Approx(218.75).epsilon(Tolerance)); + REQUIRE(node10->density(0) == Approx(62.5).epsilon(Tolerance)); + + REQUIRE(node13->density(0) == Approx(218.75).epsilon(Tolerance)); + REQUIRE(node14->density(0) == Approx(765.625).epsilon(Tolerance)); + REQUIRE(node15->density(0) == Approx(765.625).epsilon(Tolerance)); + REQUIRE(node16->density(0) == Approx(218.75).epsilon(Tolerance)); + + REQUIRE(node19->density(0) == Approx(218.75).epsilon(Tolerance)); + REQUIRE(node20->density(0) == Approx(765.625).epsilon(Tolerance)); + REQUIRE(node21->density(0) == Approx(765.625).epsilon(Tolerance)); + REQUIRE(node22->density(0) == Approx(218.75).epsilon(Tolerance)); + + REQUIRE(node25->density(0) == Approx(62.5).epsilon(Tolerance)); + REQUIRE(node26->density(0) == Approx(218.75).epsilon(Tolerance)); + REQUIRE(node27->density(0) == Approx(218.75).epsilon(Tolerance)); + REQUIRE(node28->density(0) == Approx(62.5).epsilon(Tolerance)); + + // Check solutions + std::set fsc = {6, 7, 8, 11, 13, 16, 17, 18}; + std::set fsn = {7, 8, 9, 10, 13, 16, 19, 22, 25, 26, 27, 28}; + std::set fsp = {0, 1, 2, 3, 4, 7, 8, 11, 12, 13, 14, 15}; + + // Check cell, node, and particle free surface + REQUIRE(mesh->free_surface_cells() == fsc); + REQUIRE(mesh->free_surface_nodes() == fsn); + REQUIRE(mesh->free_surface_particles() == fsp); + } + + SECTION("Mesh free surface 2D by geometry") { + + REQUIRE(mesh->compute_free_surface_by_geometry(0.25) == true); + + // Check solutions + std::set fsc = {6, 7, 8, 11, 13, 16, 17, 18}; + std::set fsn = {7, 8, 9, 10, 13, 16, 19, 22, 25, 26, 27, 28}; + std::set fsp = {0, 1, 2, 3, 4, 7, 8, 11, 12, 13, 14, 15}; + + // Check cell, node, and particle free surface + REQUIRE(mesh->free_surface_cells() == fsc); + REQUIRE(mesh->free_surface_nodes() == fsn); + REQUIRE(mesh->free_surface_particles() == fsp); + + // Check particle normal vector + REQUIRE(particle0->normal().norm() == Approx(1.0).epsilon(Tolerance)); + REQUIRE(particle1->normal().norm() == Approx(1.0).epsilon(Tolerance)); + REQUIRE(particle2->normal().norm() == Approx(1.0).epsilon(Tolerance)); + REQUIRE(particle3->normal().norm() == Approx(1.0).epsilon(Tolerance)); + REQUIRE(particle4->normal().norm() == Approx(1.0).epsilon(Tolerance)); + REQUIRE(particle5->normal().norm() == Approx(0.0).epsilon(Tolerance)); + REQUIRE(particle6->normal().norm() == Approx(0.0).epsilon(Tolerance)); + REQUIRE(particle7->normal().norm() == Approx(1.0).epsilon(Tolerance)); + REQUIRE(particle8->normal().norm() == Approx(1.0).epsilon(Tolerance)); + REQUIRE(particle9->normal().norm() == Approx(0.0).epsilon(Tolerance)); + REQUIRE(particle10->normal().norm() == Approx(0.0).epsilon(Tolerance)); + REQUIRE(particle11->normal().norm() == Approx(1.0).epsilon(Tolerance)); + REQUIRE(particle12->normal().norm() == Approx(1.0).epsilon(Tolerance)); + REQUIRE(particle13->normal().norm() == Approx(1.0).epsilon(Tolerance)); + REQUIRE(particle14->normal().norm() == Approx(1.0).epsilon(Tolerance)); + REQUIRE(particle15->normal().norm() == Approx(1.0).epsilon(Tolerance)); + } + + SECTION("Mesh free surface 2D") { + + // Check solutions + std::set fsc = {6, 7, 8, 11, 13, 16, 17, 18}; + std::set fsn = {7, 8, 9, 10, 13, 16, 19, 22, 25, 26, 27, 28}; + std::set fsp = {0, 1, 2, 3, 4, 7, 8, 11, 12, 13, 14, 15}; + + std::string method = "density"; + REQUIRE(mesh->compute_free_surface(method, 0.25) == true); + + // Check cell, node, and particle free surface + REQUIRE(mesh->free_surface_cells() == fsc); + REQUIRE(mesh->free_surface_nodes() == fsn); + REQUIRE(mesh->free_surface_particles() == fsp); + + method = "geometry"; + REQUIRE(mesh->compute_free_surface(method, 0.25) == true); + + // Check cell, node, and particle free surface + REQUIRE(mesh->free_surface_cells() == fsc); + REQUIRE(mesh->free_surface_nodes() == fsn); + REQUIRE(mesh->free_surface_particles() == fsp); + + method = "other"; + REQUIRE(mesh->compute_free_surface(method, 0.25) == true); + } +} + From f272ee7160703affe8dbf86c1fada07b2ceedf0e Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 21 Oct 2020 15:22:06 +0700 Subject: [PATCH 151/175] :construction: add check cell status in mapping volume --- include/cell.tcc | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/include/cell.tcc b/include/cell.tcc index adfd1e379..43b9da653 100644 --- a/include/cell.tcc +++ b/include/cell.tcc @@ -848,10 +848,13 @@ inline unsigned mpm::Cell::previous_mpirank() const { //! Map cell volume to nodes template void mpm::Cell::map_cell_volume_to_nodes(unsigned phase) { - // Check if cell volume is set - if (volume_ == std::numeric_limits::lowest()) this->compute_volume(); + if (this->status()) { + // 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_); + for (unsigned i = 0; i < nodes_.size(); ++i) { + nodes_[i]->update_volume(true, phase, volume_ / nnodes_); + } } } From 0738ab273f57a516f014758c5e999d770a5afeca Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 21 Oct 2020 20:43:56 +0700 Subject: [PATCH 152/175] :construction: change default value for particle density fs detection --- include/particles/particle.h | 2 +- include/particles/particle_base.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/particles/particle.h b/include/particles/particle.h index 6fd3862d0..0440aa834 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -324,7 +324,7 @@ class Particle : public ParticleBase { //! \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; + double density_ratio_tolerance = 0.65) override; //! Assign normal vector void assign_normal(const VectorDim& normal) override { normal_ = normal; }; diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 942f61349..62f6b4c19 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -314,7 +314,7 @@ class ParticleBase { //! Compute free surface in particle level by density ratio comparison virtual bool compute_free_surface_by_density( - double density_ratio_tolerance = 0.70) = 0; + double density_ratio_tolerance = 0.65) = 0; //! Assign normal vector virtual void assign_normal(const VectorDim& normal) = 0; From 79820f20c424bb1fb82afa70eb0bb0293c6ae0b9 Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 21 Oct 2020 20:44:12 +0700 Subject: [PATCH 153/175] :dart: add 3D fsd test --- tests/mesh_free_surface_test.cc | 240 ++++++++++++++++++++++++++++++-- 1 file changed, 225 insertions(+), 15 deletions(-) diff --git a/tests/mesh_free_surface_test.cc b/tests/mesh_free_surface_test.cc index 2c79ef01b..5d977fdde 100644 --- a/tests/mesh_free_surface_test.cc +++ b/tests/mesh_free_surface_test.cc @@ -859,6 +859,11 @@ TEST_CASE("Mesh free surface 2D", "[MeshCell][2D][free_surface]") { REQUIRE(particle15->free_surface() == false); } + // Check solutions + std::set fsc = {6, 7, 8, 11, 13, 16, 17, 18}; + std::set fsn = {7, 8, 9, 10, 13, 16, 19, 22, 25, 26, 27, 28}; + std::set fsp = {0, 1, 2, 3, 4, 7, 8, 11, 12, 13, 14, 15}; + SECTION("Mesh free surface 2D by density") { REQUIRE(mesh->compute_free_surface_by_density(0.25) == true); @@ -911,11 +916,6 @@ TEST_CASE("Mesh free surface 2D", "[MeshCell][2D][free_surface]") { REQUIRE(node27->density(0) == Approx(218.75).epsilon(Tolerance)); REQUIRE(node28->density(0) == Approx(62.5).epsilon(Tolerance)); - // Check solutions - std::set fsc = {6, 7, 8, 11, 13, 16, 17, 18}; - std::set fsn = {7, 8, 9, 10, 13, 16, 19, 22, 25, 26, 27, 28}; - std::set fsp = {0, 1, 2, 3, 4, 7, 8, 11, 12, 13, 14, 15}; - // Check cell, node, and particle free surface REQUIRE(mesh->free_surface_cells() == fsc); REQUIRE(mesh->free_surface_nodes() == fsn); @@ -926,11 +926,6 @@ TEST_CASE("Mesh free surface 2D", "[MeshCell][2D][free_surface]") { REQUIRE(mesh->compute_free_surface_by_geometry(0.25) == true); - // Check solutions - std::set fsc = {6, 7, 8, 11, 13, 16, 17, 18}; - std::set fsn = {7, 8, 9, 10, 13, 16, 19, 22, 25, 26, 27, 28}; - std::set fsp = {0, 1, 2, 3, 4, 7, 8, 11, 12, 13, 14, 15}; - // Check cell, node, and particle free surface REQUIRE(mesh->free_surface_cells() == fsc); REQUIRE(mesh->free_surface_nodes() == fsn); @@ -957,11 +952,6 @@ TEST_CASE("Mesh free surface 2D", "[MeshCell][2D][free_surface]") { SECTION("Mesh free surface 2D") { - // Check solutions - std::set fsc = {6, 7, 8, 11, 13, 16, 17, 18}; - std::set fsn = {7, 8, 9, 10, 13, 16, 19, 22, 25, 26, 27, 28}; - std::set fsp = {0, 1, 2, 3, 4, 7, 8, 11, 12, 13, 14, 15}; - std::string method = "density"; REQUIRE(mesh->compute_free_surface(method, 0.25) == true); @@ -983,3 +973,223 @@ TEST_CASE("Mesh free surface 2D", "[MeshCell][2D][free_surface]") { } } +TEST_CASE("Mesh free surface 3D", "[MeshCell][3D][free_surface]") { + // Dimension + const unsigned Dim = 3; + // Degrees of freedom + const unsigned Dof = 3; + // Number of phases + const unsigned Nphases = 1; + // Number of nodes per cell + const unsigned Nnodes = 8; + // Tolerance + const double Tolerance = 1.E-7; + + // Initialise material + Json jmaterial; + jmaterial["density"] = 1000.; + jmaterial["bulk_modulus"] = 8333333.333333333; + jmaterial["dynamic_viscosity"] = 8.9E-4; + auto material = + Factory, unsigned, const Json&>::instance()->create( + "Newtonian3D", std::move(0), jmaterial); + + auto mesh = std::make_shared>(0); + // Check mesh is active + REQUIRE(mesh->status() == false); + + // Create nodes + Eigen::Vector3d coords; + mpm::Index id = 0; + double mesh_size = 2.; + for (unsigned k = 0; k < 6; k++) { + for (unsigned j = 0; j < 6; j++) { + for (unsigned i = 0; i < 6; i++) { + coords << double(i * mesh_size), double(j * mesh_size), + double(k * mesh_size); + std::shared_ptr> node = + std::make_shared>(id, coords); + REQUIRE(mesh->add_node(node) == true); + id++; + } + } + } + + REQUIRE(mesh->nnodes() == 216); + + // 8-noded hexahedral shape functions + std::shared_ptr> element = + Factory>::instance()->create("ED3H8"); + + // Create cells + id = 0; + for (unsigned k = 0; k < 5; k++) { + for (unsigned j = 0; j < 5; j++) { + for (unsigned i = 0; i < 5; i++) { + auto node_0 = mesh->node(k * 36 + j * 6 + i); + auto node_1 = mesh->node(k * 36 + j * 6 + i + 1); + auto node_2 = mesh->node(k * 36 + (j + 1) * 6 + i + 1); + auto node_3 = mesh->node(k * 36 + (j + 1) * 6 + i); + + auto node_4 = mesh->node((k + 1) * 36 + j * 6 + i); + auto node_5 = mesh->node((k + 1) * 36 + j * 6 + i + 1); + auto node_6 = mesh->node((k + 1) * 36 + (j + 1) * 6 + i + 1); + auto node_7 = mesh->node((k + 1) * 36 + (j + 1) * 6 + i); + + auto cell = std::make_shared>(id, Nnodes, element); + + cell->add_node(0, node_0); + cell->add_node(1, node_1); + cell->add_node(2, node_2); + cell->add_node(3, node_3); + cell->add_node(4, node_4); + cell->add_node(5, node_5); + cell->add_node(6, node_6); + cell->add_node(7, node_7); + REQUIRE(cell->nnodes() == 8); + + // Initialise cell and add to mesh + REQUIRE(cell->initialise() == true); + REQUIRE(mesh->add_cell(cell) == true); + + id++; + } + } + } + + REQUIRE(mesh->ncells() == 125); + + // Find cell neighbours + mesh->find_cell_neighbours(); + + // Create particles + id = 0; + double particle_size = 1.; + Eigen::Vector3d base_coords; + base_coords << 3.5, 3.5, 3.5; + for (unsigned k = 0; k < 4; k++) { + for (unsigned j = 0; j < 4; j++) { + for (unsigned i = 0; i < 4; i++) { + coords << double(i * particle_size), double(j * particle_size), + double(k * particle_size); + std::shared_ptr> particle = + std::make_shared>(id, base_coords + coords); + REQUIRE(mesh->add_particle(particle, false) == true); + id++; + } + } + } + + REQUIRE(mesh->nparticles() == 64); + + // Assign material to particles + mesh->iterate_over_particles( + std::bind(&mpm::ParticleBase::assign_material, std::placeholders::_1, + material, 0)); + + // Locate particles in a mesh + auto particles = mesh->locate_particles_mesh(); + + // Should find all particles in mesh + REQUIRE(particles.size() == 0); + + // Find particle neighbours + mesh->find_particle_neighbours(); + + // Initialise particle variables + // Assign particle volume + mesh->iterate_over_particles(std::bind(&mpm::ParticleBase::assign_volume, + std::placeholders::_1, 1.)); + + // Compute mass + mesh->iterate_over_particles( + std::bind(&mpm::ParticleBase::compute_mass, std::placeholders::_1)); + + // 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)); + + // 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 + mesh->iterate_over_particles( + std::bind(&mpm::ParticleBase::map_mass_momentum_to_nodes, + std::placeholders::_1)); + + // Check solutions + std::set fsc = {31, 32, 33, 36, 37, 38, 41, 42, 43, + 56, 57, 58, 61, 63, 66, 67, 68, 81, + 82, 83, 86, 87, 88, 91, 92, 93}; + std::set fsn = { + 43, 44, 45, 46, 49, 50, 51, 52, 55, 56, 57, 58, 61, 62, + 63, 64, 79, 80, 81, 82, 85, 88, 91, 94, 97, 98, 99, 100, + 115, 116, 117, 118, 121, 124, 127, 130, 133, 134, 135, 136, 151, 152, + 153, 154, 157, 158, 159, 160, 163, 164, 165, 166, 169, 170, 171, 172}; + std::set fsp = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 23, 24, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 39, 40, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63}; + + SECTION("Mesh free surface 3D by density") { + // Check initial free surface + REQUIRE(mesh->free_surface_cells().size() == 0); + REQUIRE(mesh->free_surface_nodes().size() == 0); + REQUIRE(mesh->free_surface_particles().size() == 0); + + REQUIRE(mesh->compute_free_surface_by_density(0.125) == true); + + // Check cell, node, and particle free surface + REQUIRE(mesh->free_surface_cells() == fsc); + REQUIRE(mesh->free_surface_nodes() == fsn); + REQUIRE(mesh->free_surface_particles() == fsp); + } + + SECTION("Mesh free surface 3D by geometry") { + + REQUIRE(mesh->compute_free_surface_by_geometry(0.125) == true); + + // Check cell, node, and particle free surface + REQUIRE(mesh->free_surface_cells() == fsc); + REQUIRE(mesh->free_surface_nodes() == fsn); + REQUIRE(mesh->free_surface_particles() == fsp); + + // Check particle normal vector + auto particle_normal = mesh->particles_vector_data("normals"); + for (unsigned fs_id = 0; fs_id < particle_normal.size(); fs_id++) { + if (fsp.find(fs_id) != fsp.end()) + REQUIRE(particle_normal[fs_id].norm() == + Approx(1.0).epsilon(Tolerance)); + else + REQUIRE(particle_normal[fs_id].norm() == + Approx(0.0).epsilon(Tolerance)); + } + } + + SECTION("Mesh free surface 3D") { + + std::string method = "density"; + REQUIRE(mesh->compute_free_surface(method, 0.125) == true); + + // Check cell, node, and particle free surface + REQUIRE(mesh->free_surface_cells() == fsc); + REQUIRE(mesh->free_surface_nodes() == fsn); + REQUIRE(mesh->free_surface_particles() == fsp); + + method = "geometry"; + REQUIRE(mesh->compute_free_surface(method, 0.125) == true); + + // Check cell, node, and particle free surface + REQUIRE(mesh->free_surface_cells() == fsc); + REQUIRE(mesh->free_surface_nodes() == fsn); + REQUIRE(mesh->free_surface_particles() == fsp); + + method = "other"; + REQUIRE(mesh->compute_free_surface(method, 0.125) == true); + } +} From 5abd74341a4e2c5bff3602327d7b83a802f9f5ad Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 21 Oct 2020 23:42:57 +0700 Subject: [PATCH 154/175] :construction: take id out of the while loop --- include/io/io_mesh_ascii.tcc | 68 ++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/include/io/io_mesh_ascii.tcc b/include/io/io_mesh_ascii.tcc index eb2124e4c..48c45b75b 100644 --- a/include/io/io_mesh_ascii.tcc +++ b/include/io/io_mesh_ascii.tcc @@ -313,11 +313,11 @@ std::vector> // ignore comment lines (# or !) or blank lines if ((line.find('#') == std::string::npos) && (line.find('!') == std::string::npos) && (line != "")) { + // ID + mpm::Index id; + // Pressure + double pressure; while (istream.good()) { - // ID - mpm::Index id; - // Pressure - double pressure; // Read stream istream >> id >> pressure; constraints.emplace_back(std::make_tuple(id, pressure)); @@ -357,12 +357,12 @@ std::map> // ignore comment lines (# or !) or blank lines if ((line.find('#') == std::string::npos) && (line.find('!') == std::string::npos) && (line != "")) { + // ID + mpm::Index id; + // Angles + Eigen::Matrix angles; while (istream.good()) { - // ID and read stream - mpm::Index id; istream >> id; - // Angles and ream stream - Eigen::Matrix angles; for (unsigned i = 0; i < Tdim; ++i) istream >> angles[i]; euler_angles.emplace(std::make_pair(id, angles)); } @@ -401,11 +401,11 @@ std::vector> // ignore comment lines (# or !) or blank lines if ((line.find('#') == std::string::npos) && (line.find('!') == std::string::npos) && (line != "")) { + // ID + mpm::Index id; + // Volume + double volume; while (istream.good()) { - // ID - mpm::Index id; - // Volume - double volume; // Read stream istream >> id >> volume; volumes.emplace_back(std::make_tuple(id, volume)); @@ -445,9 +445,9 @@ std::vector> // ignore comment lines (# or !) or blank lines if ((line.find('#') == std::string::npos) && (line.find('!') == std::string::npos) && (line != "")) { + // ID + mpm::Index pid, cid; while (istream.good()) { - // ID - mpm::Index pid, cid; // Read stream istream >> pid >> cid; particles_cells.emplace_back(std::array({pid, cid})); @@ -503,13 +503,13 @@ std::vector> // ignore comment lines (# or !) or blank lines if ((line.find('#') == std::string::npos) && (line.find('!') == std::string::npos) && (line != "")) { + // ID + mpm::Index id; + // Direction + unsigned dir; + // Velocity + double velocity; while (istream.good()) { - // ID - mpm::Index id; - // Direction - unsigned dir; - // Velocity - double velocity; // Read stream istream >> id >> dir >> velocity; constraints.emplace_back(std::make_tuple(id, dir, velocity)); @@ -549,15 +549,15 @@ std::vector> // ignore comment lines (# or !) or blank lines if ((line.find('#') == std::string::npos) && (line.find('!') == std::string::npos) && (line != "")) { + // ID + mpm::Index id; + // Direction + unsigned dir; + // Sign + int sign; + // Friction + double friction; while (istream.good()) { - // ID - mpm::Index id; - // Direction - unsigned dir; - // Sign - int sign; - // Friction - double friction; // Read stream istream >> id >> dir >> sign >> friction; constraints.emplace_back(std::make_tuple(id, dir, sign, friction)); @@ -596,13 +596,13 @@ std::vector> // ignore comment lines (# or !) or blank lines if ((line.find('#') == std::string::npos) && (line.find('!') == std::string::npos) && (line != "")) { + // ID + mpm::Index id; + // Direction + unsigned dir; + // Force + double force; while (istream.good()) { - // ID - mpm::Index id; - // Direction - unsigned dir; - // Force - double force; // Read stream istream >> id >> dir >> force; forces.emplace_back(std::make_tuple(id, dir, force)); From e3127d1c599685f67531f8e3e93f2baf28b5ce49 Mon Sep 17 00:00:00 2001 From: Nanda Date: Fri, 23 Oct 2020 15:35:33 +0700 Subject: [PATCH 155/175] :construction: add parallel free surface detection by density method --- include/cell.h | 10 ++- include/mesh.tcc | 124 +++++++++++++++++++++++++----- include/particles/particle_base.h | 1 + 3 files changed, 114 insertions(+), 21 deletions(-) diff --git a/include/cell.h b/include/cell.h index fef479738..0d1f1a39f 100644 --- a/include/cell.h +++ b/include/cell.h @@ -83,6 +83,12 @@ class Cell { //! Return the status of a cell: active (if a particle is present) bool status() const { return particles_.size(); } + //! Assign solving status + void assign_solving_status(bool status) { solving_status_ = status; } + + //! Return solving status + bool solving_status() const { return solving_status_; } + //! Return particles_ std::vector particles() const { return particles_; } @@ -286,6 +292,8 @@ class Cell { //! Normal of face //! first-> face_id, second->vector of the normal std::map face_normals_; + //! Solving status + bool solving_status_{false}; //! Free surface bool bool free_surface_{false}; //! Volume fraction @@ -297,4 +305,4 @@ class Cell { #include "cell.tcc" -#endif // MPM_CELL_H_ +#endif // MPM_CELL_H_ \ No newline at end of file diff --git a/include/mesh.tcc b/include/mesh.tcc index b2da78871..0d024d7e7 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -2166,10 +2166,10 @@ bool mpm::Mesh::compute_free_surface_by_geometry( } } else { // Loop over neighbouring cells - for (const auto n_id : (*citr)->neighbours()) { - if (!map_cells_[n_id]->status()) { + for (const auto neighbour_cell_id : (*citr)->neighbours()) { + if (!map_cells_[neighbour_cell_id]->status()) { candidate_cell = true; - const auto& n_node_id = map_cells_[n_id]->nodes_id(); + const auto& n_node_id = map_cells_[neighbour_cell_id]->nodes_id(); // Detect common node id std::set common_node_id; @@ -2234,8 +2234,9 @@ bool mpm::Mesh::compute_free_surface_by_geometry( 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(); + for (const auto neighbour_particle_id : neighbour_particles) { + const auto& n_coord = + map_particles_[neighbour_particle_id]->coordinates(); const VectorDim rel_coord = n_coord - p_coord; // Compute kernel gradient @@ -2271,8 +2272,9 @@ bool mpm::Mesh::compute_free_surface_by_geometry( if (!interior) { VectorDim temporary_vec; temporary_vec.setZero(); - for (const auto n_id : neighbour_particles) { - const auto& n_coord = map_particles_[n_id]->coordinates(); + for (const auto neighbour_particle_id : neighbour_particles) { + const auto& n_coord = + map_particles_[neighbour_particle_id]->coordinates(); const VectorDim rel_coord = n_coord - p_coord; // Compute kernel gradient @@ -2299,8 +2301,9 @@ bool mpm::Mesh::compute_free_surface_by_geometry( 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(); + for (const auto neighbour_particle_id : neighbour_particles) { + const auto& n_coord = + map_particles_[neighbour_particle_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; @@ -2338,6 +2341,43 @@ template bool mpm::Mesh::compute_free_surface_by_density(double volume_tolerance) { bool status = true; try { + + // Get number of MPI ranks + int mpi_rank = 0; + int mpi_size = 1; + +#ifdef USE_MPI + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + // Reset solving status + this->iterate_over_cells(std::bind(&mpm::Cell::assign_solving_status, + std::placeholders::_1, false)); + + // Initialize pointer of booleans for send and receive + bool* send_cell_solving_status = new bool[ncells()]; + memset(send_cell_solving_status, 0, ncells() * sizeof(bool)); + bool* receive_cell_solving_status = new bool[ncells()]; + + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) + if ((*citr)->status()) + // Assign solving status for MPI solver + send_cell_solving_status[(*citr)->id()] = true; + + MPI_Allreduce(send_cell_solving_status, receive_cell_solving_status, + ncells(), MPI_CXX_BOOL, MPI_LOR, MPI_COMM_WORLD); + + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + if (receive_cell_solving_status[(*citr)->id()]) { + // Assign solving status for MPI solver + (*citr)->assign_solving_status(true); + } + } + + delete[] send_cell_solving_status; + delete[] receive_cell_solving_status; +#endif + // Reset free surface cell this->iterate_over_cells(std::bind(&mpm::Cell::assign_free_surface, std::placeholders::_1, false)); @@ -2365,6 +2405,28 @@ bool mpm::Mesh::compute_free_surface_by_density(double volume_tolerance) { } } +#ifdef USE_MPI + // Initialize vector of double for send and receive + std::vector send_cell_vol_fraction; + send_cell_vol_fraction.resize(ncells()); + std::vector receive_cell_vol_fraction; + receive_cell_vol_fraction.resize(ncells()); + + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) + if ((*citr)->status()) + // Assign volume_fraction for MPI solver + send_cell_vol_fraction[(*citr)->id()] = (*citr)->volume_fraction(); + + MPI_Allreduce(send_cell_vol_fraction.data(), + receive_cell_vol_fraction.data(), ncells(), MPI_DOUBLE, + MPI_SUM, MPI_COMM_WORLD); + + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + // Assign volume_fraction for MPI solver + (*citr)->assign_volume_fraction(receive_cell_vol_fraction[(*citr)->id()]); + } +#endif + // Compute boundary cells and nodes based on geometry for (auto citr = this->cells_.cbegin(); citr != this->cells_.cend(); ++citr) { @@ -2375,11 +2437,18 @@ bool mpm::Mesh::compute_free_surface_by_density(double volume_tolerance) { bool internal = true; //! Check internal cell - for (const auto c_id : (*citr)->neighbours()) { - if (!map_cells_[c_id]->status()) { + for (const auto neighbour_cell_id : (*citr)->neighbours()) { +#if USE_MPI + if (!map_cells_[neighbour_cell_id]->solving_status()) { internal = false; break; } +#else + if (!map_cells_[neighbour_cell_id]->status()) { + internal = false; + break; + } +#endif } //! Check volume fraction only for boundary cell @@ -2390,10 +2459,12 @@ bool mpm::Mesh::compute_free_surface_by_density(double volume_tolerance) { map_nodes_[id]->assign_free_surface(cell_at_interface); } } else { - for (const auto n_id : (*citr)->neighbours()) { - if (map_cells_[n_id]->volume_fraction() < volume_tolerance) { + for (const auto neighbour_cell_id : (*citr)->neighbours()) { + if (map_cells_[neighbour_cell_id]->volume_fraction() < + volume_tolerance) { cell_at_interface = true; - const auto& n_node_id = map_cells_[n_id]->nodes_id(); + const auto& n_node_id = + map_cells_[neighbour_cell_id]->nodes_id(); // Detect common node id std::set common_node_id; @@ -2405,8 +2476,7 @@ bool mpm::Mesh::compute_free_surface_by_density(double volume_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( - cell_at_interface); + map_nodes_[common_id]->assign_free_surface(true); } } } @@ -2414,16 +2484,31 @@ bool mpm::Mesh::compute_free_surface_by_density(double volume_tolerance) { } // Assign free surface cell - if (cell_at_interface) + if (cell_at_interface) { (*citr)->assign_free_surface(cell_at_interface); + } } } } // 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)); + this->iterate_over_cells( + std::bind(&mpm::Cell::map_cell_volume_to_nodes, + std::placeholders::_1, mpm::ParticlePhase::SinglePhase)); + +#ifdef USE_MPI + // Run if there is more than a single MPI task + if (mpi_size > 1) { + // MPI all reduce nodal volume + this->template nodal_halo_exchange( + std::bind(&mpm::NodeBase::volume, std::placeholders::_1, + mpm::ParticlePhase::SinglePhase), + std::bind(&mpm::NodeBase::update_volume, std::placeholders::_1, + false, mpm::ParticlePhase::SinglePhase, + std::placeholders::_2)); + } +#endif // Compute nodal value of mass density this->iterate_over_nodes_predicate( @@ -2438,7 +2523,6 @@ bool mpm::Mesh::compute_free_surface_by_density(double volume_tolerance) { (*pitr)->assign_free_surface(status); } } - } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); } diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 62f6b4c19..7b204ed58 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -26,6 +26,7 @@ class Material; //! Particle phases enum ParticlePhase : unsigned int { + SinglePhase = 0, Solid = 0, Liquid = 1, Gas = 2, From b79e05a83baf99b10c08930b1ad563a75891bd39 Mon Sep 17 00:00:00 2001 From: Nanda Date: Fri, 23 Oct 2020 15:53:35 +0700 Subject: [PATCH 156/175] :dart: add test for illegal functions from base class make gravity const --- include/particles/particle_base.h | 2 +- include/particles/particle_twophase.h | 2 +- include/particles/particle_twophase.tcc | 2 +- tests/particles/particle_test.cc | 30 +++++++++++++++++++++++++ 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 7b204ed58..2e0b99b74 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -393,7 +393,7 @@ class ParticleBase { //! Initialise particle pore pressure by watertable virtual bool initialise_pore_pressure_watertable( - const unsigned dir_v, const unsigned dir_h, VectorDim& gravity, + const unsigned dir_v, const unsigned dir_h, const VectorDim& gravity, std::map& reference_points) { throw std::runtime_error( "Calling the base class function " diff --git a/include/particles/particle_twophase.h b/include/particles/particle_twophase.h index 44eba3c05..88c0cac61 100644 --- a/include/particles/particle_twophase.h +++ b/include/particles/particle_twophase.h @@ -107,7 +107,7 @@ class TwoPhaseParticle : public mpm::Particle { //! \param[in] reference_points //! (Horizontal coordinate of borehole + height of 0 pore pressure) bool initialise_pore_pressure_watertable( - const unsigned dir_v, const unsigned dir_h, VectorDim& gravity, + const unsigned dir_v, const unsigned dir_h, const VectorDim& gravity, std::map& reference_points); //! Update porosity diff --git a/include/particles/particle_twophase.tcc b/include/particles/particle_twophase.tcc index 35275f7b8..2e8bd6fde 100644 --- a/include/particles/particle_twophase.tcc +++ b/include/particles/particle_twophase.tcc @@ -785,7 +785,7 @@ bool mpm::TwoPhaseParticle::map_drag_force_coefficient() { //! Initial pore pressure template bool mpm::TwoPhaseParticle::initialise_pore_pressure_watertable( - const unsigned dir_v, const unsigned dir_h, VectorDim& gravity, + const unsigned dir_v, const unsigned dir_h, const VectorDim& gravity, std::map& reference_points) { bool status = true; try { diff --git a/tests/particles/particle_test.cc b/tests/particles/particle_test.cc index e39afe425..97a50f40a 100644 --- a/tests/particles/particle_test.cc +++ b/tests/particles/particle_test.cc @@ -3047,4 +3047,34 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { REQUIRE(*mitr == material_ids.at(i)); } } + + //! Check derived particle functions (expecting throws) + SECTION("Particle illegal derived functions access") { + mpm::Index id = 0; + bool status = true; + std::shared_ptr> particle = + std::make_shared>(id, coords, status); + + // Input variables + const double dt = 0.1; + Eigen::VectorXd vectordim; + vectordim.resize(Dim); + std::map reference_points; + + // Specific functions for TwoPhaseParticle. + // Expecting throws if called from Particle. + REQUIRE_THROWS(particle->update_porosity(dt)); + REQUIRE_THROWS(particle->assign_saturation_degree()); + REQUIRE_THROWS(particle->assign_liquid_velocity(vectordim)); + REQUIRE_THROWS(particle->compute_pore_pressure(dt)); + REQUIRE_THROWS(particle->map_drag_force_coefficient()); + REQUIRE_THROWS(particle->compute_pore_pressure(dt)); + REQUIRE_THROWS(particle->initialise_pore_pressure_watertable( + 1, 0, vectordim, reference_points)); + REQUIRE_THROWS(particle->assign_porosity()); + REQUIRE_THROWS(particle->assign_permeability()); + REQUIRE_THROWS(particle->liquid_mass()); + REQUIRE_THROWS(particle->liquid_velocity()); + REQUIRE_THROWS(particle->porosity()); + } } From 5763fd078be28a828537e2c73d0ed758af1e0359 Mon Sep 17 00:00:00 2001 From: Nanda Date: Fri, 23 Oct 2020 16:10:12 +0700 Subject: [PATCH 157/175] :construction: remove mass check throw --- include/node.tcc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/include/node.tcc b/include/node.tcc index 4b5ad4857..7d26cc6d2 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -596,9 +596,7 @@ void mpm::Node::compute_density() { // 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"); + } } } From c2b48f2d94a671577b91a119fc306328d5943dbe Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Fri, 23 Oct 2020 13:26:07 -0700 Subject: [PATCH 158/175] Add test file for read particle scalar properties --- tests/io/io_mesh_ascii_test.cc | 90 ++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/tests/io/io_mesh_ascii_test.cc b/tests/io/io_mesh_ascii_test.cc index 13779101b..195c2286c 100644 --- a/tests/io/io_mesh_ascii_test.cc +++ b/tests/io/io_mesh_ascii_test.cc @@ -482,6 +482,51 @@ TEST_CASE("IOMeshAscii is checked for 2D", "[IOMesh][IOMeshAscii][2D]") { } } } + + SECTION("Check particles scalar properties file") { + // Particle scalar properties + std::map particles_scalars; + particles_scalars.emplace(std::make_pair(0, 10.5)); + particles_scalars.emplace(std::make_pair(1, -40.5)); + particles_scalars.emplace(std::make_pair(2, -60.5)); + particles_scalars.emplace(std::make_pair(3, 80.5)); + + // Dump particle scalar properties as an input file to be read + std::ofstream file; + file.open("particles-scalars-2d.txt"); + // Write particle scalar properties + for (const auto& scalars : particles_scalars) { + file << scalars.first << "\t"; + file << scalars.second << "\n"; + } + + file.close(); + + // Check read particles scalar properties file + SECTION("Check read particles scalar properties file") { + // Create a io_mesh object + auto io_mesh = std::make_unique>(); + + // Try to read particles scalar properties from a non-existant file + auto read_particles_scalars = io_mesh->read_particles_scalar_properties( + "particles-scalar-missing.txt"); + // Check number of particles scalar properties + REQUIRE(read_particles_scalars.size() == 0); + + // Check particles scalar properties + read_particles_scalars = + io_mesh->read_particles_scalar_properties("particles-scalars-2d.txt"); + + // Check number of particles + REQUIRE(read_particles_scalars.size() == particles_scalars.size()); + + // Check particles scalar properties + for (unsigned i = 0; i < particles_scalars.size(); ++i) { + REQUIRE(std::get<1>(read_particles_scalars.at(i)) == + Approx(particles_scalars.at(i)).epsilon(Tolerance)); + } + } + } } // Check IOMeshAscii @@ -1003,4 +1048,49 @@ TEST_CASE("IOMeshAscii is checked for 3D", "[IOMesh][IOMeshAscii][3D]") { } } } + + SECTION("Check particles scalar properties file") { + // Particle scalar properties + std::map particles_scalars; + particles_scalars.emplace(std::make_pair(0, 10.5)); + particles_scalars.emplace(std::make_pair(1, -40.5)); + particles_scalars.emplace(std::make_pair(2, -60.5)); + particles_scalars.emplace(std::make_pair(3, 80.5)); + + // Dump particle scalar properties as an input file to be read + std::ofstream file; + file.open("particles-scalars-3d.txt"); + // Write particle scalar properties + for (const auto& scalars : particles_scalars) { + file << scalars.first << "\t"; + file << scalars.second << "\n"; + } + + file.close(); + + // Check read particles scalar properties file + SECTION("Check read particles scalar properties file") { + // Create a io_mesh object + auto io_mesh = std::make_unique>(); + + // Try to read particles scalar properties from a non-existant file + auto read_particles_scalars = io_mesh->read_particles_scalar_properties( + "particles-scalar-missing.txt"); + // Check number of particles scalar properties + REQUIRE(read_particles_scalars.size() == 0); + + // Check particles scalar properties + read_particles_scalars = + io_mesh->read_particles_scalar_properties("particles-scalars-3d.txt"); + + // Check number of particles + REQUIRE(read_particles_scalars.size() == particles_scalars.size()); + + // Check particles scalar properties + for (unsigned i = 0; i < particles_scalars.size(); ++i) { + REQUIRE(std::get<1>(read_particles_scalars.at(i)) == + Approx(particles_scalars.at(i)).epsilon(Tolerance)); + } + } + } } From 9f3cc4af286ee1a64b26c5e118100055636feae4 Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Fri, 23 Oct 2020 13:44:27 -0700 Subject: [PATCH 159/175] Add test function for read_pressure_constraints --- tests/io/io_mesh_ascii_test.cc | 106 +++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/tests/io/io_mesh_ascii_test.cc b/tests/io/io_mesh_ascii_test.cc index 195c2286c..5d5b22d7a 100644 --- a/tests/io/io_mesh_ascii_test.cc +++ b/tests/io/io_mesh_ascii_test.cc @@ -308,6 +308,59 @@ TEST_CASE("IOMeshAscii is checked for 2D", "[IOMesh][IOMeshAscii][2D]") { } } + // Check nodal pressure constraints file + SECTION("Check pressure constraints file") { + // Vector of friction constraints + std::vector> pressure_constraints; + + // Pressure constraint + pressure_constraints.emplace_back(std::make_tuple(0, 300.5)); + pressure_constraints.emplace_back(std::make_tuple(1, 500.5)); + pressure_constraints.emplace_back(std::make_tuple(2, 250.5)); + pressure_constraints.emplace_back(std::make_tuple(3, 0.0)); + + // Dump pressure constraints as an input file to be read + std::ofstream file; + file.open("pressure-constraints-2d.txt"); + // Write particle coordinates + for (const auto& pressure_constraint : pressure_constraints) { + file << std::get<0>(pressure_constraint) << "\t"; + file << std::get<1>(pressure_constraint) << "\t"; + + file << "\n"; + } + + file.close(); + + // Check read pressure constraints + SECTION("Check pressure constraints") { + // Create a read_mesh object + auto read_mesh = std::make_unique>(); + + // Try to read pressure constraints from a non-existant file + auto constraints = read_mesh->read_pressure_constraints( + "pressure-constraints-missing.txt"); + // Check number of constraints + REQUIRE(constraints.size() == 0); + + // Check constraints + constraints = + read_mesh->read_pressure_constraints("pressure-constraints-2d.txt"); + // Check number of particles + REQUIRE(constraints.size() == pressure_constraints.size()); + + // Check coordinates of nodes + for (unsigned i = 0; i < pressure_constraints.size(); ++i) { + REQUIRE( + std::get<0>(constraints.at(i)) == + Approx(std::get<0>(pressure_constraints.at(i))).epsilon(Tolerance)); + REQUIRE( + std::get<1>(constraints.at(i)) == + Approx(std::get<1>(pressure_constraints.at(i))).epsilon(Tolerance)); + } + } + } + SECTION("Check forces file") { // Vector of particle forces std::vector> nodal_forces; @@ -873,6 +926,59 @@ TEST_CASE("IOMeshAscii is checked for 3D", "[IOMesh][IOMeshAscii][3D]") { } } + // Check nodal pressure constraints file + SECTION("Check pressure constraints file") { + // Vector of friction constraints + std::vector> pressure_constraints; + + // Pressure constraint + pressure_constraints.emplace_back(std::make_tuple(0, 300.5)); + pressure_constraints.emplace_back(std::make_tuple(1, 500.5)); + pressure_constraints.emplace_back(std::make_tuple(2, 250.5)); + pressure_constraints.emplace_back(std::make_tuple(3, 0.0)); + + // Dump pressure constraints as an input file to be read + std::ofstream file; + file.open("pressure-constraints-3d.txt"); + // Write particle coordinates + for (const auto& pressure_constraint : pressure_constraints) { + file << std::get<0>(pressure_constraint) << "\t"; + file << std::get<1>(pressure_constraint) << "\t"; + + file << "\n"; + } + + file.close(); + + // Check read pressure constraints + SECTION("Check pressure constraints") { + // Create a read_mesh object + auto read_mesh = std::make_unique>(); + + // Try to read pressure constraints from a non-existant file + auto constraints = read_mesh->read_pressure_constraints( + "pressure-constraints-missing.txt"); + // Check number of constraints + REQUIRE(constraints.size() == 0); + + // Check constraints + constraints = + read_mesh->read_pressure_constraints("pressure-constraints-3d.txt"); + // Check number of particles + REQUIRE(constraints.size() == pressure_constraints.size()); + + // Check coordinates of nodes + for (unsigned i = 0; i < pressure_constraints.size(); ++i) { + REQUIRE( + std::get<0>(constraints.at(i)) == + Approx(std::get<0>(pressure_constraints.at(i))).epsilon(Tolerance)); + REQUIRE( + std::get<1>(constraints.at(i)) == + Approx(std::get<1>(pressure_constraints.at(i))).epsilon(Tolerance)); + } + } + } + SECTION("Check forces file") { // Vector of particle forces std::vector> nodal_forces; From f6022df12566b38d8bca17c2b59fbe9856f1b3e2 Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Fri, 23 Oct 2020 15:09:50 -0700 Subject: [PATCH 160/175] Add test functions for pressure constraint --- include/loads_bcs/constraints.h | 2 +- include/loads_bcs/constraints.tcc | 2 +- tests/mesh_test_2d.cc | 50 +++++++++++++++++++++++++++++++ tests/mesh_test_3d.cc | 50 +++++++++++++++++++++++++++++++ 4 files changed, 102 insertions(+), 2 deletions(-) diff --git a/include/loads_bcs/constraints.h b/include/loads_bcs/constraints.h index 23a01081d..01e72c8cf 100644 --- a/include/loads_bcs/constraints.h +++ b/include/loads_bcs/constraints.h @@ -55,7 +55,7 @@ class Constraints { //! \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); + const unsigned phase, const double pconstraint); //! Assign nodal pressure constraints to nodes //! \param[in] pressure_constraints Constraint at node, pressure diff --git a/include/loads_bcs/constraints.tcc b/include/loads_bcs/constraints.tcc index cb2d960f2..a688ae8de 100644 --- a/include/loads_bcs/constraints.tcc +++ b/include/loads_bcs/constraints.tcc @@ -110,7 +110,7 @@ bool mpm::Constraints::assign_nodal_friction_constraints( template bool mpm::Constraints::assign_nodal_pressure_constraint( const std::shared_ptr& mfunction, int set_id, - const unsigned phase, const unsigned pconstraint) { + const unsigned phase, const double pconstraint) { bool status = true; try { auto nset = mesh_->nodes(set_id); diff --git a/tests/mesh_test_2d.cc b/tests/mesh_test_2d.cc index 435c4edb4..c721b88d8 100644 --- a/tests/mesh_test_2d.cc +++ b/tests/mesh_test_2d.cc @@ -1153,6 +1153,31 @@ TEST_CASE("Mesh is checked for 2D case", "[mesh][2D]") { set_id, friction_constraint) == false); } + SECTION("Check assign pressure constraints to nodes") { + tsl::robin_map> node_sets; + node_sets[0] = std::vector{0, 2}; + node_sets[1] = std::vector{1, 3}; + + REQUIRE(mesh->create_node_sets(node_sets, true) == true); + + //! Constraints object + auto constraints = std::make_shared>(mesh); + + int set_id = 0; + double pressure = 500.2; + // Add pressure constraint to mesh + REQUIRE(constraints->assign_nodal_pressure_constraint( + mfunction, set_id, 0, pressure) == true); + REQUIRE(constraints->assign_nodal_pressure_constraint( + mfunction, set_id, 1, pressure) == true); + + // Add pressure constraint to all nodes in mesh + REQUIRE(constraints->assign_nodal_pressure_constraint( + mfunction, -1, 0, pressure) == true); + REQUIRE(constraints->assign_nodal_pressure_constraint( + mfunction, -1, 1, pressure) == true); + } + // Test assign velocity constraints to nodes SECTION("Check assign velocity constraints to nodes") { // Vector of particle coordinates @@ -1195,6 +1220,31 @@ TEST_CASE("Mesh is checked for 2D case", "[mesh][2D]") { friction_constraints) == false); } + // Test assign pressure constraints to nodes + SECTION("Check assign pressure constraints to nodes") { + // Vector of pressure constraints + std::vector> pressure_constraints; + //! Constraints object + auto constraints = std::make_shared>(mesh); + // Constraint + pressure_constraints.emplace_back(std::make_tuple(0, 500.5)); + pressure_constraints.emplace_back(std::make_tuple(1, 210.5)); + pressure_constraints.emplace_back(std::make_tuple(2, 320.2)); + pressure_constraints.emplace_back(std::make_tuple(3, 0.0)); + + REQUIRE(constraints->assign_nodal_pressure_constraints( + 0, pressure_constraints) == true); + REQUIRE(constraints->assign_nodal_pressure_constraints( + 1, pressure_constraints) == true); + // When constraints fail + REQUIRE(constraints->assign_nodal_pressure_constraints( + 4, pressure_constraints) == false); + + pressure_constraints.emplace_back(std::make_tuple(100, 0.0)); + REQUIRE(constraints->assign_nodal_pressure_constraints( + 0, pressure_constraints) == false); + } + // Test assign nodes concentrated_forces SECTION("Check assign nodes concentrated_forces") { // Vector of node coordinates diff --git a/tests/mesh_test_3d.cc b/tests/mesh_test_3d.cc index 4f67f0ba0..689f16ced 100644 --- a/tests/mesh_test_3d.cc +++ b/tests/mesh_test_3d.cc @@ -1219,6 +1219,31 @@ TEST_CASE("Mesh is checked for 3D case", "[mesh][3D]") { set_id, velocity_constraint) == false); } + SECTION("Check assign pressure constraints to nodes") { + tsl::robin_map> node_sets; + node_sets[0] = std::vector{0, 2}; + node_sets[1] = std::vector{1, 3}; + + REQUIRE(mesh->create_node_sets(node_sets, true) == true); + + //! Constraints object + auto constraints = std::make_shared>(mesh); + + int set_id = 0; + double pressure = 500.2; + // Add pressure constraint to mesh + REQUIRE(constraints->assign_nodal_pressure_constraint( + mfunction, set_id, 0, pressure) == true); + REQUIRE(constraints->assign_nodal_pressure_constraint( + mfunction, set_id, 1, pressure) == true); + + // Add pressure constraint to all nodes in mesh + REQUIRE(constraints->assign_nodal_pressure_constraint( + mfunction, -1, 0, pressure) == true); + REQUIRE(constraints->assign_nodal_pressure_constraint( + mfunction, -1, 1, pressure) == true); + } + SECTION("Check assign friction constraints to nodes") { tsl::robin_map> node_sets; node_sets[0] = std::vector{0, 2}; @@ -1306,6 +1331,31 @@ TEST_CASE("Mesh is checked for 3D case", "[mesh][3D]") { friction_constraints) == false); } + // Test assign pressure constraints to nodes + SECTION("Check assign pressure constraints to nodes") { + // Vector of pressure constraints + std::vector> pressure_constraints; + //! Constraints object + auto constraints = std::make_shared>(mesh); + // Constraint + pressure_constraints.emplace_back(std::make_tuple(0, 500.5)); + pressure_constraints.emplace_back(std::make_tuple(1, 210.5)); + pressure_constraints.emplace_back(std::make_tuple(2, 320.2)); + pressure_constraints.emplace_back(std::make_tuple(3, 0.0)); + + REQUIRE(constraints->assign_nodal_pressure_constraints( + 0, pressure_constraints) == true); + REQUIRE(constraints->assign_nodal_pressure_constraints( + 1, pressure_constraints) == true); + // When constraints fail + REQUIRE(constraints->assign_nodal_pressure_constraints( + 4, pressure_constraints) == false); + + pressure_constraints.emplace_back(std::make_tuple(100, 0.0)); + REQUIRE(constraints->assign_nodal_pressure_constraints( + 0, pressure_constraints) == false); + } + // Test assign nodes concentrated_forces SECTION("Check assign nodes concentrated_forces") { // Vector of node coordinates From 1b34a27bb9ed2e0b7757b1d45354a6a183905a76 Mon Sep 17 00:00:00 2001 From: Nanda Date: Thu, 29 Oct 2020 16:17:47 +0700 Subject: [PATCH 161/175] :construction: :dart: modify write mesh particle --- tests/io/write_mesh_particles.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/io/write_mesh_particles.cc b/tests/io/write_mesh_particles.cc index c7f5daeec..7d9b8aea6 100644 --- a/tests/io/write_mesh_particles.cc +++ b/tests/io/write_mesh_particles.cc @@ -214,6 +214,10 @@ bool write_json_twophase(unsigned dim, bool resume, const std::string& analysis, {{"type", analysis}, {"mpm_scheme", mpm_scheme}, {"locate_particles", true}, + {"pressure_smoothing", true}, + {"pore_pressure_smoothing", true}, + {"free_surface_detection", + {{"type", "density"}, {"volume_tolerance", 0.25}}}, {"dt", 0.0001}, {"uuid", file_name + "-" + dimension}, {"nsteps", 10}, From ad851bfede223c8bcd616babd4b4f6f72ba7106c Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Tue, 3 Nov 2020 11:29:47 -0800 Subject: [PATCH 162/175] Change the density tolerance --- include/node.tcc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/node.tcc b/include/node.tcc index 7d26cc6d2..e4840f1a0 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -595,7 +595,7 @@ void mpm::Node::compute_density() { 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.; + if (std::abs(density_(phase)) < tolerance) density_(phase) = 0.; } } } From ae2b6fe4ae898aa90705e3f13ea3aeec716f77bb Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 4 Nov 2020 12:40:35 +0700 Subject: [PATCH 163/175] :construction: correct some suggestions --- include/cell.tcc | 2 +- include/node.tcc | 21 ++++++++++----------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/include/cell.tcc b/include/cell.tcc index 43b9da653..2bbbc5731 100644 --- a/include/cell.tcc +++ b/include/cell.tcc @@ -850,7 +850,7 @@ template void mpm::Cell::map_cell_volume_to_nodes(unsigned phase) { if (this->status()) { // Check if cell volume is set - if (volume_ == std::numeric_limits::lowest()) + if (volume_ <= std::numeric_limits::lowest()) this->compute_volume(); for (unsigned i = 0; i < nodes_.size(); ++i) { diff --git a/include/node.tcc b/include/node.tcc index e4840f1a0..d819cd9f2 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -183,17 +183,16 @@ bool mpm::Node::assign_pressure_constraint( bool status = true; try { // Constrain directions can take values between 0 and Tnphases - if (phase < Tnphases * 2) { - 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"); + assert(phase < Tnphases * 2); + + 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))); } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); From b8a7d89ccd7c6c7756e57494c6467850f4b67a7d Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 4 Nov 2020 16:28:45 +0700 Subject: [PATCH 164/175] :construction: move multiphase functions outside mesh.tcc --- include/mesh.h | 27 +- include/mesh.tcc | 495 ------------------------------------ include/mesh_multiphase.tcc | 494 +++++++++++++++++++++++++++++++++++ 3 files changed, 515 insertions(+), 501 deletions(-) create mode 100644 include/mesh_multiphase.tcc diff --git a/include/mesh.h b/include/mesh.h index 00869f585..3a31fb75b 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -481,7 +481,19 @@ class Mesh { //! Inject particles void inject_particles(double current_time); + // Create the nodal properties' map + void create_nodal_properties(); + + // Initialise the nodal properties' map + void initialise_nodal_properties(); + + /** + * \defgroup MultiPhase Functions dealing with multi-phase MPM + */ + /**@{*/ + //! Compute free surface + //! \ingroup MultiPhase //! \param[in] method Type of method to use //! \param[in] volume_tolerance for volume_fraction approach //! \retval status Status of compute_free_surface @@ -490,6 +502,7 @@ class Mesh { double volume_tolerance = std::numeric_limits::epsilon()); //! Compute free surface by density method + //! \ingroup MultiPhase //! \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. @@ -499,6 +512,7 @@ class Mesh { double volume_tolerance = std::numeric_limits::epsilon()); //! Compute free surface by geometry method + //! \ingroup MultiPhase //! \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 @@ -510,30 +524,30 @@ class Mesh { double volume_tolerance = std::numeric_limits::epsilon()); //! Get free surface node set + //! \ingroup MultiPhase //! \retval id_set Set of free surface node ids std::set free_surface_nodes(); //! Get free surface cell set + //! \ingroup MultiPhase //! \retval id_set Set of free surface cell ids std::set free_surface_cells(); //! Get free surface particle set + //! \ingroup MultiPhase //! \retval status Status of compute_free_surface //! \retval id_set Set of free surface particle ids std::set free_surface_particles(); - // Create the nodal properties' map - void create_nodal_properties(); - - // Initialise the nodal properties' map - void initialise_nodal_properties(); - //! Assign particles pore pressures + //! \ingroup MultiPhase //! \param[in] particle_pore_pressure Initial pore pressure of particle bool assign_particles_pore_pressures( const std::vector>& particle_pore_pressures); + /**@}*/ + private: // Read particles from file //! \param[in] pset_id Set ID of the particles @@ -606,5 +620,6 @@ class Mesh { } // namespace mpm #include "mesh.tcc" +#include "mesh_multiphase.tcc" #endif // MPM_MESH_H_ diff --git a/include/mesh.tcc b/include/mesh.tcc index 0d024d7e7..7411235c5 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -2092,504 +2092,9 @@ void mpm::Mesh::create_nodal_properties() { } } -//! Compute free surface cells, nodes, and particles -template -bool mpm::Mesh::compute_free_surface(const 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 - 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)); - - // 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(); - ++citr) { - // Cell contains particles - if ((*citr)->status()) { - bool candidate_cell = false; - const auto& node_id = (*citr)->nodes_id(); - if ((*citr)->volume_fraction() < volume_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 neighbour_cell_id : (*citr)->neighbours()) { - if (!map_cells_[neighbour_cell_id]->status()) { - candidate_cell = true; - const auto& n_node_id = map_cells_[neighbour_cell_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); - } - } - } - } - } - - // Assign free surface cell - if (candidate_cell) { - (*citr)->assign_free_surface(true); - free_surface_candidate_cells.insert((*citr)->id()); - } - } - } - - // Compute particle neighbours for particles at candidate cells - std::vector free_surface_candidate_particles_first; - 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_first.insert( - free_surface_candidate_particles_first.end(), particle_ids.begin(), - 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_first) { - const auto& particle = map_particles_[p_id]; - status = particle->compute_free_surface_by_density(); - if (status) free_surface_candidate_particles_second.insert(p_id); - } - - // Find free surface particles through geometry - for (const auto p_id : free_surface_candidate_particles_second) { - // Initialize renormalization matrix - Eigen::Matrix renormalization_matrix_inv; - renormalization_matrix_inv.setZero(); - - // Loop over neighbours - 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 neighbour_particle_id : neighbour_particles) { - const auto& n_coord = - map_particles_[neighbour_particle_id]->coordinates(); - const VectorDim rel_coord = n_coord - p_coord; - - // Compute kernel gradient - const VectorDim kernel_gradient = - mpm::RadialBasisFunction::gradient(smoothing_length, - -rel_coord, "gaussian"); - - // Inverse of renormalization matrix B - renormalization_matrix_inv += - (particle->mass() / particle->mass_density()) * kernel_gradient * - rel_coord.transpose(); - } - - // 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 = true; - else if (lambda > 0.2 && lambda <= 0.75) - secondary_check = true; - else - interior = true; - - // Compute numerical normal vector - VectorDim normal; - normal.setZero(); - if (!interior) { - VectorDim temporary_vec; - temporary_vec.setZero(); - for (const auto neighbour_particle_id : neighbour_particles) { - const auto& n_coord = - map_particles_[neighbour_particle_id]->coordinates(); - const VectorDim rel_coord = n_coord - p_coord; - - // Compute kernel gradient - 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 = -renormalization_matrix_inv.inverse() * temporary_vec; - if (normal.norm() > std::numeric_limits::epsilon()) - normal.normalize(); - else - normal.setZero(); - } - - // 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 neighbour_particle_id : neighbour_particles) { - const auto& n_coord = - map_particles_[neighbour_particle_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) { - particle->assign_free_surface(true); - particle->assign_normal(normal); - } - } - } 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 { - - // Get number of MPI ranks - int mpi_rank = 0; - int mpi_size = 1; - -#ifdef USE_MPI - MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); - MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); - - // Reset solving status - this->iterate_over_cells(std::bind(&mpm::Cell::assign_solving_status, - std::placeholders::_1, false)); - - // Initialize pointer of booleans for send and receive - bool* send_cell_solving_status = new bool[ncells()]; - memset(send_cell_solving_status, 0, ncells() * sizeof(bool)); - bool* receive_cell_solving_status = new bool[ncells()]; - - for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) - if ((*citr)->status()) - // Assign solving status for MPI solver - send_cell_solving_status[(*citr)->id()] = true; - - MPI_Allreduce(send_cell_solving_status, receive_cell_solving_status, - ncells(), MPI_CXX_BOOL, MPI_LOR, MPI_COMM_WORLD); - - for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { - if (receive_cell_solving_status[(*citr)->id()]) { - // Assign solving status for MPI solver - (*citr)->assign_solving_status(true); - } - } - - delete[] send_cell_solving_status; - delete[] receive_cell_solving_status; -#endif - - // 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); - } - } - -#ifdef USE_MPI - // Initialize vector of double for send and receive - std::vector send_cell_vol_fraction; - send_cell_vol_fraction.resize(ncells()); - std::vector receive_cell_vol_fraction; - receive_cell_vol_fraction.resize(ncells()); - - for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) - if ((*citr)->status()) - // Assign volume_fraction for MPI solver - send_cell_vol_fraction[(*citr)->id()] = (*citr)->volume_fraction(); - - MPI_Allreduce(send_cell_vol_fraction.data(), - receive_cell_vol_fraction.data(), ncells(), MPI_DOUBLE, - MPI_SUM, MPI_COMM_WORLD); - - for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { - // Assign volume_fraction for MPI solver - (*citr)->assign_volume_fraction(receive_cell_vol_fraction[(*citr)->id()]); - } -#endif - - // Compute boundary cells and nodes based on geometry - 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 neighbour_cell_id : (*citr)->neighbours()) { -#if USE_MPI - if (!map_cells_[neighbour_cell_id]->solving_status()) { - internal = false; - break; - } -#else - if (!map_cells_[neighbour_cell_id]->status()) { - internal = false; - break; - } -#endif - } - - //! 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); - } - } else { - for (const auto neighbour_cell_id : (*citr)->neighbours()) { - if (map_cells_[neighbour_cell_id]->volume_fraction() < - volume_tolerance) { - cell_at_interface = true; - const auto& n_node_id = - map_cells_[neighbour_cell_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); - } - } - } - } - } - - // Assign free surface cell - if (cell_at_interface) { - (*citr)->assign_free_surface(cell_at_interface); - } - } - } - } - - // 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, mpm::ParticlePhase::SinglePhase)); - -#ifdef USE_MPI - // Run if there is more than a single MPI task - if (mpi_size > 1) { - // MPI all reduce nodal volume - this->template nodal_halo_exchange( - std::bind(&mpm::NodeBase::volume, std::placeholders::_1, - mpm::ParticlePhase::SinglePhase), - std::bind(&mpm::NodeBase::update_volume, std::placeholders::_1, - false, mpm::ParticlePhase::SinglePhase, - std::placeholders::_2)); - } -#endif - - // 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 - 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); - } - } - } 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; -} - // Initialise the nodal properties' map template void mpm::Mesh::initialise_nodal_properties() { // Call initialise_properties function from the nodal properties nodal_properties_->initialise_nodal_properties(); -} - -//! Assign particle pore pressures -template -bool mpm::Mesh::assign_particles_pore_pressures( - const std::vector>& - particle_pore_pressures) { - bool status = true; - - try { - if (!particles_.size()) - throw std::runtime_error( - "No particles have been assigned in mesh, cannot assign pore " - "pressures"); - - for (const auto& particle_pore_pressure : particle_pore_pressures) { - // Particle id - mpm::Index pid = std::get<0>(particle_pore_pressure); - // Pore pressure - double pore_pressure = std::get<1>(particle_pore_pressure); - - if (map_particles_.find(pid) != map_particles_.end()) - map_particles_[pid]->assign_pressure(pore_pressure, - mpm::ParticlePhase::Liquid); - } - } 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/mesh_multiphase.tcc b/include/mesh_multiphase.tcc new file mode 100644 index 000000000..4a5b0a830 --- /dev/null +++ b/include/mesh_multiphase.tcc @@ -0,0 +1,494 @@ +//! Compute free surface cells, nodes, and particles +template +bool mpm::Mesh::compute_free_surface(const 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 + 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)); + + // 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(); + ++citr) { + // Cell contains particles + if ((*citr)->status()) { + bool candidate_cell = false; + const auto& node_id = (*citr)->nodes_id(); + if ((*citr)->volume_fraction() < volume_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 neighbour_cell_id : (*citr)->neighbours()) { + if (!map_cells_[neighbour_cell_id]->status()) { + candidate_cell = true; + const auto& n_node_id = map_cells_[neighbour_cell_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); + } + } + } + } + } + + // Assign free surface cell + if (candidate_cell) { + (*citr)->assign_free_surface(true); + free_surface_candidate_cells.insert((*citr)->id()); + } + } + } + + // Compute particle neighbours for particles at candidate cells + std::vector free_surface_candidate_particles_first; + 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_first.insert( + free_surface_candidate_particles_first.end(), particle_ids.begin(), + 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_first) { + const auto& particle = map_particles_[p_id]; + status = particle->compute_free_surface_by_density(); + if (status) free_surface_candidate_particles_second.insert(p_id); + } + + // Find free surface particles through geometry + for (const auto p_id : free_surface_candidate_particles_second) { + // Initialize renormalization matrix + Eigen::Matrix renormalization_matrix_inv; + renormalization_matrix_inv.setZero(); + + // Loop over neighbours + 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 neighbour_particle_id : neighbour_particles) { + const auto& n_coord = + map_particles_[neighbour_particle_id]->coordinates(); + const VectorDim rel_coord = n_coord - p_coord; + + // Compute kernel gradient + const VectorDim kernel_gradient = + mpm::RadialBasisFunction::gradient(smoothing_length, + -rel_coord, "gaussian"); + + // Inverse of renormalization matrix B + renormalization_matrix_inv += + (particle->mass() / particle->mass_density()) * kernel_gradient * + rel_coord.transpose(); + } + + // 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 = true; + else if (lambda > 0.2 && lambda <= 0.75) + secondary_check = true; + else + interior = true; + + // Compute numerical normal vector + VectorDim normal; + normal.setZero(); + if (!interior) { + VectorDim temporary_vec; + temporary_vec.setZero(); + for (const auto neighbour_particle_id : neighbour_particles) { + const auto& n_coord = + map_particles_[neighbour_particle_id]->coordinates(); + const VectorDim rel_coord = n_coord - p_coord; + + // Compute kernel gradient + 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 = -renormalization_matrix_inv.inverse() * temporary_vec; + if (normal.norm() > std::numeric_limits::epsilon()) + normal.normalize(); + else + normal.setZero(); + } + + // 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 neighbour_particle_id : neighbour_particles) { + const auto& n_coord = + map_particles_[neighbour_particle_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) { + particle->assign_free_surface(true); + particle->assign_normal(normal); + } + } + } 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 { + + // Get number of MPI ranks + int mpi_rank = 0; + int mpi_size = 1; + +#ifdef USE_MPI + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + // Reset solving status + this->iterate_over_cells(std::bind(&mpm::Cell::assign_solving_status, + std::placeholders::_1, false)); + + // Initialize pointer of booleans for send and receive + bool* send_cell_solving_status = new bool[ncells()]; + memset(send_cell_solving_status, 0, ncells() * sizeof(bool)); + bool* receive_cell_solving_status = new bool[ncells()]; + + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) + if ((*citr)->status()) + // Assign solving status for MPI solver + send_cell_solving_status[(*citr)->id()] = true; + + MPI_Allreduce(send_cell_solving_status, receive_cell_solving_status, + ncells(), MPI_CXX_BOOL, MPI_LOR, MPI_COMM_WORLD); + + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + if (receive_cell_solving_status[(*citr)->id()]) { + // Assign solving status for MPI solver + (*citr)->assign_solving_status(true); + } + } + + delete[] send_cell_solving_status; + delete[] receive_cell_solving_status; +#endif + + // 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); + } + } + +#ifdef USE_MPI + // Initialize vector of double for send and receive + std::vector send_cell_vol_fraction; + send_cell_vol_fraction.resize(ncells()); + std::vector receive_cell_vol_fraction; + receive_cell_vol_fraction.resize(ncells()); + + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) + if ((*citr)->status()) + // Assign volume_fraction for MPI solver + send_cell_vol_fraction[(*citr)->id()] = (*citr)->volume_fraction(); + + MPI_Allreduce(send_cell_vol_fraction.data(), + receive_cell_vol_fraction.data(), ncells(), MPI_DOUBLE, + MPI_SUM, MPI_COMM_WORLD); + + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + // Assign volume_fraction for MPI solver + (*citr)->assign_volume_fraction(receive_cell_vol_fraction[(*citr)->id()]); + } +#endif + + // Compute boundary cells and nodes based on geometry + 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 neighbour_cell_id : (*citr)->neighbours()) { +#if USE_MPI + if (!map_cells_[neighbour_cell_id]->solving_status()) { + internal = false; + break; + } +#else + if (!map_cells_[neighbour_cell_id]->status()) { + internal = false; + break; + } +#endif + } + + //! 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); + } + } else { + for (const auto neighbour_cell_id : (*citr)->neighbours()) { + if (map_cells_[neighbour_cell_id]->volume_fraction() < + volume_tolerance) { + cell_at_interface = true; + const auto& n_node_id = + map_cells_[neighbour_cell_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); + } + } + } + } + } + + // Assign free surface cell + if (cell_at_interface) { + (*citr)->assign_free_surface(cell_at_interface); + } + } + } + } + + // 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, mpm::ParticlePhase::SinglePhase)); + +#ifdef USE_MPI + // Run if there is more than a single MPI task + if (mpi_size > 1) { + // MPI all reduce nodal volume + this->template nodal_halo_exchange( + std::bind(&mpm::NodeBase::volume, std::placeholders::_1, + mpm::ParticlePhase::SinglePhase), + std::bind(&mpm::NodeBase::update_volume, std::placeholders::_1, + false, mpm::ParticlePhase::SinglePhase, + std::placeholders::_2)); + } +#endif + + // 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 + 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); + } + } + } 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; +} + +//! Assign particle pore pressures +template +bool mpm::Mesh::assign_particles_pore_pressures( + const std::vector>& + particle_pore_pressures) { + bool status = true; + + try { + if (!particles_.size()) + throw std::runtime_error( + "No particles have been assigned in mesh, cannot assign pore " + "pressures"); + + for (const auto& particle_pore_pressure : particle_pore_pressures) { + // Particle id + mpm::Index pid = std::get<0>(particle_pore_pressure); + // Pore pressure + double pore_pressure = std::get<1>(particle_pore_pressure); + + if (map_particles_.find(pid) != map_particles_.end()) + map_particles_[pid]->assign_pressure(pore_pressure, + mpm::ParticlePhase::Liquid); + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} \ No newline at end of file From ae92ec076608a369c3752aae10887aacb2747de7 Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 4 Nov 2020 16:29:03 +0700 Subject: [PATCH 165/175] :construction: add groups in cell and node functions --- include/cell.h | 28 ++++++++++++++++++++++------ include/node.h | 13 +++++++++++-- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/include/cell.h b/include/cell.h index 0d1f1a39f..ae52573fa 100644 --- a/include/cell.h +++ b/include/cell.h @@ -83,12 +83,6 @@ class Cell { //! Return the status of a cell: active (if a particle is present) bool status() const { return particles_.size(); } - //! Assign solving status - void assign_solving_status(bool status) { solving_status_ = status; } - - //! Return solving status - bool solving_status() const { return solving_status_; } - //! Return particles_ std::vector particles() const { return particles_; } @@ -223,28 +217,50 @@ class Cell { //! Return previous mpi rank unsigned previous_mpirank() const; + /** + * \defgroup MultiPhase Functions dealing with multi-phase MPM + */ + /**@{*/ + + //! Assign solving status + //! \ingroup MultiPhase + //! \param[in] status Cell solving status for parallel free-surface detection + void assign_solving_status(bool status) { solving_status_ = status; } + + //! Return solving status of a cell: active (if a particle is present in all + //! MPI rank) + //! \ingroup MultiPhase + bool solving_status() const { return solving_status_; } + //! Assign free surface + //! \ingroup MultiPhase //! \param[in] free_surface boolean indicating free surface cell void assign_free_surface(bool free_surface) { free_surface_ = free_surface; }; //! Return free surface bool + //! \ingroup MultiPhase //! \retval free_surface_ indicating free surface cell bool free_surface() const { return free_surface_; }; //! Assign volume traction to node + //! \ingroup MultiPhase //! \param[in] volume_fraction cell volume fraction void assign_volume_fraction(double volume_fraction) { volume_fraction_ = volume_fraction; }; //! Return cell volume fraction + //! \ingroup MultiPhase //! \retval volume_fraction_ cell volume fraction double volume_fraction() const { return volume_fraction_; }; //! Map cell volume to the nodes + //! \ingroup MultiPhase //! \param[in] phase to map volume void map_cell_volume_to_nodes(unsigned phase); + /**@}*/ + private: //! Approximately check if a point is in a cell //! \param[in] point Coordinates of point diff --git a/include/node.h b/include/node.h index f3fee8da9..d5db61c62 100644 --- a/include/node.h +++ b/include/node.h @@ -294,8 +294,13 @@ class Node : public NodeBase { //! Compute multimaterial normal unit vector void compute_multimaterial_normal_unit_vector() override; - //! TwoPhase functions-------------------------------------------------------- + /** + * \defgroup TwoPhase Functions dealing with two-phase MPM + */ + /**@{*/ + //! Update internal force (body force / traction force) + //! \ingroup TwoPhase //! \param[in] update A boolean to update (true) or assign (false) //! \param[in] drag_force Drag force from the particles in a cell //! \retval status Update status @@ -303,21 +308,25 @@ class Node : public NodeBase { const VectorDim& drag_force) override; //! Compute acceleration and velocity for two phase + //! \ingroup TwoPhase //! \param[in] dt Timestep in analysis bool compute_acceleration_velocity_twophase_explicit( double dt) noexcept override; //! Compute acceleration and velocity for two phase with cundall damping + //! \ingroup TwoPhase //! \param[in] dt Timestep in analysis \param[in] damping_factor //! Damping factor bool compute_acceleration_velocity_twophase_explicit_cundall( double dt, double damping_factor) noexcept override; //! Return drag force at a given node + //! \ingroup TwoPhase VectorDim drag_force_coefficient() const override { return drag_force_coefficient_; } - //---------------------------------------------------------------------------- + + /**@}*/ private: //! Mutex From 62e065ccab8bdf786b87db6bb78e867774857baf Mon Sep 17 00:00:00 2001 From: Nanda Date: Wed, 4 Nov 2020 16:29:22 +0700 Subject: [PATCH 166/175] :dart: modify test to fix error in assertion --- tests/mesh_test_2d.cc | 7 ------- tests/mesh_test_3d.cc | 7 ------- 2 files changed, 14 deletions(-) diff --git a/tests/mesh_test_2d.cc b/tests/mesh_test_2d.cc index c721b88d8..bdff4cad1 100644 --- a/tests/mesh_test_2d.cc +++ b/tests/mesh_test_2d.cc @@ -1236,13 +1236,6 @@ TEST_CASE("Mesh is checked for 2D case", "[mesh][2D]") { 0, pressure_constraints) == true); REQUIRE(constraints->assign_nodal_pressure_constraints( 1, pressure_constraints) == true); - // When constraints fail - REQUIRE(constraints->assign_nodal_pressure_constraints( - 4, pressure_constraints) == false); - - pressure_constraints.emplace_back(std::make_tuple(100, 0.0)); - REQUIRE(constraints->assign_nodal_pressure_constraints( - 0, pressure_constraints) == false); } // Test assign nodes concentrated_forces diff --git a/tests/mesh_test_3d.cc b/tests/mesh_test_3d.cc index 689f16ced..3b7a80b74 100644 --- a/tests/mesh_test_3d.cc +++ b/tests/mesh_test_3d.cc @@ -1347,13 +1347,6 @@ TEST_CASE("Mesh is checked for 3D case", "[mesh][3D]") { 0, pressure_constraints) == true); REQUIRE(constraints->assign_nodal_pressure_constraints( 1, pressure_constraints) == true); - // When constraints fail - REQUIRE(constraints->assign_nodal_pressure_constraints( - 4, pressure_constraints) == false); - - pressure_constraints.emplace_back(std::make_tuple(100, 0.0)); - REQUIRE(constraints->assign_nodal_pressure_constraints( - 0, pressure_constraints) == false); } // Test assign nodes concentrated_forces From 32f1c5a98d5689f54730d70a6b3e5d9006637321 Mon Sep 17 00:00:00 2001 From: Nanda Date: Thu, 5 Nov 2020 00:03:06 +0700 Subject: [PATCH 167/175] :construction: :dart: change nPhase to NPhase in nodes --- include/node.tcc | 2 +- include/node_base.h | 8 +- include/node_twophase.tcc | 92 +- include/solvers/mpm_explicit_twophase.tcc | 32 +- tests/nodes/node_test.cc | 18 +- tests/nodes/node_twophase_test.cc | 996 +++++++++++----------- tests/particles/particle_twophase_test.cc | 70 +- 7 files changed, 609 insertions(+), 609 deletions(-) diff --git a/include/node.tcc b/include/node.tcc index d819cd9f2..2fd2bb162 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -625,7 +625,7 @@ void mpm::Node momentum = property_handle_->property("momenta", prop_id_, *mitr, Tdim); const Eigen::Matrix change_in_momenta = - velocity_.col(mpm::NodePhase::nSolid) * mass - momentum; + velocity_.col(mpm::NodePhase::NSolid) * mass - momentum; property_handle_->update_property("change_in_momenta", prop_id_, *mitr, change_in_momenta, Tdim); } diff --git a/include/node_base.h b/include/node_base.h index baae25e1a..b8e206835 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -19,10 +19,10 @@ namespace mpm { //! Particle phases enum NodePhase : unsigned int { - nSolid = 0, - nLiquid = 1, - nGas = 2, - nMixture = 0 + NSolid = 0, + NLiquid = 1, + NGas = 2, + NMixture = 0 }; //! NodeBase base class for nodes diff --git a/include/node_twophase.tcc b/include/node_twophase.tcc index 3d153a0eb..d1f6f033e 100644 --- a/include/node_twophase.tcc +++ b/include/node_twophase.tcc @@ -19,26 +19,26 @@ bool mpm::Node:: compute_acceleration_velocity_twophase_explicit(double dt) noexcept { bool status = false; const double tolerance = 1.0E-15; - if (this->mass(mpm::NodePhase::nSolid) > tolerance && - this->mass(mpm::NodePhase::nLiquid) > tolerance) { + if (this->mass(mpm::NodePhase::NSolid) > tolerance && + this->mass(mpm::NodePhase::NLiquid) > tolerance) { // Compute drag force VectorDim drag_force = drag_force_coefficient_.cwiseProduct( - velocity_.col(mpm::NodePhase::nLiquid) - - velocity_.col(mpm::NodePhase::nSolid)); + velocity_.col(mpm::NodePhase::NLiquid) - + velocity_.col(mpm::NodePhase::NSolid)); // Acceleration of pore fluid (momentume balance of fluid phase) - this->acceleration_.col(mpm::NodePhase::nLiquid) = - (this->external_force_.col(mpm::NodePhase::nLiquid) + - this->internal_force_.col(mpm::NodePhase::nLiquid) - drag_force) / - this->mass_(mpm::NodePhase::nLiquid); + this->acceleration_.col(mpm::NodePhase::NLiquid) = + (this->external_force_.col(mpm::NodePhase::NLiquid) + + this->internal_force_.col(mpm::NodePhase::NLiquid) - drag_force) / + this->mass_(mpm::NodePhase::NLiquid); // Acceleration of solid skeleton (momentume balance of mixture) - this->acceleration_.col(mpm::NodePhase::nSolid) = - (this->external_force_.col(mpm::NodePhase::nMixture) + - this->internal_force_.col(mpm::NodePhase::nMixture) - - this->mass_(mpm::NodePhase::nLiquid) * - this->acceleration_.col(mpm::NodePhase::nLiquid)) / - this->mass_(mpm::NodePhase::nSolid); + this->acceleration_.col(mpm::NodePhase::NSolid) = + (this->external_force_.col(mpm::NodePhase::NMixture) + + this->internal_force_.col(mpm::NodePhase::NMixture) - + this->mass_(mpm::NodePhase::NLiquid) * + this->acceleration_.col(mpm::NodePhase::NLiquid)) / + this->mass_(mpm::NodePhase::NSolid); // Apply friction constraints this->apply_friction_constraints(dt); @@ -52,14 +52,14 @@ bool mpm::Node:: // Set a threshold for (unsigned i = 0; i < Tdim; ++i) { - if (std::abs(velocity_.col(mpm::NodePhase::nSolid)(i)) < tolerance) - velocity_.col(mpm::NodePhase::nSolid)(i) = 0.; - if (std::abs(acceleration_.col(mpm::NodePhase::nSolid)(i)) < tolerance) - acceleration_.col(mpm::NodePhase::nSolid)(i) = 0.; - if (std::abs(velocity_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) - velocity_.col(mpm::NodePhase::nLiquid)(i) = 0.; - if (std::abs(acceleration_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) - acceleration_.col(mpm::NodePhase::nLiquid)(i) = 0.; + if (std::abs(velocity_.col(mpm::NodePhase::NSolid)(i)) < tolerance) + velocity_.col(mpm::NodePhase::NSolid)(i) = 0.; + if (std::abs(acceleration_.col(mpm::NodePhase::NSolid)(i)) < tolerance) + acceleration_.col(mpm::NodePhase::NSolid)(i) = 0.; + if (std::abs(velocity_.col(mpm::NodePhase::NLiquid)(i)) < tolerance) + velocity_.col(mpm::NodePhase::NLiquid)(i) = 0.; + if (std::abs(acceleration_.col(mpm::NodePhase::NLiquid)(i)) < tolerance) + acceleration_.col(mpm::NodePhase::NLiquid)(i) = 0.; } status = true; } @@ -74,36 +74,36 @@ bool mpm::Node:: bool status = false; const double tolerance = 1.0E-15; - if (this->mass(mpm::NodePhase::nSolid) > tolerance && - this->mass(mpm::NodePhase::nLiquid) > tolerance) { + if (this->mass(mpm::NodePhase::NSolid) > tolerance && + this->mass(mpm::NodePhase::NLiquid) > tolerance) { // Compute drag force VectorDim drag_force = drag_force_coefficient_.cwiseProduct( - velocity_.col(mpm::NodePhase::nLiquid) - - velocity_.col(mpm::NodePhase::nSolid)); + velocity_.col(mpm::NodePhase::NLiquid) - + velocity_.col(mpm::NodePhase::NSolid)); // Unbalanced force of liquid phase auto unbalanced_force_liquid = - this->external_force_.col(mpm::NodePhase::nLiquid) + - this->internal_force_.col(mpm::NodePhase::nLiquid) - drag_force; + this->external_force_.col(mpm::NodePhase::NLiquid) + + this->internal_force_.col(mpm::NodePhase::NLiquid) - drag_force; // Acceleration of liquid phase (momentume balance of fluid phase) - this->acceleration_.col(mpm::NodePhase::nLiquid) = + this->acceleration_.col(mpm::NodePhase::NLiquid) = (unbalanced_force_liquid - damping_factor * unbalanced_force_liquid.norm() * - this->velocity_.col(mpm::NodePhase::nLiquid).cwiseSign()) / - this->mass(mpm::NodePhase::nLiquid); + this->velocity_.col(mpm::NodePhase::NLiquid).cwiseSign()) / + this->mass(mpm::NodePhase::NLiquid); // Unbalanced force of solid phase auto unbalanced_force_solid = - this->external_force_.col(mpm::NodePhase::nMixture) + - this->internal_force_.col(mpm::NodePhase::nMixture) - - this->mass_(mpm::NodePhase::nLiquid) * - this->acceleration_.col(mpm::NodePhase::nLiquid); + this->external_force_.col(mpm::NodePhase::NMixture) + + this->internal_force_.col(mpm::NodePhase::NMixture) - + this->mass_(mpm::NodePhase::NLiquid) * + this->acceleration_.col(mpm::NodePhase::NLiquid); // Acceleration of solid phase (momentume balance of mixture) - this->acceleration_.col(mpm::NodePhase::nSolid) = + this->acceleration_.col(mpm::NodePhase::NSolid) = (unbalanced_force_solid - damping_factor * unbalanced_force_solid.norm() * - this->velocity_.col(mpm::NodePhase::nSolid).cwiseSign()) / - this->mass(mpm::NodePhase::nSolid); + this->velocity_.col(mpm::NodePhase::NSolid).cwiseSign()) / + this->mass(mpm::NodePhase::NSolid); // Apply friction constraints this->apply_friction_constraints(dt); @@ -117,14 +117,14 @@ bool mpm::Node:: // Set a threshold for (unsigned i = 0; i < Tdim; ++i) { - if (std::abs(velocity_.col(mpm::NodePhase::nSolid)(i)) < tolerance) - velocity_.col(mpm::NodePhase::nSolid)(i) = 0.; - if (std::abs(acceleration_.col(mpm::NodePhase::nSolid)(i)) < tolerance) - acceleration_.col(mpm::NodePhase::nSolid)(i) = 0.; - if (std::abs(velocity_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) - velocity_.col(mpm::NodePhase::nLiquid)(i) = 0.; - if (std::abs(acceleration_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) - acceleration_.col(mpm::NodePhase::nLiquid)(i) = 0.; + if (std::abs(velocity_.col(mpm::NodePhase::NSolid)(i)) < tolerance) + velocity_.col(mpm::NodePhase::NSolid)(i) = 0.; + if (std::abs(acceleration_.col(mpm::NodePhase::NSolid)(i)) < tolerance) + acceleration_.col(mpm::NodePhase::NSolid)(i) = 0.; + if (std::abs(velocity_.col(mpm::NodePhase::NLiquid)(i)) < tolerance) + velocity_.col(mpm::NodePhase::NLiquid)(i) = 0.; + if (std::abs(acceleration_.col(mpm::NodePhase::NLiquid)(i)) < tolerance) + acceleration_.col(mpm::NodePhase::NLiquid)(i) = 0.; } status = true; } diff --git a/include/solvers/mpm_explicit_twophase.tcc b/include/solvers/mpm_explicit_twophase.tcc index debb780db..822e8394e 100644 --- a/include/solvers/mpm_explicit_twophase.tcc +++ b/include/solvers/mpm_explicit_twophase.tcc @@ -161,29 +161,29 @@ bool mpm::MPMExplicitTwoPhase::solve() { // MPI all reduce nodal mass for solid phase mesh_->template nodal_halo_exchange( std::bind(&mpm::NodeBase::mass, std::placeholders::_1, - mpm::NodePhase::nSolid), + mpm::NodePhase::NSolid), std::bind(&mpm::NodeBase::update_mass, std::placeholders::_1, - false, mpm::NodePhase::nSolid, std::placeholders::_2)); + false, mpm::NodePhase::NSolid, std::placeholders::_2)); // MPI all reduce nodal momentum for solid phase mesh_->template nodal_halo_exchange, Tdim>( std::bind(&mpm::NodeBase::momentum, std::placeholders::_1, - mpm::NodePhase::nSolid), + mpm::NodePhase::NSolid), std::bind(&mpm::NodeBase::update_momentum, - std::placeholders::_1, false, mpm::NodePhase::nSolid, + std::placeholders::_1, false, mpm::NodePhase::NSolid, std::placeholders::_2)); // MPI all reduce nodal mass for liquid phase mesh_->template nodal_halo_exchange( std::bind(&mpm::NodeBase::mass, std::placeholders::_1, - mpm::NodePhase::nLiquid), + mpm::NodePhase::NLiquid), std::bind(&mpm::NodeBase::update_mass, std::placeholders::_1, - false, mpm::NodePhase::nLiquid, std::placeholders::_2)); + false, mpm::NodePhase::NLiquid, std::placeholders::_2)); // MPI all reduce nodal momentum for liquid phase mesh_->template nodal_halo_exchange, Tdim>( std::bind(&mpm::NodeBase::momentum, std::placeholders::_1, - mpm::NodePhase::nLiquid), + mpm::NodePhase::NLiquid), std::bind(&mpm::NodeBase::update_momentum, - std::placeholders::_1, false, mpm::NodePhase::nLiquid, + std::placeholders::_1, false, mpm::NodePhase::NLiquid, std::placeholders::_2)); } #endif @@ -263,31 +263,31 @@ bool mpm::MPMExplicitTwoPhase::solve() { // MPI all reduce external force of mixture mesh_->template nodal_halo_exchange, Tdim>( std::bind(&mpm::NodeBase::external_force, std::placeholders::_1, - mpm::NodePhase::nMixture), + mpm::NodePhase::NMixture), std::bind(&mpm::NodeBase::update_external_force, - std::placeholders::_1, false, mpm::NodePhase::nMixture, + std::placeholders::_1, false, mpm::NodePhase::NMixture, std::placeholders::_2)); // MPI all reduce external force of pore fluid mesh_->template nodal_halo_exchange, Tdim>( std::bind(&mpm::NodeBase::external_force, std::placeholders::_1, - mpm::NodePhase::nLiquid), + mpm::NodePhase::NLiquid), std::bind(&mpm::NodeBase::update_external_force, - std::placeholders::_1, false, mpm::NodePhase::nLiquid, + std::placeholders::_1, false, mpm::NodePhase::NLiquid, std::placeholders::_2)); // MPI all reduce internal force of mixture mesh_->template nodal_halo_exchange, Tdim>( std::bind(&mpm::NodeBase::internal_force, std::placeholders::_1, - mpm::NodePhase::nMixture), + mpm::NodePhase::NMixture), std::bind(&mpm::NodeBase::update_internal_force, - std::placeholders::_1, false, mpm::NodePhase::nMixture, + std::placeholders::_1, false, mpm::NodePhase::NMixture, std::placeholders::_2)); // MPI all reduce internal force of pore liquid mesh_->template nodal_halo_exchange, Tdim>( std::bind(&mpm::NodeBase::internal_force, std::placeholders::_1, - mpm::NodePhase::nLiquid), + mpm::NodePhase::NLiquid), std::bind(&mpm::NodeBase::update_internal_force, - std::placeholders::_1, false, mpm::NodePhase::nLiquid, + std::placeholders::_1, false, mpm::NodePhase::NLiquid, std::placeholders::_2)); // MPI all reduce drag force diff --git a/tests/nodes/node_test.cc b/tests/nodes/node_test.cc index 7552300eb..8b2d4968d 100644 --- a/tests/nodes/node_test.cc +++ b/tests/nodes/node_test.cc @@ -159,13 +159,13 @@ TEST_CASE("Node is checked for 1D case", "[node][1D]") { // Check pressure constraints SECTION("Check nodal pressure constraints") { // Check assign pressure constraint - REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::nSolid, 8000, + REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::NSolid, 8000, nullptr) == true); // Check apply pressure constraint REQUIRE_NOTHROW( - node->apply_pressure_constraint(mpm::NodePhase::nSolid)); + node->apply_pressure_constraint(mpm::NodePhase::NSolid)); // Check pressure - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(8000).epsilon(Tolerance)); } } @@ -636,13 +636,13 @@ TEST_CASE("Node is checked for 2D case", "[node][2D]") { // Check pressure constraints SECTION("Check nodal pressure constraints") { // Check assign pressure constraint - REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::nSolid, 8000, + REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::NSolid, 8000, nullptr) == true); // Check apply pressure constraint REQUIRE_NOTHROW( - node->apply_pressure_constraint(mpm::NodePhase::nSolid)); + node->apply_pressure_constraint(mpm::NodePhase::NSolid)); // Check pressure - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(8000).epsilon(Tolerance)); } } @@ -1250,13 +1250,13 @@ TEST_CASE("Node is checked for 3D case", "[node][3D]") { // Check pressure constraints SECTION("Check nodal pressure constraints") { // Check assign pressure constraint - REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::nSolid, 8000, + REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::NSolid, 8000, nullptr) == true); // Check apply pressure constraint REQUIRE_NOTHROW( - node->apply_pressure_constraint(mpm::NodePhase::nSolid)); + node->apply_pressure_constraint(mpm::NodePhase::NSolid)); // Check pressure - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(8000).epsilon(Tolerance)); } } diff --git a/tests/nodes/node_twophase_test.cc b/tests/nodes/node_twophase_test.cc index eebb0182c..d5fa22f1f 100644 --- a/tests/nodes/node_twophase_test.cc +++ b/tests/nodes/node_twophase_test.cc @@ -121,111 +121,111 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { std::make_shared>(id, coords); // Check mass - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(0.0).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(0.0).epsilon(Tolerance)); double solid_mass = 100.5; double liquid_mass = 200.5; // Update mass to 100.5 and 200.5 REQUIRE_NOTHROW( - node->update_mass(true, mpm::NodePhase::nSolid, solid_mass)); + node->update_mass(true, mpm::NodePhase::NSolid, solid_mass)); REQUIRE_NOTHROW( - node->update_mass(true, mpm::NodePhase::nLiquid, liquid_mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + node->update_mass(true, mpm::NodePhase::NLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(100.5).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(200.5).epsilon(Tolerance)); // Update mass to 201 and 401 REQUIRE_NOTHROW( - node->update_mass(true, mpm::NodePhase::nSolid, solid_mass)); + node->update_mass(true, mpm::NodePhase::NSolid, solid_mass)); REQUIRE_NOTHROW( - node->update_mass(true, mpm::NodePhase::nLiquid, liquid_mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + node->update_mass(true, mpm::NodePhase::NLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(201.0).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(401.0).epsilon(Tolerance)); // Assign mass to 100 and 200 solid_mass = 100.; liquid_mass = 200.; REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nSolid, solid_mass)); + node->update_mass(false, mpm::NodePhase::NSolid, solid_mass)); REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nLiquid, liquid_mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + node->update_mass(false, mpm::NodePhase::NLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(100.0).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(200.0).epsilon(Tolerance)); SECTION("Check nodal pressure") { // Check pressure - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(0.0).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(0.0).epsilon(Tolerance)); double pressure = 1000.7; double pore_pressure = 2000.7; // Update pressure to 1000.7 and 2000.7 - REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nSolid, + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::NSolid, solid_mass * pressure)); - REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nLiquid, + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::NLiquid, liquid_mass * pore_pressure)); - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(1000.7).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(2000.7).epsilon(Tolerance)); // Update pressure to 2001.4 and 4001.4 - REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nSolid, + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::NSolid, solid_mass * pressure)); - REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nLiquid, + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::NLiquid, liquid_mass * pore_pressure)); - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(2001.4).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(4001.4).epsilon(Tolerance)); // Assign pressure to 1000 and 2000 pressure = 1000.; pore_pressure = 2000.; - node->assign_pressure(mpm::NodePhase::nSolid, pressure); - node->assign_pressure(mpm::NodePhase::nLiquid, pore_pressure); - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + node->assign_pressure(mpm::NodePhase::NSolid, pressure); + node->assign_pressure(mpm::NodePhase::NLiquid, pore_pressure); + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(1000.0).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(2000.0).epsilon(Tolerance)); // Assign mass to 0 solid_mass = 0.; liquid_mass = 0.; REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nSolid, solid_mass)); + node->update_mass(false, mpm::NodePhase::NSolid, solid_mass)); REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nLiquid, liquid_mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + node->update_mass(false, mpm::NodePhase::NLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(0.0).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(0.0).epsilon(Tolerance)); // Try to update pressure to 2000, should throw and keep to 1000. - node->assign_pressure(mpm::NodePhase::nSolid, pressure); - node->assign_pressure(mpm::NodePhase::nLiquid, pore_pressure); - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + node->assign_pressure(mpm::NodePhase::NSolid, pressure); + node->assign_pressure(mpm::NodePhase::NLiquid, pore_pressure); + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(1000.0).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(2000.0).epsilon(Tolerance)); // Check pressure constraints SECTION("Check nodal pressure constraints") { // Check assign pressure constraint - REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::nSolid, 8000, + REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::NSolid, 8000, nullptr) == true); - REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::nLiquid, 7000, + REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::NLiquid, 7000, nullptr) == true); // Check apply pressure constraint REQUIRE_NOTHROW( - node->apply_pressure_constraint(mpm::NodePhase::nSolid)); + node->apply_pressure_constraint(mpm::NodePhase::NSolid)); REQUIRE_NOTHROW( - node->apply_pressure_constraint(mpm::NodePhase::nLiquid)); + node->apply_pressure_constraint(mpm::NodePhase::NLiquid)); // Check pressure - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(8000).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(7000).epsilon(Tolerance)); } } @@ -237,45 +237,45 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { // Check current external force is zero for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NLiquid)(i) == Approx(0.).epsilon(Tolerance)); } // Update force to 10.0 REQUIRE_NOTHROW( - node->update_external_force(true, mpm::NodePhase::nMixture, force)); - REQUIRE_NOTHROW(node->update_external_force(true, mpm::NodePhase::nLiquid, + node->update_external_force(true, mpm::NodePhase::NMixture, force)); + REQUIRE_NOTHROW(node->update_external_force(true, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NLiquid)(i) == Approx(5.).epsilon(Tolerance)); } // Update force to 20.0 REQUIRE_NOTHROW( - node->update_external_force(true, mpm::NodePhase::nMixture, force)); - REQUIRE_NOTHROW(node->update_external_force(true, mpm::NodePhase::nLiquid, + node->update_external_force(true, mpm::NodePhase::NMixture, force)); + REQUIRE_NOTHROW(node->update_external_force(true, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(20.).epsilon(Tolerance)); - REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NLiquid)(i) == Approx(10.).epsilon(Tolerance)); } // Assign force as 10.0 REQUIRE_NOTHROW( - node->update_external_force(false, mpm::NodePhase::nMixture, force)); + node->update_external_force(false, mpm::NodePhase::NMixture, force)); REQUIRE_NOTHROW(node->update_external_force( - false, mpm::NodePhase::nLiquid, 0.5 * force)); + false, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NLiquid)(i) == Approx(5.).epsilon(Tolerance)); } @@ -283,7 +283,7 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { // Set external force to zero force.setZero(); REQUIRE_NOTHROW(node->update_external_force( - false, mpm::NodePhase::nMixture, force)); + false, mpm::NodePhase::NMixture, force)); // concentrated force std::shared_ptr ffunction = nullptr; @@ -291,38 +291,38 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { const unsigned Direction = 0; // Check external force for (unsigned i = 0; i < Dim; ++i) - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->assign_concentrated_force(mpm::NodePhase::nMixture, + REQUIRE(node->assign_concentrated_force(mpm::NodePhase::NMixture, Direction, concentrated_force, ffunction) == true); double current_time = 0.0; - node->apply_concentrated_force(mpm::NodePhase::nMixture, current_time); + node->apply_concentrated_force(mpm::NodePhase::NMixture, current_time); for (unsigned i = 0; i < Dim; ++i) { if (i == Direction) - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(concentrated_force).epsilon(Tolerance)); else - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(0.).epsilon(Tolerance)); } // Check for incorrect direction / phase const unsigned wrong_dir = 4; - REQUIRE(node->assign_concentrated_force(mpm::NodePhase::nMixture, + REQUIRE(node->assign_concentrated_force(mpm::NodePhase::NMixture, wrong_dir, concentrated_force, ffunction) == false); // Check again to ensure value hasn't been updated for (unsigned i = 0; i < Dim; ++i) { if (i == Direction) - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(concentrated_force).epsilon(Tolerance)); else - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(0.).epsilon(Tolerance)); } } @@ -335,45 +335,45 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { // Check current internal force is zero for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NMixture)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NLiquid)(i) == Approx(0.).epsilon(Tolerance)); } // Update force to 10.0 REQUIRE_NOTHROW( - node->update_internal_force(true, mpm::NodePhase::nMixture, force)); - REQUIRE_NOTHROW(node->update_internal_force(true, mpm::NodePhase::nLiquid, + node->update_internal_force(true, mpm::NodePhase::NMixture, force)); + REQUIRE_NOTHROW(node->update_internal_force(true, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NMixture)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NLiquid)(i) == Approx(5.).epsilon(Tolerance)); } // Update force to 20.0 REQUIRE_NOTHROW( - node->update_internal_force(true, mpm::NodePhase::nMixture, force)); - REQUIRE_NOTHROW(node->update_internal_force(true, mpm::NodePhase::nLiquid, + node->update_internal_force(true, mpm::NodePhase::NMixture, force)); + REQUIRE_NOTHROW(node->update_internal_force(true, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NMixture)(i) == Approx(20.).epsilon(Tolerance)); - REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NLiquid)(i) == Approx(10.).epsilon(Tolerance)); } // Assign force as 10.0 REQUIRE_NOTHROW( - node->update_internal_force(false, mpm::NodePhase::nMixture, force)); + node->update_internal_force(false, mpm::NodePhase::NMixture, force)); REQUIRE_NOTHROW(node->update_internal_force( - false, mpm::NodePhase::nLiquid, 0.5 * force)); + false, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NMixture)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NLiquid)(i) == Approx(5.).epsilon(Tolerance)); } } @@ -422,12 +422,12 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { double liquid_mass = 100.; // Update mass to 100.5 REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nSolid, solid_mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + node->update_mass(false, mpm::NodePhase::NSolid, solid_mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(solid_mass).epsilon(Tolerance)); REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nLiquid, liquid_mass)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + node->update_mass(false, mpm::NodePhase::NLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(liquid_mass).epsilon(Tolerance)); // Check internal force @@ -436,14 +436,14 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { for (unsigned i = 0; i < force.size(); ++i) force(i) = 10. * i; // Update force to 10.0 REQUIRE_NOTHROW( - node->update_internal_force(false, mpm::NodePhase::nMixture, force)); + node->update_internal_force(false, mpm::NodePhase::NMixture, force)); REQUIRE_NOTHROW(node->update_internal_force( - false, mpm::NodePhase::nLiquid, 0.5 * force)); + false, mpm::NodePhase::NLiquid, 0.5 * force)); // Internal force for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NMixture)(i) == Approx(force(i)).epsilon(Tolerance)); - REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NLiquid)(i) == Approx(0.5 * force(i)).epsilon(Tolerance)); } @@ -451,13 +451,13 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { for (unsigned i = 0; i < force.size(); ++i) force(i) = 5. * i; // Update force to 10.0 REQUIRE_NOTHROW( - node->update_external_force(false, mpm::NodePhase::nMixture, force)); + node->update_external_force(false, mpm::NodePhase::NMixture, force)); REQUIRE_NOTHROW(node->update_external_force( - false, mpm::NodePhase::nLiquid, 0.5 * force)); + false, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(force(i)).epsilon(Tolerance)); - REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NLiquid)(i) == Approx(0.5 * force(i)).epsilon(Tolerance)); } @@ -482,9 +482,9 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { solid_acceleration << 0.; for (unsigned i = 0; i < solid_acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(solid_acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(liquid_acceleration(i)).epsilon(Tolerance)); } @@ -492,9 +492,9 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { Eigen::Matrix solid_velocity = solid_acceleration * dt; Eigen::Matrix liquid_velocity = liquid_acceleration * dt; for (unsigned i = 0; i < solid_velocity.size(); ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(solid_velocity(i)).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(liquid_velocity(i)).epsilon(Tolerance)); } @@ -508,9 +508,9 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { solid_acceleration[0] = 0.5 * solid_acceleration[0]; liquid_acceleration[0] = 0.5 * liquid_acceleration[0]; for (unsigned i = 0; i < solid_acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(solid_acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(liquid_acceleration(i)).epsilon(Tolerance)); } @@ -522,9 +522,9 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { solid_acceleration[0] = 0.; liquid_acceleration[0] = 0.; for (unsigned i = 0; i < solid_acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(solid_acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(liquid_acceleration(i)).epsilon(Tolerance)); } @@ -538,9 +538,9 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { solid_velocity[0] = 10.5; liquid_velocity[0] = 10.5; for (unsigned i = 0; i < solid_velocity.size(); ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(solid_velocity(i)).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(liquid_velocity(i)).epsilon(Tolerance)); } @@ -548,19 +548,19 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { solid_acceleration[0] = 0.; liquid_acceleration[0] = 0.; for (unsigned i = 0; i < solid_acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(solid_acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(liquid_acceleration(i)).epsilon(Tolerance)); } // Exception check when mass is zero // Update mass to 0. - REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nSolid, 0.)); - REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nLiquid, 0.)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::NSolid, 0.)); + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::NLiquid, 0.)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(0.).epsilon(Tolerance)); REQUIRE(node->compute_acceleration_velocity_twophase_explicit(dt) == false); @@ -573,82 +573,82 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { // Check initial momentum for (unsigned i = 0; i < momentum.size(); ++i) { - REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NSolid)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NLiquid)(i) == Approx(0.).epsilon(Tolerance)); } // Check update momentum to 10 REQUIRE_NOTHROW( - node->update_momentum(true, mpm::NodePhase::nSolid, momentum)); + node->update_momentum(true, mpm::NodePhase::NSolid, momentum)); REQUIRE_NOTHROW( - node->update_momentum(true, mpm::NodePhase::nLiquid, momentum)); + node->update_momentum(true, mpm::NodePhase::NLiquid, momentum)); for (unsigned i = 0; i < momentum.size(); ++i) { - REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NSolid)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NLiquid)(i) == Approx(10.).epsilon(Tolerance)); } // Check update momentum to 20 REQUIRE_NOTHROW( - node->update_momentum(true, mpm::NodePhase::nSolid, momentum)); + node->update_momentum(true, mpm::NodePhase::NSolid, momentum)); REQUIRE_NOTHROW( - node->update_momentum(true, mpm::NodePhase::nLiquid, momentum)); + node->update_momentum(true, mpm::NodePhase::NLiquid, momentum)); for (unsigned i = 0; i < momentum.size(); ++i) { - REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NSolid)(i) == Approx(20.).epsilon(Tolerance)); - REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NLiquid)(i) == Approx(20.).epsilon(Tolerance)); } // Check assign momentum to 10 REQUIRE_NOTHROW( - node->update_momentum(false, mpm::NodePhase::nSolid, momentum)); + node->update_momentum(false, mpm::NodePhase::NSolid, momentum)); REQUIRE_NOTHROW( - node->update_momentum(false, mpm::NodePhase::nLiquid, momentum)); + node->update_momentum(false, mpm::NodePhase::NLiquid, momentum)); for (unsigned i = 0; i < momentum.size(); ++i) { - REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NSolid)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NLiquid)(i) == Approx(10.).epsilon(Tolerance)); } // Check zero velocity for (unsigned i = 0; i < Dim; ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(0.).epsilon(Tolerance)); } // Check mass double mass = 0.; - REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nSolid, mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::NSolid, mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(0.0).epsilon(Tolerance)); - REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nLiquid, mass)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::NLiquid, mass)); + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(0.0).epsilon(Tolerance)); // Compute and check velocity this should throw zero mass node->compute_velocity(); mass = 100.; // Update mass to 100. - REQUIRE_NOTHROW(node->update_mass(true, mpm::NodePhase::nSolid, mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + REQUIRE_NOTHROW(node->update_mass(true, mpm::NodePhase::NSolid, mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(100.).epsilon(Tolerance)); - REQUIRE_NOTHROW(node->update_mass(true, mpm::NodePhase::nLiquid, mass)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE_NOTHROW(node->update_mass(true, mpm::NodePhase::NLiquid, mass)); + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(100.).epsilon(Tolerance)); // Compute and check velocity node->compute_velocity(); for (unsigned i = 0; i < Dim; ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(0.1).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(0.1).epsilon(Tolerance)); } @@ -661,9 +661,9 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { Eigen::Matrix velocity; velocity << 0.1; for (unsigned i = 0; i < velocity.size(); ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(velocity(i)).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(velocity(i)).epsilon(Tolerance)); } @@ -673,9 +673,9 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { // Check apply constraints velocity << 10.5; for (unsigned i = 0; i < velocity.size(); ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(velocity(i)).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(velocity(i)).epsilon(Tolerance)); } } @@ -686,21 +686,21 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { for (unsigned i = 0; i < acceleration.size(); ++i) acceleration(i) = 5.; for (unsigned i = 0; i < acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(0.).epsilon(Tolerance)); } - REQUIRE_NOTHROW(node->update_acceleration(true, mpm::NodePhase::nSolid, + REQUIRE_NOTHROW(node->update_acceleration(true, mpm::NodePhase::NSolid, acceleration)); - REQUIRE_NOTHROW(node->update_acceleration(true, mpm::NodePhase::nLiquid, + REQUIRE_NOTHROW(node->update_acceleration(true, mpm::NodePhase::NLiquid, 0.5 * acceleration)); for (unsigned i = 0; i < acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(5.).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(2.5).epsilon(Tolerance)); } @@ -713,9 +713,9 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { acceleration.resize(Dim); acceleration << 5.; for (unsigned i = 0; i < acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(0.5 * acceleration(i)).epsilon(Tolerance)); } @@ -725,9 +725,9 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { // Check apply constraints acceleration << 0.0; for (unsigned i = 0; i < acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); } } @@ -866,135 +866,135 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { std::make_shared>(id, coords); // Check mass - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(0.0).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(0.0).epsilon(Tolerance)); double solid_mass = 100.5; double liquid_mass = 200.5; // Update mass to 100.5 and 200.5 REQUIRE_NOTHROW( - node->update_mass(true, mpm::NodePhase::nSolid, solid_mass)); + node->update_mass(true, mpm::NodePhase::NSolid, solid_mass)); REQUIRE_NOTHROW( - node->update_mass(true, mpm::NodePhase::nLiquid, liquid_mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + node->update_mass(true, mpm::NodePhase::NLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(100.5).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(200.5).epsilon(Tolerance)); // Update mass to 201 and 401 REQUIRE_NOTHROW( - node->update_mass(true, mpm::NodePhase::nSolid, solid_mass)); + node->update_mass(true, mpm::NodePhase::NSolid, solid_mass)); REQUIRE_NOTHROW( - node->update_mass(true, mpm::NodePhase::nLiquid, liquid_mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + node->update_mass(true, mpm::NodePhase::NLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(201.0).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(401.0).epsilon(Tolerance)); // Assign mass to 100 and 200 solid_mass = 100.; liquid_mass = 200.; REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nSolid, solid_mass)); + node->update_mass(false, mpm::NodePhase::NSolid, solid_mass)); REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nLiquid, liquid_mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + node->update_mass(false, mpm::NodePhase::NLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(100.0).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(200.0).epsilon(Tolerance)); SECTION("Check nodal pressure") { // Check pressure - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(0.0).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(0.0).epsilon(Tolerance)); double pressure = 1000.7; double pore_pressure = 2000.7; // Update pressure to 1000.7 and 2000.7 - REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nSolid, + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::NSolid, solid_mass * pressure)); - REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nLiquid, + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::NLiquid, liquid_mass * pore_pressure)); - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(1000.7).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(2000.7).epsilon(Tolerance)); // Update pressure to 2001.4 and 4001.4 - REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nSolid, + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::NSolid, solid_mass * pressure)); - REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nLiquid, + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::NLiquid, liquid_mass * pore_pressure)); - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(2001.4).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(4001.4).epsilon(Tolerance)); // Assign pressure to 1000 and 2000 pressure = 1000.; pore_pressure = 2000.; - node->assign_pressure(mpm::NodePhase::nSolid, pressure); - node->assign_pressure(mpm::NodePhase::nLiquid, pore_pressure); - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + node->assign_pressure(mpm::NodePhase::NSolid, pressure); + node->assign_pressure(mpm::NodePhase::NLiquid, pore_pressure); + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(1000.0).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(2000.0).epsilon(Tolerance)); // Assign mass to 0 solid_mass = 0.; liquid_mass = 0.; REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nSolid, solid_mass)); + node->update_mass(false, mpm::NodePhase::NSolid, solid_mass)); REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nLiquid, liquid_mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + node->update_mass(false, mpm::NodePhase::NLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(0.0).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(0.0).epsilon(Tolerance)); // Try to update pressure to 2000, should throw and keep to 1000. - node->assign_pressure(mpm::NodePhase::nSolid, pressure); - node->assign_pressure(mpm::NodePhase::nLiquid, pore_pressure); - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + node->assign_pressure(mpm::NodePhase::NSolid, pressure); + node->assign_pressure(mpm::NodePhase::NLiquid, pore_pressure); + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(1000.0).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(2000.0).epsilon(Tolerance)); // Check pressure constraints SECTION("Check nodal pressure constraints") { // Check assign pressure constraint - REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::nSolid, 8000, + REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::NSolid, 8000, nullptr) == true); - REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::nLiquid, 7000, + REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::NLiquid, 7000, nullptr) == true); // Check apply pressure constraint REQUIRE_NOTHROW( - node->apply_pressure_constraint(mpm::NodePhase::nSolid)); + node->apply_pressure_constraint(mpm::NodePhase::NSolid)); REQUIRE_NOTHROW( - node->apply_pressure_constraint(mpm::NodePhase::nLiquid)); + node->apply_pressure_constraint(mpm::NodePhase::NLiquid)); // Check pressure - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(8000).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(7000).epsilon(Tolerance)); } } SECTION("Check volume") { // Check volume - REQUIRE(node->volume(mpm::NodePhase::nMixture) == + REQUIRE(node->volume(mpm::NodePhase::NMixture) == Approx(0.0).epsilon(Tolerance)); double volume = 100.5; // Update volume to 100.5 REQUIRE_NOTHROW( - node->update_volume(true, mpm::NodePhase::nMixture, volume)); - REQUIRE(node->volume(mpm::NodePhase::nMixture) == + node->update_volume(true, mpm::NodePhase::NMixture, volume)); + REQUIRE(node->volume(mpm::NodePhase::NMixture) == Approx(100.5).epsilon(Tolerance)); // Update volume to 201 REQUIRE_NOTHROW( - node->update_volume(true, mpm::NodePhase::nMixture, volume)); - REQUIRE(node->volume(mpm::NodePhase::nMixture) == + node->update_volume(true, mpm::NodePhase::NMixture, volume)); + REQUIRE(node->volume(mpm::NodePhase::NMixture) == Approx(201.0).epsilon(Tolerance)); // Assign volume to 100 volume = 100.; REQUIRE_NOTHROW( - node->update_volume(false, mpm::NodePhase::nMixture, volume)); - REQUIRE(node->volume(mpm::NodePhase::nMixture) == + node->update_volume(false, mpm::NodePhase::NMixture, volume)); + REQUIRE(node->volume(mpm::NodePhase::NMixture) == Approx(100.0).epsilon(Tolerance)); } @@ -1005,45 +1005,45 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { // Check current external force is zero for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NLiquid)(i) == Approx(0.).epsilon(Tolerance)); } // Update force to 10.0 REQUIRE_NOTHROW( - node->update_external_force(true, mpm::NodePhase::nMixture, force)); - REQUIRE_NOTHROW(node->update_external_force(true, mpm::NodePhase::nLiquid, + node->update_external_force(true, mpm::NodePhase::NMixture, force)); + REQUIRE_NOTHROW(node->update_external_force(true, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NLiquid)(i) == Approx(5.).epsilon(Tolerance)); } // Update force to 20.0 REQUIRE_NOTHROW( - node->update_external_force(true, mpm::NodePhase::nMixture, force)); - REQUIRE_NOTHROW(node->update_external_force(true, mpm::NodePhase::nLiquid, + node->update_external_force(true, mpm::NodePhase::NMixture, force)); + REQUIRE_NOTHROW(node->update_external_force(true, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(20.).epsilon(Tolerance)); - REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NLiquid)(i) == Approx(10.).epsilon(Tolerance)); } // Assign force as 10.0 REQUIRE_NOTHROW( - node->update_external_force(false, mpm::NodePhase::nMixture, force)); + node->update_external_force(false, mpm::NodePhase::NMixture, force)); REQUIRE_NOTHROW(node->update_external_force( - false, mpm::NodePhase::nLiquid, 0.5 * force)); + false, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NLiquid)(i) == Approx(5.).epsilon(Tolerance)); } @@ -1051,7 +1051,7 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { // Set external force to zero force.setZero(); REQUIRE_NOTHROW(node->update_external_force( - false, mpm::NodePhase::nMixture, force)); + false, mpm::NodePhase::NMixture, force)); // Concentrated force std::shared_ptr ffunction = nullptr; @@ -1059,38 +1059,38 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { const unsigned Direction = 0; // Check traction for (unsigned i = 0; i < Dim; ++i) - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->assign_concentrated_force(mpm::NodePhase::nMixture, + REQUIRE(node->assign_concentrated_force(mpm::NodePhase::NMixture, Direction, concentrated_force, ffunction) == true); double current_time = 0.0; - node->apply_concentrated_force(mpm::NodePhase::nMixture, current_time); + node->apply_concentrated_force(mpm::NodePhase::NMixture, current_time); for (unsigned i = 0; i < Dim; ++i) { if (i == Direction) - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(concentrated_force).epsilon(Tolerance)); else - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(0.).epsilon(Tolerance)); } // Check for incorrect direction / phase const unsigned wrong_dir = 4; - REQUIRE(node->assign_concentrated_force(mpm::NodePhase::nMixture, + REQUIRE(node->assign_concentrated_force(mpm::NodePhase::NMixture, wrong_dir, concentrated_force, ffunction) == false); // Check again to ensure value hasn't been updated for (unsigned i = 0; i < Dim; ++i) { if (i == Direction) - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(concentrated_force).epsilon(Tolerance)); else - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(0.).epsilon(Tolerance)); } } @@ -1103,45 +1103,45 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { // Check current internal force is zero for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NMixture)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NLiquid)(i) == Approx(0.).epsilon(Tolerance)); } // Update force to 10.0 REQUIRE_NOTHROW( - node->update_internal_force(true, mpm::NodePhase::nMixture, force)); - REQUIRE_NOTHROW(node->update_internal_force(true, mpm::NodePhase::nLiquid, + node->update_internal_force(true, mpm::NodePhase::NMixture, force)); + REQUIRE_NOTHROW(node->update_internal_force(true, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NMixture)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NLiquid)(i) == Approx(5.).epsilon(Tolerance)); } // Update force to 20.0 REQUIRE_NOTHROW( - node->update_internal_force(true, mpm::NodePhase::nMixture, force)); - REQUIRE_NOTHROW(node->update_internal_force(true, mpm::NodePhase::nLiquid, + node->update_internal_force(true, mpm::NodePhase::NMixture, force)); + REQUIRE_NOTHROW(node->update_internal_force(true, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NMixture)(i) == Approx(20.).epsilon(Tolerance)); - REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NLiquid)(i) == Approx(10.).epsilon(Tolerance)); } // Assign force as 10.0 REQUIRE_NOTHROW( - node->update_internal_force(false, mpm::NodePhase::nMixture, force)); + node->update_internal_force(false, mpm::NodePhase::NMixture, force)); REQUIRE_NOTHROW(node->update_internal_force( - false, mpm::NodePhase::nLiquid, 0.5 * force)); + false, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NMixture)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NLiquid)(i) == Approx(5.).epsilon(Tolerance)); } } @@ -1190,12 +1190,12 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { double liquid_mass = 100.; // Update mass to 100. REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nSolid, solid_mass)); + node->update_mass(false, mpm::NodePhase::NSolid, solid_mass)); REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nLiquid, liquid_mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + node->update_mass(false, mpm::NodePhase::NLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(solid_mass).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(liquid_mass).epsilon(Tolerance)); // Check internal force @@ -1204,14 +1204,14 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { for (unsigned i = 0; i < force.size(); ++i) force(i) = 10. * i; // Update force to 10.0 REQUIRE_NOTHROW( - node->update_internal_force(false, mpm::NodePhase::nMixture, force)); + node->update_internal_force(false, mpm::NodePhase::NMixture, force)); REQUIRE_NOTHROW(node->update_internal_force( - false, mpm::NodePhase::nLiquid, 0.5 * force)); + false, mpm::NodePhase::NLiquid, 0.5 * force)); // Internal force for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NMixture)(i) == Approx(force(i)).epsilon(Tolerance)); - REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NLiquid)(i) == Approx(0.5 * force(i)).epsilon(Tolerance)); } @@ -1219,13 +1219,13 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { for (unsigned i = 0; i < force.size(); ++i) force(i) = 5. * i; // Update force to 10.0 REQUIRE_NOTHROW( - node->update_external_force(false, mpm::NodePhase::nMixture, force)); + node->update_external_force(false, mpm::NodePhase::NMixture, force)); REQUIRE_NOTHROW(node->update_external_force( - false, mpm::NodePhase::nLiquid, 0.5 * force)); + false, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(force(i)).epsilon(Tolerance)); - REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NLiquid)(i) == Approx(0.5 * force(i)).epsilon(Tolerance)); } @@ -1250,9 +1250,9 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { solid_acceleration << 0., 0.075; for (unsigned i = 0; i < solid_acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(solid_acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(liquid_acceleration(i)).epsilon(Tolerance)); } @@ -1260,9 +1260,9 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { Eigen::Matrix solid_velocity = solid_acceleration * dt; Eigen::Matrix liquid_velocity = liquid_acceleration * dt; for (unsigned i = 0; i < solid_velocity.size(); ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(solid_velocity(i)).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(liquid_velocity(i)).epsilon(Tolerance)); } @@ -1278,9 +1278,9 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { solid_velocity << 10.5, 0.03; liquid_velocity << 20.5, 1.03; for (unsigned i = 0; i < solid_velocity.size(); ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(solid_velocity(i)).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(liquid_velocity(i)).epsilon(Tolerance)); } @@ -1288,9 +1288,9 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { solid_acceleration.setZero(); liquid_acceleration.setZero(); for (unsigned i = 0; i < solid_acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(solid_acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(liquid_acceleration(i)).epsilon(Tolerance)); } @@ -1302,18 +1302,18 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { solid_acceleration << 0., 0.; liquid_acceleration << 0., 0.; for (unsigned i = 0; i < solid_acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(solid_acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(liquid_acceleration(i)).epsilon(Tolerance)); } // Exception check when mass is zero - REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nSolid, 0.)); - REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nLiquid, 0.)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::NSolid, 0.)); + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::NLiquid, 0.)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(0.).epsilon(Tolerance)); REQUIRE(node->compute_acceleration_velocity_twophase_explicit(dt) == false); @@ -1329,82 +1329,82 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { // Check initial momentum for (unsigned i = 0; i < momentum.size(); ++i) { - REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NSolid)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NLiquid)(i) == Approx(0.).epsilon(Tolerance)); } // Check update momentum to 10 REQUIRE_NOTHROW( - node->update_momentum(true, mpm::NodePhase::nSolid, momentum)); + node->update_momentum(true, mpm::NodePhase::NSolid, momentum)); REQUIRE_NOTHROW( - node->update_momentum(true, mpm::NodePhase::nLiquid, momentum)); + node->update_momentum(true, mpm::NodePhase::NLiquid, momentum)); for (unsigned i = 0; i < momentum.size(); ++i) { - REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NSolid)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NLiquid)(i) == Approx(10.).epsilon(Tolerance)); } // Check update momentum to 20 REQUIRE_NOTHROW( - node->update_momentum(true, mpm::NodePhase::nSolid, momentum)); + node->update_momentum(true, mpm::NodePhase::NSolid, momentum)); REQUIRE_NOTHROW( - node->update_momentum(true, mpm::NodePhase::nLiquid, momentum)); + node->update_momentum(true, mpm::NodePhase::NLiquid, momentum)); for (unsigned i = 0; i < momentum.size(); ++i) { - REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NSolid)(i) == Approx(20.).epsilon(Tolerance)); - REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NLiquid)(i) == Approx(20.).epsilon(Tolerance)); } // Check assign momentum to 10 REQUIRE_NOTHROW( - node->update_momentum(false, mpm::NodePhase::nSolid, momentum)); + node->update_momentum(false, mpm::NodePhase::NSolid, momentum)); REQUIRE_NOTHROW( - node->update_momentum(false, mpm::NodePhase::nLiquid, momentum)); + node->update_momentum(false, mpm::NodePhase::NLiquid, momentum)); for (unsigned i = 0; i < momentum.size(); ++i) { - REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NSolid)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NLiquid)(i) == Approx(10.).epsilon(Tolerance)); } // Check zero velocity for (unsigned i = 0; i < Dim; ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(0.).epsilon(Tolerance)); } // Check mass double mass = 0.; - REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nSolid, mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::NSolid, mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(0.0).epsilon(Tolerance)); - REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nLiquid, mass)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::NLiquid, mass)); + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(0.0).epsilon(Tolerance)); // Compute and check velocity this should throw zero mass node->compute_velocity(); mass = 100.; // Update mass to 100.5 - REQUIRE_NOTHROW(node->update_mass(true, mpm::NodePhase::nSolid, mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + REQUIRE_NOTHROW(node->update_mass(true, mpm::NodePhase::NSolid, mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(100.).epsilon(Tolerance)); - REQUIRE_NOTHROW(node->update_mass(true, mpm::NodePhase::nLiquid, mass)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE_NOTHROW(node->update_mass(true, mpm::NodePhase::NLiquid, mass)); + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(100.).epsilon(Tolerance)); // Compute and check velocity node->compute_velocity(); for (unsigned i = 0; i < Dim; ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(0.1).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(0.1).epsilon(Tolerance)); } @@ -1413,20 +1413,20 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { for (unsigned i = 0; i < acceleration.size(); ++i) acceleration(i) = 5.; for (unsigned i = 0; i < acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(0.).epsilon(Tolerance)); } - REQUIRE_NOTHROW(node->update_acceleration(true, mpm::NodePhase::nSolid, + REQUIRE_NOTHROW(node->update_acceleration(true, mpm::NodePhase::NSolid, acceleration)); - REQUIRE_NOTHROW(node->update_acceleration(true, mpm::NodePhase::nLiquid, + REQUIRE_NOTHROW(node->update_acceleration(true, mpm::NodePhase::NLiquid, acceleration)); for (unsigned i = 0; i < acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(5.).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(5.).epsilon(Tolerance)); } @@ -1439,18 +1439,18 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { Eigen::Matrix velocity; velocity << 0.1, 0.1; for (unsigned i = 0; i < velocity.size(); ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(velocity(i)).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(velocity(i)).epsilon(Tolerance)); } // Check acceleration before constraints acceleration << 5., 5.; for (unsigned i = 0; i < acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); } @@ -1466,17 +1466,17 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { // Check apply constraints velocity << -12.5, 0.1; for (unsigned i = 0; i < velocity.size(); ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(velocity(i)).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(velocity(i)).epsilon(Tolerance)); } acceleration << 0., 5.; for (unsigned i = 0; i < acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); } } @@ -1501,35 +1501,35 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { // Check applied velocity constraints in the global coordinates velocity << -9.583478335521184, -8.025403099849004; for (unsigned i = 0; i < Dim; ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(velocity(i)).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(velocity(i)).epsilon(Tolerance)); } // Check that the velocity is as specified in local coordinate REQUIRE((inverse_rotation_matrix * - node->velocity(mpm::NodePhase::nSolid))(0) == + node->velocity(mpm::NodePhase::NSolid))(0) == Approx(-12.5).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->velocity(mpm::NodePhase::nLiquid))(0) == + node->velocity(mpm::NodePhase::NLiquid))(0) == Approx(-12.5).epsilon(Tolerance)); // Check applied constraints on acceleration in the global coordinates acceleration << -0.396139826697847, 0.472101061636807; for (unsigned i = 0; i < Dim; ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); } // Check that the acceleration is 0 in local coordinate REQUIRE((inverse_rotation_matrix * - node->acceleration(mpm::NodePhase::nSolid))(0) == + node->acceleration(mpm::NodePhase::NSolid))(0) == Approx(0).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->acceleration(mpm::NodePhase::nLiquid))(0) == + node->acceleration(mpm::NodePhase::NLiquid))(0) == Approx(0).epsilon(Tolerance)); } @@ -1555,47 +1555,47 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { // Check applied velocity constraints in the global coordinates velocity << -14.311308834766370, 2.772442864323454; for (unsigned i = 0; i < Dim; ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(velocity(i)).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(velocity(i)).epsilon(Tolerance)); } // Check that the velocity is as specified in local coordinate REQUIRE((inverse_rotation_matrix * - node->velocity(mpm::NodePhase::nSolid))(0) == + node->velocity(mpm::NodePhase::NSolid))(0) == Approx(-12.5).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->velocity(mpm::NodePhase::nSolid))(1) == + node->velocity(mpm::NodePhase::NSolid))(1) == Approx(7.5).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->velocity(mpm::NodePhase::nLiquid))(0) == + node->velocity(mpm::NodePhase::NLiquid))(0) == Approx(-12.5).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->velocity(mpm::NodePhase::nLiquid))(1) == + node->velocity(mpm::NodePhase::NLiquid))(1) == Approx(7.5).epsilon(Tolerance)); // Check applied constraints on acceleration in the global coordinates acceleration << 0, 0; for (unsigned i = 0; i < Dim; ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); } // Check that the acceleration is 0 in local coordinate REQUIRE((inverse_rotation_matrix * - node->acceleration(mpm::NodePhase::nSolid))(0) == + node->acceleration(mpm::NodePhase::NSolid))(0) == Approx(0).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->acceleration(mpm::NodePhase::nSolid))(1) == + node->acceleration(mpm::NodePhase::NSolid))(1) == Approx(0).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->acceleration(mpm::NodePhase::nLiquid))(0) == + node->acceleration(mpm::NodePhase::NLiquid))(0) == Approx(0).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->acceleration(mpm::NodePhase::nLiquid))(1) == + node->acceleration(mpm::NodePhase::NLiquid))(1) == Approx(0).epsilon(Tolerance)); } @@ -1611,7 +1611,7 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { // Check apply constraints acceleration << 4., 5.; for (unsigned i = 0; i < acceleration.size(); ++i) - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); } @@ -1633,14 +1633,14 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { // Check applied constraints on acceleration in the global coordinates acceleration << 4.905579787672637, 4.920772034660430; for (unsigned i = 0; i < Dim; ++i) - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); // Check the acceleration in local coordinate acceleration << 6.920903430595146, 0.616284167162194; for (unsigned i = 0; i < Dim; ++i) REQUIRE((inverse_rotation_matrix * - node->acceleration(mpm::NodePhase::nSolid))(i) == + node->acceleration(mpm::NodePhase::NSolid))(i) == Approx(acceleration(i)).epsilon(Tolerance)); } } @@ -1779,111 +1779,111 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { std::make_shared>(id, coords); // Check mass - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(0.0).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(0.0).epsilon(Tolerance)); double solid_mass = 100.5; double liquid_mass = 200.5; // Update mass to 100.5 and 200.5 REQUIRE_NOTHROW( - node->update_mass(true, mpm::NodePhase::nSolid, solid_mass)); + node->update_mass(true, mpm::NodePhase::NSolid, solid_mass)); REQUIRE_NOTHROW( - node->update_mass(true, mpm::NodePhase::nLiquid, liquid_mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + node->update_mass(true, mpm::NodePhase::NLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(100.5).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(200.5).epsilon(Tolerance)); // Update mass to 201 and 401 REQUIRE_NOTHROW( - node->update_mass(true, mpm::NodePhase::nSolid, solid_mass)); + node->update_mass(true, mpm::NodePhase::NSolid, solid_mass)); REQUIRE_NOTHROW( - node->update_mass(true, mpm::NodePhase::nLiquid, liquid_mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + node->update_mass(true, mpm::NodePhase::NLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(201.0).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(401.0).epsilon(Tolerance)); // Assign mass to 100 and 200 solid_mass = 100.; liquid_mass = 200.; REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nSolid, solid_mass)); + node->update_mass(false, mpm::NodePhase::NSolid, solid_mass)); REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nLiquid, liquid_mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + node->update_mass(false, mpm::NodePhase::NLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(100.0).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(200.0).epsilon(Tolerance)); SECTION("Check nodal pressure") { // Check pressure - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(0.0).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(0.0).epsilon(Tolerance)); double pressure = 1000.7; double pore_pressure = 2000.7; // Update pressure to 1000.7 and 2000.7 - REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nSolid, + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::NSolid, solid_mass * pressure)); - REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nLiquid, + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::NLiquid, liquid_mass * pore_pressure)); - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(1000.7).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(2000.7).epsilon(Tolerance)); // Update pressure to 2001.4 and 4001.4 - REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nSolid, + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::NSolid, solid_mass * pressure)); - REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nLiquid, + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::NLiquid, liquid_mass * pore_pressure)); - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(2001.4).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(4001.4).epsilon(Tolerance)); // Assign pressure to 1000 and 2000 pressure = 1000.; pore_pressure = 2000.; - node->assign_pressure(mpm::NodePhase::nSolid, pressure); - node->assign_pressure(mpm::NodePhase::nLiquid, pore_pressure); - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + node->assign_pressure(mpm::NodePhase::NSolid, pressure); + node->assign_pressure(mpm::NodePhase::NLiquid, pore_pressure); + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(1000.0).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(2000.0).epsilon(Tolerance)); // Assign mass to 0 solid_mass = 0.; liquid_mass = 0.; REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nSolid, solid_mass)); + node->update_mass(false, mpm::NodePhase::NSolid, solid_mass)); REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nLiquid, liquid_mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + node->update_mass(false, mpm::NodePhase::NLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(0.0).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(0.0).epsilon(Tolerance)); // Try to update pressure to 2000, should throw and keep to 1000. - node->assign_pressure(mpm::NodePhase::nSolid, pressure); - node->assign_pressure(mpm::NodePhase::nLiquid, pore_pressure); - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + node->assign_pressure(mpm::NodePhase::NSolid, pressure); + node->assign_pressure(mpm::NodePhase::NLiquid, pore_pressure); + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(1000.0).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(2000.0).epsilon(Tolerance)); // Check pressure constraints SECTION("Check nodal pressure constraints") { // Check assign pressure constraint - REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::nSolid, 8000, + REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::NSolid, 8000, nullptr) == true); - REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::nLiquid, 7000, + REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::NLiquid, 7000, nullptr) == true); // Check apply pressure constraint REQUIRE_NOTHROW( - node->apply_pressure_constraint(mpm::NodePhase::nSolid)); + node->apply_pressure_constraint(mpm::NodePhase::NSolid)); REQUIRE_NOTHROW( - node->apply_pressure_constraint(mpm::NodePhase::nLiquid)); + node->apply_pressure_constraint(mpm::NodePhase::NLiquid)); // Check pressure - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(8000).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(7000).epsilon(Tolerance)); } } @@ -1895,45 +1895,45 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { // Check current external force is zero for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NLiquid)(i) == Approx(0.).epsilon(Tolerance)); } // Update force to 10.0 REQUIRE_NOTHROW( - node->update_external_force(true, mpm::NodePhase::nMixture, force)); - REQUIRE_NOTHROW(node->update_external_force(true, mpm::NodePhase::nLiquid, + node->update_external_force(true, mpm::NodePhase::NMixture, force)); + REQUIRE_NOTHROW(node->update_external_force(true, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NLiquid)(i) == Approx(5.).epsilon(Tolerance)); } // Update force to 20.0 REQUIRE_NOTHROW( - node->update_external_force(true, mpm::NodePhase::nMixture, force)); - REQUIRE_NOTHROW(node->update_external_force(true, mpm::NodePhase::nLiquid, + node->update_external_force(true, mpm::NodePhase::NMixture, force)); + REQUIRE_NOTHROW(node->update_external_force(true, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(20.).epsilon(Tolerance)); - REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NLiquid)(i) == Approx(10.).epsilon(Tolerance)); } // Assign force as 10.0 REQUIRE_NOTHROW( - node->update_external_force(false, mpm::NodePhase::nMixture, force)); + node->update_external_force(false, mpm::NodePhase::NMixture, force)); REQUIRE_NOTHROW(node->update_external_force( - false, mpm::NodePhase::nLiquid, 0.5 * force)); + false, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NLiquid)(i) == Approx(5.).epsilon(Tolerance)); } @@ -1941,7 +1941,7 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { // Set external force to zero force.setZero(); REQUIRE_NOTHROW(node->update_external_force( - false, mpm::NodePhase::nMixture, force)); + false, mpm::NodePhase::NMixture, force)); // Concentrated force std::shared_ptr ffunction = nullptr; @@ -1949,38 +1949,38 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { const unsigned Direction = 0; // Check traction for (unsigned i = 0; i < Dim; ++i) - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->assign_concentrated_force(mpm::NodePhase::nMixture, + REQUIRE(node->assign_concentrated_force(mpm::NodePhase::NMixture, Direction, concentrated_force, ffunction) == true); double current_time = 0.0; - node->apply_concentrated_force(mpm::NodePhase::nMixture, current_time); + node->apply_concentrated_force(mpm::NodePhase::NMixture, current_time); for (unsigned i = 0; i < Dim; ++i) { if (i == Direction) - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(concentrated_force).epsilon(Tolerance)); else - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(0.).epsilon(Tolerance)); } // Check for incorrect direction / phase const unsigned wrong_dir = 4; - REQUIRE(node->assign_concentrated_force(mpm::NodePhase::nMixture, + REQUIRE(node->assign_concentrated_force(mpm::NodePhase::NMixture, wrong_dir, concentrated_force, ffunction) == false); // Check again to ensure value hasn't been updated for (unsigned i = 0; i < Dim; ++i) { if (i == Direction) - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(concentrated_force).epsilon(Tolerance)); else - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(0.).epsilon(Tolerance)); } } @@ -1993,45 +1993,45 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { // Check current internal force is zero for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NMixture)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NLiquid)(i) == Approx(0.).epsilon(Tolerance)); } // Update force to 10.0 REQUIRE_NOTHROW( - node->update_internal_force(true, mpm::NodePhase::nMixture, force)); - REQUIRE_NOTHROW(node->update_internal_force(true, mpm::NodePhase::nLiquid, + node->update_internal_force(true, mpm::NodePhase::NMixture, force)); + REQUIRE_NOTHROW(node->update_internal_force(true, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NMixture)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NLiquid)(i) == Approx(5.).epsilon(Tolerance)); } // Update force to 20.0 REQUIRE_NOTHROW( - node->update_internal_force(true, mpm::NodePhase::nMixture, force)); - REQUIRE_NOTHROW(node->update_internal_force(true, mpm::NodePhase::nLiquid, + node->update_internal_force(true, mpm::NodePhase::NMixture, force)); + REQUIRE_NOTHROW(node->update_internal_force(true, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NMixture)(i) == Approx(20.).epsilon(Tolerance)); - REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NLiquid)(i) == Approx(10.).epsilon(Tolerance)); } // Assign force as 10.0 REQUIRE_NOTHROW( - node->update_internal_force(false, mpm::NodePhase::nMixture, force)); + node->update_internal_force(false, mpm::NodePhase::NMixture, force)); REQUIRE_NOTHROW(node->update_internal_force( - false, mpm::NodePhase::nLiquid, 0.5 * force)); + false, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NMixture)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NLiquid)(i) == Approx(5.).epsilon(Tolerance)); } } @@ -2080,12 +2080,12 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { double liquid_mass = 100.; // Update mass to 100. REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nSolid, solid_mass)); + node->update_mass(false, mpm::NodePhase::NSolid, solid_mass)); REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nLiquid, liquid_mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + node->update_mass(false, mpm::NodePhase::NLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(solid_mass).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(liquid_mass).epsilon(Tolerance)); // Check internal force @@ -2094,14 +2094,14 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { for (unsigned i = 0; i < force.size(); ++i) force(i) = 10. * i; // Update force to 10.0 REQUIRE_NOTHROW( - node->update_internal_force(false, mpm::NodePhase::nMixture, force)); + node->update_internal_force(false, mpm::NodePhase::NMixture, force)); REQUIRE_NOTHROW(node->update_internal_force( - false, mpm::NodePhase::nLiquid, 0.5 * force)); + false, mpm::NodePhase::NLiquid, 0.5 * force)); // Internal force for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NMixture)(i) == Approx(force(i)).epsilon(Tolerance)); - REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NLiquid)(i) == Approx(0.5 * force(i)).epsilon(Tolerance)); } @@ -2109,13 +2109,13 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { for (unsigned i = 0; i < force.size(); ++i) force(i) = 5. * i; // Update force to 10.0 REQUIRE_NOTHROW( - node->update_external_force(false, mpm::NodePhase::nMixture, force)); + node->update_external_force(false, mpm::NodePhase::NMixture, force)); REQUIRE_NOTHROW(node->update_external_force( - false, mpm::NodePhase::nLiquid, 0.5 * force)); + false, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(force(i)).epsilon(Tolerance)); - REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NLiquid)(i) == Approx(0.5 * force(i)).epsilon(Tolerance)); } @@ -2141,9 +2141,9 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { // Check acceleration for (unsigned i = 0; i < solid_acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(solid_acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(liquid_acceleration(i)).epsilon(Tolerance)); } @@ -2151,9 +2151,9 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { Eigen::Matrix solid_velocity = solid_acceleration * dt; Eigen::Matrix liquid_velocity = liquid_acceleration * dt; for (unsigned i = 0; i < solid_velocity.size(); ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(solid_velocity(i)).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(liquid_velocity(i)).epsilon(Tolerance)); } @@ -2171,9 +2171,9 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { solid_velocity << 10.5, 0.03, 5.13; liquid_velocity << 20.5, 1.03, 7.13; for (unsigned i = 0; i < solid_velocity.size(); ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(solid_velocity(i)).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(liquid_velocity(i)).epsilon(Tolerance)); } @@ -2181,9 +2181,9 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { solid_acceleration.setZero(); liquid_acceleration.setZero(); for (unsigned i = 0; i < solid_acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(solid_acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(liquid_acceleration(i)).epsilon(Tolerance)); } @@ -2195,9 +2195,9 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { solid_acceleration << 0., 0., 0.; liquid_acceleration << 0., 0., 0.; for (unsigned i = 0; i < solid_acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(solid_acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(liquid_acceleration(i)).epsilon(Tolerance)); } @@ -2208,11 +2208,11 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { true); // Exception check when mass is zero - REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nSolid, 0.)); - REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nLiquid, 0.)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::NSolid, 0.)); + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::NLiquid, 0.)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(0.).epsilon(Tolerance)); REQUIRE(node->compute_acceleration_velocity_twophase_explicit(dt) == false); @@ -2228,90 +2228,90 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { // Check initial momentum for (unsigned i = 0; i < momentum.size(); ++i) { - REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NSolid)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NLiquid)(i) == Approx(0.).epsilon(Tolerance)); } // Check update momentum to 10 REQUIRE_NOTHROW( - node->update_momentum(true, mpm::NodePhase::nSolid, momentum)); + node->update_momentum(true, mpm::NodePhase::NSolid, momentum)); REQUIRE_NOTHROW( - node->update_momentum(true, mpm::NodePhase::nLiquid, momentum)); + node->update_momentum(true, mpm::NodePhase::NLiquid, momentum)); for (unsigned i = 0; i < momentum.size(); ++i) { - REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NSolid)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NLiquid)(i) == Approx(10.).epsilon(Tolerance)); } // Check update momentum to 20 REQUIRE_NOTHROW( - node->update_momentum(true, mpm::NodePhase::nSolid, momentum)); + node->update_momentum(true, mpm::NodePhase::NSolid, momentum)); REQUIRE_NOTHROW( - node->update_momentum(true, mpm::NodePhase::nLiquid, momentum)); + node->update_momentum(true, mpm::NodePhase::NLiquid, momentum)); for (unsigned i = 0; i < momentum.size(); ++i) { - REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NSolid)(i) == Approx(20.).epsilon(Tolerance)); - REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NLiquid)(i) == Approx(20.).epsilon(Tolerance)); } // Check assign momentum to 10 REQUIRE_NOTHROW( - node->update_momentum(false, mpm::NodePhase::nSolid, momentum)); + node->update_momentum(false, mpm::NodePhase::NSolid, momentum)); REQUIRE_NOTHROW( - node->update_momentum(false, mpm::NodePhase::nLiquid, momentum)); + node->update_momentum(false, mpm::NodePhase::NLiquid, momentum)); for (unsigned i = 0; i < momentum.size(); ++i) { - REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NSolid)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NLiquid)(i) == Approx(10.).epsilon(Tolerance)); } // Check zero velocity for (unsigned i = 0; i < Dim; ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(0.).epsilon(Tolerance)); } // Check mass double mass = 0.; - REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nSolid, mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::NSolid, mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(0.0).epsilon(Tolerance)); - REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nLiquid, mass)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::NLiquid, mass)); + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(0.0).epsilon(Tolerance)); // Compute and check velocity this should throw zero mass node->compute_velocity(); mass = 100.; // Update mass to 100.5 - REQUIRE_NOTHROW(node->update_mass(true, mpm::NodePhase::nSolid, mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + REQUIRE_NOTHROW(node->update_mass(true, mpm::NodePhase::NSolid, mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(100.).epsilon(Tolerance)); - REQUIRE_NOTHROW(node->update_mass(true, mpm::NodePhase::nLiquid, mass)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE_NOTHROW(node->update_mass(true, mpm::NodePhase::NLiquid, mass)); + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(100.).epsilon(Tolerance)); // Check zero velocity for (unsigned i = 0; i < Dim; ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(0.).epsilon(Tolerance)); } // Compute and check velocity node->compute_velocity(); for (unsigned i = 0; i < Dim; ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(0.1).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(0.1).epsilon(Tolerance)); } @@ -2320,20 +2320,20 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { for (unsigned i = 0; i < acceleration.size(); ++i) acceleration(i) = 5.; for (unsigned i = 0; i < acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(0.).epsilon(Tolerance)); } - REQUIRE_NOTHROW(node->update_acceleration(true, mpm::NodePhase::nSolid, + REQUIRE_NOTHROW(node->update_acceleration(true, mpm::NodePhase::NSolid, acceleration)); - REQUIRE_NOTHROW(node->update_acceleration(true, mpm::NodePhase::nLiquid, + REQUIRE_NOTHROW(node->update_acceleration(true, mpm::NodePhase::NLiquid, acceleration)); for (unsigned i = 0; i < acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(5.).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(5.).epsilon(Tolerance)); } @@ -2341,18 +2341,18 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { Eigen::Matrix velocity; velocity << 0.1, 0.1, 0.1; for (unsigned i = 0; i < velocity.size(); ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(velocity(i)).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(velocity(i)).epsilon(Tolerance)); } // Check acceleration before constraints acceleration << 5., 5., 5.; for (unsigned i = 0; i < acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); } SECTION("Check Cartesian velocity constraints") { @@ -2367,17 +2367,17 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { // Check apply constraints velocity << -12.5, 0.1, 0.1; for (unsigned i = 0; i < velocity.size(); ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(velocity(i)).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(velocity(i)).epsilon(Tolerance)); } acceleration << 0., 5., 5.; for (unsigned i = 0; i < acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); } } @@ -2403,47 +2403,47 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { // Check apply constraints velocity << -14.5068204271, -0.1432759442, 1.4260971922; for (unsigned i = 0; i < Dim; ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(velocity(i)).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(velocity(i)).epsilon(Tolerance)); } // Check that the velocity is as specified in local coordinate REQUIRE((inverse_rotation_matrix * - node->velocity(mpm::NodePhase::nSolid))(0) == + node->velocity(mpm::NodePhase::NSolid))(0) == Approx(-12.5).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->velocity(mpm::NodePhase::nSolid))(1) == + node->velocity(mpm::NodePhase::NSolid))(1) == Approx(7.5).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->velocity(mpm::NodePhase::nLiquid))(0) == + node->velocity(mpm::NodePhase::NLiquid))(0) == Approx(-12.5).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->velocity(mpm::NodePhase::nLiquid))(1) == + node->velocity(mpm::NodePhase::NLiquid))(1) == Approx(7.5).epsilon(Tolerance)); // Check applied constraints on acceleration in the global coordinates acceleration << 0.1998888554, -1.1336260315, 1.9937880031; for (unsigned i = 0; i < Dim; ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); } // Check that the acceleration is 0 in local coordinate REQUIRE((inverse_rotation_matrix * - node->acceleration(mpm::NodePhase::nSolid))(0) == + node->acceleration(mpm::NodePhase::NSolid))(0) == Approx(0).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->acceleration(mpm::NodePhase::nSolid))(1) == + node->acceleration(mpm::NodePhase::NSolid))(1) == Approx(0).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->acceleration(mpm::NodePhase::nLiquid))(0) == + node->acceleration(mpm::NodePhase::NLiquid))(0) == Approx(0).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->acceleration(mpm::NodePhase::nLiquid))(1) == + node->acceleration(mpm::NodePhase::NLiquid))(1) == Approx(0).epsilon(Tolerance)); } @@ -2471,53 +2471,53 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { // Check apply constraints velocity << 13.351984588153375, -5.717804716697730, 10.572663655835457; for (unsigned i = 0; i < Dim; ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(velocity(i)).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(velocity(i)).epsilon(Tolerance)); } // Check that the velocity is as specified in local coordinate REQUIRE((inverse_rotation_matrix * - node->velocity(mpm::NodePhase::nSolid))(0) == + node->velocity(mpm::NodePhase::NSolid))(0) == Approx(10.5).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->velocity(mpm::NodePhase::nSolid))(1) == + node->velocity(mpm::NodePhase::NSolid))(1) == Approx(-12.5).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->velocity(mpm::NodePhase::nSolid))(2) == + node->velocity(mpm::NodePhase::NSolid))(2) == Approx(7.5).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->velocity(mpm::NodePhase::nLiquid))(0) == + node->velocity(mpm::NodePhase::NLiquid))(0) == Approx(10.5).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->velocity(mpm::NodePhase::nLiquid))(1) == + node->velocity(mpm::NodePhase::NLiquid))(1) == Approx(-12.5).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->velocity(mpm::NodePhase::nLiquid))(2) == + node->velocity(mpm::NodePhase::NLiquid))(2) == Approx(7.5).epsilon(Tolerance)); // Check apply constraints acceleration << 0, 0, 0; for (unsigned i = 0; i < Dim; ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); } // Check that the acceleration is 0 in local coordinate REQUIRE((inverse_rotation_matrix * - node->acceleration(mpm::NodePhase::nSolid))(0) == + node->acceleration(mpm::NodePhase::NSolid))(0) == Approx(0).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->acceleration(mpm::NodePhase::nSolid))(1) == + node->acceleration(mpm::NodePhase::NSolid))(1) == Approx(0).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->acceleration(mpm::NodePhase::nLiquid))(0) == + node->acceleration(mpm::NodePhase::NLiquid))(0) == Approx(0).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->acceleration(mpm::NodePhase::nLiquid))(1) == + node->acceleration(mpm::NodePhase::NLiquid))(1) == Approx(0).epsilon(Tolerance)); } @@ -2533,7 +2533,7 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { // Check apply constraints acceleration << 3.939339828220179, 3.939339828220179, 5.; for (unsigned i = 0; i < acceleration.size(); ++i) - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); } @@ -2556,14 +2556,14 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { // Check applied constraints on acceleration in the global coordinates acceleration << 4.602895052828914, 4.492575657560740, 4.751301246937935; for (unsigned i = 0; i < Dim; ++i) - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); // Check the acceleration in local coordinate acceleration << 6.878925666702865, 3.365244416454818, 2.302228080558999; for (unsigned i = 0; i < Dim; ++i) REQUIRE((inverse_rotation_matrix * - node->acceleration(mpm::NodePhase::nSolid))(i) == + node->acceleration(mpm::NodePhase::NSolid))(i) == Approx(acceleration(i)).epsilon(Tolerance)); } } diff --git a/tests/particles/particle_twophase_test.cc b/tests/particles/particle_twophase_test.cc index 58d71ee69..024efbe5a 100644 --- a/tests/particles/particle_twophase_test.cc +++ b/tests/particles/particle_twophase_test.cc @@ -913,12 +913,12 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", // Check nodal mass for (unsigned i = 0; i < nodes.size(); ++i) { // Solid phase - REQUIRE(nodes.at(i)->mass(mpm::NodePhase::nSolid) == + REQUIRE(nodes.at(i)->mass(mpm::NodePhase::NSolid) == Approx(nodal_mass.at(i) * (1 - particle->porosity())) .epsilon(Tolerance)); // Liquid phase REQUIRE( - nodes.at(i)->mass(mpm::NodePhase::nLiquid) == + nodes.at(i)->mass(mpm::NodePhase::NLiquid) == Approx(nodal_mass.at(i) * particle->porosity()).epsilon(Tolerance)); } @@ -937,11 +937,11 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", for (unsigned i = 0; i < nodal_momentum.rows(); ++i) for (unsigned j = 0; j < nodal_momentum.cols(); ++j) { // Solid phase - REQUIRE(nodes.at(i)->momentum(mpm::NodePhase::nSolid)(j) == + REQUIRE(nodes.at(i)->momentum(mpm::NodePhase::NSolid)(j) == Approx(nodal_momentum(i, j) * (1 - particle->porosity())) .epsilon(Tolerance)); // Liquid phase - REQUIRE(nodes.at(i)->momentum(mpm::NodePhase::nLiquid)(j) == + REQUIRE(nodes.at(i)->momentum(mpm::NodePhase::NLiquid)(j) == Approx(nodal_momentum(i, j) * particle->porosity()) .epsilon(Tolerance)); } @@ -957,10 +957,10 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", for (unsigned i = 0; i < nodal_velocity.rows(); ++i) for (unsigned j = 0; j < nodal_velocity.cols(); ++j) { // Solid phase - REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::nSolid)(j) == + REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::NSolid)(j) == Approx(nodal_velocity(i, j)).epsilon(Tolerance)); // Liquid phase - REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::nLiquid)(j) == + REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::NLiquid)(j) == Approx(nodal_velocity(i, j)).epsilon(Tolerance)); } @@ -974,11 +974,11 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", for (unsigned i = 0; i < nodes.size(); ++i) { // Solid phase REQUIRE_NOTHROW(nodes.at(i)->update_momentum( - false, mpm::NodePhase::nSolid, + false, mpm::NodePhase::NSolid, nodal_momentum.row(i) * (1 - particle->porosity()))); // Liquid phase REQUIRE_NOTHROW(nodes.at(i)->update_momentum( - false, mpm::NodePhase::nLiquid, + false, mpm::NodePhase::NLiquid, nodal_momentum.row(i) * particle->porosity())); } @@ -995,10 +995,10 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", for (unsigned i = 0; i < nodal_velocity.rows(); ++i) for (unsigned j = 0; j < nodal_velocity.cols(); ++j) { // Solid phase - REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::nSolid)(j) == + REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::NSolid)(j) == Approx(nodal_velocity(i, j)).epsilon(Tolerance)); // Liquid phase - REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::nLiquid)(j) == + REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::NLiquid)(j) == Approx(nodal_velocity(i, j)).epsilon(Tolerance)); } @@ -1069,7 +1069,7 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", // Check nodal body force for (unsigned i = 0; i < body_force.rows(); ++i) for (unsigned j = 0; j < body_force.cols(); ++j) - REQUIRE(nodes[i]->external_force(mpm::NodePhase::nSolid)[j] == + REQUIRE(nodes[i]->external_force(mpm::NodePhase::NSolid)[j] == Approx(body_force(i, j)).epsilon(Tolerance)); // Check traction force @@ -1101,7 +1101,7 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", // Check nodal traction force for (unsigned i = 0; i < traction_force.rows(); ++i) for (unsigned j = 0; j < traction_force.cols(); ++j) - REQUIRE(nodes[i]->external_force(mpm::NodePhase::nSolid)[j] == + REQUIRE(nodes[i]->external_force(mpm::NodePhase::NSolid)[j] == Approx(traction_force(i, j)).epsilon(Tolerance)); // Reset traction particle->assign_traction(direction, @@ -1111,7 +1111,7 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", // Check nodal external force for (unsigned i = 0; i < traction_force.rows(); ++i) for (unsigned j = 0; j < traction_force.cols(); ++j) - REQUIRE(nodes[i]->external_force(mpm::NodePhase::nSolid)[j] == + REQUIRE(nodes[i]->external_force(mpm::NodePhase::NSolid)[j] == Approx(body_force(i, j)).epsilon(Tolerance)); // Internal force @@ -1130,7 +1130,7 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", // Check nodal internal force for (unsigned i = 0; i < internal_force.rows(); ++i) for (unsigned j = 0; j < internal_force.cols(); ++j) - REQUIRE(nodes[i]->internal_force(mpm::NodePhase::nMixture)[j] == + REQUIRE(nodes[i]->internal_force(mpm::NodePhase::NMixture)[j] == Approx(internal_force(i, j)).epsilon(Tolerance)); // Internal force @@ -1170,10 +1170,10 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", for (unsigned i = 0; i < nodal_velocity.rows(); ++i) for (unsigned j = 0; j < nodal_velocity.cols(); ++j) { // Solid phase - REQUIRE(nodes[i]->velocity(mpm::NodePhase::nSolid)[j] == + REQUIRE(nodes[i]->velocity(mpm::NodePhase::NSolid)[j] == Approx(nodal_velocity(i, j)).epsilon(Tolerance)); // Liquid phase - REQUIRE(nodes[i]->velocity(mpm::NodePhase::nLiquid)[j] == + REQUIRE(nodes[i]->velocity(mpm::NodePhase::NLiquid)[j] == Approx(nodal_liquid_velocity(i, j)).epsilon(Tolerance)); } @@ -1194,10 +1194,10 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", for (unsigned i = 0; i < nodal_acceleration.rows(); ++i) for (unsigned j = 0; j < nodal_acceleration.cols(); ++j) { // Solid phase - REQUIRE(nodes[i]->acceleration(mpm::NodePhase::nSolid)[j] == + REQUIRE(nodes[i]->acceleration(mpm::NodePhase::NSolid)[j] == Approx(nodal_acceleration(i, j)).epsilon(Tolerance)); // Liquid phase - REQUIRE(nodes[i]->acceleration(mpm::NodePhase::nLiquid)[j] == + REQUIRE(nodes[i]->acceleration(mpm::NodePhase::NLiquid)[j] == Approx(nodal_liquid_acceleration(i, j)).epsilon(Tolerance)); } // Approx(nodal_velocity(i, j) / dt).epsilon(Tolerance)); @@ -2350,11 +2350,11 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", // Check nodal mass for (unsigned i = 0; i < nodes.size(); ++i) { // Solid phase - REQUIRE(nodes.at(i)->mass(mpm::NodePhase::nSolid) == + REQUIRE(nodes.at(i)->mass(mpm::NodePhase::NSolid) == Approx(nodal_mass.at(i) * (1 - particle->porosity()))); // Liquid phase REQUIRE( - nodes.at(i)->mass(mpm::NodePhase::nLiquid) == + nodes.at(i)->mass(mpm::NodePhase::NLiquid) == Approx(nodal_mass.at(i) * particle->porosity()).epsilon(Tolerance)); } @@ -2378,11 +2378,11 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", for (unsigned i = 0; i < nodal_momentum.rows(); ++i) for (unsigned j = 0; j < nodal_momentum.cols(); ++j) { // Solid phase - REQUIRE(nodes.at(i)->momentum(mpm::NodePhase::nSolid)(j) == + REQUIRE(nodes.at(i)->momentum(mpm::NodePhase::NSolid)(j) == Approx(nodal_momentum(i, j) * (1 - particle->porosity())) .epsilon(Tolerance)); // Liquid phase - REQUIRE(nodes.at(i)->momentum(mpm::NodePhase::nLiquid)(j) == + REQUIRE(nodes.at(i)->momentum(mpm::NodePhase::NLiquid)(j) == Approx(nodal_momentum(i, j) * particle->porosity()) .epsilon(Tolerance)); } @@ -2403,10 +2403,10 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", for (unsigned i = 0; i < nodal_velocity.rows(); ++i) for (unsigned j = 0; j < nodal_velocity.cols(); ++j) { // Solid phase - REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::nSolid)(j) == + REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::NSolid)(j) == Approx(nodal_velocity(i, j)).epsilon(Tolerance)); // Liquid phase - REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::nLiquid)(j) == + REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::NLiquid)(j) == Approx(nodal_velocity(i, j)).epsilon(Tolerance)); } @@ -2424,11 +2424,11 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", for (unsigned i = 0; i < nodes.size(); ++i) { // Solid phase REQUIRE_NOTHROW(nodes.at(i)->update_momentum( - false, mpm::NodePhase::nSolid, + false, mpm::NodePhase::NSolid, nodal_momentum.row(i) * (1 - particle->porosity()))); // Liquid phase REQUIRE_NOTHROW(nodes.at(i)->update_momentum( - false, mpm::NodePhase::nLiquid, + false, mpm::NodePhase::NLiquid, nodal_momentum.row(i) * particle->porosity())); } @@ -2449,10 +2449,10 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", for (unsigned i = 0; i < nodal_velocity.rows(); ++i) for (unsigned j = 0; j < nodal_velocity.cols(); ++j) { // Solid phase - REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::nSolid)(j) == + REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::NSolid)(j) == Approx(nodal_velocity(i, j)).epsilon(Tolerance)); // Liquid phase - REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::nLiquid)(j) == + REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::NLiquid)(j) == Approx(nodal_velocity(i, j)).epsilon(Tolerance)); } @@ -2527,7 +2527,7 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", // Check nodal body force for (unsigned i = 0; i < body_force.rows(); ++i) for (unsigned j = 0; j < body_force.cols(); ++j) - REQUIRE(nodes[i]->external_force(mpm::NodePhase::nSolid)[j] == + REQUIRE(nodes[i]->external_force(mpm::NodePhase::NSolid)[j] == Approx(body_force(i, j)).epsilon(Tolerance)); // Check traction force @@ -2562,7 +2562,7 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", // Check nodal traction force for (unsigned i = 0; i < traction_force.rows(); ++i) for (unsigned j = 0; j < traction_force.cols(); ++j) - REQUIRE(nodes[i]->external_force(mpm::NodePhase::nSolid)[j] == + REQUIRE(nodes[i]->external_force(mpm::NodePhase::NSolid)[j] == Approx(traction_force(i, j)).epsilon(Tolerance)); // Reset traction particle->assign_traction(direction, @@ -2572,7 +2572,7 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", // Check nodal external force for (unsigned i = 0; i < traction_force.rows(); ++i) for (unsigned j = 0; j < traction_force.cols(); ++j) - REQUIRE(nodes[i]->external_force(mpm::NodePhase::nSolid)[j] == + REQUIRE(nodes[i]->external_force(mpm::NodePhase::NSolid)[j] == Approx(body_force(i, j)).epsilon(Tolerance)); // Internal force @@ -2595,12 +2595,12 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", // Check nodal internal force for (unsigned i = 0; i < internal_force.rows(); ++i) for (unsigned j = 0; j < internal_force.cols(); ++j) - REQUIRE(nodes[i]->internal_force(mpm::NodePhase::nMixture)[j] == + REQUIRE(nodes[i]->internal_force(mpm::NodePhase::NMixture)[j] == Approx(internal_force(i, j)).epsilon(Tolerance)); // Calculate nodal acceleration and velocity for (const auto& node : nodes) - node->compute_acceleration_velocity(mpm::NodePhase::nSolid, dt); + node->compute_acceleration_velocity(mpm::NodePhase::NSolid, dt); // Check nodal velocity // clang-format off @@ -2616,7 +2616,7 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", // Check nodal velocity for (unsigned i = 0; i < nodal_velocity.rows(); ++i) for (unsigned j = 0; j < nodal_velocity.cols(); ++j) - REQUIRE(nodes[i]->velocity(mpm::NodePhase::nSolid)[j] == + REQUIRE(nodes[i]->velocity(mpm::NodePhase::NSolid)[j] == Approx(nodal_velocity(i, j)).epsilon(Tolerance)); // Check nodal acceleration @@ -2634,7 +2634,7 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", // Check nodal acceleration for (unsigned i = 0; i < nodal_acceleration.rows(); ++i) for (unsigned j = 0; j < nodal_acceleration.cols(); ++j) - REQUIRE(nodes[i]->acceleration(mpm::NodePhase::nSolid)[j] == + REQUIRE(nodes[i]->acceleration(mpm::NodePhase::NSolid)[j] == Approx(nodal_acceleration(i, j)).epsilon(Tolerance)); // Approx(nodal_velocity(i, j) / dt).epsilon(Tolerance)); From 2b195ee93ec34b2fa56549759275404a5111268e Mon Sep 17 00:00:00 2001 From: tianchiTJ <149181511@qq.com> Date: Wed, 4 Nov 2020 09:48:04 -0800 Subject: [PATCH 168/175] Correct the names of nodal phases --- include/node.tcc | 2 +- include/node_base.h | 6 +- include/node_twophase.tcc | 92 +- include/solvers/mpm_explicit_twophase.tcc | 32 +- tests/nodes/node_test.cc | 18 +- tests/nodes/node_twophase_test.cc | 996 +++++++++++----------- tests/particles/particle_twophase_test.cc | 70 +- 7 files changed, 608 insertions(+), 608 deletions(-) diff --git a/include/node.tcc b/include/node.tcc index e4840f1a0..5583ea056 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -626,7 +626,7 @@ void mpm::Node momentum = property_handle_->property("momenta", prop_id_, *mitr, Tdim); const Eigen::Matrix change_in_momenta = - velocity_.col(mpm::NodePhase::nSolid) * mass - momentum; + velocity_.col(mpm::NodePhase::NSolid) * mass - momentum; property_handle_->update_property("change_in_momenta", prop_id_, *mitr, change_in_momenta, Tdim); } diff --git a/include/node_base.h b/include/node_base.h index baae25e1a..e5cf021c8 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -19,10 +19,10 @@ namespace mpm { //! Particle phases enum NodePhase : unsigned int { - nSolid = 0, - nLiquid = 1, + NSolid = 0, + NLiquid = 1, nGas = 2, - nMixture = 0 + NMixture = 0 }; //! NodeBase base class for nodes diff --git a/include/node_twophase.tcc b/include/node_twophase.tcc index 3d153a0eb..d1f6f033e 100644 --- a/include/node_twophase.tcc +++ b/include/node_twophase.tcc @@ -19,26 +19,26 @@ bool mpm::Node:: compute_acceleration_velocity_twophase_explicit(double dt) noexcept { bool status = false; const double tolerance = 1.0E-15; - if (this->mass(mpm::NodePhase::nSolid) > tolerance && - this->mass(mpm::NodePhase::nLiquid) > tolerance) { + if (this->mass(mpm::NodePhase::NSolid) > tolerance && + this->mass(mpm::NodePhase::NLiquid) > tolerance) { // Compute drag force VectorDim drag_force = drag_force_coefficient_.cwiseProduct( - velocity_.col(mpm::NodePhase::nLiquid) - - velocity_.col(mpm::NodePhase::nSolid)); + velocity_.col(mpm::NodePhase::NLiquid) - + velocity_.col(mpm::NodePhase::NSolid)); // Acceleration of pore fluid (momentume balance of fluid phase) - this->acceleration_.col(mpm::NodePhase::nLiquid) = - (this->external_force_.col(mpm::NodePhase::nLiquid) + - this->internal_force_.col(mpm::NodePhase::nLiquid) - drag_force) / - this->mass_(mpm::NodePhase::nLiquid); + this->acceleration_.col(mpm::NodePhase::NLiquid) = + (this->external_force_.col(mpm::NodePhase::NLiquid) + + this->internal_force_.col(mpm::NodePhase::NLiquid) - drag_force) / + this->mass_(mpm::NodePhase::NLiquid); // Acceleration of solid skeleton (momentume balance of mixture) - this->acceleration_.col(mpm::NodePhase::nSolid) = - (this->external_force_.col(mpm::NodePhase::nMixture) + - this->internal_force_.col(mpm::NodePhase::nMixture) - - this->mass_(mpm::NodePhase::nLiquid) * - this->acceleration_.col(mpm::NodePhase::nLiquid)) / - this->mass_(mpm::NodePhase::nSolid); + this->acceleration_.col(mpm::NodePhase::NSolid) = + (this->external_force_.col(mpm::NodePhase::NMixture) + + this->internal_force_.col(mpm::NodePhase::NMixture) - + this->mass_(mpm::NodePhase::NLiquid) * + this->acceleration_.col(mpm::NodePhase::NLiquid)) / + this->mass_(mpm::NodePhase::NSolid); // Apply friction constraints this->apply_friction_constraints(dt); @@ -52,14 +52,14 @@ bool mpm::Node:: // Set a threshold for (unsigned i = 0; i < Tdim; ++i) { - if (std::abs(velocity_.col(mpm::NodePhase::nSolid)(i)) < tolerance) - velocity_.col(mpm::NodePhase::nSolid)(i) = 0.; - if (std::abs(acceleration_.col(mpm::NodePhase::nSolid)(i)) < tolerance) - acceleration_.col(mpm::NodePhase::nSolid)(i) = 0.; - if (std::abs(velocity_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) - velocity_.col(mpm::NodePhase::nLiquid)(i) = 0.; - if (std::abs(acceleration_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) - acceleration_.col(mpm::NodePhase::nLiquid)(i) = 0.; + if (std::abs(velocity_.col(mpm::NodePhase::NSolid)(i)) < tolerance) + velocity_.col(mpm::NodePhase::NSolid)(i) = 0.; + if (std::abs(acceleration_.col(mpm::NodePhase::NSolid)(i)) < tolerance) + acceleration_.col(mpm::NodePhase::NSolid)(i) = 0.; + if (std::abs(velocity_.col(mpm::NodePhase::NLiquid)(i)) < tolerance) + velocity_.col(mpm::NodePhase::NLiquid)(i) = 0.; + if (std::abs(acceleration_.col(mpm::NodePhase::NLiquid)(i)) < tolerance) + acceleration_.col(mpm::NodePhase::NLiquid)(i) = 0.; } status = true; } @@ -74,36 +74,36 @@ bool mpm::Node:: bool status = false; const double tolerance = 1.0E-15; - if (this->mass(mpm::NodePhase::nSolid) > tolerance && - this->mass(mpm::NodePhase::nLiquid) > tolerance) { + if (this->mass(mpm::NodePhase::NSolid) > tolerance && + this->mass(mpm::NodePhase::NLiquid) > tolerance) { // Compute drag force VectorDim drag_force = drag_force_coefficient_.cwiseProduct( - velocity_.col(mpm::NodePhase::nLiquid) - - velocity_.col(mpm::NodePhase::nSolid)); + velocity_.col(mpm::NodePhase::NLiquid) - + velocity_.col(mpm::NodePhase::NSolid)); // Unbalanced force of liquid phase auto unbalanced_force_liquid = - this->external_force_.col(mpm::NodePhase::nLiquid) + - this->internal_force_.col(mpm::NodePhase::nLiquid) - drag_force; + this->external_force_.col(mpm::NodePhase::NLiquid) + + this->internal_force_.col(mpm::NodePhase::NLiquid) - drag_force; // Acceleration of liquid phase (momentume balance of fluid phase) - this->acceleration_.col(mpm::NodePhase::nLiquid) = + this->acceleration_.col(mpm::NodePhase::NLiquid) = (unbalanced_force_liquid - damping_factor * unbalanced_force_liquid.norm() * - this->velocity_.col(mpm::NodePhase::nLiquid).cwiseSign()) / - this->mass(mpm::NodePhase::nLiquid); + this->velocity_.col(mpm::NodePhase::NLiquid).cwiseSign()) / + this->mass(mpm::NodePhase::NLiquid); // Unbalanced force of solid phase auto unbalanced_force_solid = - this->external_force_.col(mpm::NodePhase::nMixture) + - this->internal_force_.col(mpm::NodePhase::nMixture) - - this->mass_(mpm::NodePhase::nLiquid) * - this->acceleration_.col(mpm::NodePhase::nLiquid); + this->external_force_.col(mpm::NodePhase::NMixture) + + this->internal_force_.col(mpm::NodePhase::NMixture) - + this->mass_(mpm::NodePhase::NLiquid) * + this->acceleration_.col(mpm::NodePhase::NLiquid); // Acceleration of solid phase (momentume balance of mixture) - this->acceleration_.col(mpm::NodePhase::nSolid) = + this->acceleration_.col(mpm::NodePhase::NSolid) = (unbalanced_force_solid - damping_factor * unbalanced_force_solid.norm() * - this->velocity_.col(mpm::NodePhase::nSolid).cwiseSign()) / - this->mass(mpm::NodePhase::nSolid); + this->velocity_.col(mpm::NodePhase::NSolid).cwiseSign()) / + this->mass(mpm::NodePhase::NSolid); // Apply friction constraints this->apply_friction_constraints(dt); @@ -117,14 +117,14 @@ bool mpm::Node:: // Set a threshold for (unsigned i = 0; i < Tdim; ++i) { - if (std::abs(velocity_.col(mpm::NodePhase::nSolid)(i)) < tolerance) - velocity_.col(mpm::NodePhase::nSolid)(i) = 0.; - if (std::abs(acceleration_.col(mpm::NodePhase::nSolid)(i)) < tolerance) - acceleration_.col(mpm::NodePhase::nSolid)(i) = 0.; - if (std::abs(velocity_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) - velocity_.col(mpm::NodePhase::nLiquid)(i) = 0.; - if (std::abs(acceleration_.col(mpm::NodePhase::nLiquid)(i)) < tolerance) - acceleration_.col(mpm::NodePhase::nLiquid)(i) = 0.; + if (std::abs(velocity_.col(mpm::NodePhase::NSolid)(i)) < tolerance) + velocity_.col(mpm::NodePhase::NSolid)(i) = 0.; + if (std::abs(acceleration_.col(mpm::NodePhase::NSolid)(i)) < tolerance) + acceleration_.col(mpm::NodePhase::NSolid)(i) = 0.; + if (std::abs(velocity_.col(mpm::NodePhase::NLiquid)(i)) < tolerance) + velocity_.col(mpm::NodePhase::NLiquid)(i) = 0.; + if (std::abs(acceleration_.col(mpm::NodePhase::NLiquid)(i)) < tolerance) + acceleration_.col(mpm::NodePhase::NLiquid)(i) = 0.; } status = true; } diff --git a/include/solvers/mpm_explicit_twophase.tcc b/include/solvers/mpm_explicit_twophase.tcc index debb780db..822e8394e 100644 --- a/include/solvers/mpm_explicit_twophase.tcc +++ b/include/solvers/mpm_explicit_twophase.tcc @@ -161,29 +161,29 @@ bool mpm::MPMExplicitTwoPhase::solve() { // MPI all reduce nodal mass for solid phase mesh_->template nodal_halo_exchange( std::bind(&mpm::NodeBase::mass, std::placeholders::_1, - mpm::NodePhase::nSolid), + mpm::NodePhase::NSolid), std::bind(&mpm::NodeBase::update_mass, std::placeholders::_1, - false, mpm::NodePhase::nSolid, std::placeholders::_2)); + false, mpm::NodePhase::NSolid, std::placeholders::_2)); // MPI all reduce nodal momentum for solid phase mesh_->template nodal_halo_exchange, Tdim>( std::bind(&mpm::NodeBase::momentum, std::placeholders::_1, - mpm::NodePhase::nSolid), + mpm::NodePhase::NSolid), std::bind(&mpm::NodeBase::update_momentum, - std::placeholders::_1, false, mpm::NodePhase::nSolid, + std::placeholders::_1, false, mpm::NodePhase::NSolid, std::placeholders::_2)); // MPI all reduce nodal mass for liquid phase mesh_->template nodal_halo_exchange( std::bind(&mpm::NodeBase::mass, std::placeholders::_1, - mpm::NodePhase::nLiquid), + mpm::NodePhase::NLiquid), std::bind(&mpm::NodeBase::update_mass, std::placeholders::_1, - false, mpm::NodePhase::nLiquid, std::placeholders::_2)); + false, mpm::NodePhase::NLiquid, std::placeholders::_2)); // MPI all reduce nodal momentum for liquid phase mesh_->template nodal_halo_exchange, Tdim>( std::bind(&mpm::NodeBase::momentum, std::placeholders::_1, - mpm::NodePhase::nLiquid), + mpm::NodePhase::NLiquid), std::bind(&mpm::NodeBase::update_momentum, - std::placeholders::_1, false, mpm::NodePhase::nLiquid, + std::placeholders::_1, false, mpm::NodePhase::NLiquid, std::placeholders::_2)); } #endif @@ -263,31 +263,31 @@ bool mpm::MPMExplicitTwoPhase::solve() { // MPI all reduce external force of mixture mesh_->template nodal_halo_exchange, Tdim>( std::bind(&mpm::NodeBase::external_force, std::placeholders::_1, - mpm::NodePhase::nMixture), + mpm::NodePhase::NMixture), std::bind(&mpm::NodeBase::update_external_force, - std::placeholders::_1, false, mpm::NodePhase::nMixture, + std::placeholders::_1, false, mpm::NodePhase::NMixture, std::placeholders::_2)); // MPI all reduce external force of pore fluid mesh_->template nodal_halo_exchange, Tdim>( std::bind(&mpm::NodeBase::external_force, std::placeholders::_1, - mpm::NodePhase::nLiquid), + mpm::NodePhase::NLiquid), std::bind(&mpm::NodeBase::update_external_force, - std::placeholders::_1, false, mpm::NodePhase::nLiquid, + std::placeholders::_1, false, mpm::NodePhase::NLiquid, std::placeholders::_2)); // MPI all reduce internal force of mixture mesh_->template nodal_halo_exchange, Tdim>( std::bind(&mpm::NodeBase::internal_force, std::placeholders::_1, - mpm::NodePhase::nMixture), + mpm::NodePhase::NMixture), std::bind(&mpm::NodeBase::update_internal_force, - std::placeholders::_1, false, mpm::NodePhase::nMixture, + std::placeholders::_1, false, mpm::NodePhase::NMixture, std::placeholders::_2)); // MPI all reduce internal force of pore liquid mesh_->template nodal_halo_exchange, Tdim>( std::bind(&mpm::NodeBase::internal_force, std::placeholders::_1, - mpm::NodePhase::nLiquid), + mpm::NodePhase::NLiquid), std::bind(&mpm::NodeBase::update_internal_force, - std::placeholders::_1, false, mpm::NodePhase::nLiquid, + std::placeholders::_1, false, mpm::NodePhase::NLiquid, std::placeholders::_2)); // MPI all reduce drag force diff --git a/tests/nodes/node_test.cc b/tests/nodes/node_test.cc index 7552300eb..8b2d4968d 100644 --- a/tests/nodes/node_test.cc +++ b/tests/nodes/node_test.cc @@ -159,13 +159,13 @@ TEST_CASE("Node is checked for 1D case", "[node][1D]") { // Check pressure constraints SECTION("Check nodal pressure constraints") { // Check assign pressure constraint - REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::nSolid, 8000, + REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::NSolid, 8000, nullptr) == true); // Check apply pressure constraint REQUIRE_NOTHROW( - node->apply_pressure_constraint(mpm::NodePhase::nSolid)); + node->apply_pressure_constraint(mpm::NodePhase::NSolid)); // Check pressure - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(8000).epsilon(Tolerance)); } } @@ -636,13 +636,13 @@ TEST_CASE("Node is checked for 2D case", "[node][2D]") { // Check pressure constraints SECTION("Check nodal pressure constraints") { // Check assign pressure constraint - REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::nSolid, 8000, + REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::NSolid, 8000, nullptr) == true); // Check apply pressure constraint REQUIRE_NOTHROW( - node->apply_pressure_constraint(mpm::NodePhase::nSolid)); + node->apply_pressure_constraint(mpm::NodePhase::NSolid)); // Check pressure - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(8000).epsilon(Tolerance)); } } @@ -1250,13 +1250,13 @@ TEST_CASE("Node is checked for 3D case", "[node][3D]") { // Check pressure constraints SECTION("Check nodal pressure constraints") { // Check assign pressure constraint - REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::nSolid, 8000, + REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::NSolid, 8000, nullptr) == true); // Check apply pressure constraint REQUIRE_NOTHROW( - node->apply_pressure_constraint(mpm::NodePhase::nSolid)); + node->apply_pressure_constraint(mpm::NodePhase::NSolid)); // Check pressure - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(8000).epsilon(Tolerance)); } } diff --git a/tests/nodes/node_twophase_test.cc b/tests/nodes/node_twophase_test.cc index eebb0182c..d5fa22f1f 100644 --- a/tests/nodes/node_twophase_test.cc +++ b/tests/nodes/node_twophase_test.cc @@ -121,111 +121,111 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { std::make_shared>(id, coords); // Check mass - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(0.0).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(0.0).epsilon(Tolerance)); double solid_mass = 100.5; double liquid_mass = 200.5; // Update mass to 100.5 and 200.5 REQUIRE_NOTHROW( - node->update_mass(true, mpm::NodePhase::nSolid, solid_mass)); + node->update_mass(true, mpm::NodePhase::NSolid, solid_mass)); REQUIRE_NOTHROW( - node->update_mass(true, mpm::NodePhase::nLiquid, liquid_mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + node->update_mass(true, mpm::NodePhase::NLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(100.5).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(200.5).epsilon(Tolerance)); // Update mass to 201 and 401 REQUIRE_NOTHROW( - node->update_mass(true, mpm::NodePhase::nSolid, solid_mass)); + node->update_mass(true, mpm::NodePhase::NSolid, solid_mass)); REQUIRE_NOTHROW( - node->update_mass(true, mpm::NodePhase::nLiquid, liquid_mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + node->update_mass(true, mpm::NodePhase::NLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(201.0).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(401.0).epsilon(Tolerance)); // Assign mass to 100 and 200 solid_mass = 100.; liquid_mass = 200.; REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nSolid, solid_mass)); + node->update_mass(false, mpm::NodePhase::NSolid, solid_mass)); REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nLiquid, liquid_mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + node->update_mass(false, mpm::NodePhase::NLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(100.0).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(200.0).epsilon(Tolerance)); SECTION("Check nodal pressure") { // Check pressure - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(0.0).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(0.0).epsilon(Tolerance)); double pressure = 1000.7; double pore_pressure = 2000.7; // Update pressure to 1000.7 and 2000.7 - REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nSolid, + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::NSolid, solid_mass * pressure)); - REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nLiquid, + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::NLiquid, liquid_mass * pore_pressure)); - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(1000.7).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(2000.7).epsilon(Tolerance)); // Update pressure to 2001.4 and 4001.4 - REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nSolid, + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::NSolid, solid_mass * pressure)); - REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nLiquid, + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::NLiquid, liquid_mass * pore_pressure)); - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(2001.4).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(4001.4).epsilon(Tolerance)); // Assign pressure to 1000 and 2000 pressure = 1000.; pore_pressure = 2000.; - node->assign_pressure(mpm::NodePhase::nSolid, pressure); - node->assign_pressure(mpm::NodePhase::nLiquid, pore_pressure); - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + node->assign_pressure(mpm::NodePhase::NSolid, pressure); + node->assign_pressure(mpm::NodePhase::NLiquid, pore_pressure); + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(1000.0).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(2000.0).epsilon(Tolerance)); // Assign mass to 0 solid_mass = 0.; liquid_mass = 0.; REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nSolid, solid_mass)); + node->update_mass(false, mpm::NodePhase::NSolid, solid_mass)); REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nLiquid, liquid_mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + node->update_mass(false, mpm::NodePhase::NLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(0.0).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(0.0).epsilon(Tolerance)); // Try to update pressure to 2000, should throw and keep to 1000. - node->assign_pressure(mpm::NodePhase::nSolid, pressure); - node->assign_pressure(mpm::NodePhase::nLiquid, pore_pressure); - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + node->assign_pressure(mpm::NodePhase::NSolid, pressure); + node->assign_pressure(mpm::NodePhase::NLiquid, pore_pressure); + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(1000.0).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(2000.0).epsilon(Tolerance)); // Check pressure constraints SECTION("Check nodal pressure constraints") { // Check assign pressure constraint - REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::nSolid, 8000, + REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::NSolid, 8000, nullptr) == true); - REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::nLiquid, 7000, + REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::NLiquid, 7000, nullptr) == true); // Check apply pressure constraint REQUIRE_NOTHROW( - node->apply_pressure_constraint(mpm::NodePhase::nSolid)); + node->apply_pressure_constraint(mpm::NodePhase::NSolid)); REQUIRE_NOTHROW( - node->apply_pressure_constraint(mpm::NodePhase::nLiquid)); + node->apply_pressure_constraint(mpm::NodePhase::NLiquid)); // Check pressure - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(8000).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(7000).epsilon(Tolerance)); } } @@ -237,45 +237,45 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { // Check current external force is zero for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NLiquid)(i) == Approx(0.).epsilon(Tolerance)); } // Update force to 10.0 REQUIRE_NOTHROW( - node->update_external_force(true, mpm::NodePhase::nMixture, force)); - REQUIRE_NOTHROW(node->update_external_force(true, mpm::NodePhase::nLiquid, + node->update_external_force(true, mpm::NodePhase::NMixture, force)); + REQUIRE_NOTHROW(node->update_external_force(true, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NLiquid)(i) == Approx(5.).epsilon(Tolerance)); } // Update force to 20.0 REQUIRE_NOTHROW( - node->update_external_force(true, mpm::NodePhase::nMixture, force)); - REQUIRE_NOTHROW(node->update_external_force(true, mpm::NodePhase::nLiquid, + node->update_external_force(true, mpm::NodePhase::NMixture, force)); + REQUIRE_NOTHROW(node->update_external_force(true, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(20.).epsilon(Tolerance)); - REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NLiquid)(i) == Approx(10.).epsilon(Tolerance)); } // Assign force as 10.0 REQUIRE_NOTHROW( - node->update_external_force(false, mpm::NodePhase::nMixture, force)); + node->update_external_force(false, mpm::NodePhase::NMixture, force)); REQUIRE_NOTHROW(node->update_external_force( - false, mpm::NodePhase::nLiquid, 0.5 * force)); + false, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NLiquid)(i) == Approx(5.).epsilon(Tolerance)); } @@ -283,7 +283,7 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { // Set external force to zero force.setZero(); REQUIRE_NOTHROW(node->update_external_force( - false, mpm::NodePhase::nMixture, force)); + false, mpm::NodePhase::NMixture, force)); // concentrated force std::shared_ptr ffunction = nullptr; @@ -291,38 +291,38 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { const unsigned Direction = 0; // Check external force for (unsigned i = 0; i < Dim; ++i) - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->assign_concentrated_force(mpm::NodePhase::nMixture, + REQUIRE(node->assign_concentrated_force(mpm::NodePhase::NMixture, Direction, concentrated_force, ffunction) == true); double current_time = 0.0; - node->apply_concentrated_force(mpm::NodePhase::nMixture, current_time); + node->apply_concentrated_force(mpm::NodePhase::NMixture, current_time); for (unsigned i = 0; i < Dim; ++i) { if (i == Direction) - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(concentrated_force).epsilon(Tolerance)); else - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(0.).epsilon(Tolerance)); } // Check for incorrect direction / phase const unsigned wrong_dir = 4; - REQUIRE(node->assign_concentrated_force(mpm::NodePhase::nMixture, + REQUIRE(node->assign_concentrated_force(mpm::NodePhase::NMixture, wrong_dir, concentrated_force, ffunction) == false); // Check again to ensure value hasn't been updated for (unsigned i = 0; i < Dim; ++i) { if (i == Direction) - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(concentrated_force).epsilon(Tolerance)); else - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(0.).epsilon(Tolerance)); } } @@ -335,45 +335,45 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { // Check current internal force is zero for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NMixture)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NLiquid)(i) == Approx(0.).epsilon(Tolerance)); } // Update force to 10.0 REQUIRE_NOTHROW( - node->update_internal_force(true, mpm::NodePhase::nMixture, force)); - REQUIRE_NOTHROW(node->update_internal_force(true, mpm::NodePhase::nLiquid, + node->update_internal_force(true, mpm::NodePhase::NMixture, force)); + REQUIRE_NOTHROW(node->update_internal_force(true, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NMixture)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NLiquid)(i) == Approx(5.).epsilon(Tolerance)); } // Update force to 20.0 REQUIRE_NOTHROW( - node->update_internal_force(true, mpm::NodePhase::nMixture, force)); - REQUIRE_NOTHROW(node->update_internal_force(true, mpm::NodePhase::nLiquid, + node->update_internal_force(true, mpm::NodePhase::NMixture, force)); + REQUIRE_NOTHROW(node->update_internal_force(true, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NMixture)(i) == Approx(20.).epsilon(Tolerance)); - REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NLiquid)(i) == Approx(10.).epsilon(Tolerance)); } // Assign force as 10.0 REQUIRE_NOTHROW( - node->update_internal_force(false, mpm::NodePhase::nMixture, force)); + node->update_internal_force(false, mpm::NodePhase::NMixture, force)); REQUIRE_NOTHROW(node->update_internal_force( - false, mpm::NodePhase::nLiquid, 0.5 * force)); + false, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NMixture)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NLiquid)(i) == Approx(5.).epsilon(Tolerance)); } } @@ -422,12 +422,12 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { double liquid_mass = 100.; // Update mass to 100.5 REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nSolid, solid_mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + node->update_mass(false, mpm::NodePhase::NSolid, solid_mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(solid_mass).epsilon(Tolerance)); REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nLiquid, liquid_mass)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + node->update_mass(false, mpm::NodePhase::NLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(liquid_mass).epsilon(Tolerance)); // Check internal force @@ -436,14 +436,14 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { for (unsigned i = 0; i < force.size(); ++i) force(i) = 10. * i; // Update force to 10.0 REQUIRE_NOTHROW( - node->update_internal_force(false, mpm::NodePhase::nMixture, force)); + node->update_internal_force(false, mpm::NodePhase::NMixture, force)); REQUIRE_NOTHROW(node->update_internal_force( - false, mpm::NodePhase::nLiquid, 0.5 * force)); + false, mpm::NodePhase::NLiquid, 0.5 * force)); // Internal force for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NMixture)(i) == Approx(force(i)).epsilon(Tolerance)); - REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NLiquid)(i) == Approx(0.5 * force(i)).epsilon(Tolerance)); } @@ -451,13 +451,13 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { for (unsigned i = 0; i < force.size(); ++i) force(i) = 5. * i; // Update force to 10.0 REQUIRE_NOTHROW( - node->update_external_force(false, mpm::NodePhase::nMixture, force)); + node->update_external_force(false, mpm::NodePhase::NMixture, force)); REQUIRE_NOTHROW(node->update_external_force( - false, mpm::NodePhase::nLiquid, 0.5 * force)); + false, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(force(i)).epsilon(Tolerance)); - REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NLiquid)(i) == Approx(0.5 * force(i)).epsilon(Tolerance)); } @@ -482,9 +482,9 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { solid_acceleration << 0.; for (unsigned i = 0; i < solid_acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(solid_acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(liquid_acceleration(i)).epsilon(Tolerance)); } @@ -492,9 +492,9 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { Eigen::Matrix solid_velocity = solid_acceleration * dt; Eigen::Matrix liquid_velocity = liquid_acceleration * dt; for (unsigned i = 0; i < solid_velocity.size(); ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(solid_velocity(i)).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(liquid_velocity(i)).epsilon(Tolerance)); } @@ -508,9 +508,9 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { solid_acceleration[0] = 0.5 * solid_acceleration[0]; liquid_acceleration[0] = 0.5 * liquid_acceleration[0]; for (unsigned i = 0; i < solid_acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(solid_acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(liquid_acceleration(i)).epsilon(Tolerance)); } @@ -522,9 +522,9 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { solid_acceleration[0] = 0.; liquid_acceleration[0] = 0.; for (unsigned i = 0; i < solid_acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(solid_acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(liquid_acceleration(i)).epsilon(Tolerance)); } @@ -538,9 +538,9 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { solid_velocity[0] = 10.5; liquid_velocity[0] = 10.5; for (unsigned i = 0; i < solid_velocity.size(); ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(solid_velocity(i)).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(liquid_velocity(i)).epsilon(Tolerance)); } @@ -548,19 +548,19 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { solid_acceleration[0] = 0.; liquid_acceleration[0] = 0.; for (unsigned i = 0; i < solid_acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(solid_acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(liquid_acceleration(i)).epsilon(Tolerance)); } // Exception check when mass is zero // Update mass to 0. - REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nSolid, 0.)); - REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nLiquid, 0.)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::NSolid, 0.)); + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::NLiquid, 0.)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(0.).epsilon(Tolerance)); REQUIRE(node->compute_acceleration_velocity_twophase_explicit(dt) == false); @@ -573,82 +573,82 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { // Check initial momentum for (unsigned i = 0; i < momentum.size(); ++i) { - REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NSolid)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NLiquid)(i) == Approx(0.).epsilon(Tolerance)); } // Check update momentum to 10 REQUIRE_NOTHROW( - node->update_momentum(true, mpm::NodePhase::nSolid, momentum)); + node->update_momentum(true, mpm::NodePhase::NSolid, momentum)); REQUIRE_NOTHROW( - node->update_momentum(true, mpm::NodePhase::nLiquid, momentum)); + node->update_momentum(true, mpm::NodePhase::NLiquid, momentum)); for (unsigned i = 0; i < momentum.size(); ++i) { - REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NSolid)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NLiquid)(i) == Approx(10.).epsilon(Tolerance)); } // Check update momentum to 20 REQUIRE_NOTHROW( - node->update_momentum(true, mpm::NodePhase::nSolid, momentum)); + node->update_momentum(true, mpm::NodePhase::NSolid, momentum)); REQUIRE_NOTHROW( - node->update_momentum(true, mpm::NodePhase::nLiquid, momentum)); + node->update_momentum(true, mpm::NodePhase::NLiquid, momentum)); for (unsigned i = 0; i < momentum.size(); ++i) { - REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NSolid)(i) == Approx(20.).epsilon(Tolerance)); - REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NLiquid)(i) == Approx(20.).epsilon(Tolerance)); } // Check assign momentum to 10 REQUIRE_NOTHROW( - node->update_momentum(false, mpm::NodePhase::nSolid, momentum)); + node->update_momentum(false, mpm::NodePhase::NSolid, momentum)); REQUIRE_NOTHROW( - node->update_momentum(false, mpm::NodePhase::nLiquid, momentum)); + node->update_momentum(false, mpm::NodePhase::NLiquid, momentum)); for (unsigned i = 0; i < momentum.size(); ++i) { - REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NSolid)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NLiquid)(i) == Approx(10.).epsilon(Tolerance)); } // Check zero velocity for (unsigned i = 0; i < Dim; ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(0.).epsilon(Tolerance)); } // Check mass double mass = 0.; - REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nSolid, mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::NSolid, mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(0.0).epsilon(Tolerance)); - REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nLiquid, mass)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::NLiquid, mass)); + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(0.0).epsilon(Tolerance)); // Compute and check velocity this should throw zero mass node->compute_velocity(); mass = 100.; // Update mass to 100. - REQUIRE_NOTHROW(node->update_mass(true, mpm::NodePhase::nSolid, mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + REQUIRE_NOTHROW(node->update_mass(true, mpm::NodePhase::NSolid, mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(100.).epsilon(Tolerance)); - REQUIRE_NOTHROW(node->update_mass(true, mpm::NodePhase::nLiquid, mass)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE_NOTHROW(node->update_mass(true, mpm::NodePhase::NLiquid, mass)); + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(100.).epsilon(Tolerance)); // Compute and check velocity node->compute_velocity(); for (unsigned i = 0; i < Dim; ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(0.1).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(0.1).epsilon(Tolerance)); } @@ -661,9 +661,9 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { Eigen::Matrix velocity; velocity << 0.1; for (unsigned i = 0; i < velocity.size(); ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(velocity(i)).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(velocity(i)).epsilon(Tolerance)); } @@ -673,9 +673,9 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { // Check apply constraints velocity << 10.5; for (unsigned i = 0; i < velocity.size(); ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(velocity(i)).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(velocity(i)).epsilon(Tolerance)); } } @@ -686,21 +686,21 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { for (unsigned i = 0; i < acceleration.size(); ++i) acceleration(i) = 5.; for (unsigned i = 0; i < acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(0.).epsilon(Tolerance)); } - REQUIRE_NOTHROW(node->update_acceleration(true, mpm::NodePhase::nSolid, + REQUIRE_NOTHROW(node->update_acceleration(true, mpm::NodePhase::NSolid, acceleration)); - REQUIRE_NOTHROW(node->update_acceleration(true, mpm::NodePhase::nLiquid, + REQUIRE_NOTHROW(node->update_acceleration(true, mpm::NodePhase::NLiquid, 0.5 * acceleration)); for (unsigned i = 0; i < acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(5.).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(2.5).epsilon(Tolerance)); } @@ -713,9 +713,9 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { acceleration.resize(Dim); acceleration << 5.; for (unsigned i = 0; i < acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(0.5 * acceleration(i)).epsilon(Tolerance)); } @@ -725,9 +725,9 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { // Check apply constraints acceleration << 0.0; for (unsigned i = 0; i < acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); } } @@ -866,135 +866,135 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { std::make_shared>(id, coords); // Check mass - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(0.0).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(0.0).epsilon(Tolerance)); double solid_mass = 100.5; double liquid_mass = 200.5; // Update mass to 100.5 and 200.5 REQUIRE_NOTHROW( - node->update_mass(true, mpm::NodePhase::nSolid, solid_mass)); + node->update_mass(true, mpm::NodePhase::NSolid, solid_mass)); REQUIRE_NOTHROW( - node->update_mass(true, mpm::NodePhase::nLiquid, liquid_mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + node->update_mass(true, mpm::NodePhase::NLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(100.5).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(200.5).epsilon(Tolerance)); // Update mass to 201 and 401 REQUIRE_NOTHROW( - node->update_mass(true, mpm::NodePhase::nSolid, solid_mass)); + node->update_mass(true, mpm::NodePhase::NSolid, solid_mass)); REQUIRE_NOTHROW( - node->update_mass(true, mpm::NodePhase::nLiquid, liquid_mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + node->update_mass(true, mpm::NodePhase::NLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(201.0).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(401.0).epsilon(Tolerance)); // Assign mass to 100 and 200 solid_mass = 100.; liquid_mass = 200.; REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nSolid, solid_mass)); + node->update_mass(false, mpm::NodePhase::NSolid, solid_mass)); REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nLiquid, liquid_mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + node->update_mass(false, mpm::NodePhase::NLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(100.0).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(200.0).epsilon(Tolerance)); SECTION("Check nodal pressure") { // Check pressure - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(0.0).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(0.0).epsilon(Tolerance)); double pressure = 1000.7; double pore_pressure = 2000.7; // Update pressure to 1000.7 and 2000.7 - REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nSolid, + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::NSolid, solid_mass * pressure)); - REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nLiquid, + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::NLiquid, liquid_mass * pore_pressure)); - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(1000.7).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(2000.7).epsilon(Tolerance)); // Update pressure to 2001.4 and 4001.4 - REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nSolid, + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::NSolid, solid_mass * pressure)); - REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nLiquid, + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::NLiquid, liquid_mass * pore_pressure)); - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(2001.4).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(4001.4).epsilon(Tolerance)); // Assign pressure to 1000 and 2000 pressure = 1000.; pore_pressure = 2000.; - node->assign_pressure(mpm::NodePhase::nSolid, pressure); - node->assign_pressure(mpm::NodePhase::nLiquid, pore_pressure); - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + node->assign_pressure(mpm::NodePhase::NSolid, pressure); + node->assign_pressure(mpm::NodePhase::NLiquid, pore_pressure); + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(1000.0).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(2000.0).epsilon(Tolerance)); // Assign mass to 0 solid_mass = 0.; liquid_mass = 0.; REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nSolid, solid_mass)); + node->update_mass(false, mpm::NodePhase::NSolid, solid_mass)); REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nLiquid, liquid_mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + node->update_mass(false, mpm::NodePhase::NLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(0.0).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(0.0).epsilon(Tolerance)); // Try to update pressure to 2000, should throw and keep to 1000. - node->assign_pressure(mpm::NodePhase::nSolid, pressure); - node->assign_pressure(mpm::NodePhase::nLiquid, pore_pressure); - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + node->assign_pressure(mpm::NodePhase::NSolid, pressure); + node->assign_pressure(mpm::NodePhase::NLiquid, pore_pressure); + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(1000.0).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(2000.0).epsilon(Tolerance)); // Check pressure constraints SECTION("Check nodal pressure constraints") { // Check assign pressure constraint - REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::nSolid, 8000, + REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::NSolid, 8000, nullptr) == true); - REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::nLiquid, 7000, + REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::NLiquid, 7000, nullptr) == true); // Check apply pressure constraint REQUIRE_NOTHROW( - node->apply_pressure_constraint(mpm::NodePhase::nSolid)); + node->apply_pressure_constraint(mpm::NodePhase::NSolid)); REQUIRE_NOTHROW( - node->apply_pressure_constraint(mpm::NodePhase::nLiquid)); + node->apply_pressure_constraint(mpm::NodePhase::NLiquid)); // Check pressure - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(8000).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(7000).epsilon(Tolerance)); } } SECTION("Check volume") { // Check volume - REQUIRE(node->volume(mpm::NodePhase::nMixture) == + REQUIRE(node->volume(mpm::NodePhase::NMixture) == Approx(0.0).epsilon(Tolerance)); double volume = 100.5; // Update volume to 100.5 REQUIRE_NOTHROW( - node->update_volume(true, mpm::NodePhase::nMixture, volume)); - REQUIRE(node->volume(mpm::NodePhase::nMixture) == + node->update_volume(true, mpm::NodePhase::NMixture, volume)); + REQUIRE(node->volume(mpm::NodePhase::NMixture) == Approx(100.5).epsilon(Tolerance)); // Update volume to 201 REQUIRE_NOTHROW( - node->update_volume(true, mpm::NodePhase::nMixture, volume)); - REQUIRE(node->volume(mpm::NodePhase::nMixture) == + node->update_volume(true, mpm::NodePhase::NMixture, volume)); + REQUIRE(node->volume(mpm::NodePhase::NMixture) == Approx(201.0).epsilon(Tolerance)); // Assign volume to 100 volume = 100.; REQUIRE_NOTHROW( - node->update_volume(false, mpm::NodePhase::nMixture, volume)); - REQUIRE(node->volume(mpm::NodePhase::nMixture) == + node->update_volume(false, mpm::NodePhase::NMixture, volume)); + REQUIRE(node->volume(mpm::NodePhase::NMixture) == Approx(100.0).epsilon(Tolerance)); } @@ -1005,45 +1005,45 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { // Check current external force is zero for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NLiquid)(i) == Approx(0.).epsilon(Tolerance)); } // Update force to 10.0 REQUIRE_NOTHROW( - node->update_external_force(true, mpm::NodePhase::nMixture, force)); - REQUIRE_NOTHROW(node->update_external_force(true, mpm::NodePhase::nLiquid, + node->update_external_force(true, mpm::NodePhase::NMixture, force)); + REQUIRE_NOTHROW(node->update_external_force(true, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NLiquid)(i) == Approx(5.).epsilon(Tolerance)); } // Update force to 20.0 REQUIRE_NOTHROW( - node->update_external_force(true, mpm::NodePhase::nMixture, force)); - REQUIRE_NOTHROW(node->update_external_force(true, mpm::NodePhase::nLiquid, + node->update_external_force(true, mpm::NodePhase::NMixture, force)); + REQUIRE_NOTHROW(node->update_external_force(true, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(20.).epsilon(Tolerance)); - REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NLiquid)(i) == Approx(10.).epsilon(Tolerance)); } // Assign force as 10.0 REQUIRE_NOTHROW( - node->update_external_force(false, mpm::NodePhase::nMixture, force)); + node->update_external_force(false, mpm::NodePhase::NMixture, force)); REQUIRE_NOTHROW(node->update_external_force( - false, mpm::NodePhase::nLiquid, 0.5 * force)); + false, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NLiquid)(i) == Approx(5.).epsilon(Tolerance)); } @@ -1051,7 +1051,7 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { // Set external force to zero force.setZero(); REQUIRE_NOTHROW(node->update_external_force( - false, mpm::NodePhase::nMixture, force)); + false, mpm::NodePhase::NMixture, force)); // Concentrated force std::shared_ptr ffunction = nullptr; @@ -1059,38 +1059,38 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { const unsigned Direction = 0; // Check traction for (unsigned i = 0; i < Dim; ++i) - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->assign_concentrated_force(mpm::NodePhase::nMixture, + REQUIRE(node->assign_concentrated_force(mpm::NodePhase::NMixture, Direction, concentrated_force, ffunction) == true); double current_time = 0.0; - node->apply_concentrated_force(mpm::NodePhase::nMixture, current_time); + node->apply_concentrated_force(mpm::NodePhase::NMixture, current_time); for (unsigned i = 0; i < Dim; ++i) { if (i == Direction) - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(concentrated_force).epsilon(Tolerance)); else - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(0.).epsilon(Tolerance)); } // Check for incorrect direction / phase const unsigned wrong_dir = 4; - REQUIRE(node->assign_concentrated_force(mpm::NodePhase::nMixture, + REQUIRE(node->assign_concentrated_force(mpm::NodePhase::NMixture, wrong_dir, concentrated_force, ffunction) == false); // Check again to ensure value hasn't been updated for (unsigned i = 0; i < Dim; ++i) { if (i == Direction) - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(concentrated_force).epsilon(Tolerance)); else - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(0.).epsilon(Tolerance)); } } @@ -1103,45 +1103,45 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { // Check current internal force is zero for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NMixture)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NLiquid)(i) == Approx(0.).epsilon(Tolerance)); } // Update force to 10.0 REQUIRE_NOTHROW( - node->update_internal_force(true, mpm::NodePhase::nMixture, force)); - REQUIRE_NOTHROW(node->update_internal_force(true, mpm::NodePhase::nLiquid, + node->update_internal_force(true, mpm::NodePhase::NMixture, force)); + REQUIRE_NOTHROW(node->update_internal_force(true, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NMixture)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NLiquid)(i) == Approx(5.).epsilon(Tolerance)); } // Update force to 20.0 REQUIRE_NOTHROW( - node->update_internal_force(true, mpm::NodePhase::nMixture, force)); - REQUIRE_NOTHROW(node->update_internal_force(true, mpm::NodePhase::nLiquid, + node->update_internal_force(true, mpm::NodePhase::NMixture, force)); + REQUIRE_NOTHROW(node->update_internal_force(true, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NMixture)(i) == Approx(20.).epsilon(Tolerance)); - REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NLiquid)(i) == Approx(10.).epsilon(Tolerance)); } // Assign force as 10.0 REQUIRE_NOTHROW( - node->update_internal_force(false, mpm::NodePhase::nMixture, force)); + node->update_internal_force(false, mpm::NodePhase::NMixture, force)); REQUIRE_NOTHROW(node->update_internal_force( - false, mpm::NodePhase::nLiquid, 0.5 * force)); + false, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NMixture)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NLiquid)(i) == Approx(5.).epsilon(Tolerance)); } } @@ -1190,12 +1190,12 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { double liquid_mass = 100.; // Update mass to 100. REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nSolid, solid_mass)); + node->update_mass(false, mpm::NodePhase::NSolid, solid_mass)); REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nLiquid, liquid_mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + node->update_mass(false, mpm::NodePhase::NLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(solid_mass).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(liquid_mass).epsilon(Tolerance)); // Check internal force @@ -1204,14 +1204,14 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { for (unsigned i = 0; i < force.size(); ++i) force(i) = 10. * i; // Update force to 10.0 REQUIRE_NOTHROW( - node->update_internal_force(false, mpm::NodePhase::nMixture, force)); + node->update_internal_force(false, mpm::NodePhase::NMixture, force)); REQUIRE_NOTHROW(node->update_internal_force( - false, mpm::NodePhase::nLiquid, 0.5 * force)); + false, mpm::NodePhase::NLiquid, 0.5 * force)); // Internal force for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NMixture)(i) == Approx(force(i)).epsilon(Tolerance)); - REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NLiquid)(i) == Approx(0.5 * force(i)).epsilon(Tolerance)); } @@ -1219,13 +1219,13 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { for (unsigned i = 0; i < force.size(); ++i) force(i) = 5. * i; // Update force to 10.0 REQUIRE_NOTHROW( - node->update_external_force(false, mpm::NodePhase::nMixture, force)); + node->update_external_force(false, mpm::NodePhase::NMixture, force)); REQUIRE_NOTHROW(node->update_external_force( - false, mpm::NodePhase::nLiquid, 0.5 * force)); + false, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(force(i)).epsilon(Tolerance)); - REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NLiquid)(i) == Approx(0.5 * force(i)).epsilon(Tolerance)); } @@ -1250,9 +1250,9 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { solid_acceleration << 0., 0.075; for (unsigned i = 0; i < solid_acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(solid_acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(liquid_acceleration(i)).epsilon(Tolerance)); } @@ -1260,9 +1260,9 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { Eigen::Matrix solid_velocity = solid_acceleration * dt; Eigen::Matrix liquid_velocity = liquid_acceleration * dt; for (unsigned i = 0; i < solid_velocity.size(); ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(solid_velocity(i)).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(liquid_velocity(i)).epsilon(Tolerance)); } @@ -1278,9 +1278,9 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { solid_velocity << 10.5, 0.03; liquid_velocity << 20.5, 1.03; for (unsigned i = 0; i < solid_velocity.size(); ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(solid_velocity(i)).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(liquid_velocity(i)).epsilon(Tolerance)); } @@ -1288,9 +1288,9 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { solid_acceleration.setZero(); liquid_acceleration.setZero(); for (unsigned i = 0; i < solid_acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(solid_acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(liquid_acceleration(i)).epsilon(Tolerance)); } @@ -1302,18 +1302,18 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { solid_acceleration << 0., 0.; liquid_acceleration << 0., 0.; for (unsigned i = 0; i < solid_acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(solid_acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(liquid_acceleration(i)).epsilon(Tolerance)); } // Exception check when mass is zero - REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nSolid, 0.)); - REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nLiquid, 0.)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::NSolid, 0.)); + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::NLiquid, 0.)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(0.).epsilon(Tolerance)); REQUIRE(node->compute_acceleration_velocity_twophase_explicit(dt) == false); @@ -1329,82 +1329,82 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { // Check initial momentum for (unsigned i = 0; i < momentum.size(); ++i) { - REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NSolid)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NLiquid)(i) == Approx(0.).epsilon(Tolerance)); } // Check update momentum to 10 REQUIRE_NOTHROW( - node->update_momentum(true, mpm::NodePhase::nSolid, momentum)); + node->update_momentum(true, mpm::NodePhase::NSolid, momentum)); REQUIRE_NOTHROW( - node->update_momentum(true, mpm::NodePhase::nLiquid, momentum)); + node->update_momentum(true, mpm::NodePhase::NLiquid, momentum)); for (unsigned i = 0; i < momentum.size(); ++i) { - REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NSolid)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NLiquid)(i) == Approx(10.).epsilon(Tolerance)); } // Check update momentum to 20 REQUIRE_NOTHROW( - node->update_momentum(true, mpm::NodePhase::nSolid, momentum)); + node->update_momentum(true, mpm::NodePhase::NSolid, momentum)); REQUIRE_NOTHROW( - node->update_momentum(true, mpm::NodePhase::nLiquid, momentum)); + node->update_momentum(true, mpm::NodePhase::NLiquid, momentum)); for (unsigned i = 0; i < momentum.size(); ++i) { - REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NSolid)(i) == Approx(20.).epsilon(Tolerance)); - REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NLiquid)(i) == Approx(20.).epsilon(Tolerance)); } // Check assign momentum to 10 REQUIRE_NOTHROW( - node->update_momentum(false, mpm::NodePhase::nSolid, momentum)); + node->update_momentum(false, mpm::NodePhase::NSolid, momentum)); REQUIRE_NOTHROW( - node->update_momentum(false, mpm::NodePhase::nLiquid, momentum)); + node->update_momentum(false, mpm::NodePhase::NLiquid, momentum)); for (unsigned i = 0; i < momentum.size(); ++i) { - REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NSolid)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NLiquid)(i) == Approx(10.).epsilon(Tolerance)); } // Check zero velocity for (unsigned i = 0; i < Dim; ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(0.).epsilon(Tolerance)); } // Check mass double mass = 0.; - REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nSolid, mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::NSolid, mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(0.0).epsilon(Tolerance)); - REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nLiquid, mass)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::NLiquid, mass)); + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(0.0).epsilon(Tolerance)); // Compute and check velocity this should throw zero mass node->compute_velocity(); mass = 100.; // Update mass to 100.5 - REQUIRE_NOTHROW(node->update_mass(true, mpm::NodePhase::nSolid, mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + REQUIRE_NOTHROW(node->update_mass(true, mpm::NodePhase::NSolid, mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(100.).epsilon(Tolerance)); - REQUIRE_NOTHROW(node->update_mass(true, mpm::NodePhase::nLiquid, mass)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE_NOTHROW(node->update_mass(true, mpm::NodePhase::NLiquid, mass)); + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(100.).epsilon(Tolerance)); // Compute and check velocity node->compute_velocity(); for (unsigned i = 0; i < Dim; ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(0.1).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(0.1).epsilon(Tolerance)); } @@ -1413,20 +1413,20 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { for (unsigned i = 0; i < acceleration.size(); ++i) acceleration(i) = 5.; for (unsigned i = 0; i < acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(0.).epsilon(Tolerance)); } - REQUIRE_NOTHROW(node->update_acceleration(true, mpm::NodePhase::nSolid, + REQUIRE_NOTHROW(node->update_acceleration(true, mpm::NodePhase::NSolid, acceleration)); - REQUIRE_NOTHROW(node->update_acceleration(true, mpm::NodePhase::nLiquid, + REQUIRE_NOTHROW(node->update_acceleration(true, mpm::NodePhase::NLiquid, acceleration)); for (unsigned i = 0; i < acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(5.).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(5.).epsilon(Tolerance)); } @@ -1439,18 +1439,18 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { Eigen::Matrix velocity; velocity << 0.1, 0.1; for (unsigned i = 0; i < velocity.size(); ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(velocity(i)).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(velocity(i)).epsilon(Tolerance)); } // Check acceleration before constraints acceleration << 5., 5.; for (unsigned i = 0; i < acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); } @@ -1466,17 +1466,17 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { // Check apply constraints velocity << -12.5, 0.1; for (unsigned i = 0; i < velocity.size(); ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(velocity(i)).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(velocity(i)).epsilon(Tolerance)); } acceleration << 0., 5.; for (unsigned i = 0; i < acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); } } @@ -1501,35 +1501,35 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { // Check applied velocity constraints in the global coordinates velocity << -9.583478335521184, -8.025403099849004; for (unsigned i = 0; i < Dim; ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(velocity(i)).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(velocity(i)).epsilon(Tolerance)); } // Check that the velocity is as specified in local coordinate REQUIRE((inverse_rotation_matrix * - node->velocity(mpm::NodePhase::nSolid))(0) == + node->velocity(mpm::NodePhase::NSolid))(0) == Approx(-12.5).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->velocity(mpm::NodePhase::nLiquid))(0) == + node->velocity(mpm::NodePhase::NLiquid))(0) == Approx(-12.5).epsilon(Tolerance)); // Check applied constraints on acceleration in the global coordinates acceleration << -0.396139826697847, 0.472101061636807; for (unsigned i = 0; i < Dim; ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); } // Check that the acceleration is 0 in local coordinate REQUIRE((inverse_rotation_matrix * - node->acceleration(mpm::NodePhase::nSolid))(0) == + node->acceleration(mpm::NodePhase::NSolid))(0) == Approx(0).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->acceleration(mpm::NodePhase::nLiquid))(0) == + node->acceleration(mpm::NodePhase::NLiquid))(0) == Approx(0).epsilon(Tolerance)); } @@ -1555,47 +1555,47 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { // Check applied velocity constraints in the global coordinates velocity << -14.311308834766370, 2.772442864323454; for (unsigned i = 0; i < Dim; ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(velocity(i)).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(velocity(i)).epsilon(Tolerance)); } // Check that the velocity is as specified in local coordinate REQUIRE((inverse_rotation_matrix * - node->velocity(mpm::NodePhase::nSolid))(0) == + node->velocity(mpm::NodePhase::NSolid))(0) == Approx(-12.5).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->velocity(mpm::NodePhase::nSolid))(1) == + node->velocity(mpm::NodePhase::NSolid))(1) == Approx(7.5).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->velocity(mpm::NodePhase::nLiquid))(0) == + node->velocity(mpm::NodePhase::NLiquid))(0) == Approx(-12.5).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->velocity(mpm::NodePhase::nLiquid))(1) == + node->velocity(mpm::NodePhase::NLiquid))(1) == Approx(7.5).epsilon(Tolerance)); // Check applied constraints on acceleration in the global coordinates acceleration << 0, 0; for (unsigned i = 0; i < Dim; ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); } // Check that the acceleration is 0 in local coordinate REQUIRE((inverse_rotation_matrix * - node->acceleration(mpm::NodePhase::nSolid))(0) == + node->acceleration(mpm::NodePhase::NSolid))(0) == Approx(0).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->acceleration(mpm::NodePhase::nSolid))(1) == + node->acceleration(mpm::NodePhase::NSolid))(1) == Approx(0).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->acceleration(mpm::NodePhase::nLiquid))(0) == + node->acceleration(mpm::NodePhase::NLiquid))(0) == Approx(0).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->acceleration(mpm::NodePhase::nLiquid))(1) == + node->acceleration(mpm::NodePhase::NLiquid))(1) == Approx(0).epsilon(Tolerance)); } @@ -1611,7 +1611,7 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { // Check apply constraints acceleration << 4., 5.; for (unsigned i = 0; i < acceleration.size(); ++i) - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); } @@ -1633,14 +1633,14 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { // Check applied constraints on acceleration in the global coordinates acceleration << 4.905579787672637, 4.920772034660430; for (unsigned i = 0; i < Dim; ++i) - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); // Check the acceleration in local coordinate acceleration << 6.920903430595146, 0.616284167162194; for (unsigned i = 0; i < Dim; ++i) REQUIRE((inverse_rotation_matrix * - node->acceleration(mpm::NodePhase::nSolid))(i) == + node->acceleration(mpm::NodePhase::NSolid))(i) == Approx(acceleration(i)).epsilon(Tolerance)); } } @@ -1779,111 +1779,111 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { std::make_shared>(id, coords); // Check mass - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(0.0).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(0.0).epsilon(Tolerance)); double solid_mass = 100.5; double liquid_mass = 200.5; // Update mass to 100.5 and 200.5 REQUIRE_NOTHROW( - node->update_mass(true, mpm::NodePhase::nSolid, solid_mass)); + node->update_mass(true, mpm::NodePhase::NSolid, solid_mass)); REQUIRE_NOTHROW( - node->update_mass(true, mpm::NodePhase::nLiquid, liquid_mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + node->update_mass(true, mpm::NodePhase::NLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(100.5).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(200.5).epsilon(Tolerance)); // Update mass to 201 and 401 REQUIRE_NOTHROW( - node->update_mass(true, mpm::NodePhase::nSolid, solid_mass)); + node->update_mass(true, mpm::NodePhase::NSolid, solid_mass)); REQUIRE_NOTHROW( - node->update_mass(true, mpm::NodePhase::nLiquid, liquid_mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + node->update_mass(true, mpm::NodePhase::NLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(201.0).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(401.0).epsilon(Tolerance)); // Assign mass to 100 and 200 solid_mass = 100.; liquid_mass = 200.; REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nSolid, solid_mass)); + node->update_mass(false, mpm::NodePhase::NSolid, solid_mass)); REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nLiquid, liquid_mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + node->update_mass(false, mpm::NodePhase::NLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(100.0).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(200.0).epsilon(Tolerance)); SECTION("Check nodal pressure") { // Check pressure - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(0.0).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(0.0).epsilon(Tolerance)); double pressure = 1000.7; double pore_pressure = 2000.7; // Update pressure to 1000.7 and 2000.7 - REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nSolid, + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::NSolid, solid_mass * pressure)); - REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nLiquid, + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::NLiquid, liquid_mass * pore_pressure)); - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(1000.7).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(2000.7).epsilon(Tolerance)); // Update pressure to 2001.4 and 4001.4 - REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nSolid, + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::NSolid, solid_mass * pressure)); - REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::nLiquid, + REQUIRE_NOTHROW(node->update_mass_pressure(mpm::NodePhase::NLiquid, liquid_mass * pore_pressure)); - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(2001.4).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(4001.4).epsilon(Tolerance)); // Assign pressure to 1000 and 2000 pressure = 1000.; pore_pressure = 2000.; - node->assign_pressure(mpm::NodePhase::nSolid, pressure); - node->assign_pressure(mpm::NodePhase::nLiquid, pore_pressure); - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + node->assign_pressure(mpm::NodePhase::NSolid, pressure); + node->assign_pressure(mpm::NodePhase::NLiquid, pore_pressure); + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(1000.0).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(2000.0).epsilon(Tolerance)); // Assign mass to 0 solid_mass = 0.; liquid_mass = 0.; REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nSolid, solid_mass)); + node->update_mass(false, mpm::NodePhase::NSolid, solid_mass)); REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nLiquid, liquid_mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + node->update_mass(false, mpm::NodePhase::NLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(0.0).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(0.0).epsilon(Tolerance)); // Try to update pressure to 2000, should throw and keep to 1000. - node->assign_pressure(mpm::NodePhase::nSolid, pressure); - node->assign_pressure(mpm::NodePhase::nLiquid, pore_pressure); - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + node->assign_pressure(mpm::NodePhase::NSolid, pressure); + node->assign_pressure(mpm::NodePhase::NLiquid, pore_pressure); + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(1000.0).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(2000.0).epsilon(Tolerance)); // Check pressure constraints SECTION("Check nodal pressure constraints") { // Check assign pressure constraint - REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::nSolid, 8000, + REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::NSolid, 8000, nullptr) == true); - REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::nLiquid, 7000, + REQUIRE(node->assign_pressure_constraint(mpm::NodePhase::NLiquid, 7000, nullptr) == true); // Check apply pressure constraint REQUIRE_NOTHROW( - node->apply_pressure_constraint(mpm::NodePhase::nSolid)); + node->apply_pressure_constraint(mpm::NodePhase::NSolid)); REQUIRE_NOTHROW( - node->apply_pressure_constraint(mpm::NodePhase::nLiquid)); + node->apply_pressure_constraint(mpm::NodePhase::NLiquid)); // Check pressure - REQUIRE(node->pressure(mpm::NodePhase::nSolid) == + REQUIRE(node->pressure(mpm::NodePhase::NSolid) == Approx(8000).epsilon(Tolerance)); - REQUIRE(node->pressure(mpm::NodePhase::nLiquid) == + REQUIRE(node->pressure(mpm::NodePhase::NLiquid) == Approx(7000).epsilon(Tolerance)); } } @@ -1895,45 +1895,45 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { // Check current external force is zero for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NLiquid)(i) == Approx(0.).epsilon(Tolerance)); } // Update force to 10.0 REQUIRE_NOTHROW( - node->update_external_force(true, mpm::NodePhase::nMixture, force)); - REQUIRE_NOTHROW(node->update_external_force(true, mpm::NodePhase::nLiquid, + node->update_external_force(true, mpm::NodePhase::NMixture, force)); + REQUIRE_NOTHROW(node->update_external_force(true, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NLiquid)(i) == Approx(5.).epsilon(Tolerance)); } // Update force to 20.0 REQUIRE_NOTHROW( - node->update_external_force(true, mpm::NodePhase::nMixture, force)); - REQUIRE_NOTHROW(node->update_external_force(true, mpm::NodePhase::nLiquid, + node->update_external_force(true, mpm::NodePhase::NMixture, force)); + REQUIRE_NOTHROW(node->update_external_force(true, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(20.).epsilon(Tolerance)); - REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NLiquid)(i) == Approx(10.).epsilon(Tolerance)); } // Assign force as 10.0 REQUIRE_NOTHROW( - node->update_external_force(false, mpm::NodePhase::nMixture, force)); + node->update_external_force(false, mpm::NodePhase::NMixture, force)); REQUIRE_NOTHROW(node->update_external_force( - false, mpm::NodePhase::nLiquid, 0.5 * force)); + false, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NLiquid)(i) == Approx(5.).epsilon(Tolerance)); } @@ -1941,7 +1941,7 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { // Set external force to zero force.setZero(); REQUIRE_NOTHROW(node->update_external_force( - false, mpm::NodePhase::nMixture, force)); + false, mpm::NodePhase::NMixture, force)); // Concentrated force std::shared_ptr ffunction = nullptr; @@ -1949,38 +1949,38 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { const unsigned Direction = 0; // Check traction for (unsigned i = 0; i < Dim; ++i) - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->assign_concentrated_force(mpm::NodePhase::nMixture, + REQUIRE(node->assign_concentrated_force(mpm::NodePhase::NMixture, Direction, concentrated_force, ffunction) == true); double current_time = 0.0; - node->apply_concentrated_force(mpm::NodePhase::nMixture, current_time); + node->apply_concentrated_force(mpm::NodePhase::NMixture, current_time); for (unsigned i = 0; i < Dim; ++i) { if (i == Direction) - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(concentrated_force).epsilon(Tolerance)); else - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(0.).epsilon(Tolerance)); } // Check for incorrect direction / phase const unsigned wrong_dir = 4; - REQUIRE(node->assign_concentrated_force(mpm::NodePhase::nMixture, + REQUIRE(node->assign_concentrated_force(mpm::NodePhase::NMixture, wrong_dir, concentrated_force, ffunction) == false); // Check again to ensure value hasn't been updated for (unsigned i = 0; i < Dim; ++i) { if (i == Direction) - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(concentrated_force).epsilon(Tolerance)); else - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(0.).epsilon(Tolerance)); } } @@ -1993,45 +1993,45 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { // Check current internal force is zero for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NMixture)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NLiquid)(i) == Approx(0.).epsilon(Tolerance)); } // Update force to 10.0 REQUIRE_NOTHROW( - node->update_internal_force(true, mpm::NodePhase::nMixture, force)); - REQUIRE_NOTHROW(node->update_internal_force(true, mpm::NodePhase::nLiquid, + node->update_internal_force(true, mpm::NodePhase::NMixture, force)); + REQUIRE_NOTHROW(node->update_internal_force(true, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NMixture)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NLiquid)(i) == Approx(5.).epsilon(Tolerance)); } // Update force to 20.0 REQUIRE_NOTHROW( - node->update_internal_force(true, mpm::NodePhase::nMixture, force)); - REQUIRE_NOTHROW(node->update_internal_force(true, mpm::NodePhase::nLiquid, + node->update_internal_force(true, mpm::NodePhase::NMixture, force)); + REQUIRE_NOTHROW(node->update_internal_force(true, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NMixture)(i) == Approx(20.).epsilon(Tolerance)); - REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NLiquid)(i) == Approx(10.).epsilon(Tolerance)); } // Assign force as 10.0 REQUIRE_NOTHROW( - node->update_internal_force(false, mpm::NodePhase::nMixture, force)); + node->update_internal_force(false, mpm::NodePhase::NMixture, force)); REQUIRE_NOTHROW(node->update_internal_force( - false, mpm::NodePhase::nLiquid, 0.5 * force)); + false, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NMixture)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NLiquid)(i) == Approx(5.).epsilon(Tolerance)); } } @@ -2080,12 +2080,12 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { double liquid_mass = 100.; // Update mass to 100. REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nSolid, solid_mass)); + node->update_mass(false, mpm::NodePhase::NSolid, solid_mass)); REQUIRE_NOTHROW( - node->update_mass(false, mpm::NodePhase::nLiquid, liquid_mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + node->update_mass(false, mpm::NodePhase::NLiquid, liquid_mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(solid_mass).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(liquid_mass).epsilon(Tolerance)); // Check internal force @@ -2094,14 +2094,14 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { for (unsigned i = 0; i < force.size(); ++i) force(i) = 10. * i; // Update force to 10.0 REQUIRE_NOTHROW( - node->update_internal_force(false, mpm::NodePhase::nMixture, force)); + node->update_internal_force(false, mpm::NodePhase::NMixture, force)); REQUIRE_NOTHROW(node->update_internal_force( - false, mpm::NodePhase::nLiquid, 0.5 * force)); + false, mpm::NodePhase::NLiquid, 0.5 * force)); // Internal force for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->internal_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NMixture)(i) == Approx(force(i)).epsilon(Tolerance)); - REQUIRE(node->internal_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->internal_force(mpm::NodePhase::NLiquid)(i) == Approx(0.5 * force(i)).epsilon(Tolerance)); } @@ -2109,13 +2109,13 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { for (unsigned i = 0; i < force.size(); ++i) force(i) = 5. * i; // Update force to 10.0 REQUIRE_NOTHROW( - node->update_external_force(false, mpm::NodePhase::nMixture, force)); + node->update_external_force(false, mpm::NodePhase::NMixture, force)); REQUIRE_NOTHROW(node->update_external_force( - false, mpm::NodePhase::nLiquid, 0.5 * force)); + false, mpm::NodePhase::NLiquid, 0.5 * force)); for (unsigned i = 0; i < force.size(); ++i) { - REQUIRE(node->external_force(mpm::NodePhase::nMixture)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NMixture)(i) == Approx(force(i)).epsilon(Tolerance)); - REQUIRE(node->external_force(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->external_force(mpm::NodePhase::NLiquid)(i) == Approx(0.5 * force(i)).epsilon(Tolerance)); } @@ -2141,9 +2141,9 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { // Check acceleration for (unsigned i = 0; i < solid_acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(solid_acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(liquid_acceleration(i)).epsilon(Tolerance)); } @@ -2151,9 +2151,9 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { Eigen::Matrix solid_velocity = solid_acceleration * dt; Eigen::Matrix liquid_velocity = liquid_acceleration * dt; for (unsigned i = 0; i < solid_velocity.size(); ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(solid_velocity(i)).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(liquid_velocity(i)).epsilon(Tolerance)); } @@ -2171,9 +2171,9 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { solid_velocity << 10.5, 0.03, 5.13; liquid_velocity << 20.5, 1.03, 7.13; for (unsigned i = 0; i < solid_velocity.size(); ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(solid_velocity(i)).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(liquid_velocity(i)).epsilon(Tolerance)); } @@ -2181,9 +2181,9 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { solid_acceleration.setZero(); liquid_acceleration.setZero(); for (unsigned i = 0; i < solid_acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(solid_acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(liquid_acceleration(i)).epsilon(Tolerance)); } @@ -2195,9 +2195,9 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { solid_acceleration << 0., 0., 0.; liquid_acceleration << 0., 0., 0.; for (unsigned i = 0; i < solid_acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(solid_acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(liquid_acceleration(i)).epsilon(Tolerance)); } @@ -2208,11 +2208,11 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { true); // Exception check when mass is zero - REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nSolid, 0.)); - REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nLiquid, 0.)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::NSolid, 0.)); + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::NLiquid, 0.)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(0.).epsilon(Tolerance)); REQUIRE(node->compute_acceleration_velocity_twophase_explicit(dt) == false); @@ -2228,90 +2228,90 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { // Check initial momentum for (unsigned i = 0; i < momentum.size(); ++i) { - REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NSolid)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NLiquid)(i) == Approx(0.).epsilon(Tolerance)); } // Check update momentum to 10 REQUIRE_NOTHROW( - node->update_momentum(true, mpm::NodePhase::nSolid, momentum)); + node->update_momentum(true, mpm::NodePhase::NSolid, momentum)); REQUIRE_NOTHROW( - node->update_momentum(true, mpm::NodePhase::nLiquid, momentum)); + node->update_momentum(true, mpm::NodePhase::NLiquid, momentum)); for (unsigned i = 0; i < momentum.size(); ++i) { - REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NSolid)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NLiquid)(i) == Approx(10.).epsilon(Tolerance)); } // Check update momentum to 20 REQUIRE_NOTHROW( - node->update_momentum(true, mpm::NodePhase::nSolid, momentum)); + node->update_momentum(true, mpm::NodePhase::NSolid, momentum)); REQUIRE_NOTHROW( - node->update_momentum(true, mpm::NodePhase::nLiquid, momentum)); + node->update_momentum(true, mpm::NodePhase::NLiquid, momentum)); for (unsigned i = 0; i < momentum.size(); ++i) { - REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NSolid)(i) == Approx(20.).epsilon(Tolerance)); - REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NLiquid)(i) == Approx(20.).epsilon(Tolerance)); } // Check assign momentum to 10 REQUIRE_NOTHROW( - node->update_momentum(false, mpm::NodePhase::nSolid, momentum)); + node->update_momentum(false, mpm::NodePhase::NSolid, momentum)); REQUIRE_NOTHROW( - node->update_momentum(false, mpm::NodePhase::nLiquid, momentum)); + node->update_momentum(false, mpm::NodePhase::NLiquid, momentum)); for (unsigned i = 0; i < momentum.size(); ++i) { - REQUIRE(node->momentum(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NSolid)(i) == Approx(10.).epsilon(Tolerance)); - REQUIRE(node->momentum(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->momentum(mpm::NodePhase::NLiquid)(i) == Approx(10.).epsilon(Tolerance)); } // Check zero velocity for (unsigned i = 0; i < Dim; ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(0.).epsilon(Tolerance)); } // Check mass double mass = 0.; - REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nSolid, mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::NSolid, mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(0.0).epsilon(Tolerance)); - REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::nLiquid, mass)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE_NOTHROW(node->update_mass(false, mpm::NodePhase::NLiquid, mass)); + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(0.0).epsilon(Tolerance)); // Compute and check velocity this should throw zero mass node->compute_velocity(); mass = 100.; // Update mass to 100.5 - REQUIRE_NOTHROW(node->update_mass(true, mpm::NodePhase::nSolid, mass)); - REQUIRE(node->mass(mpm::NodePhase::nSolid) == + REQUIRE_NOTHROW(node->update_mass(true, mpm::NodePhase::NSolid, mass)); + REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(100.).epsilon(Tolerance)); - REQUIRE_NOTHROW(node->update_mass(true, mpm::NodePhase::nLiquid, mass)); - REQUIRE(node->mass(mpm::NodePhase::nLiquid) == + REQUIRE_NOTHROW(node->update_mass(true, mpm::NodePhase::NLiquid, mass)); + REQUIRE(node->mass(mpm::NodePhase::NLiquid) == Approx(100.).epsilon(Tolerance)); // Check zero velocity for (unsigned i = 0; i < Dim; ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(0.).epsilon(Tolerance)); } // Compute and check velocity node->compute_velocity(); for (unsigned i = 0; i < Dim; ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(0.1).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(0.1).epsilon(Tolerance)); } @@ -2320,20 +2320,20 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { for (unsigned i = 0; i < acceleration.size(); ++i) acceleration(i) = 5.; for (unsigned i = 0; i < acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(0.).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(0.).epsilon(Tolerance)); } - REQUIRE_NOTHROW(node->update_acceleration(true, mpm::NodePhase::nSolid, + REQUIRE_NOTHROW(node->update_acceleration(true, mpm::NodePhase::NSolid, acceleration)); - REQUIRE_NOTHROW(node->update_acceleration(true, mpm::NodePhase::nLiquid, + REQUIRE_NOTHROW(node->update_acceleration(true, mpm::NodePhase::NLiquid, acceleration)); for (unsigned i = 0; i < acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(5.).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(5.).epsilon(Tolerance)); } @@ -2341,18 +2341,18 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { Eigen::Matrix velocity; velocity << 0.1, 0.1, 0.1; for (unsigned i = 0; i < velocity.size(); ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(velocity(i)).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(velocity(i)).epsilon(Tolerance)); } // Check acceleration before constraints acceleration << 5., 5., 5.; for (unsigned i = 0; i < acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); } SECTION("Check Cartesian velocity constraints") { @@ -2367,17 +2367,17 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { // Check apply constraints velocity << -12.5, 0.1, 0.1; for (unsigned i = 0; i < velocity.size(); ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(velocity(i)).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(velocity(i)).epsilon(Tolerance)); } acceleration << 0., 5., 5.; for (unsigned i = 0; i < acceleration.size(); ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); } } @@ -2403,47 +2403,47 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { // Check apply constraints velocity << -14.5068204271, -0.1432759442, 1.4260971922; for (unsigned i = 0; i < Dim; ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(velocity(i)).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(velocity(i)).epsilon(Tolerance)); } // Check that the velocity is as specified in local coordinate REQUIRE((inverse_rotation_matrix * - node->velocity(mpm::NodePhase::nSolid))(0) == + node->velocity(mpm::NodePhase::NSolid))(0) == Approx(-12.5).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->velocity(mpm::NodePhase::nSolid))(1) == + node->velocity(mpm::NodePhase::NSolid))(1) == Approx(7.5).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->velocity(mpm::NodePhase::nLiquid))(0) == + node->velocity(mpm::NodePhase::NLiquid))(0) == Approx(-12.5).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->velocity(mpm::NodePhase::nLiquid))(1) == + node->velocity(mpm::NodePhase::NLiquid))(1) == Approx(7.5).epsilon(Tolerance)); // Check applied constraints on acceleration in the global coordinates acceleration << 0.1998888554, -1.1336260315, 1.9937880031; for (unsigned i = 0; i < Dim; ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); } // Check that the acceleration is 0 in local coordinate REQUIRE((inverse_rotation_matrix * - node->acceleration(mpm::NodePhase::nSolid))(0) == + node->acceleration(mpm::NodePhase::NSolid))(0) == Approx(0).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->acceleration(mpm::NodePhase::nSolid))(1) == + node->acceleration(mpm::NodePhase::NSolid))(1) == Approx(0).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->acceleration(mpm::NodePhase::nLiquid))(0) == + node->acceleration(mpm::NodePhase::NLiquid))(0) == Approx(0).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->acceleration(mpm::NodePhase::nLiquid))(1) == + node->acceleration(mpm::NodePhase::NLiquid))(1) == Approx(0).epsilon(Tolerance)); } @@ -2471,53 +2471,53 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { // Check apply constraints velocity << 13.351984588153375, -5.717804716697730, 10.572663655835457; for (unsigned i = 0; i < Dim; ++i) { - REQUIRE(node->velocity(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NSolid)(i) == Approx(velocity(i)).epsilon(Tolerance)); - REQUIRE(node->velocity(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->velocity(mpm::NodePhase::NLiquid)(i) == Approx(velocity(i)).epsilon(Tolerance)); } // Check that the velocity is as specified in local coordinate REQUIRE((inverse_rotation_matrix * - node->velocity(mpm::NodePhase::nSolid))(0) == + node->velocity(mpm::NodePhase::NSolid))(0) == Approx(10.5).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->velocity(mpm::NodePhase::nSolid))(1) == + node->velocity(mpm::NodePhase::NSolid))(1) == Approx(-12.5).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->velocity(mpm::NodePhase::nSolid))(2) == + node->velocity(mpm::NodePhase::NSolid))(2) == Approx(7.5).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->velocity(mpm::NodePhase::nLiquid))(0) == + node->velocity(mpm::NodePhase::NLiquid))(0) == Approx(10.5).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->velocity(mpm::NodePhase::nLiquid))(1) == + node->velocity(mpm::NodePhase::NLiquid))(1) == Approx(-12.5).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->velocity(mpm::NodePhase::nLiquid))(2) == + node->velocity(mpm::NodePhase::NLiquid))(2) == Approx(7.5).epsilon(Tolerance)); // Check apply constraints acceleration << 0, 0, 0; for (unsigned i = 0; i < Dim; ++i) { - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); - REQUIRE(node->acceleration(mpm::NodePhase::nLiquid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NLiquid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); } // Check that the acceleration is 0 in local coordinate REQUIRE((inverse_rotation_matrix * - node->acceleration(mpm::NodePhase::nSolid))(0) == + node->acceleration(mpm::NodePhase::NSolid))(0) == Approx(0).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->acceleration(mpm::NodePhase::nSolid))(1) == + node->acceleration(mpm::NodePhase::NSolid))(1) == Approx(0).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->acceleration(mpm::NodePhase::nLiquid))(0) == + node->acceleration(mpm::NodePhase::NLiquid))(0) == Approx(0).epsilon(Tolerance)); REQUIRE((inverse_rotation_matrix * - node->acceleration(mpm::NodePhase::nLiquid))(1) == + node->acceleration(mpm::NodePhase::NLiquid))(1) == Approx(0).epsilon(Tolerance)); } @@ -2533,7 +2533,7 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { // Check apply constraints acceleration << 3.939339828220179, 3.939339828220179, 5.; for (unsigned i = 0; i < acceleration.size(); ++i) - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); } @@ -2556,14 +2556,14 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { // Check applied constraints on acceleration in the global coordinates acceleration << 4.602895052828914, 4.492575657560740, 4.751301246937935; for (unsigned i = 0; i < Dim; ++i) - REQUIRE(node->acceleration(mpm::NodePhase::nSolid)(i) == + REQUIRE(node->acceleration(mpm::NodePhase::NSolid)(i) == Approx(acceleration(i)).epsilon(Tolerance)); // Check the acceleration in local coordinate acceleration << 6.878925666702865, 3.365244416454818, 2.302228080558999; for (unsigned i = 0; i < Dim; ++i) REQUIRE((inverse_rotation_matrix * - node->acceleration(mpm::NodePhase::nSolid))(i) == + node->acceleration(mpm::NodePhase::NSolid))(i) == Approx(acceleration(i)).epsilon(Tolerance)); } } diff --git a/tests/particles/particle_twophase_test.cc b/tests/particles/particle_twophase_test.cc index 58d71ee69..024efbe5a 100644 --- a/tests/particles/particle_twophase_test.cc +++ b/tests/particles/particle_twophase_test.cc @@ -913,12 +913,12 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", // Check nodal mass for (unsigned i = 0; i < nodes.size(); ++i) { // Solid phase - REQUIRE(nodes.at(i)->mass(mpm::NodePhase::nSolid) == + REQUIRE(nodes.at(i)->mass(mpm::NodePhase::NSolid) == Approx(nodal_mass.at(i) * (1 - particle->porosity())) .epsilon(Tolerance)); // Liquid phase REQUIRE( - nodes.at(i)->mass(mpm::NodePhase::nLiquid) == + nodes.at(i)->mass(mpm::NodePhase::NLiquid) == Approx(nodal_mass.at(i) * particle->porosity()).epsilon(Tolerance)); } @@ -937,11 +937,11 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", for (unsigned i = 0; i < nodal_momentum.rows(); ++i) for (unsigned j = 0; j < nodal_momentum.cols(); ++j) { // Solid phase - REQUIRE(nodes.at(i)->momentum(mpm::NodePhase::nSolid)(j) == + REQUIRE(nodes.at(i)->momentum(mpm::NodePhase::NSolid)(j) == Approx(nodal_momentum(i, j) * (1 - particle->porosity())) .epsilon(Tolerance)); // Liquid phase - REQUIRE(nodes.at(i)->momentum(mpm::NodePhase::nLiquid)(j) == + REQUIRE(nodes.at(i)->momentum(mpm::NodePhase::NLiquid)(j) == Approx(nodal_momentum(i, j) * particle->porosity()) .epsilon(Tolerance)); } @@ -957,10 +957,10 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", for (unsigned i = 0; i < nodal_velocity.rows(); ++i) for (unsigned j = 0; j < nodal_velocity.cols(); ++j) { // Solid phase - REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::nSolid)(j) == + REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::NSolid)(j) == Approx(nodal_velocity(i, j)).epsilon(Tolerance)); // Liquid phase - REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::nLiquid)(j) == + REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::NLiquid)(j) == Approx(nodal_velocity(i, j)).epsilon(Tolerance)); } @@ -974,11 +974,11 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", for (unsigned i = 0; i < nodes.size(); ++i) { // Solid phase REQUIRE_NOTHROW(nodes.at(i)->update_momentum( - false, mpm::NodePhase::nSolid, + false, mpm::NodePhase::NSolid, nodal_momentum.row(i) * (1 - particle->porosity()))); // Liquid phase REQUIRE_NOTHROW(nodes.at(i)->update_momentum( - false, mpm::NodePhase::nLiquid, + false, mpm::NodePhase::NLiquid, nodal_momentum.row(i) * particle->porosity())); } @@ -995,10 +995,10 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", for (unsigned i = 0; i < nodal_velocity.rows(); ++i) for (unsigned j = 0; j < nodal_velocity.cols(); ++j) { // Solid phase - REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::nSolid)(j) == + REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::NSolid)(j) == Approx(nodal_velocity(i, j)).epsilon(Tolerance)); // Liquid phase - REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::nLiquid)(j) == + REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::NLiquid)(j) == Approx(nodal_velocity(i, j)).epsilon(Tolerance)); } @@ -1069,7 +1069,7 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", // Check nodal body force for (unsigned i = 0; i < body_force.rows(); ++i) for (unsigned j = 0; j < body_force.cols(); ++j) - REQUIRE(nodes[i]->external_force(mpm::NodePhase::nSolid)[j] == + REQUIRE(nodes[i]->external_force(mpm::NodePhase::NSolid)[j] == Approx(body_force(i, j)).epsilon(Tolerance)); // Check traction force @@ -1101,7 +1101,7 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", // Check nodal traction force for (unsigned i = 0; i < traction_force.rows(); ++i) for (unsigned j = 0; j < traction_force.cols(); ++j) - REQUIRE(nodes[i]->external_force(mpm::NodePhase::nSolid)[j] == + REQUIRE(nodes[i]->external_force(mpm::NodePhase::NSolid)[j] == Approx(traction_force(i, j)).epsilon(Tolerance)); // Reset traction particle->assign_traction(direction, @@ -1111,7 +1111,7 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", // Check nodal external force for (unsigned i = 0; i < traction_force.rows(); ++i) for (unsigned j = 0; j < traction_force.cols(); ++j) - REQUIRE(nodes[i]->external_force(mpm::NodePhase::nSolid)[j] == + REQUIRE(nodes[i]->external_force(mpm::NodePhase::NSolid)[j] == Approx(body_force(i, j)).epsilon(Tolerance)); // Internal force @@ -1130,7 +1130,7 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", // Check nodal internal force for (unsigned i = 0; i < internal_force.rows(); ++i) for (unsigned j = 0; j < internal_force.cols(); ++j) - REQUIRE(nodes[i]->internal_force(mpm::NodePhase::nMixture)[j] == + REQUIRE(nodes[i]->internal_force(mpm::NodePhase::NMixture)[j] == Approx(internal_force(i, j)).epsilon(Tolerance)); // Internal force @@ -1170,10 +1170,10 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", for (unsigned i = 0; i < nodal_velocity.rows(); ++i) for (unsigned j = 0; j < nodal_velocity.cols(); ++j) { // Solid phase - REQUIRE(nodes[i]->velocity(mpm::NodePhase::nSolid)[j] == + REQUIRE(nodes[i]->velocity(mpm::NodePhase::NSolid)[j] == Approx(nodal_velocity(i, j)).epsilon(Tolerance)); // Liquid phase - REQUIRE(nodes[i]->velocity(mpm::NodePhase::nLiquid)[j] == + REQUIRE(nodes[i]->velocity(mpm::NodePhase::NLiquid)[j] == Approx(nodal_liquid_velocity(i, j)).epsilon(Tolerance)); } @@ -1194,10 +1194,10 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", for (unsigned i = 0; i < nodal_acceleration.rows(); ++i) for (unsigned j = 0; j < nodal_acceleration.cols(); ++j) { // Solid phase - REQUIRE(nodes[i]->acceleration(mpm::NodePhase::nSolid)[j] == + REQUIRE(nodes[i]->acceleration(mpm::NodePhase::NSolid)[j] == Approx(nodal_acceleration(i, j)).epsilon(Tolerance)); // Liquid phase - REQUIRE(nodes[i]->acceleration(mpm::NodePhase::nLiquid)[j] == + REQUIRE(nodes[i]->acceleration(mpm::NodePhase::NLiquid)[j] == Approx(nodal_liquid_acceleration(i, j)).epsilon(Tolerance)); } // Approx(nodal_velocity(i, j) / dt).epsilon(Tolerance)); @@ -2350,11 +2350,11 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", // Check nodal mass for (unsigned i = 0; i < nodes.size(); ++i) { // Solid phase - REQUIRE(nodes.at(i)->mass(mpm::NodePhase::nSolid) == + REQUIRE(nodes.at(i)->mass(mpm::NodePhase::NSolid) == Approx(nodal_mass.at(i) * (1 - particle->porosity()))); // Liquid phase REQUIRE( - nodes.at(i)->mass(mpm::NodePhase::nLiquid) == + nodes.at(i)->mass(mpm::NodePhase::NLiquid) == Approx(nodal_mass.at(i) * particle->porosity()).epsilon(Tolerance)); } @@ -2378,11 +2378,11 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", for (unsigned i = 0; i < nodal_momentum.rows(); ++i) for (unsigned j = 0; j < nodal_momentum.cols(); ++j) { // Solid phase - REQUIRE(nodes.at(i)->momentum(mpm::NodePhase::nSolid)(j) == + REQUIRE(nodes.at(i)->momentum(mpm::NodePhase::NSolid)(j) == Approx(nodal_momentum(i, j) * (1 - particle->porosity())) .epsilon(Tolerance)); // Liquid phase - REQUIRE(nodes.at(i)->momentum(mpm::NodePhase::nLiquid)(j) == + REQUIRE(nodes.at(i)->momentum(mpm::NodePhase::NLiquid)(j) == Approx(nodal_momentum(i, j) * particle->porosity()) .epsilon(Tolerance)); } @@ -2403,10 +2403,10 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", for (unsigned i = 0; i < nodal_velocity.rows(); ++i) for (unsigned j = 0; j < nodal_velocity.cols(); ++j) { // Solid phase - REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::nSolid)(j) == + REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::NSolid)(j) == Approx(nodal_velocity(i, j)).epsilon(Tolerance)); // Liquid phase - REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::nLiquid)(j) == + REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::NLiquid)(j) == Approx(nodal_velocity(i, j)).epsilon(Tolerance)); } @@ -2424,11 +2424,11 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", for (unsigned i = 0; i < nodes.size(); ++i) { // Solid phase REQUIRE_NOTHROW(nodes.at(i)->update_momentum( - false, mpm::NodePhase::nSolid, + false, mpm::NodePhase::NSolid, nodal_momentum.row(i) * (1 - particle->porosity()))); // Liquid phase REQUIRE_NOTHROW(nodes.at(i)->update_momentum( - false, mpm::NodePhase::nLiquid, + false, mpm::NodePhase::NLiquid, nodal_momentum.row(i) * particle->porosity())); } @@ -2449,10 +2449,10 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", for (unsigned i = 0; i < nodal_velocity.rows(); ++i) for (unsigned j = 0; j < nodal_velocity.cols(); ++j) { // Solid phase - REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::nSolid)(j) == + REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::NSolid)(j) == Approx(nodal_velocity(i, j)).epsilon(Tolerance)); // Liquid phase - REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::nLiquid)(j) == + REQUIRE(nodes.at(i)->velocity(mpm::NodePhase::NLiquid)(j) == Approx(nodal_velocity(i, j)).epsilon(Tolerance)); } @@ -2527,7 +2527,7 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", // Check nodal body force for (unsigned i = 0; i < body_force.rows(); ++i) for (unsigned j = 0; j < body_force.cols(); ++j) - REQUIRE(nodes[i]->external_force(mpm::NodePhase::nSolid)[j] == + REQUIRE(nodes[i]->external_force(mpm::NodePhase::NSolid)[j] == Approx(body_force(i, j)).epsilon(Tolerance)); // Check traction force @@ -2562,7 +2562,7 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", // Check nodal traction force for (unsigned i = 0; i < traction_force.rows(); ++i) for (unsigned j = 0; j < traction_force.cols(); ++j) - REQUIRE(nodes[i]->external_force(mpm::NodePhase::nSolid)[j] == + REQUIRE(nodes[i]->external_force(mpm::NodePhase::NSolid)[j] == Approx(traction_force(i, j)).epsilon(Tolerance)); // Reset traction particle->assign_traction(direction, @@ -2572,7 +2572,7 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", // Check nodal external force for (unsigned i = 0; i < traction_force.rows(); ++i) for (unsigned j = 0; j < traction_force.cols(); ++j) - REQUIRE(nodes[i]->external_force(mpm::NodePhase::nSolid)[j] == + REQUIRE(nodes[i]->external_force(mpm::NodePhase::NSolid)[j] == Approx(body_force(i, j)).epsilon(Tolerance)); // Internal force @@ -2595,12 +2595,12 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", // Check nodal internal force for (unsigned i = 0; i < internal_force.rows(); ++i) for (unsigned j = 0; j < internal_force.cols(); ++j) - REQUIRE(nodes[i]->internal_force(mpm::NodePhase::nMixture)[j] == + REQUIRE(nodes[i]->internal_force(mpm::NodePhase::NMixture)[j] == Approx(internal_force(i, j)).epsilon(Tolerance)); // Calculate nodal acceleration and velocity for (const auto& node : nodes) - node->compute_acceleration_velocity(mpm::NodePhase::nSolid, dt); + node->compute_acceleration_velocity(mpm::NodePhase::NSolid, dt); // Check nodal velocity // clang-format off @@ -2616,7 +2616,7 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", // Check nodal velocity for (unsigned i = 0; i < nodal_velocity.rows(); ++i) for (unsigned j = 0; j < nodal_velocity.cols(); ++j) - REQUIRE(nodes[i]->velocity(mpm::NodePhase::nSolid)[j] == + REQUIRE(nodes[i]->velocity(mpm::NodePhase::NSolid)[j] == Approx(nodal_velocity(i, j)).epsilon(Tolerance)); // Check nodal acceleration @@ -2634,7 +2634,7 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", // Check nodal acceleration for (unsigned i = 0; i < nodal_acceleration.rows(); ++i) for (unsigned j = 0; j < nodal_acceleration.cols(); ++j) - REQUIRE(nodes[i]->acceleration(mpm::NodePhase::nSolid)[j] == + REQUIRE(nodes[i]->acceleration(mpm::NodePhase::NSolid)[j] == Approx(nodal_acceleration(i, j)).epsilon(Tolerance)); // Approx(nodal_velocity(i, j) / dt).epsilon(Tolerance)); From c24b27e77f98b373ea658d57e2d25fe6f69108eb Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 17 Nov 2020 15:29:11 +0700 Subject: [PATCH 169/175] :construction: cleanup as suggested --- include/mesh.h | 2 +- include/mesh.tcc | 3 +- include/mesh_multiphase.tcc | 666 ++++++++++++++++++------------------ 3 files changed, 331 insertions(+), 340 deletions(-) diff --git a/include/mesh.h b/include/mesh.h index 3a31fb75b..815e896f7 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -498,7 +498,7 @@ class Mesh { //! \param[in] volume_tolerance for volume_fraction approach //! \retval status Status of compute_free_surface bool compute_free_surface( - const std::string& method, + const std::string& method = "density", double volume_tolerance = std::numeric_limits::epsilon()); //! Compute free surface by density method diff --git a/include/mesh.tcc b/include/mesh.tcc index 7411235c5..27bc733c8 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -425,7 +425,8 @@ template mpm::Index mpm::Mesh::nparticles(const std::string& particle_type) const { return std::count_if( particles_.cbegin(), particles_.cend(), - [&ptype = particle_type](std::shared_ptr> ptr) { + [&ptype = + particle_type](const std::shared_ptr>& ptr) { return (ptr)->type() == ptype; }); } diff --git a/include/mesh_multiphase.tcc b/include/mesh_multiphase.tcc index 4a5b0a830..39670aeb5 100644 --- a/include/mesh_multiphase.tcc +++ b/include/mesh_multiphase.tcc @@ -21,125 +21,160 @@ template bool mpm::Mesh::compute_free_surface_by_geometry( double volume_tolerance) { bool status = true; - try { - // Reset free surface cell and particles - 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)); - - // 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(); - ++citr) { - // Cell contains particles - if ((*citr)->status()) { - bool candidate_cell = false; - const auto& node_id = (*citr)->nodes_id(); - if ((*citr)->volume_fraction() < volume_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 neighbour_cell_id : (*citr)->neighbours()) { - if (!map_cells_[neighbour_cell_id]->status()) { - candidate_cell = true; - const auto& n_node_id = map_cells_[neighbour_cell_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())); + // Reset free surface cell and particles + 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)); + + // 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); + } + } - // 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); - } + // 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(); ++citr) { + // Cell contains particles + if ((*citr)->status()) { + bool candidate_cell = false; + const auto& node_id = (*citr)->nodes_id(); + if ((*citr)->volume_fraction() < volume_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 neighbour_cell_id : (*citr)->neighbours()) { + if (!map_cells_[neighbour_cell_id]->status()) { + candidate_cell = true; + const auto& n_node_id = map_cells_[neighbour_cell_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); } } } } + } - // Assign free surface cell - if (candidate_cell) { - (*citr)->assign_free_surface(true); - free_surface_candidate_cells.insert((*citr)->id()); - } + // Assign free surface cell + if (candidate_cell) { + (*citr)->assign_free_surface(true); + free_surface_candidate_cells.insert((*citr)->id()); } } + } - // Compute particle neighbours for particles at candidate cells - std::vector free_surface_candidate_particles_first; - 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_first.insert( - free_surface_candidate_particles_first.end(), particle_ids.begin(), - particle_ids.end()); - } + // Compute particle neighbours for particles at candidate cells + std::vector free_surface_candidate_particles_first; + 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_first.insert( + free_surface_candidate_particles_first.end(), particle_ids.begin(), + 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_first) { + const auto& particle = map_particles_[p_id]; + status = particle->compute_free_surface_by_density(); + if (status) free_surface_candidate_particles_second.insert(p_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)); - - std::set free_surface_candidate_particles_second; - for (const auto p_id : free_surface_candidate_particles_first) { - const auto& particle = map_particles_[p_id]; - status = particle->compute_free_surface_by_density(); - if (status) free_surface_candidate_particles_second.insert(p_id); + // Find free surface particles through geometry + for (const auto p_id : free_surface_candidate_particles_second) { + // Initialize renormalization matrix + Eigen::Matrix renormalization_matrix_inv; + renormalization_matrix_inv.setZero(); + + // Loop over neighbours + 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 neighbour_particle_id : neighbour_particles) { + const auto& n_coord = + map_particles_[neighbour_particle_id]->coordinates(); + const VectorDim rel_coord = n_coord - p_coord; + + // Compute kernel gradient + const VectorDim kernel_gradient = + mpm::RadialBasisFunction::gradient(smoothing_length, -rel_coord, + "gaussian"); + + // Inverse of renormalization matrix B + renormalization_matrix_inv += + (particle->mass() / particle->mass_density()) * kernel_gradient * + rel_coord.transpose(); } - // Find free surface particles through geometry - for (const auto p_id : free_surface_candidate_particles_second) { - // Initialize renormalization matrix - Eigen::Matrix renormalization_matrix_inv; - renormalization_matrix_inv.setZero(); - - // Loop over neighbours - 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(); + // 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 = true; + else if (lambda > 0.2 && lambda <= 0.75) + secondary_check = true; + else + interior = true; + + // Compute numerical normal vector + VectorDim normal; + normal.setZero(); + if (!interior) { + VectorDim temporary_vec; + temporary_vec.setZero(); for (const auto neighbour_particle_id : neighbour_particles) { const auto& n_coord = map_particles_[neighbour_particle_id]->coordinates(); @@ -150,95 +185,55 @@ bool mpm::Mesh::compute_free_surface_by_geometry( mpm::RadialBasisFunction::gradient(smoothing_length, -rel_coord, "gaussian"); - // Inverse of renormalization matrix B - renormalization_matrix_inv += - (particle->mass() / particle->mass_density()) * kernel_gradient * - rel_coord.transpose(); + // Sum of kernel by volume + temporary_vec += + (particle->mass() / particle->mass_density()) * kernel_gradient; } + normal = -renormalization_matrix_inv.inverse() * temporary_vec; + if (normal.norm() > std::numeric_limits::epsilon()) + normal.normalize(); + else + normal.setZero(); + } - // Compute lambda: minimum eigenvalue of B_inverse - Eigen::SelfAdjointEigenSolver es( - renormalization_matrix_inv); - double lambda = es.eigenvalues().minCoeff(); + // 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; - // Categorize particle based on lambda - bool free_surface = false; - bool secondary_check = false; - bool interior = false; - if (lambda <= 0.2) - free_surface = true; - else if (lambda > 0.2 && lambda <= 0.75) - secondary_check = true; - else - interior = true; - - // Compute numerical normal vector - VectorDim normal; - normal.setZero(); - if (!interior) { - VectorDim temporary_vec; - temporary_vec.setZero(); - for (const auto neighbour_particle_id : neighbour_particles) { - const auto& n_coord = - map_particles_[neighbour_particle_id]->coordinates(); - const VectorDim rel_coord = n_coord - p_coord; - - // Compute kernel gradient - 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 = -renormalization_matrix_inv.inverse() * temporary_vec; - if (normal.norm() > std::numeric_limits::epsilon()) - normal.normalize(); - else - normal.setZero(); - } + // Check all neighbours + for (const auto neighbour_particle_id : neighbour_particles) { + const auto& n_coord = + map_particles_[neighbour_particle_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(); - // 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 neighbour_particle_id : neighbour_particles) { - const auto& n_coord = - map_particles_[neighbour_particle_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; - } + 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) { - particle->assign_free_surface(true); - particle->assign_normal(normal); - } + // Assign normal only to validated free surface + if (free_surface) { + particle->assign_free_surface(true); + particle->assign_normal(normal); } - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); } + return status; } @@ -246,192 +241,187 @@ bool mpm::Mesh::compute_free_surface_by_geometry( template bool mpm::Mesh::compute_free_surface_by_density(double volume_tolerance) { bool status = true; - try { - // Get number of MPI ranks - int mpi_rank = 0; - int mpi_size = 1; + // Get number of MPI ranks + int mpi_rank = 0; + int mpi_size = 1; #ifdef USE_MPI - MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); - MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); - - // Reset solving status - this->iterate_over_cells(std::bind(&mpm::Cell::assign_solving_status, - std::placeholders::_1, false)); - - // Initialize pointer of booleans for send and receive - bool* send_cell_solving_status = new bool[ncells()]; - memset(send_cell_solving_status, 0, ncells() * sizeof(bool)); - bool* receive_cell_solving_status = new bool[ncells()]; - - for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) - if ((*citr)->status()) - // Assign solving status for MPI solver - send_cell_solving_status[(*citr)->id()] = true; - - MPI_Allreduce(send_cell_solving_status, receive_cell_solving_status, - ncells(), MPI_CXX_BOOL, MPI_LOR, MPI_COMM_WORLD); - - for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { - if (receive_cell_solving_status[(*citr)->id()]) { - // Assign solving status for MPI solver - (*citr)->assign_solving_status(true); - } - } + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + // // Reset solving status + // this->iterate_over_cells(std::bind(&mpm::Cell::assign_solving_status, + // std::placeholders::_1, false)); + + // Initialize pointer of booleans for send and receive + bool* send_cell_solving_status = new bool[ncells()]; + memset(send_cell_solving_status, 0, ncells() * sizeof(bool)); + bool* receive_cell_solving_status = new bool[ncells()]; + + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) + if ((*citr)->status()) + // Assign solving status for MPI solver + send_cell_solving_status[(*citr)->id()] = true; + else + send_cell_solving_status[(*citr)->id()] = false; + + MPI_Allreduce(send_cell_solving_status, receive_cell_solving_status, ncells(), + MPI_CXX_BOOL, MPI_LOR, MPI_COMM_WORLD); + + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + // Assign solving status for MPI solver + (*citr)->assign_solving_status(receive_cell_solving_status[(*citr)->id()]); + } - delete[] send_cell_solving_status; - delete[] receive_cell_solving_status; + delete[] send_cell_solving_status; + delete[] receive_cell_solving_status; #endif - // 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); - } + // 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); } + } #ifdef USE_MPI - // Initialize vector of double for send and receive - std::vector send_cell_vol_fraction; - send_cell_vol_fraction.resize(ncells()); - std::vector receive_cell_vol_fraction; - receive_cell_vol_fraction.resize(ncells()); - - for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) - if ((*citr)->status()) - // Assign volume_fraction for MPI solver - send_cell_vol_fraction[(*citr)->id()] = (*citr)->volume_fraction(); - - MPI_Allreduce(send_cell_vol_fraction.data(), - receive_cell_vol_fraction.data(), ncells(), MPI_DOUBLE, - MPI_SUM, MPI_COMM_WORLD); - - for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + // Initialize vector of double for send and receive + std::vector send_cell_vol_fraction; + send_cell_vol_fraction.resize(ncells()); + std::vector receive_cell_vol_fraction; + receive_cell_vol_fraction.resize(ncells()); + + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) + if ((*citr)->status()) // Assign volume_fraction for MPI solver - (*citr)->assign_volume_fraction(receive_cell_vol_fraction[(*citr)->id()]); - } + send_cell_vol_fraction[(*citr)->id()] = (*citr)->volume_fraction(); + else + send_cell_vol_fraction[(*citr)->id()] = 0.0; + + MPI_Allreduce(send_cell_vol_fraction.data(), receive_cell_vol_fraction.data(), + ncells(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + // Assign volume_fraction for MPI solver + (*citr)->assign_volume_fraction(receive_cell_vol_fraction[(*citr)->id()]); + } #endif - // Compute boundary cells and nodes based on geometry - for (auto citr = this->cells_.cbegin(); citr != this->cells_.cend(); - ++citr) { + // Compute boundary cells and nodes based on geometry + 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; + if ((*citr)->status()) { + bool cell_at_interface = false; + const auto& node_id = (*citr)->nodes_id(); + bool internal = true; - //! Check internal cell - for (const auto neighbour_cell_id : (*citr)->neighbours()) { + //! Check internal cell + for (const auto neighbour_cell_id : (*citr)->neighbours()) { #if USE_MPI - if (!map_cells_[neighbour_cell_id]->solving_status()) { - internal = false; - break; - } + if (!map_cells_[neighbour_cell_id]->solving_status()) { + internal = false; + break; + } #else - if (!map_cells_[neighbour_cell_id]->status()) { - internal = false; - break; - } -#endif + if (!map_cells_[neighbour_cell_id]->status()) { + internal = false; + break; } +#endif + } - //! 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); - } - } else { - for (const auto neighbour_cell_id : (*citr)->neighbours()) { - if (map_cells_[neighbour_cell_id]->volume_fraction() < - volume_tolerance) { - cell_at_interface = true; - const auto& n_node_id = - map_cells_[neighbour_cell_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); - } + //! 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); + } + } else { + for (const auto neighbour_cell_id : (*citr)->neighbours()) { + if (map_cells_[neighbour_cell_id]->volume_fraction() < + volume_tolerance) { + cell_at_interface = true; + const auto& n_node_id = map_cells_[neighbour_cell_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); } } } } + } - // Assign free surface cell - if (cell_at_interface) { - (*citr)->assign_free_surface(cell_at_interface); - } + // Assign free surface cell + if (cell_at_interface) { + (*citr)->assign_free_surface(cell_at_interface); } } } + } - // 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, mpm::ParticlePhase::SinglePhase)); + // 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, + mpm::ParticlePhase::SinglePhase)); #ifdef USE_MPI - // Run if there is more than a single MPI task - if (mpi_size > 1) { - // MPI all reduce nodal volume - this->template nodal_halo_exchange( - std::bind(&mpm::NodeBase::volume, std::placeholders::_1, - mpm::ParticlePhase::SinglePhase), - std::bind(&mpm::NodeBase::update_volume, std::placeholders::_1, - false, mpm::ParticlePhase::SinglePhase, - std::placeholders::_2)); - } + // Run if there is more than a single MPI task + if (mpi_size > 1) { + // MPI all reduce nodal volume + this->template nodal_halo_exchange( + std::bind(&mpm::NodeBase::volume, std::placeholders::_1, + mpm::ParticlePhase::SinglePhase), + std::bind(&mpm::NodeBase::update_volume, std::placeholders::_1, + false, mpm::ParticlePhase::SinglePhase, + std::placeholders::_2)); + } #endif - // 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 - 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); - } + // 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 + for (auto pitr = this->particles_.cbegin(); pitr != this->particles_.cend(); + ++pitr) { + status = (*pitr)->compute_free_surface_by_density(); + if (status) { + (*pitr)->assign_free_surface(status); } - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); } + return status; } From 4f550b12a948172c025aeae5125988ae841c7ae3 Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 17 Nov 2020 17:24:01 +0700 Subject: [PATCH 170/175] :construction: use iterate_over function with lambda function input --- include/mesh.h | 6 ++++ include/mesh_multiphase.tcc | 59 ++++++++++++++++--------------------- 2 files changed, 32 insertions(+), 33 deletions(-) diff --git a/include/mesh.h b/include/mesh.h index 815e896f7..d94739767 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -492,6 +492,12 @@ class Mesh { */ /**@{*/ + //! Compute cell volume fraction + //! \ingroup MultiPhase + //! \details Compute cell volume fraction based on the number of particle + //! see (Kularathna & Soga 2017). + void compute_cell_vol_fraction(); + //! Compute free surface //! \ingroup MultiPhase //! \param[in] method Type of method to use diff --git a/include/mesh_multiphase.tcc b/include/mesh_multiphase.tcc index 39670aeb5..4b1b4b99d 100644 --- a/include/mesh_multiphase.tcc +++ b/include/mesh_multiphase.tcc @@ -42,17 +42,7 @@ bool mpm::Mesh::compute_free_surface_by_geometry( 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); - } - } + this->compute_cell_vol_fraction(); // First, we detect the cell with possible free surfaces // Compute boundary cells and nodes based on geometry @@ -250,10 +240,6 @@ bool mpm::Mesh::compute_free_surface_by_density(double volume_tolerance) { MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); - // // Reset solving status - // this->iterate_over_cells(std::bind(&mpm::Cell::assign_solving_status, - // std::placeholders::_1, false)); - // Initialize pointer of booleans for send and receive bool* send_cell_solving_status = new bool[ncells()]; memset(send_cell_solving_status, 0, ncells() * sizeof(bool)); @@ -292,17 +278,7 @@ bool mpm::Mesh::compute_free_surface_by_density(double volume_tolerance) { 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); - } - } + this->compute_cell_vol_fraction(); #ifdef USE_MPI // Initialize vector of double for send and receive @@ -414,13 +390,13 @@ bool mpm::Mesh::compute_free_surface_by_density(double volume_tolerance) { std::bind(&mpm::NodeBase::status, std::placeholders::_1)); // Evaluate free surface particles - for (auto pitr = this->particles_.cbegin(); pitr != this->particles_.cend(); - ++pitr) { - status = (*pitr)->compute_free_surface_by_density(); - if (status) { - (*pitr)->assign_free_surface(status); - } - } + this->iterate_over_particles( + [](std::shared_ptr> ptr) { + bool status = ptr->compute_free_surface_by_density(); + if (status) { + return ptr->assign_free_surface(status); + } + }); return status; } @@ -453,6 +429,23 @@ std::set mpm::Mesh::free_surface_particles() { return id_set; } +//! Compute cell volume fraction +template +void mpm::Mesh::compute_cell_vol_fraction() { + this->iterate_over_cells([&map_particles = map_particles_]( + std::shared_ptr> c_ptr) { + if (c_ptr->status()) { + // Compute volume fraction + double cell_volume_fraction = 0.0; + for (const auto p_id : c_ptr->particles()) + cell_volume_fraction += map_particles[p_id]->volume(); + + cell_volume_fraction = cell_volume_fraction / c_ptr->volume(); + return c_ptr->assign_volume_fraction(cell_volume_fraction); + } + }); +} + //! Assign particle pore pressures template bool mpm::Mesh::assign_particles_pore_pressures( From 2ddbf232997b2895da093c0cdd698615b847cc38 Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 17 Nov 2020 18:37:53 +0700 Subject: [PATCH 171/175] :construction: modify particle and node functions as suggested --- include/node.h | 6 +++--- include/node_base.h | 6 +++--- include/particles/particle.h | 13 ++++--------- include/particles/particle.tcc | 11 ++++++++++- include/particles/particle_base.h | 8 ++++---- include/particles/particle_twophase.h | 2 +- include/particles/particle_twophase.tcc | 2 +- include/solvers/mpm_base.tcc | 2 +- src/particle.cc | 2 +- 9 files changed, 28 insertions(+), 24 deletions(-) diff --git a/include/node.h b/include/node.h index d5db61c62..753eb1df6 100644 --- a/include/node.h +++ b/include/node.h @@ -260,9 +260,9 @@ class Node : public NodeBase { //! Set ghost id void ghost_id(Index gid) override { ghost_id_ = gid; } - //! Return real density at a given node for a given phase + //! Return interpolated 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); } + double density(unsigned phase) const override { return density_(phase); } //! Compute nodal density void compute_density() override; @@ -273,7 +273,7 @@ class Node : public NodeBase { } //! Return free surface bool - bool free_surface() override { return free_surface_; } + bool free_surface() const override { return free_surface_; } //! Update nodal property at the nodes from particle //! \param[in] update A boolean to update (true) or assign (false) diff --git a/include/node_base.h b/include/node_base.h index b8e206835..693ea694c 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -277,9 +277,9 @@ class NodeBase { //! Set ghost id virtual void ghost_id(Index gid) = 0; - //! Return real density at a given node for a given phase + //! Return interpolated density at a given node for a given phase //! \param[in] phase Index corresponding to the phase - virtual double density(unsigned phase) = 0; + virtual double density(unsigned phase) const = 0; //! Compute nodal density virtual void compute_density() = 0; @@ -288,7 +288,7 @@ class NodeBase { virtual void assign_free_surface(bool free_surface) = 0; //! Return free surface bool - virtual bool free_surface() = 0; + virtual bool free_surface() const = 0; //! Update nodal property at the nodes from particle //! \param[in] update A boolean to update (true) or assign (false) diff --git a/include/particles/particle.h b/include/particles/particle.h index 0440aa834..b3b6ed8ed 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -62,7 +62,7 @@ class Particle : public ParticleBase { //! Return particle data as POD //! \retval particle POD of the particle - std::shared_ptr pod() override; + std::shared_ptr pod() const override; //! Initialise properties void initialise() override; @@ -113,12 +113,7 @@ class Particle : public ParticleBase { double volume() const override { return volume_; } //! Return the approximate particle diameter - double diameter() const override { - 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; - } + double diameter() const override; //! Return size of particle in natural coordinates VectorDim natural_size() const override { return natural_size_; } @@ -318,7 +313,7 @@ class Particle : public ParticleBase { }; //! Return free surface bool - bool free_surface() override { return free_surface_; }; + bool free_surface() const override { return free_surface_; }; //! Compute free surface in particle level by density ratio comparison //! \param[in] density_ratio_tolerance Tolerance of density ratio comparison @@ -330,7 +325,7 @@ class Particle : public ParticleBase { void assign_normal(const VectorDim& normal) override { normal_ = normal; }; //! Return normal vector - VectorDim normal() override { return normal_; }; + VectorDim normal() const override { return normal_; }; //! Return the number of neighbour particles unsigned nneighbours() const override { return neighbours_.size(); }; diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index 0a076cdb1..3379d4e62 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -139,7 +139,7 @@ bool mpm::Particle::initialise_particle( //! Return particle data as POD template // cppcheck-suppress * -std::shared_ptr mpm::Particle::pod() { +std::shared_ptr mpm::Particle::pod() const { // Initialise particle data auto particle_data = std::make_shared(); @@ -515,6 +515,15 @@ void mpm::Particle::update_volume() noexcept { this->mass_density_ = this->mass_density_ / (1. + dvolumetric_strain_); } +//! Return the approximate particle diameter +template +double mpm::Particle::diameter() const { + 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; +} + // Compute mass of particle template void mpm::Particle::compute_mass() noexcept { diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 2e0b99b74..2baee011a 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -36,7 +36,7 @@ enum ParticlePhase : unsigned int { //! Particle type extern std::map ParticleType; extern std::map ParticleTypeName; -extern std::map ParticleHDF5TypeName; +extern std::map ParticlePODTypeName; //! ParticleBase class //! \brief Base class that stores the information about particleBases @@ -84,7 +84,7 @@ class ParticleBase { //! Return particle data as POD //! \retval particle POD of the particle - virtual std::shared_ptr pod() = 0; + virtual std::shared_ptr pod() const = 0; //! Return id of the particleBase Index id() const { return id_; } @@ -311,7 +311,7 @@ class ParticleBase { virtual void assign_free_surface(bool free_surface) = 0; //! Assign particle free surface - virtual bool free_surface() = 0; + virtual bool free_surface() const = 0; //! Compute free surface in particle level by density ratio comparison virtual bool compute_free_surface_by_density( @@ -321,7 +321,7 @@ class ParticleBase { virtual void assign_normal(const VectorDim& normal) = 0; //! Return normal vector - virtual VectorDim normal() = 0; + virtual VectorDim normal() const = 0; //! Return the number of neighbour particles virtual unsigned nneighbours() const = 0; diff --git a/include/particles/particle_twophase.h b/include/particles/particle_twophase.h index 88c0cac61..b850c6d4b 100644 --- a/include/particles/particle_twophase.h +++ b/include/particles/particle_twophase.h @@ -61,7 +61,7 @@ class TwoPhaseParticle : public mpm::Particle { //! Return particle data as POD //! \retval particle POD of the particle - std::shared_ptr pod() override; + std::shared_ptr pod() const override; //! Assign saturation degree bool assign_saturation_degree() override; diff --git a/include/particles/particle_twophase.tcc b/include/particles/particle_twophase.tcc index 2e8bd6fde..9cd5647a4 100644 --- a/include/particles/particle_twophase.tcc +++ b/include/particles/particle_twophase.tcc @@ -34,7 +34,7 @@ mpm::TwoPhaseParticle::TwoPhaseParticle(Index id, const VectorDim& coord, //! Return particle data as POD template // cppcheck-suppress * -std::shared_ptr mpm::TwoPhaseParticle::pod() { +std::shared_ptr mpm::TwoPhaseParticle::pod() const { // Initialise particle_data auto particle_data = std::make_shared(); diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index e00b27911..194370b7b 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -452,7 +452,7 @@ bool mpm::MPMBase::checkpoint_resume() { // Input particle h5 file for resume for (const auto ptype : particle_types_) { - std::string attribute = mpm::ParticleHDF5TypeName.at(ptype); + std::string attribute = mpm::ParticlePODTypeName.at(ptype); std::string extension = ".h5"; auto particles_file = diff --git a/src/particle.cc b/src/particle.cc index b75d15b00..20f0bc997 100644 --- a/src/particle.cc +++ b/src/particle.cc @@ -9,7 +9,7 @@ std::map ParticleType = { {"P2D", 0}, {"P3D", 1}, {"P2D2PHASE", 2}, {"P3D2PHASE", 3}}; std::map ParticleTypeName = { {0, "P2D"}, {1, "P3D"}, {2, "P2D2PHASE"}, {3, "P3D2PHASE"}}; -std::map ParticleHDF5TypeName = { +std::map ParticlePODTypeName = { {"P2D", "particles"}, {"P3D", "particles"}, {"P2D2PHASE", "twophase_particles"}, From fe725f6276f27f41ac847592a7bba514d55aee1a Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 17 Nov 2020 18:59:44 +0700 Subject: [PATCH 172/175] :construction: additional fixes on assertion and some info --- include/particles/particle.h | 5 ++++- include/particles/particle.tcc | 6 ++---- include/solvers/mpm_base.tcc | 6 ------ 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/include/particles/particle.h b/include/particles/particle.h index b3b6ed8ed..f998bb112 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -316,7 +316,10 @@ class Particle : public ParticleBase { bool free_surface() const override { return free_surface_; }; //! Compute free surface in particle level by density ratio comparison - //! \param[in] density_ratio_tolerance Tolerance of density ratio comparison + //! \param[in] density_ratio_tolerance Tolerance of density ratio comparison. + //! Default value is set to be 0.65, which is derived from a 3D case where at + //! one side the cell is fully occupied by particles and the other side the + //! cell is empty. See (Hamad, 2015). //! \retval status Status of compute_free_surface bool compute_free_surface_by_density( double density_ratio_tolerance = 0.65) override; diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index 3379d4e62..351a1a63d 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -294,10 +294,8 @@ bool mpm::Particle::assign_material_state_vars( template void mpm::Particle::assign_state_variable(const std::string& var, double value, unsigned phase) { - if (state_variables_[phase].find(var) != state_variables_[phase].end()) - state_variables_[phase].at(var) = value; - else - throw std::runtime_error(var + " cannot be found in state variables!"); + assert(state_variables_[phase].find(var) != state_variables_[phase].end()); + state_variables_[phase].at(var) = value; } // Assign a cell to particle diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index 194370b7b..67f81dec6 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -965,8 +965,6 @@ template void mpm::MPMBase::nodal_pressure_constraints( const Json& mesh_props, const std::shared_ptr>& mesh_io) { try { - // TODO: Get the total phases - const unsigned Tnphases = 2; // Read and assign pressure constraints if (mesh_props.find("boundary_conditions") != mesh_props.end() && mesh_props["boundary_conditions"].find("pressure_constraints") != @@ -978,10 +976,6 @@ void mpm::MPMBase::nodal_pressure_constraints( // Pore pressure constraint phase indice unsigned constraint_phase = constraints["phase_id"]; - if (constraint_phase >= Tnphases) - throw std::runtime_error( - "Phase for nodal pressure constraints is not properly assigned"); - // Pore pressure constraints are specified in a file if (constraints.find("file") != constraints.end()) { std::string pressure_constraints_file = From eae0fbf4d78f4a1863a17cb7b622c63c165b6066 Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 17 Nov 2020 22:11:40 +0700 Subject: [PATCH 173/175] :dart: :construction: remove throw test --- tests/particles/particle_test.cc | 2 -- tests/particles/particle_twophase_test.cc | 2 -- 2 files changed, 4 deletions(-) diff --git a/tests/particles/particle_test.cc b/tests/particles/particle_test.cc index 97a50f40a..d291fca98 100644 --- a/tests/particles/particle_test.cc +++ b/tests/particles/particle_test.cc @@ -1255,7 +1255,6 @@ TEST_CASE("Particle is checked for 2D case", "[particle][2D]") { 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_THROWS(particle->assign_pressure(1000)); REQUIRE(std::isnan(particle->pressure()) == true); } @@ -2572,7 +2571,6 @@ TEST_CASE("Particle is checked for 3D case", "[particle][3D]") { 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_THROWS(particle->assign_pressure(1000)); REQUIRE(std::isnan(particle->pressure()) == true); } diff --git a/tests/particles/particle_twophase_test.cc b/tests/particles/particle_twophase_test.cc index 024efbe5a..7ef55e151 100644 --- a/tests/particles/particle_twophase_test.cc +++ b/tests/particles/particle_twophase_test.cc @@ -1304,7 +1304,6 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", 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_THROWS(particle->assign_pressure(1000)); REQUIRE(std::isnan(particle->pressure()) == true); } @@ -2754,7 +2753,6 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", 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_THROWS(particle->assign_pressure(1000)); REQUIRE(std::isnan(particle->pressure()) == true); } From 72dbc24b516407c4ca27930a589adfc1f2b08e62 Mon Sep 17 00:00:00 2001 From: Nanda Date: Mon, 23 Nov 2020 17:27:20 +0700 Subject: [PATCH 174/175] :construction: grouping node multiphase --- include/node.h | 59 +++++++------ include/node.tcc | 19 ----- include/node_base.h | 84 +++++++++++-------- ...{node_twophase.tcc => node_multiphase.tcc} | 25 ++++++ include/solvers/mpm_explicit_twophase.tcc | 4 +- 5 files changed, 111 insertions(+), 80 deletions(-) rename include/{node_twophase.tcc => node_multiphase.tcc} (86%) diff --git a/include/node.h b/include/node.h index 753eb1df6..a7224e907 100644 --- a/include/node.h +++ b/include/node.h @@ -260,21 +260,6 @@ class Node : public NodeBase { //! Set ghost id void ghost_id(Index gid) override { ghost_id_ = gid; } - //! Return interpolated density at a given node for a given phase - //! \param[in] phase Index corresponding to the phase - double density(unsigned phase) const override { return density_(phase); } - - //! Compute nodal density - void compute_density() override; - - //! Assign free surface - void assign_free_surface(bool free_surface) override { - free_surface_ = free_surface; - } - - //! Return free surface bool - bool free_surface() const override { return free_surface_; } - //! Update nodal property at the nodes from particle //! \param[in] update A boolean to update (true) or assign (false) //! \param[in] property Property name @@ -295,37 +280,59 @@ class Node : public NodeBase { void compute_multimaterial_normal_unit_vector() override; /** - * \defgroup TwoPhase Functions dealing with two-phase MPM + * \defgroup MultiPhase Functions dealing with multi-phase MPM */ /**@{*/ + //! Return interpolated density at a given node for a given phase + //! \ingroup MultiPhase + //! \param[in] phase Index corresponding to the phase + double density(unsigned phase) const override { return density_(phase); } + + //! Compute nodal density + //! \ingroup MultiPhase + void compute_density() override; + + //! Assign free surface + //! \ingroup MultiPhase + void assign_free_surface(bool free_surface) override { + free_surface_ = free_surface; + } + + //! Return free surface bool + //! \ingroup MultiPhase + bool free_surface() const override { return free_surface_; } + + //! Initialise two-phase nodal properties + void initialise_twophase() noexcept override; + //! Update internal force (body force / traction force) - //! \ingroup TwoPhase + //! \ingroup MultiPhase //! \param[in] update A boolean to update (true) or assign (false) //! \param[in] drag_force Drag force from the particles in a cell //! \retval status Update status void update_drag_force_coefficient(bool update, const VectorDim& drag_force) override; + //! Return drag force at a given node + //! \ingroup MultiPhase + VectorDim drag_force_coefficient() const override { + return drag_force_coefficient_; + } + //! Compute acceleration and velocity for two phase - //! \ingroup TwoPhase + //! \ingroup MultiPhase //! \param[in] dt Timestep in analysis bool compute_acceleration_velocity_twophase_explicit( double dt) noexcept override; //! Compute acceleration and velocity for two phase with cundall damping - //! \ingroup TwoPhase + //! \ingroup MultiPhase //! \param[in] dt Timestep in analysis \param[in] damping_factor //! Damping factor bool compute_acceleration_velocity_twophase_explicit_cundall( double dt, double damping_factor) noexcept override; - //! Return drag force at a given node - //! \ingroup TwoPhase - VectorDim drag_force_coefficient() const override { - return drag_force_coefficient_; - } - /**@}*/ private: @@ -397,6 +404,6 @@ class Node : public NodeBase { } // namespace mpm #include "node.tcc" -#include "node_twophase.tcc" +#include "node_multiphase.tcc" #endif // MPM_NODE_H_ diff --git a/include/node.tcc b/include/node.tcc index 2fd2bb162..7040e0b7f 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -35,8 +35,6 @@ void mpm::Node::initialise() noexcept { free_surface_ = false; status_ = false; material_ids_.clear(); - // Specific variables for two phase - drag_force_coefficient_.setZero(); } //! Initialise shared pointer to nodal properties pool @@ -582,23 +580,6 @@ bool mpm::Node::mpi_rank(unsigned rank) { return status.second; } -//! Compute mass density (Z. Wiezckowski, 2004) -//! density = mass / lumped volume -template -void mpm::Node::compute_density() { - 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)) < tolerance) density_(phase) = 0.; - } - } -} - //! Update nodal property at the nodes from particle template void mpm::Node::update_property( diff --git a/include/node_base.h b/include/node_base.h index 693ea694c..c6121cdf8 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -135,16 +135,6 @@ class NodeBase { //! \param[in] phase Index corresponding to the phase virtual VectorDim internal_force(unsigned phase) const = 0; - //! Update internal force (body force / traction force) - //! \param[in] update A boolean to update (true) or assign (false) - //! \param[in] drag_force Drag force from the particles in a cell - //! \retval status Update status - virtual void update_drag_force_coefficient(bool update, - const VectorDim& drag_force) = 0; - - //! Return drag force at a given node - virtual VectorDim drag_force_coefficient() const = 0; - //! Update pressure at the nodes from particle //! \param[in] phase Index corresponding to the phase //! \param[in] mass_pressure Product of mass x pressure of a particle @@ -209,16 +199,6 @@ class NodeBase { virtual bool compute_acceleration_velocity_cundall( unsigned phase, double dt, double damping_factor) noexcept = 0; - //! Compute acceleration and velocity for two phase - //! \param[in] dt Timestep in analysis - virtual bool compute_acceleration_velocity_twophase_explicit( - double dt) noexcept = 0; - - //! Compute acceleration and velocity for two phase with cundall damping - //! \param[in] dt Timestep in analysis - virtual bool compute_acceleration_velocity_twophase_explicit_cundall( - double dt, double damping_factor) noexcept = 0; - //! Assign pressure constraint //! \param[in] phase Index corresponding to the phase //! \param[in] pressure Applied pressure constraint @@ -277,19 +257,6 @@ class NodeBase { //! Set ghost id virtual void ghost_id(Index gid) = 0; - //! Return interpolated density at a given node for a given phase - //! \param[in] phase Index corresponding to the phase - virtual double density(unsigned phase) const = 0; - - //! Compute nodal density - virtual void compute_density() = 0; - - //! Assign free surface - virtual void assign_free_surface(bool free_surface) = 0; - - //! Return free surface bool - virtual bool free_surface() const = 0; - //! Update nodal property at the nodes from particle //! \param[in] update A boolean to update (true) or assign (false) //! \param[in] property Property name @@ -309,6 +276,57 @@ class NodeBase { //! Compute multimaterial normal unit vector virtual void compute_multimaterial_normal_unit_vector() = 0; + /** + * \defgroup MultiPhase Functions dealing with multi-phase MPM + */ + /**@{*/ + + //! Return interpolated density at a given node for a given phase + //! \ingroup MultiPhase + //! \param[in] phase Index corresponding to the phase + virtual double density(unsigned phase) const = 0; + + //! Compute nodal density + //! \ingroup MultiPhase + virtual void compute_density() = 0; + + //! Assign free surface + //! \ingroup MultiPhase + virtual void assign_free_surface(bool free_surface) = 0; + + //! Return free surface bool + //! \ingroup MultiPhase + virtual bool free_surface() const = 0; + + //! Initialise two-phase nodal properties + virtual void initialise_twophase() noexcept = 0; + + //! Update internal force (body force / traction force) + //! \ingroup MultiPhase + //! \param[in] update A boolean to update (true) or assign (false) + //! \param[in] drag_force Drag force from the particles in a cell + //! \retval status Update status + virtual void update_drag_force_coefficient(bool update, + const VectorDim& drag_force) = 0; + + //! Return drag force at a given node + //! \ingroup MultiPhase + virtual VectorDim drag_force_coefficient() const = 0; + + //! Compute acceleration and velocity for two phase + //! \ingroup MultiPhase + //! \param[in] dt Timestep in analysis + virtual bool compute_acceleration_velocity_twophase_explicit( + double dt) noexcept = 0; + + //! Compute acceleration and velocity for two phase with cundall damping + //! \ingroup MultiPhase + //! \param[in] dt Timestep in analysis + virtual bool compute_acceleration_velocity_twophase_explicit_cundall( + double dt, double damping_factor) noexcept = 0; + + /**@}*/ + }; // NodeBase class } // namespace mpm diff --git a/include/node_twophase.tcc b/include/node_multiphase.tcc similarity index 86% rename from include/node_twophase.tcc rename to include/node_multiphase.tcc index d1f6f033e..4b7725462 100644 --- a/include/node_twophase.tcc +++ b/include/node_multiphase.tcc @@ -1,3 +1,28 @@ +//! Compute mass density (Z. Wiezckowski, 2004) +//! density = mass / lumped volume +template +void mpm::Node::compute_density() { + 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)) < tolerance) density_(phase) = 0.; + } + } +} + +//! Initialise two-phase nodal properties +template +void mpm::Node::initialise_twophase() noexcept { + this->initialise(); + // Specific variables for two phase + drag_force_coefficient_.setZero(); +} + //! Update drag force coefficient template void mpm::Node::update_drag_force_coefficient( diff --git a/include/solvers/mpm_explicit_twophase.tcc b/include/solvers/mpm_explicit_twophase.tcc index 822e8394e..13c590fde 100644 --- a/include/solvers/mpm_explicit_twophase.tcc +++ b/include/solvers/mpm_explicit_twophase.tcc @@ -135,8 +135,8 @@ bool mpm::MPMExplicitTwoPhase::solve() { #pragma omp section { // Initialise nodes - mesh_->iterate_over_nodes( - std::bind(&mpm::NodeBase::initialise, std::placeholders::_1)); + mesh_->iterate_over_nodes(std::bind( + &mpm::NodeBase::initialise_twophase, std::placeholders::_1)); mesh_->iterate_over_cells( std::bind(&mpm::Cell::activate_nodes, std::placeholders::_1)); From 2ad9bc28c59ba464b3a4e6ec2fa22a7c9615d54b Mon Sep 17 00:00:00 2001 From: Nanda Date: Mon, 23 Nov 2020 19:10:26 +0700 Subject: [PATCH 175/175] :dart: :construction: fix test error due to initialise twophase --- include/node.h | 1 + tests/nodes/node_twophase_test.cc | 9 +++++++++ tests/particles/particle_twophase_test.cc | 7 ++++++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/include/node.h b/include/node.h index a7224e907..3ecd9af35 100644 --- a/include/node.h +++ b/include/node.h @@ -304,6 +304,7 @@ class Node : public NodeBase { bool free_surface() const override { return free_surface_; } //! Initialise two-phase nodal properties + //! \ingroup MultiPhase void initialise_twophase() noexcept override; //! Update internal force (body force / traction force) diff --git a/tests/nodes/node_twophase_test.cc b/tests/nodes/node_twophase_test.cc index d5fa22f1f..f84383299 100644 --- a/tests/nodes/node_twophase_test.cc +++ b/tests/nodes/node_twophase_test.cc @@ -120,6 +120,9 @@ TEST_CASE("Twophase Node is checked for 1D case", "[node][1D][2Phase]") { std::shared_ptr> node = std::make_shared>(id, coords); + // Initialise two-phase node + REQUIRE_NOTHROW(node->initialise_twophase()); + // Check mass REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(0.0).epsilon(Tolerance)); @@ -865,6 +868,9 @@ TEST_CASE("Twophase Node is checked for 2D case", "[node][2D][2Phase]") { std::shared_ptr> node = std::make_shared>(id, coords); + // Initialise two-phase node + REQUIRE_NOTHROW(node->initialise_twophase()); + // Check mass REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(0.0).epsilon(Tolerance)); @@ -1778,6 +1784,9 @@ TEST_CASE("Twophase Node is checked for 3D case", "[node][3D][2Phase]") { std::shared_ptr> node = std::make_shared>(id, coords); + // Initialise two-phase node + REQUIRE_NOTHROW(node->initialise_twophase()); + // Check mass REQUIRE(node->mass(mpm::NodePhase::NSolid) == Approx(0.0).epsilon(Tolerance)); diff --git a/tests/particles/particle_twophase_test.cc b/tests/particles/particle_twophase_test.cc index 7ef55e151..397cd9980 100644 --- a/tests/particles/particle_twophase_test.cc +++ b/tests/particles/particle_twophase_test.cc @@ -856,6 +856,10 @@ TEST_CASE("TwoPhase Particle is checked for 2D case", // Test compute stress before material assignment // TODO Assert: REQUIRE(particle->compute_stress() == false); + // Initialise nodal variables + for (unsigned i = 0; i < nodes.size(); ++i) + REQUIRE_NOTHROW(nodes.at(i)->initialise_twophase()); + // Assign material properties REQUIRE(particle->assign_material(material) == true); REQUIRE(particle->assign_material(liquid_material, @@ -2671,7 +2675,8 @@ TEST_CASE("TwoPhase Particle is checked for 3D case", // Map particle mass to nodes particle->assign_mass(std::numeric_limits::max()); - // TODO Assert: REQUIRE(particle->map_mass_momentum_to_nodes() == false); + // TODO Assert: REQUIRE(particle->map_mass_momentum_to_nodes() == + // false); // Map particle pressure to nodes // TODO Assert: REQUIRE(particle->map_pressure_to_nodes() == false);