From 90c00e19007569c7cb6c504598ec923737495bd7 Mon Sep 17 00:00:00 2001 From: yong liang Date: Sat, 1 Aug 2020 13:08:31 -0700 Subject: [PATCH 01/91] :tada::sparkles:creat xmpm solver and ParticleXMPM class --- CMakeLists.txt | 2 + include/io/logger.h | 3 + include/particles/particle_xmpm.h | 381 ++++++++++++ include/particles/particle_xmpm.tcc | 876 ++++++++++++++++++++++++++++ include/solvers/xmpm_explicit.h | 84 +++ include/solvers/xmpm_explicit.tcc | 333 +++++++++++ include/xmpm/discontinuity_3d.h | 79 +++ include/xmpm/discontinuity_3d.tcc | 99 ++++ include/xmpm/discontinuity_base.h | 185 ++++++ src/discontinuity.cc | 6 + src/io/logger.cc | 4 + src/mpm.cc | 5 + src/particle.cc | 6 + 13 files changed, 2063 insertions(+) create mode 100644 include/particles/particle_xmpm.h create mode 100644 include/particles/particle_xmpm.tcc create mode 100644 include/solvers/xmpm_explicit.h create mode 100644 include/solvers/xmpm_explicit.tcc create mode 100755 include/xmpm/discontinuity_3d.h create mode 100755 include/xmpm/discontinuity_3d.tcc create mode 100755 include/xmpm/discontinuity_base.h create mode 100755 src/discontinuity.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 5fc7cfa1d..b42fbace9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -144,6 +144,7 @@ include_directories(BEFORE ${mpm_SOURCE_DIR}/include/solvers/ ${mpm_SOURCE_DIR}/external/ ${mpm_SOURCE_DIR}/tests/include/ + ${mpm_SOURCE_DIR}/include/xmpm/ ) # mpm executable @@ -167,6 +168,7 @@ SET(mpm_src ${mpm_SOURCE_DIR}/src/node.cc ${mpm_SOURCE_DIR}/src/particle.cc ${mpm_SOURCE_DIR}/src/quadrature.cc + ${mpm_SOURCE_DIR}/src/discontinuity.cc ) add_executable(mpm ${mpm_SOURCE_DIR}/src/main.cc ${mpm_src} ${mpm_vtk}) diff --git a/include/io/logger.h b/include/io/logger.h index 082a0e874..01c1afcf7 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 xmpm_explicit_logger; }; } // namespace mpm diff --git a/include/particles/particle_xmpm.h b/include/particles/particle_xmpm.h new file mode 100644 index 000000000..3b2897d21 --- /dev/null +++ b/include/particles/particle_xmpm.h @@ -0,0 +1,381 @@ +#ifndef MPM_PARTICLE_XMPM_H_ +#define MPM_PARTICLE_XMPM_H_ + +#include +#include +#include +#include +#include + +#include "cell.h" +#include "logger.h" +#include "particle_base.h" + +namespace mpm { + +//! ParticleXMPM class +//! \brief Base class that stores the information about particles +//! \details ParticleXMPM class: id_ and coordinates. +//! \tparam Tdim Dimension +template +class ParticleXMPM : public ParticleBase { + public: + //! Define a vector of size dimension + using VectorDim = Eigen::Matrix; + + //! Define DOFs + static const unsigned Tdof = (Tdim == 1) ? 1 : 3 * (Tdim - 1); + + //! Construct a particle with id and coordinates + //! \param[in] id Particle id + //! \param[in] coord coordinates of the particle + ParticleXMPM(Index id, const VectorDim& coord); + + //! Construct a 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) + ParticleXMPM(Index id, const VectorDim& coord, bool status); + + //! Destructor + ~ParticleXMPM() override{}; + + //! Delete copy constructor + ParticleXMPM(const ParticleXMPM&) = delete; + + //! Delete assignment operator + ParticleXMPM& operator=(const ParticleXMPM&) = 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 + virtual bool initialise_particle( + 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; + + //! Initialise properties + void initialise() override; + + //! Compute reference coordinates in a cell + bool compute_reference_location() noexcept override; + + //! Return reference location + VectorDim reference_location() const override { return xi_; } + + //! Assign a cell to particle + //! If point is in new cell, assign new cell and remove particle id from old + //! cell. If point can't be found in the new cell, check if particle is still + //! valid in the old cell, if it is leave it as is. If not, set cell as null + //! \param[in] cellptr Pointer to a cell + bool assign_cell(const std::shared_ptr>& cellptr) override; + + //! Assign a cell to particle + //! If point is in new cell, assign new cell and remove particle id from old + //! cell. If point can't be found in the new cell, check if particle is still + //! valid in the old cell, if it is leave it as is. If not, set cell as null + //! \param[in] cellptr Pointer to a cell + //! \param[in] xi Local coordinates of the point in reference cell + bool assign_cell_xi(const std::shared_ptr>& cellptr, + const Eigen::Matrix& xi) override; + + //! Assign cell id + //! \param[in] id Cell id + bool assign_cell_id(Index id) override; + + //! Return cell id + Index cell_id() const override { return cell_id_; } + + //! Return cell ptr status + bool cell_ptr() const override { return cell_ != nullptr; } + + //! Remove cell associated with the particle + void remove_cell() override; + + //! Compute shape functions of a particle, based on local coordinates + void compute_shapefn() noexcept override; + + //! Assign volume + //! \param[in] volume Volume of particle + bool assign_volume(double volume) override; + + //! Return 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 + //! \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; + + //! Map multimaterial displacements to nodes + void map_multimaterial_displacements_to_nodes() noexcept override; + + //! Map multimaterial domain gradients to nodes + void map_multimaterial_domain_gradients_to_nodes() noexcept override; + + //! 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; } + + //! Return mass of the particles + double mass() const override { return mass_; } + + //! Assign material + //! \param[in] material Pointer to a material + //! \param[in] phase Index to indicate phase + bool assign_material(const std::shared_ptr>& material, + unsigned phase = mpm::ParticlePhase::Solid) override; + + //! Compute strain + //! \param[in] dt Analysis time step + void compute_strain(double dt) noexcept override; + + //! Return strain of the particle + Eigen::Matrix strain() const override { return strain_; } + + //! Return strain rate of the particle + Eigen::Matrix strain_rate() const override { + return strain_rate_; + }; + + //! Return dvolumetric strain of centroid + //! \retval dvolumetric strain at centroid + double dvolumetric_strain() const override { return dvolumetric_strain_; } + + //! Return volumetric strain of centroid + //! \retval volumetric strain at centroid + double volumetric_strain_centroid() const override { + return volumetric_strain_centroid_; + } + + //! Initial stress + //! \param[in] stress Initial sress + void initial_stress(const Eigen::Matrix& stress) override { + this->stress_ = stress; + } + + //! Compute stress + void compute_stress() noexcept override; + + //! 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 + //! \retval status Assignment status + bool assign_velocity(const VectorDim& velocity) override; + + //! Return velocity of the particle + VectorDim velocity() const override { return velocity_; } + + //! Return displacement of the particle + VectorDim displacement() const override { return displacement_; } + + //! 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 traction of the particle + //! \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; + + //! Return a state variable + //! \param[in] var State variable + //! \param[in] phase Index to indicate phase + //! \retval Quantity of the state history variable + double state_variable( + const std::string& var, + unsigned phase = mpm::ParticlePhase::Solid) const override { + return (state_variables_[phase].find(var) != state_variables_[phase].end()) + ? state_variables_[phase].at(var) + : std::numeric_limits::quiet_NaN(); + } + + //! 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 + 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 tensor data of particles + //! \param[in] property Property string + //! \retval vecdata Tensor data of particle property + Eigen::VectorXd tensor_data(const std::string& property) 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; + + //! Assign material id of this particle to nodes + void append_material_id_to_nodes() const override; + + //! Return the number of neighbour particles + unsigned nneighbours() const override { return neighbours_.size(); }; + + //! Assign neighbour particles + //! \param[in] neighbours set of id of the neighbouring particles + //! \retval insertion_status Return the successful addition of a node + void assign_neighbours(const std::vector& neighbours) override; + + //! Return neighbour ids + std::vector neighbours() const override { return neighbours_; }; + + protected: + //! Initialise particle material container + //! \details This function allocate memory and initialise the material related + //! containers according to the particle phase, i.e. solid or fluid particle + //! has phase_size = 1, whereas two-phase (solid-fluid) or three-phase + //! (solid-water-air) particle have phase_size = 2 and 3, respectively. + //! \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 + //! \retval strain rate at particle inside a cell + inline Eigen::Matrix compute_strain_rate( + const Eigen::MatrixXd& dn_dx, unsigned phase) noexcept; + + private: + //! particle id + using ParticleBase::id_; + //! coordinates + using ParticleBase::coordinates_; + //! Reference coordinates (in a cell) + using ParticleBase::xi_; + //! Cell + using ParticleBase::cell_; + //! Cell id + using ParticleBase::cell_id_; + //! Nodes + using ParticleBase::nodes_; + //! Status + using ParticleBase::status_; + //! Material + using ParticleBase::material_; + //! Material id + using ParticleBase::material_id_; + //! State variables + using ParticleBase::state_variables_; + //! Neighbour particles + using ParticleBase::neighbours_; + //! 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 + Eigen::Matrix natural_size_; + //! Stresses + Eigen::Matrix stress_; + //! Strains + Eigen::Matrix strain_; + //! dvolumetric strain + double dvolumetric_strain_{0.}; + //! Volumetric strain at centroid + double volumetric_strain_centroid_{0.}; + //! Strain rate + 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 + Eigen::MatrixXd dn_dx_centroid_; + //! Logger + std::unique_ptr console_; + //! Map of vector properties + std::map> properties_; + //!level set values for discontinuity + double levelset_phi_{0.}; +}; // ParticleXMPM class +} // namespace mpm + +#include "particle_xmpm.tcc" + +#endif // MPM_PARTICLE_XMPM_H__ diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc new file mode 100644 index 000000000..8220bac9c --- /dev/null +++ b/include/particles/particle_xmpm.tcc @@ -0,0 +1,876 @@ +//! Construct a particle with id and coordinates +template +mpm::ParticleXMPM::ParticleXMPM(Index id, const VectorDim& coord) + : mpm::ParticleBase(id, coord) { + this->initialise(); + // Clear cell ptr + cell_ = nullptr; + // Nodes + nodes_.clear(); + // Set material containers + this->initialise_material(1); + // Logger + std::string logger = + "particlexmpm" + std::to_string(Tdim) + "d::" + std::to_string(id); + console_ = std::make_unique(logger, mpm::stdout_sink); +} + +//! Construct a particle with id, coordinates and status +template +mpm::ParticleXMPM::ParticleXMPM(Index id, const VectorDim& coord, bool status) + : mpm::ParticleBase(id, coord, status) { + this->initialise(); + cell_ = nullptr; + nodes_.clear(); + // Set material containers + this->initialise_material(1); + //! Logger + std::string logger = + "particlexmpm" + 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::ParticleXMPM::initialise_particle(const HDF5Particle& particle) { + + // Assign id + this->id_ = particle.id; + // Mass + this->mass_ = particle.mass; + // Volume + this->volume_ = particle.volume; + // Mass Density + 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; + // Initialise particle size + for (unsigned i = 0; i < Tdim; ++i) this->natural_size_(i) = psize(i); + + // Coordinates + Eigen::Vector3d coordinates; + coordinates << particle.coord_x, particle.coord_y, particle.coord_z; + // Initialise coordinates + for (unsigned i = 0; i < Tdim; ++i) this->coordinates_(i) = coordinates(i); + + // Displacement + Eigen::Vector3d displacement; + displacement << particle.displacement_x, particle.displacement_y, + particle.displacement_z; + // Initialise displacement + 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) this->velocity_(i) = velocity(i); + + // Stress + this->stress_[0] = particle.stress_xx; + this->stress_[1] = particle.stress_yy; + this->stress_[2] = particle.stress_zz; + this->stress_[3] = particle.tau_xy; + this->stress_[4] = particle.tau_yz; + this->stress_[5] = particle.tau_xz; + + // Strain + this->strain_[0] = particle.strain_xx; + this->strain_[1] = particle.strain_yy; + this->strain_[2] = particle.strain_zz; + this->strain_[3] = particle.gamma_xy; + this->strain_[4] = particle.gamma_yz; + this->strain_[5] = particle.gamma_xz; + + // Volumetric strain + this->volumetric_strain_centroid_ = particle.epsilon_v; + + // Status + this->status_ = particle.status; + + // Cell id + this->cell_id_ = particle.cell_id; + this->cell_ = nullptr; + + // Clear nodes + this->nodes_.clear(); + + // Material id + this->material_id_[mpm::ParticlePhase::Solid] = particle.material_id; + + return true; +} + +//! Initialise particle data from HDF5 +template +bool mpm::ParticleXMPM::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 = this->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!"); + } + } + return status; +} + +//! Return particle data in HDF5 format +template +// cppcheck-suppress * +mpm::HDF5Particle mpm::ParticleXMPM::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::ParticleXMPM::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.; + levelset_phi_ = 0.; + + // Initialize vector data properties + this->properties_["stresses"] = [&]() { return stress(); }; + this->properties_["strains"] = [&]() { return strain(); }; + this->properties_["velocities"] = [&]() { return velocity(); }; + this->properties_["displacements"] = [&]() { return displacement(); }; +} + +//! Initialise particle material container +template +void mpm::ParticleXMPM::initialise_material(unsigned phase_size) { + material_.resize(phase_size); + material_id_.resize(phase_size); + state_variables_.resize(phase_size); + std::fill(material_.begin(), material_.end(), nullptr); + std::fill(material_id_.begin(), material_id_.end(), + std::numeric_limits::max()); + std::fill(state_variables_.begin(), state_variables_.end(), mpm::dense_map()); +} + +//! Assign material history variables +template +bool mpm::ParticleXMPM::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(phase) != nullptr && + this->material_id(phase) == material->id()) { + // Clone 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; + status = true; + } + } + return status; +} + +// Assign a cell to particle +template +bool mpm::ParticleXMPM::assign_cell( + const std::shared_ptr>& cellptr) { + bool status = true; + try { + Eigen::Matrix xi; + // Assign cell to the new cell ptr, if point can be found in new cell + if (cellptr->is_point_in_cell(this->coordinates_, &xi)) { + // if a cell already exists remove particle from that cell + if (cell_ != nullptr) cell_->remove_particle_id(this->id_); + + cell_ = cellptr; + cell_id_ = cellptr->id(); + // dn_dx centroid + dn_dx_centroid_ = cell_->dn_dx_centroid(); + // Copy nodal pointer to cell + nodes_.clear(); + nodes_ = cell_->nodes(); + + // Compute reference location of particle + bool xi_status = this->compute_reference_location(); + if (!xi_status) return false; + status = cell_->add_particle_id(this->id()); + } else { + throw std::runtime_error("Point cannot be found in cell!"); + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +// Assign a cell to particle +template +bool mpm::ParticleXMPM::assign_cell_xi( + const std::shared_ptr>& cellptr, + const Eigen::Matrix& xi) { + bool status = true; + try { + // Assign cell to the new cell ptr, if point can be found in new cell + if (cellptr != nullptr) { + // if a cell already exists remove particle from that cell + if (cell_ != nullptr) cell_->remove_particle_id(this->id_); + + cell_ = cellptr; + cell_id_ = cellptr->id(); + // dn_dx centroid + dn_dx_centroid_ = cell_->dn_dx_centroid(); + // Copy nodal pointer to cell + nodes_.clear(); + nodes_ = cell_->nodes(); + + // Assign the reference location of particle + bool xi_nan = false; + + // Check if point is within the cell + for (unsigned i = 0; i < xi.size(); ++i) + if (xi(i) < -1. || xi(i) > 1. || std::isnan(xi(i))) xi_nan = true; + + if (xi_nan == false) + this->xi_ = xi; + else + return false; + + status = cell_->add_particle_id(this->id()); + } else { + throw std::runtime_error("Point cannot be found in cell!"); + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +// Assign a cell id to particle +template +bool mpm::ParticleXMPM::assign_cell_id(mpm::Index id) { + bool status = false; + try { + // if a cell ptr is null + if (cell_ == nullptr && id != std::numeric_limits::max()) { + cell_id_ = id; + status = true; + } else { + throw std::runtime_error("Invalid cell id or cell is already assigned!"); + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +// Remove cell for the particle +template +void mpm::ParticleXMPM::remove_cell() { + // if a cell is not nullptr + if (cell_ != nullptr) cell_->remove_particle_id(this->id_); + cell_id_ = std::numeric_limits::max(); + // Clear all the nodes + nodes_.clear(); +} + +// Assign a material to particle +template +bool mpm::ParticleXMPM::assign_material( + const std::shared_ptr>& material, unsigned phase) { + bool status = false; + try { + // Check if material is valid and properties are set + if (material != nullptr) { + material_.at(phase) = material; + material_id_.at(phase) = material_[phase]->id(); + state_variables_.at(phase) = + material_[phase]->initialise_state_variables(); + status = true; + } else { + throw std::runtime_error("Material is undefined!"); + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + } + return status; +} + +// Compute reference location cell to particle +template +bool mpm::ParticleXMPM::compute_reference_location() noexcept { + // Set status of compute reference location + bool status = false; + // Compute local coordinates + Eigen::Matrix xi; + // Check if the point is in cell + if (cell_ != nullptr && cell_->is_point_in_cell(this->coordinates_, &xi)) { + this->xi_ = xi; + status = true; + } + + return status; +} + +// Compute shape functions and gradients +template +void mpm::ParticleXMPM::compute_shapefn() noexcept { + // Check if particle has a valid cell ptr + assert(cell_ != nullptr); + // Get element ptr of a cell + const auto element = cell_->element_ptr(); + + // Zero matrix + Eigen::Matrix zero = Eigen::Matrix::Zero(); + + // Compute shape function of the particle + shapefn_ = element->shapefn(this->xi_, this->natural_size_, zero); + + // Compute dN/dx + dn_dx_ = element->dn_dx(this->xi_, cell_->nodal_coordinates(), + this->natural_size_, zero); +} + +// Assign volume to the particle +template +bool mpm::ParticleXMPM::assign_volume(double volume) { + bool status = true; + try { + if (volume <= 0.) + throw std::runtime_error("Particle volume cannot be negative"); + + this->volume_ = volume; + // Compute size of particle in each direction + const double length = + std::pow(this->volume_, static_cast(1. / Tdim)); + // Set particle size as length on each side + this->size_.fill(length); + + if (cell_ != nullptr) { + // Get element ptr of a cell + const auto element = cell_->element_ptr(); + + // Set local particle length based on length of element in natural + // coordinates. Length/(npartices^(1/Dimension)) + this->natural_size_.fill( + element->unit_element_length() / + std::pow(cell_->nparticles(), static_cast(1. / Tdim))); + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +// Compute volume of the particle +template +void mpm::ParticleXMPM::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::ParticleXMPM::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::ParticleXMPM::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::ParticleXMPM::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 +template +void mpm::ParticleXMPM::map_multimaterial_mass_momentum_to_nodes() noexcept { + // Check if particle mass is set + 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) = mass_ * shapefn_[i]; + nodes_[i]->update_property(true, "masses", nodal_mass, this->material_id(), + 1); + nodes_[i]->update_property(true, "momenta", velocity_ * nodal_mass, + this->material_id(), Tdim); + } +} + +//! Map multimaterial displacements to nodes +template +void mpm::ParticleXMPM::map_multimaterial_displacements_to_nodes() noexcept { + // Check if particle mass is set + 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 = mass_ * shapefn_[i] * displacement_; + nodes_[i]->update_property(true, "displacements", displacement, + this->material_id(), Tdim); + } +} + +//! Map multimaterial domain gradients to nodes +template +void mpm::ParticleXMPM< + Tdim>::map_multimaterial_domain_gradients_to_nodes() noexcept { + // Check if particle volume is set + 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] = volume_ * dn_dx_(i, j); + nodes_[i]->update_property(true, "domain_gradients", gradient, + this->material_id(), Tdim); + } +} + +// Compute strain rate of the particle +template <> +inline Eigen::Matrix mpm::ParticleXMPM<1>::compute_strain_rate( + const Eigen::MatrixXd& dn_dx, unsigned phase) noexcept { + // Define strain rate + Eigen::Matrix strain_rate = Eigen::Matrix::Zero(); + + for (unsigned i = 0; i < this->nodes_.size(); ++i) { + Eigen::Matrix vel = nodes_[i]->velocity(phase); + strain_rate[0] += dn_dx(i, 0) * vel[0]; + } + + if (std::fabs(strain_rate(0)) < 1.E-15) strain_rate[0] = 0.; + return strain_rate; +} + +// Compute strain rate of the particle +template <> +inline Eigen::Matrix mpm::ParticleXMPM<2>::compute_strain_rate( + const Eigen::MatrixXd& dn_dx, unsigned phase) noexcept { + // Define strain rate + Eigen::Matrix strain_rate = Eigen::Matrix::Zero(); + + for (unsigned i = 0; i < this->nodes_.size(); ++i) { + Eigen::Matrix vel = nodes_[i]->velocity(phase); + strain_rate[0] += dn_dx(i, 0) * vel[0]; + strain_rate[1] += dn_dx(i, 1) * vel[1]; + strain_rate[3] += dn_dx(i, 1) * vel[0] + dn_dx(i, 0) * vel[1]; + } + + if (std::fabs(strain_rate[0]) < 1.E-15) strain_rate[0] = 0.; + if (std::fabs(strain_rate[1]) < 1.E-15) strain_rate[1] = 0.; + if (std::fabs(strain_rate[3]) < 1.E-15) strain_rate[3] = 0.; + return strain_rate; +} + +// Compute strain rate of the particle +template <> +inline Eigen::Matrix mpm::ParticleXMPM<3>::compute_strain_rate( + const Eigen::MatrixXd& dn_dx, unsigned phase) noexcept { + // Define strain rate + Eigen::Matrix strain_rate = Eigen::Matrix::Zero(); + + for (unsigned i = 0; i < this->nodes_.size(); ++i) { + Eigen::Matrix vel = nodes_[i]->velocity(phase); + strain_rate[0] += dn_dx(i, 0) * vel[0]; + strain_rate[1] += dn_dx(i, 1) * vel[1]; + strain_rate[2] += dn_dx(i, 2) * vel[2]; + strain_rate[3] += dn_dx(i, 1) * vel[0] + dn_dx(i, 0) * vel[1]; + strain_rate[4] += dn_dx(i, 2) * vel[1] + dn_dx(i, 1) * vel[2]; + strain_rate[5] += dn_dx(i, 2) * vel[0] + dn_dx(i, 0) * vel[2]; + } + + for (unsigned i = 0; i < strain_rate.size(); ++i) + if (std::fabs(strain_rate[i]) < 1.E-15) strain_rate[i] = 0.; + return strain_rate; +} + +// Compute strain of the particle +template +void mpm::ParticleXMPM::compute_strain(double dt) noexcept { + // Assign strain rate + strain_rate_ = this->compute_strain_rate(dn_dx_, mpm::ParticlePhase::Solid); + // Update dstrain + dstrain_ = strain_rate_ * dt; + // Update strain + strain_ += dstrain_; + + // Compute at centroid + // Strain rate for reduced integration + const Eigen::Matrix strain_rate_centroid = + this->compute_strain_rate(dn_dx_centroid_, mpm::ParticlePhase::Solid); + + // Assign volumetric strain at centroid + dvolumetric_strain_ = dt * strain_rate_centroid.head(Tdim).sum(); + volumetric_strain_centroid_ += dvolumetric_strain_; +} + +// Compute stress +template +void mpm::ParticleXMPM::compute_stress() noexcept { + // Check if material ptr is valid + assert(this->material() != nullptr); + // Calculate stress + this->stress_ = + (this->material()) + ->compute_stress(stress_, dstrain_, this, + &state_variables_[mpm::ParticlePhase::Solid]); +} + +//! Map body force +template +void mpm::ParticleXMPM::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::ParticleXMPM<1>::map_internal_force() noexcept { + // Compute nodal internal forces + 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]; + + nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Solid, force); + } +} + +//! Map internal force +template <> +inline void mpm::ParticleXMPM<2>::map_internal_force() noexcept { + // 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) * 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_; + + nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Solid, force); + } +} + +//! Map internal force +template <> +inline void mpm::ParticleXMPM<3>::map_internal_force() noexcept { + // 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) * stress_[0] + dn_dx_(i, 1) * stress_[3] + + dn_dx_(i, 2) * stress_[5]; + + force[1] = dn_dx_(i, 1) * stress_[1] + dn_dx_(i, 0) * stress_[3] + + dn_dx_(i, 2) * stress_[4]; + + force[2] = dn_dx_(i, 2) * stress_[2] + dn_dx_(i, 1) * stress_[4] + + dn_dx_(i, 0) * stress_[5]; + + force *= -1. * this->volume_; + + nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Solid, force); + } +} + +// Assign velocity to the particle +template +bool mpm::ParticleXMPM::assign_velocity( + const Eigen::Matrix& velocity) { + // Assign velocity + velocity_ = velocity; + return true; +} + +// Assign traction to the particle +template +bool mpm::ParticleXMPM::assign_traction(unsigned direction, double traction) { + bool status = false; + try { + if (direction >= Tdim || + 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); + status = true; + this->set_traction_ = true; + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +//! Map traction force +template +void mpm::ParticleXMPM::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::ParticleXMPM::compute_updated_position( + double dt, bool velocity_update) noexcept { + // 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); + + // 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); + + // Update particle velocity from interpolated nodal acceleration + this->velocity_ += nodal_acceleration * dt; + } + // Update particle velocity using interpolated nodal velocity + else + this->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; +} + +//! Map particle pressure to nodes +template +bool mpm::ParticleXMPM::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::ParticleXMPM::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 +template +void mpm::ParticleXMPM::apply_particle_velocity_constraints(unsigned dir, + double velocity) { + // Set particle velocity constraint + this->velocity_(dir) = velocity; +} + +//! Return particle tensor data +template +Eigen::VectorXd mpm::ParticleXMPM::tensor_data(const std::string& property) { + return this->properties_.at(property)(); +} + +//! Assign material id of this particle to nodes +template +void mpm::ParticleXMPM::append_material_id_to_nodes() const { + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->append_material_id(this->material_id()); +} + +//! Assign neighbour particles +template +void mpm::ParticleXMPM::assign_neighbours( + const std::vector& neighbours) { + neighbours_ = neighbours; + neighbours_.erase(std::remove(neighbours_.begin(), neighbours_.end(), id_), + neighbours_.end()); +} diff --git a/include/solvers/xmpm_explicit.h b/include/solvers/xmpm_explicit.h new file mode 100644 index 000000000..196915d1c --- /dev/null +++ b/include/solvers/xmpm_explicit.h @@ -0,0 +1,84 @@ +#ifndef MPM_XMPM_EXPLICIT_H_ +#define MPM_XMPM_EXPLICIT_H_ + +#ifdef USE_GRAPH_PARTITIONING +#include "graph.h" +#endif + +#include "mpm_base.h" + +namespace mpm { + +//! XMPMExplicit class +//! \brief A class that implements the fully explicit one phase mpm +//! \details A single-phase explicit MPM +//! \tparam Tdim Dimension +template +class XMPMExplicit : public MPMBase { + public: + //! Default constructor + XMPMExplicit(const std::shared_ptr& io); + + //! Solve + bool solve() override; + + //! Compute stress strain + //! \param[in] phase Phase to smooth pressure + void compute_stress_strain(unsigned phase); + + 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_; + //! Number of steps + 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 + + //! 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}; + //! Interface + bool interface_{false}; + +}; // XMPMExplicit class +} // namespace mpm + +#include "xmpm_explicit.tcc" + +#endif // MPM_XMPM_EXPLICIT_H_ diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc new file mode 100644 index 000000000..f8ac93850 --- /dev/null +++ b/include/solvers/xmpm_explicit.tcc @@ -0,0 +1,333 @@ +//! Constructor +template +mpm::XMPMExplicit::XMPMExplicit(const std::shared_ptr& io) + : mpm::MPMBase(io) { + //! Logger + console_ = spdlog::get("XMPMExplicit"); +} + +//! MPM Explicit compute stress strain +template +void mpm::XMPMExplicit::compute_stress_strain(unsigned phase) { + // 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)); + + // Pressure smoothing + if (pressure_smoothing_) this->pressure_smoothing(phase); + + // Iterate over each particle to compute stress + mesh_->iterate_over_particles(std::bind( + &mpm::ParticleBase::compute_stress, std::placeholders::_1)); +} + +//! MPM Explicit solver +template +bool mpm::XMPMExplicit::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 + + // Phase + const unsigned phase = 0; + + // 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_.at("pressure_smoothing").template get(); + + // Interface + if (analysis_.find("interface") != analysis_.end()) + interface_ = analysis_.at("interface").template get(); + + // Initialise material + bool mat_status = this->initialise_materials(); + if (!mat_status) { + status = false; + throw std::runtime_error("Initialisation of materials failed"); + } + + // Initialise mesh + bool mesh_status = this->initialise_mesh(); + if (!mesh_status) { + status = false; + throw std::runtime_error("Initialisation of mesh failed"); + } + + // Initialise particles + bool particle_status = this->initialise_particles(); + if (!particle_status) { + status = false; + throw std::runtime_error("Initialisation of particles failed"); + } + + // Initialise loading conditions + bool loading_status = this->initialise_loads(); + if (!loading_status) { + status = false; + throw std::runtime_error("Initialisation of loading failed"); + } + + // Create nodal properties + if (interface_) mesh_->create_nodal_properties(); + + // Compute mass + 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 + + // Inject particles + mesh_->inject_particles(this->step_ * this->dt_); + +#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 + + // Initialise nodal properties and append material ids to node + if (interface_) { + // Initialise nodal properties + mesh_->initialise_nodal_properties(); + + // Append material ids to nodes + mesh_->iterate_over_particles( + std::bind(&mpm::ParticleBase::append_material_id_to_nodes, + 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)); + +#ifdef USE_MPI + // Run if there is more than a single MPI task + if (mpi_size > 1) { + // MPI all reduce nodal mass + mesh_->template nodal_halo_exchange( + std::bind(&mpm::NodeBase::mass, std::placeholders::_1, phase), + std::bind(&mpm::NodeBase::update_mass, std::placeholders::_1, + false, phase, std::placeholders::_2)); + // MPI all reduce nodal momentum + mesh_->template nodal_halo_exchange, Tdim>( + std::bind(&mpm::NodeBase::momentum, std::placeholders::_1, + phase), + std::bind(&mpm::NodeBase::update_momentum, + std::placeholders::_1, false, phase, + std::placeholders::_2)); + } +#endif + + // Compute nodal velocity + mesh_->iterate_over_nodes_predicate( + std::bind(&mpm::NodeBase::compute_velocity, + std::placeholders::_1), + std::bind(&mpm::NodeBase::status, std::placeholders::_1)); + + if (interface_) { + // Map multimaterial properties from particles to nodes + mesh_->iterate_over_particles(std::bind( + &mpm::ParticleBase::map_multimaterial_mass_momentum_to_nodes, + std::placeholders::_1)); + + // Map multimaterial displacements from particles to nodes + mesh_->iterate_over_particles(std::bind( + &mpm::ParticleBase::map_multimaterial_displacements_to_nodes, + std::placeholders::_1)); + + // Map multimaterial domain gradients from particles to nodes + mesh_->iterate_over_particles(std::bind( + &mpm::ParticleBase::map_multimaterial_domain_gradients_to_nodes, + std::placeholders::_1)); + + // Compute multimaterial change in momentum + mesh_->iterate_over_nodes(std::bind( + &mpm::NodeBase::compute_multimaterial_change_in_momentum, + std::placeholders::_1)); + + // Compute multimaterial separation vector + mesh_->iterate_over_nodes(std::bind( + &mpm::NodeBase::compute_multimaterial_separation_vector, + std::placeholders::_1)); + + // Compute multimaterial normal unit vector + mesh_->iterate_over_nodes(std::bind( + &mpm::NodeBase::compute_multimaterial_normal_unit_vector, + std::placeholders::_1)); + } + + // Update stress first + if (this->stress_update_ == mpm::StressUpdate::USF) + this->compute_stress_strain(phase); + + // 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( + 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, phase, (this->step_ * this->dt_))); + } + +#pragma omp section + { + // Spawn a task for internal force + // Iterate over each particle to compute nodal internal force + mesh_->iterate_over_particles( + std::bind(&mpm::ParticleBase::map_internal_force, + std::placeholders::_1)); + } + } // Wait for tasks to finish + +#ifdef USE_MPI + // Run if there is more than a single MPI task + if (mpi_size > 1) { + // MPI all reduce external force + mesh_->template nodal_halo_exchange, Tdim>( + std::bind(&mpm::NodeBase::external_force, std::placeholders::_1, + phase), + std::bind(&mpm::NodeBase::update_external_force, + std::placeholders::_1, false, phase, + std::placeholders::_2)); + // MPI all reduce internal force + mesh_->template nodal_halo_exchange, Tdim>( + std::bind(&mpm::NodeBase::internal_force, std::placeholders::_1, + phase), + std::bind(&mpm::NodeBase::update_internal_force, + std::placeholders::_1, false, phase, + 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_cundall, + std::placeholders::_1, phase, this->dt_, damping_factor_), + std::bind(&mpm::NodeBase::status, std::placeholders::_1)); + else + mesh_->iterate_over_nodes_predicate( + std::bind(&mpm::NodeBase::compute_acceleration_velocity, + std::placeholders::_1, phase, this->dt_), + std::bind(&mpm::NodeBase::status, std::placeholders::_1)); + + // Iterate over each particle to compute updated position + mesh_->iterate_over_particles( + std::bind(&mpm::ParticleBase::compute_updated_position, + std::placeholders::_1, this->dt_, this->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(phase); + + // Locate particles + auto unlocatable_particles = mesh_->locate_particles_mesh(); + + if (!unlocatable_particles.empty() && this->locate_particles_) + throw std::runtime_error("Particle outside the mesh domain"); + // If unable to locate particles remove particles + if (!unlocatable_particles.empty() && !this->locate_particles_) + for (const auto& remove_particle : unlocatable_particles) + mesh_->remove_particle(remove_particle); + +#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 {}, Explicit {} solver duration: {} ms", mpi_rank, + (this->stress_update_ == mpm::StressUpdate::USL ? "USL" : "USF"), + std::chrono::duration_cast(solver_end - + solver_begin) + .count()); + + return status; +} diff --git a/include/xmpm/discontinuity_3d.h b/include/xmpm/discontinuity_3d.h new file mode 100755 index 000000000..2ebb13e0c --- /dev/null +++ b/include/xmpm/discontinuity_3d.h @@ -0,0 +1,79 @@ +#ifndef MPM_DISCONTINUITY_3D_H_ +#define MPM_DISCONTINUITY_3D_H_ + +#include "discontinuity_base.h" + +//! MPM namespace +namespace mpm { + +template +class Discontinuity_3D : public DiscontinuityBase { + + public: + //! Define a vector of size dimension + using VectorDim = Eigen::Matrix; + //constructor + Discontinuity_3D(); + + //initialization + virtual bool initialize(const std::vector& coordinates,const std::vector>& pointsets) + { + bool status = true; + // Create points from file + bool point_status = this->create_points(coordinates); + if (!point_status) { + status = false; + throw std::runtime_error("Addition of points in discontinuity to mesh failed"); + } + // Create elements from file + bool element_status = create_elements(pointsets); + if (!element_status) { + status = false; + throw std::runtime_error("Addition of elements in discontinuity to mesh failed"); + } + + bool normal_status = initialize_center_normal(); + if (!normal_status) { + status = false; + throw std::runtime_error("initialized the center and normal of the discontunity failed"); + } + return status; + }; + + //! create elements from file + virtual bool create_elements(const std::vector>& elements) override; + + //initialize the center and normal of the triangular elements + bool initialize_center_normal(); + + // return the cross product of ab and bc + VectorDim ThreeCross(const VectorDim& a,const VectorDim& b,const VectorDim& c); + + + //return the levelset values of each doordinates + //! \param[in] the vector of the coordinates + virtual void compute_levelset(const std::vector& coordinates, std::vector& phi_list) override; + + + protected: + + using mpm::DiscontinuityBase::points_; + + using mpm::DiscontinuityBase::console_; + + using mpm::DiscontinuityBase::numpoint_; + + private: + + //vector of elements + std::vector elements_; + + //number of elements + mpm::Index numelement_; + +}; + +} // namespace mpm +#include "discontinuity_3d.tcc" + +#endif // MPM_HEXAHEDRON_ELEMENT_H_ diff --git a/include/xmpm/discontinuity_3d.tcc b/include/xmpm/discontinuity_3d.tcc new file mode 100755 index 000000000..62b7eb8f1 --- /dev/null +++ b/include/xmpm/discontinuity_3d.tcc @@ -0,0 +1,99 @@ +template +mpm::Discontinuity_3D::Discontinuity_3D() +{ + numelement_ = 0; + + std::string logger = + "discontinuity" + std::to_string(Tdim) + "d"; + console_ = std::make_unique(logger, mpm::stdout_sink); +} + +//! create elements from file +template +bool mpm::Discontinuity_3D::create_elements(const std::vector>& elements) + { + + bool status = true; + try { + // Check if elements is empty + if (elements.empty()) + throw std::runtime_error("List of elements is empty"); + // Iterate over all elements + for (const auto& points : elements) { + + mpm::discontinuous_element element(points); + + elements_.emplace_back(element); // + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; + } + + //initialize the center and normal of the elements + template + bool mpm::Discontinuity_3D::initialize_center_normal() + { + bool status = true; + try { + VectorDim center; + VectorDim normal; + Eigen::Matrix points; + + for(auto& element : elements_) + { + points = element.points(); + + //the center of the element + for(int i=0; i<3; i++) + center[i] = 1.0/3*(points_[points[0]].coordinates()[i] + points_[points[1]].coordinates()[i] +points_[points[2]].coordinates()[i]); + + element.set_center(center); + + //the normal of the element + normal = ThreeCross(points_[points[0]].coordinates(),points_[points[1]].coordinates(),points_[points[2]].coordinates()); + double det = std::sqrt(normal[0]*normal[0] + normal[1]*normal[1] + normal[2]*normal[2]); + normal = 1.0/det * normal; + + element.set_normal(normal); + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; + } + +//return the cross product of ab X bc +template +Eigen::Matrix mpm::Discontinuity_3D::ThreeCross(const VectorDim& a,const VectorDim& b,const VectorDim& c){ + + VectorDim threecross; + threecross[0]=(b[1]-a[1])*(c[2]-b[2])-(b[2]-a[2])*(c[1]-b[1]); + threecross[1]=(b[2]-a[2])*(c[0]-b[0])-(b[0]-a[0])*(c[2]-b[2]); + threecross[2]=(b[0]-a[0])*(c[1]-b[1])-(b[1]-a[1])*(c[0]-b[0]); + return threecross; +} + +//return the levelset values of each doordinates +//! \param[in] the vector of the coordinates +template +void mpm::Discontinuity_3D::compute_levelset(const std::vector& coordinates,std::vector& phi_list){ + + mpm::Index i = 0; + for(const auto& coor:coordinates) + { + //find the nearest distance from particle to cell: need to do by global searching and local searching + double distance = std::numeric_limits::max(); + for(const auto& element:elements_) + { + double Vertical_distance_ = element.Vertical_distance(coor);// Vertical_distance(coor); + distance = std::abs(distance) < std::abs(Vertical_distance_)? distance:Vertical_distance_; + } + + phi_list[i] = distance; + ++i; + } +} \ No newline at end of file diff --git a/include/xmpm/discontinuity_base.h b/include/xmpm/discontinuity_base.h new file mode 100755 index 000000000..8be308b64 --- /dev/null +++ b/include/xmpm/discontinuity_base.h @@ -0,0 +1,185 @@ +#ifndef MPM_DISCONTINUITY_H_ +#define MPM_DISCONTINUITY_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "vector.h" + +namespace mpm { + +template +struct discontinuous_point +{ + public: + //! Define a vector of size dimension + using VectorDim = Eigen::Matrix; + + discontinuous_point(const VectorDim& coordinate) + { + coordinates_ = coordinate; + } + + + //! Return coordinates + //! \retval coordinates_ return coordinates of the nodebase + VectorDim coordinates() const { return coordinates_; } + + private: + + //! point coordinates + VectorDim coordinates_; +}; + +//! class for to describe the discontinuous surface +//! \brief +//! \details nodes, lines and areas +//! \tparam Tdim Dimension +template +class DiscontinuityBase { + public: + //! Define a vector of size dimension + using VectorDim = Eigen::Matrix; + + // Constructor + DiscontinuityBase(); + + //! Destructor + virtual ~DiscontinuityBase(){}; + + //! Delete copy constructor + DiscontinuityBase(const DiscontinuityBase&) = delete; + + //! Delete assignement operator + DiscontinuityBase& operator=(const DiscontinuityBase&) = delete; + + //initialization + virtual bool initialize(const std::vector& coordinates,const std::vector>& pointsets) = 0; + + //! create points from file + bool create_points(const std::vector& coordinates); + + //! create elements from file + virtual bool create_elements(const std::vector>& elements) {return true;}; + + //return the levelset values of each doordinates + //! \param[in] the vector of the coordinates + virtual void compute_levelset(const std::vector& coordinates, std::vector& phi_list) = 0; + + bool self_contact(){return self_contact_;}; + + void set_frictional_coef(double coef) {frictional_coef_ = coef;}; + + double frictional_coef(){return frictional_coef_;}; + + + protected: + + std::vector> points_; + + //number of points + mpm::Index numpoint_; + + //! Logger + std::unique_ptr console_; + + //self-contact + bool self_contact_{true}; + + double frictional_coef_; + +}; // DiscontinuityBase class + +struct discontinuous_line +{ + public: + + //! Return points indices + Eigen::Matrix points() const {return points_;}; + + private: + + //! points index of the line + Eigen::Matrix points_; + +}; + +struct discontinuous_element +{ + public: + //! Define a vector of size dimension + using VectorDim = Eigen::Matrix; + + discontinuous_element(const std::vector& points) + { + for(int i=0; i<3; ++i) + points_[i] = points[i]; + } + //! Return points indices + Eigen::Matrix points() const { return points_;} + + inline void set_center(VectorDim & center) {center_ = center; } + + inline void set_normal(VectorDim & normal) {normal_ = normal; } + + double Vertical_distance (const VectorDim & coor) const {return (coor[0]-center_[0])*normal_[0]+(coor[1]-center_[1])*normal_[1]+(coor[2]-center_[2])*normal_[2];}; + + private: + //! points indices + Eigen::Matrix points_; + + //the center of the triangular elements + VectorDim center_; + + //the normal of the triangular elements + VectorDim normal_; + +}; + + +} // namespace mpm + +template +mpm::DiscontinuityBase::DiscontinuityBase() +{ + numpoint_ = 0; + + frictional_coef_ = -1; + + std::string logger = + "discontinuitybase"; + console_ = std::make_unique(logger, mpm::stdout_sink); +} + +//! create points from file +template +bool mpm::DiscontinuityBase::create_points(const std::vector& coordinates) + { + bool status = true; + try { + // Check if point coordinates is empty + if (coordinates.empty()) + throw std::runtime_error("List of coordinates is empty"); + // Iterate over all coordinates + for (const auto& point_coordinates : coordinates) { + + // Add point + mpm::discontinuous_point point(point_coordinates); + + points_.emplace_back(point); // + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; + + } + +#endif // MPM_DiscontinuityBase_H_ diff --git a/src/discontinuity.cc b/src/discontinuity.cc new file mode 100755 index 000000000..2c9d245bc --- /dev/null +++ b/src/discontinuity.cc @@ -0,0 +1,6 @@ +#include "discontinuity_base.h" +#include "factory.h" +#include "discontinuity_3d.h" + +// Triangle 3-noded element +static Register, mpm::Discontinuity_3D<3>> tri3d("tri3d"); diff --git a/src/io/logger.cc b/src/io/logger.cc index 82e2b262c..bae042405 100644 --- a/src/io/logger.cc +++ b/src/io/logger.cc @@ -35,3 +35,7 @@ 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 XMPM Explicit +const std::shared_ptr mpm::Logger::xmpm_explicit_logger = + spdlog::stdout_color_st("XMPMExplicit"); diff --git a/src/mpm.cc b/src/mpm.cc index 19b3f5dc9..7f8f13603 100644 --- a/src/mpm.cc +++ b/src/mpm.cc @@ -4,6 +4,7 @@ #include "io.h" #include "mpm.h" #include "mpm_explicit.h" +#include "xmpm_explicit.h" namespace mpm { // Stress update method @@ -20,3 +21,7 @@ static Register, const std::shared_ptr&> // 3D Explicit MPM static Register, const std::shared_ptr&> mpm_explicit_3d("MPMExplicit3D"); + +// 3D Explicit XMPM +static Register, const std::shared_ptr&> + xmpm_explicit_3d("XMPMExplicit3D"); diff --git a/src/particle.cc b/src/particle.cc index 7488c8023..e06cda447 100644 --- a/src/particle.cc +++ b/src/particle.cc @@ -1,6 +1,7 @@ #include "particle.h" #include "factory.h" #include "particle_base.h" +#include "particle_xmpm.h" // Particle2D (2 Dim) static Register, mpm::Particle<2>, mpm::Index, @@ -11,3 +12,8 @@ static Register, mpm::Particle<2>, mpm::Index, static Register, mpm::Particle<3>, mpm::Index, const Eigen::Matrix&> particle3d("P3D"); + +// Particle3D_XMPM (3 Dim) +static Register, mpm::ParticleXMPM<3>, mpm::Index, + const Eigen::Matrix&> + particle3dxmpm("P3DXMPM"); From 06f433183765c8aab83f57911476946b989ab50f Mon Sep 17 00:00:00 2001 From: yong liang Date: Sun, 2 Aug 2020 00:55:52 -0700 Subject: [PATCH 02/91] :construction: creat and initialise nodal properties for discontinuity --- include/mesh.h | 6 ++ include/mesh.tcc | 36 ++++++++ include/node.h | 9 ++ include/node.tcc | 10 +++ include/node_base.h | 7 ++ include/particles/particle_base.h | 3 + include/particles/particle_xmpm.h | 3 +- include/particles/particle_xmpm.tcc | 1 + include/solvers/mpm_base.tcc | 2 +- include/solvers/xmpm_explicit.h | 11 +++ include/solvers/xmpm_explicit.tcc | 127 ++++++++++++++++++++++++++-- 11 files changed, 207 insertions(+), 8 deletions(-) diff --git a/include/mesh.h b/include/mesh.h index 2de4f49e9..654479f32 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -447,6 +447,12 @@ class Mesh { // Initialise the nodal properties' map void initialise_nodal_properties(); + //! Set particles lsm values + void assign_particle_levelset(std::vector& phi_list); + + // Create the nodal properties' map for discontinuity + void create_nodal_properties_discontinuity(); + 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 c603a2fea..e4d4a1c66 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1885,9 +1885,45 @@ void mpm::Mesh::create_nodal_properties() { } } +// Create the nodal properties' map for discontinuity +template +void mpm::Mesh::create_nodal_properties_discontinuity() { + // Initialise the shared pointer to nodal properties + if(nodal_properties_ == nullptr) + nodal_properties_ = std::make_shared(); + + // Check if nodes_ is empty and throw runtime error if they are + if (nodes_.size() != 0) { + // Compute number of rows in nodal properties for vector entities + const unsigned nrows = nodes_.size() * Tdim; + // Create pool data for each property in the nodal properties struct + // object. Properties must be named in the plural form + nodal_properties_->create_property("mass_enrich", nodes_.size(),1); + nodal_properties_->create_property("momenta_enrich", nrows, 1); + nodal_properties_->create_property("internal_force_enrich", nrows, 1); + nodal_properties_->create_property("external_force_enrich", nrows, 1); + nodal_properties_->create_property("normal_unit_vectors_discontinuity", nrows,1); + + // Iterate over all nodes to initialise the property handle in each node + // and assign its node id as the prop id in the nodal property data pool + for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) + (*nitr)->initialise_discontinuity_property_handle((*nitr)->id(), nodal_properties_); + } else { + throw std::runtime_error("Number of nodes is zero"); + } +} + // 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(); } + +//! Set particles lsm values +template +void mpm::Mesh::assign_particle_levelset(std::vector& phi_list) +{ + for(mpm::Index i = 0; iassign_levelsetphi(phi_list[i]); +} \ No newline at end of file diff --git a/include/node.h b/include/node.h index 31a6b9a03..2c4d7200e 100644 --- a/include/node.h +++ b/include/node.h @@ -47,6 +47,13 @@ class Node : public NodeBase { unsigned prop_id, std::shared_ptr property_handle) noexcept override; + //! Initialise shared pointer to nodal properties pool for discontinuity + //! \param[in] prop_id Property id in the nodal property pool + //! \param[in] nodal_properties Shared pointer to nodal properties pool + void initialise_discontinuity_property_handle( + unsigned prop_id, + std::shared_ptr property_handle) noexcept override; + //! Assign coordinates //! \param[in] coord Assign coord as coordinates of the nodebase void assign_coordinates(const VectorDim& coord) override { @@ -271,6 +278,8 @@ class Node : public NodeBase { Index id_{std::numeric_limits::max()}; //! nodal property id unsigned prop_id_{std::numeric_limits::max()}; + //! nodal property id + unsigned discontinuity_prop_id_{std::numeric_limits::max()}; //! shared ghost id Index ghost_id_{std::numeric_limits::max()}; //! nodal coordinates diff --git a/include/node.tcc b/include/node.tcc index 7d3a9cfcb..0594ed1d1 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -46,6 +46,16 @@ void mpm::Node::initialise_property_handle( this->prop_id_ = prop_id; } +//! Initialise shared pointer to nodal properties pool for discontinuity +template +void mpm::Node::initialise_discontinuity_property_handle( + unsigned prop_id, + std::shared_ptr property_handle) noexcept { + // the property handle and the property id is set in the node + this->property_handle_ = property_handle; + this->discontinuity_prop_id_ = prop_id; +} + //! 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..357feddb0 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -51,6 +51,13 @@ class NodeBase { unsigned prop_id, std::shared_ptr property_handle) noexcept = 0; + //! Initialise shared pointer to nodal properties pool for discontinuity + //! \param[in] prop_id Property id in the nodal property pool + //! \param[in] nodal_properties Shared pointer to nodal properties pool + virtual void initialise_discontinuity_property_handle( + unsigned prop_id, + std::shared_ptr property_handle) noexcept = 0; + //! Assign coordinates virtual void assign_coordinates(const VectorDim& coord) = 0; diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index da0d22a99..6ad4d55f9 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -282,6 +282,9 @@ class ParticleBase { //! Return neighbour ids virtual std::vector neighbours() const = 0; + //! set the level set function values + virtual void assign_levelsetphi(const double phivalue) {}; + protected: //! particleBase id Index id_{std::numeric_limits::max()}; diff --git a/include/particles/particle_xmpm.h b/include/particles/particle_xmpm.h index 3b2897d21..a931bf2d5 100644 --- a/include/particles/particle_xmpm.h +++ b/include/particles/particle_xmpm.h @@ -305,7 +305,8 @@ class ParticleXMPM : public ParticleBase { //! \retval strain rate at particle inside a cell inline Eigen::Matrix compute_strain_rate( const Eigen::MatrixXd& dn_dx, unsigned phase) noexcept; - + //! set the level set function values +virtual void assign_levelsetphi(const double phivalue) { levelset_phi_ = phivalue; }; private: //! particle id using ParticleBase::id_; diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index 8220bac9c..607ba6539 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -249,6 +249,7 @@ void mpm::ParticleXMPM::initialise() { this->properties_["strains"] = [&]() { return strain(); }; this->properties_["velocities"] = [&]() { return velocity(); }; this->properties_["displacements"] = [&]() { return displacement(); }; + this->properties_["levelset"] = [&]() { Eigen::Matrix levelset; levelset[0] = levelset_phi_ ; return levelset; }; } //! Initialise particle material container diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index 8426ccf4f..0c6d8bb49 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -506,7 +506,7 @@ 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","levelset"}; // Write VTK attributes for (const auto& attribute : vtk_vector_data) { diff --git a/include/solvers/xmpm_explicit.h b/include/solvers/xmpm_explicit.h index 196915d1c..edf588aad 100644 --- a/include/solvers/xmpm_explicit.h +++ b/include/solvers/xmpm_explicit.h @@ -6,6 +6,7 @@ #endif #include "mpm_base.h" +#include "discontinuity_base.h" namespace mpm { @@ -26,6 +27,12 @@ class XMPMExplicit : public MPMBase { //! \param[in] phase Phase to smooth pressure void compute_stress_strain(unsigned phase); + //! Initialise discontinuities + bool initialise_discontinuities(); + //! Initialise the level set function values + bool initialise_levelset(); + //return the number of discontinuities + mpm::Index ndiscontinuities(){return discontinuities_.size();}; protected: // Generate a unique id for the analysis using mpm::MPMBase::uuid_; @@ -75,6 +82,10 @@ class XMPMExplicit : public MPMBase { bool pressure_smoothing_{false}; //! Interface bool interface_{false}; + //! discontinuities statue + bool discontinuity_{false}; + //! discontinuities + std::map>> discontinuities_; }; // XMPMExplicit class } // namespace mpm diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index f8ac93850..0f45967b6 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -77,9 +77,7 @@ bool mpm::XMPMExplicit::solve() { // Initialise particles bool particle_status = this->initialise_particles(); if (!particle_status) { - status = false; - throw std::runtime_error("Initialisation of particles failed"); - } + status = false;initialise_property_handle // Initialise loading conditions bool loading_status = this->initialise_loads(); @@ -91,6 +89,24 @@ bool mpm::XMPMExplicit::solve() { // Create nodal properties if (interface_) mesh_->create_nodal_properties(); + // Initialise discontinuity + bool discontinuity_status = this->initialise_discontinuities(); + if (!discontinuity_status) { + status = false; + throw std::runtime_error("Initialisation of discontinuities failed"); + } + + //Initialise the levelset values for particles + if (discontinuity_){ + bool initialise_lsm_status = this->initialise_levelset(); + if (!initialise_lsm_status) { + status = false; + throw std::runtime_error("Initialisation of level set values failed"); + } + } + + // Create nodal properties for discontinuity + if (discontinuity_) mesh_->create_nodal_properties_discontinuity(); // Compute mass mesh_->iterate_over_particles( std::bind(&mpm::ParticleBase::compute_mass, std::placeholders::_1)); @@ -140,17 +156,24 @@ bool mpm::XMPMExplicit::solve() { } } // Wait to complete - // Initialise nodal properties and append material ids to node - if (interface_) { + // Initialise nodal properties + if (interface_ || discontinuity_) // Initialise nodal properties mesh_->initialise_nodal_properties(); - + //append material ids to node + if (interface_) { // Append material ids to nodes mesh_->iterate_over_particles( std::bind(&mpm::ParticleBase::append_material_id_to_nodes, std::placeholders::_1)); } + // Initialise nodal properties and append material ids to node + if (discontinuity_) { + + + + } // Assign mass and momentum to nodes mesh_->iterate_over_particles( std::bind(&mpm::ParticleBase::map_mass_momentum_to_nodes, @@ -331,3 +354,95 @@ bool mpm::XMPMExplicit::solve() { return status; } + +// Initialise discontinuities +template +bool mpm::XMPMExplicit::initialise_discontinuities() { + bool status = true; + try { + // Get discontinuities data + try { + auto json_discontinuities = io_->json_object("discontinuity"); + if(!json_discontinuities.empty()) + { + discontinuity_ = true; + for (const auto discontinuity_props : json_discontinuities) { + // Get discontinuity type + const std::string discontunity_type = + discontinuity_props["type"].template get(); + + // Get discontinuity id + auto discontinuity_id = discontinuity_props["id"].template get(); + + // Get discontinuity input type + auto io_type = discontinuity_props["io_type"].template get(); + + // discontinuity file + std::string discontinuity_file = + io_->file_name(discontinuity_props["file"].template get()); + + auto discontinuity_frictional_coef = discontinuity_props["frictional_coefficient"].template get(); + + // Create a mesh reader + auto discontunity_io = Factory>::instance()->create(io_type); + + // Create a new discontinuity surface from JSON object + auto discontinuity = + Factory>::instance() + ->create(discontunity_type); + + bool status = + discontinuity->initialize(discontunity_io->read_mesh_nodes(discontinuity_file),discontunity_io->read_mesh_cells(discontinuity_file)); + + discontinuity->set_frictional_coef(discontinuity_frictional_coef); + // Create points from file + + // Add discontinuity to list + auto result = discontinuities_.insert(std::make_pair(discontinuity_id, discontinuity)); + + // If insert discontinuity failed + if (!result.second) { + status = false; + throw std::runtime_error( + "New discontinuity cannot be added, insertion failed"); + } + } + } + }catch (std::exception& exception) { + console_->warn("{} #{}: No discontinuity is defined", __FILE__, + __LINE__, exception.what()); + } + }catch (std::exception& exception) { + console_->error("#{}: Reading discontinuities: {}", __LINE__, exception.what()); + status = false; + } + return status; +} + +// Initialise particles +template +bool mpm::XMPMExplicit::initialise_levelset() { + + bool status = true; + + try { + + for(mpm::Index i=0; i phi_list(mesh_->nparticles()); + + discontinuities_[i]->compute_levelset(mesh_->particle_coordinates(), phi_list); + + mesh_->assign_particle_levelset(phi_list); + } + + } catch (std::exception& exception) { + console_->error("#{}: XMPM initialise particles levelset values: {}", __LINE__, + exception.what()); + status = false; + } + + if (!status) throw std::runtime_error("Initialisation of particles LSM values failed"); + + return status; +} \ No newline at end of file From 28c684f750c486508dce6d78a327743050b42d83 Mon Sep 17 00:00:00 2001 From: yong liang Date: Sun, 2 Aug 2020 10:26:42 -0700 Subject: [PATCH 03/91] :construction:update nodal properties function and update nodal enrichen mass, momentum --- include/node.h | 14 ++++++++++++++ include/node.tcc | 13 +++++++++++++ include/node_base.h | 12 ++++++++++++ include/particles/particle_xmpm.tcc | 10 ++++++++++ include/solvers/xmpm_explicit.tcc | 20 ++++++++------------ 5 files changed, 57 insertions(+), 12 deletions(-) diff --git a/include/node.h b/include/node.h index 2c4d7200e..89b3d4a43 100644 --- a/include/node.h +++ b/include/node.h @@ -271,6 +271,18 @@ class Node : public NodeBase { //! Compute multimaterial normal unit vector void compute_multimaterial_normal_unit_vector() override; + //! Return whether the node is enriched + bool discontinuity_enrich() {return discontinuity_enrich_;}; + + //! Update nodal property at the nodes from particle for discontinuity + //! \param[in] update A boolean to update (true) or assign (false) + //! \param[in] property Property name + //! \param[in] property_value Property quantity from the particles in the cell + //! \param[in] discontinuity_id Id of the material within the property data + //! \param[in] nprops Dimension of property (1 if scalar, Tdim if vector) + void update_discontinuity_property(bool update, const std::string& property, + const Eigen::MatrixXd& property_value, unsigned discontinuity_id, + unsigned nprops) noexcept override; private: //! Mutex SpinMutex node_mutex_; @@ -328,6 +340,8 @@ class Node : public NodeBase { std::unique_ptr console_; //! MPI ranks std::set mpi_ranks_; + //! discontinuity enrich + bool discontinuity_enrich_{true}; }; // Node class } // namespace mpm diff --git a/include/node.tcc b/include/node.tcc index 0594ed1d1..70b7a8375 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -560,6 +560,19 @@ void mpm::Node::update_property( node_mutex_.unlock(); } +//! Update nodal property at the nodes from particle for discontinuity +template +void mpm::Node::update_discontinuity_property( + bool update, const std::string& property, + const Eigen::MatrixXd& property_value, unsigned discontinuity_id, + unsigned nprops) noexcept { + // Update/assign property + node_mutex_.lock(); + property_handle_->update_property(property, discontinuity_prop_id_, discontinuity_id, property_value, + nprops); + node_mutex_.unlock(); +} + //! Compute multimaterial change in momentum template void mpm::Node::map_mass_momentum_to_nodes() noexcept { mass_ * shapefn_[i]); nodes_[i]->update_momentum(true, mpm::ParticlePhase::Solid, mass_ * shapefn_[i] * velocity_); + if(nodes_[i]->discontinuity_enrich()){ + // Unit 1x1 Eigen matrix to be used with scalar quantities + Eigen::Matrix nodal_mass; + nodal_mass(0, 0) = levelset_phi_ * mass_ * shapefn_[i]; + // Map enriched mass and momentum to nodes + nodes_[i]->update_discontinuity_property(true, "mass_enrich", nodal_mass, 0, + 1); + nodes_[i]->update_discontinuity_property(true, "momenta_enrich", velocity_ * nodal_mass, + 0, Tdim); + } } } diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index 0f45967b6..2a2b20f8a 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -77,8 +77,10 @@ bool mpm::XMPMExplicit::solve() { // Initialise particles bool particle_status = this->initialise_particles(); if (!particle_status) { - status = false;initialise_property_handle - + status = false; + throw std::runtime_error("Initialisation of particles failed"); + } + // Initialise loading conditions bool loading_status = this->initialise_loads(); if (!loading_status) { @@ -168,12 +170,6 @@ bool mpm::XMPMExplicit::solve() { std::placeholders::_1)); } - // Initialise nodal properties and append material ids to node - if (discontinuity_) { - - - - } // Assign mass and momentum to nodes mesh_->iterate_over_particles( std::bind(&mpm::ParticleBase::map_mass_momentum_to_nodes, @@ -198,10 +194,10 @@ bool mpm::XMPMExplicit::solve() { #endif // Compute nodal velocity - mesh_->iterate_over_nodes_predicate( - std::bind(&mpm::NodeBase::compute_velocity, - std::placeholders::_1), - std::bind(&mpm::NodeBase::status, std::placeholders::_1)); + // mesh_->iterate_over_nodes_predicate( + // std::bind(&mpm::NodeBase::compute_velocity, + // std::placeholders::_1), + // std::bind(&mpm::NodeBase::status, std::placeholders::_1)); if (interface_) { // Map multimaterial properties from particles to nodes From 8ba5a31330e1f087dc7dc2f5ccc667f2c9203dc5 Mon Sep 17 00:00:00 2001 From: yong liang Date: Sun, 2 Aug 2020 13:03:35 -0700 Subject: [PATCH 04/91] :construction:update:external force,internal force, compute strain rate --- include/node.h | 6 ++++++ include/node.tcc | 11 +++++++++++ include/node_base.h | 5 +++++ include/particles/particle_xmpm.h | 5 ++++- include/particles/particle_xmpm.tcc | 28 ++++++++++++++++++++++++---- 5 files changed, 50 insertions(+), 5 deletions(-) diff --git a/include/node.h b/include/node.h index 89b3d4a43..b98c15307 100644 --- a/include/node.h +++ b/include/node.h @@ -283,6 +283,12 @@ class Node : public NodeBase { void update_discontinuity_property(bool update, const std::string& property, const Eigen::MatrixXd& property_value, unsigned discontinuity_id, unsigned nprops) noexcept override; + + // Return data in the nodal discontinuity properties map at a specific index + // \param[in] property Property name + // \param[in] nprops Dimension of property (1 if scalar, Tdim if vector) + Eigen::MatrixXd discontinuity_property(const std::string& property, unsigned nprops = 1) override; + private: //! Mutex SpinMutex node_mutex_; diff --git a/include/node.tcc b/include/node.tcc index 70b7a8375..ff239bb76 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -654,3 +654,14 @@ void mpm::Node +Eigen::MatrixXd mpm::Node::discontinuity_property(const std::string& property, + unsigned nprops) { + // Const pointer to location of property: node_id * nprops x mat_id + auto property_value = property_handle_->property(property, discontinuity_prop_id_, 0, nprops);; + //mpm::MapProperty property_handle(position, nprops); + return property_value; +} diff --git a/include/node_base.h b/include/node_base.h index 62b3313ac..3cef3438d 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -260,6 +260,11 @@ class NodeBase { //! Compute multimaterial normal unit vector virtual void compute_multimaterial_normal_unit_vector() = 0; + // Return data in the nodal discontinuity properties map at a specific index + // \param[in] property Property name + // \param[in] nprops Dimension of property (1 if scalar, Tdim if vector) + virtual Eigen::MatrixXd discontinuity_property(const std::string& property,unsigned nprops = 1) = 0; + //! Return whether the node is enriched virtual bool discontinuity_enrich() = 0; diff --git a/include/particles/particle_xmpm.h b/include/particles/particle_xmpm.h index a931bf2d5..340d3e59e 100644 --- a/include/particles/particle_xmpm.h +++ b/include/particles/particle_xmpm.h @@ -306,7 +306,10 @@ class ParticleXMPM : public ParticleBase { inline Eigen::Matrix compute_strain_rate( const Eigen::MatrixXd& dn_dx, unsigned phase) noexcept; //! set the level set function values -virtual void assign_levelsetphi(const double phivalue) { levelset_phi_ = phivalue; }; + virtual void assign_levelsetphi(const double phivalue) { levelset_phi_ = phivalue; }; + + //! return 1 if x > 0, -1 if x < 0 and 0 if x = 0 + inline double sgn(double x) noexcept {return (x > 0) ? 1. : ((x < 0) ? -1. : 0);}; private: //! particle id using ParticleBase::id_; diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index ce9598c2e..2534b5e47 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -525,7 +525,7 @@ void mpm::ParticleXMPM::map_mass_momentum_to_nodes() noexcept { if(nodes_[i]->discontinuity_enrich()){ // Unit 1x1 Eigen matrix to be used with scalar quantities Eigen::Matrix nodal_mass; - nodal_mass(0, 0) = levelset_phi_ * mass_ * shapefn_[i]; + nodal_mass(0, 0) = sgn(levelset_phi_) * mass_ * shapefn_[i]; // Map enriched mass and momentum to nodes nodes_[i]->update_discontinuity_property(true, "mass_enrich", nodal_mass, 0, 1); @@ -628,9 +628,24 @@ inline Eigen::Matrix mpm::ParticleXMPM<3>::compute_strain_rate( const Eigen::MatrixXd& dn_dx, unsigned phase) noexcept { // Define strain rate Eigen::Matrix strain_rate = Eigen::Matrix::Zero(); + const double tolerance = 1.E-16; + Eigen::Vector3d vel; + for (unsigned i = 0; i < this->nodes_.size(); ++i){ + vel.setZero(); + if(nodes_[i]->discontinuity_enrich()){ + double nodal_mass = nodes_[i]->mass(phase) + sgn(levelset_phi_)*nodes_[i]->discontinuity_property("mass_enrich",1)(0,0) ; + if(nodal_mass < tolerance) + continue; + + vel = (nodes_[i]->momentum(phase) + sgn(levelset_phi_)*nodes_[i]->discontinuity_property("momenta_enrich",3).col(0))/nodal_mass; + } + else{ + double nodal_mass = nodes_[i]->mass(phase); + if(nodal_mass < tolerance) + continue; + vel = nodes_[i]->momentum(phase)/nodal_mass; + } - for (unsigned i = 0; i < this->nodes_.size(); ++i) { - Eigen::Matrix vel = nodes_[i]->velocity(phase); strain_rate[0] += dn_dx(i, 0) * vel[0]; strain_rate[1] += dn_dx(i, 1) * vel[1]; strain_rate[2] += dn_dx(i, 2) * vel[2]; @@ -680,9 +695,12 @@ void mpm::ParticleXMPM::compute_stress() noexcept { template void mpm::ParticleXMPM::map_body_force(const VectorDim& pgravity) noexcept { // Compute nodal body forces - for (unsigned i = 0; i < nodes_.size(); ++i) + for (unsigned i = 0; i < nodes_.size(); ++i){ nodes_[i]->update_external_force(true, mpm::ParticlePhase::Solid, (pgravity * mass_ * shapefn_(i))); + if(nodes_[i]->discontinuity_enrich()) + nodes_[i]->update_discontinuity_property(true, "external_force_enrich", sgn(levelset_phi_)*pgravity * mass_ * shapefn_(i), 0,Tdim); + } } //! Map internal force @@ -733,6 +751,8 @@ inline void mpm::ParticleXMPM<3>::map_internal_force() noexcept { force *= -1. * this->volume_; nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Solid, force); + if(nodes_[i]->discontinuity_enrich()) + nodes_[i]->update_discontinuity_property(true, "internal_force_enrich", sgn(levelset_phi_)*force, 0,Tdim); } } From e5a61ed2d42771bc02be66f9386534478dc37bb5 Mon Sep 17 00:00:00 2001 From: yong liang Date: Sun, 2 Aug 2020 15:27:22 -0700 Subject: [PATCH 05/91] :construction:apply velocity constraints discontinuity --- include/node.h | 9 ++ include/node.tcc | 127 ++++++++++++++++++++++++++++ include/node_base.h | 9 ++ include/particles/particle_xmpm.tcc | 6 +- include/solvers/xmpm_explicit.tcc | 17 ++-- 5 files changed, 155 insertions(+), 13 deletions(-) diff --git a/include/node.h b/include/node.h index b98c15307..daaaa8106 100644 --- a/include/node.h +++ b/include/node.h @@ -208,6 +208,9 @@ class Node : public NodeBase { //! Apply velocity constraints void apply_velocity_constraints() override; + //! Apply velocity constraints for discontinuity + void apply_velocity_constraints_discontinuity() override; + //! Assign friction constraint //! Directions can take values between 0 and Dim * Nphases //! \param[in] dir Direction of friction constraint @@ -288,6 +291,12 @@ class Node : public NodeBase { // \param[in] property Property name // \param[in] nprops Dimension of property (1 if scalar, Tdim if vector) Eigen::MatrixXd discontinuity_property(const std::string& property, unsigned nprops = 1) override; + + //! Compute momentum + //! \param[in] phase Index corresponding to the phase + //! \param[in] dt Timestep in analysis + virtual bool intergrate_momentum_discontinuity( + unsigned phase, double dt) noexcept override; private: //! Mutex diff --git a/include/node.tcc b/include/node.tcc index ff239bb76..68281c006 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -665,3 +665,130 @@ Eigen::MatrixXd mpm::Node +bool mpm::Node::intergrate_momentum_discontinuity( + unsigned phase, double dt) noexcept { + momentum_.col(phase) = momentum_.col(phase) + + (internal_force_.col(phase) + external_force_.col(phase)) * dt; + if(discontinuity_enrich_){ + property_handle_->update_property("momenta_enrich", discontinuity_prop_id_, 0, + (property_handle_->property("internal_force_enrich",discontinuity_prop_id_,0,Tdim) + + property_handle_->property("external_force_enrich",discontinuity_prop_id_,0,Tdim) ) * dt, Tdim); + } + // Apply velocity constraints, which also sets acceleration to 0, + // when velocity is set. + this->apply_velocity_constraints(); + + //this->self_contact_discontinuity(dt); + + this->apply_velocity_constraints(); + + + return true; +} + //! Apply velocity constraints +template +void mpm::Node::apply_velocity_constraints_discontinuity() { + // Set velocity constraint + for (const auto& constraint : this->velocity_constraints_) { + // Direction value in the constraint (0, Dim * Nphases) + const unsigned dir = constraint.first; + // Direction: dir % Tdim (modulus) + const auto direction = static_cast(dir % Tdim); + // Phase: Integer value of division (dir / Tdim) + const auto phase = static_cast(dir / Tdim); + + if (!generic_boundary_constraints_) { + // Velocity constraints are applied on Cartesian boundaries + //this->velocity_(direction, phase) = constraint.second; + //need to do for one direction + + this->momentum_(direction, phase) = this->mass(phase) * constraint.second; + property_handle_->assign_property("momenta_enrich",discontinuity_prop_id_,0, + property_handle_->property("mass_enrich",discontinuity_prop_id_,0,1) * constraint.second,Tdim); + // Set acceleration to 0 in direction of velocity constraint + //this->acceleration_(direction, phase) = 0.; + this->internal_force_(direction, phase) = 0; + this->external_force_(direction, phase) = 0; + + Eigen::Matrix momentum; + momentum.setZero(); + property_handle_->assign_property("internal_force_enrich",discontinuity_prop_id_,0, + momentum,Tdim); + property_handle_->assign_property("external_force_enrich",discontinuity_prop_id_,0, + momentum,Tdim); + } else { //need to do + // Velocity constraints on general boundaries + // Compute inverse rotation matrix + const Eigen::Matrix inverse_rotation_matrix = + rotation_matrix_.inverse(); + // Transform to local coordinate + Eigen::Matrix local_velocity = + inverse_rotation_matrix * this->velocity_; + Eigen::Matrix local_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 + this->velocity_ = rotation_matrix_ * local_velocity; + this->acceleration_ = rotation_matrix_ * local_acceleration; + } + } +} +// //! Apply velocity constraints +// template +// void mpm::NodeXMPM::self_contact_discontinuity(double dt) { + +// if(!enrich_h_) +// return; + +// unsigned phase = 0; +// const double tolerance = 1.0E-15; + +// auto mass_positive = mass_.col(phase) + mass_h_.col(phase); +// auto mass_negative = mass_.col(phase) - mass_h_.col(phase); + +// if(mass_positive(phase) < tolerance || mass_negative(phase) < tolerance) +// return; + +// auto velocity_positive = (momentum_.col(phase) + momentum_h_.col(phase)) / mass_positive(phase); +// auto velocity_negative = (momentum_.col(phase) - momentum_h_.col(phase)) / mass_negative(phase); + +// if((velocity_positive - velocity_negative).col(phase).dot(direction_discontinuity_.col(phase)) >= 0) +// return; + +// auto momentum_contact = (mass_h_(phase)*momentum_.col(phase) - mass_(phase)*momentum_h_.col(phase)) / mass_(phase); +// auto force_contact = momentum_contact/dt; + +// //! frictional_coef < 0: move together without slide +// if(frictional_coef < 0) +// { +// momentum_h_.col(phase) = momentum_h_.col(phase) + momentum_contact.col(phase); +// internal_force_h_.col(phase) = internal_force_h_.col(phase) + force_contact.col(phase); +// } +// else +// { +// double momentum_contact_norm = momentum_contact.col(phase).dot(direction_discontinuity_.col(phase)); +// double force_contact_norm = momentum_contact_norm/dt; + +// double max_frictional_force = frictional_coef * abs(force_contact_norm); + +// auto momentum_tangential = momentum_contact.col(phase) - momentum_contact_norm*direction_discontinuity_.col(phase); +// auto force_tangential = momentum_tangential/dt; + +// double force_tangential_value = force_tangential.norm(); + +// double frictional_force = force_tangential_value < max_frictional_force? force_tangential_value : max_frictional_force; + +// //!adjust the momentum and force +// momentum_h_.col(phase) = momentum_h_.col(phase) + momentum_contact_norm*direction_discontinuity_.col(phase); +// internal_force_h_.col(phase) = internal_force_h_.col(phase) + force_contact_norm*direction_discontinuity_.col(phase); + +// momentum_h_.col(phase) = momentum_h_.col(phase) + frictional_force*force_tangential.col(phase).normalized()*dt; +// internal_force_h_.col(phase) = internal_force_h_.col(phase) + frictional_force*force_tangential.col(phase).normalized(); + +// } +// } \ No newline at end of file diff --git a/include/node_base.h b/include/node_base.h index 3cef3438d..0a9f82b34 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -200,6 +200,9 @@ class NodeBase { //! Apply velocity constraints virtual void apply_velocity_constraints() = 0; + //! Apply velocity constraints for discontinuity + virtual void apply_velocity_constraints_discontinuity() = 0; + //! Assign friction constraint //! Directions can take values between 0 and Dim * Nphases //! \param[in] dir Direction of friction constraint @@ -277,6 +280,12 @@ class NodeBase { virtual void update_discontinuity_property(bool update, const std::string& property, const Eigen::MatrixXd& property_value, unsigned discontinuity_id, unsigned nprops) noexcept = 0; + + //! Compute momentum + //! \param[in] phase Index corresponding to the phase + //! \param[in] dt Timestep in analysis + virtual bool intergrate_momentum_discontinuity( + unsigned phase, double dt) noexcept = 0; }; // NodeBase class } // namespace mpm diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index 2534b5e47..97efab4e6 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -713,6 +713,8 @@ inline void mpm::ParticleXMPM<1>::map_internal_force() noexcept { force[0] = -1. * dn_dx_(i, 0) * volume_ * stress_[0]; nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Solid, force); + if(nodes_[i]->discontinuity_enrich()) + nodes_[i]->update_discontinuity_property(true, "internal_force_enrich", sgn(levelset_phi_)*force, 0,1); } } @@ -729,6 +731,8 @@ inline void mpm::ParticleXMPM<2>::map_internal_force() noexcept { force *= -1. * this->volume_; nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Solid, force); + if(nodes_[i]->discontinuity_enrich()) + nodes_[i]->update_discontinuity_property(true, "internal_force_enrich", sgn(levelset_phi_)*force, 0,2); } } @@ -752,7 +756,7 @@ inline void mpm::ParticleXMPM<3>::map_internal_force() noexcept { nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Solid, force); if(nodes_[i]->discontinuity_enrich()) - nodes_[i]->update_discontinuity_property(true, "internal_force_enrich", sgn(levelset_phi_)*force, 0,Tdim); + nodes_[i]->update_discontinuity_property(true, "internal_force_enrich", sgn(levelset_phi_)*force, 0,3); } } diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index 2a2b20f8a..f9c53eb70 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -286,18 +286,11 @@ bool mpm::XMPMExplicit::solve() { } #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_cundall, - std::placeholders::_1, phase, this->dt_, damping_factor_), - std::bind(&mpm::NodeBase::status, std::placeholders::_1)); - else - mesh_->iterate_over_nodes_predicate( - std::bind(&mpm::NodeBase::compute_acceleration_velocity, - std::placeholders::_1, phase, this->dt_), - std::bind(&mpm::NodeBase::status, std::placeholders::_1)); + //intergrate momentum Iterate over + mesh_->iterate_over_nodes_predicate( + std::bind(&mpm::NodeBase::intergrate_momentum_discontinuity, + std::placeholders::_1, phase, this->dt_), + std::bind(&mpm::NodeBase::status, std::placeholders::_1)); // Iterate over each particle to compute updated position mesh_->iterate_over_particles( From 07bd4809df325611513f1c6d8beb39858988f7ce Mon Sep 17 00:00:00 2001 From: yong liang Date: Sun, 2 Aug 2020 15:47:45 -0700 Subject: [PATCH 06/91] :construction:compute updated position --- include/particles/particle_xmpm.tcc | 49 ++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index 97efab4e6..3bf44daec 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -810,19 +810,58 @@ void mpm::ParticleXMPM::compute_updated_position( // Get interpolated nodal velocity Eigen::Matrix nodal_velocity = Eigen::Matrix::Zero(); - + const double tolerance = 1.E-16; + unsigned int phase = mpm::ParticlePhase::Solid; for (unsigned i = 0; i < nodes_.size(); ++i) - nodal_velocity += - shapefn_[i] * nodes_[i]->velocity(mpm::ParticlePhase::Solid); + { + if(nodes_[i]->discontinuity_enrich()) + { + double nodal_mass = nodes_[i]->mass(phase) + sgn(levelset_phi_)*nodes_[i]->discontinuity_property("mass_enrich",1)(0,0); + if (nodal_mass < tolerance) + continue; + nodal_velocity += shapefn_[i] * + (nodes_[i]->momentum(phase) + sgn(levelset_phi_) * nodes_[i]->discontinuity_property("momenta_enrich",3))/nodal_mass; + } + else + { + double nodal_mass = nodes_[i]->mass(phase); + if (nodal_mass < tolerance) + continue; + nodal_velocity += + shapefn_[i] * nodes_[i]->momentum(phase)/nodal_mass; + } + } // 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); + { + if(nodes_[i]->discontinuity_enrich()) + { + double nodal_mass = nodes_[i]->mass(phase) + sgn(levelset_phi_)*nodes_[i]->discontinuity_property("mass_enrich",1)(0,0); + if (nodal_mass < tolerance) + continue; + + auto force = nodes_[i]->internal_force(phase) + sgn(levelset_phi_) * nodes_[i]->discontinuity_property("internal_force_enrich",3) + + nodes_[i]->external_force(phase) + sgn(levelset_phi_) * nodes_[i]->discontinuity_property("external_force_enrich",3); + + nodal_acceleration += shapefn_[i] * force / nodal_mass; + } + else + { + double nodal_mass = nodes_[i]->mass(phase); + if (nodal_mass < tolerance) + continue; + + auto force = nodes_[i]->internal_force(phase) + nodes_[i]->external_force(phase); + + nodal_acceleration += + shapefn_[i] * force / nodal_mass; + } + } // Update particle velocity from interpolated nodal acceleration this->velocity_ += nodal_acceleration * dt; From 2beb5ac8053a9173674c30d9e72c41fc60891621 Mon Sep 17 00:00:00 2001 From: yong liang Date: Sun, 2 Aug 2020 18:06:45 -0700 Subject: [PATCH 07/91] :hammer: --- include/node.h | 2 +- include/node.tcc | 4 ++-- include/particles/particle_xmpm.h | 4 ++-- include/particles/particle_xmpm.tcc | 2 +- include/solvers/mpm_base.tcc | 2 +- include/xmpm/discontinuity_3d.tcc | 1 + 6 files changed, 8 insertions(+), 7 deletions(-) diff --git a/include/node.h b/include/node.h index daaaa8106..160e38284 100644 --- a/include/node.h +++ b/include/node.h @@ -356,7 +356,7 @@ class Node : public NodeBase { //! MPI ranks std::set mpi_ranks_; //! discontinuity enrich - bool discontinuity_enrich_{true}; + bool discontinuity_enrich_{false}; }; // Node class } // namespace mpm diff --git a/include/node.tcc b/include/node.tcc index 68281c006..f3278483d 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -679,11 +679,11 @@ bool mpm::Node::intergrate_momentum_discontinuity( } // Apply velocity constraints, which also sets acceleration to 0, // when velocity is set. - this->apply_velocity_constraints(); + this->apply_velocity_constraints_discontinuity(); //this->self_contact_discontinuity(dt); - this->apply_velocity_constraints(); + this->apply_velocity_constraints_discontinuity(); return true; diff --git a/include/particles/particle_xmpm.h b/include/particles/particle_xmpm.h index 340d3e59e..dede2d187 100644 --- a/include/particles/particle_xmpm.h +++ b/include/particles/particle_xmpm.h @@ -305,8 +305,8 @@ class ParticleXMPM : public ParticleBase { //! \retval strain rate at particle inside a cell inline Eigen::Matrix compute_strain_rate( const Eigen::MatrixXd& dn_dx, unsigned phase) noexcept; - //! set the level set function values - virtual void assign_levelsetphi(const double phivalue) { levelset_phi_ = phivalue; }; + //! set the level set function values + void assign_levelsetphi(const double phivalue) { levelset_phi_ = phivalue;}; //! return 1 if x > 0, -1 if x < 0 and 0 if x = 0 inline double sgn(double x) noexcept {return (x > 0) ? 1. : ((x < 0) ? -1. : 0);}; diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index 3bf44daec..e2961d1a6 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -630,8 +630,8 @@ inline Eigen::Matrix mpm::ParticleXMPM<3>::compute_strain_rate( Eigen::Matrix strain_rate = Eigen::Matrix::Zero(); const double tolerance = 1.E-16; Eigen::Vector3d vel; + vel.setZero(); for (unsigned i = 0; i < this->nodes_.size(); ++i){ - vel.setZero(); if(nodes_[i]->discontinuity_enrich()){ double nodal_mass = nodes_[i]->mass(phase) + sgn(levelset_phi_)*nodes_[i]->discontinuity_property("mass_enrich",1)(0,0) ; if(nodal_mass < tolerance) diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index 0c6d8bb49..8426ccf4f 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -506,7 +506,7 @@ void mpm::MPMBase::write_vtk(mpm::Index step, mpm::Index max_steps) { #endif //! VTK vector variables - std::vector vtk_vector_data = {"displacements", "velocities","levelset"}; + std::vector vtk_vector_data = {"displacements", "velocities"}; // Write VTK attributes for (const auto& attribute : vtk_vector_data) { diff --git a/include/xmpm/discontinuity_3d.tcc b/include/xmpm/discontinuity_3d.tcc index 62b7eb8f1..23afaa359 100755 --- a/include/xmpm/discontinuity_3d.tcc +++ b/include/xmpm/discontinuity_3d.tcc @@ -91,6 +91,7 @@ void mpm::Discontinuity_3D::compute_levelset(const std::vector { double Vertical_distance_ = element.Vertical_distance(coor);// Vertical_distance(coor); distance = std::abs(distance) < std::abs(Vertical_distance_)? distance:Vertical_distance_; + if(!distance) distance = 1e-16; } phi_list[i] = distance; From 2ddda95b618d0d6dc70c5650c3ad21b6aaeb836d Mon Sep 17 00:00:00 2001 From: yong liang Date: Tue, 4 Aug 2020 21:33:14 -0700 Subject: [PATCH 08/91] :hammer::construction:self contact for XMPM and boundary condation --- include/node.h | 8 ++- include/node.tcc | 105 ++++++++++++++++-------------- include/node_base.h | 5 ++ include/solvers/xmpm_explicit.tcc | 2 +- 4 files changed, 68 insertions(+), 52 deletions(-) diff --git a/include/node.h b/include/node.h index 160e38284..eedddabd2 100644 --- a/include/node.h +++ b/include/node.h @@ -297,7 +297,10 @@ class Node : public NodeBase { //! \param[in] dt Timestep in analysis virtual bool intergrate_momentum_discontinuity( unsigned phase, double dt) noexcept override; - + + //! Apply self-contact of the discontinuity + //! \param[in] dt Time-step + void self_contact_discontinuity(double dt) override; private: //! Mutex SpinMutex node_mutex_; @@ -356,7 +359,8 @@ class Node : public NodeBase { //! MPI ranks std::set mpi_ranks_; //! discontinuity enrich - bool discontinuity_enrich_{false}; + //need to be done + bool discontinuity_enrich_{true}; }; // Node class } // namespace mpm diff --git a/include/node.tcc b/include/node.tcc index f3278483d..1806ffb6f 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -681,7 +681,12 @@ bool mpm::Node::intergrate_momentum_discontinuity( // when velocity is set. this->apply_velocity_constraints_discontinuity(); - //this->self_contact_discontinuity(dt); + //need to be done + Eigen::Matrix normal{0.44721359474414313,0,0.89442719147920724}; + property_handle_->assign_property("normal_unit_vectors_discontinuity",discontinuity_prop_id_,0, + normal,Tdim); + + this->self_contact_discontinuity(dt); this->apply_velocity_constraints_discontinuity(); @@ -706,19 +711,19 @@ void mpm::Node::apply_velocity_constraints_discontinuity() //need to do for one direction this->momentum_(direction, phase) = this->mass(phase) * constraint.second; - property_handle_->assign_property("momenta_enrich",discontinuity_prop_id_,0, - property_handle_->property("mass_enrich",discontinuity_prop_id_,0,1) * constraint.second,Tdim); + property_handle_->assign_property("momenta_enrich",discontinuity_prop_id_*Tdim+direction,0, + property_handle_->property("mass_enrich",discontinuity_prop_id_,0,1) * constraint.second,1); // Set acceleration to 0 in direction of velocity constraint //this->acceleration_(direction, phase) = 0.; this->internal_force_(direction, phase) = 0; this->external_force_(direction, phase) = 0; - Eigen::Matrix momentum; + Eigen::Matrix momentum; momentum.setZero(); - property_handle_->assign_property("internal_force_enrich",discontinuity_prop_id_,0, - momentum,Tdim); - property_handle_->assign_property("external_force_enrich",discontinuity_prop_id_,0, - momentum,Tdim); + property_handle_->assign_property("internal_force_enrich",discontinuity_prop_id_*Tdim+direction,0, + momentum,1); + property_handle_->assign_property("external_force_enrich",discontinuity_prop_id_*Tdim+direction,0, + momentum,1); } else { //need to do // Velocity constraints on general boundaries // Compute inverse rotation matrix @@ -738,57 +743,59 @@ void mpm::Node::apply_velocity_constraints_discontinuity() } } } -// //! Apply velocity constraints -// template -// void mpm::NodeXMPM::self_contact_discontinuity(double dt) { - -// if(!enrich_h_) -// return; - -// unsigned phase = 0; -// const double tolerance = 1.0E-15; +//! Apply velocity constraints +template +void mpm::Node::self_contact_discontinuity(double dt) { -// auto mass_positive = mass_.col(phase) + mass_h_.col(phase); -// auto mass_negative = mass_.col(phase) - mass_h_.col(phase); + if(!discontinuity_enrich_) + return; + + unsigned phase = 0; + const double tolerance = 1.0E-15; -// if(mass_positive(phase) < tolerance || mass_negative(phase) < tolerance) -// return; + Eigen::Matrix mass_enrich = property_handle_->property("mass_enrich",discontinuity_prop_id_,0,1); + Eigen::Matrix momenta_enrich = property_handle_->property("momenta_enrich",discontinuity_prop_id_,0,Tdim); + Eigen::Matrix normal_vector = property_handle_->property("normal_unit_vectors_discontinuity",discontinuity_prop_id_,0,Tdim); -// auto velocity_positive = (momentum_.col(phase) + momentum_h_.col(phase)) / mass_positive(phase); -// auto velocity_negative = (momentum_.col(phase) - momentum_h_.col(phase)) / mass_negative(phase); + auto mass_positive = mass_.col(phase) + mass_enrich; + auto mass_negative = mass_.col(phase) - mass_enrich; -// if((velocity_positive - velocity_negative).col(phase).dot(direction_discontinuity_.col(phase)) >= 0) -// return; + if(mass_positive(phase) < tolerance || mass_negative(phase) < tolerance) + return; -// auto momentum_contact = (mass_h_(phase)*momentum_.col(phase) - mass_(phase)*momentum_h_.col(phase)) / mass_(phase); -// auto force_contact = momentum_contact/dt; + auto velocity_positive = (momentum_.col(phase) + momenta_enrich) / mass_positive(phase); + auto velocity_negative = (momentum_.col(phase) - momenta_enrich) / mass_negative(phase); -// //! frictional_coef < 0: move together without slide -// if(frictional_coef < 0) -// { -// momentum_h_.col(phase) = momentum_h_.col(phase) + momentum_contact.col(phase); -// internal_force_h_.col(phase) = internal_force_h_.col(phase) + force_contact.col(phase); -// } -// else -// { -// double momentum_contact_norm = momentum_contact.col(phase).dot(direction_discontinuity_.col(phase)); -// double force_contact_norm = momentum_contact_norm/dt; + if((velocity_positive - velocity_negative).col(phase).dot(normal_vector) >= 0) + return; -// double max_frictional_force = frictional_coef * abs(force_contact_norm); + auto momentum_contact = (mass_enrich(phase)*momentum_.col(phase) - mass_(phase)*momenta_enrich) / mass_(phase); + auto force_contact = momentum_contact/dt; -// auto momentum_tangential = momentum_contact.col(phase) - momentum_contact_norm*direction_discontinuity_.col(phase); -// auto force_tangential = momentum_tangential/dt; + // //! frictional_coef < 0: move together without slide + // //need to be done + double frictional_coef = 0; + if(frictional_coef < 0) + { + property_handle_->update_property("momenta_enrich",discontinuity_prop_id_,0,momentum_contact.col(phase),Tdim); + property_handle_->update_property("external_force_enrich",discontinuity_prop_id_,0,force_contact.col(phase),Tdim); + } + else + { + double momentum_contact_norm = momentum_contact.col(phase).dot(normal_vector); + double force_contact_norm = momentum_contact_norm/dt; -// double force_tangential_value = force_tangential.norm(); + double max_frictional_force = frictional_coef * abs(force_contact_norm); -// double frictional_force = force_tangential_value < max_frictional_force? force_tangential_value : max_frictional_force; + auto momentum_tangential = momentum_contact.col(phase) - momentum_contact_norm*normal_vector; + auto force_tangential = momentum_tangential/dt; -// //!adjust the momentum and force -// momentum_h_.col(phase) = momentum_h_.col(phase) + momentum_contact_norm*direction_discontinuity_.col(phase); -// internal_force_h_.col(phase) = internal_force_h_.col(phase) + force_contact_norm*direction_discontinuity_.col(phase); + double force_tangential_value = force_tangential.norm(); -// momentum_h_.col(phase) = momentum_h_.col(phase) + frictional_force*force_tangential.col(phase).normalized()*dt; -// internal_force_h_.col(phase) = internal_force_h_.col(phase) + frictional_force*force_tangential.col(phase).normalized(); + double frictional_force = force_tangential_value < max_frictional_force? force_tangential_value : max_frictional_force; -// } -// } \ No newline at end of file + //!adjust the momentum and force + property_handle_->update_property("momenta_enrich",discontinuity_prop_id_,0,momentum_contact_norm*normal_vector+frictional_force*force_tangential.col(phase).normalized()*dt,Tdim); + property_handle_->update_property("external_force_enrich",discontinuity_prop_id_,0,force_contact_norm*normal_vector+frictional_force*force_tangential.col(phase).normalized(),Tdim); + } +} \ No newline at end of file diff --git a/include/node_base.h b/include/node_base.h index 0a9f82b34..9808c678c 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -286,6 +286,11 @@ class NodeBase { //! \param[in] dt Timestep in analysis virtual bool intergrate_momentum_discontinuity( unsigned phase, double dt) noexcept = 0; + + + //! Apply self-contact of the discontinuity + //! \param[in] dt Time-step + virtual void self_contact_discontinuity(double dt) = 0; }; // NodeBase class } // namespace mpm diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index f9c53eb70..9462efd4a 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -335,7 +335,7 @@ bool mpm::XMPMExplicit::solve() { } auto solver_end = std::chrono::steady_clock::now(); console_->info( - "Rank {}, Explicit {} solver duration: {} ms", mpi_rank, + "Rank {}, XMPMExplicit {} solver duration: {} ms", mpi_rank, (this->stress_update_ == mpm::StressUpdate::USL ? "USL" : "USF"), std::chrono::duration_cast(solver_end - solver_begin) From e4a1265516dcba8fbb12abbc93f15530b9063e28 Mon Sep 17 00:00:00 2001 From: yong liang Date: Tue, 4 Aug 2020 21:42:33 -0700 Subject: [PATCH 09/91] :hammer:move the node_xmpm function to a separate file --- include/node.h | 1 + include/node.tcc | 168 ------------------------------- include/node_xmpm.tcc | 224 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 225 insertions(+), 168 deletions(-) create mode 100644 include/node_xmpm.tcc diff --git a/include/node.h b/include/node.h index eedddabd2..8aa16ef74 100644 --- a/include/node.h +++ b/include/node.h @@ -365,5 +365,6 @@ class Node : public NodeBase { } // namespace mpm #include "node.tcc" +#include "node_xmpm.tcc" #endif // MPM_NODE_H_ diff --git a/include/node.tcc b/include/node.tcc index 1806ffb6f..7d3a9cfcb 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -46,16 +46,6 @@ void mpm::Node::initialise_property_handle( this->prop_id_ = prop_id; } -//! Initialise shared pointer to nodal properties pool for discontinuity -template -void mpm::Node::initialise_discontinuity_property_handle( - unsigned prop_id, - std::shared_ptr property_handle) noexcept { - // the property handle and the property id is set in the node - this->property_handle_ = property_handle; - this->discontinuity_prop_id_ = prop_id; -} - //! Update mass at the nodes from particle template void mpm::Node::update_mass(bool update, unsigned phase, @@ -560,19 +550,6 @@ void mpm::Node::update_property( node_mutex_.unlock(); } -//! Update nodal property at the nodes from particle for discontinuity -template -void mpm::Node::update_discontinuity_property( - bool update, const std::string& property, - const Eigen::MatrixXd& property_value, unsigned discontinuity_id, - unsigned nprops) noexcept { - // Update/assign property - node_mutex_.lock(); - property_handle_->update_property(property, discontinuity_prop_id_, discontinuity_id, property_value, - nprops); - node_mutex_.unlock(); -} - //! Compute multimaterial change in momentum template void mpm::Node -Eigen::MatrixXd mpm::Node::discontinuity_property(const std::string& property, - unsigned nprops) { - // Const pointer to location of property: node_id * nprops x mat_id - auto property_value = property_handle_->property(property, discontinuity_prop_id_, 0, nprops);; - //mpm::MapProperty property_handle(position, nprops); - return property_value; -} - -//! Compute acceleration and velocity with cundall damping factor -template -bool mpm::Node::intergrate_momentum_discontinuity( - unsigned phase, double dt) noexcept { - momentum_.col(phase) = momentum_.col(phase) - + (internal_force_.col(phase) + external_force_.col(phase)) * dt; - if(discontinuity_enrich_){ - property_handle_->update_property("momenta_enrich", discontinuity_prop_id_, 0, - (property_handle_->property("internal_force_enrich",discontinuity_prop_id_,0,Tdim) - + property_handle_->property("external_force_enrich",discontinuity_prop_id_,0,Tdim) ) * dt, Tdim); - } - // Apply velocity constraints, which also sets acceleration to 0, - // when velocity is set. - this->apply_velocity_constraints_discontinuity(); - - //need to be done - Eigen::Matrix normal{0.44721359474414313,0,0.89442719147920724}; - property_handle_->assign_property("normal_unit_vectors_discontinuity",discontinuity_prop_id_,0, - normal,Tdim); - - this->self_contact_discontinuity(dt); - - this->apply_velocity_constraints_discontinuity(); - - - return true; -} - //! Apply velocity constraints -template -void mpm::Node::apply_velocity_constraints_discontinuity() { - // Set velocity constraint - for (const auto& constraint : this->velocity_constraints_) { - // Direction value in the constraint (0, Dim * Nphases) - const unsigned dir = constraint.first; - // Direction: dir % Tdim (modulus) - const auto direction = static_cast(dir % Tdim); - // Phase: Integer value of division (dir / Tdim) - const auto phase = static_cast(dir / Tdim); - - if (!generic_boundary_constraints_) { - // Velocity constraints are applied on Cartesian boundaries - //this->velocity_(direction, phase) = constraint.second; - //need to do for one direction - - this->momentum_(direction, phase) = this->mass(phase) * constraint.second; - property_handle_->assign_property("momenta_enrich",discontinuity_prop_id_*Tdim+direction,0, - property_handle_->property("mass_enrich",discontinuity_prop_id_,0,1) * constraint.second,1); - // Set acceleration to 0 in direction of velocity constraint - //this->acceleration_(direction, phase) = 0.; - this->internal_force_(direction, phase) = 0; - this->external_force_(direction, phase) = 0; - - Eigen::Matrix momentum; - momentum.setZero(); - property_handle_->assign_property("internal_force_enrich",discontinuity_prop_id_*Tdim+direction,0, - momentum,1); - property_handle_->assign_property("external_force_enrich",discontinuity_prop_id_*Tdim+direction,0, - momentum,1); - } else { //need to do - // Velocity constraints on general boundaries - // Compute inverse rotation matrix - const Eigen::Matrix inverse_rotation_matrix = - rotation_matrix_.inverse(); - // Transform to local coordinate - Eigen::Matrix local_velocity = - inverse_rotation_matrix * this->velocity_; - Eigen::Matrix local_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 - this->velocity_ = rotation_matrix_ * local_velocity; - this->acceleration_ = rotation_matrix_ * local_acceleration; - } - } -} -//! Apply velocity constraints -template -void mpm::Node::self_contact_discontinuity(double dt) { - - if(!discontinuity_enrich_) - return; - - unsigned phase = 0; - const double tolerance = 1.0E-15; - - Eigen::Matrix mass_enrich = property_handle_->property("mass_enrich",discontinuity_prop_id_,0,1); - Eigen::Matrix momenta_enrich = property_handle_->property("momenta_enrich",discontinuity_prop_id_,0,Tdim); - Eigen::Matrix normal_vector = property_handle_->property("normal_unit_vectors_discontinuity",discontinuity_prop_id_,0,Tdim); - - auto mass_positive = mass_.col(phase) + mass_enrich; - auto mass_negative = mass_.col(phase) - mass_enrich; - - if(mass_positive(phase) < tolerance || mass_negative(phase) < tolerance) - return; - - auto velocity_positive = (momentum_.col(phase) + momenta_enrich) / mass_positive(phase); - auto velocity_negative = (momentum_.col(phase) - momenta_enrich) / mass_negative(phase); - - if((velocity_positive - velocity_negative).col(phase).dot(normal_vector) >= 0) - return; - - auto momentum_contact = (mass_enrich(phase)*momentum_.col(phase) - mass_(phase)*momenta_enrich) / mass_(phase); - auto force_contact = momentum_contact/dt; - - // //! frictional_coef < 0: move together without slide - // //need to be done - double frictional_coef = 0; - if(frictional_coef < 0) - { - property_handle_->update_property("momenta_enrich",discontinuity_prop_id_,0,momentum_contact.col(phase),Tdim); - property_handle_->update_property("external_force_enrich",discontinuity_prop_id_,0,force_contact.col(phase),Tdim); - } - else - { - double momentum_contact_norm = momentum_contact.col(phase).dot(normal_vector); - double force_contact_norm = momentum_contact_norm/dt; - - double max_frictional_force = frictional_coef * abs(force_contact_norm); - - auto momentum_tangential = momentum_contact.col(phase) - momentum_contact_norm*normal_vector; - auto force_tangential = momentum_tangential/dt; - - double force_tangential_value = force_tangential.norm(); - - double frictional_force = force_tangential_value < max_frictional_force? force_tangential_value : max_frictional_force; - - //!adjust the momentum and force - property_handle_->update_property("momenta_enrich",discontinuity_prop_id_,0,momentum_contact_norm*normal_vector+frictional_force*force_tangential.col(phase).normalized()*dt,Tdim); - property_handle_->update_property("external_force_enrich",discontinuity_prop_id_,0,force_contact_norm*normal_vector+frictional_force*force_tangential.col(phase).normalized(),Tdim); - } -} \ No newline at end of file diff --git a/include/node_xmpm.tcc b/include/node_xmpm.tcc new file mode 100644 index 000000000..88fd30fbc --- /dev/null +++ b/include/node_xmpm.tcc @@ -0,0 +1,224 @@ +//! Initialise shared pointer to nodal properties pool for discontinuity +template +void mpm::Node::initialise_discontinuity_property_handle( + unsigned prop_id, + std::shared_ptr property_handle) noexcept { + // the property handle and the property id is set in the node + this->property_handle_ = property_handle; + this->discontinuity_prop_id_ = prop_id; +} + +//! Update nodal property at the nodes from particle for discontinuity +template +void mpm::Node::update_discontinuity_property( + bool update, const std::string& property, + const Eigen::MatrixXd& property_value, unsigned discontinuity_id, + unsigned nprops) noexcept { + // Update/assign property + node_mutex_.lock(); + property_handle_->update_property(property, discontinuity_prop_id_, discontinuity_id, property_value, + nprops); + node_mutex_.unlock(); +} + +// Return data in the nodal properties map at a specific index +template +Eigen::MatrixXd mpm::Node::discontinuity_property(const std::string& property, + unsigned nprops) { + // Const pointer to location of property: node_id * nprops x mat_id + auto property_value = property_handle_->property(property, discontinuity_prop_id_, 0, nprops);; + //mpm::MapProperty property_handle(position, nprops); + return property_value; +} + +//! Compute acceleration and velocity with cundall damping factor +template +bool mpm::Node::intergrate_momentum_discontinuity( + unsigned phase, double dt) noexcept { + momentum_.col(phase) = momentum_.col(phase) + + (internal_force_.col(phase) + external_force_.col(phase)) * dt; + if(discontinuity_enrich_){ + property_handle_->update_property("momenta_enrich", discontinuity_prop_id_, 0, + (property_handle_->property("internal_force_enrich",discontinuity_prop_id_,0,Tdim) + + property_handle_->property("external_force_enrich",discontinuity_prop_id_,0,Tdim) ) * dt, Tdim); + } + // Apply velocity constraints, which also sets acceleration to 0, + // when velocity is set. + this->apply_velocity_constraints_discontinuity(); + + //need to be done + Eigen::Matrix normal{0.44721359474414313,0,0.89442719147920724}; + property_handle_->assign_property("normal_unit_vectors_discontinuity",discontinuity_prop_id_,0, + normal,Tdim); + + this->self_contact_discontinuity(dt); + + this->apply_velocity_constraints_discontinuity(); + + + return true; +} + //! Apply velocity constraints +template +void mpm::Node::apply_velocity_constraints_discontinuity() { + // Set velocity constraint + for (const auto& constraint : this->velocity_constraints_) { + // Direction value in the constraint (0, Dim * Nphases) + const unsigned dir = constraint.first; + // Direction: dir % Tdim (modulus) + const auto direction = static_cast(dir % Tdim); + // Phase: Integer value of division (dir / Tdim) + const auto phase = static_cast(dir / Tdim); + + if (!generic_boundary_constraints_) { + // Velocity constraints are applied on Cartesian boundaries + //this->velocity_(direction, phase) = constraint.second; + //need to do for one direction + + this->momentum_(direction, phase) = this->mass(phase) * constraint.second; + property_handle_->assign_property("momenta_enrich",discontinuity_prop_id_*Tdim+direction,0, + property_handle_->property("mass_enrich",discontinuity_prop_id_,0,1) * constraint.second,1); + // Set acceleration to 0 in direction of velocity constraint + //this->acceleration_(direction, phase) = 0.; + this->internal_force_(direction, phase) = 0; + this->external_force_(direction, phase) = 0; + + Eigen::Matrix momentum; + momentum.setZero(); + property_handle_->assign_property("internal_force_enrich",discontinuity_prop_id_*Tdim+direction,0, + momentum,1); + property_handle_->assign_property("external_force_enrich",discontinuity_prop_id_*Tdim+direction,0, + momentum,1);// Return data in the nodal properties map at a specific index +template +Eigen::MatrixXd mpm::Node::discontinuity_property(const std::string& property, + unsigned nprops) { + // Const pointer to location of property: node_id * nprops x mat_id + auto property_value = property_handle_->property(property, discontinuity_prop_id_, 0, nprops);; + //mpm::MapProperty property_handle(position, nprops); + return property_value; +} + +//! Compute acceleration and velocity with cundall damping factor +template +bool mpm::Node::intergrate_momentum_discontinuity( + unsigned phase, double dt) noexcept { + momentum_.col(phase) = momentum_.col(phase) + + (internal_force_.col(phase) + external_force_.col(phase)) * dt; + if(discontinuity_enrich_){ + property_handle_->update_property("momenta_enrich", discontinuity_prop_id_, 0, + (property_handle_->property("internal_force_enrich",discontinuity_prop_id_,0,Tdim) + + property_handle_->property("external_force_enrich",discontinuity_prop_id_,0,Tdim) ) * dt, Tdim); + } + // Apply velocity constraints, which also sets acceleration to 0, + // when velocity is set. + this->apply_velocity_constraints_discontinuity(); + + //need to be done + Eigen::Matrix normal{0.44721359474414313,0,0.89442719147920724}; + property_handle_->assign_property("normal_unit_vectors_discontinuity",discontinuity_prop_id_,0, + normal,Tdim); + + this->self_contact_discontinuity(dt); + + this->apply_velocity_constraints_discontinuity(); + + + return true; +} + //! Apply velocity constraints +template +void mpm::Node::apply_velocity_constraints_discontinuity() { + // Set velocity constraint + for (const auto& constraint : this->velocity_constraints_) { + // Direction value in the constraint (0, Dim * Nphases) + const unsigned dir = constraint.first; + // Direction: dir % Tdim (modulus) + const auto direction = static_cast(dir % Tdim); + // Phase: Integer value of division (dir / Tdim) + const auto phase = static_cast(dir / Tdim); + + if (!generic_boundary_constraints_) { + // Velocity constraints are applied on Cartesian boundaries + //this->velocity_(direction, phase) = constraint.second; + //need to do for one direction + + this->momentum_(direction, phase) = this->mass(phase) * constraint.second; + property_handle_->assign_property("momenta_enrich",discontinuity_prop_id_*Tdim+direction,0, + property_handle_->property("mass_enrich",d + } else { //need to do + // Velocity constraints on general boundaries + // Compute inverse rotation matrix + const Eigen::Matrix inverse_rotation_matrix = + rotation_matrix_.inverse(); + // Transform to local coordinate + Eigen::Matrix local_velocity = + inverse_rotation_matrix * this->velocity_; + Eigen::Matrix local_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 + this->velocity_ = rotation_matrix_ * local_velocity; + this->acceleration_ = rotation_matrix_ * local_acceleration; + } + } +} +//! Apply velocity constraints +template +void mpm::Node::self_contact_discontinuity(double dt) { + + if(!discontinuity_enrich_) + return; + + unsigned phase = 0; + const double tolerance = 1.0E-15; + + Eigen::Matrix mass_enrich = property_handle_->property("mass_enrich",discontinuity_prop_id_,0,1); + Eigen::Matrix momenta_enrich = property_handle_->property("momenta_enrich",discontinuity_prop_id_,0,Tdim); + Eigen::Matrix normal_vector = property_handle_->property("normal_unit_vectors_discontinuity",discontinuity_prop_id_,0,Tdim); + + auto mass_positive = mass_.col(phase) + mass_enrich; + auto mass_negative = mass_.col(phase) - mass_enrich; + + if(mass_positive(phase) < tolerance || mass_negative(phase) < tolerance) + return; + + auto velocity_positive = (momentum_.col(phase) + momenta_enrich) / mass_positive(phase); + auto velocity_negative = (momentum_.col(phase) - momenta_enrich) / mass_negative(phase); + + if((velocity_positive - velocity_negative).col(phase).dot(normal_vector) >= 0) + return; + + auto momentum_contact = (mass_enrich(phase)*momentum_.col(phase) - mass_(phase)*momenta_enrich) / mass_(phase); + auto force_contact = momentum_contact/dt; + + // //! frictional_coef < 0: move together without slide + // //need to be done + double frictional_coef = 0; + if(frictional_coef < 0) + { + property_handle_->update_property("momenta_enrich",discontinuity_prop_id_,0,momentum_contact.col(phase),Tdim); + property_handle_->update_property("external_force_enrich",discontinuity_prop_id_,0,force_contact.col(phase),Tdim); + } + else + { + double momentum_contact_norm = momentum_contact.col(phase).dot(normal_vector); + double force_contact_norm = momentum_contact_norm/dt; + + double max_frictional_force = frictional_coef * abs(force_contact_norm); + + auto momentum_tangential = momentum_contact.col(phase) - momentum_contact_norm*normal_vector; + auto force_tangential = momentum_tangential/dt; + + double force_tangential_value = force_tangential.norm(); + + double frictional_force = force_tangential_value < max_frictional_force? force_tangential_value : max_frictional_force; + + //!adjust the momentum and force + property_handle_->update_property("momenta_enrich",discontinuity_prop_id_,0,momentum_contact_norm*normal_vector+frictional_force*force_tangential.col(phase).normalized()*dt,Tdim); + property_handle_->update_property("external_force_enrich",discontinuity_prop_id_,0,force_contact_norm*normal_vector+frictional_force*force_tangential.col(phase).normalized(),Tdim); + } +} \ No newline at end of file From e185bb4272c56979d5d474fdbdf25e93723bacee Mon Sep 17 00:00:00 2001 From: yong liang Date: Tue, 4 Aug 2020 21:55:34 -0700 Subject: [PATCH 10/91] :bug:miss some functions for node_xmpm.tcc --- include/node_xmpm.tcc | 59 +------------------------------------------ 1 file changed, 1 insertion(+), 58 deletions(-) diff --git a/include/node_xmpm.tcc b/include/node_xmpm.tcc index 88fd30fbc..01127b18f 100644 --- a/include/node_xmpm.tcc +++ b/include/node_xmpm.tcc @@ -89,64 +89,7 @@ void mpm::Node::apply_velocity_constraints_discontinuity() property_handle_->assign_property("internal_force_enrich",discontinuity_prop_id_*Tdim+direction,0, momentum,1); property_handle_->assign_property("external_force_enrich",discontinuity_prop_id_*Tdim+direction,0, - momentum,1);// Return data in the nodal properties map at a specific index -template -Eigen::MatrixXd mpm::Node::discontinuity_property(const std::string& property, - unsigned nprops) { - // Const pointer to location of property: node_id * nprops x mat_id - auto property_value = property_handle_->property(property, discontinuity_prop_id_, 0, nprops);; - //mpm::MapProperty property_handle(position, nprops); - return property_value; -} - -//! Compute acceleration and velocity with cundall damping factor -template -bool mpm::Node::intergrate_momentum_discontinuity( - unsigned phase, double dt) noexcept { - momentum_.col(phase) = momentum_.col(phase) - + (internal_force_.col(phase) + external_force_.col(phase)) * dt; - if(discontinuity_enrich_){ - property_handle_->update_property("momenta_enrich", discontinuity_prop_id_, 0, - (property_handle_->property("internal_force_enrich",discontinuity_prop_id_,0,Tdim) - + property_handle_->property("external_force_enrich",discontinuity_prop_id_,0,Tdim) ) * dt, Tdim); - } - // Apply velocity constraints, which also sets acceleration to 0, - // when velocity is set. - this->apply_velocity_constraints_discontinuity(); - - //need to be done - Eigen::Matrix normal{0.44721359474414313,0,0.89442719147920724}; - property_handle_->assign_property("normal_unit_vectors_discontinuity",discontinuity_prop_id_,0, - normal,Tdim); - - this->self_contact_discontinuity(dt); - - this->apply_velocity_constraints_discontinuity(); - - - return true; -} - //! Apply velocity constraints -template -void mpm::Node::apply_velocity_constraints_discontinuity() { - // Set velocity constraint - for (const auto& constraint : this->velocity_constraints_) { - // Direction value in the constraint (0, Dim * Nphases) - const unsigned dir = constraint.first; - // Direction: dir % Tdim (modulus) - const auto direction = static_cast(dir % Tdim); - // Phase: Integer value of division (dir / Tdim) - const auto phase = static_cast(dir / Tdim); - - if (!generic_boundary_constraints_) { - // Velocity constraints are applied on Cartesian boundaries - //this->velocity_(direction, phase) = constraint.second; - //need to do for one direction - - this->momentum_(direction, phase) = this->mass(phase) * constraint.second; - property_handle_->assign_property("momenta_enrich",discontinuity_prop_id_*Tdim+direction,0, - property_handle_->property("mass_enrich",d + momentum,1); } else { //need to do // Velocity constraints on general boundaries // Compute inverse rotation matrix From c3992665b64c9d865d3b6120918e968a15fd0b0d Mon Sep 17 00:00:00 2001 From: yong liang Date: Wed, 5 Aug 2020 12:17:42 -0700 Subject: [PATCH 11/91] :hammer:add const --- include/node.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/node.h b/include/node.h index 8aa16ef74..0d2e5b1eb 100644 --- a/include/node.h +++ b/include/node.h @@ -209,7 +209,7 @@ class Node : public NodeBase { void apply_velocity_constraints() override; //! Apply velocity constraints for discontinuity - void apply_velocity_constraints_discontinuity() override; + void apply_velocity_constraints_discontinuity() noexcept override; //! Assign friction constraint //! Directions can take values between 0 and Dim * Nphases @@ -275,7 +275,7 @@ class Node : public NodeBase { void compute_multimaterial_normal_unit_vector() override; //! Return whether the node is enriched - bool discontinuity_enrich() {return discontinuity_enrich_;}; + bool discontinuity_enrich() const override {return discontinuity_enrich_;}; //! Update nodal property at the nodes from particle for discontinuity //! \param[in] update A boolean to update (true) or assign (false) @@ -290,7 +290,7 @@ class Node : public NodeBase { // Return data in the nodal discontinuity properties map at a specific index // \param[in] property Property name // \param[in] nprops Dimension of property (1 if scalar, Tdim if vector) - Eigen::MatrixXd discontinuity_property(const std::string& property, unsigned nprops = 1) override; + Eigen::MatrixXd discontinuity_property(const std::string& property, unsigned nprops = 1) noexcept override; //! Compute momentum //! \param[in] phase Index corresponding to the phase @@ -300,7 +300,7 @@ class Node : public NodeBase { //! Apply self-contact of the discontinuity //! \param[in] dt Time-step - void self_contact_discontinuity(double dt) override; + void self_contact_discontinuity(double dt) noexcept override; private: //! Mutex SpinMutex node_mutex_; From cf3a06bb4427365b1dd174c766e0baeecf467e77 Mon Sep 17 00:00:00 2001 From: yong liang Date: Thu, 6 Aug 2020 14:39:33 -0700 Subject: [PATCH 12/91] :construction:clang format --- include/io/logger.h | 2 +- include/mesh.h | 4 +- include/mesh.tcc | 15 +-- include/node.h | 27 ++-- include/node_base.h | 21 ++-- include/node_xmpm.tcc | 166 ++++++++++++++---------- include/particles/particle_base.h | 2 +- include/particles/particle_xmpm.h | 11 +- include/particles/particle_xmpm.tcc | 170 +++++++++++++------------ include/solvers/xmpm_explicit.h | 12 +- include/solvers/xmpm_explicit.tcc | 91 ++++++++------ include/xmpm/discontinuity_3d.h | 52 ++++---- include/xmpm/discontinuity_3d.tcc | 153 +++++++++++----------- include/xmpm/discontinuity_base.h | 188 +++++++++++++--------------- src/discontinuity.cc | 5 +- 15 files changed, 494 insertions(+), 425 deletions(-) mode change 100755 => 100644 include/xmpm/discontinuity_3d.h mode change 100755 => 100644 include/xmpm/discontinuity_3d.tcc mode change 100755 => 100644 include/xmpm/discontinuity_base.h mode change 100755 => 100644 src/discontinuity.cc diff --git a/include/io/logger.h b/include/io/logger.h index 01c1afcf7..8a7ff9766 100644 --- a/include/io/logger.h +++ b/include/io/logger.h @@ -42,7 +42,7 @@ struct Logger { // Create a logger for MPM Explicit USL static const std::shared_ptr mpm_explicit_usl_logger; - // Create a logger for MPM Explicit + // Create a logger for MPM Explicit static const std::shared_ptr xmpm_explicit_logger; }; diff --git a/include/mesh.h b/include/mesh.h index 654479f32..7226eefef 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -447,10 +447,10 @@ class Mesh { // Initialise the nodal properties' map void initialise_nodal_properties(); - //! Set particles lsm values + //! Set particles lsm values void assign_particle_levelset(std::vector& phi_list); - // Create the nodal properties' map for discontinuity + // Create the nodal properties' map for discontinuity void create_nodal_properties_discontinuity(); private: diff --git a/include/mesh.tcc b/include/mesh.tcc index e4d4a1c66..43091b138 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1889,7 +1889,7 @@ void mpm::Mesh::create_nodal_properties() { template void mpm::Mesh::create_nodal_properties_discontinuity() { // Initialise the shared pointer to nodal properties - if(nodal_properties_ == nullptr) + if (nodal_properties_ == nullptr) nodal_properties_ = std::make_shared(); // Check if nodes_ is empty and throw runtime error if they are @@ -1898,16 +1898,18 @@ void mpm::Mesh::create_nodal_properties_discontinuity() { const unsigned nrows = nodes_.size() * Tdim; // Create pool data for each property in the nodal properties struct // object. Properties must be named in the plural form - nodal_properties_->create_property("mass_enrich", nodes_.size(),1); + nodal_properties_->create_property("mass_enrich", nodes_.size(), 1); nodal_properties_->create_property("momenta_enrich", nrows, 1); nodal_properties_->create_property("internal_force_enrich", nrows, 1); nodal_properties_->create_property("external_force_enrich", nrows, 1); - nodal_properties_->create_property("normal_unit_vectors_discontinuity", nrows,1); + nodal_properties_->create_property("normal_unit_vectors_discontinuity", + nrows, 1); // Iterate over all nodes to initialise the property handle in each node // and assign its node id as the prop id in the nodal property data pool for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) - (*nitr)->initialise_discontinuity_property_handle((*nitr)->id(), nodal_properties_); + (*nitr)->initialise_discontinuity_property_handle((*nitr)->id(), + nodal_properties_); } else { throw std::runtime_error("Number of nodes is zero"); } @@ -1922,8 +1924,7 @@ void mpm::Mesh::initialise_nodal_properties() { //! Set particles lsm values template -void mpm::Mesh::assign_particle_levelset(std::vector& phi_list) -{ - for(mpm::Index i = 0; i::assign_particle_levelset(std::vector& phi_list) { + for (mpm::Index i = 0; i < nparticles(); ++i) particles_[i]->assign_levelsetphi(phi_list[i]); } \ No newline at end of file diff --git a/include/node.h b/include/node.h index 0d2e5b1eb..ce363cffb 100644 --- a/include/node.h +++ b/include/node.h @@ -208,8 +208,8 @@ class Node : public NodeBase { //! Apply velocity constraints void apply_velocity_constraints() override; - //! Apply velocity constraints for discontinuity - void apply_velocity_constraints_discontinuity() noexcept override; + //! Apply velocity constraints for discontinuity + void apply_velocity_constraints_discontinuity() override; //! Assign friction constraint //! Directions can take values between 0 and Dim * Nphases @@ -275,32 +275,35 @@ class Node : public NodeBase { void compute_multimaterial_normal_unit_vector() override; //! Return whether the node is enriched - bool discontinuity_enrich() const override {return discontinuity_enrich_;}; + bool discontinuity_enrich() const { return discontinuity_enrich_; }; - //! Update nodal property at the nodes from particle for discontinuity + //! Update nodal property at the nodes from particle for discontinuity //! \param[in] update A boolean to update (true) or assign (false) //! \param[in] property Property name //! \param[in] property_value Property quantity from the particles in the cell //! \param[in] discontinuity_id Id of the material within the property data //! \param[in] nprops Dimension of property (1 if scalar, Tdim if vector) void update_discontinuity_property(bool update, const std::string& property, - const Eigen::MatrixXd& property_value, unsigned discontinuity_id, - unsigned nprops) noexcept override; + const Eigen::MatrixXd& property_value, + unsigned discontinuity_id, + unsigned nprops) noexcept override; - // Return data in the nodal discontinuity properties map at a specific index + // Return data in the nodal discontinuity properties map at a specific index // \param[in] property Property name // \param[in] nprops Dimension of property (1 if scalar, Tdim if vector) - Eigen::MatrixXd discontinuity_property(const std::string& property, unsigned nprops = 1) noexcept override; + Eigen::MatrixXd discontinuity_property(const std::string& property, + unsigned nprops = 1) noexcept override; - //! Compute momentum + //! Compute momentum //! \param[in] phase Index corresponding to the phase //! \param[in] dt Timestep in analysis - virtual bool intergrate_momentum_discontinuity( - unsigned phase, double dt) noexcept override; + virtual bool intergrate_momentum_discontinuity(unsigned phase, + double dt) noexcept override; //! Apply self-contact of the discontinuity //! \param[in] dt Time-step void self_contact_discontinuity(double dt) noexcept override; + private: //! Mutex SpinMutex node_mutex_; @@ -359,7 +362,7 @@ class Node : public NodeBase { //! MPI ranks std::set mpi_ranks_; //! discontinuity enrich - //need to be done + // need to be done bool discontinuity_enrich_{true}; }; // Node class } // namespace mpm diff --git a/include/node_base.h b/include/node_base.h index 9808c678c..134bbf8c6 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -263,13 +263,14 @@ class NodeBase { //! Compute multimaterial normal unit vector virtual void compute_multimaterial_normal_unit_vector() = 0; - // Return data in the nodal discontinuity properties map at a specific index + // Return data in the nodal discontinuity properties map at a specific index // \param[in] property Property name // \param[in] nprops Dimension of property (1 if scalar, Tdim if vector) - virtual Eigen::MatrixXd discontinuity_property(const std::string& property,unsigned nprops = 1) = 0; + virtual Eigen::MatrixXd discontinuity_property( + const std::string& property, unsigned nprops = 1) noexcept = 0; //! Return whether the node is enriched - virtual bool discontinuity_enrich() = 0; + virtual bool discontinuity_enrich() const = 0; //! Update nodal property at the nodes from particle for discontinuity //! \param[in] update A boolean to update (true) or assign (false) @@ -277,20 +278,20 @@ class NodeBase { //! \param[in] property_value Property quantity from the particles in the cell //! \param[in] discontinuity_id Id of the material within the property data //! \param[in] nprops Dimension of property (1 if scalar, Tdim if vector) - virtual void update_discontinuity_property(bool update, const std::string& property, - const Eigen::MatrixXd& property_value, unsigned discontinuity_id, - unsigned nprops) noexcept = 0; + virtual void update_discontinuity_property( + bool update, const std::string& property, + const Eigen::MatrixXd& property_value, unsigned discontinuity_id, + unsigned nprops) noexcept = 0; //! Compute momentum //! \param[in] phase Index corresponding to the phase //! \param[in] dt Timestep in analysis - virtual bool intergrate_momentum_discontinuity( - unsigned phase, double dt) noexcept = 0; - + virtual bool intergrate_momentum_discontinuity(unsigned phase, + double dt) noexcept = 0; //! Apply self-contact of the discontinuity //! \param[in] dt Time-step - virtual void self_contact_discontinuity(double dt) = 0; + virtual void self_contact_discontinuity(double dt) noexcept = 0; }; // NodeBase class } // namespace mpm diff --git a/include/node_xmpm.tcc b/include/node_xmpm.tcc index 01127b18f..5649722d0 100644 --- a/include/node_xmpm.tcc +++ b/include/node_xmpm.tcc @@ -16,19 +16,20 @@ void mpm::Node::update_discontinuity_property( unsigned nprops) noexcept { // Update/assign property node_mutex_.lock(); - property_handle_->update_property(property, discontinuity_prop_id_, discontinuity_id, property_value, - nprops); + property_handle_->update_property(property, discontinuity_prop_id_, + discontinuity_id, property_value, nprops); node_mutex_.unlock(); } // Return data in the nodal properties map at a specific index template -Eigen::MatrixXd mpm::Node::discontinuity_property(const std::string& property, - unsigned nprops) { +Eigen::MatrixXd mpm::Node::discontinuity_property( + const std::string& property, unsigned nprops) noexcept { // Const pointer to location of property: node_id * nprops x mat_id - auto property_value = property_handle_->property(property, discontinuity_prop_id_, 0, nprops);; - //mpm::MapProperty property_handle(position, nprops); + auto property_value = + property_handle_->property(property, discontinuity_prop_id_, 0, nprops); + ; + // mpm::MapProperty property_handle(position, nprops); return property_value; } @@ -36,32 +37,39 @@ Eigen::MatrixXd mpm::Node bool mpm::Node::intergrate_momentum_discontinuity( unsigned phase, double dt) noexcept { - momentum_.col(phase) = momentum_.col(phase) - + (internal_force_.col(phase) + external_force_.col(phase)) * dt; - if(discontinuity_enrich_){ - property_handle_->update_property("momenta_enrich", discontinuity_prop_id_, 0, - (property_handle_->property("internal_force_enrich",discontinuity_prop_id_,0,Tdim) - + property_handle_->property("external_force_enrich",discontinuity_prop_id_,0,Tdim) ) * dt, Tdim); + momentum_.col(phase) = + momentum_.col(phase) + + (internal_force_.col(phase) + external_force_.col(phase)) * dt; + if (discontinuity_enrich_) { + property_handle_->update_property( + "momenta_enrich", discontinuity_prop_id_, 0, + (property_handle_->property("internal_force_enrich", + discontinuity_prop_id_, 0, Tdim) + + property_handle_->property("external_force_enrich", + discontinuity_prop_id_, 0, Tdim)) * + dt, + Tdim); } // Apply velocity constraints, which also sets acceleration to 0, // when velocity is set. this->apply_velocity_constraints_discontinuity(); - //need to be done - Eigen::Matrix normal{0.44721359474414313,0,0.89442719147920724}; - property_handle_->assign_property("normal_unit_vectors_discontinuity",discontinuity_prop_id_,0, - normal,Tdim); + // need to be done + Eigen::Matrix normal{0.44721359474414313, 0, + 0.89442719147920724}; + property_handle_->assign_property("normal_unit_vectors_discontinuity", + discontinuity_prop_id_, 0, normal, Tdim); this->self_contact_discontinuity(dt); this->apply_velocity_constraints_discontinuity(); - return true; } - //! Apply velocity constraints +//! Apply velocity constraints template -void mpm::Node::apply_velocity_constraints_discontinuity() { +void mpm::Node::apply_velocity_constraints_discontinuity() { // Set velocity constraint for (const auto& constraint : this->velocity_constraints_) { // Direction value in the constraint (0, Dim * Nphases) @@ -73,24 +81,30 @@ void mpm::Node::apply_velocity_constraints_discontinuity() if (!generic_boundary_constraints_) { // Velocity constraints are applied on Cartesian boundaries - //this->velocity_(direction, phase) = constraint.second; - //need to do for one direction + // this->velocity_(direction, phase) = constraint.second; + // need to do for one direction this->momentum_(direction, phase) = this->mass(phase) * constraint.second; - property_handle_->assign_property("momenta_enrich",discontinuity_prop_id_*Tdim+direction,0, - property_handle_->property("mass_enrich",discontinuity_prop_id_,0,1) * constraint.second,1); + property_handle_->assign_property( + "momenta_enrich", discontinuity_prop_id_ * Tdim + direction, 0, + property_handle_->property("mass_enrich", discontinuity_prop_id_, 0, + 1) * + constraint.second, + 1); // Set acceleration to 0 in direction of velocity constraint - //this->acceleration_(direction, phase) = 0.; + // this->acceleration_(direction, phase) = 0.; this->internal_force_(direction, phase) = 0; this->external_force_(direction, phase) = 0; Eigen::Matrix momentum; - momentum.setZero(); - property_handle_->assign_property("internal_force_enrich",discontinuity_prop_id_*Tdim+direction,0, - momentum,1); - property_handle_->assign_property("external_force_enrich",discontinuity_prop_id_*Tdim+direction,0, - momentum,1); - } else { //need to do + momentum.setZero(); + property_handle_->assign_property( + "internal_force_enrich", discontinuity_prop_id_ * Tdim + direction, 0, + momentum, 1); + property_handle_->assign_property( + "external_force_enrich", discontinuity_prop_id_ * Tdim + direction, 0, + momentum, 1); + } else { // need to do // Velocity constraints on general boundaries // Compute inverse rotation matrix const Eigen::Matrix inverse_rotation_matrix = @@ -111,57 +125,83 @@ void mpm::Node::apply_velocity_constraints_discontinuity() } //! Apply velocity constraints template -void mpm::Node::self_contact_discontinuity(double dt) { +void mpm::Node::self_contact_discontinuity( + double dt) noexcept { - if(!discontinuity_enrich_) - return; - - unsigned phase = 0; + if (!discontinuity_enrich_) return; + + unsigned phase = 0; const double tolerance = 1.0E-15; - Eigen::Matrix mass_enrich = property_handle_->property("mass_enrich",discontinuity_prop_id_,0,1); - Eigen::Matrix momenta_enrich = property_handle_->property("momenta_enrich",discontinuity_prop_id_,0,Tdim); - Eigen::Matrix normal_vector = property_handle_->property("normal_unit_vectors_discontinuity",discontinuity_prop_id_,0,Tdim); + Eigen::Matrix mass_enrich = + property_handle_->property("mass_enrich", discontinuity_prop_id_, 0, 1); + Eigen::Matrix momenta_enrich = property_handle_->property( + "momenta_enrich", discontinuity_prop_id_, 0, Tdim); + Eigen::Matrix normal_vector = property_handle_->property( + "normal_unit_vectors_discontinuity", discontinuity_prop_id_, 0, Tdim); + // mass for different sides auto mass_positive = mass_.col(phase) + mass_enrich; auto mass_negative = mass_.col(phase) - mass_enrich; - if(mass_positive(phase) < tolerance || mass_negative(phase) < tolerance) + if (mass_positive(phase) < tolerance || mass_negative(phase) < tolerance) return; - auto velocity_positive = (momentum_.col(phase) + momenta_enrich) / mass_positive(phase); - auto velocity_negative = (momentum_.col(phase) - momenta_enrich) / mass_negative(phase); + // velocity for different sides + auto velocity_positive = + (momentum_.col(phase) + momenta_enrich) / mass_positive(phase); + auto velocity_negative = + (momentum_.col(phase) - momenta_enrich) / mass_negative(phase); - if((velocity_positive - velocity_negative).col(phase).dot(normal_vector) >= 0) + // relative normal velocity + if ((velocity_positive - velocity_negative).col(phase).dot(normal_vector) >= + 0) return; - auto momentum_contact = (mass_enrich(phase)*momentum_.col(phase) - mass_(phase)*momenta_enrich) / mass_(phase); - auto force_contact = momentum_contact/dt; + // the contact momentum for sticking contact + auto momentum_contact = (mass_enrich(phase) * momentum_.col(phase) - + mass_(phase) * momenta_enrich) / + mass_(phase); + auto force_contact = momentum_contact / dt; - // //! frictional_coef < 0: move together without slide - // //need to be done + //! frictional_coef < 0: move together without slide + // need to be done double frictional_coef = 0; - if(frictional_coef < 0) - { - property_handle_->update_property("momenta_enrich",discontinuity_prop_id_,0,momentum_contact.col(phase),Tdim); - property_handle_->update_property("external_force_enrich",discontinuity_prop_id_,0,force_contact.col(phase),Tdim); - } - else - { - double momentum_contact_norm = momentum_contact.col(phase).dot(normal_vector); - double force_contact_norm = momentum_contact_norm/dt; + if (frictional_coef < 0) { + property_handle_->update_property("momenta_enrich", discontinuity_prop_id_, + 0, momentum_contact.col(phase), Tdim); + property_handle_->update_property("external_force_enrich", + discontinuity_prop_id_, 0, + force_contact.col(phase), Tdim); + } else { + double momentum_contact_norm = + momentum_contact.col(phase).dot(normal_vector); + double force_contact_norm = momentum_contact_norm / dt; + + // the maximum frictional contact force double max_frictional_force = frictional_coef * abs(force_contact_norm); - auto momentum_tangential = momentum_contact.col(phase) - momentum_contact_norm*normal_vector; - auto force_tangential = momentum_tangential/dt; + auto momentum_tangential = + momentum_contact.col(phase) - momentum_contact_norm * normal_vector; + auto force_tangential = momentum_tangential / dt; double force_tangential_value = force_tangential.norm(); - double frictional_force = force_tangential_value < max_frictional_force? force_tangential_value : max_frictional_force; - - //!adjust the momentum and force - property_handle_->update_property("momenta_enrich",discontinuity_prop_id_,0,momentum_contact_norm*normal_vector+frictional_force*force_tangential.col(phase).normalized()*dt,Tdim); - property_handle_->update_property("external_force_enrich",discontinuity_prop_id_,0,force_contact_norm*normal_vector+frictional_force*force_tangential.col(phase).normalized(),Tdim); + double frictional_force = force_tangential_value < max_frictional_force + ? force_tangential_value + : max_frictional_force; + + //! adjust the momentum and force + property_handle_->update_property( + "momenta_enrich", discontinuity_prop_id_, 0, + momentum_contact_norm * normal_vector + + frictional_force * force_tangential.col(phase).normalized() * dt, + Tdim); + property_handle_->update_property( + "external_force_enrich", discontinuity_prop_id_, 0, + force_contact_norm * normal_vector + + frictional_force * force_tangential.col(phase).normalized(), + Tdim); } } \ No newline at end of file diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 6ad4d55f9..a9c753c7b 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -283,7 +283,7 @@ class ParticleBase { virtual std::vector neighbours() const = 0; //! set the level set function values - virtual void assign_levelsetphi(const double phivalue) {}; + virtual void assign_levelsetphi(const double phivalue){}; protected: //! particleBase id diff --git a/include/particles/particle_xmpm.h b/include/particles/particle_xmpm.h index dede2d187..3506097bf 100644 --- a/include/particles/particle_xmpm.h +++ b/include/particles/particle_xmpm.h @@ -306,10 +306,13 @@ class ParticleXMPM : public ParticleBase { inline Eigen::Matrix compute_strain_rate( const Eigen::MatrixXd& dn_dx, unsigned phase) noexcept; //! set the level set function values - void assign_levelsetphi(const double phivalue) { levelset_phi_ = phivalue;}; + void assign_levelsetphi(const double phivalue) { levelset_phi_ = phivalue; }; + + //! return 1 if x > 0, -1 if x < 0 and 0 if x = 0 + inline double sgn(double x) noexcept { + return (x > 0) ? 1. : ((x < 0) ? -1. : 0); + }; - //! return 1 if x > 0, -1 if x < 0 and 0 if x = 0 - inline double sgn(double x) noexcept {return (x > 0) ? 1. : ((x < 0) ? -1. : 0);}; private: //! particle id using ParticleBase::id_; @@ -375,7 +378,7 @@ class ParticleXMPM : public ParticleBase { std::unique_ptr console_; //! Map of vector properties std::map> properties_; - //!level set values for discontinuity + //! level set values for discontinuity double levelset_phi_{0.}; }; // ParticleXMPM class } // namespace mpm diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index e2961d1a6..ae203b350 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -17,7 +17,8 @@ mpm::ParticleXMPM::ParticleXMPM(Index id, const VectorDim& coord) //! Construct a particle with id, coordinates and status template -mpm::ParticleXMPM::ParticleXMPM(Index id, const VectorDim& coord, bool status) +mpm::ParticleXMPM::ParticleXMPM(Index id, const VectorDim& coord, + bool status) : mpm::ParticleBase(id, coord, status) { this->initialise(); cell_ = nullptr; @@ -32,7 +33,8 @@ mpm::ParticleXMPM::ParticleXMPM(Index id, const VectorDim& coord, bool sta //! Initialise particle data from HDF5 template -bool mpm::ParticleXMPM::initialise_particle(const HDF5Particle& particle) { +bool mpm::ParticleXMPM::initialise_particle( + const HDF5Particle& particle) { // Assign id this->id_ = particle.id; @@ -249,7 +251,6 @@ void mpm::ParticleXMPM::initialise() { this->properties_["strains"] = [&]() { return strain(); }; this->properties_["velocities"] = [&]() { return velocity(); }; this->properties_["displacements"] = [&]() { return displacement(); }; - this->properties_["levelset"] = [&]() { Eigen::Matrix levelset; levelset[0] = levelset_phi_ ; return levelset; }; } //! Initialise particle material container @@ -522,22 +523,23 @@ void mpm::ParticleXMPM::map_mass_momentum_to_nodes() noexcept { mass_ * shapefn_[i]); nodes_[i]->update_momentum(true, mpm::ParticlePhase::Solid, mass_ * shapefn_[i] * velocity_); - if(nodes_[i]->discontinuity_enrich()){ - // Unit 1x1 Eigen matrix to be used with scalar quantities + if (nodes_[i]->discontinuity_enrich()) { + // Unit 1x1 Eigen matrix to be used with scalar quantities Eigen::Matrix nodal_mass; - nodal_mass(0, 0) = sgn(levelset_phi_) * mass_ * shapefn_[i]; - // Map enriched mass and momentum to nodes - nodes_[i]->update_discontinuity_property(true, "mass_enrich", nodal_mass, 0, - 1); - nodes_[i]->update_discontinuity_property(true, "momenta_enrich", velocity_ * nodal_mass, - 0, Tdim); + nodal_mass(0, 0) = sgn(levelset_phi_) * mass_ * shapefn_[i]; + // Map enriched mass and momentum to nodes + nodes_[i]->update_discontinuity_property(true, "mass_enrich", nodal_mass, + 0, 1); + nodes_[i]->update_discontinuity_property(true, "momenta_enrich", + velocity_ * nodal_mass, 0, Tdim); } } } //! Map multimaterial properties to nodes template -void mpm::ParticleXMPM::map_multimaterial_mass_momentum_to_nodes() noexcept { +void mpm::ParticleXMPM< + Tdim>::map_multimaterial_mass_momentum_to_nodes() noexcept { // Check if particle mass is set assert(mass_ != std::numeric_limits::max()); @@ -556,7 +558,8 @@ void mpm::ParticleXMPM::map_multimaterial_mass_momentum_to_nodes() noexcep //! Map multimaterial displacements to nodes template -void mpm::ParticleXMPM::map_multimaterial_displacements_to_nodes() noexcept { +void mpm::ParticleXMPM< + Tdim>::map_multimaterial_displacements_to_nodes() noexcept { // Check if particle mass is set assert(mass_ != std::numeric_limits::max()); @@ -631,19 +634,23 @@ inline Eigen::Matrix mpm::ParticleXMPM<3>::compute_strain_rate( const double tolerance = 1.E-16; Eigen::Vector3d vel; vel.setZero(); - for (unsigned i = 0; i < this->nodes_.size(); ++i){ - if(nodes_[i]->discontinuity_enrich()){ - double nodal_mass = nodes_[i]->mass(phase) + sgn(levelset_phi_)*nodes_[i]->discontinuity_property("mass_enrich",1)(0,0) ; - if(nodal_mass < tolerance) - continue; - - vel = (nodes_[i]->momentum(phase) + sgn(levelset_phi_)*nodes_[i]->discontinuity_property("momenta_enrich",3).col(0))/nodal_mass; - } - else{ + for (unsigned i = 0; i < this->nodes_.size(); ++i) { + if (nodes_[i]->discontinuity_enrich()) { + double nodal_mass = + nodes_[i]->mass(phase) + + sgn(levelset_phi_) * + nodes_[i]->discontinuity_property("mass_enrich", 1)(0, 0); + if (nodal_mass < tolerance) continue; + + vel = + (nodes_[i]->momentum(phase) + + sgn(levelset_phi_) * + nodes_[i]->discontinuity_property("momenta_enrich", 3).col(0)) / + nodal_mass; + } else { double nodal_mass = nodes_[i]->mass(phase); - if(nodal_mass < tolerance) - continue; - vel = nodes_[i]->momentum(phase)/nodal_mass; + if (nodal_mass < tolerance) continue; + vel = nodes_[i]->momentum(phase) / nodal_mass; } strain_rate[0] += dn_dx(i, 0) * vel[0]; @@ -693,13 +700,16 @@ void mpm::ParticleXMPM::compute_stress() noexcept { //! Map body force template -void mpm::ParticleXMPM::map_body_force(const VectorDim& pgravity) noexcept { +void mpm::ParticleXMPM::map_body_force( + const VectorDim& pgravity) noexcept { // Compute nodal body forces - for (unsigned i = 0; i < nodes_.size(); ++i){ + for (unsigned i = 0; i < nodes_.size(); ++i) { nodes_[i]->update_external_force(true, mpm::ParticlePhase::Solid, (pgravity * mass_ * shapefn_(i))); - if(nodes_[i]->discontinuity_enrich()) - nodes_[i]->update_discontinuity_property(true, "external_force_enrich", sgn(levelset_phi_)*pgravity * mass_ * shapefn_(i), 0,Tdim); + if (nodes_[i]->discontinuity_enrich()) + nodes_[i]->update_discontinuity_property( + true, "external_force_enrich", + sgn(levelset_phi_) * pgravity * mass_ * shapefn_(i), 0, Tdim); } } @@ -713,8 +723,9 @@ inline void mpm::ParticleXMPM<1>::map_internal_force() noexcept { force[0] = -1. * dn_dx_(i, 0) * volume_ * stress_[0]; nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Solid, force); - if(nodes_[i]->discontinuity_enrich()) - nodes_[i]->update_discontinuity_property(true, "internal_force_enrich", sgn(levelset_phi_)*force, 0,1); + if (nodes_[i]->discontinuity_enrich()) + nodes_[i]->update_discontinuity_property( + true, "internal_force_enrich", sgn(levelset_phi_) * force, 0, 1); } } @@ -731,8 +742,9 @@ inline void mpm::ParticleXMPM<2>::map_internal_force() noexcept { force *= -1. * this->volume_; nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Solid, force); - if(nodes_[i]->discontinuity_enrich()) - nodes_[i]->update_discontinuity_property(true, "internal_force_enrich", sgn(levelset_phi_)*force, 0,2); + if (nodes_[i]->discontinuity_enrich()) + nodes_[i]->update_discontinuity_property( + true, "internal_force_enrich", sgn(levelset_phi_) * force, 0, 2); } } @@ -755,8 +767,9 @@ inline void mpm::ParticleXMPM<3>::map_internal_force() noexcept { force *= -1. * this->volume_; nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Solid, force); - if(nodes_[i]->discontinuity_enrich()) - nodes_[i]->update_discontinuity_property(true, "internal_force_enrich", sgn(levelset_phi_)*force, 0,3); + if (nodes_[i]->discontinuity_enrich()) + nodes_[i]->update_discontinuity_property( + true, "internal_force_enrich", sgn(levelset_phi_) * force, 0, 3); } } @@ -771,7 +784,8 @@ bool mpm::ParticleXMPM::assign_velocity( // Assign traction to the particle template -bool mpm::ParticleXMPM::assign_traction(unsigned direction, double traction) { +bool mpm::ParticleXMPM::assign_traction(unsigned direction, + double traction) { bool status = false; try { if (direction >= Tdim || @@ -812,24 +826,23 @@ void mpm::ParticleXMPM::compute_updated_position( Eigen::Matrix::Zero(); const double tolerance = 1.E-16; unsigned int phase = mpm::ParticlePhase::Solid; - for (unsigned i = 0; i < nodes_.size(); ++i) - { - if(nodes_[i]->discontinuity_enrich()) - { - double nodal_mass = nodes_[i]->mass(phase) + sgn(levelset_phi_)*nodes_[i]->discontinuity_property("mass_enrich",1)(0,0); - if (nodal_mass < tolerance) - continue; - - nodal_velocity += shapefn_[i] * - (nodes_[i]->momentum(phase) + sgn(levelset_phi_) * nodes_[i]->discontinuity_property("momenta_enrich",3))/nodal_mass; - } - else - { + for (unsigned i = 0; i < nodes_.size(); ++i) { + if (nodes_[i]->discontinuity_enrich()) { + double nodal_mass = + nodes_[i]->mass(phase) + + sgn(levelset_phi_) * + nodes_[i]->discontinuity_property("mass_enrich", 1)(0, 0); + if (nodal_mass < tolerance) continue; + + nodal_velocity += shapefn_[i] * + (nodes_[i]->momentum(phase) + + sgn(levelset_phi_) * nodes_[i]->discontinuity_property( + "momenta_enrich", 3)) / + nodal_mass; + } else { double nodal_mass = nodes_[i]->mass(phase); - if (nodal_mass < tolerance) - continue; - nodal_velocity += - shapefn_[i] * nodes_[i]->momentum(phase)/nodal_mass; + if (nodal_mass < tolerance) continue; + nodal_velocity += shapefn_[i] * nodes_[i]->momentum(phase) / nodal_mass; } } // Acceleration update @@ -837,29 +850,30 @@ void mpm::ParticleXMPM::compute_updated_position( // Get interpolated nodal acceleration Eigen::Matrix nodal_acceleration = Eigen::Matrix::Zero(); - for (unsigned i = 0; i < nodes_.size(); ++i) - { - if(nodes_[i]->discontinuity_enrich()) - { - double nodal_mass = nodes_[i]->mass(phase) + sgn(levelset_phi_)*nodes_[i]->discontinuity_property("mass_enrich",1)(0,0); - if (nodal_mass < tolerance) - continue; - - auto force = nodes_[i]->internal_force(phase) + sgn(levelset_phi_) * nodes_[i]->discontinuity_property("internal_force_enrich",3) + - nodes_[i]->external_force(phase) + sgn(levelset_phi_) * nodes_[i]->discontinuity_property("external_force_enrich",3); - - nodal_acceleration += shapefn_[i] * force / nodal_mass; - } - else - { + for (unsigned i = 0; i < nodes_.size(); ++i) { + if (nodes_[i]->discontinuity_enrich()) { + double nodal_mass = + nodes_[i]->mass(phase) + + sgn(levelset_phi_) * + nodes_[i]->discontinuity_property("mass_enrich", 1)(0, 0); + if (nodal_mass < tolerance) continue; + + auto force = nodes_[i]->internal_force(phase) + + sgn(levelset_phi_) * nodes_[i]->discontinuity_property( + "internal_force_enrich", 3) + + nodes_[i]->external_force(phase) + + sgn(levelset_phi_) * nodes_[i]->discontinuity_property( + "external_force_enrich", 3); + + nodal_acceleration += shapefn_[i] * force / nodal_mass; + } else { double nodal_mass = nodes_[i]->mass(phase); - if (nodal_mass < tolerance) - continue; + if (nodal_mass < tolerance) continue; - auto force = nodes_[i]->internal_force(phase) + nodes_[i]->external_force(phase); + auto force = + nodes_[i]->internal_force(phase) + nodes_[i]->external_force(phase); - nodal_acceleration += - shapefn_[i] * force / nodal_mass; + nodal_acceleration += shapefn_[i] * force / nodal_mass; } } @@ -899,7 +913,8 @@ bool mpm::ParticleXMPM::map_pressure_to_nodes(unsigned phase) noexcept { // Compute pressure smoothing of the particle based on nodal pressure template -bool mpm::ParticleXMPM::compute_pressure_smoothing(unsigned phase) noexcept { +bool mpm::ParticleXMPM::compute_pressure_smoothing( + unsigned phase) noexcept { // Assert assert(cell_ != nullptr); @@ -921,15 +936,16 @@ bool mpm::ParticleXMPM::compute_pressure_smoothing(unsigned phase) noexcep //! Apply particle velocity constraints template -void mpm::ParticleXMPM::apply_particle_velocity_constraints(unsigned dir, - double velocity) { +void mpm::ParticleXMPM::apply_particle_velocity_constraints( + unsigned dir, double velocity) { // Set particle velocity constraint this->velocity_(dir) = velocity; } //! Return particle tensor data template -Eigen::VectorXd mpm::ParticleXMPM::tensor_data(const std::string& property) { +Eigen::VectorXd mpm::ParticleXMPM::tensor_data( + const std::string& property) { return this->properties_.at(property)(); } diff --git a/include/solvers/xmpm_explicit.h b/include/solvers/xmpm_explicit.h index edf588aad..b26e35855 100644 --- a/include/solvers/xmpm_explicit.h +++ b/include/solvers/xmpm_explicit.h @@ -5,8 +5,8 @@ #include "graph.h" #endif -#include "mpm_base.h" #include "discontinuity_base.h" +#include "mpm_base.h" namespace mpm { @@ -27,12 +27,13 @@ class XMPMExplicit : public MPMBase { //! \param[in] phase Phase to smooth pressure void compute_stress_strain(unsigned phase); - //! Initialise discontinuities + //! Initialise discontinuities bool initialise_discontinuities(); //! Initialise the level set function values bool initialise_levelset(); - //return the number of discontinuities - mpm::Index ndiscontinuities(){return discontinuities_.size();}; + // return the number of discontinuities + mpm::Index ndiscontinuities() { return discontinuities_.size(); }; + protected: // Generate a unique id for the analysis using mpm::MPMBase::uuid_; @@ -85,7 +86,8 @@ class XMPMExplicit : public MPMBase { //! discontinuities statue bool discontinuity_{false}; //! discontinuities - std::map>> discontinuities_; + std::map>> + discontinuities_; }; // XMPMExplicit class } // namespace mpm diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index 9462efd4a..ca84efc93 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -80,7 +80,7 @@ bool mpm::XMPMExplicit::solve() { status = false; throw std::runtime_error("Initialisation of particles failed"); } - + // Initialise loading conditions bool loading_status = this->initialise_loads(); if (!loading_status) { @@ -91,24 +91,24 @@ bool mpm::XMPMExplicit::solve() { // Create nodal properties if (interface_) mesh_->create_nodal_properties(); - // Initialise discontinuity + // Initialise discontinuity bool discontinuity_status = this->initialise_discontinuities(); if (!discontinuity_status) { status = false; throw std::runtime_error("Initialisation of discontinuities failed"); } - //Initialise the levelset values for particles - if (discontinuity_){ + // Initialise the levelset values for particles + if (discontinuity_) { bool initialise_lsm_status = this->initialise_levelset(); if (!initialise_lsm_status) { status = false; throw std::runtime_error("Initialisation of level set values failed"); - } + } } // Create nodal properties for discontinuity - if (discontinuity_) mesh_->create_nodal_properties_discontinuity(); + if (discontinuity_) mesh_->create_nodal_properties_discontinuity(); // Compute mass mesh_->iterate_over_particles( std::bind(&mpm::ParticleBase::compute_mass, std::placeholders::_1)); @@ -159,10 +159,10 @@ bool mpm::XMPMExplicit::solve() { } // Wait to complete // Initialise nodal properties - if (interface_ || discontinuity_) + if (interface_ || discontinuity_) // Initialise nodal properties mesh_->initialise_nodal_properties(); - //append material ids to node + // append material ids to node if (interface_) { // Append material ids to nodes mesh_->iterate_over_particles( @@ -286,7 +286,7 @@ bool mpm::XMPMExplicit::solve() { } #endif - //intergrate momentum Iterate over + // intergrate momentum Iterate over mesh_->iterate_over_nodes_predicate( std::bind(&mpm::NodeBase::intergrate_momentum_discontinuity, std::placeholders::_1, phase, this->dt_), @@ -349,11 +349,10 @@ template bool mpm::XMPMExplicit::initialise_discontinuities() { bool status = true; try { - // Get discontinuities data + // Get discontinuities data try { - auto json_discontinuities = io_->json_object("discontinuity"); - if(!json_discontinuities.empty()) - { + auto json_discontinuities = io_->json_object("discontinuity"); + if (!json_discontinuities.empty()) { discontinuity_ = true; for (const auto discontinuity_props : json_discontinuities) { // Get discontinuity type @@ -361,33 +360,40 @@ bool mpm::XMPMExplicit::initialise_discontinuities() { discontinuity_props["type"].template get(); // Get discontinuity id - auto discontinuity_id = discontinuity_props["id"].template get(); + auto discontinuity_id = + discontinuity_props["id"].template get(); - // Get discontinuity input type - auto io_type = discontinuity_props["io_type"].template get(); + // Get discontinuity input type + auto io_type = + discontinuity_props["io_type"].template get(); // discontinuity file - std::string discontinuity_file = - io_->file_name(discontinuity_props["file"].template get()); + std::string discontinuity_file = io_->file_name( + discontinuity_props["file"].template get()); - auto discontinuity_frictional_coef = discontinuity_props["frictional_coefficient"].template get(); + auto discontinuity_frictional_coef = + discontinuity_props["frictional_coefficient"] + .template get(); + + // Create a mesh reader + auto discontunity_io = + Factory>::instance()->create(io_type); - // Create a mesh reader - auto discontunity_io = Factory>::instance()->create(io_type); - // Create a new discontinuity surface from JSON object auto discontinuity = - Factory>::instance() - ->create(discontunity_type); + Factory>::instance()->create( + discontunity_type); - bool status = - discontinuity->initialize(discontunity_io->read_mesh_nodes(discontinuity_file),discontunity_io->read_mesh_cells(discontinuity_file)); + bool status = discontinuity->initialize( + discontunity_io->read_mesh_nodes(discontinuity_file), + discontunity_io->read_mesh_cells(discontinuity_file)); discontinuity->set_frictional_coef(discontinuity_frictional_coef); // Create points from file - + // Add discontinuity to list - auto result = discontinuities_.insert(std::make_pair(discontinuity_id, discontinuity)); + auto result = discontinuities_.insert( + std::make_pair(discontinuity_id, discontinuity)); // If insert discontinuity failed if (!result.second) { @@ -396,13 +402,14 @@ bool mpm::XMPMExplicit::initialise_discontinuities() { "New discontinuity cannot be added, insertion failed"); } } - } - }catch (std::exception& exception) { - console_->warn("{} #{}: No discontinuity is defined", __FILE__, - __LINE__, exception.what()); + } + } catch (std::exception& exception) { + console_->warn("{} #{}: No discontinuity is defined", __FILE__, __LINE__, + exception.what()); } - }catch (std::exception& exception) { - console_->error("#{}: Reading discontinuities: {}", __LINE__, exception.what()); + } catch (std::exception& exception) { + console_->error("#{}: Reading discontinuities: {}", __LINE__, + exception.what()); status = false; } return status; @@ -416,22 +423,24 @@ bool mpm::XMPMExplicit::initialise_levelset() { try { - for(mpm::Index i=0; i phi_list(mesh_->nparticles()); - discontinuities_[i]->compute_levelset(mesh_->particle_coordinates(), phi_list); + discontinuities_[i]->compute_levelset(mesh_->particle_coordinates(), + phi_list); - mesh_->assign_particle_levelset(phi_list); + mesh_->assign_particle_levelset(phi_list); } } catch (std::exception& exception) { - console_->error("#{}: XMPM initialise particles levelset values: {}", __LINE__, - exception.what()); + console_->error("#{}: XMPM initialise particles levelset values: {}", + __LINE__, exception.what()); status = false; } - if (!status) throw std::runtime_error("Initialisation of particles LSM values failed"); - + if (!status) + throw std::runtime_error("Initialisation of particles LSM values failed"); + return status; } \ No newline at end of file diff --git a/include/xmpm/discontinuity_3d.h b/include/xmpm/discontinuity_3d.h old mode 100755 new mode 100644 index 2ebb13e0c..73e7b1553 --- a/include/xmpm/discontinuity_3d.h +++ b/include/xmpm/discontinuity_3d.h @@ -10,67 +10,69 @@ template class Discontinuity_3D : public DiscontinuityBase { public: - //! Define a vector of size dimension + //! Define a vector of size dimension using VectorDim = Eigen::Matrix; - //constructor + // constructor Discontinuity_3D(); - //initialization - virtual bool initialize(const std::vector& coordinates,const std::vector>& pointsets) - { + // initialization + virtual bool initialize( + const std::vector& coordinates, + const std::vector>& pointsets) { bool status = true; - // Create points from file + // Create points from file bool point_status = this->create_points(coordinates); if (!point_status) { status = false; - throw std::runtime_error("Addition of points in discontinuity to mesh failed"); + throw std::runtime_error( + "Addition of points in discontinuity to mesh failed"); } - // Create elements from file - bool element_status = create_elements(pointsets); + // Create elements from file + bool element_status = create_elements(pointsets); if (!element_status) { status = false; - throw std::runtime_error("Addition of elements in discontinuity to mesh failed"); + throw std::runtime_error( + "Addition of elements in discontinuity to mesh failed"); } - bool normal_status = initialize_center_normal(); + bool normal_status = initialize_center_normal(); if (!normal_status) { status = false; - throw std::runtime_error("initialized the center and normal of the discontunity failed"); + throw std::runtime_error( + "initialized the center and normal of the discontunity failed"); } return status; }; //! create elements from file - virtual bool create_elements(const std::vector>& elements) override; + virtual bool create_elements( + const std::vector>& elements) override; - //initialize the center and normal of the triangular elements + // initialize the center and normal of the triangular elements bool initialize_center_normal(); // return the cross product of ab and bc - VectorDim ThreeCross(const VectorDim& a,const VectorDim& b,const VectorDim& c); + VectorDim ThreeCross(const VectorDim& a, const VectorDim& b, + const VectorDim& c); - - //return the levelset values of each doordinates + // return the levelset values of each doordinates //! \param[in] the vector of the coordinates - virtual void compute_levelset(const std::vector& coordinates, std::vector& phi_list) override; - + virtual void compute_levelset(const std::vector& coordinates, + std::vector& phi_list) override; protected: - using mpm::DiscontinuityBase::points_; using mpm::DiscontinuityBase::console_; using mpm::DiscontinuityBase::numpoint_; - private: - - //vector of elements + private: + // vector of elements std::vector elements_; - //number of elements + // number of elements mpm::Index numelement_; - }; } // namespace mpm diff --git a/include/xmpm/discontinuity_3d.tcc b/include/xmpm/discontinuity_3d.tcc old mode 100755 new mode 100644 index 23afaa359..d86f1ccae --- a/include/xmpm/discontinuity_3d.tcc +++ b/include/xmpm/discontinuity_3d.tcc @@ -1,99 +1,104 @@ template -mpm::Discontinuity_3D::Discontinuity_3D() -{ +mpm::Discontinuity_3D::Discontinuity_3D() { numelement_ = 0; - - std::string logger = - "discontinuity" + std::to_string(Tdim) + "d"; + + std::string logger = "discontinuity" + std::to_string(Tdim) + "d"; console_ = std::make_unique(logger, mpm::stdout_sink); } //! create elements from file template -bool mpm::Discontinuity_3D::create_elements(const std::vector>& elements) - { - - bool status = true; - try { - // Check if elements is empty - if (elements.empty()) - throw std::runtime_error("List of elements is empty"); - // Iterate over all elements - for (const auto& points : elements) { - - mpm::discontinuous_element element(points); - - elements_.emplace_back(element); // - } - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; +bool mpm::Discontinuity_3D::create_elements( + const std::vector>& elements) { + + bool status = true; + try { + // Check if elements is empty + if (elements.empty()) throw std::runtime_error("List of elements is empty"); + // Iterate over all elements + for (const auto& points : elements) { + + mpm::discontinuous_element element(points); + + elements_.emplace_back(element); // } - return status; + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; } + return status; +} + +// initialize the center and normal of the elements +template +bool mpm::Discontinuity_3D::initialize_center_normal() { + bool status = true; + try { + VectorDim center; + VectorDim normal; + Eigen::Matrix points; - //initialize the center and normal of the elements - template - bool mpm::Discontinuity_3D::initialize_center_normal() - { - bool status = true; - try { - VectorDim center; - VectorDim normal; - Eigen::Matrix points; - - for(auto& element : elements_) - { - points = element.points(); - - //the center of the element - for(int i=0; i<3; i++) - center[i] = 1.0/3*(points_[points[0]].coordinates()[i] + points_[points[1]].coordinates()[i] +points_[points[2]].coordinates()[i]); - - element.set_center(center); - - //the normal of the element - normal = ThreeCross(points_[points[0]].coordinates(),points_[points[1]].coordinates(),points_[points[2]].coordinates()); - double det = std::sqrt(normal[0]*normal[0] + normal[1]*normal[1] + normal[2]*normal[2]); - normal = 1.0/det * normal; - - element.set_normal(normal); - } - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; + for (auto& element : elements_) { + points = element.points(); + + // the center of the element + for (int i = 0; i < 3; i++) + center[i] = 1.0 / 3 * + (points_[points[0]].coordinates()[i] + + points_[points[1]].coordinates()[i] + + points_[points[2]].coordinates()[i]); + + element.set_center(center); + + // the normal of the element + normal = ThreeCross(points_[points[0]].coordinates(), + points_[points[1]].coordinates(), + points_[points[2]].coordinates()); + double det = std::sqrt(normal[0] * normal[0] + normal[1] * normal[1] + + normal[2] * normal[2]); + normal = 1.0 / det * normal; + + element.set_normal(normal); } - return status; + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; } + return status; +} -//return the cross product of ab X bc +// return the cross product of ab X bc template -Eigen::Matrix mpm::Discontinuity_3D::ThreeCross(const VectorDim& a,const VectorDim& b,const VectorDim& c){ - - VectorDim threecross; - threecross[0]=(b[1]-a[1])*(c[2]-b[2])-(b[2]-a[2])*(c[1]-b[1]); - threecross[1]=(b[2]-a[2])*(c[0]-b[0])-(b[0]-a[0])*(c[2]-b[2]); - threecross[2]=(b[0]-a[0])*(c[1]-b[1])-(b[1]-a[1])*(c[0]-b[0]); - return threecross; +Eigen::Matrix mpm::Discontinuity_3D::ThreeCross( + const VectorDim& a, const VectorDim& b, const VectorDim& c) { + + VectorDim threecross; + threecross[0] = (b[1] - a[1]) * (c[2] - b[2]) - (b[2] - a[2]) * (c[1] - b[1]); + threecross[1] = (b[2] - a[2]) * (c[0] - b[0]) - (b[0] - a[0]) * (c[2] - b[2]); + threecross[2] = (b[0] - a[0]) * (c[1] - b[1]) - (b[1] - a[1]) * (c[0] - b[0]); + return threecross; } -//return the levelset values of each doordinates +// return the levelset values of each doordinates //! \param[in] the vector of the coordinates template -void mpm::Discontinuity_3D::compute_levelset(const std::vector& coordinates,std::vector& phi_list){ +void mpm::Discontinuity_3D::compute_levelset( + const std::vector& coordinates, std::vector& phi_list) { mpm::Index i = 0; - for(const auto& coor:coordinates) - { - //find the nearest distance from particle to cell: need to do by global searching and local searching + for (const auto& coor : coordinates) { + // find the nearest distance from particle to cell: need to do by global + // searching and local searching double distance = std::numeric_limits::max(); - for(const auto& element:elements_) - { - double Vertical_distance_ = element.Vertical_distance(coor);// Vertical_distance(coor); - distance = std::abs(distance) < std::abs(Vertical_distance_)? distance:Vertical_distance_; - if(!distance) distance = 1e-16; + for (const auto& element : elements_) { + double Vertical_distance_ = + element.Vertical_distance(coor); // Vertical_distance(coor); + distance = std::abs(distance) < std::abs(Vertical_distance_) + ? distance + : Vertical_distance_; + if (!distance) distance = 1e-16; } - + phi_list[i] = distance; ++i; } diff --git a/include/xmpm/discontinuity_base.h b/include/xmpm/discontinuity_base.h old mode 100755 new mode 100644 index 8be308b64..a6ceb01d3 --- a/include/xmpm/discontinuity_base.h +++ b/include/xmpm/discontinuity_base.h @@ -1,44 +1,34 @@ #ifndef MPM_DISCONTINUITY_H_ #define MPM_DISCONTINUITY_H_ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "vector.h" + +#include "logger.h" + +#include "data_types.h" namespace mpm { template -struct discontinuous_point -{ - public: - //! Define a vector of size dimension - using VectorDim = Eigen::Matrix; - - discontinuous_point(const VectorDim& coordinate) - { - coordinates_ = coordinate; - } +struct discontinuous_point { + public: + //! Define a vector of size dimension + using VectorDim = Eigen::Matrix; + discontinuous_point(const VectorDim& coordinate) { + coordinates_ = coordinate; + } //! Return coordinates //! \retval coordinates_ return coordinates of the nodebase - VectorDim coordinates() const { return coordinates_; } - - private: + VectorDim coordinates() const { return coordinates_; } - //! point coordinates - VectorDim coordinates_; + private: + //! point coordinates + VectorDim coordinates_; }; //! class for to describe the discontinuous surface -//! \brief +//! \brief //! \details nodes, lines and areas //! \tparam Tdim Dimension template @@ -59,127 +49,123 @@ class DiscontinuityBase { //! Delete assignement operator DiscontinuityBase& operator=(const DiscontinuityBase&) = delete; - //initialization - virtual bool initialize(const std::vector& coordinates,const std::vector>& pointsets) = 0; + // initialization + virtual bool initialize( + const std::vector& coordinates, + const std::vector>& pointsets) = 0; //! create points from file bool create_points(const std::vector& coordinates); //! create elements from file - virtual bool create_elements(const std::vector>& elements) {return true;}; + virtual bool create_elements( + const std::vector>& elements) { + return true; + }; - //return the levelset values of each doordinates + // return the levelset values of each doordinates //! \param[in] the vector of the coordinates - virtual void compute_levelset(const std::vector& coordinates, std::vector& phi_list) = 0; - - bool self_contact(){return self_contact_;}; + virtual void compute_levelset(const std::vector& coordinates, + std::vector& phi_list) = 0; - void set_frictional_coef(double coef) {frictional_coef_ = coef;}; + bool self_contact() { return self_contact_; }; - double frictional_coef(){return frictional_coef_;}; + void set_frictional_coef(double coef) { frictional_coef_ = coef; }; + double frictional_coef() { return frictional_coef_; }; - protected: - + protected: std::vector> points_; - //number of points + // number of points mpm::Index numpoint_; //! Logger std::unique_ptr console_; - //self-contact - bool self_contact_{true}; + // self-contact + bool self_contact_{true}; double frictional_coef_; }; // DiscontinuityBase class -struct discontinuous_line -{ - public: - - //! Return points indices - Eigen::Matrix points() const {return points_;}; - - private: - - //! points index of the line - Eigen::Matrix points_; +struct discontinuous_line { + public: + //! Return points indices + Eigen::Matrix points() const { return points_; }; + private: + //! points index of the line + Eigen::Matrix points_; }; -struct discontinuous_element -{ - public: - //! Define a vector of size dimension - using VectorDim = Eigen::Matrix; +struct discontinuous_element { + public: + //! Define a vector of size dimension + using VectorDim = Eigen::Matrix; - discontinuous_element(const std::vector& points) - { - for(int i=0; i<3; ++i) - points_[i] = points[i]; - } - //! Return points indices - Eigen::Matrix points() const { return points_;} + discontinuous_element(const std::vector& points) { + for (int i = 0; i < 3; ++i) points_[i] = points[i]; + } + //! Return points indices + Eigen::Matrix points() const { return points_; } - inline void set_center(VectorDim & center) {center_ = center; } - - inline void set_normal(VectorDim & normal) {normal_ = normal; } + inline void set_center(VectorDim& center) { center_ = center; } - double Vertical_distance (const VectorDim & coor) const {return (coor[0]-center_[0])*normal_[0]+(coor[1]-center_[1])*normal_[1]+(coor[2]-center_[2])*normal_[2];}; + inline void set_normal(VectorDim& normal) { normal_ = normal; } - private: - //! points indices - Eigen::Matrix points_; + double Vertical_distance(const VectorDim& coor) const { + return (coor[0] - center_[0]) * normal_[0] + + (coor[1] - center_[1]) * normal_[1] + + (coor[2] - center_[2]) * normal_[2]; + }; - //the center of the triangular elements - VectorDim center_; + private: + //! points indices + Eigen::Matrix points_; - //the normal of the triangular elements - VectorDim normal_; - -}; + // the center of the triangular elements + VectorDim center_; + // the normal of the triangular elements + VectorDim normal_; +}; } // namespace mpm template -mpm::DiscontinuityBase::DiscontinuityBase() -{ +mpm::DiscontinuityBase::DiscontinuityBase() { numpoint_ = 0; frictional_coef_ = -1; - - std::string logger = - "discontinuitybase"; + + std::string logger = "discontinuitybase"; console_ = std::make_unique(logger, mpm::stdout_sink); } //! create points from file template -bool mpm::DiscontinuityBase::create_points(const std::vector& coordinates) - { - bool status = true; - try { - // Check if point coordinates is empty - if (coordinates.empty()) - throw std::runtime_error("List of coordinates is empty"); - // Iterate over all coordinates - for (const auto& point_coordinates : coordinates) { - - // Add point - mpm::discontinuous_point point(point_coordinates); - - points_.emplace_back(point); // - } - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; +bool mpm::DiscontinuityBase::create_points( + const std::vector& coordinates) { + bool status = true; + try { + // Check if point coordinates is empty + if (coordinates.empty()) + throw std::runtime_error("List of coordinates is empty"); + // Iterate over all coordinates + for (const auto& point_coordinates : coordinates) { + + // Add point + mpm::discontinuous_point point(point_coordinates); + + points_.emplace_back(point); // } - return status; - + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; } + return status; +} #endif // MPM_DiscontinuityBase_H_ diff --git a/src/discontinuity.cc b/src/discontinuity.cc old mode 100755 new mode 100644 index 2c9d245bc..11c2fd421 --- a/src/discontinuity.cc +++ b/src/discontinuity.cc @@ -1,6 +1,7 @@ +#include "discontinuity_3d.h" #include "discontinuity_base.h" #include "factory.h" -#include "discontinuity_3d.h" // Triangle 3-noded element -static Register, mpm::Discontinuity_3D<3>> tri3d("tri3d"); +static Register, mpm::Discontinuity_3D<3>> tri3d( + "tri3d"); From 32b51bbf4284cf0cc8f38a8994fc510c8fbc00ec Mon Sep 17 00:00:00 2001 From: yong liang Date: Sat, 15 Aug 2020 16:50:21 -0700 Subject: [PATCH 13/91] :constructor:discontinuity function --- include/mesh.h | 24 +++ include/mesh.tcc | 50 ++++++- include/node.h | 13 +- include/node.tcc | 1 + include/node_base.h | 10 ++ include/node_xmpm.tcc | 25 ++-- include/particles/particle_xmpm.tcc | 1 + include/solvers/mpm_base.tcc | 2 +- include/solvers/xmpm_explicit.tcc | 51 ++++--- include/xmpm/discontinuity_3d.h | 48 ++---- include/xmpm/discontinuity_3d.tcc | 91 ++++++++++-- include/xmpm/discontinuity_base.h | 140 ++++++++++++------ include/xmpm/discontinuity_base.tcc | 221 ++++++++++++++++++++++++++++ src/discontinuity.cc | 5 +- 14 files changed, 552 insertions(+), 130 deletions(-) create mode 100644 include/xmpm/discontinuity_base.tcc diff --git a/include/mesh.h b/include/mesh.h index 7226eefef..c67e4e74a 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -25,6 +25,7 @@ using Json = nlohmann::json; #include "cell.h" +#include "discontinuity_base.h" #include "factory.h" #include "friction_constraint.h" #include "function_base.h" @@ -453,6 +454,26 @@ class Mesh { // Create the nodal properties' map for discontinuity void create_nodal_properties_discontinuity(); + //! Initialise discontinuities + //! \param[in] discontinuities + void initialise_discontinuities( + const std::map>>& + discontinuities) { + discontinuities_ = discontinuities; + } + + //! Locate points of discontinuity in a cell + void locate_discontinuity_mesh(); + + // Update the discontinuity position + void compute_updated_position_discontinuity(double dt); + + // Update the discontinuity position + void compute_shapefn_discontinuity(); + + // compute the normal vector of enriched nodes at the discontinuity + void compute_normal_vector_discontinuity(); + private: // Read particles from file //! \param[in] pset_id Set ID of the particles @@ -521,6 +542,9 @@ class Mesh { unsigned nhalo_nodes_{0}; //! Maximum number of halo nodes unsigned ncomms_{0}; + //! discontinuities + std::map>> + discontinuities_; }; // Mesh class } // namespace mpm diff --git a/include/mesh.tcc b/include/mesh.tcc index 43091b138..00f7a4403 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1927,4 +1927,52 @@ template void mpm::Mesh::assign_particle_levelset(std::vector& phi_list) { for (mpm::Index i = 0; i < nparticles(); ++i) particles_[i]->assign_levelsetphi(phi_list[i]); -} \ No newline at end of file +} + +//! Locate points in a cell +template +void mpm::Mesh::locate_discontinuity_mesh() { + for (unsigned i = 0; i < discontinuities_.size(); ++i) { + auto discontinuity = discontinuities_[i]; + discontinuity->locate_discontinuity_mesh(cells_, map_cells_); + } +} +//! updated_position of discontinuity +template +void mpm::Mesh::compute_updated_position_discontinuity(double dt) { + for (unsigned i = 0; i < discontinuities_.size(); ++i) { + auto discontinuity = discontinuities_[i]; + discontinuity->compute_updated_position(dt); + } +} + +//! compute shape function +template +void mpm::Mesh::compute_shapefn_discontinuity() { + for (unsigned i = 0; i < discontinuities_.size(); ++i) { + auto discontinuity = discontinuities_[i]; + discontinuity->compute_shapefn(); + } +} + + // compute the normal vector of enriched nodes at the discontinuity +template +void mpm::Mesh::compute_normal_vector_discontinuity() { + //need to set + unsigned discontinuity_id = 0; + + auto discontinuity = discontinuities_[discontinuity_id]; + + VectorDim normal; + normal.setZero(); + +for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) + { + + discontinuity->compute_normal((*nitr)->coordinates(), + normal); + + nodal_properties_->assign_property("normal_unit_vectors_discontinuity", + (*nitr)->discontinuity_prop_id(), 0, normal, Tdim); + } +} diff --git a/include/node.h b/include/node.h index ce363cffb..f42f66e4e 100644 --- a/include/node.h +++ b/include/node.h @@ -274,6 +274,11 @@ class Node : public NodeBase { //! Compute multimaterial normal unit vector void compute_multimaterial_normal_unit_vector() override; + //! Assign whether the node is enriched + //! \param[in] discontinuity_enrich: true or false + void assign_discontinuity_enrich(bool discontinuity) { + discontinuity_enrich_ = discontinuity; + }; //! Return whether the node is enriched bool discontinuity_enrich() const { return discontinuity_enrich_; }; @@ -304,6 +309,12 @@ class Node : public NodeBase { //! \param[in] dt Time-step void self_contact_discontinuity(double dt) noexcept override; + //! Return the discontinuity_prop_id + virtual unsigned discontinuity_prop_id() const noexcept override{return discontinuity_prop_id_;}; + + //! Compute normal direction of each enrich node + void compute_normal_vector() noexcept override; + private: //! Mutex SpinMutex node_mutex_; @@ -363,7 +374,7 @@ class Node : public NodeBase { std::set mpi_ranks_; //! discontinuity enrich // need to be done - bool discontinuity_enrich_{true}; + bool discontinuity_enrich_{false}; }; // Node class } // namespace mpm diff --git a/include/node.tcc b/include/node.tcc index 7d3a9cfcb..d027a33e0 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -34,6 +34,7 @@ void mpm::Node::initialise() noexcept { acceleration_.setZero(); status_ = false; material_ids_.clear(); + discontinuity_enrich_ = false; } //! Initialise shared pointer to nodal properties pool diff --git a/include/node_base.h b/include/node_base.h index 134bbf8c6..194b337d0 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -269,6 +269,10 @@ class NodeBase { virtual Eigen::MatrixXd discontinuity_property( const std::string& property, unsigned nprops = 1) noexcept = 0; + //! Assign whether the node is enriched + //! \param[in] discontinuity_enrich: true or false + virtual void assign_discontinuity_enrich(bool discontinuity) = 0; + //! Return whether the node is enriched virtual bool discontinuity_enrich() const = 0; @@ -292,6 +296,12 @@ class NodeBase { //! Apply self-contact of the discontinuity //! \param[in] dt Time-step virtual void self_contact_discontinuity(double dt) noexcept = 0; + + //! Return the discontinuity_prop_id + virtual unsigned discontinuity_prop_id() const noexcept = 0; + + //! Compute normal direction of each enrich node + virtual void compute_normal_vector() noexcept = 0; }; // NodeBase class } // namespace mpm diff --git a/include/node_xmpm.tcc b/include/node_xmpm.tcc index 5649722d0..b5abd14b2 100644 --- a/include/node_xmpm.tcc +++ b/include/node_xmpm.tcc @@ -55,10 +55,10 @@ bool mpm::Node::intergrate_momentum_discontinuity( this->apply_velocity_constraints_discontinuity(); // need to be done - Eigen::Matrix normal{0.44721359474414313, 0, - 0.89442719147920724}; - property_handle_->assign_property("normal_unit_vectors_discontinuity", - discontinuity_prop_id_, 0, normal, Tdim); + //Eigen::Matrix normal{0.44721359474414313, 0, + // 0.89442719147920724}; + // property_handle_->assign_property("normal_unit_vectors_discontinuity", + // discontinuity_prop_id_, 0, normal, Tdim); this->self_contact_discontinuity(dt); @@ -164,11 +164,11 @@ void mpm::Node::self_contact_discontinuity( mass_(phase); auto force_contact = momentum_contact / dt; - //! frictional_coef < 0: move together without slide + //! friction_coef < 0: move together without slide // need to be done - double frictional_coef = 0; + double friction_coef = 0; - if (frictional_coef < 0) { + if (friction_coef < 0) { property_handle_->update_property("momenta_enrich", discontinuity_prop_id_, 0, momentum_contact.col(phase), Tdim); property_handle_->update_property("external_force_enrich", @@ -180,7 +180,7 @@ void mpm::Node::self_contact_discontinuity( double force_contact_norm = momentum_contact_norm / dt; // the maximum frictional contact force - double max_frictional_force = frictional_coef * abs(force_contact_norm); + double max_frictional_force = friction_coef * abs(force_contact_norm); auto momentum_tangential = momentum_contact.col(phase) - momentum_contact_norm * normal_vector; @@ -204,4 +204,11 @@ void mpm::Node::self_contact_discontinuity( frictional_force * force_tangential.col(phase).normalized(), Tdim); } -} \ No newline at end of file +} + + //! Compute normal direction of each enrich node + //! Apply velocity constraints +template +void mpm::Node::compute_normal_vector() noexcept { + + } \ No newline at end of file diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index ae203b350..e3ab0235f 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -251,6 +251,7 @@ void mpm::ParticleXMPM::initialise() { this->properties_["strains"] = [&]() { return strain(); }; this->properties_["velocities"] = [&]() { return velocity(); }; this->properties_["displacements"] = [&]() { return displacement(); }; + this->properties_["levelset"] = [&]() { VectorDim levelset{levelset_phi_,0,0};return levelset; }; } //! Initialise particle material container diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index 8426ccf4f..0c6d8bb49 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -506,7 +506,7 @@ 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","levelset"}; // Write VTK attributes for (const auto& attribute : vtk_vector_data) { diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index ca84efc93..4239f71f5 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -169,6 +169,19 @@ bool mpm::XMPMExplicit::solve() { std::bind(&mpm::ParticleBase::append_material_id_to_nodes, std::placeholders::_1)); } + if (discontinuity_) { + // locate points of discontinuity + mesh_->locate_discontinuity_mesh(); + // Iterate over each points to compute shapefn + mesh_->compute_shapefn_discontinuity(); + // obtain the normal direction of each enrich nodes + mesh_->compute_normal_vector_discontinuity(); + mesh_->iterate_over_nodes_predicate( + std::bind(&mpm::NodeBase::compute_normal_vector, + std::placeholders::_1), + std::bind(&mpm::NodeBase::discontinuity_enrich, std::placeholders::_1)); + } + // Assign mass and momentum to nodes mesh_->iterate_over_particles( @@ -303,6 +316,9 @@ bool mpm::XMPMExplicit::solve() { // Update Stress Last if (this->stress_update_ == mpm::StressUpdate::USL) this->compute_stress_strain(phase); + // Update the discontinuity position + if (discontinuity_) + mesh_->compute_updated_position_discontinuity(this->dt_); // Locate particles auto unlocatable_particles = mesh_->locate_particles_mesh(); @@ -363,34 +379,26 @@ bool mpm::XMPMExplicit::initialise_discontinuities() { auto discontinuity_id = discontinuity_props["id"].template get(); - // Get discontinuity input type + // Create a new discontinuity surface from JSON object + auto discontinuity = + Factory, unsigned, const Json&>::instance()->create( + discontunity_type, std::move(discontinuity_id), + discontinuity_props); + + // Get discontinuity input type auto io_type = discontinuity_props["io_type"].template get(); // discontinuity file - std::string discontinuity_file = io_->file_name( - discontinuity_props["file"].template get()); - - auto discontinuity_frictional_coef = - discontinuity_props["frictional_coefficient"] - .template get(); - + std::string discontinuity_file = + io_->file_name(discontinuity_props["file"].template get()); // Create a mesh reader auto discontunity_io = Factory>::instance()->create(io_type); - // Create a new discontinuity surface from JSON object - auto discontinuity = - Factory>::instance()->create( - discontunity_type); - - bool status = discontinuity->initialize( - discontunity_io->read_mesh_nodes(discontinuity_file), - discontunity_io->read_mesh_cells(discontinuity_file)); - - discontinuity->set_frictional_coef(discontinuity_frictional_coef); - // Create points from file - + // Create points and cells from file + discontinuity->initialize(discontunity_io->read_mesh_nodes(discontinuity_file), + discontunity_io->read_mesh_cells(discontinuity_file)); // Add discontinuity to list auto result = discontinuities_.insert( std::make_pair(discontinuity_id, discontinuity)); @@ -407,11 +415,14 @@ bool mpm::XMPMExplicit::initialise_discontinuities() { console_->warn("{} #{}: No discontinuity is defined", __FILE__, __LINE__, exception.what()); } + // Copy discontinuities to mesh + mesh_->initialise_discontinuities(this->discontinuities_); } catch (std::exception& exception) { console_->error("#{}: Reading discontinuities: {}", __LINE__, exception.what()); status = false; } + return status; } diff --git a/include/xmpm/discontinuity_3d.h b/include/xmpm/discontinuity_3d.h index 73e7b1553..793a35450 100644 --- a/include/xmpm/discontinuity_3d.h +++ b/include/xmpm/discontinuity_3d.h @@ -7,42 +7,20 @@ namespace mpm { template -class Discontinuity_3D : public DiscontinuityBase { +class Discontinuity3D : public DiscontinuityBase { public: //! Define a vector of size dimension using VectorDim = Eigen::Matrix; - // constructor - Discontinuity_3D(); + + //! Constructor with id + //! \param[in] discontinuity_properties discontinuity properties + Discontinuity3D(unsigned id, const Json& discontinuity_props); // initialization virtual bool initialize( const std::vector& coordinates, - const std::vector>& pointsets) { - bool status = true; - // Create points from file - bool point_status = this->create_points(coordinates); - if (!point_status) { - status = false; - throw std::runtime_error( - "Addition of points in discontinuity to mesh failed"); - } - // Create elements from file - bool element_status = create_elements(pointsets); - if (!element_status) { - status = false; - throw std::runtime_error( - "Addition of elements in discontinuity to mesh failed"); - } - - bool normal_status = initialize_center_normal(); - if (!normal_status) { - status = false; - throw std::runtime_error( - "initialized the center and normal of the discontunity failed"); - } - return status; - }; + const std::vector>& pointsets); //! create elements from file virtual bool create_elements( @@ -52,13 +30,17 @@ class Discontinuity_3D : public DiscontinuityBase { bool initialize_center_normal(); // return the cross product of ab and bc - VectorDim ThreeCross(const VectorDim& a, const VectorDim& b, + VectorDim three_cross_product(const VectorDim& a, const VectorDim& b, const VectorDim& c); // return the levelset values of each doordinates //! \param[in] the vector of the coordinates - virtual void compute_levelset(const std::vector& coordinates, + void compute_levelset(const std::vector& coordinates, std::vector& phi_list) override; + // return the normal vectors of given coordinates + //! \param[in] the coordinates + void compute_normal( + const VectorDim& coordinates, VectorDim& normal_vector) override; protected: using mpm::DiscontinuityBase::points_; @@ -67,11 +49,13 @@ class Discontinuity_3D : public DiscontinuityBase { using mpm::DiscontinuityBase::numpoint_; + using mpm::DiscontinuityBase::friction_coef_; + private: // vector of elements - std::vector elements_; + std::vector> elements_; - // number of elements + // number of elements //delete mpm::Index numelement_; }; diff --git a/include/xmpm/discontinuity_3d.tcc b/include/xmpm/discontinuity_3d.tcc index d86f1ccae..2f7479d4c 100644 --- a/include/xmpm/discontinuity_3d.tcc +++ b/include/xmpm/discontinuity_3d.tcc @@ -1,14 +1,55 @@ template -mpm::Discontinuity_3D::Discontinuity_3D() { - numelement_ = 0; +mpm::Discontinuity3D::Discontinuity3D(unsigned id, + const Json& discontinuity_props) + : DiscontinuityBase(id, discontinuity_props) { - std::string logger = "discontinuity" + std::to_string(Tdim) + "d"; - console_ = std::make_unique(logger, mpm::stdout_sink); + numelement_ = 0; + try { + // assign friction_coef_ if it's given in input file + if (discontinuity_props.contains("friction_coefficient")) + friction_coef_ = + discontinuity_props.at("friction_coefficient").template get(); + else + friction_coef_ = 0; + } catch (Json::exception& except) { + console_->error("discontinuity parameter not set: {} {}\n", except.what(), + except.id); + } } + // initialization + template + bool mpm::Discontinuity3D::initialize( + const std::vector& coordinates, + const std::vector>& pointsets) { + bool status = true; + // Create points from file + bool point_status = this->create_points(coordinates); + if (!point_status) { + status = false; + throw std::runtime_error( + "Addition of points in discontinuity to mesh failed"); + } + // Create elements from file + bool element_status = create_elements(pointsets); + if (!element_status) { + status = false; + throw std::runtime_error( + "Addition of elements in discontinuity to mesh failed"); + } + + bool normal_status = initialize_center_normal(); + if (!normal_status) { + status = false; + throw std::runtime_error( + "initialized the center and normal of the discontunity failed"); + } + return status; + }; + //! create elements from file template -bool mpm::Discontinuity_3D::create_elements( +bool mpm::Discontinuity3D::create_elements( const std::vector>& elements) { bool status = true; @@ -18,7 +59,7 @@ bool mpm::Discontinuity_3D::create_elements( // Iterate over all elements for (const auto& points : elements) { - mpm::discontinuous_element element(points); + mpm::discontinuous_element element(points); elements_.emplace_back(element); // } @@ -30,8 +71,8 @@ bool mpm::Discontinuity_3D::create_elements( } // initialize the center and normal of the elements -template -bool mpm::Discontinuity_3D::initialize_center_normal() { +template <> +bool mpm::Discontinuity3D<3>::initialize_center_normal() { bool status = true; try { VectorDim center; @@ -51,7 +92,7 @@ bool mpm::Discontinuity_3D::initialize_center_normal() { element.set_center(center); // the normal of the element - normal = ThreeCross(points_[points[0]].coordinates(), + normal = three_cross_product(points_[points[0]].coordinates(), points_[points[1]].coordinates(), points_[points[2]].coordinates()); double det = std::sqrt(normal[0] * normal[0] + normal[1] * normal[1] + @@ -69,7 +110,7 @@ bool mpm::Discontinuity_3D::initialize_center_normal() { // return the cross product of ab X bc template -Eigen::Matrix mpm::Discontinuity_3D::ThreeCross( +Eigen::Matrix mpm::Discontinuity3D::three_cross_product( const VectorDim& a, const VectorDim& b, const VectorDim& c) { VectorDim threecross; @@ -79,10 +120,10 @@ Eigen::Matrix mpm::Discontinuity_3D::ThreeCross( return threecross; } -// return the levelset values of each doordinates +// return the levelset values of each coordinates //! \param[in] the vector of the coordinates template -void mpm::Discontinuity_3D::compute_levelset( +void mpm::Discontinuity3D::compute_levelset( const std::vector& coordinates, std::vector& phi_list) { mpm::Index i = 0; @@ -91,15 +132,35 @@ void mpm::Discontinuity_3D::compute_levelset( // searching and local searching double distance = std::numeric_limits::max(); for (const auto& element : elements_) { - double Vertical_distance_ = + double Vertical_distance = element.Vertical_distance(coor); // Vertical_distance(coor); - distance = std::abs(distance) < std::abs(Vertical_distance_) + distance = std::abs(distance) < std::abs(Vertical_distance) ? distance - : Vertical_distance_; + : Vertical_distance; if (!distance) distance = 1e-16; + distance = 1; } phi_list[i] = distance; ++i; } +} + +// return the normal vectors of given coordinates +//! \param[in] the coordinates +template +void mpm::Discontinuity3D::compute_normal( + const VectorDim& coordinates, VectorDim& normal_vector) { + // find the nearest distance from particle to cell: need to do by global + // searching and local searching + double distance = std::numeric_limits::max(); + for (const auto& element : elements_) { + double Vertical_distance = + element.Vertical_distance(coordinates); // Vertical_distance(coor); + if(std::abs(distance) > std::abs(Vertical_distance)) + { + distance = Vertical_distance; + normal_vector = element.normal(); + } + } } \ No newline at end of file diff --git a/include/xmpm/discontinuity_base.h b/include/xmpm/discontinuity_base.h index a6ceb01d3..0e83fb81b 100644 --- a/include/xmpm/discontinuity_base.h +++ b/include/xmpm/discontinuity_base.h @@ -1,30 +1,78 @@ #ifndef MPM_DISCONTINUITY_H_ #define MPM_DISCONTINUITY_H_ - -#include "logger.h" - +#include "cell.h" #include "data_types.h" +#include "io_mesh.h" +#include "logger.h" +#include "memory.h" +#include "node_base.h" +#include "vector.h" namespace mpm { template -struct discontinuous_point { +struct discontinuity_point { public: //! Define a vector of size dimension using VectorDim = Eigen::Matrix; - discontinuous_point(const VectorDim& coordinate) { + discontinuity_point(const VectorDim& coordinate) { coordinates_ = coordinate; + cell_ = nullptr; + //! Logger + console_ = spdlog::get("discontinuity_point"); } //! Return coordinates //! \retval coordinates_ return coordinates of the nodebase VectorDim coordinates() const { return coordinates_; } + //! Return cell_id + Index cell_id() const { return cell_id_; } + + //! Assign a cell to point + //! \param[in] cellptr Pointer to a cell + //! \param[in] xi Local coordinates of the point in reference cell + bool assign_cell_xi(const std::shared_ptr>& cellptr, + const Eigen::Matrix& xi); + + //! Return cell ptr status + bool cell_ptr() const { return cell_ != nullptr; } + + //! Assign a cell to point + //! \param[in] cellptr Pointer to a cell + bool assign_cell(const std::shared_ptr>& cellptr); + + //! Compute reference coordinates in a cell + bool compute_reference_location() noexcept; + + //! Locate points in a cell + void locate_discontinuity_mesh(Vector>& cells, + Map>& map_cells) noexcept; + + //! Compute updated position + void compute_updated_position(double dt) noexcept; + + //! Compute shape function + void compute_shapefn() noexcept; + private: //! point coordinates VectorDim coordinates_; + //! Cell id + Index cell_id_{std::numeric_limits::max()}; + //! Shape functions + Eigen::VectorXd shapefn_; + //! Cell + std::shared_ptr> cell_; + + //! Reference coordinates (in a cell) + Eigen::Matrix xi_; + //! Vector of nodal pointers + std::vector>> nodes_; + //! Logger + std::shared_ptr console_; }; //! class for to describe the discontinuous surface @@ -37,8 +85,9 @@ class DiscontinuityBase { //! Define a vector of size dimension using VectorDim = Eigen::Matrix; - // Constructor - DiscontinuityBase(); + //! Constructor with id + //! \param[in] discontinuity_properties discontinuity properties + DiscontinuityBase(unsigned id, const Json& discontinuity_props); //! Destructor virtual ~DiscontinuityBase(){}; @@ -68,25 +117,46 @@ class DiscontinuityBase { virtual void compute_levelset(const std::vector& coordinates, std::vector& phi_list) = 0; + // return the normal vectors of given coordinates +//! \param[in] the coordinates +virtual void compute_normal( + const VectorDim& coordinates, VectorDim& normal_vector) = 0; + + // return self_contact bool self_contact() { return self_contact_; }; - void set_frictional_coef(double coef) { frictional_coef_ = coef; }; + // return the friction coefficient + double friction_coef() { return friction_coef_; }; - double frictional_coef() { return frictional_coef_; }; + // return the number of the points + mpm::Index npoints() { return points_.size(); }; - protected: - std::vector> points_; + void points_list(std::vector>& points) { + points = points_; + } + //! Locate points in a cell + void locate_discontinuity_mesh(Vector>& cells, + Map>& map_cells) noexcept; - // number of points - mpm::Index numpoint_; + //! Compute updated position + void compute_updated_position(double dt) noexcept; + //! Compute shape function + void compute_shapefn() noexcept; + + protected: //! Logger std::unique_ptr console_; + std::vector> points_; + + // number of points + mpm::Index numpoint_; //delete + // self-contact bool self_contact_{true}; - double frictional_coef_; + double friction_coef_; }; // DiscontinuityBase class @@ -100,13 +170,14 @@ struct discontinuous_line { Eigen::Matrix points_; }; +template struct discontinuous_element { public: //! Define a vector of size dimension - using VectorDim = Eigen::Matrix; + using VectorDim = Eigen::Matrix; discontinuous_element(const std::vector& points) { - for (int i = 0; i < 3; ++i) points_[i] = points[i]; + for (int i = 0; i < points.size(); ++i) points_[i] = points[i]; } //! Return points indices Eigen::Matrix points() const { return points_; } @@ -114,6 +185,9 @@ struct discontinuous_element { inline void set_center(VectorDim& center) { center_ = center; } inline void set_normal(VectorDim& normal) { normal_ = normal; } + + //! Reture normal of the elements + VectorDim normal() const {return normal_;} double Vertical_distance(const VectorDim& coor) const { return (coor[0] - center_[0]) * normal_[0] + @@ -134,38 +208,6 @@ struct discontinuous_element { } // namespace mpm -template -mpm::DiscontinuityBase::DiscontinuityBase() { - numpoint_ = 0; - - frictional_coef_ = -1; - - std::string logger = "discontinuitybase"; - console_ = std::make_unique(logger, mpm::stdout_sink); -} - -//! create points from file -template -bool mpm::DiscontinuityBase::create_points( - const std::vector& coordinates) { - bool status = true; - try { - // Check if point coordinates is empty - if (coordinates.empty()) - throw std::runtime_error("List of coordinates is empty"); - // Iterate over all coordinates - for (const auto& point_coordinates : coordinates) { - - // Add point - mpm::discontinuous_point point(point_coordinates); - - points_.emplace_back(point); // - } - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; - } - return status; -} +#include "discontinuity_base.tcc" #endif // MPM_DiscontinuityBase_H_ diff --git a/include/xmpm/discontinuity_base.tcc b/include/xmpm/discontinuity_base.tcc new file mode 100644 index 000000000..92737322a --- /dev/null +++ b/include/xmpm/discontinuity_base.tcc @@ -0,0 +1,221 @@ +//! Constructor +template +mpm::DiscontinuityBase::DiscontinuityBase( + unsigned id, const Json& discontinuity_props) { + + numpoint_ = 0; + + friction_coef_ = 0; + + std::string logger = "discontinuity::" + std::to_string(id); + console_ = std::make_unique(logger, mpm::stdout_sink); +} + +//! create points from file +template +bool mpm::DiscontinuityBase::create_points( + const std::vector& coordinates) { + bool status = true; + try { + // Check if point coordinates is empty + if (coordinates.empty()) + throw std::runtime_error("List of coordinates is empty"); + // Iterate over all coordinates + for (const auto& point_coordinates : coordinates) { + + // Add point + mpm::discontinuity_point point(point_coordinates); + + points_.emplace_back(point); // + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +// Assign a cell to particle +template +bool mpm::discontinuity_point::assign_cell_xi( + const std::shared_ptr>& cellptr, + const Eigen::Matrix& xi) { + bool status = true; + try { + // Assign cell to the new cell ptr, if point can be found in new cell + if (cellptr != nullptr) { + + cell_ = cellptr; + cell_id_ = cellptr->id(); + nodes_ = cell_->nodes(); + // assign discontinuity_enrich + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->assign_discontinuity_enrich(true); + // Assign the reference location of particle + bool xi_nan = false; + + // Check if point is within the cell + for (unsigned i = 0; i < xi.size(); ++i) + if (xi(i) < -1. || xi(i) > 1. || std::isnan(xi(i))) xi_nan = true; + + if (xi_nan == false) + this->xi_ = xi; + else + return false; + } else { + console_->warn("Points of discontinuity cannot be found in cell!"); + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +// Assign a cell to point +template +bool mpm::discontinuity_point::assign_cell( + const std::shared_ptr>& cellptr) { + bool status = true; + try { + Eigen::Matrix xi; + // Assign cell to the new cell ptr, if point can be found in new cell + if (cellptr->is_point_in_cell(this->coordinates_, &xi)) { + + cell_ = cellptr; + cell_id_ = cellptr->id(); + nodes_ = cell_->nodes(); + // assign discontinuity_enrich + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->assign_discontinuity_enrich(true); + } else { + console_->warn("Points of discontinuity cannot be found in cell!"); + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +// Compute reference location cell to particle +template +bool mpm::discontinuity_point::compute_reference_location() noexcept { + // Set status of compute reference location + bool status = false; + // Compute local coordinates + Eigen::Matrix xi; + // Check if the point is in cell + if (cell_ != nullptr && cell_->is_point_in_cell(this->coordinates_, &xi)) { + this->xi_ = xi; + status = true; + } + + return status; +} + +//! Locate points in a cell +template +void mpm::discontinuity_point::locate_discontinuity_mesh( + Vector>& cells, Map>& map_cells) noexcept { + + // Check the current cell if it is not invalid + if (cell_id() != std::numeric_limits::max()) { + // If a cell id is present, but not a cell locate the cell from map + if (!cell_ptr()) assign_cell(map_cells[cell_id()]); + if (compute_reference_location()) return; + + // Check if discontinuity point is in any of its nearest neighbours + const auto neighbours = map_cells[cell_id()]->neighbours(); + Eigen::Matrix xi; + for (auto neighbour : neighbours) { + if (map_cells[neighbour]->is_point_in_cell(coordinates_, &xi)) { + assign_cell_xi(map_cells[neighbour], xi); + return; + } + } + } +#pragma omp parallel for schedule(runtime) + for (auto citr = cells.cbegin(); citr != cells.cend(); ++citr) { + // Check if particle is already found, if so don't run for other cells + // Check if co-ordinates is within the cell, if true + // add particle to cell + Eigen::Matrix xi; + if ((*citr)->is_point_in_cell(coordinates(), &xi)) { + assign_cell_xi(*citr, xi); + } + } +} + +// Compute updated position of the particle +template +void mpm::discontinuity_point::compute_updated_position( + double dt) noexcept { + // Check if point has a valid cell ptr + if (cell_ == nullptr) return; + // Get interpolated nodal velocity + Eigen::Matrix nodal_velocity = + Eigen::Matrix::Zero(); + const double tolerance = 1.E-16; + unsigned int phase = 0; + // need to do, points move with which side + int move_direction = -1; + for (unsigned i = 0; i < nodes_.size(); ++i) { + if (nodes_[i]->discontinuity_enrich()) { + double nodal_mass = + nodes_[i]->mass(phase) - + nodes_[i]->discontinuity_property("mass_enrich", 1)(0, 0); + if (nodal_mass < tolerance) continue; + + nodal_velocity += + shapefn_[i] * + (nodes_[i]->momentum(phase) - + nodes_[i]->discontinuity_property("momenta_enrich", 3)) / + nodal_mass; + } else { + double nodal_mass = nodes_[i]->mass(phase); + if (nodal_mass < tolerance) continue; + nodal_velocity += shapefn_[i] * nodes_[i]->momentum(phase) / nodal_mass; + } + } + // New position current position + velocity * dt + this->coordinates_ += nodal_velocity * dt; +} + +// Compute updated position of the particle +template +void mpm::discontinuity_point::compute_shapefn() noexcept { + // Check if point has a valid cell ptr + if (cell_ == nullptr) return; + // Get element ptr of a cell + const auto element = cell_->element_ptr(); + + // Zero matrix + Eigen::Matrix zero = Eigen::Matrix::Zero(); + + // Compute shape function of the point + //! Size of particle in natural coordinates + Eigen::Matrix natural_size_; + natural_size_.setZero(); + shapefn_ = element->shapefn(this->xi_, natural_size_, zero); +} +//! Locate points in a cell +template +void mpm::DiscontinuityBase::locate_discontinuity_mesh( + Vector>& cells, Map>& map_cells) noexcept { + for (auto& point : this->points_) + point.locate_discontinuity_mesh(cells, map_cells); +} + +// Compute updated position of the particle +template +void mpm::DiscontinuityBase::compute_updated_position( + double dt) noexcept { + for (auto& point : this->points_) point.compute_updated_position(dt); +} + +// Compute updated position of the particle +template +void mpm::DiscontinuityBase::compute_shapefn() noexcept { + for (auto& point : this->points_) point.compute_shapefn(); +} \ No newline at end of file diff --git a/src/discontinuity.cc b/src/discontinuity.cc index 11c2fd421..defd1814b 100644 --- a/src/discontinuity.cc +++ b/src/discontinuity.cc @@ -3,5 +3,6 @@ #include "factory.h" // Triangle 3-noded element -static Register, mpm::Discontinuity_3D<3>> tri3d( - "tri3d"); +static Register, mpm::Discontinuity3D<3>, unsigned, + const Json&> + tri3d("tri3d"); From 67ae1db7a3c2e3940a9f651a287105ed86012cd7 Mon Sep 17 00:00:00 2001 From: yong liang Date: Sun, 16 Aug 2020 00:11:08 -0700 Subject: [PATCH 14/91] :hammer::construction:clean xmpmparticle class --- include/node.tcc | 2 +- include/node_xmpm.tcc | 10 +- include/particles/particle.h | 2 +- include/particles/particle_xmpm.h | 294 ++---------- include/particles/particle_xmpm.tcc | 714 +--------------------------- include/solvers/xmpm_explicit.tcc | 4 +- include/xmpm/discontinuity_3d.tcc | 1 - 7 files changed, 48 insertions(+), 979 deletions(-) diff --git a/include/node.tcc b/include/node.tcc index d027a33e0..ba979d6da 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -34,7 +34,7 @@ void mpm::Node::initialise() noexcept { acceleration_.setZero(); status_ = false; material_ids_.clear(); - discontinuity_enrich_ = false; + discontinuity_enrich_ = true; } //! Initialise shared pointer to nodal properties pool diff --git a/include/node_xmpm.tcc b/include/node_xmpm.tcc index b5abd14b2..2394b0169 100644 --- a/include/node_xmpm.tcc +++ b/include/node_xmpm.tcc @@ -54,11 +54,11 @@ bool mpm::Node::intergrate_momentum_discontinuity( // when velocity is set. this->apply_velocity_constraints_discontinuity(); - // need to be done - //Eigen::Matrix normal{0.44721359474414313, 0, - // 0.89442719147920724}; - // property_handle_->assign_property("normal_unit_vectors_discontinuity", - // discontinuity_prop_id_, 0, normal, Tdim); + //need to be done + Eigen::Matrix normal{0.44721359474414313, 0, + 0.89442719147920724}; + property_handle_->assign_property("normal_unit_vectors_discontinuity", + discontinuity_prop_id_, 0, normal, Tdim); this->self_contact_discontinuity(dt); diff --git a/include/particles/particle.h b/include/particles/particle.h index 849b72f56..676592955 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -306,7 +306,7 @@ class Particle : public ParticleBase { inline Eigen::Matrix compute_strain_rate( const Eigen::MatrixXd& dn_dx, unsigned phase) noexcept; - private: + protected: //! particle id using ParticleBase::id_; //! coordinates diff --git a/include/particles/particle_xmpm.h b/include/particles/particle_xmpm.h index 3506097bf..dfcc4e37c 100644 --- a/include/particles/particle_xmpm.h +++ b/include/particles/particle_xmpm.h @@ -18,7 +18,7 @@ namespace mpm { //! \details ParticleXMPM class: id_ and coordinates. //! \tparam Tdim Dimension template -class ParticleXMPM : public ParticleBase { +class ParticleXMPM : public Particle { public: //! Define a vector of size dimension using VectorDim = Eigen::Matrix; @@ -46,157 +46,12 @@ class ParticleXMPM : public ParticleBase { //! Delete assignment operator ParticleXMPM& operator=(const ParticleXMPM&) = 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 - virtual bool initialise_particle( - 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; - - //! Initialise properties + //! Initialise properties void initialise() override; - //! Compute reference coordinates in a cell - bool compute_reference_location() noexcept override; - - //! Return reference location - VectorDim reference_location() const override { return xi_; } - - //! Assign a cell to particle - //! If point is in new cell, assign new cell and remove particle id from old - //! cell. If point can't be found in the new cell, check if particle is still - //! valid in the old cell, if it is leave it as is. If not, set cell as null - //! \param[in] cellptr Pointer to a cell - bool assign_cell(const std::shared_ptr>& cellptr) override; - - //! Assign a cell to particle - //! If point is in new cell, assign new cell and remove particle id from old - //! cell. If point can't be found in the new cell, check if particle is still - //! valid in the old cell, if it is leave it as is. If not, set cell as null - //! \param[in] cellptr Pointer to a cell - //! \param[in] xi Local coordinates of the point in reference cell - bool assign_cell_xi(const std::shared_ptr>& cellptr, - const Eigen::Matrix& xi) override; - - //! Assign cell id - //! \param[in] id Cell id - bool assign_cell_id(Index id) override; - - //! Return cell id - Index cell_id() const override { return cell_id_; } - - //! Return cell ptr status - bool cell_ptr() const override { return cell_ != nullptr; } - - //! Remove cell associated with the particle - void remove_cell() override; - - //! Compute shape functions of a particle, based on local coordinates - void compute_shapefn() noexcept override; - - //! Assign volume - //! \param[in] volume Volume of particle - bool assign_volume(double volume) override; - - //! Return 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 - //! \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; - - //! Map multimaterial displacements to nodes - void map_multimaterial_displacements_to_nodes() noexcept override; - - //! Map multimaterial domain gradients to nodes - void map_multimaterial_domain_gradients_to_nodes() noexcept override; - - //! 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; } - - //! Return mass of the particles - double mass() const override { return mass_; } - - //! Assign material - //! \param[in] material Pointer to a material - //! \param[in] phase Index to indicate phase - bool assign_material(const std::shared_ptr>& material, - unsigned phase = mpm::ParticlePhase::Solid) override; - - //! Compute strain - //! \param[in] dt Analysis time step - void compute_strain(double dt) noexcept override; - - //! Return strain of the particle - Eigen::Matrix strain() const override { return strain_; } - - //! Return strain rate of the particle - Eigen::Matrix strain_rate() const override { - return strain_rate_; - }; - - //! Return dvolumetric strain of centroid - //! \retval dvolumetric strain at centroid - double dvolumetric_strain() const override { return dvolumetric_strain_; } - - //! Return volumetric strain of centroid - //! \retval volumetric strain at centroid - double volumetric_strain_centroid() const override { - return volumetric_strain_centroid_; - } - - //! Initial stress - //! \param[in] stress Initial sress - void initial_stress(const Eigen::Matrix& stress) override { - this->stress_ = stress; - } - - //! Compute stress - void compute_stress() noexcept override; - - //! 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; @@ -204,91 +59,12 @@ class ParticleXMPM : public ParticleBase { //! Map internal force inline void map_internal_force() noexcept override; - //! Assign velocity to the particle - //! \param[in] velocity A vector of particle velocity - //! \retval status Assignment status - bool assign_velocity(const VectorDim& velocity) override; - - //! Return velocity of the particle - VectorDim velocity() const override { return velocity_; } - - //! Return displacement of the particle - VectorDim displacement() const override { return displacement_; } - - //! 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 traction of the particle - //! \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; - //! Return a state variable - //! \param[in] var State variable - //! \param[in] phase Index to indicate phase - //! \retval Quantity of the state history variable - double state_variable( - const std::string& var, - unsigned phase = mpm::ParticlePhase::Solid) const override { - return (state_variables_[phase].find(var) != state_variables_[phase].end()) - ? state_variables_[phase].at(var) - : std::numeric_limits::quiet_NaN(); - } - - //! 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 - 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 tensor data of particles - //! \param[in] property Property string - //! \retval vecdata Tensor data of particle property - Eigen::VectorXd tensor_data(const std::string& property) 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; - - //! Assign material id of this particle to nodes - void append_material_id_to_nodes() const override; - - //! Return the number of neighbour particles - unsigned nneighbours() const override { return neighbours_.size(); }; - - //! Assign neighbour particles - //! \param[in] neighbours set of id of the neighbouring particles - //! \retval insertion_status Return the successful addition of a node - void assign_neighbours(const std::vector& neighbours) override; - - //! Return neighbour ids - std::vector neighbours() const override { return neighbours_; }; - protected: //! Initialise particle material container //! \details This function allocate memory and initialise the material related @@ -315,69 +91,71 @@ class ParticleXMPM : public ParticleBase { private: //! particle id - using ParticleBase::id_; + using Particle::id_; //! coordinates - using ParticleBase::coordinates_; + using Particle::coordinates_; //! Reference coordinates (in a cell) - using ParticleBase::xi_; + using Particle::xi_; //! Cell - using ParticleBase::cell_; + using Particle::cell_; //! Cell id - using ParticleBase::cell_id_; + using Particle::cell_id_; //! Nodes - using ParticleBase::nodes_; + using Particle::nodes_; //! Status - using ParticleBase::status_; + using Particle::status_; //! Material - using ParticleBase::material_; + using Particle::material_; //! Material id - using ParticleBase::material_id_; + using Particle::material_id_; //! State variables - using ParticleBase::state_variables_; + using Particle::state_variables_; //! Neighbour particles - using ParticleBase::neighbours_; + using Particle::neighbours_; //! Volumetric mass density (mass / volume) - double mass_density_{0.}; + using Particle::mass_density_; //! Mass - double mass_{0.}; + using Particle::mass_; //! Volume - double volume_{0.}; + using Particle::volume_; //! Size of particle - Eigen::Matrix size_; + using Particle:: size_; //! Size of particle in natural coordinates - Eigen::Matrix natural_size_; + using Particle:: natural_size_; //! Stresses - Eigen::Matrix stress_; + using Particle:: stress_; //! Strains - Eigen::Matrix strain_; + using Particle:: strain_; //! dvolumetric strain - double dvolumetric_strain_{0.}; + using Particle::dvolumetric_strain_; //! Volumetric strain at centroid - double volumetric_strain_centroid_{0.}; + using Particle::volumetric_strain_centroid_; //! Strain rate - Eigen::Matrix strain_rate_; + using Particle:: strain_rate_; //! dstrains - Eigen::Matrix dstrain_; + using Particle:: dstrain_; //! Velocity - Eigen::Matrix velocity_; + using Particle:: velocity_; //! Displacement - Eigen::Matrix displacement_; + using Particle:: displacement_; //! Particle velocity constraints - std::map particle_velocity_constraints_; + using Particle:: particle_velocity_constraints_; //! Set traction - bool set_traction_{false}; + using Particle:: set_traction_; //! Surface Traction (given as a stress; force/area) - Eigen::Matrix traction_; + using Particle:: traction_; //! Shape functions - Eigen::VectorXd shapefn_; + using Particle:: shapefn_; //! dN/dX - Eigen::MatrixXd dn_dx_; + using Particle:: dn_dx_; //! dN/dX at cell centroid - Eigen::MatrixXd dn_dx_centroid_; + using Particle:: dn_dx_centroid_; //! Logger - std::unique_ptr console_; + using Particle:: console_; //! Map of vector properties - std::map> properties_; + using Particle:: properties_; + +private: //! level set values for discontinuity double levelset_phi_{0.}; }; // ParticleXMPM class diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index e3ab0235f..ea8a24a4e 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -1,14 +1,9 @@ //! Construct a particle with id and coordinates template mpm::ParticleXMPM::ParticleXMPM(Index id, const VectorDim& coord) - : mpm::ParticleBase(id, coord) { + : mpm::Particle(id, coord) { + this->initialise(); - // Clear cell ptr - cell_ = nullptr; - // Nodes - nodes_.clear(); - // Set material containers - this->initialise_material(1); // Logger std::string logger = "particlexmpm" + std::to_string(Tdim) + "d::" + std::to_string(id); @@ -19,498 +14,26 @@ mpm::ParticleXMPM::ParticleXMPM(Index id, const VectorDim& coord) template mpm::ParticleXMPM::ParticleXMPM(Index id, const VectorDim& coord, bool status) - : mpm::ParticleBase(id, coord, status) { + : mpm::Particle(id, coord, status) { this->initialise(); - cell_ = nullptr; - nodes_.clear(); - // Set material containers - this->initialise_material(1); //! Logger std::string logger = "particlexmpm" + 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::ParticleXMPM::initialise_particle( - const HDF5Particle& particle) { - - // Assign id - this->id_ = particle.id; - // Mass - this->mass_ = particle.mass; - // Volume - this->volume_ = particle.volume; - // Mass Density - 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; - // Initialise particle size - for (unsigned i = 0; i < Tdim; ++i) this->natural_size_(i) = psize(i); - - // Coordinates - Eigen::Vector3d coordinates; - coordinates << particle.coord_x, particle.coord_y, particle.coord_z; - // Initialise coordinates - for (unsigned i = 0; i < Tdim; ++i) this->coordinates_(i) = coordinates(i); - - // Displacement - Eigen::Vector3d displacement; - displacement << particle.displacement_x, particle.displacement_y, - particle.displacement_z; - // Initialise displacement - 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) this->velocity_(i) = velocity(i); - - // Stress - this->stress_[0] = particle.stress_xx; - this->stress_[1] = particle.stress_yy; - this->stress_[2] = particle.stress_zz; - this->stress_[3] = particle.tau_xy; - this->stress_[4] = particle.tau_yz; - this->stress_[5] = particle.tau_xz; - - // Strain - this->strain_[0] = particle.strain_xx; - this->strain_[1] = particle.strain_yy; - this->strain_[2] = particle.strain_zz; - this->strain_[3] = particle.gamma_xy; - this->strain_[4] = particle.gamma_yz; - this->strain_[5] = particle.gamma_xz; - - // Volumetric strain - this->volumetric_strain_centroid_ = particle.epsilon_v; - - // Status - this->status_ = particle.status; - - // Cell id - this->cell_id_ = particle.cell_id; - this->cell_ = nullptr; - - // Clear nodes - this->nodes_.clear(); - - // Material id - this->material_id_[mpm::ParticlePhase::Solid] = particle.material_id; - - return true; -} -//! Initialise particle data from HDF5 -template -bool mpm::ParticleXMPM::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 = this->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!"); - } - } - return status; -} -//! Return particle data in HDF5 format -template -// cppcheck-suppress * -mpm::HDF5Particle mpm::ParticleXMPM::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::ParticleXMPM::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.; levelset_phi_ = 0.; // Initialize vector data properties - this->properties_["stresses"] = [&]() { return stress(); }; - this->properties_["strains"] = [&]() { return strain(); }; - this->properties_["velocities"] = [&]() { return velocity(); }; - this->properties_["displacements"] = [&]() { return displacement(); }; this->properties_["levelset"] = [&]() { VectorDim levelset{levelset_phi_,0,0};return levelset; }; } -//! Initialise particle material container -template -void mpm::ParticleXMPM::initialise_material(unsigned phase_size) { - material_.resize(phase_size); - material_id_.resize(phase_size); - state_variables_.resize(phase_size); - std::fill(material_.begin(), material_.end(), nullptr); - std::fill(material_id_.begin(), material_id_.end(), - std::numeric_limits::max()); - std::fill(state_variables_.begin(), state_variables_.end(), mpm::dense_map()); -} - -//! Assign material history variables -template -bool mpm::ParticleXMPM::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(phase) != nullptr && - this->material_id(phase) == material->id()) { - // Clone 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; - status = true; - } - } - return status; -} - -// Assign a cell to particle -template -bool mpm::ParticleXMPM::assign_cell( - const std::shared_ptr>& cellptr) { - bool status = true; - try { - Eigen::Matrix xi; - // Assign cell to the new cell ptr, if point can be found in new cell - if (cellptr->is_point_in_cell(this->coordinates_, &xi)) { - // if a cell already exists remove particle from that cell - if (cell_ != nullptr) cell_->remove_particle_id(this->id_); - - cell_ = cellptr; - cell_id_ = cellptr->id(); - // dn_dx centroid - dn_dx_centroid_ = cell_->dn_dx_centroid(); - // Copy nodal pointer to cell - nodes_.clear(); - nodes_ = cell_->nodes(); - - // Compute reference location of particle - bool xi_status = this->compute_reference_location(); - if (!xi_status) return false; - status = cell_->add_particle_id(this->id()); - } else { - throw std::runtime_error("Point cannot be found in cell!"); - } - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; - } - return status; -} - -// Assign a cell to particle -template -bool mpm::ParticleXMPM::assign_cell_xi( - const std::shared_ptr>& cellptr, - const Eigen::Matrix& xi) { - bool status = true; - try { - // Assign cell to the new cell ptr, if point can be found in new cell - if (cellptr != nullptr) { - // if a cell already exists remove particle from that cell - if (cell_ != nullptr) cell_->remove_particle_id(this->id_); - - cell_ = cellptr; - cell_id_ = cellptr->id(); - // dn_dx centroid - dn_dx_centroid_ = cell_->dn_dx_centroid(); - // Copy nodal pointer to cell - nodes_.clear(); - nodes_ = cell_->nodes(); - - // Assign the reference location of particle - bool xi_nan = false; - - // Check if point is within the cell - for (unsigned i = 0; i < xi.size(); ++i) - if (xi(i) < -1. || xi(i) > 1. || std::isnan(xi(i))) xi_nan = true; - - if (xi_nan == false) - this->xi_ = xi; - else - return false; - - status = cell_->add_particle_id(this->id()); - } else { - throw std::runtime_error("Point cannot be found in cell!"); - } - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; - } - return status; -} - -// Assign a cell id to particle -template -bool mpm::ParticleXMPM::assign_cell_id(mpm::Index id) { - bool status = false; - try { - // if a cell ptr is null - if (cell_ == nullptr && id != std::numeric_limits::max()) { - cell_id_ = id; - status = true; - } else { - throw std::runtime_error("Invalid cell id or cell is already assigned!"); - } - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; - } - return status; -} - -// Remove cell for the particle -template -void mpm::ParticleXMPM::remove_cell() { - // if a cell is not nullptr - if (cell_ != nullptr) cell_->remove_particle_id(this->id_); - cell_id_ = std::numeric_limits::max(); - // Clear all the nodes - nodes_.clear(); -} - -// Assign a material to particle -template -bool mpm::ParticleXMPM::assign_material( - const std::shared_ptr>& material, unsigned phase) { - bool status = false; - try { - // Check if material is valid and properties are set - if (material != nullptr) { - material_.at(phase) = material; - material_id_.at(phase) = material_[phase]->id(); - state_variables_.at(phase) = - material_[phase]->initialise_state_variables(); - status = true; - } else { - throw std::runtime_error("Material is undefined!"); - } - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - } - return status; -} - -// Compute reference location cell to particle -template -bool mpm::ParticleXMPM::compute_reference_location() noexcept { - // Set status of compute reference location - bool status = false; - // Compute local coordinates - Eigen::Matrix xi; - // Check if the point is in cell - if (cell_ != nullptr && cell_->is_point_in_cell(this->coordinates_, &xi)) { - this->xi_ = xi; - status = true; - } - - return status; -} - -// Compute shape functions and gradients -template -void mpm::ParticleXMPM::compute_shapefn() noexcept { - // Check if particle has a valid cell ptr - assert(cell_ != nullptr); - // Get element ptr of a cell - const auto element = cell_->element_ptr(); - - // Zero matrix - Eigen::Matrix zero = Eigen::Matrix::Zero(); - - // Compute shape function of the particle - shapefn_ = element->shapefn(this->xi_, this->natural_size_, zero); - - // Compute dN/dx - dn_dx_ = element->dn_dx(this->xi_, cell_->nodal_coordinates(), - this->natural_size_, zero); -} - -// Assign volume to the particle -template -bool mpm::ParticleXMPM::assign_volume(double volume) { - bool status = true; - try { - if (volume <= 0.) - throw std::runtime_error("Particle volume cannot be negative"); - - this->volume_ = volume; - // Compute size of particle in each direction - const double length = - std::pow(this->volume_, static_cast(1. / Tdim)); - // Set particle size as length on each side - this->size_.fill(length); - - if (cell_ != nullptr) { - // Get element ptr of a cell - const auto element = cell_->element_ptr(); - - // Set local particle length based on length of element in natural - // coordinates. Length/(npartices^(1/Dimension)) - this->natural_size_.fill( - element->unit_element_length() / - std::pow(cell_->nparticles(), static_cast(1. / Tdim))); - } - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; - } - return status; -} - -// Compute volume of the particle -template -void mpm::ParticleXMPM::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::ParticleXMPM::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::ParticleXMPM::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 @@ -537,94 +60,7 @@ void mpm::ParticleXMPM::map_mass_momentum_to_nodes() noexcept { } } -//! Map multimaterial properties to nodes -template -void mpm::ParticleXMPM< - Tdim>::map_multimaterial_mass_momentum_to_nodes() noexcept { - // Check if particle mass is set - 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) = mass_ * shapefn_[i]; - nodes_[i]->update_property(true, "masses", nodal_mass, this->material_id(), - 1); - nodes_[i]->update_property(true, "momenta", velocity_ * nodal_mass, - this->material_id(), Tdim); - } -} - -//! Map multimaterial displacements to nodes -template -void mpm::ParticleXMPM< - Tdim>::map_multimaterial_displacements_to_nodes() noexcept { - // Check if particle mass is set - 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 = mass_ * shapefn_[i] * displacement_; - nodes_[i]->update_property(true, "displacements", displacement, - this->material_id(), Tdim); - } -} - -//! Map multimaterial domain gradients to nodes -template -void mpm::ParticleXMPM< - Tdim>::map_multimaterial_domain_gradients_to_nodes() noexcept { - // Check if particle volume is set - 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] = volume_ * dn_dx_(i, j); - nodes_[i]->update_property(true, "domain_gradients", gradient, - this->material_id(), Tdim); - } -} - -// Compute strain rate of the particle -template <> -inline Eigen::Matrix mpm::ParticleXMPM<1>::compute_strain_rate( - const Eigen::MatrixXd& dn_dx, unsigned phase) noexcept { - // Define strain rate - Eigen::Matrix strain_rate = Eigen::Matrix::Zero(); - - for (unsigned i = 0; i < this->nodes_.size(); ++i) { - Eigen::Matrix vel = nodes_[i]->velocity(phase); - strain_rate[0] += dn_dx(i, 0) * vel[0]; - } - if (std::fabs(strain_rate(0)) < 1.E-15) strain_rate[0] = 0.; - return strain_rate; -} - -// Compute strain rate of the particle -template <> -inline Eigen::Matrix mpm::ParticleXMPM<2>::compute_strain_rate( - const Eigen::MatrixXd& dn_dx, unsigned phase) noexcept { - // Define strain rate - Eigen::Matrix strain_rate = Eigen::Matrix::Zero(); - - for (unsigned i = 0; i < this->nodes_.size(); ++i) { - Eigen::Matrix vel = nodes_[i]->velocity(phase); - strain_rate[0] += dn_dx(i, 0) * vel[0]; - strain_rate[1] += dn_dx(i, 1) * vel[1]; - strain_rate[3] += dn_dx(i, 1) * vel[0] + dn_dx(i, 0) * vel[1]; - } - - if (std::fabs(strain_rate[0]) < 1.E-15) strain_rate[0] = 0.; - if (std::fabs(strain_rate[1]) < 1.E-15) strain_rate[1] = 0.; - if (std::fabs(strain_rate[3]) < 1.E-15) strain_rate[3] = 0.; - return strain_rate; -} // Compute strain rate of the particle template <> @@ -667,37 +103,6 @@ inline Eigen::Matrix mpm::ParticleXMPM<3>::compute_strain_rate( return strain_rate; } -// Compute strain of the particle -template -void mpm::ParticleXMPM::compute_strain(double dt) noexcept { - // Assign strain rate - strain_rate_ = this->compute_strain_rate(dn_dx_, mpm::ParticlePhase::Solid); - // Update dstrain - dstrain_ = strain_rate_ * dt; - // Update strain - strain_ += dstrain_; - - // Compute at centroid - // Strain rate for reduced integration - const Eigen::Matrix strain_rate_centroid = - this->compute_strain_rate(dn_dx_centroid_, mpm::ParticlePhase::Solid); - - // Assign volumetric strain at centroid - dvolumetric_strain_ = dt * strain_rate_centroid.head(Tdim).sum(); - volumetric_strain_centroid_ += dvolumetric_strain_; -} - -// Compute stress -template -void mpm::ParticleXMPM::compute_stress() noexcept { - // Check if material ptr is valid - assert(this->material() != nullptr); - // Calculate stress - this->stress_ = - (this->material()) - ->compute_stress(stress_, dstrain_, this, - &state_variables_[mpm::ParticlePhase::Solid]); -} //! Map body force template @@ -774,47 +179,7 @@ inline void mpm::ParticleXMPM<3>::map_internal_force() noexcept { } } -// Assign velocity to the particle -template -bool mpm::ParticleXMPM::assign_velocity( - const Eigen::Matrix& velocity) { - // Assign velocity - velocity_ = velocity; - return true; -} -// Assign traction to the particle -template -bool mpm::ParticleXMPM::assign_traction(unsigned direction, - double traction) { - bool status = false; - try { - if (direction >= Tdim || - 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); - status = true; - this->set_traction_ = true; - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; - } - return status; -} - -//! Map traction force -template -void mpm::ParticleXMPM::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 @@ -891,77 +256,4 @@ void mpm::ParticleXMPM::compute_updated_position( this->displacement_ += nodal_velocity * dt; } -//! Map particle pressure to nodes -template -bool mpm::ParticleXMPM::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::ParticleXMPM::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 -template -void mpm::ParticleXMPM::apply_particle_velocity_constraints( - unsigned dir, double velocity) { - // Set particle velocity constraint - this->velocity_(dir) = velocity; -} - -//! Return particle tensor data -template -Eigen::VectorXd mpm::ParticleXMPM::tensor_data( - const std::string& property) { - return this->properties_.at(property)(); -} - -//! Assign material id of this particle to nodes -template -void mpm::ParticleXMPM::append_material_id_to_nodes() const { - for (unsigned i = 0; i < nodes_.size(); ++i) - nodes_[i]->append_material_id(this->material_id()); -} - -//! Assign neighbour particles -template -void mpm::ParticleXMPM::assign_neighbours( - const std::vector& neighbours) { - neighbours_ = neighbours; - neighbours_.erase(std::remove(neighbours_.begin(), neighbours_.end(), id_), - neighbours_.end()); -} diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index 4239f71f5..4204cac67 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -317,8 +317,8 @@ bool mpm::XMPMExplicit::solve() { if (this->stress_update_ == mpm::StressUpdate::USL) this->compute_stress_strain(phase); // Update the discontinuity position - if (discontinuity_) - mesh_->compute_updated_position_discontinuity(this->dt_); + // if (discontinuity_) + // mesh_->compute_updated_position_discontinuity(this->dt_); // Locate particles auto unlocatable_particles = mesh_->locate_particles_mesh(); diff --git a/include/xmpm/discontinuity_3d.tcc b/include/xmpm/discontinuity_3d.tcc index 2f7479d4c..e7842013f 100644 --- a/include/xmpm/discontinuity_3d.tcc +++ b/include/xmpm/discontinuity_3d.tcc @@ -138,7 +138,6 @@ void mpm::Discontinuity3D::compute_levelset( ? distance : Vertical_distance; if (!distance) distance = 1e-16; - distance = 1; } phi_list[i] = distance; From 6f9da8b0bc6021fb94feec5268c4471d22b8ced5 Mon Sep 17 00:00:00 2001 From: yong liang Date: Sun, 16 Aug 2020 00:19:28 -0700 Subject: [PATCH 15/91] :hammer:change discontinuouty_point_line name --- include/xmpm/discontinuity_3d.h | 2 +- include/xmpm/discontinuity_3d.tcc | 2 +- include/xmpm/discontinuity_base.h | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/xmpm/discontinuity_3d.h b/include/xmpm/discontinuity_3d.h index 793a35450..ffe30abcd 100644 --- a/include/xmpm/discontinuity_3d.h +++ b/include/xmpm/discontinuity_3d.h @@ -53,7 +53,7 @@ class Discontinuity3D : public DiscontinuityBase { private: // vector of elements - std::vector> elements_; + std::vector> elements_; // number of elements //delete mpm::Index numelement_; diff --git a/include/xmpm/discontinuity_3d.tcc b/include/xmpm/discontinuity_3d.tcc index e7842013f..b489731cb 100644 --- a/include/xmpm/discontinuity_3d.tcc +++ b/include/xmpm/discontinuity_3d.tcc @@ -59,7 +59,7 @@ bool mpm::Discontinuity3D::create_elements( // Iterate over all elements for (const auto& points : elements) { - mpm::discontinuous_element element(points); + mpm::discontinuity_element element(points); elements_.emplace_back(element); // } diff --git a/include/xmpm/discontinuity_base.h b/include/xmpm/discontinuity_base.h index 0e83fb81b..0c6ee6a8c 100644 --- a/include/xmpm/discontinuity_base.h +++ b/include/xmpm/discontinuity_base.h @@ -160,7 +160,7 @@ virtual void compute_normal( }; // DiscontinuityBase class -struct discontinuous_line { +struct discontinuity_line { public: //! Return points indices Eigen::Matrix points() const { return points_; }; @@ -171,12 +171,12 @@ struct discontinuous_line { }; template -struct discontinuous_element { +struct discontinuity_element { public: //! Define a vector of size dimension using VectorDim = Eigen::Matrix; - discontinuous_element(const std::vector& points) { + discontinuity_element(const std::vector& points) { for (int i = 0; i < points.size(); ++i) points_[i] = points[i]; } //! Return points indices From 030993a6174840bf436cd41cc653f7dc96f7590f Mon Sep 17 00:00:00 2001 From: yong liang Date: Sun, 16 Aug 2020 00:42:16 -0700 Subject: [PATCH 16/91] :hammer:separate the discontinuity functions into different files --- include/xmpm/discontinuity_3d.tcc | 2 +- include/xmpm/discontinuity_base.h | 128 +++++++++-------- include/xmpm/discontinuity_base.tcc | 165 ---------------------- include/xmpm/discontinuity_base_point.tcc | 164 +++++++++++++++++++++ 4 files changed, 231 insertions(+), 228 deletions(-) create mode 100644 include/xmpm/discontinuity_base_point.tcc diff --git a/include/xmpm/discontinuity_3d.tcc b/include/xmpm/discontinuity_3d.tcc index b489731cb..19d69f095 100644 --- a/include/xmpm/discontinuity_3d.tcc +++ b/include/xmpm/discontinuity_3d.tcc @@ -1,7 +1,7 @@ template mpm::Discontinuity3D::Discontinuity3D(unsigned id, const Json& discontinuity_props) - : DiscontinuityBase(id, discontinuity_props) { + :DiscontinuityBase(id, discontinuity_props) { numelement_ = 0; try { diff --git a/include/xmpm/discontinuity_base.h b/include/xmpm/discontinuity_base.h index 0c6ee6a8c..61e36ea2b 100644 --- a/include/xmpm/discontinuity_base.h +++ b/include/xmpm/discontinuity_base.h @@ -12,68 +12,7 @@ namespace mpm { template -struct discontinuity_point { - public: - //! Define a vector of size dimension - using VectorDim = Eigen::Matrix; - - discontinuity_point(const VectorDim& coordinate) { - coordinates_ = coordinate; - cell_ = nullptr; - //! Logger - console_ = spdlog::get("discontinuity_point"); - } - - //! Return coordinates - //! \retval coordinates_ return coordinates of the nodebase - VectorDim coordinates() const { return coordinates_; } - - //! Return cell_id - Index cell_id() const { return cell_id_; } - - //! Assign a cell to point - //! \param[in] cellptr Pointer to a cell - //! \param[in] xi Local coordinates of the point in reference cell - bool assign_cell_xi(const std::shared_ptr>& cellptr, - const Eigen::Matrix& xi); - - //! Return cell ptr status - bool cell_ptr() const { return cell_ != nullptr; } - - //! Assign a cell to point - //! \param[in] cellptr Pointer to a cell - bool assign_cell(const std::shared_ptr>& cellptr); - - //! Compute reference coordinates in a cell - bool compute_reference_location() noexcept; - - //! Locate points in a cell - void locate_discontinuity_mesh(Vector>& cells, - Map>& map_cells) noexcept; - - //! Compute updated position - void compute_updated_position(double dt) noexcept; - - //! Compute shape function - void compute_shapefn() noexcept; - - private: - //! point coordinates - VectorDim coordinates_; - //! Cell id - Index cell_id_{std::numeric_limits::max()}; - //! Shape functions - Eigen::VectorXd shapefn_; - //! Cell - std::shared_ptr> cell_; - - //! Reference coordinates (in a cell) - Eigen::Matrix xi_; - //! Vector of nodal pointers - std::vector>> nodes_; - //! Logger - std::shared_ptr console_; -}; +struct discontinuity_point; //! class for to describe the discontinuous surface //! \brief @@ -160,6 +99,70 @@ virtual void compute_normal( }; // DiscontinuityBase class +template +struct discontinuity_point { + public: + //! Define a vector of size dimension + using VectorDim = Eigen::Matrix; + + discontinuity_point(const VectorDim& coordinate) { + coordinates_ = coordinate; + cell_ = nullptr; + //! Logger + console_ = spdlog::get("discontinuity_point"); + } + + //! Return coordinates + //! \retval coordinates_ return coordinates of the nodebase + VectorDim coordinates() const { return coordinates_; } + + //! Return cell_id + Index cell_id() const { return cell_id_; } + + //! Assign a cell to point + //! \param[in] cellptr Pointer to a cell + //! \param[in] xi Local coordinates of the point in reference cell + bool assign_cell_xi(const std::shared_ptr>& cellptr, + const Eigen::Matrix& xi); + + //! Return cell ptr status + bool cell_ptr() const { return cell_ != nullptr; } + + //! Assign a cell to point + //! \param[in] cellptr Pointer to a cell + bool assign_cell(const std::shared_ptr>& cellptr); + + //! Compute reference coordinates in a cell + bool compute_reference_location() noexcept; + + //! Locate points in a cell + void locate_discontinuity_mesh(Vector>& cells, + Map>& map_cells) noexcept; + + //! Compute updated position + void compute_updated_position(double dt) noexcept; + + //! Compute shape function + void compute_shapefn() noexcept; + + private: + //! point coordinates + VectorDim coordinates_; + //! Cell id + Index cell_id_{std::numeric_limits::max()}; + //! Shape functions + Eigen::VectorXd shapefn_; + //! Cell + std::shared_ptr> cell_; + + //! Reference coordinates (in a cell) + Eigen::Matrix xi_; + //! Vector of nodal pointers + std::vector>> nodes_; + //! Logger + std::shared_ptr console_; +}; + struct discontinuity_line { public: //! Return points indices @@ -209,5 +212,6 @@ struct discontinuity_element { } // namespace mpm #include "discontinuity_base.tcc" +#include "discontinuity_base_point.tcc" #endif // MPM_DiscontinuityBase_H_ diff --git a/include/xmpm/discontinuity_base.tcc b/include/xmpm/discontinuity_base.tcc index 92737322a..e7a232295 100644 --- a/include/xmpm/discontinuity_base.tcc +++ b/include/xmpm/discontinuity_base.tcc @@ -34,171 +34,6 @@ bool mpm::DiscontinuityBase::create_points( } return status; } - -// Assign a cell to particle -template -bool mpm::discontinuity_point::assign_cell_xi( - const std::shared_ptr>& cellptr, - const Eigen::Matrix& xi) { - bool status = true; - try { - // Assign cell to the new cell ptr, if point can be found in new cell - if (cellptr != nullptr) { - - cell_ = cellptr; - cell_id_ = cellptr->id(); - nodes_ = cell_->nodes(); - // assign discontinuity_enrich - for (unsigned i = 0; i < nodes_.size(); ++i) - nodes_[i]->assign_discontinuity_enrich(true); - // Assign the reference location of particle - bool xi_nan = false; - - // Check if point is within the cell - for (unsigned i = 0; i < xi.size(); ++i) - if (xi(i) < -1. || xi(i) > 1. || std::isnan(xi(i))) xi_nan = true; - - if (xi_nan == false) - this->xi_ = xi; - else - return false; - } else { - console_->warn("Points of discontinuity cannot be found in cell!"); - } - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; - } - return status; -} - -// Assign a cell to point -template -bool mpm::discontinuity_point::assign_cell( - const std::shared_ptr>& cellptr) { - bool status = true; - try { - Eigen::Matrix xi; - // Assign cell to the new cell ptr, if point can be found in new cell - if (cellptr->is_point_in_cell(this->coordinates_, &xi)) { - - cell_ = cellptr; - cell_id_ = cellptr->id(); - nodes_ = cell_->nodes(); - // assign discontinuity_enrich - for (unsigned i = 0; i < nodes_.size(); ++i) - nodes_[i]->assign_discontinuity_enrich(true); - } else { - console_->warn("Points of discontinuity cannot be found in cell!"); - } - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; - } - return status; -} - -// Compute reference location cell to particle -template -bool mpm::discontinuity_point::compute_reference_location() noexcept { - // Set status of compute reference location - bool status = false; - // Compute local coordinates - Eigen::Matrix xi; - // Check if the point is in cell - if (cell_ != nullptr && cell_->is_point_in_cell(this->coordinates_, &xi)) { - this->xi_ = xi; - status = true; - } - - return status; -} - -//! Locate points in a cell -template -void mpm::discontinuity_point::locate_discontinuity_mesh( - Vector>& cells, Map>& map_cells) noexcept { - - // Check the current cell if it is not invalid - if (cell_id() != std::numeric_limits::max()) { - // If a cell id is present, but not a cell locate the cell from map - if (!cell_ptr()) assign_cell(map_cells[cell_id()]); - if (compute_reference_location()) return; - - // Check if discontinuity point is in any of its nearest neighbours - const auto neighbours = map_cells[cell_id()]->neighbours(); - Eigen::Matrix xi; - for (auto neighbour : neighbours) { - if (map_cells[neighbour]->is_point_in_cell(coordinates_, &xi)) { - assign_cell_xi(map_cells[neighbour], xi); - return; - } - } - } -#pragma omp parallel for schedule(runtime) - for (auto citr = cells.cbegin(); citr != cells.cend(); ++citr) { - // Check if particle is already found, if so don't run for other cells - // Check if co-ordinates is within the cell, if true - // add particle to cell - Eigen::Matrix xi; - if ((*citr)->is_point_in_cell(coordinates(), &xi)) { - assign_cell_xi(*citr, xi); - } - } -} - -// Compute updated position of the particle -template -void mpm::discontinuity_point::compute_updated_position( - double dt) noexcept { - // Check if point has a valid cell ptr - if (cell_ == nullptr) return; - // Get interpolated nodal velocity - Eigen::Matrix nodal_velocity = - Eigen::Matrix::Zero(); - const double tolerance = 1.E-16; - unsigned int phase = 0; - // need to do, points move with which side - int move_direction = -1; - for (unsigned i = 0; i < nodes_.size(); ++i) { - if (nodes_[i]->discontinuity_enrich()) { - double nodal_mass = - nodes_[i]->mass(phase) - - nodes_[i]->discontinuity_property("mass_enrich", 1)(0, 0); - if (nodal_mass < tolerance) continue; - - nodal_velocity += - shapefn_[i] * - (nodes_[i]->momentum(phase) - - nodes_[i]->discontinuity_property("momenta_enrich", 3)) / - nodal_mass; - } else { - double nodal_mass = nodes_[i]->mass(phase); - if (nodal_mass < tolerance) continue; - nodal_velocity += shapefn_[i] * nodes_[i]->momentum(phase) / nodal_mass; - } - } - // New position current position + velocity * dt - this->coordinates_ += nodal_velocity * dt; -} - -// Compute updated position of the particle -template -void mpm::discontinuity_point::compute_shapefn() noexcept { - // Check if point has a valid cell ptr - if (cell_ == nullptr) return; - // Get element ptr of a cell - const auto element = cell_->element_ptr(); - - // Zero matrix - Eigen::Matrix zero = Eigen::Matrix::Zero(); - - // Compute shape function of the point - //! Size of particle in natural coordinates - Eigen::Matrix natural_size_; - natural_size_.setZero(); - shapefn_ = element->shapefn(this->xi_, natural_size_, zero); -} //! Locate points in a cell template void mpm::DiscontinuityBase::locate_discontinuity_mesh( diff --git a/include/xmpm/discontinuity_base_point.tcc b/include/xmpm/discontinuity_base_point.tcc new file mode 100644 index 000000000..95c30ca94 --- /dev/null +++ b/include/xmpm/discontinuity_base_point.tcc @@ -0,0 +1,164 @@ +// Assign a cell to particle +template +bool mpm::discontinuity_point::assign_cell_xi( + const std::shared_ptr>& cellptr, + const Eigen::Matrix& xi) { + bool status = true; + try { + // Assign cell to the new cell ptr, if point can be found in new cell + if (cellptr != nullptr) { + + cell_ = cellptr; + cell_id_ = cellptr->id(); + nodes_ = cell_->nodes(); + // assign discontinuity_enrich + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->assign_discontinuity_enrich(true); + // Assign the reference location of particle + bool xi_nan = false; + + // Check if point is within the cell + for (unsigned i = 0; i < xi.size(); ++i) + if (xi(i) < -1. || xi(i) > 1. || std::isnan(xi(i))) xi_nan = true; + + if (xi_nan == false) + this->xi_ = xi; + else + return false; + } else { + console_->warn("Points of discontinuity cannot be found in cell!"); + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +// Assign a cell to point +template +bool mpm::discontinuity_point::assign_cell( + const std::shared_ptr>& cellptr) { + bool status = true; + try { + Eigen::Matrix xi; + // Assign cell to the new cell ptr, if point can be found in new cell + if (cellptr->is_point_in_cell(this->coordinates_, &xi)) { + + cell_ = cellptr; + cell_id_ = cellptr->id(); + nodes_ = cell_->nodes(); + // assign discontinuity_enrich + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->assign_discontinuity_enrich(true); + } else { + console_->warn("Points of discontinuity cannot be found in cell!"); + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +// Compute reference location cell to particle +template +bool mpm::discontinuity_point::compute_reference_location() noexcept { + // Set status of compute reference location + bool status = false; + // Compute local coordinates + Eigen::Matrix xi; + // Check if the point is in cell + if (cell_ != nullptr && cell_->is_point_in_cell(this->coordinates_, &xi)) { + this->xi_ = xi; + status = true; + } + + return status; +} + +//! Locate points in a cell +template +void mpm::discontinuity_point::locate_discontinuity_mesh( + Vector>& cells, Map>& map_cells) noexcept { + + // Check the current cell if it is not invalid + if (cell_id() != std::numeric_limits::max()) { + // If a cell id is present, but not a cell locate the cell from map + if (!cell_ptr()) assign_cell(map_cells[cell_id()]); + if (compute_reference_location()) return; + + // Check if discontinuity point is in any of its nearest neighbours + const auto neighbours = map_cells[cell_id()]->neighbours(); + Eigen::Matrix xi; + for (auto neighbour : neighbours) { + if (map_cells[neighbour]->is_point_in_cell(coordinates_, &xi)) { + assign_cell_xi(map_cells[neighbour], xi); + return; + } + } + } +#pragma omp parallel for schedule(runtime) + for (auto citr = cells.cbegin(); citr != cells.cend(); ++citr) { + // Check if particle is already found, if so don't run for other cells + // Check if co-ordinates is within the cell, if true + // add particle to cell + Eigen::Matrix xi; + if ((*citr)->is_point_in_cell(coordinates(), &xi)) { + assign_cell_xi(*citr, xi); + } + } +} + +// Compute updated position of the particle +template +void mpm::discontinuity_point::compute_updated_position( + double dt) noexcept { + // Check if point has a valid cell ptr + if (cell_ == nullptr) return; + // Get interpolated nodal velocity + Eigen::Matrix nodal_velocity = + Eigen::Matrix::Zero(); + const double tolerance = 1.E-16; + unsigned int phase = 0; + // need to do, points move with which side + int move_direction = -1; + for (unsigned i = 0; i < nodes_.size(); ++i) { + if (nodes_[i]->discontinuity_enrich()) { + double nodal_mass = + nodes_[i]->mass(phase) - + nodes_[i]->discontinuity_property("mass_enrich", 1)(0, 0); + if (nodal_mass < tolerance) continue; + + nodal_velocity += + shapefn_[i] * + (nodes_[i]->momentum(phase) - + nodes_[i]->discontinuity_property("momenta_enrich", 3)) / + nodal_mass; + } else { + double nodal_mass = nodes_[i]->mass(phase); + if (nodal_mass < tolerance) continue; + nodal_velocity += shapefn_[i] * nodes_[i]->momentum(phase) / nodal_mass; + } + } + // New position current position + velocity * dt + this->coordinates_ += nodal_velocity * dt; +} + +// Compute updated position of the particle +template +void mpm::discontinuity_point::compute_shapefn() noexcept { + // Check if point has a valid cell ptr + if (cell_ == nullptr) return; + // Get element ptr of a cell + const auto element = cell_->element_ptr(); + + // Zero matrix + Eigen::Matrix zero = Eigen::Matrix::Zero(); + + // Compute shape function of the point + //! Size of particle in natural coordinates + Eigen::Matrix natural_size_; + natural_size_.setZero(); + shapefn_ = element->shapefn(this->xi_, natural_size_, zero); +} \ No newline at end of file From f4792f44ee182211e7b777d09a63c91ac27bbeb4 Mon Sep 17 00:00:00 2001 From: yong liang Date: Sun, 16 Aug 2020 19:24:35 -0700 Subject: [PATCH 17/91] :pencil::hammer::construction:clean up particleXMPM class --- include/mesh.tcc | 15 +++-- include/node.h | 8 ++- include/node_xmpm.tcc | 12 ++-- include/particles/particle_xmpm.h | 67 +++++++++----------- include/particles/particle_xmpm.tcc | 34 ++++++---- include/solvers/mpm_base.tcc | 2 +- include/solvers/xmpm_explicit.tcc | 33 ++++++---- include/xmpm/discontinuity_3d.h | 21 +++---- include/xmpm/discontinuity_3d.tcc | 97 ++++++++++++++--------------- include/xmpm/discontinuity_base.h | 31 ++++----- 10 files changed, 164 insertions(+), 156 deletions(-) diff --git a/include/mesh.tcc b/include/mesh.tcc index 00f7a4403..572afa90f 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1955,10 +1955,10 @@ void mpm::Mesh::compute_shapefn_discontinuity() { } } - // compute the normal vector of enriched nodes at the discontinuity +// compute the normal vector of enriched nodes at the discontinuity template void mpm::Mesh::compute_normal_vector_discontinuity() { - //need to set + // need to set unsigned discontinuity_id = 0; auto discontinuity = discontinuities_[discontinuity_id]; @@ -1966,13 +1966,12 @@ void mpm::Mesh::compute_normal_vector_discontinuity() { VectorDim normal; normal.setZero(); -for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) - { - - discontinuity->compute_normal((*nitr)->coordinates(), - normal); + for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { + + discontinuity->compute_normal((*nitr)->coordinates(), normal); nodal_properties_->assign_property("normal_unit_vectors_discontinuity", - (*nitr)->discontinuity_prop_id(), 0, normal, Tdim); + (*nitr)->discontinuity_prop_id(), 0, + normal, Tdim); } } diff --git a/include/node.h b/include/node.h index f42f66e4e..c268c6dbd 100644 --- a/include/node.h +++ b/include/node.h @@ -309,10 +309,12 @@ class Node : public NodeBase { //! \param[in] dt Time-step void self_contact_discontinuity(double dt) noexcept override; - //! Return the discontinuity_prop_id - virtual unsigned discontinuity_prop_id() const noexcept override{return discontinuity_prop_id_;}; + //! Return the discontinuity_prop_id + virtual unsigned discontinuity_prop_id() const noexcept override { + return discontinuity_prop_id_; + }; - //! Compute normal direction of each enrich node + //! Compute normal direction of each enrich node void compute_normal_vector() noexcept override; private: diff --git a/include/node_xmpm.tcc b/include/node_xmpm.tcc index 2394b0169..2e52633aa 100644 --- a/include/node_xmpm.tcc +++ b/include/node_xmpm.tcc @@ -54,9 +54,9 @@ bool mpm::Node::intergrate_momentum_discontinuity( // when velocity is set. this->apply_velocity_constraints_discontinuity(); - //need to be done + // need to be done Eigen::Matrix normal{0.44721359474414313, 0, - 0.89442719147920724}; + 0.89442719147920724}; property_handle_->assign_property("normal_unit_vectors_discontinuity", discontinuity_prop_id_, 0, normal, Tdim); @@ -206,9 +206,7 @@ void mpm::Node::self_contact_discontinuity( } } - //! Compute normal direction of each enrich node - //! Apply velocity constraints +//! Compute normal direction of each enrich node +//! Apply velocity constraints template -void mpm::Node::compute_normal_vector() noexcept { - - } \ No newline at end of file +void mpm::Node::compute_normal_vector() noexcept {} \ No newline at end of file diff --git a/include/particles/particle_xmpm.h b/include/particles/particle_xmpm.h index dfcc4e37c..0cd3dd109 100644 --- a/include/particles/particle_xmpm.h +++ b/include/particles/particle_xmpm.h @@ -14,18 +14,15 @@ namespace mpm { //! ParticleXMPM class -//! \brief Base class that stores the information about particles -//! \details ParticleXMPM class: id_ and coordinates. -//! \tparam Tdim Dimension +//! \brief ParticleXMPM class derived from particle class, stores the +//! information for XMPMExplicit solver \details ParticleXMPM class: id_ and +//! coordinates. \tparam Tdim Dimension template class ParticleXMPM : public Particle { public: //! Define a vector of size dimension using VectorDim = Eigen::Matrix; - //! Define DOFs - static const unsigned Tdof = (Tdim == 1) ? 1 : 3 * (Tdim - 1); - //! Construct a particle with id and coordinates //! \param[in] id Particle id //! \param[in] coord coordinates of the particle @@ -46,7 +43,7 @@ class ParticleXMPM : public Particle { //! Delete assignment operator ParticleXMPM& operator=(const ParticleXMPM&) = delete; - //! Initialise properties + //! Initialise properties void initialise() override; //! Map particle mass and momentum to nodes @@ -65,14 +62,9 @@ class ParticleXMPM : public Particle { void compute_updated_position(double dt, bool velocity_update = false) noexcept override; - protected: - //! Initialise particle material container - //! \details This function allocate memory and initialise the material related - //! containers according to the particle phase, i.e. solid or fluid particle - //! has phase_size = 1, whereas two-phase (solid-fluid) or three-phase - //! (solid-water-air) particle have phase_size = 2 and 3, respectively. - //! \param[in] phase_size The material phase size - void initialise_material(unsigned phase_size = 1); + //! Compute strain + //! \param[in] dt Analysis time step + void compute_strain(double dt) noexcept override; private: //! Compute strain rate @@ -81,10 +73,13 @@ class ParticleXMPM : public Particle { //! \retval strain rate at particle inside a cell inline Eigen::Matrix compute_strain_rate( const Eigen::MatrixXd& dn_dx, unsigned phase) noexcept; - //! set the level set function values + + //! Assign the level set function values + //! \param[in] phivalue The level set values void assign_levelsetphi(const double phivalue) { levelset_phi_ = phivalue; }; - //! return 1 if x > 0, -1 if x < 0 and 0 if x = 0 + //! Return 1 if x > 0, -1 if x < 0 and 0 if x = 0 + //! \param[in] x double value inline double sgn(double x) noexcept { return (x > 0) ? 1. : ((x < 0) ? -1. : 0); }; @@ -119,44 +114,44 @@ class ParticleXMPM : public Particle { //! Volume using Particle::volume_; //! Size of particle - using Particle:: size_; + using Particle::size_; //! Size of particle in natural coordinates - using Particle:: natural_size_; + using Particle::natural_size_; //! Stresses - using Particle:: stress_; + using Particle::stress_; //! Strains - using Particle:: strain_; + using Particle::strain_; //! dvolumetric strain using Particle::dvolumetric_strain_; //! Volumetric strain at centroid using Particle::volumetric_strain_centroid_; //! Strain rate - using Particle:: strain_rate_; + using Particle::strain_rate_; //! dstrains - using Particle:: dstrain_; + using Particle::dstrain_; //! Velocity - using Particle:: velocity_; + using Particle::velocity_; //! Displacement - using Particle:: displacement_; + using Particle::displacement_; //! Particle velocity constraints - using Particle:: particle_velocity_constraints_; + using Particle::particle_velocity_constraints_; //! Set traction - using Particle:: set_traction_; + using Particle::set_traction_; //! Surface Traction (given as a stress; force/area) - using Particle:: traction_; + using Particle::traction_; //! Shape functions - using Particle:: shapefn_; + using Particle::shapefn_; //! dN/dX - using Particle:: dn_dx_; + using Particle::dn_dx_; //! dN/dX at cell centroid - using Particle:: dn_dx_centroid_; + using Particle::dn_dx_centroid_; //! Logger - using Particle:: console_; + using Particle::console_; //! Map of vector properties - using Particle:: properties_; - -private: - //! level set values for discontinuity + using Particle::properties_; + + private: + //! level set value: phi for discontinuity double levelset_phi_{0.}; }; // ParticleXMPM class } // namespace mpm diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index ea8a24a4e..c8f906992 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -22,19 +22,13 @@ mpm::ParticleXMPM::ParticleXMPM(Index id, const VectorDim& coord, console_ = std::make_unique(logger, mpm::stdout_sink); } - - - // Initialise particle properties template void mpm::ParticleXMPM::initialise() { levelset_phi_ = 0.; - - // Initialize vector data properties - this->properties_["levelset"] = [&]() { VectorDim levelset{levelset_phi_,0,0};return levelset; }; + }; } - //! Map particle mass and momentum to nodes template void mpm::ParticleXMPM::map_mass_momentum_to_nodes() noexcept { @@ -60,8 +54,6 @@ void mpm::ParticleXMPM::map_mass_momentum_to_nodes() noexcept { } } - - // Compute strain rate of the particle template <> inline Eigen::Matrix mpm::ParticleXMPM<3>::compute_strain_rate( @@ -71,6 +63,7 @@ inline Eigen::Matrix mpm::ParticleXMPM<3>::compute_strain_rate( const double tolerance = 1.E-16; Eigen::Vector3d vel; vel.setZero(); + // Compute corresponding nodal velocity for (unsigned i = 0; i < this->nodes_.size(); ++i) { if (nodes_[i]->discontinuity_enrich()) { double nodal_mass = @@ -103,6 +96,25 @@ inline Eigen::Matrix mpm::ParticleXMPM<3>::compute_strain_rate( return strain_rate; } +// Compute strain of the particle +template +void mpm::ParticleXMPM::compute_strain(double dt) noexcept { + // Assign strain rate + strain_rate_ = this->compute_strain_rate(dn_dx_, mpm::ParticlePhase::Solid); + // Update dstrain + dstrain_ = strain_rate_ * dt; + // Update strain + strain_ += dstrain_; + + // Compute at centroid + // Strain rate for reduced integration + const Eigen::Matrix strain_rate_centroid = + this->compute_strain_rate(dn_dx_centroid_, mpm::ParticlePhase::Solid); + + // Assign volumetric strain at centroid + dvolumetric_strain_ = dt * strain_rate_centroid.head(Tdim).sum(); + volumetric_strain_centroid_ += dvolumetric_strain_; +} //! Map body force template @@ -179,8 +191,6 @@ inline void mpm::ParticleXMPM<3>::map_internal_force() noexcept { } } - - // Compute updated position of the particle template void mpm::ParticleXMPM::compute_updated_position( @@ -255,5 +265,3 @@ void mpm::ParticleXMPM::compute_updated_position( // Update displacement (displacement is initialized from zero) this->displacement_ += nodal_velocity * dt; } - - diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index 0c6d8bb49..8426ccf4f 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -506,7 +506,7 @@ void mpm::MPMBase::write_vtk(mpm::Index step, mpm::Index max_steps) { #endif //! VTK vector variables - std::vector vtk_vector_data = {"displacements", "velocities","levelset"}; + std::vector vtk_vector_data = {"displacements", "velocities"}; // Write VTK attributes for (const auto& attribute : vtk_vector_data) { diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index 4204cac67..c6aa9a239 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -170,18 +170,23 @@ bool mpm::XMPMExplicit::solve() { std::placeholders::_1)); } if (discontinuity_) { + // locate points of discontinuity mesh_->locate_discontinuity_mesh(); + // Iterate over each points to compute shapefn mesh_->compute_shapefn_discontinuity(); + // obtain the normal direction of each enrich nodes mesh_->compute_normal_vector_discontinuity(); - mesh_->iterate_over_nodes_predicate( - std::bind(&mpm::NodeBase::compute_normal_vector, - std::placeholders::_1), - std::bind(&mpm::NodeBase::discontinuity_enrich, std::placeholders::_1)); + + // + // mesh_->iterate_over_nodes_predicate( + // std::bind(&mpm::NodeBase::compute_normal_vector, + // std::placeholders::_1), + // std::bind(&mpm::NodeBase::discontinuity_enrich, + // std::placeholders::_1)); } - // Assign mass and momentum to nodes mesh_->iterate_over_particles( @@ -381,24 +386,26 @@ bool mpm::XMPMExplicit::initialise_discontinuities() { // Create a new discontinuity surface from JSON object auto discontinuity = - Factory, unsigned, const Json&>::instance()->create( - discontunity_type, std::move(discontinuity_id), - discontinuity_props); + Factory, unsigned, + const Json&>::instance() + ->create(discontunity_type, std::move(discontinuity_id), + discontinuity_props); - // Get discontinuity input type + // Get discontinuity input type auto io_type = discontinuity_props["io_type"].template get(); // discontinuity file - std::string discontinuity_file = - io_->file_name(discontinuity_props["file"].template get()); + std::string discontinuity_file = io_->file_name( + discontinuity_props["file"].template get()); // Create a mesh reader auto discontunity_io = Factory>::instance()->create(io_type); // Create points and cells from file - discontinuity->initialize(discontunity_io->read_mesh_nodes(discontinuity_file), - discontunity_io->read_mesh_cells(discontinuity_file)); + discontinuity->initialize( + discontunity_io->read_mesh_nodes(discontinuity_file), + discontunity_io->read_mesh_cells(discontinuity_file)); // Add discontinuity to list auto result = discontinuities_.insert( std::make_pair(discontinuity_id, discontinuity)); diff --git a/include/xmpm/discontinuity_3d.h b/include/xmpm/discontinuity_3d.h index ffe30abcd..ced6331d0 100644 --- a/include/xmpm/discontinuity_3d.h +++ b/include/xmpm/discontinuity_3d.h @@ -18,29 +18,28 @@ class Discontinuity3D : public DiscontinuityBase { Discontinuity3D(unsigned id, const Json& discontinuity_props); // initialization - virtual bool initialize( - const std::vector& coordinates, - const std::vector>& pointsets); + virtual bool initialize(const std::vector& points, + const std::vector>& cells); //! create elements from file - virtual bool create_elements( - const std::vector>& elements) override; + virtual bool create_areas( + const std::vector>& cells) override; // initialize the center and normal of the triangular elements bool initialize_center_normal(); // return the cross product of ab and bc VectorDim three_cross_product(const VectorDim& a, const VectorDim& b, - const VectorDim& c); + const VectorDim& c); // return the levelset values of each doordinates //! \param[in] the vector of the coordinates - void compute_levelset(const std::vector& coordinates, - std::vector& phi_list) override; + void compute_levelset(const std::vector& coordinates, + std::vector& phi_list) override; // return the normal vectors of given coordinates //! \param[in] the coordinates - void compute_normal( - const VectorDim& coordinates, VectorDim& normal_vector) override; + void compute_normal(const VectorDim& coordinates, + VectorDim& normal_vector) override; protected: using mpm::DiscontinuityBase::points_; @@ -53,7 +52,7 @@ class Discontinuity3D : public DiscontinuityBase { private: // vector of elements - std::vector> elements_; + std::vector> elements_; // number of elements //delete mpm::Index numelement_; diff --git a/include/xmpm/discontinuity_3d.tcc b/include/xmpm/discontinuity_3d.tcc index 19d69f095..e89757641 100644 --- a/include/xmpm/discontinuity_3d.tcc +++ b/include/xmpm/discontinuity_3d.tcc @@ -1,7 +1,7 @@ template mpm::Discontinuity3D::Discontinuity3D(unsigned id, const Json& discontinuity_props) - :DiscontinuityBase(id, discontinuity_props) { + : DiscontinuityBase(id, discontinuity_props) { numelement_ = 0; try { @@ -17,49 +17,49 @@ mpm::Discontinuity3D::Discontinuity3D(unsigned id, } } - // initialization - template - bool mpm::Discontinuity3D::initialize( - const std::vector& coordinates, - const std::vector>& pointsets) { - bool status = true; - // Create points from file - bool point_status = this->create_points(coordinates); - if (!point_status) { - status = false; - throw std::runtime_error( - "Addition of points in discontinuity to mesh failed"); - } - // Create elements from file - bool element_status = create_elements(pointsets); - if (!element_status) { - status = false; - throw std::runtime_error( - "Addition of elements in discontinuity to mesh failed"); - } +// initialization +template +bool mpm::Discontinuity3D::initialize( + const std::vector& points, + const std::vector>& cells) { + bool status = true; + // Create points from file + bool point_status = this->create_points(points); + if (!point_status) { + status = false; + throw std::runtime_error( + "Addition of points in discontinuity to mesh failed"); + } + // Create elements from file + bool element_status = create_areas(cells); + if (!element_status) { + status = false; + throw std::runtime_error( + "Addition of elements in discontinuity to mesh failed"); + } - bool normal_status = initialize_center_normal(); - if (!normal_status) { - status = false; - throw std::runtime_error( - "initialized the center and normal of the discontunity failed"); - } - return status; - }; + bool normal_status = initialize_center_normal(); + if (!normal_status) { + status = false; + throw std::runtime_error( + "initialized the center and normal of the discontunity failed"); + } + return status; +}; //! create elements from file template -bool mpm::Discontinuity3D::create_elements( - const std::vector>& elements) { +bool mpm::Discontinuity3D::create_areas( + const std::vector>& cells) { bool status = true; try { // Check if elements is empty - if (elements.empty()) throw std::runtime_error("List of elements is empty"); + if (cells.empty()) throw std::runtime_error("List of elements is empty"); // Iterate over all elements - for (const auto& points : elements) { + for (const auto& points : cells) { - mpm::discontinuity_element element(points); + mpm::discontinuity_area element(points); elements_.emplace_back(element); // } @@ -93,8 +93,8 @@ bool mpm::Discontinuity3D<3>::initialize_center_normal() { // the normal of the element normal = three_cross_product(points_[points[0]].coordinates(), - points_[points[1]].coordinates(), - points_[points[2]].coordinates()); + points_[points[1]].coordinates(), + points_[points[2]].coordinates()); double det = std::sqrt(normal[0] * normal[0] + normal[1] * normal[1] + normal[2] * normal[2]); normal = 1.0 / det * normal; @@ -148,18 +148,17 @@ void mpm::Discontinuity3D::compute_levelset( // return the normal vectors of given coordinates //! \param[in] the coordinates template -void mpm::Discontinuity3D::compute_normal( - const VectorDim& coordinates, VectorDim& normal_vector) { - // find the nearest distance from particle to cell: need to do by global - // searching and local searching - double distance = std::numeric_limits::max(); - for (const auto& element : elements_) { - double Vertical_distance = - element.Vertical_distance(coordinates); // Vertical_distance(coor); - if(std::abs(distance) > std::abs(Vertical_distance)) - { - distance = Vertical_distance; - normal_vector = element.normal(); - } +void mpm::Discontinuity3D::compute_normal(const VectorDim& coordinates, + VectorDim& normal_vector) { + // find the nearest distance from particle to cell: need to do by global + // searching and local searching + double distance = std::numeric_limits::max(); + for (const auto& element : elements_) { + double Vertical_distance = + element.Vertical_distance(coordinates); // Vertical_distance(coor); + if (std::abs(distance) > std::abs(Vertical_distance)) { + distance = Vertical_distance; + normal_vector = element.normal(); } + } } \ No newline at end of file diff --git a/include/xmpm/discontinuity_base.h b/include/xmpm/discontinuity_base.h index 61e36ea2b..a496a26b4 100644 --- a/include/xmpm/discontinuity_base.h +++ b/include/xmpm/discontinuity_base.h @@ -16,7 +16,6 @@ struct discontinuity_point; //! class for to describe the discontinuous surface //! \brief -//! \details nodes, lines and areas //! \tparam Tdim Dimension template class DiscontinuityBase { @@ -25,7 +24,8 @@ class DiscontinuityBase { using VectorDim = Eigen::Matrix; //! Constructor with id - //! \param[in] discontinuity_properties discontinuity properties + //! \param[in] discontinuity id + //! \param[in] discontinuity properties json DiscontinuityBase(unsigned id, const Json& discontinuity_props); //! Destructor @@ -38,16 +38,17 @@ class DiscontinuityBase { DiscontinuityBase& operator=(const DiscontinuityBase&) = delete; // initialization + //! \param[in] the coordinates of all points + //! \param[in] the point index of each areas virtual bool initialize( - const std::vector& coordinates, - const std::vector>& pointsets) = 0; + const std::vector& points, + const std::vector>& cells) = 0; //! create points from file - bool create_points(const std::vector& coordinates); + bool create_points(const std::vector& points); //! create elements from file - virtual bool create_elements( - const std::vector>& elements) { + virtual bool create_areas(const std::vector>& cells) { return true; }; @@ -57,9 +58,9 @@ class DiscontinuityBase { std::vector& phi_list) = 0; // return the normal vectors of given coordinates -//! \param[in] the coordinates -virtual void compute_normal( - const VectorDim& coordinates, VectorDim& normal_vector) = 0; + //! \param[in] the coordinates + virtual void compute_normal(const VectorDim& coordinates, + VectorDim& normal_vector) = 0; // return self_contact bool self_contact() { return self_contact_; }; @@ -90,7 +91,7 @@ virtual void compute_normal( std::vector> points_; // number of points - mpm::Index numpoint_; //delete + mpm::Index numpoint_; // delete // self-contact bool self_contact_{true}; @@ -174,12 +175,12 @@ struct discontinuity_line { }; template -struct discontinuity_element { +struct discontinuity_area { public: //! Define a vector of size dimension using VectorDim = Eigen::Matrix; - discontinuity_element(const std::vector& points) { + discontinuity_area(const std::vector& points) { for (int i = 0; i < points.size(); ++i) points_[i] = points[i]; } //! Return points indices @@ -188,9 +189,9 @@ struct discontinuity_element { inline void set_center(VectorDim& center) { center_ = center; } inline void set_normal(VectorDim& normal) { normal_ = normal; } - + //! Reture normal of the elements - VectorDim normal() const {return normal_;} + VectorDim normal() const { return normal_; } double Vertical_distance(const VectorDim& coor) const { return (coor[0] - center_[0]) * normal_[0] + From 701cdd9bbc84aa9892b57bed1095588a086e6b1a Mon Sep 17 00:00:00 2001 From: yong liang Date: Sun, 16 Aug 2020 21:12:30 -0700 Subject: [PATCH 18/91] :pencil::hammer::construction:clean the discontinuity base class --- include/node.h | 5 +- include/node_base.h | 4 +- include/node_xmpm.tcc | 28 ++++--- include/particles/particle_xmpm.tcc | 1 - include/xmpm/discontinuity_3d.h | 12 +-- include/xmpm/discontinuity_3d.tcc | 43 ++++++----- include/xmpm/discontinuity_base.h | 91 ++++++++++++++--------- include/xmpm/discontinuity_base.tcc | 6 +- include/xmpm/discontinuity_base_point.tcc | 7 +- 9 files changed, 105 insertions(+), 92 deletions(-) diff --git a/include/node.h b/include/node.h index c268c6dbd..1a15ef69a 100644 --- a/include/node.h +++ b/include/node.h @@ -275,10 +275,11 @@ class Node : public NodeBase { void compute_multimaterial_normal_unit_vector() override; //! Assign whether the node is enriched - //! \param[in] discontinuity_enrich: true or false + //! \param[in] discontinuity discontinuity_enrich: true or false void assign_discontinuity_enrich(bool discontinuity) { discontinuity_enrich_ = discontinuity; }; + //! Return whether the node is enriched bool discontinuity_enrich() const { return discontinuity_enrich_; }; @@ -314,7 +315,7 @@ class Node : public NodeBase { return discontinuity_prop_id_; }; - //! Compute normal direction of each enrich node + //! Compute normal direction for discontinuity void compute_normal_vector() noexcept override; private: diff --git a/include/node_base.h b/include/node_base.h index 194b337d0..c22a448a0 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -270,7 +270,7 @@ class NodeBase { const std::string& property, unsigned nprops = 1) noexcept = 0; //! Assign whether the node is enriched - //! \param[in] discontinuity_enrich: true or false + //! \param[in] discontinuity discontinuity_enrich: true or false virtual void assign_discontinuity_enrich(bool discontinuity) = 0; //! Return whether the node is enriched @@ -300,7 +300,7 @@ class NodeBase { //! Return the discontinuity_prop_id virtual unsigned discontinuity_prop_id() const noexcept = 0; - //! Compute normal direction of each enrich node + //! Compute normal direction for discontinuity virtual void compute_normal_vector() noexcept = 0; }; // NodeBase class } // namespace mpm diff --git a/include/node_xmpm.tcc b/include/node_xmpm.tcc index 2e52633aa..609bbf1d3 100644 --- a/include/node_xmpm.tcc +++ b/include/node_xmpm.tcc @@ -104,7 +104,7 @@ void mpm::Nodeassign_property( "external_force_enrich", discontinuity_prop_id_ * Tdim + direction, 0, momentum, 1); - } else { // need to do + } else { // need to be done // Velocity constraints on general boundaries // Compute inverse rotation matrix const Eigen::Matrix inverse_rotation_matrix = @@ -129,10 +129,11 @@ void mpm::Node::self_contact_discontinuity( double dt) noexcept { if (!discontinuity_enrich_) return; - + // single phase for solid unsigned phase = 0; const double tolerance = 1.0E-15; - + + //obtain the enriched values of enriched nodes Eigen::Matrix mass_enrich = property_handle_->property("mass_enrich", discontinuity_prop_id_, 0, 1); Eigen::Matrix momenta_enrich = property_handle_->property( @@ -158,13 +159,13 @@ void mpm::Node::self_contact_discontinuity( 0) return; - // the contact momentum for sticking contact + // the contact momentum, force vector for sticking contact auto momentum_contact = (mass_enrich(phase) * momentum_.col(phase) - mass_(phase) * momenta_enrich) / mass_(phase); auto force_contact = momentum_contact / dt; - //! friction_coef < 0: move together without slide + // friction_coef < 0: move together without slide // need to be done double friction_coef = 0; @@ -175,33 +176,36 @@ void mpm::Node::self_contact_discontinuity( discontinuity_prop_id_, 0, force_contact.col(phase), Tdim); } else { + //the contact momentum, force value for sticking contact at normal direction double momentum_contact_norm = momentum_contact.col(phase).dot(normal_vector); double force_contact_norm = momentum_contact_norm / dt; - // the maximum frictional contact force - double max_frictional_force = friction_coef * abs(force_contact_norm); + // the maximum friction contact force + double max_friction_force = friction_coef * abs(force_contact_norm); + // the contact momentum, force vector for sticking contact at tangential direction auto momentum_tangential = momentum_contact.col(phase) - momentum_contact_norm * normal_vector; auto force_tangential = momentum_tangential / dt; + //the friction force magnitude double force_tangential_value = force_tangential.norm(); - double frictional_force = force_tangential_value < max_frictional_force + double force_friction = force_tangential_value < max_friction_force ? force_tangential_value - : max_frictional_force; + : max_friction_force; - //! adjust the momentum and force + // adjust the momentum and force property_handle_->update_property( "momenta_enrich", discontinuity_prop_id_, 0, momentum_contact_norm * normal_vector + - frictional_force * force_tangential.col(phase).normalized() * dt, + force_friction * force_tangential.col(phase).normalized() * dt, Tdim); property_handle_->update_property( "external_force_enrich", discontinuity_prop_id_, 0, force_contact_norm * normal_vector + - frictional_force * force_tangential.col(phase).normalized(), + force_friction * force_tangential.col(phase).normalized(), Tdim); } } diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index c8f906992..9ec1411bc 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -26,7 +26,6 @@ mpm::ParticleXMPM::ParticleXMPM(Index id, const VectorDim& coord, template void mpm::ParticleXMPM::initialise() { levelset_phi_ = 0.; - }; } //! Map particle mass and momentum to nodes diff --git a/include/xmpm/discontinuity_3d.h b/include/xmpm/discontinuity_3d.h index ced6331d0..8ec010c2d 100644 --- a/include/xmpm/discontinuity_3d.h +++ b/include/xmpm/discontinuity_3d.h @@ -19,11 +19,11 @@ class Discontinuity3D : public DiscontinuityBase { // initialization virtual bool initialize(const std::vector& points, - const std::vector>& cells); + const std::vector>& surfs); //! create elements from file - virtual bool create_areas( - const std::vector>& cells) override; + virtual bool create_surfaces( + const std::vector>& surfs) override; // initialize the center and normal of the triangular elements bool initialize_center_normal(); @@ -46,16 +46,12 @@ class Discontinuity3D : public DiscontinuityBase { using mpm::DiscontinuityBase::console_; - using mpm::DiscontinuityBase::numpoint_; - using mpm::DiscontinuityBase::friction_coef_; private: // vector of elements - std::vector> elements_; + std::vector> surfaces_; - // number of elements //delete - mpm::Index numelement_; }; } // namespace mpm diff --git a/include/xmpm/discontinuity_3d.tcc b/include/xmpm/discontinuity_3d.tcc index e89757641..903093626 100644 --- a/include/xmpm/discontinuity_3d.tcc +++ b/include/xmpm/discontinuity_3d.tcc @@ -3,7 +3,6 @@ mpm::Discontinuity3D::Discontinuity3D(unsigned id, const Json& discontinuity_props) : DiscontinuityBase(id, discontinuity_props) { - numelement_ = 0; try { // assign friction_coef_ if it's given in input file if (discontinuity_props.contains("friction_coefficient")) @@ -21,7 +20,7 @@ mpm::Discontinuity3D::Discontinuity3D(unsigned id, template bool mpm::Discontinuity3D::initialize( const std::vector& points, - const std::vector>& cells) { + const std::vector>& surfs) { bool status = true; // Create points from file bool point_status = this->create_points(points); @@ -31,7 +30,7 @@ bool mpm::Discontinuity3D::initialize( "Addition of points in discontinuity to mesh failed"); } // Create elements from file - bool element_status = create_areas(cells); + bool element_status = create_surfaces(surfs); if (!element_status) { status = false; throw std::runtime_error( @@ -49,19 +48,19 @@ bool mpm::Discontinuity3D::initialize( //! create elements from file template -bool mpm::Discontinuity3D::create_areas( - const std::vector>& cells) { +bool mpm::Discontinuity3D::create_surfaces( + const std::vector>& surfs) { bool status = true; try { // Check if elements is empty - if (cells.empty()) throw std::runtime_error("List of elements is empty"); + if (surfs.empty()) throw std::runtime_error("List of elements is empty"); // Iterate over all elements - for (const auto& points : cells) { + for (const auto& points : surfs) { - mpm::discontinuity_area element(points); + mpm::discontinuity_surface element(points); - elements_.emplace_back(element); // + surfaces_.emplace_back(element); // } } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); @@ -79,7 +78,7 @@ bool mpm::Discontinuity3D<3>::initialize_center_normal() { VectorDim normal; Eigen::Matrix points; - for (auto& element : elements_) { + for (auto& element : surfaces_) { points = element.points(); // the center of the element @@ -89,7 +88,7 @@ bool mpm::Discontinuity3D<3>::initialize_center_normal() { points_[points[1]].coordinates()[i] + points_[points[2]].coordinates()[i]); - element.set_center(center); + element.assign_center(center); // the normal of the element normal = three_cross_product(points_[points[0]].coordinates(), @@ -99,7 +98,7 @@ bool mpm::Discontinuity3D<3>::initialize_center_normal() { normal[2] * normal[2]); normal = 1.0 / det * normal; - element.set_normal(normal); + element.assign_normal(normal); } } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); @@ -131,12 +130,12 @@ void mpm::Discontinuity3D::compute_levelset( // find the nearest distance from particle to cell: need to do by global // searching and local searching double distance = std::numeric_limits::max(); - for (const auto& element : elements_) { - double Vertical_distance = - element.Vertical_distance(coor); // Vertical_distance(coor); - distance = std::abs(distance) < std::abs(Vertical_distance) + for (const auto& element : surfaces_) { + double vertical_distance = + element.vertical_distance(coor); // vertical_distance(coor); + distance = std::abs(distance) < std::abs(vertical_distance) ? distance - : Vertical_distance; + : vertical_distance; if (!distance) distance = 1e-16; } @@ -153,11 +152,11 @@ void mpm::Discontinuity3D::compute_normal(const VectorDim& coordinates, // find the nearest distance from particle to cell: need to do by global // searching and local searching double distance = std::numeric_limits::max(); - for (const auto& element : elements_) { - double Vertical_distance = - element.Vertical_distance(coordinates); // Vertical_distance(coor); - if (std::abs(distance) > std::abs(Vertical_distance)) { - distance = Vertical_distance; + for (const auto& element : surfaces_) { + double vertical_distance = + element.vertical_distance(coordinates); // vertical_distance(coor); + if (std::abs(distance) > std::abs(vertical_distance)) { + distance = vertical_distance; normal_vector = element.normal(); } } diff --git a/include/xmpm/discontinuity_base.h b/include/xmpm/discontinuity_base.h index a496a26b4..8c625f6e0 100644 --- a/include/xmpm/discontinuity_base.h +++ b/include/xmpm/discontinuity_base.h @@ -14,7 +14,7 @@ namespace mpm { template struct discontinuity_point; -//! class for to describe the discontinuous surface +//! class for describe the discontinuous surface //! \brief //! \tparam Tdim Dimension template @@ -37,49 +37,53 @@ class DiscontinuityBase { //! Delete assignement operator DiscontinuityBase& operator=(const DiscontinuityBase&) = delete; - // initialization + //! initialization //! \param[in] the coordinates of all points - //! \param[in] the point index of each areas + //! \param[in] the point index of each surface virtual bool initialize( const std::vector& points, - const std::vector>& cells) = 0; + const std::vector>& surfs) = 0; //! create points from file + //! \param[in] points the coordinates list of points bool create_points(const std::vector& points); //! create elements from file - virtual bool create_areas(const std::vector>& cells) { + //! \param[in] surfs the point index list of each surface + virtual bool create_surfaces(const std::vector>& surfs) { return true; }; - // return the levelset values of each doordinates - //! \param[in] the vector of the coordinates + // return the levelset values of each coordinates + //! \param[in] coordinates coordinates + //! \param[in] phi_list the reference of phi for all coordinates virtual void compute_levelset(const std::vector& coordinates, std::vector& phi_list) = 0; - // return the normal vectors of given coordinates - //! \param[in] the coordinates + //! compute the normal vectors of coordinates + //! \param[in] coordinates The coordinates + //! \param[in] normal vector the normal vector of the given coordinates virtual void compute_normal(const VectorDim& coordinates, VectorDim& normal_vector) = 0; - // return self_contact - bool self_contact() { return self_contact_; }; + //! return self_contact + bool self_contact() const { return self_contact_; }; - // return the friction coefficient - double friction_coef() { return friction_coef_; }; + //! return the friction coefficient + double friction_coef() const { return friction_coef_; }; - // return the number of the points - mpm::Index npoints() { return points_.size(); }; + //! return the number of the points + mpm::Index npoints() const { return points_.size(); }; - void points_list(std::vector>& points) { - points = points_; - } //! Locate points in a cell - void locate_discontinuity_mesh(Vector>& cells, - Map>& map_cells) noexcept; + //! \param[in] cells vector of cells + //! \param[in] map_cells map of cells + void locate_discontinuity_mesh(const Vector>& cells, + const Map>& map_cells) noexcept; //! Compute updated position - void compute_updated_position(double dt) noexcept; + //! \param[in] dt Time-step + void compute_updated_position(const double dt) noexcept; //! Compute shape function void compute_shapefn() noexcept; @@ -88,24 +92,26 @@ class DiscontinuityBase { //! Logger std::unique_ptr console_; + //! vector of points std::vector> points_; - // number of points - mpm::Index numpoint_; // delete - - // self-contact + //! self-contact bool self_contact_{true}; + //! friction coefficient double friction_coef_; }; // DiscontinuityBase class + +//! struct of discontinuity point template struct discontinuity_point { public: //! Define a vector of size dimension using VectorDim = Eigen::Matrix; + //! construct with coordinate discontinuity_point(const VectorDim& coordinate) { coordinates_ = coordinate; cell_ = nullptr; @@ -114,10 +120,11 @@ struct discontinuity_point { } //! Return coordinates - //! \retval coordinates_ return coordinates of the nodebase + //! \retval return coordinates VectorDim coordinates() const { return coordinates_; } //! Return cell_id + //! \retval return cell_id_ Index cell_id() const { return cell_id_; } //! Assign a cell to point @@ -136,9 +143,11 @@ struct discontinuity_point { //! Compute reference coordinates in a cell bool compute_reference_location() noexcept; - //! Locate points in a cell - void locate_discontinuity_mesh(Vector>& cells, - Map>& map_cells) noexcept; + //! Locate particles in a cell + //! \param[in] cells vector of cells + //! \param[in] map_cells map of cells + void locate_discontinuity_mesh(const Vector>& cells, + const Map>& map_cells) noexcept; //! Compute updated position void compute_updated_position(double dt) noexcept; @@ -155,7 +164,6 @@ struct discontinuity_point { Eigen::VectorXd shapefn_; //! Cell std::shared_ptr> cell_; - //! Reference coordinates (in a cell) Eigen::Matrix xi_; //! Vector of nodal pointers @@ -164,6 +172,7 @@ struct discontinuity_point { std::shared_ptr console_; }; +//! struct of discontinuity line: for 2d, need to be done struct discontinuity_line { public: //! Return points indices @@ -174,26 +183,34 @@ struct discontinuity_line { Eigen::Matrix points_; }; +//! struct of discontinuity surface: triangle template -struct discontinuity_area { +struct discontinuity_surface { public: //! Define a vector of size dimension using VectorDim = Eigen::Matrix; - discontinuity_area(const std::vector& points) { + //! construct with points indices + discontinuity_surface(const std::vector& points) { for (int i = 0; i < points.size(); ++i) points_[i] = points[i]; } //! Return points indices Eigen::Matrix points() const { return points_; } - inline void set_center(VectorDim& center) { center_ = center; } + //! assign the surface center + //! \param[in] center coordinates of the surface center + inline void assign_center(VectorDim& center) { center_ = center; } - inline void set_normal(VectorDim& normal) { normal_ = normal; } + //! assign the surface normal vector + //! \param[in] normal normal vector of the surface + inline void assign_normal(VectorDim& normal) { normal_ = normal; } //! Reture normal of the elements VectorDim normal() const { return normal_; } - double Vertical_distance(const VectorDim& coor) const { + //! Return the vertical distance to the surface + //! \param[in] coor coordinates + double vertical_distance(const VectorDim& coor) const { return (coor[0] - center_[0]) * normal_[0] + (coor[1] - center_[1]) * normal_[1] + (coor[2] - center_[2]) * normal_[2]; @@ -203,10 +220,10 @@ struct discontinuity_area { //! points indices Eigen::Matrix points_; - // the center of the triangular elements + // the center coordinates VectorDim center_; - // the normal of the triangular elements + // the normal vector VectorDim normal_; }; diff --git a/include/xmpm/discontinuity_base.tcc b/include/xmpm/discontinuity_base.tcc index e7a232295..ea76693b9 100644 --- a/include/xmpm/discontinuity_base.tcc +++ b/include/xmpm/discontinuity_base.tcc @@ -3,8 +3,6 @@ template mpm::DiscontinuityBase::DiscontinuityBase( unsigned id, const Json& discontinuity_props) { - numpoint_ = 0; - friction_coef_ = 0; std::string logger = "discontinuity::" + std::to_string(id); @@ -36,8 +34,8 @@ bool mpm::DiscontinuityBase::create_points( } //! Locate points in a cell template -void mpm::DiscontinuityBase::locate_discontinuity_mesh( - Vector>& cells, Map>& map_cells) noexcept { +void mpm::DiscontinuityBase::locate_discontinuity_mesh(const + Vector>& cells, const Map>& map_cells) noexcept { for (auto& point : this->points_) point.locate_discontinuity_mesh(cells, map_cells); } diff --git a/include/xmpm/discontinuity_base_point.tcc b/include/xmpm/discontinuity_base_point.tcc index 95c30ca94..deb921538 100644 --- a/include/xmpm/discontinuity_base_point.tcc +++ b/include/xmpm/discontinuity_base_point.tcc @@ -79,9 +79,8 @@ bool mpm::discontinuity_point::compute_reference_location() noexcept { //! Locate points in a cell template -void mpm::discontinuity_point::locate_discontinuity_mesh( - Vector>& cells, Map>& map_cells) noexcept { - +void mpm::discontinuity_point::locate_discontinuity_mesh(const + Vector>& cells, const Map>& map_cells) noexcept { // Check the current cell if it is not invalid if (cell_id() != std::numeric_limits::max()) { // If a cell id is present, but not a cell locate the cell from map @@ -113,7 +112,7 @@ void mpm::discontinuity_point::locate_discontinuity_mesh( // Compute updated position of the particle template void mpm::discontinuity_point::compute_updated_position( - double dt) noexcept { + const double dt) noexcept { // Check if point has a valid cell ptr if (cell_ == nullptr) return; // Get interpolated nodal velocity From 7c58d827c938df5cc11ff9364c797159d444f2d2 Mon Sep 17 00:00:00 2001 From: yong liang Date: Sun, 16 Aug 2020 23:01:59 -0700 Subject: [PATCH 19/91] :pencil:clean discontinuity3d class --- include/solvers/xmpm_explicit.tcc | 1 - include/xmpm/discontinuity_3d.h | 34 +++++++++++++++++++------------ include/xmpm/discontinuity_3d.tcc | 13 +++++------- 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index c6aa9a239..32f753fda 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -180,7 +180,6 @@ bool mpm::XMPMExplicit::solve() { // obtain the normal direction of each enrich nodes mesh_->compute_normal_vector_discontinuity(); - // // mesh_->iterate_over_nodes_predicate( // std::bind(&mpm::NodeBase::compute_normal_vector, // std::placeholders::_1), diff --git a/include/xmpm/discontinuity_3d.h b/include/xmpm/discontinuity_3d.h index 8ec010c2d..bb5395866 100644 --- a/include/xmpm/discontinuity_3d.h +++ b/include/xmpm/discontinuity_3d.h @@ -5,7 +5,7 @@ //! MPM namespace namespace mpm { - +//! Discontinuity3D class derived from DiscontinuityBase class for 3D template class Discontinuity3D : public DiscontinuityBase { @@ -14,42 +14,50 @@ class Discontinuity3D : public DiscontinuityBase { using VectorDim = Eigen::Matrix; //! Constructor with id - //! \param[in] discontinuity_properties discontinuity properties + //! \param[in] discontinuity_props discontinuity properties Discontinuity3D(unsigned id, const Json& discontinuity_props); - // initialization + //! initialization + //! \param[in] the coordinates of all points + //! \param[in] the point index of each surface virtual bool initialize(const std::vector& points, const std::vector>& surfs); - + //! create elements from file + //! \param[in] surfs the point index list of each surface virtual bool create_surfaces( const std::vector>& surfs) override; - // initialize the center and normal of the triangular elements + //! initialize the center and normal vector of each surface bool initialize_center_normal(); - // return the cross product of ab and bc + //! return the cross product of ab and bc + //! \param[in] a,b,c coordinates of three points VectorDim three_cross_product(const VectorDim& a, const VectorDim& b, const VectorDim& c); - // return the levelset values of each doordinates - //! \param[in] the vector of the coordinates + // return the levelset values of each coordinates + //! \param[in] coordinates coordinates + //! \param[in] phi_list the reference of phi for all coordinates void compute_levelset(const std::vector& coordinates, std::vector& phi_list) override; - // return the normal vectors of given coordinates - //! \param[in] the coordinates + + //! compute the normal vectors of coordinates + //! \param[in] coordinates The coordinates + //! \param[in] normal vector the normal vector of the given coordinates void compute_normal(const VectorDim& coordinates, VectorDim& normal_vector) override; protected: + //! vector of points using mpm::DiscontinuityBase::points_; - + //! Logger using mpm::DiscontinuityBase::console_; - + //! friction coefficient using mpm::DiscontinuityBase::friction_coef_; private: - // vector of elements + // vector of surfaces std::vector> surfaces_; }; diff --git a/include/xmpm/discontinuity_3d.tcc b/include/xmpm/discontinuity_3d.tcc index 903093626..2868a2d22 100644 --- a/include/xmpm/discontinuity_3d.tcc +++ b/include/xmpm/discontinuity_3d.tcc @@ -41,20 +41,20 @@ bool mpm::Discontinuity3D::initialize( if (!normal_status) { status = false; throw std::runtime_error( - "initialized the center and normal of the discontunity failed"); + "initialization of the center and normal vector of the discontunity failed"); } return status; }; -//! create elements from file +//! create surfaces from file template bool mpm::Discontinuity3D::create_surfaces( const std::vector>& surfs) { bool status = true; try { - // Check if elements is empty - if (surfs.empty()) throw std::runtime_error("List of elements is empty"); + // Check if surfs is empty + if (surfs.empty()) throw std::runtime_error("List of surfaces is empty"); // Iterate over all elements for (const auto& points : surfs) { @@ -111,7 +111,6 @@ bool mpm::Discontinuity3D<3>::initialize_center_normal() { template Eigen::Matrix mpm::Discontinuity3D::three_cross_product( const VectorDim& a, const VectorDim& b, const VectorDim& c) { - VectorDim threecross; threecross[0] = (b[1] - a[1]) * (c[2] - b[2]) - (b[2] - a[2]) * (c[1] - b[1]); threecross[1] = (b[2] - a[2]) * (c[0] - b[0]) - (b[0] - a[0]) * (c[2] - b[2]); @@ -120,7 +119,6 @@ Eigen::Matrix mpm::Discontinuity3D::three_cross_product( } // return the levelset values of each coordinates -//! \param[in] the vector of the coordinates template void mpm::Discontinuity3D::compute_levelset( const std::vector& coordinates, std::vector& phi_list) { @@ -145,11 +143,10 @@ void mpm::Discontinuity3D::compute_levelset( } // return the normal vectors of given coordinates -//! \param[in] the coordinates template void mpm::Discontinuity3D::compute_normal(const VectorDim& coordinates, VectorDim& normal_vector) { - // find the nearest distance from particle to cell: need to do by global + // find the nearest distance from particle to cell: need to do better by global // searching and local searching double distance = std::numeric_limits::max(); for (const auto& element : surfaces_) { From c3ad208402958346782811ee7e80e02c862e8c1b Mon Sep 17 00:00:00 2001 From: yong liang Date: Mon, 17 Aug 2020 07:50:18 -0700 Subject: [PATCH 20/91] :constructuin:assign friction coefficient for nodes --- include/mesh.h | 7 +-- include/mesh.tcc | 7 ++- include/node.tcc | 1 + include/node_xmpm.tcc | 12 +---- include/xmpm/discontinuity_3d.h | 3 ++ include/xmpm/discontinuity_3d.tcc | 47 +++++++++++-------- include/xmpm/discontinuity_base.h | 13 ++++- ...base_point.tcc => discontinuity_point.tcc} | 12 ++++- 8 files changed, 62 insertions(+), 40 deletions(-) rename include/xmpm/{discontinuity_base_point.tcc => discontinuity_point.tcc} (92%) diff --git a/include/mesh.h b/include/mesh.h index c67e4e74a..ae03cf22f 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -465,13 +465,14 @@ class Mesh { //! Locate points of discontinuity in a cell void locate_discontinuity_mesh(); - // Update the discontinuity position + //! Update the discontinuity position + //! \param[in] dt Analysis time step void compute_updated_position_discontinuity(double dt); - // Update the discontinuity position + //! Update the discontinuity position void compute_shapefn_discontinuity(); - // compute the normal vector of enriched nodes at the discontinuity + //! compute the normal vector of enriched nodes at the discontinuity void compute_normal_vector_discontinuity(); private: diff --git a/include/mesh.tcc b/include/mesh.tcc index 572afa90f..c897e2d92 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1904,7 +1904,8 @@ void mpm::Mesh::create_nodal_properties_discontinuity() { nodal_properties_->create_property("external_force_enrich", nrows, 1); nodal_properties_->create_property("normal_unit_vectors_discontinuity", nrows, 1); - + nodal_properties_->create_property("friction_coef", + nodes_.size(), 1); // Iterate over all nodes to initialise the property handle in each node // and assign its node id as the prop id in the nodal property data pool for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) @@ -1945,7 +1946,6 @@ void mpm::Mesh::compute_updated_position_discontinuity(double dt) { discontinuity->compute_updated_position(dt); } } - //! compute shape function template void mpm::Mesh::compute_shapefn_discontinuity() { @@ -1958,9 +1958,8 @@ void mpm::Mesh::compute_shapefn_discontinuity() { // compute the normal vector of enriched nodes at the discontinuity template void mpm::Mesh::compute_normal_vector_discontinuity() { - // need to set + // just compute for one discontinuity for now unsigned discontinuity_id = 0; - auto discontinuity = discontinuities_[discontinuity_id]; VectorDim normal; diff --git a/include/node.tcc b/include/node.tcc index ba979d6da..421090f52 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -34,6 +34,7 @@ void mpm::Node::initialise() noexcept { acceleration_.setZero(); status_ = false; material_ids_.clear(); + //mark: need to check discontinuity_enrich_ = true; } diff --git a/include/node_xmpm.tcc b/include/node_xmpm.tcc index 609bbf1d3..9ee058d5f 100644 --- a/include/node_xmpm.tcc +++ b/include/node_xmpm.tcc @@ -54,12 +54,6 @@ bool mpm::Node::intergrate_momentum_discontinuity( // when velocity is set. this->apply_velocity_constraints_discontinuity(); - // need to be done - Eigen::Matrix normal{0.44721359474414313, 0, - 0.89442719147920724}; - property_handle_->assign_property("normal_unit_vectors_discontinuity", - discontinuity_prop_id_, 0, normal, Tdim); - this->self_contact_discontinuity(dt); this->apply_velocity_constraints_discontinuity(); @@ -81,9 +75,6 @@ void mpm::Nodevelocity_(direction, phase) = constraint.second; - // need to do for one direction - this->momentum_(direction, phase) = this->mass(phase) * constraint.second; property_handle_->assign_property( "momenta_enrich", discontinuity_prop_id_ * Tdim + direction, 0, @@ -92,7 +83,6 @@ void mpm::Nodeacceleration_(direction, phase) = 0.; this->internal_force_(direction, phase) = 0; this->external_force_(direction, phase) = 0; @@ -167,7 +157,7 @@ void mpm::Node::self_contact_discontinuity( // friction_coef < 0: move together without slide // need to be done - double friction_coef = 0; + double friction_coef = property_handle_->property("friction_coef", discontinuity_prop_id_, 0, 1)(0,0); if (friction_coef < 0) { property_handle_->update_property("momenta_enrich", discontinuity_prop_id_, diff --git a/include/xmpm/discontinuity_3d.h b/include/xmpm/discontinuity_3d.h index bb5395866..ee8afd464 100644 --- a/include/xmpm/discontinuity_3d.h +++ b/include/xmpm/discontinuity_3d.h @@ -48,6 +48,9 @@ class Discontinuity3D : public DiscontinuityBase { void compute_normal(const VectorDim& coordinates, VectorDim& normal_vector) override; + //! Assign point friction coefficient + void assign_point_friction_coef() noexcept override; + protected: //! vector of points using mpm::DiscontinuityBase::points_; diff --git a/include/xmpm/discontinuity_3d.tcc b/include/xmpm/discontinuity_3d.tcc index 2868a2d22..983af1204 100644 --- a/include/xmpm/discontinuity_3d.tcc +++ b/include/xmpm/discontinuity_3d.tcc @@ -29,12 +29,12 @@ bool mpm::Discontinuity3D::initialize( throw std::runtime_error( "Addition of points in discontinuity to mesh failed"); } - // Create elements from file - bool element_status = create_surfaces(surfs); - if (!element_status) { + // Create surfaces from file + bool surf_status = create_surfaces(surfs); + if (!surf_status) { status = false; throw std::runtime_error( - "Addition of elements in discontinuity to mesh failed"); + "Addition of surfaces in discontinuity to mesh failed"); } bool normal_status = initialize_center_normal(); @@ -43,6 +43,8 @@ bool mpm::Discontinuity3D::initialize( throw std::runtime_error( "initialization of the center and normal vector of the discontunity failed"); } + + this->assign_point_friction_coef(); return status; }; @@ -55,12 +57,12 @@ bool mpm::Discontinuity3D::create_surfaces( try { // Check if surfs is empty if (surfs.empty()) throw std::runtime_error("List of surfaces is empty"); - // Iterate over all elements + // Iterate over all surfaces for (const auto& points : surfs) { - mpm::discontinuity_surface element(points); + mpm::discontinuity_surface surf(points); - surfaces_.emplace_back(element); // + surfaces_.emplace_back(surf); // } } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); @@ -69,7 +71,7 @@ bool mpm::Discontinuity3D::create_surfaces( return status; } -// initialize the center and normal of the elements +// initialize the center and normal of the surfaces template <> bool mpm::Discontinuity3D<3>::initialize_center_normal() { bool status = true; @@ -78,19 +80,19 @@ bool mpm::Discontinuity3D<3>::initialize_center_normal() { VectorDim normal; Eigen::Matrix points; - for (auto& element : surfaces_) { - points = element.points(); + for (auto& surf: surfaces_) { + points = surf.points(); - // the center of the element + // the center of the surfaces for (int i = 0; i < 3; i++) center[i] = 1.0 / 3 * (points_[points[0]].coordinates()[i] + points_[points[1]].coordinates()[i] + points_[points[2]].coordinates()[i]); - element.assign_center(center); + surf.assign_center(center); - // the normal of the element + // the normal of the surfaces normal = three_cross_product(points_[points[0]].coordinates(), points_[points[1]].coordinates(), points_[points[2]].coordinates()); @@ -98,7 +100,7 @@ bool mpm::Discontinuity3D<3>::initialize_center_normal() { normal[2] * normal[2]); normal = 1.0 / det * normal; - element.assign_normal(normal); + surf.assign_normal(normal); } } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); @@ -128,9 +130,9 @@ void mpm::Discontinuity3D::compute_levelset( // find the nearest distance from particle to cell: need to do by global // searching and local searching double distance = std::numeric_limits::max(); - for (const auto& element : surfaces_) { + for (const auto& surf : surfaces_) { double vertical_distance = - element.vertical_distance(coor); // vertical_distance(coor); + surf.vertical_distance(coor); // vertical_distance(coor); distance = std::abs(distance) < std::abs(vertical_distance) ? distance : vertical_distance; @@ -149,12 +151,19 @@ void mpm::Discontinuity3D::compute_normal(const VectorDim& coordinates, // find the nearest distance from particle to cell: need to do better by global // searching and local searching double distance = std::numeric_limits::max(); - for (const auto& element : surfaces_) { + for (const auto& surf : surfaces_) { double vertical_distance = - element.vertical_distance(coordinates); // vertical_distance(coor); + surf.vertical_distance(coordinates); // vertical_distance(coor); if (std::abs(distance) > std::abs(vertical_distance)) { distance = vertical_distance; - normal_vector = element.normal(); + normal_vector = surf.normal(); } } +} + +//! Assign point friction coefficient +template +void mpm::Discontinuity3D::assign_point_friction_coef() noexcept{ +for(auto & point: points_) + point.assign_friction_coef(friction_coef_); } \ No newline at end of file diff --git a/include/xmpm/discontinuity_base.h b/include/xmpm/discontinuity_base.h index 8c625f6e0..5c7dcc9ad 100644 --- a/include/xmpm/discontinuity_base.h +++ b/include/xmpm/discontinuity_base.h @@ -88,6 +88,9 @@ class DiscontinuityBase { //! Compute shape function void compute_shapefn() noexcept; + //! Assign point friction coefficient + virtual void assign_point_friction_coef() noexcept = 0; + protected: //! Logger std::unique_ptr console_; @@ -113,6 +116,8 @@ struct discontinuity_point { //! construct with coordinate discontinuity_point(const VectorDim& coordinate) { + + friction_coef_ = 0; coordinates_ = coordinate; cell_ = nullptr; //! Logger @@ -155,6 +160,10 @@ struct discontinuity_point { //! Compute shape function void compute_shapefn() noexcept; + //! Assign point friction coefficient + //! \param[in] friction_coef + void assign_friction_coef(double friction_coef) noexcept {friction_coef_ = friction_coef;}; + private: //! point coordinates VectorDim coordinates_; @@ -170,6 +179,8 @@ struct discontinuity_point { std::vector>> nodes_; //! Logger std::shared_ptr console_; + //! friction coefficient + double friction_coef_{0.}; }; //! struct of discontinuity line: for 2d, need to be done @@ -230,6 +241,6 @@ struct discontinuity_surface { } // namespace mpm #include "discontinuity_base.tcc" -#include "discontinuity_base_point.tcc" +#include "discontinuity_point.tcc" #endif // MPM_DiscontinuityBase_H_ diff --git a/include/xmpm/discontinuity_base_point.tcc b/include/xmpm/discontinuity_point.tcc similarity index 92% rename from include/xmpm/discontinuity_base_point.tcc rename to include/xmpm/discontinuity_point.tcc index deb921538..a176e8b6d 100644 --- a/include/xmpm/discontinuity_base_point.tcc +++ b/include/xmpm/discontinuity_point.tcc @@ -4,6 +4,8 @@ bool mpm::discontinuity_point::assign_cell_xi( const std::shared_ptr>& cellptr, const Eigen::Matrix& xi) { bool status = true; + Eigen::Matrix friction_coef; + friction_coef(0,0) = friction_coef_; try { // Assign cell to the new cell ptr, if point can be found in new cell if (cellptr != nullptr) { @@ -11,9 +13,10 @@ bool mpm::discontinuity_point::assign_cell_xi( cell_ = cellptr; cell_id_ = cellptr->id(); nodes_ = cell_->nodes(); - // assign discontinuity_enrich - for (unsigned i = 0; i < nodes_.size(); ++i) + for (unsigned i = 0; i < nodes_.size(); ++i){ nodes_[i]->assign_discontinuity_enrich(true); + nodes_[i]->update_discontinuity_property(true, "friction_coef", friction_coef, 0, 1); + } // Assign the reference location of particle bool xi_nan = false; @@ -40,6 +43,8 @@ template bool mpm::discontinuity_point::assign_cell( const std::shared_ptr>& cellptr) { bool status = true; + Eigen::Matrix friction_coef; + friction_coef(0,0) = friction_coef_; try { Eigen::Matrix xi; // Assign cell to the new cell ptr, if point can be found in new cell @@ -50,7 +55,10 @@ bool mpm::discontinuity_point::assign_cell( nodes_ = cell_->nodes(); // assign discontinuity_enrich for (unsigned i = 0; i < nodes_.size(); ++i) + { nodes_[i]->assign_discontinuity_enrich(true); + nodes_[i]->update_discontinuity_property(true, "friction_coef", friction_coef, 0, 1); + } } else { console_->warn("Points of discontinuity cannot be found in cell!"); } From ce0c7b3830cda3c6b995399a1bd9dfc5045dd5bf Mon Sep 17 00:00:00 2001 From: Yong Liang <60054151+yliang-sn@users.noreply.github.com> Date: Tue, 25 Aug 2020 13:45:39 -0700 Subject: [PATCH 21/91] Update include/mesh.h Co-authored-by: Krishna Kumar <3963513+kks32@users.noreply.github.com> --- include/mesh.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mesh.h b/include/mesh.h index ae03cf22f..a7fa87a8d 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -455,7 +455,7 @@ class Mesh { void create_nodal_properties_discontinuity(); //! Initialise discontinuities - //! \param[in] discontinuities + //! \param[in] discontinuities List of discontinuities void initialise_discontinuities( const std::map>>& discontinuities) { From 2d95f12bbc49943442179bd75f15678ea20a66f0 Mon Sep 17 00:00:00 2001 From: yong liang Date: Sat, 1 Aug 2020 13:08:31 -0700 Subject: [PATCH 22/91] :tada::sparkles:creat xmpm solver and ParticleXMPM class --- CMakeLists.txt | 2 + include/io/logger.h | 3 + include/particles/particle_xmpm.h | 381 ++++++++++++ include/particles/particle_xmpm.tcc | 876 ++++++++++++++++++++++++++++ include/solvers/xmpm_explicit.h | 84 +++ include/solvers/xmpm_explicit.tcc | 333 +++++++++++ include/xmpm/discontinuity_3d.h | 79 +++ include/xmpm/discontinuity_3d.tcc | 99 ++++ include/xmpm/discontinuity_base.h | 185 ++++++ src/discontinuity.cc | 6 + src/io/logger.cc | 4 + src/mpm.cc | 5 + src/particle.cc | 6 + 13 files changed, 2063 insertions(+) create mode 100644 include/particles/particle_xmpm.h create mode 100644 include/particles/particle_xmpm.tcc create mode 100644 include/solvers/xmpm_explicit.h create mode 100644 include/solvers/xmpm_explicit.tcc create mode 100755 include/xmpm/discontinuity_3d.h create mode 100755 include/xmpm/discontinuity_3d.tcc create mode 100755 include/xmpm/discontinuity_base.h create mode 100755 src/discontinuity.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 284ae8d23..e425d8d38 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -146,6 +146,7 @@ include_directories(BEFORE ${mpm_SOURCE_DIR}/include/solvers/mpm_scheme/ ${mpm_SOURCE_DIR}/external/ ${mpm_SOURCE_DIR}/tests/include/ + ${mpm_SOURCE_DIR}/include/xmpm/ ) # mpm executable @@ -169,6 +170,7 @@ SET(mpm_src ${mpm_SOURCE_DIR}/src/node.cc ${mpm_SOURCE_DIR}/src/particle.cc ${mpm_SOURCE_DIR}/src/quadrature.cc + ${mpm_SOURCE_DIR}/src/discontinuity.cc ) add_executable(mpm ${mpm_SOURCE_DIR}/src/main.cc ${mpm_src} ${mpm_vtk}) diff --git a/include/io/logger.h b/include/io/logger.h index 082a0e874..01c1afcf7 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 xmpm_explicit_logger; }; } // namespace mpm diff --git a/include/particles/particle_xmpm.h b/include/particles/particle_xmpm.h new file mode 100644 index 000000000..3b2897d21 --- /dev/null +++ b/include/particles/particle_xmpm.h @@ -0,0 +1,381 @@ +#ifndef MPM_PARTICLE_XMPM_H_ +#define MPM_PARTICLE_XMPM_H_ + +#include +#include +#include +#include +#include + +#include "cell.h" +#include "logger.h" +#include "particle_base.h" + +namespace mpm { + +//! ParticleXMPM class +//! \brief Base class that stores the information about particles +//! \details ParticleXMPM class: id_ and coordinates. +//! \tparam Tdim Dimension +template +class ParticleXMPM : public ParticleBase { + public: + //! Define a vector of size dimension + using VectorDim = Eigen::Matrix; + + //! Define DOFs + static const unsigned Tdof = (Tdim == 1) ? 1 : 3 * (Tdim - 1); + + //! Construct a particle with id and coordinates + //! \param[in] id Particle id + //! \param[in] coord coordinates of the particle + ParticleXMPM(Index id, const VectorDim& coord); + + //! Construct a 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) + ParticleXMPM(Index id, const VectorDim& coord, bool status); + + //! Destructor + ~ParticleXMPM() override{}; + + //! Delete copy constructor + ParticleXMPM(const ParticleXMPM&) = delete; + + //! Delete assignment operator + ParticleXMPM& operator=(const ParticleXMPM&) = 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 + virtual bool initialise_particle( + 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; + + //! Initialise properties + void initialise() override; + + //! Compute reference coordinates in a cell + bool compute_reference_location() noexcept override; + + //! Return reference location + VectorDim reference_location() const override { return xi_; } + + //! Assign a cell to particle + //! If point is in new cell, assign new cell and remove particle id from old + //! cell. If point can't be found in the new cell, check if particle is still + //! valid in the old cell, if it is leave it as is. If not, set cell as null + //! \param[in] cellptr Pointer to a cell + bool assign_cell(const std::shared_ptr>& cellptr) override; + + //! Assign a cell to particle + //! If point is in new cell, assign new cell and remove particle id from old + //! cell. If point can't be found in the new cell, check if particle is still + //! valid in the old cell, if it is leave it as is. If not, set cell as null + //! \param[in] cellptr Pointer to a cell + //! \param[in] xi Local coordinates of the point in reference cell + bool assign_cell_xi(const std::shared_ptr>& cellptr, + const Eigen::Matrix& xi) override; + + //! Assign cell id + //! \param[in] id Cell id + bool assign_cell_id(Index id) override; + + //! Return cell id + Index cell_id() const override { return cell_id_; } + + //! Return cell ptr status + bool cell_ptr() const override { return cell_ != nullptr; } + + //! Remove cell associated with the particle + void remove_cell() override; + + //! Compute shape functions of a particle, based on local coordinates + void compute_shapefn() noexcept override; + + //! Assign volume + //! \param[in] volume Volume of particle + bool assign_volume(double volume) override; + + //! Return 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 + //! \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; + + //! Map multimaterial displacements to nodes + void map_multimaterial_displacements_to_nodes() noexcept override; + + //! Map multimaterial domain gradients to nodes + void map_multimaterial_domain_gradients_to_nodes() noexcept override; + + //! 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; } + + //! Return mass of the particles + double mass() const override { return mass_; } + + //! Assign material + //! \param[in] material Pointer to a material + //! \param[in] phase Index to indicate phase + bool assign_material(const std::shared_ptr>& material, + unsigned phase = mpm::ParticlePhase::Solid) override; + + //! Compute strain + //! \param[in] dt Analysis time step + void compute_strain(double dt) noexcept override; + + //! Return strain of the particle + Eigen::Matrix strain() const override { return strain_; } + + //! Return strain rate of the particle + Eigen::Matrix strain_rate() const override { + return strain_rate_; + }; + + //! Return dvolumetric strain of centroid + //! \retval dvolumetric strain at centroid + double dvolumetric_strain() const override { return dvolumetric_strain_; } + + //! Return volumetric strain of centroid + //! \retval volumetric strain at centroid + double volumetric_strain_centroid() const override { + return volumetric_strain_centroid_; + } + + //! Initial stress + //! \param[in] stress Initial sress + void initial_stress(const Eigen::Matrix& stress) override { + this->stress_ = stress; + } + + //! Compute stress + void compute_stress() noexcept override; + + //! 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 + //! \retval status Assignment status + bool assign_velocity(const VectorDim& velocity) override; + + //! Return velocity of the particle + VectorDim velocity() const override { return velocity_; } + + //! Return displacement of the particle + VectorDim displacement() const override { return displacement_; } + + //! 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 traction of the particle + //! \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; + + //! Return a state variable + //! \param[in] var State variable + //! \param[in] phase Index to indicate phase + //! \retval Quantity of the state history variable + double state_variable( + const std::string& var, + unsigned phase = mpm::ParticlePhase::Solid) const override { + return (state_variables_[phase].find(var) != state_variables_[phase].end()) + ? state_variables_[phase].at(var) + : std::numeric_limits::quiet_NaN(); + } + + //! 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 + 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 tensor data of particles + //! \param[in] property Property string + //! \retval vecdata Tensor data of particle property + Eigen::VectorXd tensor_data(const std::string& property) 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; + + //! Assign material id of this particle to nodes + void append_material_id_to_nodes() const override; + + //! Return the number of neighbour particles + unsigned nneighbours() const override { return neighbours_.size(); }; + + //! Assign neighbour particles + //! \param[in] neighbours set of id of the neighbouring particles + //! \retval insertion_status Return the successful addition of a node + void assign_neighbours(const std::vector& neighbours) override; + + //! Return neighbour ids + std::vector neighbours() const override { return neighbours_; }; + + protected: + //! Initialise particle material container + //! \details This function allocate memory and initialise the material related + //! containers according to the particle phase, i.e. solid or fluid particle + //! has phase_size = 1, whereas two-phase (solid-fluid) or three-phase + //! (solid-water-air) particle have phase_size = 2 and 3, respectively. + //! \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 + //! \retval strain rate at particle inside a cell + inline Eigen::Matrix compute_strain_rate( + const Eigen::MatrixXd& dn_dx, unsigned phase) noexcept; + + private: + //! particle id + using ParticleBase::id_; + //! coordinates + using ParticleBase::coordinates_; + //! Reference coordinates (in a cell) + using ParticleBase::xi_; + //! Cell + using ParticleBase::cell_; + //! Cell id + using ParticleBase::cell_id_; + //! Nodes + using ParticleBase::nodes_; + //! Status + using ParticleBase::status_; + //! Material + using ParticleBase::material_; + //! Material id + using ParticleBase::material_id_; + //! State variables + using ParticleBase::state_variables_; + //! Neighbour particles + using ParticleBase::neighbours_; + //! 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 + Eigen::Matrix natural_size_; + //! Stresses + Eigen::Matrix stress_; + //! Strains + Eigen::Matrix strain_; + //! dvolumetric strain + double dvolumetric_strain_{0.}; + //! Volumetric strain at centroid + double volumetric_strain_centroid_{0.}; + //! Strain rate + 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 + Eigen::MatrixXd dn_dx_centroid_; + //! Logger + std::unique_ptr console_; + //! Map of vector properties + std::map> properties_; + //!level set values for discontinuity + double levelset_phi_{0.}; +}; // ParticleXMPM class +} // namespace mpm + +#include "particle_xmpm.tcc" + +#endif // MPM_PARTICLE_XMPM_H__ diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc new file mode 100644 index 000000000..8220bac9c --- /dev/null +++ b/include/particles/particle_xmpm.tcc @@ -0,0 +1,876 @@ +//! Construct a particle with id and coordinates +template +mpm::ParticleXMPM::ParticleXMPM(Index id, const VectorDim& coord) + : mpm::ParticleBase(id, coord) { + this->initialise(); + // Clear cell ptr + cell_ = nullptr; + // Nodes + nodes_.clear(); + // Set material containers + this->initialise_material(1); + // Logger + std::string logger = + "particlexmpm" + std::to_string(Tdim) + "d::" + std::to_string(id); + console_ = std::make_unique(logger, mpm::stdout_sink); +} + +//! Construct a particle with id, coordinates and status +template +mpm::ParticleXMPM::ParticleXMPM(Index id, const VectorDim& coord, bool status) + : mpm::ParticleBase(id, coord, status) { + this->initialise(); + cell_ = nullptr; + nodes_.clear(); + // Set material containers + this->initialise_material(1); + //! Logger + std::string logger = + "particlexmpm" + 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::ParticleXMPM::initialise_particle(const HDF5Particle& particle) { + + // Assign id + this->id_ = particle.id; + // Mass + this->mass_ = particle.mass; + // Volume + this->volume_ = particle.volume; + // Mass Density + 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; + // Initialise particle size + for (unsigned i = 0; i < Tdim; ++i) this->natural_size_(i) = psize(i); + + // Coordinates + Eigen::Vector3d coordinates; + coordinates << particle.coord_x, particle.coord_y, particle.coord_z; + // Initialise coordinates + for (unsigned i = 0; i < Tdim; ++i) this->coordinates_(i) = coordinates(i); + + // Displacement + Eigen::Vector3d displacement; + displacement << particle.displacement_x, particle.displacement_y, + particle.displacement_z; + // Initialise displacement + 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) this->velocity_(i) = velocity(i); + + // Stress + this->stress_[0] = particle.stress_xx; + this->stress_[1] = particle.stress_yy; + this->stress_[2] = particle.stress_zz; + this->stress_[3] = particle.tau_xy; + this->stress_[4] = particle.tau_yz; + this->stress_[5] = particle.tau_xz; + + // Strain + this->strain_[0] = particle.strain_xx; + this->strain_[1] = particle.strain_yy; + this->strain_[2] = particle.strain_zz; + this->strain_[3] = particle.gamma_xy; + this->strain_[4] = particle.gamma_yz; + this->strain_[5] = particle.gamma_xz; + + // Volumetric strain + this->volumetric_strain_centroid_ = particle.epsilon_v; + + // Status + this->status_ = particle.status; + + // Cell id + this->cell_id_ = particle.cell_id; + this->cell_ = nullptr; + + // Clear nodes + this->nodes_.clear(); + + // Material id + this->material_id_[mpm::ParticlePhase::Solid] = particle.material_id; + + return true; +} + +//! Initialise particle data from HDF5 +template +bool mpm::ParticleXMPM::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 = this->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!"); + } + } + return status; +} + +//! Return particle data in HDF5 format +template +// cppcheck-suppress * +mpm::HDF5Particle mpm::ParticleXMPM::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::ParticleXMPM::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.; + levelset_phi_ = 0.; + + // Initialize vector data properties + this->properties_["stresses"] = [&]() { return stress(); }; + this->properties_["strains"] = [&]() { return strain(); }; + this->properties_["velocities"] = [&]() { return velocity(); }; + this->properties_["displacements"] = [&]() { return displacement(); }; +} + +//! Initialise particle material container +template +void mpm::ParticleXMPM::initialise_material(unsigned phase_size) { + material_.resize(phase_size); + material_id_.resize(phase_size); + state_variables_.resize(phase_size); + std::fill(material_.begin(), material_.end(), nullptr); + std::fill(material_id_.begin(), material_id_.end(), + std::numeric_limits::max()); + std::fill(state_variables_.begin(), state_variables_.end(), mpm::dense_map()); +} + +//! Assign material history variables +template +bool mpm::ParticleXMPM::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(phase) != nullptr && + this->material_id(phase) == material->id()) { + // Clone 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; + status = true; + } + } + return status; +} + +// Assign a cell to particle +template +bool mpm::ParticleXMPM::assign_cell( + const std::shared_ptr>& cellptr) { + bool status = true; + try { + Eigen::Matrix xi; + // Assign cell to the new cell ptr, if point can be found in new cell + if (cellptr->is_point_in_cell(this->coordinates_, &xi)) { + // if a cell already exists remove particle from that cell + if (cell_ != nullptr) cell_->remove_particle_id(this->id_); + + cell_ = cellptr; + cell_id_ = cellptr->id(); + // dn_dx centroid + dn_dx_centroid_ = cell_->dn_dx_centroid(); + // Copy nodal pointer to cell + nodes_.clear(); + nodes_ = cell_->nodes(); + + // Compute reference location of particle + bool xi_status = this->compute_reference_location(); + if (!xi_status) return false; + status = cell_->add_particle_id(this->id()); + } else { + throw std::runtime_error("Point cannot be found in cell!"); + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +// Assign a cell to particle +template +bool mpm::ParticleXMPM::assign_cell_xi( + const std::shared_ptr>& cellptr, + const Eigen::Matrix& xi) { + bool status = true; + try { + // Assign cell to the new cell ptr, if point can be found in new cell + if (cellptr != nullptr) { + // if a cell already exists remove particle from that cell + if (cell_ != nullptr) cell_->remove_particle_id(this->id_); + + cell_ = cellptr; + cell_id_ = cellptr->id(); + // dn_dx centroid + dn_dx_centroid_ = cell_->dn_dx_centroid(); + // Copy nodal pointer to cell + nodes_.clear(); + nodes_ = cell_->nodes(); + + // Assign the reference location of particle + bool xi_nan = false; + + // Check if point is within the cell + for (unsigned i = 0; i < xi.size(); ++i) + if (xi(i) < -1. || xi(i) > 1. || std::isnan(xi(i))) xi_nan = true; + + if (xi_nan == false) + this->xi_ = xi; + else + return false; + + status = cell_->add_particle_id(this->id()); + } else { + throw std::runtime_error("Point cannot be found in cell!"); + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +// Assign a cell id to particle +template +bool mpm::ParticleXMPM::assign_cell_id(mpm::Index id) { + bool status = false; + try { + // if a cell ptr is null + if (cell_ == nullptr && id != std::numeric_limits::max()) { + cell_id_ = id; + status = true; + } else { + throw std::runtime_error("Invalid cell id or cell is already assigned!"); + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +// Remove cell for the particle +template +void mpm::ParticleXMPM::remove_cell() { + // if a cell is not nullptr + if (cell_ != nullptr) cell_->remove_particle_id(this->id_); + cell_id_ = std::numeric_limits::max(); + // Clear all the nodes + nodes_.clear(); +} + +// Assign a material to particle +template +bool mpm::ParticleXMPM::assign_material( + const std::shared_ptr>& material, unsigned phase) { + bool status = false; + try { + // Check if material is valid and properties are set + if (material != nullptr) { + material_.at(phase) = material; + material_id_.at(phase) = material_[phase]->id(); + state_variables_.at(phase) = + material_[phase]->initialise_state_variables(); + status = true; + } else { + throw std::runtime_error("Material is undefined!"); + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + } + return status; +} + +// Compute reference location cell to particle +template +bool mpm::ParticleXMPM::compute_reference_location() noexcept { + // Set status of compute reference location + bool status = false; + // Compute local coordinates + Eigen::Matrix xi; + // Check if the point is in cell + if (cell_ != nullptr && cell_->is_point_in_cell(this->coordinates_, &xi)) { + this->xi_ = xi; + status = true; + } + + return status; +} + +// Compute shape functions and gradients +template +void mpm::ParticleXMPM::compute_shapefn() noexcept { + // Check if particle has a valid cell ptr + assert(cell_ != nullptr); + // Get element ptr of a cell + const auto element = cell_->element_ptr(); + + // Zero matrix + Eigen::Matrix zero = Eigen::Matrix::Zero(); + + // Compute shape function of the particle + shapefn_ = element->shapefn(this->xi_, this->natural_size_, zero); + + // Compute dN/dx + dn_dx_ = element->dn_dx(this->xi_, cell_->nodal_coordinates(), + this->natural_size_, zero); +} + +// Assign volume to the particle +template +bool mpm::ParticleXMPM::assign_volume(double volume) { + bool status = true; + try { + if (volume <= 0.) + throw std::runtime_error("Particle volume cannot be negative"); + + this->volume_ = volume; + // Compute size of particle in each direction + const double length = + std::pow(this->volume_, static_cast(1. / Tdim)); + // Set particle size as length on each side + this->size_.fill(length); + + if (cell_ != nullptr) { + // Get element ptr of a cell + const auto element = cell_->element_ptr(); + + // Set local particle length based on length of element in natural + // coordinates. Length/(npartices^(1/Dimension)) + this->natural_size_.fill( + element->unit_element_length() / + std::pow(cell_->nparticles(), static_cast(1. / Tdim))); + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +// Compute volume of the particle +template +void mpm::ParticleXMPM::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::ParticleXMPM::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::ParticleXMPM::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::ParticleXMPM::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 +template +void mpm::ParticleXMPM::map_multimaterial_mass_momentum_to_nodes() noexcept { + // Check if particle mass is set + 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) = mass_ * shapefn_[i]; + nodes_[i]->update_property(true, "masses", nodal_mass, this->material_id(), + 1); + nodes_[i]->update_property(true, "momenta", velocity_ * nodal_mass, + this->material_id(), Tdim); + } +} + +//! Map multimaterial displacements to nodes +template +void mpm::ParticleXMPM::map_multimaterial_displacements_to_nodes() noexcept { + // Check if particle mass is set + 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 = mass_ * shapefn_[i] * displacement_; + nodes_[i]->update_property(true, "displacements", displacement, + this->material_id(), Tdim); + } +} + +//! Map multimaterial domain gradients to nodes +template +void mpm::ParticleXMPM< + Tdim>::map_multimaterial_domain_gradients_to_nodes() noexcept { + // Check if particle volume is set + 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] = volume_ * dn_dx_(i, j); + nodes_[i]->update_property(true, "domain_gradients", gradient, + this->material_id(), Tdim); + } +} + +// Compute strain rate of the particle +template <> +inline Eigen::Matrix mpm::ParticleXMPM<1>::compute_strain_rate( + const Eigen::MatrixXd& dn_dx, unsigned phase) noexcept { + // Define strain rate + Eigen::Matrix strain_rate = Eigen::Matrix::Zero(); + + for (unsigned i = 0; i < this->nodes_.size(); ++i) { + Eigen::Matrix vel = nodes_[i]->velocity(phase); + strain_rate[0] += dn_dx(i, 0) * vel[0]; + } + + if (std::fabs(strain_rate(0)) < 1.E-15) strain_rate[0] = 0.; + return strain_rate; +} + +// Compute strain rate of the particle +template <> +inline Eigen::Matrix mpm::ParticleXMPM<2>::compute_strain_rate( + const Eigen::MatrixXd& dn_dx, unsigned phase) noexcept { + // Define strain rate + Eigen::Matrix strain_rate = Eigen::Matrix::Zero(); + + for (unsigned i = 0; i < this->nodes_.size(); ++i) { + Eigen::Matrix vel = nodes_[i]->velocity(phase); + strain_rate[0] += dn_dx(i, 0) * vel[0]; + strain_rate[1] += dn_dx(i, 1) * vel[1]; + strain_rate[3] += dn_dx(i, 1) * vel[0] + dn_dx(i, 0) * vel[1]; + } + + if (std::fabs(strain_rate[0]) < 1.E-15) strain_rate[0] = 0.; + if (std::fabs(strain_rate[1]) < 1.E-15) strain_rate[1] = 0.; + if (std::fabs(strain_rate[3]) < 1.E-15) strain_rate[3] = 0.; + return strain_rate; +} + +// Compute strain rate of the particle +template <> +inline Eigen::Matrix mpm::ParticleXMPM<3>::compute_strain_rate( + const Eigen::MatrixXd& dn_dx, unsigned phase) noexcept { + // Define strain rate + Eigen::Matrix strain_rate = Eigen::Matrix::Zero(); + + for (unsigned i = 0; i < this->nodes_.size(); ++i) { + Eigen::Matrix vel = nodes_[i]->velocity(phase); + strain_rate[0] += dn_dx(i, 0) * vel[0]; + strain_rate[1] += dn_dx(i, 1) * vel[1]; + strain_rate[2] += dn_dx(i, 2) * vel[2]; + strain_rate[3] += dn_dx(i, 1) * vel[0] + dn_dx(i, 0) * vel[1]; + strain_rate[4] += dn_dx(i, 2) * vel[1] + dn_dx(i, 1) * vel[2]; + strain_rate[5] += dn_dx(i, 2) * vel[0] + dn_dx(i, 0) * vel[2]; + } + + for (unsigned i = 0; i < strain_rate.size(); ++i) + if (std::fabs(strain_rate[i]) < 1.E-15) strain_rate[i] = 0.; + return strain_rate; +} + +// Compute strain of the particle +template +void mpm::ParticleXMPM::compute_strain(double dt) noexcept { + // Assign strain rate + strain_rate_ = this->compute_strain_rate(dn_dx_, mpm::ParticlePhase::Solid); + // Update dstrain + dstrain_ = strain_rate_ * dt; + // Update strain + strain_ += dstrain_; + + // Compute at centroid + // Strain rate for reduced integration + const Eigen::Matrix strain_rate_centroid = + this->compute_strain_rate(dn_dx_centroid_, mpm::ParticlePhase::Solid); + + // Assign volumetric strain at centroid + dvolumetric_strain_ = dt * strain_rate_centroid.head(Tdim).sum(); + volumetric_strain_centroid_ += dvolumetric_strain_; +} + +// Compute stress +template +void mpm::ParticleXMPM::compute_stress() noexcept { + // Check if material ptr is valid + assert(this->material() != nullptr); + // Calculate stress + this->stress_ = + (this->material()) + ->compute_stress(stress_, dstrain_, this, + &state_variables_[mpm::ParticlePhase::Solid]); +} + +//! Map body force +template +void mpm::ParticleXMPM::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::ParticleXMPM<1>::map_internal_force() noexcept { + // Compute nodal internal forces + 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]; + + nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Solid, force); + } +} + +//! Map internal force +template <> +inline void mpm::ParticleXMPM<2>::map_internal_force() noexcept { + // 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) * 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_; + + nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Solid, force); + } +} + +//! Map internal force +template <> +inline void mpm::ParticleXMPM<3>::map_internal_force() noexcept { + // 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) * stress_[0] + dn_dx_(i, 1) * stress_[3] + + dn_dx_(i, 2) * stress_[5]; + + force[1] = dn_dx_(i, 1) * stress_[1] + dn_dx_(i, 0) * stress_[3] + + dn_dx_(i, 2) * stress_[4]; + + force[2] = dn_dx_(i, 2) * stress_[2] + dn_dx_(i, 1) * stress_[4] + + dn_dx_(i, 0) * stress_[5]; + + force *= -1. * this->volume_; + + nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Solid, force); + } +} + +// Assign velocity to the particle +template +bool mpm::ParticleXMPM::assign_velocity( + const Eigen::Matrix& velocity) { + // Assign velocity + velocity_ = velocity; + return true; +} + +// Assign traction to the particle +template +bool mpm::ParticleXMPM::assign_traction(unsigned direction, double traction) { + bool status = false; + try { + if (direction >= Tdim || + 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); + status = true; + this->set_traction_ = true; + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +//! Map traction force +template +void mpm::ParticleXMPM::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::ParticleXMPM::compute_updated_position( + double dt, bool velocity_update) noexcept { + // 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); + + // 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); + + // Update particle velocity from interpolated nodal acceleration + this->velocity_ += nodal_acceleration * dt; + } + // Update particle velocity using interpolated nodal velocity + else + this->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; +} + +//! Map particle pressure to nodes +template +bool mpm::ParticleXMPM::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::ParticleXMPM::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 +template +void mpm::ParticleXMPM::apply_particle_velocity_constraints(unsigned dir, + double velocity) { + // Set particle velocity constraint + this->velocity_(dir) = velocity; +} + +//! Return particle tensor data +template +Eigen::VectorXd mpm::ParticleXMPM::tensor_data(const std::string& property) { + return this->properties_.at(property)(); +} + +//! Assign material id of this particle to nodes +template +void mpm::ParticleXMPM::append_material_id_to_nodes() const { + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->append_material_id(this->material_id()); +} + +//! Assign neighbour particles +template +void mpm::ParticleXMPM::assign_neighbours( + const std::vector& neighbours) { + neighbours_ = neighbours; + neighbours_.erase(std::remove(neighbours_.begin(), neighbours_.end(), id_), + neighbours_.end()); +} diff --git a/include/solvers/xmpm_explicit.h b/include/solvers/xmpm_explicit.h new file mode 100644 index 000000000..196915d1c --- /dev/null +++ b/include/solvers/xmpm_explicit.h @@ -0,0 +1,84 @@ +#ifndef MPM_XMPM_EXPLICIT_H_ +#define MPM_XMPM_EXPLICIT_H_ + +#ifdef USE_GRAPH_PARTITIONING +#include "graph.h" +#endif + +#include "mpm_base.h" + +namespace mpm { + +//! XMPMExplicit class +//! \brief A class that implements the fully explicit one phase mpm +//! \details A single-phase explicit MPM +//! \tparam Tdim Dimension +template +class XMPMExplicit : public MPMBase { + public: + //! Default constructor + XMPMExplicit(const std::shared_ptr& io); + + //! Solve + bool solve() override; + + //! Compute stress strain + //! \param[in] phase Phase to smooth pressure + void compute_stress_strain(unsigned phase); + + 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_; + //! Number of steps + 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 + + //! 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}; + //! Interface + bool interface_{false}; + +}; // XMPMExplicit class +} // namespace mpm + +#include "xmpm_explicit.tcc" + +#endif // MPM_XMPM_EXPLICIT_H_ diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc new file mode 100644 index 000000000..f8ac93850 --- /dev/null +++ b/include/solvers/xmpm_explicit.tcc @@ -0,0 +1,333 @@ +//! Constructor +template +mpm::XMPMExplicit::XMPMExplicit(const std::shared_ptr& io) + : mpm::MPMBase(io) { + //! Logger + console_ = spdlog::get("XMPMExplicit"); +} + +//! MPM Explicit compute stress strain +template +void mpm::XMPMExplicit::compute_stress_strain(unsigned phase) { + // 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)); + + // Pressure smoothing + if (pressure_smoothing_) this->pressure_smoothing(phase); + + // Iterate over each particle to compute stress + mesh_->iterate_over_particles(std::bind( + &mpm::ParticleBase::compute_stress, std::placeholders::_1)); +} + +//! MPM Explicit solver +template +bool mpm::XMPMExplicit::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 + + // Phase + const unsigned phase = 0; + + // 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_.at("pressure_smoothing").template get(); + + // Interface + if (analysis_.find("interface") != analysis_.end()) + interface_ = analysis_.at("interface").template get(); + + // Initialise material + bool mat_status = this->initialise_materials(); + if (!mat_status) { + status = false; + throw std::runtime_error("Initialisation of materials failed"); + } + + // Initialise mesh + bool mesh_status = this->initialise_mesh(); + if (!mesh_status) { + status = false; + throw std::runtime_error("Initialisation of mesh failed"); + } + + // Initialise particles + bool particle_status = this->initialise_particles(); + if (!particle_status) { + status = false; + throw std::runtime_error("Initialisation of particles failed"); + } + + // Initialise loading conditions + bool loading_status = this->initialise_loads(); + if (!loading_status) { + status = false; + throw std::runtime_error("Initialisation of loading failed"); + } + + // Create nodal properties + if (interface_) mesh_->create_nodal_properties(); + + // Compute mass + 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 + + // Inject particles + mesh_->inject_particles(this->step_ * this->dt_); + +#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 + + // Initialise nodal properties and append material ids to node + if (interface_) { + // Initialise nodal properties + mesh_->initialise_nodal_properties(); + + // Append material ids to nodes + mesh_->iterate_over_particles( + std::bind(&mpm::ParticleBase::append_material_id_to_nodes, + 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)); + +#ifdef USE_MPI + // Run if there is more than a single MPI task + if (mpi_size > 1) { + // MPI all reduce nodal mass + mesh_->template nodal_halo_exchange( + std::bind(&mpm::NodeBase::mass, std::placeholders::_1, phase), + std::bind(&mpm::NodeBase::update_mass, std::placeholders::_1, + false, phase, std::placeholders::_2)); + // MPI all reduce nodal momentum + mesh_->template nodal_halo_exchange, Tdim>( + std::bind(&mpm::NodeBase::momentum, std::placeholders::_1, + phase), + std::bind(&mpm::NodeBase::update_momentum, + std::placeholders::_1, false, phase, + std::placeholders::_2)); + } +#endif + + // Compute nodal velocity + mesh_->iterate_over_nodes_predicate( + std::bind(&mpm::NodeBase::compute_velocity, + std::placeholders::_1), + std::bind(&mpm::NodeBase::status, std::placeholders::_1)); + + if (interface_) { + // Map multimaterial properties from particles to nodes + mesh_->iterate_over_particles(std::bind( + &mpm::ParticleBase::map_multimaterial_mass_momentum_to_nodes, + std::placeholders::_1)); + + // Map multimaterial displacements from particles to nodes + mesh_->iterate_over_particles(std::bind( + &mpm::ParticleBase::map_multimaterial_displacements_to_nodes, + std::placeholders::_1)); + + // Map multimaterial domain gradients from particles to nodes + mesh_->iterate_over_particles(std::bind( + &mpm::ParticleBase::map_multimaterial_domain_gradients_to_nodes, + std::placeholders::_1)); + + // Compute multimaterial change in momentum + mesh_->iterate_over_nodes(std::bind( + &mpm::NodeBase::compute_multimaterial_change_in_momentum, + std::placeholders::_1)); + + // Compute multimaterial separation vector + mesh_->iterate_over_nodes(std::bind( + &mpm::NodeBase::compute_multimaterial_separation_vector, + std::placeholders::_1)); + + // Compute multimaterial normal unit vector + mesh_->iterate_over_nodes(std::bind( + &mpm::NodeBase::compute_multimaterial_normal_unit_vector, + std::placeholders::_1)); + } + + // Update stress first + if (this->stress_update_ == mpm::StressUpdate::USF) + this->compute_stress_strain(phase); + + // 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( + 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, phase, (this->step_ * this->dt_))); + } + +#pragma omp section + { + // Spawn a task for internal force + // Iterate over each particle to compute nodal internal force + mesh_->iterate_over_particles( + std::bind(&mpm::ParticleBase::map_internal_force, + std::placeholders::_1)); + } + } // Wait for tasks to finish + +#ifdef USE_MPI + // Run if there is more than a single MPI task + if (mpi_size > 1) { + // MPI all reduce external force + mesh_->template nodal_halo_exchange, Tdim>( + std::bind(&mpm::NodeBase::external_force, std::placeholders::_1, + phase), + std::bind(&mpm::NodeBase::update_external_force, + std::placeholders::_1, false, phase, + std::placeholders::_2)); + // MPI all reduce internal force + mesh_->template nodal_halo_exchange, Tdim>( + std::bind(&mpm::NodeBase::internal_force, std::placeholders::_1, + phase), + std::bind(&mpm::NodeBase::update_internal_force, + std::placeholders::_1, false, phase, + 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_cundall, + std::placeholders::_1, phase, this->dt_, damping_factor_), + std::bind(&mpm::NodeBase::status, std::placeholders::_1)); + else + mesh_->iterate_over_nodes_predicate( + std::bind(&mpm::NodeBase::compute_acceleration_velocity, + std::placeholders::_1, phase, this->dt_), + std::bind(&mpm::NodeBase::status, std::placeholders::_1)); + + // Iterate over each particle to compute updated position + mesh_->iterate_over_particles( + std::bind(&mpm::ParticleBase::compute_updated_position, + std::placeholders::_1, this->dt_, this->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(phase); + + // Locate particles + auto unlocatable_particles = mesh_->locate_particles_mesh(); + + if (!unlocatable_particles.empty() && this->locate_particles_) + throw std::runtime_error("Particle outside the mesh domain"); + // If unable to locate particles remove particles + if (!unlocatable_particles.empty() && !this->locate_particles_) + for (const auto& remove_particle : unlocatable_particles) + mesh_->remove_particle(remove_particle); + +#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 {}, Explicit {} solver duration: {} ms", mpi_rank, + (this->stress_update_ == mpm::StressUpdate::USL ? "USL" : "USF"), + std::chrono::duration_cast(solver_end - + solver_begin) + .count()); + + return status; +} diff --git a/include/xmpm/discontinuity_3d.h b/include/xmpm/discontinuity_3d.h new file mode 100755 index 000000000..2ebb13e0c --- /dev/null +++ b/include/xmpm/discontinuity_3d.h @@ -0,0 +1,79 @@ +#ifndef MPM_DISCONTINUITY_3D_H_ +#define MPM_DISCONTINUITY_3D_H_ + +#include "discontinuity_base.h" + +//! MPM namespace +namespace mpm { + +template +class Discontinuity_3D : public DiscontinuityBase { + + public: + //! Define a vector of size dimension + using VectorDim = Eigen::Matrix; + //constructor + Discontinuity_3D(); + + //initialization + virtual bool initialize(const std::vector& coordinates,const std::vector>& pointsets) + { + bool status = true; + // Create points from file + bool point_status = this->create_points(coordinates); + if (!point_status) { + status = false; + throw std::runtime_error("Addition of points in discontinuity to mesh failed"); + } + // Create elements from file + bool element_status = create_elements(pointsets); + if (!element_status) { + status = false; + throw std::runtime_error("Addition of elements in discontinuity to mesh failed"); + } + + bool normal_status = initialize_center_normal(); + if (!normal_status) { + status = false; + throw std::runtime_error("initialized the center and normal of the discontunity failed"); + } + return status; + }; + + //! create elements from file + virtual bool create_elements(const std::vector>& elements) override; + + //initialize the center and normal of the triangular elements + bool initialize_center_normal(); + + // return the cross product of ab and bc + VectorDim ThreeCross(const VectorDim& a,const VectorDim& b,const VectorDim& c); + + + //return the levelset values of each doordinates + //! \param[in] the vector of the coordinates + virtual void compute_levelset(const std::vector& coordinates, std::vector& phi_list) override; + + + protected: + + using mpm::DiscontinuityBase::points_; + + using mpm::DiscontinuityBase::console_; + + using mpm::DiscontinuityBase::numpoint_; + + private: + + //vector of elements + std::vector elements_; + + //number of elements + mpm::Index numelement_; + +}; + +} // namespace mpm +#include "discontinuity_3d.tcc" + +#endif // MPM_HEXAHEDRON_ELEMENT_H_ diff --git a/include/xmpm/discontinuity_3d.tcc b/include/xmpm/discontinuity_3d.tcc new file mode 100755 index 000000000..62b7eb8f1 --- /dev/null +++ b/include/xmpm/discontinuity_3d.tcc @@ -0,0 +1,99 @@ +template +mpm::Discontinuity_3D::Discontinuity_3D() +{ + numelement_ = 0; + + std::string logger = + "discontinuity" + std::to_string(Tdim) + "d"; + console_ = std::make_unique(logger, mpm::stdout_sink); +} + +//! create elements from file +template +bool mpm::Discontinuity_3D::create_elements(const std::vector>& elements) + { + + bool status = true; + try { + // Check if elements is empty + if (elements.empty()) + throw std::runtime_error("List of elements is empty"); + // Iterate over all elements + for (const auto& points : elements) { + + mpm::discontinuous_element element(points); + + elements_.emplace_back(element); // + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; + } + + //initialize the center and normal of the elements + template + bool mpm::Discontinuity_3D::initialize_center_normal() + { + bool status = true; + try { + VectorDim center; + VectorDim normal; + Eigen::Matrix points; + + for(auto& element : elements_) + { + points = element.points(); + + //the center of the element + for(int i=0; i<3; i++) + center[i] = 1.0/3*(points_[points[0]].coordinates()[i] + points_[points[1]].coordinates()[i] +points_[points[2]].coordinates()[i]); + + element.set_center(center); + + //the normal of the element + normal = ThreeCross(points_[points[0]].coordinates(),points_[points[1]].coordinates(),points_[points[2]].coordinates()); + double det = std::sqrt(normal[0]*normal[0] + normal[1]*normal[1] + normal[2]*normal[2]); + normal = 1.0/det * normal; + + element.set_normal(normal); + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; + } + +//return the cross product of ab X bc +template +Eigen::Matrix mpm::Discontinuity_3D::ThreeCross(const VectorDim& a,const VectorDim& b,const VectorDim& c){ + + VectorDim threecross; + threecross[0]=(b[1]-a[1])*(c[2]-b[2])-(b[2]-a[2])*(c[1]-b[1]); + threecross[1]=(b[2]-a[2])*(c[0]-b[0])-(b[0]-a[0])*(c[2]-b[2]); + threecross[2]=(b[0]-a[0])*(c[1]-b[1])-(b[1]-a[1])*(c[0]-b[0]); + return threecross; +} + +//return the levelset values of each doordinates +//! \param[in] the vector of the coordinates +template +void mpm::Discontinuity_3D::compute_levelset(const std::vector& coordinates,std::vector& phi_list){ + + mpm::Index i = 0; + for(const auto& coor:coordinates) + { + //find the nearest distance from particle to cell: need to do by global searching and local searching + double distance = std::numeric_limits::max(); + for(const auto& element:elements_) + { + double Vertical_distance_ = element.Vertical_distance(coor);// Vertical_distance(coor); + distance = std::abs(distance) < std::abs(Vertical_distance_)? distance:Vertical_distance_; + } + + phi_list[i] = distance; + ++i; + } +} \ No newline at end of file diff --git a/include/xmpm/discontinuity_base.h b/include/xmpm/discontinuity_base.h new file mode 100755 index 000000000..8be308b64 --- /dev/null +++ b/include/xmpm/discontinuity_base.h @@ -0,0 +1,185 @@ +#ifndef MPM_DISCONTINUITY_H_ +#define MPM_DISCONTINUITY_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "vector.h" + +namespace mpm { + +template +struct discontinuous_point +{ + public: + //! Define a vector of size dimension + using VectorDim = Eigen::Matrix; + + discontinuous_point(const VectorDim& coordinate) + { + coordinates_ = coordinate; + } + + + //! Return coordinates + //! \retval coordinates_ return coordinates of the nodebase + VectorDim coordinates() const { return coordinates_; } + + private: + + //! point coordinates + VectorDim coordinates_; +}; + +//! class for to describe the discontinuous surface +//! \brief +//! \details nodes, lines and areas +//! \tparam Tdim Dimension +template +class DiscontinuityBase { + public: + //! Define a vector of size dimension + using VectorDim = Eigen::Matrix; + + // Constructor + DiscontinuityBase(); + + //! Destructor + virtual ~DiscontinuityBase(){}; + + //! Delete copy constructor + DiscontinuityBase(const DiscontinuityBase&) = delete; + + //! Delete assignement operator + DiscontinuityBase& operator=(const DiscontinuityBase&) = delete; + + //initialization + virtual bool initialize(const std::vector& coordinates,const std::vector>& pointsets) = 0; + + //! create points from file + bool create_points(const std::vector& coordinates); + + //! create elements from file + virtual bool create_elements(const std::vector>& elements) {return true;}; + + //return the levelset values of each doordinates + //! \param[in] the vector of the coordinates + virtual void compute_levelset(const std::vector& coordinates, std::vector& phi_list) = 0; + + bool self_contact(){return self_contact_;}; + + void set_frictional_coef(double coef) {frictional_coef_ = coef;}; + + double frictional_coef(){return frictional_coef_;}; + + + protected: + + std::vector> points_; + + //number of points + mpm::Index numpoint_; + + //! Logger + std::unique_ptr console_; + + //self-contact + bool self_contact_{true}; + + double frictional_coef_; + +}; // DiscontinuityBase class + +struct discontinuous_line +{ + public: + + //! Return points indices + Eigen::Matrix points() const {return points_;}; + + private: + + //! points index of the line + Eigen::Matrix points_; + +}; + +struct discontinuous_element +{ + public: + //! Define a vector of size dimension + using VectorDim = Eigen::Matrix; + + discontinuous_element(const std::vector& points) + { + for(int i=0; i<3; ++i) + points_[i] = points[i]; + } + //! Return points indices + Eigen::Matrix points() const { return points_;} + + inline void set_center(VectorDim & center) {center_ = center; } + + inline void set_normal(VectorDim & normal) {normal_ = normal; } + + double Vertical_distance (const VectorDim & coor) const {return (coor[0]-center_[0])*normal_[0]+(coor[1]-center_[1])*normal_[1]+(coor[2]-center_[2])*normal_[2];}; + + private: + //! points indices + Eigen::Matrix points_; + + //the center of the triangular elements + VectorDim center_; + + //the normal of the triangular elements + VectorDim normal_; + +}; + + +} // namespace mpm + +template +mpm::DiscontinuityBase::DiscontinuityBase() +{ + numpoint_ = 0; + + frictional_coef_ = -1; + + std::string logger = + "discontinuitybase"; + console_ = std::make_unique(logger, mpm::stdout_sink); +} + +//! create points from file +template +bool mpm::DiscontinuityBase::create_points(const std::vector& coordinates) + { + bool status = true; + try { + // Check if point coordinates is empty + if (coordinates.empty()) + throw std::runtime_error("List of coordinates is empty"); + // Iterate over all coordinates + for (const auto& point_coordinates : coordinates) { + + // Add point + mpm::discontinuous_point point(point_coordinates); + + points_.emplace_back(point); // + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; + + } + +#endif // MPM_DiscontinuityBase_H_ diff --git a/src/discontinuity.cc b/src/discontinuity.cc new file mode 100755 index 000000000..2c9d245bc --- /dev/null +++ b/src/discontinuity.cc @@ -0,0 +1,6 @@ +#include "discontinuity_base.h" +#include "factory.h" +#include "discontinuity_3d.h" + +// Triangle 3-noded element +static Register, mpm::Discontinuity_3D<3>> tri3d("tri3d"); diff --git a/src/io/logger.cc b/src/io/logger.cc index 82e2b262c..bae042405 100644 --- a/src/io/logger.cc +++ b/src/io/logger.cc @@ -35,3 +35,7 @@ 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 XMPM Explicit +const std::shared_ptr mpm::Logger::xmpm_explicit_logger = + spdlog::stdout_color_st("XMPMExplicit"); diff --git a/src/mpm.cc b/src/mpm.cc index d57b3a9a8..2e6bf3591 100644 --- a/src/mpm.cc +++ b/src/mpm.cc @@ -4,6 +4,7 @@ #include "io.h" #include "mpm.h" #include "mpm_explicit.h" +#include "xmpm_explicit.h" namespace mpm { // 2D Explicit MPM @@ -14,4 +15,8 @@ static Register, const std::shared_ptr&> static Register, const std::shared_ptr&> mpm_explicit_3d("MPMExplicit3D"); +// 3D Explicit XMPM +static Register, const std::shared_ptr&> + xmpm_explicit_3d("XMPMExplicit3D"); } // namespace mpm + diff --git a/src/particle.cc b/src/particle.cc index b9f656edd..9683a987f 100644 --- a/src/particle.cc +++ b/src/particle.cc @@ -1,6 +1,7 @@ #include "particle.h" #include "factory.h" #include "particle_base.h" +#include "particle_xmpm.h" namespace mpm { // ParticleType @@ -17,3 +18,8 @@ static Register, mpm::Particle<2>, mpm::Index, static Register, mpm::Particle<3>, mpm::Index, const Eigen::Matrix&> particle3d("P3D"); + +// Particle3D_XMPM (3 Dim) +static Register, mpm::ParticleXMPM<3>, mpm::Index, + const Eigen::Matrix&> + particle3dxmpm("P3DXMPM"); From 41a05a15c48e44903accbc3be2a2ca45fc2c4b7a Mon Sep 17 00:00:00 2001 From: yong liang Date: Sun, 2 Aug 2020 00:55:52 -0700 Subject: [PATCH 23/91] :construction: creat and initialise nodal properties for discontinuity --- include/mesh.h | 6 ++ include/mesh.tcc | 36 ++++++++ include/node.h | 9 ++ include/node.tcc | 10 +++ include/node_base.h | 7 ++ include/particles/particle_base.h | 2 + include/particles/particle_xmpm.h | 3 +- include/particles/particle_xmpm.tcc | 1 + include/solvers/xmpm_explicit.h | 11 +++ include/solvers/xmpm_explicit.tcc | 127 ++++++++++++++++++++++++++-- 10 files changed, 205 insertions(+), 7 deletions(-) diff --git a/include/mesh.h b/include/mesh.h index 4b0bc3b68..35872f025 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -461,6 +461,12 @@ class Mesh { // Initialise the nodal properties' map void initialise_nodal_properties(); + //! Set particles lsm values + void assign_particle_levelset(std::vector& phi_list); + + // Create the nodal properties' map for discontinuity + void create_nodal_properties_discontinuity(); + 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 f2cb78945..4b2f238fb 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1956,9 +1956,45 @@ void mpm::Mesh::create_nodal_properties() { } } +// Create the nodal properties' map for discontinuity +template +void mpm::Mesh::create_nodal_properties_discontinuity() { + // Initialise the shared pointer to nodal properties + if(nodal_properties_ == nullptr) + nodal_properties_ = std::make_shared(); + + // Check if nodes_ is empty and throw runtime error if they are + if (nodes_.size() != 0) { + // Compute number of rows in nodal properties for vector entities + const unsigned nrows = nodes_.size() * Tdim; + // Create pool data for each property in the nodal properties struct + // object. Properties must be named in the plural form + nodal_properties_->create_property("mass_enrich", nodes_.size(),1); + nodal_properties_->create_property("momenta_enrich", nrows, 1); + nodal_properties_->create_property("internal_force_enrich", nrows, 1); + nodal_properties_->create_property("external_force_enrich", nrows, 1); + nodal_properties_->create_property("normal_unit_vectors_discontinuity", nrows,1); + + // Iterate over all nodes to initialise the property handle in each node + // and assign its node id as the prop id in the nodal property data pool + for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) + (*nitr)->initialise_discontinuity_property_handle((*nitr)->id(), nodal_properties_); + } else { + throw std::runtime_error("Number of nodes is zero"); + } +} + // 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(); } + +//! Set particles lsm values +template +void mpm::Mesh::assign_particle_levelset(std::vector& phi_list) +{ + for(mpm::Index i = 0; iassign_levelsetphi(phi_list[i]); +} \ No newline at end of file diff --git a/include/node.h b/include/node.h index 31a6b9a03..2c4d7200e 100644 --- a/include/node.h +++ b/include/node.h @@ -47,6 +47,13 @@ class Node : public NodeBase { unsigned prop_id, std::shared_ptr property_handle) noexcept override; + //! Initialise shared pointer to nodal properties pool for discontinuity + //! \param[in] prop_id Property id in the nodal property pool + //! \param[in] nodal_properties Shared pointer to nodal properties pool + void initialise_discontinuity_property_handle( + unsigned prop_id, + std::shared_ptr property_handle) noexcept override; + //! Assign coordinates //! \param[in] coord Assign coord as coordinates of the nodebase void assign_coordinates(const VectorDim& coord) override { @@ -271,6 +278,8 @@ class Node : public NodeBase { Index id_{std::numeric_limits::max()}; //! nodal property id unsigned prop_id_{std::numeric_limits::max()}; + //! nodal property id + unsigned discontinuity_prop_id_{std::numeric_limits::max()}; //! shared ghost id Index ghost_id_{std::numeric_limits::max()}; //! nodal coordinates diff --git a/include/node.tcc b/include/node.tcc index 7d3a9cfcb..0594ed1d1 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -46,6 +46,16 @@ void mpm::Node::initialise_property_handle( this->prop_id_ = prop_id; } +//! Initialise shared pointer to nodal properties pool for discontinuity +template +void mpm::Node::initialise_discontinuity_property_handle( + unsigned prop_id, + std::shared_ptr property_handle) noexcept { + // the property handle and the property id is set in the node + this->property_handle_ = property_handle; + this->discontinuity_prop_id_ = prop_id; +} + //! 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..357feddb0 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -51,6 +51,13 @@ class NodeBase { unsigned prop_id, std::shared_ptr property_handle) noexcept = 0; + //! Initialise shared pointer to nodal properties pool for discontinuity + //! \param[in] prop_id Property id in the nodal property pool + //! \param[in] nodal_properties Shared pointer to nodal properties pool + virtual void initialise_discontinuity_property_handle( + unsigned prop_id, + std::shared_ptr property_handle) noexcept = 0; + //! Assign coordinates virtual void assign_coordinates(const VectorDim& coord) = 0; diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index dcb2bc419..4a02392b7 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -314,6 +314,8 @@ class ParticleBase { virtual void deserialize( const std::vector& buffer, std::vector>>& materials) = 0; + //! set the level set function values + virtual void assign_levelsetphi(const double phivalue) {}; protected: //! particleBase id diff --git a/include/particles/particle_xmpm.h b/include/particles/particle_xmpm.h index 3b2897d21..a931bf2d5 100644 --- a/include/particles/particle_xmpm.h +++ b/include/particles/particle_xmpm.h @@ -305,7 +305,8 @@ class ParticleXMPM : public ParticleBase { //! \retval strain rate at particle inside a cell inline Eigen::Matrix compute_strain_rate( const Eigen::MatrixXd& dn_dx, unsigned phase) noexcept; - + //! set the level set function values +virtual void assign_levelsetphi(const double phivalue) { levelset_phi_ = phivalue; }; private: //! particle id using ParticleBase::id_; diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index 8220bac9c..607ba6539 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -249,6 +249,7 @@ void mpm::ParticleXMPM::initialise() { this->properties_["strains"] = [&]() { return strain(); }; this->properties_["velocities"] = [&]() { return velocity(); }; this->properties_["displacements"] = [&]() { return displacement(); }; + this->properties_["levelset"] = [&]() { Eigen::Matrix levelset; levelset[0] = levelset_phi_ ; return levelset; }; } //! Initialise particle material container diff --git a/include/solvers/xmpm_explicit.h b/include/solvers/xmpm_explicit.h index 196915d1c..edf588aad 100644 --- a/include/solvers/xmpm_explicit.h +++ b/include/solvers/xmpm_explicit.h @@ -6,6 +6,7 @@ #endif #include "mpm_base.h" +#include "discontinuity_base.h" namespace mpm { @@ -26,6 +27,12 @@ class XMPMExplicit : public MPMBase { //! \param[in] phase Phase to smooth pressure void compute_stress_strain(unsigned phase); + //! Initialise discontinuities + bool initialise_discontinuities(); + //! Initialise the level set function values + bool initialise_levelset(); + //return the number of discontinuities + mpm::Index ndiscontinuities(){return discontinuities_.size();}; protected: // Generate a unique id for the analysis using mpm::MPMBase::uuid_; @@ -75,6 +82,10 @@ class XMPMExplicit : public MPMBase { bool pressure_smoothing_{false}; //! Interface bool interface_{false}; + //! discontinuities statue + bool discontinuity_{false}; + //! discontinuities + std::map>> discontinuities_; }; // XMPMExplicit class } // namespace mpm diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index f8ac93850..0f45967b6 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -77,9 +77,7 @@ bool mpm::XMPMExplicit::solve() { // Initialise particles bool particle_status = this->initialise_particles(); if (!particle_status) { - status = false; - throw std::runtime_error("Initialisation of particles failed"); - } + status = false;initialise_property_handle // Initialise loading conditions bool loading_status = this->initialise_loads(); @@ -91,6 +89,24 @@ bool mpm::XMPMExplicit::solve() { // Create nodal properties if (interface_) mesh_->create_nodal_properties(); + // Initialise discontinuity + bool discontinuity_status = this->initialise_discontinuities(); + if (!discontinuity_status) { + status = false; + throw std::runtime_error("Initialisation of discontinuities failed"); + } + + //Initialise the levelset values for particles + if (discontinuity_){ + bool initialise_lsm_status = this->initialise_levelset(); + if (!initialise_lsm_status) { + status = false; + throw std::runtime_error("Initialisation of level set values failed"); + } + } + + // Create nodal properties for discontinuity + if (discontinuity_) mesh_->create_nodal_properties_discontinuity(); // Compute mass mesh_->iterate_over_particles( std::bind(&mpm::ParticleBase::compute_mass, std::placeholders::_1)); @@ -140,17 +156,24 @@ bool mpm::XMPMExplicit::solve() { } } // Wait to complete - // Initialise nodal properties and append material ids to node - if (interface_) { + // Initialise nodal properties + if (interface_ || discontinuity_) // Initialise nodal properties mesh_->initialise_nodal_properties(); - + //append material ids to node + if (interface_) { // Append material ids to nodes mesh_->iterate_over_particles( std::bind(&mpm::ParticleBase::append_material_id_to_nodes, std::placeholders::_1)); } + // Initialise nodal properties and append material ids to node + if (discontinuity_) { + + + + } // Assign mass and momentum to nodes mesh_->iterate_over_particles( std::bind(&mpm::ParticleBase::map_mass_momentum_to_nodes, @@ -331,3 +354,95 @@ bool mpm::XMPMExplicit::solve() { return status; } + +// Initialise discontinuities +template +bool mpm::XMPMExplicit::initialise_discontinuities() { + bool status = true; + try { + // Get discontinuities data + try { + auto json_discontinuities = io_->json_object("discontinuity"); + if(!json_discontinuities.empty()) + { + discontinuity_ = true; + for (const auto discontinuity_props : json_discontinuities) { + // Get discontinuity type + const std::string discontunity_type = + discontinuity_props["type"].template get(); + + // Get discontinuity id + auto discontinuity_id = discontinuity_props["id"].template get(); + + // Get discontinuity input type + auto io_type = discontinuity_props["io_type"].template get(); + + // discontinuity file + std::string discontinuity_file = + io_->file_name(discontinuity_props["file"].template get()); + + auto discontinuity_frictional_coef = discontinuity_props["frictional_coefficient"].template get(); + + // Create a mesh reader + auto discontunity_io = Factory>::instance()->create(io_type); + + // Create a new discontinuity surface from JSON object + auto discontinuity = + Factory>::instance() + ->create(discontunity_type); + + bool status = + discontinuity->initialize(discontunity_io->read_mesh_nodes(discontinuity_file),discontunity_io->read_mesh_cells(discontinuity_file)); + + discontinuity->set_frictional_coef(discontinuity_frictional_coef); + // Create points from file + + // Add discontinuity to list + auto result = discontinuities_.insert(std::make_pair(discontinuity_id, discontinuity)); + + // If insert discontinuity failed + if (!result.second) { + status = false; + throw std::runtime_error( + "New discontinuity cannot be added, insertion failed"); + } + } + } + }catch (std::exception& exception) { + console_->warn("{} #{}: No discontinuity is defined", __FILE__, + __LINE__, exception.what()); + } + }catch (std::exception& exception) { + console_->error("#{}: Reading discontinuities: {}", __LINE__, exception.what()); + status = false; + } + return status; +} + +// Initialise particles +template +bool mpm::XMPMExplicit::initialise_levelset() { + + bool status = true; + + try { + + for(mpm::Index i=0; i phi_list(mesh_->nparticles()); + + discontinuities_[i]->compute_levelset(mesh_->particle_coordinates(), phi_list); + + mesh_->assign_particle_levelset(phi_list); + } + + } catch (std::exception& exception) { + console_->error("#{}: XMPM initialise particles levelset values: {}", __LINE__, + exception.what()); + status = false; + } + + if (!status) throw std::runtime_error("Initialisation of particles LSM values failed"); + + return status; +} \ No newline at end of file From 54e7b4dfdda21adbe4f1e484c5fcd415dd771a6c Mon Sep 17 00:00:00 2001 From: yong liang Date: Sun, 2 Aug 2020 10:26:42 -0700 Subject: [PATCH 24/91] :construction:update nodal properties function and update nodal enrichen mass, momentum --- include/node.h | 14 ++++++++++++++ include/node.tcc | 13 +++++++++++++ include/node_base.h | 12 ++++++++++++ include/particles/particle_xmpm.tcc | 10 ++++++++++ include/solvers/xmpm_explicit.tcc | 20 ++++++++------------ 5 files changed, 57 insertions(+), 12 deletions(-) diff --git a/include/node.h b/include/node.h index 2c4d7200e..89b3d4a43 100644 --- a/include/node.h +++ b/include/node.h @@ -271,6 +271,18 @@ class Node : public NodeBase { //! Compute multimaterial normal unit vector void compute_multimaterial_normal_unit_vector() override; + //! Return whether the node is enriched + bool discontinuity_enrich() {return discontinuity_enrich_;}; + + //! Update nodal property at the nodes from particle for discontinuity + //! \param[in] update A boolean to update (true) or assign (false) + //! \param[in] property Property name + //! \param[in] property_value Property quantity from the particles in the cell + //! \param[in] discontinuity_id Id of the material within the property data + //! \param[in] nprops Dimension of property (1 if scalar, Tdim if vector) + void update_discontinuity_property(bool update, const std::string& property, + const Eigen::MatrixXd& property_value, unsigned discontinuity_id, + unsigned nprops) noexcept override; private: //! Mutex SpinMutex node_mutex_; @@ -328,6 +340,8 @@ class Node : public NodeBase { std::unique_ptr console_; //! MPI ranks std::set mpi_ranks_; + //! discontinuity enrich + bool discontinuity_enrich_{true}; }; // Node class } // namespace mpm diff --git a/include/node.tcc b/include/node.tcc index 0594ed1d1..70b7a8375 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -560,6 +560,19 @@ void mpm::Node::update_property( node_mutex_.unlock(); } +//! Update nodal property at the nodes from particle for discontinuity +template +void mpm::Node::update_discontinuity_property( + bool update, const std::string& property, + const Eigen::MatrixXd& property_value, unsigned discontinuity_id, + unsigned nprops) noexcept { + // Update/assign property + node_mutex_.lock(); + property_handle_->update_property(property, discontinuity_prop_id_, discontinuity_id, property_value, + nprops); + node_mutex_.unlock(); +} + //! Compute multimaterial change in momentum template void mpm::Node::map_mass_momentum_to_nodes() noexcept { mass_ * shapefn_[i]); nodes_[i]->update_momentum(true, mpm::ParticlePhase::Solid, mass_ * shapefn_[i] * velocity_); + if(nodes_[i]->discontinuity_enrich()){ + // Unit 1x1 Eigen matrix to be used with scalar quantities + Eigen::Matrix nodal_mass; + nodal_mass(0, 0) = levelset_phi_ * mass_ * shapefn_[i]; + // Map enriched mass and momentum to nodes + nodes_[i]->update_discontinuity_property(true, "mass_enrich", nodal_mass, 0, + 1); + nodes_[i]->update_discontinuity_property(true, "momenta_enrich", velocity_ * nodal_mass, + 0, Tdim); + } } } diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index 0f45967b6..2a2b20f8a 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -77,8 +77,10 @@ bool mpm::XMPMExplicit::solve() { // Initialise particles bool particle_status = this->initialise_particles(); if (!particle_status) { - status = false;initialise_property_handle - + status = false; + throw std::runtime_error("Initialisation of particles failed"); + } + // Initialise loading conditions bool loading_status = this->initialise_loads(); if (!loading_status) { @@ -168,12 +170,6 @@ bool mpm::XMPMExplicit::solve() { std::placeholders::_1)); } - // Initialise nodal properties and append material ids to node - if (discontinuity_) { - - - - } // Assign mass and momentum to nodes mesh_->iterate_over_particles( std::bind(&mpm::ParticleBase::map_mass_momentum_to_nodes, @@ -198,10 +194,10 @@ bool mpm::XMPMExplicit::solve() { #endif // Compute nodal velocity - mesh_->iterate_over_nodes_predicate( - std::bind(&mpm::NodeBase::compute_velocity, - std::placeholders::_1), - std::bind(&mpm::NodeBase::status, std::placeholders::_1)); + // mesh_->iterate_over_nodes_predicate( + // std::bind(&mpm::NodeBase::compute_velocity, + // std::placeholders::_1), + // std::bind(&mpm::NodeBase::status, std::placeholders::_1)); if (interface_) { // Map multimaterial properties from particles to nodes From 332e9403612683a4d53a831e56d86d4a0421d2b6 Mon Sep 17 00:00:00 2001 From: yong liang Date: Sun, 2 Aug 2020 13:03:35 -0700 Subject: [PATCH 25/91] :construction:update:external force,internal force, compute strain rate --- include/node.h | 6 ++++++ include/node.tcc | 11 +++++++++++ include/node_base.h | 5 +++++ include/particles/particle_xmpm.h | 5 ++++- include/particles/particle_xmpm.tcc | 28 ++++++++++++++++++++++++---- 5 files changed, 50 insertions(+), 5 deletions(-) diff --git a/include/node.h b/include/node.h index 89b3d4a43..b98c15307 100644 --- a/include/node.h +++ b/include/node.h @@ -283,6 +283,12 @@ class Node : public NodeBase { void update_discontinuity_property(bool update, const std::string& property, const Eigen::MatrixXd& property_value, unsigned discontinuity_id, unsigned nprops) noexcept override; + + // Return data in the nodal discontinuity properties map at a specific index + // \param[in] property Property name + // \param[in] nprops Dimension of property (1 if scalar, Tdim if vector) + Eigen::MatrixXd discontinuity_property(const std::string& property, unsigned nprops = 1) override; + private: //! Mutex SpinMutex node_mutex_; diff --git a/include/node.tcc b/include/node.tcc index 70b7a8375..ff239bb76 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -654,3 +654,14 @@ void mpm::Node +Eigen::MatrixXd mpm::Node::discontinuity_property(const std::string& property, + unsigned nprops) { + // Const pointer to location of property: node_id * nprops x mat_id + auto property_value = property_handle_->property(property, discontinuity_prop_id_, 0, nprops);; + //mpm::MapProperty property_handle(position, nprops); + return property_value; +} diff --git a/include/node_base.h b/include/node_base.h index 62b3313ac..3cef3438d 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -260,6 +260,11 @@ class NodeBase { //! Compute multimaterial normal unit vector virtual void compute_multimaterial_normal_unit_vector() = 0; + // Return data in the nodal discontinuity properties map at a specific index + // \param[in] property Property name + // \param[in] nprops Dimension of property (1 if scalar, Tdim if vector) + virtual Eigen::MatrixXd discontinuity_property(const std::string& property,unsigned nprops = 1) = 0; + //! Return whether the node is enriched virtual bool discontinuity_enrich() = 0; diff --git a/include/particles/particle_xmpm.h b/include/particles/particle_xmpm.h index a931bf2d5..340d3e59e 100644 --- a/include/particles/particle_xmpm.h +++ b/include/particles/particle_xmpm.h @@ -306,7 +306,10 @@ class ParticleXMPM : public ParticleBase { inline Eigen::Matrix compute_strain_rate( const Eigen::MatrixXd& dn_dx, unsigned phase) noexcept; //! set the level set function values -virtual void assign_levelsetphi(const double phivalue) { levelset_phi_ = phivalue; }; + virtual void assign_levelsetphi(const double phivalue) { levelset_phi_ = phivalue; }; + + //! return 1 if x > 0, -1 if x < 0 and 0 if x = 0 + inline double sgn(double x) noexcept {return (x > 0) ? 1. : ((x < 0) ? -1. : 0);}; private: //! particle id using ParticleBase::id_; diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index ce9598c2e..2534b5e47 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -525,7 +525,7 @@ void mpm::ParticleXMPM::map_mass_momentum_to_nodes() noexcept { if(nodes_[i]->discontinuity_enrich()){ // Unit 1x1 Eigen matrix to be used with scalar quantities Eigen::Matrix nodal_mass; - nodal_mass(0, 0) = levelset_phi_ * mass_ * shapefn_[i]; + nodal_mass(0, 0) = sgn(levelset_phi_) * mass_ * shapefn_[i]; // Map enriched mass and momentum to nodes nodes_[i]->update_discontinuity_property(true, "mass_enrich", nodal_mass, 0, 1); @@ -628,9 +628,24 @@ inline Eigen::Matrix mpm::ParticleXMPM<3>::compute_strain_rate( const Eigen::MatrixXd& dn_dx, unsigned phase) noexcept { // Define strain rate Eigen::Matrix strain_rate = Eigen::Matrix::Zero(); + const double tolerance = 1.E-16; + Eigen::Vector3d vel; + for (unsigned i = 0; i < this->nodes_.size(); ++i){ + vel.setZero(); + if(nodes_[i]->discontinuity_enrich()){ + double nodal_mass = nodes_[i]->mass(phase) + sgn(levelset_phi_)*nodes_[i]->discontinuity_property("mass_enrich",1)(0,0) ; + if(nodal_mass < tolerance) + continue; + + vel = (nodes_[i]->momentum(phase) + sgn(levelset_phi_)*nodes_[i]->discontinuity_property("momenta_enrich",3).col(0))/nodal_mass; + } + else{ + double nodal_mass = nodes_[i]->mass(phase); + if(nodal_mass < tolerance) + continue; + vel = nodes_[i]->momentum(phase)/nodal_mass; + } - for (unsigned i = 0; i < this->nodes_.size(); ++i) { - Eigen::Matrix vel = nodes_[i]->velocity(phase); strain_rate[0] += dn_dx(i, 0) * vel[0]; strain_rate[1] += dn_dx(i, 1) * vel[1]; strain_rate[2] += dn_dx(i, 2) * vel[2]; @@ -680,9 +695,12 @@ void mpm::ParticleXMPM::compute_stress() noexcept { template void mpm::ParticleXMPM::map_body_force(const VectorDim& pgravity) noexcept { // Compute nodal body forces - for (unsigned i = 0; i < nodes_.size(); ++i) + for (unsigned i = 0; i < nodes_.size(); ++i){ nodes_[i]->update_external_force(true, mpm::ParticlePhase::Solid, (pgravity * mass_ * shapefn_(i))); + if(nodes_[i]->discontinuity_enrich()) + nodes_[i]->update_discontinuity_property(true, "external_force_enrich", sgn(levelset_phi_)*pgravity * mass_ * shapefn_(i), 0,Tdim); + } } //! Map internal force @@ -733,6 +751,8 @@ inline void mpm::ParticleXMPM<3>::map_internal_force() noexcept { force *= -1. * this->volume_; nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Solid, force); + if(nodes_[i]->discontinuity_enrich()) + nodes_[i]->update_discontinuity_property(true, "internal_force_enrich", sgn(levelset_phi_)*force, 0,Tdim); } } From c24c3f45be972ed2d4d78edfff9d1354efba5cf4 Mon Sep 17 00:00:00 2001 From: yong liang Date: Sun, 2 Aug 2020 15:27:22 -0700 Subject: [PATCH 26/91] :construction:apply velocity constraints discontinuity --- include/node.h | 9 ++ include/node.tcc | 127 ++++++++++++++++++++++++++++ include/node_base.h | 9 ++ include/particles/particle_xmpm.tcc | 6 +- include/solvers/xmpm_explicit.tcc | 17 ++-- 5 files changed, 155 insertions(+), 13 deletions(-) diff --git a/include/node.h b/include/node.h index b98c15307..daaaa8106 100644 --- a/include/node.h +++ b/include/node.h @@ -208,6 +208,9 @@ class Node : public NodeBase { //! Apply velocity constraints void apply_velocity_constraints() override; + //! Apply velocity constraints for discontinuity + void apply_velocity_constraints_discontinuity() override; + //! Assign friction constraint //! Directions can take values between 0 and Dim * Nphases //! \param[in] dir Direction of friction constraint @@ -288,6 +291,12 @@ class Node : public NodeBase { // \param[in] property Property name // \param[in] nprops Dimension of property (1 if scalar, Tdim if vector) Eigen::MatrixXd discontinuity_property(const std::string& property, unsigned nprops = 1) override; + + //! Compute momentum + //! \param[in] phase Index corresponding to the phase + //! \param[in] dt Timestep in analysis + virtual bool intergrate_momentum_discontinuity( + unsigned phase, double dt) noexcept override; private: //! Mutex diff --git a/include/node.tcc b/include/node.tcc index ff239bb76..68281c006 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -665,3 +665,130 @@ Eigen::MatrixXd mpm::Node +bool mpm::Node::intergrate_momentum_discontinuity( + unsigned phase, double dt) noexcept { + momentum_.col(phase) = momentum_.col(phase) + + (internal_force_.col(phase) + external_force_.col(phase)) * dt; + if(discontinuity_enrich_){ + property_handle_->update_property("momenta_enrich", discontinuity_prop_id_, 0, + (property_handle_->property("internal_force_enrich",discontinuity_prop_id_,0,Tdim) + + property_handle_->property("external_force_enrich",discontinuity_prop_id_,0,Tdim) ) * dt, Tdim); + } + // Apply velocity constraints, which also sets acceleration to 0, + // when velocity is set. + this->apply_velocity_constraints(); + + //this->self_contact_discontinuity(dt); + + this->apply_velocity_constraints(); + + + return true; +} + //! Apply velocity constraints +template +void mpm::Node::apply_velocity_constraints_discontinuity() { + // Set velocity constraint + for (const auto& constraint : this->velocity_constraints_) { + // Direction value in the constraint (0, Dim * Nphases) + const unsigned dir = constraint.first; + // Direction: dir % Tdim (modulus) + const auto direction = static_cast(dir % Tdim); + // Phase: Integer value of division (dir / Tdim) + const auto phase = static_cast(dir / Tdim); + + if (!generic_boundary_constraints_) { + // Velocity constraints are applied on Cartesian boundaries + //this->velocity_(direction, phase) = constraint.second; + //need to do for one direction + + this->momentum_(direction, phase) = this->mass(phase) * constraint.second; + property_handle_->assign_property("momenta_enrich",discontinuity_prop_id_,0, + property_handle_->property("mass_enrich",discontinuity_prop_id_,0,1) * constraint.second,Tdim); + // Set acceleration to 0 in direction of velocity constraint + //this->acceleration_(direction, phase) = 0.; + this->internal_force_(direction, phase) = 0; + this->external_force_(direction, phase) = 0; + + Eigen::Matrix momentum; + momentum.setZero(); + property_handle_->assign_property("internal_force_enrich",discontinuity_prop_id_,0, + momentum,Tdim); + property_handle_->assign_property("external_force_enrich",discontinuity_prop_id_,0, + momentum,Tdim); + } else { //need to do + // Velocity constraints on general boundaries + // Compute inverse rotation matrix + const Eigen::Matrix inverse_rotation_matrix = + rotation_matrix_.inverse(); + // Transform to local coordinate + Eigen::Matrix local_velocity = + inverse_rotation_matrix * this->velocity_; + Eigen::Matrix local_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 + this->velocity_ = rotation_matrix_ * local_velocity; + this->acceleration_ = rotation_matrix_ * local_acceleration; + } + } +} +// //! Apply velocity constraints +// template +// void mpm::NodeXMPM::self_contact_discontinuity(double dt) { + +// if(!enrich_h_) +// return; + +// unsigned phase = 0; +// const double tolerance = 1.0E-15; + +// auto mass_positive = mass_.col(phase) + mass_h_.col(phase); +// auto mass_negative = mass_.col(phase) - mass_h_.col(phase); + +// if(mass_positive(phase) < tolerance || mass_negative(phase) < tolerance) +// return; + +// auto velocity_positive = (momentum_.col(phase) + momentum_h_.col(phase)) / mass_positive(phase); +// auto velocity_negative = (momentum_.col(phase) - momentum_h_.col(phase)) / mass_negative(phase); + +// if((velocity_positive - velocity_negative).col(phase).dot(direction_discontinuity_.col(phase)) >= 0) +// return; + +// auto momentum_contact = (mass_h_(phase)*momentum_.col(phase) - mass_(phase)*momentum_h_.col(phase)) / mass_(phase); +// auto force_contact = momentum_contact/dt; + +// //! frictional_coef < 0: move together without slide +// if(frictional_coef < 0) +// { +// momentum_h_.col(phase) = momentum_h_.col(phase) + momentum_contact.col(phase); +// internal_force_h_.col(phase) = internal_force_h_.col(phase) + force_contact.col(phase); +// } +// else +// { +// double momentum_contact_norm = momentum_contact.col(phase).dot(direction_discontinuity_.col(phase)); +// double force_contact_norm = momentum_contact_norm/dt; + +// double max_frictional_force = frictional_coef * abs(force_contact_norm); + +// auto momentum_tangential = momentum_contact.col(phase) - momentum_contact_norm*direction_discontinuity_.col(phase); +// auto force_tangential = momentum_tangential/dt; + +// double force_tangential_value = force_tangential.norm(); + +// double frictional_force = force_tangential_value < max_frictional_force? force_tangential_value : max_frictional_force; + +// //!adjust the momentum and force +// momentum_h_.col(phase) = momentum_h_.col(phase) + momentum_contact_norm*direction_discontinuity_.col(phase); +// internal_force_h_.col(phase) = internal_force_h_.col(phase) + force_contact_norm*direction_discontinuity_.col(phase); + +// momentum_h_.col(phase) = momentum_h_.col(phase) + frictional_force*force_tangential.col(phase).normalized()*dt; +// internal_force_h_.col(phase) = internal_force_h_.col(phase) + frictional_force*force_tangential.col(phase).normalized(); + +// } +// } \ No newline at end of file diff --git a/include/node_base.h b/include/node_base.h index 3cef3438d..0a9f82b34 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -200,6 +200,9 @@ class NodeBase { //! Apply velocity constraints virtual void apply_velocity_constraints() = 0; + //! Apply velocity constraints for discontinuity + virtual void apply_velocity_constraints_discontinuity() = 0; + //! Assign friction constraint //! Directions can take values between 0 and Dim * Nphases //! \param[in] dir Direction of friction constraint @@ -277,6 +280,12 @@ class NodeBase { virtual void update_discontinuity_property(bool update, const std::string& property, const Eigen::MatrixXd& property_value, unsigned discontinuity_id, unsigned nprops) noexcept = 0; + + //! Compute momentum + //! \param[in] phase Index corresponding to the phase + //! \param[in] dt Timestep in analysis + virtual bool intergrate_momentum_discontinuity( + unsigned phase, double dt) noexcept = 0; }; // NodeBase class } // namespace mpm diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index 2534b5e47..97efab4e6 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -713,6 +713,8 @@ inline void mpm::ParticleXMPM<1>::map_internal_force() noexcept { force[0] = -1. * dn_dx_(i, 0) * volume_ * stress_[0]; nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Solid, force); + if(nodes_[i]->discontinuity_enrich()) + nodes_[i]->update_discontinuity_property(true, "internal_force_enrich", sgn(levelset_phi_)*force, 0,1); } } @@ -729,6 +731,8 @@ inline void mpm::ParticleXMPM<2>::map_internal_force() noexcept { force *= -1. * this->volume_; nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Solid, force); + if(nodes_[i]->discontinuity_enrich()) + nodes_[i]->update_discontinuity_property(true, "internal_force_enrich", sgn(levelset_phi_)*force, 0,2); } } @@ -752,7 +756,7 @@ inline void mpm::ParticleXMPM<3>::map_internal_force() noexcept { nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Solid, force); if(nodes_[i]->discontinuity_enrich()) - nodes_[i]->update_discontinuity_property(true, "internal_force_enrich", sgn(levelset_phi_)*force, 0,Tdim); + nodes_[i]->update_discontinuity_property(true, "internal_force_enrich", sgn(levelset_phi_)*force, 0,3); } } diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index 2a2b20f8a..f9c53eb70 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -286,18 +286,11 @@ bool mpm::XMPMExplicit::solve() { } #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_cundall, - std::placeholders::_1, phase, this->dt_, damping_factor_), - std::bind(&mpm::NodeBase::status, std::placeholders::_1)); - else - mesh_->iterate_over_nodes_predicate( - std::bind(&mpm::NodeBase::compute_acceleration_velocity, - std::placeholders::_1, phase, this->dt_), - std::bind(&mpm::NodeBase::status, std::placeholders::_1)); + //intergrate momentum Iterate over + mesh_->iterate_over_nodes_predicate( + std::bind(&mpm::NodeBase::intergrate_momentum_discontinuity, + std::placeholders::_1, phase, this->dt_), + std::bind(&mpm::NodeBase::status, std::placeholders::_1)); // Iterate over each particle to compute updated position mesh_->iterate_over_particles( From faec00b4e408cd339322c9e5e7fe758d8de6ff23 Mon Sep 17 00:00:00 2001 From: yong liang Date: Sun, 2 Aug 2020 15:47:45 -0700 Subject: [PATCH 27/91] :construction:compute updated position --- include/particles/particle_xmpm.tcc | 49 ++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index 97efab4e6..3bf44daec 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -810,19 +810,58 @@ void mpm::ParticleXMPM::compute_updated_position( // Get interpolated nodal velocity Eigen::Matrix nodal_velocity = Eigen::Matrix::Zero(); - + const double tolerance = 1.E-16; + unsigned int phase = mpm::ParticlePhase::Solid; for (unsigned i = 0; i < nodes_.size(); ++i) - nodal_velocity += - shapefn_[i] * nodes_[i]->velocity(mpm::ParticlePhase::Solid); + { + if(nodes_[i]->discontinuity_enrich()) + { + double nodal_mass = nodes_[i]->mass(phase) + sgn(levelset_phi_)*nodes_[i]->discontinuity_property("mass_enrich",1)(0,0); + if (nodal_mass < tolerance) + continue; + nodal_velocity += shapefn_[i] * + (nodes_[i]->momentum(phase) + sgn(levelset_phi_) * nodes_[i]->discontinuity_property("momenta_enrich",3))/nodal_mass; + } + else + { + double nodal_mass = nodes_[i]->mass(phase); + if (nodal_mass < tolerance) + continue; + nodal_velocity += + shapefn_[i] * nodes_[i]->momentum(phase)/nodal_mass; + } + } // 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); + { + if(nodes_[i]->discontinuity_enrich()) + { + double nodal_mass = nodes_[i]->mass(phase) + sgn(levelset_phi_)*nodes_[i]->discontinuity_property("mass_enrich",1)(0,0); + if (nodal_mass < tolerance) + continue; + + auto force = nodes_[i]->internal_force(phase) + sgn(levelset_phi_) * nodes_[i]->discontinuity_property("internal_force_enrich",3) + + nodes_[i]->external_force(phase) + sgn(levelset_phi_) * nodes_[i]->discontinuity_property("external_force_enrich",3); + + nodal_acceleration += shapefn_[i] * force / nodal_mass; + } + else + { + double nodal_mass = nodes_[i]->mass(phase); + if (nodal_mass < tolerance) + continue; + + auto force = nodes_[i]->internal_force(phase) + nodes_[i]->external_force(phase); + + nodal_acceleration += + shapefn_[i] * force / nodal_mass; + } + } // Update particle velocity from interpolated nodal acceleration this->velocity_ += nodal_acceleration * dt; From d94e611f07ecd3848b9330505c3e07d74039b8cf Mon Sep 17 00:00:00 2001 From: yong liang Date: Sun, 2 Aug 2020 18:06:45 -0700 Subject: [PATCH 28/91] :hammer: --- include/node.h | 2 +- include/node.tcc | 4 ++-- include/particles/particle_xmpm.h | 4 ++-- include/particles/particle_xmpm.tcc | 2 +- include/xmpm/discontinuity_3d.tcc | 1 + 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/include/node.h b/include/node.h index daaaa8106..160e38284 100644 --- a/include/node.h +++ b/include/node.h @@ -356,7 +356,7 @@ class Node : public NodeBase { //! MPI ranks std::set mpi_ranks_; //! discontinuity enrich - bool discontinuity_enrich_{true}; + bool discontinuity_enrich_{false}; }; // Node class } // namespace mpm diff --git a/include/node.tcc b/include/node.tcc index 68281c006..f3278483d 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -679,11 +679,11 @@ bool mpm::Node::intergrate_momentum_discontinuity( } // Apply velocity constraints, which also sets acceleration to 0, // when velocity is set. - this->apply_velocity_constraints(); + this->apply_velocity_constraints_discontinuity(); //this->self_contact_discontinuity(dt); - this->apply_velocity_constraints(); + this->apply_velocity_constraints_discontinuity(); return true; diff --git a/include/particles/particle_xmpm.h b/include/particles/particle_xmpm.h index 340d3e59e..dede2d187 100644 --- a/include/particles/particle_xmpm.h +++ b/include/particles/particle_xmpm.h @@ -305,8 +305,8 @@ class ParticleXMPM : public ParticleBase { //! \retval strain rate at particle inside a cell inline Eigen::Matrix compute_strain_rate( const Eigen::MatrixXd& dn_dx, unsigned phase) noexcept; - //! set the level set function values - virtual void assign_levelsetphi(const double phivalue) { levelset_phi_ = phivalue; }; + //! set the level set function values + void assign_levelsetphi(const double phivalue) { levelset_phi_ = phivalue;}; //! return 1 if x > 0, -1 if x < 0 and 0 if x = 0 inline double sgn(double x) noexcept {return (x > 0) ? 1. : ((x < 0) ? -1. : 0);}; diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index 3bf44daec..e2961d1a6 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -630,8 +630,8 @@ inline Eigen::Matrix mpm::ParticleXMPM<3>::compute_strain_rate( Eigen::Matrix strain_rate = Eigen::Matrix::Zero(); const double tolerance = 1.E-16; Eigen::Vector3d vel; + vel.setZero(); for (unsigned i = 0; i < this->nodes_.size(); ++i){ - vel.setZero(); if(nodes_[i]->discontinuity_enrich()){ double nodal_mass = nodes_[i]->mass(phase) + sgn(levelset_phi_)*nodes_[i]->discontinuity_property("mass_enrich",1)(0,0) ; if(nodal_mass < tolerance) diff --git a/include/xmpm/discontinuity_3d.tcc b/include/xmpm/discontinuity_3d.tcc index 62b7eb8f1..23afaa359 100755 --- a/include/xmpm/discontinuity_3d.tcc +++ b/include/xmpm/discontinuity_3d.tcc @@ -91,6 +91,7 @@ void mpm::Discontinuity_3D::compute_levelset(const std::vector { double Vertical_distance_ = element.Vertical_distance(coor);// Vertical_distance(coor); distance = std::abs(distance) < std::abs(Vertical_distance_)? distance:Vertical_distance_; + if(!distance) distance = 1e-16; } phi_list[i] = distance; From 4a8deb616eba64c0acd776fc3e01dda45d944eaf Mon Sep 17 00:00:00 2001 From: yong liang Date: Tue, 4 Aug 2020 21:33:14 -0700 Subject: [PATCH 29/91] :hammer::construction:self contact for XMPM and boundary condation --- include/node.h | 8 ++- include/node.tcc | 105 ++++++++++++++++-------------- include/node_base.h | 5 ++ include/solvers/xmpm_explicit.tcc | 2 +- 4 files changed, 68 insertions(+), 52 deletions(-) diff --git a/include/node.h b/include/node.h index 160e38284..eedddabd2 100644 --- a/include/node.h +++ b/include/node.h @@ -297,7 +297,10 @@ class Node : public NodeBase { //! \param[in] dt Timestep in analysis virtual bool intergrate_momentum_discontinuity( unsigned phase, double dt) noexcept override; - + + //! Apply self-contact of the discontinuity + //! \param[in] dt Time-step + void self_contact_discontinuity(double dt) override; private: //! Mutex SpinMutex node_mutex_; @@ -356,7 +359,8 @@ class Node : public NodeBase { //! MPI ranks std::set mpi_ranks_; //! discontinuity enrich - bool discontinuity_enrich_{false}; + //need to be done + bool discontinuity_enrich_{true}; }; // Node class } // namespace mpm diff --git a/include/node.tcc b/include/node.tcc index f3278483d..1806ffb6f 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -681,7 +681,12 @@ bool mpm::Node::intergrate_momentum_discontinuity( // when velocity is set. this->apply_velocity_constraints_discontinuity(); - //this->self_contact_discontinuity(dt); + //need to be done + Eigen::Matrix normal{0.44721359474414313,0,0.89442719147920724}; + property_handle_->assign_property("normal_unit_vectors_discontinuity",discontinuity_prop_id_,0, + normal,Tdim); + + this->self_contact_discontinuity(dt); this->apply_velocity_constraints_discontinuity(); @@ -706,19 +711,19 @@ void mpm::Node::apply_velocity_constraints_discontinuity() //need to do for one direction this->momentum_(direction, phase) = this->mass(phase) * constraint.second; - property_handle_->assign_property("momenta_enrich",discontinuity_prop_id_,0, - property_handle_->property("mass_enrich",discontinuity_prop_id_,0,1) * constraint.second,Tdim); + property_handle_->assign_property("momenta_enrich",discontinuity_prop_id_*Tdim+direction,0, + property_handle_->property("mass_enrich",discontinuity_prop_id_,0,1) * constraint.second,1); // Set acceleration to 0 in direction of velocity constraint //this->acceleration_(direction, phase) = 0.; this->internal_force_(direction, phase) = 0; this->external_force_(direction, phase) = 0; - Eigen::Matrix momentum; + Eigen::Matrix momentum; momentum.setZero(); - property_handle_->assign_property("internal_force_enrich",discontinuity_prop_id_,0, - momentum,Tdim); - property_handle_->assign_property("external_force_enrich",discontinuity_prop_id_,0, - momentum,Tdim); + property_handle_->assign_property("internal_force_enrich",discontinuity_prop_id_*Tdim+direction,0, + momentum,1); + property_handle_->assign_property("external_force_enrich",discontinuity_prop_id_*Tdim+direction,0, + momentum,1); } else { //need to do // Velocity constraints on general boundaries // Compute inverse rotation matrix @@ -738,57 +743,59 @@ void mpm::Node::apply_velocity_constraints_discontinuity() } } } -// //! Apply velocity constraints -// template -// void mpm::NodeXMPM::self_contact_discontinuity(double dt) { - -// if(!enrich_h_) -// return; - -// unsigned phase = 0; -// const double tolerance = 1.0E-15; +//! Apply velocity constraints +template +void mpm::Node::self_contact_discontinuity(double dt) { -// auto mass_positive = mass_.col(phase) + mass_h_.col(phase); -// auto mass_negative = mass_.col(phase) - mass_h_.col(phase); + if(!discontinuity_enrich_) + return; + + unsigned phase = 0; + const double tolerance = 1.0E-15; -// if(mass_positive(phase) < tolerance || mass_negative(phase) < tolerance) -// return; + Eigen::Matrix mass_enrich = property_handle_->property("mass_enrich",discontinuity_prop_id_,0,1); + Eigen::Matrix momenta_enrich = property_handle_->property("momenta_enrich",discontinuity_prop_id_,0,Tdim); + Eigen::Matrix normal_vector = property_handle_->property("normal_unit_vectors_discontinuity",discontinuity_prop_id_,0,Tdim); -// auto velocity_positive = (momentum_.col(phase) + momentum_h_.col(phase)) / mass_positive(phase); -// auto velocity_negative = (momentum_.col(phase) - momentum_h_.col(phase)) / mass_negative(phase); + auto mass_positive = mass_.col(phase) + mass_enrich; + auto mass_negative = mass_.col(phase) - mass_enrich; -// if((velocity_positive - velocity_negative).col(phase).dot(direction_discontinuity_.col(phase)) >= 0) -// return; + if(mass_positive(phase) < tolerance || mass_negative(phase) < tolerance) + return; -// auto momentum_contact = (mass_h_(phase)*momentum_.col(phase) - mass_(phase)*momentum_h_.col(phase)) / mass_(phase); -// auto force_contact = momentum_contact/dt; + auto velocity_positive = (momentum_.col(phase) + momenta_enrich) / mass_positive(phase); + auto velocity_negative = (momentum_.col(phase) - momenta_enrich) / mass_negative(phase); -// //! frictional_coef < 0: move together without slide -// if(frictional_coef < 0) -// { -// momentum_h_.col(phase) = momentum_h_.col(phase) + momentum_contact.col(phase); -// internal_force_h_.col(phase) = internal_force_h_.col(phase) + force_contact.col(phase); -// } -// else -// { -// double momentum_contact_norm = momentum_contact.col(phase).dot(direction_discontinuity_.col(phase)); -// double force_contact_norm = momentum_contact_norm/dt; + if((velocity_positive - velocity_negative).col(phase).dot(normal_vector) >= 0) + return; -// double max_frictional_force = frictional_coef * abs(force_contact_norm); + auto momentum_contact = (mass_enrich(phase)*momentum_.col(phase) - mass_(phase)*momenta_enrich) / mass_(phase); + auto force_contact = momentum_contact/dt; -// auto momentum_tangential = momentum_contact.col(phase) - momentum_contact_norm*direction_discontinuity_.col(phase); -// auto force_tangential = momentum_tangential/dt; + // //! frictional_coef < 0: move together without slide + // //need to be done + double frictional_coef = 0; + if(frictional_coef < 0) + { + property_handle_->update_property("momenta_enrich",discontinuity_prop_id_,0,momentum_contact.col(phase),Tdim); + property_handle_->update_property("external_force_enrich",discontinuity_prop_id_,0,force_contact.col(phase),Tdim); + } + else + { + double momentum_contact_norm = momentum_contact.col(phase).dot(normal_vector); + double force_contact_norm = momentum_contact_norm/dt; -// double force_tangential_value = force_tangential.norm(); + double max_frictional_force = frictional_coef * abs(force_contact_norm); -// double frictional_force = force_tangential_value < max_frictional_force? force_tangential_value : max_frictional_force; + auto momentum_tangential = momentum_contact.col(phase) - momentum_contact_norm*normal_vector; + auto force_tangential = momentum_tangential/dt; -// //!adjust the momentum and force -// momentum_h_.col(phase) = momentum_h_.col(phase) + momentum_contact_norm*direction_discontinuity_.col(phase); -// internal_force_h_.col(phase) = internal_force_h_.col(phase) + force_contact_norm*direction_discontinuity_.col(phase); + double force_tangential_value = force_tangential.norm(); -// momentum_h_.col(phase) = momentum_h_.col(phase) + frictional_force*force_tangential.col(phase).normalized()*dt; -// internal_force_h_.col(phase) = internal_force_h_.col(phase) + frictional_force*force_tangential.col(phase).normalized(); + double frictional_force = force_tangential_value < max_frictional_force? force_tangential_value : max_frictional_force; -// } -// } \ No newline at end of file + //!adjust the momentum and force + property_handle_->update_property("momenta_enrich",discontinuity_prop_id_,0,momentum_contact_norm*normal_vector+frictional_force*force_tangential.col(phase).normalized()*dt,Tdim); + property_handle_->update_property("external_force_enrich",discontinuity_prop_id_,0,force_contact_norm*normal_vector+frictional_force*force_tangential.col(phase).normalized(),Tdim); + } +} \ No newline at end of file diff --git a/include/node_base.h b/include/node_base.h index 0a9f82b34..9808c678c 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -286,6 +286,11 @@ class NodeBase { //! \param[in] dt Timestep in analysis virtual bool intergrate_momentum_discontinuity( unsigned phase, double dt) noexcept = 0; + + + //! Apply self-contact of the discontinuity + //! \param[in] dt Time-step + virtual void self_contact_discontinuity(double dt) = 0; }; // NodeBase class } // namespace mpm diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index f9c53eb70..9462efd4a 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -335,7 +335,7 @@ bool mpm::XMPMExplicit::solve() { } auto solver_end = std::chrono::steady_clock::now(); console_->info( - "Rank {}, Explicit {} solver duration: {} ms", mpi_rank, + "Rank {}, XMPMExplicit {} solver duration: {} ms", mpi_rank, (this->stress_update_ == mpm::StressUpdate::USL ? "USL" : "USF"), std::chrono::duration_cast(solver_end - solver_begin) From ab32ab3b0a07a55f51e5425aa98c16f35fe66844 Mon Sep 17 00:00:00 2001 From: yong liang Date: Tue, 4 Aug 2020 21:42:33 -0700 Subject: [PATCH 30/91] :hammer:move the node_xmpm function to a separate file --- include/node.h | 1 + include/node.tcc | 168 ------------------------------- include/node_xmpm.tcc | 224 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 225 insertions(+), 168 deletions(-) create mode 100644 include/node_xmpm.tcc diff --git a/include/node.h b/include/node.h index eedddabd2..8aa16ef74 100644 --- a/include/node.h +++ b/include/node.h @@ -365,5 +365,6 @@ class Node : public NodeBase { } // namespace mpm #include "node.tcc" +#include "node_xmpm.tcc" #endif // MPM_NODE_H_ diff --git a/include/node.tcc b/include/node.tcc index 1806ffb6f..7d3a9cfcb 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -46,16 +46,6 @@ void mpm::Node::initialise_property_handle( this->prop_id_ = prop_id; } -//! Initialise shared pointer to nodal properties pool for discontinuity -template -void mpm::Node::initialise_discontinuity_property_handle( - unsigned prop_id, - std::shared_ptr property_handle) noexcept { - // the property handle and the property id is set in the node - this->property_handle_ = property_handle; - this->discontinuity_prop_id_ = prop_id; -} - //! Update mass at the nodes from particle template void mpm::Node::update_mass(bool update, unsigned phase, @@ -560,19 +550,6 @@ void mpm::Node::update_property( node_mutex_.unlock(); } -//! Update nodal property at the nodes from particle for discontinuity -template -void mpm::Node::update_discontinuity_property( - bool update, const std::string& property, - const Eigen::MatrixXd& property_value, unsigned discontinuity_id, - unsigned nprops) noexcept { - // Update/assign property - node_mutex_.lock(); - property_handle_->update_property(property, discontinuity_prop_id_, discontinuity_id, property_value, - nprops); - node_mutex_.unlock(); -} - //! Compute multimaterial change in momentum template void mpm::Node -Eigen::MatrixXd mpm::Node::discontinuity_property(const std::string& property, - unsigned nprops) { - // Const pointer to location of property: node_id * nprops x mat_id - auto property_value = property_handle_->property(property, discontinuity_prop_id_, 0, nprops);; - //mpm::MapProperty property_handle(position, nprops); - return property_value; -} - -//! Compute acceleration and velocity with cundall damping factor -template -bool mpm::Node::intergrate_momentum_discontinuity( - unsigned phase, double dt) noexcept { - momentum_.col(phase) = momentum_.col(phase) - + (internal_force_.col(phase) + external_force_.col(phase)) * dt; - if(discontinuity_enrich_){ - property_handle_->update_property("momenta_enrich", discontinuity_prop_id_, 0, - (property_handle_->property("internal_force_enrich",discontinuity_prop_id_,0,Tdim) - + property_handle_->property("external_force_enrich",discontinuity_prop_id_,0,Tdim) ) * dt, Tdim); - } - // Apply velocity constraints, which also sets acceleration to 0, - // when velocity is set. - this->apply_velocity_constraints_discontinuity(); - - //need to be done - Eigen::Matrix normal{0.44721359474414313,0,0.89442719147920724}; - property_handle_->assign_property("normal_unit_vectors_discontinuity",discontinuity_prop_id_,0, - normal,Tdim); - - this->self_contact_discontinuity(dt); - - this->apply_velocity_constraints_discontinuity(); - - - return true; -} - //! Apply velocity constraints -template -void mpm::Node::apply_velocity_constraints_discontinuity() { - // Set velocity constraint - for (const auto& constraint : this->velocity_constraints_) { - // Direction value in the constraint (0, Dim * Nphases) - const unsigned dir = constraint.first; - // Direction: dir % Tdim (modulus) - const auto direction = static_cast(dir % Tdim); - // Phase: Integer value of division (dir / Tdim) - const auto phase = static_cast(dir / Tdim); - - if (!generic_boundary_constraints_) { - // Velocity constraints are applied on Cartesian boundaries - //this->velocity_(direction, phase) = constraint.second; - //need to do for one direction - - this->momentum_(direction, phase) = this->mass(phase) * constraint.second; - property_handle_->assign_property("momenta_enrich",discontinuity_prop_id_*Tdim+direction,0, - property_handle_->property("mass_enrich",discontinuity_prop_id_,0,1) * constraint.second,1); - // Set acceleration to 0 in direction of velocity constraint - //this->acceleration_(direction, phase) = 0.; - this->internal_force_(direction, phase) = 0; - this->external_force_(direction, phase) = 0; - - Eigen::Matrix momentum; - momentum.setZero(); - property_handle_->assign_property("internal_force_enrich",discontinuity_prop_id_*Tdim+direction,0, - momentum,1); - property_handle_->assign_property("external_force_enrich",discontinuity_prop_id_*Tdim+direction,0, - momentum,1); - } else { //need to do - // Velocity constraints on general boundaries - // Compute inverse rotation matrix - const Eigen::Matrix inverse_rotation_matrix = - rotation_matrix_.inverse(); - // Transform to local coordinate - Eigen::Matrix local_velocity = - inverse_rotation_matrix * this->velocity_; - Eigen::Matrix local_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 - this->velocity_ = rotation_matrix_ * local_velocity; - this->acceleration_ = rotation_matrix_ * local_acceleration; - } - } -} -//! Apply velocity constraints -template -void mpm::Node::self_contact_discontinuity(double dt) { - - if(!discontinuity_enrich_) - return; - - unsigned phase = 0; - const double tolerance = 1.0E-15; - - Eigen::Matrix mass_enrich = property_handle_->property("mass_enrich",discontinuity_prop_id_,0,1); - Eigen::Matrix momenta_enrich = property_handle_->property("momenta_enrich",discontinuity_prop_id_,0,Tdim); - Eigen::Matrix normal_vector = property_handle_->property("normal_unit_vectors_discontinuity",discontinuity_prop_id_,0,Tdim); - - auto mass_positive = mass_.col(phase) + mass_enrich; - auto mass_negative = mass_.col(phase) - mass_enrich; - - if(mass_positive(phase) < tolerance || mass_negative(phase) < tolerance) - return; - - auto velocity_positive = (momentum_.col(phase) + momenta_enrich) / mass_positive(phase); - auto velocity_negative = (momentum_.col(phase) - momenta_enrich) / mass_negative(phase); - - if((velocity_positive - velocity_negative).col(phase).dot(normal_vector) >= 0) - return; - - auto momentum_contact = (mass_enrich(phase)*momentum_.col(phase) - mass_(phase)*momenta_enrich) / mass_(phase); - auto force_contact = momentum_contact/dt; - - // //! frictional_coef < 0: move together without slide - // //need to be done - double frictional_coef = 0; - if(frictional_coef < 0) - { - property_handle_->update_property("momenta_enrich",discontinuity_prop_id_,0,momentum_contact.col(phase),Tdim); - property_handle_->update_property("external_force_enrich",discontinuity_prop_id_,0,force_contact.col(phase),Tdim); - } - else - { - double momentum_contact_norm = momentum_contact.col(phase).dot(normal_vector); - double force_contact_norm = momentum_contact_norm/dt; - - double max_frictional_force = frictional_coef * abs(force_contact_norm); - - auto momentum_tangential = momentum_contact.col(phase) - momentum_contact_norm*normal_vector; - auto force_tangential = momentum_tangential/dt; - - double force_tangential_value = force_tangential.norm(); - - double frictional_force = force_tangential_value < max_frictional_force? force_tangential_value : max_frictional_force; - - //!adjust the momentum and force - property_handle_->update_property("momenta_enrich",discontinuity_prop_id_,0,momentum_contact_norm*normal_vector+frictional_force*force_tangential.col(phase).normalized()*dt,Tdim); - property_handle_->update_property("external_force_enrich",discontinuity_prop_id_,0,force_contact_norm*normal_vector+frictional_force*force_tangential.col(phase).normalized(),Tdim); - } -} \ No newline at end of file diff --git a/include/node_xmpm.tcc b/include/node_xmpm.tcc new file mode 100644 index 000000000..88fd30fbc --- /dev/null +++ b/include/node_xmpm.tcc @@ -0,0 +1,224 @@ +//! Initialise shared pointer to nodal properties pool for discontinuity +template +void mpm::Node::initialise_discontinuity_property_handle( + unsigned prop_id, + std::shared_ptr property_handle) noexcept { + // the property handle and the property id is set in the node + this->property_handle_ = property_handle; + this->discontinuity_prop_id_ = prop_id; +} + +//! Update nodal property at the nodes from particle for discontinuity +template +void mpm::Node::update_discontinuity_property( + bool update, const std::string& property, + const Eigen::MatrixXd& property_value, unsigned discontinuity_id, + unsigned nprops) noexcept { + // Update/assign property + node_mutex_.lock(); + property_handle_->update_property(property, discontinuity_prop_id_, discontinuity_id, property_value, + nprops); + node_mutex_.unlock(); +} + +// Return data in the nodal properties map at a specific index +template +Eigen::MatrixXd mpm::Node::discontinuity_property(const std::string& property, + unsigned nprops) { + // Const pointer to location of property: node_id * nprops x mat_id + auto property_value = property_handle_->property(property, discontinuity_prop_id_, 0, nprops);; + //mpm::MapProperty property_handle(position, nprops); + return property_value; +} + +//! Compute acceleration and velocity with cundall damping factor +template +bool mpm::Node::intergrate_momentum_discontinuity( + unsigned phase, double dt) noexcept { + momentum_.col(phase) = momentum_.col(phase) + + (internal_force_.col(phase) + external_force_.col(phase)) * dt; + if(discontinuity_enrich_){ + property_handle_->update_property("momenta_enrich", discontinuity_prop_id_, 0, + (property_handle_->property("internal_force_enrich",discontinuity_prop_id_,0,Tdim) + + property_handle_->property("external_force_enrich",discontinuity_prop_id_,0,Tdim) ) * dt, Tdim); + } + // Apply velocity constraints, which also sets acceleration to 0, + // when velocity is set. + this->apply_velocity_constraints_discontinuity(); + + //need to be done + Eigen::Matrix normal{0.44721359474414313,0,0.89442719147920724}; + property_handle_->assign_property("normal_unit_vectors_discontinuity",discontinuity_prop_id_,0, + normal,Tdim); + + this->self_contact_discontinuity(dt); + + this->apply_velocity_constraints_discontinuity(); + + + return true; +} + //! Apply velocity constraints +template +void mpm::Node::apply_velocity_constraints_discontinuity() { + // Set velocity constraint + for (const auto& constraint : this->velocity_constraints_) { + // Direction value in the constraint (0, Dim * Nphases) + const unsigned dir = constraint.first; + // Direction: dir % Tdim (modulus) + const auto direction = static_cast(dir % Tdim); + // Phase: Integer value of division (dir / Tdim) + const auto phase = static_cast(dir / Tdim); + + if (!generic_boundary_constraints_) { + // Velocity constraints are applied on Cartesian boundaries + //this->velocity_(direction, phase) = constraint.second; + //need to do for one direction + + this->momentum_(direction, phase) = this->mass(phase) * constraint.second; + property_handle_->assign_property("momenta_enrich",discontinuity_prop_id_*Tdim+direction,0, + property_handle_->property("mass_enrich",discontinuity_prop_id_,0,1) * constraint.second,1); + // Set acceleration to 0 in direction of velocity constraint + //this->acceleration_(direction, phase) = 0.; + this->internal_force_(direction, phase) = 0; + this->external_force_(direction, phase) = 0; + + Eigen::Matrix momentum; + momentum.setZero(); + property_handle_->assign_property("internal_force_enrich",discontinuity_prop_id_*Tdim+direction,0, + momentum,1); + property_handle_->assign_property("external_force_enrich",discontinuity_prop_id_*Tdim+direction,0, + momentum,1);// Return data in the nodal properties map at a specific index +template +Eigen::MatrixXd mpm::Node::discontinuity_property(const std::string& property, + unsigned nprops) { + // Const pointer to location of property: node_id * nprops x mat_id + auto property_value = property_handle_->property(property, discontinuity_prop_id_, 0, nprops);; + //mpm::MapProperty property_handle(position, nprops); + return property_value; +} + +//! Compute acceleration and velocity with cundall damping factor +template +bool mpm::Node::intergrate_momentum_discontinuity( + unsigned phase, double dt) noexcept { + momentum_.col(phase) = momentum_.col(phase) + + (internal_force_.col(phase) + external_force_.col(phase)) * dt; + if(discontinuity_enrich_){ + property_handle_->update_property("momenta_enrich", discontinuity_prop_id_, 0, + (property_handle_->property("internal_force_enrich",discontinuity_prop_id_,0,Tdim) + + property_handle_->property("external_force_enrich",discontinuity_prop_id_,0,Tdim) ) * dt, Tdim); + } + // Apply velocity constraints, which also sets acceleration to 0, + // when velocity is set. + this->apply_velocity_constraints_discontinuity(); + + //need to be done + Eigen::Matrix normal{0.44721359474414313,0,0.89442719147920724}; + property_handle_->assign_property("normal_unit_vectors_discontinuity",discontinuity_prop_id_,0, + normal,Tdim); + + this->self_contact_discontinuity(dt); + + this->apply_velocity_constraints_discontinuity(); + + + return true; +} + //! Apply velocity constraints +template +void mpm::Node::apply_velocity_constraints_discontinuity() { + // Set velocity constraint + for (const auto& constraint : this->velocity_constraints_) { + // Direction value in the constraint (0, Dim * Nphases) + const unsigned dir = constraint.first; + // Direction: dir % Tdim (modulus) + const auto direction = static_cast(dir % Tdim); + // Phase: Integer value of division (dir / Tdim) + const auto phase = static_cast(dir / Tdim); + + if (!generic_boundary_constraints_) { + // Velocity constraints are applied on Cartesian boundaries + //this->velocity_(direction, phase) = constraint.second; + //need to do for one direction + + this->momentum_(direction, phase) = this->mass(phase) * constraint.second; + property_handle_->assign_property("momenta_enrich",discontinuity_prop_id_*Tdim+direction,0, + property_handle_->property("mass_enrich",d + } else { //need to do + // Velocity constraints on general boundaries + // Compute inverse rotation matrix + const Eigen::Matrix inverse_rotation_matrix = + rotation_matrix_.inverse(); + // Transform to local coordinate + Eigen::Matrix local_velocity = + inverse_rotation_matrix * this->velocity_; + Eigen::Matrix local_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 + this->velocity_ = rotation_matrix_ * local_velocity; + this->acceleration_ = rotation_matrix_ * local_acceleration; + } + } +} +//! Apply velocity constraints +template +void mpm::Node::self_contact_discontinuity(double dt) { + + if(!discontinuity_enrich_) + return; + + unsigned phase = 0; + const double tolerance = 1.0E-15; + + Eigen::Matrix mass_enrich = property_handle_->property("mass_enrich",discontinuity_prop_id_,0,1); + Eigen::Matrix momenta_enrich = property_handle_->property("momenta_enrich",discontinuity_prop_id_,0,Tdim); + Eigen::Matrix normal_vector = property_handle_->property("normal_unit_vectors_discontinuity",discontinuity_prop_id_,0,Tdim); + + auto mass_positive = mass_.col(phase) + mass_enrich; + auto mass_negative = mass_.col(phase) - mass_enrich; + + if(mass_positive(phase) < tolerance || mass_negative(phase) < tolerance) + return; + + auto velocity_positive = (momentum_.col(phase) + momenta_enrich) / mass_positive(phase); + auto velocity_negative = (momentum_.col(phase) - momenta_enrich) / mass_negative(phase); + + if((velocity_positive - velocity_negative).col(phase).dot(normal_vector) >= 0) + return; + + auto momentum_contact = (mass_enrich(phase)*momentum_.col(phase) - mass_(phase)*momenta_enrich) / mass_(phase); + auto force_contact = momentum_contact/dt; + + // //! frictional_coef < 0: move together without slide + // //need to be done + double frictional_coef = 0; + if(frictional_coef < 0) + { + property_handle_->update_property("momenta_enrich",discontinuity_prop_id_,0,momentum_contact.col(phase),Tdim); + property_handle_->update_property("external_force_enrich",discontinuity_prop_id_,0,force_contact.col(phase),Tdim); + } + else + { + double momentum_contact_norm = momentum_contact.col(phase).dot(normal_vector); + double force_contact_norm = momentum_contact_norm/dt; + + double max_frictional_force = frictional_coef * abs(force_contact_norm); + + auto momentum_tangential = momentum_contact.col(phase) - momentum_contact_norm*normal_vector; + auto force_tangential = momentum_tangential/dt; + + double force_tangential_value = force_tangential.norm(); + + double frictional_force = force_tangential_value < max_frictional_force? force_tangential_value : max_frictional_force; + + //!adjust the momentum and force + property_handle_->update_property("momenta_enrich",discontinuity_prop_id_,0,momentum_contact_norm*normal_vector+frictional_force*force_tangential.col(phase).normalized()*dt,Tdim); + property_handle_->update_property("external_force_enrich",discontinuity_prop_id_,0,force_contact_norm*normal_vector+frictional_force*force_tangential.col(phase).normalized(),Tdim); + } +} \ No newline at end of file From d7a5c859dc984239cc7d45bc17ae186528bac645 Mon Sep 17 00:00:00 2001 From: yong liang Date: Tue, 4 Aug 2020 21:55:34 -0700 Subject: [PATCH 31/91] :bug:miss some functions for node_xmpm.tcc --- include/node_xmpm.tcc | 59 +------------------------------------------ 1 file changed, 1 insertion(+), 58 deletions(-) diff --git a/include/node_xmpm.tcc b/include/node_xmpm.tcc index 88fd30fbc..01127b18f 100644 --- a/include/node_xmpm.tcc +++ b/include/node_xmpm.tcc @@ -89,64 +89,7 @@ void mpm::Node::apply_velocity_constraints_discontinuity() property_handle_->assign_property("internal_force_enrich",discontinuity_prop_id_*Tdim+direction,0, momentum,1); property_handle_->assign_property("external_force_enrich",discontinuity_prop_id_*Tdim+direction,0, - momentum,1);// Return data in the nodal properties map at a specific index -template -Eigen::MatrixXd mpm::Node::discontinuity_property(const std::string& property, - unsigned nprops) { - // Const pointer to location of property: node_id * nprops x mat_id - auto property_value = property_handle_->property(property, discontinuity_prop_id_, 0, nprops);; - //mpm::MapProperty property_handle(position, nprops); - return property_value; -} - -//! Compute acceleration and velocity with cundall damping factor -template -bool mpm::Node::intergrate_momentum_discontinuity( - unsigned phase, double dt) noexcept { - momentum_.col(phase) = momentum_.col(phase) - + (internal_force_.col(phase) + external_force_.col(phase)) * dt; - if(discontinuity_enrich_){ - property_handle_->update_property("momenta_enrich", discontinuity_prop_id_, 0, - (property_handle_->property("internal_force_enrich",discontinuity_prop_id_,0,Tdim) - + property_handle_->property("external_force_enrich",discontinuity_prop_id_,0,Tdim) ) * dt, Tdim); - } - // Apply velocity constraints, which also sets acceleration to 0, - // when velocity is set. - this->apply_velocity_constraints_discontinuity(); - - //need to be done - Eigen::Matrix normal{0.44721359474414313,0,0.89442719147920724}; - property_handle_->assign_property("normal_unit_vectors_discontinuity",discontinuity_prop_id_,0, - normal,Tdim); - - this->self_contact_discontinuity(dt); - - this->apply_velocity_constraints_discontinuity(); - - - return true; -} - //! Apply velocity constraints -template -void mpm::Node::apply_velocity_constraints_discontinuity() { - // Set velocity constraint - for (const auto& constraint : this->velocity_constraints_) { - // Direction value in the constraint (0, Dim * Nphases) - const unsigned dir = constraint.first; - // Direction: dir % Tdim (modulus) - const auto direction = static_cast(dir % Tdim); - // Phase: Integer value of division (dir / Tdim) - const auto phase = static_cast(dir / Tdim); - - if (!generic_boundary_constraints_) { - // Velocity constraints are applied on Cartesian boundaries - //this->velocity_(direction, phase) = constraint.second; - //need to do for one direction - - this->momentum_(direction, phase) = this->mass(phase) * constraint.second; - property_handle_->assign_property("momenta_enrich",discontinuity_prop_id_*Tdim+direction,0, - property_handle_->property("mass_enrich",d + momentum,1); } else { //need to do // Velocity constraints on general boundaries // Compute inverse rotation matrix From 3b9b316a8776a0bc08cd0d54645997fa5675e4a2 Mon Sep 17 00:00:00 2001 From: yong liang Date: Wed, 5 Aug 2020 12:17:42 -0700 Subject: [PATCH 32/91] :hammer:add const --- include/node.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/node.h b/include/node.h index 8aa16ef74..0d2e5b1eb 100644 --- a/include/node.h +++ b/include/node.h @@ -209,7 +209,7 @@ class Node : public NodeBase { void apply_velocity_constraints() override; //! Apply velocity constraints for discontinuity - void apply_velocity_constraints_discontinuity() override; + void apply_velocity_constraints_discontinuity() noexcept override; //! Assign friction constraint //! Directions can take values between 0 and Dim * Nphases @@ -275,7 +275,7 @@ class Node : public NodeBase { void compute_multimaterial_normal_unit_vector() override; //! Return whether the node is enriched - bool discontinuity_enrich() {return discontinuity_enrich_;}; + bool discontinuity_enrich() const override {return discontinuity_enrich_;}; //! Update nodal property at the nodes from particle for discontinuity //! \param[in] update A boolean to update (true) or assign (false) @@ -290,7 +290,7 @@ class Node : public NodeBase { // Return data in the nodal discontinuity properties map at a specific index // \param[in] property Property name // \param[in] nprops Dimension of property (1 if scalar, Tdim if vector) - Eigen::MatrixXd discontinuity_property(const std::string& property, unsigned nprops = 1) override; + Eigen::MatrixXd discontinuity_property(const std::string& property, unsigned nprops = 1) noexcept override; //! Compute momentum //! \param[in] phase Index corresponding to the phase @@ -300,7 +300,7 @@ class Node : public NodeBase { //! Apply self-contact of the discontinuity //! \param[in] dt Time-step - void self_contact_discontinuity(double dt) override; + void self_contact_discontinuity(double dt) noexcept override; private: //! Mutex SpinMutex node_mutex_; From fee31b75bee7abe8571a582bc34d54cceaf94d4b Mon Sep 17 00:00:00 2001 From: yong liang Date: Thu, 6 Aug 2020 14:39:33 -0700 Subject: [PATCH 33/91] :construction:clang format --- include/io/logger.h | 2 +- include/mesh.h | 4 +- include/mesh.tcc | 15 +-- include/node.h | 27 ++-- include/node_base.h | 21 ++-- include/node_xmpm.tcc | 166 ++++++++++++++---------- include/particles/particle_base.h | 2 +- include/particles/particle_xmpm.h | 11 +- include/particles/particle_xmpm.tcc | 170 +++++++++++++------------ include/solvers/xmpm_explicit.h | 12 +- include/solvers/xmpm_explicit.tcc | 91 ++++++++------ include/xmpm/discontinuity_3d.h | 52 ++++---- include/xmpm/discontinuity_3d.tcc | 153 +++++++++++----------- include/xmpm/discontinuity_base.h | 188 +++++++++++++--------------- src/discontinuity.cc | 5 +- 15 files changed, 494 insertions(+), 425 deletions(-) mode change 100755 => 100644 include/xmpm/discontinuity_3d.h mode change 100755 => 100644 include/xmpm/discontinuity_3d.tcc mode change 100755 => 100644 include/xmpm/discontinuity_base.h mode change 100755 => 100644 src/discontinuity.cc diff --git a/include/io/logger.h b/include/io/logger.h index 01c1afcf7..8a7ff9766 100644 --- a/include/io/logger.h +++ b/include/io/logger.h @@ -42,7 +42,7 @@ struct Logger { // Create a logger for MPM Explicit USL static const std::shared_ptr mpm_explicit_usl_logger; - // Create a logger for MPM Explicit + // Create a logger for MPM Explicit static const std::shared_ptr xmpm_explicit_logger; }; diff --git a/include/mesh.h b/include/mesh.h index 35872f025..0582bf809 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -461,10 +461,10 @@ class Mesh { // Initialise the nodal properties' map void initialise_nodal_properties(); - //! Set particles lsm values + //! Set particles lsm values void assign_particle_levelset(std::vector& phi_list); - // Create the nodal properties' map for discontinuity + // Create the nodal properties' map for discontinuity void create_nodal_properties_discontinuity(); private: diff --git a/include/mesh.tcc b/include/mesh.tcc index 4b2f238fb..a9384eba4 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1960,7 +1960,7 @@ void mpm::Mesh::create_nodal_properties() { template void mpm::Mesh::create_nodal_properties_discontinuity() { // Initialise the shared pointer to nodal properties - if(nodal_properties_ == nullptr) + if (nodal_properties_ == nullptr) nodal_properties_ = std::make_shared(); // Check if nodes_ is empty and throw runtime error if they are @@ -1969,16 +1969,18 @@ void mpm::Mesh::create_nodal_properties_discontinuity() { const unsigned nrows = nodes_.size() * Tdim; // Create pool data for each property in the nodal properties struct // object. Properties must be named in the plural form - nodal_properties_->create_property("mass_enrich", nodes_.size(),1); + nodal_properties_->create_property("mass_enrich", nodes_.size(), 1); nodal_properties_->create_property("momenta_enrich", nrows, 1); nodal_properties_->create_property("internal_force_enrich", nrows, 1); nodal_properties_->create_property("external_force_enrich", nrows, 1); - nodal_properties_->create_property("normal_unit_vectors_discontinuity", nrows,1); + nodal_properties_->create_property("normal_unit_vectors_discontinuity", + nrows, 1); // Iterate over all nodes to initialise the property handle in each node // and assign its node id as the prop id in the nodal property data pool for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) - (*nitr)->initialise_discontinuity_property_handle((*nitr)->id(), nodal_properties_); + (*nitr)->initialise_discontinuity_property_handle((*nitr)->id(), + nodal_properties_); } else { throw std::runtime_error("Number of nodes is zero"); } @@ -1993,8 +1995,7 @@ void mpm::Mesh::initialise_nodal_properties() { //! Set particles lsm values template -void mpm::Mesh::assign_particle_levelset(std::vector& phi_list) -{ - for(mpm::Index i = 0; i::assign_particle_levelset(std::vector& phi_list) { + for (mpm::Index i = 0; i < nparticles(); ++i) particles_[i]->assign_levelsetphi(phi_list[i]); } \ No newline at end of file diff --git a/include/node.h b/include/node.h index 0d2e5b1eb..ce363cffb 100644 --- a/include/node.h +++ b/include/node.h @@ -208,8 +208,8 @@ class Node : public NodeBase { //! Apply velocity constraints void apply_velocity_constraints() override; - //! Apply velocity constraints for discontinuity - void apply_velocity_constraints_discontinuity() noexcept override; + //! Apply velocity constraints for discontinuity + void apply_velocity_constraints_discontinuity() override; //! Assign friction constraint //! Directions can take values between 0 and Dim * Nphases @@ -275,32 +275,35 @@ class Node : public NodeBase { void compute_multimaterial_normal_unit_vector() override; //! Return whether the node is enriched - bool discontinuity_enrich() const override {return discontinuity_enrich_;}; + bool discontinuity_enrich() const { return discontinuity_enrich_; }; - //! Update nodal property at the nodes from particle for discontinuity + //! Update nodal property at the nodes from particle for discontinuity //! \param[in] update A boolean to update (true) or assign (false) //! \param[in] property Property name //! \param[in] property_value Property quantity from the particles in the cell //! \param[in] discontinuity_id Id of the material within the property data //! \param[in] nprops Dimension of property (1 if scalar, Tdim if vector) void update_discontinuity_property(bool update, const std::string& property, - const Eigen::MatrixXd& property_value, unsigned discontinuity_id, - unsigned nprops) noexcept override; + const Eigen::MatrixXd& property_value, + unsigned discontinuity_id, + unsigned nprops) noexcept override; - // Return data in the nodal discontinuity properties map at a specific index + // Return data in the nodal discontinuity properties map at a specific index // \param[in] property Property name // \param[in] nprops Dimension of property (1 if scalar, Tdim if vector) - Eigen::MatrixXd discontinuity_property(const std::string& property, unsigned nprops = 1) noexcept override; + Eigen::MatrixXd discontinuity_property(const std::string& property, + unsigned nprops = 1) noexcept override; - //! Compute momentum + //! Compute momentum //! \param[in] phase Index corresponding to the phase //! \param[in] dt Timestep in analysis - virtual bool intergrate_momentum_discontinuity( - unsigned phase, double dt) noexcept override; + virtual bool intergrate_momentum_discontinuity(unsigned phase, + double dt) noexcept override; //! Apply self-contact of the discontinuity //! \param[in] dt Time-step void self_contact_discontinuity(double dt) noexcept override; + private: //! Mutex SpinMutex node_mutex_; @@ -359,7 +362,7 @@ class Node : public NodeBase { //! MPI ranks std::set mpi_ranks_; //! discontinuity enrich - //need to be done + // need to be done bool discontinuity_enrich_{true}; }; // Node class } // namespace mpm diff --git a/include/node_base.h b/include/node_base.h index 9808c678c..134bbf8c6 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -263,13 +263,14 @@ class NodeBase { //! Compute multimaterial normal unit vector virtual void compute_multimaterial_normal_unit_vector() = 0; - // Return data in the nodal discontinuity properties map at a specific index + // Return data in the nodal discontinuity properties map at a specific index // \param[in] property Property name // \param[in] nprops Dimension of property (1 if scalar, Tdim if vector) - virtual Eigen::MatrixXd discontinuity_property(const std::string& property,unsigned nprops = 1) = 0; + virtual Eigen::MatrixXd discontinuity_property( + const std::string& property, unsigned nprops = 1) noexcept = 0; //! Return whether the node is enriched - virtual bool discontinuity_enrich() = 0; + virtual bool discontinuity_enrich() const = 0; //! Update nodal property at the nodes from particle for discontinuity //! \param[in] update A boolean to update (true) or assign (false) @@ -277,20 +278,20 @@ class NodeBase { //! \param[in] property_value Property quantity from the particles in the cell //! \param[in] discontinuity_id Id of the material within the property data //! \param[in] nprops Dimension of property (1 if scalar, Tdim if vector) - virtual void update_discontinuity_property(bool update, const std::string& property, - const Eigen::MatrixXd& property_value, unsigned discontinuity_id, - unsigned nprops) noexcept = 0; + virtual void update_discontinuity_property( + bool update, const std::string& property, + const Eigen::MatrixXd& property_value, unsigned discontinuity_id, + unsigned nprops) noexcept = 0; //! Compute momentum //! \param[in] phase Index corresponding to the phase //! \param[in] dt Timestep in analysis - virtual bool intergrate_momentum_discontinuity( - unsigned phase, double dt) noexcept = 0; - + virtual bool intergrate_momentum_discontinuity(unsigned phase, + double dt) noexcept = 0; //! Apply self-contact of the discontinuity //! \param[in] dt Time-step - virtual void self_contact_discontinuity(double dt) = 0; + virtual void self_contact_discontinuity(double dt) noexcept = 0; }; // NodeBase class } // namespace mpm diff --git a/include/node_xmpm.tcc b/include/node_xmpm.tcc index 01127b18f..5649722d0 100644 --- a/include/node_xmpm.tcc +++ b/include/node_xmpm.tcc @@ -16,19 +16,20 @@ void mpm::Node::update_discontinuity_property( unsigned nprops) noexcept { // Update/assign property node_mutex_.lock(); - property_handle_->update_property(property, discontinuity_prop_id_, discontinuity_id, property_value, - nprops); + property_handle_->update_property(property, discontinuity_prop_id_, + discontinuity_id, property_value, nprops); node_mutex_.unlock(); } // Return data in the nodal properties map at a specific index template -Eigen::MatrixXd mpm::Node::discontinuity_property(const std::string& property, - unsigned nprops) { +Eigen::MatrixXd mpm::Node::discontinuity_property( + const std::string& property, unsigned nprops) noexcept { // Const pointer to location of property: node_id * nprops x mat_id - auto property_value = property_handle_->property(property, discontinuity_prop_id_, 0, nprops);; - //mpm::MapProperty property_handle(position, nprops); + auto property_value = + property_handle_->property(property, discontinuity_prop_id_, 0, nprops); + ; + // mpm::MapProperty property_handle(position, nprops); return property_value; } @@ -36,32 +37,39 @@ Eigen::MatrixXd mpm::Node bool mpm::Node::intergrate_momentum_discontinuity( unsigned phase, double dt) noexcept { - momentum_.col(phase) = momentum_.col(phase) - + (internal_force_.col(phase) + external_force_.col(phase)) * dt; - if(discontinuity_enrich_){ - property_handle_->update_property("momenta_enrich", discontinuity_prop_id_, 0, - (property_handle_->property("internal_force_enrich",discontinuity_prop_id_,0,Tdim) - + property_handle_->property("external_force_enrich",discontinuity_prop_id_,0,Tdim) ) * dt, Tdim); + momentum_.col(phase) = + momentum_.col(phase) + + (internal_force_.col(phase) + external_force_.col(phase)) * dt; + if (discontinuity_enrich_) { + property_handle_->update_property( + "momenta_enrich", discontinuity_prop_id_, 0, + (property_handle_->property("internal_force_enrich", + discontinuity_prop_id_, 0, Tdim) + + property_handle_->property("external_force_enrich", + discontinuity_prop_id_, 0, Tdim)) * + dt, + Tdim); } // Apply velocity constraints, which also sets acceleration to 0, // when velocity is set. this->apply_velocity_constraints_discontinuity(); - //need to be done - Eigen::Matrix normal{0.44721359474414313,0,0.89442719147920724}; - property_handle_->assign_property("normal_unit_vectors_discontinuity",discontinuity_prop_id_,0, - normal,Tdim); + // need to be done + Eigen::Matrix normal{0.44721359474414313, 0, + 0.89442719147920724}; + property_handle_->assign_property("normal_unit_vectors_discontinuity", + discontinuity_prop_id_, 0, normal, Tdim); this->self_contact_discontinuity(dt); this->apply_velocity_constraints_discontinuity(); - return true; } - //! Apply velocity constraints +//! Apply velocity constraints template -void mpm::Node::apply_velocity_constraints_discontinuity() { +void mpm::Node::apply_velocity_constraints_discontinuity() { // Set velocity constraint for (const auto& constraint : this->velocity_constraints_) { // Direction value in the constraint (0, Dim * Nphases) @@ -73,24 +81,30 @@ void mpm::Node::apply_velocity_constraints_discontinuity() if (!generic_boundary_constraints_) { // Velocity constraints are applied on Cartesian boundaries - //this->velocity_(direction, phase) = constraint.second; - //need to do for one direction + // this->velocity_(direction, phase) = constraint.second; + // need to do for one direction this->momentum_(direction, phase) = this->mass(phase) * constraint.second; - property_handle_->assign_property("momenta_enrich",discontinuity_prop_id_*Tdim+direction,0, - property_handle_->property("mass_enrich",discontinuity_prop_id_,0,1) * constraint.second,1); + property_handle_->assign_property( + "momenta_enrich", discontinuity_prop_id_ * Tdim + direction, 0, + property_handle_->property("mass_enrich", discontinuity_prop_id_, 0, + 1) * + constraint.second, + 1); // Set acceleration to 0 in direction of velocity constraint - //this->acceleration_(direction, phase) = 0.; + // this->acceleration_(direction, phase) = 0.; this->internal_force_(direction, phase) = 0; this->external_force_(direction, phase) = 0; Eigen::Matrix momentum; - momentum.setZero(); - property_handle_->assign_property("internal_force_enrich",discontinuity_prop_id_*Tdim+direction,0, - momentum,1); - property_handle_->assign_property("external_force_enrich",discontinuity_prop_id_*Tdim+direction,0, - momentum,1); - } else { //need to do + momentum.setZero(); + property_handle_->assign_property( + "internal_force_enrich", discontinuity_prop_id_ * Tdim + direction, 0, + momentum, 1); + property_handle_->assign_property( + "external_force_enrich", discontinuity_prop_id_ * Tdim + direction, 0, + momentum, 1); + } else { // need to do // Velocity constraints on general boundaries // Compute inverse rotation matrix const Eigen::Matrix inverse_rotation_matrix = @@ -111,57 +125,83 @@ void mpm::Node::apply_velocity_constraints_discontinuity() } //! Apply velocity constraints template -void mpm::Node::self_contact_discontinuity(double dt) { +void mpm::Node::self_contact_discontinuity( + double dt) noexcept { - if(!discontinuity_enrich_) - return; - - unsigned phase = 0; + if (!discontinuity_enrich_) return; + + unsigned phase = 0; const double tolerance = 1.0E-15; - Eigen::Matrix mass_enrich = property_handle_->property("mass_enrich",discontinuity_prop_id_,0,1); - Eigen::Matrix momenta_enrich = property_handle_->property("momenta_enrich",discontinuity_prop_id_,0,Tdim); - Eigen::Matrix normal_vector = property_handle_->property("normal_unit_vectors_discontinuity",discontinuity_prop_id_,0,Tdim); + Eigen::Matrix mass_enrich = + property_handle_->property("mass_enrich", discontinuity_prop_id_, 0, 1); + Eigen::Matrix momenta_enrich = property_handle_->property( + "momenta_enrich", discontinuity_prop_id_, 0, Tdim); + Eigen::Matrix normal_vector = property_handle_->property( + "normal_unit_vectors_discontinuity", discontinuity_prop_id_, 0, Tdim); + // mass for different sides auto mass_positive = mass_.col(phase) + mass_enrich; auto mass_negative = mass_.col(phase) - mass_enrich; - if(mass_positive(phase) < tolerance || mass_negative(phase) < tolerance) + if (mass_positive(phase) < tolerance || mass_negative(phase) < tolerance) return; - auto velocity_positive = (momentum_.col(phase) + momenta_enrich) / mass_positive(phase); - auto velocity_negative = (momentum_.col(phase) - momenta_enrich) / mass_negative(phase); + // velocity for different sides + auto velocity_positive = + (momentum_.col(phase) + momenta_enrich) / mass_positive(phase); + auto velocity_negative = + (momentum_.col(phase) - momenta_enrich) / mass_negative(phase); - if((velocity_positive - velocity_negative).col(phase).dot(normal_vector) >= 0) + // relative normal velocity + if ((velocity_positive - velocity_negative).col(phase).dot(normal_vector) >= + 0) return; - auto momentum_contact = (mass_enrich(phase)*momentum_.col(phase) - mass_(phase)*momenta_enrich) / mass_(phase); - auto force_contact = momentum_contact/dt; + // the contact momentum for sticking contact + auto momentum_contact = (mass_enrich(phase) * momentum_.col(phase) - + mass_(phase) * momenta_enrich) / + mass_(phase); + auto force_contact = momentum_contact / dt; - // //! frictional_coef < 0: move together without slide - // //need to be done + //! frictional_coef < 0: move together without slide + // need to be done double frictional_coef = 0; - if(frictional_coef < 0) - { - property_handle_->update_property("momenta_enrich",discontinuity_prop_id_,0,momentum_contact.col(phase),Tdim); - property_handle_->update_property("external_force_enrich",discontinuity_prop_id_,0,force_contact.col(phase),Tdim); - } - else - { - double momentum_contact_norm = momentum_contact.col(phase).dot(normal_vector); - double force_contact_norm = momentum_contact_norm/dt; + if (frictional_coef < 0) { + property_handle_->update_property("momenta_enrich", discontinuity_prop_id_, + 0, momentum_contact.col(phase), Tdim); + property_handle_->update_property("external_force_enrich", + discontinuity_prop_id_, 0, + force_contact.col(phase), Tdim); + } else { + double momentum_contact_norm = + momentum_contact.col(phase).dot(normal_vector); + double force_contact_norm = momentum_contact_norm / dt; + + // the maximum frictional contact force double max_frictional_force = frictional_coef * abs(force_contact_norm); - auto momentum_tangential = momentum_contact.col(phase) - momentum_contact_norm*normal_vector; - auto force_tangential = momentum_tangential/dt; + auto momentum_tangential = + momentum_contact.col(phase) - momentum_contact_norm * normal_vector; + auto force_tangential = momentum_tangential / dt; double force_tangential_value = force_tangential.norm(); - double frictional_force = force_tangential_value < max_frictional_force? force_tangential_value : max_frictional_force; - - //!adjust the momentum and force - property_handle_->update_property("momenta_enrich",discontinuity_prop_id_,0,momentum_contact_norm*normal_vector+frictional_force*force_tangential.col(phase).normalized()*dt,Tdim); - property_handle_->update_property("external_force_enrich",discontinuity_prop_id_,0,force_contact_norm*normal_vector+frictional_force*force_tangential.col(phase).normalized(),Tdim); + double frictional_force = force_tangential_value < max_frictional_force + ? force_tangential_value + : max_frictional_force; + + //! adjust the momentum and force + property_handle_->update_property( + "momenta_enrich", discontinuity_prop_id_, 0, + momentum_contact_norm * normal_vector + + frictional_force * force_tangential.col(phase).normalized() * dt, + Tdim); + property_handle_->update_property( + "external_force_enrich", discontinuity_prop_id_, 0, + force_contact_norm * normal_vector + + frictional_force * force_tangential.col(phase).normalized(), + Tdim); } } \ No newline at end of file diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 4a02392b7..4b46e3e19 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -315,7 +315,7 @@ class ParticleBase { const std::vector& buffer, std::vector>>& materials) = 0; //! set the level set function values - virtual void assign_levelsetphi(const double phivalue) {}; + virtual void assign_levelsetphi(const double phivalue){}; protected: //! particleBase id diff --git a/include/particles/particle_xmpm.h b/include/particles/particle_xmpm.h index dede2d187..3506097bf 100644 --- a/include/particles/particle_xmpm.h +++ b/include/particles/particle_xmpm.h @@ -306,10 +306,13 @@ class ParticleXMPM : public ParticleBase { inline Eigen::Matrix compute_strain_rate( const Eigen::MatrixXd& dn_dx, unsigned phase) noexcept; //! set the level set function values - void assign_levelsetphi(const double phivalue) { levelset_phi_ = phivalue;}; + void assign_levelsetphi(const double phivalue) { levelset_phi_ = phivalue; }; + + //! return 1 if x > 0, -1 if x < 0 and 0 if x = 0 + inline double sgn(double x) noexcept { + return (x > 0) ? 1. : ((x < 0) ? -1. : 0); + }; - //! return 1 if x > 0, -1 if x < 0 and 0 if x = 0 - inline double sgn(double x) noexcept {return (x > 0) ? 1. : ((x < 0) ? -1. : 0);}; private: //! particle id using ParticleBase::id_; @@ -375,7 +378,7 @@ class ParticleXMPM : public ParticleBase { std::unique_ptr console_; //! Map of vector properties std::map> properties_; - //!level set values for discontinuity + //! level set values for discontinuity double levelset_phi_{0.}; }; // ParticleXMPM class } // namespace mpm diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index e2961d1a6..ae203b350 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -17,7 +17,8 @@ mpm::ParticleXMPM::ParticleXMPM(Index id, const VectorDim& coord) //! Construct a particle with id, coordinates and status template -mpm::ParticleXMPM::ParticleXMPM(Index id, const VectorDim& coord, bool status) +mpm::ParticleXMPM::ParticleXMPM(Index id, const VectorDim& coord, + bool status) : mpm::ParticleBase(id, coord, status) { this->initialise(); cell_ = nullptr; @@ -32,7 +33,8 @@ mpm::ParticleXMPM::ParticleXMPM(Index id, const VectorDim& coord, bool sta //! Initialise particle data from HDF5 template -bool mpm::ParticleXMPM::initialise_particle(const HDF5Particle& particle) { +bool mpm::ParticleXMPM::initialise_particle( + const HDF5Particle& particle) { // Assign id this->id_ = particle.id; @@ -249,7 +251,6 @@ void mpm::ParticleXMPM::initialise() { this->properties_["strains"] = [&]() { return strain(); }; this->properties_["velocities"] = [&]() { return velocity(); }; this->properties_["displacements"] = [&]() { return displacement(); }; - this->properties_["levelset"] = [&]() { Eigen::Matrix levelset; levelset[0] = levelset_phi_ ; return levelset; }; } //! Initialise particle material container @@ -522,22 +523,23 @@ void mpm::ParticleXMPM::map_mass_momentum_to_nodes() noexcept { mass_ * shapefn_[i]); nodes_[i]->update_momentum(true, mpm::ParticlePhase::Solid, mass_ * shapefn_[i] * velocity_); - if(nodes_[i]->discontinuity_enrich()){ - // Unit 1x1 Eigen matrix to be used with scalar quantities + if (nodes_[i]->discontinuity_enrich()) { + // Unit 1x1 Eigen matrix to be used with scalar quantities Eigen::Matrix nodal_mass; - nodal_mass(0, 0) = sgn(levelset_phi_) * mass_ * shapefn_[i]; - // Map enriched mass and momentum to nodes - nodes_[i]->update_discontinuity_property(true, "mass_enrich", nodal_mass, 0, - 1); - nodes_[i]->update_discontinuity_property(true, "momenta_enrich", velocity_ * nodal_mass, - 0, Tdim); + nodal_mass(0, 0) = sgn(levelset_phi_) * mass_ * shapefn_[i]; + // Map enriched mass and momentum to nodes + nodes_[i]->update_discontinuity_property(true, "mass_enrich", nodal_mass, + 0, 1); + nodes_[i]->update_discontinuity_property(true, "momenta_enrich", + velocity_ * nodal_mass, 0, Tdim); } } } //! Map multimaterial properties to nodes template -void mpm::ParticleXMPM::map_multimaterial_mass_momentum_to_nodes() noexcept { +void mpm::ParticleXMPM< + Tdim>::map_multimaterial_mass_momentum_to_nodes() noexcept { // Check if particle mass is set assert(mass_ != std::numeric_limits::max()); @@ -556,7 +558,8 @@ void mpm::ParticleXMPM::map_multimaterial_mass_momentum_to_nodes() noexcep //! Map multimaterial displacements to nodes template -void mpm::ParticleXMPM::map_multimaterial_displacements_to_nodes() noexcept { +void mpm::ParticleXMPM< + Tdim>::map_multimaterial_displacements_to_nodes() noexcept { // Check if particle mass is set assert(mass_ != std::numeric_limits::max()); @@ -631,19 +634,23 @@ inline Eigen::Matrix mpm::ParticleXMPM<3>::compute_strain_rate( const double tolerance = 1.E-16; Eigen::Vector3d vel; vel.setZero(); - for (unsigned i = 0; i < this->nodes_.size(); ++i){ - if(nodes_[i]->discontinuity_enrich()){ - double nodal_mass = nodes_[i]->mass(phase) + sgn(levelset_phi_)*nodes_[i]->discontinuity_property("mass_enrich",1)(0,0) ; - if(nodal_mass < tolerance) - continue; - - vel = (nodes_[i]->momentum(phase) + sgn(levelset_phi_)*nodes_[i]->discontinuity_property("momenta_enrich",3).col(0))/nodal_mass; - } - else{ + for (unsigned i = 0; i < this->nodes_.size(); ++i) { + if (nodes_[i]->discontinuity_enrich()) { + double nodal_mass = + nodes_[i]->mass(phase) + + sgn(levelset_phi_) * + nodes_[i]->discontinuity_property("mass_enrich", 1)(0, 0); + if (nodal_mass < tolerance) continue; + + vel = + (nodes_[i]->momentum(phase) + + sgn(levelset_phi_) * + nodes_[i]->discontinuity_property("momenta_enrich", 3).col(0)) / + nodal_mass; + } else { double nodal_mass = nodes_[i]->mass(phase); - if(nodal_mass < tolerance) - continue; - vel = nodes_[i]->momentum(phase)/nodal_mass; + if (nodal_mass < tolerance) continue; + vel = nodes_[i]->momentum(phase) / nodal_mass; } strain_rate[0] += dn_dx(i, 0) * vel[0]; @@ -693,13 +700,16 @@ void mpm::ParticleXMPM::compute_stress() noexcept { //! Map body force template -void mpm::ParticleXMPM::map_body_force(const VectorDim& pgravity) noexcept { +void mpm::ParticleXMPM::map_body_force( + const VectorDim& pgravity) noexcept { // Compute nodal body forces - for (unsigned i = 0; i < nodes_.size(); ++i){ + for (unsigned i = 0; i < nodes_.size(); ++i) { nodes_[i]->update_external_force(true, mpm::ParticlePhase::Solid, (pgravity * mass_ * shapefn_(i))); - if(nodes_[i]->discontinuity_enrich()) - nodes_[i]->update_discontinuity_property(true, "external_force_enrich", sgn(levelset_phi_)*pgravity * mass_ * shapefn_(i), 0,Tdim); + if (nodes_[i]->discontinuity_enrich()) + nodes_[i]->update_discontinuity_property( + true, "external_force_enrich", + sgn(levelset_phi_) * pgravity * mass_ * shapefn_(i), 0, Tdim); } } @@ -713,8 +723,9 @@ inline void mpm::ParticleXMPM<1>::map_internal_force() noexcept { force[0] = -1. * dn_dx_(i, 0) * volume_ * stress_[0]; nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Solid, force); - if(nodes_[i]->discontinuity_enrich()) - nodes_[i]->update_discontinuity_property(true, "internal_force_enrich", sgn(levelset_phi_)*force, 0,1); + if (nodes_[i]->discontinuity_enrich()) + nodes_[i]->update_discontinuity_property( + true, "internal_force_enrich", sgn(levelset_phi_) * force, 0, 1); } } @@ -731,8 +742,9 @@ inline void mpm::ParticleXMPM<2>::map_internal_force() noexcept { force *= -1. * this->volume_; nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Solid, force); - if(nodes_[i]->discontinuity_enrich()) - nodes_[i]->update_discontinuity_property(true, "internal_force_enrich", sgn(levelset_phi_)*force, 0,2); + if (nodes_[i]->discontinuity_enrich()) + nodes_[i]->update_discontinuity_property( + true, "internal_force_enrich", sgn(levelset_phi_) * force, 0, 2); } } @@ -755,8 +767,9 @@ inline void mpm::ParticleXMPM<3>::map_internal_force() noexcept { force *= -1. * this->volume_; nodes_[i]->update_internal_force(true, mpm::ParticlePhase::Solid, force); - if(nodes_[i]->discontinuity_enrich()) - nodes_[i]->update_discontinuity_property(true, "internal_force_enrich", sgn(levelset_phi_)*force, 0,3); + if (nodes_[i]->discontinuity_enrich()) + nodes_[i]->update_discontinuity_property( + true, "internal_force_enrich", sgn(levelset_phi_) * force, 0, 3); } } @@ -771,7 +784,8 @@ bool mpm::ParticleXMPM::assign_velocity( // Assign traction to the particle template -bool mpm::ParticleXMPM::assign_traction(unsigned direction, double traction) { +bool mpm::ParticleXMPM::assign_traction(unsigned direction, + double traction) { bool status = false; try { if (direction >= Tdim || @@ -812,24 +826,23 @@ void mpm::ParticleXMPM::compute_updated_position( Eigen::Matrix::Zero(); const double tolerance = 1.E-16; unsigned int phase = mpm::ParticlePhase::Solid; - for (unsigned i = 0; i < nodes_.size(); ++i) - { - if(nodes_[i]->discontinuity_enrich()) - { - double nodal_mass = nodes_[i]->mass(phase) + sgn(levelset_phi_)*nodes_[i]->discontinuity_property("mass_enrich",1)(0,0); - if (nodal_mass < tolerance) - continue; - - nodal_velocity += shapefn_[i] * - (nodes_[i]->momentum(phase) + sgn(levelset_phi_) * nodes_[i]->discontinuity_property("momenta_enrich",3))/nodal_mass; - } - else - { + for (unsigned i = 0; i < nodes_.size(); ++i) { + if (nodes_[i]->discontinuity_enrich()) { + double nodal_mass = + nodes_[i]->mass(phase) + + sgn(levelset_phi_) * + nodes_[i]->discontinuity_property("mass_enrich", 1)(0, 0); + if (nodal_mass < tolerance) continue; + + nodal_velocity += shapefn_[i] * + (nodes_[i]->momentum(phase) + + sgn(levelset_phi_) * nodes_[i]->discontinuity_property( + "momenta_enrich", 3)) / + nodal_mass; + } else { double nodal_mass = nodes_[i]->mass(phase); - if (nodal_mass < tolerance) - continue; - nodal_velocity += - shapefn_[i] * nodes_[i]->momentum(phase)/nodal_mass; + if (nodal_mass < tolerance) continue; + nodal_velocity += shapefn_[i] * nodes_[i]->momentum(phase) / nodal_mass; } } // Acceleration update @@ -837,29 +850,30 @@ void mpm::ParticleXMPM::compute_updated_position( // Get interpolated nodal acceleration Eigen::Matrix nodal_acceleration = Eigen::Matrix::Zero(); - for (unsigned i = 0; i < nodes_.size(); ++i) - { - if(nodes_[i]->discontinuity_enrich()) - { - double nodal_mass = nodes_[i]->mass(phase) + sgn(levelset_phi_)*nodes_[i]->discontinuity_property("mass_enrich",1)(0,0); - if (nodal_mass < tolerance) - continue; - - auto force = nodes_[i]->internal_force(phase) + sgn(levelset_phi_) * nodes_[i]->discontinuity_property("internal_force_enrich",3) + - nodes_[i]->external_force(phase) + sgn(levelset_phi_) * nodes_[i]->discontinuity_property("external_force_enrich",3); - - nodal_acceleration += shapefn_[i] * force / nodal_mass; - } - else - { + for (unsigned i = 0; i < nodes_.size(); ++i) { + if (nodes_[i]->discontinuity_enrich()) { + double nodal_mass = + nodes_[i]->mass(phase) + + sgn(levelset_phi_) * + nodes_[i]->discontinuity_property("mass_enrich", 1)(0, 0); + if (nodal_mass < tolerance) continue; + + auto force = nodes_[i]->internal_force(phase) + + sgn(levelset_phi_) * nodes_[i]->discontinuity_property( + "internal_force_enrich", 3) + + nodes_[i]->external_force(phase) + + sgn(levelset_phi_) * nodes_[i]->discontinuity_property( + "external_force_enrich", 3); + + nodal_acceleration += shapefn_[i] * force / nodal_mass; + } else { double nodal_mass = nodes_[i]->mass(phase); - if (nodal_mass < tolerance) - continue; + if (nodal_mass < tolerance) continue; - auto force = nodes_[i]->internal_force(phase) + nodes_[i]->external_force(phase); + auto force = + nodes_[i]->internal_force(phase) + nodes_[i]->external_force(phase); - nodal_acceleration += - shapefn_[i] * force / nodal_mass; + nodal_acceleration += shapefn_[i] * force / nodal_mass; } } @@ -899,7 +913,8 @@ bool mpm::ParticleXMPM::map_pressure_to_nodes(unsigned phase) noexcept { // Compute pressure smoothing of the particle based on nodal pressure template -bool mpm::ParticleXMPM::compute_pressure_smoothing(unsigned phase) noexcept { +bool mpm::ParticleXMPM::compute_pressure_smoothing( + unsigned phase) noexcept { // Assert assert(cell_ != nullptr); @@ -921,15 +936,16 @@ bool mpm::ParticleXMPM::compute_pressure_smoothing(unsigned phase) noexcep //! Apply particle velocity constraints template -void mpm::ParticleXMPM::apply_particle_velocity_constraints(unsigned dir, - double velocity) { +void mpm::ParticleXMPM::apply_particle_velocity_constraints( + unsigned dir, double velocity) { // Set particle velocity constraint this->velocity_(dir) = velocity; } //! Return particle tensor data template -Eigen::VectorXd mpm::ParticleXMPM::tensor_data(const std::string& property) { +Eigen::VectorXd mpm::ParticleXMPM::tensor_data( + const std::string& property) { return this->properties_.at(property)(); } diff --git a/include/solvers/xmpm_explicit.h b/include/solvers/xmpm_explicit.h index edf588aad..b26e35855 100644 --- a/include/solvers/xmpm_explicit.h +++ b/include/solvers/xmpm_explicit.h @@ -5,8 +5,8 @@ #include "graph.h" #endif -#include "mpm_base.h" #include "discontinuity_base.h" +#include "mpm_base.h" namespace mpm { @@ -27,12 +27,13 @@ class XMPMExplicit : public MPMBase { //! \param[in] phase Phase to smooth pressure void compute_stress_strain(unsigned phase); - //! Initialise discontinuities + //! Initialise discontinuities bool initialise_discontinuities(); //! Initialise the level set function values bool initialise_levelset(); - //return the number of discontinuities - mpm::Index ndiscontinuities(){return discontinuities_.size();}; + // return the number of discontinuities + mpm::Index ndiscontinuities() { return discontinuities_.size(); }; + protected: // Generate a unique id for the analysis using mpm::MPMBase::uuid_; @@ -85,7 +86,8 @@ class XMPMExplicit : public MPMBase { //! discontinuities statue bool discontinuity_{false}; //! discontinuities - std::map>> discontinuities_; + std::map>> + discontinuities_; }; // XMPMExplicit class } // namespace mpm diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index 9462efd4a..ca84efc93 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -80,7 +80,7 @@ bool mpm::XMPMExplicit::solve() { status = false; throw std::runtime_error("Initialisation of particles failed"); } - + // Initialise loading conditions bool loading_status = this->initialise_loads(); if (!loading_status) { @@ -91,24 +91,24 @@ bool mpm::XMPMExplicit::solve() { // Create nodal properties if (interface_) mesh_->create_nodal_properties(); - // Initialise discontinuity + // Initialise discontinuity bool discontinuity_status = this->initialise_discontinuities(); if (!discontinuity_status) { status = false; throw std::runtime_error("Initialisation of discontinuities failed"); } - //Initialise the levelset values for particles - if (discontinuity_){ + // Initialise the levelset values for particles + if (discontinuity_) { bool initialise_lsm_status = this->initialise_levelset(); if (!initialise_lsm_status) { status = false; throw std::runtime_error("Initialisation of level set values failed"); - } + } } // Create nodal properties for discontinuity - if (discontinuity_) mesh_->create_nodal_properties_discontinuity(); + if (discontinuity_) mesh_->create_nodal_properties_discontinuity(); // Compute mass mesh_->iterate_over_particles( std::bind(&mpm::ParticleBase::compute_mass, std::placeholders::_1)); @@ -159,10 +159,10 @@ bool mpm::XMPMExplicit::solve() { } // Wait to complete // Initialise nodal properties - if (interface_ || discontinuity_) + if (interface_ || discontinuity_) // Initialise nodal properties mesh_->initialise_nodal_properties(); - //append material ids to node + // append material ids to node if (interface_) { // Append material ids to nodes mesh_->iterate_over_particles( @@ -286,7 +286,7 @@ bool mpm::XMPMExplicit::solve() { } #endif - //intergrate momentum Iterate over + // intergrate momentum Iterate over mesh_->iterate_over_nodes_predicate( std::bind(&mpm::NodeBase::intergrate_momentum_discontinuity, std::placeholders::_1, phase, this->dt_), @@ -349,11 +349,10 @@ template bool mpm::XMPMExplicit::initialise_discontinuities() { bool status = true; try { - // Get discontinuities data + // Get discontinuities data try { - auto json_discontinuities = io_->json_object("discontinuity"); - if(!json_discontinuities.empty()) - { + auto json_discontinuities = io_->json_object("discontinuity"); + if (!json_discontinuities.empty()) { discontinuity_ = true; for (const auto discontinuity_props : json_discontinuities) { // Get discontinuity type @@ -361,33 +360,40 @@ bool mpm::XMPMExplicit::initialise_discontinuities() { discontinuity_props["type"].template get(); // Get discontinuity id - auto discontinuity_id = discontinuity_props["id"].template get(); + auto discontinuity_id = + discontinuity_props["id"].template get(); - // Get discontinuity input type - auto io_type = discontinuity_props["io_type"].template get(); + // Get discontinuity input type + auto io_type = + discontinuity_props["io_type"].template get(); // discontinuity file - std::string discontinuity_file = - io_->file_name(discontinuity_props["file"].template get()); + std::string discontinuity_file = io_->file_name( + discontinuity_props["file"].template get()); - auto discontinuity_frictional_coef = discontinuity_props["frictional_coefficient"].template get(); + auto discontinuity_frictional_coef = + discontinuity_props["frictional_coefficient"] + .template get(); + + // Create a mesh reader + auto discontunity_io = + Factory>::instance()->create(io_type); - // Create a mesh reader - auto discontunity_io = Factory>::instance()->create(io_type); - // Create a new discontinuity surface from JSON object auto discontinuity = - Factory>::instance() - ->create(discontunity_type); + Factory>::instance()->create( + discontunity_type); - bool status = - discontinuity->initialize(discontunity_io->read_mesh_nodes(discontinuity_file),discontunity_io->read_mesh_cells(discontinuity_file)); + bool status = discontinuity->initialize( + discontunity_io->read_mesh_nodes(discontinuity_file), + discontunity_io->read_mesh_cells(discontinuity_file)); discontinuity->set_frictional_coef(discontinuity_frictional_coef); // Create points from file - + // Add discontinuity to list - auto result = discontinuities_.insert(std::make_pair(discontinuity_id, discontinuity)); + auto result = discontinuities_.insert( + std::make_pair(discontinuity_id, discontinuity)); // If insert discontinuity failed if (!result.second) { @@ -396,13 +402,14 @@ bool mpm::XMPMExplicit::initialise_discontinuities() { "New discontinuity cannot be added, insertion failed"); } } - } - }catch (std::exception& exception) { - console_->warn("{} #{}: No discontinuity is defined", __FILE__, - __LINE__, exception.what()); + } + } catch (std::exception& exception) { + console_->warn("{} #{}: No discontinuity is defined", __FILE__, __LINE__, + exception.what()); } - }catch (std::exception& exception) { - console_->error("#{}: Reading discontinuities: {}", __LINE__, exception.what()); + } catch (std::exception& exception) { + console_->error("#{}: Reading discontinuities: {}", __LINE__, + exception.what()); status = false; } return status; @@ -416,22 +423,24 @@ bool mpm::XMPMExplicit::initialise_levelset() { try { - for(mpm::Index i=0; i phi_list(mesh_->nparticles()); - discontinuities_[i]->compute_levelset(mesh_->particle_coordinates(), phi_list); + discontinuities_[i]->compute_levelset(mesh_->particle_coordinates(), + phi_list); - mesh_->assign_particle_levelset(phi_list); + mesh_->assign_particle_levelset(phi_list); } } catch (std::exception& exception) { - console_->error("#{}: XMPM initialise particles levelset values: {}", __LINE__, - exception.what()); + console_->error("#{}: XMPM initialise particles levelset values: {}", + __LINE__, exception.what()); status = false; } - if (!status) throw std::runtime_error("Initialisation of particles LSM values failed"); - + if (!status) + throw std::runtime_error("Initialisation of particles LSM values failed"); + return status; } \ No newline at end of file diff --git a/include/xmpm/discontinuity_3d.h b/include/xmpm/discontinuity_3d.h old mode 100755 new mode 100644 index 2ebb13e0c..73e7b1553 --- a/include/xmpm/discontinuity_3d.h +++ b/include/xmpm/discontinuity_3d.h @@ -10,67 +10,69 @@ template class Discontinuity_3D : public DiscontinuityBase { public: - //! Define a vector of size dimension + //! Define a vector of size dimension using VectorDim = Eigen::Matrix; - //constructor + // constructor Discontinuity_3D(); - //initialization - virtual bool initialize(const std::vector& coordinates,const std::vector>& pointsets) - { + // initialization + virtual bool initialize( + const std::vector& coordinates, + const std::vector>& pointsets) { bool status = true; - // Create points from file + // Create points from file bool point_status = this->create_points(coordinates); if (!point_status) { status = false; - throw std::runtime_error("Addition of points in discontinuity to mesh failed"); + throw std::runtime_error( + "Addition of points in discontinuity to mesh failed"); } - // Create elements from file - bool element_status = create_elements(pointsets); + // Create elements from file + bool element_status = create_elements(pointsets); if (!element_status) { status = false; - throw std::runtime_error("Addition of elements in discontinuity to mesh failed"); + throw std::runtime_error( + "Addition of elements in discontinuity to mesh failed"); } - bool normal_status = initialize_center_normal(); + bool normal_status = initialize_center_normal(); if (!normal_status) { status = false; - throw std::runtime_error("initialized the center and normal of the discontunity failed"); + throw std::runtime_error( + "initialized the center and normal of the discontunity failed"); } return status; }; //! create elements from file - virtual bool create_elements(const std::vector>& elements) override; + virtual bool create_elements( + const std::vector>& elements) override; - //initialize the center and normal of the triangular elements + // initialize the center and normal of the triangular elements bool initialize_center_normal(); // return the cross product of ab and bc - VectorDim ThreeCross(const VectorDim& a,const VectorDim& b,const VectorDim& c); + VectorDim ThreeCross(const VectorDim& a, const VectorDim& b, + const VectorDim& c); - - //return the levelset values of each doordinates + // return the levelset values of each doordinates //! \param[in] the vector of the coordinates - virtual void compute_levelset(const std::vector& coordinates, std::vector& phi_list) override; - + virtual void compute_levelset(const std::vector& coordinates, + std::vector& phi_list) override; protected: - using mpm::DiscontinuityBase::points_; using mpm::DiscontinuityBase::console_; using mpm::DiscontinuityBase::numpoint_; - private: - - //vector of elements + private: + // vector of elements std::vector elements_; - //number of elements + // number of elements mpm::Index numelement_; - }; } // namespace mpm diff --git a/include/xmpm/discontinuity_3d.tcc b/include/xmpm/discontinuity_3d.tcc old mode 100755 new mode 100644 index 23afaa359..d86f1ccae --- a/include/xmpm/discontinuity_3d.tcc +++ b/include/xmpm/discontinuity_3d.tcc @@ -1,99 +1,104 @@ template -mpm::Discontinuity_3D::Discontinuity_3D() -{ +mpm::Discontinuity_3D::Discontinuity_3D() { numelement_ = 0; - - std::string logger = - "discontinuity" + std::to_string(Tdim) + "d"; + + std::string logger = "discontinuity" + std::to_string(Tdim) + "d"; console_ = std::make_unique(logger, mpm::stdout_sink); } //! create elements from file template -bool mpm::Discontinuity_3D::create_elements(const std::vector>& elements) - { - - bool status = true; - try { - // Check if elements is empty - if (elements.empty()) - throw std::runtime_error("List of elements is empty"); - // Iterate over all elements - for (const auto& points : elements) { - - mpm::discontinuous_element element(points); - - elements_.emplace_back(element); // - } - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; +bool mpm::Discontinuity_3D::create_elements( + const std::vector>& elements) { + + bool status = true; + try { + // Check if elements is empty + if (elements.empty()) throw std::runtime_error("List of elements is empty"); + // Iterate over all elements + for (const auto& points : elements) { + + mpm::discontinuous_element element(points); + + elements_.emplace_back(element); // } - return status; + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; } + return status; +} + +// initialize the center and normal of the elements +template +bool mpm::Discontinuity_3D::initialize_center_normal() { + bool status = true; + try { + VectorDim center; + VectorDim normal; + Eigen::Matrix points; - //initialize the center and normal of the elements - template - bool mpm::Discontinuity_3D::initialize_center_normal() - { - bool status = true; - try { - VectorDim center; - VectorDim normal; - Eigen::Matrix points; - - for(auto& element : elements_) - { - points = element.points(); - - //the center of the element - for(int i=0; i<3; i++) - center[i] = 1.0/3*(points_[points[0]].coordinates()[i] + points_[points[1]].coordinates()[i] +points_[points[2]].coordinates()[i]); - - element.set_center(center); - - //the normal of the element - normal = ThreeCross(points_[points[0]].coordinates(),points_[points[1]].coordinates(),points_[points[2]].coordinates()); - double det = std::sqrt(normal[0]*normal[0] + normal[1]*normal[1] + normal[2]*normal[2]); - normal = 1.0/det * normal; - - element.set_normal(normal); - } - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; + for (auto& element : elements_) { + points = element.points(); + + // the center of the element + for (int i = 0; i < 3; i++) + center[i] = 1.0 / 3 * + (points_[points[0]].coordinates()[i] + + points_[points[1]].coordinates()[i] + + points_[points[2]].coordinates()[i]); + + element.set_center(center); + + // the normal of the element + normal = ThreeCross(points_[points[0]].coordinates(), + points_[points[1]].coordinates(), + points_[points[2]].coordinates()); + double det = std::sqrt(normal[0] * normal[0] + normal[1] * normal[1] + + normal[2] * normal[2]); + normal = 1.0 / det * normal; + + element.set_normal(normal); } - return status; + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; } + return status; +} -//return the cross product of ab X bc +// return the cross product of ab X bc template -Eigen::Matrix mpm::Discontinuity_3D::ThreeCross(const VectorDim& a,const VectorDim& b,const VectorDim& c){ - - VectorDim threecross; - threecross[0]=(b[1]-a[1])*(c[2]-b[2])-(b[2]-a[2])*(c[1]-b[1]); - threecross[1]=(b[2]-a[2])*(c[0]-b[0])-(b[0]-a[0])*(c[2]-b[2]); - threecross[2]=(b[0]-a[0])*(c[1]-b[1])-(b[1]-a[1])*(c[0]-b[0]); - return threecross; +Eigen::Matrix mpm::Discontinuity_3D::ThreeCross( + const VectorDim& a, const VectorDim& b, const VectorDim& c) { + + VectorDim threecross; + threecross[0] = (b[1] - a[1]) * (c[2] - b[2]) - (b[2] - a[2]) * (c[1] - b[1]); + threecross[1] = (b[2] - a[2]) * (c[0] - b[0]) - (b[0] - a[0]) * (c[2] - b[2]); + threecross[2] = (b[0] - a[0]) * (c[1] - b[1]) - (b[1] - a[1]) * (c[0] - b[0]); + return threecross; } -//return the levelset values of each doordinates +// return the levelset values of each doordinates //! \param[in] the vector of the coordinates template -void mpm::Discontinuity_3D::compute_levelset(const std::vector& coordinates,std::vector& phi_list){ +void mpm::Discontinuity_3D::compute_levelset( + const std::vector& coordinates, std::vector& phi_list) { mpm::Index i = 0; - for(const auto& coor:coordinates) - { - //find the nearest distance from particle to cell: need to do by global searching and local searching + for (const auto& coor : coordinates) { + // find the nearest distance from particle to cell: need to do by global + // searching and local searching double distance = std::numeric_limits::max(); - for(const auto& element:elements_) - { - double Vertical_distance_ = element.Vertical_distance(coor);// Vertical_distance(coor); - distance = std::abs(distance) < std::abs(Vertical_distance_)? distance:Vertical_distance_; - if(!distance) distance = 1e-16; + for (const auto& element : elements_) { + double Vertical_distance_ = + element.Vertical_distance(coor); // Vertical_distance(coor); + distance = std::abs(distance) < std::abs(Vertical_distance_) + ? distance + : Vertical_distance_; + if (!distance) distance = 1e-16; } - + phi_list[i] = distance; ++i; } diff --git a/include/xmpm/discontinuity_base.h b/include/xmpm/discontinuity_base.h old mode 100755 new mode 100644 index 8be308b64..a6ceb01d3 --- a/include/xmpm/discontinuity_base.h +++ b/include/xmpm/discontinuity_base.h @@ -1,44 +1,34 @@ #ifndef MPM_DISCONTINUITY_H_ #define MPM_DISCONTINUITY_H_ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "vector.h" + +#include "logger.h" + +#include "data_types.h" namespace mpm { template -struct discontinuous_point -{ - public: - //! Define a vector of size dimension - using VectorDim = Eigen::Matrix; - - discontinuous_point(const VectorDim& coordinate) - { - coordinates_ = coordinate; - } +struct discontinuous_point { + public: + //! Define a vector of size dimension + using VectorDim = Eigen::Matrix; + discontinuous_point(const VectorDim& coordinate) { + coordinates_ = coordinate; + } //! Return coordinates //! \retval coordinates_ return coordinates of the nodebase - VectorDim coordinates() const { return coordinates_; } - - private: + VectorDim coordinates() const { return coordinates_; } - //! point coordinates - VectorDim coordinates_; + private: + //! point coordinates + VectorDim coordinates_; }; //! class for to describe the discontinuous surface -//! \brief +//! \brief //! \details nodes, lines and areas //! \tparam Tdim Dimension template @@ -59,127 +49,123 @@ class DiscontinuityBase { //! Delete assignement operator DiscontinuityBase& operator=(const DiscontinuityBase&) = delete; - //initialization - virtual bool initialize(const std::vector& coordinates,const std::vector>& pointsets) = 0; + // initialization + virtual bool initialize( + const std::vector& coordinates, + const std::vector>& pointsets) = 0; //! create points from file bool create_points(const std::vector& coordinates); //! create elements from file - virtual bool create_elements(const std::vector>& elements) {return true;}; + virtual bool create_elements( + const std::vector>& elements) { + return true; + }; - //return the levelset values of each doordinates + // return the levelset values of each doordinates //! \param[in] the vector of the coordinates - virtual void compute_levelset(const std::vector& coordinates, std::vector& phi_list) = 0; - - bool self_contact(){return self_contact_;}; + virtual void compute_levelset(const std::vector& coordinates, + std::vector& phi_list) = 0; - void set_frictional_coef(double coef) {frictional_coef_ = coef;}; + bool self_contact() { return self_contact_; }; - double frictional_coef(){return frictional_coef_;}; + void set_frictional_coef(double coef) { frictional_coef_ = coef; }; + double frictional_coef() { return frictional_coef_; }; - protected: - + protected: std::vector> points_; - //number of points + // number of points mpm::Index numpoint_; //! Logger std::unique_ptr console_; - //self-contact - bool self_contact_{true}; + // self-contact + bool self_contact_{true}; double frictional_coef_; }; // DiscontinuityBase class -struct discontinuous_line -{ - public: - - //! Return points indices - Eigen::Matrix points() const {return points_;}; - - private: - - //! points index of the line - Eigen::Matrix points_; +struct discontinuous_line { + public: + //! Return points indices + Eigen::Matrix points() const { return points_; }; + private: + //! points index of the line + Eigen::Matrix points_; }; -struct discontinuous_element -{ - public: - //! Define a vector of size dimension - using VectorDim = Eigen::Matrix; +struct discontinuous_element { + public: + //! Define a vector of size dimension + using VectorDim = Eigen::Matrix; - discontinuous_element(const std::vector& points) - { - for(int i=0; i<3; ++i) - points_[i] = points[i]; - } - //! Return points indices - Eigen::Matrix points() const { return points_;} + discontinuous_element(const std::vector& points) { + for (int i = 0; i < 3; ++i) points_[i] = points[i]; + } + //! Return points indices + Eigen::Matrix points() const { return points_; } - inline void set_center(VectorDim & center) {center_ = center; } - - inline void set_normal(VectorDim & normal) {normal_ = normal; } + inline void set_center(VectorDim& center) { center_ = center; } - double Vertical_distance (const VectorDim & coor) const {return (coor[0]-center_[0])*normal_[0]+(coor[1]-center_[1])*normal_[1]+(coor[2]-center_[2])*normal_[2];}; + inline void set_normal(VectorDim& normal) { normal_ = normal; } - private: - //! points indices - Eigen::Matrix points_; + double Vertical_distance(const VectorDim& coor) const { + return (coor[0] - center_[0]) * normal_[0] + + (coor[1] - center_[1]) * normal_[1] + + (coor[2] - center_[2]) * normal_[2]; + }; - //the center of the triangular elements - VectorDim center_; + private: + //! points indices + Eigen::Matrix points_; - //the normal of the triangular elements - VectorDim normal_; - -}; + // the center of the triangular elements + VectorDim center_; + // the normal of the triangular elements + VectorDim normal_; +}; } // namespace mpm template -mpm::DiscontinuityBase::DiscontinuityBase() -{ +mpm::DiscontinuityBase::DiscontinuityBase() { numpoint_ = 0; frictional_coef_ = -1; - - std::string logger = - "discontinuitybase"; + + std::string logger = "discontinuitybase"; console_ = std::make_unique(logger, mpm::stdout_sink); } //! create points from file template -bool mpm::DiscontinuityBase::create_points(const std::vector& coordinates) - { - bool status = true; - try { - // Check if point coordinates is empty - if (coordinates.empty()) - throw std::runtime_error("List of coordinates is empty"); - // Iterate over all coordinates - for (const auto& point_coordinates : coordinates) { - - // Add point - mpm::discontinuous_point point(point_coordinates); - - points_.emplace_back(point); // - } - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; +bool mpm::DiscontinuityBase::create_points( + const std::vector& coordinates) { + bool status = true; + try { + // Check if point coordinates is empty + if (coordinates.empty()) + throw std::runtime_error("List of coordinates is empty"); + // Iterate over all coordinates + for (const auto& point_coordinates : coordinates) { + + // Add point + mpm::discontinuous_point point(point_coordinates); + + points_.emplace_back(point); // } - return status; - + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; } + return status; +} #endif // MPM_DiscontinuityBase_H_ diff --git a/src/discontinuity.cc b/src/discontinuity.cc old mode 100755 new mode 100644 index 2c9d245bc..11c2fd421 --- a/src/discontinuity.cc +++ b/src/discontinuity.cc @@ -1,6 +1,7 @@ +#include "discontinuity_3d.h" #include "discontinuity_base.h" #include "factory.h" -#include "discontinuity_3d.h" // Triangle 3-noded element -static Register, mpm::Discontinuity_3D<3>> tri3d("tri3d"); +static Register, mpm::Discontinuity_3D<3>> tri3d( + "tri3d"); From 835db0a70a42bdf654f3c1275deffb1711f41f4d Mon Sep 17 00:00:00 2001 From: yong liang Date: Sat, 15 Aug 2020 16:50:21 -0700 Subject: [PATCH 34/91] :constructor:discontinuity function --- include/mesh.h | 24 +++ include/mesh.tcc | 50 ++++++- include/node.h | 13 +- include/node.tcc | 1 + include/node_base.h | 10 ++ include/node_xmpm.tcc | 25 ++-- include/particles/particle_xmpm.tcc | 1 + include/solvers/xmpm_explicit.tcc | 51 ++++--- include/xmpm/discontinuity_3d.h | 48 ++---- include/xmpm/discontinuity_3d.tcc | 91 ++++++++++-- include/xmpm/discontinuity_base.h | 140 ++++++++++++------ include/xmpm/discontinuity_base.tcc | 221 ++++++++++++++++++++++++++++ src/discontinuity.cc | 5 +- 13 files changed, 551 insertions(+), 129 deletions(-) create mode 100644 include/xmpm/discontinuity_base.tcc diff --git a/include/mesh.h b/include/mesh.h index 0582bf809..fd4f1537f 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -25,6 +25,7 @@ using Json = nlohmann::json; #include "cell.h" +#include "discontinuity_base.h" #include "factory.h" #include "friction_constraint.h" #include "function_base.h" @@ -467,6 +468,26 @@ class Mesh { // Create the nodal properties' map for discontinuity void create_nodal_properties_discontinuity(); + //! Initialise discontinuities + //! \param[in] discontinuities + void initialise_discontinuities( + const std::map>>& + discontinuities) { + discontinuities_ = discontinuities; + } + + //! Locate points of discontinuity in a cell + void locate_discontinuity_mesh(); + + // Update the discontinuity position + void compute_updated_position_discontinuity(double dt); + + // Update the discontinuity position + void compute_shapefn_discontinuity(); + + // compute the normal vector of enriched nodes at the discontinuity + void compute_normal_vector_discontinuity(); + private: // Read particles from file //! \param[in] pset_id Set ID of the particles @@ -535,6 +556,9 @@ class Mesh { unsigned nhalo_nodes_{0}; //! Maximum number of halo nodes unsigned ncomms_{0}; + //! discontinuities + std::map>> + discontinuities_; }; // Mesh class } // namespace mpm diff --git a/include/mesh.tcc b/include/mesh.tcc index a9384eba4..431bd8c18 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1998,4 +1998,52 @@ template void mpm::Mesh::assign_particle_levelset(std::vector& phi_list) { for (mpm::Index i = 0; i < nparticles(); ++i) particles_[i]->assign_levelsetphi(phi_list[i]); -} \ No newline at end of file +} + +//! Locate points in a cell +template +void mpm::Mesh::locate_discontinuity_mesh() { + for (unsigned i = 0; i < discontinuities_.size(); ++i) { + auto discontinuity = discontinuities_[i]; + discontinuity->locate_discontinuity_mesh(cells_, map_cells_); + } +} +//! updated_position of discontinuity +template +void mpm::Mesh::compute_updated_position_discontinuity(double dt) { + for (unsigned i = 0; i < discontinuities_.size(); ++i) { + auto discontinuity = discontinuities_[i]; + discontinuity->compute_updated_position(dt); + } +} + +//! compute shape function +template +void mpm::Mesh::compute_shapefn_discontinuity() { + for (unsigned i = 0; i < discontinuities_.size(); ++i) { + auto discontinuity = discontinuities_[i]; + discontinuity->compute_shapefn(); + } +} + + // compute the normal vector of enriched nodes at the discontinuity +template +void mpm::Mesh::compute_normal_vector_discontinuity() { + //need to set + unsigned discontinuity_id = 0; + + auto discontinuity = discontinuities_[discontinuity_id]; + + VectorDim normal; + normal.setZero(); + +for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) + { + + discontinuity->compute_normal((*nitr)->coordinates(), + normal); + + nodal_properties_->assign_property("normal_unit_vectors_discontinuity", + (*nitr)->discontinuity_prop_id(), 0, normal, Tdim); + } +} diff --git a/include/node.h b/include/node.h index ce363cffb..f42f66e4e 100644 --- a/include/node.h +++ b/include/node.h @@ -274,6 +274,11 @@ class Node : public NodeBase { //! Compute multimaterial normal unit vector void compute_multimaterial_normal_unit_vector() override; + //! Assign whether the node is enriched + //! \param[in] discontinuity_enrich: true or false + void assign_discontinuity_enrich(bool discontinuity) { + discontinuity_enrich_ = discontinuity; + }; //! Return whether the node is enriched bool discontinuity_enrich() const { return discontinuity_enrich_; }; @@ -304,6 +309,12 @@ class Node : public NodeBase { //! \param[in] dt Time-step void self_contact_discontinuity(double dt) noexcept override; + //! Return the discontinuity_prop_id + virtual unsigned discontinuity_prop_id() const noexcept override{return discontinuity_prop_id_;}; + + //! Compute normal direction of each enrich node + void compute_normal_vector() noexcept override; + private: //! Mutex SpinMutex node_mutex_; @@ -363,7 +374,7 @@ class Node : public NodeBase { std::set mpi_ranks_; //! discontinuity enrich // need to be done - bool discontinuity_enrich_{true}; + bool discontinuity_enrich_{false}; }; // Node class } // namespace mpm diff --git a/include/node.tcc b/include/node.tcc index 7d3a9cfcb..d027a33e0 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -34,6 +34,7 @@ void mpm::Node::initialise() noexcept { acceleration_.setZero(); status_ = false; material_ids_.clear(); + discontinuity_enrich_ = false; } //! Initialise shared pointer to nodal properties pool diff --git a/include/node_base.h b/include/node_base.h index 134bbf8c6..194b337d0 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -269,6 +269,10 @@ class NodeBase { virtual Eigen::MatrixXd discontinuity_property( const std::string& property, unsigned nprops = 1) noexcept = 0; + //! Assign whether the node is enriched + //! \param[in] discontinuity_enrich: true or false + virtual void assign_discontinuity_enrich(bool discontinuity) = 0; + //! Return whether the node is enriched virtual bool discontinuity_enrich() const = 0; @@ -292,6 +296,12 @@ class NodeBase { //! Apply self-contact of the discontinuity //! \param[in] dt Time-step virtual void self_contact_discontinuity(double dt) noexcept = 0; + + //! Return the discontinuity_prop_id + virtual unsigned discontinuity_prop_id() const noexcept = 0; + + //! Compute normal direction of each enrich node + virtual void compute_normal_vector() noexcept = 0; }; // NodeBase class } // namespace mpm diff --git a/include/node_xmpm.tcc b/include/node_xmpm.tcc index 5649722d0..b5abd14b2 100644 --- a/include/node_xmpm.tcc +++ b/include/node_xmpm.tcc @@ -55,10 +55,10 @@ bool mpm::Node::intergrate_momentum_discontinuity( this->apply_velocity_constraints_discontinuity(); // need to be done - Eigen::Matrix normal{0.44721359474414313, 0, - 0.89442719147920724}; - property_handle_->assign_property("normal_unit_vectors_discontinuity", - discontinuity_prop_id_, 0, normal, Tdim); + //Eigen::Matrix normal{0.44721359474414313, 0, + // 0.89442719147920724}; + // property_handle_->assign_property("normal_unit_vectors_discontinuity", + // discontinuity_prop_id_, 0, normal, Tdim); this->self_contact_discontinuity(dt); @@ -164,11 +164,11 @@ void mpm::Node::self_contact_discontinuity( mass_(phase); auto force_contact = momentum_contact / dt; - //! frictional_coef < 0: move together without slide + //! friction_coef < 0: move together without slide // need to be done - double frictional_coef = 0; + double friction_coef = 0; - if (frictional_coef < 0) { + if (friction_coef < 0) { property_handle_->update_property("momenta_enrich", discontinuity_prop_id_, 0, momentum_contact.col(phase), Tdim); property_handle_->update_property("external_force_enrich", @@ -180,7 +180,7 @@ void mpm::Node::self_contact_discontinuity( double force_contact_norm = momentum_contact_norm / dt; // the maximum frictional contact force - double max_frictional_force = frictional_coef * abs(force_contact_norm); + double max_frictional_force = friction_coef * abs(force_contact_norm); auto momentum_tangential = momentum_contact.col(phase) - momentum_contact_norm * normal_vector; @@ -204,4 +204,11 @@ void mpm::Node::self_contact_discontinuity( frictional_force * force_tangential.col(phase).normalized(), Tdim); } -} \ No newline at end of file +} + + //! Compute normal direction of each enrich node + //! Apply velocity constraints +template +void mpm::Node::compute_normal_vector() noexcept { + + } \ No newline at end of file diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index ae203b350..e3ab0235f 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -251,6 +251,7 @@ void mpm::ParticleXMPM::initialise() { this->properties_["strains"] = [&]() { return strain(); }; this->properties_["velocities"] = [&]() { return velocity(); }; this->properties_["displacements"] = [&]() { return displacement(); }; + this->properties_["levelset"] = [&]() { VectorDim levelset{levelset_phi_,0,0};return levelset; }; } //! Initialise particle material container diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index ca84efc93..4239f71f5 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -169,6 +169,19 @@ bool mpm::XMPMExplicit::solve() { std::bind(&mpm::ParticleBase::append_material_id_to_nodes, std::placeholders::_1)); } + if (discontinuity_) { + // locate points of discontinuity + mesh_->locate_discontinuity_mesh(); + // Iterate over each points to compute shapefn + mesh_->compute_shapefn_discontinuity(); + // obtain the normal direction of each enrich nodes + mesh_->compute_normal_vector_discontinuity(); + mesh_->iterate_over_nodes_predicate( + std::bind(&mpm::NodeBase::compute_normal_vector, + std::placeholders::_1), + std::bind(&mpm::NodeBase::discontinuity_enrich, std::placeholders::_1)); + } + // Assign mass and momentum to nodes mesh_->iterate_over_particles( @@ -303,6 +316,9 @@ bool mpm::XMPMExplicit::solve() { // Update Stress Last if (this->stress_update_ == mpm::StressUpdate::USL) this->compute_stress_strain(phase); + // Update the discontinuity position + if (discontinuity_) + mesh_->compute_updated_position_discontinuity(this->dt_); // Locate particles auto unlocatable_particles = mesh_->locate_particles_mesh(); @@ -363,34 +379,26 @@ bool mpm::XMPMExplicit::initialise_discontinuities() { auto discontinuity_id = discontinuity_props["id"].template get(); - // Get discontinuity input type + // Create a new discontinuity surface from JSON object + auto discontinuity = + Factory, unsigned, const Json&>::instance()->create( + discontunity_type, std::move(discontinuity_id), + discontinuity_props); + + // Get discontinuity input type auto io_type = discontinuity_props["io_type"].template get(); // discontinuity file - std::string discontinuity_file = io_->file_name( - discontinuity_props["file"].template get()); - - auto discontinuity_frictional_coef = - discontinuity_props["frictional_coefficient"] - .template get(); - + std::string discontinuity_file = + io_->file_name(discontinuity_props["file"].template get()); // Create a mesh reader auto discontunity_io = Factory>::instance()->create(io_type); - // Create a new discontinuity surface from JSON object - auto discontinuity = - Factory>::instance()->create( - discontunity_type); - - bool status = discontinuity->initialize( - discontunity_io->read_mesh_nodes(discontinuity_file), - discontunity_io->read_mesh_cells(discontinuity_file)); - - discontinuity->set_frictional_coef(discontinuity_frictional_coef); - // Create points from file - + // Create points and cells from file + discontinuity->initialize(discontunity_io->read_mesh_nodes(discontinuity_file), + discontunity_io->read_mesh_cells(discontinuity_file)); // Add discontinuity to list auto result = discontinuities_.insert( std::make_pair(discontinuity_id, discontinuity)); @@ -407,11 +415,14 @@ bool mpm::XMPMExplicit::initialise_discontinuities() { console_->warn("{} #{}: No discontinuity is defined", __FILE__, __LINE__, exception.what()); } + // Copy discontinuities to mesh + mesh_->initialise_discontinuities(this->discontinuities_); } catch (std::exception& exception) { console_->error("#{}: Reading discontinuities: {}", __LINE__, exception.what()); status = false; } + return status; } diff --git a/include/xmpm/discontinuity_3d.h b/include/xmpm/discontinuity_3d.h index 73e7b1553..793a35450 100644 --- a/include/xmpm/discontinuity_3d.h +++ b/include/xmpm/discontinuity_3d.h @@ -7,42 +7,20 @@ namespace mpm { template -class Discontinuity_3D : public DiscontinuityBase { +class Discontinuity3D : public DiscontinuityBase { public: //! Define a vector of size dimension using VectorDim = Eigen::Matrix; - // constructor - Discontinuity_3D(); + + //! Constructor with id + //! \param[in] discontinuity_properties discontinuity properties + Discontinuity3D(unsigned id, const Json& discontinuity_props); // initialization virtual bool initialize( const std::vector& coordinates, - const std::vector>& pointsets) { - bool status = true; - // Create points from file - bool point_status = this->create_points(coordinates); - if (!point_status) { - status = false; - throw std::runtime_error( - "Addition of points in discontinuity to mesh failed"); - } - // Create elements from file - bool element_status = create_elements(pointsets); - if (!element_status) { - status = false; - throw std::runtime_error( - "Addition of elements in discontinuity to mesh failed"); - } - - bool normal_status = initialize_center_normal(); - if (!normal_status) { - status = false; - throw std::runtime_error( - "initialized the center and normal of the discontunity failed"); - } - return status; - }; + const std::vector>& pointsets); //! create elements from file virtual bool create_elements( @@ -52,13 +30,17 @@ class Discontinuity_3D : public DiscontinuityBase { bool initialize_center_normal(); // return the cross product of ab and bc - VectorDim ThreeCross(const VectorDim& a, const VectorDim& b, + VectorDim three_cross_product(const VectorDim& a, const VectorDim& b, const VectorDim& c); // return the levelset values of each doordinates //! \param[in] the vector of the coordinates - virtual void compute_levelset(const std::vector& coordinates, + void compute_levelset(const std::vector& coordinates, std::vector& phi_list) override; + // return the normal vectors of given coordinates + //! \param[in] the coordinates + void compute_normal( + const VectorDim& coordinates, VectorDim& normal_vector) override; protected: using mpm::DiscontinuityBase::points_; @@ -67,11 +49,13 @@ class Discontinuity_3D : public DiscontinuityBase { using mpm::DiscontinuityBase::numpoint_; + using mpm::DiscontinuityBase::friction_coef_; + private: // vector of elements - std::vector elements_; + std::vector> elements_; - // number of elements + // number of elements //delete mpm::Index numelement_; }; diff --git a/include/xmpm/discontinuity_3d.tcc b/include/xmpm/discontinuity_3d.tcc index d86f1ccae..2f7479d4c 100644 --- a/include/xmpm/discontinuity_3d.tcc +++ b/include/xmpm/discontinuity_3d.tcc @@ -1,14 +1,55 @@ template -mpm::Discontinuity_3D::Discontinuity_3D() { - numelement_ = 0; +mpm::Discontinuity3D::Discontinuity3D(unsigned id, + const Json& discontinuity_props) + : DiscontinuityBase(id, discontinuity_props) { - std::string logger = "discontinuity" + std::to_string(Tdim) + "d"; - console_ = std::make_unique(logger, mpm::stdout_sink); + numelement_ = 0; + try { + // assign friction_coef_ if it's given in input file + if (discontinuity_props.contains("friction_coefficient")) + friction_coef_ = + discontinuity_props.at("friction_coefficient").template get(); + else + friction_coef_ = 0; + } catch (Json::exception& except) { + console_->error("discontinuity parameter not set: {} {}\n", except.what(), + except.id); + } } + // initialization + template + bool mpm::Discontinuity3D::initialize( + const std::vector& coordinates, + const std::vector>& pointsets) { + bool status = true; + // Create points from file + bool point_status = this->create_points(coordinates); + if (!point_status) { + status = false; + throw std::runtime_error( + "Addition of points in discontinuity to mesh failed"); + } + // Create elements from file + bool element_status = create_elements(pointsets); + if (!element_status) { + status = false; + throw std::runtime_error( + "Addition of elements in discontinuity to mesh failed"); + } + + bool normal_status = initialize_center_normal(); + if (!normal_status) { + status = false; + throw std::runtime_error( + "initialized the center and normal of the discontunity failed"); + } + return status; + }; + //! create elements from file template -bool mpm::Discontinuity_3D::create_elements( +bool mpm::Discontinuity3D::create_elements( const std::vector>& elements) { bool status = true; @@ -18,7 +59,7 @@ bool mpm::Discontinuity_3D::create_elements( // Iterate over all elements for (const auto& points : elements) { - mpm::discontinuous_element element(points); + mpm::discontinuous_element element(points); elements_.emplace_back(element); // } @@ -30,8 +71,8 @@ bool mpm::Discontinuity_3D::create_elements( } // initialize the center and normal of the elements -template -bool mpm::Discontinuity_3D::initialize_center_normal() { +template <> +bool mpm::Discontinuity3D<3>::initialize_center_normal() { bool status = true; try { VectorDim center; @@ -51,7 +92,7 @@ bool mpm::Discontinuity_3D::initialize_center_normal() { element.set_center(center); // the normal of the element - normal = ThreeCross(points_[points[0]].coordinates(), + normal = three_cross_product(points_[points[0]].coordinates(), points_[points[1]].coordinates(), points_[points[2]].coordinates()); double det = std::sqrt(normal[0] * normal[0] + normal[1] * normal[1] + @@ -69,7 +110,7 @@ bool mpm::Discontinuity_3D::initialize_center_normal() { // return the cross product of ab X bc template -Eigen::Matrix mpm::Discontinuity_3D::ThreeCross( +Eigen::Matrix mpm::Discontinuity3D::three_cross_product( const VectorDim& a, const VectorDim& b, const VectorDim& c) { VectorDim threecross; @@ -79,10 +120,10 @@ Eigen::Matrix mpm::Discontinuity_3D::ThreeCross( return threecross; } -// return the levelset values of each doordinates +// return the levelset values of each coordinates //! \param[in] the vector of the coordinates template -void mpm::Discontinuity_3D::compute_levelset( +void mpm::Discontinuity3D::compute_levelset( const std::vector& coordinates, std::vector& phi_list) { mpm::Index i = 0; @@ -91,15 +132,35 @@ void mpm::Discontinuity_3D::compute_levelset( // searching and local searching double distance = std::numeric_limits::max(); for (const auto& element : elements_) { - double Vertical_distance_ = + double Vertical_distance = element.Vertical_distance(coor); // Vertical_distance(coor); - distance = std::abs(distance) < std::abs(Vertical_distance_) + distance = std::abs(distance) < std::abs(Vertical_distance) ? distance - : Vertical_distance_; + : Vertical_distance; if (!distance) distance = 1e-16; + distance = 1; } phi_list[i] = distance; ++i; } +} + +// return the normal vectors of given coordinates +//! \param[in] the coordinates +template +void mpm::Discontinuity3D::compute_normal( + const VectorDim& coordinates, VectorDim& normal_vector) { + // find the nearest distance from particle to cell: need to do by global + // searching and local searching + double distance = std::numeric_limits::max(); + for (const auto& element : elements_) { + double Vertical_distance = + element.Vertical_distance(coordinates); // Vertical_distance(coor); + if(std::abs(distance) > std::abs(Vertical_distance)) + { + distance = Vertical_distance; + normal_vector = element.normal(); + } + } } \ No newline at end of file diff --git a/include/xmpm/discontinuity_base.h b/include/xmpm/discontinuity_base.h index a6ceb01d3..0e83fb81b 100644 --- a/include/xmpm/discontinuity_base.h +++ b/include/xmpm/discontinuity_base.h @@ -1,30 +1,78 @@ #ifndef MPM_DISCONTINUITY_H_ #define MPM_DISCONTINUITY_H_ - -#include "logger.h" - +#include "cell.h" #include "data_types.h" +#include "io_mesh.h" +#include "logger.h" +#include "memory.h" +#include "node_base.h" +#include "vector.h" namespace mpm { template -struct discontinuous_point { +struct discontinuity_point { public: //! Define a vector of size dimension using VectorDim = Eigen::Matrix; - discontinuous_point(const VectorDim& coordinate) { + discontinuity_point(const VectorDim& coordinate) { coordinates_ = coordinate; + cell_ = nullptr; + //! Logger + console_ = spdlog::get("discontinuity_point"); } //! Return coordinates //! \retval coordinates_ return coordinates of the nodebase VectorDim coordinates() const { return coordinates_; } + //! Return cell_id + Index cell_id() const { return cell_id_; } + + //! Assign a cell to point + //! \param[in] cellptr Pointer to a cell + //! \param[in] xi Local coordinates of the point in reference cell + bool assign_cell_xi(const std::shared_ptr>& cellptr, + const Eigen::Matrix& xi); + + //! Return cell ptr status + bool cell_ptr() const { return cell_ != nullptr; } + + //! Assign a cell to point + //! \param[in] cellptr Pointer to a cell + bool assign_cell(const std::shared_ptr>& cellptr); + + //! Compute reference coordinates in a cell + bool compute_reference_location() noexcept; + + //! Locate points in a cell + void locate_discontinuity_mesh(Vector>& cells, + Map>& map_cells) noexcept; + + //! Compute updated position + void compute_updated_position(double dt) noexcept; + + //! Compute shape function + void compute_shapefn() noexcept; + private: //! point coordinates VectorDim coordinates_; + //! Cell id + Index cell_id_{std::numeric_limits::max()}; + //! Shape functions + Eigen::VectorXd shapefn_; + //! Cell + std::shared_ptr> cell_; + + //! Reference coordinates (in a cell) + Eigen::Matrix xi_; + //! Vector of nodal pointers + std::vector>> nodes_; + //! Logger + std::shared_ptr console_; }; //! class for to describe the discontinuous surface @@ -37,8 +85,9 @@ class DiscontinuityBase { //! Define a vector of size dimension using VectorDim = Eigen::Matrix; - // Constructor - DiscontinuityBase(); + //! Constructor with id + //! \param[in] discontinuity_properties discontinuity properties + DiscontinuityBase(unsigned id, const Json& discontinuity_props); //! Destructor virtual ~DiscontinuityBase(){}; @@ -68,25 +117,46 @@ class DiscontinuityBase { virtual void compute_levelset(const std::vector& coordinates, std::vector& phi_list) = 0; + // return the normal vectors of given coordinates +//! \param[in] the coordinates +virtual void compute_normal( + const VectorDim& coordinates, VectorDim& normal_vector) = 0; + + // return self_contact bool self_contact() { return self_contact_; }; - void set_frictional_coef(double coef) { frictional_coef_ = coef; }; + // return the friction coefficient + double friction_coef() { return friction_coef_; }; - double frictional_coef() { return frictional_coef_; }; + // return the number of the points + mpm::Index npoints() { return points_.size(); }; - protected: - std::vector> points_; + void points_list(std::vector>& points) { + points = points_; + } + //! Locate points in a cell + void locate_discontinuity_mesh(Vector>& cells, + Map>& map_cells) noexcept; - // number of points - mpm::Index numpoint_; + //! Compute updated position + void compute_updated_position(double dt) noexcept; + //! Compute shape function + void compute_shapefn() noexcept; + + protected: //! Logger std::unique_ptr console_; + std::vector> points_; + + // number of points + mpm::Index numpoint_; //delete + // self-contact bool self_contact_{true}; - double frictional_coef_; + double friction_coef_; }; // DiscontinuityBase class @@ -100,13 +170,14 @@ struct discontinuous_line { Eigen::Matrix points_; }; +template struct discontinuous_element { public: //! Define a vector of size dimension - using VectorDim = Eigen::Matrix; + using VectorDim = Eigen::Matrix; discontinuous_element(const std::vector& points) { - for (int i = 0; i < 3; ++i) points_[i] = points[i]; + for (int i = 0; i < points.size(); ++i) points_[i] = points[i]; } //! Return points indices Eigen::Matrix points() const { return points_; } @@ -114,6 +185,9 @@ struct discontinuous_element { inline void set_center(VectorDim& center) { center_ = center; } inline void set_normal(VectorDim& normal) { normal_ = normal; } + + //! Reture normal of the elements + VectorDim normal() const {return normal_;} double Vertical_distance(const VectorDim& coor) const { return (coor[0] - center_[0]) * normal_[0] + @@ -134,38 +208,6 @@ struct discontinuous_element { } // namespace mpm -template -mpm::DiscontinuityBase::DiscontinuityBase() { - numpoint_ = 0; - - frictional_coef_ = -1; - - std::string logger = "discontinuitybase"; - console_ = std::make_unique(logger, mpm::stdout_sink); -} - -//! create points from file -template -bool mpm::DiscontinuityBase::create_points( - const std::vector& coordinates) { - bool status = true; - try { - // Check if point coordinates is empty - if (coordinates.empty()) - throw std::runtime_error("List of coordinates is empty"); - // Iterate over all coordinates - for (const auto& point_coordinates : coordinates) { - - // Add point - mpm::discontinuous_point point(point_coordinates); - - points_.emplace_back(point); // - } - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; - } - return status; -} +#include "discontinuity_base.tcc" #endif // MPM_DiscontinuityBase_H_ diff --git a/include/xmpm/discontinuity_base.tcc b/include/xmpm/discontinuity_base.tcc new file mode 100644 index 000000000..92737322a --- /dev/null +++ b/include/xmpm/discontinuity_base.tcc @@ -0,0 +1,221 @@ +//! Constructor +template +mpm::DiscontinuityBase::DiscontinuityBase( + unsigned id, const Json& discontinuity_props) { + + numpoint_ = 0; + + friction_coef_ = 0; + + std::string logger = "discontinuity::" + std::to_string(id); + console_ = std::make_unique(logger, mpm::stdout_sink); +} + +//! create points from file +template +bool mpm::DiscontinuityBase::create_points( + const std::vector& coordinates) { + bool status = true; + try { + // Check if point coordinates is empty + if (coordinates.empty()) + throw std::runtime_error("List of coordinates is empty"); + // Iterate over all coordinates + for (const auto& point_coordinates : coordinates) { + + // Add point + mpm::discontinuity_point point(point_coordinates); + + points_.emplace_back(point); // + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +// Assign a cell to particle +template +bool mpm::discontinuity_point::assign_cell_xi( + const std::shared_ptr>& cellptr, + const Eigen::Matrix& xi) { + bool status = true; + try { + // Assign cell to the new cell ptr, if point can be found in new cell + if (cellptr != nullptr) { + + cell_ = cellptr; + cell_id_ = cellptr->id(); + nodes_ = cell_->nodes(); + // assign discontinuity_enrich + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->assign_discontinuity_enrich(true); + // Assign the reference location of particle + bool xi_nan = false; + + // Check if point is within the cell + for (unsigned i = 0; i < xi.size(); ++i) + if (xi(i) < -1. || xi(i) > 1. || std::isnan(xi(i))) xi_nan = true; + + if (xi_nan == false) + this->xi_ = xi; + else + return false; + } else { + console_->warn("Points of discontinuity cannot be found in cell!"); + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +// Assign a cell to point +template +bool mpm::discontinuity_point::assign_cell( + const std::shared_ptr>& cellptr) { + bool status = true; + try { + Eigen::Matrix xi; + // Assign cell to the new cell ptr, if point can be found in new cell + if (cellptr->is_point_in_cell(this->coordinates_, &xi)) { + + cell_ = cellptr; + cell_id_ = cellptr->id(); + nodes_ = cell_->nodes(); + // assign discontinuity_enrich + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->assign_discontinuity_enrich(true); + } else { + console_->warn("Points of discontinuity cannot be found in cell!"); + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +// Compute reference location cell to particle +template +bool mpm::discontinuity_point::compute_reference_location() noexcept { + // Set status of compute reference location + bool status = false; + // Compute local coordinates + Eigen::Matrix xi; + // Check if the point is in cell + if (cell_ != nullptr && cell_->is_point_in_cell(this->coordinates_, &xi)) { + this->xi_ = xi; + status = true; + } + + return status; +} + +//! Locate points in a cell +template +void mpm::discontinuity_point::locate_discontinuity_mesh( + Vector>& cells, Map>& map_cells) noexcept { + + // Check the current cell if it is not invalid + if (cell_id() != std::numeric_limits::max()) { + // If a cell id is present, but not a cell locate the cell from map + if (!cell_ptr()) assign_cell(map_cells[cell_id()]); + if (compute_reference_location()) return; + + // Check if discontinuity point is in any of its nearest neighbours + const auto neighbours = map_cells[cell_id()]->neighbours(); + Eigen::Matrix xi; + for (auto neighbour : neighbours) { + if (map_cells[neighbour]->is_point_in_cell(coordinates_, &xi)) { + assign_cell_xi(map_cells[neighbour], xi); + return; + } + } + } +#pragma omp parallel for schedule(runtime) + for (auto citr = cells.cbegin(); citr != cells.cend(); ++citr) { + // Check if particle is already found, if so don't run for other cells + // Check if co-ordinates is within the cell, if true + // add particle to cell + Eigen::Matrix xi; + if ((*citr)->is_point_in_cell(coordinates(), &xi)) { + assign_cell_xi(*citr, xi); + } + } +} + +// Compute updated position of the particle +template +void mpm::discontinuity_point::compute_updated_position( + double dt) noexcept { + // Check if point has a valid cell ptr + if (cell_ == nullptr) return; + // Get interpolated nodal velocity + Eigen::Matrix nodal_velocity = + Eigen::Matrix::Zero(); + const double tolerance = 1.E-16; + unsigned int phase = 0; + // need to do, points move with which side + int move_direction = -1; + for (unsigned i = 0; i < nodes_.size(); ++i) { + if (nodes_[i]->discontinuity_enrich()) { + double nodal_mass = + nodes_[i]->mass(phase) - + nodes_[i]->discontinuity_property("mass_enrich", 1)(0, 0); + if (nodal_mass < tolerance) continue; + + nodal_velocity += + shapefn_[i] * + (nodes_[i]->momentum(phase) - + nodes_[i]->discontinuity_property("momenta_enrich", 3)) / + nodal_mass; + } else { + double nodal_mass = nodes_[i]->mass(phase); + if (nodal_mass < tolerance) continue; + nodal_velocity += shapefn_[i] * nodes_[i]->momentum(phase) / nodal_mass; + } + } + // New position current position + velocity * dt + this->coordinates_ += nodal_velocity * dt; +} + +// Compute updated position of the particle +template +void mpm::discontinuity_point::compute_shapefn() noexcept { + // Check if point has a valid cell ptr + if (cell_ == nullptr) return; + // Get element ptr of a cell + const auto element = cell_->element_ptr(); + + // Zero matrix + Eigen::Matrix zero = Eigen::Matrix::Zero(); + + // Compute shape function of the point + //! Size of particle in natural coordinates + Eigen::Matrix natural_size_; + natural_size_.setZero(); + shapefn_ = element->shapefn(this->xi_, natural_size_, zero); +} +//! Locate points in a cell +template +void mpm::DiscontinuityBase::locate_discontinuity_mesh( + Vector>& cells, Map>& map_cells) noexcept { + for (auto& point : this->points_) + point.locate_discontinuity_mesh(cells, map_cells); +} + +// Compute updated position of the particle +template +void mpm::DiscontinuityBase::compute_updated_position( + double dt) noexcept { + for (auto& point : this->points_) point.compute_updated_position(dt); +} + +// Compute updated position of the particle +template +void mpm::DiscontinuityBase::compute_shapefn() noexcept { + for (auto& point : this->points_) point.compute_shapefn(); +} \ No newline at end of file diff --git a/src/discontinuity.cc b/src/discontinuity.cc index 11c2fd421..defd1814b 100644 --- a/src/discontinuity.cc +++ b/src/discontinuity.cc @@ -3,5 +3,6 @@ #include "factory.h" // Triangle 3-noded element -static Register, mpm::Discontinuity_3D<3>> tri3d( - "tri3d"); +static Register, mpm::Discontinuity3D<3>, unsigned, + const Json&> + tri3d("tri3d"); From 201f6cf12ab431297f94d93116061c1db81a4fd6 Mon Sep 17 00:00:00 2001 From: yong liang Date: Sun, 16 Aug 2020 00:11:08 -0700 Subject: [PATCH 35/91] :hammer::construction:clean xmpmparticle class --- include/node.tcc | 2 +- include/node_xmpm.tcc | 10 +- include/particles/particle.h | 2 +- include/particles/particle_xmpm.h | 294 ++---------- include/particles/particle_xmpm.tcc | 714 +--------------------------- include/solvers/xmpm_explicit.tcc | 4 +- include/xmpm/discontinuity_3d.tcc | 1 - 7 files changed, 48 insertions(+), 979 deletions(-) diff --git a/include/node.tcc b/include/node.tcc index d027a33e0..ba979d6da 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -34,7 +34,7 @@ void mpm::Node::initialise() noexcept { acceleration_.setZero(); status_ = false; material_ids_.clear(); - discontinuity_enrich_ = false; + discontinuity_enrich_ = true; } //! Initialise shared pointer to nodal properties pool diff --git a/include/node_xmpm.tcc b/include/node_xmpm.tcc index b5abd14b2..2394b0169 100644 --- a/include/node_xmpm.tcc +++ b/include/node_xmpm.tcc @@ -54,11 +54,11 @@ bool mpm::Node::intergrate_momentum_discontinuity( // when velocity is set. this->apply_velocity_constraints_discontinuity(); - // need to be done - //Eigen::Matrix normal{0.44721359474414313, 0, - // 0.89442719147920724}; - // property_handle_->assign_property("normal_unit_vectors_discontinuity", - // discontinuity_prop_id_, 0, normal, Tdim); + //need to be done + Eigen::Matrix normal{0.44721359474414313, 0, + 0.89442719147920724}; + property_handle_->assign_property("normal_unit_vectors_discontinuity", + discontinuity_prop_id_, 0, normal, Tdim); this->self_contact_discontinuity(dt); diff --git a/include/particles/particle.h b/include/particles/particle.h index a362d7c76..167eec3dd 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -333,7 +333,7 @@ class Particle : public ParticleBase { //! \retval pack size of serialized object int compute_pack_size() const; - private: + protected: //! particle id using ParticleBase::id_; //! coordinates diff --git a/include/particles/particle_xmpm.h b/include/particles/particle_xmpm.h index 3506097bf..dfcc4e37c 100644 --- a/include/particles/particle_xmpm.h +++ b/include/particles/particle_xmpm.h @@ -18,7 +18,7 @@ namespace mpm { //! \details ParticleXMPM class: id_ and coordinates. //! \tparam Tdim Dimension template -class ParticleXMPM : public ParticleBase { +class ParticleXMPM : public Particle { public: //! Define a vector of size dimension using VectorDim = Eigen::Matrix; @@ -46,157 +46,12 @@ class ParticleXMPM : public ParticleBase { //! Delete assignment operator ParticleXMPM& operator=(const ParticleXMPM&) = 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 - virtual bool initialise_particle( - 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; - - //! Initialise properties + //! Initialise properties void initialise() override; - //! Compute reference coordinates in a cell - bool compute_reference_location() noexcept override; - - //! Return reference location - VectorDim reference_location() const override { return xi_; } - - //! Assign a cell to particle - //! If point is in new cell, assign new cell and remove particle id from old - //! cell. If point can't be found in the new cell, check if particle is still - //! valid in the old cell, if it is leave it as is. If not, set cell as null - //! \param[in] cellptr Pointer to a cell - bool assign_cell(const std::shared_ptr>& cellptr) override; - - //! Assign a cell to particle - //! If point is in new cell, assign new cell and remove particle id from old - //! cell. If point can't be found in the new cell, check if particle is still - //! valid in the old cell, if it is leave it as is. If not, set cell as null - //! \param[in] cellptr Pointer to a cell - //! \param[in] xi Local coordinates of the point in reference cell - bool assign_cell_xi(const std::shared_ptr>& cellptr, - const Eigen::Matrix& xi) override; - - //! Assign cell id - //! \param[in] id Cell id - bool assign_cell_id(Index id) override; - - //! Return cell id - Index cell_id() const override { return cell_id_; } - - //! Return cell ptr status - bool cell_ptr() const override { return cell_ != nullptr; } - - //! Remove cell associated with the particle - void remove_cell() override; - - //! Compute shape functions of a particle, based on local coordinates - void compute_shapefn() noexcept override; - - //! Assign volume - //! \param[in] volume Volume of particle - bool assign_volume(double volume) override; - - //! Return 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 - //! \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; - - //! Map multimaterial displacements to nodes - void map_multimaterial_displacements_to_nodes() noexcept override; - - //! Map multimaterial domain gradients to nodes - void map_multimaterial_domain_gradients_to_nodes() noexcept override; - - //! 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; } - - //! Return mass of the particles - double mass() const override { return mass_; } - - //! Assign material - //! \param[in] material Pointer to a material - //! \param[in] phase Index to indicate phase - bool assign_material(const std::shared_ptr>& material, - unsigned phase = mpm::ParticlePhase::Solid) override; - - //! Compute strain - //! \param[in] dt Analysis time step - void compute_strain(double dt) noexcept override; - - //! Return strain of the particle - Eigen::Matrix strain() const override { return strain_; } - - //! Return strain rate of the particle - Eigen::Matrix strain_rate() const override { - return strain_rate_; - }; - - //! Return dvolumetric strain of centroid - //! \retval dvolumetric strain at centroid - double dvolumetric_strain() const override { return dvolumetric_strain_; } - - //! Return volumetric strain of centroid - //! \retval volumetric strain at centroid - double volumetric_strain_centroid() const override { - return volumetric_strain_centroid_; - } - - //! Initial stress - //! \param[in] stress Initial sress - void initial_stress(const Eigen::Matrix& stress) override { - this->stress_ = stress; - } - - //! Compute stress - void compute_stress() noexcept override; - - //! 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; @@ -204,91 +59,12 @@ class ParticleXMPM : public ParticleBase { //! Map internal force inline void map_internal_force() noexcept override; - //! Assign velocity to the particle - //! \param[in] velocity A vector of particle velocity - //! \retval status Assignment status - bool assign_velocity(const VectorDim& velocity) override; - - //! Return velocity of the particle - VectorDim velocity() const override { return velocity_; } - - //! Return displacement of the particle - VectorDim displacement() const override { return displacement_; } - - //! 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 traction of the particle - //! \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; - //! Return a state variable - //! \param[in] var State variable - //! \param[in] phase Index to indicate phase - //! \retval Quantity of the state history variable - double state_variable( - const std::string& var, - unsigned phase = mpm::ParticlePhase::Solid) const override { - return (state_variables_[phase].find(var) != state_variables_[phase].end()) - ? state_variables_[phase].at(var) - : std::numeric_limits::quiet_NaN(); - } - - //! 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 - 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 tensor data of particles - //! \param[in] property Property string - //! \retval vecdata Tensor data of particle property - Eigen::VectorXd tensor_data(const std::string& property) 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; - - //! Assign material id of this particle to nodes - void append_material_id_to_nodes() const override; - - //! Return the number of neighbour particles - unsigned nneighbours() const override { return neighbours_.size(); }; - - //! Assign neighbour particles - //! \param[in] neighbours set of id of the neighbouring particles - //! \retval insertion_status Return the successful addition of a node - void assign_neighbours(const std::vector& neighbours) override; - - //! Return neighbour ids - std::vector neighbours() const override { return neighbours_; }; - protected: //! Initialise particle material container //! \details This function allocate memory and initialise the material related @@ -315,69 +91,71 @@ class ParticleXMPM : public ParticleBase { private: //! particle id - using ParticleBase::id_; + using Particle::id_; //! coordinates - using ParticleBase::coordinates_; + using Particle::coordinates_; //! Reference coordinates (in a cell) - using ParticleBase::xi_; + using Particle::xi_; //! Cell - using ParticleBase::cell_; + using Particle::cell_; //! Cell id - using ParticleBase::cell_id_; + using Particle::cell_id_; //! Nodes - using ParticleBase::nodes_; + using Particle::nodes_; //! Status - using ParticleBase::status_; + using Particle::status_; //! Material - using ParticleBase::material_; + using Particle::material_; //! Material id - using ParticleBase::material_id_; + using Particle::material_id_; //! State variables - using ParticleBase::state_variables_; + using Particle::state_variables_; //! Neighbour particles - using ParticleBase::neighbours_; + using Particle::neighbours_; //! Volumetric mass density (mass / volume) - double mass_density_{0.}; + using Particle::mass_density_; //! Mass - double mass_{0.}; + using Particle::mass_; //! Volume - double volume_{0.}; + using Particle::volume_; //! Size of particle - Eigen::Matrix size_; + using Particle:: size_; //! Size of particle in natural coordinates - Eigen::Matrix natural_size_; + using Particle:: natural_size_; //! Stresses - Eigen::Matrix stress_; + using Particle:: stress_; //! Strains - Eigen::Matrix strain_; + using Particle:: strain_; //! dvolumetric strain - double dvolumetric_strain_{0.}; + using Particle::dvolumetric_strain_; //! Volumetric strain at centroid - double volumetric_strain_centroid_{0.}; + using Particle::volumetric_strain_centroid_; //! Strain rate - Eigen::Matrix strain_rate_; + using Particle:: strain_rate_; //! dstrains - Eigen::Matrix dstrain_; + using Particle:: dstrain_; //! Velocity - Eigen::Matrix velocity_; + using Particle:: velocity_; //! Displacement - Eigen::Matrix displacement_; + using Particle:: displacement_; //! Particle velocity constraints - std::map particle_velocity_constraints_; + using Particle:: particle_velocity_constraints_; //! Set traction - bool set_traction_{false}; + using Particle:: set_traction_; //! Surface Traction (given as a stress; force/area) - Eigen::Matrix traction_; + using Particle:: traction_; //! Shape functions - Eigen::VectorXd shapefn_; + using Particle:: shapefn_; //! dN/dX - Eigen::MatrixXd dn_dx_; + using Particle:: dn_dx_; //! dN/dX at cell centroid - Eigen::MatrixXd dn_dx_centroid_; + using Particle:: dn_dx_centroid_; //! Logger - std::unique_ptr console_; + using Particle:: console_; //! Map of vector properties - std::map> properties_; + using Particle:: properties_; + +private: //! level set values for discontinuity double levelset_phi_{0.}; }; // ParticleXMPM class diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index e3ab0235f..ea8a24a4e 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -1,14 +1,9 @@ //! Construct a particle with id and coordinates template mpm::ParticleXMPM::ParticleXMPM(Index id, const VectorDim& coord) - : mpm::ParticleBase(id, coord) { + : mpm::Particle(id, coord) { + this->initialise(); - // Clear cell ptr - cell_ = nullptr; - // Nodes - nodes_.clear(); - // Set material containers - this->initialise_material(1); // Logger std::string logger = "particlexmpm" + std::to_string(Tdim) + "d::" + std::to_string(id); @@ -19,498 +14,26 @@ mpm::ParticleXMPM::ParticleXMPM(Index id, const VectorDim& coord) template mpm::ParticleXMPM::ParticleXMPM(Index id, const VectorDim& coord, bool status) - : mpm::ParticleBase(id, coord, status) { + : mpm::Particle(id, coord, status) { this->initialise(); - cell_ = nullptr; - nodes_.clear(); - // Set material containers - this->initialise_material(1); //! Logger std::string logger = "particlexmpm" + 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::ParticleXMPM::initialise_particle( - const HDF5Particle& particle) { - - // Assign id - this->id_ = particle.id; - // Mass - this->mass_ = particle.mass; - // Volume - this->volume_ = particle.volume; - // Mass Density - 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; - // Initialise particle size - for (unsigned i = 0; i < Tdim; ++i) this->natural_size_(i) = psize(i); - - // Coordinates - Eigen::Vector3d coordinates; - coordinates << particle.coord_x, particle.coord_y, particle.coord_z; - // Initialise coordinates - for (unsigned i = 0; i < Tdim; ++i) this->coordinates_(i) = coordinates(i); - - // Displacement - Eigen::Vector3d displacement; - displacement << particle.displacement_x, particle.displacement_y, - particle.displacement_z; - // Initialise displacement - 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) this->velocity_(i) = velocity(i); - - // Stress - this->stress_[0] = particle.stress_xx; - this->stress_[1] = particle.stress_yy; - this->stress_[2] = particle.stress_zz; - this->stress_[3] = particle.tau_xy; - this->stress_[4] = particle.tau_yz; - this->stress_[5] = particle.tau_xz; - - // Strain - this->strain_[0] = particle.strain_xx; - this->strain_[1] = particle.strain_yy; - this->strain_[2] = particle.strain_zz; - this->strain_[3] = particle.gamma_xy; - this->strain_[4] = particle.gamma_yz; - this->strain_[5] = particle.gamma_xz; - - // Volumetric strain - this->volumetric_strain_centroid_ = particle.epsilon_v; - - // Status - this->status_ = particle.status; - - // Cell id - this->cell_id_ = particle.cell_id; - this->cell_ = nullptr; - - // Clear nodes - this->nodes_.clear(); - - // Material id - this->material_id_[mpm::ParticlePhase::Solid] = particle.material_id; - - return true; -} -//! Initialise particle data from HDF5 -template -bool mpm::ParticleXMPM::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 = this->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!"); - } - } - return status; -} -//! Return particle data in HDF5 format -template -// cppcheck-suppress * -mpm::HDF5Particle mpm::ParticleXMPM::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::ParticleXMPM::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.; levelset_phi_ = 0.; // Initialize vector data properties - this->properties_["stresses"] = [&]() { return stress(); }; - this->properties_["strains"] = [&]() { return strain(); }; - this->properties_["velocities"] = [&]() { return velocity(); }; - this->properties_["displacements"] = [&]() { return displacement(); }; this->properties_["levelset"] = [&]() { VectorDim levelset{levelset_phi_,0,0};return levelset; }; } -//! Initialise particle material container -template -void mpm::ParticleXMPM::initialise_material(unsigned phase_size) { - material_.resize(phase_size); - material_id_.resize(phase_size); - state_variables_.resize(phase_size); - std::fill(material_.begin(), material_.end(), nullptr); - std::fill(material_id_.begin(), material_id_.end(), - std::numeric_limits::max()); - std::fill(state_variables_.begin(), state_variables_.end(), mpm::dense_map()); -} - -//! Assign material history variables -template -bool mpm::ParticleXMPM::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(phase) != nullptr && - this->material_id(phase) == material->id()) { - // Clone 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; - status = true; - } - } - return status; -} - -// Assign a cell to particle -template -bool mpm::ParticleXMPM::assign_cell( - const std::shared_ptr>& cellptr) { - bool status = true; - try { - Eigen::Matrix xi; - // Assign cell to the new cell ptr, if point can be found in new cell - if (cellptr->is_point_in_cell(this->coordinates_, &xi)) { - // if a cell already exists remove particle from that cell - if (cell_ != nullptr) cell_->remove_particle_id(this->id_); - - cell_ = cellptr; - cell_id_ = cellptr->id(); - // dn_dx centroid - dn_dx_centroid_ = cell_->dn_dx_centroid(); - // Copy nodal pointer to cell - nodes_.clear(); - nodes_ = cell_->nodes(); - - // Compute reference location of particle - bool xi_status = this->compute_reference_location(); - if (!xi_status) return false; - status = cell_->add_particle_id(this->id()); - } else { - throw std::runtime_error("Point cannot be found in cell!"); - } - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; - } - return status; -} - -// Assign a cell to particle -template -bool mpm::ParticleXMPM::assign_cell_xi( - const std::shared_ptr>& cellptr, - const Eigen::Matrix& xi) { - bool status = true; - try { - // Assign cell to the new cell ptr, if point can be found in new cell - if (cellptr != nullptr) { - // if a cell already exists remove particle from that cell - if (cell_ != nullptr) cell_->remove_particle_id(this->id_); - - cell_ = cellptr; - cell_id_ = cellptr->id(); - // dn_dx centroid - dn_dx_centroid_ = cell_->dn_dx_centroid(); - // Copy nodal pointer to cell - nodes_.clear(); - nodes_ = cell_->nodes(); - - // Assign the reference location of particle - bool xi_nan = false; - - // Check if point is within the cell - for (unsigned i = 0; i < xi.size(); ++i) - if (xi(i) < -1. || xi(i) > 1. || std::isnan(xi(i))) xi_nan = true; - - if (xi_nan == false) - this->xi_ = xi; - else - return false; - - status = cell_->add_particle_id(this->id()); - } else { - throw std::runtime_error("Point cannot be found in cell!"); - } - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; - } - return status; -} - -// Assign a cell id to particle -template -bool mpm::ParticleXMPM::assign_cell_id(mpm::Index id) { - bool status = false; - try { - // if a cell ptr is null - if (cell_ == nullptr && id != std::numeric_limits::max()) { - cell_id_ = id; - status = true; - } else { - throw std::runtime_error("Invalid cell id or cell is already assigned!"); - } - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; - } - return status; -} - -// Remove cell for the particle -template -void mpm::ParticleXMPM::remove_cell() { - // if a cell is not nullptr - if (cell_ != nullptr) cell_->remove_particle_id(this->id_); - cell_id_ = std::numeric_limits::max(); - // Clear all the nodes - nodes_.clear(); -} - -// Assign a material to particle -template -bool mpm::ParticleXMPM::assign_material( - const std::shared_ptr>& material, unsigned phase) { - bool status = false; - try { - // Check if material is valid and properties are set - if (material != nullptr) { - material_.at(phase) = material; - material_id_.at(phase) = material_[phase]->id(); - state_variables_.at(phase) = - material_[phase]->initialise_state_variables(); - status = true; - } else { - throw std::runtime_error("Material is undefined!"); - } - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - } - return status; -} - -// Compute reference location cell to particle -template -bool mpm::ParticleXMPM::compute_reference_location() noexcept { - // Set status of compute reference location - bool status = false; - // Compute local coordinates - Eigen::Matrix xi; - // Check if the point is in cell - if (cell_ != nullptr && cell_->is_point_in_cell(this->coordinates_, &xi)) { - this->xi_ = xi; - status = true; - } - - return status; -} - -// Compute shape functions and gradients -template -void mpm::ParticleXMPM::compute_shapefn() noexcept { - // Check if particle has a valid cell ptr - assert(cell_ != nullptr); - // Get element ptr of a cell - const auto element = cell_->element_ptr(); - - // Zero matrix - Eigen::Matrix zero = Eigen::Matrix::Zero(); - - // Compute shape function of the particle - shapefn_ = element->shapefn(this->xi_, this->natural_size_, zero); - - // Compute dN/dx - dn_dx_ = element->dn_dx(this->xi_, cell_->nodal_coordinates(), - this->natural_size_, zero); -} - -// Assign volume to the particle -template -bool mpm::ParticleXMPM::assign_volume(double volume) { - bool status = true; - try { - if (volume <= 0.) - throw std::runtime_error("Particle volume cannot be negative"); - - this->volume_ = volume; - // Compute size of particle in each direction - const double length = - std::pow(this->volume_, static_cast(1. / Tdim)); - // Set particle size as length on each side - this->size_.fill(length); - - if (cell_ != nullptr) { - // Get element ptr of a cell - const auto element = cell_->element_ptr(); - - // Set local particle length based on length of element in natural - // coordinates. Length/(npartices^(1/Dimension)) - this->natural_size_.fill( - element->unit_element_length() / - std::pow(cell_->nparticles(), static_cast(1. / Tdim))); - } - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; - } - return status; -} - -// Compute volume of the particle -template -void mpm::ParticleXMPM::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::ParticleXMPM::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::ParticleXMPM::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 @@ -537,94 +60,7 @@ void mpm::ParticleXMPM::map_mass_momentum_to_nodes() noexcept { } } -//! Map multimaterial properties to nodes -template -void mpm::ParticleXMPM< - Tdim>::map_multimaterial_mass_momentum_to_nodes() noexcept { - // Check if particle mass is set - 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) = mass_ * shapefn_[i]; - nodes_[i]->update_property(true, "masses", nodal_mass, this->material_id(), - 1); - nodes_[i]->update_property(true, "momenta", velocity_ * nodal_mass, - this->material_id(), Tdim); - } -} - -//! Map multimaterial displacements to nodes -template -void mpm::ParticleXMPM< - Tdim>::map_multimaterial_displacements_to_nodes() noexcept { - // Check if particle mass is set - 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 = mass_ * shapefn_[i] * displacement_; - nodes_[i]->update_property(true, "displacements", displacement, - this->material_id(), Tdim); - } -} - -//! Map multimaterial domain gradients to nodes -template -void mpm::ParticleXMPM< - Tdim>::map_multimaterial_domain_gradients_to_nodes() noexcept { - // Check if particle volume is set - 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] = volume_ * dn_dx_(i, j); - nodes_[i]->update_property(true, "domain_gradients", gradient, - this->material_id(), Tdim); - } -} - -// Compute strain rate of the particle -template <> -inline Eigen::Matrix mpm::ParticleXMPM<1>::compute_strain_rate( - const Eigen::MatrixXd& dn_dx, unsigned phase) noexcept { - // Define strain rate - Eigen::Matrix strain_rate = Eigen::Matrix::Zero(); - - for (unsigned i = 0; i < this->nodes_.size(); ++i) { - Eigen::Matrix vel = nodes_[i]->velocity(phase); - strain_rate[0] += dn_dx(i, 0) * vel[0]; - } - if (std::fabs(strain_rate(0)) < 1.E-15) strain_rate[0] = 0.; - return strain_rate; -} - -// Compute strain rate of the particle -template <> -inline Eigen::Matrix mpm::ParticleXMPM<2>::compute_strain_rate( - const Eigen::MatrixXd& dn_dx, unsigned phase) noexcept { - // Define strain rate - Eigen::Matrix strain_rate = Eigen::Matrix::Zero(); - - for (unsigned i = 0; i < this->nodes_.size(); ++i) { - Eigen::Matrix vel = nodes_[i]->velocity(phase); - strain_rate[0] += dn_dx(i, 0) * vel[0]; - strain_rate[1] += dn_dx(i, 1) * vel[1]; - strain_rate[3] += dn_dx(i, 1) * vel[0] + dn_dx(i, 0) * vel[1]; - } - - if (std::fabs(strain_rate[0]) < 1.E-15) strain_rate[0] = 0.; - if (std::fabs(strain_rate[1]) < 1.E-15) strain_rate[1] = 0.; - if (std::fabs(strain_rate[3]) < 1.E-15) strain_rate[3] = 0.; - return strain_rate; -} // Compute strain rate of the particle template <> @@ -667,37 +103,6 @@ inline Eigen::Matrix mpm::ParticleXMPM<3>::compute_strain_rate( return strain_rate; } -// Compute strain of the particle -template -void mpm::ParticleXMPM::compute_strain(double dt) noexcept { - // Assign strain rate - strain_rate_ = this->compute_strain_rate(dn_dx_, mpm::ParticlePhase::Solid); - // Update dstrain - dstrain_ = strain_rate_ * dt; - // Update strain - strain_ += dstrain_; - - // Compute at centroid - // Strain rate for reduced integration - const Eigen::Matrix strain_rate_centroid = - this->compute_strain_rate(dn_dx_centroid_, mpm::ParticlePhase::Solid); - - // Assign volumetric strain at centroid - dvolumetric_strain_ = dt * strain_rate_centroid.head(Tdim).sum(); - volumetric_strain_centroid_ += dvolumetric_strain_; -} - -// Compute stress -template -void mpm::ParticleXMPM::compute_stress() noexcept { - // Check if material ptr is valid - assert(this->material() != nullptr); - // Calculate stress - this->stress_ = - (this->material()) - ->compute_stress(stress_, dstrain_, this, - &state_variables_[mpm::ParticlePhase::Solid]); -} //! Map body force template @@ -774,47 +179,7 @@ inline void mpm::ParticleXMPM<3>::map_internal_force() noexcept { } } -// Assign velocity to the particle -template -bool mpm::ParticleXMPM::assign_velocity( - const Eigen::Matrix& velocity) { - // Assign velocity - velocity_ = velocity; - return true; -} -// Assign traction to the particle -template -bool mpm::ParticleXMPM::assign_traction(unsigned direction, - double traction) { - bool status = false; - try { - if (direction >= Tdim || - 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); - status = true; - this->set_traction_ = true; - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; - } - return status; -} - -//! Map traction force -template -void mpm::ParticleXMPM::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 @@ -891,77 +256,4 @@ void mpm::ParticleXMPM::compute_updated_position( this->displacement_ += nodal_velocity * dt; } -//! Map particle pressure to nodes -template -bool mpm::ParticleXMPM::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::ParticleXMPM::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 -template -void mpm::ParticleXMPM::apply_particle_velocity_constraints( - unsigned dir, double velocity) { - // Set particle velocity constraint - this->velocity_(dir) = velocity; -} - -//! Return particle tensor data -template -Eigen::VectorXd mpm::ParticleXMPM::tensor_data( - const std::string& property) { - return this->properties_.at(property)(); -} - -//! Assign material id of this particle to nodes -template -void mpm::ParticleXMPM::append_material_id_to_nodes() const { - for (unsigned i = 0; i < nodes_.size(); ++i) - nodes_[i]->append_material_id(this->material_id()); -} - -//! Assign neighbour particles -template -void mpm::ParticleXMPM::assign_neighbours( - const std::vector& neighbours) { - neighbours_ = neighbours; - neighbours_.erase(std::remove(neighbours_.begin(), neighbours_.end(), id_), - neighbours_.end()); -} diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index 4239f71f5..4204cac67 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -317,8 +317,8 @@ bool mpm::XMPMExplicit::solve() { if (this->stress_update_ == mpm::StressUpdate::USL) this->compute_stress_strain(phase); // Update the discontinuity position - if (discontinuity_) - mesh_->compute_updated_position_discontinuity(this->dt_); + // if (discontinuity_) + // mesh_->compute_updated_position_discontinuity(this->dt_); // Locate particles auto unlocatable_particles = mesh_->locate_particles_mesh(); diff --git a/include/xmpm/discontinuity_3d.tcc b/include/xmpm/discontinuity_3d.tcc index 2f7479d4c..e7842013f 100644 --- a/include/xmpm/discontinuity_3d.tcc +++ b/include/xmpm/discontinuity_3d.tcc @@ -138,7 +138,6 @@ void mpm::Discontinuity3D::compute_levelset( ? distance : Vertical_distance; if (!distance) distance = 1e-16; - distance = 1; } phi_list[i] = distance; From c1850df6af4bfb3b0ba60b97e42355b24efcf14a Mon Sep 17 00:00:00 2001 From: yong liang Date: Sun, 16 Aug 2020 00:19:28 -0700 Subject: [PATCH 36/91] :hammer:change discontinuouty_point_line name --- include/xmpm/discontinuity_3d.h | 2 +- include/xmpm/discontinuity_3d.tcc | 2 +- include/xmpm/discontinuity_base.h | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/xmpm/discontinuity_3d.h b/include/xmpm/discontinuity_3d.h index 793a35450..ffe30abcd 100644 --- a/include/xmpm/discontinuity_3d.h +++ b/include/xmpm/discontinuity_3d.h @@ -53,7 +53,7 @@ class Discontinuity3D : public DiscontinuityBase { private: // vector of elements - std::vector> elements_; + std::vector> elements_; // number of elements //delete mpm::Index numelement_; diff --git a/include/xmpm/discontinuity_3d.tcc b/include/xmpm/discontinuity_3d.tcc index e7842013f..b489731cb 100644 --- a/include/xmpm/discontinuity_3d.tcc +++ b/include/xmpm/discontinuity_3d.tcc @@ -59,7 +59,7 @@ bool mpm::Discontinuity3D::create_elements( // Iterate over all elements for (const auto& points : elements) { - mpm::discontinuous_element element(points); + mpm::discontinuity_element element(points); elements_.emplace_back(element); // } diff --git a/include/xmpm/discontinuity_base.h b/include/xmpm/discontinuity_base.h index 0e83fb81b..0c6ee6a8c 100644 --- a/include/xmpm/discontinuity_base.h +++ b/include/xmpm/discontinuity_base.h @@ -160,7 +160,7 @@ virtual void compute_normal( }; // DiscontinuityBase class -struct discontinuous_line { +struct discontinuity_line { public: //! Return points indices Eigen::Matrix points() const { return points_; }; @@ -171,12 +171,12 @@ struct discontinuous_line { }; template -struct discontinuous_element { +struct discontinuity_element { public: //! Define a vector of size dimension using VectorDim = Eigen::Matrix; - discontinuous_element(const std::vector& points) { + discontinuity_element(const std::vector& points) { for (int i = 0; i < points.size(); ++i) points_[i] = points[i]; } //! Return points indices From 6494559ccf8fa0ba6c31fa3e37d3677af9343f4a Mon Sep 17 00:00:00 2001 From: yong liang Date: Sun, 16 Aug 2020 00:42:16 -0700 Subject: [PATCH 37/91] :hammer:separate the discontinuity functions into different files --- include/xmpm/discontinuity_3d.tcc | 2 +- include/xmpm/discontinuity_base.h | 128 +++++++++-------- include/xmpm/discontinuity_base.tcc | 165 ---------------------- include/xmpm/discontinuity_base_point.tcc | 164 +++++++++++++++++++++ 4 files changed, 231 insertions(+), 228 deletions(-) create mode 100644 include/xmpm/discontinuity_base_point.tcc diff --git a/include/xmpm/discontinuity_3d.tcc b/include/xmpm/discontinuity_3d.tcc index b489731cb..19d69f095 100644 --- a/include/xmpm/discontinuity_3d.tcc +++ b/include/xmpm/discontinuity_3d.tcc @@ -1,7 +1,7 @@ template mpm::Discontinuity3D::Discontinuity3D(unsigned id, const Json& discontinuity_props) - : DiscontinuityBase(id, discontinuity_props) { + :DiscontinuityBase(id, discontinuity_props) { numelement_ = 0; try { diff --git a/include/xmpm/discontinuity_base.h b/include/xmpm/discontinuity_base.h index 0c6ee6a8c..61e36ea2b 100644 --- a/include/xmpm/discontinuity_base.h +++ b/include/xmpm/discontinuity_base.h @@ -12,68 +12,7 @@ namespace mpm { template -struct discontinuity_point { - public: - //! Define a vector of size dimension - using VectorDim = Eigen::Matrix; - - discontinuity_point(const VectorDim& coordinate) { - coordinates_ = coordinate; - cell_ = nullptr; - //! Logger - console_ = spdlog::get("discontinuity_point"); - } - - //! Return coordinates - //! \retval coordinates_ return coordinates of the nodebase - VectorDim coordinates() const { return coordinates_; } - - //! Return cell_id - Index cell_id() const { return cell_id_; } - - //! Assign a cell to point - //! \param[in] cellptr Pointer to a cell - //! \param[in] xi Local coordinates of the point in reference cell - bool assign_cell_xi(const std::shared_ptr>& cellptr, - const Eigen::Matrix& xi); - - //! Return cell ptr status - bool cell_ptr() const { return cell_ != nullptr; } - - //! Assign a cell to point - //! \param[in] cellptr Pointer to a cell - bool assign_cell(const std::shared_ptr>& cellptr); - - //! Compute reference coordinates in a cell - bool compute_reference_location() noexcept; - - //! Locate points in a cell - void locate_discontinuity_mesh(Vector>& cells, - Map>& map_cells) noexcept; - - //! Compute updated position - void compute_updated_position(double dt) noexcept; - - //! Compute shape function - void compute_shapefn() noexcept; - - private: - //! point coordinates - VectorDim coordinates_; - //! Cell id - Index cell_id_{std::numeric_limits::max()}; - //! Shape functions - Eigen::VectorXd shapefn_; - //! Cell - std::shared_ptr> cell_; - - //! Reference coordinates (in a cell) - Eigen::Matrix xi_; - //! Vector of nodal pointers - std::vector>> nodes_; - //! Logger - std::shared_ptr console_; -}; +struct discontinuity_point; //! class for to describe the discontinuous surface //! \brief @@ -160,6 +99,70 @@ virtual void compute_normal( }; // DiscontinuityBase class +template +struct discontinuity_point { + public: + //! Define a vector of size dimension + using VectorDim = Eigen::Matrix; + + discontinuity_point(const VectorDim& coordinate) { + coordinates_ = coordinate; + cell_ = nullptr; + //! Logger + console_ = spdlog::get("discontinuity_point"); + } + + //! Return coordinates + //! \retval coordinates_ return coordinates of the nodebase + VectorDim coordinates() const { return coordinates_; } + + //! Return cell_id + Index cell_id() const { return cell_id_; } + + //! Assign a cell to point + //! \param[in] cellptr Pointer to a cell + //! \param[in] xi Local coordinates of the point in reference cell + bool assign_cell_xi(const std::shared_ptr>& cellptr, + const Eigen::Matrix& xi); + + //! Return cell ptr status + bool cell_ptr() const { return cell_ != nullptr; } + + //! Assign a cell to point + //! \param[in] cellptr Pointer to a cell + bool assign_cell(const std::shared_ptr>& cellptr); + + //! Compute reference coordinates in a cell + bool compute_reference_location() noexcept; + + //! Locate points in a cell + void locate_discontinuity_mesh(Vector>& cells, + Map>& map_cells) noexcept; + + //! Compute updated position + void compute_updated_position(double dt) noexcept; + + //! Compute shape function + void compute_shapefn() noexcept; + + private: + //! point coordinates + VectorDim coordinates_; + //! Cell id + Index cell_id_{std::numeric_limits::max()}; + //! Shape functions + Eigen::VectorXd shapefn_; + //! Cell + std::shared_ptr> cell_; + + //! Reference coordinates (in a cell) + Eigen::Matrix xi_; + //! Vector of nodal pointers + std::vector>> nodes_; + //! Logger + std::shared_ptr console_; +}; + struct discontinuity_line { public: //! Return points indices @@ -209,5 +212,6 @@ struct discontinuity_element { } // namespace mpm #include "discontinuity_base.tcc" +#include "discontinuity_base_point.tcc" #endif // MPM_DiscontinuityBase_H_ diff --git a/include/xmpm/discontinuity_base.tcc b/include/xmpm/discontinuity_base.tcc index 92737322a..e7a232295 100644 --- a/include/xmpm/discontinuity_base.tcc +++ b/include/xmpm/discontinuity_base.tcc @@ -34,171 +34,6 @@ bool mpm::DiscontinuityBase::create_points( } return status; } - -// Assign a cell to particle -template -bool mpm::discontinuity_point::assign_cell_xi( - const std::shared_ptr>& cellptr, - const Eigen::Matrix& xi) { - bool status = true; - try { - // Assign cell to the new cell ptr, if point can be found in new cell - if (cellptr != nullptr) { - - cell_ = cellptr; - cell_id_ = cellptr->id(); - nodes_ = cell_->nodes(); - // assign discontinuity_enrich - for (unsigned i = 0; i < nodes_.size(); ++i) - nodes_[i]->assign_discontinuity_enrich(true); - // Assign the reference location of particle - bool xi_nan = false; - - // Check if point is within the cell - for (unsigned i = 0; i < xi.size(); ++i) - if (xi(i) < -1. || xi(i) > 1. || std::isnan(xi(i))) xi_nan = true; - - if (xi_nan == false) - this->xi_ = xi; - else - return false; - } else { - console_->warn("Points of discontinuity cannot be found in cell!"); - } - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; - } - return status; -} - -// Assign a cell to point -template -bool mpm::discontinuity_point::assign_cell( - const std::shared_ptr>& cellptr) { - bool status = true; - try { - Eigen::Matrix xi; - // Assign cell to the new cell ptr, if point can be found in new cell - if (cellptr->is_point_in_cell(this->coordinates_, &xi)) { - - cell_ = cellptr; - cell_id_ = cellptr->id(); - nodes_ = cell_->nodes(); - // assign discontinuity_enrich - for (unsigned i = 0; i < nodes_.size(); ++i) - nodes_[i]->assign_discontinuity_enrich(true); - } else { - console_->warn("Points of discontinuity cannot be found in cell!"); - } - } catch (std::exception& exception) { - console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); - status = false; - } - return status; -} - -// Compute reference location cell to particle -template -bool mpm::discontinuity_point::compute_reference_location() noexcept { - // Set status of compute reference location - bool status = false; - // Compute local coordinates - Eigen::Matrix xi; - // Check if the point is in cell - if (cell_ != nullptr && cell_->is_point_in_cell(this->coordinates_, &xi)) { - this->xi_ = xi; - status = true; - } - - return status; -} - -//! Locate points in a cell -template -void mpm::discontinuity_point::locate_discontinuity_mesh( - Vector>& cells, Map>& map_cells) noexcept { - - // Check the current cell if it is not invalid - if (cell_id() != std::numeric_limits::max()) { - // If a cell id is present, but not a cell locate the cell from map - if (!cell_ptr()) assign_cell(map_cells[cell_id()]); - if (compute_reference_location()) return; - - // Check if discontinuity point is in any of its nearest neighbours - const auto neighbours = map_cells[cell_id()]->neighbours(); - Eigen::Matrix xi; - for (auto neighbour : neighbours) { - if (map_cells[neighbour]->is_point_in_cell(coordinates_, &xi)) { - assign_cell_xi(map_cells[neighbour], xi); - return; - } - } - } -#pragma omp parallel for schedule(runtime) - for (auto citr = cells.cbegin(); citr != cells.cend(); ++citr) { - // Check if particle is already found, if so don't run for other cells - // Check if co-ordinates is within the cell, if true - // add particle to cell - Eigen::Matrix xi; - if ((*citr)->is_point_in_cell(coordinates(), &xi)) { - assign_cell_xi(*citr, xi); - } - } -} - -// Compute updated position of the particle -template -void mpm::discontinuity_point::compute_updated_position( - double dt) noexcept { - // Check if point has a valid cell ptr - if (cell_ == nullptr) return; - // Get interpolated nodal velocity - Eigen::Matrix nodal_velocity = - Eigen::Matrix::Zero(); - const double tolerance = 1.E-16; - unsigned int phase = 0; - // need to do, points move with which side - int move_direction = -1; - for (unsigned i = 0; i < nodes_.size(); ++i) { - if (nodes_[i]->discontinuity_enrich()) { - double nodal_mass = - nodes_[i]->mass(phase) - - nodes_[i]->discontinuity_property("mass_enrich", 1)(0, 0); - if (nodal_mass < tolerance) continue; - - nodal_velocity += - shapefn_[i] * - (nodes_[i]->momentum(phase) - - nodes_[i]->discontinuity_property("momenta_enrich", 3)) / - nodal_mass; - } else { - double nodal_mass = nodes_[i]->mass(phase); - if (nodal_mass < tolerance) continue; - nodal_velocity += shapefn_[i] * nodes_[i]->momentum(phase) / nodal_mass; - } - } - // New position current position + velocity * dt - this->coordinates_ += nodal_velocity * dt; -} - -// Compute updated position of the particle -template -void mpm::discontinuity_point::compute_shapefn() noexcept { - // Check if point has a valid cell ptr - if (cell_ == nullptr) return; - // Get element ptr of a cell - const auto element = cell_->element_ptr(); - - // Zero matrix - Eigen::Matrix zero = Eigen::Matrix::Zero(); - - // Compute shape function of the point - //! Size of particle in natural coordinates - Eigen::Matrix natural_size_; - natural_size_.setZero(); - shapefn_ = element->shapefn(this->xi_, natural_size_, zero); -} //! Locate points in a cell template void mpm::DiscontinuityBase::locate_discontinuity_mesh( diff --git a/include/xmpm/discontinuity_base_point.tcc b/include/xmpm/discontinuity_base_point.tcc new file mode 100644 index 000000000..95c30ca94 --- /dev/null +++ b/include/xmpm/discontinuity_base_point.tcc @@ -0,0 +1,164 @@ +// Assign a cell to particle +template +bool mpm::discontinuity_point::assign_cell_xi( + const std::shared_ptr>& cellptr, + const Eigen::Matrix& xi) { + bool status = true; + try { + // Assign cell to the new cell ptr, if point can be found in new cell + if (cellptr != nullptr) { + + cell_ = cellptr; + cell_id_ = cellptr->id(); + nodes_ = cell_->nodes(); + // assign discontinuity_enrich + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->assign_discontinuity_enrich(true); + // Assign the reference location of particle + bool xi_nan = false; + + // Check if point is within the cell + for (unsigned i = 0; i < xi.size(); ++i) + if (xi(i) < -1. || xi(i) > 1. || std::isnan(xi(i))) xi_nan = true; + + if (xi_nan == false) + this->xi_ = xi; + else + return false; + } else { + console_->warn("Points of discontinuity cannot be found in cell!"); + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +// Assign a cell to point +template +bool mpm::discontinuity_point::assign_cell( + const std::shared_ptr>& cellptr) { + bool status = true; + try { + Eigen::Matrix xi; + // Assign cell to the new cell ptr, if point can be found in new cell + if (cellptr->is_point_in_cell(this->coordinates_, &xi)) { + + cell_ = cellptr; + cell_id_ = cellptr->id(); + nodes_ = cell_->nodes(); + // assign discontinuity_enrich + for (unsigned i = 0; i < nodes_.size(); ++i) + nodes_[i]->assign_discontinuity_enrich(true); + } else { + console_->warn("Points of discontinuity cannot be found in cell!"); + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} + +// Compute reference location cell to particle +template +bool mpm::discontinuity_point::compute_reference_location() noexcept { + // Set status of compute reference location + bool status = false; + // Compute local coordinates + Eigen::Matrix xi; + // Check if the point is in cell + if (cell_ != nullptr && cell_->is_point_in_cell(this->coordinates_, &xi)) { + this->xi_ = xi; + status = true; + } + + return status; +} + +//! Locate points in a cell +template +void mpm::discontinuity_point::locate_discontinuity_mesh( + Vector>& cells, Map>& map_cells) noexcept { + + // Check the current cell if it is not invalid + if (cell_id() != std::numeric_limits::max()) { + // If a cell id is present, but not a cell locate the cell from map + if (!cell_ptr()) assign_cell(map_cells[cell_id()]); + if (compute_reference_location()) return; + + // Check if discontinuity point is in any of its nearest neighbours + const auto neighbours = map_cells[cell_id()]->neighbours(); + Eigen::Matrix xi; + for (auto neighbour : neighbours) { + if (map_cells[neighbour]->is_point_in_cell(coordinates_, &xi)) { + assign_cell_xi(map_cells[neighbour], xi); + return; + } + } + } +#pragma omp parallel for schedule(runtime) + for (auto citr = cells.cbegin(); citr != cells.cend(); ++citr) { + // Check if particle is already found, if so don't run for other cells + // Check if co-ordinates is within the cell, if true + // add particle to cell + Eigen::Matrix xi; + if ((*citr)->is_point_in_cell(coordinates(), &xi)) { + assign_cell_xi(*citr, xi); + } + } +} + +// Compute updated position of the particle +template +void mpm::discontinuity_point::compute_updated_position( + double dt) noexcept { + // Check if point has a valid cell ptr + if (cell_ == nullptr) return; + // Get interpolated nodal velocity + Eigen::Matrix nodal_velocity = + Eigen::Matrix::Zero(); + const double tolerance = 1.E-16; + unsigned int phase = 0; + // need to do, points move with which side + int move_direction = -1; + for (unsigned i = 0; i < nodes_.size(); ++i) { + if (nodes_[i]->discontinuity_enrich()) { + double nodal_mass = + nodes_[i]->mass(phase) - + nodes_[i]->discontinuity_property("mass_enrich", 1)(0, 0); + if (nodal_mass < tolerance) continue; + + nodal_velocity += + shapefn_[i] * + (nodes_[i]->momentum(phase) - + nodes_[i]->discontinuity_property("momenta_enrich", 3)) / + nodal_mass; + } else { + double nodal_mass = nodes_[i]->mass(phase); + if (nodal_mass < tolerance) continue; + nodal_velocity += shapefn_[i] * nodes_[i]->momentum(phase) / nodal_mass; + } + } + // New position current position + velocity * dt + this->coordinates_ += nodal_velocity * dt; +} + +// Compute updated position of the particle +template +void mpm::discontinuity_point::compute_shapefn() noexcept { + // Check if point has a valid cell ptr + if (cell_ == nullptr) return; + // Get element ptr of a cell + const auto element = cell_->element_ptr(); + + // Zero matrix + Eigen::Matrix zero = Eigen::Matrix::Zero(); + + // Compute shape function of the point + //! Size of particle in natural coordinates + Eigen::Matrix natural_size_; + natural_size_.setZero(); + shapefn_ = element->shapefn(this->xi_, natural_size_, zero); +} \ No newline at end of file From 8152840917060e9b031ddd1d217177a19a60f9cf Mon Sep 17 00:00:00 2001 From: yong liang Date: Sun, 16 Aug 2020 19:24:35 -0700 Subject: [PATCH 38/91] :pencil::hammer::construction:clean up particleXMPM class --- include/mesh.tcc | 15 +++-- include/node.h | 8 ++- include/node_xmpm.tcc | 12 ++-- include/particles/particle_xmpm.h | 67 +++++++++----------- include/particles/particle_xmpm.tcc | 34 ++++++---- include/solvers/xmpm_explicit.tcc | 33 ++++++---- include/xmpm/discontinuity_3d.h | 21 +++---- include/xmpm/discontinuity_3d.tcc | 97 ++++++++++++++--------------- include/xmpm/discontinuity_base.h | 31 ++++----- 9 files changed, 163 insertions(+), 155 deletions(-) diff --git a/include/mesh.tcc b/include/mesh.tcc index 431bd8c18..ee0e794dd 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -2026,10 +2026,10 @@ void mpm::Mesh::compute_shapefn_discontinuity() { } } - // compute the normal vector of enriched nodes at the discontinuity +// compute the normal vector of enriched nodes at the discontinuity template void mpm::Mesh::compute_normal_vector_discontinuity() { - //need to set + // need to set unsigned discontinuity_id = 0; auto discontinuity = discontinuities_[discontinuity_id]; @@ -2037,13 +2037,12 @@ void mpm::Mesh::compute_normal_vector_discontinuity() { VectorDim normal; normal.setZero(); -for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) - { - - discontinuity->compute_normal((*nitr)->coordinates(), - normal); + for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { + + discontinuity->compute_normal((*nitr)->coordinates(), normal); nodal_properties_->assign_property("normal_unit_vectors_discontinuity", - (*nitr)->discontinuity_prop_id(), 0, normal, Tdim); + (*nitr)->discontinuity_prop_id(), 0, + normal, Tdim); } } diff --git a/include/node.h b/include/node.h index f42f66e4e..c268c6dbd 100644 --- a/include/node.h +++ b/include/node.h @@ -309,10 +309,12 @@ class Node : public NodeBase { //! \param[in] dt Time-step void self_contact_discontinuity(double dt) noexcept override; - //! Return the discontinuity_prop_id - virtual unsigned discontinuity_prop_id() const noexcept override{return discontinuity_prop_id_;}; + //! Return the discontinuity_prop_id + virtual unsigned discontinuity_prop_id() const noexcept override { + return discontinuity_prop_id_; + }; - //! Compute normal direction of each enrich node + //! Compute normal direction of each enrich node void compute_normal_vector() noexcept override; private: diff --git a/include/node_xmpm.tcc b/include/node_xmpm.tcc index 2394b0169..2e52633aa 100644 --- a/include/node_xmpm.tcc +++ b/include/node_xmpm.tcc @@ -54,9 +54,9 @@ bool mpm::Node::intergrate_momentum_discontinuity( // when velocity is set. this->apply_velocity_constraints_discontinuity(); - //need to be done + // need to be done Eigen::Matrix normal{0.44721359474414313, 0, - 0.89442719147920724}; + 0.89442719147920724}; property_handle_->assign_property("normal_unit_vectors_discontinuity", discontinuity_prop_id_, 0, normal, Tdim); @@ -206,9 +206,7 @@ void mpm::Node::self_contact_discontinuity( } } - //! Compute normal direction of each enrich node - //! Apply velocity constraints +//! Compute normal direction of each enrich node +//! Apply velocity constraints template -void mpm::Node::compute_normal_vector() noexcept { - - } \ No newline at end of file +void mpm::Node::compute_normal_vector() noexcept {} \ No newline at end of file diff --git a/include/particles/particle_xmpm.h b/include/particles/particle_xmpm.h index dfcc4e37c..0cd3dd109 100644 --- a/include/particles/particle_xmpm.h +++ b/include/particles/particle_xmpm.h @@ -14,18 +14,15 @@ namespace mpm { //! ParticleXMPM class -//! \brief Base class that stores the information about particles -//! \details ParticleXMPM class: id_ and coordinates. -//! \tparam Tdim Dimension +//! \brief ParticleXMPM class derived from particle class, stores the +//! information for XMPMExplicit solver \details ParticleXMPM class: id_ and +//! coordinates. \tparam Tdim Dimension template class ParticleXMPM : public Particle { public: //! Define a vector of size dimension using VectorDim = Eigen::Matrix; - //! Define DOFs - static const unsigned Tdof = (Tdim == 1) ? 1 : 3 * (Tdim - 1); - //! Construct a particle with id and coordinates //! \param[in] id Particle id //! \param[in] coord coordinates of the particle @@ -46,7 +43,7 @@ class ParticleXMPM : public Particle { //! Delete assignment operator ParticleXMPM& operator=(const ParticleXMPM&) = delete; - //! Initialise properties + //! Initialise properties void initialise() override; //! Map particle mass and momentum to nodes @@ -65,14 +62,9 @@ class ParticleXMPM : public Particle { void compute_updated_position(double dt, bool velocity_update = false) noexcept override; - protected: - //! Initialise particle material container - //! \details This function allocate memory and initialise the material related - //! containers according to the particle phase, i.e. solid or fluid particle - //! has phase_size = 1, whereas two-phase (solid-fluid) or three-phase - //! (solid-water-air) particle have phase_size = 2 and 3, respectively. - //! \param[in] phase_size The material phase size - void initialise_material(unsigned phase_size = 1); + //! Compute strain + //! \param[in] dt Analysis time step + void compute_strain(double dt) noexcept override; private: //! Compute strain rate @@ -81,10 +73,13 @@ class ParticleXMPM : public Particle { //! \retval strain rate at particle inside a cell inline Eigen::Matrix compute_strain_rate( const Eigen::MatrixXd& dn_dx, unsigned phase) noexcept; - //! set the level set function values + + //! Assign the level set function values + //! \param[in] phivalue The level set values void assign_levelsetphi(const double phivalue) { levelset_phi_ = phivalue; }; - //! return 1 if x > 0, -1 if x < 0 and 0 if x = 0 + //! Return 1 if x > 0, -1 if x < 0 and 0 if x = 0 + //! \param[in] x double value inline double sgn(double x) noexcept { return (x > 0) ? 1. : ((x < 0) ? -1. : 0); }; @@ -119,44 +114,44 @@ class ParticleXMPM : public Particle { //! Volume using Particle::volume_; //! Size of particle - using Particle:: size_; + using Particle::size_; //! Size of particle in natural coordinates - using Particle:: natural_size_; + using Particle::natural_size_; //! Stresses - using Particle:: stress_; + using Particle::stress_; //! Strains - using Particle:: strain_; + using Particle::strain_; //! dvolumetric strain using Particle::dvolumetric_strain_; //! Volumetric strain at centroid using Particle::volumetric_strain_centroid_; //! Strain rate - using Particle:: strain_rate_; + using Particle::strain_rate_; //! dstrains - using Particle:: dstrain_; + using Particle::dstrain_; //! Velocity - using Particle:: velocity_; + using Particle::velocity_; //! Displacement - using Particle:: displacement_; + using Particle::displacement_; //! Particle velocity constraints - using Particle:: particle_velocity_constraints_; + using Particle::particle_velocity_constraints_; //! Set traction - using Particle:: set_traction_; + using Particle::set_traction_; //! Surface Traction (given as a stress; force/area) - using Particle:: traction_; + using Particle::traction_; //! Shape functions - using Particle:: shapefn_; + using Particle::shapefn_; //! dN/dX - using Particle:: dn_dx_; + using Particle::dn_dx_; //! dN/dX at cell centroid - using Particle:: dn_dx_centroid_; + using Particle::dn_dx_centroid_; //! Logger - using Particle:: console_; + using Particle::console_; //! Map of vector properties - using Particle:: properties_; - -private: - //! level set values for discontinuity + using Particle::properties_; + + private: + //! level set value: phi for discontinuity double levelset_phi_{0.}; }; // ParticleXMPM class } // namespace mpm diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index ea8a24a4e..c8f906992 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -22,19 +22,13 @@ mpm::ParticleXMPM::ParticleXMPM(Index id, const VectorDim& coord, console_ = std::make_unique(logger, mpm::stdout_sink); } - - - // Initialise particle properties template void mpm::ParticleXMPM::initialise() { levelset_phi_ = 0.; - - // Initialize vector data properties - this->properties_["levelset"] = [&]() { VectorDim levelset{levelset_phi_,0,0};return levelset; }; + }; } - //! Map particle mass and momentum to nodes template void mpm::ParticleXMPM::map_mass_momentum_to_nodes() noexcept { @@ -60,8 +54,6 @@ void mpm::ParticleXMPM::map_mass_momentum_to_nodes() noexcept { } } - - // Compute strain rate of the particle template <> inline Eigen::Matrix mpm::ParticleXMPM<3>::compute_strain_rate( @@ -71,6 +63,7 @@ inline Eigen::Matrix mpm::ParticleXMPM<3>::compute_strain_rate( const double tolerance = 1.E-16; Eigen::Vector3d vel; vel.setZero(); + // Compute corresponding nodal velocity for (unsigned i = 0; i < this->nodes_.size(); ++i) { if (nodes_[i]->discontinuity_enrich()) { double nodal_mass = @@ -103,6 +96,25 @@ inline Eigen::Matrix mpm::ParticleXMPM<3>::compute_strain_rate( return strain_rate; } +// Compute strain of the particle +template +void mpm::ParticleXMPM::compute_strain(double dt) noexcept { + // Assign strain rate + strain_rate_ = this->compute_strain_rate(dn_dx_, mpm::ParticlePhase::Solid); + // Update dstrain + dstrain_ = strain_rate_ * dt; + // Update strain + strain_ += dstrain_; + + // Compute at centroid + // Strain rate for reduced integration + const Eigen::Matrix strain_rate_centroid = + this->compute_strain_rate(dn_dx_centroid_, mpm::ParticlePhase::Solid); + + // Assign volumetric strain at centroid + dvolumetric_strain_ = dt * strain_rate_centroid.head(Tdim).sum(); + volumetric_strain_centroid_ += dvolumetric_strain_; +} //! Map body force template @@ -179,8 +191,6 @@ inline void mpm::ParticleXMPM<3>::map_internal_force() noexcept { } } - - // Compute updated position of the particle template void mpm::ParticleXMPM::compute_updated_position( @@ -255,5 +265,3 @@ void mpm::ParticleXMPM::compute_updated_position( // Update displacement (displacement is initialized from zero) this->displacement_ += nodal_velocity * dt; } - - diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index 4204cac67..c6aa9a239 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -170,18 +170,23 @@ bool mpm::XMPMExplicit::solve() { std::placeholders::_1)); } if (discontinuity_) { + // locate points of discontinuity mesh_->locate_discontinuity_mesh(); + // Iterate over each points to compute shapefn mesh_->compute_shapefn_discontinuity(); + // obtain the normal direction of each enrich nodes mesh_->compute_normal_vector_discontinuity(); - mesh_->iterate_over_nodes_predicate( - std::bind(&mpm::NodeBase::compute_normal_vector, - std::placeholders::_1), - std::bind(&mpm::NodeBase::discontinuity_enrich, std::placeholders::_1)); + + // + // mesh_->iterate_over_nodes_predicate( + // std::bind(&mpm::NodeBase::compute_normal_vector, + // std::placeholders::_1), + // std::bind(&mpm::NodeBase::discontinuity_enrich, + // std::placeholders::_1)); } - // Assign mass and momentum to nodes mesh_->iterate_over_particles( @@ -381,24 +386,26 @@ bool mpm::XMPMExplicit::initialise_discontinuities() { // Create a new discontinuity surface from JSON object auto discontinuity = - Factory, unsigned, const Json&>::instance()->create( - discontunity_type, std::move(discontinuity_id), - discontinuity_props); + Factory, unsigned, + const Json&>::instance() + ->create(discontunity_type, std::move(discontinuity_id), + discontinuity_props); - // Get discontinuity input type + // Get discontinuity input type auto io_type = discontinuity_props["io_type"].template get(); // discontinuity file - std::string discontinuity_file = - io_->file_name(discontinuity_props["file"].template get()); + std::string discontinuity_file = io_->file_name( + discontinuity_props["file"].template get()); // Create a mesh reader auto discontunity_io = Factory>::instance()->create(io_type); // Create points and cells from file - discontinuity->initialize(discontunity_io->read_mesh_nodes(discontinuity_file), - discontunity_io->read_mesh_cells(discontinuity_file)); + discontinuity->initialize( + discontunity_io->read_mesh_nodes(discontinuity_file), + discontunity_io->read_mesh_cells(discontinuity_file)); // Add discontinuity to list auto result = discontinuities_.insert( std::make_pair(discontinuity_id, discontinuity)); diff --git a/include/xmpm/discontinuity_3d.h b/include/xmpm/discontinuity_3d.h index ffe30abcd..ced6331d0 100644 --- a/include/xmpm/discontinuity_3d.h +++ b/include/xmpm/discontinuity_3d.h @@ -18,29 +18,28 @@ class Discontinuity3D : public DiscontinuityBase { Discontinuity3D(unsigned id, const Json& discontinuity_props); // initialization - virtual bool initialize( - const std::vector& coordinates, - const std::vector>& pointsets); + virtual bool initialize(const std::vector& points, + const std::vector>& cells); //! create elements from file - virtual bool create_elements( - const std::vector>& elements) override; + virtual bool create_areas( + const std::vector>& cells) override; // initialize the center and normal of the triangular elements bool initialize_center_normal(); // return the cross product of ab and bc VectorDim three_cross_product(const VectorDim& a, const VectorDim& b, - const VectorDim& c); + const VectorDim& c); // return the levelset values of each doordinates //! \param[in] the vector of the coordinates - void compute_levelset(const std::vector& coordinates, - std::vector& phi_list) override; + void compute_levelset(const std::vector& coordinates, + std::vector& phi_list) override; // return the normal vectors of given coordinates //! \param[in] the coordinates - void compute_normal( - const VectorDim& coordinates, VectorDim& normal_vector) override; + void compute_normal(const VectorDim& coordinates, + VectorDim& normal_vector) override; protected: using mpm::DiscontinuityBase::points_; @@ -53,7 +52,7 @@ class Discontinuity3D : public DiscontinuityBase { private: // vector of elements - std::vector> elements_; + std::vector> elements_; // number of elements //delete mpm::Index numelement_; diff --git a/include/xmpm/discontinuity_3d.tcc b/include/xmpm/discontinuity_3d.tcc index 19d69f095..e89757641 100644 --- a/include/xmpm/discontinuity_3d.tcc +++ b/include/xmpm/discontinuity_3d.tcc @@ -1,7 +1,7 @@ template mpm::Discontinuity3D::Discontinuity3D(unsigned id, const Json& discontinuity_props) - :DiscontinuityBase(id, discontinuity_props) { + : DiscontinuityBase(id, discontinuity_props) { numelement_ = 0; try { @@ -17,49 +17,49 @@ mpm::Discontinuity3D::Discontinuity3D(unsigned id, } } - // initialization - template - bool mpm::Discontinuity3D::initialize( - const std::vector& coordinates, - const std::vector>& pointsets) { - bool status = true; - // Create points from file - bool point_status = this->create_points(coordinates); - if (!point_status) { - status = false; - throw std::runtime_error( - "Addition of points in discontinuity to mesh failed"); - } - // Create elements from file - bool element_status = create_elements(pointsets); - if (!element_status) { - status = false; - throw std::runtime_error( - "Addition of elements in discontinuity to mesh failed"); - } +// initialization +template +bool mpm::Discontinuity3D::initialize( + const std::vector& points, + const std::vector>& cells) { + bool status = true; + // Create points from file + bool point_status = this->create_points(points); + if (!point_status) { + status = false; + throw std::runtime_error( + "Addition of points in discontinuity to mesh failed"); + } + // Create elements from file + bool element_status = create_areas(cells); + if (!element_status) { + status = false; + throw std::runtime_error( + "Addition of elements in discontinuity to mesh failed"); + } - bool normal_status = initialize_center_normal(); - if (!normal_status) { - status = false; - throw std::runtime_error( - "initialized the center and normal of the discontunity failed"); - } - return status; - }; + bool normal_status = initialize_center_normal(); + if (!normal_status) { + status = false; + throw std::runtime_error( + "initialized the center and normal of the discontunity failed"); + } + return status; +}; //! create elements from file template -bool mpm::Discontinuity3D::create_elements( - const std::vector>& elements) { +bool mpm::Discontinuity3D::create_areas( + const std::vector>& cells) { bool status = true; try { // Check if elements is empty - if (elements.empty()) throw std::runtime_error("List of elements is empty"); + if (cells.empty()) throw std::runtime_error("List of elements is empty"); // Iterate over all elements - for (const auto& points : elements) { + for (const auto& points : cells) { - mpm::discontinuity_element element(points); + mpm::discontinuity_area element(points); elements_.emplace_back(element); // } @@ -93,8 +93,8 @@ bool mpm::Discontinuity3D<3>::initialize_center_normal() { // the normal of the element normal = three_cross_product(points_[points[0]].coordinates(), - points_[points[1]].coordinates(), - points_[points[2]].coordinates()); + points_[points[1]].coordinates(), + points_[points[2]].coordinates()); double det = std::sqrt(normal[0] * normal[0] + normal[1] * normal[1] + normal[2] * normal[2]); normal = 1.0 / det * normal; @@ -148,18 +148,17 @@ void mpm::Discontinuity3D::compute_levelset( // return the normal vectors of given coordinates //! \param[in] the coordinates template -void mpm::Discontinuity3D::compute_normal( - const VectorDim& coordinates, VectorDim& normal_vector) { - // find the nearest distance from particle to cell: need to do by global - // searching and local searching - double distance = std::numeric_limits::max(); - for (const auto& element : elements_) { - double Vertical_distance = - element.Vertical_distance(coordinates); // Vertical_distance(coor); - if(std::abs(distance) > std::abs(Vertical_distance)) - { - distance = Vertical_distance; - normal_vector = element.normal(); - } +void mpm::Discontinuity3D::compute_normal(const VectorDim& coordinates, + VectorDim& normal_vector) { + // find the nearest distance from particle to cell: need to do by global + // searching and local searching + double distance = std::numeric_limits::max(); + for (const auto& element : elements_) { + double Vertical_distance = + element.Vertical_distance(coordinates); // Vertical_distance(coor); + if (std::abs(distance) > std::abs(Vertical_distance)) { + distance = Vertical_distance; + normal_vector = element.normal(); } + } } \ No newline at end of file diff --git a/include/xmpm/discontinuity_base.h b/include/xmpm/discontinuity_base.h index 61e36ea2b..a496a26b4 100644 --- a/include/xmpm/discontinuity_base.h +++ b/include/xmpm/discontinuity_base.h @@ -16,7 +16,6 @@ struct discontinuity_point; //! class for to describe the discontinuous surface //! \brief -//! \details nodes, lines and areas //! \tparam Tdim Dimension template class DiscontinuityBase { @@ -25,7 +24,8 @@ class DiscontinuityBase { using VectorDim = Eigen::Matrix; //! Constructor with id - //! \param[in] discontinuity_properties discontinuity properties + //! \param[in] discontinuity id + //! \param[in] discontinuity properties json DiscontinuityBase(unsigned id, const Json& discontinuity_props); //! Destructor @@ -38,16 +38,17 @@ class DiscontinuityBase { DiscontinuityBase& operator=(const DiscontinuityBase&) = delete; // initialization + //! \param[in] the coordinates of all points + //! \param[in] the point index of each areas virtual bool initialize( - const std::vector& coordinates, - const std::vector>& pointsets) = 0; + const std::vector& points, + const std::vector>& cells) = 0; //! create points from file - bool create_points(const std::vector& coordinates); + bool create_points(const std::vector& points); //! create elements from file - virtual bool create_elements( - const std::vector>& elements) { + virtual bool create_areas(const std::vector>& cells) { return true; }; @@ -57,9 +58,9 @@ class DiscontinuityBase { std::vector& phi_list) = 0; // return the normal vectors of given coordinates -//! \param[in] the coordinates -virtual void compute_normal( - const VectorDim& coordinates, VectorDim& normal_vector) = 0; + //! \param[in] the coordinates + virtual void compute_normal(const VectorDim& coordinates, + VectorDim& normal_vector) = 0; // return self_contact bool self_contact() { return self_contact_; }; @@ -90,7 +91,7 @@ virtual void compute_normal( std::vector> points_; // number of points - mpm::Index numpoint_; //delete + mpm::Index numpoint_; // delete // self-contact bool self_contact_{true}; @@ -174,12 +175,12 @@ struct discontinuity_line { }; template -struct discontinuity_element { +struct discontinuity_area { public: //! Define a vector of size dimension using VectorDim = Eigen::Matrix; - discontinuity_element(const std::vector& points) { + discontinuity_area(const std::vector& points) { for (int i = 0; i < points.size(); ++i) points_[i] = points[i]; } //! Return points indices @@ -188,9 +189,9 @@ struct discontinuity_element { inline void set_center(VectorDim& center) { center_ = center; } inline void set_normal(VectorDim& normal) { normal_ = normal; } - + //! Reture normal of the elements - VectorDim normal() const {return normal_;} + VectorDim normal() const { return normal_; } double Vertical_distance(const VectorDim& coor) const { return (coor[0] - center_[0]) * normal_[0] + From 71179ea91542a67d9f4866735f21a48eed06c0ba Mon Sep 17 00:00:00 2001 From: yong liang Date: Sun, 16 Aug 2020 21:12:30 -0700 Subject: [PATCH 39/91] :pencil::hammer::construction:clean the discontinuity base class --- include/node.h | 5 +- include/node_base.h | 4 +- include/node_xmpm.tcc | 28 ++++--- include/particles/particle_xmpm.tcc | 1 - include/xmpm/discontinuity_3d.h | 12 +-- include/xmpm/discontinuity_3d.tcc | 43 ++++++----- include/xmpm/discontinuity_base.h | 91 ++++++++++++++--------- include/xmpm/discontinuity_base.tcc | 6 +- include/xmpm/discontinuity_base_point.tcc | 7 +- 9 files changed, 105 insertions(+), 92 deletions(-) diff --git a/include/node.h b/include/node.h index c268c6dbd..1a15ef69a 100644 --- a/include/node.h +++ b/include/node.h @@ -275,10 +275,11 @@ class Node : public NodeBase { void compute_multimaterial_normal_unit_vector() override; //! Assign whether the node is enriched - //! \param[in] discontinuity_enrich: true or false + //! \param[in] discontinuity discontinuity_enrich: true or false void assign_discontinuity_enrich(bool discontinuity) { discontinuity_enrich_ = discontinuity; }; + //! Return whether the node is enriched bool discontinuity_enrich() const { return discontinuity_enrich_; }; @@ -314,7 +315,7 @@ class Node : public NodeBase { return discontinuity_prop_id_; }; - //! Compute normal direction of each enrich node + //! Compute normal direction for discontinuity void compute_normal_vector() noexcept override; private: diff --git a/include/node_base.h b/include/node_base.h index 194b337d0..c22a448a0 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -270,7 +270,7 @@ class NodeBase { const std::string& property, unsigned nprops = 1) noexcept = 0; //! Assign whether the node is enriched - //! \param[in] discontinuity_enrich: true or false + //! \param[in] discontinuity discontinuity_enrich: true or false virtual void assign_discontinuity_enrich(bool discontinuity) = 0; //! Return whether the node is enriched @@ -300,7 +300,7 @@ class NodeBase { //! Return the discontinuity_prop_id virtual unsigned discontinuity_prop_id() const noexcept = 0; - //! Compute normal direction of each enrich node + //! Compute normal direction for discontinuity virtual void compute_normal_vector() noexcept = 0; }; // NodeBase class } // namespace mpm diff --git a/include/node_xmpm.tcc b/include/node_xmpm.tcc index 2e52633aa..609bbf1d3 100644 --- a/include/node_xmpm.tcc +++ b/include/node_xmpm.tcc @@ -104,7 +104,7 @@ void mpm::Nodeassign_property( "external_force_enrich", discontinuity_prop_id_ * Tdim + direction, 0, momentum, 1); - } else { // need to do + } else { // need to be done // Velocity constraints on general boundaries // Compute inverse rotation matrix const Eigen::Matrix inverse_rotation_matrix = @@ -129,10 +129,11 @@ void mpm::Node::self_contact_discontinuity( double dt) noexcept { if (!discontinuity_enrich_) return; - + // single phase for solid unsigned phase = 0; const double tolerance = 1.0E-15; - + + //obtain the enriched values of enriched nodes Eigen::Matrix mass_enrich = property_handle_->property("mass_enrich", discontinuity_prop_id_, 0, 1); Eigen::Matrix momenta_enrich = property_handle_->property( @@ -158,13 +159,13 @@ void mpm::Node::self_contact_discontinuity( 0) return; - // the contact momentum for sticking contact + // the contact momentum, force vector for sticking contact auto momentum_contact = (mass_enrich(phase) * momentum_.col(phase) - mass_(phase) * momenta_enrich) / mass_(phase); auto force_contact = momentum_contact / dt; - //! friction_coef < 0: move together without slide + // friction_coef < 0: move together without slide // need to be done double friction_coef = 0; @@ -175,33 +176,36 @@ void mpm::Node::self_contact_discontinuity( discontinuity_prop_id_, 0, force_contact.col(phase), Tdim); } else { + //the contact momentum, force value for sticking contact at normal direction double momentum_contact_norm = momentum_contact.col(phase).dot(normal_vector); double force_contact_norm = momentum_contact_norm / dt; - // the maximum frictional contact force - double max_frictional_force = friction_coef * abs(force_contact_norm); + // the maximum friction contact force + double max_friction_force = friction_coef * abs(force_contact_norm); + // the contact momentum, force vector for sticking contact at tangential direction auto momentum_tangential = momentum_contact.col(phase) - momentum_contact_norm * normal_vector; auto force_tangential = momentum_tangential / dt; + //the friction force magnitude double force_tangential_value = force_tangential.norm(); - double frictional_force = force_tangential_value < max_frictional_force + double force_friction = force_tangential_value < max_friction_force ? force_tangential_value - : max_frictional_force; + : max_friction_force; - //! adjust the momentum and force + // adjust the momentum and force property_handle_->update_property( "momenta_enrich", discontinuity_prop_id_, 0, momentum_contact_norm * normal_vector + - frictional_force * force_tangential.col(phase).normalized() * dt, + force_friction * force_tangential.col(phase).normalized() * dt, Tdim); property_handle_->update_property( "external_force_enrich", discontinuity_prop_id_, 0, force_contact_norm * normal_vector + - frictional_force * force_tangential.col(phase).normalized(), + force_friction * force_tangential.col(phase).normalized(), Tdim); } } diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index c8f906992..9ec1411bc 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -26,7 +26,6 @@ mpm::ParticleXMPM::ParticleXMPM(Index id, const VectorDim& coord, template void mpm::ParticleXMPM::initialise() { levelset_phi_ = 0.; - }; } //! Map particle mass and momentum to nodes diff --git a/include/xmpm/discontinuity_3d.h b/include/xmpm/discontinuity_3d.h index ced6331d0..8ec010c2d 100644 --- a/include/xmpm/discontinuity_3d.h +++ b/include/xmpm/discontinuity_3d.h @@ -19,11 +19,11 @@ class Discontinuity3D : public DiscontinuityBase { // initialization virtual bool initialize(const std::vector& points, - const std::vector>& cells); + const std::vector>& surfs); //! create elements from file - virtual bool create_areas( - const std::vector>& cells) override; + virtual bool create_surfaces( + const std::vector>& surfs) override; // initialize the center and normal of the triangular elements bool initialize_center_normal(); @@ -46,16 +46,12 @@ class Discontinuity3D : public DiscontinuityBase { using mpm::DiscontinuityBase::console_; - using mpm::DiscontinuityBase::numpoint_; - using mpm::DiscontinuityBase::friction_coef_; private: // vector of elements - std::vector> elements_; + std::vector> surfaces_; - // number of elements //delete - mpm::Index numelement_; }; } // namespace mpm diff --git a/include/xmpm/discontinuity_3d.tcc b/include/xmpm/discontinuity_3d.tcc index e89757641..903093626 100644 --- a/include/xmpm/discontinuity_3d.tcc +++ b/include/xmpm/discontinuity_3d.tcc @@ -3,7 +3,6 @@ mpm::Discontinuity3D::Discontinuity3D(unsigned id, const Json& discontinuity_props) : DiscontinuityBase(id, discontinuity_props) { - numelement_ = 0; try { // assign friction_coef_ if it's given in input file if (discontinuity_props.contains("friction_coefficient")) @@ -21,7 +20,7 @@ mpm::Discontinuity3D::Discontinuity3D(unsigned id, template bool mpm::Discontinuity3D::initialize( const std::vector& points, - const std::vector>& cells) { + const std::vector>& surfs) { bool status = true; // Create points from file bool point_status = this->create_points(points); @@ -31,7 +30,7 @@ bool mpm::Discontinuity3D::initialize( "Addition of points in discontinuity to mesh failed"); } // Create elements from file - bool element_status = create_areas(cells); + bool element_status = create_surfaces(surfs); if (!element_status) { status = false; throw std::runtime_error( @@ -49,19 +48,19 @@ bool mpm::Discontinuity3D::initialize( //! create elements from file template -bool mpm::Discontinuity3D::create_areas( - const std::vector>& cells) { +bool mpm::Discontinuity3D::create_surfaces( + const std::vector>& surfs) { bool status = true; try { // Check if elements is empty - if (cells.empty()) throw std::runtime_error("List of elements is empty"); + if (surfs.empty()) throw std::runtime_error("List of elements is empty"); // Iterate over all elements - for (const auto& points : cells) { + for (const auto& points : surfs) { - mpm::discontinuity_area element(points); + mpm::discontinuity_surface element(points); - elements_.emplace_back(element); // + surfaces_.emplace_back(element); // } } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); @@ -79,7 +78,7 @@ bool mpm::Discontinuity3D<3>::initialize_center_normal() { VectorDim normal; Eigen::Matrix points; - for (auto& element : elements_) { + for (auto& element : surfaces_) { points = element.points(); // the center of the element @@ -89,7 +88,7 @@ bool mpm::Discontinuity3D<3>::initialize_center_normal() { points_[points[1]].coordinates()[i] + points_[points[2]].coordinates()[i]); - element.set_center(center); + element.assign_center(center); // the normal of the element normal = three_cross_product(points_[points[0]].coordinates(), @@ -99,7 +98,7 @@ bool mpm::Discontinuity3D<3>::initialize_center_normal() { normal[2] * normal[2]); normal = 1.0 / det * normal; - element.set_normal(normal); + element.assign_normal(normal); } } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); @@ -131,12 +130,12 @@ void mpm::Discontinuity3D::compute_levelset( // find the nearest distance from particle to cell: need to do by global // searching and local searching double distance = std::numeric_limits::max(); - for (const auto& element : elements_) { - double Vertical_distance = - element.Vertical_distance(coor); // Vertical_distance(coor); - distance = std::abs(distance) < std::abs(Vertical_distance) + for (const auto& element : surfaces_) { + double vertical_distance = + element.vertical_distance(coor); // vertical_distance(coor); + distance = std::abs(distance) < std::abs(vertical_distance) ? distance - : Vertical_distance; + : vertical_distance; if (!distance) distance = 1e-16; } @@ -153,11 +152,11 @@ void mpm::Discontinuity3D::compute_normal(const VectorDim& coordinates, // find the nearest distance from particle to cell: need to do by global // searching and local searching double distance = std::numeric_limits::max(); - for (const auto& element : elements_) { - double Vertical_distance = - element.Vertical_distance(coordinates); // Vertical_distance(coor); - if (std::abs(distance) > std::abs(Vertical_distance)) { - distance = Vertical_distance; + for (const auto& element : surfaces_) { + double vertical_distance = + element.vertical_distance(coordinates); // vertical_distance(coor); + if (std::abs(distance) > std::abs(vertical_distance)) { + distance = vertical_distance; normal_vector = element.normal(); } } diff --git a/include/xmpm/discontinuity_base.h b/include/xmpm/discontinuity_base.h index a496a26b4..8c625f6e0 100644 --- a/include/xmpm/discontinuity_base.h +++ b/include/xmpm/discontinuity_base.h @@ -14,7 +14,7 @@ namespace mpm { template struct discontinuity_point; -//! class for to describe the discontinuous surface +//! class for describe the discontinuous surface //! \brief //! \tparam Tdim Dimension template @@ -37,49 +37,53 @@ class DiscontinuityBase { //! Delete assignement operator DiscontinuityBase& operator=(const DiscontinuityBase&) = delete; - // initialization + //! initialization //! \param[in] the coordinates of all points - //! \param[in] the point index of each areas + //! \param[in] the point index of each surface virtual bool initialize( const std::vector& points, - const std::vector>& cells) = 0; + const std::vector>& surfs) = 0; //! create points from file + //! \param[in] points the coordinates list of points bool create_points(const std::vector& points); //! create elements from file - virtual bool create_areas(const std::vector>& cells) { + //! \param[in] surfs the point index list of each surface + virtual bool create_surfaces(const std::vector>& surfs) { return true; }; - // return the levelset values of each doordinates - //! \param[in] the vector of the coordinates + // return the levelset values of each coordinates + //! \param[in] coordinates coordinates + //! \param[in] phi_list the reference of phi for all coordinates virtual void compute_levelset(const std::vector& coordinates, std::vector& phi_list) = 0; - // return the normal vectors of given coordinates - //! \param[in] the coordinates + //! compute the normal vectors of coordinates + //! \param[in] coordinates The coordinates + //! \param[in] normal vector the normal vector of the given coordinates virtual void compute_normal(const VectorDim& coordinates, VectorDim& normal_vector) = 0; - // return self_contact - bool self_contact() { return self_contact_; }; + //! return self_contact + bool self_contact() const { return self_contact_; }; - // return the friction coefficient - double friction_coef() { return friction_coef_; }; + //! return the friction coefficient + double friction_coef() const { return friction_coef_; }; - // return the number of the points - mpm::Index npoints() { return points_.size(); }; + //! return the number of the points + mpm::Index npoints() const { return points_.size(); }; - void points_list(std::vector>& points) { - points = points_; - } //! Locate points in a cell - void locate_discontinuity_mesh(Vector>& cells, - Map>& map_cells) noexcept; + //! \param[in] cells vector of cells + //! \param[in] map_cells map of cells + void locate_discontinuity_mesh(const Vector>& cells, + const Map>& map_cells) noexcept; //! Compute updated position - void compute_updated_position(double dt) noexcept; + //! \param[in] dt Time-step + void compute_updated_position(const double dt) noexcept; //! Compute shape function void compute_shapefn() noexcept; @@ -88,24 +92,26 @@ class DiscontinuityBase { //! Logger std::unique_ptr console_; + //! vector of points std::vector> points_; - // number of points - mpm::Index numpoint_; // delete - - // self-contact + //! self-contact bool self_contact_{true}; + //! friction coefficient double friction_coef_; }; // DiscontinuityBase class + +//! struct of discontinuity point template struct discontinuity_point { public: //! Define a vector of size dimension using VectorDim = Eigen::Matrix; + //! construct with coordinate discontinuity_point(const VectorDim& coordinate) { coordinates_ = coordinate; cell_ = nullptr; @@ -114,10 +120,11 @@ struct discontinuity_point { } //! Return coordinates - //! \retval coordinates_ return coordinates of the nodebase + //! \retval return coordinates VectorDim coordinates() const { return coordinates_; } //! Return cell_id + //! \retval return cell_id_ Index cell_id() const { return cell_id_; } //! Assign a cell to point @@ -136,9 +143,11 @@ struct discontinuity_point { //! Compute reference coordinates in a cell bool compute_reference_location() noexcept; - //! Locate points in a cell - void locate_discontinuity_mesh(Vector>& cells, - Map>& map_cells) noexcept; + //! Locate particles in a cell + //! \param[in] cells vector of cells + //! \param[in] map_cells map of cells + void locate_discontinuity_mesh(const Vector>& cells, + const Map>& map_cells) noexcept; //! Compute updated position void compute_updated_position(double dt) noexcept; @@ -155,7 +164,6 @@ struct discontinuity_point { Eigen::VectorXd shapefn_; //! Cell std::shared_ptr> cell_; - //! Reference coordinates (in a cell) Eigen::Matrix xi_; //! Vector of nodal pointers @@ -164,6 +172,7 @@ struct discontinuity_point { std::shared_ptr console_; }; +//! struct of discontinuity line: for 2d, need to be done struct discontinuity_line { public: //! Return points indices @@ -174,26 +183,34 @@ struct discontinuity_line { Eigen::Matrix points_; }; +//! struct of discontinuity surface: triangle template -struct discontinuity_area { +struct discontinuity_surface { public: //! Define a vector of size dimension using VectorDim = Eigen::Matrix; - discontinuity_area(const std::vector& points) { + //! construct with points indices + discontinuity_surface(const std::vector& points) { for (int i = 0; i < points.size(); ++i) points_[i] = points[i]; } //! Return points indices Eigen::Matrix points() const { return points_; } - inline void set_center(VectorDim& center) { center_ = center; } + //! assign the surface center + //! \param[in] center coordinates of the surface center + inline void assign_center(VectorDim& center) { center_ = center; } - inline void set_normal(VectorDim& normal) { normal_ = normal; } + //! assign the surface normal vector + //! \param[in] normal normal vector of the surface + inline void assign_normal(VectorDim& normal) { normal_ = normal; } //! Reture normal of the elements VectorDim normal() const { return normal_; } - double Vertical_distance(const VectorDim& coor) const { + //! Return the vertical distance to the surface + //! \param[in] coor coordinates + double vertical_distance(const VectorDim& coor) const { return (coor[0] - center_[0]) * normal_[0] + (coor[1] - center_[1]) * normal_[1] + (coor[2] - center_[2]) * normal_[2]; @@ -203,10 +220,10 @@ struct discontinuity_area { //! points indices Eigen::Matrix points_; - // the center of the triangular elements + // the center coordinates VectorDim center_; - // the normal of the triangular elements + // the normal vector VectorDim normal_; }; diff --git a/include/xmpm/discontinuity_base.tcc b/include/xmpm/discontinuity_base.tcc index e7a232295..ea76693b9 100644 --- a/include/xmpm/discontinuity_base.tcc +++ b/include/xmpm/discontinuity_base.tcc @@ -3,8 +3,6 @@ template mpm::DiscontinuityBase::DiscontinuityBase( unsigned id, const Json& discontinuity_props) { - numpoint_ = 0; - friction_coef_ = 0; std::string logger = "discontinuity::" + std::to_string(id); @@ -36,8 +34,8 @@ bool mpm::DiscontinuityBase::create_points( } //! Locate points in a cell template -void mpm::DiscontinuityBase::locate_discontinuity_mesh( - Vector>& cells, Map>& map_cells) noexcept { +void mpm::DiscontinuityBase::locate_discontinuity_mesh(const + Vector>& cells, const Map>& map_cells) noexcept { for (auto& point : this->points_) point.locate_discontinuity_mesh(cells, map_cells); } diff --git a/include/xmpm/discontinuity_base_point.tcc b/include/xmpm/discontinuity_base_point.tcc index 95c30ca94..deb921538 100644 --- a/include/xmpm/discontinuity_base_point.tcc +++ b/include/xmpm/discontinuity_base_point.tcc @@ -79,9 +79,8 @@ bool mpm::discontinuity_point::compute_reference_location() noexcept { //! Locate points in a cell template -void mpm::discontinuity_point::locate_discontinuity_mesh( - Vector>& cells, Map>& map_cells) noexcept { - +void mpm::discontinuity_point::locate_discontinuity_mesh(const + Vector>& cells, const Map>& map_cells) noexcept { // Check the current cell if it is not invalid if (cell_id() != std::numeric_limits::max()) { // If a cell id is present, but not a cell locate the cell from map @@ -113,7 +112,7 @@ void mpm::discontinuity_point::locate_discontinuity_mesh( // Compute updated position of the particle template void mpm::discontinuity_point::compute_updated_position( - double dt) noexcept { + const double dt) noexcept { // Check if point has a valid cell ptr if (cell_ == nullptr) return; // Get interpolated nodal velocity From 435dccdfc6e4c817fcd3f047c3375b899f303a7c Mon Sep 17 00:00:00 2001 From: yong liang Date: Sun, 16 Aug 2020 23:01:59 -0700 Subject: [PATCH 40/91] :pencil:clean discontinuity3d class --- include/solvers/xmpm_explicit.tcc | 1 - include/xmpm/discontinuity_3d.h | 34 +++++++++++++++++++------------ include/xmpm/discontinuity_3d.tcc | 13 +++++------- 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index c6aa9a239..32f753fda 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -180,7 +180,6 @@ bool mpm::XMPMExplicit::solve() { // obtain the normal direction of each enrich nodes mesh_->compute_normal_vector_discontinuity(); - // // mesh_->iterate_over_nodes_predicate( // std::bind(&mpm::NodeBase::compute_normal_vector, // std::placeholders::_1), diff --git a/include/xmpm/discontinuity_3d.h b/include/xmpm/discontinuity_3d.h index 8ec010c2d..bb5395866 100644 --- a/include/xmpm/discontinuity_3d.h +++ b/include/xmpm/discontinuity_3d.h @@ -5,7 +5,7 @@ //! MPM namespace namespace mpm { - +//! Discontinuity3D class derived from DiscontinuityBase class for 3D template class Discontinuity3D : public DiscontinuityBase { @@ -14,42 +14,50 @@ class Discontinuity3D : public DiscontinuityBase { using VectorDim = Eigen::Matrix; //! Constructor with id - //! \param[in] discontinuity_properties discontinuity properties + //! \param[in] discontinuity_props discontinuity properties Discontinuity3D(unsigned id, const Json& discontinuity_props); - // initialization + //! initialization + //! \param[in] the coordinates of all points + //! \param[in] the point index of each surface virtual bool initialize(const std::vector& points, const std::vector>& surfs); - + //! create elements from file + //! \param[in] surfs the point index list of each surface virtual bool create_surfaces( const std::vector>& surfs) override; - // initialize the center and normal of the triangular elements + //! initialize the center and normal vector of each surface bool initialize_center_normal(); - // return the cross product of ab and bc + //! return the cross product of ab and bc + //! \param[in] a,b,c coordinates of three points VectorDim three_cross_product(const VectorDim& a, const VectorDim& b, const VectorDim& c); - // return the levelset values of each doordinates - //! \param[in] the vector of the coordinates + // return the levelset values of each coordinates + //! \param[in] coordinates coordinates + //! \param[in] phi_list the reference of phi for all coordinates void compute_levelset(const std::vector& coordinates, std::vector& phi_list) override; - // return the normal vectors of given coordinates - //! \param[in] the coordinates + + //! compute the normal vectors of coordinates + //! \param[in] coordinates The coordinates + //! \param[in] normal vector the normal vector of the given coordinates void compute_normal(const VectorDim& coordinates, VectorDim& normal_vector) override; protected: + //! vector of points using mpm::DiscontinuityBase::points_; - + //! Logger using mpm::DiscontinuityBase::console_; - + //! friction coefficient using mpm::DiscontinuityBase::friction_coef_; private: - // vector of elements + // vector of surfaces std::vector> surfaces_; }; diff --git a/include/xmpm/discontinuity_3d.tcc b/include/xmpm/discontinuity_3d.tcc index 903093626..2868a2d22 100644 --- a/include/xmpm/discontinuity_3d.tcc +++ b/include/xmpm/discontinuity_3d.tcc @@ -41,20 +41,20 @@ bool mpm::Discontinuity3D::initialize( if (!normal_status) { status = false; throw std::runtime_error( - "initialized the center and normal of the discontunity failed"); + "initialization of the center and normal vector of the discontunity failed"); } return status; }; -//! create elements from file +//! create surfaces from file template bool mpm::Discontinuity3D::create_surfaces( const std::vector>& surfs) { bool status = true; try { - // Check if elements is empty - if (surfs.empty()) throw std::runtime_error("List of elements is empty"); + // Check if surfs is empty + if (surfs.empty()) throw std::runtime_error("List of surfaces is empty"); // Iterate over all elements for (const auto& points : surfs) { @@ -111,7 +111,6 @@ bool mpm::Discontinuity3D<3>::initialize_center_normal() { template Eigen::Matrix mpm::Discontinuity3D::three_cross_product( const VectorDim& a, const VectorDim& b, const VectorDim& c) { - VectorDim threecross; threecross[0] = (b[1] - a[1]) * (c[2] - b[2]) - (b[2] - a[2]) * (c[1] - b[1]); threecross[1] = (b[2] - a[2]) * (c[0] - b[0]) - (b[0] - a[0]) * (c[2] - b[2]); @@ -120,7 +119,6 @@ Eigen::Matrix mpm::Discontinuity3D::three_cross_product( } // return the levelset values of each coordinates -//! \param[in] the vector of the coordinates template void mpm::Discontinuity3D::compute_levelset( const std::vector& coordinates, std::vector& phi_list) { @@ -145,11 +143,10 @@ void mpm::Discontinuity3D::compute_levelset( } // return the normal vectors of given coordinates -//! \param[in] the coordinates template void mpm::Discontinuity3D::compute_normal(const VectorDim& coordinates, VectorDim& normal_vector) { - // find the nearest distance from particle to cell: need to do by global + // find the nearest distance from particle to cell: need to do better by global // searching and local searching double distance = std::numeric_limits::max(); for (const auto& element : surfaces_) { From a62c28566883d17963b7c6e70320bf532ec71302 Mon Sep 17 00:00:00 2001 From: yong liang Date: Mon, 17 Aug 2020 07:50:18 -0700 Subject: [PATCH 41/91] :constructuin:assign friction coefficient for nodes --- include/mesh.h | 7 +-- include/mesh.tcc | 7 ++- include/node.tcc | 1 + include/node_xmpm.tcc | 12 +---- include/xmpm/discontinuity_3d.h | 3 ++ include/xmpm/discontinuity_3d.tcc | 47 +++++++++++-------- include/xmpm/discontinuity_base.h | 13 ++++- ...base_point.tcc => discontinuity_point.tcc} | 12 ++++- 8 files changed, 62 insertions(+), 40 deletions(-) rename include/xmpm/{discontinuity_base_point.tcc => discontinuity_point.tcc} (92%) diff --git a/include/mesh.h b/include/mesh.h index fd4f1537f..8bc96338d 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -479,13 +479,14 @@ class Mesh { //! Locate points of discontinuity in a cell void locate_discontinuity_mesh(); - // Update the discontinuity position + //! Update the discontinuity position + //! \param[in] dt Analysis time step void compute_updated_position_discontinuity(double dt); - // Update the discontinuity position + //! Update the discontinuity position void compute_shapefn_discontinuity(); - // compute the normal vector of enriched nodes at the discontinuity + //! compute the normal vector of enriched nodes at the discontinuity void compute_normal_vector_discontinuity(); private: diff --git a/include/mesh.tcc b/include/mesh.tcc index ee0e794dd..7435469a8 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1975,7 +1975,8 @@ void mpm::Mesh::create_nodal_properties_discontinuity() { nodal_properties_->create_property("external_force_enrich", nrows, 1); nodal_properties_->create_property("normal_unit_vectors_discontinuity", nrows, 1); - + nodal_properties_->create_property("friction_coef", + nodes_.size(), 1); // Iterate over all nodes to initialise the property handle in each node // and assign its node id as the prop id in the nodal property data pool for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) @@ -2016,7 +2017,6 @@ void mpm::Mesh::compute_updated_position_discontinuity(double dt) { discontinuity->compute_updated_position(dt); } } - //! compute shape function template void mpm::Mesh::compute_shapefn_discontinuity() { @@ -2029,9 +2029,8 @@ void mpm::Mesh::compute_shapefn_discontinuity() { // compute the normal vector of enriched nodes at the discontinuity template void mpm::Mesh::compute_normal_vector_discontinuity() { - // need to set + // just compute for one discontinuity for now unsigned discontinuity_id = 0; - auto discontinuity = discontinuities_[discontinuity_id]; VectorDim normal; diff --git a/include/node.tcc b/include/node.tcc index ba979d6da..421090f52 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -34,6 +34,7 @@ void mpm::Node::initialise() noexcept { acceleration_.setZero(); status_ = false; material_ids_.clear(); + //mark: need to check discontinuity_enrich_ = true; } diff --git a/include/node_xmpm.tcc b/include/node_xmpm.tcc index 609bbf1d3..9ee058d5f 100644 --- a/include/node_xmpm.tcc +++ b/include/node_xmpm.tcc @@ -54,12 +54,6 @@ bool mpm::Node::intergrate_momentum_discontinuity( // when velocity is set. this->apply_velocity_constraints_discontinuity(); - // need to be done - Eigen::Matrix normal{0.44721359474414313, 0, - 0.89442719147920724}; - property_handle_->assign_property("normal_unit_vectors_discontinuity", - discontinuity_prop_id_, 0, normal, Tdim); - this->self_contact_discontinuity(dt); this->apply_velocity_constraints_discontinuity(); @@ -81,9 +75,6 @@ void mpm::Nodevelocity_(direction, phase) = constraint.second; - // need to do for one direction - this->momentum_(direction, phase) = this->mass(phase) * constraint.second; property_handle_->assign_property( "momenta_enrich", discontinuity_prop_id_ * Tdim + direction, 0, @@ -92,7 +83,6 @@ void mpm::Nodeacceleration_(direction, phase) = 0.; this->internal_force_(direction, phase) = 0; this->external_force_(direction, phase) = 0; @@ -167,7 +157,7 @@ void mpm::Node::self_contact_discontinuity( // friction_coef < 0: move together without slide // need to be done - double friction_coef = 0; + double friction_coef = property_handle_->property("friction_coef", discontinuity_prop_id_, 0, 1)(0,0); if (friction_coef < 0) { property_handle_->update_property("momenta_enrich", discontinuity_prop_id_, diff --git a/include/xmpm/discontinuity_3d.h b/include/xmpm/discontinuity_3d.h index bb5395866..ee8afd464 100644 --- a/include/xmpm/discontinuity_3d.h +++ b/include/xmpm/discontinuity_3d.h @@ -48,6 +48,9 @@ class Discontinuity3D : public DiscontinuityBase { void compute_normal(const VectorDim& coordinates, VectorDim& normal_vector) override; + //! Assign point friction coefficient + void assign_point_friction_coef() noexcept override; + protected: //! vector of points using mpm::DiscontinuityBase::points_; diff --git a/include/xmpm/discontinuity_3d.tcc b/include/xmpm/discontinuity_3d.tcc index 2868a2d22..983af1204 100644 --- a/include/xmpm/discontinuity_3d.tcc +++ b/include/xmpm/discontinuity_3d.tcc @@ -29,12 +29,12 @@ bool mpm::Discontinuity3D::initialize( throw std::runtime_error( "Addition of points in discontinuity to mesh failed"); } - // Create elements from file - bool element_status = create_surfaces(surfs); - if (!element_status) { + // Create surfaces from file + bool surf_status = create_surfaces(surfs); + if (!surf_status) { status = false; throw std::runtime_error( - "Addition of elements in discontinuity to mesh failed"); + "Addition of surfaces in discontinuity to mesh failed"); } bool normal_status = initialize_center_normal(); @@ -43,6 +43,8 @@ bool mpm::Discontinuity3D::initialize( throw std::runtime_error( "initialization of the center and normal vector of the discontunity failed"); } + + this->assign_point_friction_coef(); return status; }; @@ -55,12 +57,12 @@ bool mpm::Discontinuity3D::create_surfaces( try { // Check if surfs is empty if (surfs.empty()) throw std::runtime_error("List of surfaces is empty"); - // Iterate over all elements + // Iterate over all surfaces for (const auto& points : surfs) { - mpm::discontinuity_surface element(points); + mpm::discontinuity_surface surf(points); - surfaces_.emplace_back(element); // + surfaces_.emplace_back(surf); // } } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); @@ -69,7 +71,7 @@ bool mpm::Discontinuity3D::create_surfaces( return status; } -// initialize the center and normal of the elements +// initialize the center and normal of the surfaces template <> bool mpm::Discontinuity3D<3>::initialize_center_normal() { bool status = true; @@ -78,19 +80,19 @@ bool mpm::Discontinuity3D<3>::initialize_center_normal() { VectorDim normal; Eigen::Matrix points; - for (auto& element : surfaces_) { - points = element.points(); + for (auto& surf: surfaces_) { + points = surf.points(); - // the center of the element + // the center of the surfaces for (int i = 0; i < 3; i++) center[i] = 1.0 / 3 * (points_[points[0]].coordinates()[i] + points_[points[1]].coordinates()[i] + points_[points[2]].coordinates()[i]); - element.assign_center(center); + surf.assign_center(center); - // the normal of the element + // the normal of the surfaces normal = three_cross_product(points_[points[0]].coordinates(), points_[points[1]].coordinates(), points_[points[2]].coordinates()); @@ -98,7 +100,7 @@ bool mpm::Discontinuity3D<3>::initialize_center_normal() { normal[2] * normal[2]); normal = 1.0 / det * normal; - element.assign_normal(normal); + surf.assign_normal(normal); } } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); @@ -128,9 +130,9 @@ void mpm::Discontinuity3D::compute_levelset( // find the nearest distance from particle to cell: need to do by global // searching and local searching double distance = std::numeric_limits::max(); - for (const auto& element : surfaces_) { + for (const auto& surf : surfaces_) { double vertical_distance = - element.vertical_distance(coor); // vertical_distance(coor); + surf.vertical_distance(coor); // vertical_distance(coor); distance = std::abs(distance) < std::abs(vertical_distance) ? distance : vertical_distance; @@ -149,12 +151,19 @@ void mpm::Discontinuity3D::compute_normal(const VectorDim& coordinates, // find the nearest distance from particle to cell: need to do better by global // searching and local searching double distance = std::numeric_limits::max(); - for (const auto& element : surfaces_) { + for (const auto& surf : surfaces_) { double vertical_distance = - element.vertical_distance(coordinates); // vertical_distance(coor); + surf.vertical_distance(coordinates); // vertical_distance(coor); if (std::abs(distance) > std::abs(vertical_distance)) { distance = vertical_distance; - normal_vector = element.normal(); + normal_vector = surf.normal(); } } +} + +//! Assign point friction coefficient +template +void mpm::Discontinuity3D::assign_point_friction_coef() noexcept{ +for(auto & point: points_) + point.assign_friction_coef(friction_coef_); } \ No newline at end of file diff --git a/include/xmpm/discontinuity_base.h b/include/xmpm/discontinuity_base.h index 8c625f6e0..5c7dcc9ad 100644 --- a/include/xmpm/discontinuity_base.h +++ b/include/xmpm/discontinuity_base.h @@ -88,6 +88,9 @@ class DiscontinuityBase { //! Compute shape function void compute_shapefn() noexcept; + //! Assign point friction coefficient + virtual void assign_point_friction_coef() noexcept = 0; + protected: //! Logger std::unique_ptr console_; @@ -113,6 +116,8 @@ struct discontinuity_point { //! construct with coordinate discontinuity_point(const VectorDim& coordinate) { + + friction_coef_ = 0; coordinates_ = coordinate; cell_ = nullptr; //! Logger @@ -155,6 +160,10 @@ struct discontinuity_point { //! Compute shape function void compute_shapefn() noexcept; + //! Assign point friction coefficient + //! \param[in] friction_coef + void assign_friction_coef(double friction_coef) noexcept {friction_coef_ = friction_coef;}; + private: //! point coordinates VectorDim coordinates_; @@ -170,6 +179,8 @@ struct discontinuity_point { std::vector>> nodes_; //! Logger std::shared_ptr console_; + //! friction coefficient + double friction_coef_{0.}; }; //! struct of discontinuity line: for 2d, need to be done @@ -230,6 +241,6 @@ struct discontinuity_surface { } // namespace mpm #include "discontinuity_base.tcc" -#include "discontinuity_base_point.tcc" +#include "discontinuity_point.tcc" #endif // MPM_DiscontinuityBase_H_ diff --git a/include/xmpm/discontinuity_base_point.tcc b/include/xmpm/discontinuity_point.tcc similarity index 92% rename from include/xmpm/discontinuity_base_point.tcc rename to include/xmpm/discontinuity_point.tcc index deb921538..a176e8b6d 100644 --- a/include/xmpm/discontinuity_base_point.tcc +++ b/include/xmpm/discontinuity_point.tcc @@ -4,6 +4,8 @@ bool mpm::discontinuity_point::assign_cell_xi( const std::shared_ptr>& cellptr, const Eigen::Matrix& xi) { bool status = true; + Eigen::Matrix friction_coef; + friction_coef(0,0) = friction_coef_; try { // Assign cell to the new cell ptr, if point can be found in new cell if (cellptr != nullptr) { @@ -11,9 +13,10 @@ bool mpm::discontinuity_point::assign_cell_xi( cell_ = cellptr; cell_id_ = cellptr->id(); nodes_ = cell_->nodes(); - // assign discontinuity_enrich - for (unsigned i = 0; i < nodes_.size(); ++i) + for (unsigned i = 0; i < nodes_.size(); ++i){ nodes_[i]->assign_discontinuity_enrich(true); + nodes_[i]->update_discontinuity_property(true, "friction_coef", friction_coef, 0, 1); + } // Assign the reference location of particle bool xi_nan = false; @@ -40,6 +43,8 @@ template bool mpm::discontinuity_point::assign_cell( const std::shared_ptr>& cellptr) { bool status = true; + Eigen::Matrix friction_coef; + friction_coef(0,0) = friction_coef_; try { Eigen::Matrix xi; // Assign cell to the new cell ptr, if point can be found in new cell @@ -50,7 +55,10 @@ bool mpm::discontinuity_point::assign_cell( nodes_ = cell_->nodes(); // assign discontinuity_enrich for (unsigned i = 0; i < nodes_.size(); ++i) + { nodes_[i]->assign_discontinuity_enrich(true); + nodes_[i]->update_discontinuity_property(true, "friction_coef", friction_coef, 0, 1); + } } else { console_->warn("Points of discontinuity cannot be found in cell!"); } From 684f1926bdcfb344a81c4dda73559727063981d8 Mon Sep 17 00:00:00 2001 From: Yong Liang <60054151+yliang-sn@users.noreply.github.com> Date: Tue, 25 Aug 2020 13:45:39 -0700 Subject: [PATCH 42/91] Update include/mesh.h Co-authored-by: Krishna Kumar <3963513+kks32@users.noreply.github.com> --- include/mesh.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mesh.h b/include/mesh.h index 8bc96338d..1cc7533ec 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -469,7 +469,7 @@ class Mesh { void create_nodal_properties_discontinuity(); //! Initialise discontinuities - //! \param[in] discontinuities + //! \param[in] discontinuities List of discontinuities void initialise_discontinuities( const std::map>>& discontinuities) { From f1f6af3bdb562c398a9419a6e0bcead1e872ab67 Mon Sep 17 00:00:00 2001 From: yong liang Date: Thu, 27 Aug 2020 19:54:12 -0700 Subject: [PATCH 43/91] :pencil::construction:delete the compute_strain function in XMPM --- include/mesh.h | 4 ++-- include/mesh.tcc | 4 ++-- include/node.h | 2 +- include/node_xmpm.tcc | 1 - include/particles/particle.h | 3 +-- include/particles/particle_xmpm.h | 11 +++-------- include/particles/particle_xmpm.tcc | 20 -------------------- include/solvers/xmpm_explicit.tcc | 2 +- include/xmpm/discontinuity_base.h | 2 +- 9 files changed, 11 insertions(+), 38 deletions(-) diff --git a/include/mesh.h b/include/mesh.h index 1cc7533ec..8c6ade529 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -463,7 +463,7 @@ class Mesh { void initialise_nodal_properties(); //! Set particles lsm values - void assign_particle_levelset(std::vector& phi_list); + void assign_particle_levelset(const std::vector& phi_list); // Create the nodal properties' map for discontinuity void create_nodal_properties_discontinuity(); @@ -477,7 +477,7 @@ class Mesh { } //! Locate points of discontinuity in a cell - void locate_discontinuity_mesh(); + void locate_discontinuity(); //! Update the discontinuity position //! \param[in] dt Analysis time step diff --git a/include/mesh.tcc b/include/mesh.tcc index 7435469a8..df39c303a 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1996,14 +1996,14 @@ void mpm::Mesh::initialise_nodal_properties() { //! Set particles lsm values template -void mpm::Mesh::assign_particle_levelset(std::vector& phi_list) { +void mpm::Mesh::assign_particle_levelset(const std::vector& phi_list) { for (mpm::Index i = 0; i < nparticles(); ++i) particles_[i]->assign_levelsetphi(phi_list[i]); } //! Locate points in a cell template -void mpm::Mesh::locate_discontinuity_mesh() { +void mpm::Mesh::locate_discontinuity() { for (unsigned i = 0; i < discontinuities_.size(); ++i) { auto discontinuity = discontinuities_[i]; discontinuity->locate_discontinuity_mesh(cells_, map_cells_); diff --git a/include/node.h b/include/node.h index 1a15ef69a..0c9caa49f 100644 --- a/include/node.h +++ b/include/node.h @@ -325,7 +325,7 @@ class Node : public NodeBase { Index id_{std::numeric_limits::max()}; //! nodal property id unsigned prop_id_{std::numeric_limits::max()}; - //! nodal property id + //! nodal discontinuity property id unsigned discontinuity_prop_id_{std::numeric_limits::max()}; //! shared ghost id Index ghost_id_{std::numeric_limits::max()}; diff --git a/include/node_xmpm.tcc b/include/node_xmpm.tcc index 9ee058d5f..b0d48fb53 100644 --- a/include/node_xmpm.tcc +++ b/include/node_xmpm.tcc @@ -28,7 +28,6 @@ Eigen::MatrixXd mpm::Node::discontinuity_property( // Const pointer to location of property: node_id * nprops x mat_id auto property_value = property_handle_->property(property, discontinuity_prop_id_, 0, nprops); - ; // mpm::MapProperty property_handle(position, nprops); return property_value; } diff --git a/include/particles/particle.h b/include/particles/particle.h index 167eec3dd..860c828e4 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -321,12 +321,11 @@ 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 //! \retval strain rate at particle inside a cell - inline Eigen::Matrix compute_strain_rate( + virtual inline Eigen::Matrix compute_strain_rate( const Eigen::MatrixXd& dn_dx, unsigned phase) noexcept; //! Compute pack size diff --git a/include/particles/particle_xmpm.h b/include/particles/particle_xmpm.h index 0cd3dd109..9cc606f72 100644 --- a/include/particles/particle_xmpm.h +++ b/include/particles/particle_xmpm.h @@ -35,7 +35,7 @@ class ParticleXMPM : public Particle { ParticleXMPM(Index id, const VectorDim& coord, bool status); //! Destructor - ~ParticleXMPM() override{}; + ~ParticleXMPM() override = default; //! Delete copy constructor ParticleXMPM(const ParticleXMPM&) = delete; @@ -62,18 +62,13 @@ class ParticleXMPM : public Particle { void compute_updated_position(double dt, bool velocity_update = false) noexcept override; - //! Compute strain - //! \param[in] dt Analysis time step - void compute_strain(double dt) noexcept override; - - private: //! Compute strain rate //! \param[in] dn_dx The spatial gradient of shape function //! \param[in] phase Index to indicate phase //! \retval strain rate at particle inside a cell inline Eigen::Matrix compute_strain_rate( const Eigen::MatrixXd& dn_dx, unsigned phase) noexcept; - + private: //! Assign the level set function values //! \param[in] phivalue The level set values void assign_levelsetphi(const double phivalue) { levelset_phi_ = phivalue; }; @@ -82,7 +77,7 @@ class ParticleXMPM : public Particle { //! \param[in] x double value inline double sgn(double x) noexcept { return (x > 0) ? 1. : ((x < 0) ? -1. : 0); - }; + } private: //! particle id diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index 9ec1411bc..063b1b64a 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -95,26 +95,6 @@ inline Eigen::Matrix mpm::ParticleXMPM<3>::compute_strain_rate( return strain_rate; } -// Compute strain of the particle -template -void mpm::ParticleXMPM::compute_strain(double dt) noexcept { - // Assign strain rate - strain_rate_ = this->compute_strain_rate(dn_dx_, mpm::ParticlePhase::Solid); - // Update dstrain - dstrain_ = strain_rate_ * dt; - // Update strain - strain_ += dstrain_; - - // Compute at centroid - // Strain rate for reduced integration - const Eigen::Matrix strain_rate_centroid = - this->compute_strain_rate(dn_dx_centroid_, mpm::ParticlePhase::Solid); - - // Assign volumetric strain at centroid - dvolumetric_strain_ = dt * strain_rate_centroid.head(Tdim).sum(); - volumetric_strain_centroid_ += dvolumetric_strain_; -} - //! Map body force template void mpm::ParticleXMPM::map_body_force( diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index 32f753fda..ad4cb8fe9 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -172,7 +172,7 @@ bool mpm::XMPMExplicit::solve() { if (discontinuity_) { // locate points of discontinuity - mesh_->locate_discontinuity_mesh(); + mesh_->locate_discontinuity(); // Iterate over each points to compute shapefn mesh_->compute_shapefn_discontinuity(); diff --git a/include/xmpm/discontinuity_base.h b/include/xmpm/discontinuity_base.h index 5c7dcc9ad..8b5107535 100644 --- a/include/xmpm/discontinuity_base.h +++ b/include/xmpm/discontinuity_base.h @@ -216,7 +216,7 @@ struct discontinuity_surface { //! \param[in] normal normal vector of the surface inline void assign_normal(VectorDim& normal) { normal_ = normal; } - //! Reture normal of the elements + //! Return normal of the elements VectorDim normal() const { return normal_; } //! Return the vertical distance to the surface From 7869f64c471d01b828281fe4d98ad70898bc78f9 Mon Sep 17 00:00:00 2001 From: yong liang Date: Sun, 30 Aug 2020 22:58:45 -0700 Subject: [PATCH 44/91] :hammer:modify the solver scheme --- include/mesh.h | 8 +- include/mesh.tcc | 24 +- include/node.h | 2 +- include/node.tcc | 2 +- include/node_xmpm.tcc | 19 +- include/particles/particle.tcc | 4 +- include/particles/particle_xmpm.h | 9 +- include/solvers/xmpm_explicit.h | 11 +- include/solvers/xmpm_explicit.tcc | 396 +++++++-------------------- include/xmpm/discontinuity_3d.h | 9 +- include/xmpm/discontinuity_3d.tcc | 46 ++-- include/xmpm/discontinuity_base.h | 14 +- include/xmpm/discontinuity_base.tcc | 5 +- include/xmpm/discontinuity_point.tcc | 22 +- src/mpm.cc | 1 - 15 files changed, 195 insertions(+), 377 deletions(-) diff --git a/include/mesh.h b/include/mesh.h index 8c6ade529..d00ed3ea4 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -462,14 +462,11 @@ class Mesh { // Initialise the nodal properties' map void initialise_nodal_properties(); - //! Set particles lsm values - void assign_particle_levelset(const std::vector& phi_list); - // Create the nodal properties' map for discontinuity void create_nodal_properties_discontinuity(); //! Initialise discontinuities - //! \param[in] discontinuities List of discontinuities + //! \param[in] discontinuities List of discontinuities void initialise_discontinuities( const std::map>>& discontinuities) { @@ -489,6 +486,9 @@ class Mesh { //! compute the normal vector of enriched nodes at the discontinuity void compute_normal_vector_discontinuity(); + //! Initialise the level set function values + void initialise_levelset_discontinuity(); + 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 df39c303a..4a6ff0ce5 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1975,8 +1975,7 @@ void mpm::Mesh::create_nodal_properties_discontinuity() { nodal_properties_->create_property("external_force_enrich", nrows, 1); nodal_properties_->create_property("normal_unit_vectors_discontinuity", nrows, 1); - nodal_properties_->create_property("friction_coef", - nodes_.size(), 1); + nodal_properties_->create_property("friction_coef", nodes_.size(), 1); // Iterate over all nodes to initialise the property handle in each node // and assign its node id as the prop id in the nodal property data pool for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) @@ -1994,13 +1993,6 @@ void mpm::Mesh::initialise_nodal_properties() { nodal_properties_->initialise_nodal_properties(); } -//! Set particles lsm values -template -void mpm::Mesh::assign_particle_levelset(const std::vector& phi_list) { - for (mpm::Index i = 0; i < nparticles(); ++i) - particles_[i]->assign_levelsetphi(phi_list[i]); -} - //! Locate points in a cell template void mpm::Mesh::locate_discontinuity() { @@ -2045,3 +2037,17 @@ void mpm::Mesh::compute_normal_vector_discontinuity() { normal, Tdim); } } + +// Initialise level set values particles +template +void mpm::Mesh::initialise_levelset_discontinuity() { + + double phi_particle; + for (unsigned i = 0; i < discontinuities_.size(); ++i) { + for (mpm::Index j = 0; j < nparticles(); ++j) { + discontinuities_[i]->compute_levelset(particles_[j]->coordinates(), + phi_particle); + particles_[j]->assign_levelsetphi(phi_particle); + } + } +} \ No newline at end of file diff --git a/include/node.h b/include/node.h index 0c9caa49f..82665ade4 100644 --- a/include/node.h +++ b/include/node.h @@ -279,7 +279,7 @@ class Node : public NodeBase { void assign_discontinuity_enrich(bool discontinuity) { discontinuity_enrich_ = discontinuity; }; - + //! Return whether the node is enriched bool discontinuity_enrich() const { return discontinuity_enrich_; }; diff --git a/include/node.tcc b/include/node.tcc index 421090f52..abd3906c4 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -34,7 +34,7 @@ void mpm::Node::initialise() noexcept { acceleration_.setZero(); status_ = false; material_ids_.clear(); - //mark: need to check + // mark: need to check discontinuity_enrich_ = true; } diff --git a/include/node_xmpm.tcc b/include/node_xmpm.tcc index b0d48fb53..a83a1fdb8 100644 --- a/include/node_xmpm.tcc +++ b/include/node_xmpm.tcc @@ -121,8 +121,8 @@ void mpm::Node::self_contact_discontinuity( // single phase for solid unsigned phase = 0; const double tolerance = 1.0E-15; - - //obtain the enriched values of enriched nodes + + // obtain the enriched values of enriched nodes Eigen::Matrix mass_enrich = property_handle_->property("mass_enrich", discontinuity_prop_id_, 0, 1); Eigen::Matrix momenta_enrich = property_handle_->property( @@ -156,7 +156,8 @@ void mpm::Node::self_contact_discontinuity( // friction_coef < 0: move together without slide // need to be done - double friction_coef = property_handle_->property("friction_coef", discontinuity_prop_id_, 0, 1)(0,0); + double friction_coef = property_handle_->property( + "friction_coef", discontinuity_prop_id_, 0, 1)(0, 0); if (friction_coef < 0) { property_handle_->update_property("momenta_enrich", discontinuity_prop_id_, @@ -165,7 +166,8 @@ void mpm::Node::self_contact_discontinuity( discontinuity_prop_id_, 0, force_contact.col(phase), Tdim); } else { - //the contact momentum, force value for sticking contact at normal direction + // the contact momentum, force value for sticking contact at normal + // direction double momentum_contact_norm = momentum_contact.col(phase).dot(normal_vector); double force_contact_norm = momentum_contact_norm / dt; @@ -173,17 +175,18 @@ void mpm::Node::self_contact_discontinuity( // the maximum friction contact force double max_friction_force = friction_coef * abs(force_contact_norm); - // the contact momentum, force vector for sticking contact at tangential direction + // the contact momentum, force vector for sticking contact at tangential + // direction auto momentum_tangential = momentum_contact.col(phase) - momentum_contact_norm * normal_vector; auto force_tangential = momentum_tangential / dt; - //the friction force magnitude + // the friction force magnitude double force_tangential_value = force_tangential.norm(); double force_friction = force_tangential_value < max_friction_force - ? force_tangential_value - : max_friction_force; + ? force_tangential_value + : max_friction_force; // adjust the momentum and force property_handle_->update_property( diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index f8dea3a20..020195d05 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -977,8 +977,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_[mpm::ParticlePhase::Solid], 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, diff --git a/include/particles/particle_xmpm.h b/include/particles/particle_xmpm.h index 9cc606f72..178c861ff 100644 --- a/include/particles/particle_xmpm.h +++ b/include/particles/particle_xmpm.h @@ -68,6 +68,7 @@ class ParticleXMPM : public Particle { //! \retval strain rate at particle inside a cell inline Eigen::Matrix compute_strain_rate( const Eigen::MatrixXd& dn_dx, unsigned phase) noexcept; + private: //! Assign the level set function values //! \param[in] phivalue The level set values @@ -142,8 +143,14 @@ class ParticleXMPM : public Particle { using Particle::dn_dx_centroid_; //! Logger using Particle::console_; + //! Map of scalar properties + using Particle::scalar_properties_; //! Map of vector properties - using Particle::properties_; + using Particle::vector_properties_; + //! Map of tensor properties + using Particle::tensor_properties_; + //! Pack size + using Particle::pack_size_; private: //! level set value: phi for discontinuity diff --git a/include/solvers/xmpm_explicit.h b/include/solvers/xmpm_explicit.h index b26e35855..9e3f4875d 100644 --- a/include/solvers/xmpm_explicit.h +++ b/include/solvers/xmpm_explicit.h @@ -28,9 +28,8 @@ class XMPMExplicit : public MPMBase { void compute_stress_strain(unsigned phase); //! Initialise discontinuities - bool initialise_discontinuities(); - //! Initialise the level set function values - bool initialise_levelset(); + void initialise_discontinuities(); + // return the number of discontinuities mpm::Index ndiscontinuities() { return discontinuities_.size(); }; @@ -55,6 +54,12 @@ class XMPMExplicit : public MPMBase { using mpm::MPMBase::post_process_; //! Logger using mpm::MPMBase::console_; + //! MPM Scheme + using mpm::MPMBase::mpm_scheme_; + //! Stress update method + using mpm::MPMBase::stress_update_; + //! Interface scheme + using mpm::MPMBase::contact_; #ifdef USE_GRAPH_PARTITIONING //! Graph diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index ad4cb8fe9..80bfdd940 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -4,6 +4,17 @@ mpm::XMPMExplicit::XMPMExplicit(const std::shared_ptr& io) : mpm::MPMBase(io) { //! Logger console_ = spdlog::get("XMPMExplicit"); + //! Stress update + if (this->stress_update_ == "usl") + mpm_scheme_ = std::make_shared>(mesh_, dt_); + else + mpm_scheme_ = std::make_shared>(mesh_, dt_); + + //! Interface scheme + if (this->interface_) + contact_ = std::make_shared>(mesh_); + else + contact_ = std::make_shared>(mesh_); } //! MPM Explicit compute stress strain @@ -52,60 +63,31 @@ bool mpm::XMPMExplicit::solve() { resume = analysis_["resume"]["resume"].template get(); // Pressure smoothing - if (analysis_.find("pressure_smoothing") != analysis_.end()) - pressure_smoothing_ = - analysis_.at("pressure_smoothing").template get(); + pressure_smoothing_ = io_->analysis_bool("pressure_smoothing"); // Interface - if (analysis_.find("interface") != analysis_.end()) - interface_ = analysis_.at("interface").template get(); + interface_ = io_->analysis_bool("interface"); // 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(); // Create nodal properties if (interface_) mesh_->create_nodal_properties(); // Initialise discontinuity - bool discontinuity_status = this->initialise_discontinuities(); - if (!discontinuity_status) { - status = false; - throw std::runtime_error("Initialisation of discontinuities failed"); - } + this->initialise_discontinuities(); // Initialise the levelset values for particles - if (discontinuity_) { - bool initialise_lsm_status = this->initialise_levelset(); - if (!initialise_lsm_status) { - status = false; - throw std::runtime_error("Initialisation of level set values failed"); - } - } + if (discontinuity_) mesh_->initialise_levelset_discontinuity(); // Create nodal properties for discontinuity if (discontinuity_) mesh_->create_nodal_properties_discontinuity(); @@ -135,41 +117,17 @@ bool mpm::XMPMExplicit::solve() { #endif // Inject particles - mesh_->inject_particles(this->step_ * this->dt_); - -#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 + mesh_->inject_particles(step_ * dt_); - // Initialise nodal properties - if (interface_ || discontinuity_) + // Initialise nodes, cells and shape functions + mpm_scheme_->initialise(); + + // Initialise nodal properties and append material ids to node + contact_->initialise(); + + if (discontinuity_) { // Initialise nodal properties mesh_->initialise_nodal_properties(); - // append material ids to node - if (interface_) { - // Append material ids to nodes - mesh_->iterate_over_particles( - std::bind(&mpm::ParticleBase::append_material_id_to_nodes, - std::placeholders::_1)); - } - if (discontinuity_) { // locate points of discontinuity mesh_->locate_discontinuity(); @@ -179,164 +137,47 @@ bool mpm::XMPMExplicit::solve() { // obtain the normal direction of each enrich nodes mesh_->compute_normal_vector_discontinuity(); - - // mesh_->iterate_over_nodes_predicate( - // std::bind(&mpm::NodeBase::compute_normal_vector, - // std::placeholders::_1), - // std::bind(&mpm::NodeBase::discontinuity_enrich, - // 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)); - -#ifdef USE_MPI - // Run if there is more than a single MPI task - if (mpi_size > 1) { - // MPI all reduce nodal mass - mesh_->template nodal_halo_exchange( - std::bind(&mpm::NodeBase::mass, std::placeholders::_1, phase), - std::bind(&mpm::NodeBase::update_mass, std::placeholders::_1, - false, phase, std::placeholders::_2)); - // MPI all reduce nodal momentum - mesh_->template nodal_halo_exchange, Tdim>( - std::bind(&mpm::NodeBase::momentum, std::placeholders::_1, - phase), - std::bind(&mpm::NodeBase::update_momentum, - std::placeholders::_1, false, phase, - std::placeholders::_2)); - } -#endif + // Mass momentum and compute velocity at nodes + mpm_scheme_->compute_nodal_kinematics(phase); - // Compute nodal velocity - // mesh_->iterate_over_nodes_predicate( - // std::bind(&mpm::NodeBase::compute_velocity, - // std::placeholders::_1), - // std::bind(&mpm::NodeBase::status, std::placeholders::_1)); - - if (interface_) { - // Map multimaterial properties from particles to nodes - mesh_->iterate_over_particles(std::bind( - &mpm::ParticleBase::map_multimaterial_mass_momentum_to_nodes, - std::placeholders::_1)); - - // Map multimaterial displacements from particles to nodes - mesh_->iterate_over_particles(std::bind( - &mpm::ParticleBase::map_multimaterial_displacements_to_nodes, - std::placeholders::_1)); - - // Map multimaterial domain gradients from particles to nodes - mesh_->iterate_over_particles(std::bind( - &mpm::ParticleBase::map_multimaterial_domain_gradients_to_nodes, - std::placeholders::_1)); - - // Compute multimaterial change in momentum - mesh_->iterate_over_nodes(std::bind( - &mpm::NodeBase::compute_multimaterial_change_in_momentum, - std::placeholders::_1)); - - // Compute multimaterial separation vector - mesh_->iterate_over_nodes(std::bind( - &mpm::NodeBase::compute_multimaterial_separation_vector, - std::placeholders::_1)); - - // Compute multimaterial normal unit vector - mesh_->iterate_over_nodes(std::bind( - &mpm::NodeBase::compute_multimaterial_normal_unit_vector, - std::placeholders::_1)); - } + // Map material properties to nodes + contact_->compute_contact_forces(); // Update stress first - if (this->stress_update_ == mpm::StressUpdate::USF) - this->compute_stress_strain(phase); - - // 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( - 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, phase, (this->step_ * this->dt_))); - } - -#pragma omp section - { - // Spawn a task for internal force - // Iterate over each particle to compute nodal internal force - mesh_->iterate_over_particles( - std::bind(&mpm::ParticleBase::map_internal_force, - std::placeholders::_1)); - } - } // Wait for tasks to finish - -#ifdef USE_MPI - // Run if there is more than a single MPI task - if (mpi_size > 1) { - // MPI all reduce external force - mesh_->template nodal_halo_exchange, Tdim>( - std::bind(&mpm::NodeBase::external_force, std::placeholders::_1, - phase), - std::bind(&mpm::NodeBase::update_external_force, - std::placeholders::_1, false, phase, - std::placeholders::_2)); - // MPI all reduce internal force - mesh_->template nodal_halo_exchange, Tdim>( - std::bind(&mpm::NodeBase::internal_force, std::placeholders::_1, - phase), - std::bind(&mpm::NodeBase::update_internal_force, - std::placeholders::_1, false, phase, - std::placeholders::_2)); - } -#endif + mpm_scheme_->precompute_stress_strain(phase, pressure_smoothing_); + // Compute forces + mpm_scheme_->compute_forces(gravity_, phase, step_, + set_node_concentrated_force_); + // intergrate momentum Iterate over mesh_->iterate_over_nodes_predicate( std::bind(&mpm::NodeBase::intergrate_momentum_discontinuity, std::placeholders::_1, phase, this->dt_), std::bind(&mpm::NodeBase::status, std::placeholders::_1)); - // Iterate over each particle to compute updated position - mesh_->iterate_over_particles( - std::bind(&mpm::ParticleBase::compute_updated_position, - std::placeholders::_1, this->dt_, this->velocity_update_)); + //Update the discontinuity position + if (discontinuity_) + mesh_->compute_updated_position_discontinuity(this->dt_); - // Apply particle velocity constraints - mesh_->apply_particle_velocity_constraints(); + // Particle kinematics + mpm_scheme_->compute_particle_kinematics(velocity_update_, phase, "Cundall", + damping_factor_); // Update Stress Last - if (this->stress_update_ == mpm::StressUpdate::USL) - this->compute_stress_strain(phase); - // Update the discontinuity position - // if (discontinuity_) - // mesh_->compute_updated_position_discontinuity(this->dt_); + mpm_scheme_->postcompute_stress_strain(phase, pressure_smoothing_); // Locate particles - auto unlocatable_particles = mesh_->locate_particles_mesh(); + mpm_scheme_->locate_particles(this->locate_particles_); + - 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(); + MPI_Barrier(MPI_COMM_WORLD); #endif #endif @@ -354,110 +195,69 @@ bool mpm::XMPMExplicit::solve() { } } auto solver_end = std::chrono::steady_clock::now(); - console_->info( - "Rank {}, XMPMExplicit {} 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, + mpm_scheme_->scheme(), + std::chrono::duration_cast( + solver_end - solver_begin) + .count()); return status; } // Initialise discontinuities template -bool mpm::XMPMExplicit::initialise_discontinuities() { - bool status = true; +void mpm::XMPMExplicit::initialise_discontinuities() { try { // Get discontinuities data - try { - auto json_discontinuities = io_->json_object("discontinuity"); - if (!json_discontinuities.empty()) { - discontinuity_ = true; - for (const auto discontinuity_props : json_discontinuities) { - // Get discontinuity type - const std::string discontunity_type = - discontinuity_props["type"].template get(); - - // Get discontinuity id - auto discontinuity_id = - discontinuity_props["id"].template get(); - - // Create a new discontinuity surface from JSON object - auto discontinuity = - Factory, unsigned, - const Json&>::instance() - ->create(discontunity_type, std::move(discontinuity_id), - discontinuity_props); - - // Get discontinuity input type - auto io_type = - discontinuity_props["io_type"].template get(); - - // discontinuity file - std::string discontinuity_file = io_->file_name( - discontinuity_props["file"].template get()); - // Create a mesh reader - auto discontunity_io = - Factory>::instance()->create(io_type); - - // Create points and cells from file - discontinuity->initialize( - discontunity_io->read_mesh_nodes(discontinuity_file), - discontunity_io->read_mesh_cells(discontinuity_file)); - // Add discontinuity to list - auto result = discontinuities_.insert( - std::make_pair(discontinuity_id, discontinuity)); - - // If insert discontinuity failed - if (!result.second) { - status = false; - throw std::runtime_error( - "New discontinuity cannot be added, insertion failed"); - } + auto json_discontinuities = io_->json_object("discontinuity"); + if (!json_discontinuities.empty()) { + discontinuity_ = true; + for (const auto discontinuity_props : json_discontinuities) { + // Get discontinuity type + const std::string discontunity_type = + discontinuity_props["type"].template get(); + + // Get discontinuity id + auto discontinuity_id = + discontinuity_props["id"].template get(); + + // Create a new discontinuity surface from JSON object + auto discontinuity = + Factory, unsigned, + const Json&>::instance() + ->create(discontunity_type, std::move(discontinuity_id), + discontinuity_props); + + // Get discontinuity input type + auto io_type = + discontinuity_props["io_type"].template get(); + + // discontinuity file + std::string discontinuity_file = io_->file_name( + discontinuity_props["file"].template get()); + // Create a mesh reader + auto discontunity_io = + Factory>::instance()->create(io_type); + + // Create points and cells from file + discontinuity->initialize( + discontunity_io->read_mesh_nodes(discontinuity_file), + discontunity_io->read_mesh_cells(discontinuity_file)); + // Add discontinuity to list + auto result = discontinuities_.insert( + std::make_pair(discontinuity_id, discontinuity)); + + // If insert discontinuity failed + if (!result.second) { + throw std::runtime_error( + "New discontinuity cannot be added, insertion failed"); } } - } catch (std::exception& exception) { - console_->warn("{} #{}: No discontinuity is defined", __FILE__, __LINE__, - exception.what()); + // Copy discontinuities to mesh + mesh_->initialise_discontinuities(this->discontinuities_); } - // Copy discontinuities to mesh - mesh_->initialise_discontinuities(this->discontinuities_); } catch (std::exception& exception) { - console_->error("#{}: Reading discontinuities: {}", __LINE__, - exception.what()); - status = false; + console_->warn("{} #{}: No discontinuity is defined", __FILE__, __LINE__, + exception.what()); } - - return status; } - -// Initialise particles -template -bool mpm::XMPMExplicit::initialise_levelset() { - - bool status = true; - - try { - - for (mpm::Index i = 0; i < ndiscontinuities(); ++i) { - - std::vector phi_list(mesh_->nparticles()); - - discontinuities_[i]->compute_levelset(mesh_->particle_coordinates(), - phi_list); - - mesh_->assign_particle_levelset(phi_list); - } - - } catch (std::exception& exception) { - console_->error("#{}: XMPM initialise particles levelset values: {}", - __LINE__, exception.what()); - status = false; - } - - if (!status) - throw std::runtime_error("Initialisation of particles LSM values failed"); - - return status; -} \ No newline at end of file diff --git a/include/xmpm/discontinuity_3d.h b/include/xmpm/discontinuity_3d.h index ee8afd464..7f524d243 100644 --- a/include/xmpm/discontinuity_3d.h +++ b/include/xmpm/discontinuity_3d.h @@ -22,7 +22,7 @@ class Discontinuity3D : public DiscontinuityBase { //! \param[in] the point index of each surface virtual bool initialize(const std::vector& points, const std::vector>& surfs); - + //! create elements from file //! \param[in] surfs the point index list of each surface virtual bool create_surfaces( @@ -39,8 +39,8 @@ class Discontinuity3D : public DiscontinuityBase { // return the levelset values of each coordinates //! \param[in] coordinates coordinates //! \param[in] phi_list the reference of phi for all coordinates - void compute_levelset(const std::vector& coordinates, - std::vector& phi_list) override; + void compute_levelset(const VectorDim& coordinates, + double& phi_particle) override; //! compute the normal vectors of coordinates //! \param[in] coordinates The coordinates @@ -54,7 +54,7 @@ class Discontinuity3D : public DiscontinuityBase { protected: //! vector of points using mpm::DiscontinuityBase::points_; - //! Logger + //! Logger using mpm::DiscontinuityBase::console_; //! friction coefficient using mpm::DiscontinuityBase::friction_coef_; @@ -62,7 +62,6 @@ class Discontinuity3D : public DiscontinuityBase { private: // vector of surfaces std::vector> surfaces_; - }; } // namespace mpm diff --git a/include/xmpm/discontinuity_3d.tcc b/include/xmpm/discontinuity_3d.tcc index 983af1204..da9ca3c8b 100644 --- a/include/xmpm/discontinuity_3d.tcc +++ b/include/xmpm/discontinuity_3d.tcc @@ -41,7 +41,8 @@ bool mpm::Discontinuity3D::initialize( if (!normal_status) { status = false; throw std::runtime_error( - "initialization of the center and normal vector of the discontunity failed"); + "initialization of the center and normal vector of the discontunity " + "failed"); } this->assign_point_friction_coef(); @@ -80,7 +81,7 @@ bool mpm::Discontinuity3D<3>::initialize_center_normal() { VectorDim normal; Eigen::Matrix points; - for (auto& surf: surfaces_) { + for (auto& surf : surfaces_) { points = surf.points(); // the center of the surfaces @@ -122,34 +123,28 @@ Eigen::Matrix mpm::Discontinuity3D::three_cross_product( // return the levelset values of each coordinates template -void mpm::Discontinuity3D::compute_levelset( - const std::vector& coordinates, std::vector& phi_list) { - - mpm::Index i = 0; - for (const auto& coor : coordinates) { - // find the nearest distance from particle to cell: need to do by global - // searching and local searching - double distance = std::numeric_limits::max(); - for (const auto& surf : surfaces_) { - double vertical_distance = - surf.vertical_distance(coor); // vertical_distance(coor); - distance = std::abs(distance) < std::abs(vertical_distance) - ? distance - : vertical_distance; - if (!distance) distance = 1e-16; - } - - phi_list[i] = distance; - ++i; +void mpm::Discontinuity3D::compute_levelset(const VectorDim& coordinates, + double& phi_particle) { + // find the nearest distance from particle to cell: need to do by global + // searching and local searching + double distance = std::numeric_limits::max(); + for (const auto& surf : surfaces_) { + double vertical_distance = + surf.vertical_distance(coordinates); // vertical_distance(coor); + distance = std::abs(distance) < std::abs(vertical_distance) + ? distance + : vertical_distance; + if (!distance) distance = 1e-16; } + phi_particle = distance; } // return the normal vectors of given coordinates template void mpm::Discontinuity3D::compute_normal(const VectorDim& coordinates, VectorDim& normal_vector) { - // find the nearest distance from particle to cell: need to do better by global - // searching and local searching + // find the nearest distance from particle to cell: need to do better by + // global searching and local searching double distance = std::numeric_limits::max(); for (const auto& surf : surfaces_) { double vertical_distance = @@ -163,7 +158,6 @@ void mpm::Discontinuity3D::compute_normal(const VectorDim& coordinates, //! Assign point friction coefficient template -void mpm::Discontinuity3D::assign_point_friction_coef() noexcept{ -for(auto & point: points_) - point.assign_friction_coef(friction_coef_); +void mpm::Discontinuity3D::assign_point_friction_coef() noexcept { + for (auto& point : points_) point.assign_friction_coef(friction_coef_); } \ No newline at end of file diff --git a/include/xmpm/discontinuity_base.h b/include/xmpm/discontinuity_base.h index 8b5107535..218c210ba 100644 --- a/include/xmpm/discontinuity_base.h +++ b/include/xmpm/discontinuity_base.h @@ -50,15 +50,16 @@ class DiscontinuityBase { //! create elements from file //! \param[in] surfs the point index list of each surface - virtual bool create_surfaces(const std::vector>& surfs) { + virtual bool create_surfaces( + const std::vector>& surfs) { return true; }; // return the levelset values of each coordinates //! \param[in] coordinates coordinates //! \param[in] phi_list the reference of phi for all coordinates - virtual void compute_levelset(const std::vector& coordinates, - std::vector& phi_list) = 0; + virtual void compute_levelset(const VectorDim& coordinates, + double& phi_particle) = 0; //! compute the normal vectors of coordinates //! \param[in] coordinates The coordinates @@ -106,7 +107,6 @@ class DiscontinuityBase { }; // DiscontinuityBase class - //! struct of discontinuity point template struct discontinuity_point { @@ -152,7 +152,7 @@ struct discontinuity_point { //! \param[in] cells vector of cells //! \param[in] map_cells map of cells void locate_discontinuity_mesh(const Vector>& cells, - const Map>& map_cells) noexcept; + const Map>& map_cells) noexcept; //! Compute updated position void compute_updated_position(double dt) noexcept; @@ -162,7 +162,9 @@ struct discontinuity_point { //! Assign point friction coefficient //! \param[in] friction_coef - void assign_friction_coef(double friction_coef) noexcept {friction_coef_ = friction_coef;}; + void assign_friction_coef(double friction_coef) noexcept { + friction_coef_ = friction_coef; + }; private: //! point coordinates diff --git a/include/xmpm/discontinuity_base.tcc b/include/xmpm/discontinuity_base.tcc index ea76693b9..169ff6572 100644 --- a/include/xmpm/discontinuity_base.tcc +++ b/include/xmpm/discontinuity_base.tcc @@ -34,8 +34,9 @@ bool mpm::DiscontinuityBase::create_points( } //! Locate points in a cell template -void mpm::DiscontinuityBase::locate_discontinuity_mesh(const - Vector>& cells, const Map>& map_cells) noexcept { +void mpm::DiscontinuityBase::locate_discontinuity_mesh( + const Vector>& cells, + const Map>& map_cells) noexcept { for (auto& point : this->points_) point.locate_discontinuity_mesh(cells, map_cells); } diff --git a/include/xmpm/discontinuity_point.tcc b/include/xmpm/discontinuity_point.tcc index a176e8b6d..f5b9b3f6c 100644 --- a/include/xmpm/discontinuity_point.tcc +++ b/include/xmpm/discontinuity_point.tcc @@ -5,7 +5,7 @@ bool mpm::discontinuity_point::assign_cell_xi( const Eigen::Matrix& xi) { bool status = true; Eigen::Matrix friction_coef; - friction_coef(0,0) = friction_coef_; + friction_coef(0, 0) = friction_coef_; try { // Assign cell to the new cell ptr, if point can be found in new cell if (cellptr != nullptr) { @@ -13,9 +13,10 @@ bool mpm::discontinuity_point::assign_cell_xi( cell_ = cellptr; cell_id_ = cellptr->id(); nodes_ = cell_->nodes(); - for (unsigned i = 0; i < nodes_.size(); ++i){ + for (unsigned i = 0; i < nodes_.size(); ++i) { nodes_[i]->assign_discontinuity_enrich(true); - nodes_[i]->update_discontinuity_property(true, "friction_coef", friction_coef, 0, 1); + nodes_[i]->update_discontinuity_property(true, "friction_coef", + friction_coef, 0, 1); } // Assign the reference location of particle bool xi_nan = false; @@ -44,7 +45,7 @@ bool mpm::discontinuity_point::assign_cell( const std::shared_ptr>& cellptr) { bool status = true; Eigen::Matrix friction_coef; - friction_coef(0,0) = friction_coef_; + friction_coef(0, 0) = friction_coef_; try { Eigen::Matrix xi; // Assign cell to the new cell ptr, if point can be found in new cell @@ -54,10 +55,10 @@ bool mpm::discontinuity_point::assign_cell( cell_id_ = cellptr->id(); nodes_ = cell_->nodes(); // assign discontinuity_enrich - for (unsigned i = 0; i < nodes_.size(); ++i) - { + for (unsigned i = 0; i < nodes_.size(); ++i) { nodes_[i]->assign_discontinuity_enrich(true); - nodes_[i]->update_discontinuity_property(true, "friction_coef", friction_coef, 0, 1); + nodes_[i]->update_discontinuity_property(true, "friction_coef", + friction_coef, 0, 1); } } else { console_->warn("Points of discontinuity cannot be found in cell!"); @@ -87,8 +88,9 @@ bool mpm::discontinuity_point::compute_reference_location() noexcept { //! Locate points in a cell template -void mpm::discontinuity_point::locate_discontinuity_mesh(const - Vector>& cells, const Map>& map_cells) noexcept { +void mpm::discontinuity_point::locate_discontinuity_mesh( + const Vector>& cells, + const Map>& map_cells) noexcept { // Check the current cell if it is not invalid if (cell_id() != std::numeric_limits::max()) { // If a cell id is present, but not a cell locate the cell from map @@ -120,7 +122,7 @@ void mpm::discontinuity_point::locate_discontinuity_mesh(const // Compute updated position of the particle template void mpm::discontinuity_point::compute_updated_position( - const double dt) noexcept { + const double dt) noexcept { // Check if point has a valid cell ptr if (cell_ == nullptr) return; // Get interpolated nodal velocity diff --git a/src/mpm.cc b/src/mpm.cc index 2e6bf3591..b1ab107cc 100644 --- a/src/mpm.cc +++ b/src/mpm.cc @@ -19,4 +19,3 @@ static Register, const std::shared_ptr&> static Register, const std::shared_ptr&> xmpm_explicit_3d("XMPMExplicit3D"); } // namespace mpm - From 91ff3823ee3e52323c3afd6c007fe70ef70984f7 Mon Sep 17 00:00:00 2001 From: yong liang Date: Mon, 31 Aug 2020 10:57:53 -0700 Subject: [PATCH 45/91] :hammer:use assert instead of if --- include/mesh.tcc | 64 ++++++++++++++----------------- include/solvers/xmpm_explicit.tcc | 16 ++++---- 2 files changed, 37 insertions(+), 43 deletions(-) diff --git a/include/mesh.tcc b/include/mesh.tcc index 4a6ff0ce5..58e42ca3c 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1964,26 +1964,24 @@ void mpm::Mesh::create_nodal_properties_discontinuity() { nodal_properties_ = std::make_shared(); // Check if nodes_ is empty and throw runtime error if they are - if (nodes_.size() != 0) { - // Compute number of rows in nodal properties for vector entities - const unsigned nrows = nodes_.size() * Tdim; - // Create pool data for each property in the nodal properties struct - // object. Properties must be named in the plural form - nodal_properties_->create_property("mass_enrich", nodes_.size(), 1); - nodal_properties_->create_property("momenta_enrich", nrows, 1); - nodal_properties_->create_property("internal_force_enrich", nrows, 1); - nodal_properties_->create_property("external_force_enrich", nrows, 1); - nodal_properties_->create_property("normal_unit_vectors_discontinuity", - nrows, 1); - nodal_properties_->create_property("friction_coef", nodes_.size(), 1); - // Iterate over all nodes to initialise the property handle in each node - // and assign its node id as the prop id in the nodal property data pool - for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) - (*nitr)->initialise_discontinuity_property_handle((*nitr)->id(), - nodal_properties_); - } else { - throw std::runtime_error("Number of nodes is zero"); - } + assert(nodes_.size()); + // Compute number of rows in nodal properties for vector entities + const unsigned nrows = nodes_.size() * Tdim; + // Create pool data for each property in the nodal properties struct + // object. Properties must be named in the plural form + nodal_properties_->create_property("mass_enrich", nodes_.size(), 1); + nodal_properties_->create_property("momenta_enrich", nrows, 1); + nodal_properties_->create_property("internal_force_enrich", nrows, 1); + nodal_properties_->create_property("external_force_enrich", nrows, 1); + nodal_properties_->create_property("normal_unit_vectors_discontinuity", + nrows, 1); + nodal_properties_->create_property("friction_coef", nodes_.size(), 1); + // Iterate over all nodes to initialise the property handle in each node + // and assign its node id as the prop id in the nodal property data pool + for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) + (*nitr)->initialise_discontinuity_property_handle((*nitr)->id(), + nodal_properties_); + } // Initialise the nodal properties' map @@ -1997,44 +1995,38 @@ void mpm::Mesh::initialise_nodal_properties() { template void mpm::Mesh::locate_discontinuity() { for (unsigned i = 0; i < discontinuities_.size(); ++i) { - auto discontinuity = discontinuities_[i]; - discontinuity->locate_discontinuity_mesh(cells_, map_cells_); + discontinuities_[i]->locate_discontinuity_mesh(cells_, map_cells_); } } //! updated_position of discontinuity template void mpm::Mesh::compute_updated_position_discontinuity(double dt) { for (unsigned i = 0; i < discontinuities_.size(); ++i) { - auto discontinuity = discontinuities_[i]; - discontinuity->compute_updated_position(dt); + discontinuities_[i]->compute_updated_position(dt); } } //! compute shape function template void mpm::Mesh::compute_shapefn_discontinuity() { for (unsigned i = 0; i < discontinuities_.size(); ++i) { - auto discontinuity = discontinuities_[i]; - discontinuity->compute_shapefn(); + discontinuities_[i]->compute_shapefn(); } } // compute the normal vector of enriched nodes at the discontinuity template void mpm::Mesh::compute_normal_vector_discontinuity() { - // just compute for one discontinuity for now - unsigned discontinuity_id = 0; - auto discontinuity = discontinuities_[discontinuity_id]; - VectorDim normal; normal.setZero(); + for (unsigned i = 0; i < discontinuities_.size(); ++i) { + for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { - for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { - - discontinuity->compute_normal((*nitr)->coordinates(), normal); + discontinuities_[i]->compute_normal((*nitr)->coordinates(), normal); - nodal_properties_->assign_property("normal_unit_vectors_discontinuity", - (*nitr)->discontinuity_prop_id(), 0, - normal, Tdim); + nodal_properties_->assign_property("normal_unit_vectors_discontinuity", + (*nitr)->discontinuity_prop_id(), 0, + normal, Tdim); + } } } diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index 80bfdd940..5c398f7b3 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -151,20 +151,24 @@ bool mpm::XMPMExplicit::solve() { // Compute forces mpm_scheme_->compute_forces(gravity_, phase, step_, set_node_concentrated_force_); - + // intergrate momentum Iterate over mesh_->iterate_over_nodes_predicate( std::bind(&mpm::NodeBase::intergrate_momentum_discontinuity, std::placeholders::_1, phase, this->dt_), std::bind(&mpm::NodeBase::status, std::placeholders::_1)); - //Update the discontinuity position + // Update the discontinuity position if (discontinuity_) mesh_->compute_updated_position_discontinuity(this->dt_); - // Particle kinematics - mpm_scheme_->compute_particle_kinematics(velocity_update_, phase, "Cundall", - damping_factor_); + // // Particle kinematics + // mpm_scheme_->compute_particle_kinematics(velocity_update_, phase, "Cundall", + // damping_factor_); + // Iterate over each particle to compute updated position + mesh_->iterate_over_particles( + std::bind(&mpm::ParticleBase::compute_updated_position, + std::placeholders::_1, dt_, velocity_update_)); // Update Stress Last mpm_scheme_->postcompute_stress_strain(phase, pressure_smoothing_); @@ -172,8 +176,6 @@ bool mpm::XMPMExplicit::solve() { // Locate particles mpm_scheme_->locate_particles(this->locate_particles_); - - #ifdef USE_MPI #ifdef USE_GRAPH_PARTITIONING mesh_->transfer_halo_particles(); From 84158b6340e243210c18ee406c2d7fa3445dcbfd Mon Sep 17 00:00:00 2001 From: yong liang Date: Mon, 31 Aug 2020 19:03:21 -0700 Subject: [PATCH 46/91] :hammer:update some comments and fix some code --- include/mesh.tcc | 9 ++++----- include/node.h | 11 ++++------- include/node_base.h | 8 +++----- include/node_xmpm.tcc | 13 ++++--------- include/particles/particle_base.h | 3 ++- include/particles/particle_xmpm.h | 5 +---- include/particles/particle_xmpm.tcc | 7 ------- include/solvers/xmpm_explicit.tcc | 11 ++++++----- include/xmpm/discontinuity_3d.tcc | 18 +++++++++--------- include/xmpm/discontinuity_base.h | 2 +- 10 files changed, 34 insertions(+), 53 deletions(-) diff --git a/include/mesh.tcc b/include/mesh.tcc index 58e42ca3c..7987c178b 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1973,15 +1973,14 @@ void mpm::Mesh::create_nodal_properties_discontinuity() { nodal_properties_->create_property("momenta_enrich", nrows, 1); nodal_properties_->create_property("internal_force_enrich", nrows, 1); nodal_properties_->create_property("external_force_enrich", nrows, 1); - nodal_properties_->create_property("normal_unit_vectors_discontinuity", - nrows, 1); + nodal_properties_->create_property("normal_unit_vectors_discontinuity", nrows, + 1); nodal_properties_->create_property("friction_coef", nodes_.size(), 1); // Iterate over all nodes to initialise the property handle in each node // and assign its node id as the prop id in the nodal property data pool for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) (*nitr)->initialise_discontinuity_property_handle((*nitr)->id(), nodal_properties_); - } // Initialise the nodal properties' map @@ -2024,8 +2023,8 @@ void mpm::Mesh::compute_normal_vector_discontinuity() { discontinuities_[i]->compute_normal((*nitr)->coordinates(), normal); nodal_properties_->assign_property("normal_unit_vectors_discontinuity", - (*nitr)->discontinuity_prop_id(), 0, - normal, Tdim); + (*nitr)->discontinuity_prop_id(), 0, + normal, Tdim); } } } diff --git a/include/node.h b/include/node.h index 82665ade4..9043eb28d 100644 --- a/include/node.h +++ b/include/node.h @@ -208,7 +208,7 @@ class Node : public NodeBase { //! Apply velocity constraints void apply_velocity_constraints() override; - //! Apply velocity constraints for discontinuity + //! Apply self-contact for discontinuity void apply_velocity_constraints_discontinuity() override; //! Assign friction constraint @@ -300,11 +300,11 @@ class Node : public NodeBase { Eigen::MatrixXd discontinuity_property(const std::string& property, unsigned nprops = 1) noexcept override; - //! Compute momentum + //! Compute momentum for discontinuity //! \param[in] phase Index corresponding to the phase //! \param[in] dt Timestep in analysis - virtual bool intergrate_momentum_discontinuity(unsigned phase, - double dt) noexcept override; + virtual bool compute_momentum_discontinuity(unsigned phase, + double dt) noexcept override; //! Apply self-contact of the discontinuity //! \param[in] dt Time-step @@ -315,9 +315,6 @@ class Node : public NodeBase { return discontinuity_prop_id_; }; - //! Compute normal direction for discontinuity - void compute_normal_vector() noexcept override; - private: //! Mutex SpinMutex node_mutex_; diff --git a/include/node_base.h b/include/node_base.h index c22a448a0..5aa06ff58 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -287,11 +287,11 @@ class NodeBase { const Eigen::MatrixXd& property_value, unsigned discontinuity_id, unsigned nprops) noexcept = 0; - //! Compute momentum + //! Compute momentum for discontinuity //! \param[in] phase Index corresponding to the phase //! \param[in] dt Timestep in analysis - virtual bool intergrate_momentum_discontinuity(unsigned phase, - double dt) noexcept = 0; + virtual bool compute_momentum_discontinuity(unsigned phase, + double dt) noexcept = 0; //! Apply self-contact of the discontinuity //! \param[in] dt Time-step @@ -300,8 +300,6 @@ class NodeBase { //! Return the discontinuity_prop_id virtual unsigned discontinuity_prop_id() const noexcept = 0; - //! Compute normal direction for discontinuity - virtual void compute_normal_vector() noexcept = 0; }; // NodeBase class } // namespace mpm diff --git a/include/node_xmpm.tcc b/include/node_xmpm.tcc index a83a1fdb8..c322d45f1 100644 --- a/include/node_xmpm.tcc +++ b/include/node_xmpm.tcc @@ -32,9 +32,9 @@ Eigen::MatrixXd mpm::Node::discontinuity_property( return property_value; } -//! Compute acceleration and velocity with cundall damping factor +//! Compute momentum for discontinuity template -bool mpm::Node::intergrate_momentum_discontinuity( +bool mpm::Node::compute_momentum_discontinuity( unsigned phase, double dt) noexcept { momentum_.col(phase) = momentum_.col(phase) + @@ -59,7 +59,7 @@ bool mpm::Node::intergrate_momentum_discontinuity( return true; } -//! Apply velocity constraints +//! Apply velocity constraints for discontinuity template void mpm::Node::apply_velocity_constraints_discontinuity() { @@ -112,7 +112,7 @@ void mpm::Node void mpm::Node::self_contact_discontinuity( double dt) noexcept { @@ -201,8 +201,3 @@ void mpm::Node::self_contact_discontinuity( Tdim); } } - -//! Compute normal direction of each enrich node -//! Apply velocity constraints -template -void mpm::Node::compute_normal_vector() noexcept {} \ No newline at end of file diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 4b46e3e19..8404add63 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -315,7 +315,8 @@ class ParticleBase { const std::vector& buffer, std::vector>>& materials) = 0; //! set the level set function values - virtual void assign_levelsetphi(const double phivalue){}; + //! \param[in] phivalue Signed distance function + virtual void assign_levelsetphi(double phivalue){}; protected: //! particleBase id diff --git a/include/particles/particle_xmpm.h b/include/particles/particle_xmpm.h index 178c861ff..e030b786c 100644 --- a/include/particles/particle_xmpm.h +++ b/include/particles/particle_xmpm.h @@ -43,9 +43,6 @@ class ParticleXMPM : public Particle { //! Delete assignment operator ParticleXMPM& operator=(const ParticleXMPM&) = delete; - //! Initialise properties - void initialise() override; - //! Map particle mass and momentum to nodes void map_mass_momentum_to_nodes() noexcept override; @@ -72,7 +69,7 @@ class ParticleXMPM : public Particle { private: //! Assign the level set function values //! \param[in] phivalue The level set values - void assign_levelsetphi(const double phivalue) { levelset_phi_ = phivalue; }; + void assign_levelsetphi(double phivalue) { levelset_phi_ = phivalue; }; //! Return 1 if x > 0, -1 if x < 0 and 0 if x = 0 //! \param[in] x double value diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index 063b1b64a..884ba9b8f 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -3,7 +3,6 @@ template mpm::ParticleXMPM::ParticleXMPM(Index id, const VectorDim& coord) : mpm::Particle(id, coord) { - this->initialise(); // Logger std::string logger = "particlexmpm" + std::to_string(Tdim) + "d::" + std::to_string(id); @@ -22,12 +21,6 @@ mpm::ParticleXMPM::ParticleXMPM(Index id, const VectorDim& coord, console_ = std::make_unique(logger, mpm::stdout_sink); } -// Initialise particle properties -template -void mpm::ParticleXMPM::initialise() { - levelset_phi_ = 0.; -} - //! Map particle mass and momentum to nodes template void mpm::ParticleXMPM::map_mass_momentum_to_nodes() noexcept { diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index 5c398f7b3..7f18a96a4 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -152,9 +152,9 @@ bool mpm::XMPMExplicit::solve() { mpm_scheme_->compute_forces(gravity_, phase, step_, set_node_concentrated_force_); - // intergrate momentum Iterate over + // integrate momentum by iterating over nodes mesh_->iterate_over_nodes_predicate( - std::bind(&mpm::NodeBase::intergrate_momentum_discontinuity, + std::bind(&mpm::NodeBase::compute_momentum_discontinuity, std::placeholders::_1, phase, this->dt_), std::bind(&mpm::NodeBase::status, std::placeholders::_1)); @@ -163,12 +163,13 @@ bool mpm::XMPMExplicit::solve() { mesh_->compute_updated_position_discontinuity(this->dt_); // // Particle kinematics - // mpm_scheme_->compute_particle_kinematics(velocity_update_, phase, "Cundall", + // mpm_scheme_->compute_particle_kinematics(velocity_update_, phase, + // "Cundall", // damping_factor_); // Iterate over each particle to compute updated position mesh_->iterate_over_particles( - std::bind(&mpm::ParticleBase::compute_updated_position, - std::placeholders::_1, dt_, velocity_update_)); + std::bind(&mpm::ParticleBase::compute_updated_position, + std::placeholders::_1, dt_, velocity_update_)); // Update Stress Last mpm_scheme_->postcompute_stress_strain(phase, pressure_smoothing_); diff --git a/include/xmpm/discontinuity_3d.tcc b/include/xmpm/discontinuity_3d.tcc index da9ca3c8b..1176c300a 100644 --- a/include/xmpm/discontinuity_3d.tcc +++ b/include/xmpm/discontinuity_3d.tcc @@ -5,11 +5,11 @@ mpm::Discontinuity3D::Discontinuity3D(unsigned id, try { // assign friction_coef_ if it's given in input file + friction_coef_ = 0; if (discontinuity_props.contains("friction_coefficient")) friction_coef_ = discontinuity_props.at("friction_coefficient").template get(); - else - friction_coef_ = 0; + } catch (Json::exception& except) { console_->error("discontinuity parameter not set: {} {}\n", except.what(), except.id); @@ -41,8 +41,8 @@ bool mpm::Discontinuity3D::initialize( if (!normal_status) { status = false; throw std::runtime_error( - "initialization of the center and normal vector of the discontunity " - "failed"); + "initialization of the center and the normal vector of the " + "discontinuity failed"); } this->assign_point_friction_coef(); @@ -63,7 +63,7 @@ bool mpm::Discontinuity3D::create_surfaces( mpm::discontinuity_surface surf(points); - surfaces_.emplace_back(surf); // + surfaces_.emplace_back(surf); } } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); @@ -97,10 +97,10 @@ bool mpm::Discontinuity3D<3>::initialize_center_normal() { normal = three_cross_product(points_[points[0]].coordinates(), points_[points[1]].coordinates(), points_[points[2]].coordinates()); - double det = std::sqrt(normal[0] * normal[0] + normal[1] * normal[1] + - normal[2] * normal[2]); - normal = 1.0 / det * normal; - + if (normal.norm() > std::numeric_limits::epsilon()) + normal.normalize(); + else + normal = VectorDim::Zero(); surf.assign_normal(normal); } } catch (std::exception& exception) { diff --git a/include/xmpm/discontinuity_base.h b/include/xmpm/discontinuity_base.h index 218c210ba..6e8ae6933 100644 --- a/include/xmpm/discontinuity_base.h +++ b/include/xmpm/discontinuity_base.h @@ -205,7 +205,7 @@ struct discontinuity_surface { //! construct with points indices discontinuity_surface(const std::vector& points) { - for (int i = 0; i < points.size(); ++i) points_[i] = points[i]; + for (int i = 0; i < 3; ++i) points_[i] = points[i]; } //! Return points indices Eigen::Matrix points() const { return points_; } From 0c86c24a355d52bc4cb534b710ab2f8470364898 Mon Sep 17 00:00:00 2001 From: yong liang Date: Sun, 6 Sep 2020 23:34:49 -0700 Subject: [PATCH 47/91] :construction:xmpm solver test functions for 3d --- CMakeLists.txt | 4 + tests/include/write_mesh_particles.h | 7 + tests/io/write_mesh_particles.cc | 188 ++++++++++++++++++ tests/solvers/xmpm_explicit_usf_test.cc | 93 +++++++++ .../xmpm_explicit_usf_unitcell_test.cc | 120 +++++++++++ tests/solvers/xmpm_explicit_usl_test.cc | 88 ++++++++ .../xmpm_explicit_usl_unitcell_test.cc | 122 ++++++++++++ 7 files changed, 622 insertions(+) create mode 100644 tests/solvers/xmpm_explicit_usf_test.cc create mode 100644 tests/solvers/xmpm_explicit_usf_unitcell_test.cc create mode 100644 tests/solvers/xmpm_explicit_usl_test.cc create mode 100644 tests/solvers/xmpm_explicit_usl_unitcell_test.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index e425d8d38..e918b14e3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -215,6 +215,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/xmpm_explicit_usf_test.cc +# ${mpm_SOURCE_DIR}/tests/solvers/xmpm_explicit_usf_unitcell_test.cc + ${mpm_SOURCE_DIR}/tests/solvers/xmpm_explicit_usl_test.cc +# ${mpm_SOURCE_DIR}/tests/solvers/xmpm_explicit_usl_unitcell_test.cc ${mpm_SOURCE_DIR}/tests/solvers/mpm_scheme_test.cc ${mpm_SOURCE_DIR}/tests/nodal_properties_test.cc ${mpm_SOURCE_DIR}/tests/node_map_test.cc diff --git a/tests/include/write_mesh_particles.h b/tests/include/write_mesh_particles.h index 5e2f00980..299acfb45 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& mpm_scheme, const std::string& file_name); +// Write JSON Configuration file for xmpm +bool write_json_xmpm(unsigned dim, bool resume, const std::string& analysis, + const std::string& mpm_scheme, + const std::string& file_name); + // Write JSON Entity Set bool write_entity_set(); @@ -20,5 +25,7 @@ bool write_particles_2d(); bool write_mesh_3d(); // Write particles file in 3D bool write_particles_3d(); +// Write discontinuity file in 3D +bool write_discontinuity_3d(); } // namespace mpm_test diff --git a/tests/io/write_mesh_particles.cc b/tests/io/write_mesh_particles.cc index b69637511..5cf32b099 100644 --- a/tests/io/write_mesh_particles.cc +++ b/tests/io/write_mesh_particles.cc @@ -113,6 +113,125 @@ bool write_json(unsigned dim, bool resume, const std::string& analysis, return true; } +// Write JSON Configuration file for xmpm +bool write_json_xmpm(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 = "P2DXMPM"; + auto node_type = "N2D"; + auto cell_type = "ED2Q4"; + auto io_type = "Ascii2D"; + auto discontinuity_file = "discontinuity-2d.txt"; + std::string material = "LinearElastic2D"; + std::vector gravity{{0., -9.81}}; + unsigned material_id = 0; + 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 = "P3DXMPM"; + node_type = "N3D"; + cell_type = "ED3H8"; + io_type = "Ascii3D"; + material = "LinearElastic3D"; + gravity.clear(); + gravity = {0., 0., -9.81}; + discontinuity_file = "discontinuity-3d.txt"; + } + + 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"}}}}}}, + {"discontinuity", + {{{"id", 0}, + {"type", "tri3d"}, + {"io_type", "Ascii3D"}, + {"file", discontinuity_file}, + {"frictional_coefficient", 0.3}}}}, + {"materials", + {{{"id", 0}, + {"type", material}, + {"density", 1000.}, + {"youngs_modulus", 1.0E+8}, + {"poisson_ratio", 0.495}}, + {{"id", 1}, + {"type", material}, + {"density", 2300.}, + {"youngs_modulus", 1.5E+6}, + {"poisson_ratio", 0.25}}}}, + {"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.001}, + {"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", "velocities"}}, + {"vtk_statevars", {{{"phase_id", 0}, {"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 @@ -417,4 +536,73 @@ bool write_particles_3d() { return true; } +// Write mesh file in 3D +bool write_discontinuity_3d() { + + // Dimension + const unsigned dim = 3; + + // Vector of nodal coordinates + std::vector> coordinates; + + // Nodal coordinates + Eigen::Matrix point; + + // point 0 + point << 0., 0., 0.25; + coordinates.emplace_back(point); + // point 1 + point << 0.5, 0., 0.25; + coordinates.emplace_back(point); + // point 2 + point << 1.0, 0., 0.25; + coordinates.emplace_back(point); + // point 3 + point << 1.0, 0.5, 0.25; + coordinates.emplace_back(point); + // point 4 + point << 0.5, 0.5, 0.25; + coordinates.emplace_back(point); + // point 5 + point << 0., 0.5, 0.25; + coordinates.emplace_back(point); + + // surfaces with point ids + std::vector> surfs{// surface #0 + {0, 1, 5}, + // surface #1 + {1, 4, 5}, + // surface #2 + {1, 3, 4}, + // surface #3 + {1, 2, 3}}; + + // Dump discontinuity file as an input file to be read + std::ofstream file; + file.open("discontinuity-3d.txt"); + file << "! surfaceShape triangle\n"; + file << coordinates.size() << "\t" << surfs.size() << "\n"; + + // Write point coordinates + for (const auto& coord : coordinates) { + for (unsigned i = 0; i < coord.size(); ++i) file << coord[i] << "\t"; + file << "\n"; + } + + // Write cell node ids + for (const auto& surf : surfs) { + for (auto pid : surf) file << pid << "\t"; + file << "\n"; + } + + file.close(); + + // Dump mesh velocity constraints + std::ofstream file_constraints; + file_constraints.open("velocity-constraints.txt"); + file_constraints << 0 << "\t" << 0 << "\t" << 0 << "\n"; + file_constraints.close(); + + return true; +} } // namespace mpm_test diff --git a/tests/solvers/xmpm_explicit_usf_test.cc b/tests/solvers/xmpm_explicit_usf_test.cc new file mode 100644 index 000000000..e8facc811 --- /dev/null +++ b/tests/solvers/xmpm_explicit_usf_test.cc @@ -0,0 +1,93 @@ +#include "catch.hpp" + +//! Alias for JSON +#include "json.hpp" +using Json = nlohmann::json; + +#include "write_mesh_particles.h" +#include "xmpm_explicit.h" + +// Check XMPM Explicit +TEST_CASE("XMPM 3D Explicit implementation is checked", + "[XMPM][3D][Explicit][USF][1Phase]") { + // Dimension + const unsigned Dim = 3; + + // Write JSON file + const std::string fname = "xmpm-explicit-usf"; + const std::string analysis = "XMPMExplicit3D"; + const std::string mpm_scheme = "usf"; + const bool resume = false; + REQUIRE(mpm_test::write_json_xmpm(3, resume, analysis, mpm_scheme, 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); + + // Write discontinuity + REQUIRE(mpm_test::write_discontinuity_3d() == true); + + // Assign argc and argv to input arguments of XMPM + int argc = 5; + // clang-format off + char* argv[] = {(char*)"./mpm", + (char*)"-f", (char*)"./", + (char*)"-i", (char*)"xmpm-explicit-usf-3d.json"}; + // clang-format on + + SECTION("Check initialisation") { + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit XMPM + auto mpm = std::make_unique>(std::move(io)); + + // Initialise materials + REQUIRE_NOTHROW(mpm->initialise_materials()); + // Initialise mesh + REQUIRE_NOTHROW(mpm->initialise_mesh()); + // Initialise particles + REQUIRE_NOTHROW(mpm->initialise_particles()); + // Initialise discontinuities + REQUIRE_NOTHROW(mpm->initialise_discontinuities()); + + // Renitialise materials + REQUIRE_THROWS(mpm->initialise_materials()); + } + + SECTION("Check solver") { + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit XMPM + 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 = "xmpm-explicit-usf"; + const std::string analysis = "XMPMExplicit3D"; + const std::string mpm_scheme = "usf"; + bool resume = true; + REQUIRE(mpm_test::write_json_xmpm(3, resume, analysis, mpm_scheme, fname) == + true); + + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit XMPM + auto mpm = std::make_unique>(std::move(io)); + + // Test check point restart + REQUIRE(mpm->checkpoint_resume() == true); + // Solve + REQUIRE(mpm->solve() == true); + } +} diff --git a/tests/solvers/xmpm_explicit_usf_unitcell_test.cc b/tests/solvers/xmpm_explicit_usf_unitcell_test.cc new file mode 100644 index 000000000..18d1a9bb5 --- /dev/null +++ b/tests/solvers/xmpm_explicit_usf_unitcell_test.cc @@ -0,0 +1,120 @@ +#include "catch.hpp" + +//! Alias for JSON +#include "json.hpp" +using Json = nlohmann::json; + +#include "write_mesh_particles_unitcell.h" +#include "xmpm_explicit.h" + +// Check XMPM Explicit USF +TEST_CASE("XMPM 2D Explicit USF implementation is checked in unitcells", + "[XMPM][2D][USF][Explicit][1Phase][unitcell]") { + // Dimension + const unsigned Dim = 2; + + // Write JSON file + const std::string fname = "Xmpm-explicit-usf"; + // need to be done + const std::string analysis = "XMPMExplicit3D"; + const std::string mpm_scheme = "usf"; + REQUIRE(mpm_test::write_json_unitcell(2, analysis, mpm_scheme, 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 XMPM + int argc = 5; + // clang-format off + char* argv[] = {(char*)"./mpm", + (char*)"-f", (char*)"./", + (char*)"-i", (char*)"xmpm-explicit-usf-2d-unitcell.json"}; + // clang-format on + + SECTION("Check initialisation") { + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit XMPM + auto mpm = std::make_unique>(std::move(io)); + + // Initialise materials + REQUIRE_NOTHROW(mpm->initialise_materials()); + + // Initialise mesh and particles + REQUIRE_NOTHROW(mpm->initialise_mesh()); + REQUIRE_NOTHROW(mpm->initialise_particles()); + + // Initialise external loading + REQUIRE_NOTHROW(mpm->initialise_loads()); + + // Renitialise materials + REQUIRE_THROWS(mpm->initialise_materials()); + } + + SECTION("Check solver") { + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit XMPM + auto mpm = std::make_unique>(std::move(io)); + // Solve + REQUIRE(mpm->solve() == true); + } +} + +// Check XMPM Explicit +TEST_CASE("XMPM 3D Explicit USF implementation is checked in unitcells", + "[XMPM][3D][Explicit][USF][1Phase][unitcell]") { + // Dimension + const unsigned Dim = 3; + + // Write JSON file + const std::string fname = "xmpm-explicit-usf"; + const std::string analysis = "XMPMExplicit3D"; + const std::string mpm_scheme = "usf"; + REQUIRE(mpm_test::write_json_unitcell(3, analysis, mpm_scheme, 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 XMPM + int argc = 5; + // clang-format off + char* argv[] = {(char*)"./mpm", + (char*)"-f", (char*)"./", + (char*)"-i", (char*)"xmpm-explicit-usf-3d-unitcell.json"}; + // clang-format on + + SECTION("Check initialisation") { + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit XMPM + auto mpm = std::make_unique>(std::move(io)); + + // Initialise materials + REQUIRE_NOTHROW(mpm->initialise_materials()); + + // Initialise mesh and particles + REQUIRE_NOTHROW(mpm->initialise_mesh()); + REQUIRE_NOTHROW(mpm->initialise_particles()); + + // Renitialise materials + REQUIRE_THROWS(mpm->initialise_materials()); + } + + SECTION("Check solver") { + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit XMPM + auto mpm = std::make_unique>(std::move(io)); + // Solve + REQUIRE(mpm->solve() == true); + } +} diff --git a/tests/solvers/xmpm_explicit_usl_test.cc b/tests/solvers/xmpm_explicit_usl_test.cc new file mode 100644 index 000000000..2e0dc6a56 --- /dev/null +++ b/tests/solvers/xmpm_explicit_usl_test.cc @@ -0,0 +1,88 @@ +#include "catch.hpp" + +//! Alias for JSON +#include "json.hpp" +using Json = nlohmann::json; + +#include "write_mesh_particles.h" +#include "xmpm_explicit.h" + +// Check XMPM Explicit USL +TEST_CASE("XMPM 3D Explicit USL implementation is checked", + "[XMPM][3D][Explicit][USL][1Phase]") { + // Dimension + const unsigned Dim = 3; + + // Write JSON file + const std::string fname = "xmpm-explicit-usl"; + const std::string analysis = "XMPMExplicit3D"; + const std::string mpm_scheme = "usl"; + const bool resume = false; + REQUIRE(mpm_test::write_json_xmpm(3, resume, analysis, mpm_scheme, 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); + + // Write Particles + REQUIRE(mpm_test::write_discontinuity_3d() == true); + // Assign argc and argv to input arguments of XMPM + int argc = 5; + // clang-format off + char* argv[] = {(char*)"./mpm", + (char*)"-f", (char*)"./", + (char*)"-i", (char*)"xmpm-explicit-usl-3d.json"}; + // clang-format on + + SECTION("Check initialisation") { + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit XMPM + auto mpm = std::make_unique>(std::move(io)); + + // Initialise materials + REQUIRE_NOTHROW(mpm->initialise_materials()); + // Initialise discontinuities + REQUIRE_NOTHROW(mpm->initialise_discontinuities()); + // Initialise mesh and particles + REQUIRE_NOTHROW(mpm->initialise_mesh()); + REQUIRE_NOTHROW(mpm->initialise_particles()); + } + + SECTION("Check solver") { + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit XMPM + 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 = "xmpm-explicit-usl"; + const std::string analysis = "XMPMExplicit3D"; + const std::string mpm_scheme = "usl"; + bool resume = true; + REQUIRE(mpm_test::write_json_xmpm(3, resume, analysis, mpm_scheme, fname) == + true); + + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit XMPM + auto mpm = std::make_unique>(std::move(io)); + + // Test check point restart + REQUIRE(mpm->checkpoint_resume() == true); + // Solve + REQUIRE(mpm->solve() == true); + } +} diff --git a/tests/solvers/xmpm_explicit_usl_unitcell_test.cc b/tests/solvers/xmpm_explicit_usl_unitcell_test.cc new file mode 100644 index 000000000..699ee9463 --- /dev/null +++ b/tests/solvers/xmpm_explicit_usl_unitcell_test.cc @@ -0,0 +1,122 @@ +#include "catch.hpp" + +//! Alias for JSON +#include "json.hpp" +using Json = nlohmann::json; + +#include "write_mesh_particles_unitcell.h" +#include "xmpm_explicit.h" + +// Check XMPM Explicit USL +TEST_CASE("XMPM 2D Explicit USL implementation is checked in unitcells", + "[XMPM][2D][USL][Explicit][1Phase][unitcell]") { + // Dimension + const unsigned Dim = 2; + + // Write JSON file + const std::string fname = "xmpm-explicit-usl"; + const std::string analysis = "XMPMExplicit2D"; + const std::string mpm_scheme = "usl"; + REQUIRE(mpm_test::write_json_unitcell(2, analysis, mpm_scheme, 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 XMPM + int argc = 5; + // clang-format off + char* argv[] = {(char*)"./mpm", + (char*)"-f", (char*)"./", + (char*)"-i", (char*)"xmpm-explicit-usl-2d-unitcell.json"}; + // clang-format on + + SECTION("Check initialisation") { + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit XMPM + auto mpm = std::make_unique>(std::move(io)); + + // Initialise materials + REQUIRE_NOTHROW(mpm->initialise_materials()); + + // Initialise mesh and particles + REQUIRE_NOTHROW(mpm->initialise_mesh()); + REQUIRE_NOTHROW(mpm->initialise_particles()); + + // Initialise external loading + REQUIRE_NOTHROW(mpm->initialise_loads()); + + // Renitialise materials + REQUIRE_THROWS(mpm->initialise_materials()); + } + + SECTION("Check solver") { + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit XMPM + auto mpm = std::make_unique>(std::move(io)); + // Solve + REQUIRE(mpm->solve() == true); + } +} + +// Check XMPM Explicit +TEST_CASE("XMPM 3D Explicit USL implementation is checked in unitcells", + "[XMPM][3D][Explicit][USL][1Phase][unitcell]") { + // Dimension + const unsigned Dim = 3; + + // Write JSON file + const std::string fname = "xmpm-explicit-usl"; + const std::string analysis = "XMPMExplicit3D"; + const std::string mpm_scheme = "usl"; + REQUIRE(mpm_test::write_json_unitcell(3, analysis, mpm_scheme, 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 XMPM + int argc = 5; + // clang-format off + char* argv[] = {(char*)"./mpm", + (char*)"-f", (char*)"./", + (char*)"-i", (char*)"xmpm-explicit-usl-3d-unitcell.json"}; + // clang-format on + + SECTION("Check initialisation") { + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit XMPM + auto mpm = std::make_unique>(std::move(io)); + + // Initialise materials + REQUIRE_NOTHROW(mpm->initialise_materials()); + + // Initialise mesh and particles + REQUIRE_NOTHROW(mpm->initialise_mesh()); + REQUIRE_NOTHROW(mpm->initialise_particles()); + + // Initialise external loading + REQUIRE_NOTHROW(mpm->initialise_loads()); + + // Renitialise materials + REQUIRE_THROWS(mpm->initialise_materials()); + } + + SECTION("Check solver") { + // Create an IO object + auto io = std::make_unique(argc, argv); + // Run explicit XMPM + auto mpm = std::make_unique>(std::move(io)); + // Solve + REQUIRE(mpm->solve() == true); + } +} From 2734df63386d37ac7146466297e8a95558f3ecb1 Mon Sep 17 00:00:00 2001 From: yong liang Date: Mon, 7 Sep 2020 01:52:45 -0700 Subject: [PATCH 48/91] :construction:particle_xmpm test functions --- CMakeLists.txt | 1 + tests/particle_xmpm_test.cc | 547 ++++++++++++++++++++++++++++++++++++ 2 files changed, 548 insertions(+) create mode 100644 tests/particle_xmpm_test.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index e918b14e3..b3cabf8d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -227,6 +227,7 @@ if(MPM_BUILD_TESTING) ${mpm_SOURCE_DIR}/tests/particle_cell_crossing_test.cc ${mpm_SOURCE_DIR}/tests/particle_serialize_deserialize_test.cc ${mpm_SOURCE_DIR}/tests/particle_test.cc + ${mpm_SOURCE_DIR}/tests/particle_xmpm_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/tests/particle_xmpm_test.cc b/tests/particle_xmpm_test.cc new file mode 100644 index 000000000..5e864debe --- /dev/null +++ b/tests/particle_xmpm_test.cc @@ -0,0 +1,547 @@ +#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 "particle_xmpm.h" +#include "quadrilateral_element.h" + +//! \brief Check particle class for 3D case +TEST_CASE("Particle_XMPM is checked for 3D case", "[particle][3D][XMPM]") { + // 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 = 1; + // Phase + const unsigned phase = 0; + // 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("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("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("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 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); + + // Phase + const unsigned phase = 0; + // 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)); + + double levelsetphi = 1; + REQUIRE_NOTHROW(particle->assign_levelsetphi(levelsetphi)); + + // 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); + + auto nodal_properties_ = std::make_shared(); + // Compute number of rows in nodal properties for vector entities + const unsigned nrows = nodes.size() * Dim; + // Create pool data for each property in the nodal properties struct + // object. Properties must be named in the plural form + nodal_properties_->create_property("mass_enrich", nodes.size(), 1); + nodal_properties_->create_property("momenta_enrich", nrows, 1); + nodal_properties_->create_property("internal_force_enrich", nrows, 1); + nodal_properties_->create_property("external_force_enrich", nrows, 1); + // Iterate over all nodes to initialise the property handle in each node + // and assign its node id as the prop id in the nodal property data pool + for (unsigned i = 0; i < nodes.size(); ++i) + nodes.at(i)->initialise_discontinuity_property_handle(nodes.at(i)->id(), + nodal_properties_); + // Initialise cell properties + cell->initialise(); + + // Check if cell is initialised + REQUIRE(cell->is_initialised() == true); + + // Add cell to particle + REQUIRE(cell->status() == false); + // Compute reference location should throw + REQUIRE(particle->compute_reference_location() == 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()); + + // Check reference location + REQUIRE(particle->compute_reference_location() == true); + + // Assign material + unsigned mid = 0; + // 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); + + // Assign material properties + REQUIRE(particle->assign_material(material) == true); + + // Compute volume + REQUIRE_NOTHROW(particle->compute_volume()); + + // Compute mass + REQUIRE_NOTHROW(particle->compute_mass()); + + // 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_NOTHROW(particle->map_mass_momentum_to_nodes()); + + // 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) + REQUIRE(nodes.at(i)->mass(phase) == + Approx(nodal_mass.at(i)).epsilon(Tolerance)); + // Check nodal enriched mass + for (unsigned i = 0; i < nodes.size(); ++i) + REQUIRE(nodes.at(i)->discontinuity_property("mass_enrich", 1)(0, 0) == + Approx(nodal_mass.at(i)).epsilon(Tolerance)); + + // 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) + REQUIRE(nodes.at(i)->momentum(phase)[j] == + Approx(nodal_momentum(i, j)).epsilon(Tolerance)); + // Check nodal enriched momentum + for (unsigned i = 0; i < nodal_momentum.rows(); ++i) + for (unsigned j = 0; j < nodal_momentum.cols(); ++j) + REQUIRE(nodes.at(i)->discontinuity_property("momenta_enrich", 3)( + j, 0) == Approx(nodal_momentum(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) + // REQUIRE_NOTHROW( + // nodes.at(i)->update_momentum(false, phase, nodal_momentum.row(i))); + + // // 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) + // REQUIRE(nodes.at(i)->velocity(phase)(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)); + + // 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(phase)[j] == + Approx(body_force(i, j)).epsilon(Tolerance)); + // Check nodal enriched body force + for (unsigned i = 0; i < body_force.rows(); ++i) + for (unsigned j = 0; j < body_force.cols(); ++j) + REQUIRE(nodes.at(i)->discontinuity_property("external_force_enrich", 3)( + j, 0) == 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(phase)[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(phase)[j] == + // Approx(body_force(i, j)).epsilon(Tolerance)); + + // Internal force + // Eigen::Matrix internal_force; + // // clang-format off + // internal_force << 612980.7692307689, 1141826.923076923, + // 1742788.461538461, + // -901442.3076923079, 3521634.615384615, + // 5420673.076923076, -2415865.384615385, + // 612980.7692307703, 12223557.69230769, + // 1935096.153846153, 108173.0769230771, + // 3882211.538461538, + // 2031250, 2079326.923076922, + // -588942.3076923075, + // -2127403.846153846, 6526442.307692306, + // -1189903.846153845, + // -5516826.92307692, -10276442.30769231, + // -15685096.15384615, 6382211.538461537, + // -3713942.307692308, -5805288.461538462; + // // 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(phase)[j] == + // Approx(internal_force(i, j)).epsilon(Tolerance)); + // // Check nodal enriched internal force + // for (unsigned i = 0; i < internal_force.rows(); ++i) + // for (unsigned j = 0; j < internal_force.cols(); ++j) + // REQUIRE(nodes.at(i)->discontinuity_property("internal_force_enrich", + // 3)(j,0) == + // Approx(internal_force(i, j)).epsilon(Tolerance)); + // // Calculate nodal acceleration and velocity + // for (const auto& node : nodes) + // node->compute_acceleration_velocity(phase, dt); + + // // Check nodal velocity + // // clang-format off + // nodal_velocity << 490.3846153846152, 914.4615384615383, + // 1395.249769230769, + // -240.3846153846155, 941.1025641025641, + // 1448.531820512821, -214.7435897435898, + // 57.4871794871796, 1091.557461538462, + // 516.0256410256410, 32.8461538461539, + // 1042.275410256410, 541.6666666666666, + // 559.4871794871794, -148.032282051282, + // -189.1025641025641, 586.1282051282051, + // -94.75023076923067, -163.4615384615384, + // -297.4871794871795, -451.7245897435898, + // 567.3076923076923, -322.1282051282053, + // -501.0066410256412; + // // 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(phase)[j] == + // Approx(nodal_velocity(i, j)).epsilon(Tolerance)); + + // // Check nodal acceleration + // Eigen::Matrix nodal_acceleration; + // // clang-format off + // nodal_acceleration << 4903.846153846152, 9134.615384615383, + // 13932.49769230769, + // -2403.846153846155, 9391.025641025641, + // 14445.31820512821, -2147.435897435898, + // 544.8717948717959, 10855.57461538462, + // 5160.256410256409, 288.461538461539, + // 10342.7541025641, 5416.666666666666, + // 5544.871794871794, -1580.32282051282, + // -1891.025641025641, 5801.282051282051, + // -1067.502307692307, -1634.615384615384, + // -3044.871794871795, -4657.245897435898, + // 5673.076923076923, -3301.282051282052, + // -5170.066410256411; + // // 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(phase)[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)); + + // // Compute updated particle location + // REQUIRE_NOTHROW(particle->compute_updated_position(dt)); + // // Check particle velocity + // velocity << 0., 1., 1.019; + // 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.0769; + // 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.5769; + // // 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.769; + // 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.1538; + // 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.6538; + // // Check particle coordinates + // coordinates = particle->coordinates(); + // for (unsigned i = 0; i < coordinates.size(); ++i) + // REQUIRE(coordinates(i) == Approx(coords(i)).epsilon(Tolerance)); + } +} From 85a8d686b743fb35a296b6b41f3b341d9689ea49 Mon Sep 17 00:00:00 2001 From: yong liang Date: Mon, 7 Sep 2020 03:26:33 -0700 Subject: [PATCH 49/91] :construction:check discontinuity in mesh --- tests/mesh_test_3d.cc | 99 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/tests/mesh_test_3d.cc b/tests/mesh_test_3d.cc index 06f4e0cf2..a75bde214 100644 --- a/tests/mesh_test_3d.cc +++ b/tests/mesh_test_3d.cc @@ -1437,4 +1437,103 @@ TEST_CASE("Mesh is checked for 3D case", "[mesh][3D]") { // Check nodal properties initialisation REQUIRE_NOTHROW(mesh->initialise_nodal_properties()); } + + //! Check discontinuity + SECTION("Check discontinuity") { + // Create the mesh + std::shared_ptr> mesh = std::make_shared>(0); + + // Define nodes + Eigen::Vector3d coords; + 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); + + // Add nodes 0 to 7 to the mesh + REQUIRE(mesh->add_node(node0) == true); + REQUIRE(mesh->add_node(node1) == true); + REQUIRE(mesh->add_node(node2) == true); + REQUIRE(mesh->add_node(node3) == true); + REQUIRE(mesh->add_node(node4) == true); + REQUIRE(mesh->add_node(node5) == true); + REQUIRE(mesh->add_node(node6) == true); + REQUIRE(mesh->add_node(node7) == true); + + // Check nodal properties creation for discontinuity + REQUIRE_NOTHROW(mesh->create_nodal_properties_discontinuity()); + + // Check nodal properties initialisation + REQUIRE_NOTHROW(mesh->initialise_nodal_properties()); + + // discontinuity + std::vector> points; + // point 0 + coords << 0.5, 0.5, 1.; + points.emplace_back(coords); + // point 1 + coords << 1.5, 0., 1.; + points.emplace_back(coords); + // point 2 + coords << 1.5, 1.5, 1.; + points.emplace_back(coords); + std::vector> surfs; + // surface 0 + std::vector indices{0, 1, 2}; + surfs.emplace_back(indices); + + const std::string discontunity_type = "tri3d"; + // Get discontinuity id + int discontinuity_id = 0; + Json discontinuity_props; + // Create a new discontinuity surface from JSON object + auto discontinuity = + Factory, unsigned, const Json&>::instance() + ->create(discontunity_type, std::move(discontinuity_id), + discontinuity_props); + + REQUIRE(discontinuity->initialize(points, surfs) == true); + + //! discontinuities + std::map>> + discontinuities; + + discontinuities.insert(std::make_pair(discontinuity_id, discontinuity)); + REQUIRE_NOTHROW(mesh->initialise_discontinuities(discontinuities)); + REQUIRE_NOTHROW(mesh->locate_discontinuity()); + + double dt = 0.1; + REQUIRE_NOTHROW(mesh->compute_updated_position_discontinuity(dt)); + + REQUIRE_NOTHROW(mesh->compute_shapefn_discontinuity()); + REQUIRE_NOTHROW(mesh->compute_normal_vector_discontinuity()); + REQUIRE_NOTHROW(mesh->initialise_levelset_discontinuity()); + } } From 66332b02c7510d62526316b26e7b28d2202d2cb2 Mon Sep 17 00:00:00 2001 From: yong liang Date: Wed, 30 Sep 2020 19:07:38 -0700 Subject: [PATCH 50/91] add width of the discontinuity --- include/xmpm/discontinuity_3d.tcc | 47 ++++++++++++++--------------- include/xmpm/discontinuity_base.h | 10 +++++- include/xmpm/discontinuity_base.tcc | 15 +++++++++ 3 files changed, 46 insertions(+), 26 deletions(-) diff --git a/include/xmpm/discontinuity_3d.tcc b/include/xmpm/discontinuity_3d.tcc index 1176c300a..633b1ee56 100644 --- a/include/xmpm/discontinuity_3d.tcc +++ b/include/xmpm/discontinuity_3d.tcc @@ -2,18 +2,6 @@ template mpm::Discontinuity3D::Discontinuity3D(unsigned id, const Json& discontinuity_props) : DiscontinuityBase(id, discontinuity_props) { - - try { - // assign friction_coef_ if it's given in input file - friction_coef_ = 0; - if (discontinuity_props.contains("friction_coefficient")) - friction_coef_ = - discontinuity_props.at("friction_coefficient").template get(); - - } catch (Json::exception& except) { - console_->error("discontinuity parameter not set: {} {}\n", except.what(), - except.id); - } } // initialization @@ -97,6 +85,7 @@ bool mpm::Discontinuity3D<3>::initialize_center_normal() { normal = three_cross_product(points_[points[0]].coordinates(), points_[points[1]].coordinates(), points_[points[2]].coordinates()); + if (normal.norm() > std::numeric_limits::epsilon()) normal.normalize(); else @@ -127,16 +116,25 @@ void mpm::Discontinuity3D::compute_levelset(const VectorDim& coordinates, double& phi_particle) { // find the nearest distance from particle to cell: need to do by global // searching and local searching - double distance = std::numeric_limits::max(); + double min_distance = std::numeric_limits::max(); + double vertical_distance = std::numeric_limits::max(); for (const auto& surf : surfaces_) { - double vertical_distance = - surf.vertical_distance(coordinates); // vertical_distance(coor); - distance = std::abs(distance) < std::abs(vertical_distance) - ? distance - : vertical_distance; - if (!distance) distance = 1e-16; + double distance = surf.ptocenter_distance(coordinates); + if (std::abs(distance) < std::abs(min_distance)) { + min_distance = distance; + vertical_distance = surf.vertical_distance(coordinates); + } + if (!vertical_distance) vertical_distance = 1e-16; + } + //need to check + VectorDim circle {28.238, 27.216, circle[2]}; + double r = 22.5339; + double test_r =r - (coordinates - circle).norm(); + if(abs(test_r - vertical_distance)>1){ + test_r = 0; } - phi_particle = distance; + + phi_particle = vertical_distance; } // return the normal vectors of given coordinates @@ -145,12 +143,11 @@ void mpm::Discontinuity3D::compute_normal(const VectorDim& coordinates, VectorDim& normal_vector) { // find the nearest distance from particle to cell: need to do better by // global searching and local searching - double distance = std::numeric_limits::max(); + double min_distance = std::numeric_limits::max(); for (const auto& surf : surfaces_) { - double vertical_distance = - surf.vertical_distance(coordinates); // vertical_distance(coor); - if (std::abs(distance) > std::abs(vertical_distance)) { - distance = vertical_distance; + double distance = surf.ptocenter_distance(coordinates); + if (std::abs(distance) < std::abs(min_distance)) { + min_distance = distance; normal_vector = surf.normal(); } } diff --git a/include/xmpm/discontinuity_base.h b/include/xmpm/discontinuity_base.h index 6e8ae6933..fdbe8b7aa 100644 --- a/include/xmpm/discontinuity_base.h +++ b/include/xmpm/discontinuity_base.h @@ -22,7 +22,6 @@ class DiscontinuityBase { public: //! Define a vector of size dimension using VectorDim = Eigen::Matrix; - //! Constructor with id //! \param[in] discontinuity id //! \param[in] discontinuity properties json @@ -105,6 +104,9 @@ class DiscontinuityBase { //! friction coefficient double friction_coef_; + //! the influence length of the discontinuity + double width_{std::numeric_limits::max()}; + }; // DiscontinuityBase class //! struct of discontinuity point @@ -229,6 +231,12 @@ struct discontinuity_surface { (coor[2] - center_[2]) * normal_[2]; }; + //! Return the vertical distance to the surface + //! \param[in] coor coordinates + double ptocenter_distance(const VectorDim& coor) const { + return (coor - center_).norm(); + }; + private: //! points indices Eigen::Matrix points_; diff --git a/include/xmpm/discontinuity_base.tcc b/include/xmpm/discontinuity_base.tcc index 169ff6572..71301da67 100644 --- a/include/xmpm/discontinuity_base.tcc +++ b/include/xmpm/discontinuity_base.tcc @@ -7,6 +7,21 @@ mpm::DiscontinuityBase::DiscontinuityBase( std::string logger = "discontinuity::" + std::to_string(id); console_ = std::make_unique(logger, mpm::stdout_sink); + + try { + // assign friction_coef_ if it's given in input file + if (discontinuity_props.contains("friction_coefficient")) + friction_coef_ = + discontinuity_props.at("friction_coefficient").template get(); + // assign width if it's given in input file + if (discontinuity_props.contains("width")) + width_ = + discontinuity_props.at("width").template get(); + + } catch (Json::exception& except) { + console_->error("discontinuity parameter not set: {} {}\n", except.what(), + except.id); + } } //! create points from file From 48755b6f7851a64da1e062d431aa0ea95a78e1bf Mon Sep 17 00:00:00 2001 From: yong liang Date: Sun, 4 Oct 2020 14:40:59 -0700 Subject: [PATCH 51/91] :construction:assign the levelset width and coefficient --- include/xmpm/discontinuity_3d.h | 2 ++ include/xmpm/discontinuity_base.h | 3 +++ include/xmpm/discontinuity_base.tcc | 3 +-- include/xmpm/discontinuity_point.tcc | 35 ++++++++++++++-------------- 4 files changed, 24 insertions(+), 19 deletions(-) diff --git a/include/xmpm/discontinuity_3d.h b/include/xmpm/discontinuity_3d.h index a426ce62f..d5fc5a34d 100644 --- a/include/xmpm/discontinuity_3d.h +++ b/include/xmpm/discontinuity_3d.h @@ -57,6 +57,8 @@ class Discontinuity3D : public DiscontinuityBase { using mpm::DiscontinuityBase::console_; //! friction coefficient using mpm::DiscontinuityBase::friction_coef_; + //! width + using mpm::DiscontinuityBase::width_; private: // vector of surfaces diff --git a/include/xmpm/discontinuity_base.h b/include/xmpm/discontinuity_base.h index fdbe8b7aa..3fffd4723 100644 --- a/include/xmpm/discontinuity_base.h +++ b/include/xmpm/discontinuity_base.h @@ -147,6 +147,9 @@ struct discontinuity_point { //! \param[in] cellptr Pointer to a cell bool assign_cell(const std::shared_ptr>& cellptr); + //! Assign the discontinuity enrich to node + void assign_discontinuity_enrich(); + //! Compute reference coordinates in a cell bool compute_reference_location() noexcept; diff --git a/include/xmpm/discontinuity_base.tcc b/include/xmpm/discontinuity_base.tcc index 71301da67..76bcb3e08 100644 --- a/include/xmpm/discontinuity_base.tcc +++ b/include/xmpm/discontinuity_base.tcc @@ -15,8 +15,7 @@ mpm::DiscontinuityBase::DiscontinuityBase( discontinuity_props.at("friction_coefficient").template get(); // assign width if it's given in input file if (discontinuity_props.contains("width")) - width_ = - discontinuity_props.at("width").template get(); + width_ = discontinuity_props.at("width").template get(); } catch (Json::exception& except) { console_->error("discontinuity parameter not set: {} {}\n", except.what(), diff --git a/include/xmpm/discontinuity_point.tcc b/include/xmpm/discontinuity_point.tcc index f5b9b3f6c..49aa7ff17 100644 --- a/include/xmpm/discontinuity_point.tcc +++ b/include/xmpm/discontinuity_point.tcc @@ -4,20 +4,12 @@ bool mpm::discontinuity_point::assign_cell_xi( const std::shared_ptr>& cellptr, const Eigen::Matrix& xi) { bool status = true; - Eigen::Matrix friction_coef; - friction_coef(0, 0) = friction_coef_; try { // Assign cell to the new cell ptr, if point can be found in new cell if (cellptr != nullptr) { cell_ = cellptr; cell_id_ = cellptr->id(); - nodes_ = cell_->nodes(); - for (unsigned i = 0; i < nodes_.size(); ++i) { - nodes_[i]->assign_discontinuity_enrich(true); - nodes_[i]->update_discontinuity_property(true, "friction_coef", - friction_coef, 0, 1); - } // Assign the reference location of particle bool xi_nan = false; @@ -44,8 +36,6 @@ template bool mpm::discontinuity_point::assign_cell( const std::shared_ptr>& cellptr) { bool status = true; - Eigen::Matrix friction_coef; - friction_coef(0, 0) = friction_coef_; try { Eigen::Matrix xi; // Assign cell to the new cell ptr, if point can be found in new cell @@ -53,13 +43,7 @@ bool mpm::discontinuity_point::assign_cell( cell_ = cellptr; cell_id_ = cellptr->id(); - nodes_ = cell_->nodes(); - // assign discontinuity_enrich - for (unsigned i = 0; i < nodes_.size(); ++i) { - nodes_[i]->assign_discontinuity_enrich(true); - nodes_[i]->update_discontinuity_property(true, "friction_coef", - friction_coef, 0, 1); - } + assign_discontinuity_enrich(); } else { console_->warn("Points of discontinuity cannot be found in cell!"); } @@ -95,6 +79,9 @@ void mpm::discontinuity_point::locate_discontinuity_mesh( if (cell_id() != std::numeric_limits::max()) { // If a cell id is present, but not a cell locate the cell from map if (!cell_ptr()) assign_cell(map_cells[cell_id()]); + + assign_discontinuity_enrich(); + if (compute_reference_location()) return; // Check if discontinuity point is in any of its nearest neighbours @@ -170,4 +157,18 @@ void mpm::discontinuity_point::compute_shapefn() noexcept { Eigen::Matrix natural_size_; natural_size_.setZero(); shapefn_ = element->shapefn(this->xi_, natural_size_, zero); +} + +//! Assign the discontinuity enrich to node +template +void mpm::discontinuity_point::assign_discontinuity_enrich() { + Eigen::Matrix friction_coef; + friction_coef(0, 0) = friction_coef_; + nodes_ = cell_->nodes(); + // assign discontinuity_enrich + for (unsigned i = 0; i < nodes_.size(); ++i) { + nodes_[i]->assign_discontinuity_enrich(true); + nodes_[i]->update_discontinuity_property(true, "friction_coef", + friction_coef, 0, 1); + } } \ No newline at end of file From ff7ff1500f25b52011ca7a83d227534964b8d38e Mon Sep 17 00:00:00 2001 From: yong liang Date: Sun, 4 Oct 2020 14:42:06 -0700 Subject: [PATCH 52/91] :construction:node_xmpm test functions --- CMakeLists.txt | 1 + tests/node_xmpm_test.cc | 177 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 178 insertions(+) create mode 100644 tests/node_xmpm_test.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index b3cabf8d8..e824a4697 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -223,6 +223,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/node_xmpm_test.cc ${mpm_SOURCE_DIR}/tests/node_vector_test.cc ${mpm_SOURCE_DIR}/tests/particle_cell_crossing_test.cc ${mpm_SOURCE_DIR}/tests/particle_serialize_deserialize_test.cc diff --git a/tests/node_xmpm_test.cc b/tests/node_xmpm_test.cc new file mode 100644 index 000000000..c68c3e6cb --- /dev/null +++ b/tests/node_xmpm_test.cc @@ -0,0 +1,177 @@ +#include +#include + +#include "catch.hpp" + +#include "node.h" + +//! \brief Check nodal functions for xmpm +TEST_CASE("Node_xmpm is checked for 3D case", "[node][XMPM][3D]") { + + const unsigned Dim = 3; + const unsigned Dof = 3; + const unsigned Nphases = 1; + const unsigned Nphase = 0; + + Eigen::Vector3d coords; + coords.setZero(); + mpm::Index id = 0; + std::shared_ptr> node = + std::make_shared>(id, coords); + // Number of nodes + unsigned nnodes = 1; + // Number of materials + unsigned nmaterials = 1; + // Tolerance + const double Tolerance = 1.E-7; + // Declare nodal properties + std::shared_ptr property_handle = + std::make_shared(); + // Define properties to be created + std::string property = "momentum"; + unsigned prop_id = 0; + REQUIRE(property_handle->create_property(property, nnodes * Dim, nmaterials)); + // clang-format off + Eigen::Matrix data; + data<< 0.0, + 0.5, + 1.0; + // clang-format on + REQUIRE_NOTHROW(property_handle->assign_property(property, 0, 0, data, Dim)); + node->initialise_discontinuity_property_handle(prop_id, property_handle); + // Check discontinuous property + SECTION("Check discontinuous properties") { + REQUIRE_NOTHROW(node->assign_discontinuity_enrich(true)); + REQUIRE(node->discontinuity_enrich() == true); + // // initialise discontinuity property handle + + REQUIRE(node->discontinuity_property(property, Dim)(0, 0) == + Approx(0.0).epsilon(Tolerance)); + REQUIRE(node->discontinuity_property(property, Dim)(1, 0) == + Approx(0.5).epsilon(Tolerance)); + REQUIRE(node->discontinuity_property(property, Dim)(2, 0) == + Approx(1.0).epsilon(Tolerance)); + + node->update_discontinuity_property(true, property, data, prop_id, Dim); + REQUIRE(node->discontinuity_property(property, Dim)(0, 0) == + Approx(0.0).epsilon(Tolerance)); + REQUIRE(node->discontinuity_property(property, Dim)(1, 0) == + Approx(1.0).epsilon(Tolerance)); + REQUIRE(node->discontinuity_property(property, Dim)(2, 0) == + Approx(2.0).epsilon(Tolerance)); + } + SECTION("Check momentum and velocity constrains") { + // Time step + const double dt = 0.1; + // Check momentum + Eigen::Matrix momentum; + for (unsigned i = 0; i < momentum.size(); ++i) momentum(i) = 1.; + + // Check initial momentum + for (unsigned i = 0; i < momentum.size(); ++i) + REQUIRE(node->momentum(Nphase)(i) == Approx(0.).epsilon(Tolerance)); + + // update momentum to 1 + REQUIRE_NOTHROW(node->update_momentum(true, Nphase, momentum)); + + // clang-format off + Eigen::Matrix momentum_enrich; + momentum_enrich<< 1.0, + 1.0, + 1.0; + // clang-format on + REQUIRE(property_handle->create_property("momenta_enrich", nnodes * Dim, + nmaterials)); + REQUIRE_NOTHROW(property_handle->assign_property("momenta_enrich", prop_id, + 0, momentum_enrich, Dim)); + + // clang-format off + Eigen::Matrix force_enrich; + force_enrich<< 10, + 10, + 10; + // clang-format on + + REQUIRE(property_handle->create_property("internal_force_enrich", + nnodes * Dim, nmaterials)); + REQUIRE_NOTHROW(property_handle->assign_property( + "internal_force_enrich", prop_id, 0, force_enrich, Dim)); + + REQUIRE(property_handle->create_property("external_force_enrich", + nnodes * Dim, nmaterials)); + REQUIRE_NOTHROW(property_handle->assign_property( + "external_force_enrich", prop_id, 0, force_enrich, Dim)); + + // clang-format off + Eigen::Matrix normal_enrich; + normal_enrich<< 0, + 0, + 1; + // clang-format on + REQUIRE(property_handle->create_property( + "normal_unit_vectors_discontinuity", nnodes * Dim, nmaterials)); + REQUIRE_NOTHROW(property_handle->assign_property( + "normal_unit_vectors_discontinuity", prop_id, 0, normal_enrich, Dim)); + + Eigen::Matrix coef; + coef << -1.0; + REQUIRE( + property_handle->create_property("friction_coef", nnodes, nmaterials)); + REQUIRE_NOTHROW( + property_handle->assign_property("friction_coef", prop_id, 0, coef, 1)); + + node->compute_momentum_discontinuity(Nphase, dt); + for (unsigned i = 0; i < momentum.size(); ++i) + REQUIRE(node->discontinuity_property("momenta_enrich", Dim)(i, 0) == + Approx(3.0).epsilon(Tolerance)); + + for (unsigned i = 0; i < momentum.size(); ++i) momentum(i) = 10.; + + // Check assign momentum to 10 + REQUIRE_NOTHROW(node->update_momentum(false, Nphase, momentum)); + + // check velocity and constrain + double mass = 100.; + // Update mass to 100.0 + REQUIRE_NOTHROW(node->update_mass(false, Nphase, mass)); + REQUIRE(node->mass(Nphase) == Approx(100.).epsilon(Tolerance)); + + // Compute and check velocity this should throw zero mass + node->compute_velocity(); + // Apply velocity constraints + REQUIRE(node->assign_velocity_constraint(0, 10.5) == true); + + // Check velocity before constraints + Eigen::Matrix velocity; + for (unsigned i = 0; i < momentum.size(); ++i) velocity(i) = 0.1; + for (unsigned i = 0; i < velocity.size(); ++i) + REQUIRE(node->velocity(Nphase)(i) == + Approx(velocity(i)).epsilon(Tolerance)); + + Eigen::Matrix mass_enrich; + mass_enrich << 1.0; + + REQUIRE(property_handle->create_property("mass_enrich", nnodes * 1, + nmaterials)); + REQUIRE_NOTHROW(property_handle->assign_property("mass_enrich", prop_id, 0, + mass_enrich, 1)); + // Apply constraints + node->apply_velocity_constraints_discontinuity(); + + velocity << 10.5; + + for (unsigned i = 0; i < 1; ++i) + REQUIRE((node->momentum(Nphase)(i) + + node->discontinuity_property("momenta_enrich", Dim)(i, 0)) / + ((node->mass(Nphase) + + node->discontinuity_property("mass_enrich", 1)(i, 0))) == + Approx(10.5).epsilon(Tolerance)); + + for (unsigned i = 0; i < 1; ++i) + REQUIRE((node->momentum(Nphase)(i) - + node->discontinuity_property("momenta_enrich", Dim)(i, 0)) / + ((node->mass(Nphase) - + node->discontinuity_property("mass_enrich", 1)(i, 0))) == + Approx(10.5).epsilon(Tolerance)); + } +} From 3be07a8426c0373a0b9ccac961bd0363a106e837 Mon Sep 17 00:00:00 2001 From: yong liang Date: Sun, 4 Oct 2020 14:44:11 -0700 Subject: [PATCH 53/91] :hammer:modify node default enriched type --- include/node.tcc | 2 +- include/node_xmpm.tcc | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/include/node.tcc b/include/node.tcc index abd3906c4..ea20b2054 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -35,7 +35,7 @@ void mpm::Node::initialise() noexcept { status_ = false; material_ids_.clear(); // mark: need to check - discontinuity_enrich_ = true; + discontinuity_enrich_ = false; } //! Initialise shared pointer to nodal properties pool diff --git a/include/node_xmpm.tcc b/include/node_xmpm.tcc index c322d45f1..f1171b849 100644 --- a/include/node_xmpm.tcc +++ b/include/node_xmpm.tcc @@ -85,14 +85,14 @@ void mpm::Nodeinternal_force_(direction, phase) = 0; this->external_force_(direction, phase) = 0; - Eigen::Matrix momentum; - momentum.setZero(); + Eigen::Matrix zero_force; + zero_force.setZero(); property_handle_->assign_property( "internal_force_enrich", discontinuity_prop_id_ * Tdim + direction, 0, - momentum, 1); + zero_force, 1); property_handle_->assign_property( "external_force_enrich", discontinuity_prop_id_ * Tdim + direction, 0, - momentum, 1); + zero_force, 1); } else { // need to be done // Velocity constraints on general boundaries // Compute inverse rotation matrix @@ -155,10 +155,8 @@ void mpm::Node::self_contact_discontinuity( auto force_contact = momentum_contact / dt; // friction_coef < 0: move together without slide - // need to be done double friction_coef = property_handle_->property( "friction_coef", discontinuity_prop_id_, 0, 1)(0, 0); - if (friction_coef < 0) { property_handle_->update_property("momenta_enrich", discontinuity_prop_id_, 0, momentum_contact.col(phase), Tdim); From c2d91422ad15cc5170ce2f65233de8fa5dba0e9f Mon Sep 17 00:00:00 2001 From: yong liang Date: Sun, 4 Oct 2020 14:44:59 -0700 Subject: [PATCH 54/91] :hammer:modify the level set computation --- include/solvers/xmpm_explicit.tcc | 10 ++++++---- include/xmpm/discontinuity_3d.tcc | 16 +++++----------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index 7f18a96a4..d509c9d22 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -86,11 +86,13 @@ bool mpm::XMPMExplicit::solve() { // Initialise discontinuity this->initialise_discontinuities(); - // Initialise the levelset values for particles - if (discontinuity_) mesh_->initialise_levelset_discontinuity(); + if (discontinuity_) { + // Initialise the levelset values for particles + mesh_->initialise_levelset_discontinuity(); - // Create nodal properties for discontinuity - if (discontinuity_) mesh_->create_nodal_properties_discontinuity(); + // Create nodal properties for discontinuity + mesh_->create_nodal_properties_discontinuity(); + } // Compute mass mesh_->iterate_over_particles( std::bind(&mpm::ParticleBase::compute_mass, std::placeholders::_1)); diff --git a/include/xmpm/discontinuity_3d.tcc b/include/xmpm/discontinuity_3d.tcc index 633b1ee56..5549963a3 100644 --- a/include/xmpm/discontinuity_3d.tcc +++ b/include/xmpm/discontinuity_3d.tcc @@ -1,8 +1,7 @@ template mpm::Discontinuity3D::Discontinuity3D(unsigned id, const Json& discontinuity_props) - : DiscontinuityBase(id, discontinuity_props) { -} + : DiscontinuityBase(id, discontinuity_props) {} // initialization template @@ -126,15 +125,10 @@ void mpm::Discontinuity3D::compute_levelset(const VectorDim& coordinates, } if (!vertical_distance) vertical_distance = 1e-16; } - //need to check - VectorDim circle {28.238, 27.216, circle[2]}; - double r = 22.5339; - double test_r =r - (coordinates - circle).norm(); - if(abs(test_r - vertical_distance)>1){ - test_r = 0; - } - - phi_particle = vertical_distance; + if (abs(min_distance) < width_) + phi_particle = vertical_distance; + else + phi_particle = 0; } // return the normal vectors of given coordinates From 44afbe05a0acdcaa736926833468778f576264fe Mon Sep 17 00:00:00 2001 From: yong liang Date: Sun, 4 Oct 2020 14:46:24 -0700 Subject: [PATCH 55/91] :construction:output level set values --- include/particles/particle_xmpm.h | 3 ++- include/particles/particle_xmpm.tcc | 8 ++++++++ include/solvers/mpm_base.tcc | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/include/particles/particle_xmpm.h b/include/particles/particle_xmpm.h index e030b786c..11af871e9 100644 --- a/include/particles/particle_xmpm.h +++ b/include/particles/particle_xmpm.h @@ -42,7 +42,8 @@ class ParticleXMPM : public Particle { //! Delete assignment operator ParticleXMPM& operator=(const ParticleXMPM&) = delete; - + //! Initialise properties + void initialise() override; //! Map particle mass and momentum to nodes void map_mass_momentum_to_nodes() noexcept override; diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index 6ba76d3a5..e8e237344 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -2,6 +2,7 @@ template mpm::ParticleXMPM::ParticleXMPM(Index id, const VectorDim& coord) : mpm::Particle(id, coord) { + this->initialise(); // Logger std::string logger = "particlexmpm" + std::to_string(Tdim) + "d::" + std::to_string(id); @@ -13,12 +14,19 @@ template mpm::ParticleXMPM::ParticleXMPM(Index id, const VectorDim& coord, bool status) : mpm::Particle(id, coord, status) { + this->initialise(); //! Logger std::string logger = "particlexmpm" + std::to_string(Tdim) + "d::" + std::to_string(id); console_ = std::make_unique(logger, mpm::stdout_sink); } +// Initialise particle properties +template +void mpm::ParticleXMPM::initialise() { + this->scalar_properties_["levelset"] = [&]() { return levelset_phi_; }; +} + //! Map particle mass and momentum to nodes template void mpm::ParticleXMPM::map_mass_momentum_to_nodes() noexcept { diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index 9b0674d99..fcf115f23 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -27,6 +27,7 @@ mpm::MPMBase::MPMBase(const std::shared_ptr& io) : mpm::MPM(io) { {"mass", VariableType::Scalar}, {"volume", VariableType::Scalar}, {"mass_density", VariableType::Scalar}, + {"levelset", VariableType::Scalar}, // Vector variables {"displacements", VariableType::Vector}, {"velocities", VariableType::Vector}, From 0af8791d059ecb39f32a7208b672b55c87966dcd Mon Sep 17 00:00:00 2001 From: yong liang Date: Sun, 4 Oct 2020 21:12:16 -0700 Subject: [PATCH 56/91] :hammer:fix the issue about friction coefficient --- include/node.h | 13 ++++++++++++- include/node_base.h | 11 +++++++++++ include/node_xmpm.tcc | 13 +++++++++++++ include/xmpm/discontinuity_point.tcc | 2 +- 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/include/node.h b/include/node.h index 5895e6a26..45439bb22 100644 --- a/include/node.h +++ b/include/node.h @@ -291,7 +291,18 @@ class Node : public NodeBase { void update_discontinuity_property(bool update, const std::string& property, const Eigen::MatrixXd& property_value, unsigned discontinuity_id, - unsigned nprops) noexcept override; + unsigned nprops) noexcept; + + //! assign nodal property at the nodes from particle for discontinuity + //! \param[in] update A boolean to update (true) or assign (false) + //! \param[in] property Property name + //! \param[in] property_value Property quantity from the particles in the cell + //! \param[in] discontinuity_id Id of the material within the property data + //! \param[in] nprops Dimension of property (1 if scalar, Tdim if vector) + void assign_discontinuity_property(bool update, const std::string& property, + const Eigen::MatrixXd& property_value, + unsigned discontinuity_id, + unsigned nprops) noexcept; // Return data in the nodal discontinuity properties map at a specific index // \param[in] property Property name diff --git a/include/node_base.h b/include/node_base.h index 5aa06ff58..169d36f07 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -287,6 +287,17 @@ class NodeBase { const Eigen::MatrixXd& property_value, unsigned discontinuity_id, unsigned nprops) noexcept = 0; + //! Assign nodal property at the nodes from particle for discontinuity + //! \param[in] update A boolean to update (true) or assign (false) + //! \param[in] property Property name + //! \param[in] property_value Property quantity from the particles in the cell + //! \param[in] discontinuity_id Id of the material within the property data + //! \param[in] nprops Dimension of property (1 if scalar, Tdim if vector) + virtual void assign_discontinuity_property( + bool update, const std::string& property, + const Eigen::MatrixXd& property_value, unsigned discontinuity_id, + unsigned nprops) noexcept = 0; + //! Compute momentum for discontinuity //! \param[in] phase Index corresponding to the phase //! \param[in] dt Timestep in analysis diff --git a/include/node_xmpm.tcc b/include/node_xmpm.tcc index f1171b849..5beba771b 100644 --- a/include/node_xmpm.tcc +++ b/include/node_xmpm.tcc @@ -21,6 +21,19 @@ void mpm::Node::update_discontinuity_property( node_mutex_.unlock(); } +//! Assign nodal property at the nodes from particle for discontinuity +template +void mpm::Node::assign_discontinuity_property( + bool update, const std::string& property, + const Eigen::MatrixXd& property_value, unsigned discontinuity_id, + unsigned nprops) noexcept { + // Update/assign property + node_mutex_.lock(); + property_handle_->assign_property(property, discontinuity_prop_id_, + discontinuity_id, property_value, nprops); + node_mutex_.unlock(); +} + // Return data in the nodal properties map at a specific index template Eigen::MatrixXd mpm::Node::discontinuity_property( diff --git a/include/xmpm/discontinuity_point.tcc b/include/xmpm/discontinuity_point.tcc index 49aa7ff17..367f9b3cc 100644 --- a/include/xmpm/discontinuity_point.tcc +++ b/include/xmpm/discontinuity_point.tcc @@ -168,7 +168,7 @@ void mpm::discontinuity_point::assign_discontinuity_enrich() { // assign discontinuity_enrich for (unsigned i = 0; i < nodes_.size(); ++i) { nodes_[i]->assign_discontinuity_enrich(true); - nodes_[i]->update_discontinuity_property(true, "friction_coef", + nodes_[i]->assign_discontinuity_property(true, "friction_coef", friction_coef, 0, 1); } } \ No newline at end of file From 8decf2b788c1a95a3169d2fa9ddf8144b3ecf767 Mon Sep 17 00:00:00 2001 From: yong liang Date: Mon, 5 Oct 2020 15:44:41 -0700 Subject: [PATCH 57/91] :construction:compute the principal stress and strain --- include/particles/particle_base.h | 3 ++ include/particles/particle_xmpm.h | 10 +++++++ include/particles/particle_xmpm.tcc | 43 +++++++++++++++++++++++++++++ include/solvers/mpm_base.tcc | 3 ++ include/solvers/xmpm_explicit.tcc | 4 +++ 5 files changed, 63 insertions(+) diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 8404add63..9fa454792 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -318,6 +318,9 @@ class ParticleBase { //! \param[in] phivalue Signed distance function virtual void assign_levelsetphi(double phivalue){}; + //! Compute the principal stress and strain + virtual void compute_principal_stress_strain(){}; + protected: //! particleBase id Index id_{std::numeric_limits::max()}; diff --git a/include/particles/particle_xmpm.h b/include/particles/particle_xmpm.h index 11af871e9..0890e1b06 100644 --- a/include/particles/particle_xmpm.h +++ b/include/particles/particle_xmpm.h @@ -54,6 +54,9 @@ class ParticleXMPM : public Particle { //! Map internal force inline void map_internal_force() noexcept override; + //! Compute the principal stress and strain + void compute_principal_stress_strain(); + //! Compute updated position of the particle //! \param[in] dt Analysis time step //! \param[in] velocity_update Update particle velocity from nodal vel @@ -153,6 +156,13 @@ class ParticleXMPM : public Particle { private: //! level set value: phi for discontinuity double levelset_phi_{0.}; + + //! first principal stress + double first_principal_stress_{0.}; + //! first principal strain + double first_principal_strain_{0.}; + //! energy:first_principal_stress_*first_principal_strain_*0.5 + double energy_{0.}; }; // ParticleXMPM class } // namespace mpm diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index e8e237344..efb8853e7 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -25,6 +25,13 @@ mpm::ParticleXMPM::ParticleXMPM(Index id, const VectorDim& coord, template void mpm::ParticleXMPM::initialise() { this->scalar_properties_["levelset"] = [&]() { return levelset_phi_; }; + this->scalar_properties_["first_principal_stress"] = [&]() { + return first_principal_stress_; + }; + this->scalar_properties_["first_principal_strain"] = [&]() { + return first_principal_strain_; + }; + this->scalar_properties_["energy"] = [&]() { return energy_; }; } //! Map particle mass and momentum to nodes @@ -243,3 +250,39 @@ void mpm::ParticleXMPM::compute_updated_position( // Update displacement (displacement is initialized from zero) this->displacement_ += nodal_velocity * dt; } + +//! Compute the principal stress and strain +template +void mpm::ParticleXMPM::compute_principal_stress_strain() { + + Eigen::Matrix3d strain_tensor; + strain_tensor(0, 0) = strain_[0]; + strain_tensor(0, 1) = strain_[3] * 0.5; + strain_tensor(0, 2) = strain_[5] * 0.5; + strain_tensor(1, 0) = strain_[3] * 0.5; + strain_tensor(1, 1) = strain_[1]; + strain_tensor(1, 2) = strain_[4] * 0.5; + strain_tensor(2, 0) = strain_[5] * 0.5; + strain_tensor(2, 1) = strain_[4] * 0.5; + strain_tensor(2, 2) = strain_[2]; + + Eigen::Matrix3d stress_tensor; + stress_tensor(0, 0) = stress_[0]; + stress_tensor(0, 1) = stress_[3]; + stress_tensor(0, 2) = stress_[5]; + stress_tensor(1, 0) = stress_[3]; + stress_tensor(1, 1) = stress_[1]; + stress_tensor(1, 2) = stress_[4]; + stress_tensor(2, 0) = stress_[5]; + stress_tensor(2, 1) = stress_[4]; + stress_tensor(2, 2) = stress_[2]; + + Eigen::EigenSolver estrain(strain_tensor); + Eigen::EigenSolver estress(stress_tensor); + + first_principal_strain_ = estrain.pseudoEigenvalueMatrix()(0); + first_principal_stress_ = estress.pseudoEigenvalueMatrix()(0); + auto strain_value = estrain.pseudoEigenvectors(); + auto stress_value = estress.pseudoEigenvectors(); + energy_ = 0.5 * first_principal_strain_ * first_principal_stress_; +} diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index fcf115f23..8c606bf1a 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -28,6 +28,9 @@ mpm::MPMBase::MPMBase(const std::shared_ptr& io) : mpm::MPM(io) { {"volume", VariableType::Scalar}, {"mass_density", VariableType::Scalar}, {"levelset", VariableType::Scalar}, + {"first_principal_stress", VariableType::Scalar}, + {"first_principal_strain", VariableType::Scalar}, + {"energy", VariableType::Scalar}, // Vector variables {"displacements", VariableType::Vector}, {"velocities", VariableType::Vector}, diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index d509c9d22..6707c03ba 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -131,6 +131,10 @@ bool mpm::XMPMExplicit::solve() { // Initialise nodal properties mesh_->initialise_nodal_properties(); + // Iterate over each particle to compute the principal stress and strain + mesh_->iterate_over_particles( + std::bind(&mpm::ParticleBase::compute_principal_stress_strain, + std::placeholders::_1)); // locate points of discontinuity mesh_->locate_discontinuity(); From 2d64ccd27c701b60ddff4b0e7c87e7c5429e1c56 Mon Sep 17 00:00:00 2001 From: yong liang Date: Tue, 6 Oct 2020 15:35:57 -0700 Subject: [PATCH 58/91] :hammer:velocity update by the enriched nodes --- include/particles/particle_xmpm.tcc | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index efb8853e7..468b19ddc 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -208,6 +208,8 @@ void mpm::ParticleXMPM::compute_updated_position( } // Acceleration update if (!velocity_update) { + nodal_velocity.setZero(); + double shapefn_enrich = 0; // Get interpolated nodal acceleration Eigen::Matrix nodal_acceleration = Eigen::Matrix::Zero(); @@ -219,14 +221,13 @@ void mpm::ParticleXMPM::compute_updated_position( nodes_[i]->discontinuity_property("mass_enrich", 1)(0, 0); if (nodal_mass < tolerance) continue; - auto force = nodes_[i]->internal_force(phase) + - sgn(levelset_phi_) * nodes_[i]->discontinuity_property( - "internal_force_enrich", 3) + - nodes_[i]->external_force(phase) + - sgn(levelset_phi_) * nodes_[i]->discontinuity_property( - "external_force_enrich", 3); - - nodal_acceleration += shapefn_[i] * force / nodal_mass; + nodal_velocity += + shapefn_[i] * + (nodes_[i]->momentum(phase) + + sgn(levelset_phi_) * + nodes_[i]->discontinuity_property("momenta_enrich", 3)) / + nodal_mass; + shapefn_enrich += shapefn_[i]; } else { double nodal_mass = nodes_[i]->mass(phase); if (nodal_mass < tolerance) continue; @@ -239,7 +240,8 @@ void mpm::ParticleXMPM::compute_updated_position( } // Update particle velocity from interpolated nodal acceleration - this->velocity_ += nodal_acceleration * dt; + this->velocity_ = nodal_velocity + (1 - shapefn_enrich) * this->velocity_ + + nodal_acceleration * dt; } // Update particle velocity using interpolated nodal velocity else From 026ca2a5c9aeefa6d03f1752a9bef761959f1a1e Mon Sep 17 00:00:00 2001 From: yliang-sn Date: Wed, 8 Sep 2021 09:37:14 -0700 Subject: [PATCH 59/91] xmpm solver --- include/xmpm/discontinuity_element.h | 105 +++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 include/xmpm/discontinuity_element.h diff --git a/include/xmpm/discontinuity_element.h b/include/xmpm/discontinuity_element.h new file mode 100644 index 000000000..07d85b8d5 --- /dev/null +++ b/include/xmpm/discontinuity_element.h @@ -0,0 +1,105 @@ +#ifndef MPM_DISCONTINUITY_ELEMENT_H_ +#define MPM_DISCONTINUITY_ELEMENT_H_ + +#include +#include +#include + +#include + +//! MPM namespace +namespace mpm { + +// Element enrich type +enum EnrichType { + Regular = 1, + Crossed = 2, + Tip = 3, + NeighbourTip_1 = 4, + NeighbourTip_2 = 5, + NeighbourTip_3 = 6, + PotentialTip = 7, + NextTip = 8, + NeighbourNextTip_1 = 9, + NeighbourNextTip_2 = 10, + NeighbourNextTip_3 = 11, + InitialTip = 12 +}; + +// Discontinuity element class +//! \brief Base class for Discontinuity element +//! \tparam Tdim Dimension +template +class DiscontinuityElement { + public: + //! Define a vector of size dimension + using VectorDim = Eigen::Matrix; + //! Default constructor + DiscontinuityElement(mpm::EnrichType type) { enrich_type_ = type; }; + + //! Destructor + virtual ~DiscontinuityElement(){}; + + void initialize() { + enrich_type_ = mpm::EnrichType::Regular; + normal_.setZero(); + d_ = 0; + area_ = 0; + cohesion_cor_ = VectorDim::Ones() * std::numeric_limits::max(); + } + + //! Assign discontinuity element type + void assign_element_type(mpm::EnrichType type) { enrich_type_ = type; } + + //! assign the normal direction of the discontinuity in the cell + //! \param[in] the normal direction + void assign_normal_discontinuity(VectorDim normal) { normal_ = normal; }; + + //! assign constant value of the discontinuity plane equation + //! \param[in] the constant value + void assign_d(double d) { d_ = d; }; + + //! assign the area of the discontinuity in the cell + //! \param[in] the area + void assign_area(double area) { area_ = area; }; + + //! assign the center of the discontinuity in the cell + //! \param[in] the area + void assign_cohesion_cor(VectorDim cor) { cohesion_cor_ = cor; }; + + //! return enriched type + unsigned element_type() { return enrich_type_; } + + //! return normal_discontinuity + VectorDim normal_discontinuity() { return normal_; } + + //! return d + double d_discontinuity() { return d_; } + + //! return area + double area() { return area_; } + + //! return the centroid + VectorDim cohesion_cor() { return cohesion_cor_; } + + private: + // default enrich type + mpm::EnrichType enrich_type_; + + // normal direction + VectorDim normal_; + + // constant value of the discontinuity plane equation a*x + b*y + c*z + d = 0 + double d_; + + // the section area of the crossed cell + double area_{0}; + + // the center of the discontinuity + VectorDim cohesion_cor_ = + VectorDim::Ones() * std::numeric_limits::max(); +}; + +} // namespace mpm + +#endif // MPM_QUADRATURE_BASE_H_ From c4140eacc1a288ddf9d8708d1d7299f44a485443 Mon Sep 17 00:00:00 2001 From: yliang-sn Date: Wed, 8 Sep 2021 09:37:43 -0700 Subject: [PATCH 60/91] xmpm solver --- cmake/FindKaHIP.cmake | 2 +- include/cell.h | 77 ++ include/cell.tcc | 389 ++++++ include/hdf5_particle.h | 2 + include/materials/material.h | 11 + include/materials/mohr_coulomb.h | 21 + include/materials/mohr_coulomb.tcc | 51 + include/materials/norsand.h | 18 + include/mesh.h | 78 +- include/mesh.tcc | 1498 ++++++++++++++++++++++- include/node.h | 25 +- include/node_base.h | 16 + include/node_xmpm.tcc | 256 +++- include/particles/particle.h | 3 + include/particles/particle.tcc | 14 + include/particles/particle_base.h | 28 + include/particles/particle_xmpm.h | 54 + include/particles/particle_xmpm.tcc | 586 ++++++++- include/solvers/mpm_base.h | 3 + include/solvers/mpm_base.tcc | 5 +- include/solvers/mpm_explicit.tcc | 24 +- include/solvers/mpm_scheme/mpm_scheme.h | 2 + include/solvers/xmpm_explicit.h | 38 +- include/solvers/xmpm_explicit.tcc | 386 ++++-- include/xmpm/discontinuity_3d.h | 8 +- include/xmpm/discontinuity_3d.tcc | 17 +- include/xmpm/discontinuity_base.h | 61 +- include/xmpm/discontinuity_base.tcc | 54 +- include/xmpm/discontinuity_point.tcc | 75 +- src/discontinuity.cc | 3 +- src/nodal_properties.cc | 2 + 31 files changed, 3627 insertions(+), 180 deletions(-) diff --git a/cmake/FindKaHIP.cmake b/cmake/FindKaHIP.cmake index 6063ffff3..d7ff19bfb 100644 --- a/cmake/FindKaHIP.cmake +++ b/cmake/FindKaHIP.cmake @@ -46,7 +46,7 @@ if (MPI_CXX_FOUND) DOC "Directory where the KaHIP header files are located" ) - find_library(KAHIP_LIBRARY kahip + find_library(KAHIP_LIBRARY libkahip.a HINTS ${KAHIP_ROOT}/deploy $ENV{KAHIP_ROOT}/deploy /usr/local/KaHIP/deploy NO_DEFAULT_PATH DOC "Directory where the KaHIP library is located" diff --git a/include/cell.h b/include/cell.h index 2380b7d3d..207a947fd 100644 --- a/include/cell.h +++ b/include/cell.h @@ -1,6 +1,7 @@ #ifndef MPM_CELL_H_ #define MPM_CELL_H_ +#include #include #include #include @@ -12,6 +13,7 @@ #include "Eigen/LU" #include "affine_transform.h" +#include "discontinuity_element.h" #include "element.h" #include "geometry.h" #include "logger.h" @@ -217,6 +219,79 @@ class Cell { //! Return previous mpi rank unsigned previous_mpirank() const; + //! Assign discontinuity element type + void assign_type_discontinuity(mpm::EnrichType type); + + //! Initialize discontinuity element properties + void initialise_element_properties_discontinuity(); + + //! assign the normal direction of the discontinuity in the cell + //! \param[in] the normal direction + void assign_normal_discontinuity(VectorDim normal); + + //! assign the constant parameters of the discontinuity in the cell + //! \param[in] the constant parameters + void assign_d_discontinuity(double d) { + this->discontinuity_element_->assign_d(d); + }; + + //! assign the normal direction of the discontinuity in the cell + //! \param[in] the normal direction + //! \param[in] the plane constant + void assign_normal_discontinuity(VectorDim normal, double d); + + //! return the normal direction of the discontinuity in the cell + VectorDim normal_discontinuity() { + return discontinuity_element_->normal_discontinuity(); + }; + + //! Return discontinuity element type + unsigned element_type_discontinuity(); + + //! potential tip element + void potential_tip_element(); + + //! determine tip element + void tip_element(); + // //! change the nodal discontinuity enrich to true for the TIP cell + // void assign_tipcell_nodal_discontinuity(bool status); + + //! compute normal vector of discontinuity by the nodal level set values + void compute_normal_vector_discontinuity(); + + //! compute gradient of the nodal level set values + VectorDim compute_gradient_levelset(); + + //! compute the discontinuity plane by the nodal level set values + //! \param[in] from the enriched nodes + void compute_plane_discontinuity(bool enrich); + + //! update nodal nodal level set + void compute_discontinuity_point(std::vector& coordinates); + + // product of the nodal level set value + double product_levelset(); + + // Initialise the cells in node + void add_cell_in_node(); + + // return the constant value of the discontinuity plane + double d_discontinuity() { + return this->discontinuity_element_->d_discontinuity(); + } + // determine the celltype by the nodal level set + void determine_crossed(); + + // compute the nodal level set values by plane equations + void compute_nodal_levelset_equation(); + + // compute the area of the crossed cell + void compute_area_discontinuity(); + + double discontinuity_area() { return this->discontinuity_element_->area(); } + + void assign_cohesion_area(); + private: //! Approximately check if a point is in a cell //! \param[in] point Coordinates of point @@ -266,6 +341,8 @@ class Cell { std::map face_normals_; //! Logger std::unique_ptr console_; + //! discontinuity element + std::shared_ptr> discontinuity_element_{nullptr}; }; // Cell class } // namespace mpm diff --git a/include/cell.tcc b/include/cell.tcc index 05f839dab..16804e502 100644 --- a/include/cell.tcc +++ b/include/cell.tcc @@ -82,6 +82,30 @@ void mpm::Cell::assign_quadrature(unsigned nquadratures) { this->quadrature_ = element_->quadrature(nquadratures); } +//! Assign discontinuity element type +template +void mpm::Cell::assign_type_discontinuity(mpm::EnrichType type) { + if (nparticles() == 0 && type != mpm::EnrichType::NeighbourTip_2) + type = mpm::EnrichType::Regular; + if (discontinuity_element_ == nullptr) + discontinuity_element_ = + std::make_shared>(type); + else + discontinuity_element_->assign_element_type(type); +} +// Initialize discontinuity element type +template +void mpm::Cell::initialise_element_properties_discontinuity() { + if (discontinuity_element_ == nullptr) return; + discontinuity_element_->initialize(); +} + +// Return discontinuity element type +template +unsigned mpm::Cell::element_type_discontinuity() { + if (discontinuity_element_ == nullptr) return mpm::EnrichType::Regular; + return discontinuity_element_->element_type(); +} //! Assign quadrature template std::vector> mpm::Cell::generate_points() { @@ -844,3 +868,368 @@ template inline unsigned mpm::Cell::previous_mpirank() const { return this->previous_mpirank_; } + +//! potential tip element +template +void mpm::Cell::potential_tip_element() { + if (this->discontinuity_element_ == nullptr) return; + if (this->discontinuity_element_->element_type() != + mpm::EnrichType::NeighbourTip_1) + return; + if (this->nparticles() == 0) return; + + if (product_levelset() < 0) + this->discontinuity_element_->assign_element_type( + mpm::EnrichType::PotentialTip); + + // for (unsigned i = 0; i < nodes_.size(); ++i) { + // if (nodes_[i]->discontinuity_enrich()) + // nodes_[i]->assign_discontinuity_enrich(false); + // } +} + +//! determine tip element +template +void mpm::Cell::tip_element() { + if (this->discontinuity_element_ == nullptr) return; + if (this->discontinuity_element_->element_type() != mpm::EnrichType::Crossed) + return; + + for (unsigned i = 0; i < nodes_.size(); ++i) { + if (nodes_[i]->discontinuity_enrich()) continue; + this->discontinuity_element_->assign_element_type(mpm::EnrichType::Tip); + } +} + +// //! change the nodal discontinuity enrich to true for the TIP cell +// template +// void mpm::Cell::assign_tipcell_nodal_discontinuity(bool status) { +// if (this->discontinuity_element_ == nullptr) return; +// if (this->discontinuity_element_->element_type() != mpm::EnrichType::Tip) +// return; + +// for (unsigned i = 0; i < nodes_.size(); ++i) { +// if (nodes_[i]->discontinuity_enrich()) continue; +// nodes_[i]->assign_discontinuity_enrich(status); +// } +// } + +//! potential tip element +template +void mpm::Cell::compute_discontinuity_point( + std::vector& coordinates) { + + // if (this->discontinuity_element_->area() == 0) + // compute_area_discontinuity(); + std::vector> intersections_list; + + Eigen::Matrix center = + this->discontinuity_element_->cohesion_cor(); + int index_area[6][5] = {{0, 1, 2, 3, 0}, {0, 1, 5, 4, 0}, {1, 2, 6, 5, 1}, + {3, 2, 6, 7, 3}, {0, 3, 7, 4, 0}, {4, 5, 6, 7, 4}}; + for (int i = 0; i < 6; i++) { + std::vector> intersections; + for (int j = 0; j < 4; j++) { + double phi[2]; + phi[0] = nodes_[index_area[i][j]]->discontinuity_property("levelset_phi", + 1)(0, 0); + phi[1] = nodes_[index_area[i][j + 1]]->discontinuity_property( + "levelset_phi", 1)(0, 0); + if (phi[0] * phi[1] >= 0) continue; + Eigen::Matrix intersection; + Eigen::Matrix cor0 = + nodes_[index_area[i][j]]->coordinates(); + Eigen::Matrix cor1 = + nodes_[index_area[i][j + 1]]->coordinates(); + intersection = cor0 * std::abs(phi[1] / ((phi[1] - phi[0]))) + + cor1 * std::abs(phi[0] / ((phi[1] - phi[0]))); + + intersections.push_back(intersection); + intersections_list.push_back(intersection); + } + // if (intersections.size() != 2) continue; + // if (this->discontinuity_element_->area() == 0) continue; + // Eigen::Matrix cor = + // 1.0 / 3 * (intersections[0] + intersections[1] + center); + // double length = (cor - center).norm(); + // if (length < 0.25 * mean_length_) continue; + // coordinates.push_back(cor); + } + + // if (this->discontinuity_element_->area() != 0) { + // coordinates.push_back(this->discontinuity_element_->cohesion_cor()); + // } else { + // if (intersections_list.size() < 3) return; + + // Eigen::Matrix cor; + // cor.setZero(); + // for (int i = 0; i < intersections_list.size(); i++) + // cor += 1.0 / intersections_list.size() * intersections_list[i]; + // coordinates.push_back(cor); + // } + if (intersections_list.size() < 3) return; + + Eigen::Matrix cor; + cor.setZero(); + for (int i = 0; i < intersections_list.size(); i++) + cor += 1.0 / intersections_list.size() * intersections_list[i]; + coordinates.push_back(cor); +} + +//! assign the normal direction of the discontinuity in the cell +template +void mpm::Cell::assign_normal_discontinuity(VectorDim normal) { + this->discontinuity_element_->assign_normal_discontinuity(normal); +} + +//! assign the normal direction of the discontinuity in the cell +template +void mpm::Cell::assign_normal_discontinuity(VectorDim normal, double d) { + this->discontinuity_element_->assign_normal_discontinuity(normal); + this->discontinuity_element_->assign_d(d); +} + +//! compute normal vector of discontinuity by the nodal level set values +template +void mpm::Cell::compute_normal_vector_discontinuity() { + VectorDim normal; + normal.setZero(); + // determine the discontinuity plane by the enriched nodes + for (unsigned i = 0; i < nodes_.size(); ++i) { + double phi = nodes_[i]->discontinuity_property("levelset_phi", 1)(0, 0); + for (unsigned int j = 0; j < Tdim; j++) { + normal[j] += phi * dn_dx_centroid_(i, j); + } + } + normal.normalize(); + this->discontinuity_element_->assign_normal_discontinuity(normal); +} + +//! compute gradient of the nodal level set values +template +Eigen::Matrix mpm::Cell::compute_gradient_levelset() { + VectorDim gradient; + gradient.setZero(); + // determine the discontinuity plane by the enriched nodes + for (unsigned i = 0; i < nodes_.size(); ++i) { + double phi = nodes_[i]->discontinuity_property("levelset_phi", 1)(0, 0); + for (unsigned int j = 0; j < Tdim; j++) { + gradient[j] += phi * dn_dx_centroid_(i, j); + } + } + + return gradient; +} + +//! assign nodal normal vector +template +void mpm::Cell::add_cell_in_node() { + for (unsigned i = 0; i < nodes_.size(); ++i) { + nodes_[i]->add_cell_id(id_); + } +} + +template +void mpm::Cell::compute_plane_discontinuity(bool enrich) { + int enriched_node = 0; + auto normal = discontinuity_element_->normal_discontinuity(); + double dis = 0; + // determine the discontinuity plane by the enriched nodes + for (unsigned i = 0; i < nodes_.size(); ++i) { + if (enrich) { + if (!nodes_[i]->discontinuity_enrich()) continue; + } + enriched_node++; + auto node_coordinate = nodes_[i]->coordinates(); + for (unsigned int j = 0; j < Tdim; j++) + dis -= node_coordinate[j] * normal[j]; + dis = nodes_[i]->discontinuity_property("levelset_phi", 1)(0, 0) + dis; + } + // update the level set values of the unenriched nodes + dis = dis / enriched_node; + this->discontinuity_element_->assign_d(dis); +} + +// product of the nodal level set value +template +double mpm::Cell::product_levelset() { + double levelset_max = -std::numeric_limits::max(); + double levelset_min = std::numeric_limits::max(); + for (unsigned i = 0; i < nodes_.size(); ++i) { + + double levelset = + nodes_[i]->discontinuity_property("levelset_phi", 1)(0, 0); + levelset_max = levelset > levelset_max ? levelset : levelset_max; + levelset_min = levelset < levelset_min ? levelset : levelset_min; + } + return levelset_max * levelset_min; +} + +template +void mpm::Cell::determine_crossed() { + + //if (this->nparticles() == 0) return; + + double max_phi = -1e15, min_phi = 1e15; + + for (unsigned i = 0; i < nodes_.size(); ++i) { + double phi = nodes_[i]->discontinuity_property("levelset_phi", 1)(0, 0); + if (phi > max_phi) max_phi = phi; + if (phi < min_phi) min_phi = phi; + } + // std::ofstream testnormal("crossed cell.txt", std::ios::app); + // testnormal << centroid_[0] << "\t" << max_phi << "\t" << min_phi << "\t" + // << max_phi * min_phi << std::endl; + this->assign_type_discontinuity(mpm::EnrichType::Regular); + if (max_phi * min_phi >= 0) return; + + this->assign_type_discontinuity(mpm::EnrichType::Crossed); +} + +template +void mpm::Cell::compute_nodal_levelset_equation() { + for (unsigned i = 0; i < nodes_.size(); ++i) { + auto coor = nodes_[i]->coordinates(); + double phi = 0; + for (unsigned int j = 0; j < Tdim; j++) + phi += coor[j] * this->discontinuity_element_->normal_discontinuity()[j]; + phi += this->discontinuity_element_->d_discontinuity(); + Eigen::Matrix phi_matrix; + phi_matrix(0, 0) = phi; + nodes_[i]->assign_discontinuity_property(true, "levelset_phi", phi_matrix, + 0, 1); + } +} + +template +void mpm::Cell::compute_area_discontinuity() { + + // if(this->id() == 1671) + // int a = 0; + + if (this->discontinuity_element_ == nullptr) return; + if (this->discontinuity_element_->element_type() != mpm::EnrichType::Crossed) + return; + // compute the level set values + Eigen::VectorXd phi_list(nnodes()); + phi_list.setZero(); + + auto normal = this->discontinuity_element_->normal_discontinuity(); + auto d = this->discontinuity_element_->d_discontinuity(); + for (int i = 0; i < nodes_.size(); ++i) { + phi_list[i] = normal.dot(nodes_[i]->coordinates()) + d; + } + // determine the intersections + std::vector> intersections; + + // node id of the 12 edges of one cell + int index_line[13][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 0}, {0, 4}, {1, 5}, + {2, 6}, {3, 7}, {4, 5}, {5, 6}, {6, 7}, {7, 4}}; + for (int i = 0; i < 12; ++i) { + if (phi_list[index_line[i][0]] * phi_list[index_line[i][1]] >= 0) continue; + + Eigen::Matrix intersection; + Eigen::Matrix cor0 = + nodes_[index_line[i][0]]->coordinates(); + Eigen::Matrix cor1 = + nodes_[index_line[i][1]]->coordinates(); + intersection = cor0 * std::abs(phi_list[index_line[i][1]] / + ((phi_list[index_line[i][1]] - + phi_list[index_line[i][0]]))) + + cor1 * std::abs(phi_list[index_line[i][0]] / + ((phi_list[index_line[i][1]] - + phi_list[index_line[i][0]]))); + + intersections.push_back(intersection); + } + if (intersections.size() < 3) return; + Eigen::Matrix average_cor; + average_cor.setZero(); + for (int i = 0; i < intersections.size(); ++i) + average_cor += intersections[i]; + + average_cor /= intersections.size(); + + // compute angle + // obtain e1 e2 of the local coordinate system + Eigen::Matrix e1 = + (intersections[0] - average_cor).normalized(); + Eigen::Matrix e2 = normal.cross(e1).normalized(); + // the angle and the order of the intersections + Eigen::VectorXd angles(intersections.size()); + angles.setZero(); + Eigen::VectorXd orders(intersections.size()); + orders.setZero(); + + for (int i = 1; i < intersections.size(); ++i) { + double costh = (intersections[i] - average_cor).normalized().dot(e1); + double sinth = (intersections[i] - average_cor).normalized().dot(e2); + + costh = costh > 1 ? 1 : costh; + costh = costh < -1 ? -1 : costh; + + double theta = std::acos(costh); + + if (sinth < 0) theta = 2 * M_PI - theta; + + angles[i] = theta; + } + // compute orders + for (int i = 1; i < intersections.size(); ++i) { + for (int j = 0; j < intersections.size(); j++) { + if (angles[i] > angles[j]) orders[i] += 1; + } + } + + // exchange intersections + auto intersections_copy = intersections; + for (int i = 1; i < intersections.size(); ++i) + intersections[orders[i]] = intersections_copy[i]; + + // compute area + double area = 0.0; + Eigen::Matrix subcenters; + subcenters.setZero(); + for (int i = 0; i < intersections.size() - 2; ++i) { + // the coordinates of the triangle + Eigen::Matrix cor0 = intersections[0]; + Eigen::Matrix cor1 = intersections[i + 1]; + Eigen::Matrix cor2 = intersections[i + 2]; + double subarea = + std::abs(0.5 * (cor1 - cor0).cross(cor2 - cor0).dot(normal)); + area += subarea; + subcenters += subarea * 1 / 3 * (cor0 + cor1 + cor2); + } + subcenters = subcenters / area; + + this->discontinuity_element_->assign_area(area); + this->discontinuity_element_->assign_cohesion_cor(subcenters); +} + +template +void mpm::Cell::assign_cohesion_area() { + + auto centers = this->discontinuity_element_->cohesion_cor(); + auto area = this->discontinuity_element_->area(); + + const Eigen::Matrix zeros = + Eigen::Matrix::Zero(); + Eigen::Matrix xi; + + // std::ofstream crossedtxt("crossed.txt", std::ios::app); + // crossedtxt << id() << " " << centroid_[0] << " " << centroid_[1] << " " + // << std::endl; + if (!this->is_point_in_cell(centers, &xi)) return; + + auto shapefn = element_->shapefn(xi, zeros, zeros); + Eigen::Matrix node_area; + for (int i = 0; i < nodes_.size(); i++) { + + node_area(0, 0) = shapefn[i] * area; + nodes_[i]->update_discontinuity_property(true, "cohesion_area", node_area, + 0, 1); + } + // std::ofstream areatxt("area.txt", std::ios::app); + // areatxt << id() << " " << centroid_[0] << " " << centroid_[1] << " " + // << area << std::endl; +} \ No newline at end of file diff --git a/include/hdf5_particle.h b/include/hdf5_particle.h index b5ebd54d5..bce9028f3 100644 --- a/include/hdf5_particle.h +++ b/include/hdf5_particle.h @@ -44,6 +44,8 @@ typedef struct HDF5Particle { unsigned nstate_vars; // State variables (init to zero) double svars[20] = {0}; + // level set values + double levelset_phi{0}; } HDF5Particle; namespace hdf5 { diff --git a/include/materials/material.h b/include/materials/material.h index 2e0d9fefb..56c6ee628 100644 --- a/include/materials/material.h +++ b/include/materials/material.h @@ -78,6 +78,17 @@ class Material { const ParticleBase* ptr, mpm::dense_map* state_vars) = 0; + //! return Plastic stiffness matrix + //! \param[in] stress Stress + //! \param[in] state_vars History-dependent state variables + //! \param[in] the yield status + virtual Matrix6x6 dp(const Vector6d& stress, mpm::dense_map* state_vars, + bool& status) { + return Matrix6x6::Zero(); + } + //! return Elastic stiffness matrix + virtual Matrix6x6 de() { return Matrix6x6::Zero(); } + protected: //! material id unsigned id_{std::numeric_limits::max()}; diff --git a/include/materials/mohr_coulomb.h b/include/materials/mohr_coulomb.h index 3784ea99c..90a2344bb 100644 --- a/include/materials/mohr_coulomb.h +++ b/include/materials/mohr_coulomb.h @@ -85,6 +85,25 @@ class MohrCoulomb : public Material { Vector6d* df_dsigma, Vector6d* dp_dsigma, double* dp_dq, double* softening); + //! return Plastic stiffness matrix + //! \param[in] stress Stress + //! \param[in] state_vars History-dependent state variables + //! \param[in] the yield status + virtual Matrix6x6 dp(const Vector6d& stress, mpm::dense_map* state_vars, + bool& status) { + status = compute_plastic_tensor(stress, state_vars); + return dp_; + } + + //! Compute plastic tensor + //! \param[in] stress Stress + //! \param[in] state_vars History-dependent state variables + bool compute_plastic_tensor(const Vector6d& stress, + mpm::dense_map* state_vars); + + //! return Elastic stiffness matrix + Matrix6x6 de() { return de_; } + protected: //! material id using Material::id_; @@ -99,6 +118,8 @@ class MohrCoulomb : public Material { //! Elastic stiffness matrix Matrix6x6 de_; + //! Plastic stiffness matrix + Matrix6x6 dp_; //! Density double density_{std::numeric_limits::max()}; //! Youngs modulus diff --git a/include/materials/mohr_coulomb.tcc b/include/materials/mohr_coulomb.tcc index 165a92634..5e5ab3a01 100644 --- a/include/materials/mohr_coulomb.tcc +++ b/include/materials/mohr_coulomb.tcc @@ -331,7 +331,11 @@ Eigen::Matrix mpm::MohrCoulomb::compute_stress( const ParticleBase* ptr, mpm::dense_map* state_vars) { // Get equivalent plastic deviatoric strain const double pdstrain = (*state_vars).at("pdstrain"); + // Update MC parameters using a linear softening rule + (*state_vars).at("phi") = phi_peak_; + (*state_vars).at("psi") = psi_peak_; + (*state_vars).at("cohesion") = cohesion_peak_; if (softening_ && pdstrain > pdstrain_peak_) { if (pdstrain < pdstrain_residual_) { (*state_vars).at("phi") = @@ -463,3 +467,50 @@ Eigen::Matrix mpm::MohrCoulomb::compute_stress( return updated_stress; } + +//! compute the acoustic tensor +template +bool mpm::MohrCoulomb::compute_plastic_tensor( + const Vector6d& stress, mpm::dense_map* state_vars) { + //------------------------------------------------------------------------- + // Compute yield function based on the stress + Eigen::Matrix yield_function; + auto yield_type = this->compute_yield_state(&yield_function, (*state_vars)); + // Return the updated stress in elastic state + if (yield_type == mpm::mohrcoulomb::FailureState::Elastic) { + return false; + } + //------------------------------------------------------------------------- + // Compute df_dsigma dp_dsigma + double softening = 0.; + double dp_dq = 0.; + Vector6d df_dsigma = Vector6d::Zero(); + Vector6d dp_dsigma = Vector6d::Zero(); + this->compute_df_dp(yield_type, state_vars, stress, &df_dsigma, &dp_dsigma, + &dp_dq, &softening); + //------------------------------------------------------------------------- + // Compute the acoustic tensor + Eigen::Matrix de_dpdsigma = Eigen::Matrix::Zero(); + for (int i = 0; i < 6; i++) { + for (int j = 0; j < 3; j++) de_dpdsigma(i) += de_(i, j) * dp_dsigma(j); + for (int j = 3; j < 6; j++) de_dpdsigma(i) += 2 * de_(i, j) * dp_dsigma(j); + } + double dfdsigma_de_dpdsigma = 0; + for (int j = 0; j < 3; j++) + dfdsigma_de_dpdsigma += df_dsigma(j) * de_dpdsigma(j); + for (int j = 3; j < 6; j++) + dfdsigma_de_dpdsigma += 2 * df_dsigma(j) * de_dpdsigma(j); + + Eigen::Matrix de_dfdsigma = Eigen::Matrix::Zero(); + for (int i = 0; i < 6; i++) { + for (int j = 0; j < 3; j++) de_dfdsigma(i) += de_(i, j) * df_dsigma(j); + for (int j = 3; j < 6; j++) de_dfdsigma(i) += 2 * de_(i, j) * df_dsigma(j); + } + + for (int i = 0; i < 6; i++) + for (int j = 0; j < 6; j++) + dp_(i, j) = + de_(i, j) - de_dpdsigma(i) * de_dfdsigma(j) / dfdsigma_de_dpdsigma; + + return true; +} \ No newline at end of file diff --git a/include/materials/norsand.h b/include/materials/norsand.h index d73888b8e..f4d074883 100644 --- a/include/materials/norsand.h +++ b/include/materials/norsand.h @@ -55,6 +55,24 @@ class NorSand : public Material { Vector6d compute_stress(const Vector6d& stress, const Vector6d& dstrain, const ParticleBase* ptr, mpm::dense_map* state_vars) override; + //! return Plastic stiffness matrix + //! \param[in] stress Stress + //! \param[in] state_vars History-dependent state variables + //! \param[in] the yield status + virtual Matrix6x6 dp(const Vector6d& stress, mpm::dense_map* state_vars, + bool& status) { + //------------------------------------------------------------------------- + // Compute yield function based on the stress + double yield_function; + auto yield_type = + this->compute_yield_state(&yield_function, stress, state_vars); + // Return the updated stress in elastic state + if (yield_type == mpm::norsand::FailureState::Elastic) { + status = false; + } + compute_plastic_tensor(stress, state_vars); + return dp_; + } protected: //! material id diff --git a/include/mesh.h b/include/mesh.h index 8d29af6b9..29a33c58f 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -401,8 +401,10 @@ class Mesh { //! 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 type of HDF5 file to generate particles class //! \retval status Status of reading HDF5 output - bool read_particles_hdf5(unsigned phase, const std::string& filename); + bool read_particles_hdf5(unsigned phase, const std::string& filename, + const std::string& particle_type); //! Return HDF5 particles //! \retval particles_hdf5 Vector of HDF5 particles @@ -468,12 +470,11 @@ class Mesh { // Create the nodal properties' map for discontinuity void create_nodal_properties_discontinuity(); - //! Initialise discontinuities - //! \param[in] discontinuities List of discontinuities - void initialise_discontinuities( - const std::map>>& - discontinuities) { - discontinuities_ = discontinuities; + //! Initialise discontinuity + //! \param[in] discontinuity List of discontinuity + void initialise_discontinuity( + const std::shared_ptr>& discontinuity) { + discontinuity_ = discontinuity; } //! Locate points of discontinuity in a cell @@ -486,12 +487,67 @@ class Mesh { //! Update the discontinuity position void compute_shapefn_discontinuity(); + //! compute the normal vector of cells + void compute_cell_normal_vector_discontinuity(); + //! compute the normal vector of enriched nodes at the discontinuity - void compute_normal_vector_discontinuity(); + void compute_nodal_normal_vector_discontinuity(); //! Initialise the level set function values void initialise_levelset_discontinuity(); + //! Initialise the nodal level set function values + void initialise_nodal_levelset_discontinuity(); + + //! solve nodal levelset values + void update_node_levelset(); + + // discontinuity growth + void update_discontinuity(); + + // find next tip element + void next_tip_element_discontinuity(); + // Initialise the cells in node + void add_cell_in_node(); + + //! remove spurious potential tip element + void spurious_potential_tip_element(); + + // assign_node_enrich + void assign_node_enrich(bool friction_coef_average, bool enrich_all); + + // update_node_enrich + void update_node_enrich(); + // the initiation of discontinuity + bool initiation_discontinuity(); + // modify the nodal levelset_phi by mls + void modify_nodal_levelset_mls(); + + void selfcontact_detection(); + + void output_discontinuity(int step) { + this->discontinuity_->output_markpoints(step); + }; + + void compute_error(); + void output_celltype(int step); + void output_force(int step); + void output_nodal_levelset(int step); + void change_mat(); + void define_levelset(); + void update_nodal_levelset(double dt); + + void output_surface(); + + void check_particle_levelset(bool particle_levelset); + + int step_{0}; + void assign_step(int step) { + step_ = step; + for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) + (*nitr)->step_ = step; + }; + private: // Read particles from file //! \param[in] pset_id Set ID of the particles @@ -560,9 +616,9 @@ class Mesh { unsigned nhalo_nodes_{0}; //! Maximum number of halo nodes unsigned ncomms_{0}; - //! discontinuities - std::map>> - discontinuities_; + //! discontinuity + std::shared_ptr> discontinuity_; + }; // Mesh class } // namespace mpm diff --git a/include/mesh.tcc b/include/mesh.tcc index a6cdf9ac7..b42423eac 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1493,7 +1493,8 @@ bool mpm::Mesh::write_particles_hdf5(unsigned phase, //! Write particles to HDF5 template bool mpm::Mesh::read_particles_hdf5(unsigned phase, - const std::string& filename) { + const std::string& filename, + const std::string& particle_type) { // Create a new file using default properties. hid_t file_id = H5Fopen(filename.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT); @@ -1516,7 +1517,7 @@ bool mpm::Mesh::read_particles_hdf5(unsigned phase, mpm::hdf5::particle::dst_sizes, dst_buf.data()); // Particle type - const std::string particle_type = (Tdim == 2) ? "P2D" : "P3D"; + // const std::string particle_type = (Tdim == 2) ? "P2D" : "P3D"; // Iterate over all HDF5 particles for (unsigned i = 0; i < nrecords; ++i) { @@ -2000,12 +2001,16 @@ void mpm::Mesh::create_nodal_properties_discontinuity() { // Create pool data for each property in the nodal properties struct // object. Properties must be named in the plural form nodal_properties_->create_property("mass_enrich", nodes_.size(), 1); + nodal_properties_->create_property("levelset_phi", nodes_.size(), 1); nodal_properties_->create_property("momenta_enrich", nrows, 1); nodal_properties_->create_property("internal_force_enrich", nrows, 1); nodal_properties_->create_property("external_force_enrich", nrows, 1); nodal_properties_->create_property("normal_unit_vectors_discontinuity", nrows, 1); nodal_properties_->create_property("friction_coef", nodes_.size(), 1); + nodal_properties_->create_property("cohesion", nodes_.size(), 1); + nodal_properties_->create_property("cohesion_area", nodes_.size(), 1); + nodal_properties_->create_property("contact_distance", nodes_.size(), 1); // Iterate over all nodes to initialise the property handle in each node // and assign its node id as the prop id in the nodal property data pool for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) @@ -2023,40 +2028,66 @@ void mpm::Mesh::initialise_nodal_properties() { //! Locate points in a cell template void mpm::Mesh::locate_discontinuity() { - for (unsigned i = 0; i < discontinuities_.size(); ++i) { - discontinuities_[i]->locate_discontinuity_mesh(cells_, map_cells_); - } + discontinuity_->locate_discontinuity_mesh(cells_, map_cells_); } //! updated_position of discontinuity template void mpm::Mesh::compute_updated_position_discontinuity(double dt) { - for (unsigned i = 0; i < discontinuities_.size(); ++i) { - discontinuities_[i]->compute_updated_position(dt); - } + discontinuity_->compute_updated_position(dt); } //! compute shape function template void mpm::Mesh::compute_shapefn_discontinuity() { - for (unsigned i = 0; i < discontinuities_.size(); ++i) { - discontinuities_[i]->compute_shapefn(); + discontinuity_->compute_shapefn(); +} + +// compute the normal vector of cells +template +void mpm::Mesh::compute_cell_normal_vector_discontinuity() { + // std::ofstream testnormal("cell_normal.txt", std::ios::app); + + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + // for oso + // if ((*citr)->element_type_discontinuity() == mpm::EnrichType::Regular) + // continue; + + (*citr)->compute_normal_vector_discontinuity(); + (*citr)->compute_plane_discontinuity(false); + + //auto normal_cell = (*citr)->normal_discontinuity(); + // testnormal << normal_cell[0] << " " << normal_cell[2] << " " + // << normal_cell[1] << std::endl; } } // compute the normal vector of enriched nodes at the discontinuity template -void mpm::Mesh::compute_normal_vector_discontinuity() { - VectorDim normal; - normal.setZero(); - for (unsigned i = 0; i < discontinuities_.size(); ++i) { - for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { +void mpm::Mesh::compute_nodal_normal_vector_discontinuity() { - discontinuities_[i]->compute_normal((*nitr)->coordinates(), normal); - - nodal_properties_->assign_property("normal_unit_vectors_discontinuity", - (*nitr)->discontinuity_prop_id(), 0, - normal, Tdim); + VectorDim normal_cell; + std::ofstream testnormal("mls_normal.txt", std::ios::app); + for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { + // for oso + if (!(*nitr)->discontinuity_enrich()) continue; + normal_cell.setZero(); + int crossed_cell = 0; + for (auto cell : (*nitr)->cells()) { + // for oso + // if (map_cells_[cell]->element_type_discontinuity() != + // mpm::EnrichType::Crossed) + // continue; + normal_cell += map_cells_[cell]->normal_discontinuity(); + crossed_cell += 1; } + if (crossed_cell == 0) continue; + normal_cell = normal_cell / crossed_cell; + + // normal_cell << 0.5,0,1; + normal_cell.normalize(); + (*nitr)->assign_discontinuity_property( + true, "normal_unit_vectors_discontinuity", normal_cell, 0, Tdim); } + // testnormal << std::endl; } // Initialise level set values particles @@ -2064,11 +2095,1428 @@ template void mpm::Mesh::initialise_levelset_discontinuity() { double phi_particle; - for (unsigned i = 0; i < discontinuities_.size(); ++i) { - for (mpm::Index j = 0; j < nparticles(); ++j) { - discontinuities_[i]->compute_levelset(particles_[j]->coordinates(), - phi_particle); - particles_[j]->assign_levelsetphi(phi_particle); + + for (mpm::Index j = 0; j < nparticles(); ++j) { + discontinuity_->compute_levelset(particles_[j]->coordinates(), + phi_particle); + particles_[j]->assign_levelsetphi(phi_particle); + } +} + +// Initialise nodal level set values particles +template +void mpm::Mesh::initialise_nodal_levelset_discontinuity() { + + Eigen::Matrix phi; + phi.setZero(); + double phi_node; + for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { + discontinuity_->compute_levelset((*nitr)->coordinates(), phi_node); + phi(0, 0) = phi_node; + (*nitr)->assign_discontinuity_property(true, "levelset_phi", phi, 0, 1); + } +} + +//! solve nodal levelset values +template +void mpm::Mesh::update_node_levelset() { + for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) + (*nitr)->update_levelset(); +} + +// discontinuity growth +template +void mpm::Mesh::update_discontinuity() { + + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + if ((*citr)->element_type_discontinuity() == mpm::EnrichType::PotentialTip) + (*citr)->assign_type_discontinuity(mpm::EnrichType::NeighbourTip_1); + } + + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + if ((*citr)->element_type_discontinuity() != mpm::EnrichType::NextTip) + continue; + // compute nodal normal direction and find neighbour cells + for (auto node : (*citr)->nodes()) { + + bool virtual_enrich = false; + for (auto cell : node->cells()) { + if (map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Tip && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Crossed) + continue; + virtual_enrich = true; + break; + } + if (virtual_enrich) { + // node->assign_discontinuity_enrich(true); + continue; + } + + for (auto cell : node->cells()) { + if (map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NextTip) + map_cells_[cell]->assign_type_discontinuity( + mpm::EnrichType::NeighbourNextTip_1); + } + + VectorDim normal_cell; + normal_cell.setZero(); + int crossed_cell = 0; + for (auto cell : node->cells()) { + if (map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NextTip) + continue; + normal_cell += map_cells_[cell]->normal_discontinuity(); + crossed_cell += 1; + } + + normal_cell = normal_cell / crossed_cell; + normal_cell.normalize(); + node->assign_discontinuity_property( + true, "normal_unit_vectors_discontinuity", normal_cell, 0, Tdim); + } + } + + // modify normal vector of NextTip cell + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + if ((*citr)->element_type_discontinuity() != mpm::EnrichType::NextTip) + continue; + VectorDim normal_cell; + normal_cell.setZero(); + + for (auto node : (*citr)->nodes()) { + normal_cell += node->discontinuity_property( + "normal_unit_vectors_discontinuity", Tdim); + } + normal_cell = normal_cell / (*citr)->nodes().size(); + normal_cell.normalize(); + (*citr)->assign_normal_discontinuity(normal_cell); + + int enriched_node = 0; + double dis = 0; + // determine the discontinuity plane by the virtual enriched nodes + + for (auto node : (*citr)->nodes()) { + + bool virtual_enrich = false; + for (auto cell : node->cells()) { + if (map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Tip && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Crossed) + continue; + virtual_enrich = true; + break; + } + if (!virtual_enrich) continue; + enriched_node++; + auto node_coordinate = node->coordinates(); + for (unsigned int j = 0; j < Tdim; j++) + dis -= node_coordinate[j] * normal_cell[j]; + dis = node->discontinuity_property("levelset_phi", 1)(0, 0) + dis; + } + + // update the level set values of the unenriched nodes + dis = dis / enriched_node; + (*citr)->assign_d_discontinuity(dis); + } + + // compute nodal level set values + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + if ((*citr)->element_type_discontinuity() != mpm::EnrichType::NextTip) + continue; + // compute nodal normal direction and find neighbour cells + for (auto node : (*citr)->nodes()) { + + bool virtual_enrich = false; + for (auto cell : node->cells()) { + if (map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Tip && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Crossed) + continue; + virtual_enrich = true; + break; + } + if (virtual_enrich) continue; + + VectorDim normal_cell; + normal_cell.setZero(); + int nexttip_cell = 0; + Eigen::Matrix phi; + phi.setZero(); + for (auto cell : node->cells()) { + if (map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NextTip) + continue; + double d = map_cells_[cell]->d_discontinuity(); + normal_cell = map_cells_[cell]->normal_discontinuity(); + for (unsigned int i = 0; i < Tdim; i++) + phi(0, 0) += node->coordinates()[i] * normal_cell[i]; + phi(0, 0) += d; + nexttip_cell += 1; + } + + if (nexttip_cell == 0) continue; + + node->assign_discontinuity_property(true, "levelset_phi", + phi / nexttip_cell, 0, 1); + } + } + + // modify normal vector of NeighbourNextTip_1 cell + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + if ((*citr)->element_type_discontinuity() != + mpm::EnrichType::NeighbourNextTip_1) + continue; + VectorDim normal_cell; + normal_cell.setZero(); + int enriched_node = 0; + for (auto node : (*citr)->nodes()) { + + bool virtual_enrich = false; + for (auto cell : node->cells()) { + if (map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Tip && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Crossed && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NextTip) + continue; + virtual_enrich = true; + break; + } + if (!virtual_enrich) continue; + + normal_cell += node->discontinuity_property( + "normal_unit_vectors_discontinuity", Tdim); + enriched_node += 1; + } + normal_cell = normal_cell / enriched_node; + normal_cell.normalize(); + (*citr)->assign_normal_discontinuity(normal_cell); + + enriched_node = 0; + double dis = 0; + // determine the discontinuity plane by the virtual enriched nodes + + for (auto node : (*citr)->nodes()) { + + bool virtual_enrich = false; + for (auto cell : node->cells()) { + if (map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Tip && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Crossed && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NextTip) + continue; + virtual_enrich = true; + break; + } + if (!virtual_enrich) continue; + enriched_node++; + auto node_coordinate = node->coordinates(); + for (unsigned int j = 0; j < Tdim; j++) + dis -= node_coordinate[j] * normal_cell[j]; + dis = node->discontinuity_property("levelset_phi", 1)(0, 0) + dis; + } + + // update the level set values of the unenriched nodes + dis = dis / enriched_node; + (*citr)->assign_d_discontinuity(dis); + } + + // update nodal level set values of the NeighbourNextTip_1 cell + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + if ((*citr)->element_type_discontinuity() != + mpm::EnrichType::NeighbourNextTip_1) + continue; + // compute nodal normal direction and find neighbour cells + for (auto node : (*citr)->nodes()) { + + bool virtual_enrich = false; + for (auto cell : node->cells()) { + if (map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Tip && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Crossed && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NextTip) + continue; + virtual_enrich = true; + break; + } + if (virtual_enrich) continue; + + for (auto cell : node->cells()) { + if (map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NeighbourTip_1 && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NeighbourNextTip_1) + map_cells_[cell]->assign_type_discontinuity( + mpm::EnrichType::NeighbourNextTip_2); + } + + VectorDim normal_cell; + normal_cell.setZero(); + VectorDim normal_cell_sum; + normal_cell_sum.setZero(); + int cell_num = 0; + Eigen::Matrix phi; + phi.setZero(); + for (auto cell : node->cells()) { + + if (map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NeighbourNextTip_1 && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NeighbourTip_1) + continue; + double d = map_cells_[cell]->d_discontinuity(); + normal_cell = map_cells_[cell]->normal_discontinuity(); + normal_cell_sum += normal_cell; + for (unsigned int i = 0; i < Tdim; i++) + phi(0, 0) += node->coordinates()[i] * normal_cell[i]; + phi(0, 0) += d; + cell_num++; + } + + if (cell_num == 0) continue; + normal_cell_sum = normal_cell_sum / cell_num; + normal_cell_sum.normalize(); + node->assign_discontinuity_property( + true, "normal_unit_vectors_discontinuity", normal_cell_sum, 0, Tdim); + + node->assign_discontinuity_property(true, "levelset_phi", phi / cell_num, + 0, 1); + } + } + // modify normal vector of NeighbourNextTip_2 cell + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + if ((*citr)->element_type_discontinuity() != + mpm::EnrichType::NeighbourNextTip_2) + continue; + + VectorDim normal_cell; + normal_cell.setZero(); + int enriched_node = 0; + for (auto node : (*citr)->nodes()) { + + bool virtual_enrich = false; + for (auto cell : node->cells()) { + if (map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Tip && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Crossed && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NextTip && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NeighbourTip_1 && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NeighbourNextTip_1) + continue; + virtual_enrich = true; + break; + } + if (!virtual_enrich) continue; + + normal_cell += node->discontinuity_property( + "normal_unit_vectors_discontinuity", Tdim); + enriched_node += 1; + } + normal_cell = normal_cell / enriched_node; + normal_cell.normalize(); + (*citr)->assign_normal_discontinuity(normal_cell); + + enriched_node = 0; + double dis = 0; + // determine the discontinuity plane by the virtual enriched nodes + + for (auto node : (*citr)->nodes()) { + + bool virtual_enrich = false; + for (auto cell : node->cells()) { + if (map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Tip && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Crossed && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NextTip && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NeighbourTip_1 && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NeighbourNextTip_1) + continue; + virtual_enrich = true; + break; + } + if (!virtual_enrich) continue; + enriched_node++; + auto node_coordinate = node->coordinates(); + for (unsigned int j = 0; j < Tdim; j++) + dis -= node_coordinate[j] * normal_cell[j]; + dis = node->discontinuity_property("levelset_phi", 1)(0, 0) + dis; + } + + // update the level set values of the unenriched nodes + + dis = dis / enriched_node; + (*citr)->assign_d_discontinuity(dis); + } + + // update nodal level set values of the NeighbourNextTip_2 cell + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + if ((*citr)->element_type_discontinuity() != + mpm::EnrichType::NeighbourNextTip_2) + continue; + // compute nodal normal direction and find neighbour cells + for (auto node : (*citr)->nodes()) { + + bool virtual_enrich = false; + for (auto cell : node->cells()) { + if (map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Tip && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Crossed && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NextTip && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NeighbourTip_1 && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NeighbourNextTip_1) + continue; + virtual_enrich = true; + break; + } + + if (virtual_enrich) continue; + + VectorDim normal_cell; + normal_cell.setZero(); + VectorDim normal_cell_sum; + normal_cell_sum.setZero(); + int cell_num = 0; + Eigen::Matrix phi; + phi.setZero(); + for (auto cell : node->cells()) { + if (map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NeighbourNextTip_2) + continue; + double d = map_cells_[cell]->d_discontinuity(); + normal_cell = map_cells_[cell]->normal_discontinuity(); + normal_cell_sum += normal_cell; + for (unsigned int i = 0; i < Tdim; i++) + phi(0, 0) += node->coordinates()[i] * normal_cell[i]; + phi(0, 0) += d; + cell_num++; + } + + if (cell_num == 0) continue; + + normal_cell_sum = normal_cell_sum / cell_num; + normal_cell_sum.normalize(); + node->assign_discontinuity_property( + true, "normal_unit_vectors_discontinuity", normal_cell_sum, 0, Tdim); + node->assign_discontinuity_property(true, "levelset_phi", phi / cell_num, + 0, 1); + } + } + // update particle level set values + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + if ((*citr)->element_type_discontinuity() == mpm::EnrichType::NextTip || + (*citr)->element_type_discontinuity() == + mpm::EnrichType::NeighbourNextTip_1 || + (*citr)->element_type_discontinuity() == + mpm::EnrichType::NeighbourNextTip_2) { + for (auto particle_id : (*citr)->particles()) { + map_particles_[particle_id]->map_levelset_to_particle(); + } + } + } + + // update discontinuity points + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + if ((*citr)->element_type_discontinuity() != mpm::EnrichType::NextTip) + continue; + std::vector coordinates; + (*citr)->compute_discontinuity_point(coordinates); + // if ((*citr)->discontinuity_area() <= 0) continue; + for (int i = 0; i < coordinates.size(); i++) { + discontinuity_->insert_particles(coordinates[i], cells_, map_cells_); + + double d = (*citr)->d_discontinuity(); + auto normal_cell = (*citr)->normal_discontinuity(); + + std::ofstream normal("normal.txt", std::ios::app); + normal << coordinates[i][0] << " " << coordinates[i][1] << " " + << std::atan(normal_cell[0] / normal_cell[1]) / M_PI * 180 + << std::endl; } } } + +//! find next tip element +template +void mpm::Mesh::next_tip_element_discontinuity() { + std::string shear; +#pragma omp parallel for schedule(runtime) + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + if ((*citr)->element_type_discontinuity() != mpm::EnrichType::PotentialTip) + continue; + mpm::Index pid; + double max_pdstrain = 0; + for (auto particle_id : (*citr)->particles()) { + double pdstrain = map_particles_[particle_id]->state_variable("pdstrain"); + if (pdstrain > max_pdstrain) { + max_pdstrain = pdstrain; + pid = particle_id; + } + } + + if (max_pdstrain <= discontinuity_->maximum_pdstrain()) continue; + VectorDim normal; + bool propagation = + map_particles_[pid]->minimum_acoustic_tensor(normal, false); + if (propagation) { + (*citr)->assign_type_discontinuity(mpm::EnrichType::NextTip); + (*citr)->assign_normal_discontinuity(normal); + } + } + return; +} + +// Initialise the cells in node +template +void mpm::Mesh::add_cell_in_node() { + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + (*citr)->add_cell_in_node(); + } +} + +//! remove spurious potential tip element +template +void mpm::Mesh::spurious_potential_tip_element() { + + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + if ((*citr)->element_type_discontinuity() != mpm::EnrichType::PotentialTip) + continue; + + bool boundary = false; + bool potential_tip = false; + for (auto neighbour : (*citr)->neighbours()) { + if (cells_[neighbour]->element_type_discontinuity() != + mpm::EnrichType::NeighbourTip_2) + continue; + + if (cells_[neighbour]->nparticles() == 0) { + boundary = true; + } + if (cells_[neighbour]->product_levelset() < 0) potential_tip = true; + } + + if (potential_tip) continue; + (*citr)->assign_type_discontinuity(mpm::EnrichType::Crossed); + + continue; + if (!boundary) continue; + + // avoid the node located near the discontinuity + if ((*citr)->discontinuity_area() == 0) continue; + + std::vector coordinates; + (*citr)->compute_discontinuity_point(coordinates); + + for (int i = 0; i < coordinates.size(); i++) + discontinuity_->insert_particles(coordinates[i], cells_, map_cells_); + } +} + +// assign_node_enrich +template +void mpm::Mesh::assign_node_enrich(bool friction_coef_average, + bool enrich_all) { + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + if ((*citr)->element_type_discontinuity() != mpm::EnrichType::Crossed) + continue; + Eigen::Matrix friction_coef; + friction_coef(0, 0) = discontinuity_->friction_coef(); + + Eigen::Matrix cohesion; + cohesion(0, 0) = discontinuity_->cohesion(); + for (auto node : (*citr)->nodes()) { + if (node->discontinuity_enrich()) continue; + node->assign_discontinuity_enrich(true); + + if (!friction_coef_average) + node->assign_discontinuity_property(true, "friction_coef", + friction_coef, 0, 1); + node->assign_discontinuity_property(true, "cohesion", cohesion, 0, 1); + } + + // bool negative = false; + // bool positive = false; + // for(auto particle : (*citr)->particles()) + // { + // if(particles_[particle]->levelset_phi() > 0) + // positive = true; + // if(particles_[particle]->levelset_phi() < 0) + // negative = true; + // } + + // if(!negative || !positive) + // continue; + + (*citr)->assign_cohesion_area(); + } + + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + if ((*citr)->element_type_discontinuity() != mpm::EnrichType::PotentialTip) + continue; + for (auto node : (*citr)->nodes()) { + if (node->discontinuity_enrich()) + node->assign_discontinuity_enrich(false); + } + } + + if (!enrich_all) return; + + // double tolerance = 1e-16; + // for(auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr){ + // (*nitr)->assign_discontinuity_enrich(true); + // double positive_mass = (*nitr)->mass(mpm::ParticlePhase::Solid) + + // (*nitr)->discontinuity_property("mass_enrich", 1)(0, 0); double + // negative_mass = (*nitr)->mass(mpm::ParticlePhase::Solid) - + // (*nitr)->discontinuity_property("mass_enrich", 1)(0, 0); + // if(positive_mass < tolerance || negative_mass < tolerance) + // (*nitr)->assign_discontinuity_enrich(false); + // } + + for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { + (*nitr)->assign_discontinuity_enrich(true); + } +} + +// modify_node_enrich +template +void mpm::Mesh::update_node_enrich() { + + double tolerance = 1e-16; + for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { + double positive_mass = + (*nitr)->mass(mpm::ParticlePhase::Solid) + + (*nitr)->discontinuity_property("mass_enrich", 1)(0, 0); + double negative_mass = + (*nitr)->mass(mpm::ParticlePhase::Solid) - + (*nitr)->discontinuity_property("mass_enrich", 1)(0, 0); + if (positive_mass < tolerance || negative_mass < tolerance) + (*nitr)->assign_discontinuity_enrich(false); + } +} + +template +void mpm::Mesh::change_mat() { + + for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { + // FOR SLOPE_SRF + if (true) { + unsigned material_id = 2; + unsigned phase_id = mpm::ParticlePhase::Solid; + (*pitr)->assign_material(materials_.at(material_id), phase_id); + } + + // FOR OSO + // if ((*pitr)->material_id(mpm::ParticlePhase::Solid) == 4) { + // unsigned material_id = 1; + // unsigned phase_id = mpm::ParticlePhase::Solid; + // (*pitr)->assign_material(materials_.at(material_id), phase_id); + // } else if ((*pitr)->material_id(mpm::ParticlePhase::Solid) == 5) { + // unsigned material_id = 2; + // unsigned phase_id = mpm::ParticlePhase::Solid; + // (*pitr)->assign_material(materials_.at(material_id), phase_id); + // } else if ((*pitr)->material_id(mpm::ParticlePhase::Solid) == 6) { + // unsigned material_id = 3; + // unsigned phase_id = mpm::ParticlePhase::Solid; + // (*pitr)->assign_material(materials_.at(material_id), phase_id); + // } + } +} + +template +void mpm::Mesh::define_levelset() { + // for oso + std::ifstream in("stage1.txt"); + double stage[63126]; + for (int i = 0; i < 63126; ++i) { + in >> stage[i]; + if (stage[i] == 0) stage[i] = std::numeric_limits::min(); + } + int i = 0; + Eigen::Matrix phi_mls; + for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { + phi_mls(0, 0) = stage[i]; + i += 1; + + (*nitr)->assign_discontinuity_property(true, "levelset_phi", phi_mls, 0, 1); + } + for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { + + (*pitr)->map_levelset_to_particle(); + } + + return; + for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { + + auto cor = (*pitr)->coordinates(); + double phi; + // phi = 1 / std::sqrt(3) * cor[0] + 1 / std::sqrt(3) * cor[1] + + // 1 / std::sqrt(3) * cor[2] - 0.5 * std::sqrt(3); + + // phi = std::sqrt(std::pow(cor[0] - 35, 2) + std::pow(cor[1] - 30, 2) + + // std::pow(cor[2] - 0, 2)) - + // 25; + // slide body + phi = (0.5 * cor[0] + cor[2] - 0.5) / std::sqrt(0.25 + 1); + phi = cor[1] - 1.5; + (*pitr)->assign_levelsetphi(phi); + // case 4-2d + // if (cor[0] > 35 && cor[1] > 4 && cor[1] < 5) { + // phi = 5 - cor[1]; + // (*pitr)->assign_levelsetphi(phi); + // } + // if (cor[0] > 34 && cor[0] < 35 && cor[1] > 4) { + // if ((*pitr)->levelset_phi() < 0) continue; + // Eigen::Matrix e1, e2, p2n; + // e1 << 1 / std::sqrt(5), 2 / std::sqrt(5); + // e2 << 2 / std::sqrt(5), -1 / std::sqrt(5); + + // p2n << cor[0] - 35, cor[1] - 5; + // if (e2.dot(p2n) >= 0) + // phi = p2n.norm(); + // else if (e2.dot(p2n) < 0) { + // double dis1 = 5.25 - cor[1]; // 5.27118 + // double dis2 = std::abs(e1.dot(p2n)); + // if (dis1 < dis2) + // dis1 = (*pitr)->levelset_phi(); + // else + // dis1 = dis2; + // phi = dis1; + // } + // (*pitr)->assign_levelsetphi(phi); + // } + // case 5 + // if (cor[0] > 35 && cor[1] > 4 && cor[1] < 5) { + // phi = 5 - cor[1]; + // (*pitr)->assign_levelsetphi(phi); + // } + // if (cor[0] > 34 && cor[0] < 35 && cor[1] > 4) { + // if ((*pitr)->levelset_phi() != 0) continue; + // Eigen::Matrix e1, e2, p2n; + // e1 << 1 / std::sqrt(5), 2 / std::sqrt(5); + // e2 << 2 / std::sqrt(5), -1 / std::sqrt(5); + + // p2n << cor[0] - 35, cor[1] - 5; + // if (e2.dot(p2n) >= 0) + // phi = p2n.norm(); + // else if (e2.dot(p2n) < 0) { + // double dis1 = 5.25 - cor[1]; // 5.27118 + // double dis2 = std::abs(e1.dot(p2n)); + // phi = dis2; + // } + // (*pitr)->assign_levelsetphi(phi); + // } + // if ((*pitr)->material_id(mpm::ParticlePhase::Solid) == 4) + // (*pitr)->assign_levelsetphi(1.0); + // else if ((*pitr)->material_id(mpm::ParticlePhase::Solid) == 5) + // (*pitr)->assign_levelsetphi(-1); + // else if ((*pitr)->material_id(mpm::ParticlePhase::Solid) == 6) + // (*pitr)->assign_levelsetphi(-1); + } +} + +template +bool mpm::Mesh::initiation_discontinuity() { + bool status = false; + + mpm::Index pid; + double max_pdstrain = 0; + for (int i = 0; i < nparticles(); ++i) { + double pdstrain = map_particles_[i]->state_variable("pdstrain"); + // if(map_particles_[i]->coordinates()[1] < 0.2 || + // map_particles_[i]->coordinates()[1] > 0.8 || + // map_particles_[i]->coordinates()[0] > 0.05) continue; + + if (pdstrain > max_pdstrain) { + max_pdstrain = pdstrain; + pid = i; + } + } + + if (max_pdstrain <= discontinuity_->maximum_pdstrain()) return status; + VectorDim normal; + bool initiation = map_particles_[pid]->minimum_acoustic_tensor(normal, true); + + if (initiation) { + status = true; + auto cell_id = map_particles_[pid]->cell_id(); + map_cells_[cell_id]->assign_type_discontinuity(mpm::EnrichType::InitialTip); + map_cells_[cell_id]->assign_normal_discontinuity(normal); + auto center = map_cells_[cell_id]->centroid(); + + double d = 0; + + for (unsigned int i = 0; i < Tdim; i++) d -= center[i] * normal[i]; + + map_cells_[cell_id]->assign_normal_discontinuity(normal, d); + + map_cells_[cell_id]->compute_nodal_levelset_equation(); + + std::vector coordinates_dis; + map_cells_[cell_id]->compute_discontinuity_point(coordinates_dis); + + for (int i = 0; i < coordinates_dis.size(); i++) + discontinuity_->insert_particles(coordinates_dis[i], cells_, map_cells_); + // initialise neighbour cells + std::ofstream normalfile("normal.txt", std::ios::app); + normalfile << coordinates_dis[0][0] << " " << coordinates_dis[0][1] << " " + << std::atan(normal[0] / normal[1]) / M_PI * 180 << std::endl; + + auto neighbours = map_cells_[cell_id]->neighbours(); + for (auto neighbour : neighbours) { + if (map_cells_[neighbour]->nparticles() == 0) continue; + map_cells_[neighbour]->assign_type_discontinuity( + mpm::EnrichType::NeighbourTip_1); + map_cells_[neighbour]->assign_normal_discontinuity(normal, d); + map_cells_[neighbour]->compute_nodal_levelset_equation(); + if (map_cells_[neighbour]->product_levelset() >= 0) continue; + map_cells_[neighbour]->assign_type_discontinuity( + mpm::EnrichType::InitialTip); + + std::vector coordinates_dis_neigh; + map_cells_[neighbour]->compute_discontinuity_point(coordinates_dis_neigh); + + for (int i = 0; i < coordinates_dis_neigh.size(); i++) { + discontinuity_->insert_particles(coordinates_dis_neigh[i], cells_, + map_cells_); + + normalfile << coordinates_dis_neigh[i][0] << " " + << coordinates_dis_neigh[i][1] << " " + << std::atan(normal[0] / normal[1]) / M_PI * 180 + << std::endl; + } + } + // initialise level set values + + for (int i = 0; i < nparticles(); ++i) { + bool neighbour = true; + for (int j = 0; j < Tdim; j++) { + if (std::abs(center[j] - particles_[i]->coordinates()[j]) > + 3.5 * discontinuity_->width()) + neighbour = false; + } + if (!neighbour) continue; + double phi = particles_[i]->coordinates().dot(normal) + d; + particles_[i]->assign_levelsetphi(phi); + } + } + return status; +} + +template +void mpm::Mesh::modify_nodal_levelset_mls() { + Eigen::Matrix au; + Eigen::Matrix bu; + // double error_max = 0; + const double tolerance = std::numeric_limits::epsilon(); + + for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { + if ((*nitr)->discontinuity_property("levelset_phi", 1)(0, 0) == 0) continue; + double phi = 0; + + au.setZero(); + bu.setZero(); + + double particle_volume = 0; + double cell_volume = 0; + std::vector cell_list; + for (auto cell : (*nitr)->cells()) cell_list.push_back(cell); + + for (auto cell : cell_list) { + double length = discontinuity_->width(); + cell_volume += map_cells_[cell]->volume(); + for (auto particle : map_cells_[cell]->particles()) { + auto corp = map_particles_[particle]->coordinates(); + phi = map_particles_[particle]->levelset_phi(); + if (phi == 0) continue; + particle_volume += map_particles_[particle]->volume(); + // compute weight + double w[3]; + for (int i = 0; i < 3; i++) { + w[i] = 1 - std::abs(corp[i] - (*nitr)->coordinates()[i]) / length; + if (w[i] < 0) w[i] = 0; + } + + double weight = w[0] * w[1] * w[2]; + au(0, 0) += weight; + au(0, 1) += weight * corp[0]; + au(0, 2) += weight * corp[1]; + au(0, 3) += weight * corp[2]; + au(1, 0) += weight * corp[0]; + au(1, 1) += weight * corp[0] * corp[0]; + au(1, 2) += weight * corp[0] * corp[1]; + au(1, 3) += weight * corp[0] * corp[2]; + au(2, 0) += weight * corp[1]; + au(2, 1) += weight * corp[1] * corp[0]; + au(2, 2) += weight * corp[1] * corp[1]; + au(2, 3) += weight * corp[1] * corp[2]; + au(3, 0) += weight * corp[2]; + au(3, 1) += weight * corp[2] * corp[0]; + au(3, 2) += weight * corp[2] * corp[1]; + au(3, 3) += weight * corp[2] * corp[2]; + + bu(0, 0) += weight * phi; + bu(1, 0) += weight * phi * corp[0]; + bu(2, 0) += weight * phi * corp[1]; + bu(3, 0) += weight * phi * corp[2]; + } + } + + // find particles from neighbour cells + if (particle_volume < 0.5 * cell_volume || + std::abs(au.determinant()) < tolerance) { + au.setZero(); + bu.setZero(); + for (auto cells : (*nitr)->cells()) { + for (auto cell : map_cells_[cells]->neighbours()) { + std::vector::iterator ret; + ret = std::find(cell_list.begin(), cell_list.end(), cell); + if (ret != cell_list.end()) continue; + cell_list.push_back(cell); + } + } + + for (auto cell : cell_list) { + for (auto particle : map_cells_[cell]->particles()) { + auto corp = map_particles_[particle]->coordinates(); + phi = map_particles_[particle]->levelset_phi(); + if (phi == 0) continue; + // compute weight + double length = 2 * discontinuity_->width(); + double w[3]; + for (int i = 0; i < 3; i++) { + w[i] = 1 - std::abs(corp[i] - (*nitr)->coordinates()[i]) / length; + if (w[i] < 0) w[i] = 0; + } + double weight = w[0] * w[1] * w[2]; + + au(0, 0) += weight; + au(0, 1) += weight * corp[0]; + au(0, 2) += weight * corp[1]; + au(0, 3) += weight * corp[2]; + au(1, 0) += weight * corp[0]; + au(1, 1) += weight * corp[0] * corp[0]; + au(1, 2) += weight * corp[0] * corp[1]; + au(1, 3) += weight * corp[0] * corp[2]; + au(2, 0) += weight * corp[1]; + au(2, 1) += weight * corp[1] * corp[0]; + au(2, 2) += weight * corp[1] * corp[1]; + au(2, 3) += weight * corp[1] * corp[2]; + au(3, 0) += weight * corp[2]; + au(3, 1) += weight * corp[2] * corp[0]; + au(3, 2) += weight * corp[2] * corp[1]; + au(3, 3) += weight * corp[2] * corp[2]; + + bu(0, 0) += weight * phi; + bu(1, 0) += weight * phi * corp[0]; + bu(2, 0) += weight * phi * corp[1]; + bu(3, 0) += weight * phi * corp[2]; + } + } + } + + if (std::abs(au.determinant()) < tolerance) continue; + + Eigen::Vector4d coef; + coef.setZero(); + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) coef[i] += au.inverse()(i, j) * bu(j, 0); + + // compute the error + double error = 0; + int error_p = 0; + for (auto cell : cell_list) { + for (auto particle : map_cells_[cell]->particles()) { + auto corp = map_particles_[particle]->coordinates(); + phi = map_particles_[particle]->levelset_phi(); + if (phi == 0) continue; + double phi_mls = 1 * coef[0] + corp[0] * coef[1] + corp[1] * coef[2] + + corp[2] * coef[3]; + error += std::pow(phi_mls - phi, 2); + error_p += 1; + } + } + error = std::sqrt(error / error_p) / discontinuity_->width(); + + // if (error > error_max) error_max = error; + // std::ofstream test("testmlserror.txt",std::ios::app); + // test<<(*nitr)->coordinates()[0]<<" "<<(*nitr)->coordinates()[1]<<" + // "<<(*nitr)->coordinates()[2]<<" "< 1e-3) continue; + + // phi_mls(0, 0) = + // (0.5 * (*nitr)->coordinates()[0] + (*nitr)->coordinates()[2] - 0.8) / + // std::sqrt(0.25 + 1); + Eigen::Matrix cor; + Eigen::Matrix phi_mls; + + cor << 1, (*nitr)->coordinates()[0], (*nitr)->coordinates()[1], + (*nitr)->coordinates()[2]; + phi_mls(0, 0) = cor.dot(coef); + + std::ofstream test("testmls.txt", std::ios::app); + test << (*nitr)->id() << " " << cor.dot(coef) << std::endl; + // if(std::abs(phi_mls(0, 0)-1) < 1e-10 || std::abs(phi_mls(0, 0)-0.5) < + // 1e-10) + // console_->info("coefficient is + // :{},{},{},{}",coef[0],coef[1],coef[2],coef[3]); + (*nitr)->assign_discontinuity_property(true, "levelset_phi", phi_mls, 0, 1); + } + // std::ofstream test("testmlserror.txt", std::ios::app); + // test << error_max << std::endl; +} + +template +void mpm::Mesh::compute_error() { + double error = 0; + double error_max = 0; + int nnode = 0; + for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { + auto cor = (*nitr)->coordinates(); + double phi_ana = 1 / std::sqrt(3) * cor[0] + 1 / std::sqrt(3) * cor[1] + + 1 / std::sqrt(3) * cor[2] - 0.5 * std::sqrt(3); + phi_ana = std::sqrt(std::pow(cor[0] - 0.5, 2) + std::pow(cor[1] - 0.5, 2) + + std::pow(cor[2] - 0.5, 2)) - + 0.4; + if (std::abs(phi_ana) > 0.2 * 0.5 * 0.5) continue; + + nnode++; + + double phi = (*nitr)->discontinuity_property("levelset_phi", 1)(0, 0); + + error += std::pow(std::abs(phi - phi_ana), 2); + + if (std::abs(phi - phi_ana) > error_max) + error_max = std::abs(phi - phi_ana); + } + error = std::sqrt(error / nnode); + console_->info("the error is {}.\n", error); + console_->info("the maximum error is {}.\n", error_max); + double area = 0; + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + if ((*citr)->element_type_discontinuity() != mpm::EnrichType::Crossed) + continue; + area += (*citr)->discontinuity_area(); + } + console_->info("the error of area is {}.\n", + (area - 4 * M_PI * 0.16) / (4 * M_PI * 0.16)); +} + +template +void mpm::Mesh::selfcontact_detection() { + + double contact_distance = discontinuity_->contact_distance(); + + for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { + if (!(*nitr)->discontinuity_enrich()) continue; + + auto cor = (*nitr)->coordinates(); + auto normal = (*nitr)->discontinuity_property( + "normal_unit_vectors_discontinuity", Tdim); + double dis_negative = -10 * contact_distance; + double dis_positive = 10 * contact_distance; + for (auto cell : (*nitr)->cells()) { + + for (auto particle : map_cells_[cell]->particles()) { + auto corp = map_particles_[particle]->coordinates(); + double phi = map_particles_[particle]->levelset_phi(); + + double dis = 0; + for (unsigned int i = 0; i < Tdim; i++) + dis += (corp[i] - cor[i]) * normal(i); + + if (phi > 0) dis_positive = dis < dis_positive ? dis : dis_positive; + if (phi < 0) dis_negative = dis > dis_negative ? dis : dis_negative; + } + } + Eigen::Matrix dis; + dis(0, 0) = dis_positive - dis_negative - contact_distance; + (*nitr)->assign_discontinuity_property(true, "contact_distance", dis, 0, 1); + } +} + +template +void mpm::Mesh::check_particle_levelset(bool particle_levelset) { + + for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { + if ((*pitr)->levelset_phi() != 0) continue; + + auto cell_id = (*pitr)->cell_id(); + + for (auto node : cells_[cell_id]->nodes()) { + if (!node->discontinuity_enrich()) continue; + + Eigen::Matrix au; + Eigen::Matrix bu; + au.setZero(); + bu.setZero(); + auto cell_list = cells_[cell_id]->neighbours(); + cell_list.insert(cell_id); + + for (auto cell : cell_list) { + for (auto particle : cells_[cell]->particles()) { + auto corp = map_particles_[particle]->coordinates(); + double phi = map_particles_[particle]->levelset_phi(); + if (phi == 0) continue; + // compute weight + double length = 2.0 * discontinuity_->width(); + double w[3]; + for (int i = 0; i < 3; i++) { + w[i] = 1 - std::abs(corp[i] - (*pitr)->coordinates()[i]) / length; + if (w[i] < 0) w[i] = 0; + } + double weight = w[0] * w[1] * w[2]; + + au(0, 0) += weight; + au(0, 1) += weight * corp[0]; + au(0, 2) += weight * corp[1]; + au(0, 3) += weight * corp[2]; + au(1, 0) += weight * corp[0]; + au(1, 1) += weight * corp[0] * corp[0]; + au(1, 2) += weight * corp[0] * corp[1]; + au(1, 3) += weight * corp[0] * corp[2]; + au(2, 0) += weight * corp[1]; + au(2, 1) += weight * corp[1] * corp[0]; + au(2, 2) += weight * corp[1] * corp[1]; + au(2, 3) += weight * corp[1] * corp[2]; + au(3, 0) += weight * corp[2]; + au(3, 1) += weight * corp[2] * corp[0]; + au(3, 2) += weight * corp[2] * corp[1]; + au(3, 3) += weight * corp[2] * corp[2]; + + bu(0, 0) += weight * phi; + bu(1, 0) += weight * phi * corp[0]; + bu(2, 0) += weight * phi * corp[1]; + bu(3, 0) += weight * phi * corp[2]; + } + } + + const double tolerance = std::numeric_limits::epsilon(); + + if (std::abs(au.determinant()) < tolerance) { + (*pitr)->map_levelset_to_particle(); + continue; + } + + Eigen::Vector4d coef; + coef.setZero(); + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) coef[i] += au.inverse()(i, j) * bu(j, 0); + + // compute the error + // double error = 0; + // int error_p = 0; + // for (auto cell : cell_list) { + // for (auto particle : map_cells_[cell]->particles()) { + // auto corp = map_particles_[particle]->coordinates(); + // double phi = map_particles_[particle]->levelset_phi(); + // if (phi == 0) continue; + // double phi_mls = 1 * coef[0] + corp[0] * coef[1] + corp[1] * + // coef[2] + + // corp[2] * coef[3]; + // error += std::pow(phi_mls - phi, 2); + // error_p += 1; + // } + // } + // error = std::sqrt(error / error_p) / discontinuity_->width(); + + // if (error > 1e-3) { + // (*pitr)->map_levelset_to_particle(); + // continue; + // } + + Eigen::Vector4d cor; + cor << 1, (*pitr)->coordinates()[0], (*pitr)->coordinates()[1], + (*pitr)->coordinates()[2]; + double phi = cor.dot(coef); + + (*pitr)->assign_levelsetphi(phi); + + break; + } + } + if (particle_levelset) return; + for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { + if ((*pitr)->levelset_phi() == 0) continue; + auto cell_id = (*pitr)->cell_id(); + + if (cells_[cell_id]->element_type_discontinuity() == + mpm::EnrichType::Regular || + cells_[cell_id]->element_type_discontinuity() == + mpm::EnrichType::NeighbourTip_3) + (*pitr)->assign_levelsetphi(0); + } +} + +template +void mpm::Mesh::output_celltype(int step) { + std::ofstream test("cell_type.txt", std::ios::app); + + test << step << ":" << std::endl; + for (int i = 0; i < cells_.size(); i++) { + auto type = cells_[i]->element_type_discontinuity(); + if (type == 1) + test << "o "; + else if (type == 2) + test << "\\ "; + else if (type == 3) + test << "^ "; + else if (type == 4) + test << "1 "; + else if (type == 5) + test << "2 "; + else if (type == 6) + test << "* "; + else + test << type << " "; + if (((i + 1) % 90) == 0) test << std::endl; + } + test << std::endl; + + std::ofstream testnormal("node_normal.txt", std::ios::app); + testnormal << step << ":" << std::endl; + for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { + if (!(*nitr)->discontinuity_enrich()) continue; + + if ((*nitr)->coordinates()[0] < 35) continue; + + Eigen::Matrix normal = (*nitr)->discontinuity_property( + "normal_unit_vectors_discontinuity", Tdim); + testnormal << (*nitr)->coordinates()[0] << "\t" << (*nitr)->coordinates()[1] + << "\t" << normal[0] << "\t" << normal[1] << "\t" << normal[2] + << std::endl; + } +} + +template +void mpm::Mesh::output_force(int step) { + std::ofstream test("nodal_force.txt", std::ios::app); + + VectorDim force; + force.setZero(); + unsigned phase = mpm::ParticlePhase::Solid; + for (int i = 0; i < nodes_.size(); i++) { + if (nodes_[i]->coordinates()[1] > 1e-6) + // nodes_[i]->coordinates()[0] < -0.2 || nodes_[i]->coordinates()[0] + // > 1.2) + continue; + force += nodes_[i]->internal_force(phase); + } + test << step << "\t" << force[0] << "\t" << force[1] << std::endl; +} + +template +void mpm::Mesh::output_surface() { + // std::ofstream test("surface.txt", std::ios::app); + + // double height[91]{0}; + // double volume = 0; + // double size = 0.0625; + + // for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { + // auto coordinates = (*pitr)->coordinates(); + + // int id = std::round(coordinates[0]/0.5); + // if(coordinates[1]>height[id]) + // height[id] = coordinates[1]; + + // volume += (*pitr)->volume(); + // } + // test <coordinates(); + // if (coordinates[2] < 22 || coordinates[2] > 23) continue; + // int id = std::round(coordinates[0] / 0.5); + // if (coordinates[1] > height[id]) height[id] = coordinates[1]; + + // volume += (*pitr)->volume(); + // } + // test << volume / 0.5 << std::endl; + // for (int i = 0; i < 91; i++) test << height[i] + size << std::endl; +} + +// Regular = 1, +// Crossed = 2, +// Tip = 3, +// NeighbourTip_1 = 4, +// NeighbourTip_2 = 5, +// PotentialTip = 6, +// NextTip = 7, +// NeighbourNextTip_1 = 8, +// NeighbourNextTip_2 = 9, +// InitialTip = 10 + +template +void mpm::Mesh::update_nodal_levelset(double dt) { + unsigned phase = mpm::ParticlePhase::Solid; + auto tolerance = 1e-15; + + int sign = -1; + // std::ofstream levelset("dlevelset.txt", std::ios::app); + + for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { + + Eigen::Matrix nodal_velocity; + + double nodal_mass = + (*nitr)->mass(phase) + + sign * (*nitr)->discontinuity_property("mass_enrich", 1)(0, 0); + if (nodal_mass < tolerance) continue; + + // the gradient of the level set at nodes + + VectorDim gradient; + gradient.setZero(); + int numcell = 0; + for (auto cell : (*nitr)->cells()) { + // for oso + gradient += map_cells_[cell]->compute_gradient_levelset(); + numcell += 1; + } + gradient /= numcell; + + // double levelset = (*nitr)->discontinuity_property("levelset_phi", 1)(0, + // 0); + + Eigen::Matrix normal = (*nitr)->discontinuity_property( + "normal_unit_vectors_discontinuity", Tdim); + + nodal_velocity = + ((*nitr)->momentum(phase) + + sign * (*nitr)->discontinuity_property("momenta_enrich", 3)) / + nodal_mass; + + Eigen::Matrix dlevelset; + dlevelset(0, 0) = -nodal_velocity.dot(gradient) * dt; + + (*nitr)->update_discontinuity_property(true, "levelset_phi", dlevelset, 0, + 1); + + // levelset << nodal_velocity.norm() << " " << dlevelset(0, 0) << + // std::endl; + } + + // for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) + // { + + // (*pitr)->map_levelset_to_particle(); + // } +} + +template +void mpm::Mesh::output_nodal_levelset(int step) { + + std::ostringstream convert; + + convert << step; + + std::string filename = "levelset" + convert.str() + ".vtk"; + std::ofstream test(filename, std::ios::app); + + test << "# vtk DataFile Version 2.0\n" + << "ASCII\n" + << "DATASET UNSTRUCTURED_GRID\n" + << "POINTS " << nodes_.size() << " double\n"; + for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { + test << (*nitr)->coordinates()[0] << " " << (*nitr)->coordinates()[1] + << " " << (*nitr)->coordinates()[2] << " " << std::endl; + } + + test << "POINT_DATA " << nodes_.size() << std::endl; + test << "SCALARS sample_scalars float 1 \n"; + test << "LOOKUP_TABLE my_table \n"; + for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { + test << (*nitr)->coordinates()[0] << " " << (*nitr)->coordinates()[1] + << " " << (*nitr)->coordinates()[2] << " " << std::endl; + } + + test << "CELLS " << cells_.size() << std::endl; + for (int i = 0; i < cells_.size(); i++) { + test << "4 " << cells_[i]->nodes()[0]->id() << " " + << cells_[i]->nodes()[1]->id() << " " << cells_[i]->nodes()[2]->id() + << " " << cells_[i]->nodes()[3]->id() << std::endl; + } + + test << "CELL_TYPES " << cells_.size() << std::endl; + for (int i = 0; i < cells_.size(); i++) { + test << "8" << std::endl; + } + + // test << "CELL_TYPES " << cells_.size()<< std::endl; + // for (int i = 0; i < cells_.size(); i++) { + // test << "8" <element_type_discontinuity(); + // if (type == 1) + // test << "o "; + // else if (type == 2) + // test << "\\ "; + // else if (type == 3) + // test << "^ "; + // else if (type == 4) + // test << "1 "; + // else if (type == 5) + // test << "2 "; + // else if (type == 6) + // test << "* "; + // else + // test << type << " "; + // if (((i + 1) % 90) == 0) test << std::endl; + // } + // test << std::endl; + + // std::ofstream testnormal("node_normal.txt", std::ios::app); + // testnormal << step << ":" << std::endl; + // for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { + // if (!(*nitr)->discontinuity_enrich()) continue; + + // if ((*nitr)->coordinates()[0] < 35) continue; + + // Eigen::Matrix normal = + // (*nitr)->discontinuity_property( + // "normal_unit_vectors_discontinuity", Tdim); + // testnormal << (*nitr)->coordinates()[0] << "\t" << + // (*nitr)->coordinates()[1] + // << "\t" << normal[0] << "\t" << normal[1] << "\t" << + // normal[2] + // << std::endl; + // } +} \ No newline at end of file diff --git a/include/node.h b/include/node.h index 45439bb22..bd6d5c134 100644 --- a/include/node.h +++ b/include/node.h @@ -5,6 +5,7 @@ #include "mutex.h" #include "nodal_properties.h" #include "node_base.h" +#include namespace mpm { @@ -313,18 +314,34 @@ class Node : public NodeBase { //! Compute momentum for discontinuity //! \param[in] phase Index corresponding to the phase //! \param[in] dt Timestep in analysis - virtual bool compute_momentum_discontinuity(unsigned phase, - double dt) noexcept override; + bool compute_momentum_discontinuity(unsigned phase, + double dt) noexcept override; + + //! Compute momentum for discontinuity with cundall damping factor + //! \param[in] phase Index corresponding to the phase + //! \param[in] dt Timestep in analysis + //! \param[in] damping_factor Damping factor + virtual bool compute_momentum_discontinuity_cundall( + unsigned phase, double dt, double damping_factor) noexcept override; //! Apply self-contact of the discontinuity //! \param[in] dt Time-step void self_contact_discontinuity(double dt) noexcept override; //! Return the discontinuity_prop_id - virtual unsigned discontinuity_prop_id() const noexcept override { + unsigned discontinuity_prop_id() const noexcept override { return discontinuity_prop_id_; }; + //! update the nodal levelset values + void update_levelset() noexcept override; + + //! Add a cell id + void add_cell_id(Index id) noexcept override; + + //! Return cells_ + std::vector cells() const { return cells_; } + private: //! Mutex SpinMutex node_mutex_; @@ -385,6 +402,8 @@ class Node : public NodeBase { //! discontinuity enrich // need to be done bool discontinuity_enrich_{false}; + //! cells ids including the node + std::vector cells_; }; // Node class } // namespace mpm diff --git a/include/node_base.h b/include/node_base.h index 169d36f07..1e144826d 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -24,6 +24,7 @@ namespace mpm { template class NodeBase { public: + double step_{0}; //! Define a vector of size dimension using VectorDim = Eigen::Matrix; @@ -304,6 +305,13 @@ class NodeBase { virtual bool compute_momentum_discontinuity(unsigned phase, double dt) noexcept = 0; + //! Compute momentum for discontinuity with cundall damping factor + //! \param[in] phase Index corresponding to the phase + //! \param[in] dt Timestep in analysis + //! \param[in] damping_factor Damping factor + virtual bool compute_momentum_discontinuity_cundall( + unsigned phase, double dt, double damping_factor) noexcept = 0; + //! Apply self-contact of the discontinuity //! \param[in] dt Time-step virtual void self_contact_discontinuity(double dt) noexcept = 0; @@ -311,6 +319,14 @@ class NodeBase { //! Return the discontinuity_prop_id virtual unsigned discontinuity_prop_id() const noexcept = 0; + //! update the nodal levelset values + virtual void update_levelset() = 0; + //! Add a cell id + virtual void add_cell_id(Index id) = 0; + + //! Return cells_ + virtual std::vector cells() const = 0; + }; // NodeBase class } // namespace mpm diff --git a/include/node_xmpm.tcc b/include/node_xmpm.tcc index 5beba771b..7717169fc 100644 --- a/include/node_xmpm.tcc +++ b/include/node_xmpm.tcc @@ -72,6 +72,143 @@ bool mpm::Node::compute_momentum_discontinuity( return true; } + +//! Compute momentum for discontinuity +template +bool mpm::Node::compute_momentum_discontinuity_cundall( + unsigned phase, double dt, double damping_factor) noexcept { + const double tolerance = 1.0E-15; + // std::ofstream force("force.txt", std::ios::app); + // force << discontinuity_enrich_ <<":"<<"damping factor:"<< damping_factor<< + // std::endl; + if (!discontinuity_enrich_) { + + if (mass_.col(phase)(0, 0) > tolerance) { + + // acceleration = (unbalaced force / mass) + // force << "external force:"<external_force_.col(phase)[0]<<" " + // << this->external_force_.col(phase)[1]<<" " + // << this->external_force_.col(phase)[2] << std::endl; + // force << "internal force:"<internal_force_.col(phase)[0]<<" " + // << this->internal_force_.col(phase)[1]<<" " + // << this->internal_force_.col(phase)[2] << std::endl; + auto unbalanced_force = + this->external_force_.col(phase) + this->internal_force_.col(phase); + this->external_force_.col(phase) -= + damping_factor * unbalanced_force.norm() * + this->momentum_.col(phase).normalized(); + // force <<"unbalanced force:"<external_force_.col(phase)[0]<<" " + // << this->external_force_.col(phase)[1]<<" " + // << this->external_force_.col(phase)[2] << std::endl; + // force << std::endl; + } + + } else { + + // force <<"external force:"<external_force_.col(phase)[0]<<" " + // << this->external_force_.col(phase)[1]<<" " + // << this->external_force_.col(phase)[2] << std::endl; + // force <<"internal force:"<internal_force_.col(phase)[0]<<" " + // << this->internal_force_.col(phase)[1]<<" " + // << this->internal_force_.col(phase)[2] << std::endl; + // force <<"enriched external force:"<property("external_force_enrich", + // discontinuity_prop_id_, 0, Tdim)(0, + // 0)<<" " + // << property_handle_->property("external_force_enrich", + // discontinuity_prop_id_, 0, Tdim)(1, + // 0)<<" " + // << property_handle_->property("external_force_enrich", + // discontinuity_prop_id_, 0, Tdim)(2, + // 0) + // << std::endl; + // force <<"enriched internal force:"<property("internal_force_enrich", + // discontinuity_prop_id_, 0, Tdim)(0, + // 0)<<" " + // << property_handle_->property("internal_force_enrich", + // discontinuity_prop_id_, 0, Tdim)(1, + // 0)<<" " + // << property_handle_->property("internal_force_enrich", + // discontinuity_prop_id_, 0, Tdim)(2, + // 0) + // << std::endl; + // obtain the enriched values of enriched nodes + Eigen::Matrix mass_enrich = + property_handle_->property("mass_enrich", discontinuity_prop_id_, 0, 1); + + // mass for different sides + auto mass_positive = mass_.col(phase) + mass_enrich; + auto mass_negative = mass_.col(phase) - mass_enrich; + + Eigen::Matrix momenta_enrich = property_handle_->property( + "momenta_enrich", discontinuity_prop_id_, 0, Tdim); + Eigen::Matrix unbalanced_force = + this->external_force_.col(phase) + this->internal_force_.col(phase); + Eigen::Matrix unbalanced_force_enrich = + property_handle_->property("internal_force_enrich", + discontinuity_prop_id_, 0, Tdim) + + property_handle_->property("external_force_enrich", + discontinuity_prop_id_, 0, Tdim); + + Eigen::Matrix damp_force_positive = + -damping_factor * (unbalanced_force + unbalanced_force_enrich).norm() * + (this->momentum_.col(phase) + momenta_enrich).normalized(); + + if (mass_positive(phase) < tolerance) damp_force_positive.setZero(); + + Eigen::Matrix damp_force_negative = + -damping_factor * (unbalanced_force - unbalanced_force_enrich).norm() * + (this->momentum_.col(phase) - momenta_enrich).normalized(); + + if (mass_negative(phase) < tolerance) damp_force_negative.setZero(); + this->external_force_.col(phase) += + 0.5 * (damp_force_positive + damp_force_negative); + + property_handle_->update_property( + "external_force_enrich", discontinuity_prop_id_, 0, + 0.5 * (damp_force_positive - damp_force_negative), Tdim); + + // force <<"unbalanced positive force:"<external_force_.col(phase)[0]<<" " + // << this->external_force_.col(phase)[1]<<" " + // << this->external_force_.col(phase)[2] << std::endl; + // force <<"enriched external force:"<property("external_force_enrich", + // discontinuity_prop_id_, 0, Tdim)(0, + // 0)<<" " + // << property_handle_->property("external_force_enrich", + // discontinuity_prop_id_, 0, Tdim)(1, + // 0)<<" " + // << property_handle_->property("external_force_enrich", + // discontinuity_prop_id_, 0, Tdim)(2, + // 0) + // << std::endl; + // force << std::endl; + } + + compute_momentum_discontinuity(phase, dt); + + return true; +} + //! Apply velocity constraints for discontinuity template void mpm::Nodemomentum_(direction, phase) = this->mass(phase) * constraint.second; - property_handle_->assign_property( - "momenta_enrich", discontinuity_prop_id_ * Tdim + direction, 0, - property_handle_->property("mass_enrich", discontinuity_prop_id_, 0, - 1) * - constraint.second, - 1); + // Set acceleration to 0 in direction of velocity constraint this->internal_force_(direction, phase) = 0; this->external_force_(direction, phase) = 0; - - Eigen::Matrix zero_force; - zero_force.setZero(); - property_handle_->assign_property( - "internal_force_enrich", discontinuity_prop_id_ * Tdim + direction, 0, - zero_force, 1); - property_handle_->assign_property( - "external_force_enrich", discontinuity_prop_id_ * Tdim + direction, 0, - zero_force, 1); + if (discontinuity_enrich_) { + property_handle_->assign_property( + "momenta_enrich", discontinuity_prop_id_ * Tdim + direction, 0, + property_handle_->property("mass_enrich", discontinuity_prop_id_, 0, + 1) * + constraint.second, + 1); + Eigen::Matrix zero_force; + zero_force.setZero(); + property_handle_->assign_property( + "internal_force_enrich", discontinuity_prop_id_ * Tdim + direction, + 0, zero_force, 1); + property_handle_->assign_property( + "external_force_enrich", discontinuity_prop_id_ * Tdim + direction, + 0, zero_force, 1); + } } else { // need to be done // Velocity constraints on general boundaries // Compute inverse rotation matrix @@ -131,6 +270,21 @@ void mpm::Node::self_contact_discontinuity( double dt) noexcept { if (!discontinuity_enrich_) return; + + double contact_distance = property_handle_->property( + "contact_distance", discontinuity_prop_id_, 0, 1)(0, 0); + + Eigen::Matrix normal_vector = property_handle_->property( + "normal_unit_vectors_discontinuity", discontinuity_prop_id_, 0, Tdim); + std::ofstream testnormal("testnormal.txt", std::ios::app); + testnormal << coordinates_[0] << " " << coordinates_[1] << " " + << coordinates_[2] << " " << normal_vector[0] << " " + << normal_vector[1] << " " << normal_vector[2] << " " + << contact_distance << std::endl; + // normal_vector[0] = 0; + // normal_vector[1] = -1; + // normal_vector[2] = 0; + if (contact_distance >= 0) return; // single phase for solid unsigned phase = 0; const double tolerance = 1.0E-15; @@ -140,8 +294,6 @@ void mpm::Node::self_contact_discontinuity( property_handle_->property("mass_enrich", discontinuity_prop_id_, 0, 1); Eigen::Matrix momenta_enrich = property_handle_->property( "momenta_enrich", discontinuity_prop_id_, 0, Tdim); - Eigen::Matrix normal_vector = property_handle_->property( - "normal_unit_vectors_discontinuity", discontinuity_prop_id_, 0, Tdim); // mass for different sides auto mass_positive = mass_.col(phase) + mass_enrich; @@ -170,6 +322,10 @@ void mpm::Node::self_contact_discontinuity( // friction_coef < 0: move together without slide double friction_coef = property_handle_->property( "friction_coef", discontinuity_prop_id_, 0, 1)(0, 0); + + // std::ofstream testnormal("test_coef.txt", std::ios::app); + // testnormal << coordinates_[0] << " " << friction_coef << std::endl; + if (friction_coef < 0) { property_handle_->update_property("momenta_enrich", discontinuity_prop_id_, 0, momentum_contact.col(phase), Tdim); @@ -183,8 +339,46 @@ void mpm::Node::self_contact_discontinuity( momentum_contact.col(phase).dot(normal_vector); double force_contact_norm = momentum_contact_norm / dt; - // the maximum friction contact force - double max_friction_force = friction_coef * abs(force_contact_norm); + // the cohesion at nodes + double cohesion = property_handle_->property( + "cohesion", discontinuity_prop_id_, 0, 1)(0, 0); + + if (coordinates_[0] < 513) + cohesion = 25000; + else if (coordinates_[0] < 660) + cohesion = 25000; + else if (coordinates_[0] < 893.6) + cohesion = 10000; + else if (coordinates_[0] < 955) + cohesion = 0; + else if (coordinates_[0] < 1005) + cohesion = (coordinates_[0] - 955) / 50 * 10000; + else + cohesion = 10000; + + if (coordinates_[0] < 200) + cohesion = 0; + else if (coordinates_[0] < 513) + cohesion = 150000; + else if (coordinates_[0] < 660) + cohesion = 25000; + else if (coordinates_[0] < 893.6) + cohesion = 10000; + else if (coordinates_[0] < 955) + cohesion = 0; + else if (coordinates_[0] < 1005) + cohesion = (coordinates_[0] - 955) / 50 * 10000; + else + cohesion = 10000; + // cohesion = 0; + + // the cohesion at nodes + double cohesion_area = property_handle_->property( + "cohesion_area", discontinuity_prop_id_, 0, 1)(0, 0); + // if (std::isnan(cohesion_area) || cohesion_area <= 0 || cohesion_area > 2) + // cohesion_area = 0; + double max_friction_force = + friction_coef * abs(force_contact_norm) + 2 * cohesion * cohesion_area; // the contact momentum, force vector for sticking contact at tangential // direction @@ -199,6 +393,9 @@ void mpm::Node::self_contact_discontinuity( ? force_tangential_value : max_friction_force; + // std::ofstream cohesion_force("cohesion_force.txt",std::ios::app); + // cohesion_force<update_property( "momenta_enrich", discontinuity_prop_id_, 0, @@ -212,3 +409,24 @@ void mpm::Node::self_contact_discontinuity( Tdim); } } + +//! Apply self-contact of the discontinuity +template +void mpm::Node::update_levelset() noexcept { + Eigen::Matrix origin; + return; + origin << 28.2 - coordinates_[0], 27.2 - coordinates_[1], coordinates_[2]; + + Eigen::Matrix levelset; + // levelset(0, 0) = 22.4933 - origin.norm(); + // levelset(0, 0) = (2.05 - 1.738)/(0.99-0.81)*() + + // if (discontinuity_enrich_) + property_handle_->assign_property("levelset_phi", discontinuity_prop_id_, 0, + levelset, 1); +} + +//! Add a cell id +template +void mpm::Node::add_cell_id(Index id) noexcept { + cells_.emplace_back(id); +} diff --git a/include/particles/particle.h b/include/particles/particle.h index 860c828e4..62890c4f3 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -149,6 +149,9 @@ class Particle : public ParticleBase { //! Map multimaterial domain gradients to nodes void map_multimaterial_domain_gradients_to_nodes() noexcept override; + //! Map particle volume to nodes + void map_volume_to_nodes() noexcept override; + //! Assign nodal mass to particles //! \param[in] mass Mass from the particles in a cell //! \retval status Assignment status diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index 020195d05..4d5633812 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -526,6 +526,19 @@ void mpm::Particle::map_mass_momentum_to_nodes() noexcept { } } +//! Map particle volume to nodes +template +void mpm::Particle::map_volume_to_nodes() noexcept { + // Check if particle mass is set + assert(volume_ != std::numeric_limits::max()); + + // Map volume to nodes + for (unsigned i = 0; i < nodes_.size(); ++i) { + nodes_[i]->update_volume(true, mpm::ParticlePhase::Solid, + volume_ * shapefn_[i]); + } +} + //! Map multimaterial properties to nodes template void mpm::Particle::map_multimaterial_mass_momentum_to_nodes() noexcept { @@ -748,6 +761,7 @@ bool mpm::Particle::assign_traction(unsigned direction, double traction) { } // Assign traction traction_(direction) = traction * this->volume_ / this->size_(direction); + traction_(direction) = traction; status = true; this->set_traction_ = true; } catch (std::exception& exception) { diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 9fa454792..81602aa58 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -321,6 +321,34 @@ class ParticleBase { //! Compute the principal stress and strain virtual void compute_principal_stress_strain(){}; + //! Map particle volume to nodes + virtual void map_volume_to_nodes() noexcept = 0; + + //! Map particle levelset to nodes + virtual void map_levelset_to_nodes(){}; + + //! Map particle frictional_coef to nodes + virtual void map_friction_coef_to_nodes(double discontinuity_friction_coef){}; + + //! Map levelset from nodes to particles + virtual void map_levelset_to_particle(){}; + + //! Compute dudx + //! \param[in] dt Analysis time step + virtual void compute_dudx(double dt){}; + + // virtual void check_levelset(){}; + + //! return levelset values + virtual double levelset_phi() { return 0; } + + //! compute the minimum eigenvalue of the acoustic tensor + //! \param[in] the normal direction of the discontinuity + virtual bool minimum_acoustic_tensor(VectorDim& normal_cell, + bool initiation) { + return false; + }; + protected: //! particleBase id Index id_{std::numeric_limits::max()}; diff --git a/include/particles/particle_xmpm.h b/include/particles/particle_xmpm.h index 0890e1b06..43fe0a3e9 100644 --- a/include/particles/particle_xmpm.h +++ b/include/particles/particle_xmpm.h @@ -11,6 +11,9 @@ #include "logger.h" #include "particle_base.h" +#include +#include + namespace mpm { //! ParticleXMPM class @@ -42,8 +45,22 @@ class ParticleXMPM : public Particle { //! Delete assignment operator ParticleXMPM& operator=(const ParticleXMPM&) = 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; + + //! Retrun particle data as HDF5 + //! \retval particle HDF5 data of the particle + HDF5Particle hdf5() const override; + //! Initialise properties void initialise() override; + //! Type of particle + std::string type() const override { + return (Tdim == 2) ? "P2DXMPM" : "P3DXMPM"; + } //! Map particle mass and momentum to nodes void map_mass_momentum_to_nodes() noexcept override; @@ -51,12 +68,28 @@ class ParticleXMPM : public Particle { //! \param[in] pgravity Gravity of a particle void map_body_force(const VectorDim& pgravity) noexcept override; + //! Map traction force + void map_traction_force() noexcept override; + //! Map internal force inline void map_internal_force() noexcept override; //! Compute the principal stress and strain void compute_principal_stress_strain(); + //! Map particle levelset to nodes + void map_levelset_to_nodes() noexcept override; + + //! Map particle frictional_coef to nodes + //! \param[in] friction_coef of the discontinuity + void map_friction_coef_to_nodes( + double discontinuity_friction_coef) noexcept override; + //! Compute dudx + //! \param[in] dt Analysis time step + void compute_dudx(double dt) noexcept; + + // virtual void check_levelset() noexcept override; + //! Compute updated position of the particle //! \param[in] dt Analysis time step //! \param[in] velocity_update Update particle velocity from nodal vel @@ -70,6 +103,19 @@ class ParticleXMPM : public Particle { inline Eigen::Matrix compute_strain_rate( const Eigen::MatrixXd& dn_dx, unsigned phase) noexcept; + //! Map levelset from nodes to particles + void map_levelset_to_particle(); + + //! return levelset values + double levelset_phi() { return levelset_phi_; } + + //! compute the minimum eigenvalue of the acoustic tensor + //! \param[in] the normal direction of the discontinuity + bool minimum_acoustic_tensor(VectorDim& normal_cell, bool initiation); + + //! compute the gradient of displacement dot direction + void compute_initiation_normal(VectorDim& normal); + private: //! Assign the level set function values //! \param[in] phivalue The level set values @@ -152,6 +198,8 @@ class ParticleXMPM : public Particle { using Particle::tensor_properties_; //! Pack size using Particle::pack_size_; + //! du/dx at particles + Eigen::Matrix du_dx_; private: //! level set value: phi for discontinuity @@ -163,6 +211,12 @@ class ParticleXMPM : public Particle { double first_principal_strain_{0.}; //! energy:first_principal_stress_*first_principal_strain_*0.5 double energy_{0.}; + + //! the minimum eigenvalue of the acoustic tensor + double minimum_acoustic_eigenvalue_{1e16}; + + //! angle + double discontinuity_angle_{0.}; }; // ParticleXMPM class } // namespace mpm diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index 468b19ddc..1736224b0 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -21,9 +21,35 @@ mpm::ParticleXMPM::ParticleXMPM(Index id, const VectorDim& coord, console_ = std::make_unique(logger, mpm::stdout_sink); } +//! Initialise particle data from HDF5 +template +bool mpm::ParticleXMPM::initialise_particle( + const HDF5Particle& particle) { + mpm::Particle::initialise_particle(particle); + + // levelset_phi + this->levelset_phi_ = particle.levelset_phi; + + return true; +} + +//! Return particle data in HDF5 format +template +// cppcheck-suppress * +mpm::HDF5Particle mpm::ParticleXMPM::hdf5() const { + + mpm::HDF5Particle particle_data = mpm::Particle::hdf5(); + + particle_data.levelset_phi = levelset_phi_; + return particle_data; +} + // Initialise particle properties template void mpm::ParticleXMPM::initialise() { + + du_dx_.setZero(); + this->scalar_properties_["levelset"] = [&]() { return levelset_phi_; }; this->scalar_properties_["first_principal_stress"] = [&]() { return first_principal_stress_; @@ -32,6 +58,13 @@ void mpm::ParticleXMPM::initialise() { return first_principal_strain_; }; this->scalar_properties_["energy"] = [&]() { return energy_; }; + + this->scalar_properties_["minimum_acoustic_eigenvalue"] = [&]() { + return minimum_acoustic_eigenvalue_; + }; + this->scalar_properties_["discontinuity_angle"] = [&]() { + return discontinuity_angle_; + }; } //! Map particle mass and momentum to nodes @@ -59,6 +92,48 @@ void mpm::ParticleXMPM::map_mass_momentum_to_nodes() noexcept { } } +//! Map particle levelset to nodes +template +void mpm::ParticleXMPM::map_levelset_to_nodes() noexcept { + double volume_node; + Eigen::Matrix levelset; + // Map levelset to nodes + for (unsigned i = 0; i < nodes_.size(); ++i) { + volume_node = nodes_[i]->volume(mpm::ParticlePhase::Solid); + // Unit 1x1 Eigen matrix to be used with scalar quantities + levelset(0, 0) = levelset_phi_ * volume_ * shapefn_[i] / volume_node; + // Map levelset to nodes + nodes_[i]->update_discontinuity_property(true, "levelset_phi", levelset, 0, + 1); + } +} + +//! Map particle friction_coef_to_nodes +template +void mpm::ParticleXMPM::map_friction_coef_to_nodes( + double discontinuity_friction_coef) noexcept { + double volume_node; + + double friction_coef_scalar = 0; + Eigen::Matrix friction_coef; + + double friction_angle = this->state_variable("phi"); + + if (std::isnan(friction_angle)) + friction_angle = std::atan(discontinuity_friction_coef); + friction_coef_scalar = std::tan(friction_angle); + for (unsigned i = 0; i < nodes_.size(); ++i) { + volume_node = nodes_[i]->volume(mpm::ParticlePhase::Solid); + + // Unit 1x1 Eigen matrix to be used with scalar quantities + friction_coef(0, 0) = + friction_coef_scalar * volume_ * shapefn_[i] / volume_node; + + nodes_[i]->update_discontinuity_property(true, "friction_coef", + friction_coef, 0, 1); + } +} + // Compute strain rate of the particle template <> inline Eigen::Matrix mpm::ParticleXMPM<3>::compute_strain_rate( @@ -116,6 +191,22 @@ void mpm::ParticleXMPM::map_body_force( } } +//! Map traction force +template +void mpm::ParticleXMPM::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_)); + if (nodes_[i]->discontinuity_enrich()) + nodes_[i]->update_discontinuity_property( + true, "external_force_enrich", + sgn(levelset_phi_) * shapefn_[i] * traction_, 0, Tdim); + } + } +} + //! Map internal force template <> inline void mpm::ParticleXMPM<1>::map_internal_force() noexcept { @@ -180,6 +271,7 @@ inline void mpm::ParticleXMPM<3>::map_internal_force() noexcept { template void mpm::ParticleXMPM::compute_updated_position( double dt, bool velocity_update) noexcept { + // Check if particle has a valid cell ptr assert(cell_ != nullptr); // Get interpolated nodal velocity @@ -206,9 +298,11 @@ void mpm::ParticleXMPM::compute_updated_position( nodal_velocity += shapefn_[i] * nodes_[i]->momentum(phase) / nodal_mass; } } + Eigen::Matrix nodal_velocity_enrich = + Eigen::Matrix::Zero(); // Acceleration update if (!velocity_update) { - nodal_velocity.setZero(); + double shapefn_enrich = 0; // Get interpolated nodal acceleration Eigen::Matrix nodal_acceleration = @@ -221,7 +315,7 @@ void mpm::ParticleXMPM::compute_updated_position( nodes_[i]->discontinuity_property("mass_enrich", 1)(0, 0); if (nodal_mass < tolerance) continue; - nodal_velocity += + nodal_velocity_enrich += shapefn_[i] * (nodes_[i]->momentum(phase) + sgn(levelset_phi_) * @@ -240,7 +334,8 @@ void mpm::ParticleXMPM::compute_updated_position( } // Update particle velocity from interpolated nodal acceleration - this->velocity_ = nodal_velocity + (1 - shapefn_enrich) * this->velocity_ + + this->velocity_ = nodal_velocity_enrich + + (1 - shapefn_enrich) * this->velocity_ + nodal_acceleration * dt; } // Update particle velocity using interpolated nodal velocity @@ -288,3 +383,488 @@ void mpm::ParticleXMPM::compute_principal_stress_strain() { auto stress_value = estress.pseudoEigenvectors(); energy_ = 0.5 * first_principal_strain_ * first_principal_stress_; } + +//! Map levelset from nodes to particles +template +void mpm::ParticleXMPM::map_levelset_to_particle() { + + levelset_phi_ = 0; + for (unsigned i = 0; i < nodes_.size(); ++i) { + levelset_phi_ += shapefn_[i] * + nodes_[i]->discontinuity_property("levelset_phi", 1)(0, 0); + } + // for oso + if (this->material_id() == 1 || this->material_id() == 2 || this->material_id() == 2 || + this->material_id() == 4) + levelset_phi_ = levelset_phi_ > 1e-10 ? levelset_phi_ : 1e-10; + else if (this->material_id() == 3 || this->material_id() == 5 || + this->material_id() == 5) + levelset_phi_ = levelset_phi_ > -1e-10 ? -1e-10 : levelset_phi_; +} + +//! compute the mininum eigenvalue of the acoustic tensor +//! Map levelset from nodes to particles +template +bool mpm::ParticleXMPM::minimum_acoustic_tensor(VectorDim& normal_cell, + bool initiation) { + + minimum_acoustic_eigenvalue_ = std::numeric_limits::max(); + // compute the acoustic tensor + // std::ofstream testa("acoustic.txt", std::ios::app); + + bool yield_status = true; + Eigen::Matrix dp = + (this->material()) + ->dp(stress_, &state_variables_[mpm::ParticlePhase::Solid], + yield_status); + if (!yield_status) return false; + // testa <<"dp"< de = (this->material())->de(); + // clang-format off + Eigen::Matrix index; + index << 0, 3, 5, + 3, 1, 4, + 5, 4, 2; +//testa <<"de"< normal_cellcenter; + normal_cellcenter.setZero(); + //compute the initial direction + if (!initiation) { + + for (int i = 0; i < nodes_.size(); i++) { + double levelset = + nodes_[i]->discontinuity_property("levelset_phi", 1)(0, 0); + for (int j = 0; j < 3; j++) + normal_cellcenter[j] += dn_dx_centroid_(i, j) * levelset; + } + normal_cellcenter = cell_->normal_discontinuity(); + } + + if(initiation){ + //!compute the gradient of displacement dot direction + compute_initiation_normal(normal_cellcenter); + initiation = false; +// normal_cell << 0, 1,0; +// return true; + } + + normal_cellcenter.normalize(); + //Iteration + Eigen::Matrix nk = normal_cellcenter; + Eigen::Matrix nk1; + + double uk = 0; + double uk1; + + int itr_max = 1000; + double itr_tol = 1e-9; + double itr_error = 1; + double eigenvalue_j[3]{0}; + + Eigen::Matrix A; + Eigen::Matrix J; + for(int itr = 0; itr < itr_max; ++itr) + { + if(itr_error < itr_tol) + break; + + A.setZero(); + J.setZero(); + for (int m = 0; m < 3; m++) + for (int n = 0; n < 3; n++) { + + for (int r = 0; r < 3; r++) + for (int s = 0; s < 3; s++) + A(m, n) += + nk(r) * nk(s) * dp(index(m, r), index(n, s)); + } + double det_A = A.determinant(); + Eigen::Matrix inv_A = A.inverse(); + + //testa <<"A"< eigen_J(J); + auto eigenvalues = eigen_J.pseudoEigenvalueMatrix(); + auto eigenvectors = eigen_J.pseudoEigenvectors(); + + + + double project = -1e6; + for(int i = 0; i < 3; ++i) + { + Eigen::Matrix eigen = eigenvectors.col(i); + eigenvalue_j[i] = eigenvalues(i,i); + + if(eigen.dot(nk) < 0) + eigen = -eigen; + if(std::abs(eigen.dot(nk)) < project) + continue; + + project = std::abs(eigen.dot(nk)); + nk1 = eigen; + uk1 = eigenvalues(i,i); + } + + + itr_error = (nk1-nk).norm() + std::abs(uk1/uk - 1); + console_->info("\n itr:{},{}\nJ eigen:{},{},{}", itr,itr_error,eigenvalues(0,0),eigenvalues(1,1),eigenvalues(2,2)); + // console_->info("wrong iteration of acoustic tensor, {},{},{},{},{},{},{},{},{},{},{}",itr,det_A,itr_error,nk[0],nk[1],nk[2],nk1[0],nk1[1],nk1[2],uk1,uk); + nk = nk1; + uk = uk1; + if(itr >= 999){ + console_->error("wrong iteration of acoustic tensor, {},{},{},{},{},{},{},{},{},{}",itr,itr_error,nk[0],nk[1],nk[2],nk1[0],nk1[1],nk1[2],uk1,uk); + if(itr_error < 1e-6) + continue; + nk = normal_cellcenter; + } + } + if(normal_cellcenter.dot(nk) < 0) + nk = -nk; + + //check det(A) + A.setZero(); + for (int m = 0; m < 3; m++) + for (int n = 0; n < 3; n++) { + for (int r = 0; r < 3; r++) + for (int s = 0; s < 3; s++) + A(m, n) += + nk(r) * nk(s) * dp(index(m, r), index(n, s)); + } + double det_A = A.determinant(); + Eigen::EigenSolver eigen_A(A); + auto eigenvalues = eigen_A.pseudoEigenvalueMatrix(); + auto eigenvectors = eigen_A.pseudoEigenvectors(); + + // testa<info("\n A eigen:{},{},{},{}\n", det_A,eigenvalues(0,0),eigenvalues(1,1),eigenvalues(2,2)); + // if(det_A > 0) + // return false; + normal_cell = nk; + console_->info("\n normal:{},{},{},\nA eigen:{},{},{},{}\n", nk[0],nk[1],nk[2],det_A,eigenvalues(0,0),eigenvalues(1,1),eigenvalues(2,2)); + + return true; + + // clang-format on + Eigen::Matrix dp_n; + Eigen::Matrix de_n; + + Eigen::Matrix normal; + Eigen::Matrix normal_propagation; + + normal_propagation.setZero(); + + if (!initiation) { + + for (int i = 0; i < nodes_.size(); i++) { + double levelset = + nodes_[i]->discontinuity_property("levelset_phi", 1)(0, 0); + for (int j = 0; j < 3; j++) + normal_cellcenter[j] += dn_dx_centroid_(i, j) * levelset; + } + + normal_cellcenter.normalize(); + } + + if (initiation) { + normal_cellcenter << 0, 1, 0; + initiation = false; + } + + double theta; + double phi; + double discontinuity_angle = 0; + double dtheta = 0.1; + const double PI = 3.141592653 / 180; + + double det_de_n; + double det_dp_n; + + double mininum_ratio = std::numeric_limits::max(); + // std::ofstream test("test.txt", std::ios::app); + for (int i = 0; i < std::floor(360 / dtheta); i++) { + for (int j = 0; j < 1; j++) { + double theta = i * dtheta * PI; + double phi = j * dtheta * PI; + normal << std::cos(phi) * std::cos(theta), + std::cos(phi) * std::sin(theta), std::sin(phi); + dp_n.setZero(); + de_n.setZero(); + for (int m = 0; m < 3; m++) + for (int n = 0; n < 3; n++) { + + for (int r = 0; r < 3; r++) + for (int s = 0; s < 3; s++) + dp_n(m, n) += + normal(r) * normal(s) * dp(index(m, r), index(n, s)); + } + + det_dp_n = dp_n.determinant(); + for (int m = 0; m < 3; m++) + for (int n = 0; n < 3; n++) { + + for (int r = 0; r < 3; r++) + for (int s = 0; s < 3; s++) + de_n(m, n) += + normal(r) * normal(s) * de(index(m, r), index(n, s)); + } + + det_de_n = de_n.determinant(); + double ratio = det_dp_n / det_de_n; + + if (ratio < 1e-3) { + + if (!initiation) { + if (normal_cellcenter(0) * normal(0) + + normal_cellcenter(1) * normal(1) + + normal_cellcenter(1) * normal(2) > + normal_cellcenter(0) * normal_propagation(0) + + normal_cellcenter(1) * normal_propagation(1) + + normal_cellcenter(2) * normal_propagation(2)) { + minimum_acoustic_eigenvalue_ = -1; + normal_propagation = normal; + discontinuity_angle = theta; + // test << ratio << ", angele: "; + // test << discontinuity_angle / PI << ", "; + } + } else { + if (ratio < mininum_ratio) { + mininum_ratio = ratio; + minimum_acoustic_eigenvalue_ = -1; + normal_propagation = normal; + discontinuity_angle = theta; + // test << ratio << ", angele: "; + // test << discontinuity_angle / PI << ", "; + } + } + } + + // Eigen::EigenSolver eigen_acoustic_n(acoustic_n); + // auto eigenvalues = eigen_acoustic_n.pseudoEigenvalueMatrix(); + // auto minimum_eigen = eigenvalues(0, 0) < eigenvalues(1, 1) + // ? eigenvalues(0, 0) + // : eigenvalues(1, 1); + // minimum_eigen = + // minimum_eigen < eigenvalues(1, 1) ? minimum_eigen : eigenvalues(2, + // 2); + // if (minimum_acoustic_eigenvalue_ > minimum_eigen) { + // minimum_acoustic_eigenvalue_ = minimum_eigen; + // normal_propagation = normal; + // } + } + } + + // test << std::endl; + discontinuity_angle_ = discontinuity_angle / PI; + + if (minimum_acoustic_eigenvalue_ > 0) return false; + + // if (discontinuity_angle_ < 120) { + // discontinuity_angle_ = 120; + // double theta = discontinuity_angle_ * PI; + // double phi = 0; + // normal_propagation << std::cos(phi) * std::cos(theta), + // std::cos(phi) * std::sin(theta), std::sin(phi); + // } + + double max_theta = 60 * PI; + if (!initiation) { + double dot_normal = normal_cellcenter(0) * normal_propagation(0) + + normal_cellcenter(1) * normal_propagation(1) + + normal_cellcenter(2) * normal_propagation(2); + + if (dot_normal < 0) normal_propagation = -normal_propagation; + + dot_normal = normal_cellcenter(0) * normal_propagation(0) + + normal_cellcenter(1) * normal_propagation(1) + + normal_cellcenter(2) * normal_propagation(2); + + if (dot_normal < std::cos(max_theta)) return false; + } + + // double theta_diff = std::acos(dot_normal); + + normal_propagation = 1.0 * normal_propagation; + + normal_propagation.normalize(); + discontinuity_angle_ = std::acos(normal_propagation(0)) / PI; + if (normal_propagation(1) < 0) discontinuity_angle_ = -discontinuity_angle_; + + normal_cell = normal_propagation; + return true; +} + +template +void mpm::ParticleXMPM::compute_initiation_normal( + VectorDim& normal_initiation) { + + double theta; + double phi; + double dtheta = 1; + const double PI = M_PI / 180; + VectorDim normal_m; + VectorDim normal_m1; + VectorDim normal_m2; + VectorDim dudx_n; + VectorDim normal; + double a1, a2; + + Eigen::Matrix dp_n; + Eigen::Matrix de_n; + + double det_de_n; + double det_dp_n; + + double mininum_ratio = std::numeric_limits::max(); + double max_dudxmn = 0; + + bool yield_status = true; + Eigen::Matrix dp = + (this->material()) + ->dp(stress_, &state_variables_[mpm::ParticlePhase::Solid], + yield_status); + // testa <<"dp"< de = (this->material())->de(); + // clang-format off + Eigen::Matrix index; + index << 0, 3, 5, + 3, 1, 4, + 5, 4, 2; + + //std::ofstream test("test.txt", std::ios::app); + //std::ofstream testdp("testdp.txt", std::ios::app); + for (int i = 0; i < std::floor(360 / dtheta); i++) { + for (int j = 0; j < 180; j++) { + double theta = i * dtheta * PI; + double phi = j * dtheta * PI; + normal << std::cos(phi) * std::cos(theta), + std::cos(phi) * std::sin(theta), std::sin(phi); + + dp_n.setZero(); + de_n.setZero(); + for (int m = 0; m < 3; m++) + for (int n = 0; n < 3; n++) { + + for (int r = 0; r < 3; r++) + for (int s = 0; s < 3; s++) + dp_n(m, n) += + normal(r) * normal(s) * dp(index(m, r), index(n, s)); + } + + det_dp_n = dp_n.determinant(); + for (int m = 0; m < 3; m++) + for (int n = 0; n < 3; n++) { + + for (int r = 0; r < 3; r++) + for (int s = 0; s < 3; s++) + de_n(m, n) += + normal(r) * normal(s) * de(index(m, r), index(n, s)); + } + + det_de_n = de_n.determinant(); + double ratio = det_dp_n / det_de_n; + if(ratio > 0.01) + continue; + + dudx_n.setZero(); + for(unsigned m = 0; m < 3; m++) + for(unsigned n = 0; n < 3; n++) + dudx_n[m] += du_dx_(m,n)*normal[n]; + + normal_m1 << std::sin(theta),-std::cos(theta),0; + normal_m2 = normal.cross(normal_m1); + + a1 = dudx_n.dot(normal_m1); + a2 = dudx_n.dot(normal_m2); + + double angle = 0; + if(a1 == 0) + angle = M_PI_2; + angle = std::atan(a2/a1); + + double dudx_mn = std::abs(a1*std::cos(angle) + a2*std::sin(angle)); + if(dudx_mn > max_dudxmn) + { + max_dudxmn = dudx_mn; + normal_initiation = normal; + + } + //test< +void mpm::ParticleXMPM<3>::compute_dudx(double dt) noexcept { + // Define strain rate + Eigen::Matrix dudx_rate = Eigen::Matrix::Zero(); + const double tolerance = 1.E-16; + unsigned phase = mpm::ParticlePhase::Solid; + Eigen::Vector3d vel; + vel.setZero(); + // Compute corresponding nodal velocity + for (unsigned i = 0; i < this->nodes_.size(); ++i) { + if (nodes_[i]->discontinuity_enrich()) { + double nodal_mass = + nodes_[i]->mass(phase) + + sgn(levelset_phi_) * + nodes_[i]->discontinuity_property("mass_enrich", 1)(0, 0); + if (nodal_mass < tolerance) continue; + + vel = + (nodes_[i]->momentum(phase) + + sgn(levelset_phi_) * + nodes_[i]->discontinuity_property("momenta_enrich", 3).col(0)) / + nodal_mass; + } else { + double nodal_mass = nodes_[i]->mass(phase); + if (nodal_mass < tolerance) continue; + vel = nodes_[i]->momentum(phase) / nodal_mass; + } + for(unsigned j = 0; j < 3; j++) + for(unsigned k = 0; k < 3; k++) + dudx_rate(j,k) += vel[j] * dn_dx_(i, k) ; + } + + for(unsigned j = 0; j < 3; j++) + for(unsigned k = 0; k < 3; k++) + du_dx_(j,k) += dudx_rate(j,k)*dt; +} + +//! Map particle friction_coef_to_nodes +// template +// void mpm::ParticleXMPM::check_levelset() noexcept { +// if(levelset_phi_ != 0) +// return; +// assert(cell_ != nullptr); + +// for (unsigned i = 0; i < nodes_.size(); ++i) { +// if (!nodes_[i]->discontinuity_enrich()) +// continue; +// cell_->compute_normal_vector_discontinuity(); +// cell_->compute_plane_discontinuity(false); +// auto normal = cell_->normal_discontinuity(); +// double d = cell_->d_discontinuity(); +// levelset_phi_ = coordinates_.dot(normal) + d; +// return; +// } +// } \ No newline at end of file diff --git a/include/solvers/mpm_base.h b/include/solvers/mpm_base.h index 30b4e06ae..140c8470d 100644 --- a/include/solvers/mpm_base.h +++ b/include/solvers/mpm_base.h @@ -71,6 +71,8 @@ class MPMBase : public MPM { //! Checkpoint resume bool checkpoint_resume() override; + void initialise_particle_sets(){}; + #ifdef USE_VTK //! Write VTK files void write_vtk(mpm::Index step, mpm::Index max_steps) override; @@ -154,6 +156,7 @@ class MPMBase : public MPM { //! Particle entity sets //! \param[in] mesh_prop Mesh properties //! \param[in] check Check duplicates + public: void particle_entity_sets(const Json& mesh_prop, bool check); //! Initialise damping diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index d87f1e0bd..86e06cd1f 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -28,6 +28,8 @@ mpm::MPMBase::MPMBase(const std::shared_ptr& io) : mpm::MPM(io) { {"volume", VariableType::Scalar}, {"mass_density", VariableType::Scalar}, {"levelset", VariableType::Scalar}, + {"minimum_acoustic_eigenvalue", VariableType::Scalar}, + {"discontinuity_angle", VariableType::Scalar}, {"first_principal_stress", VariableType::Scalar}, {"first_principal_strain", VariableType::Scalar}, {"energy", VariableType::Scalar}, @@ -457,7 +459,8 @@ bool mpm::MPMBase::checkpoint_resume() { .string(); // Load particle information from file - mesh_->read_particles_hdf5(phase, particles_file); + const std::string particle_type = (Tdim == 2) ? "P2D" : "P3D"; + mesh_->read_particles_hdf5(phase, particles_file, particle_type); // Clear all particle ids mesh_->iterate_over_cells( diff --git a/include/solvers/mpm_explicit.tcc b/include/solvers/mpm_explicit.tcc index 8bda961a4..6072b1fe2 100644 --- a/include/solvers/mpm_explicit.tcc +++ b/include/solvers/mpm_explicit.tcc @@ -105,10 +105,26 @@ bool mpm::MPMExplicit::solve() { auto solver_begin = std::chrono::steady_clock::now(); // Main loop + // HDF5 outputs the initial status + 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 + for (; step_ < nsteps_; ++step_) { if (mpi_rank == 0) console_->info("Step: {} of {}.\n", step_, nsteps_); + // if (step_ == 0 || resume == true) { + // mesh_->output_surface(); + // resume = false; + // } + #ifdef USE_MPI #ifdef USE_GRAPH_PARTITIONING // Run load balancer at a specified frequency @@ -156,16 +172,16 @@ bool mpm::MPMExplicit::solve() { #endif #endif - if (step_ % output_steps_ == 0) { + if ((step_ + 1) % output_steps_ == 0) { // HDF5 outputs - this->write_hdf5(this->step_, this->nsteps_); + this->write_hdf5(this->step_ + 1, this->nsteps_); #ifdef USE_VTK // VTK outputs - this->write_vtk(this->step_, this->nsteps_); + this->write_vtk(this->step_ + 1, this->nsteps_); #endif #ifdef USE_PARTIO // Partio outputs - this->write_partio(this->step_, this->nsteps_); + this->write_partio(this->step_ + 1, this->nsteps_); #endif } } diff --git a/include/solvers/mpm_scheme/mpm_scheme.h b/include/solvers/mpm_scheme/mpm_scheme.h index 683d149ad..b5472e19f 100644 --- a/include/solvers/mpm_scheme/mpm_scheme.h +++ b/include/solvers/mpm_scheme/mpm_scheme.h @@ -74,6 +74,8 @@ class MPMScheme { //! Stress update scheme //! \retval scheme Stress update scheme virtual inline std::string scheme() const = 0; + //! Time increment + void assign_dt(double dt) { dt_ = dt; }; protected: //! Mesh object diff --git a/include/solvers/xmpm_explicit.h b/include/solvers/xmpm_explicit.h index 9e3f4875d..ad38202e3 100644 --- a/include/solvers/xmpm_explicit.h +++ b/include/solvers/xmpm_explicit.h @@ -17,6 +17,8 @@ namespace mpm { template class XMPMExplicit : public MPMBase { public: + //! Define a vector of size dimension + using VectorDim = Eigen::Matrix; //! Default constructor XMPMExplicit(const std::shared_ptr& io); @@ -27,11 +29,22 @@ class XMPMExplicit : public MPMBase { //! \param[in] phase Phase to smooth pressure void compute_stress_strain(unsigned phase); - //! Initialise discontinuities - void initialise_discontinuities(); + //! Initialise discontinuity + void initialise_discontinuity(); - // return the number of discontinuities - mpm::Index ndiscontinuities() { return discontinuities_.size(); }; + //! Checkpoint resume + bool checkpoint_resume() override; + + void initialise_particle_sets() { + // Get mesh properties + auto mesh_props = io_->json_object("mesh"); + // Check duplicates default set to true + bool check_duplicates = true; + if (mesh_props.find("check_duplicates") != mesh_props.end()) + check_duplicates = mesh_props["check_duplicates"].template get(); + + this->particle_entity_sets(mesh_props, check_duplicates); + }; protected: // Generate a unique id for the analysis @@ -89,10 +102,21 @@ class XMPMExplicit : public MPMBase { //! Interface bool interface_{false}; //! discontinuities statue - bool discontinuity_{false}; + bool setdiscontinuity_{false}; //! discontinuities - std::map>> - discontinuities_; + std::shared_ptr> discontinuity_; + + bool surfacemesh_{false}; + + bool particle_levelet_{false}; + + bool propagation_{false}; + + bool initiation_{false}; + + std::string nodal_levelset_{"shepard"}; + + bool friction_coef_average_{false}; }; // XMPMExplicit class } // namespace mpm diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index 6707c03ba..1b800863b 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -75,38 +75,80 @@ bool mpm::XMPMExplicit::solve() { this->initialise_mesh(); // Initialise particles - this->initialise_particles(); + if (!resume) + this->initialise_particles(); + else + this->initialise_particle_sets(); // Initialise loading conditions this->initialise_loads(); + // Initialise the cells in node + mesh_->add_cell_in_node(); + // Create nodal properties if (interface_) mesh_->create_nodal_properties(); // Initialise discontinuity - this->initialise_discontinuities(); + this->initialise_discontinuity(); - if (discontinuity_) { - // Initialise the levelset values for particles - mesh_->initialise_levelset_discontinuity(); + // Create nodal properties for discontinuity + if (setdiscontinuity_) mesh_->create_nodal_properties_discontinuity(); - // Create nodal properties for discontinuity - mesh_->create_nodal_properties_discontinuity(); - } // Compute mass - mesh_->iterate_over_particles( - std::bind(&mpm::ParticleBase::compute_mass, std::placeholders::_1)); + if (!resume) + mesh_->iterate_over_particles(std::bind( + &mpm::ParticleBase::compute_mass, std::placeholders::_1)); // Check point resume - if (resume) this->checkpoint_resume(); + if (resume) { + this->checkpoint_resume(); + --this->step_; + mesh_->resume_domain_cell_ranks(); +#ifdef USE_MPI +#ifdef USE_GRAPH_PARTITIONING + MPI_Barrier(MPI_COMM_WORLD); +#endif +#endif + } else { + // Domain decompose + bool initial_step = (resume == true) ? false : true; + this->mpi_domain_decompose(initial_step); + } - // Domain decompose - bool initial_step = (resume == true) ? false : true; - this->mpi_domain_decompose(initial_step); + // Initialise the levelset values for particles + if (surfacemesh_) mesh_->initialise_levelset_discontinuity(); auto solver_begin = std::chrono::steady_clock::now(); - // Main loop + + if (!resume) { + // Main loop + // HDF5 outputs + // HDF5 outputs the initial status + 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 + } + for (; step_ < nsteps_; ++step_) { + bool nodal_update = true; + + int change_step = 0; + + mesh_->assign_step(step_); + if (step_ == change_step) { + // output_steps_ = 10; + // console_->info("change material"); + // mesh_->change_mat(); + // //dt_ = 0.001; + // mpm_scheme_->assign_dt(dt_); + } if (mpi_rank == 0) console_->info("Step: {} of {}.\n", step_, nsteps_); @@ -124,58 +166,177 @@ bool mpm::XMPMExplicit::solve() { // Initialise nodes, cells and shape functions mpm_scheme_->initialise(); + if (step_ == 0 || resume == true) { + // for oso + mesh_->define_levelset(); + resume = false; + } + // if (step_ == 0 || resume == true) { + // mesh_->output_surface(); + // resume = false; + // } + // if (step_ == 40800) { + // particle_levelet_ = true; + // initiation_ = false; + // propagation_ = false; + // } + // if (step_ == 40600) { + // output_steps_ = 1; + // } + // Initialise nodal properties and append material ids to node contact_->initialise(); - if (discontinuity_) { + if (initiation_) initiation_ = !mesh_->initiation_discontinuity(); + + if (setdiscontinuity_ && !initiation_ && step_ >= change_step) { // Initialise nodal properties mesh_->initialise_nodal_properties(); + // Initialise element properties + mesh_->iterate_over_cells(std::bind( + &mpm::Cell::initialise_element_properties_discontinuity, + std::placeholders::_1)); + if (!particle_levelet_) { + // locate points of discontinuity + mesh_->locate_discontinuity(); + + // Iterate over each points to compute shapefn + mesh_->compute_shapefn_discontinuity(); + } + + // if (surfacemesh_ && (step_ + 1) % 2000 == 0 ) + // mesh_->initialise_levelset_discontinuity(); + + // // obtain nodal volume - // Iterate over each particle to compute the principal stress and strain mesh_->iterate_over_particles( - std::bind(&mpm::ParticleBase::compute_principal_stress_strain, + std::bind(&mpm::ParticleBase::map_volume_to_nodes, std::placeholders::_1)); - // locate points of discontinuity - mesh_->locate_discontinuity(); + if (!nodal_update) { + mesh_->iterate_over_particles( + std::bind(&mpm::ParticleBase::map_levelset_to_nodes, + std::placeholders::_1)); + } + + if (nodal_levelset_ == "mls") + // modify the nodal levelset_phi by mls + mesh_->modify_nodal_levelset_mls(); + + // obtain nodal frictional_coefficient + + if (friction_coef_average_) + mesh_->iterate_over_particles( + std::bind(&mpm::ParticleBase::map_friction_coef_to_nodes, + std::placeholders::_1, discontinuity_->friction_coef())); - // Iterate over each points to compute shapefn - mesh_->compute_shapefn_discontinuity(); + if (propagation_) { + // find the potential tip element + mesh_->iterate_over_cells(std::bind( + &mpm::Cell::potential_tip_element, std::placeholders::_1)); + } + if (particle_levelet_) { + // determine the celltype by the nodal level set + mesh_->iterate_over_cells(std::bind(&mpm::Cell::determine_crossed, + std::placeholders::_1)); + } + + // obtain the normal direction of non-regular cell + mesh_->compute_cell_normal_vector_discontinuity(); + + mesh_->iterate_over_cells(std::bind( + &mpm::Cell::compute_area_discontinuity, std::placeholders::_1)); + // mesh_->output_celltype(step_); + if (propagation_) + // remove the spurious potential tip element + mesh_->spurious_potential_tip_element(); + // mesh_->output_celltype(step_); + // mesh_->compute_error(); + // assign_node_enrich + mesh_->assign_node_enrich(friction_coef_average_, nodal_update); + + mesh_->check_particle_levelset(particle_levelet_); + + // mesh_->output_celltype(step_); + // obtain the normal direction of each cell and enrich nodes + mesh_->compute_nodal_normal_vector_discontinuity(); + // mesh_->output_celltype(step_); + if (propagation_) // find the tip element + { + + mesh_->iterate_over_cells( + std::bind(&mpm::Cell::tip_element, std::placeholders::_1)); + // mesh_->update_node_enrich(friction_coef_average_); + } - // obtain the normal direction of each enrich nodes - mesh_->compute_normal_vector_discontinuity(); + // mesh_->output_celltype(step_); + mesh_->selfcontact_detection(); } + // mesh_->iterate_over_particles(std::bind( + // &mpm::ParticleBase::check_levelset, std::placeholders::_1)); + // Mass momentum and compute velocity at nodes mpm_scheme_->compute_nodal_kinematics(phase); + if (particle_levelet_ || nodal_update) mesh_->update_node_enrich(); + // Map material properties to nodes contact_->compute_contact_forces(); // Update stress first mpm_scheme_->precompute_stress_strain(phase, pressure_smoothing_); + // Iterate over each particle to calculate dudx + mesh_->iterate_over_particles(std::bind( + &mpm::ParticleBase::compute_dudx, std::placeholders::_1, dt_)); + // Compute forces mpm_scheme_->compute_forces(gravity_, phase, step_, set_node_concentrated_force_); + // if ((step_ + 1) % 10 == 0) { + // mesh_->output_force(step_); + // } + // integrate momentum by iterating over nodes - mesh_->iterate_over_nodes_predicate( - std::bind(&mpm::NodeBase::compute_momentum_discontinuity, - std::placeholders::_1, phase, this->dt_), - std::bind(&mpm::NodeBase::status, std::placeholders::_1)); - - // Update the discontinuity position - if (discontinuity_) - mesh_->compute_updated_position_discontinuity(this->dt_); - - // // Particle kinematics - // mpm_scheme_->compute_particle_kinematics(velocity_update_, phase, - // "Cundall", - // damping_factor_); + if (damping_type_ == mpm::Damping::Cundall) + mesh_->iterate_over_nodes_predicate( + std::bind( + &mpm::NodeBase::compute_momentum_discontinuity_cundall, + std::placeholders::_1, phase, dt_, damping_factor_), + std::bind(&mpm::NodeBase::status, std::placeholders::_1)); + else + mesh_->iterate_over_nodes_predicate( + std::bind(&mpm::NodeBase::compute_momentum_discontinuity, + std::placeholders::_1, phase, this->dt_), + std::bind(&mpm::NodeBase::status, std::placeholders::_1)); + + if (setdiscontinuity_ && !initiation_ && step_ >= change_step) { + + if (propagation_) { + // find the next tip element + mesh_->next_tip_element_discontinuity(); + + // mesh_->iterate_over_cells( + // std::bind(&mpm::Cell::assign_tipcell_nodal_discontinuity, + // std::placeholders::_1, true)); + // discontinuity growth + // mesh_->output_celltype(step_); + mesh_->update_discontinuity(); + // mesh_->output_celltype(step_); + } + + // Update the discontinuity position + if (!particle_levelet_) + mesh_->compute_updated_position_discontinuity(this->dt_); + } + // Iterate over each particle to compute updated position mesh_->iterate_over_particles( std::bind(&mpm::ParticleBase::compute_updated_position, std::placeholders::_1, dt_, velocity_update_)); + // Apply particle velocity constraints + mesh_->apply_particle_velocity_constraints(); // Update Stress Last mpm_scheme_->postcompute_stress_strain(phase, pressure_smoothing_); @@ -183,6 +344,12 @@ bool mpm::XMPMExplicit::solve() { // Locate particles mpm_scheme_->locate_particles(this->locate_particles_); + //if (nodal_update) mesh_->update_nodal_levelset(dt_); + + // if ((step_ + 1) % 1 == 0) { + // mesh_->output_nodal_levelset(step_); + // } + #ifdef USE_MPI #ifdef USE_GRAPH_PARTITIONING mesh_->transfer_halo_particles(); @@ -190,16 +357,19 @@ bool mpm::XMPMExplicit::solve() { #endif #endif - if (step_ % output_steps_ == 0) { + if ((step_ + 1) % output_steps_ == 0) { // HDF5 outputs - this->write_hdf5(this->step_, this->nsteps_); + this->write_hdf5(this->step_ + 1, this->nsteps_); + + mesh_->output_discontinuity(this->step_ + 1); + // mesh_->output_force(step_); #ifdef USE_VTK // VTK outputs - this->write_vtk(this->step_, this->nsteps_); + this->write_vtk(this->step_ + 1, this->nsteps_); #endif #ifdef USE_PARTIO // Partio outputs - this->write_partio(this->step_, this->nsteps_); + this->write_partio(this->step_ + 1, this->nsteps_); #endif } } @@ -213,30 +383,44 @@ bool mpm::XMPMExplicit::solve() { return status; } -// Initialise discontinuities +// Initialise discontinuity template -void mpm::XMPMExplicit::initialise_discontinuities() { +void mpm::XMPMExplicit::initialise_discontinuity() { try { - // Get discontinuities data - auto json_discontinuities = io_->json_object("discontinuity"); - if (!json_discontinuities.empty()) { - discontinuity_ = true; - for (const auto discontinuity_props : json_discontinuities) { - // Get discontinuity type - const std::string discontunity_type = - discontinuity_props["type"].template get(); - - // Get discontinuity id - auto discontinuity_id = - discontinuity_props["id"].template get(); - - // Create a new discontinuity surface from JSON object - auto discontinuity = - Factory, unsigned, - const Json&>::instance() - ->create(discontunity_type, std::move(discontinuity_id), - discontinuity_props); - + // Get discontinuity data + auto discontinuity_props = io_->json_object("discontinuity"); + if (!discontinuity_props.empty()) { + setdiscontinuity_ = true; + // Get discontinuity type + const std::string discontunity_type = + discontinuity_props["type"].template get(); + + // Create a new discontinuity surface from JSON object + auto discontinuity = + Factory, const Json&>::instance() + ->create(discontunity_type, discontinuity_props); + + if (discontinuity_props.contains("initiation")) + initiation_ = discontinuity_props.at("initiation").template get(); + + if (discontinuity_props.contains("nodal_levelset")) + nodal_levelset_ = discontinuity_props.at("nodal_levelset") + .template get(); + + if (discontinuity_props.contains("friction_coefficient_average")) + friction_coef_average_ = + discontinuity_props.at("friction_coefficient_average") + .template get(); + + if (discontinuity_props.contains("propagation")) + propagation_ = + discontinuity_props.at("propagation").template get(); + + if (discontinuity_props.contains("io_type") && + discontinuity_props.contains("file")) { + + surfacemesh_ = true; + // particle_levelet_ = true; // Get discontinuity input type auto io_type = discontinuity_props["io_type"].template get(); @@ -252,21 +436,75 @@ void mpm::XMPMExplicit::initialise_discontinuities() { discontinuity->initialize( discontunity_io->read_mesh_nodes(discontinuity_file), discontunity_io->read_mesh_cells(discontinuity_file)); - // Add discontinuity to list - auto result = discontinuities_.insert( - std::make_pair(discontinuity_id, discontinuity)); - - // If insert discontinuity failed - if (!result.second) { - throw std::runtime_error( - "New discontinuity cannot be added, insertion failed"); - } + } else if (discontinuity_props.contains("particle_levelset")) { + particle_levelet_ = + discontinuity_props.at("particle_levelset").template get(); } - // Copy discontinuities to mesh - mesh_->initialise_discontinuities(this->discontinuities_); + + // Add discontinuity + discontinuity_ = discontinuity; + // Copy discontinuity to mesh + mesh_->initialise_discontinuity(this->discontinuity_); } } catch (std::exception& exception) { console_->warn("{} #{}: No discontinuity is defined", __FILE__, __LINE__, exception.what()); } } + +//! Checkpoint resume +template +bool mpm::XMPMExplicit::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); +#endif + + if (!analysis_["resume"]["resume"].template get()) + throw std::runtime_error("Resume analysis option is disabled!"); + + // Get unique analysis id + this->uuid_ = analysis_["resume"]["uuid"].template get(); + // Get step + this->step_ = analysis_["resume"]["step"].template get(); + + // Input particle h5 file for resume + std::string attribute = "particles"; + std::string extension = ".h5"; + + auto particles_file = + io_->output_file(attribute, extension, uuid_, step_, this->nsteps_) + .string(); + + // Load particle information from file + const std::string particle_type = (Tdim == 2) ? "P2DXMPM" : "P3DXMPM"; + mesh_->read_particles_hdf5(phase, particles_file, particle_type); + + // Clear all particle ids + mesh_->iterate_over_cells( + std::bind(&mpm::Cell::clear_particle_ids, std::placeholders::_1)); + + // Locate particles + auto unlocatable_particles = mesh_->locate_particles_mesh(); + + if (!unlocatable_particles.empty()) + throw std::runtime_error("Particle outside the mesh domain"); + + // Increament step + ++this->step_; + console_->info("Checkpoint resume at step {} of {}", this->step_, + this->nsteps_); + + } catch (std::exception& exception) { + console_->info("{} {} Resume failed, restarting analysis: {}", __FILE__, + __LINE__, exception.what()); + this->step_ = 0; + checkpoint = false; + } + return checkpoint; +} diff --git a/include/xmpm/discontinuity_3d.h b/include/xmpm/discontinuity_3d.h index d5fc5a34d..0749f0d0a 100644 --- a/include/xmpm/discontinuity_3d.h +++ b/include/xmpm/discontinuity_3d.h @@ -15,7 +15,7 @@ class Discontinuity3D : public DiscontinuityBase { //! Constructor with id //! \param[in] discontinuity_props discontinuity properties - Discontinuity3D(unsigned id, const Json& discontinuity_props); + Discontinuity3D(const Json& discontinuity_props); //! initialization //! \param[in] the coordinates of all points @@ -50,6 +50,10 @@ class Discontinuity3D : public DiscontinuityBase { //! Assign point friction coefficient void assign_point_friction_coef() noexcept override; + //! Compute updated position + //! \param[in] dt Time-step + void compute_updated_position(const double dt) noexcept; + protected: //! vector of points using mpm::DiscontinuityBase::points_; @@ -60,6 +64,8 @@ class Discontinuity3D : public DiscontinuityBase { //! width using mpm::DiscontinuityBase::width_; + using mpm::DiscontinuityBase::move_direction_; + private: // vector of surfaces std::vector> surfaces_; diff --git a/include/xmpm/discontinuity_3d.tcc b/include/xmpm/discontinuity_3d.tcc index 5549963a3..b760190bc 100644 --- a/include/xmpm/discontinuity_3d.tcc +++ b/include/xmpm/discontinuity_3d.tcc @@ -1,7 +1,6 @@ template -mpm::Discontinuity3D::Discontinuity3D(unsigned id, - const Json& discontinuity_props) - : DiscontinuityBase(id, discontinuity_props) {} +mpm::Discontinuity3D::Discontinuity3D(const Json& discontinuity_props) + : DiscontinuityBase(discontinuity_props) {} // initialization template @@ -123,8 +122,9 @@ void mpm::Discontinuity3D::compute_levelset(const VectorDim& coordinates, min_distance = distance; vertical_distance = surf.vertical_distance(coordinates); } - if (!vertical_distance) vertical_distance = 1e-16; } + if (!vertical_distance) + vertical_distance = std::numeric_limits::min(); if (abs(min_distance) < width_) phi_particle = vertical_distance; else @@ -151,4 +151,13 @@ void mpm::Discontinuity3D::compute_normal(const VectorDim& coordinates, template void mpm::Discontinuity3D::assign_point_friction_coef() noexcept { for (auto& point : points_) point.assign_friction_coef(friction_coef_); +} + +// Compute updated position of the particle +template +void mpm::Discontinuity3D::compute_updated_position(double dt) noexcept { + for (auto& point : this->points_) + point.compute_updated_position(dt, move_direction_); + + initialize_center_normal(); } \ No newline at end of file diff --git a/include/xmpm/discontinuity_base.h b/include/xmpm/discontinuity_base.h index 3fffd4723..90babf5fc 100644 --- a/include/xmpm/discontinuity_base.h +++ b/include/xmpm/discontinuity_base.h @@ -3,11 +3,13 @@ #include "cell.h" #include "data_types.h" +#include "discontinuity_element.h" #include "io_mesh.h" #include "logger.h" #include "memory.h" #include "node_base.h" #include "vector.h" +#include namespace mpm { @@ -25,7 +27,7 @@ class DiscontinuityBase { //! Constructor with id //! \param[in] discontinuity id //! \param[in] discontinuity properties json - DiscontinuityBase(unsigned id, const Json& discontinuity_props); + DiscontinuityBase(const Json& discontinuity_props); //! Destructor virtual ~DiscontinuityBase(){}; @@ -72,6 +74,18 @@ class DiscontinuityBase { //! return the friction coefficient double friction_coef() const { return friction_coef_; }; + //! return the cohesion + double cohesion() const { return cohesion_; }; + + //! return the width + double width() const { return width_; } + + //! return the contact_distance + double contact_distance() const { return contact_distance_; } + + //! return the maximum_pdstrain + double maximum_pdstrain() const { return maximum_pdstrain_; } + //! return the number of the points mpm::Index npoints() const { return points_.size(); }; @@ -83,7 +97,7 @@ class DiscontinuityBase { //! Compute updated position //! \param[in] dt Time-step - void compute_updated_position(const double dt) noexcept; + virtual void compute_updated_position(const double dt) noexcept; //! Compute shape function void compute_shapefn() noexcept; @@ -91,6 +105,12 @@ class DiscontinuityBase { //! Assign point friction coefficient virtual void assign_point_friction_coef() noexcept = 0; + //! Insert new point + void insert_particles(VectorDim& point, const Vector>& cells, + const Map>& map_cells); + + void output_markpoints(int step); + protected: //! Logger std::unique_ptr console_; @@ -104,9 +124,21 @@ class DiscontinuityBase { //! friction coefficient double friction_coef_; + //! cohesion + double cohesion_; + //! the influence length of the discontinuity double width_{std::numeric_limits::max()}; + //! move_direction + int move_direction_{1}; + + //! contact distance + double contact_distance_{std::numeric_limits::max()}; + + //! maximum pdstrain + double maximum_pdstrain_{0}; + }; // DiscontinuityBase class //! struct of discontinuity point @@ -120,6 +152,7 @@ struct discontinuity_point { discontinuity_point(const VectorDim& coordinate) { friction_coef_ = 0; + cohesion_ = 0; coordinates_ = coordinate; cell_ = nullptr; //! Logger @@ -147,9 +180,13 @@ struct discontinuity_point { //! \param[in] cellptr Pointer to a cell bool assign_cell(const std::shared_ptr>& cellptr); - //! Assign the discontinuity enrich to node - void assign_discontinuity_enrich(); + //! Assign the discontinuity type to cell + //! \param[in] map_cells map of cells + void assign_cell_enrich(const Map>& map_cells); + //! Assign the discontinuity enrich to node + //! \param[in] map_cells map of cells + void assign_node_enrich(const Map>& map_cells); //! Compute reference coordinates in a cell bool compute_reference_location() noexcept; @@ -160,7 +197,7 @@ struct discontinuity_point { const Map>& map_cells) noexcept; //! Compute updated position - void compute_updated_position(double dt) noexcept; + void compute_updated_position(double dt, int move_direction) noexcept; //! Compute shape function void compute_shapefn() noexcept; @@ -169,7 +206,15 @@ struct discontinuity_point { //! \param[in] friction_coef void assign_friction_coef(double friction_coef) noexcept { friction_coef_ = friction_coef; - }; + } + + //! Assign cohesion + //! \param[in] friction_coef + void assign_cohesion(double cohesion) noexcept { cohesion_ = cohesion; } + + //! Assign tip + //! \param[in] tip + void assign_tip(bool tip) { tip_ = tip; } private: //! point coordinates @@ -188,6 +233,10 @@ struct discontinuity_point { std::shared_ptr console_; //! friction coefficient double friction_coef_{0.}; + //! cohesion + double cohesion_{0.}; + //! tip + bool tip_{false}; }; //! struct of discontinuity line: for 2d, need to be done diff --git a/include/xmpm/discontinuity_base.tcc b/include/xmpm/discontinuity_base.tcc index 76bcb3e08..0d15abac2 100644 --- a/include/xmpm/discontinuity_base.tcc +++ b/include/xmpm/discontinuity_base.tcc @@ -1,11 +1,11 @@ //! Constructor template mpm::DiscontinuityBase::DiscontinuityBase( - unsigned id, const Json& discontinuity_props) { + const Json& discontinuity_props) { friction_coef_ = 0; - std::string logger = "discontinuity::" + std::to_string(id); + std::string logger = "discontinuity"; console_ = std::make_unique(logger, mpm::stdout_sink); try { @@ -13,10 +13,27 @@ mpm::DiscontinuityBase::DiscontinuityBase( if (discontinuity_props.contains("friction_coefficient")) friction_coef_ = discontinuity_props.at("friction_coefficient").template get(); + // assign cohesion_ if it's given in input file + if (discontinuity_props.contains("cohesion")) + cohesion_ = discontinuity_props.at("cohesion").template get(); + // assign contact_distance_ if it's given in input file + if (discontinuity_props.contains("contact_distance")) + contact_distance_ = + discontinuity_props.at("contact_distance").template get(); + + // assign move direction if it's given in input file + if (discontinuity_props.contains("move_direction")) + move_direction_ = + discontinuity_props.at("move_direction").template get(); // assign width if it's given in input file if (discontinuity_props.contains("width")) width_ = discontinuity_props.at("width").template get(); + // assign maximum_pdstrain if it's given in input file + if (discontinuity_props.contains("maximum_pdstrain")) + maximum_pdstrain_ = + discontinuity_props.at("maximum_pdstrain").template get(); + } catch (Json::exception& except) { console_->error("discontinuity parameter not set: {} {}\n", except.what(), except.id); @@ -53,17 +70,48 @@ void mpm::DiscontinuityBase::locate_discontinuity_mesh( const Map>& map_cells) noexcept { for (auto& point : this->points_) point.locate_discontinuity_mesh(cells, map_cells); + // for (auto& point : this->points_) point.assign_node_enrich(map_cells); } // Compute updated position of the particle template void mpm::DiscontinuityBase::compute_updated_position( double dt) noexcept { - for (auto& point : this->points_) point.compute_updated_position(dt); + for (auto& point : this->points_) + point.compute_updated_position(dt, move_direction_); } // Compute updated position of the particle template void mpm::DiscontinuityBase::compute_shapefn() noexcept { for (auto& point : this->points_) point.compute_shapefn(); +} + +//! Insert new point +template +void mpm::DiscontinuityBase::insert_particles( + VectorDim& coordinates, const Vector>& cells, + const Map>& map_cells) { + for (auto& point : this->points_) { + point.assign_tip(false); + } + // Add point + mpm::discontinuity_point point(coordinates); + point.locate_discontinuity_mesh(cells, map_cells); + point.compute_shapefn(); + points_.emplace_back(point); +} + +//! Output mark points +template +void mpm::DiscontinuityBase::output_markpoints(int step) { + + std::ofstream path("markpoints.txt", std::ios::app); + path << step << ":" << std::endl; + for (auto& point : this->points_) { + path << point.coordinates()[0] << " " << point.coordinates()[1] << " " + << point.coordinates()[2] << std::endl; + } + path << std::endl; + path.close(); } \ No newline at end of file diff --git a/include/xmpm/discontinuity_point.tcc b/include/xmpm/discontinuity_point.tcc index 367f9b3cc..35c4039ed 100644 --- a/include/xmpm/discontinuity_point.tcc +++ b/include/xmpm/discontinuity_point.tcc @@ -10,6 +10,7 @@ bool mpm::discontinuity_point::assign_cell_xi( cell_ = cellptr; cell_id_ = cellptr->id(); + nodes_ = cell_->nodes(); // Assign the reference location of particle bool xi_nan = false; @@ -43,7 +44,7 @@ bool mpm::discontinuity_point::assign_cell( cell_ = cellptr; cell_id_ = cellptr->id(); - assign_discontinuity_enrich(); + nodes_ = cell_->nodes(); } else { console_->warn("Points of discontinuity cannot be found in cell!"); } @@ -80,9 +81,10 @@ void mpm::discontinuity_point::locate_discontinuity_mesh( // If a cell id is present, but not a cell locate the cell from map if (!cell_ptr()) assign_cell(map_cells[cell_id()]); - assign_discontinuity_enrich(); - - if (compute_reference_location()) return; + if (compute_reference_location()) { + assign_cell_enrich(map_cells); + return; + } // Check if discontinuity point is in any of its nearest neighbours const auto neighbours = map_cells[cell_id()]->neighbours(); @@ -90,6 +92,7 @@ void mpm::discontinuity_point::locate_discontinuity_mesh( for (auto neighbour : neighbours) { if (map_cells[neighbour]->is_point_in_cell(coordinates_, &xi)) { assign_cell_xi(map_cells[neighbour], xi); + assign_cell_enrich(map_cells); return; } } @@ -102,6 +105,7 @@ void mpm::discontinuity_point::locate_discontinuity_mesh( Eigen::Matrix xi; if ((*citr)->is_point_in_cell(coordinates(), &xi)) { assign_cell_xi(*citr, xi); + assign_cell_enrich(map_cells); } } } @@ -109,7 +113,7 @@ void mpm::discontinuity_point::locate_discontinuity_mesh( // Compute updated position of the particle template void mpm::discontinuity_point::compute_updated_position( - const double dt) noexcept { + const double dt, int move_direction) noexcept { // Check if point has a valid cell ptr if (cell_ == nullptr) return; // Get interpolated nodal velocity @@ -118,19 +122,18 @@ void mpm::discontinuity_point::compute_updated_position( const double tolerance = 1.E-16; unsigned int phase = 0; // need to do, points move with which side - int move_direction = -1; for (unsigned i = 0; i < nodes_.size(); ++i) { if (nodes_[i]->discontinuity_enrich()) { - double nodal_mass = - nodes_[i]->mass(phase) - - nodes_[i]->discontinuity_property("mass_enrich", 1)(0, 0); + double nodal_mass = nodes_[i]->mass(phase) + + move_direction * nodes_[i]->discontinuity_property( + "mass_enrich", 1)(0, 0); if (nodal_mass < tolerance) continue; - nodal_velocity += - shapefn_[i] * - (nodes_[i]->momentum(phase) - - nodes_[i]->discontinuity_property("momenta_enrich", 3)) / - nodal_mass; + nodal_velocity += shapefn_[i] * + (nodes_[i]->momentum(phase) + + move_direction * nodes_[i]->discontinuity_property( + "momenta_enrich", 3)) / + nodal_mass; } else { double nodal_mass = nodes_[i]->mass(phase); if (nodal_mass < tolerance) continue; @@ -159,16 +162,56 @@ void mpm::discontinuity_point::compute_shapefn() noexcept { shapefn_ = element->shapefn(this->xi_, natural_size_, zero); } +//! Assign the discontinuity enrich type to cell +template +void mpm::discontinuity_point::assign_cell_enrich( + const Map>& map_cells) { + if (cell_->nparticles() == 0) return; + cell_->assign_type_discontinuity(mpm::EnrichType::Crossed); + const auto neighbours_1 = cell_->neighbours(); + for (auto neighbour_1 : neighbours_1) { + if (map_cells[neighbour_1]->element_type_discontinuity() == + mpm::EnrichType::Crossed) + continue; + map_cells[neighbour_1]->assign_type_discontinuity( + mpm::EnrichType::NeighbourTip_1); + const auto neighbours_2 = map_cells[neighbour_1]->neighbours(); + for (auto neighbour_2 : neighbours_2) { + if (map_cells[neighbour_2]->element_type_discontinuity() == + mpm::EnrichType::Regular || + map_cells[neighbour_2]->element_type_discontinuity() == + mpm::EnrichType::NeighbourTip_3) + map_cells[neighbour_2]->assign_type_discontinuity( + mpm::EnrichType::NeighbourTip_2); + + const auto neighbours_3 = map_cells[neighbour_2]->neighbours(); + for (auto neighbour_3 : neighbours_3) { + if (map_cells[neighbour_3]->element_type_discontinuity() == + mpm::EnrichType::Regular) + map_cells[neighbour_3]->assign_type_discontinuity( + mpm::EnrichType::NeighbourTip_3); + } + } + } +} + //! Assign the discontinuity enrich to node template -void mpm::discontinuity_point::assign_discontinuity_enrich() { +void mpm::discontinuity_point::assign_node_enrich( + const Map>& map_cells) { + if (cell_->element_type_discontinuity() != mpm::EnrichType::Crossed) return; Eigen::Matrix friction_coef; friction_coef(0, 0) = friction_coef_; + + Eigen::Matrix cohesion; + cohesion(0, 0) = cohesion_; nodes_ = cell_->nodes(); - // assign discontinuity_enrich for (unsigned i = 0; i < nodes_.size(); ++i) { nodes_[i]->assign_discontinuity_enrich(true); nodes_[i]->assign_discontinuity_property(true, "friction_coef", friction_coef, 0, 1); + nodes_[i]->assign_discontinuity_property(true, "cohesion", cohesion, 0, 1); } + std::ofstream test("cor.txt", std::ios::app); + test << coordinates_; } \ No newline at end of file diff --git a/src/discontinuity.cc b/src/discontinuity.cc index defd1814b..8bf1abd83 100644 --- a/src/discontinuity.cc +++ b/src/discontinuity.cc @@ -3,6 +3,5 @@ #include "factory.h" // Triangle 3-noded element -static Register, mpm::Discontinuity3D<3>, unsigned, - const Json&> +static Register, mpm::Discontinuity3D<3>, const Json&> tri3d("tri3d"); diff --git a/src/nodal_properties.cc b/src/nodal_properties.cc index d081f38d1..48072db75 100644 --- a/src/nodal_properties.cc +++ b/src/nodal_properties.cc @@ -54,6 +54,8 @@ void mpm::NodalProperties::initialise_nodal_properties() { // rows = number of nodes * size of property (1 if property is scalar, Tdim // if property is vector) // cols = number of materials + if (prop_itr->first == "levelset_phi") continue; + Eigen::MatrixXd zeroed_property = Eigen::MatrixXd::Zero(prop_itr->second.rows(), prop_itr->second.cols()); this->assign_property(prop_itr->first, 0, 0, zeroed_property); From 512a160e5db7871d1dd0e4d4c864bd230f347650 Mon Sep 17 00:00:00 2001 From: yliang-sn Date: Thu, 7 Oct 2021 10:53:35 -0700 Subject: [PATCH 61/91] clean oso part --- include/particles/particle_xmpm.tcc | 7 ------- src/nodal_properties.cc | 1 - 2 files changed, 8 deletions(-) diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index 1736224b0..fcac378eb 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -393,13 +393,6 @@ void mpm::ParticleXMPM::map_levelset_to_particle() { levelset_phi_ += shapefn_[i] * nodes_[i]->discontinuity_property("levelset_phi", 1)(0, 0); } - // for oso - if (this->material_id() == 1 || this->material_id() == 2 || this->material_id() == 2 || - this->material_id() == 4) - levelset_phi_ = levelset_phi_ > 1e-10 ? levelset_phi_ : 1e-10; - else if (this->material_id() == 3 || this->material_id() == 5 || - this->material_id() == 5) - levelset_phi_ = levelset_phi_ > -1e-10 ? -1e-10 : levelset_phi_; } //! compute the mininum eigenvalue of the acoustic tensor diff --git a/src/nodal_properties.cc b/src/nodal_properties.cc index 48072db75..1972d775d 100644 --- a/src/nodal_properties.cc +++ b/src/nodal_properties.cc @@ -54,7 +54,6 @@ void mpm::NodalProperties::initialise_nodal_properties() { // rows = number of nodes * size of property (1 if property is scalar, Tdim // if property is vector) // cols = number of materials - if (prop_itr->first == "levelset_phi") continue; Eigen::MatrixXd zeroed_property = Eigen::MatrixXd::Zero(prop_itr->second.rows(), prop_itr->second.cols()); From 8ce78500f2da2f6c1434a81a519651a128276527 Mon Sep 17 00:00:00 2001 From: yliang-sn Date: Thu, 7 Oct 2021 11:03:36 -0700 Subject: [PATCH 62/91] clean oso hardcode --- include/solvers/mpm_base.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/solvers/mpm_base.h b/include/solvers/mpm_base.h index fc6a28452..b4d607070 100644 --- a/include/solvers/mpm_base.h +++ b/include/solvers/mpm_base.h @@ -18,13 +18,13 @@ #endif #include "constraints.h" -#include "contact_interface.h" -#include "interface.h" +#include "contact.h" +#include "contact_friction.h" #include "mpm.h" +#include "mpm_scheme.h" +#include "mpm_scheme_usf.h" +#include "mpm_scheme_usl.h" #include "particle.h" -#include "stress_update.h" -#include "stress_update_usf.h" -#include "stress_update_usl.h" #include "vector.h" namespace mpm { From a71f04810bef907bc7aa9d9f48feb32f942c5ae5 Mon Sep 17 00:00:00 2001 From: yliang-sn Date: Thu, 7 Oct 2021 17:13:32 -0700 Subject: [PATCH 63/91] clean hard code --- include/cell.h | 2 - include/cell.tcc | 23 +- include/mesh.h | 14 +- include/mesh.tcc | 320 ---------------------------- include/node_xmpm.tcc | 93 +------- include/particles/particle_xmpm.tcc | 6 +- include/solvers/mpm_base.h | 28 ++- include/solvers/xmpm_explicit.h | 11 - include/solvers/xmpm_explicit.tcc | 74 ++----- 9 files changed, 37 insertions(+), 534 deletions(-) diff --git a/include/cell.h b/include/cell.h index 207a947fd..bb2dcea2f 100644 --- a/include/cell.h +++ b/include/cell.h @@ -253,8 +253,6 @@ class Cell { //! determine tip element void tip_element(); - // //! change the nodal discontinuity enrich to true for the TIP cell - // void assign_tipcell_nodal_discontinuity(bool status); //! compute normal vector of discontinuity by the nodal level set values void compute_normal_vector_discontinuity(); diff --git a/include/cell.tcc b/include/cell.tcc index 16804e502..834accba3 100644 --- a/include/cell.tcc +++ b/include/cell.tcc @@ -901,18 +901,6 @@ void mpm::Cell::tip_element() { } } -// //! change the nodal discontinuity enrich to true for the TIP cell -// template -// void mpm::Cell::assign_tipcell_nodal_discontinuity(bool status) { -// if (this->discontinuity_element_ == nullptr) return; -// if (this->discontinuity_element_->element_type() != mpm::EnrichType::Tip) -// return; - -// for (unsigned i = 0; i < nodes_.size(); ++i) { -// if (nodes_[i]->discontinuity_enrich()) continue; -// nodes_[i]->assign_discontinuity_enrich(status); -// } -// } //! potential tip element template @@ -1077,9 +1065,7 @@ void mpm::Cell::determine_crossed() { if (phi > max_phi) max_phi = phi; if (phi < min_phi) min_phi = phi; } - // std::ofstream testnormal("crossed cell.txt", std::ios::app); - // testnormal << centroid_[0] << "\t" << max_phi << "\t" << min_phi << "\t" - // << max_phi * min_phi << std::endl; + this->assign_type_discontinuity(mpm::EnrichType::Regular); if (max_phi * min_phi >= 0) return; @@ -1216,9 +1202,6 @@ void mpm::Cell::assign_cohesion_area() { Eigen::Matrix::Zero(); Eigen::Matrix xi; - // std::ofstream crossedtxt("crossed.txt", std::ios::app); - // crossedtxt << id() << " " << centroid_[0] << " " << centroid_[1] << " " - // << std::endl; if (!this->is_point_in_cell(centers, &xi)) return; auto shapefn = element_->shapefn(xi, zeros, zeros); @@ -1229,7 +1212,5 @@ void mpm::Cell::assign_cohesion_area() { nodes_[i]->update_discontinuity_property(true, "cohesion_area", node_area, 0, 1); } - // std::ofstream areatxt("area.txt", std::ios::app); - // areatxt << id() << " " << centroid_[0] << " " << centroid_[1] << " " - // << area << std::endl; + } \ No newline at end of file diff --git a/include/mesh.h b/include/mesh.h index 29a33c58f..41a861a6c 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -528,26 +528,14 @@ class Mesh { void output_discontinuity(int step) { this->discontinuity_->output_markpoints(step); }; - - void compute_error(); void output_celltype(int step); - void output_force(int step); - void output_nodal_levelset(int step); - void change_mat(); + void define_levelset(); - void update_nodal_levelset(double dt); void output_surface(); void check_particle_levelset(bool particle_levelset); - int step_{0}; - void assign_step(int step) { - step_ = step; - for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) - (*nitr)->step_ = step; - }; - 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 e49f45eea..1d9c6801a 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -2059,19 +2059,9 @@ void mpm::Mesh::compute_shapefn_discontinuity() { // compute the normal vector of cells template void mpm::Mesh::compute_cell_normal_vector_discontinuity() { - // std::ofstream testnormal("cell_normal.txt", std::ios::app); - for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { - // for oso - // if ((*citr)->element_type_discontinuity() == mpm::EnrichType::Regular) - // continue; - (*citr)->compute_normal_vector_discontinuity(); (*citr)->compute_plane_discontinuity(false); - - //auto normal_cell = (*citr)->normal_discontinuity(); - // testnormal << normal_cell[0] << " " << normal_cell[2] << " " - // << normal_cell[1] << std::endl; } } @@ -2080,17 +2070,11 @@ template void mpm::Mesh::compute_nodal_normal_vector_discontinuity() { VectorDim normal_cell; - std::ofstream testnormal("mls_normal.txt", std::ios::app); for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { - // for oso if (!(*nitr)->discontinuity_enrich()) continue; normal_cell.setZero(); int crossed_cell = 0; for (auto cell : (*nitr)->cells()) { - // for oso - // if (map_cells_[cell]->element_type_discontinuity() != - // mpm::EnrichType::Crossed) - // continue; normal_cell += map_cells_[cell]->normal_discontinuity(); crossed_cell += 1; } @@ -2102,7 +2086,6 @@ void mpm::Mesh::compute_nodal_normal_vector_discontinuity() { (*nitr)->assign_discontinuity_property( true, "normal_unit_vectors_discontinuity", normal_cell, 0, Tdim); } - // testnormal << std::endl; } // Initialise level set values particles @@ -2557,17 +2540,11 @@ void mpm::Mesh::update_discontinuity() { continue; std::vector coordinates; (*citr)->compute_discontinuity_point(coordinates); - // if ((*citr)->discontinuity_area() <= 0) continue; for (int i = 0; i < coordinates.size(); i++) { discontinuity_->insert_particles(coordinates[i], cells_, map_cells_); double d = (*citr)->d_discontinuity(); auto normal_cell = (*citr)->normal_discontinuity(); - - std::ofstream normal("normal.txt", std::ios::app); - normal << coordinates[i][0] << " " << coordinates[i][1] << " " - << std::atan(normal_cell[0] / normal_cell[1]) / M_PI * 180 - << std::endl; } } } @@ -2730,33 +2707,6 @@ void mpm::Mesh::update_node_enrich() { } } -template -void mpm::Mesh::change_mat() { - - for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { - // FOR SLOPE_SRF - if (true) { - unsigned material_id = 2; - unsigned phase_id = mpm::ParticlePhase::Solid; - (*pitr)->assign_material(materials_.at(material_id), phase_id); - } - - // FOR OSO - // if ((*pitr)->material_id(mpm::ParticlePhase::Solid) == 4) { - // unsigned material_id = 1; - // unsigned phase_id = mpm::ParticlePhase::Solid; - // (*pitr)->assign_material(materials_.at(material_id), phase_id); - // } else if ((*pitr)->material_id(mpm::ParticlePhase::Solid) == 5) { - // unsigned material_id = 2; - // unsigned phase_id = mpm::ParticlePhase::Solid; - // (*pitr)->assign_material(materials_.at(material_id), phase_id); - // } else if ((*pitr)->material_id(mpm::ParticlePhase::Solid) == 6) { - // unsigned material_id = 3; - // unsigned phase_id = mpm::ParticlePhase::Solid; - // (*pitr)->assign_material(materials_.at(material_id), phase_id); - // } - } -} template void mpm::Mesh::define_levelset() { @@ -2893,9 +2843,6 @@ bool mpm::Mesh::initiation_discontinuity() { for (int i = 0; i < coordinates_dis.size(); i++) discontinuity_->insert_particles(coordinates_dis[i], cells_, map_cells_); // initialise neighbour cells - std::ofstream normalfile("normal.txt", std::ios::app); - normalfile << coordinates_dis[0][0] << " " << coordinates_dis[0][1] << " " - << std::atan(normal[0] / normal[1]) / M_PI * 180 << std::endl; auto neighbours = map_cells_[cell_id]->neighbours(); for (auto neighbour : neighbours) { @@ -2915,10 +2862,6 @@ bool mpm::Mesh::initiation_discontinuity() { discontinuity_->insert_particles(coordinates_dis_neigh[i], cells_, map_cells_); - normalfile << coordinates_dis_neigh[i][0] << " " - << coordinates_dis_neigh[i][1] << " " - << std::atan(normal[0] / normal[1]) / M_PI * 180 - << std::endl; } } // initialise level set values @@ -3073,16 +3016,8 @@ void mpm::Mesh::modify_nodal_levelset_mls() { } error = std::sqrt(error / error_p) / discontinuity_->width(); - // if (error > error_max) error_max = error; - // std::ofstream test("testmlserror.txt",std::ios::app); - // test<<(*nitr)->coordinates()[0]<<" "<<(*nitr)->coordinates()[1]<<" - // "<<(*nitr)->coordinates()[2]<<" "< 1e-3) continue; - // phi_mls(0, 0) = - // (0.5 * (*nitr)->coordinates()[0] + (*nitr)->coordinates()[2] - 0.8) / - // std::sqrt(0.25 + 1); Eigen::Matrix cor; Eigen::Matrix phi_mls; @@ -3090,52 +3025,8 @@ void mpm::Mesh::modify_nodal_levelset_mls() { (*nitr)->coordinates()[2]; phi_mls(0, 0) = cor.dot(coef); - std::ofstream test("testmls.txt", std::ios::app); - test << (*nitr)->id() << " " << cor.dot(coef) << std::endl; - // if(std::abs(phi_mls(0, 0)-1) < 1e-10 || std::abs(phi_mls(0, 0)-0.5) < - // 1e-10) - // console_->info("coefficient is - // :{},{},{},{}",coef[0],coef[1],coef[2],coef[3]); (*nitr)->assign_discontinuity_property(true, "levelset_phi", phi_mls, 0, 1); } - // std::ofstream test("testmlserror.txt", std::ios::app); - // test << error_max << std::endl; -} - -template -void mpm::Mesh::compute_error() { - double error = 0; - double error_max = 0; - int nnode = 0; - for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { - auto cor = (*nitr)->coordinates(); - double phi_ana = 1 / std::sqrt(3) * cor[0] + 1 / std::sqrt(3) * cor[1] + - 1 / std::sqrt(3) * cor[2] - 0.5 * std::sqrt(3); - phi_ana = std::sqrt(std::pow(cor[0] - 0.5, 2) + std::pow(cor[1] - 0.5, 2) + - std::pow(cor[2] - 0.5, 2)) - - 0.4; - if (std::abs(phi_ana) > 0.2 * 0.5 * 0.5) continue; - - nnode++; - - double phi = (*nitr)->discontinuity_property("levelset_phi", 1)(0, 0); - - error += std::pow(std::abs(phi - phi_ana), 2); - - if (std::abs(phi - phi_ana) > error_max) - error_max = std::abs(phi - phi_ana); - } - error = std::sqrt(error / nnode); - console_->info("the error is {}.\n", error); - console_->info("the maximum error is {}.\n", error_max); - double area = 0; - for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { - if ((*citr)->element_type_discontinuity() != mpm::EnrichType::Crossed) - continue; - area += (*citr)->discontinuity_area(); - } - console_->info("the error of area is {}.\n", - (area - 4 * M_PI * 0.16) / (4 * M_PI * 0.16)); } template @@ -3324,214 +3215,3 @@ void mpm::Mesh::output_celltype(int step) { } } -template -void mpm::Mesh::output_force(int step) { - std::ofstream test("nodal_force.txt", std::ios::app); - - VectorDim force; - force.setZero(); - unsigned phase = mpm::ParticlePhase::Solid; - for (int i = 0; i < nodes_.size(); i++) { - if (nodes_[i]->coordinates()[1] > 1e-6) - // nodes_[i]->coordinates()[0] < -0.2 || nodes_[i]->coordinates()[0] - // > 1.2) - continue; - force += nodes_[i]->internal_force(phase); - } - test << step << "\t" << force[0] << "\t" << force[1] << std::endl; -} - -template -void mpm::Mesh::output_surface() { - // std::ofstream test("surface.txt", std::ios::app); - - // double height[91]{0}; - // double volume = 0; - // double size = 0.0625; - - // for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { - // auto coordinates = (*pitr)->coordinates(); - - // int id = std::round(coordinates[0]/0.5); - // if(coordinates[1]>height[id]) - // height[id] = coordinates[1]; - - // volume += (*pitr)->volume(); - // } - // test <coordinates(); - // if (coordinates[2] < 22 || coordinates[2] > 23) continue; - // int id = std::round(coordinates[0] / 0.5); - // if (coordinates[1] > height[id]) height[id] = coordinates[1]; - - // volume += (*pitr)->volume(); - // } - // test << volume / 0.5 << std::endl; - // for (int i = 0; i < 91; i++) test << height[i] + size << std::endl; -} - -// Regular = 1, -// Crossed = 2, -// Tip = 3, -// NeighbourTip_1 = 4, -// NeighbourTip_2 = 5, -// PotentialTip = 6, -// NextTip = 7, -// NeighbourNextTip_1 = 8, -// NeighbourNextTip_2 = 9, -// InitialTip = 10 - -template -void mpm::Mesh::update_nodal_levelset(double dt) { - unsigned phase = mpm::ParticlePhase::Solid; - auto tolerance = 1e-15; - - int sign = -1; - // std::ofstream levelset("dlevelset.txt", std::ios::app); - - for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { - - Eigen::Matrix nodal_velocity; - - double nodal_mass = - (*nitr)->mass(phase) + - sign * (*nitr)->discontinuity_property("mass_enrich", 1)(0, 0); - if (nodal_mass < tolerance) continue; - - // the gradient of the level set at nodes - - VectorDim gradient; - gradient.setZero(); - int numcell = 0; - for (auto cell : (*nitr)->cells()) { - // for oso - gradient += map_cells_[cell]->compute_gradient_levelset(); - numcell += 1; - } - gradient /= numcell; - - // double levelset = (*nitr)->discontinuity_property("levelset_phi", 1)(0, - // 0); - - Eigen::Matrix normal = (*nitr)->discontinuity_property( - "normal_unit_vectors_discontinuity", Tdim); - - nodal_velocity = - ((*nitr)->momentum(phase) + - sign * (*nitr)->discontinuity_property("momenta_enrich", 3)) / - nodal_mass; - - Eigen::Matrix dlevelset; - dlevelset(0, 0) = -nodal_velocity.dot(gradient) * dt; - - (*nitr)->update_discontinuity_property(true, "levelset_phi", dlevelset, 0, - 1); - - // levelset << nodal_velocity.norm() << " " << dlevelset(0, 0) << - // std::endl; - } - - // for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) - // { - - // (*pitr)->map_levelset_to_particle(); - // } -} - -template -void mpm::Mesh::output_nodal_levelset(int step) { - - std::ostringstream convert; - - convert << step; - - std::string filename = "levelset" + convert.str() + ".vtk"; - std::ofstream test(filename, std::ios::app); - - test << "# vtk DataFile Version 2.0\n" - << "ASCII\n" - << "DATASET UNSTRUCTURED_GRID\n" - << "POINTS " << nodes_.size() << " double\n"; - for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { - test << (*nitr)->coordinates()[0] << " " << (*nitr)->coordinates()[1] - << " " << (*nitr)->coordinates()[2] << " " << std::endl; - } - - test << "POINT_DATA " << nodes_.size() << std::endl; - test << "SCALARS sample_scalars float 1 \n"; - test << "LOOKUP_TABLE my_table \n"; - for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { - test << (*nitr)->coordinates()[0] << " " << (*nitr)->coordinates()[1] - << " " << (*nitr)->coordinates()[2] << " " << std::endl; - } - - test << "CELLS " << cells_.size() << std::endl; - for (int i = 0; i < cells_.size(); i++) { - test << "4 " << cells_[i]->nodes()[0]->id() << " " - << cells_[i]->nodes()[1]->id() << " " << cells_[i]->nodes()[2]->id() - << " " << cells_[i]->nodes()[3]->id() << std::endl; - } - - test << "CELL_TYPES " << cells_.size() << std::endl; - for (int i = 0; i < cells_.size(); i++) { - test << "8" << std::endl; - } - - // test << "CELL_TYPES " << cells_.size()<< std::endl; - // for (int i = 0; i < cells_.size(); i++) { - // test << "8" <element_type_discontinuity(); - // if (type == 1) - // test << "o "; - // else if (type == 2) - // test << "\\ "; - // else if (type == 3) - // test << "^ "; - // else if (type == 4) - // test << "1 "; - // else if (type == 5) - // test << "2 "; - // else if (type == 6) - // test << "* "; - // else - // test << type << " "; - // if (((i + 1) % 90) == 0) test << std::endl; - // } - // test << std::endl; - - // std::ofstream testnormal("node_normal.txt", std::ios::app); - // testnormal << step << ":" << std::endl; - // for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { - // if (!(*nitr)->discontinuity_enrich()) continue; - - // if ((*nitr)->coordinates()[0] < 35) continue; - - // Eigen::Matrix normal = - // (*nitr)->discontinuity_property( - // "normal_unit_vectors_discontinuity", Tdim); - // testnormal << (*nitr)->coordinates()[0] << "\t" << - // (*nitr)->coordinates()[1] - // << "\t" << normal[0] << "\t" << normal[1] << "\t" << - // normal[2] - // << std::endl; - // } -} \ No newline at end of file diff --git a/include/node_xmpm.tcc b/include/node_xmpm.tcc index 7717169fc..dcb45a089 100644 --- a/include/node_xmpm.tcc +++ b/include/node_xmpm.tcc @@ -78,70 +78,22 @@ template bool mpm::Node::compute_momentum_discontinuity_cundall( unsigned phase, double dt, double damping_factor) noexcept { const double tolerance = 1.0E-15; - // std::ofstream force("force.txt", std::ios::app); - // force << discontinuity_enrich_ <<":"<<"damping factor:"<< damping_factor<< - // std::endl; + if (!discontinuity_enrich_) { if (mass_.col(phase)(0, 0) > tolerance) { - // acceleration = (unbalaced force / mass) - // force << "external force:"<external_force_.col(phase)[0]<<" " - // << this->external_force_.col(phase)[1]<<" " - // << this->external_force_.col(phase)[2] << std::endl; - // force << "internal force:"<internal_force_.col(phase)[0]<<" " - // << this->internal_force_.col(phase)[1]<<" " - // << this->internal_force_.col(phase)[2] << std::endl; auto unbalanced_force = this->external_force_.col(phase) + this->internal_force_.col(phase); this->external_force_.col(phase) -= damping_factor * unbalanced_force.norm() * this->momentum_.col(phase).normalized(); - // force <<"unbalanced force:"<external_force_.col(phase)[0]<<" " - // << this->external_force_.col(phase)[1]<<" " - // << this->external_force_.col(phase)[2] << std::endl; - // force << std::endl; + } } else { - // force <<"external force:"<external_force_.col(phase)[0]<<" " - // << this->external_force_.col(phase)[1]<<" " - // << this->external_force_.col(phase)[2] << std::endl; - // force <<"internal force:"<internal_force_.col(phase)[0]<<" " - // << this->internal_force_.col(phase)[1]<<" " - // << this->internal_force_.col(phase)[2] << std::endl; - // force <<"enriched external force:"<property("external_force_enrich", - // discontinuity_prop_id_, 0, Tdim)(0, - // 0)<<" " - // << property_handle_->property("external_force_enrich", - // discontinuity_prop_id_, 0, Tdim)(1, - // 0)<<" " - // << property_handle_->property("external_force_enrich", - // discontinuity_prop_id_, 0, Tdim)(2, - // 0) - // << std::endl; - // force <<"enriched internal force:"<property("internal_force_enrich", - // discontinuity_prop_id_, 0, Tdim)(0, - // 0)<<" " - // << property_handle_->property("internal_force_enrich", - // discontinuity_prop_id_, 0, Tdim)(1, - // 0)<<" " - // << property_handle_->property("internal_force_enrich", - // discontinuity_prop_id_, 0, Tdim)(2, - // 0) - // << std::endl; + // obtain the enriched values of enriched nodes Eigen::Matrix mass_enrich = property_handle_->property("mass_enrich", discontinuity_prop_id_, 0, 1); @@ -177,31 +129,6 @@ bool mpm::Node::compute_momentum_discontinuity_cundall( property_handle_->update_property( "external_force_enrich", discontinuity_prop_id_, 0, 0.5 * (damp_force_positive - damp_force_negative), Tdim); - - // force <<"unbalanced positive force:"<external_force_.col(phase)[0]<<" " - // << this->external_force_.col(phase)[1]<<" " - // << this->external_force_.col(phase)[2] << std::endl; - // force <<"enriched external force:"<property("external_force_enrich", - // discontinuity_prop_id_, 0, Tdim)(0, - // 0)<<" " - // << property_handle_->property("external_force_enrich", - // discontinuity_prop_id_, 0, Tdim)(1, - // 0)<<" " - // << property_handle_->property("external_force_enrich", - // discontinuity_prop_id_, 0, Tdim)(2, - // 0) - // << std::endl; - // force << std::endl; } compute_momentum_discontinuity(phase, dt); @@ -276,14 +203,7 @@ void mpm::Node::self_contact_discontinuity( Eigen::Matrix normal_vector = property_handle_->property( "normal_unit_vectors_discontinuity", discontinuity_prop_id_, 0, Tdim); - std::ofstream testnormal("testnormal.txt", std::ios::app); - testnormal << coordinates_[0] << " " << coordinates_[1] << " " - << coordinates_[2] << " " << normal_vector[0] << " " - << normal_vector[1] << " " << normal_vector[2] << " " - << contact_distance << std::endl; - // normal_vector[0] = 0; - // normal_vector[1] = -1; - // normal_vector[2] = 0; + if (contact_distance >= 0) return; // single phase for solid unsigned phase = 0; @@ -323,8 +243,6 @@ void mpm::Node::self_contact_discontinuity( double friction_coef = property_handle_->property( "friction_coef", discontinuity_prop_id_, 0, 1)(0, 0); - // std::ofstream testnormal("test_coef.txt", std::ios::app); - // testnormal << coordinates_[0] << " " << friction_coef << std::endl; if (friction_coef < 0) { property_handle_->update_property("momenta_enrich", discontinuity_prop_id_, @@ -393,9 +311,6 @@ void mpm::Node::self_contact_discontinuity( ? force_tangential_value : max_friction_force; - // std::ofstream cohesion_force("cohesion_force.txt",std::ios::app); - // cohesion_force<update_property( "momenta_enrich", discontinuity_prop_id_, 0, diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index fcac378eb..b2f0677d0 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -403,8 +403,6 @@ bool mpm::ParticleXMPM::minimum_acoustic_tensor(VectorDim& normal_cell, minimum_acoustic_eigenvalue_ = std::numeric_limits::max(); // compute the acoustic tensor - // std::ofstream testa("acoustic.txt", std::ios::app); - bool yield_status = true; Eigen::Matrix dp = (this->material()) @@ -588,7 +586,7 @@ bool mpm::ParticleXMPM::minimum_acoustic_tensor(VectorDim& normal_cell, double det_dp_n; double mininum_ratio = std::numeric_limits::max(); - // std::ofstream test("test.txt", std::ios::app); + for (int i = 0; i < std::floor(360 / dtheta); i++) { for (int j = 0; j < 1; j++) { double theta = i * dtheta * PI; @@ -738,8 +736,6 @@ void mpm::ParticleXMPM::compute_initiation_normal( 3, 1, 4, 5, 4, 2; - //std::ofstream test("test.txt", std::ios::app); - //std::ofstream testdp("testdp.txt", std::ios::app); for (int i = 0; i < std::floor(360 / dtheta); i++) { for (int j = 0; j < 180; j++) { double theta = i * dtheta * PI; diff --git a/include/solvers/mpm_base.h b/include/solvers/mpm_base.h index b4d607070..db861295a 100644 --- a/include/solvers/mpm_base.h +++ b/include/solvers/mpm_base.h @@ -79,6 +79,11 @@ class MPMBase : public MPM { //! Checkpoint resume bool checkpoint_resume() override; + + //! Particle entity sets + //! \param[in] check Check duplicates + void particle_entity_sets(bool check); + #ifdef USE_VTK //! Write VTK files void write_vtk(mpm::Index step, mpm::Index max_steps) override; @@ -100,6 +105,11 @@ class MPMBase : public MPM { //! \param[in] phase Phase to smooth pressure void pressure_smoothing(unsigned phase); + //! Particle velocity constraints + //! \param[in] mesh_prop Mesh properties + //! \param[in] particle_io Particle IO handle + void particle_velocity_constraints(); + private: //! Return if a mesh will be isoparametric or not //! \retval isoparametric Status of mesh type @@ -145,13 +155,6 @@ class MPMBase : public MPM { void particles_volumes(const Json& mesh_prop, const std::shared_ptr>& particle_io); - //! Particle velocity constraints - //! \param[in] mesh_prop Mesh properties - //! \param[in] particle_io Particle IO handle - void particle_velocity_constraints( - const Json& mesh_prop, - const std::shared_ptr>& particle_io); - //! Particles stresses //! \param[in] mesh_prop Mesh properties //! \param[in] particle_io Particle IO handle @@ -159,11 +162,6 @@ class MPMBase : public MPM { const Json& mesh_prop, const std::shared_ptr>& particle_io); - //! Particle entity sets - //! \param[in] mesh_prop Mesh properties - //! \param[in] check Check duplicates - void particle_entity_sets(const Json& mesh_prop, bool check); - //! Initialise damping //! \param[in] damping_props Damping properties bool initialise_damping(const Json& damping_props); @@ -191,11 +189,11 @@ class MPMBase : public MPM { using mpm::MPM::console_; //! Stress update method - std::string stress_update_; + std::string stress_update_{"usf"}; //! Stress update scheme - std::shared_ptr> stress_update_scheme_{nullptr}; + std::shared_ptr> mpm_scheme_{nullptr}; //! Interface scheme - std::shared_ptr> interface_scheme_{nullptr}; + std::shared_ptr> contact_{nullptr}; //! velocity update bool velocity_update_{false}; //! Gravity diff --git a/include/solvers/xmpm_explicit.h b/include/solvers/xmpm_explicit.h index ad38202e3..064a725a9 100644 --- a/include/solvers/xmpm_explicit.h +++ b/include/solvers/xmpm_explicit.h @@ -35,17 +35,6 @@ class XMPMExplicit : public MPMBase { //! Checkpoint resume bool checkpoint_resume() override; - void initialise_particle_sets() { - // Get mesh properties - auto mesh_props = io_->json_object("mesh"); - // Check duplicates default set to true - bool check_duplicates = true; - if (mesh_props.find("check_duplicates") != mesh_props.end()) - check_duplicates = mesh_props["check_duplicates"].template get(); - - this->particle_entity_sets(mesh_props, check_duplicates); - }; - protected: // Generate a unique id for the analysis using mpm::MPMBase::uuid_; diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index 1b800863b..6b03853c5 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -77,11 +77,6 @@ bool mpm::XMPMExplicit::solve() { // Initialise particles if (!resume) this->initialise_particles(); - else - this->initialise_particle_sets(); - - // Initialise loading conditions - this->initialise_loads(); // Initialise the cells in node mesh_->add_cell_in_node(); @@ -116,6 +111,15 @@ bool mpm::XMPMExplicit::solve() { this->mpi_domain_decompose(initial_step); } + //! Particle entity sets and velocity constraints + if (resume) { + this->particle_entity_sets(false); + this->particle_velocity_constraints(); + } + + // Initialise loading conditions + this->initialise_loads(); + // Initialise the levelset values for particles if (surfacemesh_) mesh_->initialise_levelset_discontinuity(); @@ -139,17 +143,6 @@ bool mpm::XMPMExplicit::solve() { for (; step_ < nsteps_; ++step_) { bool nodal_update = true; - int change_step = 0; - - mesh_->assign_step(step_); - if (step_ == change_step) { - // output_steps_ = 10; - // console_->info("change material"); - // mesh_->change_mat(); - // //dt_ = 0.001; - // mpm_scheme_->assign_dt(dt_); - } - if (mpi_rank == 0) console_->info("Step: {} of {}.\n", step_, nsteps_); #ifdef USE_MPI @@ -167,29 +160,16 @@ bool mpm::XMPMExplicit::solve() { mpm_scheme_->initialise(); if (step_ == 0 || resume == true) { - // for oso + //predefine level set values mesh_->define_levelset(); resume = false; } - // if (step_ == 0 || resume == true) { - // mesh_->output_surface(); - // resume = false; - // } - // if (step_ == 40800) { - // particle_levelet_ = true; - // initiation_ = false; - // propagation_ = false; - // } - // if (step_ == 40600) { - // output_steps_ = 1; - // } - // Initialise nodal properties and append material ids to node contact_->initialise(); if (initiation_) initiation_ = !mesh_->initiation_discontinuity(); - if (setdiscontinuity_ && !initiation_ && step_ >= change_step) { + if (setdiscontinuity_ && !initiation_) { // Initialise nodal properties mesh_->initialise_nodal_properties(); // Initialise element properties @@ -204,9 +184,6 @@ bool mpm::XMPMExplicit::solve() { mesh_->compute_shapefn_discontinuity(); } - // if (surfacemesh_ && (step_ + 1) % 2000 == 0 ) - // mesh_->initialise_levelset_discontinuity(); - // // obtain nodal volume mesh_->iterate_over_particles( @@ -218,12 +195,11 @@ bool mpm::XMPMExplicit::solve() { std::placeholders::_1)); } + // modify the nodal levelset_phi by mls if (nodal_levelset_ == "mls") - // modify the nodal levelset_phi by mls mesh_->modify_nodal_levelset_mls(); // obtain nodal frictional_coefficient - if (friction_coef_average_) mesh_->iterate_over_particles( std::bind(&mpm::ParticleBase::map_friction_coef_to_nodes, @@ -245,24 +221,21 @@ bool mpm::XMPMExplicit::solve() { mesh_->iterate_over_cells(std::bind( &mpm::Cell::compute_area_discontinuity, std::placeholders::_1)); - // mesh_->output_celltype(step_); + if (propagation_) // remove the spurious potential tip element mesh_->spurious_potential_tip_element(); - // mesh_->output_celltype(step_); - // mesh_->compute_error(); + // assign_node_enrich mesh_->assign_node_enrich(friction_coef_average_, nodal_update); mesh_->check_particle_levelset(particle_levelet_); - // mesh_->output_celltype(step_); // obtain the normal direction of each cell and enrich nodes mesh_->compute_nodal_normal_vector_discontinuity(); - // mesh_->output_celltype(step_); + if (propagation_) // find the tip element { - mesh_->iterate_over_cells( std::bind(&mpm::Cell::tip_element, std::placeholders::_1)); // mesh_->update_node_enrich(friction_coef_average_); @@ -294,10 +267,6 @@ bool mpm::XMPMExplicit::solve() { mpm_scheme_->compute_forces(gravity_, phase, step_, set_node_concentrated_force_); - // if ((step_ + 1) % 10 == 0) { - // mesh_->output_force(step_); - // } - // integrate momentum by iterating over nodes if (damping_type_ == mpm::Damping::Cundall) mesh_->iterate_over_nodes_predicate( @@ -311,19 +280,14 @@ bool mpm::XMPMExplicit::solve() { std::placeholders::_1, phase, this->dt_), std::bind(&mpm::NodeBase::status, std::placeholders::_1)); - if (setdiscontinuity_ && !initiation_ && step_ >= change_step) { + if (setdiscontinuity_ && !initiation_) { if (propagation_) { // find the next tip element mesh_->next_tip_element_discontinuity(); - // mesh_->iterate_over_cells( - // std::bind(&mpm::Cell::assign_tipcell_nodal_discontinuity, - // std::placeholders::_1, true)); // discontinuity growth - // mesh_->output_celltype(step_); mesh_->update_discontinuity(); - // mesh_->output_celltype(step_); } // Update the discontinuity position @@ -344,12 +308,6 @@ bool mpm::XMPMExplicit::solve() { // Locate particles mpm_scheme_->locate_particles(this->locate_particles_); - //if (nodal_update) mesh_->update_nodal_levelset(dt_); - - // if ((step_ + 1) % 1 == 0) { - // mesh_->output_nodal_levelset(step_); - // } - #ifdef USE_MPI #ifdef USE_GRAPH_PARTITIONING mesh_->transfer_halo_particles(); From 3f8f0b06443516638a5bae96cba422be07947452 Mon Sep 17 00:00:00 2001 From: Yong Liang <60054151+yliang-sn@users.noreply.github.com> Date: Thu, 7 Oct 2021 17:21:19 -0700 Subject: [PATCH 64/91] Update cell.h --- include/cell.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/cell.h b/include/cell.h index bb2dcea2f..984bb4cbe 100644 --- a/include/cell.h +++ b/include/cell.h @@ -1,7 +1,6 @@ #ifndef MPM_CELL_H_ #define MPM_CELL_H_ -#include #include #include #include From 8316654b1fc95bfb6deb1a8eb8b3a240b61d9a6a Mon Sep 17 00:00:00 2001 From: yliang-sn Date: Thu, 7 Oct 2021 17:26:09 -0700 Subject: [PATCH 65/91] apply the clang format --- include/cell.tcc | 4 +--- include/mesh.tcc | 3 --- include/node_xmpm.tcc | 5 +---- include/particles/particle_xmpm.tcc | 2 +- include/solvers/mpm_base.h | 1 - include/solvers/xmpm_explicit.tcc | 8 +++----- 6 files changed, 6 insertions(+), 17 deletions(-) diff --git a/include/cell.tcc b/include/cell.tcc index 834accba3..2ac877160 100644 --- a/include/cell.tcc +++ b/include/cell.tcc @@ -901,7 +901,6 @@ void mpm::Cell::tip_element() { } } - //! potential tip element template void mpm::Cell::compute_discontinuity_point( @@ -1056,7 +1055,7 @@ double mpm::Cell::product_levelset() { template void mpm::Cell::determine_crossed() { - //if (this->nparticles() == 0) return; + // if (this->nparticles() == 0) return; double max_phi = -1e15, min_phi = 1e15; @@ -1212,5 +1211,4 @@ void mpm::Cell::assign_cohesion_area() { nodes_[i]->update_discontinuity_property(true, "cohesion_area", node_area, 0, 1); } - } \ No newline at end of file diff --git a/include/mesh.tcc b/include/mesh.tcc index 1d9c6801a..e87e8ef6b 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -2707,7 +2707,6 @@ void mpm::Mesh::update_node_enrich() { } } - template void mpm::Mesh::define_levelset() { // for oso @@ -2861,7 +2860,6 @@ bool mpm::Mesh::initiation_discontinuity() { for (int i = 0; i < coordinates_dis_neigh.size(); i++) { discontinuity_->insert_particles(coordinates_dis_neigh[i], cells_, map_cells_); - } } // initialise level set values @@ -3214,4 +3212,3 @@ void mpm::Mesh::output_celltype(int step) { << std::endl; } } - diff --git a/include/node_xmpm.tcc b/include/node_xmpm.tcc index dcb45a089..344d44654 100644 --- a/include/node_xmpm.tcc +++ b/include/node_xmpm.tcc @@ -88,12 +88,10 @@ bool mpm::Node::compute_momentum_discontinuity_cundall( this->external_force_.col(phase) -= damping_factor * unbalanced_force.norm() * this->momentum_.col(phase).normalized(); - } } else { - // obtain the enriched values of enriched nodes Eigen::Matrix mass_enrich = property_handle_->property("mass_enrich", discontinuity_prop_id_, 0, 1); @@ -203,7 +201,7 @@ void mpm::Node::self_contact_discontinuity( Eigen::Matrix normal_vector = property_handle_->property( "normal_unit_vectors_discontinuity", discontinuity_prop_id_, 0, Tdim); - + if (contact_distance >= 0) return; // single phase for solid unsigned phase = 0; @@ -243,7 +241,6 @@ void mpm::Node::self_contact_discontinuity( double friction_coef = property_handle_->property( "friction_coef", discontinuity_prop_id_, 0, 1)(0, 0); - if (friction_coef < 0) { property_handle_->update_property("momenta_enrich", discontinuity_prop_id_, 0, momentum_contact.col(phase), Tdim); diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index b2f0677d0..1c418c040 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -586,7 +586,7 @@ bool mpm::ParticleXMPM::minimum_acoustic_tensor(VectorDim& normal_cell, double det_dp_n; double mininum_ratio = std::numeric_limits::max(); - + for (int i = 0; i < std::floor(360 / dtheta); i++) { for (int j = 0; j < 1; j++) { double theta = i * dtheta * PI; diff --git a/include/solvers/mpm_base.h b/include/solvers/mpm_base.h index db861295a..7bd7d74a7 100644 --- a/include/solvers/mpm_base.h +++ b/include/solvers/mpm_base.h @@ -79,7 +79,6 @@ class MPMBase : public MPM { //! Checkpoint resume bool checkpoint_resume() override; - //! Particle entity sets //! \param[in] check Check duplicates void particle_entity_sets(bool check); diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index 6b03853c5..e67a4d6a6 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -75,8 +75,7 @@ bool mpm::XMPMExplicit::solve() { this->initialise_mesh(); // Initialise particles - if (!resume) - this->initialise_particles(); + if (!resume) this->initialise_particles(); // Initialise the cells in node mesh_->add_cell_in_node(); @@ -160,7 +159,7 @@ bool mpm::XMPMExplicit::solve() { mpm_scheme_->initialise(); if (step_ == 0 || resume == true) { - //predefine level set values + // predefine level set values mesh_->define_levelset(); resume = false; } @@ -196,8 +195,7 @@ bool mpm::XMPMExplicit::solve() { } // modify the nodal levelset_phi by mls - if (nodal_levelset_ == "mls") - mesh_->modify_nodal_levelset_mls(); + if (nodal_levelset_ == "mls") mesh_->modify_nodal_levelset_mls(); // obtain nodal frictional_coefficient if (friction_coef_average_) From 8b5f8134a0afde35781f05c4cb55e392204e4da5 Mon Sep 17 00:00:00 2001 From: yliang-sn Date: Sun, 17 Oct 2021 17:16:25 -0700 Subject: [PATCH 66/91] make a separate file mesh_xmpm --- include/mesh.h | 1 + include/mesh.tcc | 1213 +---------------------------------------- include/mesh_xmpm.tcc | 1210 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1212 insertions(+), 1212 deletions(-) create mode 100644 include/mesh_xmpm.tcc diff --git a/include/mesh.h b/include/mesh.h index 41a861a6c..e2e52fcb6 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -611,5 +611,6 @@ class Mesh { } // namespace mpm #include "mesh.tcc" +#include "mesh_xmpm.tcc" #endif // MPM_MESH_H_ diff --git a/include/mesh.tcc b/include/mesh.tcc index e87e8ef6b..2dae6bc2e 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -2000,1215 +2000,4 @@ void mpm::Mesh::create_nodal_properties() { } else { throw std::runtime_error("Number of nodes or number of materials is zero"); } -} - -// Create the nodal properties' map for discontinuity -template -void mpm::Mesh::create_nodal_properties_discontinuity() { - // Initialise the shared pointer to nodal properties - if (nodal_properties_ == nullptr) - nodal_properties_ = std::make_shared(); - - // Check if nodes_ is empty and throw runtime error if they are - assert(nodes_.size()); - // Compute number of rows in nodal properties for vector entities - const unsigned nrows = nodes_.size() * Tdim; - // Create pool data for each property in the nodal properties struct - // object. Properties must be named in the plural form - nodal_properties_->create_property("mass_enrich", nodes_.size(), 1); - nodal_properties_->create_property("levelset_phi", nodes_.size(), 1); - nodal_properties_->create_property("momenta_enrich", nrows, 1); - nodal_properties_->create_property("internal_force_enrich", nrows, 1); - nodal_properties_->create_property("external_force_enrich", nrows, 1); - nodal_properties_->create_property("normal_unit_vectors_discontinuity", nrows, - 1); - nodal_properties_->create_property("friction_coef", nodes_.size(), 1); - nodal_properties_->create_property("cohesion", nodes_.size(), 1); - nodal_properties_->create_property("cohesion_area", nodes_.size(), 1); - nodal_properties_->create_property("contact_distance", nodes_.size(), 1); - // Iterate over all nodes to initialise the property handle in each node - // and assign its node id as the prop id in the nodal property data pool - for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) - (*nitr)->initialise_discontinuity_property_handle((*nitr)->id(), - nodal_properties_); -} - -// 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(); -} - -//! Locate points in a cell -template -void mpm::Mesh::locate_discontinuity() { - discontinuity_->locate_discontinuity_mesh(cells_, map_cells_); -} -//! updated_position of discontinuity -template -void mpm::Mesh::compute_updated_position_discontinuity(double dt) { - discontinuity_->compute_updated_position(dt); -} -//! compute shape function -template -void mpm::Mesh::compute_shapefn_discontinuity() { - discontinuity_->compute_shapefn(); -} - -// compute the normal vector of cells -template -void mpm::Mesh::compute_cell_normal_vector_discontinuity() { - for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { - (*citr)->compute_normal_vector_discontinuity(); - (*citr)->compute_plane_discontinuity(false); - } -} - -// compute the normal vector of enriched nodes at the discontinuity -template -void mpm::Mesh::compute_nodal_normal_vector_discontinuity() { - - VectorDim normal_cell; - for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { - if (!(*nitr)->discontinuity_enrich()) continue; - normal_cell.setZero(); - int crossed_cell = 0; - for (auto cell : (*nitr)->cells()) { - normal_cell += map_cells_[cell]->normal_discontinuity(); - crossed_cell += 1; - } - if (crossed_cell == 0) continue; - normal_cell = normal_cell / crossed_cell; - - // normal_cell << 0.5,0,1; - normal_cell.normalize(); - (*nitr)->assign_discontinuity_property( - true, "normal_unit_vectors_discontinuity", normal_cell, 0, Tdim); - } -} - -// Initialise level set values particles -template -void mpm::Mesh::initialise_levelset_discontinuity() { - - double phi_particle; - - for (mpm::Index j = 0; j < nparticles(); ++j) { - discontinuity_->compute_levelset(particles_[j]->coordinates(), - phi_particle); - particles_[j]->assign_levelsetphi(phi_particle); - } -} - -// Initialise nodal level set values particles -template -void mpm::Mesh::initialise_nodal_levelset_discontinuity() { - - Eigen::Matrix phi; - phi.setZero(); - double phi_node; - for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { - discontinuity_->compute_levelset((*nitr)->coordinates(), phi_node); - phi(0, 0) = phi_node; - (*nitr)->assign_discontinuity_property(true, "levelset_phi", phi, 0, 1); - } -} - -//! solve nodal levelset values -template -void mpm::Mesh::update_node_levelset() { - for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) - (*nitr)->update_levelset(); -} - -// discontinuity growth -template -void mpm::Mesh::update_discontinuity() { - - for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { - if ((*citr)->element_type_discontinuity() == mpm::EnrichType::PotentialTip) - (*citr)->assign_type_discontinuity(mpm::EnrichType::NeighbourTip_1); - } - - for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { - if ((*citr)->element_type_discontinuity() != mpm::EnrichType::NextTip) - continue; - // compute nodal normal direction and find neighbour cells - for (auto node : (*citr)->nodes()) { - - bool virtual_enrich = false; - for (auto cell : node->cells()) { - if (map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::Tip && - map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::Crossed) - continue; - virtual_enrich = true; - break; - } - if (virtual_enrich) { - // node->assign_discontinuity_enrich(true); - continue; - } - - for (auto cell : node->cells()) { - if (map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::NextTip) - map_cells_[cell]->assign_type_discontinuity( - mpm::EnrichType::NeighbourNextTip_1); - } - - VectorDim normal_cell; - normal_cell.setZero(); - int crossed_cell = 0; - for (auto cell : node->cells()) { - if (map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::NextTip) - continue; - normal_cell += map_cells_[cell]->normal_discontinuity(); - crossed_cell += 1; - } - - normal_cell = normal_cell / crossed_cell; - normal_cell.normalize(); - node->assign_discontinuity_property( - true, "normal_unit_vectors_discontinuity", normal_cell, 0, Tdim); - } - } - - // modify normal vector of NextTip cell - for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { - if ((*citr)->element_type_discontinuity() != mpm::EnrichType::NextTip) - continue; - VectorDim normal_cell; - normal_cell.setZero(); - - for (auto node : (*citr)->nodes()) { - normal_cell += node->discontinuity_property( - "normal_unit_vectors_discontinuity", Tdim); - } - normal_cell = normal_cell / (*citr)->nodes().size(); - normal_cell.normalize(); - (*citr)->assign_normal_discontinuity(normal_cell); - - int enriched_node = 0; - double dis = 0; - // determine the discontinuity plane by the virtual enriched nodes - - for (auto node : (*citr)->nodes()) { - - bool virtual_enrich = false; - for (auto cell : node->cells()) { - if (map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::Tip && - map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::Crossed) - continue; - virtual_enrich = true; - break; - } - if (!virtual_enrich) continue; - enriched_node++; - auto node_coordinate = node->coordinates(); - for (unsigned int j = 0; j < Tdim; j++) - dis -= node_coordinate[j] * normal_cell[j]; - dis = node->discontinuity_property("levelset_phi", 1)(0, 0) + dis; - } - - // update the level set values of the unenriched nodes - dis = dis / enriched_node; - (*citr)->assign_d_discontinuity(dis); - } - - // compute nodal level set values - for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { - if ((*citr)->element_type_discontinuity() != mpm::EnrichType::NextTip) - continue; - // compute nodal normal direction and find neighbour cells - for (auto node : (*citr)->nodes()) { - - bool virtual_enrich = false; - for (auto cell : node->cells()) { - if (map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::Tip && - map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::Crossed) - continue; - virtual_enrich = true; - break; - } - if (virtual_enrich) continue; - - VectorDim normal_cell; - normal_cell.setZero(); - int nexttip_cell = 0; - Eigen::Matrix phi; - phi.setZero(); - for (auto cell : node->cells()) { - if (map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::NextTip) - continue; - double d = map_cells_[cell]->d_discontinuity(); - normal_cell = map_cells_[cell]->normal_discontinuity(); - for (unsigned int i = 0; i < Tdim; i++) - phi(0, 0) += node->coordinates()[i] * normal_cell[i]; - phi(0, 0) += d; - nexttip_cell += 1; - } - - if (nexttip_cell == 0) continue; - - node->assign_discontinuity_property(true, "levelset_phi", - phi / nexttip_cell, 0, 1); - } - } - - // modify normal vector of NeighbourNextTip_1 cell - for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { - if ((*citr)->element_type_discontinuity() != - mpm::EnrichType::NeighbourNextTip_1) - continue; - VectorDim normal_cell; - normal_cell.setZero(); - int enriched_node = 0; - for (auto node : (*citr)->nodes()) { - - bool virtual_enrich = false; - for (auto cell : node->cells()) { - if (map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::Tip && - map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::Crossed && - map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::NextTip) - continue; - virtual_enrich = true; - break; - } - if (!virtual_enrich) continue; - - normal_cell += node->discontinuity_property( - "normal_unit_vectors_discontinuity", Tdim); - enriched_node += 1; - } - normal_cell = normal_cell / enriched_node; - normal_cell.normalize(); - (*citr)->assign_normal_discontinuity(normal_cell); - - enriched_node = 0; - double dis = 0; - // determine the discontinuity plane by the virtual enriched nodes - - for (auto node : (*citr)->nodes()) { - - bool virtual_enrich = false; - for (auto cell : node->cells()) { - if (map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::Tip && - map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::Crossed && - map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::NextTip) - continue; - virtual_enrich = true; - break; - } - if (!virtual_enrich) continue; - enriched_node++; - auto node_coordinate = node->coordinates(); - for (unsigned int j = 0; j < Tdim; j++) - dis -= node_coordinate[j] * normal_cell[j]; - dis = node->discontinuity_property("levelset_phi", 1)(0, 0) + dis; - } - - // update the level set values of the unenriched nodes - dis = dis / enriched_node; - (*citr)->assign_d_discontinuity(dis); - } - - // update nodal level set values of the NeighbourNextTip_1 cell - for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { - if ((*citr)->element_type_discontinuity() != - mpm::EnrichType::NeighbourNextTip_1) - continue; - // compute nodal normal direction and find neighbour cells - for (auto node : (*citr)->nodes()) { - - bool virtual_enrich = false; - for (auto cell : node->cells()) { - if (map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::Tip && - map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::Crossed && - map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::NextTip) - continue; - virtual_enrich = true; - break; - } - if (virtual_enrich) continue; - - for (auto cell : node->cells()) { - if (map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::NeighbourTip_1 && - map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::NeighbourNextTip_1) - map_cells_[cell]->assign_type_discontinuity( - mpm::EnrichType::NeighbourNextTip_2); - } - - VectorDim normal_cell; - normal_cell.setZero(); - VectorDim normal_cell_sum; - normal_cell_sum.setZero(); - int cell_num = 0; - Eigen::Matrix phi; - phi.setZero(); - for (auto cell : node->cells()) { - - if (map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::NeighbourNextTip_1 && - map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::NeighbourTip_1) - continue; - double d = map_cells_[cell]->d_discontinuity(); - normal_cell = map_cells_[cell]->normal_discontinuity(); - normal_cell_sum += normal_cell; - for (unsigned int i = 0; i < Tdim; i++) - phi(0, 0) += node->coordinates()[i] * normal_cell[i]; - phi(0, 0) += d; - cell_num++; - } - - if (cell_num == 0) continue; - normal_cell_sum = normal_cell_sum / cell_num; - normal_cell_sum.normalize(); - node->assign_discontinuity_property( - true, "normal_unit_vectors_discontinuity", normal_cell_sum, 0, Tdim); - - node->assign_discontinuity_property(true, "levelset_phi", phi / cell_num, - 0, 1); - } - } - // modify normal vector of NeighbourNextTip_2 cell - for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { - if ((*citr)->element_type_discontinuity() != - mpm::EnrichType::NeighbourNextTip_2) - continue; - - VectorDim normal_cell; - normal_cell.setZero(); - int enriched_node = 0; - for (auto node : (*citr)->nodes()) { - - bool virtual_enrich = false; - for (auto cell : node->cells()) { - if (map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::Tip && - map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::Crossed && - map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::NextTip && - map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::NeighbourTip_1 && - map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::NeighbourNextTip_1) - continue; - virtual_enrich = true; - break; - } - if (!virtual_enrich) continue; - - normal_cell += node->discontinuity_property( - "normal_unit_vectors_discontinuity", Tdim); - enriched_node += 1; - } - normal_cell = normal_cell / enriched_node; - normal_cell.normalize(); - (*citr)->assign_normal_discontinuity(normal_cell); - - enriched_node = 0; - double dis = 0; - // determine the discontinuity plane by the virtual enriched nodes - - for (auto node : (*citr)->nodes()) { - - bool virtual_enrich = false; - for (auto cell : node->cells()) { - if (map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::Tip && - map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::Crossed && - map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::NextTip && - map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::NeighbourTip_1 && - map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::NeighbourNextTip_1) - continue; - virtual_enrich = true; - break; - } - if (!virtual_enrich) continue; - enriched_node++; - auto node_coordinate = node->coordinates(); - for (unsigned int j = 0; j < Tdim; j++) - dis -= node_coordinate[j] * normal_cell[j]; - dis = node->discontinuity_property("levelset_phi", 1)(0, 0) + dis; - } - - // update the level set values of the unenriched nodes - - dis = dis / enriched_node; - (*citr)->assign_d_discontinuity(dis); - } - - // update nodal level set values of the NeighbourNextTip_2 cell - for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { - if ((*citr)->element_type_discontinuity() != - mpm::EnrichType::NeighbourNextTip_2) - continue; - // compute nodal normal direction and find neighbour cells - for (auto node : (*citr)->nodes()) { - - bool virtual_enrich = false; - for (auto cell : node->cells()) { - if (map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::Tip && - map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::Crossed && - map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::NextTip && - map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::NeighbourTip_1 && - map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::NeighbourNextTip_1) - continue; - virtual_enrich = true; - break; - } - - if (virtual_enrich) continue; - - VectorDim normal_cell; - normal_cell.setZero(); - VectorDim normal_cell_sum; - normal_cell_sum.setZero(); - int cell_num = 0; - Eigen::Matrix phi; - phi.setZero(); - for (auto cell : node->cells()) { - if (map_cells_[cell]->element_type_discontinuity() != - mpm::EnrichType::NeighbourNextTip_2) - continue; - double d = map_cells_[cell]->d_discontinuity(); - normal_cell = map_cells_[cell]->normal_discontinuity(); - normal_cell_sum += normal_cell; - for (unsigned int i = 0; i < Tdim; i++) - phi(0, 0) += node->coordinates()[i] * normal_cell[i]; - phi(0, 0) += d; - cell_num++; - } - - if (cell_num == 0) continue; - - normal_cell_sum = normal_cell_sum / cell_num; - normal_cell_sum.normalize(); - node->assign_discontinuity_property( - true, "normal_unit_vectors_discontinuity", normal_cell_sum, 0, Tdim); - node->assign_discontinuity_property(true, "levelset_phi", phi / cell_num, - 0, 1); - } - } - // update particle level set values - for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { - if ((*citr)->element_type_discontinuity() == mpm::EnrichType::NextTip || - (*citr)->element_type_discontinuity() == - mpm::EnrichType::NeighbourNextTip_1 || - (*citr)->element_type_discontinuity() == - mpm::EnrichType::NeighbourNextTip_2) { - for (auto particle_id : (*citr)->particles()) { - map_particles_[particle_id]->map_levelset_to_particle(); - } - } - } - - // update discontinuity points - for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { - if ((*citr)->element_type_discontinuity() != mpm::EnrichType::NextTip) - continue; - std::vector coordinates; - (*citr)->compute_discontinuity_point(coordinates); - for (int i = 0; i < coordinates.size(); i++) { - discontinuity_->insert_particles(coordinates[i], cells_, map_cells_); - - double d = (*citr)->d_discontinuity(); - auto normal_cell = (*citr)->normal_discontinuity(); - } - } -} - -//! find next tip element -template -void mpm::Mesh::next_tip_element_discontinuity() { - std::string shear; -#pragma omp parallel for schedule(runtime) - for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { - if ((*citr)->element_type_discontinuity() != mpm::EnrichType::PotentialTip) - continue; - mpm::Index pid; - double max_pdstrain = 0; - for (auto particle_id : (*citr)->particles()) { - double pdstrain = map_particles_[particle_id]->state_variable("pdstrain"); - if (pdstrain > max_pdstrain) { - max_pdstrain = pdstrain; - pid = particle_id; - } - } - - if (max_pdstrain <= discontinuity_->maximum_pdstrain()) continue; - VectorDim normal; - bool propagation = - map_particles_[pid]->minimum_acoustic_tensor(normal, false); - if (propagation) { - (*citr)->assign_type_discontinuity(mpm::EnrichType::NextTip); - (*citr)->assign_normal_discontinuity(normal); - } - } - return; -} - -// Initialise the cells in node -template -void mpm::Mesh::add_cell_in_node() { - for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { - (*citr)->add_cell_in_node(); - } -} - -//! remove spurious potential tip element -template -void mpm::Mesh::spurious_potential_tip_element() { - - for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { - if ((*citr)->element_type_discontinuity() != mpm::EnrichType::PotentialTip) - continue; - - bool boundary = false; - bool potential_tip = false; - for (auto neighbour : (*citr)->neighbours()) { - if (cells_[neighbour]->element_type_discontinuity() != - mpm::EnrichType::NeighbourTip_2) - continue; - - if (cells_[neighbour]->nparticles() == 0) { - boundary = true; - } - if (cells_[neighbour]->product_levelset() < 0) potential_tip = true; - } - - if (potential_tip) continue; - (*citr)->assign_type_discontinuity(mpm::EnrichType::Crossed); - - continue; - if (!boundary) continue; - - // avoid the node located near the discontinuity - if ((*citr)->discontinuity_area() == 0) continue; - - std::vector coordinates; - (*citr)->compute_discontinuity_point(coordinates); - - for (int i = 0; i < coordinates.size(); i++) - discontinuity_->insert_particles(coordinates[i], cells_, map_cells_); - } -} - -// assign_node_enrich -template -void mpm::Mesh::assign_node_enrich(bool friction_coef_average, - bool enrich_all) { - for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { - if ((*citr)->element_type_discontinuity() != mpm::EnrichType::Crossed) - continue; - Eigen::Matrix friction_coef; - friction_coef(0, 0) = discontinuity_->friction_coef(); - - Eigen::Matrix cohesion; - cohesion(0, 0) = discontinuity_->cohesion(); - for (auto node : (*citr)->nodes()) { - if (node->discontinuity_enrich()) continue; - node->assign_discontinuity_enrich(true); - - if (!friction_coef_average) - node->assign_discontinuity_property(true, "friction_coef", - friction_coef, 0, 1); - node->assign_discontinuity_property(true, "cohesion", cohesion, 0, 1); - } - - // bool negative = false; - // bool positive = false; - // for(auto particle : (*citr)->particles()) - // { - // if(particles_[particle]->levelset_phi() > 0) - // positive = true; - // if(particles_[particle]->levelset_phi() < 0) - // negative = true; - // } - - // if(!negative || !positive) - // continue; - - (*citr)->assign_cohesion_area(); - } - - for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { - if ((*citr)->element_type_discontinuity() != mpm::EnrichType::PotentialTip) - continue; - for (auto node : (*citr)->nodes()) { - if (node->discontinuity_enrich()) - node->assign_discontinuity_enrich(false); - } - } - - if (!enrich_all) return; - - // double tolerance = 1e-16; - // for(auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr){ - // (*nitr)->assign_discontinuity_enrich(true); - // double positive_mass = (*nitr)->mass(mpm::ParticlePhase::Solid) + - // (*nitr)->discontinuity_property("mass_enrich", 1)(0, 0); double - // negative_mass = (*nitr)->mass(mpm::ParticlePhase::Solid) - - // (*nitr)->discontinuity_property("mass_enrich", 1)(0, 0); - // if(positive_mass < tolerance || negative_mass < tolerance) - // (*nitr)->assign_discontinuity_enrich(false); - // } - - for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { - (*nitr)->assign_discontinuity_enrich(true); - } -} - -// modify_node_enrich -template -void mpm::Mesh::update_node_enrich() { - - double tolerance = 1e-16; - for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { - double positive_mass = - (*nitr)->mass(mpm::ParticlePhase::Solid) + - (*nitr)->discontinuity_property("mass_enrich", 1)(0, 0); - double negative_mass = - (*nitr)->mass(mpm::ParticlePhase::Solid) - - (*nitr)->discontinuity_property("mass_enrich", 1)(0, 0); - if (positive_mass < tolerance || negative_mass < tolerance) - (*nitr)->assign_discontinuity_enrich(false); - } -} - -template -void mpm::Mesh::define_levelset() { - // for oso - std::ifstream in("stage1.txt"); - double stage[63126]; - for (int i = 0; i < 63126; ++i) { - in >> stage[i]; - if (stage[i] == 0) stage[i] = std::numeric_limits::min(); - } - int i = 0; - Eigen::Matrix phi_mls; - for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { - phi_mls(0, 0) = stage[i]; - i += 1; - - (*nitr)->assign_discontinuity_property(true, "levelset_phi", phi_mls, 0, 1); - } - for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { - - (*pitr)->map_levelset_to_particle(); - } - - return; - for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { - - auto cor = (*pitr)->coordinates(); - double phi; - // phi = 1 / std::sqrt(3) * cor[0] + 1 / std::sqrt(3) * cor[1] + - // 1 / std::sqrt(3) * cor[2] - 0.5 * std::sqrt(3); - - // phi = std::sqrt(std::pow(cor[0] - 35, 2) + std::pow(cor[1] - 30, 2) + - // std::pow(cor[2] - 0, 2)) - - // 25; - // slide body - phi = (0.5 * cor[0] + cor[2] - 0.5) / std::sqrt(0.25 + 1); - phi = cor[1] - 1.5; - (*pitr)->assign_levelsetphi(phi); - // case 4-2d - // if (cor[0] > 35 && cor[1] > 4 && cor[1] < 5) { - // phi = 5 - cor[1]; - // (*pitr)->assign_levelsetphi(phi); - // } - // if (cor[0] > 34 && cor[0] < 35 && cor[1] > 4) { - // if ((*pitr)->levelset_phi() < 0) continue; - // Eigen::Matrix e1, e2, p2n; - // e1 << 1 / std::sqrt(5), 2 / std::sqrt(5); - // e2 << 2 / std::sqrt(5), -1 / std::sqrt(5); - - // p2n << cor[0] - 35, cor[1] - 5; - // if (e2.dot(p2n) >= 0) - // phi = p2n.norm(); - // else if (e2.dot(p2n) < 0) { - // double dis1 = 5.25 - cor[1]; // 5.27118 - // double dis2 = std::abs(e1.dot(p2n)); - // if (dis1 < dis2) - // dis1 = (*pitr)->levelset_phi(); - // else - // dis1 = dis2; - // phi = dis1; - // } - // (*pitr)->assign_levelsetphi(phi); - // } - // case 5 - // if (cor[0] > 35 && cor[1] > 4 && cor[1] < 5) { - // phi = 5 - cor[1]; - // (*pitr)->assign_levelsetphi(phi); - // } - // if (cor[0] > 34 && cor[0] < 35 && cor[1] > 4) { - // if ((*pitr)->levelset_phi() != 0) continue; - // Eigen::Matrix e1, e2, p2n; - // e1 << 1 / std::sqrt(5), 2 / std::sqrt(5); - // e2 << 2 / std::sqrt(5), -1 / std::sqrt(5); - - // p2n << cor[0] - 35, cor[1] - 5; - // if (e2.dot(p2n) >= 0) - // phi = p2n.norm(); - // else if (e2.dot(p2n) < 0) { - // double dis1 = 5.25 - cor[1]; // 5.27118 - // double dis2 = std::abs(e1.dot(p2n)); - // phi = dis2; - // } - // (*pitr)->assign_levelsetphi(phi); - // } - // if ((*pitr)->material_id(mpm::ParticlePhase::Solid) == 4) - // (*pitr)->assign_levelsetphi(1.0); - // else if ((*pitr)->material_id(mpm::ParticlePhase::Solid) == 5) - // (*pitr)->assign_levelsetphi(-1); - // else if ((*pitr)->material_id(mpm::ParticlePhase::Solid) == 6) - // (*pitr)->assign_levelsetphi(-1); - } -} - -template -bool mpm::Mesh::initiation_discontinuity() { - bool status = false; - - mpm::Index pid; - double max_pdstrain = 0; - for (int i = 0; i < nparticles(); ++i) { - double pdstrain = map_particles_[i]->state_variable("pdstrain"); - // if(map_particles_[i]->coordinates()[1] < 0.2 || - // map_particles_[i]->coordinates()[1] > 0.8 || - // map_particles_[i]->coordinates()[0] > 0.05) continue; - - if (pdstrain > max_pdstrain) { - max_pdstrain = pdstrain; - pid = i; - } - } - - if (max_pdstrain <= discontinuity_->maximum_pdstrain()) return status; - VectorDim normal; - bool initiation = map_particles_[pid]->minimum_acoustic_tensor(normal, true); - - if (initiation) { - status = true; - auto cell_id = map_particles_[pid]->cell_id(); - map_cells_[cell_id]->assign_type_discontinuity(mpm::EnrichType::InitialTip); - map_cells_[cell_id]->assign_normal_discontinuity(normal); - auto center = map_cells_[cell_id]->centroid(); - - double d = 0; - - for (unsigned int i = 0; i < Tdim; i++) d -= center[i] * normal[i]; - - map_cells_[cell_id]->assign_normal_discontinuity(normal, d); - - map_cells_[cell_id]->compute_nodal_levelset_equation(); - - std::vector coordinates_dis; - map_cells_[cell_id]->compute_discontinuity_point(coordinates_dis); - - for (int i = 0; i < coordinates_dis.size(); i++) - discontinuity_->insert_particles(coordinates_dis[i], cells_, map_cells_); - // initialise neighbour cells - - auto neighbours = map_cells_[cell_id]->neighbours(); - for (auto neighbour : neighbours) { - if (map_cells_[neighbour]->nparticles() == 0) continue; - map_cells_[neighbour]->assign_type_discontinuity( - mpm::EnrichType::NeighbourTip_1); - map_cells_[neighbour]->assign_normal_discontinuity(normal, d); - map_cells_[neighbour]->compute_nodal_levelset_equation(); - if (map_cells_[neighbour]->product_levelset() >= 0) continue; - map_cells_[neighbour]->assign_type_discontinuity( - mpm::EnrichType::InitialTip); - - std::vector coordinates_dis_neigh; - map_cells_[neighbour]->compute_discontinuity_point(coordinates_dis_neigh); - - for (int i = 0; i < coordinates_dis_neigh.size(); i++) { - discontinuity_->insert_particles(coordinates_dis_neigh[i], cells_, - map_cells_); - } - } - // initialise level set values - - for (int i = 0; i < nparticles(); ++i) { - bool neighbour = true; - for (int j = 0; j < Tdim; j++) { - if (std::abs(center[j] - particles_[i]->coordinates()[j]) > - 3.5 * discontinuity_->width()) - neighbour = false; - } - if (!neighbour) continue; - double phi = particles_[i]->coordinates().dot(normal) + d; - particles_[i]->assign_levelsetphi(phi); - } - } - return status; -} - -template -void mpm::Mesh::modify_nodal_levelset_mls() { - Eigen::Matrix au; - Eigen::Matrix bu; - // double error_max = 0; - const double tolerance = std::numeric_limits::epsilon(); - - for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { - if ((*nitr)->discontinuity_property("levelset_phi", 1)(0, 0) == 0) continue; - double phi = 0; - - au.setZero(); - bu.setZero(); - - double particle_volume = 0; - double cell_volume = 0; - std::vector cell_list; - for (auto cell : (*nitr)->cells()) cell_list.push_back(cell); - - for (auto cell : cell_list) { - double length = discontinuity_->width(); - cell_volume += map_cells_[cell]->volume(); - for (auto particle : map_cells_[cell]->particles()) { - auto corp = map_particles_[particle]->coordinates(); - phi = map_particles_[particle]->levelset_phi(); - if (phi == 0) continue; - particle_volume += map_particles_[particle]->volume(); - // compute weight - double w[3]; - for (int i = 0; i < 3; i++) { - w[i] = 1 - std::abs(corp[i] - (*nitr)->coordinates()[i]) / length; - if (w[i] < 0) w[i] = 0; - } - - double weight = w[0] * w[1] * w[2]; - au(0, 0) += weight; - au(0, 1) += weight * corp[0]; - au(0, 2) += weight * corp[1]; - au(0, 3) += weight * corp[2]; - au(1, 0) += weight * corp[0]; - au(1, 1) += weight * corp[0] * corp[0]; - au(1, 2) += weight * corp[0] * corp[1]; - au(1, 3) += weight * corp[0] * corp[2]; - au(2, 0) += weight * corp[1]; - au(2, 1) += weight * corp[1] * corp[0]; - au(2, 2) += weight * corp[1] * corp[1]; - au(2, 3) += weight * corp[1] * corp[2]; - au(3, 0) += weight * corp[2]; - au(3, 1) += weight * corp[2] * corp[0]; - au(3, 2) += weight * corp[2] * corp[1]; - au(3, 3) += weight * corp[2] * corp[2]; - - bu(0, 0) += weight * phi; - bu(1, 0) += weight * phi * corp[0]; - bu(2, 0) += weight * phi * corp[1]; - bu(3, 0) += weight * phi * corp[2]; - } - } - - // find particles from neighbour cells - if (particle_volume < 0.5 * cell_volume || - std::abs(au.determinant()) < tolerance) { - au.setZero(); - bu.setZero(); - for (auto cells : (*nitr)->cells()) { - for (auto cell : map_cells_[cells]->neighbours()) { - std::vector::iterator ret; - ret = std::find(cell_list.begin(), cell_list.end(), cell); - if (ret != cell_list.end()) continue; - cell_list.push_back(cell); - } - } - - for (auto cell : cell_list) { - for (auto particle : map_cells_[cell]->particles()) { - auto corp = map_particles_[particle]->coordinates(); - phi = map_particles_[particle]->levelset_phi(); - if (phi == 0) continue; - // compute weight - double length = 2 * discontinuity_->width(); - double w[3]; - for (int i = 0; i < 3; i++) { - w[i] = 1 - std::abs(corp[i] - (*nitr)->coordinates()[i]) / length; - if (w[i] < 0) w[i] = 0; - } - double weight = w[0] * w[1] * w[2]; - - au(0, 0) += weight; - au(0, 1) += weight * corp[0]; - au(0, 2) += weight * corp[1]; - au(0, 3) += weight * corp[2]; - au(1, 0) += weight * corp[0]; - au(1, 1) += weight * corp[0] * corp[0]; - au(1, 2) += weight * corp[0] * corp[1]; - au(1, 3) += weight * corp[0] * corp[2]; - au(2, 0) += weight * corp[1]; - au(2, 1) += weight * corp[1] * corp[0]; - au(2, 2) += weight * corp[1] * corp[1]; - au(2, 3) += weight * corp[1] * corp[2]; - au(3, 0) += weight * corp[2]; - au(3, 1) += weight * corp[2] * corp[0]; - au(3, 2) += weight * corp[2] * corp[1]; - au(3, 3) += weight * corp[2] * corp[2]; - - bu(0, 0) += weight * phi; - bu(1, 0) += weight * phi * corp[0]; - bu(2, 0) += weight * phi * corp[1]; - bu(3, 0) += weight * phi * corp[2]; - } - } - } - - if (std::abs(au.determinant()) < tolerance) continue; - - Eigen::Vector4d coef; - coef.setZero(); - for (int i = 0; i < 4; i++) - for (int j = 0; j < 4; j++) coef[i] += au.inverse()(i, j) * bu(j, 0); - - // compute the error - double error = 0; - int error_p = 0; - for (auto cell : cell_list) { - for (auto particle : map_cells_[cell]->particles()) { - auto corp = map_particles_[particle]->coordinates(); - phi = map_particles_[particle]->levelset_phi(); - if (phi == 0) continue; - double phi_mls = 1 * coef[0] + corp[0] * coef[1] + corp[1] * coef[2] + - corp[2] * coef[3]; - error += std::pow(phi_mls - phi, 2); - error_p += 1; - } - } - error = std::sqrt(error / error_p) / discontinuity_->width(); - - if (error > 1e-3) continue; - - Eigen::Matrix cor; - Eigen::Matrix phi_mls; - - cor << 1, (*nitr)->coordinates()[0], (*nitr)->coordinates()[1], - (*nitr)->coordinates()[2]; - phi_mls(0, 0) = cor.dot(coef); - - (*nitr)->assign_discontinuity_property(true, "levelset_phi", phi_mls, 0, 1); - } -} - -template -void mpm::Mesh::selfcontact_detection() { - - double contact_distance = discontinuity_->contact_distance(); - - for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { - if (!(*nitr)->discontinuity_enrich()) continue; - - auto cor = (*nitr)->coordinates(); - auto normal = (*nitr)->discontinuity_property( - "normal_unit_vectors_discontinuity", Tdim); - double dis_negative = -10 * contact_distance; - double dis_positive = 10 * contact_distance; - for (auto cell : (*nitr)->cells()) { - - for (auto particle : map_cells_[cell]->particles()) { - auto corp = map_particles_[particle]->coordinates(); - double phi = map_particles_[particle]->levelset_phi(); - - double dis = 0; - for (unsigned int i = 0; i < Tdim; i++) - dis += (corp[i] - cor[i]) * normal(i); - - if (phi > 0) dis_positive = dis < dis_positive ? dis : dis_positive; - if (phi < 0) dis_negative = dis > dis_negative ? dis : dis_negative; - } - } - Eigen::Matrix dis; - dis(0, 0) = dis_positive - dis_negative - contact_distance; - (*nitr)->assign_discontinuity_property(true, "contact_distance", dis, 0, 1); - } -} - -template -void mpm::Mesh::check_particle_levelset(bool particle_levelset) { - - for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { - if ((*pitr)->levelset_phi() != 0) continue; - - auto cell_id = (*pitr)->cell_id(); - - for (auto node : cells_[cell_id]->nodes()) { - if (!node->discontinuity_enrich()) continue; - - Eigen::Matrix au; - Eigen::Matrix bu; - au.setZero(); - bu.setZero(); - auto cell_list = cells_[cell_id]->neighbours(); - cell_list.insert(cell_id); - - for (auto cell : cell_list) { - for (auto particle : cells_[cell]->particles()) { - auto corp = map_particles_[particle]->coordinates(); - double phi = map_particles_[particle]->levelset_phi(); - if (phi == 0) continue; - // compute weight - double length = 2.0 * discontinuity_->width(); - double w[3]; - for (int i = 0; i < 3; i++) { - w[i] = 1 - std::abs(corp[i] - (*pitr)->coordinates()[i]) / length; - if (w[i] < 0) w[i] = 0; - } - double weight = w[0] * w[1] * w[2]; - - au(0, 0) += weight; - au(0, 1) += weight * corp[0]; - au(0, 2) += weight * corp[1]; - au(0, 3) += weight * corp[2]; - au(1, 0) += weight * corp[0]; - au(1, 1) += weight * corp[0] * corp[0]; - au(1, 2) += weight * corp[0] * corp[1]; - au(1, 3) += weight * corp[0] * corp[2]; - au(2, 0) += weight * corp[1]; - au(2, 1) += weight * corp[1] * corp[0]; - au(2, 2) += weight * corp[1] * corp[1]; - au(2, 3) += weight * corp[1] * corp[2]; - au(3, 0) += weight * corp[2]; - au(3, 1) += weight * corp[2] * corp[0]; - au(3, 2) += weight * corp[2] * corp[1]; - au(3, 3) += weight * corp[2] * corp[2]; - - bu(0, 0) += weight * phi; - bu(1, 0) += weight * phi * corp[0]; - bu(2, 0) += weight * phi * corp[1]; - bu(3, 0) += weight * phi * corp[2]; - } - } - - const double tolerance = std::numeric_limits::epsilon(); - - if (std::abs(au.determinant()) < tolerance) { - (*pitr)->map_levelset_to_particle(); - continue; - } - - Eigen::Vector4d coef; - coef.setZero(); - for (int i = 0; i < 4; i++) - for (int j = 0; j < 4; j++) coef[i] += au.inverse()(i, j) * bu(j, 0); - - // compute the error - // double error = 0; - // int error_p = 0; - // for (auto cell : cell_list) { - // for (auto particle : map_cells_[cell]->particles()) { - // auto corp = map_particles_[particle]->coordinates(); - // double phi = map_particles_[particle]->levelset_phi(); - // if (phi == 0) continue; - // double phi_mls = 1 * coef[0] + corp[0] * coef[1] + corp[1] * - // coef[2] + - // corp[2] * coef[3]; - // error += std::pow(phi_mls - phi, 2); - // error_p += 1; - // } - // } - // error = std::sqrt(error / error_p) / discontinuity_->width(); - - // if (error > 1e-3) { - // (*pitr)->map_levelset_to_particle(); - // continue; - // } - - Eigen::Vector4d cor; - cor << 1, (*pitr)->coordinates()[0], (*pitr)->coordinates()[1], - (*pitr)->coordinates()[2]; - double phi = cor.dot(coef); - - (*pitr)->assign_levelsetphi(phi); - - break; - } - } - if (particle_levelset) return; - for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { - if ((*pitr)->levelset_phi() == 0) continue; - auto cell_id = (*pitr)->cell_id(); - - if (cells_[cell_id]->element_type_discontinuity() == - mpm::EnrichType::Regular || - cells_[cell_id]->element_type_discontinuity() == - mpm::EnrichType::NeighbourTip_3) - (*pitr)->assign_levelsetphi(0); - } -} - -template -void mpm::Mesh::output_celltype(int step) { - std::ofstream test("cell_type.txt", std::ios::app); - - test << step << ":" << std::endl; - for (int i = 0; i < cells_.size(); i++) { - auto type = cells_[i]->element_type_discontinuity(); - if (type == 1) - test << "o "; - else if (type == 2) - test << "\\ "; - else if (type == 3) - test << "^ "; - else if (type == 4) - test << "1 "; - else if (type == 5) - test << "2 "; - else if (type == 6) - test << "* "; - else - test << type << " "; - if (((i + 1) % 90) == 0) test << std::endl; - } - test << std::endl; - - std::ofstream testnormal("node_normal.txt", std::ios::app); - testnormal << step << ":" << std::endl; - for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { - if (!(*nitr)->discontinuity_enrich()) continue; - - if ((*nitr)->coordinates()[0] < 35) continue; - - Eigen::Matrix normal = (*nitr)->discontinuity_property( - "normal_unit_vectors_discontinuity", Tdim); - testnormal << (*nitr)->coordinates()[0] << "\t" << (*nitr)->coordinates()[1] - << "\t" << normal[0] << "\t" << normal[1] << "\t" << normal[2] - << std::endl; - } -} +} \ No newline at end of file diff --git a/include/mesh_xmpm.tcc b/include/mesh_xmpm.tcc new file mode 100644 index 000000000..53ef07843 --- /dev/null +++ b/include/mesh_xmpm.tcc @@ -0,0 +1,1210 @@ +// Create the nodal properties' map for discontinuity +template +void mpm::Mesh::create_nodal_properties_discontinuity() { + // Initialise the shared pointer to nodal properties + if (nodal_properties_ == nullptr) + nodal_properties_ = std::make_shared(); + + // Check if nodes_ is empty and throw runtime error if they are + assert(nodes_.size()); + // Compute number of rows in nodal properties for vector entities + const unsigned nrows = nodes_.size() * Tdim; + // Create pool data for each property in the nodal properties struct + // object. Properties must be named in the plural form + nodal_properties_->create_property("mass_enrich", nodes_.size(), 1); + nodal_properties_->create_property("levelset_phi", nodes_.size(), 1); + nodal_properties_->create_property("momenta_enrich", nrows, 1); + nodal_properties_->create_property("internal_force_enrich", nrows, 1); + nodal_properties_->create_property("external_force_enrich", nrows, 1); + nodal_properties_->create_property("normal_unit_vectors_discontinuity", nrows, + 1); + nodal_properties_->create_property("friction_coef", nodes_.size(), 1); + nodal_properties_->create_property("cohesion", nodes_.size(), 1); + nodal_properties_->create_property("cohesion_area", nodes_.size(), 1); + nodal_properties_->create_property("contact_distance", nodes_.size(), 1); + // Iterate over all nodes to initialise the property handle in each node + // and assign its node id as the prop id in the nodal property data pool + for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) + (*nitr)->initialise_discontinuity_property_handle((*nitr)->id(), + nodal_properties_); +} + +// 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(); +} + +//! Locate points in a cell +template +void mpm::Mesh::locate_discontinuity() { + discontinuity_->locate_discontinuity_mesh(cells_, map_cells_); +} +//! updated_position of discontinuity +template +void mpm::Mesh::compute_updated_position_discontinuity(double dt) { + discontinuity_->compute_updated_position(dt); +} +//! compute shape function +template +void mpm::Mesh::compute_shapefn_discontinuity() { + discontinuity_->compute_shapefn(); +} + +// compute the normal vector of cells +template +void mpm::Mesh::compute_cell_normal_vector_discontinuity() { + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + (*citr)->compute_normal_vector_discontinuity(); + (*citr)->compute_plane_discontinuity(false); + } +} + +// compute the normal vector of enriched nodes at the discontinuity +template +void mpm::Mesh::compute_nodal_normal_vector_discontinuity() { + + VectorDim normal_cell; + for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { + if (!(*nitr)->discontinuity_enrich()) continue; + normal_cell.setZero(); + int crossed_cell = 0; + for (auto cell : (*nitr)->cells()) { + normal_cell += map_cells_[cell]->normal_discontinuity(); + crossed_cell += 1; + } + if (crossed_cell == 0) continue; + normal_cell = normal_cell / crossed_cell; + + // normal_cell << 0.5,0,1; + normal_cell.normalize(); + (*nitr)->assign_discontinuity_property( + true, "normal_unit_vectors_discontinuity", normal_cell, 0, Tdim); + } +} + +// Initialise level set values particles +template +void mpm::Mesh::initialise_levelset_discontinuity() { + + double phi_particle; + + for (mpm::Index j = 0; j < nparticles(); ++j) { + discontinuity_->compute_levelset(particles_[j]->coordinates(), + phi_particle); + particles_[j]->assign_levelsetphi(phi_particle); + } +} + +// Initialise nodal level set values particles +template +void mpm::Mesh::initialise_nodal_levelset_discontinuity() { + + Eigen::Matrix phi; + phi.setZero(); + double phi_node; + for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { + discontinuity_->compute_levelset((*nitr)->coordinates(), phi_node); + phi(0, 0) = phi_node; + (*nitr)->assign_discontinuity_property(true, "levelset_phi", phi, 0, 1); + } +} + +//! solve nodal levelset values +template +void mpm::Mesh::update_node_levelset() { + for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) + (*nitr)->update_levelset(); +} + +// discontinuity growth +template +void mpm::Mesh::update_discontinuity() { + + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + if ((*citr)->element_type_discontinuity() == mpm::EnrichType::PotentialTip) + (*citr)->assign_type_discontinuity(mpm::EnrichType::NeighbourTip_1); + } + + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + if ((*citr)->element_type_discontinuity() != mpm::EnrichType::NextTip) + continue; + // compute nodal normal direction and find neighbour cells + for (auto node : (*citr)->nodes()) { + + bool virtual_enrich = false; + for (auto cell : node->cells()) { + if (map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Tip && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Crossed) + continue; + virtual_enrich = true; + break; + } + if (virtual_enrich) { + // node->assign_discontinuity_enrich(true); + continue; + } + + for (auto cell : node->cells()) { + if (map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NextTip) + map_cells_[cell]->assign_type_discontinuity( + mpm::EnrichType::NeighbourNextTip_1); + } + + VectorDim normal_cell; + normal_cell.setZero(); + int crossed_cell = 0; + for (auto cell : node->cells()) { + if (map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NextTip) + continue; + normal_cell += map_cells_[cell]->normal_discontinuity(); + crossed_cell += 1; + } + + normal_cell = normal_cell / crossed_cell; + normal_cell.normalize(); + node->assign_discontinuity_property( + true, "normal_unit_vectors_discontinuity", normal_cell, 0, Tdim); + } + } + + // modify normal vector of NextTip cell + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + if ((*citr)->element_type_discontinuity() != mpm::EnrichType::NextTip) + continue; + VectorDim normal_cell; + normal_cell.setZero(); + + for (auto node : (*citr)->nodes()) { + normal_cell += node->discontinuity_property( + "normal_unit_vectors_discontinuity", Tdim); + } + normal_cell = normal_cell / (*citr)->nodes().size(); + normal_cell.normalize(); + (*citr)->assign_normal_discontinuity(normal_cell); + + int enriched_node = 0; + double dis = 0; + // determine the discontinuity plane by the virtual enriched nodes + + for (auto node : (*citr)->nodes()) { + + bool virtual_enrich = false; + for (auto cell : node->cells()) { + if (map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Tip && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Crossed) + continue; + virtual_enrich = true; + break; + } + if (!virtual_enrich) continue; + enriched_node++; + auto node_coordinate = node->coordinates(); + for (unsigned int j = 0; j < Tdim; j++) + dis -= node_coordinate[j] * normal_cell[j]; + dis = node->discontinuity_property("levelset_phi", 1)(0, 0) + dis; + } + + // update the level set values of the unenriched nodes + dis = dis / enriched_node; + (*citr)->assign_d_discontinuity(dis); + } + + // compute nodal level set values + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + if ((*citr)->element_type_discontinuity() != mpm::EnrichType::NextTip) + continue; + // compute nodal normal direction and find neighbour cells + for (auto node : (*citr)->nodes()) { + + bool virtual_enrich = false; + for (auto cell : node->cells()) { + if (map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Tip && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Crossed) + continue; + virtual_enrich = true; + break; + } + if (virtual_enrich) continue; + + VectorDim normal_cell; + normal_cell.setZero(); + int nexttip_cell = 0; + Eigen::Matrix phi; + phi.setZero(); + for (auto cell : node->cells()) { + if (map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NextTip) + continue; + double d = map_cells_[cell]->d_discontinuity(); + normal_cell = map_cells_[cell]->normal_discontinuity(); + for (unsigned int i = 0; i < Tdim; i++) + phi(0, 0) += node->coordinates()[i] * normal_cell[i]; + phi(0, 0) += d; + nexttip_cell += 1; + } + + if (nexttip_cell == 0) continue; + + node->assign_discontinuity_property(true, "levelset_phi", + phi / nexttip_cell, 0, 1); + } + } + + // modify normal vector of NeighbourNextTip_1 cell + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + if ((*citr)->element_type_discontinuity() != + mpm::EnrichType::NeighbourNextTip_1) + continue; + VectorDim normal_cell; + normal_cell.setZero(); + int enriched_node = 0; + for (auto node : (*citr)->nodes()) { + + bool virtual_enrich = false; + for (auto cell : node->cells()) { + if (map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Tip && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Crossed && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NextTip) + continue; + virtual_enrich = true; + break; + } + if (!virtual_enrich) continue; + + normal_cell += node->discontinuity_property( + "normal_unit_vectors_discontinuity", Tdim); + enriched_node += 1; + } + normal_cell = normal_cell / enriched_node; + normal_cell.normalize(); + (*citr)->assign_normal_discontinuity(normal_cell); + + enriched_node = 0; + double dis = 0; + // determine the discontinuity plane by the virtual enriched nodes + + for (auto node : (*citr)->nodes()) { + + bool virtual_enrich = false; + for (auto cell : node->cells()) { + if (map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Tip && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Crossed && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NextTip) + continue; + virtual_enrich = true; + break; + } + if (!virtual_enrich) continue; + enriched_node++; + auto node_coordinate = node->coordinates(); + for (unsigned int j = 0; j < Tdim; j++) + dis -= node_coordinate[j] * normal_cell[j]; + dis = node->discontinuity_property("levelset_phi", 1)(0, 0) + dis; + } + + // update the level set values of the unenriched nodes + dis = dis / enriched_node; + (*citr)->assign_d_discontinuity(dis); + } + + // update nodal level set values of the NeighbourNextTip_1 cell + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + if ((*citr)->element_type_discontinuity() != + mpm::EnrichType::NeighbourNextTip_1) + continue; + // compute nodal normal direction and find neighbour cells + for (auto node : (*citr)->nodes()) { + + bool virtual_enrich = false; + for (auto cell : node->cells()) { + if (map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Tip && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Crossed && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NextTip) + continue; + virtual_enrich = true; + break; + } + if (virtual_enrich) continue; + + for (auto cell : node->cells()) { + if (map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NeighbourTip_1 && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NeighbourNextTip_1) + map_cells_[cell]->assign_type_discontinuity( + mpm::EnrichType::NeighbourNextTip_2); + } + + VectorDim normal_cell; + normal_cell.setZero(); + VectorDim normal_cell_sum; + normal_cell_sum.setZero(); + int cell_num = 0; + Eigen::Matrix phi; + phi.setZero(); + for (auto cell : node->cells()) { + + if (map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NeighbourNextTip_1 && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NeighbourTip_1) + continue; + double d = map_cells_[cell]->d_discontinuity(); + normal_cell = map_cells_[cell]->normal_discontinuity(); + normal_cell_sum += normal_cell; + for (unsigned int i = 0; i < Tdim; i++) + phi(0, 0) += node->coordinates()[i] * normal_cell[i]; + phi(0, 0) += d; + cell_num++; + } + + if (cell_num == 0) continue; + normal_cell_sum = normal_cell_sum / cell_num; + normal_cell_sum.normalize(); + node->assign_discontinuity_property( + true, "normal_unit_vectors_discontinuity", normal_cell_sum, 0, Tdim); + + node->assign_discontinuity_property(true, "levelset_phi", phi / cell_num, + 0, 1); + } + } + // modify normal vector of NeighbourNextTip_2 cell + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + if ((*citr)->element_type_discontinuity() != + mpm::EnrichType::NeighbourNextTip_2) + continue; + + VectorDim normal_cell; + normal_cell.setZero(); + int enriched_node = 0; + for (auto node : (*citr)->nodes()) { + + bool virtual_enrich = false; + for (auto cell : node->cells()) { + if (map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Tip && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Crossed && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NextTip && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NeighbourTip_1 && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NeighbourNextTip_1) + continue; + virtual_enrich = true; + break; + } + if (!virtual_enrich) continue; + + normal_cell += node->discontinuity_property( + "normal_unit_vectors_discontinuity", Tdim); + enriched_node += 1; + } + normal_cell = normal_cell / enriched_node; + normal_cell.normalize(); + (*citr)->assign_normal_discontinuity(normal_cell); + + enriched_node = 0; + double dis = 0; + // determine the discontinuity plane by the virtual enriched nodes + + for (auto node : (*citr)->nodes()) { + + bool virtual_enrich = false; + for (auto cell : node->cells()) { + if (map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Tip && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Crossed && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NextTip && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NeighbourTip_1 && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NeighbourNextTip_1) + continue; + virtual_enrich = true; + break; + } + if (!virtual_enrich) continue; + enriched_node++; + auto node_coordinate = node->coordinates(); + for (unsigned int j = 0; j < Tdim; j++) + dis -= node_coordinate[j] * normal_cell[j]; + dis = node->discontinuity_property("levelset_phi", 1)(0, 0) + dis; + } + + // update the level set values of the unenriched nodes + + dis = dis / enriched_node; + (*citr)->assign_d_discontinuity(dis); + } + + // update nodal level set values of the NeighbourNextTip_2 cell + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + if ((*citr)->element_type_discontinuity() != + mpm::EnrichType::NeighbourNextTip_2) + continue; + // compute nodal normal direction and find neighbour cells + for (auto node : (*citr)->nodes()) { + + bool virtual_enrich = false; + for (auto cell : node->cells()) { + if (map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Tip && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::Crossed && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NextTip && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NeighbourTip_1 && + map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NeighbourNextTip_1) + continue; + virtual_enrich = true; + break; + } + + if (virtual_enrich) continue; + + VectorDim normal_cell; + normal_cell.setZero(); + VectorDim normal_cell_sum; + normal_cell_sum.setZero(); + int cell_num = 0; + Eigen::Matrix phi; + phi.setZero(); + for (auto cell : node->cells()) { + if (map_cells_[cell]->element_type_discontinuity() != + mpm::EnrichType::NeighbourNextTip_2) + continue; + double d = map_cells_[cell]->d_discontinuity(); + normal_cell = map_cells_[cell]->normal_discontinuity(); + normal_cell_sum += normal_cell; + for (unsigned int i = 0; i < Tdim; i++) + phi(0, 0) += node->coordinates()[i] * normal_cell[i]; + phi(0, 0) += d; + cell_num++; + } + + if (cell_num == 0) continue; + + normal_cell_sum = normal_cell_sum / cell_num; + normal_cell_sum.normalize(); + node->assign_discontinuity_property( + true, "normal_unit_vectors_discontinuity", normal_cell_sum, 0, Tdim); + node->assign_discontinuity_property(true, "levelset_phi", phi / cell_num, + 0, 1); + } + } + // update particle level set values + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + if ((*citr)->element_type_discontinuity() == mpm::EnrichType::NextTip || + (*citr)->element_type_discontinuity() == + mpm::EnrichType::NeighbourNextTip_1 || + (*citr)->element_type_discontinuity() == + mpm::EnrichType::NeighbourNextTip_2) { + for (auto particle_id : (*citr)->particles()) { + map_particles_[particle_id]->map_levelset_to_particle(); + } + } + } + + // update discontinuity points + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + if ((*citr)->element_type_discontinuity() != mpm::EnrichType::NextTip) + continue; + std::vector coordinates; + (*citr)->compute_discontinuity_point(coordinates); + for (int i = 0; i < coordinates.size(); i++) { + discontinuity_->insert_particles(coordinates[i], cells_, map_cells_); + + double d = (*citr)->d_discontinuity(); + auto normal_cell = (*citr)->normal_discontinuity(); + } + } +} + +//! find next tip element +template +void mpm::Mesh::next_tip_element_discontinuity() { + std::string shear; +#pragma omp parallel for schedule(runtime) + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + if ((*citr)->element_type_discontinuity() != mpm::EnrichType::PotentialTip) + continue; + mpm::Index pid; + double max_pdstrain = 0; + for (auto particle_id : (*citr)->particles()) { + double pdstrain = map_particles_[particle_id]->state_variable("pdstrain"); + if (pdstrain > max_pdstrain) { + max_pdstrain = pdstrain; + pid = particle_id; + } + } + + if (max_pdstrain <= discontinuity_->maximum_pdstrain()) continue; + VectorDim normal; + bool propagation = + map_particles_[pid]->minimum_acoustic_tensor(normal, false); + if (propagation) { + (*citr)->assign_type_discontinuity(mpm::EnrichType::NextTip); + (*citr)->assign_normal_discontinuity(normal); + } + } + return; +} + +// Initialise the cells in node +template +void mpm::Mesh::add_cell_in_node() { + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + (*citr)->add_cell_in_node(); + } +} + +//! remove spurious potential tip element +template +void mpm::Mesh::spurious_potential_tip_element() { + + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + if ((*citr)->element_type_discontinuity() != mpm::EnrichType::PotentialTip) + continue; + + bool boundary = false; + bool potential_tip = false; + for (auto neighbour : (*citr)->neighbours()) { + if (cells_[neighbour]->element_type_discontinuity() != + mpm::EnrichType::NeighbourTip_2) + continue; + + if (cells_[neighbour]->nparticles() == 0) { + boundary = true; + } + if (cells_[neighbour]->product_levelset() < 0) potential_tip = true; + } + + if (potential_tip) continue; + (*citr)->assign_type_discontinuity(mpm::EnrichType::Crossed); + + continue; + if (!boundary) continue; + + // avoid the node located near the discontinuity + if ((*citr)->discontinuity_area() == 0) continue; + + std::vector coordinates; + (*citr)->compute_discontinuity_point(coordinates); + + for (int i = 0; i < coordinates.size(); i++) + discontinuity_->insert_particles(coordinates[i], cells_, map_cells_); + } +} + +// assign_node_enrich +template +void mpm::Mesh::assign_node_enrich(bool friction_coef_average, + bool enrich_all) { + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + if ((*citr)->element_type_discontinuity() != mpm::EnrichType::Crossed) + continue; + Eigen::Matrix friction_coef; + friction_coef(0, 0) = discontinuity_->friction_coef(); + + Eigen::Matrix cohesion; + cohesion(0, 0) = discontinuity_->cohesion(); + for (auto node : (*citr)->nodes()) { + if (node->discontinuity_enrich()) continue; + node->assign_discontinuity_enrich(true); + + if (!friction_coef_average) + node->assign_discontinuity_property(true, "friction_coef", + friction_coef, 0, 1); + node->assign_discontinuity_property(true, "cohesion", cohesion, 0, 1); + } + + // bool negative = false; + // bool positive = false; + // for(auto particle : (*citr)->particles()) + // { + // if(particles_[particle]->levelset_phi() > 0) + // positive = true; + // if(particles_[particle]->levelset_phi() < 0) + // negative = true; + // } + + // if(!negative || !positive) + // continue; + + (*citr)->assign_cohesion_area(); + } + + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + if ((*citr)->element_type_discontinuity() != mpm::EnrichType::PotentialTip) + continue; + for (auto node : (*citr)->nodes()) { + if (node->discontinuity_enrich()) + node->assign_discontinuity_enrich(false); + } + } + + if (!enrich_all) return; + + // double tolerance = 1e-16; + // for(auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr){ + // (*nitr)->assign_discontinuity_enrich(true); + // double positive_mass = (*nitr)->mass(mpm::ParticlePhase::Solid) + + // (*nitr)->discontinuity_property("mass_enrich", 1)(0, 0); double + // negative_mass = (*nitr)->mass(mpm::ParticlePhase::Solid) - + // (*nitr)->discontinuity_property("mass_enrich", 1)(0, 0); + // if(positive_mass < tolerance || negative_mass < tolerance) + // (*nitr)->assign_discontinuity_enrich(false); + // } + + for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { + (*nitr)->assign_discontinuity_enrich(true); + } +} + +// modify_node_enrich +template +void mpm::Mesh::update_node_enrich() { + + double tolerance = 1e-16; + for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { + double positive_mass = + (*nitr)->mass(mpm::ParticlePhase::Solid) + + (*nitr)->discontinuity_property("mass_enrich", 1)(0, 0); + double negative_mass = + (*nitr)->mass(mpm::ParticlePhase::Solid) - + (*nitr)->discontinuity_property("mass_enrich", 1)(0, 0); + if (positive_mass < tolerance || negative_mass < tolerance) + (*nitr)->assign_discontinuity_enrich(false); + } +} + +template +void mpm::Mesh::define_levelset() { + // for oso + std::ifstream in("stage1.txt"); + double stage[63126]; + for (int i = 0; i < 63126; ++i) { + in >> stage[i]; + if (stage[i] == 0) stage[i] = std::numeric_limits::min(); + } + int i = 0; + Eigen::Matrix phi_mls; + for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { + phi_mls(0, 0) = stage[i]; + i += 1; + + (*nitr)->assign_discontinuity_property(true, "levelset_phi", phi_mls, 0, 1); + } + for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { + + (*pitr)->map_levelset_to_particle(); + } + + return; + for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { + + auto cor = (*pitr)->coordinates(); + double phi; + // phi = 1 / std::sqrt(3) * cor[0] + 1 / std::sqrt(3) * cor[1] + + // 1 / std::sqrt(3) * cor[2] - 0.5 * std::sqrt(3); + + // phi = std::sqrt(std::pow(cor[0] - 35, 2) + std::pow(cor[1] - 30, 2) + + // std::pow(cor[2] - 0, 2)) - + // 25; + // slide body + phi = (0.5 * cor[0] + cor[2] - 0.5) / std::sqrt(0.25 + 1); + phi = cor[1] - 1.5; + (*pitr)->assign_levelsetphi(phi); + // case 4-2d + // if (cor[0] > 35 && cor[1] > 4 && cor[1] < 5) { + // phi = 5 - cor[1]; + // (*pitr)->assign_levelsetphi(phi); + // } + // if (cor[0] > 34 && cor[0] < 35 && cor[1] > 4) { + // if ((*pitr)->levelset_phi() < 0) continue; + // Eigen::Matrix e1, e2, p2n; + // e1 << 1 / std::sqrt(5), 2 / std::sqrt(5); + // e2 << 2 / std::sqrt(5), -1 / std::sqrt(5); + + // p2n << cor[0] - 35, cor[1] - 5; + // if (e2.dot(p2n) >= 0) + // phi = p2n.norm(); + // else if (e2.dot(p2n) < 0) { + // double dis1 = 5.25 - cor[1]; // 5.27118 + // double dis2 = std::abs(e1.dot(p2n)); + // if (dis1 < dis2) + // dis1 = (*pitr)->levelset_phi(); + // else + // dis1 = dis2; + // phi = dis1; + // } + // (*pitr)->assign_levelsetphi(phi); + // } + // case 5 + // if (cor[0] > 35 && cor[1] > 4 && cor[1] < 5) { + // phi = 5 - cor[1]; + // (*pitr)->assign_levelsetphi(phi); + // } + // if (cor[0] > 34 && cor[0] < 35 && cor[1] > 4) { + // if ((*pitr)->levelset_phi() != 0) continue; + // Eigen::Matrix e1, e2, p2n; + // e1 << 1 / std::sqrt(5), 2 / std::sqrt(5); + // e2 << 2 / std::sqrt(5), -1 / std::sqrt(5); + + // p2n << cor[0] - 35, cor[1] - 5; + // if (e2.dot(p2n) >= 0) + // phi = p2n.norm(); + // else if (e2.dot(p2n) < 0) { + // double dis1 = 5.25 - cor[1]; // 5.27118 + // double dis2 = std::abs(e1.dot(p2n)); + // phi = dis2; + // } + // (*pitr)->assign_levelsetphi(phi); + // } + // if ((*pitr)->material_id(mpm::ParticlePhase::Solid) == 4) + // (*pitr)->assign_levelsetphi(1.0); + // else if ((*pitr)->material_id(mpm::ParticlePhase::Solid) == 5) + // (*pitr)->assign_levelsetphi(-1); + // else if ((*pitr)->material_id(mpm::ParticlePhase::Solid) == 6) + // (*pitr)->assign_levelsetphi(-1); + } +} + +template +bool mpm::Mesh::initiation_discontinuity() { + bool status = false; + + mpm::Index pid; + double max_pdstrain = 0; + for (int i = 0; i < nparticles(); ++i) { + double pdstrain = map_particles_[i]->state_variable("pdstrain"); + // if(map_particles_[i]->coordinates()[1] < 0.2 || + // map_particles_[i]->coordinates()[1] > 0.8 || + // map_particles_[i]->coordinates()[0] > 0.05) continue; + + if (pdstrain > max_pdstrain) { + max_pdstrain = pdstrain; + pid = i; + } + } + + if (max_pdstrain <= discontinuity_->maximum_pdstrain()) return status; + VectorDim normal; + bool initiation = map_particles_[pid]->minimum_acoustic_tensor(normal, true); + + if (initiation) { + status = true; + auto cell_id = map_particles_[pid]->cell_id(); + map_cells_[cell_id]->assign_type_discontinuity(mpm::EnrichType::InitialTip); + map_cells_[cell_id]->assign_normal_discontinuity(normal); + auto center = map_cells_[cell_id]->centroid(); + + double d = 0; + + for (unsigned int i = 0; i < Tdim; i++) d -= center[i] * normal[i]; + + map_cells_[cell_id]->assign_normal_discontinuity(normal, d); + + map_cells_[cell_id]->compute_nodal_levelset_equation(); + + std::vector coordinates_dis; + map_cells_[cell_id]->compute_discontinuity_point(coordinates_dis); + + for (int i = 0; i < coordinates_dis.size(); i++) + discontinuity_->insert_particles(coordinates_dis[i], cells_, map_cells_); + // initialise neighbour cells + + auto neighbours = map_cells_[cell_id]->neighbours(); + for (auto neighbour : neighbours) { + if (map_cells_[neighbour]->nparticles() == 0) continue; + map_cells_[neighbour]->assign_type_discontinuity( + mpm::EnrichType::NeighbourTip_1); + map_cells_[neighbour]->assign_normal_discontinuity(normal, d); + map_cells_[neighbour]->compute_nodal_levelset_equation(); + if (map_cells_[neighbour]->product_levelset() >= 0) continue; + map_cells_[neighbour]->assign_type_discontinuity( + mpm::EnrichType::InitialTip); + + std::vector coordinates_dis_neigh; + map_cells_[neighbour]->compute_discontinuity_point(coordinates_dis_neigh); + + for (int i = 0; i < coordinates_dis_neigh.size(); i++) { + discontinuity_->insert_particles(coordinates_dis_neigh[i], cells_, + map_cells_); + } + } + // initialise level set values + + for (int i = 0; i < nparticles(); ++i) { + bool neighbour = true; + for (int j = 0; j < Tdim; j++) { + if (std::abs(center[j] - particles_[i]->coordinates()[j]) > + 3.5 * discontinuity_->width()) + neighbour = false; + } + if (!neighbour) continue; + double phi = particles_[i]->coordinates().dot(normal) + d; + particles_[i]->assign_levelsetphi(phi); + } + } + return status; +} + +template +void mpm::Mesh::modify_nodal_levelset_mls() { + Eigen::Matrix au; + Eigen::Matrix bu; + // double error_max = 0; + const double tolerance = std::numeric_limits::epsilon(); + + for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { + if ((*nitr)->discontinuity_property("levelset_phi", 1)(0, 0) == 0) continue; + double phi = 0; + + au.setZero(); + bu.setZero(); + + double particle_volume = 0; + double cell_volume = 0; + std::vector cell_list; + for (auto cell : (*nitr)->cells()) cell_list.push_back(cell); + + for (auto cell : cell_list) { + double length = discontinuity_->width(); + cell_volume += map_cells_[cell]->volume(); + for (auto particle : map_cells_[cell]->particles()) { + auto corp = map_particles_[particle]->coordinates(); + phi = map_particles_[particle]->levelset_phi(); + if (phi == 0) continue; + particle_volume += map_particles_[particle]->volume(); + // compute weight + double w[3]; + for (int i = 0; i < 3; i++) { + w[i] = 1 - std::abs(corp[i] - (*nitr)->coordinates()[i]) / length; + if (w[i] < 0) w[i] = 0; + } + + double weight = w[0] * w[1] * w[2]; + au(0, 0) += weight; + au(0, 1) += weight * corp[0]; + au(0, 2) += weight * corp[1]; + au(0, 3) += weight * corp[2]; + au(1, 0) += weight * corp[0]; + au(1, 1) += weight * corp[0] * corp[0]; + au(1, 2) += weight * corp[0] * corp[1]; + au(1, 3) += weight * corp[0] * corp[2]; + au(2, 0) += weight * corp[1]; + au(2, 1) += weight * corp[1] * corp[0]; + au(2, 2) += weight * corp[1] * corp[1]; + au(2, 3) += weight * corp[1] * corp[2]; + au(3, 0) += weight * corp[2]; + au(3, 1) += weight * corp[2] * corp[0]; + au(3, 2) += weight * corp[2] * corp[1]; + au(3, 3) += weight * corp[2] * corp[2]; + + bu(0, 0) += weight * phi; + bu(1, 0) += weight * phi * corp[0]; + bu(2, 0) += weight * phi * corp[1]; + bu(3, 0) += weight * phi * corp[2]; + } + } + + // find particles from neighbour cells + if (particle_volume < 0.5 * cell_volume || + std::abs(au.determinant()) < tolerance) { + au.setZero(); + bu.setZero(); + for (auto cells : (*nitr)->cells()) { + for (auto cell : map_cells_[cells]->neighbours()) { + std::vector::iterator ret; + ret = std::find(cell_list.begin(), cell_list.end(), cell); + if (ret != cell_list.end()) continue; + cell_list.push_back(cell); + } + } + + for (auto cell : cell_list) { + for (auto particle : map_cells_[cell]->particles()) { + auto corp = map_particles_[particle]->coordinates(); + phi = map_particles_[particle]->levelset_phi(); + if (phi == 0) continue; + // compute weight + double length = 2 * discontinuity_->width(); + double w[3]; + for (int i = 0; i < 3; i++) { + w[i] = 1 - std::abs(corp[i] - (*nitr)->coordinates()[i]) / length; + if (w[i] < 0) w[i] = 0; + } + double weight = w[0] * w[1] * w[2]; + + au(0, 0) += weight; + au(0, 1) += weight * corp[0]; + au(0, 2) += weight * corp[1]; + au(0, 3) += weight * corp[2]; + au(1, 0) += weight * corp[0]; + au(1, 1) += weight * corp[0] * corp[0]; + au(1, 2) += weight * corp[0] * corp[1]; + au(1, 3) += weight * corp[0] * corp[2]; + au(2, 0) += weight * corp[1]; + au(2, 1) += weight * corp[1] * corp[0]; + au(2, 2) += weight * corp[1] * corp[1]; + au(2, 3) += weight * corp[1] * corp[2]; + au(3, 0) += weight * corp[2]; + au(3, 1) += weight * corp[2] * corp[0]; + au(3, 2) += weight * corp[2] * corp[1]; + au(3, 3) += weight * corp[2] * corp[2]; + + bu(0, 0) += weight * phi; + bu(1, 0) += weight * phi * corp[0]; + bu(2, 0) += weight * phi * corp[1]; + bu(3, 0) += weight * phi * corp[2]; + } + } + } + + if (std::abs(au.determinant()) < tolerance) continue; + + Eigen::Vector4d coef; + coef.setZero(); + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) coef[i] += au.inverse()(i, j) * bu(j, 0); + + // compute the error + double error = 0; + int error_p = 0; + for (auto cell : cell_list) { + for (auto particle : map_cells_[cell]->particles()) { + auto corp = map_particles_[particle]->coordinates(); + phi = map_particles_[particle]->levelset_phi(); + if (phi == 0) continue; + double phi_mls = 1 * coef[0] + corp[0] * coef[1] + corp[1] * coef[2] + + corp[2] * coef[3]; + error += std::pow(phi_mls - phi, 2); + error_p += 1; + } + } + error = std::sqrt(error / error_p) / discontinuity_->width(); + + if (error > 1e-3) continue; + + Eigen::Matrix cor; + Eigen::Matrix phi_mls; + + cor << 1, (*nitr)->coordinates()[0], (*nitr)->coordinates()[1], + (*nitr)->coordinates()[2]; + phi_mls(0, 0) = cor.dot(coef); + + (*nitr)->assign_discontinuity_property(true, "levelset_phi", phi_mls, 0, 1); + } +} + +template +void mpm::Mesh::selfcontact_detection() { + + double contact_distance = discontinuity_->contact_distance(); + + for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { + if (!(*nitr)->discontinuity_enrich()) continue; + + auto cor = (*nitr)->coordinates(); + auto normal = (*nitr)->discontinuity_property( + "normal_unit_vectors_discontinuity", Tdim); + double dis_negative = -10 * contact_distance; + double dis_positive = 10 * contact_distance; + for (auto cell : (*nitr)->cells()) { + + for (auto particle : map_cells_[cell]->particles()) { + auto corp = map_particles_[particle]->coordinates(); + double phi = map_particles_[particle]->levelset_phi(); + + double dis = 0; + for (unsigned int i = 0; i < Tdim; i++) + dis += (corp[i] - cor[i]) * normal(i); + + if (phi > 0) dis_positive = dis < dis_positive ? dis : dis_positive; + if (phi < 0) dis_negative = dis > dis_negative ? dis : dis_negative; + } + } + Eigen::Matrix dis; + dis(0, 0) = dis_positive - dis_negative - contact_distance; + (*nitr)->assign_discontinuity_property(true, "contact_distance", dis, 0, 1); + } +} + +template +void mpm::Mesh::check_particle_levelset(bool particle_levelset) { + + for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { + if ((*pitr)->levelset_phi() != 0) continue; + + auto cell_id = (*pitr)->cell_id(); + + for (auto node : cells_[cell_id]->nodes()) { + if (!node->discontinuity_enrich()) continue; + + Eigen::Matrix au; + Eigen::Matrix bu; + au.setZero(); + bu.setZero(); + auto cell_list = cells_[cell_id]->neighbours(); + cell_list.insert(cell_id); + + for (auto cell : cell_list) { + for (auto particle : cells_[cell]->particles()) { + auto corp = map_particles_[particle]->coordinates(); + double phi = map_particles_[particle]->levelset_phi(); + if (phi == 0) continue; + // compute weight + double length = 2.0 * discontinuity_->width(); + double w[3]; + for (int i = 0; i < 3; i++) { + w[i] = 1 - std::abs(corp[i] - (*pitr)->coordinates()[i]) / length; + if (w[i] < 0) w[i] = 0; + } + double weight = w[0] * w[1] * w[2]; + + au(0, 0) += weight; + au(0, 1) += weight * corp[0]; + au(0, 2) += weight * corp[1]; + au(0, 3) += weight * corp[2]; + au(1, 0) += weight * corp[0]; + au(1, 1) += weight * corp[0] * corp[0]; + au(1, 2) += weight * corp[0] * corp[1]; + au(1, 3) += weight * corp[0] * corp[2]; + au(2, 0) += weight * corp[1]; + au(2, 1) += weight * corp[1] * corp[0]; + au(2, 2) += weight * corp[1] * corp[1]; + au(2, 3) += weight * corp[1] * corp[2]; + au(3, 0) += weight * corp[2]; + au(3, 1) += weight * corp[2] * corp[0]; + au(3, 2) += weight * corp[2] * corp[1]; + au(3, 3) += weight * corp[2] * corp[2]; + + bu(0, 0) += weight * phi; + bu(1, 0) += weight * phi * corp[0]; + bu(2, 0) += weight * phi * corp[1]; + bu(3, 0) += weight * phi * corp[2]; + } + } + + const double tolerance = std::numeric_limits::epsilon(); + + if (std::abs(au.determinant()) < tolerance) { + (*pitr)->map_levelset_to_particle(); + continue; + } + + Eigen::Vector4d coef; + coef.setZero(); + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) coef[i] += au.inverse()(i, j) * bu(j, 0); + + // compute the error + // double error = 0; + // int error_p = 0; + // for (auto cell : cell_list) { + // for (auto particle : map_cells_[cell]->particles()) { + // auto corp = map_particles_[particle]->coordinates(); + // double phi = map_particles_[particle]->levelset_phi(); + // if (phi == 0) continue; + // double phi_mls = 1 * coef[0] + corp[0] * coef[1] + corp[1] * + // coef[2] + + // corp[2] * coef[3]; + // error += std::pow(phi_mls - phi, 2); + // error_p += 1; + // } + // } + // error = std::sqrt(error / error_p) / discontinuity_->width(); + + // if (error > 1e-3) { + // (*pitr)->map_levelset_to_particle(); + // continue; + // } + + Eigen::Vector4d cor; + cor << 1, (*pitr)->coordinates()[0], (*pitr)->coordinates()[1], + (*pitr)->coordinates()[2]; + double phi = cor.dot(coef); + + (*pitr)->assign_levelsetphi(phi); + + break; + } + } + if (particle_levelset) return; + for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { + if ((*pitr)->levelset_phi() == 0) continue; + auto cell_id = (*pitr)->cell_id(); + + if (cells_[cell_id]->element_type_discontinuity() == + mpm::EnrichType::Regular || + cells_[cell_id]->element_type_discontinuity() == + mpm::EnrichType::NeighbourTip_3) + (*pitr)->assign_levelsetphi(0); + } +} + +template +void mpm::Mesh::output_celltype(int step) { + std::ofstream test("cell_type.txt", std::ios::app); + + test << step << ":" << std::endl; + for (int i = 0; i < cells_.size(); i++) { + auto type = cells_[i]->element_type_discontinuity(); + if (type == 1) + test << "o "; + else if (type == 2) + test << "\\ "; + else if (type == 3) + test << "^ "; + else if (type == 4) + test << "1 "; + else if (type == 5) + test << "2 "; + else if (type == 6) + test << "* "; + else + test << type << " "; + if (((i + 1) % 90) == 0) test << std::endl; + } + test << std::endl; + + std::ofstream testnormal("node_normal.txt", std::ios::app); + testnormal << step << ":" << std::endl; + for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { + if (!(*nitr)->discontinuity_enrich()) continue; + + if ((*nitr)->coordinates()[0] < 35) continue; + + Eigen::Matrix normal = (*nitr)->discontinuity_property( + "normal_unit_vectors_discontinuity", Tdim); + testnormal << (*nitr)->coordinates()[0] << "\t" << (*nitr)->coordinates()[1] + << "\t" << normal[0] << "\t" << normal[1] << "\t" << normal[2] + << std::endl; + } +} From b9d63856355d556444431344c2246e47a0954dcd Mon Sep 17 00:00:00 2001 From: yliang-sn Date: Tue, 19 Oct 2021 17:13:40 -0700 Subject: [PATCH 67/91] find the cells at nodes --- include/cell.h | 3 - include/cell.tcc | 8 - include/mesh.h | 2 +- include/mesh.tcc | 30 ++-- include/mesh_xmpm.tcc | 242 ++++++++++++------------------ include/solvers/mpm_base.h | 2 + include/solvers/mpm_base.tcc | 3 +- include/solvers/xmpm_explicit.h | 2 + include/solvers/xmpm_explicit.tcc | 4 +- 9 files changed, 122 insertions(+), 174 deletions(-) diff --git a/include/cell.h b/include/cell.h index 984bb4cbe..1fc322d8c 100644 --- a/include/cell.h +++ b/include/cell.h @@ -269,9 +269,6 @@ class Cell { // product of the nodal level set value double product_levelset(); - // Initialise the cells in node - void add_cell_in_node(); - // return the constant value of the discontinuity plane double d_discontinuity() { return this->discontinuity_element_->d_discontinuity(); diff --git a/include/cell.tcc b/include/cell.tcc index 2ac877160..3a6fb08bd 100644 --- a/include/cell.tcc +++ b/include/cell.tcc @@ -1008,14 +1008,6 @@ Eigen::Matrix mpm::Cell::compute_gradient_levelset() { return gradient; } -//! assign nodal normal vector -template -void mpm::Cell::add_cell_in_node() { - for (unsigned i = 0; i < nodes_.size(); ++i) { - nodes_[i]->add_cell_id(id_); - } -} - template void mpm::Cell::compute_plane_discontinuity(bool enrich) { int enriched_node = 0; diff --git a/include/mesh.h b/include/mesh.h index e2e52fcb6..97473f53b 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -181,7 +181,7 @@ class Mesh { void iterate_over_cells(Toper oper); //! Find cell neighbours - void find_cell_neighbours(); + void find_cell_neighbours(bool assign_to_nodes = false); //! Find global nparticles across MPI ranks / cell void find_nglobal_particles_cells(); diff --git a/include/mesh.tcc b/include/mesh.tcc index 2dae6bc2e..5945cccb9 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -266,7 +266,7 @@ void mpm::Mesh::iterate_over_cells(Toper oper) { //! Create cells from node lists template -void mpm::Mesh::find_cell_neighbours() { +void mpm::Mesh::find_cell_neighbours(bool assign_to_nodes) { // Initialize and compute node cell map tsl::robin_map> node_cell_map; for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { @@ -275,14 +275,26 @@ void mpm::Mesh::find_cell_neighbours() { for (auto id : (*citr)->nodes_id()) node_cell_map[id].insert(cell_id); } -#pragma omp parallel for schedule(runtime) - for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { - // Iterate over each node in current cell - for (auto id : (*citr)->nodes_id()) { - auto cell_id = (*citr)->id(); - // Get the cells associated with each node - for (auto neighbour_id : node_cell_map[id]) - if (neighbour_id != cell_id) (*citr)->add_neighbour(neighbour_id); +#pragma omp parallel + { + if (assign_to_nodes) { +#pragma for schedule(runtime) + for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { + auto node_id = (*nitr)->id(); + for (auto neighbour_id : node_cell_map[node_id]) + (*nitr)->add_cell_id(neighbour_id); + } + } + +#pragma for schedule(runtime) + for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + // Iterate over each node in current cell + for (auto id : (*citr)->nodes_id()) { + auto cell_id = (*citr)->id(); + // Get the cells associated with each node + for (auto neighbour_id : node_cell_map[id]) + if (neighbour_id != cell_id) (*citr)->add_neighbour(neighbour_id); + } } } } diff --git a/include/mesh_xmpm.tcc b/include/mesh_xmpm.tcc index 53ef07843..88fd0d73d 100644 --- a/include/mesh_xmpm.tcc +++ b/include/mesh_xmpm.tcc @@ -575,14 +575,6 @@ void mpm::Mesh::next_tip_element_discontinuity() { return; } -// Initialise the cells in node -template -void mpm::Mesh::add_cell_in_node() { - for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { - (*citr)->add_cell_in_node(); - } -} - //! remove spurious potential tip element template void mpm::Mesh::spurious_potential_tip_element() { @@ -643,19 +635,6 @@ void mpm::Mesh::assign_node_enrich(bool friction_coef_average, node->assign_discontinuity_property(true, "cohesion", cohesion, 0, 1); } - // bool negative = false; - // bool positive = false; - // for(auto particle : (*citr)->particles()) - // { - // if(particles_[particle]->levelset_phi() > 0) - // positive = true; - // if(particles_[particle]->levelset_phi() < 0) - // negative = true; - // } - - // if(!negative || !positive) - // continue; - (*citr)->assign_cohesion_area(); } @@ -670,17 +649,6 @@ void mpm::Mesh::assign_node_enrich(bool friction_coef_average, if (!enrich_all) return; - // double tolerance = 1e-16; - // for(auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr){ - // (*nitr)->assign_discontinuity_enrich(true); - // double positive_mass = (*nitr)->mass(mpm::ParticlePhase::Solid) + - // (*nitr)->discontinuity_property("mass_enrich", 1)(0, 0); double - // negative_mass = (*nitr)->mass(mpm::ParticlePhase::Solid) - - // (*nitr)->discontinuity_property("mass_enrich", 1)(0, 0); - // if(positive_mass < tolerance || negative_mass < tolerance) - // (*nitr)->assign_discontinuity_enrich(false); - // } - for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { (*nitr)->assign_discontinuity_enrich(true); } @@ -703,98 +671,6 @@ void mpm::Mesh::update_node_enrich() { } } -template -void mpm::Mesh::define_levelset() { - // for oso - std::ifstream in("stage1.txt"); - double stage[63126]; - for (int i = 0; i < 63126; ++i) { - in >> stage[i]; - if (stage[i] == 0) stage[i] = std::numeric_limits::min(); - } - int i = 0; - Eigen::Matrix phi_mls; - for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { - phi_mls(0, 0) = stage[i]; - i += 1; - - (*nitr)->assign_discontinuity_property(true, "levelset_phi", phi_mls, 0, 1); - } - for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { - - (*pitr)->map_levelset_to_particle(); - } - - return; - for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { - - auto cor = (*pitr)->coordinates(); - double phi; - // phi = 1 / std::sqrt(3) * cor[0] + 1 / std::sqrt(3) * cor[1] + - // 1 / std::sqrt(3) * cor[2] - 0.5 * std::sqrt(3); - - // phi = std::sqrt(std::pow(cor[0] - 35, 2) + std::pow(cor[1] - 30, 2) + - // std::pow(cor[2] - 0, 2)) - - // 25; - // slide body - phi = (0.5 * cor[0] + cor[2] - 0.5) / std::sqrt(0.25 + 1); - phi = cor[1] - 1.5; - (*pitr)->assign_levelsetphi(phi); - // case 4-2d - // if (cor[0] > 35 && cor[1] > 4 && cor[1] < 5) { - // phi = 5 - cor[1]; - // (*pitr)->assign_levelsetphi(phi); - // } - // if (cor[0] > 34 && cor[0] < 35 && cor[1] > 4) { - // if ((*pitr)->levelset_phi() < 0) continue; - // Eigen::Matrix e1, e2, p2n; - // e1 << 1 / std::sqrt(5), 2 / std::sqrt(5); - // e2 << 2 / std::sqrt(5), -1 / std::sqrt(5); - - // p2n << cor[0] - 35, cor[1] - 5; - // if (e2.dot(p2n) >= 0) - // phi = p2n.norm(); - // else if (e2.dot(p2n) < 0) { - // double dis1 = 5.25 - cor[1]; // 5.27118 - // double dis2 = std::abs(e1.dot(p2n)); - // if (dis1 < dis2) - // dis1 = (*pitr)->levelset_phi(); - // else - // dis1 = dis2; - // phi = dis1; - // } - // (*pitr)->assign_levelsetphi(phi); - // } - // case 5 - // if (cor[0] > 35 && cor[1] > 4 && cor[1] < 5) { - // phi = 5 - cor[1]; - // (*pitr)->assign_levelsetphi(phi); - // } - // if (cor[0] > 34 && cor[0] < 35 && cor[1] > 4) { - // if ((*pitr)->levelset_phi() != 0) continue; - // Eigen::Matrix e1, e2, p2n; - // e1 << 1 / std::sqrt(5), 2 / std::sqrt(5); - // e2 << 2 / std::sqrt(5), -1 / std::sqrt(5); - - // p2n << cor[0] - 35, cor[1] - 5; - // if (e2.dot(p2n) >= 0) - // phi = p2n.norm(); - // else if (e2.dot(p2n) < 0) { - // double dis1 = 5.25 - cor[1]; // 5.27118 - // double dis2 = std::abs(e1.dot(p2n)); - // phi = dis2; - // } - // (*pitr)->assign_levelsetphi(phi); - // } - // if ((*pitr)->material_id(mpm::ParticlePhase::Solid) == 4) - // (*pitr)->assign_levelsetphi(1.0); - // else if ((*pitr)->material_id(mpm::ParticlePhase::Solid) == 5) - // (*pitr)->assign_levelsetphi(-1); - // else if ((*pitr)->material_id(mpm::ParticlePhase::Solid) == 6) - // (*pitr)->assign_levelsetphi(-1); - } -} - template bool mpm::Mesh::initiation_discontinuity() { bool status = false; @@ -803,9 +679,6 @@ bool mpm::Mesh::initiation_discontinuity() { double max_pdstrain = 0; for (int i = 0; i < nparticles(); ++i) { double pdstrain = map_particles_[i]->state_variable("pdstrain"); - // if(map_particles_[i]->coordinates()[1] < 0.2 || - // map_particles_[i]->coordinates()[1] > 0.8 || - // map_particles_[i]->coordinates()[0] > 0.05) continue; if (pdstrain > max_pdstrain) { max_pdstrain = pdstrain; @@ -1124,28 +997,6 @@ void mpm::Mesh::check_particle_levelset(bool particle_levelset) { for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) coef[i] += au.inverse()(i, j) * bu(j, 0); - // compute the error - // double error = 0; - // int error_p = 0; - // for (auto cell : cell_list) { - // for (auto particle : map_cells_[cell]->particles()) { - // auto corp = map_particles_[particle]->coordinates(); - // double phi = map_particles_[particle]->levelset_phi(); - // if (phi == 0) continue; - // double phi_mls = 1 * coef[0] + corp[0] * coef[1] + corp[1] * - // coef[2] + - // corp[2] * coef[3]; - // error += std::pow(phi_mls - phi, 2); - // error_p += 1; - // } - // } - // error = std::sqrt(error / error_p) / discontinuity_->width(); - - // if (error > 1e-3) { - // (*pitr)->map_levelset_to_particle(); - // continue; - // } - Eigen::Vector4d cor; cor << 1, (*pitr)->coordinates()[0], (*pitr)->coordinates()[1], (*pitr)->coordinates()[2]; @@ -1169,6 +1020,7 @@ void mpm::Mesh::check_particle_levelset(bool particle_levelset) { } } +// code for debugging added by yliang template void mpm::Mesh::output_celltype(int step) { std::ofstream test("cell_type.txt", std::ios::app); @@ -1208,3 +1060,95 @@ void mpm::Mesh::output_celltype(int step) { << std::endl; } } + +template +void mpm::Mesh::define_levelset() { + // for oso + std::ifstream in("stage1.txt"); + double stage[63126]; + for (int i = 0; i < 63126; ++i) { + in >> stage[i]; + if (stage[i] == 0) stage[i] = std::numeric_limits::min(); + } + int i = 0; + Eigen::Matrix phi_mls; + for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) { + phi_mls(0, 0) = stage[i]; + i += 1; + + (*nitr)->assign_discontinuity_property(true, "levelset_phi", phi_mls, 0, 1); + } + for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { + + (*pitr)->map_levelset_to_particle(); + } + + return; + for (auto pitr = particles_.cbegin(); pitr != particles_.cend(); ++pitr) { + + auto cor = (*pitr)->coordinates(); + double phi; + // phi = 1 / std::sqrt(3) * cor[0] + 1 / std::sqrt(3) * cor[1] + + // 1 / std::sqrt(3) * cor[2] - 0.5 * std::sqrt(3); + + // phi = std::sqrt(std::pow(cor[0] - 35, 2) + std::pow(cor[1] - 30, 2) + + // std::pow(cor[2] - 0, 2)) - + // 25; + // slide body + phi = (0.5 * cor[0] + cor[2] - 0.5) / std::sqrt(0.25 + 1); + phi = cor[1] - 1.5; + (*pitr)->assign_levelsetphi(phi); + // case 4-2d + // if (cor[0] > 35 && cor[1] > 4 && cor[1] < 5) { + // phi = 5 - cor[1]; + // (*pitr)->assign_levelsetphi(phi); + // } + // if (cor[0] > 34 && cor[0] < 35 && cor[1] > 4) { + // if ((*pitr)->levelset_phi() < 0) continue; + // Eigen::Matrix e1, e2, p2n; + // e1 << 1 / std::sqrt(5), 2 / std::sqrt(5); + // e2 << 2 / std::sqrt(5), -1 / std::sqrt(5); + + // p2n << cor[0] - 35, cor[1] - 5; + // if (e2.dot(p2n) >= 0) + // phi = p2n.norm(); + // else if (e2.dot(p2n) < 0) { + // double dis1 = 5.25 - cor[1]; // 5.27118 + // double dis2 = std::abs(e1.dot(p2n)); + // if (dis1 < dis2) + // dis1 = (*pitr)->levelset_phi(); + // else + // dis1 = dis2; + // phi = dis1; + // } + // (*pitr)->assign_levelsetphi(phi); + // } + // case 5 + // if (cor[0] > 35 && cor[1] > 4 && cor[1] < 5) { + // phi = 5 - cor[1]; + // (*pitr)->assign_levelsetphi(phi); + // } + // if (cor[0] > 34 && cor[0] < 35 && cor[1] > 4) { + // if ((*pitr)->levelset_phi() != 0) continue; + // Eigen::Matrix e1, e2, p2n; + // e1 << 1 / std::sqrt(5), 2 / std::sqrt(5); + // e2 << 2 / std::sqrt(5), -1 / std::sqrt(5); + + // p2n << cor[0] - 35, cor[1] - 5; + // if (e2.dot(p2n) >= 0) + // phi = p2n.norm(); + // else if (e2.dot(p2n) < 0) { + // double dis1 = 5.25 - cor[1]; // 5.27118 + // double dis2 = std::abs(e1.dot(p2n)); + // phi = dis2; + // } + // (*pitr)->assign_levelsetphi(phi); + // } + // if ((*pitr)->material_id(mpm::ParticlePhase::Solid) == 4) + // (*pitr)->assign_levelsetphi(1.0); + // else if ((*pitr)->material_id(mpm::ParticlePhase::Solid) == 5) + // (*pitr)->assign_levelsetphi(-1); + // else if ((*pitr)->material_id(mpm::ParticlePhase::Solid) == 6) + // (*pitr)->assign_levelsetphi(-1); + } +} \ No newline at end of file diff --git a/include/solvers/mpm_base.h b/include/solvers/mpm_base.h index 7bd7d74a7..de816db87 100644 --- a/include/solvers/mpm_base.h +++ b/include/solvers/mpm_base.h @@ -217,6 +217,8 @@ class MPMBase : public MPM { double damping_factor_{0.}; //! Locate particles bool locate_particles_{true}; + //! XMPM Solver + bool xmpm_{false}; #ifdef USE_GRAPH_PARTITIONING // graph pass the address of the container of cell diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index 34bdd26f6..0c61d782a 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -262,7 +262,8 @@ void mpm::MPMBase::initialise_mesh() { "mpm::base::init_mesh(): Addition of cells to mesh failed"); // Compute cell neighbours - mesh_->find_cell_neighbours(); + bool assign_to_nodes = xmpm_; + mesh_->find_cell_neighbours(assign_to_nodes); // Read and assign cell sets this->cell_entity_sets(mesh_props, check_duplicates); diff --git a/include/solvers/xmpm_explicit.h b/include/solvers/xmpm_explicit.h index 064a725a9..4d8f95b5a 100644 --- a/include/solvers/xmpm_explicit.h +++ b/include/solvers/xmpm_explicit.h @@ -62,6 +62,8 @@ class XMPMExplicit : public MPMBase { using mpm::MPMBase::stress_update_; //! Interface scheme using mpm::MPMBase::contact_; + //! xmpm solver + using mpm::MPMBase::xmpm_; #ifdef USE_GRAPH_PARTITIONING //! Graph diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index e67a4d6a6..4ad2bff46 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -2,6 +2,7 @@ template mpm::XMPMExplicit::XMPMExplicit(const std::shared_ptr& io) : mpm::MPMBase(io) { + this->xmpm_ = true; //! Logger console_ = spdlog::get("XMPMExplicit"); //! Stress update @@ -77,9 +78,6 @@ bool mpm::XMPMExplicit::solve() { // Initialise particles if (!resume) this->initialise_particles(); - // Initialise the cells in node - mesh_->add_cell_in_node(); - // Create nodal properties if (interface_) mesh_->create_nodal_properties(); From 26291c8598ac2b6221c33221ccc84a14f6833aae Mon Sep 17 00:00:00 2001 From: yliang-sn Date: Tue, 19 Oct 2021 17:30:59 -0700 Subject: [PATCH 68/91] make a separate file cell_xmpm.tcc --- include/cell.h | 1 + include/cell.tcc | 336 ------------------------------------------ include/cell_xmpm.tcc | 335 +++++++++++++++++++++++++++++++++++++++++ include/mesh_xmpm.tcc | 1 + 4 files changed, 337 insertions(+), 336 deletions(-) create mode 100644 include/cell_xmpm.tcc diff --git a/include/cell.h b/include/cell.h index 1fc322d8c..6e66ea655 100644 --- a/include/cell.h +++ b/include/cell.h @@ -341,5 +341,6 @@ class Cell { } // namespace mpm #include "cell.tcc" +#include "cell_xmpm.tcc" #endif // MPM_CELL_H_ diff --git a/include/cell.tcc b/include/cell.tcc index 3a6fb08bd..1581a1193 100644 --- a/include/cell.tcc +++ b/include/cell.tcc @@ -867,340 +867,4 @@ inline unsigned mpm::Cell::rank() const { template inline unsigned mpm::Cell::previous_mpirank() const { return this->previous_mpirank_; -} - -//! potential tip element -template -void mpm::Cell::potential_tip_element() { - if (this->discontinuity_element_ == nullptr) return; - if (this->discontinuity_element_->element_type() != - mpm::EnrichType::NeighbourTip_1) - return; - if (this->nparticles() == 0) return; - - if (product_levelset() < 0) - this->discontinuity_element_->assign_element_type( - mpm::EnrichType::PotentialTip); - - // for (unsigned i = 0; i < nodes_.size(); ++i) { - // if (nodes_[i]->discontinuity_enrich()) - // nodes_[i]->assign_discontinuity_enrich(false); - // } -} - -//! determine tip element -template -void mpm::Cell::tip_element() { - if (this->discontinuity_element_ == nullptr) return; - if (this->discontinuity_element_->element_type() != mpm::EnrichType::Crossed) - return; - - for (unsigned i = 0; i < nodes_.size(); ++i) { - if (nodes_[i]->discontinuity_enrich()) continue; - this->discontinuity_element_->assign_element_type(mpm::EnrichType::Tip); - } -} - -//! potential tip element -template -void mpm::Cell::compute_discontinuity_point( - std::vector& coordinates) { - - // if (this->discontinuity_element_->area() == 0) - // compute_area_discontinuity(); - std::vector> intersections_list; - - Eigen::Matrix center = - this->discontinuity_element_->cohesion_cor(); - int index_area[6][5] = {{0, 1, 2, 3, 0}, {0, 1, 5, 4, 0}, {1, 2, 6, 5, 1}, - {3, 2, 6, 7, 3}, {0, 3, 7, 4, 0}, {4, 5, 6, 7, 4}}; - for (int i = 0; i < 6; i++) { - std::vector> intersections; - for (int j = 0; j < 4; j++) { - double phi[2]; - phi[0] = nodes_[index_area[i][j]]->discontinuity_property("levelset_phi", - 1)(0, 0); - phi[1] = nodes_[index_area[i][j + 1]]->discontinuity_property( - "levelset_phi", 1)(0, 0); - if (phi[0] * phi[1] >= 0) continue; - Eigen::Matrix intersection; - Eigen::Matrix cor0 = - nodes_[index_area[i][j]]->coordinates(); - Eigen::Matrix cor1 = - nodes_[index_area[i][j + 1]]->coordinates(); - intersection = cor0 * std::abs(phi[1] / ((phi[1] - phi[0]))) + - cor1 * std::abs(phi[0] / ((phi[1] - phi[0]))); - - intersections.push_back(intersection); - intersections_list.push_back(intersection); - } - // if (intersections.size() != 2) continue; - // if (this->discontinuity_element_->area() == 0) continue; - // Eigen::Matrix cor = - // 1.0 / 3 * (intersections[0] + intersections[1] + center); - // double length = (cor - center).norm(); - // if (length < 0.25 * mean_length_) continue; - // coordinates.push_back(cor); - } - - // if (this->discontinuity_element_->area() != 0) { - // coordinates.push_back(this->discontinuity_element_->cohesion_cor()); - // } else { - // if (intersections_list.size() < 3) return; - - // Eigen::Matrix cor; - // cor.setZero(); - // for (int i = 0; i < intersections_list.size(); i++) - // cor += 1.0 / intersections_list.size() * intersections_list[i]; - // coordinates.push_back(cor); - // } - if (intersections_list.size() < 3) return; - - Eigen::Matrix cor; - cor.setZero(); - for (int i = 0; i < intersections_list.size(); i++) - cor += 1.0 / intersections_list.size() * intersections_list[i]; - coordinates.push_back(cor); -} - -//! assign the normal direction of the discontinuity in the cell -template -void mpm::Cell::assign_normal_discontinuity(VectorDim normal) { - this->discontinuity_element_->assign_normal_discontinuity(normal); -} - -//! assign the normal direction of the discontinuity in the cell -template -void mpm::Cell::assign_normal_discontinuity(VectorDim normal, double d) { - this->discontinuity_element_->assign_normal_discontinuity(normal); - this->discontinuity_element_->assign_d(d); -} - -//! compute normal vector of discontinuity by the nodal level set values -template -void mpm::Cell::compute_normal_vector_discontinuity() { - VectorDim normal; - normal.setZero(); - // determine the discontinuity plane by the enriched nodes - for (unsigned i = 0; i < nodes_.size(); ++i) { - double phi = nodes_[i]->discontinuity_property("levelset_phi", 1)(0, 0); - for (unsigned int j = 0; j < Tdim; j++) { - normal[j] += phi * dn_dx_centroid_(i, j); - } - } - normal.normalize(); - this->discontinuity_element_->assign_normal_discontinuity(normal); -} - -//! compute gradient of the nodal level set values -template -Eigen::Matrix mpm::Cell::compute_gradient_levelset() { - VectorDim gradient; - gradient.setZero(); - // determine the discontinuity plane by the enriched nodes - for (unsigned i = 0; i < nodes_.size(); ++i) { - double phi = nodes_[i]->discontinuity_property("levelset_phi", 1)(0, 0); - for (unsigned int j = 0; j < Tdim; j++) { - gradient[j] += phi * dn_dx_centroid_(i, j); - } - } - - return gradient; -} - -template -void mpm::Cell::compute_plane_discontinuity(bool enrich) { - int enriched_node = 0; - auto normal = discontinuity_element_->normal_discontinuity(); - double dis = 0; - // determine the discontinuity plane by the enriched nodes - for (unsigned i = 0; i < nodes_.size(); ++i) { - if (enrich) { - if (!nodes_[i]->discontinuity_enrich()) continue; - } - enriched_node++; - auto node_coordinate = nodes_[i]->coordinates(); - for (unsigned int j = 0; j < Tdim; j++) - dis -= node_coordinate[j] * normal[j]; - dis = nodes_[i]->discontinuity_property("levelset_phi", 1)(0, 0) + dis; - } - // update the level set values of the unenriched nodes - dis = dis / enriched_node; - this->discontinuity_element_->assign_d(dis); -} - -// product of the nodal level set value -template -double mpm::Cell::product_levelset() { - double levelset_max = -std::numeric_limits::max(); - double levelset_min = std::numeric_limits::max(); - for (unsigned i = 0; i < nodes_.size(); ++i) { - - double levelset = - nodes_[i]->discontinuity_property("levelset_phi", 1)(0, 0); - levelset_max = levelset > levelset_max ? levelset : levelset_max; - levelset_min = levelset < levelset_min ? levelset : levelset_min; - } - return levelset_max * levelset_min; -} - -template -void mpm::Cell::determine_crossed() { - - // if (this->nparticles() == 0) return; - - double max_phi = -1e15, min_phi = 1e15; - - for (unsigned i = 0; i < nodes_.size(); ++i) { - double phi = nodes_[i]->discontinuity_property("levelset_phi", 1)(0, 0); - if (phi > max_phi) max_phi = phi; - if (phi < min_phi) min_phi = phi; - } - - this->assign_type_discontinuity(mpm::EnrichType::Regular); - if (max_phi * min_phi >= 0) return; - - this->assign_type_discontinuity(mpm::EnrichType::Crossed); -} - -template -void mpm::Cell::compute_nodal_levelset_equation() { - for (unsigned i = 0; i < nodes_.size(); ++i) { - auto coor = nodes_[i]->coordinates(); - double phi = 0; - for (unsigned int j = 0; j < Tdim; j++) - phi += coor[j] * this->discontinuity_element_->normal_discontinuity()[j]; - phi += this->discontinuity_element_->d_discontinuity(); - Eigen::Matrix phi_matrix; - phi_matrix(0, 0) = phi; - nodes_[i]->assign_discontinuity_property(true, "levelset_phi", phi_matrix, - 0, 1); - } -} - -template -void mpm::Cell::compute_area_discontinuity() { - - // if(this->id() == 1671) - // int a = 0; - - if (this->discontinuity_element_ == nullptr) return; - if (this->discontinuity_element_->element_type() != mpm::EnrichType::Crossed) - return; - // compute the level set values - Eigen::VectorXd phi_list(nnodes()); - phi_list.setZero(); - - auto normal = this->discontinuity_element_->normal_discontinuity(); - auto d = this->discontinuity_element_->d_discontinuity(); - for (int i = 0; i < nodes_.size(); ++i) { - phi_list[i] = normal.dot(nodes_[i]->coordinates()) + d; - } - // determine the intersections - std::vector> intersections; - - // node id of the 12 edges of one cell - int index_line[13][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 0}, {0, 4}, {1, 5}, - {2, 6}, {3, 7}, {4, 5}, {5, 6}, {6, 7}, {7, 4}}; - for (int i = 0; i < 12; ++i) { - if (phi_list[index_line[i][0]] * phi_list[index_line[i][1]] >= 0) continue; - - Eigen::Matrix intersection; - Eigen::Matrix cor0 = - nodes_[index_line[i][0]]->coordinates(); - Eigen::Matrix cor1 = - nodes_[index_line[i][1]]->coordinates(); - intersection = cor0 * std::abs(phi_list[index_line[i][1]] / - ((phi_list[index_line[i][1]] - - phi_list[index_line[i][0]]))) + - cor1 * std::abs(phi_list[index_line[i][0]] / - ((phi_list[index_line[i][1]] - - phi_list[index_line[i][0]]))); - - intersections.push_back(intersection); - } - if (intersections.size() < 3) return; - Eigen::Matrix average_cor; - average_cor.setZero(); - for (int i = 0; i < intersections.size(); ++i) - average_cor += intersections[i]; - - average_cor /= intersections.size(); - - // compute angle - // obtain e1 e2 of the local coordinate system - Eigen::Matrix e1 = - (intersections[0] - average_cor).normalized(); - Eigen::Matrix e2 = normal.cross(e1).normalized(); - // the angle and the order of the intersections - Eigen::VectorXd angles(intersections.size()); - angles.setZero(); - Eigen::VectorXd orders(intersections.size()); - orders.setZero(); - - for (int i = 1; i < intersections.size(); ++i) { - double costh = (intersections[i] - average_cor).normalized().dot(e1); - double sinth = (intersections[i] - average_cor).normalized().dot(e2); - - costh = costh > 1 ? 1 : costh; - costh = costh < -1 ? -1 : costh; - - double theta = std::acos(costh); - - if (sinth < 0) theta = 2 * M_PI - theta; - - angles[i] = theta; - } - // compute orders - for (int i = 1; i < intersections.size(); ++i) { - for (int j = 0; j < intersections.size(); j++) { - if (angles[i] > angles[j]) orders[i] += 1; - } - } - - // exchange intersections - auto intersections_copy = intersections; - for (int i = 1; i < intersections.size(); ++i) - intersections[orders[i]] = intersections_copy[i]; - - // compute area - double area = 0.0; - Eigen::Matrix subcenters; - subcenters.setZero(); - for (int i = 0; i < intersections.size() - 2; ++i) { - // the coordinates of the triangle - Eigen::Matrix cor0 = intersections[0]; - Eigen::Matrix cor1 = intersections[i + 1]; - Eigen::Matrix cor2 = intersections[i + 2]; - double subarea = - std::abs(0.5 * (cor1 - cor0).cross(cor2 - cor0).dot(normal)); - area += subarea; - subcenters += subarea * 1 / 3 * (cor0 + cor1 + cor2); - } - subcenters = subcenters / area; - - this->discontinuity_element_->assign_area(area); - this->discontinuity_element_->assign_cohesion_cor(subcenters); -} - -template -void mpm::Cell::assign_cohesion_area() { - - auto centers = this->discontinuity_element_->cohesion_cor(); - auto area = this->discontinuity_element_->area(); - - const Eigen::Matrix zeros = - Eigen::Matrix::Zero(); - Eigen::Matrix xi; - - if (!this->is_point_in_cell(centers, &xi)) return; - - auto shapefn = element_->shapefn(xi, zeros, zeros); - Eigen::Matrix node_area; - for (int i = 0; i < nodes_.size(); i++) { - - node_area(0, 0) = shapefn[i] * area; - nodes_[i]->update_discontinuity_property(true, "cohesion_area", node_area, - 0, 1); - } } \ No newline at end of file diff --git a/include/cell_xmpm.tcc b/include/cell_xmpm.tcc new file mode 100644 index 000000000..719732d23 --- /dev/null +++ b/include/cell_xmpm.tcc @@ -0,0 +1,335 @@ +//! potential tip element +template +void mpm::Cell::potential_tip_element() { + if (this->discontinuity_element_ == nullptr) return; + if (this->discontinuity_element_->element_type() != + mpm::EnrichType::NeighbourTip_1) + return; + if (this->nparticles() == 0) return; + + if (product_levelset() < 0) + this->discontinuity_element_->assign_element_type( + mpm::EnrichType::PotentialTip); + + // for (unsigned i = 0; i < nodes_.size(); ++i) { + // if (nodes_[i]->discontinuity_enrich()) + // nodes_[i]->assign_discontinuity_enrich(false); + // } +} + +//! determine tip element +template +void mpm::Cell::tip_element() { + if (this->discontinuity_element_ == nullptr) return; + if (this->discontinuity_element_->element_type() != mpm::EnrichType::Crossed) + return; + + for (unsigned i = 0; i < nodes_.size(); ++i) { + if (nodes_[i]->discontinuity_enrich()) continue; + this->discontinuity_element_->assign_element_type(mpm::EnrichType::Tip); + } +} + +//! potential tip element +template +void mpm::Cell::compute_discontinuity_point( + std::vector& coordinates) { + + // if (this->discontinuity_element_->area() == 0) + // compute_area_discontinuity(); + std::vector> intersections_list; + + Eigen::Matrix center = + this->discontinuity_element_->cohesion_cor(); + int index_area[6][5] = {{0, 1, 2, 3, 0}, {0, 1, 5, 4, 0}, {1, 2, 6, 5, 1}, + {3, 2, 6, 7, 3}, {0, 3, 7, 4, 0}, {4, 5, 6, 7, 4}}; + for (int i = 0; i < 6; i++) { + std::vector> intersections; + for (int j = 0; j < 4; j++) { + double phi[2]; + phi[0] = nodes_[index_area[i][j]]->discontinuity_property("levelset_phi", + 1)(0, 0); + phi[1] = nodes_[index_area[i][j + 1]]->discontinuity_property( + "levelset_phi", 1)(0, 0); + if (phi[0] * phi[1] >= 0) continue; + Eigen::Matrix intersection; + Eigen::Matrix cor0 = + nodes_[index_area[i][j]]->coordinates(); + Eigen::Matrix cor1 = + nodes_[index_area[i][j + 1]]->coordinates(); + intersection = cor0 * std::abs(phi[1] / ((phi[1] - phi[0]))) + + cor1 * std::abs(phi[0] / ((phi[1] - phi[0]))); + + intersections.push_back(intersection); + intersections_list.push_back(intersection); + } + // if (intersections.size() != 2) continue; + // if (this->discontinuity_element_->area() == 0) continue; + // Eigen::Matrix cor = + // 1.0 / 3 * (intersections[0] + intersections[1] + center); + // double length = (cor - center).norm(); + // if (length < 0.25 * mean_length_) continue; + // coordinates.push_back(cor); + } + + // if (this->discontinuity_element_->area() != 0) { + // coordinates.push_back(this->discontinuity_element_->cohesion_cor()); + // } else { + // if (intersections_list.size() < 3) return; + + // Eigen::Matrix cor; + // cor.setZero(); + // for (int i = 0; i < intersections_list.size(); i++) + // cor += 1.0 / intersections_list.size() * intersections_list[i]; + // coordinates.push_back(cor); + // } + if (intersections_list.size() < 3) return; + + Eigen::Matrix cor; + cor.setZero(); + for (int i = 0; i < intersections_list.size(); i++) + cor += 1.0 / intersections_list.size() * intersections_list[i]; + coordinates.push_back(cor); +} + +//! assign the normal direction of the discontinuity in the cell +template +void mpm::Cell::assign_normal_discontinuity(VectorDim normal) { + this->discontinuity_element_->assign_normal_discontinuity(normal); +} + +//! assign the normal direction of the discontinuity in the cell +template +void mpm::Cell::assign_normal_discontinuity(VectorDim normal, double d) { + this->discontinuity_element_->assign_normal_discontinuity(normal); + this->discontinuity_element_->assign_d(d); +} + +//! compute normal vector of discontinuity by the nodal level set values +template +void mpm::Cell::compute_normal_vector_discontinuity() { + VectorDim normal; + normal.setZero(); + // determine the discontinuity plane by the enriched nodes + for (unsigned i = 0; i < nodes_.size(); ++i) { + double phi = nodes_[i]->discontinuity_property("levelset_phi", 1)(0, 0); + for (unsigned int j = 0; j < Tdim; j++) { + normal[j] += phi * dn_dx_centroid_(i, j); + } + } + normal.normalize(); + this->discontinuity_element_->assign_normal_discontinuity(normal); +} + +//! compute gradient of the nodal level set values +template +Eigen::Matrix mpm::Cell::compute_gradient_levelset() { + VectorDim gradient; + gradient.setZero(); + // determine the discontinuity plane by the enriched nodes + for (unsigned i = 0; i < nodes_.size(); ++i) { + double phi = nodes_[i]->discontinuity_property("levelset_phi", 1)(0, 0); + for (unsigned int j = 0; j < Tdim; j++) { + gradient[j] += phi * dn_dx_centroid_(i, j); + } + } + + return gradient; +} + +template +void mpm::Cell::compute_plane_discontinuity(bool enrich) { + int enriched_node = 0; + auto normal = discontinuity_element_->normal_discontinuity(); + double dis = 0; + // determine the discontinuity plane by the enriched nodes + for (unsigned i = 0; i < nodes_.size(); ++i) { + if (enrich) { + if (!nodes_[i]->discontinuity_enrich()) continue; + } + enriched_node++; + auto node_coordinate = nodes_[i]->coordinates(); + for (unsigned int j = 0; j < Tdim; j++) + dis -= node_coordinate[j] * normal[j]; + dis = nodes_[i]->discontinuity_property("levelset_phi", 1)(0, 0) + dis; + } + // update the level set values of the unenriched nodes + dis = dis / enriched_node; + this->discontinuity_element_->assign_d(dis); +} + +// product of the nodal level set value +template +double mpm::Cell::product_levelset() { + double levelset_max = -std::numeric_limits::max(); + double levelset_min = std::numeric_limits::max(); + for (unsigned i = 0; i < nodes_.size(); ++i) { + + double levelset = + nodes_[i]->discontinuity_property("levelset_phi", 1)(0, 0); + levelset_max = levelset > levelset_max ? levelset : levelset_max; + levelset_min = levelset < levelset_min ? levelset : levelset_min; + } + return levelset_max * levelset_min; +} + +template +void mpm::Cell::determine_crossed() { + + // if (this->nparticles() == 0) return; + + double max_phi = -1e15, min_phi = 1e15; + + for (unsigned i = 0; i < nodes_.size(); ++i) { + double phi = nodes_[i]->discontinuity_property("levelset_phi", 1)(0, 0); + if (phi > max_phi) max_phi = phi; + if (phi < min_phi) min_phi = phi; + } + + this->assign_type_discontinuity(mpm::EnrichType::Regular); + if (max_phi * min_phi >= 0) return; + + this->assign_type_discontinuity(mpm::EnrichType::Crossed); +} + +template +void mpm::Cell::compute_nodal_levelset_equation() { + for (unsigned i = 0; i < nodes_.size(); ++i) { + auto coor = nodes_[i]->coordinates(); + double phi = 0; + for (unsigned int j = 0; j < Tdim; j++) + phi += coor[j] * this->discontinuity_element_->normal_discontinuity()[j]; + phi += this->discontinuity_element_->d_discontinuity(); + Eigen::Matrix phi_matrix; + phi_matrix(0, 0) = phi; + nodes_[i]->assign_discontinuity_property(true, "levelset_phi", phi_matrix, + 0, 1); + } +} + +template +void mpm::Cell::compute_area_discontinuity() { + + // if(this->id() == 1671) + // int a = 0; + + if (this->discontinuity_element_ == nullptr) return; + if (this->discontinuity_element_->element_type() != mpm::EnrichType::Crossed) + return; + // compute the level set values + Eigen::VectorXd phi_list(nnodes()); + phi_list.setZero(); + + auto normal = this->discontinuity_element_->normal_discontinuity(); + auto d = this->discontinuity_element_->d_discontinuity(); + for (int i = 0; i < nodes_.size(); ++i) { + phi_list[i] = normal.dot(nodes_[i]->coordinates()) + d; + } + // determine the intersections + std::vector> intersections; + + // node id of the 12 edges of one cell + int index_line[13][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 0}, {0, 4}, {1, 5}, + {2, 6}, {3, 7}, {4, 5}, {5, 6}, {6, 7}, {7, 4}}; + for (int i = 0; i < 12; ++i) { + if (phi_list[index_line[i][0]] * phi_list[index_line[i][1]] >= 0) continue; + + Eigen::Matrix intersection; + Eigen::Matrix cor0 = + nodes_[index_line[i][0]]->coordinates(); + Eigen::Matrix cor1 = + nodes_[index_line[i][1]]->coordinates(); + intersection = cor0 * std::abs(phi_list[index_line[i][1]] / + ((phi_list[index_line[i][1]] - + phi_list[index_line[i][0]]))) + + cor1 * std::abs(phi_list[index_line[i][0]] / + ((phi_list[index_line[i][1]] - + phi_list[index_line[i][0]]))); + + intersections.push_back(intersection); + } + if (intersections.size() < 3) return; + Eigen::Matrix average_cor; + average_cor.setZero(); + for (int i = 0; i < intersections.size(); ++i) + average_cor += intersections[i]; + + average_cor /= intersections.size(); + + // compute angle + // obtain e1 e2 of the local coordinate system + Eigen::Matrix e1 = + (intersections[0] - average_cor).normalized(); + Eigen::Matrix e2 = normal.cross(e1).normalized(); + // the angle and the order of the intersections + Eigen::VectorXd angles(intersections.size()); + angles.setZero(); + Eigen::VectorXd orders(intersections.size()); + orders.setZero(); + + for (int i = 1; i < intersections.size(); ++i) { + double costh = (intersections[i] - average_cor).normalized().dot(e1); + double sinth = (intersections[i] - average_cor).normalized().dot(e2); + + costh = costh > 1 ? 1 : costh; + costh = costh < -1 ? -1 : costh; + + double theta = std::acos(costh); + + if (sinth < 0) theta = 2 * M_PI - theta; + + angles[i] = theta; + } + // compute orders + for (int i = 1; i < intersections.size(); ++i) { + for (int j = 0; j < intersections.size(); j++) { + if (angles[i] > angles[j]) orders[i] += 1; + } + } + + // exchange intersections + auto intersections_copy = intersections; + for (int i = 1; i < intersections.size(); ++i) + intersections[orders[i]] = intersections_copy[i]; + + // compute area + double area = 0.0; + Eigen::Matrix subcenters; + subcenters.setZero(); + for (int i = 0; i < intersections.size() - 2; ++i) { + // the coordinates of the triangle + Eigen::Matrix cor0 = intersections[0]; + Eigen::Matrix cor1 = intersections[i + 1]; + Eigen::Matrix cor2 = intersections[i + 2]; + double subarea = + std::abs(0.5 * (cor1 - cor0).cross(cor2 - cor0).dot(normal)); + area += subarea; + subcenters += subarea * 1 / 3 * (cor0 + cor1 + cor2); + } + subcenters = subcenters / area; + + this->discontinuity_element_->assign_area(area); + this->discontinuity_element_->assign_cohesion_cor(subcenters); +} + +template +void mpm::Cell::assign_cohesion_area() { + + auto centers = this->discontinuity_element_->cohesion_cor(); + auto area = this->discontinuity_element_->area(); + + const Eigen::Matrix zeros = + Eigen::Matrix::Zero(); + Eigen::Matrix xi; + + if (!this->is_point_in_cell(centers, &xi)) return; + + auto shapefn = element_->shapefn(xi, zeros, zeros); + Eigen::Matrix node_area; + for (int i = 0; i < nodes_.size(); i++) { + + node_area(0, 0) = shapefn[i] * area; + nodes_[i]->update_discontinuity_property(true, "cohesion_area", node_area, + 0, 1); + } +} \ No newline at end of file diff --git a/include/mesh_xmpm.tcc b/include/mesh_xmpm.tcc index 88fd0d73d..461162505 100644 --- a/include/mesh_xmpm.tcc +++ b/include/mesh_xmpm.tcc @@ -111,6 +111,7 @@ void mpm::Mesh::initialise_nodal_levelset_discontinuity() { } } +//code for debugging added by yliang //! solve nodal levelset values template void mpm::Mesh::update_node_levelset() { From 9aa54048f67e08663c26a1fb4a6ba83033622c7e Mon Sep 17 00:00:00 2001 From: yliang-sn Date: Tue, 19 Oct 2021 17:40:26 -0700 Subject: [PATCH 69/91] tidy the mark points generation --- include/cell.tcc | 24 ------------ include/cell_xmpm.tcc | 87 ++++++++++++++++++++++--------------------- include/mesh_xmpm.tcc | 2 +- 3 files changed, 46 insertions(+), 67 deletions(-) diff --git a/include/cell.tcc b/include/cell.tcc index 1581a1193..027bcdfad 100644 --- a/include/cell.tcc +++ b/include/cell.tcc @@ -82,30 +82,6 @@ void mpm::Cell::assign_quadrature(unsigned nquadratures) { this->quadrature_ = element_->quadrature(nquadratures); } -//! Assign discontinuity element type -template -void mpm::Cell::assign_type_discontinuity(mpm::EnrichType type) { - if (nparticles() == 0 && type != mpm::EnrichType::NeighbourTip_2) - type = mpm::EnrichType::Regular; - if (discontinuity_element_ == nullptr) - discontinuity_element_ = - std::make_shared>(type); - else - discontinuity_element_->assign_element_type(type); -} -// Initialize discontinuity element type -template -void mpm::Cell::initialise_element_properties_discontinuity() { - if (discontinuity_element_ == nullptr) return; - discontinuity_element_->initialize(); -} - -// Return discontinuity element type -template -unsigned mpm::Cell::element_type_discontinuity() { - if (discontinuity_element_ == nullptr) return mpm::EnrichType::Regular; - return discontinuity_element_->element_type(); -} //! Assign quadrature template std::vector> mpm::Cell::generate_points() { diff --git a/include/cell_xmpm.tcc b/include/cell_xmpm.tcc index 719732d23..9cd5fa088 100644 --- a/include/cell_xmpm.tcc +++ b/include/cell_xmpm.tcc @@ -1,3 +1,28 @@ +//! Assign discontinuity element type +template +void mpm::Cell::assign_type_discontinuity(mpm::EnrichType type) { + if (nparticles() == 0 && type != mpm::EnrichType::NeighbourTip_2) + type = mpm::EnrichType::Regular; + if (discontinuity_element_ == nullptr) + discontinuity_element_ = + std::make_shared>(type); + else + discontinuity_element_->assign_element_type(type); +} +// Initialize discontinuity element type +template +void mpm::Cell::initialise_element_properties_discontinuity() { + if (discontinuity_element_ == nullptr) return; + discontinuity_element_->initialize(); +} + +// Return discontinuity element type +template +unsigned mpm::Cell::element_type_discontinuity() { + if (discontinuity_element_ == nullptr) return mpm::EnrichType::Regular; + return discontinuity_element_->element_type(); +} + //! potential tip element template void mpm::Cell::potential_tip_element() { @@ -35,54 +60,32 @@ template void mpm::Cell::compute_discontinuity_point( std::vector& coordinates) { - // if (this->discontinuity_element_->area() == 0) - // compute_area_discontinuity(); std::vector> intersections_list; Eigen::Matrix center = this->discontinuity_element_->cohesion_cor(); - int index_area[6][5] = {{0, 1, 2, 3, 0}, {0, 1, 5, 4, 0}, {1, 2, 6, 5, 1}, - {3, 2, 6, 7, 3}, {0, 3, 7, 4, 0}, {4, 5, 6, 7, 4}}; - for (int i = 0; i < 6; i++) { - std::vector> intersections; - for (int j = 0; j < 4; j++) { - double phi[2]; - phi[0] = nodes_[index_area[i][j]]->discontinuity_property("levelset_phi", - 1)(0, 0); - phi[1] = nodes_[index_area[i][j + 1]]->discontinuity_property( - "levelset_phi", 1)(0, 0); - if (phi[0] * phi[1] >= 0) continue; - Eigen::Matrix intersection; - Eigen::Matrix cor0 = - nodes_[index_area[i][j]]->coordinates(); - Eigen::Matrix cor1 = - nodes_[index_area[i][j + 1]]->coordinates(); - intersection = cor0 * std::abs(phi[1] / ((phi[1] - phi[0]))) + - cor1 * std::abs(phi[0] / ((phi[1] - phi[0]))); - - intersections.push_back(intersection); - intersections_list.push_back(intersection); - } - // if (intersections.size() != 2) continue; - // if (this->discontinuity_element_->area() == 0) continue; - // Eigen::Matrix cor = - // 1.0 / 3 * (intersections[0] + intersections[1] + center); - // double length = (cor - center).norm(); - // if (length < 0.25 * mean_length_) continue; - // coordinates.push_back(cor); + + int index_line[12][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 0}, {0, 4}, {1, 5}, + {2, 6}, {3, 7}, {4, 5}, {5, 6}, {6, 7}, {7, 4}}; + for (int i = 0; i < 12; i++) { + + double phi[2]; + phi[0] = nodes_[index_line[i][0]]->discontinuity_property("levelset_phi", + 1)(0, 0); + phi[1] = nodes_[index_line[i][1]]->discontinuity_property("levelset_phi", + 1)(0, 0); + if (phi[0] * phi[1] >= 0) continue; + Eigen::Matrix intersection; + Eigen::Matrix cor0 = + nodes_[index_line[i][0]]->coordinates(); + Eigen::Matrix cor1 = + nodes_[index_line[i][1]]->coordinates(); + intersection = cor0 * std::abs(phi[1] / ((phi[1] - phi[0]))) + + cor1 * std::abs(phi[0] / ((phi[1] - phi[0]))); + + intersections_list.push_back(intersection); } - // if (this->discontinuity_element_->area() != 0) { - // coordinates.push_back(this->discontinuity_element_->cohesion_cor()); - // } else { - // if (intersections_list.size() < 3) return; - - // Eigen::Matrix cor; - // cor.setZero(); - // for (int i = 0; i < intersections_list.size(); i++) - // cor += 1.0 / intersections_list.size() * intersections_list[i]; - // coordinates.push_back(cor); - // } if (intersections_list.size() < 3) return; Eigen::Matrix cor; diff --git a/include/mesh_xmpm.tcc b/include/mesh_xmpm.tcc index 461162505..09b684677 100644 --- a/include/mesh_xmpm.tcc +++ b/include/mesh_xmpm.tcc @@ -111,7 +111,7 @@ void mpm::Mesh::initialise_nodal_levelset_discontinuity() { } } -//code for debugging added by yliang +// code for debugging added by yliang //! solve nodal levelset values template void mpm::Mesh::update_node_levelset() { From 0ba0c011127bf2519e572a68b043c9ec67b8512f Mon Sep 17 00:00:00 2001 From: yliang-sn Date: Thu, 21 Oct 2021 16:25:28 -0700 Subject: [PATCH 70/91] solve the conflicts about hdf5 --- CMakeLists.txt | 12 - include/cell.h | 6 - include/mesh.h | 9 - include/mesh.tcc | 13 - include/mesh_xmpm.tcc | 7 - include/node.h | 6 - include/node_xmpm.tcc | 322 +++++++++--------- include/particles/particle_xmpm.h | 12 +- include/particles/particle_xmpm.tcc | 23 +- .../particles/pod_particles/pod_particle.h | 7 +- include/solvers/mpm_base.tcc | 6 - include/solvers/xmpm_explicit.tcc | 2 +- 12 files changed, 182 insertions(+), 243 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a5c9d776..c186d7a3d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -265,25 +265,14 @@ 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 -<<<<<<< HEAD ${mpm_SOURCE_DIR}/tests/solvers/xmpm_explicit_usf_test.cc # ${mpm_SOURCE_DIR}/tests/solvers/xmpm_explicit_usf_unitcell_test.cc ${mpm_SOURCE_DIR}/tests/solvers/xmpm_explicit_usl_test.cc # ${mpm_SOURCE_DIR}/tests/solvers/xmpm_explicit_usl_unitcell_test.cc ${mpm_SOURCE_DIR}/tests/solvers/mpm_scheme_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/node_xmpm_test.cc - ${mpm_SOURCE_DIR}/tests/node_vector_test.cc - ${mpm_SOURCE_DIR}/tests/particle_cell_crossing_test.cc - ${mpm_SOURCE_DIR}/tests/particle_serialize_deserialize_test.cc - ${mpm_SOURCE_DIR}/tests/particle_test.cc ${mpm_SOURCE_DIR}/tests/particle_xmpm_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 -======= ${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 @@ -295,7 +284,6 @@ if(MPM_BUILD_TESTING) ${mpm_SOURCE_DIR}/tests/solvers/mpm_semi_implicit_twophase_test.cc ${mpm_SOURCE_DIR}/tests/solvers/mpm_semi_implicit_twophase_unitcell_test.cc ${mpm_SOURCE_DIR}/tests/solvers/mpm_scheme_test.cc ->>>>>>> master ) add_executable(mpmtest ${mpm_src} ${test_src}) add_test(NAME mpmtest COMMAND $) diff --git a/include/cell.h b/include/cell.h index c0f336b10..ec8d16c5d 100644 --- a/include/cell.h +++ b/include/cell.h @@ -218,7 +218,6 @@ class Cell { //! Return previous mpi rank unsigned previous_mpirank() const; -<<<<<<< HEAD //! Assign discontinuity element type void assign_type_discontinuity(mpm::EnrichType type); @@ -286,7 +285,6 @@ class Cell { double discontinuity_area() { return this->discontinuity_element_->area(); } void assign_cohesion_area(); -======= /** * \defgroup Implicit Functions dealing with implicit MPM */ @@ -468,7 +466,6 @@ class Cell { double multiplier = 1.0) noexcept; /**@}*/ ->>>>>>> master private: //! Approximately check if a point is in a cell @@ -559,11 +556,8 @@ class Cell { } // namespace mpm #include "cell.tcc" -<<<<<<< HEAD #include "cell_xmpm.tcc" -======= #include "cell_implicit.tcc" #include "cell_multiphase.tcc" ->>>>>>> master #endif // MPM_CELL_H_ \ No newline at end of file diff --git a/include/mesh.h b/include/mesh.h index c8ea71e06..e745f28a6 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -428,12 +428,10 @@ class Mesh { //! Read HDF5 particles for singlephase particle //! \param[in] filename Name of HDF5 file to write particles data -<<<<<<< HEAD //! \param[in] particle type of HDF5 file to generate particles class //! \retval status Status of reading HDF5 output bool read_particles_hdf5(unsigned phase, const std::string& filename, const std::string& particle_type); -======= //! \param[in] particle_type Particle type to be generated //! \retval status Status of reading HDF5 output bool read_particles_hdf5(const std::string& filename, @@ -445,7 +443,6 @@ class Mesh { //! \retval status Status of reading HDF5 output bool read_particles_hdf5_twophase(const std::string& filename, const std::string& particle_type); ->>>>>>> master //! Return HDF5 particles //! \retval particles_hdf5 Vector of HDF5 particles @@ -508,7 +505,6 @@ class Mesh { // Initialise the nodal properties' map void initialise_nodal_properties(); -<<<<<<< HEAD // Create the nodal properties' map for discontinuity void create_nodal_properties_discontinuity(); @@ -577,7 +573,6 @@ class Mesh { void output_surface(); void check_particle_levelset(bool particle_levelset); -======= /** * \defgroup MultiPhase Functions dealing with multi-phase MPM */ @@ -672,7 +667,6 @@ class Mesh { const Eigen::VectorXd& pressure_increment, double dt); /**@}*/ ->>>>>>> master private: // Read particles from file @@ -749,10 +743,7 @@ class Mesh { } // namespace mpm #include "mesh.tcc" -<<<<<<< HEAD #include "mesh_xmpm.tcc" -======= #include "mesh_multiphase.tcc" ->>>>>>> master #endif // MPM_MESH_H_ diff --git a/include/mesh.tcc b/include/mesh.tcc index c5e4174ea..af0957997 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1600,12 +1600,7 @@ bool mpm::Mesh::read_particles_hdf5(const std::string& filename, //! Read HDF5 particles for singlephase particle template -<<<<<<< HEAD -bool mpm::Mesh::read_particles_hdf5(unsigned phase, - const std::string& filename, -======= bool mpm::Mesh::read_particles_hdf5(const std::string& filename, ->>>>>>> master const std::string& particle_type) { // Create a new file using default properties. @@ -1628,10 +1623,6 @@ bool mpm::Mesh::read_particles_hdf5(const std::string& filename, mpm::pod::particle::dst_offset, mpm::pod::particle::dst_sizes, dst_buf.data()); -<<<<<<< HEAD - // Particle type - // const std::string particle_type = (Tdim == 2) ? "P2D" : "P3D"; -======= // Iterate over all HDF5 particles for (unsigned i = 0; i < nrecords; ++i) { PODParticle pod_particle = dst_buf[i]; @@ -1690,7 +1681,6 @@ bool mpm::Mesh::read_particles_hdf5_twophase( H5TBread_table(file_id, "table", mpm::pod::particletwophase::dst_size, mpm::pod::particletwophase::dst_offset, mpm::pod::particletwophase::dst_sizes, dst_buf.data()); ->>>>>>> master // Iterate over all HDF5 particles for (unsigned i = 0; i < nrecords; ++i) { @@ -2164,8 +2154,6 @@ void mpm::Mesh::create_nodal_properties() { } else { throw std::runtime_error("Number of nodes or number of materials is zero"); } -<<<<<<< HEAD -======= } // Initialise the nodal properties' map @@ -2173,5 +2161,4 @@ template void mpm::Mesh::initialise_nodal_properties() { // Call initialise_properties function from the nodal properties nodal_properties_->initialise_nodal_properties(); ->>>>>>> master } \ No newline at end of file diff --git a/include/mesh_xmpm.tcc b/include/mesh_xmpm.tcc index 09b684677..c3078fa7b 100644 --- a/include/mesh_xmpm.tcc +++ b/include/mesh_xmpm.tcc @@ -29,13 +29,6 @@ void mpm::Mesh::create_nodal_properties_discontinuity() { nodal_properties_); } -// 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(); -} - //! Locate points in a cell template void mpm::Mesh::locate_discontinuity() { diff --git a/include/node.h b/include/node.h index e79e45a66..fcb110663 100644 --- a/include/node.h +++ b/include/node.h @@ -656,13 +656,11 @@ class Node : public NodeBase { std::unique_ptr console_; //! MPI ranks std::set mpi_ranks_; -<<<<<<< HEAD //! discontinuity enrich // need to be done bool discontinuity_enrich_{false}; //! cells ids including the node std::vector cells_; -======= //! Global index for active node (in each rank) Index active_id_{std::numeric_limits::max()}; //! Global index for active node (globally) @@ -699,16 +697,12 @@ class Node : public NodeBase { //! Drag force Eigen::Matrix drag_force_coefficient_; /**@}*/ ->>>>>>> master }; // Node class } // namespace mpm #include "node.tcc" -<<<<<<< HEAD #include "node_xmpm.tcc" -======= #include "node_implicit.tcc" #include "node_multiphase.tcc" ->>>>>>> master #endif // MPM_NODE_H_ diff --git a/include/node_xmpm.tcc b/include/node_xmpm.tcc index 344d44654..15af720e0 100644 --- a/include/node_xmpm.tcc +++ b/include/node_xmpm.tcc @@ -92,41 +92,41 @@ bool mpm::Node::compute_momentum_discontinuity_cundall( } else { - // obtain the enriched values of enriched nodes - Eigen::Matrix mass_enrich = - property_handle_->property("mass_enrich", discontinuity_prop_id_, 0, 1); - - // mass for different sides - auto mass_positive = mass_.col(phase) + mass_enrich; - auto mass_negative = mass_.col(phase) - mass_enrich; - - Eigen::Matrix momenta_enrich = property_handle_->property( - "momenta_enrich", discontinuity_prop_id_, 0, Tdim); - Eigen::Matrix unbalanced_force = - this->external_force_.col(phase) + this->internal_force_.col(phase); - Eigen::Matrix unbalanced_force_enrich = - property_handle_->property("internal_force_enrich", - discontinuity_prop_id_, 0, Tdim) + - property_handle_->property("external_force_enrich", - discontinuity_prop_id_, 0, Tdim); - - Eigen::Matrix damp_force_positive = - -damping_factor * (unbalanced_force + unbalanced_force_enrich).norm() * - (this->momentum_.col(phase) + momenta_enrich).normalized(); - - if (mass_positive(phase) < tolerance) damp_force_positive.setZero(); - - Eigen::Matrix damp_force_negative = - -damping_factor * (unbalanced_force - unbalanced_force_enrich).norm() * - (this->momentum_.col(phase) - momenta_enrich).normalized(); - - if (mass_negative(phase) < tolerance) damp_force_negative.setZero(); - this->external_force_.col(phase) += - 0.5 * (damp_force_positive + damp_force_negative); - - property_handle_->update_property( - "external_force_enrich", discontinuity_prop_id_, 0, - 0.5 * (damp_force_positive - damp_force_negative), Tdim); + // // obtain the enriched values of enriched nodes + // Eigen::Matrix mass_enrich = + // property_handle_->property("mass_enrich", discontinuity_prop_id_, 0, 1); + + // // mass for different sides + // auto mass_positive = mass_.col(phase) + mass_enrich; + // auto mass_negative = mass_.col(phase) - mass_enrich; + + // Eigen::Matrix momenta_enrich = property_handle_->property( + // "momenta_enrich", discontinuity_prop_id_, 0, Tdim); + // Eigen::Matrix unbalanced_force = + // this->external_force_.col(phase) + this->internal_force_.col(phase); + // Eigen::Matrix unbalanced_force_enrich = + // property_handle_->property("internal_force_enrich", + // discontinuity_prop_id_, 0, Tdim) + + // property_handle_->property("external_force_enrich", + // discontinuity_prop_id_, 0, Tdim); + + // Eigen::Matrix damp_force_positive = + // -damping_factor * (unbalanced_force + unbalanced_force_enrich).norm() * + // (this->momentum_.col(phase) + momenta_enrich).normalized(); + + // if (mass_positive(phase) < tolerance) damp_force_positive.setZero(); + + // Eigen::Matrix damp_force_negative = + // -damping_factor * (unbalanced_force - unbalanced_force_enrich).norm() * + // (this->momentum_.col(phase) - momenta_enrich).normalized(); + + // if (mass_negative(phase) < tolerance) damp_force_negative.setZero(); + // this->external_force_.col(phase) += + // 0.5 * (damp_force_positive + damp_force_negative); + + // property_handle_->update_property( + // "external_force_enrich", discontinuity_prop_id_, 0, + // 0.5 * (damp_force_positive - damp_force_negative), Tdim); } compute_momentum_discontinuity(phase, dt); @@ -194,132 +194,132 @@ template void mpm::Node::self_contact_discontinuity( double dt) noexcept { - if (!discontinuity_enrich_) return; - - double contact_distance = property_handle_->property( - "contact_distance", discontinuity_prop_id_, 0, 1)(0, 0); - - Eigen::Matrix normal_vector = property_handle_->property( - "normal_unit_vectors_discontinuity", discontinuity_prop_id_, 0, Tdim); - - if (contact_distance >= 0) return; - // single phase for solid - unsigned phase = 0; - const double tolerance = 1.0E-15; - - // obtain the enriched values of enriched nodes - Eigen::Matrix mass_enrich = - property_handle_->property("mass_enrich", discontinuity_prop_id_, 0, 1); - Eigen::Matrix momenta_enrich = property_handle_->property( - "momenta_enrich", discontinuity_prop_id_, 0, Tdim); - - // mass for different sides - auto mass_positive = mass_.col(phase) + mass_enrich; - auto mass_negative = mass_.col(phase) - mass_enrich; - - if (mass_positive(phase) < tolerance || mass_negative(phase) < tolerance) - return; - - // velocity for different sides - auto velocity_positive = - (momentum_.col(phase) + momenta_enrich) / mass_positive(phase); - auto velocity_negative = - (momentum_.col(phase) - momenta_enrich) / mass_negative(phase); - - // relative normal velocity - if ((velocity_positive - velocity_negative).col(phase).dot(normal_vector) >= - 0) - return; - - // the contact momentum, force vector for sticking contact - auto momentum_contact = (mass_enrich(phase) * momentum_.col(phase) - - mass_(phase) * momenta_enrich) / - mass_(phase); - auto force_contact = momentum_contact / dt; - - // friction_coef < 0: move together without slide - double friction_coef = property_handle_->property( - "friction_coef", discontinuity_prop_id_, 0, 1)(0, 0); - - if (friction_coef < 0) { - property_handle_->update_property("momenta_enrich", discontinuity_prop_id_, - 0, momentum_contact.col(phase), Tdim); - property_handle_->update_property("external_force_enrich", - discontinuity_prop_id_, 0, - force_contact.col(phase), Tdim); - } else { - // the contact momentum, force value for sticking contact at normal - // direction - double momentum_contact_norm = - momentum_contact.col(phase).dot(normal_vector); - double force_contact_norm = momentum_contact_norm / dt; - - // the cohesion at nodes - double cohesion = property_handle_->property( - "cohesion", discontinuity_prop_id_, 0, 1)(0, 0); - - if (coordinates_[0] < 513) - cohesion = 25000; - else if (coordinates_[0] < 660) - cohesion = 25000; - else if (coordinates_[0] < 893.6) - cohesion = 10000; - else if (coordinates_[0] < 955) - cohesion = 0; - else if (coordinates_[0] < 1005) - cohesion = (coordinates_[0] - 955) / 50 * 10000; - else - cohesion = 10000; - - if (coordinates_[0] < 200) - cohesion = 0; - else if (coordinates_[0] < 513) - cohesion = 150000; - else if (coordinates_[0] < 660) - cohesion = 25000; - else if (coordinates_[0] < 893.6) - cohesion = 10000; - else if (coordinates_[0] < 955) - cohesion = 0; - else if (coordinates_[0] < 1005) - cohesion = (coordinates_[0] - 955) / 50 * 10000; - else - cohesion = 10000; - // cohesion = 0; - - // the cohesion at nodes - double cohesion_area = property_handle_->property( - "cohesion_area", discontinuity_prop_id_, 0, 1)(0, 0); - // if (std::isnan(cohesion_area) || cohesion_area <= 0 || cohesion_area > 2) - // cohesion_area = 0; - double max_friction_force = - friction_coef * abs(force_contact_norm) + 2 * cohesion * cohesion_area; - - // the contact momentum, force vector for sticking contact at tangential - // direction - auto momentum_tangential = - momentum_contact.col(phase) - momentum_contact_norm * normal_vector; - auto force_tangential = momentum_tangential / dt; - - // the friction force magnitude - double force_tangential_value = force_tangential.norm(); - - double force_friction = force_tangential_value < max_friction_force - ? force_tangential_value - : max_friction_force; - - // adjust the momentum and force - property_handle_->update_property( - "momenta_enrich", discontinuity_prop_id_, 0, - momentum_contact_norm * normal_vector + - force_friction * force_tangential.col(phase).normalized() * dt, - Tdim); - property_handle_->update_property( - "external_force_enrich", discontinuity_prop_id_, 0, - force_contact_norm * normal_vector + - force_friction * force_tangential.col(phase).normalized(), - Tdim); - } +// if (!discontinuity_enrich_) return; + +// double contact_distance = property_handle_->property( +// "contact_distance", discontinuity_prop_id_, 0, 1)(0, 0); + +// Eigen::Matrix normal_vector = property_handle_->property( +// "normal_unit_vectors_discontinuity", discontinuity_prop_id_, 0, Tdim); + +// if (contact_distance >= 0) return; +// // single phase for solid +// unsigned phase = 0; +// const double tolerance = 1.0E-15; + +// // obtain the enriched values of enriched nodes +// Eigen::Matrix mass_enrich = +// property_handle_->property("mass_enrich", discontinuity_prop_id_, 0, 1); +// Eigen::Matrix momenta_enrich = property_handle_->property( +// "momenta_enrich", discontinuity_prop_id_, 0, Tdim); + +// // mass for different sides +// auto mass_positive = mass_.col(phase) + mass_enrich; +// auto mass_negative = mass_.col(phase) - mass_enrich; + +// if (mass_positive(phase) < tolerance || mass_negative(phase) < tolerance) +// return; + +// // velocity for different sides +// auto velocity_positive = +// (momentum_.col(phase) + momenta_enrich) / mass_positive(phase); +// auto velocity_negative = +// (momentum_.col(phase) - momenta_enrich) / mass_negative(phase); + +// // relative normal velocity +// if ((velocity_positive - velocity_negative).col(phase).dot(normal_vector) >= +// 0) +// return; + +// // the contact momentum, force vector for sticking contact +// auto momentum_contact = (mass_enrich(phase) * momentum_.col(phase) - +// mass_(phase) * momenta_enrich) / +// mass_(phase); +// auto force_contact = momentum_contact / dt; + +// // friction_coef < 0: move together without slide +// double friction_coef = property_handle_->property( +// "friction_coef", discontinuity_prop_id_, 0, 1)(0, 0); + +// if (friction_coef < 0) { +// property_handle_->update_property("momenta_enrich", discontinuity_prop_id_, +// 0, momentum_contact.col(phase), Tdim); +// property_handle_->update_property("external_force_enrich", +// discontinuity_prop_id_, 0, +// force_contact.col(phase), Tdim); +// } else { +// // the contact momentum, force value for sticking contact at normal +// // direction +// double momentum_contact_norm = +// momentum_contact.col(phase).dot(normal_vector); +// double force_contact_norm = momentum_contact_norm / dt; + +// // the cohesion at nodes +// double cohesion = property_handle_->property( +// "cohesion", discontinuity_prop_id_, 0, 1)(0, 0); + +// if (coordinates_[0] < 513) +// cohesion = 25000; +// else if (coordinates_[0] < 660) +// cohesion = 25000; +// else if (coordinates_[0] < 893.6) +// cohesion = 10000; +// else if (coordinates_[0] < 955) +// cohesion = 0; +// else if (coordinates_[0] < 1005) +// cohesion = (coordinates_[0] - 955) / 50 * 10000; +// else +// cohesion = 10000; + +// if (coordinates_[0] < 200) +// cohesion = 0; +// else if (coordinates_[0] < 513) +// cohesion = 150000; +// else if (coordinates_[0] < 660) +// cohesion = 25000; +// else if (coordinates_[0] < 893.6) +// cohesion = 10000; +// else if (coordinates_[0] < 955) +// cohesion = 0; +// else if (coordinates_[0] < 1005) +// cohesion = (coordinates_[0] - 955) / 50 * 10000; +// else +// cohesion = 10000; +// // cohesion = 0; + +// // the cohesion at nodes +// double cohesion_area = property_handle_->property( +// "cohesion_area", discontinuity_prop_id_, 0, 1)(0, 0); +// // if (std::isnan(cohesion_area) || cohesion_area <= 0 || cohesion_area > 2) +// // cohesion_area = 0; +// double max_friction_force = +// friction_coef * abs(force_contact_norm) + 2 * cohesion * cohesion_area; + +// // the contact momentum, force vector for sticking contact at tangential +// // direction +// auto momentum_tangential = +// momentum_contact.col(phase) - momentum_contact_norm * normal_vector; +// auto force_tangential = momentum_tangential / dt; + +// // the friction force magnitude +// double force_tangential_value = force_tangential.norm(); + +// double force_friction = force_tangential_value < max_friction_force +// ? force_tangential_value +// : max_friction_force; + +// // adjust the momentum and force +// property_handle_->update_property( +// "momenta_enrich", discontinuity_prop_id_, 0, +// momentum_contact_norm * normal_vector + +// force_friction * force_tangential.col(phase).normalized() * dt, +// Tdim); +// property_handle_->update_property( +// "external_force_enrich", discontinuity_prop_id_, 0, +// force_contact_norm * normal_vector + +// force_friction * force_tangential.col(phase).normalized(), +// Tdim); +// } } //! Apply self-contact of the discontinuity diff --git a/include/particles/particle_xmpm.h b/include/particles/particle_xmpm.h index 43fe0a3e9..8c4c4d60f 100644 --- a/include/particles/particle_xmpm.h +++ b/include/particles/particle_xmpm.h @@ -11,9 +11,6 @@ #include "logger.h" #include "particle_base.h" -#include -#include - namespace mpm { //! ParticleXMPM class @@ -49,11 +46,12 @@ class ParticleXMPM : public 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(PODParticle& particle) override; + + //! Return particle data as POD + //! \retval particle POD of the particle + std::shared_ptr pod() const override; - //! Retrun particle data as HDF5 - //! \retval particle HDF5 data of the particle - HDF5Particle hdf5() const override; //! Initialise properties void initialise() override; diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index 1c418c040..7e7c272ad 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -21,26 +21,27 @@ mpm::ParticleXMPM::ParticleXMPM(Index id, const VectorDim& coord, console_ = std::make_unique(logger, mpm::stdout_sink); } -//! Initialise particle data from HDF5 +//! Initialise particle data from pod template -bool mpm::ParticleXMPM::initialise_particle( - const HDF5Particle& particle) { - mpm::Particle::initialise_particle(particle); - +bool mpm::ParticleXMPM::initialise_particle(PODParticle& particle) { + bool status = mpm::Particle::initialise_particle(particle); // levelset_phi - this->levelset_phi_ = particle.levelset_phi; + //to do + levelset_phi_ = particle.levelset_phi; - return true; + return status; } -//! Return particle data in HDF5 format + +//! Return particle data as POD template // cppcheck-suppress * -mpm::HDF5Particle mpm::ParticleXMPM::hdf5() const { +std::shared_ptr mpm::ParticleXMPM::pod() const { - mpm::HDF5Particle particle_data = mpm::Particle::hdf5(); - particle_data.levelset_phi = levelset_phi_; + auto particle_data = std::make_shared(); + //to do + particle_data->levelset_phi = levelset_phi_; return particle_data; } diff --git a/include/particles/pod_particles/pod_particle.h b/include/particles/pod_particles/pod_particle.h index 5ce1e657e..ff50624fe 100644 --- a/include/particles/pod_particles/pod_particle.h +++ b/include/particles/pod_particles/pod_particle.h @@ -44,11 +44,10 @@ typedef struct PODParticle { unsigned material_id; // Number of state variables unsigned nstate_vars; + //! Level set values + double levelset_phi; // State variables (init to zero) double svars[20] = {0}; - // level set values - double levelset_phi{0}; -} HDF5Particle; // Destructor virtual ~PODParticle() = default; } PODParticle; @@ -76,4 +75,4 @@ extern const hid_t field_type[NFIELDS]; } // namespace mpm -#endif // MPM_POD_H_ +#endif // MPM_POD_H_ \ No newline at end of file diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index 5ac11c375..d358b1116 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -485,15 +485,9 @@ bool mpm::MPMBase::checkpoint_resume() { io_->output_file(attribute, extension, uuid_, step_, this->nsteps_) .string(); -<<<<<<< HEAD - // Load particle information from file - const std::string particle_type = (Tdim == 2) ? "P2D" : "P3D"; - mesh_->read_particles_hdf5(phase, particles_file, particle_type); -======= // Load particle information from file mesh_->read_particles_hdf5(particles_file, attribute, ptype); } ->>>>>>> master // Clear all particle ids mesh_->iterate_over_cells( diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index 4ad2bff46..bbcb7818d 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -437,7 +437,7 @@ bool mpm::XMPMExplicit::checkpoint_resume() { // Load particle information from file const std::string particle_type = (Tdim == 2) ? "P2DXMPM" : "P3DXMPM"; - mesh_->read_particles_hdf5(phase, particles_file, particle_type); + mesh_->read_particles_hdf5(particles_file, particle_type); // Clear all particle ids mesh_->iterate_over_cells( From 2462fe802f7ebbd64941181772202f8ceeeb1c3d Mon Sep 17 00:00:00 2001 From: yliang-sn Date: Wed, 3 Nov 2021 14:32:43 -0700 Subject: [PATCH 71/91] tidy the code and comments --- include/cell.h | 42 +- include/cell_xmpm.tcc | 53 +- include/io/logger.h | 2 +- include/materials/material.h | 7 +- include/materials/mohr_coulomb.h | 12 +- include/materials/mohr_coulomb.tcc | 4 +- include/materials/norsand.h | 18 - include/mesh.h | 44 +- include/mesh_multiphase.tcc | 2 +- include/mesh_xmpm.tcc | 48 +- include/node.h | 22 +- include/node_base.h | 13 +- include/node_xmpm.tcc | 325 ++--- include/particles/particle.tcc | 1 - include/particles/particle_base.h | 13 +- include/particles/particle_xmpm.h | 34 +- include/particles/particle_xmpm.tcc | 376 ++---- include/solvers/mpm_base.h | 8 - include/solvers/mpm_explicit.tcc | 24 +- include/solvers/mpm_scheme/mpm_scheme.h | 4 +- include/solvers/xmpm_explicit.h | 20 +- include/solvers/xmpm_explicit.tcc | 3 +- include/xmpm/discontinuity_3d.h | 27 +- include/xmpm/discontinuity_3d.tcc | 20 +- include/xmpm/discontinuity_base.h | 84 +- include/xmpm/discontinuity_base.tcc | 5 +- include/xmpm/discontinuity_element.h | 42 +- include/xmpm/discontinuity_point.tcc | 2 - src/mpm.cc | 2 +- src/nodal_properties.cc | 1 - src/particle.cc | 2 +- tests/io/write_mesh_particles.cc | 1572 +++++++++++------------ tests/mesh_test_3d.cc | 2 +- 33 files changed, 1233 insertions(+), 1601 deletions(-) diff --git a/include/cell.h b/include/cell.h index ec8d16c5d..06b4cbaed 100644 --- a/include/cell.h +++ b/include/cell.h @@ -224,22 +224,23 @@ class Cell { //! Initialize discontinuity element properties void initialise_element_properties_discontinuity(); - //! assign the normal direction of the discontinuity in the cell + //! Assign the normal direction of the discontinuity in the cell //! \param[in] the normal direction void assign_normal_discontinuity(VectorDim normal); - //! assign the constant parameters of the discontinuity in the cell + //! Assign the constant parameters of the discontinuity in the cell //! \param[in] the constant parameters void assign_d_discontinuity(double d) { this->discontinuity_element_->assign_d(d); }; - //! assign the normal direction of the discontinuity in the cell + //! Assign the normal direction of the discontinuity in the cell //! \param[in] the normal direction //! \param[in] the plane constant void assign_normal_discontinuity(VectorDim normal, double d); - //! return the normal direction of the discontinuity in the cell + //! Return the normal direction of the discontinuity in the cell + //! \retval the normal direction of the discontinuity VectorDim normal_discontinuity() { return discontinuity_element_->normal_discontinuity(); }; @@ -247,44 +248,47 @@ class Cell { //! Return discontinuity element type unsigned element_type_discontinuity(); - //! potential tip element + //! Find the potential tip element void potential_tip_element(); - //! determine tip element + //! Determine tip element void tip_element(); - //! compute normal vector of discontinuity by the nodal level set values + //! Compute normal vector of discontinuity by the nodal level set values void compute_normal_vector_discontinuity(); - //! compute gradient of the nodal level set values - VectorDim compute_gradient_levelset(); - - //! compute the discontinuity plane by the nodal level set values - //! \param[in] from the enriched nodes + //! Compute the discontinuity plane by the nodal level set values + //! \param[in] true: compute by the enriched nodes void compute_plane_discontinuity(bool enrich); - //! update nodal nodal level set + //! Compute the discontinuity point: the average coordinates of the + //! intersection points \param[in] mark points list void compute_discontinuity_point(std::vector& coordinates); - // product of the nodal level set value + //! Return the product of the maximum and minimum nodal level set value + //! \retval the product of the maximum and minimum nodal level set value double product_levelset(); - // return the constant value of the discontinuity plane + //! Return the constant value of the discontinuity plane double d_discontinuity() { return this->discontinuity_element_->d_discontinuity(); } - // determine the celltype by the nodal level set + + //! Determine the celltype by the nodal level set void determine_crossed(); - // compute the nodal level set values by plane equations + //! Compute the nodal level set values by plane equations void compute_nodal_levelset_equation(); - // compute the area of the crossed cell + //! Compute the area of the discontinuity void compute_area_discontinuity(); + //! Return the area of the discontinuity double discontinuity_area() { return this->discontinuity_element_->area(); } + //! Assign the area of the discontinuity to nodes void assign_cohesion_area(); + /** * \defgroup Implicit Functions dealing with implicit MPM */ @@ -556,8 +560,8 @@ class Cell { } // namespace mpm #include "cell.tcc" -#include "cell_xmpm.tcc" #include "cell_implicit.tcc" #include "cell_multiphase.tcc" +#include "cell_xmpm.tcc" #endif // MPM_CELL_H_ \ No newline at end of file diff --git a/include/cell_xmpm.tcc b/include/cell_xmpm.tcc index 9cd5fa088..9912ffdc5 100644 --- a/include/cell_xmpm.tcc +++ b/include/cell_xmpm.tcc @@ -13,7 +13,7 @@ void mpm::Cell::assign_type_discontinuity(mpm::EnrichType type) { template void mpm::Cell::initialise_element_properties_discontinuity() { if (discontinuity_element_ == nullptr) return; - discontinuity_element_->initialize(); + discontinuity_element_->initialise(); } // Return discontinuity element type @@ -23,7 +23,7 @@ unsigned mpm::Cell::element_type_discontinuity() { return discontinuity_element_->element_type(); } -//! potential tip element +//! Find the potential tip element template void mpm::Cell::potential_tip_element() { if (this->discontinuity_element_ == nullptr) return; @@ -35,14 +35,9 @@ void mpm::Cell::potential_tip_element() { if (product_levelset() < 0) this->discontinuity_element_->assign_element_type( mpm::EnrichType::PotentialTip); - - // for (unsigned i = 0; i < nodes_.size(); ++i) { - // if (nodes_[i]->discontinuity_enrich()) - // nodes_[i]->assign_discontinuity_enrich(false); - // } } -//! determine tip element +//! Determine tip element template void mpm::Cell::tip_element() { if (this->discontinuity_element_ == nullptr) return; @@ -55,7 +50,8 @@ void mpm::Cell::tip_element() { } } -//! potential tip element +//! Compute the discontinuity point: the average coordinates of the intersection +//! points template void mpm::Cell::compute_discontinuity_point( std::vector& coordinates) { @@ -95,20 +91,20 @@ void mpm::Cell::compute_discontinuity_point( coordinates.push_back(cor); } -//! assign the normal direction of the discontinuity in the cell +//! Assign the normal direction of the discontinuity in the cell template void mpm::Cell::assign_normal_discontinuity(VectorDim normal) { this->discontinuity_element_->assign_normal_discontinuity(normal); } -//! assign the normal direction of the discontinuity in the cell +//! Assign the normal direction of the discontinuity in the cell template void mpm::Cell::assign_normal_discontinuity(VectorDim normal, double d) { this->discontinuity_element_->assign_normal_discontinuity(normal); this->discontinuity_element_->assign_d(d); } -//! compute normal vector of discontinuity by the nodal level set values +//! Compute normal vector of discontinuity by the nodal level set values template void mpm::Cell::compute_normal_vector_discontinuity() { VectorDim normal; @@ -124,22 +120,7 @@ void mpm::Cell::compute_normal_vector_discontinuity() { this->discontinuity_element_->assign_normal_discontinuity(normal); } -//! compute gradient of the nodal level set values -template -Eigen::Matrix mpm::Cell::compute_gradient_levelset() { - VectorDim gradient; - gradient.setZero(); - // determine the discontinuity plane by the enriched nodes - for (unsigned i = 0; i < nodes_.size(); ++i) { - double phi = nodes_[i]->discontinuity_property("levelset_phi", 1)(0, 0); - for (unsigned int j = 0; j < Tdim; j++) { - gradient[j] += phi * dn_dx_centroid_(i, j); - } - } - - return gradient; -} - +//! Compute the discontinuity plane by the nodal level set values template void mpm::Cell::compute_plane_discontinuity(bool enrich) { int enriched_node = 0; @@ -147,9 +128,8 @@ void mpm::Cell::compute_plane_discontinuity(bool enrich) { double dis = 0; // determine the discontinuity plane by the enriched nodes for (unsigned i = 0; i < nodes_.size(); ++i) { - if (enrich) { + if (enrich) if (!nodes_[i]->discontinuity_enrich()) continue; - } enriched_node++; auto node_coordinate = nodes_[i]->coordinates(); for (unsigned int j = 0; j < Tdim; j++) @@ -161,7 +141,7 @@ void mpm::Cell::compute_plane_discontinuity(bool enrich) { this->discontinuity_element_->assign_d(dis); } -// product of the nodal level set value +// product of the maximum and minimum nodal level set value template double mpm::Cell::product_levelset() { double levelset_max = -std::numeric_limits::max(); @@ -176,11 +156,10 @@ double mpm::Cell::product_levelset() { return levelset_max * levelset_min; } +//! Determine the celltype by the nodal level set template void mpm::Cell::determine_crossed() { - // if (this->nparticles() == 0) return; - double max_phi = -1e15, min_phi = 1e15; for (unsigned i = 0; i < nodes_.size(); ++i) { @@ -195,6 +174,7 @@ void mpm::Cell::determine_crossed() { this->assign_type_discontinuity(mpm::EnrichType::Crossed); } +//! Compute the nodal level set values by plane equations template void mpm::Cell::compute_nodal_levelset_equation() { for (unsigned i = 0; i < nodes_.size(); ++i) { @@ -210,12 +190,10 @@ void mpm::Cell::compute_nodal_levelset_equation() { } } +//! Compute the area of the discontinuity template void mpm::Cell::compute_area_discontinuity() { - // if(this->id() == 1671) - // int a = 0; - if (this->discontinuity_element_ == nullptr) return; if (this->discontinuity_element_->element_type() != mpm::EnrichType::Crossed) return; @@ -232,7 +210,7 @@ void mpm::Cell::compute_area_discontinuity() { std::vector> intersections; // node id of the 12 edges of one cell - int index_line[13][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 0}, {0, 4}, {1, 5}, + int index_line[12][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 0}, {0, 4}, {1, 5}, {2, 6}, {3, 7}, {4, 5}, {5, 6}, {6, 7}, {7, 4}}; for (int i = 0; i < 12; ++i) { if (phi_list[index_line[i][0]] * phi_list[index_line[i][1]] >= 0) continue; @@ -315,6 +293,7 @@ void mpm::Cell::compute_area_discontinuity() { this->discontinuity_element_->assign_cohesion_cor(subcenters); } +//! Assign the area of the discontinuity to nodes template void mpm::Cell::assign_cohesion_area() { diff --git a/include/io/logger.h b/include/io/logger.h index 4c5a3dd5b..9e0be165c 100644 --- a/include/io/logger.h +++ b/include/io/logger.h @@ -42,7 +42,7 @@ struct Logger { // Create a logger for MPM Explicit USL static const std::shared_ptr mpm_explicit_usl_logger; - // Create a logger for MPM Explicit + // Create a logger for XMPM Explicit static const std::shared_ptr xmpm_explicit_logger; // Create a logger for MPM Explicit MUSL static const std::shared_ptr mpm_explicit_musl_logger; diff --git a/include/materials/material.h b/include/materials/material.h index 42e2ae44b..16836e862 100644 --- a/include/materials/material.h +++ b/include/materials/material.h @@ -78,16 +78,19 @@ class Material { const ParticleBase* ptr, mpm::dense_map* state_vars) = 0; - //! return Plastic stiffness matrix + //! Return Elastic-Plastic stiffness matrix //! \param[in] stress Stress //! \param[in] state_vars History-dependent state variables //! \param[in] the yield status + //! \retval dp_ Elastic-Plastic stiffness matrix virtual Matrix6x6 dp(const Vector6d& stress, mpm::dense_map* state_vars, bool& status) { return Matrix6x6::Zero(); } - //! return Elastic stiffness matrix + //! Return Elastic stiffness matrix + //! \retval de_ Elastic stiffness matrix virtual Matrix6x6 de() { return Matrix6x6::Zero(); } + //! Compute constitutive relations matrix //! \ingroup Implicit //! \param[in] stress Stress diff --git a/include/materials/mohr_coulomb.h b/include/materials/mohr_coulomb.h index 90a2344bb..6b0b0f7d5 100644 --- a/include/materials/mohr_coulomb.h +++ b/include/materials/mohr_coulomb.h @@ -85,23 +85,25 @@ class MohrCoulomb : public Material { Vector6d* df_dsigma, Vector6d* dp_dsigma, double* dp_dq, double* softening); - //! return Plastic stiffness matrix + //! Return elastic plastic stiffness matrix //! \param[in] stress Stress //! \param[in] state_vars History-dependent state variables //! \param[in] the yield status + //! \retval dp_ Elastic-Plastic stiffness matrix virtual Matrix6x6 dp(const Vector6d& stress, mpm::dense_map* state_vars, bool& status) { - status = compute_plastic_tensor(stress, state_vars); + status = compute_elastic_plastic_tensor(stress, state_vars); return dp_; } - //! Compute plastic tensor + //! Compute elastic plastic tensor //! \param[in] stress Stress //! \param[in] state_vars History-dependent state variables - bool compute_plastic_tensor(const Vector6d& stress, - mpm::dense_map* state_vars); + bool compute_elastic_plastic_tensor(const Vector6d& stress, + mpm::dense_map* state_vars); //! return Elastic stiffness matrix + //! \retval de_ Elastic stiffness matrix Matrix6x6 de() { return de_; } protected: diff --git a/include/materials/mohr_coulomb.tcc b/include/materials/mohr_coulomb.tcc index e9044558d..f7d3afcd9 100644 --- a/include/materials/mohr_coulomb.tcc +++ b/include/materials/mohr_coulomb.tcc @@ -468,9 +468,9 @@ Eigen::Matrix mpm::MohrCoulomb::compute_stress( return updated_stress; } -//! compute the acoustic tensor +//! Compute the elastic plastic tensor template -bool mpm::MohrCoulomb::compute_plastic_tensor( +bool mpm::MohrCoulomb::compute_elastic_plastic_tensor( const Vector6d& stress, mpm::dense_map* state_vars) { //------------------------------------------------------------------------- // Compute yield function based on the stress diff --git a/include/materials/norsand.h b/include/materials/norsand.h index e651bcaf1..8b23b5e69 100644 --- a/include/materials/norsand.h +++ b/include/materials/norsand.h @@ -55,24 +55,6 @@ class NorSand : public Material { Vector6d compute_stress(const Vector6d& stress, const Vector6d& dstrain, const ParticleBase* ptr, mpm::dense_map* state_vars) override; - //! return Plastic stiffness matrix - //! \param[in] stress Stress - //! \param[in] state_vars History-dependent state variables - //! \param[in] the yield status - virtual Matrix6x6 dp(const Vector6d& stress, mpm::dense_map* state_vars, - bool& status) { - //------------------------------------------------------------------------- - // Compute yield function based on the stress - double yield_function; - auto yield_type = - this->compute_yield_state(&yield_function, stress, state_vars); - // Return the updated stress in elastic state - if (yield_type == mpm::norsand::FailureState::Elastic) { - status = false; - } - compute_plastic_tensor(stress, state_vars); - return dp_; - } protected: //! material id diff --git a/include/mesh.h b/include/mesh.h index e745f28a6..40b0d3a45 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -428,10 +428,6 @@ class Mesh { //! Read HDF5 particles for singlephase particle //! \param[in] filename Name of HDF5 file to write particles data - //! \param[in] particle type of HDF5 file to generate particles class - //! \retval status Status of reading HDF5 output - bool read_particles_hdf5(unsigned phase, const std::string& filename, - const std::string& particle_type); //! \param[in] particle_type Particle type to be generated //! \retval status Status of reading HDF5 output bool read_particles_hdf5(const std::string& filename, @@ -505,7 +501,7 @@ class Mesh { // Initialise the nodal properties' map void initialise_nodal_properties(); - // Create the nodal properties' map for discontinuity + //! Create the nodal properties' map for discontinuity void create_nodal_properties_discontinuity(); //! Initialise discontinuity @@ -531,47 +527,51 @@ class Mesh { //! compute the normal vector of enriched nodes at the discontinuity void compute_nodal_normal_vector_discontinuity(); - //! Initialise the level set function values + //! Initialize the level set function values void initialise_levelset_discontinuity(); - //! Initialise the nodal level set function values + //! Initialize the nodal level set function values void initialise_nodal_levelset_discontinuity(); - //! solve nodal levelset values - void update_node_levelset(); - - // discontinuity growth + //! The evolution of the discontinuity void update_discontinuity(); - // find next tip element + //! Find next tip element void next_tip_element_discontinuity(); - // Initialise the cells in node + + // Initialize the cells in node void add_cell_in_node(); - //! remove spurious potential tip element + //! Remove spurious potential tip element void spurious_potential_tip_element(); - // assign_node_enrich + //! Assign node type as enrich + //! \param[in] whether use the average value of the surrounding particle + //! friction angle \param[in] whether enrich all the nodes void assign_node_enrich(bool friction_coef_average, bool enrich_all); - // update_node_enrich + //! Find all the nodes need to enriched void update_node_enrich(); - // the initiation of discontinuity + + //! The initiation of discontinuity bool initiation_discontinuity(); - // modify the nodal levelset_phi by mls + + //! Adjust the nodal levelset_phi by mls void modify_nodal_levelset_mls(); + //! Compute the distance between two sides of discontinuity void selfcontact_detection(); + //! code for debugging added by yliang start------------------------------- void output_discontinuity(int step) { this->discontinuity_->output_markpoints(step); }; void output_celltype(int step); - void define_levelset(); + //! code for debugging added by yliang end--------------------------------- - void output_surface(); - + //! Assign the level set values to the particles which just enter the crossed + //! cell void check_particle_levelset(bool particle_levelset); /** * \defgroup MultiPhase Functions dealing with multi-phase MPM @@ -743,7 +743,7 @@ class Mesh { } // namespace mpm #include "mesh.tcc" -#include "mesh_xmpm.tcc" #include "mesh_multiphase.tcc" +#include "mesh_xmpm.tcc" #endif // MPM_MESH_H_ diff --git a/include/mesh_multiphase.tcc b/include/mesh_multiphase.tcc index 7ae0e17e0..5fc10999a 100644 --- a/include/mesh_multiphase.tcc +++ b/include/mesh_multiphase.tcc @@ -439,7 +439,7 @@ std::set mpm::Mesh::free_surface_particles() { //! Compute cell volume fraction template void mpm::Mesh::compute_cell_vol_fraction() { - this->iterate_over_cells([&map_particles = map_particles_]( + this->iterate_over_cells([& map_particles = map_particles_]( std::shared_ptr> c_ptr) { if (c_ptr->status()) { // Compute volume fraction diff --git a/include/mesh_xmpm.tcc b/include/mesh_xmpm.tcc index c3078fa7b..eb43b915b 100644 --- a/include/mesh_xmpm.tcc +++ b/include/mesh_xmpm.tcc @@ -1,4 +1,4 @@ -// Create the nodal properties' map for discontinuity +//! Create the nodal properties' map for discontinuity template void mpm::Mesh::create_nodal_properties_discontinuity() { // Initialise the shared pointer to nodal properties @@ -34,18 +34,19 @@ template void mpm::Mesh::locate_discontinuity() { discontinuity_->locate_discontinuity_mesh(cells_, map_cells_); } -//! updated_position of discontinuity +//! Updated_position of discontinuity template void mpm::Mesh::compute_updated_position_discontinuity(double dt) { discontinuity_->compute_updated_position(dt); } -//! compute shape function + +//! Compute shape function template void mpm::Mesh::compute_shapefn_discontinuity() { discontinuity_->compute_shapefn(); } -// compute the normal vector of cells +//! Compute the normal vector of cells template void mpm::Mesh::compute_cell_normal_vector_discontinuity() { for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { @@ -54,7 +55,7 @@ void mpm::Mesh::compute_cell_normal_vector_discontinuity() { } } -// compute the normal vector of enriched nodes at the discontinuity +//! Compute the normal vector of enriched nodes at the discontinuity template void mpm::Mesh::compute_nodal_normal_vector_discontinuity() { @@ -77,7 +78,7 @@ void mpm::Mesh::compute_nodal_normal_vector_discontinuity() { } } -// Initialise level set values particles +//! Initialise level set values at particles template void mpm::Mesh::initialise_levelset_discontinuity() { @@ -90,7 +91,7 @@ void mpm::Mesh::initialise_levelset_discontinuity() { } } -// Initialise nodal level set values particles +//! Initialise nodal level set values particles template void mpm::Mesh::initialise_nodal_levelset_discontinuity() { @@ -104,15 +105,7 @@ void mpm::Mesh::initialise_nodal_levelset_discontinuity() { } } -// code for debugging added by yliang -//! solve nodal levelset values -template -void mpm::Mesh::update_node_levelset() { - for (auto nitr = nodes_.cbegin(); nitr != nodes_.cend(); ++nitr) - (*nitr)->update_levelset(); -} - -// discontinuity growth +//! The evolution of the discontinuity template void mpm::Mesh::update_discontinuity() { @@ -137,10 +130,7 @@ void mpm::Mesh::update_discontinuity() { virtual_enrich = true; break; } - if (virtual_enrich) { - // node->assign_discontinuity_enrich(true); - continue; - } + if (virtual_enrich) continue; for (auto cell : node->cells()) { if (map_cells_[cell]->element_type_discontinuity() != @@ -539,7 +529,7 @@ void mpm::Mesh::update_discontinuity() { } } -//! find next tip element +//! Find next tip element template void mpm::Mesh::next_tip_element_discontinuity() { std::string shear; @@ -569,7 +559,7 @@ void mpm::Mesh::next_tip_element_discontinuity() { return; } -//! remove spurious potential tip element +//! Remove spurious potential tip element template void mpm::Mesh::spurious_potential_tip_element() { @@ -607,7 +597,7 @@ void mpm::Mesh::spurious_potential_tip_element() { } } -// assign_node_enrich +//! Assign node type as enrich template void mpm::Mesh::assign_node_enrich(bool friction_coef_average, bool enrich_all) { @@ -648,7 +638,7 @@ void mpm::Mesh::assign_node_enrich(bool friction_coef_average, } } -// modify_node_enrich +//! Find all the nodes need to enriched template void mpm::Mesh::update_node_enrich() { @@ -665,6 +655,7 @@ void mpm::Mesh::update_node_enrich() { } } +//! The initiation of discontinuity template bool mpm::Mesh::initiation_discontinuity() { bool status = false; @@ -742,6 +733,7 @@ bool mpm::Mesh::initiation_discontinuity() { return status; } +//! Adjust the nodal levelset_phi by mls template void mpm::Mesh::modify_nodal_levelset_mls() { Eigen::Matrix au; @@ -890,6 +882,7 @@ void mpm::Mesh::modify_nodal_levelset_mls() { } } +//! Compute the distance between two sides of discontinuity template void mpm::Mesh::selfcontact_detection() { @@ -923,6 +916,8 @@ void mpm::Mesh::selfcontact_detection() { } } +//! Assign the level set values to the particles which just enter the crossed +//! cell template void mpm::Mesh::check_particle_levelset(bool particle_levelset) { @@ -1014,7 +1009,7 @@ void mpm::Mesh::check_particle_levelset(bool particle_levelset) { } } -// code for debugging added by yliang +//! code for debugging added by yliang start------------------------------- template void mpm::Mesh::output_celltype(int step) { std::ofstream test("cell_type.txt", std::ios::app); @@ -1145,4 +1140,5 @@ void mpm::Mesh::define_levelset() { // else if ((*pitr)->material_id(mpm::ParticlePhase::Solid) == 6) // (*pitr)->assign_levelsetphi(-1); } -} \ No newline at end of file +} +//! code for debugging added by yliang start------------------------------- \ No newline at end of file diff --git a/include/node.h b/include/node.h index fcb110663..295216007 100644 --- a/include/node.h +++ b/include/node.h @@ -297,10 +297,11 @@ class Node : public NodeBase { void compute_multimaterial_normal_unit_vector() override; //! Assign whether the node is enriched - //! \param[in] discontinuity discontinuity_enrich: true or false + //! \param[in] discontinuity_enrich_: true or false void assign_discontinuity_enrich(bool discontinuity) { discontinuity_enrich_ = discontinuity; }; + //! Return whether the node is enriched bool discontinuity_enrich() const { return discontinuity_enrich_; }; @@ -326,9 +327,9 @@ class Node : public NodeBase { unsigned discontinuity_id, unsigned nprops) noexcept; - // Return data in the nodal discontinuity properties map at a specific index - // \param[in] property Property name - // \param[in] nprops Dimension of property (1 if scalar, Tdim if vector) + //! Return data in the nodal discontinuity properties map at a specific index + //! \param[in] property Property name + //! \param[in] nprops Dimension of property (1 if scalar, Tdim if vector) Eigen::MatrixXd discontinuity_property(const std::string& property, unsigned nprops = 1) noexcept override; @@ -342,10 +343,10 @@ class Node : public NodeBase { //! \param[in] phase Index corresponding to the phase //! \param[in] dt Timestep in analysis //! \param[in] damping_factor Damping factor - virtual bool compute_momentum_discontinuity_cundall( + bool compute_momentum_discontinuity_cundall( unsigned phase, double dt, double damping_factor) noexcept override; - //! Apply self-contact of the discontinuity + //! Apply self-contact force of the discontinuity //! \param[in] dt Time-step void self_contact_discontinuity(double dt) noexcept override; @@ -354,14 +355,13 @@ class Node : public NodeBase { return discontinuity_prop_id_; }; - //! update the nodal levelset values - void update_levelset() noexcept override; - //! Add a cell id void add_cell_id(Index id) noexcept override; - //! Return cells_ + //! Return connected cells + //! \retval cells_ connected cells std::vector cells() const { return cells_; } + /** * \defgroup Implicit Functions dealing with implicit MPM */ @@ -701,8 +701,8 @@ class Node : public NodeBase { } // namespace mpm #include "node.tcc" -#include "node_xmpm.tcc" #include "node_implicit.tcc" #include "node_multiphase.tcc" +#include "node_xmpm.tcc" #endif // MPM_NODE_H_ diff --git a/include/node_base.h b/include/node_base.h index 9b9f1a548..63dcaa416 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -33,7 +33,6 @@ enum NodePhase : unsigned int { template class NodeBase { public: - double step_{0}; //! Define a vector of size dimension using VectorDim = Eigen::Matrix; @@ -225,7 +224,7 @@ class NodeBase { //! Assign velocity constraint //! Directions can take values between 0 and Dim * Nphases //! \param[in] dir Direction of velocity constraint - //! \param[in] velocity Applied velocity constraint + //! \param[ivirtualn] velocity Applied velocity constraint virtual bool assign_velocity_constraint(unsigned dir, double velocity) = 0; //! Apply velocity constraints @@ -294,9 +293,9 @@ class NodeBase { //! Compute multimaterial normal unit vector virtual void compute_multimaterial_normal_unit_vector() = 0; - // Return data in the nodal discontinuity properties map at a specific index - // \param[in] property Property name - // \param[in] nprops Dimension of property (1 if scalar, Tdim if vector) + //! Return data in the nodal discontinuity properties map at a specific index + //! \param[in] property Property name + //! \param[in] nprops Dimension of property (1 if scalar, Tdim if vector) virtual Eigen::MatrixXd discontinuity_property( const std::string& property, unsigned nprops = 1) noexcept = 0; @@ -342,15 +341,13 @@ class NodeBase { virtual bool compute_momentum_discontinuity_cundall( unsigned phase, double dt, double damping_factor) noexcept = 0; - //! Apply self-contact of the discontinuity + //! Apply self-contact force of the discontinuity //! \param[in] dt Time-step virtual void self_contact_discontinuity(double dt) noexcept = 0; //! Return the discontinuity_prop_id virtual unsigned discontinuity_prop_id() const noexcept = 0; - //! update the nodal levelset values - virtual void update_levelset() = 0; //! Add a cell id virtual void add_cell_id(Index id) = 0; diff --git a/include/node_xmpm.tcc b/include/node_xmpm.tcc index 15af720e0..ba7ea8431 100644 --- a/include/node_xmpm.tcc +++ b/include/node_xmpm.tcc @@ -14,7 +14,7 @@ void mpm::Node::update_discontinuity_property( bool update, const std::string& property, const Eigen::MatrixXd& property_value, unsigned discontinuity_id, unsigned nprops) noexcept { - // Update/assign property + // Update property node_mutex_.lock(); property_handle_->update_property(property, discontinuity_prop_id_, discontinuity_id, property_value, nprops); @@ -27,7 +27,7 @@ void mpm::Node::assign_discontinuity_property( bool update, const std::string& property, const Eigen::MatrixXd& property_value, unsigned discontinuity_id, unsigned nprops) noexcept { - // Update/assign property + // assign property node_mutex_.lock(); property_handle_->assign_property(property, discontinuity_prop_id_, discontinuity_id, property_value, nprops); @@ -41,7 +41,7 @@ Eigen::MatrixXd mpm::Node::discontinuity_property( // Const pointer to location of property: node_id * nprops x mat_id auto property_value = property_handle_->property(property, discontinuity_prop_id_, 0, nprops); - // mpm::MapProperty property_handle(position, nprops); + return property_value; } @@ -92,41 +92,41 @@ bool mpm::Node::compute_momentum_discontinuity_cundall( } else { - // // obtain the enriched values of enriched nodes - // Eigen::Matrix mass_enrich = - // property_handle_->property("mass_enrich", discontinuity_prop_id_, 0, 1); - - // // mass for different sides - // auto mass_positive = mass_.col(phase) + mass_enrich; - // auto mass_negative = mass_.col(phase) - mass_enrich; - - // Eigen::Matrix momenta_enrich = property_handle_->property( - // "momenta_enrich", discontinuity_prop_id_, 0, Tdim); - // Eigen::Matrix unbalanced_force = - // this->external_force_.col(phase) + this->internal_force_.col(phase); - // Eigen::Matrix unbalanced_force_enrich = - // property_handle_->property("internal_force_enrich", - // discontinuity_prop_id_, 0, Tdim) + - // property_handle_->property("external_force_enrich", - // discontinuity_prop_id_, 0, Tdim); - - // Eigen::Matrix damp_force_positive = - // -damping_factor * (unbalanced_force + unbalanced_force_enrich).norm() * - // (this->momentum_.col(phase) + momenta_enrich).normalized(); - - // if (mass_positive(phase) < tolerance) damp_force_positive.setZero(); - - // Eigen::Matrix damp_force_negative = - // -damping_factor * (unbalanced_force - unbalanced_force_enrich).norm() * - // (this->momentum_.col(phase) - momenta_enrich).normalized(); - - // if (mass_negative(phase) < tolerance) damp_force_negative.setZero(); - // this->external_force_.col(phase) += - // 0.5 * (damp_force_positive + damp_force_negative); - - // property_handle_->update_property( - // "external_force_enrich", discontinuity_prop_id_, 0, - // 0.5 * (damp_force_positive - damp_force_negative), Tdim); + // obtain the enriched values of enriched nodes + double mass_enrich = property_handle_->property( + "mass_enrich", discontinuity_prop_id_, 0, 1)(0, 0); + + // mass for different sides + double mass_positive = mass_(phase) + mass_enrich; + double mass_negative = mass_(phase) - mass_enrich; + + Eigen::Matrix momenta_enrich = property_handle_->property( + "momenta_enrich", discontinuity_prop_id_, 0, Tdim); + Eigen::Matrix unbalanced_force = + this->external_force_.col(phase) + this->internal_force_.col(phase); + Eigen::Matrix unbalanced_force_enrich = + property_handle_->property("internal_force_enrich", + discontinuity_prop_id_, 0, Tdim) + + property_handle_->property("external_force_enrich", + discontinuity_prop_id_, 0, Tdim); + // neet to be fixed + Eigen::Matrix damp_force_positive = + -damping_factor * (unbalanced_force + unbalanced_force_enrich).norm() * + (this->momentum_.col(phase) + momenta_enrich).normalized(); + + if (mass_positive < tolerance) damp_force_positive.setZero(); + + Eigen::Matrix damp_force_negative = + -damping_factor * (unbalanced_force - unbalanced_force_enrich).norm() * + (this->momentum_.col(phase) - momenta_enrich).normalized(); + + if (mass_negative < tolerance) damp_force_negative.setZero(); + this->external_force_.col(phase) += + 0.5 * (damp_force_positive + damp_force_negative); + + property_handle_->update_property( + "external_force_enrich", discontinuity_prop_id_, 0, + 0.5 * (damp_force_positive - damp_force_negative), Tdim); } compute_momentum_discontinuity(phase, dt); @@ -171,21 +171,6 @@ void mpm::Node inverse_rotation_matrix = - rotation_matrix_.inverse(); - // Transform to local coordinate - Eigen::Matrix local_velocity = - inverse_rotation_matrix * this->velocity_; - Eigen::Matrix local_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 - this->velocity_ = rotation_matrix_ * local_velocity; - this->acceleration_ = rotation_matrix_ * local_acceleration; } } } @@ -193,148 +178,102 @@ void mpm::Node void mpm::Node::self_contact_discontinuity( double dt) noexcept { + // need to be fixed + if (!discontinuity_enrich_) return; -// if (!discontinuity_enrich_) return; - -// double contact_distance = property_handle_->property( -// "contact_distance", discontinuity_prop_id_, 0, 1)(0, 0); - -// Eigen::Matrix normal_vector = property_handle_->property( -// "normal_unit_vectors_discontinuity", discontinuity_prop_id_, 0, Tdim); - -// if (contact_distance >= 0) return; -// // single phase for solid -// unsigned phase = 0; -// const double tolerance = 1.0E-15; - -// // obtain the enriched values of enriched nodes -// Eigen::Matrix mass_enrich = -// property_handle_->property("mass_enrich", discontinuity_prop_id_, 0, 1); -// Eigen::Matrix momenta_enrich = property_handle_->property( -// "momenta_enrich", discontinuity_prop_id_, 0, Tdim); - -// // mass for different sides -// auto mass_positive = mass_.col(phase) + mass_enrich; -// auto mass_negative = mass_.col(phase) - mass_enrich; - -// if (mass_positive(phase) < tolerance || mass_negative(phase) < tolerance) -// return; - -// // velocity for different sides -// auto velocity_positive = -// (momentum_.col(phase) + momenta_enrich) / mass_positive(phase); -// auto velocity_negative = -// (momentum_.col(phase) - momenta_enrich) / mass_negative(phase); - -// // relative normal velocity -// if ((velocity_positive - velocity_negative).col(phase).dot(normal_vector) >= -// 0) -// return; - -// // the contact momentum, force vector for sticking contact -// auto momentum_contact = (mass_enrich(phase) * momentum_.col(phase) - -// mass_(phase) * momenta_enrich) / -// mass_(phase); -// auto force_contact = momentum_contact / dt; - -// // friction_coef < 0: move together without slide -// double friction_coef = property_handle_->property( -// "friction_coef", discontinuity_prop_id_, 0, 1)(0, 0); - -// if (friction_coef < 0) { -// property_handle_->update_property("momenta_enrich", discontinuity_prop_id_, -// 0, momentum_contact.col(phase), Tdim); -// property_handle_->update_property("external_force_enrich", -// discontinuity_prop_id_, 0, -// force_contact.col(phase), Tdim); -// } else { -// // the contact momentum, force value for sticking contact at normal -// // direction -// double momentum_contact_norm = -// momentum_contact.col(phase).dot(normal_vector); -// double force_contact_norm = momentum_contact_norm / dt; - -// // the cohesion at nodes -// double cohesion = property_handle_->property( -// "cohesion", discontinuity_prop_id_, 0, 1)(0, 0); - -// if (coordinates_[0] < 513) -// cohesion = 25000; -// else if (coordinates_[0] < 660) -// cohesion = 25000; -// else if (coordinates_[0] < 893.6) -// cohesion = 10000; -// else if (coordinates_[0] < 955) -// cohesion = 0; -// else if (coordinates_[0] < 1005) -// cohesion = (coordinates_[0] - 955) / 50 * 10000; -// else -// cohesion = 10000; - -// if (coordinates_[0] < 200) -// cohesion = 0; -// else if (coordinates_[0] < 513) -// cohesion = 150000; -// else if (coordinates_[0] < 660) -// cohesion = 25000; -// else if (coordinates_[0] < 893.6) -// cohesion = 10000; -// else if (coordinates_[0] < 955) -// cohesion = 0; -// else if (coordinates_[0] < 1005) -// cohesion = (coordinates_[0] - 955) / 50 * 10000; -// else -// cohesion = 10000; -// // cohesion = 0; - -// // the cohesion at nodes -// double cohesion_area = property_handle_->property( -// "cohesion_area", discontinuity_prop_id_, 0, 1)(0, 0); -// // if (std::isnan(cohesion_area) || cohesion_area <= 0 || cohesion_area > 2) -// // cohesion_area = 0; -// double max_friction_force = -// friction_coef * abs(force_contact_norm) + 2 * cohesion * cohesion_area; - -// // the contact momentum, force vector for sticking contact at tangential -// // direction -// auto momentum_tangential = -// momentum_contact.col(phase) - momentum_contact_norm * normal_vector; -// auto force_tangential = momentum_tangential / dt; - -// // the friction force magnitude -// double force_tangential_value = force_tangential.norm(); - -// double force_friction = force_tangential_value < max_friction_force -// ? force_tangential_value -// : max_friction_force; - -// // adjust the momentum and force -// property_handle_->update_property( -// "momenta_enrich", discontinuity_prop_id_, 0, -// momentum_contact_norm * normal_vector + -// force_friction * force_tangential.col(phase).normalized() * dt, -// Tdim); -// property_handle_->update_property( -// "external_force_enrich", discontinuity_prop_id_, 0, -// force_contact_norm * normal_vector + -// force_friction * force_tangential.col(phase).normalized(), -// Tdim); -// } -} + double contact_distance = property_handle_->property( + "contact_distance", discontinuity_prop_id_, 0, 1)(0, 0); -//! Apply self-contact of the discontinuity -template -void mpm::Node::update_levelset() noexcept { - Eigen::Matrix origin; - return; - origin << 28.2 - coordinates_[0], 27.2 - coordinates_[1], coordinates_[2]; - - Eigen::Matrix levelset; - // levelset(0, 0) = 22.4933 - origin.norm(); - // levelset(0, 0) = (2.05 - 1.738)/(0.99-0.81)*() + - // if (discontinuity_enrich_) - property_handle_->assign_property("levelset_phi", discontinuity_prop_id_, 0, - levelset, 1); + Eigen::Matrix normal_vector = property_handle_->property( + "normal_unit_vectors_discontinuity", discontinuity_prop_id_, 0, Tdim); + + if (contact_distance >= 0) return; + // single phase for solid + unsigned phase = 0; + const double tolerance = 1.0E-15; + + // obtain the enriched values of enriched nodes + double mass_enrich = property_handle_->property( + "mass_enrich", discontinuity_prop_id_, 0, 1)(0, 0); + Eigen::Matrix momenta_enrich = property_handle_->property( + "momenta_enrich", discontinuity_prop_id_, 0, Tdim); + + // mass for different sides + double mass_positive = mass_(phase) + mass_enrich; + double mass_negative = mass_(phase) - mass_enrich; + + if (mass_positive < tolerance || mass_negative < tolerance) return; + + // velocity for different sides + auto velocity_positive = + (momentum_.col(phase) + momenta_enrich) / mass_positive; + auto velocity_negative = + (momentum_.col(phase) - momenta_enrich) / mass_negative; + + // relative normal velocity + if ((velocity_positive - velocity_negative).col(phase).dot(normal_vector) >= + 0) + return; + + // the contact momentum, force vector for sticking contact + auto momentum_contact = + (mass_enrich * momentum_.col(phase) - mass_(phase) * momenta_enrich) / + mass_(phase); + auto force_contact = momentum_contact / dt; + + // friction_coef < 0: move together without slide + double friction_coef = property_handle_->property( + "friction_coef", discontinuity_prop_id_, 0, 1)(0, 0); + + if (friction_coef < 0) { + property_handle_->update_property("momenta_enrich", discontinuity_prop_id_, + 0, momentum_contact.col(phase), Tdim); + property_handle_->update_property("external_force_enrich", + discontinuity_prop_id_, 0, + force_contact.col(phase), Tdim); + } else { + // the contact momentum, force value for sticking contact at normal + // direction + double momentum_contact_norm = + momentum_contact.col(phase).dot(normal_vector); + double force_contact_norm = momentum_contact_norm / dt; + + // the cohesion at nodes + double cohesion = property_handle_->property( + "cohesion", discontinuity_prop_id_, 0, 1)(0, 0); + + // the cohesion at nodes + double cohesion_area = property_handle_->property( + "cohesion_area", discontinuity_prop_id_, 0, 1)(0, 0); + + double max_friction_force = + friction_coef * abs(force_contact_norm) + 2 * cohesion * cohesion_area; + + // the contact momentum, force vector for sticking contact at tangential + // direction + auto momentum_tangential = + momentum_contact.col(phase) - momentum_contact_norm * normal_vector; + auto force_tangential = momentum_tangential / dt; + + // the friction force magnitude + double force_tangential_value = force_tangential.norm(); + + double force_friction = force_tangential_value < max_friction_force + ? force_tangential_value + : max_friction_force; + + // adjust the momentum and force + property_handle_->update_property( + "momenta_enrich", discontinuity_prop_id_, 0, + momentum_contact_norm * normal_vector + + force_friction * force_tangential.col(phase).normalized() * dt, + Tdim); + property_handle_->update_property( + "external_force_enrich", discontinuity_prop_id_, 0, + force_contact_norm * normal_vector + + force_friction * force_tangential.col(phase).normalized(), + Tdim); + } } //! Add a cell id diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index 217336035..6e3171ccd 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -806,7 +806,6 @@ bool mpm::Particle::assign_traction(unsigned direction, double traction) { } // Assign traction traction_(direction) = traction * this->volume_ / this->size_(direction); - traction_(direction) = traction; status = true; this->set_traction_ = true; } catch (std::exception& exception) { diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 71740c7a1..2891e1cf9 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -351,9 +351,6 @@ class ParticleBase { //! \param[in] phivalue Signed distance function virtual void assign_levelsetphi(double phivalue){}; - //! Compute the principal stress and strain - virtual void compute_principal_stress_strain(){}; - //! Map particle volume to nodes virtual void map_volume_to_nodes() noexcept = 0; @@ -361,22 +358,26 @@ class ParticleBase { virtual void map_levelset_to_nodes(){}; //! Map particle frictional_coef to nodes + //! \param[in] the default friction coefficient virtual void map_friction_coef_to_nodes(double discontinuity_friction_coef){}; //! Map levelset from nodes to particles virtual void map_levelset_to_particle(){}; - //! Compute dudx + //! Compute displacement //! \param[in] dt Analysis time step virtual void compute_dudx(double dt){}; - // virtual void check_levelset(){}; + //! to do + //! virtual void check_levelset(){}; //! return levelset values virtual double levelset_phi() { return 0; } //! compute the minimum eigenvalue of the acoustic tensor - //! \param[in] the normal direction of the discontinuity + //! \param[in] the normal direction of the previous discontinuity + //! \param[in] do the initiation detection loop + //! \retval whether initiate or propagate virtual bool minimum_acoustic_tensor(VectorDim& normal_cell, bool initiation) { return false; diff --git a/include/particles/particle_xmpm.h b/include/particles/particle_xmpm.h index 8c4c4d60f..ecd937018 100644 --- a/include/particles/particle_xmpm.h +++ b/include/particles/particle_xmpm.h @@ -28,12 +28,6 @@ class ParticleXMPM : public Particle { //! \param[in] coord coordinates of the particle ParticleXMPM(Index id, const VectorDim& coord); - //! Construct a 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) - ParticleXMPM(Index id, const VectorDim& coord, bool status); - //! Destructor ~ParticleXMPM() override = default; @@ -43,8 +37,8 @@ class ParticleXMPM : public Particle { //! Delete assignment operator ParticleXMPM& operator=(const ParticleXMPM&) = delete; - //! Initialise particle from HDF5 data - //! \param[in] particle HDF5 data of particle + //! Initialise particle from POD data + //! \param[in] particle POD data of particle //! \retval status Status of reading HDF5 particle bool initialise_particle(PODParticle& particle) override; @@ -52,7 +46,6 @@ class ParticleXMPM : public Particle { //! \retval particle POD of the particle std::shared_ptr pod() const override; - //! Initialise properties void initialise() override; //! Type of particle @@ -72,9 +65,6 @@ class ParticleXMPM : public Particle { //! Map internal force inline void map_internal_force() noexcept override; - //! Compute the principal stress and strain - void compute_principal_stress_strain(); - //! Map particle levelset to nodes void map_levelset_to_nodes() noexcept override; @@ -82,11 +72,13 @@ class ParticleXMPM : public Particle { //! \param[in] friction_coef of the discontinuity void map_friction_coef_to_nodes( double discontinuity_friction_coef) noexcept override; - //! Compute dudx + + //! Compute displacement gradient //! \param[in] dt Analysis time step void compute_dudx(double dt) noexcept; - // virtual void check_levelset() noexcept override; + //! to do + //! virtual void check_levelset() noexcept override; //! Compute updated position of the particle //! \param[in] dt Analysis time step @@ -105,13 +97,16 @@ class ParticleXMPM : public Particle { void map_levelset_to_particle(); //! return levelset values + //! \retval particle levelset values double levelset_phi() { return levelset_phi_; } //! compute the minimum eigenvalue of the acoustic tensor - //! \param[in] the normal direction of the discontinuity + //! \param[in] the normal direction of the previous discontinuity + //! \param[in] do the initiation detection loop bool minimum_acoustic_tensor(VectorDim& normal_cell, bool initiation); - //! compute the gradient of displacement dot direction + //! compute the initiation normal direction + //! \param[in] initiation normal direction void compute_initiation_normal(VectorDim& normal); private: @@ -203,13 +198,6 @@ class ParticleXMPM : public Particle { //! level set value: phi for discontinuity double levelset_phi_{0.}; - //! first principal stress - double first_principal_stress_{0.}; - //! first principal strain - double first_principal_strain_{0.}; - //! energy:first_principal_stress_*first_principal_strain_*0.5 - double energy_{0.}; - //! the minimum eigenvalue of the acoustic tensor double minimum_acoustic_eigenvalue_{1e16}; diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index 7e7c272ad..9693ab858 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -9,38 +9,24 @@ mpm::ParticleXMPM::ParticleXMPM(Index id, const VectorDim& coord) console_ = std::make_unique(logger, mpm::stdout_sink); } -//! Construct a particle with id, coordinates and status -template -mpm::ParticleXMPM::ParticleXMPM(Index id, const VectorDim& coord, - bool status) - : mpm::Particle(id, coord, status) { - this->initialise(); - //! Logger - std::string logger = - "particlexmpm" + std::to_string(Tdim) + "d::" + std::to_string(id); - console_ = std::make_unique(logger, mpm::stdout_sink); -} - //! Initialise particle data from pod template bool mpm::ParticleXMPM::initialise_particle(PODParticle& particle) { bool status = mpm::Particle::initialise_particle(particle); // levelset_phi - //to do + // to do levelset_phi_ = particle.levelset_phi; return status; } - //! Return particle data as POD template // cppcheck-suppress * std::shared_ptr mpm::ParticleXMPM::pod() const { - auto particle_data = std::make_shared(); - //to do + // to do particle_data->levelset_phi = levelset_phi_; return particle_data; } @@ -52,13 +38,6 @@ void mpm::ParticleXMPM::initialise() { du_dx_.setZero(); this->scalar_properties_["levelset"] = [&]() { return levelset_phi_; }; - this->scalar_properties_["first_principal_stress"] = [&]() { - return first_principal_stress_; - }; - this->scalar_properties_["first_principal_strain"] = [&]() { - return first_principal_strain_; - }; - this->scalar_properties_["energy"] = [&]() { return energy_; }; this->scalar_properties_["minimum_acoustic_eigenvalue"] = [&]() { return minimum_acoustic_eigenvalue_; @@ -349,42 +328,6 @@ void mpm::ParticleXMPM::compute_updated_position( this->displacement_ += nodal_velocity * dt; } -//! Compute the principal stress and strain -template -void mpm::ParticleXMPM::compute_principal_stress_strain() { - - Eigen::Matrix3d strain_tensor; - strain_tensor(0, 0) = strain_[0]; - strain_tensor(0, 1) = strain_[3] * 0.5; - strain_tensor(0, 2) = strain_[5] * 0.5; - strain_tensor(1, 0) = strain_[3] * 0.5; - strain_tensor(1, 1) = strain_[1]; - strain_tensor(1, 2) = strain_[4] * 0.5; - strain_tensor(2, 0) = strain_[5] * 0.5; - strain_tensor(2, 1) = strain_[4] * 0.5; - strain_tensor(2, 2) = strain_[2]; - - Eigen::Matrix3d stress_tensor; - stress_tensor(0, 0) = stress_[0]; - stress_tensor(0, 1) = stress_[3]; - stress_tensor(0, 2) = stress_[5]; - stress_tensor(1, 0) = stress_[3]; - stress_tensor(1, 1) = stress_[1]; - stress_tensor(1, 2) = stress_[4]; - stress_tensor(2, 0) = stress_[5]; - stress_tensor(2, 1) = stress_[4]; - stress_tensor(2, 2) = stress_[2]; - - Eigen::EigenSolver estrain(strain_tensor); - Eigen::EigenSolver estress(stress_tensor); - - first_principal_strain_ = estrain.pseudoEigenvalueMatrix()(0); - first_principal_stress_ = estress.pseudoEigenvalueMatrix()(0); - auto strain_value = estrain.pseudoEigenvectors(); - auto stress_value = estress.pseudoEigenvectors(); - energy_ = 0.5 * first_principal_strain_ * first_principal_stress_; -} - //! Map levelset from nodes to particles template void mpm::ParticleXMPM::map_levelset_to_particle() { @@ -412,15 +355,12 @@ bool mpm::ParticleXMPM::minimum_acoustic_tensor(VectorDim& normal_cell, if (!yield_status) return false; // testa <<"dp"< de = (this->material())->de(); - // clang-format off + Eigen::Matrix index; - index << 0, 3, 5, - 3, 1, 4, - 5, 4, 2; -//testa <<"de"< normal_cellcenter; normal_cellcenter.setZero(); - //compute the initial direction + // compute the initial direction if (!initiation) { for (int i = 0; i < nodes_.size(); i++) { @@ -432,16 +372,14 @@ bool mpm::ParticleXMPM::minimum_acoustic_tensor(VectorDim& normal_cell, normal_cellcenter = cell_->normal_discontinuity(); } - if(initiation){ - //!compute the gradient of displacement dot direction - compute_initiation_normal(normal_cellcenter); - initiation = false; -// normal_cell << 0, 1,0; -// return true; + if (initiation) { + //! compute the gradient of displacement dot direction + compute_initiation_normal(normal_cellcenter); + initiation = false; } normal_cellcenter.normalize(); - //Iteration + // Iteration Eigen::Matrix nk = normal_cellcenter; Eigen::Matrix nk1; @@ -455,248 +393,84 @@ bool mpm::ParticleXMPM::minimum_acoustic_tensor(VectorDim& normal_cell, Eigen::Matrix A; Eigen::Matrix J; - for(int itr = 0; itr < itr_max; ++itr) - { - if(itr_error < itr_tol) - break; - - A.setZero(); - J.setZero(); - for (int m = 0; m < 3; m++) - for (int n = 0; n < 3; n++) { + for (int itr = 0; itr < itr_max; ++itr) { + if (itr_error < itr_tol) break; - for (int r = 0; r < 3; r++) - for (int s = 0; s < 3; s++) - A(m, n) += - nk(r) * nk(s) * dp(index(m, r), index(n, s)); - } - double det_A = A.determinant(); - Eigen::Matrix inv_A = A.inverse(); - - //testa <<"A"< eigen_J(J); - auto eigenvalues = eigen_J.pseudoEigenvalueMatrix(); - auto eigenvectors = eigen_J.pseudoEigenvectors(); - - - - double project = -1e6; - for(int i = 0; i < 3; ++i) - { - Eigen::Matrix eigen = eigenvectors.col(i); - eigenvalue_j[i] = eigenvalues(i,i); - - if(eigen.dot(nk) < 0) - eigen = -eigen; - if(std::abs(eigen.dot(nk)) < project) - continue; - - project = std::abs(eigen.dot(nk)); - nk1 = eigen; - uk1 = eigenvalues(i,i); + A(m, n) += nk(r) * nk(s) * dp(index(m, r), index(n, s)); } - - - itr_error = (nk1-nk).norm() + std::abs(uk1/uk - 1); - console_->info("\n itr:{},{}\nJ eigen:{},{},{}", itr,itr_error,eigenvalues(0,0),eigenvalues(1,1),eigenvalues(2,2)); - // console_->info("wrong iteration of acoustic tensor, {},{},{},{},{},{},{},{},{},{},{}",itr,det_A,itr_error,nk[0],nk[1],nk[2],nk1[0],nk1[1],nk1[2],uk1,uk); - nk = nk1; - uk = uk1; - if(itr >= 999){ - console_->error("wrong iteration of acoustic tensor, {},{},{},{},{},{},{},{},{},{}",itr,itr_error,nk[0],nk[1],nk[2],nk1[0],nk1[1],nk1[2],uk1,uk); - if(itr_error < 1e-6) - continue; - nk = normal_cellcenter; - } - } - if(normal_cellcenter.dot(nk) < 0) - nk = -nk; - - //check det(A) - A.setZero(); - for (int m = 0; m < 3; m++) - for (int n = 0; n < 3; n++) { - for (int r = 0; r < 3; r++) - for (int s = 0; s < 3; s++) - A(m, n) += - nk(r) * nk(s) * dp(index(m, r), index(n, s)); - } double det_A = A.determinant(); - Eigen::EigenSolver eigen_A(A); - auto eigenvalues = eigen_A.pseudoEigenvalueMatrix(); - auto eigenvectors = eigen_A.pseudoEigenvectors(); - - // testa<info("\n A eigen:{},{},{},{}\n", det_A,eigenvalues(0,0),eigenvalues(1,1),eigenvalues(2,2)); - // if(det_A > 0) - // return false; - normal_cell = nk; - console_->info("\n normal:{},{},{},\nA eigen:{},{},{},{}\n", nk[0],nk[1],nk[2],det_A,eigenvalues(0,0),eigenvalues(1,1),eigenvalues(2,2)); + Eigen::Matrix inv_A = A.inverse(); - return true; + for (int m = 0; m < 3; m++) + for (int n = 0; n < 3; n++) { - // clang-format on - Eigen::Matrix dp_n; - Eigen::Matrix de_n; + for (int r = 0; r < 3; r++) + for (int s = 0; s < 3; s++) + J(m, n) += inv_A(r, s) * (dp(index(m, s), index(r, n)) + + dp(index(n, s), index(r, m))); + } + J = J * 0.5 * det_A; - Eigen::Matrix normal; - Eigen::Matrix normal_propagation; + Eigen::EigenSolver eigen_J(J); + auto eigenvalues = eigen_J.pseudoEigenvalueMatrix(); + auto eigenvectors = eigen_J.pseudoEigenvectors(); - normal_propagation.setZero(); + double project = -1e6; + for (int i = 0; i < 3; ++i) { + Eigen::Matrix eigen = eigenvectors.col(i); + eigenvalue_j[i] = eigenvalues(i, i); - if (!initiation) { + if (eigen.dot(nk) < 0) eigen = -eigen; + if (std::abs(eigen.dot(nk)) < project) continue; - for (int i = 0; i < nodes_.size(); i++) { - double levelset = - nodes_[i]->discontinuity_property("levelset_phi", 1)(0, 0); - for (int j = 0; j < 3; j++) - normal_cellcenter[j] += dn_dx_centroid_(i, j) * levelset; + project = std::abs(eigen.dot(nk)); + nk1 = eigen; + uk1 = eigenvalues(i, i); } - normal_cellcenter.normalize(); - } - - if (initiation) { - normal_cellcenter << 0, 1, 0; - initiation = false; - } - - double theta; - double phi; - double discontinuity_angle = 0; - double dtheta = 0.1; - const double PI = 3.141592653 / 180; - - double det_de_n; - double det_dp_n; - - double mininum_ratio = std::numeric_limits::max(); - - for (int i = 0; i < std::floor(360 / dtheta); i++) { - for (int j = 0; j < 1; j++) { - double theta = i * dtheta * PI; - double phi = j * dtheta * PI; - normal << std::cos(phi) * std::cos(theta), - std::cos(phi) * std::sin(theta), std::sin(phi); - dp_n.setZero(); - de_n.setZero(); - for (int m = 0; m < 3; m++) - for (int n = 0; n < 3; n++) { - - for (int r = 0; r < 3; r++) - for (int s = 0; s < 3; s++) - dp_n(m, n) += - normal(r) * normal(s) * dp(index(m, r), index(n, s)); - } - - det_dp_n = dp_n.determinant(); - for (int m = 0; m < 3; m++) - for (int n = 0; n < 3; n++) { - - for (int r = 0; r < 3; r++) - for (int s = 0; s < 3; s++) - de_n(m, n) += - normal(r) * normal(s) * de(index(m, r), index(n, s)); - } - - det_de_n = de_n.determinant(); - double ratio = det_dp_n / det_de_n; - - if (ratio < 1e-3) { - - if (!initiation) { - if (normal_cellcenter(0) * normal(0) + - normal_cellcenter(1) * normal(1) + - normal_cellcenter(1) * normal(2) > - normal_cellcenter(0) * normal_propagation(0) + - normal_cellcenter(1) * normal_propagation(1) + - normal_cellcenter(2) * normal_propagation(2)) { - minimum_acoustic_eigenvalue_ = -1; - normal_propagation = normal; - discontinuity_angle = theta; - // test << ratio << ", angele: "; - // test << discontinuity_angle / PI << ", "; - } - } else { - if (ratio < mininum_ratio) { - mininum_ratio = ratio; - minimum_acoustic_eigenvalue_ = -1; - normal_propagation = normal; - discontinuity_angle = theta; - // test << ratio << ", angele: "; - // test << discontinuity_angle / PI << ", "; - } - } - } - - // Eigen::EigenSolver eigen_acoustic_n(acoustic_n); - // auto eigenvalues = eigen_acoustic_n.pseudoEigenvalueMatrix(); - // auto minimum_eigen = eigenvalues(0, 0) < eigenvalues(1, 1) - // ? eigenvalues(0, 0) - // : eigenvalues(1, 1); - // minimum_eigen = - // minimum_eigen < eigenvalues(1, 1) ? minimum_eigen : eigenvalues(2, - // 2); - // if (minimum_acoustic_eigenvalue_ > minimum_eigen) { - // minimum_acoustic_eigenvalue_ = minimum_eigen; - // normal_propagation = normal; - // } + itr_error = (nk1 - nk).norm() + std::abs(uk1 / uk - 1); + console_->info("\n itr:{},{}\nJ eigen:{},{},{}", itr, itr_error, + eigenvalues(0, 0), eigenvalues(1, 1), eigenvalues(2, 2)); + nk = nk1; + uk = uk1; + if (itr >= 999) { + console_->error( + "wrong iteration of acoustic tensor, {},{},{},{},{},{},{},{},{},{}", + itr, itr_error, nk[0], nk[1], nk[2], nk1[0], nk1[1], nk1[2], uk1, uk); + if (itr_error < 1e-6) continue; + nk = normal_cellcenter; } } - - // test << std::endl; - discontinuity_angle_ = discontinuity_angle / PI; - - if (minimum_acoustic_eigenvalue_ > 0) return false; - - // if (discontinuity_angle_ < 120) { - // discontinuity_angle_ = 120; - // double theta = discontinuity_angle_ * PI; - // double phi = 0; - // normal_propagation << std::cos(phi) * std::cos(theta), - // std::cos(phi) * std::sin(theta), std::sin(phi); + if (normal_cellcenter.dot(nk) < 0) nk = -nk; + normal_cell = nk; + // to do + // A.setZero(); + // for (int m = 0; m < 3; m++) + // for (int n = 0; n < 3; n++) { + // for (int r = 0; r < 3; r++) + // for (int s = 0; s < 3; s++) + // A(m, n) += + // nk(r) * nk(s) * dp(index(m, r), index(n, s)); // } - - double max_theta = 60 * PI; - if (!initiation) { - double dot_normal = normal_cellcenter(0) * normal_propagation(0) + - normal_cellcenter(1) * normal_propagation(1) + - normal_cellcenter(2) * normal_propagation(2); - - if (dot_normal < 0) normal_propagation = -normal_propagation; - - dot_normal = normal_cellcenter(0) * normal_propagation(0) + - normal_cellcenter(1) * normal_propagation(1) + - normal_cellcenter(2) * normal_propagation(2); - - if (dot_normal < std::cos(max_theta)) return false; - } - - // double theta_diff = std::acos(dot_normal); - - normal_propagation = 1.0 * normal_propagation; - - normal_propagation.normalize(); - discontinuity_angle_ = std::acos(normal_propagation(0)) / PI; - if (normal_propagation(1) < 0) discontinuity_angle_ = -discontinuity_angle_; - - normal_cell = normal_propagation; + // double det_A = A.determinant(); + // Eigen::EigenSolver eigen_A(A); + // auto eigenvalues = eigen_A.pseudoEigenvalueMatrix(); + // auto eigenvectors = eigen_A.pseudoEigenvectors(); + + // console_->info("\n A eigen:{},{},{},{}\n", + // det_A,eigenvalues(0,0),eigenvalues(1,1),eigenvalues(2,2)); + + // console_->info("\n normal:{},{},{},\nA eigen:{},{},{},{}\n", nk[0], + // nk[1], + // nk[2], det_A, eigenvalues(0, 0), eigenvalues(1, 1), + // eigenvalues(2, 2)); return true; } @@ -729,7 +503,7 @@ void mpm::ParticleXMPM::compute_initiation_normal( (this->material()) ->dp(stress_, &state_variables_[mpm::ParticlePhase::Solid], yield_status); - // testa <<"dp"< de = (this->material())->de(); // clang-format off Eigen::Matrix index; @@ -782,24 +556,19 @@ void mpm::ParticleXMPM::compute_initiation_normal( a2 = dudx_n.dot(normal_m2); double angle = 0; + + angle = std::atan(a2/a1); if(a1 == 0) angle = M_PI_2; - angle = std::atan(a2/a1); double dudx_mn = std::abs(a1*std::cos(angle) + a2*std::sin(angle)); if(dudx_mn > max_dudxmn) { max_dudxmn = dudx_mn; normal_initiation = normal; - } - //test<::compute_dudx(double dt) noexcept { du_dx_(j,k) += dudx_rate(j,k)*dt; } +//to do //! Map particle friction_coef_to_nodes // template // void mpm::ParticleXMPM::check_levelset() noexcept { diff --git a/include/solvers/mpm_base.h b/include/solvers/mpm_base.h index 2d3da492d..be2e5fbdb 100644 --- a/include/solvers/mpm_base.h +++ b/include/solvers/mpm_base.h @@ -37,14 +37,6 @@ namespace mpm { //! Vector: Vector of size 3 //! Tensor: Symmetric tensor arranged in voigt notation enum class VariableType { Scalar, Vector, Tensor }; -extern tsl::robin_map variables; - -//! Stress update method -//! USF: Update Stress First -//! USL: Update Stress Last -//! MUSL: Modified Stress Last -enum class StressUpdate { USF, USL, MUSL }; -extern std::map stress_update; //! Damping type //! None: No damping is specified diff --git a/include/solvers/mpm_explicit.tcc b/include/solvers/mpm_explicit.tcc index 31b68277e..8e6950119 100644 --- a/include/solvers/mpm_explicit.tcc +++ b/include/solvers/mpm_explicit.tcc @@ -125,26 +125,10 @@ bool mpm::MPMExplicit::solve() { auto solver_begin = std::chrono::steady_clock::now(); // Main loop - // HDF5 outputs the initial status - 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 - for (; step_ < nsteps_; ++step_) { if (mpi_rank == 0) console_->info("Step: {} of {}.\n", step_, nsteps_); - // if (step_ == 0 || resume == true) { - // mesh_->output_surface(); - // resume = false; - // } - #ifdef USE_MPI #ifdef USE_GRAPH_PARTITIONING // Run load balancer at a specified frequency @@ -195,16 +179,16 @@ bool mpm::MPMExplicit::solve() { #endif #endif - if ((step_ + 1) % output_steps_ == 0) { + if (step_ % output_steps_ == 0) { // HDF5 outputs - this->write_hdf5(this->step_ + 1, this->nsteps_); + this->write_hdf5(this->step_, this->nsteps_); #ifdef USE_VTK // VTK outputs - this->write_vtk(this->step_ + 1, this->nsteps_); + this->write_vtk(this->step_, this->nsteps_); #endif #ifdef USE_PARTIO // Partio outputs - this->write_partio(this->step_ + 1, this->nsteps_); + this->write_partio(this->step_, this->nsteps_); #endif } } diff --git a/include/solvers/mpm_scheme/mpm_scheme.h b/include/solvers/mpm_scheme/mpm_scheme.h index f422e7792..512e8763c 100644 --- a/include/solvers/mpm_scheme/mpm_scheme.h +++ b/include/solvers/mpm_scheme/mpm_scheme.h @@ -78,7 +78,9 @@ class MPMScheme { //! Stress update scheme //! \retval scheme Stress update scheme virtual inline std::string scheme() const = 0; - //! Time increment + + //! Assign time increment + //! \param[in] the time increment void assign_dt(double dt) { dt_ = dt; }; /** diff --git a/include/solvers/xmpm_explicit.h b/include/solvers/xmpm_explicit.h index 4d8f95b5a..ed1d7bd35 100644 --- a/include/solvers/xmpm_explicit.h +++ b/include/solvers/xmpm_explicit.h @@ -11,8 +11,8 @@ namespace mpm { //! XMPMExplicit class -//! \brief A class that implements the fully explicit one phase mpm -//! \details A single-phase explicit MPM +//! \brief A class that implements the fully explicit one phase xmpm +//! \details A single-phase explicit XMPM //! \tparam Tdim Dimension template class XMPMExplicit : public MPMBase { @@ -92,21 +92,21 @@ class XMPMExplicit : public MPMBase { bool pressure_smoothing_{false}; //! Interface bool interface_{false}; - //! discontinuities statue + //! With or without discontinuities bool setdiscontinuity_{false}; - //! discontinuities + //! Discontinuities std::shared_ptr> discontinuity_; - + //! Describe a discontinuity by mesh bool surfacemesh_{false}; - + //! Initialize the discontinuity by level set values bool particle_levelet_{false}; - + //! Proparate or not bool propagation_{false}; - + //! Initiate or not bool initiation_{false}; - + //! Compute the nodal level set values by: "shepard" of "mls" std::string nodal_levelset_{"shepard"}; - + //! Compute the average friction coefficient from the neighbour particles bool friction_coef_average_{false}; }; // XMPMExplicit class diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index bbcb7818d..6b5c2933c 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -234,7 +234,6 @@ bool mpm::XMPMExplicit::solve() { { mesh_->iterate_over_cells( std::bind(&mpm::Cell::tip_element, std::placeholders::_1)); - // mesh_->update_node_enrich(friction_coef_average_); } // mesh_->output_celltype(step_); @@ -387,7 +386,7 @@ void mpm::XMPMExplicit::initialise_discontinuity() { Factory>::instance()->create(io_type); // Create points and cells from file - discontinuity->initialize( + discontinuity->initialise( discontunity_io->read_mesh_nodes(discontinuity_file), discontunity_io->read_mesh_cells(discontinuity_file)); } else if (discontinuity_props.contains("particle_levelset")) { diff --git a/include/xmpm/discontinuity_3d.h b/include/xmpm/discontinuity_3d.h index 0749f0d0a..aa34e2b22 100644 --- a/include/xmpm/discontinuity_3d.h +++ b/include/xmpm/discontinuity_3d.h @@ -17,31 +17,32 @@ class Discontinuity3D : public DiscontinuityBase { //! \param[in] discontinuity_props discontinuity properties Discontinuity3D(const Json& discontinuity_props); - //! initialization + //! Initialization //! \param[in] the coordinates of all points //! \param[in] the point index of each surface - virtual bool initialize(const std::vector& points, + virtual bool initialise(const std::vector& points, const std::vector>& surfs); - //! create elements from file + //! Create elements from file //! \param[in] surfs the point index list of each surface virtual bool create_surfaces( const std::vector>& surfs) override; - //! initialize the center and normal vector of each surface - bool initialize_center_normal(); + //! Initialize the center and normal vector of each surface + bool initialise_center_normal(); - //! return the cross product of ab and bc + //! Return the cross product of ab and bc //! \param[in] a,b,c coordinates of three points + //! \retval the cross product of ab and bc VectorDim three_cross_product(const VectorDim& a, const VectorDim& b, const VectorDim& c); - // return the levelset values of each coordinates + // Return the levelset values of each coordinates //! \param[in] coordinates coordinates //! \param[in] phi_list the reference of phi for all coordinates void compute_levelset(const VectorDim& coordinates, double& phi_particle) override; - //! compute the normal vectors of coordinates + //! Compute the normal vectors of coordinates //! \param[in] coordinates The coordinates //! \param[in] normal vector the normal vector of the given coordinates void compute_normal(const VectorDim& coordinates, @@ -55,19 +56,19 @@ class Discontinuity3D : public DiscontinuityBase { void compute_updated_position(const double dt) noexcept; protected: - //! vector of points + //! Vector of points using mpm::DiscontinuityBase::points_; //! Logger using mpm::DiscontinuityBase::console_; - //! friction coefficient + //! Friction coefficient using mpm::DiscontinuityBase::friction_coef_; - //! width + //! Width using mpm::DiscontinuityBase::width_; - + //! The mark points move with which side using mpm::DiscontinuityBase::move_direction_; private: - // vector of surfaces + //! Vector of surfaces std::vector> surfaces_; }; diff --git a/include/xmpm/discontinuity_3d.tcc b/include/xmpm/discontinuity_3d.tcc index b760190bc..d44c065c9 100644 --- a/include/xmpm/discontinuity_3d.tcc +++ b/include/xmpm/discontinuity_3d.tcc @@ -4,7 +4,7 @@ mpm::Discontinuity3D::Discontinuity3D(const Json& discontinuity_props) // initialization template -bool mpm::Discontinuity3D::initialize( +bool mpm::Discontinuity3D::initialise( const std::vector& points, const std::vector>& surfs) { bool status = true; @@ -23,7 +23,7 @@ bool mpm::Discontinuity3D::initialize( "Addition of surfaces in discontinuity to mesh failed"); } - bool normal_status = initialize_center_normal(); + bool normal_status = initialise_center_normal(); if (!normal_status) { status = false; throw std::runtime_error( @@ -35,7 +35,7 @@ bool mpm::Discontinuity3D::initialize( return status; }; -//! create surfaces from file +//! Create surfaces from file template bool mpm::Discontinuity3D::create_surfaces( const std::vector>& surfs) { @@ -58,9 +58,9 @@ bool mpm::Discontinuity3D::create_surfaces( return status; } -// initialize the center and normal of the surfaces +//! Initialize the center and normal of the surfaces template <> -bool mpm::Discontinuity3D<3>::initialize_center_normal() { +bool mpm::Discontinuity3D<3>::initialise_center_normal() { bool status = true; try { VectorDim center; @@ -97,7 +97,7 @@ bool mpm::Discontinuity3D<3>::initialize_center_normal() { return status; } -// return the cross product of ab X bc +//! Return the cross product of ab X bc template Eigen::Matrix mpm::Discontinuity3D::three_cross_product( const VectorDim& a, const VectorDim& b, const VectorDim& c) { @@ -108,7 +108,7 @@ Eigen::Matrix mpm::Discontinuity3D::three_cross_product( return threecross; } -// return the levelset values of each coordinates +//! Return the levelset values of each coordinates template void mpm::Discontinuity3D::compute_levelset(const VectorDim& coordinates, double& phi_particle) { @@ -131,7 +131,7 @@ void mpm::Discontinuity3D::compute_levelset(const VectorDim& coordinates, phi_particle = 0; } -// return the normal vectors of given coordinates +//! Return the normal vectors of given coordinates template void mpm::Discontinuity3D::compute_normal(const VectorDim& coordinates, VectorDim& normal_vector) { @@ -153,11 +153,11 @@ void mpm::Discontinuity3D::assign_point_friction_coef() noexcept { for (auto& point : points_) point.assign_friction_coef(friction_coef_); } -// Compute updated position of the particle +//! Compute updated position of the particle template void mpm::Discontinuity3D::compute_updated_position(double dt) noexcept { for (auto& point : this->points_) point.compute_updated_position(dt, move_direction_); - initialize_center_normal(); + initialise_center_normal(); } \ No newline at end of file diff --git a/include/xmpm/discontinuity_base.h b/include/xmpm/discontinuity_base.h index 90babf5fc..f01f85a95 100644 --- a/include/xmpm/discontinuity_base.h +++ b/include/xmpm/discontinuity_base.h @@ -16,7 +16,7 @@ namespace mpm { template struct discontinuity_point; -//! class for describe the discontinuous surface +//! Class for describe the discontinuous surface //! \brief //! \tparam Tdim Dimension template @@ -38,55 +38,62 @@ class DiscontinuityBase { //! Delete assignement operator DiscontinuityBase& operator=(const DiscontinuityBase&) = delete; - //! initialization + //! Initialization //! \param[in] the coordinates of all points //! \param[in] the point index of each surface - virtual bool initialize( + virtual bool initialise( const std::vector& points, const std::vector>& surfs) = 0; - //! create points from file + //! Create points from file //! \param[in] points the coordinates list of points bool create_points(const std::vector& points); - //! create elements from file + //! Create elements from file //! \param[in] surfs the point index list of each surface virtual bool create_surfaces( const std::vector>& surfs) { return true; }; - // return the levelset values of each coordinates + // Return the levelset values of each coordinates //! \param[in] coordinates coordinates //! \param[in] phi_list the reference of phi for all coordinates virtual void compute_levelset(const VectorDim& coordinates, double& phi_particle) = 0; - //! compute the normal vectors of coordinates + //! Compute the normal vectors of coordinates //! \param[in] coordinates The coordinates //! \param[in] normal vector the normal vector of the given coordinates virtual void compute_normal(const VectorDim& coordinates, VectorDim& normal_vector) = 0; - //! return self_contact + //! Return self_contact + //! \retval compute the self-contact force bool self_contact() const { return self_contact_; }; - //! return the friction coefficient + //! Return the friction coefficient + //! \retval the friction coeffcient of this discontinuity double friction_coef() const { return friction_coef_; }; - //! return the cohesion + //! Return the cohesion + //! \retval the surface cohesion double cohesion() const { return cohesion_; }; - //! return the width + //! Return the width + //! \retval the width of the dsicontinuity double width() const { return width_; } - //! return the contact_distance + //! Return the contact_distance + //! \retval the contact distance for the contact detection double contact_distance() const { return contact_distance_; } - //! return the maximum_pdstrain + //! Return the maximum_pdstrain + //! \retval the critical value of the pdstrain double maximum_pdstrain() const { return maximum_pdstrain_; } - //! return the number of the points + //! Return the number of the points + //! \retval the numberof the mark points mpm::Index npoints() const { return points_.size(); }; //! Locate points in a cell @@ -109,48 +116,40 @@ class DiscontinuityBase { void insert_particles(VectorDim& point, const Vector>& cells, const Map>& map_cells); + //! to do:output mark points void output_markpoints(int step); protected: //! Logger std::unique_ptr console_; - - //! vector of points + //! Vector of points std::vector> points_; - - //! self-contact + //! Self-contact bool self_contact_{true}; - - //! friction coefficient + //! Friction coefficient double friction_coef_; - - //! cohesion + //! Cohesion double cohesion_; - - //! the influence length of the discontinuity + //! The width of the discontinuity double width_{std::numeric_limits::max()}; - - //! move_direction + //! Move_direction int move_direction_{1}; - - //! contact distance + //! Contact distance, consider the particle size double contact_distance_{std::numeric_limits::max()}; - - //! maximum pdstrain + //! Maximum pdstrain double maximum_pdstrain_{0}; }; // DiscontinuityBase class -//! struct of discontinuity point +//! Struct of discontinuity point template struct discontinuity_point { public: //! Define a vector of size dimension using VectorDim = Eigen::Matrix; - //! construct with coordinate + //! Construct with coordinate discontinuity_point(const VectorDim& coordinate) { - friction_coef_ = 0; cohesion_ = 0; coordinates_ = coordinate; @@ -187,6 +186,7 @@ struct discontinuity_point { //! Assign the discontinuity enrich to node //! \param[in] map_cells map of cells void assign_node_enrich(const Map>& map_cells); + //! Compute reference coordinates in a cell bool compute_reference_location() noexcept; @@ -239,7 +239,7 @@ struct discontinuity_point { bool tip_{false}; }; -//! struct of discontinuity line: for 2d, need to be done +//! To do: Struct of discontinuity line: for 2d struct discontinuity_line { public: //! Return points indices @@ -250,25 +250,25 @@ struct discontinuity_line { Eigen::Matrix points_; }; -//! struct of discontinuity surface: triangle +//! Struct of discontinuity surface: triangle template struct discontinuity_surface { public: //! Define a vector of size dimension using VectorDim = Eigen::Matrix; - //! construct with points indices + //! Construct with points indices discontinuity_surface(const std::vector& points) { for (int i = 0; i < 3; ++i) points_[i] = points[i]; } //! Return points indices Eigen::Matrix points() const { return points_; } - //! assign the surface center + //! Assign the surface center //! \param[in] center coordinates of the surface center inline void assign_center(VectorDim& center) { center_ = center; } - //! assign the surface normal vector + //! Assign the surface normal vector //! \param[in] normal normal vector of the surface inline void assign_normal(VectorDim& normal) { normal_ = normal; } @@ -290,13 +290,11 @@ struct discontinuity_surface { }; private: - //! points indices + //! Points indices Eigen::Matrix points_; - - // the center coordinates + //! The center coordinates VectorDim center_; - - // the normal vector + //! The normal vector VectorDim normal_; }; diff --git a/include/xmpm/discontinuity_base.tcc b/include/xmpm/discontinuity_base.tcc index 0d15abac2..5c59b3558 100644 --- a/include/xmpm/discontinuity_base.tcc +++ b/include/xmpm/discontinuity_base.tcc @@ -40,7 +40,7 @@ mpm::DiscontinuityBase::DiscontinuityBase( } } -//! create points from file +//! Create points from file template bool mpm::DiscontinuityBase::create_points( const std::vector& coordinates) { @@ -70,7 +70,6 @@ void mpm::DiscontinuityBase::locate_discontinuity_mesh( const Map>& map_cells) noexcept { for (auto& point : this->points_) point.locate_discontinuity_mesh(cells, map_cells); - // for (auto& point : this->points_) point.assign_node_enrich(map_cells); } // Compute updated position of the particle @@ -95,7 +94,7 @@ void mpm::DiscontinuityBase::insert_particles( for (auto& point : this->points_) { point.assign_tip(false); } - // Add point + // add points mpm::discontinuity_point point(coordinates); point.locate_discontinuity_mesh(cells, map_cells); point.compute_shapefn(); diff --git a/include/xmpm/discontinuity_element.h b/include/xmpm/discontinuity_element.h index 07d85b8d5..58357cbff 100644 --- a/include/xmpm/discontinuity_element.h +++ b/include/xmpm/discontinuity_element.h @@ -40,7 +40,7 @@ class DiscontinuityElement { //! Destructor virtual ~DiscontinuityElement(){}; - void initialize() { + void initialise() { enrich_type_ = mpm::EnrichType::Regular; normal_.setZero(); d_ = 0; @@ -49,53 +49,55 @@ class DiscontinuityElement { } //! Assign discontinuity element type + //! \param[in] the element type void assign_element_type(mpm::EnrichType type) { enrich_type_ = type; } - //! assign the normal direction of the discontinuity in the cell + //! Assign the normal direction of the discontinuity in the cell //! \param[in] the normal direction void assign_normal_discontinuity(VectorDim normal) { normal_ = normal; }; - //! assign constant value of the discontinuity plane equation + //! Assign constant value of the discontinuity plane equation //! \param[in] the constant value void assign_d(double d) { d_ = d; }; - //! assign the area of the discontinuity in the cell + //! Assign the area of the discontinuity in the cell //! \param[in] the area void assign_area(double area) { area_ = area; }; - //! assign the center of the discontinuity in the cell - //! \param[in] the area + //! Assign the center of the discontinuity in the cell + //! \param[in] the center of the discontinuity void assign_cohesion_cor(VectorDim cor) { cohesion_cor_ = cor; }; - //! return enriched type + //! Return enriched type + //! \retval the element type unsigned element_type() { return enrich_type_; } - //! return normal_discontinuity + //! Return normal_discontinuity + //! \retval the normal of the discontinuity at the cell center VectorDim normal_discontinuity() { return normal_; } - //! return d + //! Return d + //! \retval the constant of the plane equation double d_discontinuity() { return d_; } - //! return area + //! Return area + //! \retval the area of the discontinuity for the cohesion double area() { return area_; } - //! return the centroid + //! Return the centroid + //! \retval the center of the discontinuity VectorDim cohesion_cor() { return cohesion_cor_; } private: - // default enrich type + //! Default enrich type mpm::EnrichType enrich_type_; - - // normal direction + //! Normal direction VectorDim normal_; - - // constant value of the discontinuity plane equation a*x + b*y + c*z + d = 0 + //! Constant value of the discontinuity plane equation a*x + b*y + c*z + d = 0 double d_; - - // the section area of the crossed cell + //! The section area of the crossed cell double area_{0}; - - // the center of the discontinuity + //! The center of the discontinuity VectorDim cohesion_cor_ = VectorDim::Ones() * std::numeric_limits::max(); }; diff --git a/include/xmpm/discontinuity_point.tcc b/include/xmpm/discontinuity_point.tcc index 35c4039ed..ef987de25 100644 --- a/include/xmpm/discontinuity_point.tcc +++ b/include/xmpm/discontinuity_point.tcc @@ -212,6 +212,4 @@ void mpm::discontinuity_point::assign_node_enrich( friction_coef, 0, 1); nodes_[i]->assign_discontinuity_property(true, "cohesion", cohesion, 0, 1); } - std::ofstream test("cor.txt", std::ios::app); - test << coordinates_; } \ No newline at end of file diff --git a/src/mpm.cc b/src/mpm.cc index b48bc8b4a..bbc6728d4 100644 --- a/src/mpm.cc +++ b/src/mpm.cc @@ -4,11 +4,11 @@ #include "io.h" #include "mpm.h" #include "mpm_explicit.h" -#include "xmpm_explicit.h" #include "mpm_explicit_twophase.h" #include "mpm_implicit_linear.h" #include "mpm_semi_implicit_navierstokes.h" #include "mpm_semi_implicit_twophase.h" +#include "xmpm_explicit.h" namespace mpm { // 2D Explicit MPM diff --git a/src/nodal_properties.cc b/src/nodal_properties.cc index 1972d775d..d081f38d1 100644 --- a/src/nodal_properties.cc +++ b/src/nodal_properties.cc @@ -54,7 +54,6 @@ void mpm::NodalProperties::initialise_nodal_properties() { // rows = number of nodes * size of property (1 if property is scalar, Tdim // if property is vector) // cols = number of materials - Eigen::MatrixXd zeroed_property = Eigen::MatrixXd::Zero(prop_itr->second.rows(), prop_itr->second.cols()); this->assign_property(prop_itr->first, 0, 0, zeroed_property); diff --git a/src/particle.cc b/src/particle.cc index 91c8d997f..0c993d816 100644 --- a/src/particle.cc +++ b/src/particle.cc @@ -1,9 +1,9 @@ #include "particle.h" #include "factory.h" #include "particle_base.h" -#include "particle_xmpm.h" #include "particle_fluid.h" #include "particle_twophase.h" +#include "particle_xmpm.h" namespace mpm { // ParticleType diff --git a/tests/io/write_mesh_particles.cc b/tests/io/write_mesh_particles.cc index 3430aa5eb..c17af69af 100644 --- a/tests/io/write_mesh_particles.cc +++ b/tests/io/write_mesh_particles.cc @@ -128,824 +128,822 @@ bool write_json_xmpm(unsigned dim, bool resume, const std::string& analysis, std::string material = "LinearElastic2D"; std::vector gravity{{0., -9.81}}; unsigned material_id = 0; -// Write JSON Configuration file for implicit linear -bool write_json_implicit_linear(unsigned dim, bool resume, - const std::string& analysis, - const std::string& mpm_scheme, - const std::string& file_name, - const std::string& linear_solver_type) { - // Make json object with input files - // 2D - std::string dimension = "2d"; - auto particle_type = "P2D"; - auto node_type = "N2D"; - auto cell_type = "ED2Q4"; - auto io_type = "Ascii2D"; - auto assembler_type = "EigenImplicitLinear2D"; - std::string entity_set_name = "entity_sets_0"; - std::string material = "LinearElastic2D"; - std::vector gravity{{0., -9.81}}; - std::vector material_id{{0}}; - 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 = "P3DXMPM"; - node_type = "N3D"; - cell_type = "ED3H8"; - particle_type = "P3D"; - node_type = "N3D"; - cell_type = "ED3H8"; - assembler_type = "EigenImplicitLinear3D"; - io_type = "Ascii3D"; - material = "LinearElastic3D"; - gravity.clear(); - gravity = {0., 0., -9.81}; - discontinuity_file = "discontinuity-3d.txt"; - entity_set_name = "entity_sets_1"; - } + // Write JSON Configuration file for implicit linear + bool write_json_implicit_linear( + unsigned dim, bool resume, const std::string& analysis, + const std::string& mpm_scheme, const std::string& file_name, + const std::string& linear_solver_type) { + // Make json object with input files + // 2D + std::string dimension = "2d"; + auto particle_type = "P2D"; + auto node_type = "N2D"; + auto cell_type = "ED2Q4"; + auto io_type = "Ascii2D"; + auto assembler_type = "EigenImplicitLinear2D"; + std::string entity_set_name = "entity_sets_0"; + std::string material = "LinearElastic2D"; + std::vector gravity{{0., -9.81}}; + std::vector material_id{{0}}; + 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 = "P3DXMPM"; + node_type = "N3D"; + cell_type = "ED3H8"; + particle_type = "P3D"; + node_type = "N3D"; + cell_type = "ED3H8"; + assembler_type = "EigenImplicitLinear3D"; + io_type = "Ascii3D"; + material = "LinearElastic3D"; + gravity.clear(); + gravity = {0., 0., -9.81}; + discontinuity_file = "discontinuity-3d.txt"; + entity_set_name = "entity_sets_1"; + } - Json json_file = { - {"title", "Example JSON Input for MPM"}, - {"mesh", - {{"mesh", "mesh-" + dimension + ".txt"}, - {"entity_sets", "entity_sets_0.json"}, - {"entity_sets", entity_set_name + ".json"}, - {"io_type", io_type}, - {"check_duplicates", true}, - {"isoparametric", false}, - {"node_type", node_type}, - {"boundary_conditions", - {{"displacement_constraints", - {{"file", "displacement-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}}, - {{"id", 1}, - {"type", material}, - {"density", 2300.}, - {"youngs_modulus", 1.5E+6}, - {"poisson_ratio", 0.25}}}}, - {"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}, - {"mpm_scheme", mpm_scheme}, - {"locate_particles", true}, - {"pressure_smoothing", true}, - {"dt", 0.0001}, - {"uuid", file_name + "-" + dimension}, - {"nsteps", 10}, - {"resume", - {{"resume", resume}, + Json json_file = { + {"title", "Example JSON Input for MPM"}, + {"mesh", + {{"mesh", "mesh-" + dimension + ".txt"}, + {"entity_sets", "entity_sets_0.json"}, + {"entity_sets", entity_set_name + ".json"}, + {"io_type", io_type}, + {"check_duplicates", true}, + {"isoparametric", false}, + {"node_type", node_type}, + {"boundary_conditions", + {{"displacement_constraints", + {{"file", "displacement-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}}, + {{"id", 1}, + {"type", material}, + {"density", 2300.}, + {"youngs_modulus", 1.5E+6}, + {"poisson_ratio", 0.25}}}}, + {"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}, + {"mpm_scheme", mpm_scheme}, + {"locate_particles", true}, + {"pressure_smoothing", true}, + {"dt", 0.0001}, {"uuid", file_name + "-" + dimension}, - {"step", 5}}}, - {"linear_solver", - {{"assembler_type", assembler_type}, - {"solver_settings", - {{{"dof", "displacement"}, - {"solver_type", linear_solver_type}, - {"sub_solver_type", "cg"}, - {"preconditioner_type", "none"}, - {"max_iter", 100}, - {"tolerance", 1E-5}, - {"verbosity", 0}}}}}}, - {"damping", {{"type", "Cundall"}, {"damping_factor", 0.0}}}, - {"newmark", {{"beta", 0.25}, {"gamma", 0.5}}}}}, - {"post_processing", - {{"path", "results/"}, - {"vtk", {"stresses", "strains", "velocity"}}, - {"vtk_statevars", {{{"phase_id", 0}, {"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 Configuration file for navierstokes -bool write_json_navierstokes(unsigned dim, bool resume, - const std::string& analysis, - const std::string& mpm_scheme, - const std::string& file_name, - const std::string& free_surface_type, - const std::string& linear_solver_type) { - // Make json object with input files - // 2D - std::string dimension = "2d"; - auto particle_type = "P2DFLUID"; - auto node_type = "N2D"; - auto cell_type = "ED2Q4"; - auto io_type = "Ascii2D"; - auto assembler_type = "EigenSemiImplicitNavierStokes2D"; - std::string entity_set_name = "entity_sets_0"; - std::string material = "Newtonian2D"; - std::vector gravity{{0., -9.81}}; - std::vector material_id{{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 = "P3DFLUID"; - node_type = "N3D"; - cell_type = "ED3H8"; - assembler_type = "EigenSemiImplicitNavierStokes3D"; - io_type = "Ascii3D"; - material = "Newtonian3D"; - gravity.clear(); - gravity = {0., 0., -9.81}; - entity_set_name = "entity_sets_1"; + {"nsteps", 10}, + {"resume", + {{"resume", resume}, + {"uuid", file_name + "-" + dimension}, + {"step", 5}}}, + {"linear_solver", + {{"assembler_type", assembler_type}, + {"solver_settings", + {{{"dof", "displacement"}, + {"solver_type", linear_solver_type}, + {"sub_solver_type", "cg"}, + {"preconditioner_type", "none"}, + {"max_iter", 100}, + {"tolerance", 1E-5}, + {"verbosity", 0}}}}}}, + {"damping", {{"type", "Cundall"}, {"damping_factor", 0.0}}}, + {"newmark", {{"beta", 0.25}, {"gamma", 0.5}}}}}, + {"post_processing", + {{"path", "results/"}, + {"vtk", {"stresses", "strains", "velocity"}}, + {"vtk_statevars", {{{"phase_id", 0}, {"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; } - Json json_file = { - {"title", "Example JSON Input for MPM"}, - {"mesh", - {{"mesh", "mesh-" + dimension + ".txt"}, - {"entity_sets", entity_set_name + ".json"}, - {"io_type", io_type}, - {"check_duplicates", true}, - {"isoparametric", false}, - {"node_type", node_type}, - {"boundary_conditions", - {{"velocity_constraints", {{"file", "velocity-constraints.txt"}}}, - {"pressure_constraints", - {{{"phase_id", 0}, {"nset_id", 1}, {"pressure", 0.0}}}}, - {"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"}}}}}}, - {"discontinuity", - {{{"id", 0}, - {"type", "tri3d"}, - {"io_type", "Ascii3D"}, - {"file", discontinuity_file}, - {"frictional_coefficient", 0.3}}}}, - {"materials", - {{{"id", 2}, - {"type", material}, - {"density", 1000.}, - {"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}, - {"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}, - {"boundary_friction", 0.5}, - {"resume", - {{"resume", resume}, - {"uuid", file_name + "-" + dimension}, - {"step", 5}}}, - {"semi_implicit", {{"beta", 1}, {"integration", "mp"}}}, - {"free_surface_detection", - {{"type", free_surface_type}, {"volume_tolerance", 0.25}}}, - {"linear_solver", - {{"assembler_type", assembler_type}, - {"solver_settings", - {{{"dof", "pressure"}, - {"solver_type", linear_solver_type}, - {"sub_solver_type", "cg"}, - {"preconditioner_type", "none"}, - {"max_iter", 100}, - {"tolerance", 1E-5}, - {"verbosity", 0}}}}}}, - {"damping", {{"type", "Cundall"}, {"damping_factor", 0.02}}}, - {"newmark", {{"beta", 0.25}, {"gamma", 0.5}}}}}, - {"post_processing", - {{"path", "results/"}, - {"vtk", {"stresses", "strains", "velocity"}}, - {"vtk_statevars", {{{"phase_id", 0}, {"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 Configuration file for twophase -bool write_json_twophase(unsigned dim, bool resume, const std::string& analysis, - const std::string& mpm_scheme, - const std::string& file_name, - const std::string& free_surface_type, - const std::string& linear_solver_type) { - // 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"; - auto assembler_type = "EigenSemiImplicitTwoPhase2D"; - std::string entity_set_name = "entity_sets_0"; - 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}}; + // Write JSON Configuration file for navierstokes + bool write_json_navierstokes( + unsigned dim, bool resume, const std::string& analysis, + const std::string& mpm_scheme, const std::string& file_name, + const std::string& free_surface_type, + const std::string& linear_solver_type) { + // Make json object with input files + // 2D + std::string dimension = "2d"; + auto particle_type = "P2DFLUID"; + auto node_type = "N2D"; + auto cell_type = "ED2Q4"; + auto io_type = "Ascii2D"; + auto assembler_type = "EigenSemiImplicitNavierStokes2D"; + std::string entity_set_name = "entity_sets_0"; + std::string material = "Newtonian2D"; + std::vector gravity{{0., -9.81}}; + std::vector material_id{{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 = "P3DFLUID"; + node_type = "N3D"; + cell_type = "ED3H8"; + assembler_type = "EigenSemiImplicitNavierStokes3D"; + io_type = "Ascii3D"; + material = "Newtonian3D"; + gravity.clear(); + gravity = {0., 0., -9.81}; + entity_set_name = "entity_sets_1"; + } - // 3D - if (dim == 3) { - dimension = "3d"; - particle_type = "P3D2PHASE"; - node_type = "N3D2P"; - cell_type = "ED3H8"; - assembler_type = "EigenSemiImplicitTwoPhase3D"; - io_type = "Ascii3D"; - material = "LinearElastic3D"; - liquid_material = "Newtonian3D"; - gravity.clear(); - gravity = {0., 0., -9.81}; - entity_set_name = "entity_sets_1"; + Json json_file = { + {"title", "Example JSON Input for MPM"}, + {"mesh", + {{"mesh", "mesh-" + dimension + ".txt"}, + {"entity_sets", entity_set_name + ".json"}, + {"io_type", io_type}, + {"check_duplicates", true}, + {"isoparametric", false}, + {"node_type", node_type}, + {"boundary_conditions", + {{"velocity_constraints", {{"file", "velocity-constraints.txt"}}}, + {"pressure_constraints", + {{{"phase_id", 0}, {"nset_id", 1}, {"pressure", 0.0}}}}, + {"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"}}}}}}, + {"discontinuity", + {{{"id", 0}, + {"type", "tri3d"}, + {"io_type", "Ascii3D"}, + {"file", discontinuity_file}, + {"frictional_coefficient", 0.3}}}}, + {"materials", + {{{"id", 2}, + {"type", material}, + {"density", 1000.}, + {"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}, + {"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}, + {"boundary_friction", 0.5}, + {"resume", + {{"resume", resume}, + {"uuid", file_name + "-" + dimension}, + {"step", 5}}}, + {"semi_implicit", {{"beta", 1}, {"integration", "mp"}}}, + {"free_surface_detection", + {{"type", free_surface_type}, {"volume_tolerance", 0.25}}}, + {"linear_solver", + {{"assembler_type", assembler_type}, + {"solver_settings", + {{{"dof", "pressure"}, + {"solver_type", linear_solver_type}, + {"sub_solver_type", "cg"}, + {"preconditioner_type", "none"}, + {"max_iter", 100}, + {"tolerance", 1E-5}, + {"verbosity", 0}}}}}}, + {"damping", {{"type", "Cundall"}, {"damping_factor", 0.02}}}, + {"newmark", {{"beta", 0.25}, {"gamma", 0.5}}}}}, + {"post_processing", + {{"path", "results/"}, + {"vtk", {"stresses", "strains", "velocity"}}, + {"vtk_statevars", {{{"phase_id", 0}, {"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; } - Json json_file = { - {"title", "Example JSON Input for MPM"}, - {"mesh", - {{"mesh", "mesh-" + dimension + ".txt"}, - {"entity_sets", entity_set_name + ".json"}, - {"io_type", io_type}, - {"check_duplicates", true}, - {"isoparametric", false}, - {"node_type", node_type}, - {"boundary_conditions", - {{"velocity_constraints", {{"file", "velocity-constraints.txt"}}}, - {"pressure_constraints", - {{{"phase_id", 1}, {"nset_id", 1}, {"pressure", 0.0}}}}, - {"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", 1000.}, - {"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}, - {"dt", 0.001}, + // Write JSON Configuration file for twophase + bool write_json_twophase( + unsigned dim, bool resume, const std::string& analysis, + const std::string& mpm_scheme, const std::string& file_name, + const std::string& free_surface_type, + const std::string& linear_solver_type) { + // 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"; + auto assembler_type = "EigenSemiImplicitTwoPhase2D"; + std::string entity_set_name = "entity_sets_0"; + 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"; + assembler_type = "EigenSemiImplicitTwoPhase3D"; + io_type = "Ascii3D"; + material = "LinearElastic3D"; + liquid_material = "Newtonian3D"; + gravity.clear(); + gravity = {0., 0., -9.81}; + entity_set_name = "entity_sets_1"; + } + + Json json_file = { + {"title", "Example JSON Input for MPM"}, + {"mesh", + {{"mesh", "mesh-" + dimension + ".txt"}, + {"entity_sets", entity_set_name + ".json"}, + {"io_type", io_type}, + {"check_duplicates", true}, + {"isoparametric", false}, + {"node_type", node_type}, + {"boundary_conditions", + {{"velocity_constraints", {{"file", "velocity-constraints.txt"}}}, + {"pressure_constraints", + {{{"phase_id", 1}, {"nset_id", 1}, {"pressure", 0.0}}}}, + {"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", 1000.}, + {"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}, + {"dt", 0.001}, ======= - {"locate_particles", true}, - {"pressure_smoothing", true}, - {"pore_pressure_smoothing", true}, - {"free_surface_detection", - {{"type", "density"}, {"volume_tolerance", 0.25}}}, - {"dt", 0.0001}, + {"locate_particles", true}, + {"pressure_smoothing", true}, + {"pore_pressure_smoothing", true}, + {"free_surface_detection", + {{"type", "density"}, {"volume_tolerance", 0.25}}}, + {"dt", 0.0001}, >>>>>>> master - {"nsteps", 10}, - {"boundary_friction", 0.5}, - {"resume", - {{"resume", resume}, - {"uuid", file_name + "-" + dimension}, - {"step", 5}}}, - {"semi_implicit", {{"beta", 1}, {"integration", "mp"}}}, - {"free_surface_detection", - {{"type", free_surface_type}, {"volume_tolerance", 0.25}}}, - {"linear_solver", - {{"assembler_type", assembler_type}, - {"solver_settings", - {{{"dof", "pressure"}, - {"solver_type", linear_solver_type}, - {"sub_solver_type", "cg"}, - {"preconditioner_type", "none"}, - {"max_iter", 100}, - {"tolerance", 1E-5}, - {"verbosity", 0}}, - {{"dof", "acceleration"}, - {"solver_type", linear_solver_type}, - {"sub_solver_type", "lscg"}, - {"preconditioner_type", "none"}, - {"max_iter", 100}, - {"tolerance", 1E-5}, - {"verbosity", 0}}}}}}, - {"damping", {{"type", "Cundall"}, {"damping_factor", 0.02}}}, - {"newmark", {{"beta", 0.25}, {"gamma", 0.5}}}}}, - {"post_processing", - {{"path", "results/"}, - {"vtk", {"stresses", "strains", "velocity"}}, - {"vtk_statevars", {{{"phase_id", 0}, {"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; -} + {"nsteps", 10}, + {"boundary_friction", 0.5}, + {"resume", + {{"resume", resume}, + {"uuid", file_name + "-" + dimension}, + {"step", 5}}}, + {"semi_implicit", {{"beta", 1}, {"integration", "mp"}}}, + {"free_surface_detection", + {{"type", free_surface_type}, {"volume_tolerance", 0.25}}}, + {"linear_solver", + {{"assembler_type", assembler_type}, + {"solver_settings", + {{{"dof", "pressure"}, + {"solver_type", linear_solver_type}, + {"sub_solver_type", "cg"}, + {"preconditioner_type", "none"}, + {"max_iter", 100}, + {"tolerance", 1E-5}, + {"verbosity", 0}}, + {{"dof", "acceleration"}, + {"solver_type", linear_solver_type}, + {"sub_solver_type", "lscg"}, + {"preconditioner_type", "none"}, + {"max_iter", 100}, + {"tolerance", 1E-5}, + {"verbosity", 0}}}}}}, + {"damping", {{"type", "Cundall"}, {"damping_factor", 0.02}}}, + {"newmark", {{"beta", 0.25}, {"gamma", 0.5}}}}}, + {"post_processing", + {{"path", "results/"}, + {"vtk", {"stresses", "strains", "velocity"}}, + {"vtk_statevars", {{{"phase_id", 0}, {"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 - Json json_file0 = { - {"particle_sets", - {{{"id", 2}, - {"set", {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}}}}}, - {"node_sets", {{{"id", 1}, {"set", {4, 5}}}}}}; - - Json json_file1 = { - {"particle_sets", - {{{"id", 2}, - {"set", {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}}}}}, - {"node_sets", {{{"id", 1}, {"set", {8, 9, 10, 11}}}}}}; + // Write JSON Entity Set + bool write_entity_set() { + // JSON Entity Sets + Json json_file0 = { + {"particle_sets", + {{{"id", 2}, + {"set", {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}}}}}, + {"node_sets", {{{"id", 1}, {"set", {4, 5}}}}}}; + + Json json_file1 = { + {"particle_sets", + {{{"id", 2}, + {"set", {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}}}}}, + {"node_sets", {{{"id", 1}, {"set", {8, 9, 10, 11}}}}}}; + + // Dump JSON as an input file to be read + std::ofstream file; + file.open("entity_sets_0.json"); + file << json_file0.dump(2); + file.close(); + + file.open("entity_sets_1.json"); + file << json_file1.dump(2); + file.close(); + + return true; + } - // Dump JSON as an input file to be read - std::ofstream file; - file.open("entity_sets_0.json"); - file << json_file0.dump(2); - file.close(); + // Write Mesh file in 2D + bool write_mesh_2d() { + // Dimension + const unsigned dim = 2; + + // Vector of nodal coordinates + std::vector> coordinates; + + // Nodal coordinates + Eigen::Matrix node; + + // Cell 0 + // Node 0 + node << 0., 0.; + coordinates.emplace_back(node); + // Node 1 + node << 0.5, 0.; + coordinates.emplace_back(node); + // Node 2 + node << 0.5, 0.5; + coordinates.emplace_back(node); + // Node 3 + node << 0., 0.5; + coordinates.emplace_back(node); + + // Cell 1 + // Node 4 + node << 1.0, 0.; + coordinates.emplace_back(node); + // Node 5 + node << 1.0, 0.5; + coordinates.emplace_back(node); + + // Cell with node ids + std::vector> cells{// cell #0 + {0, 1, 2, 3}, + // cell #1 + {1, 4, 5, 2}}; + + // Dump mesh file as an input file to be read + std::ofstream file; + file.open("mesh-2d.txt"); + file << "! elementShape hexahedron\n"; + file << "! elementNumPoints 8\n"; + file << coordinates.size() << "\t" << cells.size() << "\n"; + + // Write nodal coordinates + for (const auto& coord : coordinates) { + for (unsigned i = 0; i < coord.size(); ++i) file << coord[i] << "\t"; + file << "\n"; + } - file.open("entity_sets_1.json"); - file << json_file1.dump(2); - file.close(); + // Write cell node ids + for (const auto& cell : cells) { + for (auto nid : cell) file << nid << "\t"; + file << "\n"; + } + file.close(); - return true; -} + // Dump mesh velocity constraints + std::ofstream file_constraints; + file_constraints.open("velocity-constraints.txt"); + file_constraints << 0 << "\t" << 1 << "\t" << 0 << "\n"; + file_constraints << 1 << "\t" << 1 << "\t" << 0 << "\n"; + file_constraints.close(); -// Write Mesh file in 2D -bool write_mesh_2d() { - // Dimension - const unsigned dim = 2; - - // Vector of nodal coordinates - std::vector> coordinates; - - // Nodal coordinates - Eigen::Matrix node; - - // Cell 0 - // Node 0 - node << 0., 0.; - coordinates.emplace_back(node); - // Node 1 - node << 0.5, 0.; - coordinates.emplace_back(node); - // Node 2 - node << 0.5, 0.5; - coordinates.emplace_back(node); - // Node 3 - node << 0., 0.5; - coordinates.emplace_back(node); - - // Cell 1 - // Node 4 - node << 1.0, 0.; - coordinates.emplace_back(node); - // Node 5 - node << 1.0, 0.5; - coordinates.emplace_back(node); - - // Cell with node ids - std::vector> cells{// cell #0 - {0, 1, 2, 3}, - // cell #1 - {1, 4, 5, 2}}; - - // Dump mesh file as an input file to be read - std::ofstream file; - file.open("mesh-2d.txt"); - file << "! elementShape hexahedron\n"; - file << "! elementNumPoints 8\n"; - file << coordinates.size() << "\t" << cells.size() << "\n"; - - // Write nodal coordinates - for (const auto& coord : coordinates) { - for (unsigned i = 0; i < coord.size(); ++i) file << coord[i] << "\t"; - file << "\n"; + return true; } - // Write cell node ids - for (const auto& cell : cells) { - for (auto nid : cell) file << nid << "\t"; - file << "\n"; - } - file.close(); + // Write particles file in 2D + bool write_particles_2d() { + const unsigned dim = 2; + // Vector of particle coordinates + std::vector> coordinates; + coordinates.clear(); + + // Particle coordinates + Eigen::Matrix particle; + + // Cell 0 + // Particle 0 + particle << 0.125, 0.125; + coordinates.emplace_back(particle); + // Particle 1 + particle << 0.25, 0.125; + coordinates.emplace_back(particle); + // Particle 2 + particle << 0.25, 0.25; + coordinates.emplace_back(particle); + // Particle 3 + particle << 0.125, 0.25; + coordinates.emplace_back(particle); + + // Cell 1 + // Particle 4 + particle << 0.675, 0.125; + coordinates.emplace_back(particle); + // Particle 5 + particle << 0.85, 0.125; + coordinates.emplace_back(particle); + // Particle 6 + particle << 0.85, 0.25; + coordinates.emplace_back(particle); + // Particle 7 + particle << 0.675, 0.25; + coordinates.emplace_back(particle); + + // Dump particles coordinates as an input file to be read + std::ofstream file; + file.open("particles-2d.txt"); + file << coordinates.size() << "\n"; + // Write particle coordinates + for (const auto& coord : coordinates) { + for (unsigned i = 0; i < coord.size(); ++i) { + file << coord[i] << "\t"; + } + file << "\n"; + } - // Dump mesh velocity constraints - std::ofstream file_constraints; - file_constraints.open("velocity-constraints.txt"); - file_constraints << 0 << "\t" << 1 << "\t" << 0 << "\n"; - file_constraints << 1 << "\t" << 1 << "\t" << 0 << "\n"; - file_constraints.close(); + file.close(); + return true; + } - return true; -} + // Write mesh file in 3D + bool write_mesh_3d() { + + // Dimension + const unsigned dim = 3; + + // Vector of nodal coordinates + std::vector> coordinates; + + // Nodal coordinates + Eigen::Matrix node; + + // Cell 0 + // Node 0 + node << 0., 0., 0.; + coordinates.emplace_back(node); + // Node 1 + node << 0.5, 0., 0.; + coordinates.emplace_back(node); + // Node 2 + node << 0.5, 0.5, 0.; + coordinates.emplace_back(node); + // Node 3 + node << 0., 0.5, 0.; + coordinates.emplace_back(node); + // Node 4 + node << 0., 0., 0.5; + coordinates.emplace_back(node); + // Node 5 + node << 0.5, 0., 0.5; + coordinates.emplace_back(node); + // Node 6 + node << 0.5, 0.5, 0.5; + coordinates.emplace_back(node); + // Node 7 + node << 0., 0.5, 0.5; + coordinates.emplace_back(node); + + // Cell 1 + // Node 8 + node << 1.0, 0., 0.; + coordinates.emplace_back(node); + // Node 9 + node << 1.0, 0.5, 0.; + coordinates.emplace_back(node); + // Node 10 + node << 1.0, 0., 0.5; + coordinates.emplace_back(node); + // Node 11 + node << 1.0, 0.5, 0.5; + coordinates.emplace_back(node); + + // Cell with node ids + std::vector> cells{// cell #0 + {0, 1, 2, 3, 4, 5, 6, 7}, + // cell #1 + {1, 8, 9, 2, 5, 10, 11, 6}}; + + // Dump mesh file as an input file to be read + std::ofstream file; + file.open("mesh-3d.txt"); + file << "! elementShape hexahedron\n"; + file << "! elementNumPoints 8\n"; + file << coordinates.size() << "\t" << cells.size() << "\n"; + + // Write nodal coordinates + for (const auto& coord : coordinates) { + for (unsigned i = 0; i < coord.size(); ++i) file << coord[i] << "\t"; + file << "\n"; + } -// Write particles file in 2D -bool write_particles_2d() { - const unsigned dim = 2; - // Vector of particle coordinates - std::vector> coordinates; - coordinates.clear(); - - // Particle coordinates - Eigen::Matrix particle; - - // Cell 0 - // Particle 0 - particle << 0.125, 0.125; - coordinates.emplace_back(particle); - // Particle 1 - particle << 0.25, 0.125; - coordinates.emplace_back(particle); - // Particle 2 - particle << 0.25, 0.25; - coordinates.emplace_back(particle); - // Particle 3 - particle << 0.125, 0.25; - coordinates.emplace_back(particle); - - // Cell 1 - // Particle 4 - particle << 0.675, 0.125; - coordinates.emplace_back(particle); - // Particle 5 - particle << 0.85, 0.125; - coordinates.emplace_back(particle); - // Particle 6 - particle << 0.85, 0.25; - coordinates.emplace_back(particle); - // Particle 7 - particle << 0.675, 0.25; - coordinates.emplace_back(particle); - - // Dump particles coordinates as an input file to be read - std::ofstream file; - file.open("particles-2d.txt"); - file << coordinates.size() << "\n"; - // Write particle coordinates - for (const auto& coord : coordinates) { - for (unsigned i = 0; i < coord.size(); ++i) { - file << coord[i] << "\t"; + // Write cell node ids + for (const auto& cell : cells) { + for (auto nid : cell) file << nid << "\t"; + file << "\n"; } - file << "\n"; - } - file.close(); - return true; -} + file.close(); -// Write mesh file in 3D -bool write_mesh_3d() { - - // Dimension - const unsigned dim = 3; - - // Vector of nodal coordinates - std::vector> coordinates; - - // Nodal coordinates - Eigen::Matrix node; - - // Cell 0 - // Node 0 - node << 0., 0., 0.; - coordinates.emplace_back(node); - // Node 1 - node << 0.5, 0., 0.; - coordinates.emplace_back(node); - // Node 2 - node << 0.5, 0.5, 0.; - coordinates.emplace_back(node); - // Node 3 - node << 0., 0.5, 0.; - coordinates.emplace_back(node); - // Node 4 - node << 0., 0., 0.5; - coordinates.emplace_back(node); - // Node 5 - node << 0.5, 0., 0.5; - coordinates.emplace_back(node); - // Node 6 - node << 0.5, 0.5, 0.5; - coordinates.emplace_back(node); - // Node 7 - node << 0., 0.5, 0.5; - coordinates.emplace_back(node); - - // Cell 1 - // Node 8 - node << 1.0, 0., 0.; - coordinates.emplace_back(node); - // Node 9 - node << 1.0, 0.5, 0.; - coordinates.emplace_back(node); - // Node 10 - node << 1.0, 0., 0.5; - coordinates.emplace_back(node); - // Node 11 - node << 1.0, 0.5, 0.5; - coordinates.emplace_back(node); - - // Cell with node ids - std::vector> cells{// cell #0 - {0, 1, 2, 3, 4, 5, 6, 7}, - // cell #1 - {1, 8, 9, 2, 5, 10, 11, 6}}; - - // Dump mesh file as an input file to be read - std::ofstream file; - file.open("mesh-3d.txt"); - file << "! elementShape hexahedron\n"; - file << "! elementNumPoints 8\n"; - file << coordinates.size() << "\t" << cells.size() << "\n"; - - // Write nodal coordinates - for (const auto& coord : coordinates) { - for (unsigned i = 0; i < coord.size(); ++i) file << coord[i] << "\t"; - file << "\n"; - } + // Dump mesh velocity constraints + std::ofstream file_constraints; + file_constraints.open("velocity-constraints.txt"); + file_constraints << 0 << "\t" << 3 << "\t" << 0 << "\n"; + file_constraints << 1 << "\t" << 3 << "\t" << 0 << "\n"; + file_constraints << 2 << "\t" << 3 << "\t" << 0 << "\n"; + file_constraints << 3 << "\t" << 3 << "\t" << 0 << "\n"; + file_constraints.close(); - // Write cell node ids - for (const auto& cell : cells) { - for (auto nid : cell) file << nid << "\t"; - file << "\n"; + return true; } - file.close(); + // Write particles file in 3D + bool write_particles_3d() { + const unsigned dim = 3; + // Vector of particle coordinates + std::vector> coordinates; + + // Particle coordinates + Eigen::Matrix particle; + + // Cell 0 + // Particle 0 + particle << 0.125, 0.125, 0.125; + coordinates.emplace_back(particle); + // Particle 1 + particle << 0.25, 0.125, 0.125; + coordinates.emplace_back(particle); + // Particle 2 + particle << 0.25, 0.25, 0.125; + coordinates.emplace_back(particle); + // Particle 3 + particle << 0.125, 0.25, 0.125; + coordinates.emplace_back(particle); + // Particle 4 + particle << 0.125, 0.125, 0.25; + coordinates.emplace_back(particle); + // Particle 5 + particle << 0.25, 0.125, 0.25; + coordinates.emplace_back(particle); + // Particle 6 + particle << 0.25, 0.25, 0.25; + coordinates.emplace_back(particle); + // Particle 7 + particle << 0.125, 0.25, 0.25; + coordinates.emplace_back(particle); + + // Cell 1 + // Particle 8 + particle << 0.675, 0.125, 0.125; + coordinates.emplace_back(particle); + // Particle 9 + particle << 0.85, 0.125, 0.125; + coordinates.emplace_back(particle); + // Particle 10 + particle << 0.85, 0.25, 0.125; + coordinates.emplace_back(particle); + // Particle 11 + particle << 0.675, 0.25, 0.125; + coordinates.emplace_back(particle); + // Particle 12 + particle << 0.675, 0.125, 0.25; + coordinates.emplace_back(particle); + // Particle 13 + particle << 0.85, 0.125, 0.25; + coordinates.emplace_back(particle); + // Particle 14 + particle << 0.85, 0.25, 0.25; + coordinates.emplace_back(particle); + // Particle 15 + particle << 0.675, 0.25, 0.25; + coordinates.emplace_back(particle); + + // Dump particles coordinates as an input file to be read + std::ofstream file; + file.open("particles-3d.txt"); + file << coordinates.size() << "\n"; + // Write particle coordinates + for (const auto& coord : coordinates) { + for (unsigned i = 0; i < coord.size(); ++i) { + file << coord[i] << "\t"; + } + file << "\n"; + } - // Dump mesh velocity constraints - std::ofstream file_constraints; - file_constraints.open("velocity-constraints.txt"); - file_constraints << 0 << "\t" << 3 << "\t" << 0 << "\n"; - file_constraints << 1 << "\t" << 3 << "\t" << 0 << "\n"; - file_constraints << 2 << "\t" << 3 << "\t" << 0 << "\n"; - file_constraints << 3 << "\t" << 3 << "\t" << 0 << "\n"; - file_constraints.close(); + file.close(); + return true; + } - return true; -} + // Write mesh file in 3D + bool write_discontinuity_3d() { + + // Dimension + const unsigned dim = 3; + + // Vector of nodal coordinates + std::vector> coordinates; + + // Nodal coordinates + Eigen::Matrix point; + + // point 0 + point << 0., 0., 0.25; + coordinates.emplace_back(point); + // point 1 + point << 0.5, 0., 0.25; + coordinates.emplace_back(point); + // point 2 + point << 1.0, 0., 0.25; + coordinates.emplace_back(point); + // point 3 + point << 1.0, 0.5, 0.25; + coordinates.emplace_back(point); + // point 4 + point << 0.5, 0.5, 0.25; + coordinates.emplace_back(point); + // point 5 + point << 0., 0.5, 0.25; + coordinates.emplace_back(point); + + // surfaces with point ids + std::vector> surfs{// surface #0 + {0, 1, 5}, + // surface #1 + {1, 4, 5}, + // surface #2 + {1, 3, 4}, + // surface #3 + {1, 2, 3}}; + + // Dump discontinuity file as an input file to be read + std::ofstream file; + file.open("discontinuity-3d.txt"); + file << "! surfaceShape triangle\n"; + file << coordinates.size() << "\t" << surfs.size() << "\n"; + + // Write point coordinates + for (const auto& coord : coordinates) { + for (unsigned i = 0; i < coord.size(); ++i) file << coord[i] << "\t"; + file << "\n"; + } -// Write particles file in 3D -bool write_particles_3d() { - const unsigned dim = 3; - // Vector of particle coordinates - std::vector> coordinates; - - // Particle coordinates - Eigen::Matrix particle; - - // Cell 0 - // Particle 0 - particle << 0.125, 0.125, 0.125; - coordinates.emplace_back(particle); - // Particle 1 - particle << 0.25, 0.125, 0.125; - coordinates.emplace_back(particle); - // Particle 2 - particle << 0.25, 0.25, 0.125; - coordinates.emplace_back(particle); - // Particle 3 - particle << 0.125, 0.25, 0.125; - coordinates.emplace_back(particle); - // Particle 4 - particle << 0.125, 0.125, 0.25; - coordinates.emplace_back(particle); - // Particle 5 - particle << 0.25, 0.125, 0.25; - coordinates.emplace_back(particle); - // Particle 6 - particle << 0.25, 0.25, 0.25; - coordinates.emplace_back(particle); - // Particle 7 - particle << 0.125, 0.25, 0.25; - coordinates.emplace_back(particle); - - // Cell 1 - // Particle 8 - particle << 0.675, 0.125, 0.125; - coordinates.emplace_back(particle); - // Particle 9 - particle << 0.85, 0.125, 0.125; - coordinates.emplace_back(particle); - // Particle 10 - particle << 0.85, 0.25, 0.125; - coordinates.emplace_back(particle); - // Particle 11 - particle << 0.675, 0.25, 0.125; - coordinates.emplace_back(particle); - // Particle 12 - particle << 0.675, 0.125, 0.25; - coordinates.emplace_back(particle); - // Particle 13 - particle << 0.85, 0.125, 0.25; - coordinates.emplace_back(particle); - // Particle 14 - particle << 0.85, 0.25, 0.25; - coordinates.emplace_back(particle); - // Particle 15 - particle << 0.675, 0.25, 0.25; - coordinates.emplace_back(particle); - - // Dump particles coordinates as an input file to be read - std::ofstream file; - file.open("particles-3d.txt"); - file << coordinates.size() << "\n"; - // Write particle coordinates - for (const auto& coord : coordinates) { - for (unsigned i = 0; i < coord.size(); ++i) { - file << coord[i] << "\t"; + // Write cell node ids + for (const auto& surf : surfs) { + for (auto pid : surf) file << pid << "\t"; + file << "\n"; } - file << "\n"; - } - file.close(); - return true; -} + file.close(); -// Write mesh file in 3D -bool write_discontinuity_3d() { - - // Dimension - const unsigned dim = 3; - - // Vector of nodal coordinates - std::vector> coordinates; - - // Nodal coordinates - Eigen::Matrix point; - - // point 0 - point << 0., 0., 0.25; - coordinates.emplace_back(point); - // point 1 - point << 0.5, 0., 0.25; - coordinates.emplace_back(point); - // point 2 - point << 1.0, 0., 0.25; - coordinates.emplace_back(point); - // point 3 - point << 1.0, 0.5, 0.25; - coordinates.emplace_back(point); - // point 4 - point << 0.5, 0.5, 0.25; - coordinates.emplace_back(point); - // point 5 - point << 0., 0.5, 0.25; - coordinates.emplace_back(point); - - // surfaces with point ids - std::vector> surfs{// surface #0 - {0, 1, 5}, - // surface #1 - {1, 4, 5}, - // surface #2 - {1, 3, 4}, - // surface #3 - {1, 2, 3}}; - - // Dump discontinuity file as an input file to be read - std::ofstream file; - file.open("discontinuity-3d.txt"); - file << "! surfaceShape triangle\n"; - file << coordinates.size() << "\t" << surfs.size() << "\n"; - - // Write point coordinates - for (const auto& coord : coordinates) { - for (unsigned i = 0; i < coord.size(); ++i) file << coord[i] << "\t"; - file << "\n"; - } + // Dump mesh velocity constraints + std::ofstream file_constraints; + file_constraints.open("velocity-constraints.txt"); + file_constraints << 0 << "\t" << 0 << "\t" << 0 << "\n"; + file_constraints.close(); - // Write cell node ids - for (const auto& surf : surfs) { - for (auto pid : surf) file << pid << "\t"; - file << "\n"; + return true; } - - file.close(); - - // Dump mesh velocity constraints - std::ofstream file_constraints; - file_constraints.open("velocity-constraints.txt"); - file_constraints << 0 << "\t" << 0 << "\t" << 0 << "\n"; - file_constraints.close(); - - return true; -} } // namespace mpm_test diff --git a/tests/mesh_test_3d.cc b/tests/mesh_test_3d.cc index 6b9b5fdeb..5e6e0eb87 100644 --- a/tests/mesh_test_3d.cc +++ b/tests/mesh_test_3d.cc @@ -1561,7 +1561,7 @@ TEST_CASE("Mesh is checked for 3D case", "[mesh][3D]") { ->create(discontunity_type, std::move(discontinuity_id), discontinuity_props); - REQUIRE(discontinuity->initialize(points, surfs) == true); + REQUIRE(discontinuity->initialise(points, surfs) == true); //! discontinuities std::map>> From 98d5aa3b5d0e7554e3ba68acdd6437acd3241b7f Mon Sep 17 00:00:00 2001 From: yliang-sn Date: Wed, 3 Nov 2021 17:14:10 -0700 Subject: [PATCH 72/91] add P3DXMPM particle type --- include/mesh_xmpm.tcc | 2 ++ include/solvers/xmpm_explicit.tcc | 5 +++-- src/particle.cc | 10 ++++++---- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/include/mesh_xmpm.tcc b/include/mesh_xmpm.tcc index eb43b915b..8f1f7beb6 100644 --- a/include/mesh_xmpm.tcc +++ b/include/mesh_xmpm.tcc @@ -50,6 +50,8 @@ void mpm::Mesh::compute_shapefn_discontinuity() { template void mpm::Mesh::compute_cell_normal_vector_discontinuity() { for (auto citr = cells_.cbegin(); citr != cells_.cend(); ++citr) { + if ((*citr)->element_type_discontinuity() == mpm::EnrichType::Regular) + continue; (*citr)->compute_normal_vector_discontinuity(); (*citr)->compute_plane_discontinuity(false); } diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index 6b5c2933c..dd461fff5 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -138,7 +138,8 @@ bool mpm::XMPMExplicit::solve() { } for (; step_ < nsteps_; ++step_) { - bool nodal_update = true; + // to do + bool nodal_update = false; if (mpi_rank == 0) console_->info("Step: {} of {}.\n", step_, nsteps_); @@ -313,7 +314,7 @@ bool mpm::XMPMExplicit::solve() { if ((step_ + 1) % output_steps_ == 0) { // HDF5 outputs this->write_hdf5(this->step_ + 1, this->nsteps_); - + // to do mesh_->output_discontinuity(this->step_ + 1); // mesh_->output_force(step_); #ifdef USE_VTK diff --git a/src/particle.cc b/src/particle.cc index 0c993d816..1b799d359 100644 --- a/src/particle.cc +++ b/src/particle.cc @@ -7,9 +7,9 @@ namespace mpm { // ParticleType -std::map ParticleType = {{"P2D", 0}, {"P3D", 1}, - {"P2DFLUID", 2}, {"P3DFLUID", 3}, - {"P2D2PHASE", 4}, {"P3D2PHASE", 5}}; +std::map ParticleType = { + {"P2D", 0}, {"P3D", 1}, {"P2DFLUID", 2}, {"P3DFLUID", 3}, + {"P2D2PHASE", 4}, {"P3D2PHASE", 5}, {"P2DXMPM", 7}, {"P3DXMPM", 8}}; std::map ParticleTypeName = { {0, "P2D"}, {1, "P3D"}, {2, "P2DFLUID"}, {3, "P3DFLUID"}, {4, "P2D2PHASE"}, {5, "P3D2PHASE"}}; @@ -19,7 +19,9 @@ std::map ParticlePODTypeName = { {"P2DFLUID", "fluid_particles"}, {"P3DFLUID", "fluid_particles"}, {"P2D2PHASE", "twophase_particles"}, - {"P3D2PHASE", "twophase_particles"}}; + {"P3D2PHASE", "twophase_particles"}, + {"P2DXMPM", "particles"}, + {"P3DXMPM", "particles"}}; } // namespace mpm // Particle2D (2 Dim) From 128ea5c88ff52a5f1b2284b2035fc632363a885a Mon Sep 17 00:00:00 2001 From: Nanda Date: Thu, 4 Nov 2021 16:21:53 -0700 Subject: [PATCH 73/91] clang formating --- include/mesh_multiphase.tcc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mesh_multiphase.tcc b/include/mesh_multiphase.tcc index 5fc10999a..7ae0e17e0 100644 --- a/include/mesh_multiphase.tcc +++ b/include/mesh_multiphase.tcc @@ -439,7 +439,7 @@ std::set mpm::Mesh::free_surface_particles() { //! Compute cell volume fraction template void mpm::Mesh::compute_cell_vol_fraction() { - this->iterate_over_cells([& map_particles = map_particles_]( + this->iterate_over_cells([&map_particles = map_particles_]( std::shared_ptr> c_ptr) { if (c_ptr->status()) { // Compute volume fraction From 50138ee7f933af996bcf311eb5381df4bfba4df2 Mon Sep 17 00:00:00 2001 From: yliang-sn Date: Thu, 4 Nov 2021 18:17:55 -0700 Subject: [PATCH 74/91] clean the unsed variables --- include/mesh_xmpm.tcc | 3 --- include/particles/particle_xmpm.tcc | 3 --- include/solvers/xmpm_explicit.tcc | 2 -- 3 files changed, 8 deletions(-) diff --git a/include/mesh_xmpm.tcc b/include/mesh_xmpm.tcc index 8f1f7beb6..0c07aa30b 100644 --- a/include/mesh_xmpm.tcc +++ b/include/mesh_xmpm.tcc @@ -524,9 +524,6 @@ void mpm::Mesh::update_discontinuity() { (*citr)->compute_discontinuity_point(coordinates); for (int i = 0; i < coordinates.size(); i++) { discontinuity_->insert_particles(coordinates[i], cells_, map_cells_); - - double d = (*citr)->d_discontinuity(); - auto normal_cell = (*citr)->normal_discontinuity(); } } } diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index 9693ab858..e663f2d50 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -478,8 +478,6 @@ template void mpm::ParticleXMPM::compute_initiation_normal( VectorDim& normal_initiation) { - double theta; - double phi; double dtheta = 1; const double PI = M_PI / 180; VectorDim normal_m; @@ -495,7 +493,6 @@ void mpm::ParticleXMPM::compute_initiation_normal( double det_de_n; double det_dp_n; - double mininum_ratio = std::numeric_limits::max(); double max_dudxmn = 0; bool yield_status = true; diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index dd461fff5..91481aea1 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -411,8 +411,6 @@ template bool mpm::XMPMExplicit::checkpoint_resume() { bool checkpoint = true; try { - // TODO: Set phase - const unsigned phase = 0; int mpi_rank = 0; #ifdef USE_MPI From b178b1340dab538c531ff014d68501721f9ce29c Mon Sep 17 00:00:00 2001 From: yliang-sn Date: Thu, 4 Nov 2021 18:21:22 -0700 Subject: [PATCH 75/91] clean the unsed variables --- include/particles/particle_xmpm.tcc | 3 +++ include/solvers/xmpm_explicit.tcc | 2 ++ 2 files changed, 5 insertions(+) diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index e663f2d50..9693ab858 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -478,6 +478,8 @@ template void mpm::ParticleXMPM::compute_initiation_normal( VectorDim& normal_initiation) { + double theta; + double phi; double dtheta = 1; const double PI = M_PI / 180; VectorDim normal_m; @@ -493,6 +495,7 @@ void mpm::ParticleXMPM::compute_initiation_normal( double det_de_n; double det_dp_n; + double mininum_ratio = std::numeric_limits::max(); double max_dudxmn = 0; bool yield_status = true; diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index 91481aea1..dd461fff5 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -411,6 +411,8 @@ template bool mpm::XMPMExplicit::checkpoint_resume() { bool checkpoint = true; try { + // TODO: Set phase + const unsigned phase = 0; int mpi_rank = 0; #ifdef USE_MPI From f27b51ca8fd10fe87123cff9637733615e24c452 Mon Sep 17 00:00:00 2001 From: yliang-sn Date: Thu, 4 Nov 2021 18:22:02 -0700 Subject: [PATCH 76/91] clean the unsed variables --- include/particles/particle_xmpm.tcc | 3 --- include/solvers/xmpm_explicit.tcc | 2 -- 2 files changed, 5 deletions(-) diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index 9693ab858..e663f2d50 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -478,8 +478,6 @@ template void mpm::ParticleXMPM::compute_initiation_normal( VectorDim& normal_initiation) { - double theta; - double phi; double dtheta = 1; const double PI = M_PI / 180; VectorDim normal_m; @@ -495,7 +493,6 @@ void mpm::ParticleXMPM::compute_initiation_normal( double det_de_n; double det_dp_n; - double mininum_ratio = std::numeric_limits::max(); double max_dudxmn = 0; bool yield_status = true; diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index dd461fff5..91481aea1 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -411,8 +411,6 @@ template bool mpm::XMPMExplicit::checkpoint_resume() { bool checkpoint = true; try { - // TODO: Set phase - const unsigned phase = 0; int mpi_rank = 0; #ifdef USE_MPI From 5aa3fbd00e62fc4d08d4f44c5627f374f23af967 Mon Sep 17 00:00:00 2001 From: Nanda Date: Fri, 5 Nov 2021 10:29:25 -0700 Subject: [PATCH 77/91] fix particle cc --- src/particle.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/particle.cc b/src/particle.cc index 1b799d359..2a8dfedcd 100644 --- a/src/particle.cc +++ b/src/particle.cc @@ -9,10 +9,10 @@ namespace mpm { // ParticleType std::map ParticleType = { {"P2D", 0}, {"P3D", 1}, {"P2DFLUID", 2}, {"P3DFLUID", 3}, - {"P2D2PHASE", 4}, {"P3D2PHASE", 5}, {"P2DXMPM", 7}, {"P3DXMPM", 8}}; + {"P2D2PHASE", 4}, {"P3D2PHASE", 5}, {"P2DXMPM", 6}, {"P3DXMPM", 7}}; std::map ParticleTypeName = { - {0, "P2D"}, {1, "P3D"}, {2, "P2DFLUID"}, - {3, "P3DFLUID"}, {4, "P2D2PHASE"}, {5, "P3D2PHASE"}}; + {0, "P2D"}, {1, "P3D"}, {2, "P2DFLUID"}, {3, "P3DFLUID"}, + {4, "P2D2PHASE"}, {5, "P3D2PHASE"}, {6, "P2DXMPM"}, {7, "P3DXMPM"}}; std::map ParticlePODTypeName = { {"P2D", "particles"}, {"P3D", "particles"}, @@ -38,6 +38,7 @@ static Register, mpm::Particle<3>, mpm::Index, static Register, mpm::ParticleXMPM<3>, mpm::Index, const Eigen::Matrix&> particle3dxmpm("P3DXMPM"); + // Single phase (fluid) particle2D (2 Dim) static Register, mpm::FluidParticle<2>, mpm::Index, const Eigen::Matrix&> From 652dec6f5241d84abda3fa8f04fa7835e6f3010f Mon Sep 17 00:00:00 2001 From: yliang-sn Date: Fri, 5 Nov 2021 11:15:30 -0700 Subject: [PATCH 78/91] remove hardcode in mohr_coulomb.tcc --- include/materials/mohr_coulomb.tcc | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/materials/mohr_coulomb.tcc b/include/materials/mohr_coulomb.tcc index f7d3afcd9..641ab3f7c 100644 --- a/include/materials/mohr_coulomb.tcc +++ b/include/materials/mohr_coulomb.tcc @@ -333,9 +333,6 @@ Eigen::Matrix mpm::MohrCoulomb::compute_stress( const double pdstrain = (*state_vars).at("pdstrain"); // Update MC parameters using a linear softening rule - (*state_vars).at("phi") = phi_peak_; - (*state_vars).at("psi") = psi_peak_; - (*state_vars).at("cohesion") = cohesion_peak_; if (softening_ && pdstrain > pdstrain_peak_) { if (pdstrain < pdstrain_residual_) { (*state_vars).at("phi") = From 7daa8d83e1c6bcf28fad07a108ff2167acb30940 Mon Sep 17 00:00:00 2001 From: yliang-sn Date: Fri, 5 Nov 2021 11:19:46 -0700 Subject: [PATCH 79/91] remove typo --- include/node_base.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/node_base.h b/include/node_base.h index 63dcaa416..05a7a38d6 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -224,7 +224,7 @@ class NodeBase { //! Assign velocity constraint //! Directions can take values between 0 and Dim * Nphases //! \param[in] dir Direction of velocity constraint - //! \param[ivirtualn] velocity Applied velocity constraint + //! \param[in] velocity Applied velocity constraint virtual bool assign_velocity_constraint(unsigned dir, double velocity) = 0; //! Apply velocity constraints From 170658cd3b686cc5092ec1472edee8fae4747966 Mon Sep 17 00:00:00 2001 From: yliang-sn Date: Fri, 5 Nov 2021 11:29:46 -0700 Subject: [PATCH 80/91] update write_mesh_particles.cc --- include/mesh_multiphase.tcc | 2 +- tests/io/write_mesh_particles.cc | 949 ------------------------------- 2 files changed, 1 insertion(+), 950 deletions(-) delete mode 100644 tests/io/write_mesh_particles.cc diff --git a/include/mesh_multiphase.tcc b/include/mesh_multiphase.tcc index 7ae0e17e0..5fc10999a 100644 --- a/include/mesh_multiphase.tcc +++ b/include/mesh_multiphase.tcc @@ -439,7 +439,7 @@ std::set mpm::Mesh::free_surface_particles() { //! Compute cell volume fraction template void mpm::Mesh::compute_cell_vol_fraction() { - this->iterate_over_cells([&map_particles = map_particles_]( + this->iterate_over_cells([& map_particles = map_particles_]( std::shared_ptr> c_ptr) { if (c_ptr->status()) { // Compute volume fraction diff --git a/tests/io/write_mesh_particles.cc b/tests/io/write_mesh_particles.cc deleted file mode 100644 index c17af69af..000000000 --- a/tests/io/write_mesh_particles.cc +++ /dev/null @@ -1,949 +0,0 @@ -#include "write_mesh_particles.h" - -namespace mpm_test { - -// Write JSON Configuration file -bool write_json(unsigned dim, bool resume, const std::string& analysis, - const std::string& mpm_scheme, const std::string& file_name) { - // Make json object with input files - // 2D - std::string dimension = "2d"; - auto particle_type = "P2D"; - auto node_type = "N2D"; - auto cell_type = "ED2Q4"; - auto io_type = "Ascii2D"; - std::string material = "LinearElastic2D"; - std::vector gravity{{0., -9.81}}; - unsigned material_id = 0; - 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 = "P3D"; - node_type = "N3D"; - cell_type = "ED3H8"; - io_type = "Ascii3D"; - material = "LinearElastic3D"; - 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}}, - {{"id", 1}, - {"type", material}, - {"density", 2300.}, - {"youngs_modulus", 1.5E+6}, - {"poisson_ratio", 0.25}}}}, - {"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}, - {"mpm_scheme", mpm_scheme}, - {"locate_particles", true}, - {"dt", 0.001}, - {"uuid", file_name + "-" + dimension}, - {"nsteps", 10}, - {"boundary_friction", 0.5}, - {"resume", - {{"resume", resume}, - {"uuid", file_name + "-" + dimension}, - {"step", 5}}}, - {"damping", {{"type", "Cundall"}, {"damping_factor", 0.02}}}, - {"newmark", {{"beta", 0.25}, {"gamma", 0.5}}}}}, - {"post_processing", - {{"path", "results/"}, - {"vtk", {"stresses", "strains", "velocities"}}, - {"vtk_statevars", {{{"phase_id", 0}, {"statevars", {"pdstrain"}}}}}, - {"output_steps", 5}}}}; - - // Dump JSON as an input file to be read - std::string fname = (file_name + "-" + dimension + ".json").c_str(); - std::ofstream file; - file.open(fname, std::ios_base::out); - file << json_file.dump(2); - file.close(); - - return true; -} - -// Write JSON Configuration file for xmpm -bool write_json_xmpm(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 = "P2DXMPM"; - auto node_type = "N2D"; - auto cell_type = "ED2Q4"; - auto io_type = "Ascii2D"; - auto discontinuity_file = "discontinuity-2d.txt"; - std::string material = "LinearElastic2D"; - std::vector gravity{{0., -9.81}}; - unsigned material_id = 0; - // Write JSON Configuration file for implicit linear - bool write_json_implicit_linear( - unsigned dim, bool resume, const std::string& analysis, - const std::string& mpm_scheme, const std::string& file_name, - const std::string& linear_solver_type) { - // Make json object with input files - // 2D - std::string dimension = "2d"; - auto particle_type = "P2D"; - auto node_type = "N2D"; - auto cell_type = "ED2Q4"; - auto io_type = "Ascii2D"; - auto assembler_type = "EigenImplicitLinear2D"; - std::string entity_set_name = "entity_sets_0"; - std::string material = "LinearElastic2D"; - std::vector gravity{{0., -9.81}}; - std::vector material_id{{0}}; - 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 = "P3DXMPM"; - node_type = "N3D"; - cell_type = "ED3H8"; - particle_type = "P3D"; - node_type = "N3D"; - cell_type = "ED3H8"; - assembler_type = "EigenImplicitLinear3D"; - io_type = "Ascii3D"; - material = "LinearElastic3D"; - gravity.clear(); - gravity = {0., 0., -9.81}; - discontinuity_file = "discontinuity-3d.txt"; - entity_set_name = "entity_sets_1"; - } - - Json json_file = { - {"title", "Example JSON Input for MPM"}, - {"mesh", - {{"mesh", "mesh-" + dimension + ".txt"}, - {"entity_sets", "entity_sets_0.json"}, - {"entity_sets", entity_set_name + ".json"}, - {"io_type", io_type}, - {"check_duplicates", true}, - {"isoparametric", false}, - {"node_type", node_type}, - {"boundary_conditions", - {{"displacement_constraints", - {{"file", "displacement-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}}, - {{"id", 1}, - {"type", material}, - {"density", 2300.}, - {"youngs_modulus", 1.5E+6}, - {"poisson_ratio", 0.25}}}}, - {"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}, - {"mpm_scheme", mpm_scheme}, - {"locate_particles", true}, - {"pressure_smoothing", true}, - {"dt", 0.0001}, - {"uuid", file_name + "-" + dimension}, - {"nsteps", 10}, - {"resume", - {{"resume", resume}, - {"uuid", file_name + "-" + dimension}, - {"step", 5}}}, - {"linear_solver", - {{"assembler_type", assembler_type}, - {"solver_settings", - {{{"dof", "displacement"}, - {"solver_type", linear_solver_type}, - {"sub_solver_type", "cg"}, - {"preconditioner_type", "none"}, - {"max_iter", 100}, - {"tolerance", 1E-5}, - {"verbosity", 0}}}}}}, - {"damping", {{"type", "Cundall"}, {"damping_factor", 0.0}}}, - {"newmark", {{"beta", 0.25}, {"gamma", 0.5}}}}}, - {"post_processing", - {{"path", "results/"}, - {"vtk", {"stresses", "strains", "velocity"}}, - {"vtk_statevars", {{{"phase_id", 0}, {"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 Configuration file for navierstokes - bool write_json_navierstokes( - unsigned dim, bool resume, const std::string& analysis, - const std::string& mpm_scheme, const std::string& file_name, - const std::string& free_surface_type, - const std::string& linear_solver_type) { - // Make json object with input files - // 2D - std::string dimension = "2d"; - auto particle_type = "P2DFLUID"; - auto node_type = "N2D"; - auto cell_type = "ED2Q4"; - auto io_type = "Ascii2D"; - auto assembler_type = "EigenSemiImplicitNavierStokes2D"; - std::string entity_set_name = "entity_sets_0"; - std::string material = "Newtonian2D"; - std::vector gravity{{0., -9.81}}; - std::vector material_id{{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 = "P3DFLUID"; - node_type = "N3D"; - cell_type = "ED3H8"; - assembler_type = "EigenSemiImplicitNavierStokes3D"; - io_type = "Ascii3D"; - material = "Newtonian3D"; - gravity.clear(); - gravity = {0., 0., -9.81}; - entity_set_name = "entity_sets_1"; - } - - Json json_file = { - {"title", "Example JSON Input for MPM"}, - {"mesh", - {{"mesh", "mesh-" + dimension + ".txt"}, - {"entity_sets", entity_set_name + ".json"}, - {"io_type", io_type}, - {"check_duplicates", true}, - {"isoparametric", false}, - {"node_type", node_type}, - {"boundary_conditions", - {{"velocity_constraints", {{"file", "velocity-constraints.txt"}}}, - {"pressure_constraints", - {{{"phase_id", 0}, {"nset_id", 1}, {"pressure", 0.0}}}}, - {"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"}}}}}}, - {"discontinuity", - {{{"id", 0}, - {"type", "tri3d"}, - {"io_type", "Ascii3D"}, - {"file", discontinuity_file}, - {"frictional_coefficient", 0.3}}}}, - {"materials", - {{{"id", 2}, - {"type", material}, - {"density", 1000.}, - {"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}, - {"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}, - {"boundary_friction", 0.5}, - {"resume", - {{"resume", resume}, - {"uuid", file_name + "-" + dimension}, - {"step", 5}}}, - {"semi_implicit", {{"beta", 1}, {"integration", "mp"}}}, - {"free_surface_detection", - {{"type", free_surface_type}, {"volume_tolerance", 0.25}}}, - {"linear_solver", - {{"assembler_type", assembler_type}, - {"solver_settings", - {{{"dof", "pressure"}, - {"solver_type", linear_solver_type}, - {"sub_solver_type", "cg"}, - {"preconditioner_type", "none"}, - {"max_iter", 100}, - {"tolerance", 1E-5}, - {"verbosity", 0}}}}}}, - {"damping", {{"type", "Cundall"}, {"damping_factor", 0.02}}}, - {"newmark", {{"beta", 0.25}, {"gamma", 0.5}}}}}, - {"post_processing", - {{"path", "results/"}, - {"vtk", {"stresses", "strains", "velocity"}}, - {"vtk_statevars", {{{"phase_id", 0}, {"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 Configuration file for twophase - bool write_json_twophase( - unsigned dim, bool resume, const std::string& analysis, - const std::string& mpm_scheme, const std::string& file_name, - const std::string& free_surface_type, - const std::string& linear_solver_type) { - // 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"; - auto assembler_type = "EigenSemiImplicitTwoPhase2D"; - std::string entity_set_name = "entity_sets_0"; - 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"; - assembler_type = "EigenSemiImplicitTwoPhase3D"; - io_type = "Ascii3D"; - material = "LinearElastic3D"; - liquid_material = "Newtonian3D"; - gravity.clear(); - gravity = {0., 0., -9.81}; - entity_set_name = "entity_sets_1"; - } - - Json json_file = { - {"title", "Example JSON Input for MPM"}, - {"mesh", - {{"mesh", "mesh-" + dimension + ".txt"}, - {"entity_sets", entity_set_name + ".json"}, - {"io_type", io_type}, - {"check_duplicates", true}, - {"isoparametric", false}, - {"node_type", node_type}, - {"boundary_conditions", - {{"velocity_constraints", {{"file", "velocity-constraints.txt"}}}, - {"pressure_constraints", - {{{"phase_id", 1}, {"nset_id", 1}, {"pressure", 0.0}}}}, - {"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", 1000.}, - {"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}, - {"dt", 0.001}, -======= - {"locate_particles", true}, - {"pressure_smoothing", true}, - {"pore_pressure_smoothing", true}, - {"free_surface_detection", - {{"type", "density"}, {"volume_tolerance", 0.25}}}, - {"dt", 0.0001}, ->>>>>>> master - {"nsteps", 10}, - {"boundary_friction", 0.5}, - {"resume", - {{"resume", resume}, - {"uuid", file_name + "-" + dimension}, - {"step", 5}}}, - {"semi_implicit", {{"beta", 1}, {"integration", "mp"}}}, - {"free_surface_detection", - {{"type", free_surface_type}, {"volume_tolerance", 0.25}}}, - {"linear_solver", - {{"assembler_type", assembler_type}, - {"solver_settings", - {{{"dof", "pressure"}, - {"solver_type", linear_solver_type}, - {"sub_solver_type", "cg"}, - {"preconditioner_type", "none"}, - {"max_iter", 100}, - {"tolerance", 1E-5}, - {"verbosity", 0}}, - {{"dof", "acceleration"}, - {"solver_type", linear_solver_type}, - {"sub_solver_type", "lscg"}, - {"preconditioner_type", "none"}, - {"max_iter", 100}, - {"tolerance", 1E-5}, - {"verbosity", 0}}}}}}, - {"damping", {{"type", "Cundall"}, {"damping_factor", 0.02}}}, - {"newmark", {{"beta", 0.25}, {"gamma", 0.5}}}}}, - {"post_processing", - {{"path", "results/"}, - {"vtk", {"stresses", "strains", "velocity"}}, - {"vtk_statevars", {{{"phase_id", 0}, {"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 - Json json_file0 = { - {"particle_sets", - {{{"id", 2}, - {"set", {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}}}}}, - {"node_sets", {{{"id", 1}, {"set", {4, 5}}}}}}; - - Json json_file1 = { - {"particle_sets", - {{{"id", 2}, - {"set", {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}}}}}, - {"node_sets", {{{"id", 1}, {"set", {8, 9, 10, 11}}}}}}; - - // Dump JSON as an input file to be read - std::ofstream file; - file.open("entity_sets_0.json"); - file << json_file0.dump(2); - file.close(); - - file.open("entity_sets_1.json"); - file << json_file1.dump(2); - file.close(); - - return true; - } - - // Write Mesh file in 2D - bool write_mesh_2d() { - // Dimension - const unsigned dim = 2; - - // Vector of nodal coordinates - std::vector> coordinates; - - // Nodal coordinates - Eigen::Matrix node; - - // Cell 0 - // Node 0 - node << 0., 0.; - coordinates.emplace_back(node); - // Node 1 - node << 0.5, 0.; - coordinates.emplace_back(node); - // Node 2 - node << 0.5, 0.5; - coordinates.emplace_back(node); - // Node 3 - node << 0., 0.5; - coordinates.emplace_back(node); - - // Cell 1 - // Node 4 - node << 1.0, 0.; - coordinates.emplace_back(node); - // Node 5 - node << 1.0, 0.5; - coordinates.emplace_back(node); - - // Cell with node ids - std::vector> cells{// cell #0 - {0, 1, 2, 3}, - // cell #1 - {1, 4, 5, 2}}; - - // Dump mesh file as an input file to be read - std::ofstream file; - file.open("mesh-2d.txt"); - file << "! elementShape hexahedron\n"; - file << "! elementNumPoints 8\n"; - file << coordinates.size() << "\t" << cells.size() << "\n"; - - // Write nodal coordinates - for (const auto& coord : coordinates) { - for (unsigned i = 0; i < coord.size(); ++i) file << coord[i] << "\t"; - file << "\n"; - } - - // Write cell node ids - for (const auto& cell : cells) { - for (auto nid : cell) file << nid << "\t"; - file << "\n"; - } - file.close(); - - // Dump mesh velocity constraints - std::ofstream file_constraints; - file_constraints.open("velocity-constraints.txt"); - file_constraints << 0 << "\t" << 1 << "\t" << 0 << "\n"; - file_constraints << 1 << "\t" << 1 << "\t" << 0 << "\n"; - file_constraints.close(); - - return true; - } - - // Write particles file in 2D - bool write_particles_2d() { - const unsigned dim = 2; - // Vector of particle coordinates - std::vector> coordinates; - coordinates.clear(); - - // Particle coordinates - Eigen::Matrix particle; - - // Cell 0 - // Particle 0 - particle << 0.125, 0.125; - coordinates.emplace_back(particle); - // Particle 1 - particle << 0.25, 0.125; - coordinates.emplace_back(particle); - // Particle 2 - particle << 0.25, 0.25; - coordinates.emplace_back(particle); - // Particle 3 - particle << 0.125, 0.25; - coordinates.emplace_back(particle); - - // Cell 1 - // Particle 4 - particle << 0.675, 0.125; - coordinates.emplace_back(particle); - // Particle 5 - particle << 0.85, 0.125; - coordinates.emplace_back(particle); - // Particle 6 - particle << 0.85, 0.25; - coordinates.emplace_back(particle); - // Particle 7 - particle << 0.675, 0.25; - coordinates.emplace_back(particle); - - // Dump particles coordinates as an input file to be read - std::ofstream file; - file.open("particles-2d.txt"); - file << coordinates.size() << "\n"; - // Write particle coordinates - for (const auto& coord : coordinates) { - for (unsigned i = 0; i < coord.size(); ++i) { - file << coord[i] << "\t"; - } - file << "\n"; - } - - file.close(); - return true; - } - - // Write mesh file in 3D - bool write_mesh_3d() { - - // Dimension - const unsigned dim = 3; - - // Vector of nodal coordinates - std::vector> coordinates; - - // Nodal coordinates - Eigen::Matrix node; - - // Cell 0 - // Node 0 - node << 0., 0., 0.; - coordinates.emplace_back(node); - // Node 1 - node << 0.5, 0., 0.; - coordinates.emplace_back(node); - // Node 2 - node << 0.5, 0.5, 0.; - coordinates.emplace_back(node); - // Node 3 - node << 0., 0.5, 0.; - coordinates.emplace_back(node); - // Node 4 - node << 0., 0., 0.5; - coordinates.emplace_back(node); - // Node 5 - node << 0.5, 0., 0.5; - coordinates.emplace_back(node); - // Node 6 - node << 0.5, 0.5, 0.5; - coordinates.emplace_back(node); - // Node 7 - node << 0., 0.5, 0.5; - coordinates.emplace_back(node); - - // Cell 1 - // Node 8 - node << 1.0, 0., 0.; - coordinates.emplace_back(node); - // Node 9 - node << 1.0, 0.5, 0.; - coordinates.emplace_back(node); - // Node 10 - node << 1.0, 0., 0.5; - coordinates.emplace_back(node); - // Node 11 - node << 1.0, 0.5, 0.5; - coordinates.emplace_back(node); - - // Cell with node ids - std::vector> cells{// cell #0 - {0, 1, 2, 3, 4, 5, 6, 7}, - // cell #1 - {1, 8, 9, 2, 5, 10, 11, 6}}; - - // Dump mesh file as an input file to be read - std::ofstream file; - file.open("mesh-3d.txt"); - file << "! elementShape hexahedron\n"; - file << "! elementNumPoints 8\n"; - file << coordinates.size() << "\t" << cells.size() << "\n"; - - // Write nodal coordinates - for (const auto& coord : coordinates) { - for (unsigned i = 0; i < coord.size(); ++i) file << coord[i] << "\t"; - file << "\n"; - } - - // Write cell node ids - for (const auto& cell : cells) { - for (auto nid : cell) file << nid << "\t"; - file << "\n"; - } - - file.close(); - - // Dump mesh velocity constraints - std::ofstream file_constraints; - file_constraints.open("velocity-constraints.txt"); - file_constraints << 0 << "\t" << 3 << "\t" << 0 << "\n"; - file_constraints << 1 << "\t" << 3 << "\t" << 0 << "\n"; - file_constraints << 2 << "\t" << 3 << "\t" << 0 << "\n"; - file_constraints << 3 << "\t" << 3 << "\t" << 0 << "\n"; - file_constraints.close(); - - return true; - } - - // Write particles file in 3D - bool write_particles_3d() { - const unsigned dim = 3; - // Vector of particle coordinates - std::vector> coordinates; - - // Particle coordinates - Eigen::Matrix particle; - - // Cell 0 - // Particle 0 - particle << 0.125, 0.125, 0.125; - coordinates.emplace_back(particle); - // Particle 1 - particle << 0.25, 0.125, 0.125; - coordinates.emplace_back(particle); - // Particle 2 - particle << 0.25, 0.25, 0.125; - coordinates.emplace_back(particle); - // Particle 3 - particle << 0.125, 0.25, 0.125; - coordinates.emplace_back(particle); - // Particle 4 - particle << 0.125, 0.125, 0.25; - coordinates.emplace_back(particle); - // Particle 5 - particle << 0.25, 0.125, 0.25; - coordinates.emplace_back(particle); - // Particle 6 - particle << 0.25, 0.25, 0.25; - coordinates.emplace_back(particle); - // Particle 7 - particle << 0.125, 0.25, 0.25; - coordinates.emplace_back(particle); - - // Cell 1 - // Particle 8 - particle << 0.675, 0.125, 0.125; - coordinates.emplace_back(particle); - // Particle 9 - particle << 0.85, 0.125, 0.125; - coordinates.emplace_back(particle); - // Particle 10 - particle << 0.85, 0.25, 0.125; - coordinates.emplace_back(particle); - // Particle 11 - particle << 0.675, 0.25, 0.125; - coordinates.emplace_back(particle); - // Particle 12 - particle << 0.675, 0.125, 0.25; - coordinates.emplace_back(particle); - // Particle 13 - particle << 0.85, 0.125, 0.25; - coordinates.emplace_back(particle); - // Particle 14 - particle << 0.85, 0.25, 0.25; - coordinates.emplace_back(particle); - // Particle 15 - particle << 0.675, 0.25, 0.25; - coordinates.emplace_back(particle); - - // Dump particles coordinates as an input file to be read - std::ofstream file; - file.open("particles-3d.txt"); - file << coordinates.size() << "\n"; - // Write particle coordinates - for (const auto& coord : coordinates) { - for (unsigned i = 0; i < coord.size(); ++i) { - file << coord[i] << "\t"; - } - file << "\n"; - } - - file.close(); - return true; - } - - // Write mesh file in 3D - bool write_discontinuity_3d() { - - // Dimension - const unsigned dim = 3; - - // Vector of nodal coordinates - std::vector> coordinates; - - // Nodal coordinates - Eigen::Matrix point; - - // point 0 - point << 0., 0., 0.25; - coordinates.emplace_back(point); - // point 1 - point << 0.5, 0., 0.25; - coordinates.emplace_back(point); - // point 2 - point << 1.0, 0., 0.25; - coordinates.emplace_back(point); - // point 3 - point << 1.0, 0.5, 0.25; - coordinates.emplace_back(point); - // point 4 - point << 0.5, 0.5, 0.25; - coordinates.emplace_back(point); - // point 5 - point << 0., 0.5, 0.25; - coordinates.emplace_back(point); - - // surfaces with point ids - std::vector> surfs{// surface #0 - {0, 1, 5}, - // surface #1 - {1, 4, 5}, - // surface #2 - {1, 3, 4}, - // surface #3 - {1, 2, 3}}; - - // Dump discontinuity file as an input file to be read - std::ofstream file; - file.open("discontinuity-3d.txt"); - file << "! surfaceShape triangle\n"; - file << coordinates.size() << "\t" << surfs.size() << "\n"; - - // Write point coordinates - for (const auto& coord : coordinates) { - for (unsigned i = 0; i < coord.size(); ++i) file << coord[i] << "\t"; - file << "\n"; - } - - // Write cell node ids - for (const auto& surf : surfs) { - for (auto pid : surf) file << pid << "\t"; - file << "\n"; - } - - file.close(); - - // Dump mesh velocity constraints - std::ofstream file_constraints; - file_constraints.open("velocity-constraints.txt"); - file_constraints << 0 << "\t" << 0 << "\t" << 0 << "\n"; - file_constraints.close(); - - return true; - } -} // namespace mpm_test From 99179d8b4f18302cf9d72f5cb4f1bf2bbe86683a Mon Sep 17 00:00:00 2001 From: yliang-sn Date: Fri, 5 Nov 2021 11:32:21 -0700 Subject: [PATCH 81/91] update write_mesh_particles.cc --- tests/io/write_mesh_particles.cc | 854 +++++++++++++++++++++++++++++++ 1 file changed, 854 insertions(+) create mode 100644 tests/io/write_mesh_particles.cc diff --git a/tests/io/write_mesh_particles.cc b/tests/io/write_mesh_particles.cc new file mode 100644 index 000000000..58014eb94 --- /dev/null +++ b/tests/io/write_mesh_particles.cc @@ -0,0 +1,854 @@ +#include "write_mesh_particles.h" + +namespace mpm_test { + +// Write JSON Configuration file +bool write_json(unsigned dim, bool resume, const std::string& analysis, + const std::string& mpm_scheme, const std::string& file_name) { + // Make json object with input files + // 2D + std::string dimension = "2d"; + auto particle_type = "P2D"; + auto node_type = "N2D"; + auto cell_type = "ED2Q4"; + auto io_type = "Ascii2D"; + std::string material = "LinearElastic2D"; + std::vector gravity{{0., -9.81}}; + unsigned material_id = 0; + 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 = "P3D"; + node_type = "N3D"; + cell_type = "ED3H8"; + io_type = "Ascii3D"; + material = "LinearElastic3D"; + 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}}, + {{"id", 1}, + {"type", material}, + {"density", 2300.}, + {"youngs_modulus", 1.5E+6}, + {"poisson_ratio", 0.25}}}}, + {"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}, + {"mpm_scheme", mpm_scheme}, + {"locate_particles", true}, + {"dt", 0.001}, + {"uuid", file_name + "-" + dimension}, + {"nsteps", 10}, + {"boundary_friction", 0.5}, + {"resume", + {{"resume", resume}, + {"uuid", file_name + "-" + dimension}, + {"step", 5}}}, + {"damping", {{"type", "Cundall"}, {"damping_factor", 0.02}}}, + {"newmark", {{"beta", 0.25}, {"gamma", 0.5}}}}}, + {"post_processing", + {{"path", "results/"}, + {"vtk", {"stresses", "strains", "velocities"}}, + {"vtk_statevars", {{{"phase_id", 0}, {"statevars", {"pdstrain"}}}}}, + {"output_steps", 5}}}}; + + // Dump JSON as an input file to be read + std::string fname = (file_name + "-" + dimension + ".json").c_str(); + std::ofstream file; + file.open(fname, std::ios_base::out); + file << json_file.dump(2); + file.close(); + + return true; +} + +// Write JSON Configuration file for implicit linear +bool write_json_implicit_linear(unsigned dim, bool resume, + const std::string& analysis, + const std::string& mpm_scheme, + const std::string& file_name, + const std::string& linear_solver_type) { + // Make json object with input files + // 2D + std::string dimension = "2d"; + auto particle_type = "P2D"; + auto node_type = "N2D"; + auto cell_type = "ED2Q4"; + auto io_type = "Ascii2D"; + auto assembler_type = "EigenImplicitLinear2D"; + std::string entity_set_name = "entity_sets_0"; + std::string material = "LinearElastic2D"; + std::vector gravity{{0., -9.81}}; + std::vector material_id{{0}}; + 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 = "P3D"; + node_type = "N3D"; + cell_type = "ED3H8"; + assembler_type = "EigenImplicitLinear3D"; + io_type = "Ascii3D"; + material = "LinearElastic3D"; + gravity.clear(); + gravity = {0., 0., -9.81}; + entity_set_name = "entity_sets_1"; + } + + Json json_file = { + {"title", "Example JSON Input for MPM"}, + {"mesh", + {{"mesh", "mesh-" + dimension + ".txt"}, + {"entity_sets", entity_set_name + ".json"}, + {"io_type", io_type}, + {"check_duplicates", true}, + {"isoparametric", false}, + {"node_type", node_type}, + {"boundary_conditions", + {{"displacement_constraints", + {{"file", "displacement-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}}, + {{"id", 1}, + {"type", material}, + {"density", 2300.}, + {"youngs_modulus", 1.5E+6}, + {"poisson_ratio", 0.25}}}}, + {"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}, + {"mpm_scheme", mpm_scheme}, + {"locate_particles", true}, + {"pressure_smoothing", true}, + {"dt", 0.0001}, + {"uuid", file_name + "-" + dimension}, + {"nsteps", 10}, + {"resume", + {{"resume", resume}, + {"uuid", file_name + "-" + dimension}, + {"step", 5}}}, + {"linear_solver", + {{"assembler_type", assembler_type}, + {"solver_settings", + {{{"dof", "displacement"}, + {"solver_type", linear_solver_type}, + {"sub_solver_type", "cg"}, + {"preconditioner_type", "none"}, + {"max_iter", 100}, + {"tolerance", 1E-5}, + {"verbosity", 0}}}}}}, + {"damping", {{"type", "Cundall"}, {"damping_factor", 0.0}}}, + {"newmark", {{"beta", 0.25}, {"gamma", 0.5}}}}}, + {"post_processing", + {{"path", "results/"}, + {"vtk", {"stresses", "strains", "velocity"}}, + {"vtk_statevars", {{{"phase_id", 0}, {"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 Configuration file for navierstokes +bool write_json_navierstokes(unsigned dim, bool resume, + const std::string& analysis, + const std::string& mpm_scheme, + const std::string& file_name, + const std::string& free_surface_type, + const std::string& linear_solver_type) { + // Make json object with input files + // 2D + std::string dimension = "2d"; + auto particle_type = "P2DFLUID"; + auto node_type = "N2D"; + auto cell_type = "ED2Q4"; + auto io_type = "Ascii2D"; + auto assembler_type = "EigenSemiImplicitNavierStokes2D"; + std::string entity_set_name = "entity_sets_0"; + std::string material = "Newtonian2D"; + std::vector gravity{{0., -9.81}}; + std::vector material_id{{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 = "P3DFLUID"; + node_type = "N3D"; + cell_type = "ED3H8"; + assembler_type = "EigenSemiImplicitNavierStokes3D"; + io_type = "Ascii3D"; + material = "Newtonian3D"; + gravity.clear(); + gravity = {0., 0., -9.81}; + entity_set_name = "entity_sets_1"; + } + + Json json_file = { + {"title", "Example JSON Input for MPM"}, + {"mesh", + {{"mesh", "mesh-" + dimension + ".txt"}, + {"entity_sets", entity_set_name + ".json"}, + {"io_type", io_type}, + {"check_duplicates", true}, + {"isoparametric", false}, + {"node_type", node_type}, + {"boundary_conditions", + {{"velocity_constraints", {{"file", "velocity-constraints.txt"}}}, + {"pressure_constraints", + {{{"phase_id", 0}, {"nset_id", 1}, {"pressure", 0.0}}}}, + {"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", 2}, + {"type", material}, + {"density", 1000.}, + {"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}, + {"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}, + {"boundary_friction", 0.5}, + {"resume", + {{"resume", resume}, + {"uuid", file_name + "-" + dimension}, + {"step", 5}}}, + {"semi_implicit", {{"beta", 1}, {"integration", "mp"}}}, + {"free_surface_detection", + {{"type", free_surface_type}, {"volume_tolerance", 0.25}}}, + {"linear_solver", + {{"assembler_type", assembler_type}, + {"solver_settings", + {{{"dof", "pressure"}, + {"solver_type", linear_solver_type}, + {"sub_solver_type", "cg"}, + {"preconditioner_type", "none"}, + {"max_iter", 100}, + {"tolerance", 1E-5}, + {"verbosity", 0}}}}}}, + {"damping", {{"type", "Cundall"}, {"damping_factor", 0.02}}}, + {"newmark", {{"beta", 0.25}, {"gamma", 0.5}}}}}, + {"post_processing", + {{"path", "results/"}, + {"vtk", {"stresses", "strains", "velocity"}}, + {"vtk_statevars", {{{"phase_id", 0}, {"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 Configuration file for twophase +bool write_json_twophase(unsigned dim, bool resume, const std::string& analysis, + const std::string& mpm_scheme, + const std::string& file_name, + const std::string& free_surface_type, + const std::string& linear_solver_type) { + // 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"; + auto assembler_type = "EigenSemiImplicitTwoPhase2D"; + std::string entity_set_name = "entity_sets_0"; + 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"; + assembler_type = "EigenSemiImplicitTwoPhase3D"; + io_type = "Ascii3D"; + material = "LinearElastic3D"; + liquid_material = "Newtonian3D"; + gravity.clear(); + gravity = {0., 0., -9.81}; + entity_set_name = "entity_sets_1"; + } + + Json json_file = { + {"title", "Example JSON Input for MPM"}, + {"mesh", + {{"mesh", "mesh-" + dimension + ".txt"}, + {"entity_sets", entity_set_name + ".json"}, + {"io_type", io_type}, + {"check_duplicates", true}, + {"isoparametric", false}, + {"node_type", node_type}, + {"boundary_conditions", + {{"velocity_constraints", {{"file", "velocity-constraints.txt"}}}, + {"pressure_constraints", + {{{"phase_id", 1}, {"nset_id", 1}, {"pressure", 0.0}}}}, + {"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", 1000.}, + {"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}, + {"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}, + {"boundary_friction", 0.5}, + {"resume", + {{"resume", resume}, + {"uuid", file_name + "-" + dimension}, + {"step", 5}}}, + {"semi_implicit", {{"beta", 1}, {"integration", "mp"}}}, + {"free_surface_detection", + {{"type", free_surface_type}, {"volume_tolerance", 0.25}}}, + {"linear_solver", + {{"assembler_type", assembler_type}, + {"solver_settings", + {{{"dof", "pressure"}, + {"solver_type", linear_solver_type}, + {"sub_solver_type", "cg"}, + {"preconditioner_type", "none"}, + {"max_iter", 100}, + {"tolerance", 1E-5}, + {"verbosity", 0}}, + {{"dof", "acceleration"}, + {"solver_type", linear_solver_type}, + {"sub_solver_type", "lscg"}, + {"preconditioner_type", "none"}, + {"max_iter", 100}, + {"tolerance", 1E-5}, + {"verbosity", 0}}}}}}, + {"damping", {{"type", "Cundall"}, {"damping_factor", 0.02}}}, + {"newmark", {{"beta", 0.25}, {"gamma", 0.5}}}}}, + {"post_processing", + {{"path", "results/"}, + {"vtk", {"stresses", "strains", "velocity"}}, + {"vtk_statevars", {{{"phase_id", 0}, {"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 + Json json_file0 = { + {"particle_sets", + {{{"id", 2}, + {"set", {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}}}}}, + {"node_sets", {{{"id", 1}, {"set", {4, 5}}}}}}; + + Json json_file1 = { + {"particle_sets", + {{{"id", 2}, + {"set", {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}}}}}, + {"node_sets", {{{"id", 1}, {"set", {8, 9, 10, 11}}}}}}; + + // Dump JSON as an input file to be read + std::ofstream file; + file.open("entity_sets_0.json"); + file << json_file0.dump(2); + file.close(); + + file.open("entity_sets_1.json"); + file << json_file1.dump(2); + file.close(); + + return true; +} + +// Write Mesh file in 2D +bool write_mesh_2d() { + // Dimension + const unsigned dim = 2; + + // Vector of nodal coordinates + std::vector> coordinates; + + // Nodal coordinates + Eigen::Matrix node; + + // Cell 0 + // Node 0 + node << 0., 0.; + coordinates.emplace_back(node); + // Node 1 + node << 0.5, 0.; + coordinates.emplace_back(node); + // Node 2 + node << 0.5, 0.5; + coordinates.emplace_back(node); + // Node 3 + node << 0., 0.5; + coordinates.emplace_back(node); + + // Cell 1 + // Node 4 + node << 1.0, 0.; + coordinates.emplace_back(node); + // Node 5 + node << 1.0, 0.5; + coordinates.emplace_back(node); + + // Cell with node ids + std::vector> cells{// cell #0 + {0, 1, 2, 3}, + // cell #1 + {1, 4, 5, 2}}; + + // Dump mesh file as an input file to be read + std::ofstream file; + file.open("mesh-2d.txt"); + file << "! elementShape hexahedron\n"; + file << "! elementNumPoints 8\n"; + file << coordinates.size() << "\t" << cells.size() << "\n"; + + // Write nodal coordinates + for (const auto& coord : coordinates) { + for (unsigned i = 0; i < coord.size(); ++i) file << coord[i] << "\t"; + file << "\n"; + } + + // Write cell node ids + for (const auto& cell : cells) { + for (auto nid : cell) file << nid << "\t"; + file << "\n"; + } + file.close(); + + // Dump mesh velocity constraints + std::ofstream file_constraints; + file_constraints.open("velocity-constraints.txt"); + file_constraints << 0 << "\t" << 1 << "\t" << 0 << "\n"; + file_constraints << 1 << "\t" << 1 << "\t" << 0 << "\n"; + file_constraints.close(); + + return true; +} + +// Write particles file in 2D +bool write_particles_2d() { + const unsigned dim = 2; + // Vector of particle coordinates + std::vector> coordinates; + coordinates.clear(); + + // Particle coordinates + Eigen::Matrix particle; + + // Cell 0 + // Particle 0 + particle << 0.125, 0.125; + coordinates.emplace_back(particle); + // Particle 1 + particle << 0.25, 0.125; + coordinates.emplace_back(particle); + // Particle 2 + particle << 0.25, 0.25; + coordinates.emplace_back(particle); + // Particle 3 + particle << 0.125, 0.25; + coordinates.emplace_back(particle); + + // Cell 1 + // Particle 4 + particle << 0.675, 0.125; + coordinates.emplace_back(particle); + // Particle 5 + particle << 0.85, 0.125; + coordinates.emplace_back(particle); + // Particle 6 + particle << 0.85, 0.25; + coordinates.emplace_back(particle); + // Particle 7 + particle << 0.675, 0.25; + coordinates.emplace_back(particle); + + // Dump particles coordinates as an input file to be read + std::ofstream file; + file.open("particles-2d.txt"); + file << coordinates.size() << "\n"; + // Write particle coordinates + for (const auto& coord : coordinates) { + for (unsigned i = 0; i < coord.size(); ++i) { + file << coord[i] << "\t"; + } + file << "\n"; + } + + file.close(); + return true; +} + +// Write mesh file in 3D +bool write_mesh_3d() { + + // Dimension + const unsigned dim = 3; + + // Vector of nodal coordinates + std::vector> coordinates; + + // Nodal coordinates + Eigen::Matrix node; + + // Cell 0 + // Node 0 + node << 0., 0., 0.; + coordinates.emplace_back(node); + // Node 1 + node << 0.5, 0., 0.; + coordinates.emplace_back(node); + // Node 2 + node << 0.5, 0.5, 0.; + coordinates.emplace_back(node); + // Node 3 + node << 0., 0.5, 0.; + coordinates.emplace_back(node); + // Node 4 + node << 0., 0., 0.5; + coordinates.emplace_back(node); + // Node 5 + node << 0.5, 0., 0.5; + coordinates.emplace_back(node); + // Node 6 + node << 0.5, 0.5, 0.5; + coordinates.emplace_back(node); + // Node 7 + node << 0., 0.5, 0.5; + coordinates.emplace_back(node); + + // Cell 1 + // Node 8 + node << 1.0, 0., 0.; + coordinates.emplace_back(node); + // Node 9 + node << 1.0, 0.5, 0.; + coordinates.emplace_back(node); + // Node 10 + node << 1.0, 0., 0.5; + coordinates.emplace_back(node); + // Node 11 + node << 1.0, 0.5, 0.5; + coordinates.emplace_back(node); + + // Cell with node ids + std::vector> cells{// cell #0 + {0, 1, 2, 3, 4, 5, 6, 7}, + // cell #1 + {1, 8, 9, 2, 5, 10, 11, 6}}; + + // Dump mesh file as an input file to be read + std::ofstream file; + file.open("mesh-3d.txt"); + file << "! elementShape hexahedron\n"; + file << "! elementNumPoints 8\n"; + file << coordinates.size() << "\t" << cells.size() << "\n"; + + // Write nodal coordinates + for (const auto& coord : coordinates) { + for (unsigned i = 0; i < coord.size(); ++i) file << coord[i] << "\t"; + file << "\n"; + } + + // Write cell node ids + for (const auto& cell : cells) { + for (auto nid : cell) file << nid << "\t"; + file << "\n"; + } + + file.close(); + + // Dump mesh velocity constraints + std::ofstream file_constraints; + file_constraints.open("velocity-constraints.txt"); + file_constraints << 0 << "\t" << 3 << "\t" << 0 << "\n"; + file_constraints << 1 << "\t" << 3 << "\t" << 0 << "\n"; + file_constraints << 2 << "\t" << 3 << "\t" << 0 << "\n"; + file_constraints << 3 << "\t" << 3 << "\t" << 0 << "\n"; + file_constraints.close(); + + return true; +} + +// Write particles file in 3D +bool write_particles_3d() { + const unsigned dim = 3; + // Vector of particle coordinates + std::vector> coordinates; + + // Particle coordinates + Eigen::Matrix particle; + + // Cell 0 + // Particle 0 + particle << 0.125, 0.125, 0.125; + coordinates.emplace_back(particle); + // Particle 1 + particle << 0.25, 0.125, 0.125; + coordinates.emplace_back(particle); + // Particle 2 + particle << 0.25, 0.25, 0.125; + coordinates.emplace_back(particle); + // Particle 3 + particle << 0.125, 0.25, 0.125; + coordinates.emplace_back(particle); + // Particle 4 + particle << 0.125, 0.125, 0.25; + coordinates.emplace_back(particle); + // Particle 5 + particle << 0.25, 0.125, 0.25; + coordinates.emplace_back(particle); + // Particle 6 + particle << 0.25, 0.25, 0.25; + coordinates.emplace_back(particle); + // Particle 7 + particle << 0.125, 0.25, 0.25; + coordinates.emplace_back(particle); + + // Cell 1 + // Particle 8 + particle << 0.675, 0.125, 0.125; + coordinates.emplace_back(particle); + // Particle 9 + particle << 0.85, 0.125, 0.125; + coordinates.emplace_back(particle); + // Particle 10 + particle << 0.85, 0.25, 0.125; + coordinates.emplace_back(particle); + // Particle 11 + particle << 0.675, 0.25, 0.125; + coordinates.emplace_back(particle); + // Particle 12 + particle << 0.675, 0.125, 0.25; + coordinates.emplace_back(particle); + // Particle 13 + particle << 0.85, 0.125, 0.25; + coordinates.emplace_back(particle); + // Particle 14 + particle << 0.85, 0.25, 0.25; + coordinates.emplace_back(particle); + // Particle 15 + particle << 0.675, 0.25, 0.25; + coordinates.emplace_back(particle); + + // Dump particles coordinates as an input file to be read + std::ofstream file; + file.open("particles-3d.txt"); + file << coordinates.size() << "\n"; + // Write particle coordinates + for (const auto& coord : coordinates) { + for (unsigned i = 0; i < coord.size(); ++i) { + file << coord[i] << "\t"; + } + file << "\n"; + } + + file.close(); + return true; +} + +} // namespace mpm_test From 302708dd1fc94af0c52198b5180dcb3928d083c7 Mon Sep 17 00:00:00 2001 From: yliang-sn Date: Fri, 5 Nov 2021 13:53:33 -0700 Subject: [PATCH 82/91] resolve bugs in test part --- include/particles/particle_base.h | 2 +- include/particles/particle_xmpm.h | 2 +- include/particles/particle_xmpm.tcc | 2 +- include/solvers/xmpm_explicit.tcc | 5 +- tests/io/write_mesh_particles.cc | 188 ++++++++++++++++++++++++ tests/mesh_test_3d.cc | 2 - tests/particle_xmpm_test.cc | 3 +- tests/solvers/xmpm_explicit_usf_test.cc | 2 +- tests/solvers/xmpm_explicit_usl_test.cc | 2 +- 9 files changed, 197 insertions(+), 11 deletions(-) diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 2891e1cf9..c073bc38a 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -366,7 +366,7 @@ class ParticleBase { //! Compute displacement //! \param[in] dt Analysis time step - virtual void compute_dudx(double dt){}; + virtual inline void compute_displacement_gradient(double dt) noexcept {}; //! to do //! virtual void check_levelset(){}; diff --git a/include/particles/particle_xmpm.h b/include/particles/particle_xmpm.h index ecd937018..0f54eaf61 100644 --- a/include/particles/particle_xmpm.h +++ b/include/particles/particle_xmpm.h @@ -75,7 +75,7 @@ class ParticleXMPM : public Particle { //! Compute displacement gradient //! \param[in] dt Analysis time step - void compute_dudx(double dt) noexcept; + void inline compute_displacement_gradient(double dt) noexcept override; //! to do //! virtual void check_levelset() noexcept override; diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index e663f2d50..980187e16 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -570,7 +570,7 @@ void mpm::ParticleXMPM::compute_initiation_normal( // Compute du_dx_ of the particle template <> -void mpm::ParticleXMPM<3>::compute_dudx(double dt) noexcept { +void inline mpm::ParticleXMPM<3>::compute_displacement_gradient(double dt) noexcept { // Define strain rate Eigen::Matrix dudx_rate = Eigen::Matrix::Zero(); const double tolerance = 1.E-16; diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index 91481aea1..49020cbee 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -256,8 +256,9 @@ bool mpm::XMPMExplicit::solve() { mpm_scheme_->precompute_stress_strain(phase, pressure_smoothing_); // Iterate over each particle to calculate dudx - mesh_->iterate_over_particles(std::bind( - &mpm::ParticleBase::compute_dudx, std::placeholders::_1, dt_)); + mesh_->iterate_over_particles( + std::bind(&mpm::ParticleBase::compute_displacement_gradient, + std::placeholders::_1, dt_)); // Compute forces mpm_scheme_->compute_forces(gravity_, phase, step_, diff --git a/tests/io/write_mesh_particles.cc b/tests/io/write_mesh_particles.cc index 58014eb94..0d759b83e 100644 --- a/tests/io/write_mesh_particles.cc +++ b/tests/io/write_mesh_particles.cc @@ -113,6 +113,125 @@ bool write_json(unsigned dim, bool resume, const std::string& analysis, return true; } +// Write JSON Configuration file for xmpm +bool write_json_xmpm(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 = "P2DXMPM"; + auto node_type = "N2D"; + auto cell_type = "ED2Q4"; + auto io_type = "Ascii2D"; + auto discontinuity_file = "discontinuity-2d.txt"; + std::string material = "LinearElastic2D"; + std::vector gravity{{0., -9.81}}; + unsigned material_id = 0; + 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 = "P3DXMPM"; + node_type = "N3D"; + cell_type = "ED3H8"; + io_type = "Ascii3D"; + material = "LinearElastic3D"; + gravity.clear(); + gravity = {0., 0., -9.81}; + discontinuity_file = "discontinuity-3d.txt"; + } + + 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"}}}}}}, + {"discontinuity", + {{{"id", 0}, + {"type", "tri3d"}, + {"io_type", "Ascii3D"}, + {"file", discontinuity_file}, + {"frictional_coefficient", 0.3}}}}, + {"materials", + {{{"id", 0}, + {"type", material}, + {"density", 1000.}, + {"youngs_modulus", 1.0E+8}, + {"poisson_ratio", 0.495}}, + {{"id", 1}, + {"type", material}, + {"density", 2300.}, + {"youngs_modulus", 1.5E+6}, + {"poisson_ratio", 0.25}}}}, + {"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.001}, + {"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", "velocities"}}, + {"vtk_statevars", {{{"phase_id", 0}, {"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 Configuration file for implicit linear bool write_json_implicit_linear(unsigned dim, bool resume, const std::string& analysis, @@ -851,4 +970,73 @@ bool write_particles_3d() { return true; } +// Write mesh file in 3D +bool write_discontinuity_3d() { + + // Dimension + const unsigned dim = 3; + + // Vector of nodal coordinates + std::vector> coordinates; + + // Nodal coordinates + Eigen::Matrix point; + + // point 0 + point << 0., 0., 0.25; + coordinates.emplace_back(point); + // point 1 + point << 0.5, 0., 0.25; + coordinates.emplace_back(point); + // point 2 + point << 1.0, 0., 0.25; + coordinates.emplace_back(point); + // point 3 + point << 1.0, 0.5, 0.25; + coordinates.emplace_back(point); + // point 4 + point << 0.5, 0.5, 0.25; + coordinates.emplace_back(point); + // point 5 + point << 0., 0.5, 0.25; + coordinates.emplace_back(point); + + // surfaces with point ids + std::vector> surfs{// surface #0 + {0, 1, 5}, + // surface #1 + {1, 4, 5}, + // surface #2 + {1, 3, 4}, + // surface #3 + {1, 2, 3}}; + + // Dump discontinuity file as an input file to be read + std::ofstream file; + file.open("discontinuity-3d.txt"); + file << "! surfaceShape triangle\n"; + file << coordinates.size() << "\t" << surfs.size() << "\n"; + + // Write point coordinates + for (const auto& coord : coordinates) { + for (unsigned i = 0; i < coord.size(); ++i) file << coord[i] << "\t"; + file << "\n"; + } + + // Write cell node ids + for (const auto& surf : surfs) { + for (auto pid : surf) file << pid << "\t"; + file << "\n"; + } + + file.close(); + + // Dump mesh velocity constraints + std::ofstream file_constraints; + file_constraints.open("velocity-constraints.txt"); + file_constraints << 0 << "\t" << 0 << "\t" << 0 << "\n"; + file_constraints.close(); + + return true; +} } // namespace mpm_test diff --git a/tests/mesh_test_3d.cc b/tests/mesh_test_3d.cc index 5e6e0eb87..56d40ab1c 100644 --- a/tests/mesh_test_3d.cc +++ b/tests/mesh_test_3d.cc @@ -1568,14 +1568,12 @@ TEST_CASE("Mesh is checked for 3D case", "[mesh][3D]") { discontinuities; discontinuities.insert(std::make_pair(discontinuity_id, discontinuity)); - REQUIRE_NOTHROW(mesh->initialise_discontinuities(discontinuities)); REQUIRE_NOTHROW(mesh->locate_discontinuity()); double dt = 0.1; REQUIRE_NOTHROW(mesh->compute_updated_position_discontinuity(dt)); REQUIRE_NOTHROW(mesh->compute_shapefn_discontinuity()); - REQUIRE_NOTHROW(mesh->compute_normal_vector_discontinuity()); REQUIRE_NOTHROW(mesh->initialise_levelset_discontinuity()); } } diff --git a/tests/particle_xmpm_test.cc b/tests/particle_xmpm_test.cc index 5e864debe..150841f96 100644 --- a/tests/particle_xmpm_test.cc +++ b/tests/particle_xmpm_test.cc @@ -5,7 +5,6 @@ #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" @@ -69,7 +68,7 @@ TEST_CASE("Particle_XMPM is checked for 3D case", "[particle][3D][XMPM]") { mpm::Index id = 0; bool status = true; std::shared_ptr> particle = - std::make_shared>(id, coords, status); + std::make_shared>(id, coords); REQUIRE(particle->id() == 0); REQUIRE(particle->status() == true); particle->assign_status(false); diff --git a/tests/solvers/xmpm_explicit_usf_test.cc b/tests/solvers/xmpm_explicit_usf_test.cc index e8facc811..6c6d14bb4 100644 --- a/tests/solvers/xmpm_explicit_usf_test.cc +++ b/tests/solvers/xmpm_explicit_usf_test.cc @@ -54,7 +54,7 @@ TEST_CASE("XMPM 3D Explicit implementation is checked", // Initialise particles REQUIRE_NOTHROW(mpm->initialise_particles()); // Initialise discontinuities - REQUIRE_NOTHROW(mpm->initialise_discontinuities()); + REQUIRE_NOTHROW(mpm->initialise_discontinuity()); // Renitialise materials REQUIRE_THROWS(mpm->initialise_materials()); diff --git a/tests/solvers/xmpm_explicit_usl_test.cc b/tests/solvers/xmpm_explicit_usl_test.cc index 2e0dc6a56..6a54694b5 100644 --- a/tests/solvers/xmpm_explicit_usl_test.cc +++ b/tests/solvers/xmpm_explicit_usl_test.cc @@ -49,7 +49,7 @@ TEST_CASE("XMPM 3D Explicit USL implementation is checked", // Initialise materials REQUIRE_NOTHROW(mpm->initialise_materials()); // Initialise discontinuities - REQUIRE_NOTHROW(mpm->initialise_discontinuities()); + REQUIRE_NOTHROW(mpm->initialise_discontinuity()); // Initialise mesh and particles REQUIRE_NOTHROW(mpm->initialise_mesh()); REQUIRE_NOTHROW(mpm->initialise_particles()); From 708682daeeafeacfd11fd7f1d8a8a8e8762c0a99 Mon Sep 17 00:00:00 2001 From: yliang-sn Date: Sat, 6 Nov 2021 16:33:30 -0700 Subject: [PATCH 83/91] define XMPM group for XMPM functions and variables --- include/cell.h | 12 ++++++++++++ include/mesh.h | 13 +++++++++++++ include/node.h | 6 +++++- include/node_base.h | 7 +++++++ include/particles/particle_base.h | 7 +++++++ 5 files changed, 44 insertions(+), 1 deletion(-) diff --git a/include/cell.h b/include/cell.h index 06b4cbaed..53639601a 100644 --- a/include/cell.h +++ b/include/cell.h @@ -218,6 +218,11 @@ class Cell { //! Return previous mpi rank unsigned previous_mpirank() const; + /** + * \defgroup XMPM Functions dealing with XMPM + */ + /**@{*/ + //! Assign discontinuity element type void assign_type_discontinuity(mpm::EnrichType type); @@ -289,6 +294,8 @@ class Cell { //! Assign the area of the discontinuity to nodes void assign_cohesion_area(); + /**@}*/ + /** * \defgroup Implicit Functions dealing with implicit MPM */ @@ -554,8 +561,13 @@ class Cell { //! Logger std::unique_ptr console_; + /** + * \defgroup XMPM Varibales for XMPM + */ + /**@{*/ //! discontinuity element std::shared_ptr> discontinuity_element_{nullptr}; + /**@}*/ }; // Cell class } // namespace mpm diff --git a/include/mesh.h b/include/mesh.h index 40b0d3a45..2c5d1178e 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -501,6 +501,11 @@ class Mesh { // Initialise the nodal properties' map void initialise_nodal_properties(); + /** + * \defgroup XMPM Functions dealing with XMPM + */ + /**@{*/ + //! Create the nodal properties' map for discontinuity void create_nodal_properties_discontinuity(); @@ -573,6 +578,9 @@ class Mesh { //! Assign the level set values to the particles which just enter the crossed //! cell void check_particle_levelset(bool particle_levelset); + + /**@}*/ + /** * \defgroup MultiPhase Functions dealing with multi-phase MPM */ @@ -736,8 +744,13 @@ class Mesh { unsigned nhalo_nodes_{0}; //! Maximum number of halo nodes unsigned ncomms_{0}; + /** + * \defgroup XMPM Variables for XMPM + */ + /**@{*/ //! discontinuity std::shared_ptr> discontinuity_; + /**@}*/ }; // Mesh class } // namespace mpm diff --git a/include/node.h b/include/node.h index 295216007..b23b5342f 100644 --- a/include/node.h +++ b/include/node.h @@ -5,7 +5,6 @@ #include "mutex.h" #include "nodal_properties.h" #include "node_base.h" -#include namespace mpm { @@ -296,6 +295,10 @@ class Node : public NodeBase { //! Compute multimaterial normal unit vector void compute_multimaterial_normal_unit_vector() override; + /** + * \defgroup XMPM Functions dealing with XMPM + */ + /**@{*/ //! Assign whether the node is enriched //! \param[in] discontinuity_enrich_: true or false void assign_discontinuity_enrich(bool discontinuity) { @@ -361,6 +364,7 @@ class Node : public NodeBase { //! Return connected cells //! \retval cells_ connected cells std::vector cells() const { return cells_; } + /**@}*/ /** * \defgroup Implicit Functions dealing with implicit MPM diff --git a/include/node_base.h b/include/node_base.h index 05a7a38d6..c4c6c3bc2 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -293,6 +293,11 @@ class NodeBase { //! Compute multimaterial normal unit vector virtual void compute_multimaterial_normal_unit_vector() = 0; + /** + * \defgroup XMPM Functions dealing with XMPM + */ + /**@{*/ + //! Return data in the nodal discontinuity properties map at a specific index //! \param[in] property Property name //! \param[in] nprops Dimension of property (1 if scalar, Tdim if vector) @@ -353,6 +358,8 @@ class NodeBase { //! Return cells_ virtual std::vector cells() const = 0; + /**@}*/ + /** * \defgroup Implicit Functions dealing with implicit MPM */ diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index c073bc38a..70a1f75d5 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -347,6 +347,11 @@ class ParticleBase { virtual void deserialize( const std::vector& buffer, std::vector>>& materials) = 0; + + /** + * \defgroup XMPM Functions dealing with XMPM + */ + /**@{*/ //! set the level set function values //! \param[in] phivalue Signed distance function virtual void assign_levelsetphi(double phivalue){}; @@ -383,6 +388,8 @@ class ParticleBase { return false; }; + /**@}*/ + /** * \defgroup Implicit Functions dealing with implicit MPM */ From 93497aabe51cc6ddee7f3498689b86322e5d8354 Mon Sep 17 00:00:00 2001 From: yliang-sn Date: Sat, 6 Nov 2021 16:59:57 -0700 Subject: [PATCH 84/91] add comment "\ingroup XMPM" and initialise_xmpm function --- include/cell.h | 21 ++++++++++++++++++++- include/mesh.h | 24 ++++++++++++++++++++++-- include/node.h | 15 ++++++++++++++- include/node_base.h | 18 ++++++++++++++++-- include/node_xmpm.tcc | 8 ++++++++ include/particles/particle_base.h | 10 +++++++++- 6 files changed, 89 insertions(+), 7 deletions(-) diff --git a/include/cell.h b/include/cell.h index 53639601a..7f04dcb67 100644 --- a/include/cell.h +++ b/include/cell.h @@ -224,74 +224,93 @@ class Cell { /**@{*/ //! Assign discontinuity element type + //! \ingroup XMPM void assign_type_discontinuity(mpm::EnrichType type); //! Initialize discontinuity element properties + //! \ingroup XMPM void initialise_element_properties_discontinuity(); //! Assign the normal direction of the discontinuity in the cell + //! \ingroup XMPM //! \param[in] the normal direction void assign_normal_discontinuity(VectorDim normal); //! Assign the constant parameters of the discontinuity in the cell + //! \ingroup XMPM //! \param[in] the constant parameters void assign_d_discontinuity(double d) { this->discontinuity_element_->assign_d(d); }; //! Assign the normal direction of the discontinuity in the cell + //! \ingroup XMPM //! \param[in] the normal direction //! \param[in] the plane constant void assign_normal_discontinuity(VectorDim normal, double d); //! Return the normal direction of the discontinuity in the cell + //! \ingroup XMPM //! \retval the normal direction of the discontinuity VectorDim normal_discontinuity() { return discontinuity_element_->normal_discontinuity(); }; //! Return discontinuity element type + //! \ingroup XMPM unsigned element_type_discontinuity(); //! Find the potential tip element + //! \ingroup XMPM void potential_tip_element(); //! Determine tip element + //! \ingroup XMPM void tip_element(); //! Compute normal vector of discontinuity by the nodal level set values + //! \ingroup XMPM void compute_normal_vector_discontinuity(); //! Compute the discontinuity plane by the nodal level set values + //! \ingroup XMPM //! \param[in] true: compute by the enriched nodes void compute_plane_discontinuity(bool enrich); //! Compute the discontinuity point: the average coordinates of the - //! intersection points \param[in] mark points list + //! \ingroup XMPM + //! \param[in] mark points list void compute_discontinuity_point(std::vector& coordinates); //! Return the product of the maximum and minimum nodal level set value + //! \ingroup XMPM //! \retval the product of the maximum and minimum nodal level set value double product_levelset(); //! Return the constant value of the discontinuity plane + //! \ingroup XMPM double d_discontinuity() { return this->discontinuity_element_->d_discontinuity(); } //! Determine the celltype by the nodal level set + //! \ingroup XMPM void determine_crossed(); //! Compute the nodal level set values by plane equations + //! \ingroup XMPM void compute_nodal_levelset_equation(); //! Compute the area of the discontinuity + //! \ingroup XMPM void compute_area_discontinuity(); //! Return the area of the discontinuity + //! \ingroup XMPM double discontinuity_area() { return this->discontinuity_element_->area(); } //! Assign the area of the discontinuity to nodes + //! \ingroup XMPM void assign_cohesion_area(); /**@}*/ diff --git a/include/mesh.h b/include/mesh.h index 2c5d1178e..fcab714c7 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -507,9 +507,11 @@ class Mesh { /**@{*/ //! Create the nodal properties' map for discontinuity + //! \ingroup XMPM void create_nodal_properties_discontinuity(); //! Initialise discontinuity + //! \ingroup XMPM //! \param[in] discontinuity List of discontinuity void initialise_discontinuity( const std::shared_ptr>& discontinuity) { @@ -517,57 +519,74 @@ class Mesh { } //! Locate points of discontinuity in a cell + //! \ingroup XMPM void locate_discontinuity(); //! Update the discontinuity position + //! \ingroup XMPM //! \param[in] dt Analysis time step void compute_updated_position_discontinuity(double dt); //! Update the discontinuity position + //! \ingroup XMPM void compute_shapefn_discontinuity(); //! compute the normal vector of cells + //! \ingroup XMPM void compute_cell_normal_vector_discontinuity(); //! compute the normal vector of enriched nodes at the discontinuity + //! \ingroup XMPM void compute_nodal_normal_vector_discontinuity(); //! Initialize the level set function values + //! \ingroup XMPM void initialise_levelset_discontinuity(); //! Initialize the nodal level set function values + //! \ingroup XMPM void initialise_nodal_levelset_discontinuity(); //! The evolution of the discontinuity + //! \ingroup XMPM void update_discontinuity(); //! Find next tip element + //! \ingroup XMPM void next_tip_element_discontinuity(); // Initialize the cells in node + //! \ingroup XMPM void add_cell_in_node(); //! Remove spurious potential tip element + //! \ingroup XMPM void spurious_potential_tip_element(); //! Assign node type as enrich + //! \ingroup XMPM //! \param[in] whether use the average value of the surrounding particle - //! friction angle \param[in] whether enrich all the nodes + //! \param[in] whether enrich all the nodes void assign_node_enrich(bool friction_coef_average, bool enrich_all); //! Find all the nodes need to enriched + //! \ingroup XMPM void update_node_enrich(); //! The initiation of discontinuity + //! \ingroup XMPM bool initiation_discontinuity(); //! Adjust the nodal levelset_phi by mls + //! \ingroup XMPM void modify_nodal_levelset_mls(); //! Compute the distance between two sides of discontinuity + //! \ingroup XMPM void selfcontact_detection(); //! code for debugging added by yliang start------------------------------- + //! \ingroup XMPM void output_discontinuity(int step) { this->discontinuity_->output_markpoints(step); }; @@ -576,7 +595,8 @@ class Mesh { //! code for debugging added by yliang end--------------------------------- //! Assign the level set values to the particles which just enter the crossed - //! cell + //! \ingroup XMPM + //! \param[in] the way to initialise the discontinuity void check_particle_levelset(bool particle_levelset); /**@}*/ diff --git a/include/node.h b/include/node.h index b23b5342f..25d0b8520 100644 --- a/include/node.h +++ b/include/node.h @@ -295,20 +295,27 @@ class Node : public NodeBase { //! Compute multimaterial normal unit vector void compute_multimaterial_normal_unit_vector() override; - /** + /** * \defgroup XMPM Functions dealing with XMPM */ /**@{*/ + //! Initialise nodal properties for XMPM solver + //! \ingroup XMPM + void initialise_xmpm() noexcept override; + //! Assign whether the node is enriched + //! \ingroup XMPM //! \param[in] discontinuity_enrich_: true or false void assign_discontinuity_enrich(bool discontinuity) { discontinuity_enrich_ = discontinuity; }; //! Return whether the node is enriched + //! \ingroup XMPM bool discontinuity_enrich() const { return discontinuity_enrich_; }; //! Update nodal property at the nodes from particle for discontinuity + //! \ingroup XMPM //! \param[in] update A boolean to update (true) or assign (false) //! \param[in] property Property name //! \param[in] property_value Property quantity from the particles in the cell @@ -320,6 +327,7 @@ class Node : public NodeBase { unsigned nprops) noexcept; //! assign nodal property at the nodes from particle for discontinuity + //! \ingroup XMPM //! \param[in] update A boolean to update (true) or assign (false) //! \param[in] property Property name //! \param[in] property_value Property quantity from the particles in the cell @@ -331,18 +339,21 @@ class Node : public NodeBase { unsigned nprops) noexcept; //! Return data in the nodal discontinuity properties map at a specific index + //! \ingroup XMPM //! \param[in] property Property name //! \param[in] nprops Dimension of property (1 if scalar, Tdim if vector) Eigen::MatrixXd discontinuity_property(const std::string& property, unsigned nprops = 1) noexcept override; //! Compute momentum for discontinuity + //! \ingroup XMPM //! \param[in] phase Index corresponding to the phase //! \param[in] dt Timestep in analysis bool compute_momentum_discontinuity(unsigned phase, double dt) noexcept override; //! Compute momentum for discontinuity with cundall damping factor + //! \ingroup XMPM //! \param[in] phase Index corresponding to the phase //! \param[in] dt Timestep in analysis //! \param[in] damping_factor Damping factor @@ -350,10 +361,12 @@ class Node : public NodeBase { unsigned phase, double dt, double damping_factor) noexcept override; //! Apply self-contact force of the discontinuity + //! \ingroup XMPM //! \param[in] dt Time-step void self_contact_discontinuity(double dt) noexcept override; //! Return the discontinuity_prop_id + //! \ingroup XMPM unsigned discontinuity_prop_id() const noexcept override { return discontinuity_prop_id_; }; diff --git a/include/node_base.h b/include/node_base.h index c4c6c3bc2..d311b9bc0 100644 --- a/include/node_base.h +++ b/include/node_base.h @@ -293,25 +293,32 @@ class NodeBase { //! Compute multimaterial normal unit vector virtual void compute_multimaterial_normal_unit_vector() = 0; - /** + /** * \defgroup XMPM Functions dealing with XMPM */ /**@{*/ + //! Initialise nodal properties for XMPM solver + //! \ingroup XMPM + virtual void initialise_xmpm() noexcept = 0; //! Return data in the nodal discontinuity properties map at a specific index + //! \ingroup XMPM //! \param[in] property Property name //! \param[in] nprops Dimension of property (1 if scalar, Tdim if vector) virtual Eigen::MatrixXd discontinuity_property( const std::string& property, unsigned nprops = 1) noexcept = 0; //! Assign whether the node is enriched + //! \ingroup XMPM //! \param[in] discontinuity discontinuity_enrich: true or false virtual void assign_discontinuity_enrich(bool discontinuity) = 0; //! Return whether the node is enriched + //! \ingroup XMPM virtual bool discontinuity_enrich() const = 0; //! Update nodal property at the nodes from particle for discontinuity + //! \ingroup XMPM //! \param[in] update A boolean to update (true) or assign (false) //! \param[in] property Property name //! \param[in] property_value Property quantity from the particles in the cell @@ -323,6 +330,7 @@ class NodeBase { unsigned nprops) noexcept = 0; //! Assign nodal property at the nodes from particle for discontinuity + //! \ingroup XMPM //! \param[in] update A boolean to update (true) or assign (false) //! \param[in] property Property name //! \param[in] property_value Property quantity from the particles in the cell @@ -334,12 +342,14 @@ class NodeBase { unsigned nprops) noexcept = 0; //! Compute momentum for discontinuity + //! \ingroup XMPM //! \param[in] phase Index corresponding to the phase //! \param[in] dt Timestep in analysis virtual bool compute_momentum_discontinuity(unsigned phase, double dt) noexcept = 0; //! Compute momentum for discontinuity with cundall damping factor + //! \ingroup XMPM //! \param[in] phase Index corresponding to the phase //! \param[in] dt Timestep in analysis //! \param[in] damping_factor Damping factor @@ -347,19 +357,23 @@ class NodeBase { unsigned phase, double dt, double damping_factor) noexcept = 0; //! Apply self-contact force of the discontinuity + //! \ingroup XMPM //! \param[in] dt Time-step virtual void self_contact_discontinuity(double dt) noexcept = 0; //! Return the discontinuity_prop_id + //! \ingroup XMPM virtual unsigned discontinuity_prop_id() const noexcept = 0; //! Add a cell id + //! \ingroup XMPM virtual void add_cell_id(Index id) = 0; //! Return cells_ + //! \ingroup XMPM virtual std::vector cells() const = 0; /**@}*/ - + /** * \defgroup Implicit Functions dealing with implicit MPM */ diff --git a/include/node_xmpm.tcc b/include/node_xmpm.tcc index ba7ea8431..82c0973db 100644 --- a/include/node_xmpm.tcc +++ b/include/node_xmpm.tcc @@ -1,3 +1,11 @@ +//! Initialise xmpm nodal variables +template +void mpm::Node::initialise_xmpm() noexcept { + this->initialise(); + // Specific variables for xmpm + discontinuity_enrich_ = false; +} + //! Initialise shared pointer to nodal properties pool for discontinuity template void mpm::Node::initialise_discontinuity_property_handle( diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 70a1f75d5..42906e823 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -348,28 +348,34 @@ class ParticleBase { const std::vector& buffer, std::vector>>& materials) = 0; - /** + /** * \defgroup XMPM Functions dealing with XMPM */ /**@{*/ //! set the level set function values + //! \ingroup XMPM //! \param[in] phivalue Signed distance function virtual void assign_levelsetphi(double phivalue){}; //! Map particle volume to nodes + //! \ingroup XMPM virtual void map_volume_to_nodes() noexcept = 0; //! Map particle levelset to nodes + //! \ingroup XMPM virtual void map_levelset_to_nodes(){}; //! Map particle frictional_coef to nodes + //! \ingroup XMPM //! \param[in] the default friction coefficient virtual void map_friction_coef_to_nodes(double discontinuity_friction_coef){}; //! Map levelset from nodes to particles + //! \ingroup XMPM virtual void map_levelset_to_particle(){}; //! Compute displacement + //! \ingroup XMPM //! \param[in] dt Analysis time step virtual inline void compute_displacement_gradient(double dt) noexcept {}; @@ -377,9 +383,11 @@ class ParticleBase { //! virtual void check_levelset(){}; //! return levelset values + //! \ingroup XMPM virtual double levelset_phi() { return 0; } //! compute the minimum eigenvalue of the acoustic tensor + //! \ingroup XMPM //! \param[in] the normal direction of the previous discontinuity //! \param[in] do the initiation detection loop //! \retval whether initiate or propagate From 76fbda15542c777d4b781fcdc0c5c599f17452a1 Mon Sep 17 00:00:00 2001 From: yliang-sn Date: Sat, 6 Nov 2021 17:01:09 -0700 Subject: [PATCH 85/91] delete discontinuity_enrich_ initialization in the node.tcc --- include/node.tcc | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/node.tcc b/include/node.tcc index 8ad582a4c..ec267cf2b 100644 --- a/include/node.tcc +++ b/include/node.tcc @@ -38,8 +38,6 @@ void mpm::Node::initialise() noexcept { status_ = false; solving_status_ = false; material_ids_.clear(); - // mark: need to check - discontinuity_enrich_ = false; } //! Initialise shared pointer to nodal properties pool From 1bb55d5a443a839891c49ffb4d644cec3d55a339 Mon Sep 17 00:00:00 2001 From: yliang-sn Date: Sat, 6 Nov 2021 17:07:06 -0700 Subject: [PATCH 86/91] defgroup xmpm --- include/particles/particle_base.h | 54 +++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 42906e823..780e54737 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -355,7 +355,13 @@ class ParticleBase { //! set the level set function values //! \ingroup XMPM //! \param[in] phivalue Signed distance function - virtual void assign_levelsetphi(double phivalue){}; + virtual void assign_levelsetphi(double phivalue) { + throw std::runtime_error( + "Calling the base class function (assign_levelsetphi) in " + "ParticleBase:: " + "illegal operation!"); + return 0; + }; //! Map particle volume to nodes //! \ingroup XMPM @@ -363,28 +369,58 @@ class ParticleBase { //! Map particle levelset to nodes //! \ingroup XMPM - virtual void map_levelset_to_nodes(){}; + virtual void map_levelset_to_nodes() { + throw std::runtime_error( + "Calling the base class function (map_levelset_to_nodes) in " + "ParticleBase:: " + "illegal operation!"); + return 0; + }; //! Map particle frictional_coef to nodes //! \ingroup XMPM //! \param[in] the default friction coefficient - virtual void map_friction_coef_to_nodes(double discontinuity_friction_coef){}; + virtual void map_friction_coef_to_nodes(double discontinuity_friction_coef) { + throw std::runtime_error( + "Calling the base class function (map_friction_coef_to_nodes) in " + "ParticleBase:: " + "illegal operation!"); + return 0; + }; //! Map levelset from nodes to particles //! \ingroup XMPM - virtual void map_levelset_to_particle(){}; + virtual void map_levelset_to_particle() { + throw std::runtime_error( + "Calling the base class function (map_levelset_to_particle) in " + "ParticleBase:: " + "illegal operation!"); + return 0; + }; //! Compute displacement //! \ingroup XMPM //! \param[in] dt Analysis time step - virtual inline void compute_displacement_gradient(double dt) noexcept {}; + virtual inline void compute_displacement_gradient(double dt) noexcept { + throw std::runtime_error( + "Calling the base class function (compute_displacement_gradient) in " + "ParticleBase:: " + "illegal operation!"); + return 0; + }; //! to do //! virtual void check_levelset(){}; //! return levelset values //! \ingroup XMPM - virtual double levelset_phi() { return 0; } + virtual double levelset_phi() { + throw std::runtime_error( + "Calling the base class function (levelset_phi) in " + "ParticleBase:: " + "illegal operation!"); + return 0; + } //! compute the minimum eigenvalue of the acoustic tensor //! \ingroup XMPM @@ -393,7 +429,11 @@ class ParticleBase { //! \retval whether initiate or propagate virtual bool minimum_acoustic_tensor(VectorDim& normal_cell, bool initiation) { - return false; + throw std::runtime_error( + "Calling the base class function (minimum_acoustic_tensor) in " + "ParticleBase:: " + "illegal operation!"); + return 0; }; /**@}*/ From 3b7250956a66d17d284212b8b130fe6ff082d0e3 Mon Sep 17 00:00:00 2001 From: yliang-sn Date: Sat, 6 Nov 2021 17:09:51 -0700 Subject: [PATCH 87/91] tidy the code --- include/solvers/mpm_base.tcc | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index 1b9860e87..db859e412 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -30,9 +30,6 @@ mpm::MPMBase::MPMBase(const std::shared_ptr& io) : mpm::MPM(io) { {"levelset", VariableType::Scalar}, {"minimum_acoustic_eigenvalue", VariableType::Scalar}, {"discontinuity_angle", VariableType::Scalar}, - {"first_principal_stress", VariableType::Scalar}, - {"first_principal_strain", VariableType::Scalar}, - {"energy", VariableType::Scalar}, // Vector variables {"displacements", VariableType::Vector}, {"velocities", VariableType::Vector}, From 288371e736e355df2a8a3033d2d06a3d6d4e2ea0 Mon Sep 17 00:00:00 2001 From: yliang-sn Date: Sun, 7 Nov 2021 14:59:20 -0800 Subject: [PATCH 88/91] add the pod_particle_xmpm class --- CMakeLists.txt | 1 + include/mesh.h | 14 ++ include/mesh.tcc | 2 + include/mesh_xmpm.tcc | 96 ++++++++ include/particles/particle_base.h | 8 +- include/particles/particle_xmpm.h | 3 +- include/particles/particle_xmpm.tcc | 103 ++++++++- .../pod_particles/pod_particle_xmpm.h | 40 ++++ include/solvers/mpm_base.tcc | 7 + include/solvers/xmpm_explicit.h | 3 - include/solvers/xmpm_explicit.tcc | 55 ----- src/particle.cc | 4 +- src/pod_particle_xmpm.cc | 217 ++++++++++++++++++ ...cle_serialize_deserialize_twophase_test.cc | 1 + 14 files changed, 482 insertions(+), 72 deletions(-) create mode 100644 include/particles/pod_particles/pod_particle_xmpm.h create mode 100644 src/pod_particle_xmpm.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index c186d7a3d..46ffc10cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -178,6 +178,7 @@ SET(mpm_src ${mpm_SOURCE_DIR}/src/geometry.cc ${mpm_SOURCE_DIR}/src/pod_particle.cc ${mpm_SOURCE_DIR}/src/pod_particle_twophase.cc + ${mpm_SOURCE_DIR}/src/pod_particle_xmpm.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/mesh.h b/include/mesh.h index fcab714c7..209c7dac3 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -599,6 +599,20 @@ class Mesh { //! \param[in] the way to initialise the discontinuity void check_particle_levelset(bool particle_levelset); + //! Read HDF5 particles for xmpm particle + //! \ingroup XMPM + //! \param[in] filename Name of HDF5 file to write particles data + //! \param[in] particle_type Particle type to be generated + //! \retval status Status of reading HDF5 output + bool read_particles_hdf5_xmpm(const std::string& filename, + const std::string& particle_type); + + //! Write HDF5 particles for xmpm particle + //! \ingroup XMPM + //! \param[in] filename Name of HDF5 file to write particles data + //! \retval status Status of writing HDF5 output + bool write_particles_hdf5_xmpm(const std::string& filename); + /**@}*/ /** diff --git a/include/mesh.tcc b/include/mesh.tcc index af0957997..0ec2ea260 100644 --- a/include/mesh.tcc +++ b/include/mesh.tcc @@ -1595,6 +1595,8 @@ bool mpm::Mesh::read_particles_hdf5(const std::string& filename, status = this->read_particles_hdf5(filename, particle_type); else if (type_name == "twophase_particles") status = this->read_particles_hdf5_twophase(filename, particle_type); + else if (type_name == "xmpm_particles") + status = this->read_particles_hdf5_xmpm(filename, particle_type); return status; } diff --git a/include/mesh_xmpm.tcc b/include/mesh_xmpm.tcc index 0c07aa30b..a7f1d05db 100644 --- a/include/mesh_xmpm.tcc +++ b/include/mesh_xmpm.tcc @@ -1008,6 +1008,102 @@ void mpm::Mesh::check_particle_levelset(bool particle_levelset) { } } +//! Read HDF5 particles for xmpm particle +template +bool mpm::Mesh::read_particles_hdf5_xmpm( + const std::string& filename, const std::string& particle_type) { + + // 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::pod::particlexmpm::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::particlexmpm::dst_size, + mpm::pod::particlexmpm::dst_offset, + mpm::pod::particlexmpm::dst_sizes, dst_buf.data()); + + // Iterate over all HDF5 particles + for (unsigned i = 0; i < nrecords; ++i) { + PODParticleXMPM pod_particle = dst_buf[i]; + // Get particle's material from list of materials + // Get particle's material from list of materials + std::vector>> materials; + materials.emplace_back(materials_.at(pod_particle.material_id)); + // Particle id + mpm::Index pid = pod_particle.id; + // Initialise coordinates + Eigen::Matrix coords; + coords.setZero(); + + // Create particle + auto particle = + Factory, mpm::Index, + const Eigen::Matrix&>::instance() + ->create(particle_type, static_cast(pid), coords); + + // Initialise particle with HDF5 data + particle->initialise_particle(pod_particle, materials); + + // Add particle to mesh and check + bool insert_status = this->add_particle(particle, false); + + // If insertion is successful + if (!insert_status) + throw std::runtime_error("Addition of particle to mesh failed!"); + } + // close the file + H5Fclose(file_id); + return true; +} + +//! Write particles to HDF5 for xmpm particle +template +bool mpm::Mesh::write_particles_hdf5_xmpm(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::particlexmpm::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::particlexmpm::dst_size, mpm::pod::particlexmpm::field_names, + mpm::pod::particlexmpm::dst_offset, mpm::pod::particlexmpm::field_type, + chunk_size, fill_data, compress, particle_data.data()); + + H5Fclose(file_id); + return true; +} + //! code for debugging added by yliang start------------------------------- template void mpm::Mesh::output_celltype(int step) { diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index 780e54737..a761146a4 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -17,6 +17,7 @@ #include "material.h" #include "pod_particle.h" #include "pod_particle_twophase.h" +#include "pod_particle_xmpm.h" namespace mpm { @@ -360,7 +361,6 @@ class ParticleBase { "Calling the base class function (assign_levelsetphi) in " "ParticleBase:: " "illegal operation!"); - return 0; }; //! Map particle volume to nodes @@ -374,7 +374,6 @@ class ParticleBase { "Calling the base class function (map_levelset_to_nodes) in " "ParticleBase:: " "illegal operation!"); - return 0; }; //! Map particle frictional_coef to nodes @@ -385,7 +384,6 @@ class ParticleBase { "Calling the base class function (map_friction_coef_to_nodes) in " "ParticleBase:: " "illegal operation!"); - return 0; }; //! Map levelset from nodes to particles @@ -395,18 +393,16 @@ class ParticleBase { "Calling the base class function (map_levelset_to_particle) in " "ParticleBase:: " "illegal operation!"); - return 0; }; //! Compute displacement //! \ingroup XMPM //! \param[in] dt Analysis time step - virtual inline void compute_displacement_gradient(double dt) noexcept { + virtual inline void compute_displacement_gradient(double dt) { throw std::runtime_error( "Calling the base class function (compute_displacement_gradient) in " "ParticleBase:: " "illegal operation!"); - return 0; }; //! to do diff --git a/include/particles/particle_xmpm.h b/include/particles/particle_xmpm.h index 0f54eaf61..10551d708 100644 --- a/include/particles/particle_xmpm.h +++ b/include/particles/particle_xmpm.h @@ -10,6 +10,7 @@ #include "cell.h" #include "logger.h" #include "particle_base.h" +#include "pod_particle_xmpm.h" namespace mpm { @@ -75,7 +76,7 @@ class ParticleXMPM : public Particle { //! Compute displacement gradient //! \param[in] dt Analysis time step - void inline compute_displacement_gradient(double dt) noexcept override; + void inline compute_displacement_gradient(double dt) override; //! to do //! virtual void check_levelset() noexcept override; diff --git a/include/particles/particle_xmpm.tcc b/include/particles/particle_xmpm.tcc index 980187e16..0976a9fa1 100644 --- a/include/particles/particle_xmpm.tcc +++ b/include/particles/particle_xmpm.tcc @@ -13,9 +13,9 @@ mpm::ParticleXMPM::ParticleXMPM(Index id, const VectorDim& coord) template bool mpm::ParticleXMPM::initialise_particle(PODParticle& particle) { bool status = mpm::Particle::initialise_particle(particle); + auto xmpm_particle = reinterpret_cast(&particle); // levelset_phi - // to do - levelset_phi_ = particle.levelset_phi; + this->levelset_phi_ = xmpm_particle->levelset_phi; return status; } @@ -25,8 +25,101 @@ template // cppcheck-suppress * std::shared_ptr mpm::ParticleXMPM::pod() const { - auto particle_data = std::make_shared(); - // to do + 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]; + + Eigen::Vector3d acceleration; + acceleration.setZero(); + for (unsigned j = 0; j < Tdim; ++j) acceleration[j] = this->acceleration_[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->acceleration_x = acceleration[0]; + particle_data->acceleration_y = acceleration[1]; + particle_data->acceleration_z = acceleration[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; + } + } + + // XMPM particle_data->levelset_phi = levelset_phi_; return particle_data; } @@ -570,7 +663,7 @@ void mpm::ParticleXMPM::compute_initiation_normal( // Compute du_dx_ of the particle template <> -void inline mpm::ParticleXMPM<3>::compute_displacement_gradient(double dt) noexcept { +void inline mpm::ParticleXMPM<3>::compute_displacement_gradient(double dt) { // Define strain rate Eigen::Matrix dudx_rate = Eigen::Matrix::Zero(); const double tolerance = 1.E-16; diff --git a/include/particles/pod_particles/pod_particle_xmpm.h b/include/particles/pod_particles/pod_particle_xmpm.h new file mode 100644 index 000000000..d2dbad880 --- /dev/null +++ b/include/particles/pod_particles/pod_particle_xmpm.h @@ -0,0 +1,40 @@ +#ifndef MPM_POD_XMPM_H_ +#define MPM_POD_XMPM_H_ + +// POD Particle +#include "pod_particle.h" + +namespace mpm { +// Define a struct of particle +typedef struct PODParticleXMPM : PODParticle { + // Level set values + double levelset_phi; + + // Destructor + virtual ~PODParticleXMPM() = default; +} PODParticleXMPM; + +namespace pod { +namespace particlexmpm { +const hsize_t NFIELDS = 57; + +const size_t dst_size = sizeof(PODParticleXMPM); + +// 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 particlexmpm +} // namespace pod + +} // namespace mpm + +#endif // MPM_POD_XMPM_H_ diff --git a/include/solvers/mpm_base.tcc b/include/solvers/mpm_base.tcc index db859e412..018c34139 100644 --- a/include/solvers/mpm_base.tcc +++ b/include/solvers/mpm_base.tcc @@ -523,6 +523,13 @@ void mpm::MPMBase::write_hdf5(mpm::Index step, mpm::Index max_steps) { // Load particle information from file mesh_->write_particles_hdf5(particles_file); + + if (attribute == "particles") + mesh_->write_particles_hdf5(particles_file); + else if (attribute == "twophase_particles") + mesh_->write_particles_hdf5_twophase(particles_file); + else if (attribute == "xmpm_particles") + mesh_->write_particles_hdf5_xmpm(particles_file); } } diff --git a/include/solvers/xmpm_explicit.h b/include/solvers/xmpm_explicit.h index ed1d7bd35..9e01e60c4 100644 --- a/include/solvers/xmpm_explicit.h +++ b/include/solvers/xmpm_explicit.h @@ -32,9 +32,6 @@ class XMPMExplicit : public MPMBase { //! Initialise discontinuity void initialise_discontinuity(); - //! Checkpoint resume - bool checkpoint_resume() override; - protected: // Generate a unique id for the analysis using mpm::MPMBase::uuid_; diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index 49020cbee..2b3acde7e 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -406,58 +406,3 @@ void mpm::XMPMExplicit::initialise_discontinuity() { exception.what()); } } - -//! Checkpoint resume -template -bool mpm::XMPMExplicit::checkpoint_resume() { - bool checkpoint = true; - try { - - int mpi_rank = 0; -#ifdef USE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); -#endif - - if (!analysis_["resume"]["resume"].template get()) - throw std::runtime_error("Resume analysis option is disabled!"); - - // Get unique analysis id - this->uuid_ = analysis_["resume"]["uuid"].template get(); - // Get step - this->step_ = analysis_["resume"]["step"].template get(); - - // Input particle h5 file for resume - std::string attribute = "particles"; - std::string extension = ".h5"; - - auto particles_file = - io_->output_file(attribute, extension, uuid_, step_, this->nsteps_) - .string(); - - // Load particle information from file - const std::string particle_type = (Tdim == 2) ? "P2DXMPM" : "P3DXMPM"; - mesh_->read_particles_hdf5(particles_file, particle_type); - - // Clear all particle ids - mesh_->iterate_over_cells( - std::bind(&mpm::Cell::clear_particle_ids, std::placeholders::_1)); - - // Locate particles - auto unlocatable_particles = mesh_->locate_particles_mesh(); - - if (!unlocatable_particles.empty()) - throw std::runtime_error("Particle outside the mesh domain"); - - // Increament step - ++this->step_; - console_->info("Checkpoint resume at step {} of {}", this->step_, - this->nsteps_); - - } catch (std::exception& exception) { - console_->info("{} {} Resume failed, restarting analysis: {}", __FILE__, - __LINE__, exception.what()); - this->step_ = 0; - checkpoint = false; - } - return checkpoint; -} diff --git a/src/particle.cc b/src/particle.cc index 2a8dfedcd..6081192b9 100644 --- a/src/particle.cc +++ b/src/particle.cc @@ -20,8 +20,8 @@ std::map ParticlePODTypeName = { {"P3DFLUID", "fluid_particles"}, {"P2D2PHASE", "twophase_particles"}, {"P3D2PHASE", "twophase_particles"}, - {"P2DXMPM", "particles"}, - {"P3DXMPM", "particles"}}; + {"P2DXMPM", "xmpm_particles"}, + {"P3DXMPM", "xmpm_particles"}}; } // namespace mpm // Particle2D (2 Dim) diff --git a/src/pod_particle_xmpm.cc b/src/pod_particle_xmpm.cc new file mode 100644 index 000000000..52929b189 --- /dev/null +++ b/src/pod_particle_xmpm.cc @@ -0,0 +1,217 @@ +#include "pod_particle_xmpm.h" +namespace mpm { +namespace pod { +namespace particlexmpm { +const size_t dst_offset[NFIELDS] = { + // Solid phase + HOFFSET(PODParticleXMPM, id), + HOFFSET(PODParticleXMPM, mass), + HOFFSET(PODParticleXMPM, volume), + HOFFSET(PODParticleXMPM, pressure), + HOFFSET(PODParticleXMPM, coord_x), + HOFFSET(PODParticleXMPM, coord_y), + HOFFSET(PODParticleXMPM, coord_z), + HOFFSET(PODParticleXMPM, displacement_x), + HOFFSET(PODParticleXMPM, displacement_y), + HOFFSET(PODParticleXMPM, displacement_z), + HOFFSET(PODParticleXMPM, nsize_x), + HOFFSET(PODParticleXMPM, nsize_y), + HOFFSET(PODParticleXMPM, nsize_z), + HOFFSET(PODParticleXMPM, velocity_x), + HOFFSET(PODParticleXMPM, velocity_y), + HOFFSET(PODParticleXMPM, velocity_z), + HOFFSET(PODParticleXMPM, acceleration_x), + HOFFSET(PODParticleXMPM, acceleration_y), + HOFFSET(PODParticleXMPM, acceleration_z), + HOFFSET(PODParticleXMPM, stress_xx), + HOFFSET(PODParticleXMPM, stress_yy), + HOFFSET(PODParticleXMPM, stress_zz), + HOFFSET(PODParticleXMPM, tau_xy), + HOFFSET(PODParticleXMPM, tau_yz), + HOFFSET(PODParticleXMPM, tau_xz), + HOFFSET(PODParticleXMPM, strain_xx), + HOFFSET(PODParticleXMPM, strain_yy), + HOFFSET(PODParticleXMPM, strain_zz), + HOFFSET(PODParticleXMPM, gamma_xy), + HOFFSET(PODParticleXMPM, gamma_yz), + HOFFSET(PODParticleXMPM, gamma_xz), + HOFFSET(PODParticleXMPM, epsilon_v), + HOFFSET(PODParticleXMPM, status), + HOFFSET(PODParticleXMPM, cell_id), + HOFFSET(PODParticleXMPM, material_id), + HOFFSET(PODParticleXMPM, nstate_vars), + HOFFSET(PODParticleXMPM, svars[0]), + HOFFSET(PODParticleXMPM, svars[1]), + HOFFSET(PODParticleXMPM, svars[2]), + HOFFSET(PODParticleXMPM, svars[3]), + HOFFSET(PODParticleXMPM, svars[4]), + HOFFSET(PODParticleXMPM, svars[5]), + HOFFSET(PODParticleXMPM, svars[6]), + HOFFSET(PODParticleXMPM, svars[7]), + HOFFSET(PODParticleXMPM, svars[8]), + HOFFSET(PODParticleXMPM, svars[9]), + HOFFSET(PODParticleXMPM, svars[10]), + HOFFSET(PODParticleXMPM, svars[11]), + HOFFSET(PODParticleXMPM, svars[12]), + HOFFSET(PODParticleXMPM, svars[13]), + HOFFSET(PODParticleXMPM, svars[14]), + HOFFSET(PODParticleXMPM, svars[15]), + HOFFSET(PODParticleXMPM, svars[16]), + HOFFSET(PODParticleXMPM, svars[17]), + HOFFSET(PODParticleXMPM, svars[18]), + HOFFSET(PODParticleXMPM, svars[19]), + // 56 + // XMPM variables + HOFFSET(PODParticleXMPM, levelset_phi), +}; + +// Get size of particleXMPM +PODParticleXMPM 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.acceleration_x), + sizeof(particle.acceleration_y), + sizeof(particle.acceleration_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]), + // XMPM + sizeof(particle.levelset_phi), + +}; + +// Define particlexmpm 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", + "acceleration_x", + "acceleration_y", + "acceleration_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", + // XMPM + "levelset_phi", +}; + +// 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_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, + // 56 + // XMPM + H5T_NATIVE_DOUBLE}; +} // namespace particlexmpm +} // namespace pod +} // namespace mpm diff --git a/tests/particles/particle_serialize_deserialize_twophase_test.cc b/tests/particles/particle_serialize_deserialize_twophase_test.cc index 6c5504e7a..9b588bcf0 100644 --- a/tests/particles/particle_serialize_deserialize_twophase_test.cc +++ b/tests/particles/particle_serialize_deserialize_twophase_test.cc @@ -7,6 +7,7 @@ #include "particle.h" #include "particle_twophase.h" #include "pod_particle_twophase.h" +#include "pod_particle_xmpm.h" //! \brief Check particle class for serialization and deserialization TEST_CASE("Twophase particle is checked for serialization and deserialization", From 66da94749e69272cf3916b38f2c1e2d40a348a9a Mon Sep 17 00:00:00 2001 From: yliang-sn Date: Mon, 15 Nov 2021 15:01:16 -0800 Subject: [PATCH 89/91] Merge branch 'master' of https://github.com/geomechanics/mpm into solver/xmpm --- CMakeLists.txt | 28 +- include/{ => cells}/cell.h | 0 include/{ => cells}/cell.tcc | 0 include/{ => cells}/cell_implicit.tcc | 0 include/{ => cells}/cell_multiphase.tcc | 0 include/{ => cells}/cell_xmpm.tcc | 0 include/{ => data_structures}/data_types.h | 0 include/{ => data_structures}/factory.h | 0 include/{ => data_structures}/graph.h | 0 include/{ => data_structures}/graph.tcc | 0 include/{ => data_structures}/mutex.h | 0 include/io/logger.h | 4 +- .../assemblers/assembler_base.h | 1 + ...it_linear.h => assembler_eigen_implicit.h} | 16 +- ...inear.tcc => assembler_eigen_implicit.tcc} | 18 +- .../convergence_criterion_base.h | 105 +++++++ .../convergence_criterion_residual.h | 73 +++++ .../convergence_criterion_residual.tcc | 65 +++++ .../convergence_criterion_solution.h | 61 ++++ .../convergence_criterion_solution.tcc | 56 ++++ .../linear_solvers/direct_eigen.h | 4 +- .../linear_solvers/iterative_eigen.h | 4 +- .../linear_solvers/krylov_petsc.h | 3 +- .../linear_solvers/solver_base.h | 2 +- include/{ => mesh}/mesh.h | 0 include/{ => mesh}/mesh.tcc | 0 include/{ => mesh}/mesh_multiphase.tcc | 0 include/{ => mesh}/mesh_xmpm.tcc | 0 include/{ => nodes}/nodal_properties.h | 0 include/{ => nodes}/node.h | 4 + include/{ => nodes}/node.tcc | 0 include/{ => nodes}/node_base.h | 4 + include/{ => nodes}/node_implicit.tcc | 10 +- include/{ => nodes}/node_multiphase.tcc | 0 include/{ => nodes}/node_xmpm.tcc | 0 include/particles/particle.h | 16 ++ include/particles/particle.tcc | 3 + include/particles/particle_base.h | 12 + include/particles/particle_implicit.tcc | 46 ++- .../{mpm_implicit_linear.h => mpm_implicit.h} | 61 +++- ...m_implicit_linear.tcc => mpm_implicit.tcc} | 266 ++++++++++++++---- include/solvers/mpm_scheme/mpm_scheme.h | 9 + .../solvers/mpm_scheme/mpm_scheme_newmark.h | 25 +- .../solvers/mpm_scheme/mpm_scheme_newmark.tcc | 21 +- include/{ => utilities}/affine_transform.h | 0 include/{ => utilities}/geometry.h | 0 include/{ => utilities}/geometry.tcc | 0 include/{ => utilities}/polynomial.h | 0 include/{ => utilities}/polynomial.tcc | 0 references/1985_Davies.pdf | Bin 404738 -> 0 bytes ...three-dimensional Bingham plastic flow.pdf | Bin 1537921 -> 0 bytes references/references.md | 11 - references/transform-real-to-unit-cell.png | Bin 127237 -> 0 bytes src/io/logger.cc | 6 +- src/linear_solver.cc | 16 +- src/mpm.cc | 19 +- .../cell_implicit_test.cc} | 6 +- tests/{ => cells}/cell_test.cc | 0 tests/{ => cells}/cell_vector_test.cc | 0 tests/convergence_criteria_test.cc | 179 ++++++++++++ tests/include/write_mesh_particles.h | 12 +- tests/include/write_mesh_particles_unitcell.h | 6 +- tests/io/write_mesh_particles.cc | 24 +- tests/io/write_mesh_particles_unitcell.cc | 22 +- tests/{ => mesh}/mesh_free_surface_test.cc | 0 tests/{ => mesh}/mesh_neighbours_test.cc | 0 tests/{ => mesh}/mesh_test_2d.cc | 0 tests/{ => mesh}/mesh_test_3d.cc | 0 ...t_linear_test.cc => node_implicit_test.cc} | 9 +- ...near_test.cc => particle_implicit_test.cc} | 98 ++++--- ...it_linear_test.cc => mpm_implicit_test.cc} | 90 +++--- ..._test.cc => mpm_implicit_unitcell_test.cc} | 50 ++-- tests/solvers/mpm_scheme_test.cc | 46 ++- 73 files changed, 1208 insertions(+), 303 deletions(-) rename include/{ => cells}/cell.h (100%) rename include/{ => cells}/cell.tcc (100%) rename include/{ => cells}/cell_implicit.tcc (100%) rename include/{ => cells}/cell_multiphase.tcc (100%) rename include/{ => cells}/cell_xmpm.tcc (100%) rename include/{ => data_structures}/data_types.h (100%) rename include/{ => data_structures}/factory.h (100%) rename include/{ => data_structures}/graph.h (100%) rename include/{ => data_structures}/graph.tcc (100%) rename include/{ => data_structures}/mutex.h (100%) rename include/linear_solvers/assemblers/{assembler_eigen_implicit_linear.h => assembler_eigen_implicit.h} (87%) rename include/linear_solvers/assemblers/{assembler_eigen_implicit_linear.tcc => assembler_eigen_implicit.tcc} (90%) create mode 100644 include/linear_solvers/convergence_criteria/convergence_criterion_base.h create mode 100644 include/linear_solvers/convergence_criteria/convergence_criterion_residual.h create mode 100644 include/linear_solvers/convergence_criteria/convergence_criterion_residual.tcc create mode 100644 include/linear_solvers/convergence_criteria/convergence_criterion_solution.h create mode 100644 include/linear_solvers/convergence_criteria/convergence_criterion_solution.tcc rename include/{ => mesh}/mesh.h (100%) rename include/{ => mesh}/mesh.tcc (100%) rename include/{ => mesh}/mesh_multiphase.tcc (100%) rename include/{ => mesh}/mesh_xmpm.tcc (100%) rename include/{ => nodes}/nodal_properties.h (100%) rename include/{ => nodes}/node.h (99%) rename include/{ => nodes}/node.tcc (100%) rename include/{ => nodes}/node_base.h (99%) rename include/{ => nodes}/node_implicit.tcc (92%) rename include/{ => nodes}/node_multiphase.tcc (100%) rename include/{ => nodes}/node_xmpm.tcc (100%) rename include/solvers/{mpm_implicit_linear.h => mpm_implicit.h} (60%) rename include/solvers/{mpm_implicit_linear.tcc => mpm_implicit.tcc} (55%) rename include/{ => utilities}/affine_transform.h (100%) rename include/{ => utilities}/geometry.h (100%) rename include/{ => utilities}/geometry.tcc (100%) rename include/{ => utilities}/polynomial.h (100%) rename include/{ => utilities}/polynomial.tcc (100%) delete mode 100644 references/1985_Davies.pdf delete mode 100644 references/Beverly and Tanner (1992) - Numerical analysis of three-dimensional Bingham plastic flow.pdf delete mode 100644 references/references.md delete mode 100644 references/transform-real-to-unit-cell.png rename tests/{cell_implicit_linear_test.cc => cells/cell_implicit_test.cc} (99%) rename tests/{ => cells}/cell_test.cc (100%) rename tests/{ => cells}/cell_vector_test.cc (100%) create mode 100644 tests/convergence_criteria_test.cc rename tests/{ => mesh}/mesh_free_surface_test.cc (100%) rename tests/{ => mesh}/mesh_neighbours_test.cc (100%) rename tests/{ => mesh}/mesh_test_2d.cc (100%) rename tests/{ => mesh}/mesh_test_3d.cc (100%) rename tests/nodes/{node_implicit_linear_test.cc => node_implicit_test.cc} (98%) rename tests/particles/{particle_implicit_linear_test.cc => particle_implicit_test.cc} (96%) rename tests/solvers/{mpm_implicit_linear_test.cc => mpm_implicit_test.cc} (62%) rename tests/solvers/{mpm_implicit_linear_unitcell_test.cc => mpm_implicit_unitcell_test.cc} (64%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 46ffc10cf..8d3464a9a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -144,8 +144,10 @@ endif() # Include directories include_directories(BEFORE ${mpm_SOURCE_DIR}/include/ + ${mpm_SOURCE_DIR}/include/cells/ ${mpm_SOURCE_DIR}/include/contacts/ ${mpm_SOURCE_DIR}/include/containers/ + ${mpm_SOURCE_DIR}/include/data_structures/ ${mpm_SOURCE_DIR}/include/elements/ ${mpm_SOURCE_DIR}/include/elements/2d ${mpm_SOURCE_DIR}/include/elements/3d @@ -154,9 +156,12 @@ include_directories(BEFORE ${mpm_SOURCE_DIR}/include/io/ ${mpm_SOURCE_DIR}/include/linear_solvers/ ${mpm_SOURCE_DIR}/include/linear_solvers/assemblers + ${mpm_SOURCE_DIR}/include/linear_solvers/convergence_criteria ${mpm_SOURCE_DIR}/include/linear_solvers/linear_solvers ${mpm_SOURCE_DIR}/include/loads_bcs/ ${mpm_SOURCE_DIR}/include/materials/ + ${mpm_SOURCE_DIR}/include/mesh/ + ${mpm_SOURCE_DIR}/include/nodes/ ${mpm_SOURCE_DIR}/include/particles/ ${mpm_SOURCE_DIR}/include/particles/pod_particles ${mpm_SOURCE_DIR}/include/solvers/ @@ -208,10 +213,11 @@ target_link_libraries(mpm git) if(MPM_BUILD_TESTING) SET(test_src ${mpm_SOURCE_DIR}/tests/test_main.cc - ${mpm_SOURCE_DIR}/tests/cell_implicit_linear_test.cc - ${mpm_SOURCE_DIR}/tests/cell_test.cc - ${mpm_SOURCE_DIR}/tests/cell_vector_test.cc + ${mpm_SOURCE_DIR}/tests/cells/cell_implicit_test.cc + ${mpm_SOURCE_DIR}/tests/cells/cell_test.cc + ${mpm_SOURCE_DIR}/tests/cells/cell_vector_test.cc ${mpm_SOURCE_DIR}/tests/contact_test.cc + ${mpm_SOURCE_DIR}/tests/convergence_criteria_test.cc ${mpm_SOURCE_DIR}/tests/factory_test.cc ${mpm_SOURCE_DIR}/tests/geometry_test.cc ${mpm_SOURCE_DIR}/tests/elements/hexahedron_element_test.cc @@ -240,19 +246,19 @@ 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 + ${mpm_SOURCE_DIR}/tests/mesh/mesh_free_surface_test.cc + ${mpm_SOURCE_DIR}/tests/mesh/mesh_neighbours_test.cc + ${mpm_SOURCE_DIR}/tests/mesh/mesh_test_2d.cc + ${mpm_SOURCE_DIR}/tests/mesh/mesh_test_3d.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_implicit_linear_test.cc + ${mpm_SOURCE_DIR}/tests/nodes/node_implicit_test.cc ${mpm_SOURCE_DIR}/tests/nodes/node_map_test.cc ${mpm_SOURCE_DIR}/tests/nodes/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_implicit_linear_test.cc + ${mpm_SOURCE_DIR}/tests/particles/particle_implicit_test.cc ${mpm_SOURCE_DIR}/tests/particles/particle_test.cc ${mpm_SOURCE_DIR}/tests/particles/particle_twophase_test.cc ${mpm_SOURCE_DIR}/tests/particles/particle_traction_test.cc @@ -278,8 +284,8 @@ if(MPM_BUILD_TESTING) ${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 - ${mpm_SOURCE_DIR}/tests/solvers/mpm_implicit_linear_test.cc - ${mpm_SOURCE_DIR}/tests/solvers/mpm_implicit_linear_unitcell_test.cc + ${mpm_SOURCE_DIR}/tests/solvers/mpm_implicit_test.cc + ${mpm_SOURCE_DIR}/tests/solvers/mpm_implicit_unitcell_test.cc ${mpm_SOURCE_DIR}/tests/solvers/mpm_semi_implicit_navierstokes_test.cc ${mpm_SOURCE_DIR}/tests/solvers/mpm_semi_implicit_navierstokes_unitcell_test.cc ${mpm_SOURCE_DIR}/tests/solvers/mpm_semi_implicit_twophase_test.cc diff --git a/include/cell.h b/include/cells/cell.h similarity index 100% rename from include/cell.h rename to include/cells/cell.h diff --git a/include/cell.tcc b/include/cells/cell.tcc similarity index 100% rename from include/cell.tcc rename to include/cells/cell.tcc diff --git a/include/cell_implicit.tcc b/include/cells/cell_implicit.tcc similarity index 100% rename from include/cell_implicit.tcc rename to include/cells/cell_implicit.tcc diff --git a/include/cell_multiphase.tcc b/include/cells/cell_multiphase.tcc similarity index 100% rename from include/cell_multiphase.tcc rename to include/cells/cell_multiphase.tcc diff --git a/include/cell_xmpm.tcc b/include/cells/cell_xmpm.tcc similarity index 100% rename from include/cell_xmpm.tcc rename to include/cells/cell_xmpm.tcc diff --git a/include/data_types.h b/include/data_structures/data_types.h similarity index 100% rename from include/data_types.h rename to include/data_structures/data_types.h diff --git a/include/factory.h b/include/data_structures/factory.h similarity index 100% rename from include/factory.h rename to include/data_structures/factory.h diff --git a/include/graph.h b/include/data_structures/graph.h similarity index 100% rename from include/graph.h rename to include/data_structures/graph.h diff --git a/include/graph.tcc b/include/data_structures/graph.tcc similarity index 100% rename from include/graph.tcc rename to include/data_structures/graph.tcc diff --git a/include/mutex.h b/include/data_structures/mutex.h similarity index 100% rename from include/mutex.h rename to include/data_structures/mutex.h diff --git a/include/io/logger.h b/include/io/logger.h index 9e0be165c..206b4c3bb 100644 --- a/include/io/logger.h +++ b/include/io/logger.h @@ -47,8 +47,8 @@ struct Logger { // Create a logger for MPM Explicit MUSL static const std::shared_ptr mpm_explicit_musl_logger; - // Create a logger for MPM Implicit Linear - static const std::shared_ptr mpm_implicit_linear_logger; + // Create a logger for MPM Implicit + static const std::shared_ptr mpm_implicit_logger; // Create a logger for MPM Implicit Newmark static const std::shared_ptr mpm_implicit_newmark_logger; diff --git a/include/linear_solvers/assemblers/assembler_base.h b/include/linear_solvers/assemblers/assembler_base.h index 833123916..11abdd8c7 100644 --- a/include/linear_solvers/assemblers/assembler_base.h +++ b/include/linear_solvers/assemblers/assembler_base.h @@ -135,6 +135,7 @@ class AssemblerBase { "Calling the base class function (assign_displacement_increment) in " "AssemblerBase:: illegal operation!"); }; + /**@{*/ //! Navier-Stokes diff --git a/include/linear_solvers/assemblers/assembler_eigen_implicit_linear.h b/include/linear_solvers/assemblers/assembler_eigen_implicit.h similarity index 87% rename from include/linear_solvers/assemblers/assembler_eigen_implicit_linear.h rename to include/linear_solvers/assemblers/assembler_eigen_implicit.h index 2fae56e1c..1eef713ec 100644 --- a/include/linear_solvers/assemblers/assembler_eigen_implicit_linear.h +++ b/include/linear_solvers/assemblers/assembler_eigen_implicit.h @@ -1,5 +1,5 @@ -#ifndef MPM_ASSEMBLER_EIGEN_IMPLICIT_LINEAR_H_ -#define MPM_ASSEMBLER_EIGEN_IMPLICIT_LINEAR_H_ +#ifndef MPM_ASSEMBLER_EIGEN_IMPLICIT_H_ +#define MPM_ASSEMBLER_EIGEN_IMPLICIT_H_ #include #include @@ -12,11 +12,11 @@ namespace mpm { template -class AssemblerEigenImplicitLinear : public AssemblerBase { +class AssemblerEigenImplicit : public AssemblerBase { public: //! Constructor //! \param[in] node_neighbourhood Number of node neighbourhood considered - AssemblerEigenImplicitLinear(unsigned node_neighbourhood); + AssemblerEigenImplicit(unsigned node_neighbourhood); /** * \defgroup Implicit Functions dealing with implicit MPM @@ -62,6 +62,7 @@ class AssemblerEigenImplicitLinear : public AssemblerBase { const Eigen::VectorXd& displacement_increment) override { displacement_increment_ = displacement_increment; } + /**@{*/ protected: @@ -83,9 +84,10 @@ class AssemblerEigenImplicitLinear : public AssemblerBase { Eigen::SparseVector displacement_constraints_; //! Displacement increment Eigen::VectorXd displacement_increment_; + /**@{*/ -}; +}; // namespace mpm } // namespace mpm -#include "assembler_eigen_implicit_linear.tcc" -#endif // MPM_ASSEMBLER_EIGEN_IMPLICIT_LINEAR_H_ +#include "assembler_eigen_implicit.tcc" +#endif // MPM_ASSEMBLER_EIGEN_IMPLICIT_H_ diff --git a/include/linear_solvers/assemblers/assembler_eigen_implicit_linear.tcc b/include/linear_solvers/assemblers/assembler_eigen_implicit.tcc similarity index 90% rename from include/linear_solvers/assemblers/assembler_eigen_implicit_linear.tcc rename to include/linear_solvers/assemblers/assembler_eigen_implicit.tcc index f54090728..aed95f881 100644 --- a/include/linear_solvers/assemblers/assembler_eigen_implicit_linear.tcc +++ b/include/linear_solvers/assemblers/assembler_eigen_implicit.tcc @@ -1,16 +1,16 @@ //! Construct a implicit eigen matrix assembler template -mpm::AssemblerEigenImplicitLinear::AssemblerEigenImplicitLinear( +mpm::AssemblerEigenImplicit::AssemblerEigenImplicit( unsigned node_neighbourhood) : mpm::AssemblerBase(node_neighbourhood) { //! Logger - std::string logger = "AssemblerEigenImplicitLinear::"; + std::string logger = "AssemblerEigenImplicit::"; console_ = std::make_unique(logger, mpm::stdout_sink); } //! Assemble stiffness matrix template -bool mpm::AssemblerEigenImplicitLinear::assemble_stiffness_matrix() { +bool mpm::AssemblerEigenImplicit::assemble_stiffness_matrix() { bool status = true; try { // Initialise stiffness matrix @@ -69,7 +69,7 @@ bool mpm::AssemblerEigenImplicitLinear::assemble_stiffness_matrix() { // Assemble residual force right vector template -bool mpm::AssemblerEigenImplicitLinear::assemble_residual_force_right() { +bool mpm::AssemblerEigenImplicit::assemble_residual_force_right() { bool status = true; try { // Initialise residual force RHS vector @@ -102,7 +102,7 @@ bool mpm::AssemblerEigenImplicitLinear::assemble_residual_force_right() { //! Assign displacement constraints template -bool mpm::AssemblerEigenImplicitLinear::assign_displacement_constraints( +bool mpm::AssemblerEigenImplicit::assign_displacement_constraints( double current_time) { bool status = false; try { @@ -115,13 +115,13 @@ bool mpm::AssemblerEigenImplicitLinear::assign_displacement_constraints( // Iterate over nodes to get displacement constraints for (auto node = nodes.cbegin(); node != nodes.cend(); ++node) { for (unsigned i = 0; i < Tdim; ++i) { - // Assign total pressure constraint + // Assign total displacement constraint const double displacement_constraint = (*node)->displacement_constraint(i, current_time); // Check if there is a displacement constraint if (displacement_constraint != std::numeric_limits::max()) { - // Insert the pressure constraints + // Insert the displacement constraints displacement_constraints_.insert( active_dof_ * i + (*node)->active_id()) = displacement_constraint; } @@ -136,7 +136,7 @@ bool mpm::AssemblerEigenImplicitLinear::assign_displacement_constraints( //! Apply displacement constraints vector template -void mpm::AssemblerEigenImplicitLinear::apply_displacement_constraints() { +void mpm::AssemblerEigenImplicit::apply_displacement_constraints() { try { // Modify residual_force_rhs_vector_ residual_force_rhs_vector_ -= stiffness_matrix_ * displacement_constraints_; @@ -156,4 +156,4 @@ void mpm::AssemblerEigenImplicitLinear::apply_displacement_constraints() { } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); } -} \ No newline at end of file +} diff --git a/include/linear_solvers/convergence_criteria/convergence_criterion_base.h b/include/linear_solvers/convergence_criteria/convergence_criterion_base.h new file mode 100644 index 000000000..8e9f0e625 --- /dev/null +++ b/include/linear_solvers/convergence_criteria/convergence_criterion_base.h @@ -0,0 +1,105 @@ +#ifndef MPM_CONVERGENCE_CRITERION_BASE_H_ +#define MPM_CONVERGENCE_CRITERION_BASE_H_ + +#include "logger.h" +#include +#include +#include +#include +#include + +// MPI +#ifdef USE_MPI +#include "mpi.h" +#endif + +// Eigen +#include "Eigen/Dense" +#include + +namespace mpm { + +// Convergence criterion base class +//! \brief Class which perform check of convergence +//! \details Given a certain tolerance, the class will return boolean to check +//! convergence of an iteration. +class ConvergenceCriterionBase { + public: + //! Constructor with two arguments + ConvergenceCriterionBase(double tolerance, unsigned verbosity) { + tolerance_ = tolerance; + verbosity_ = verbosity; + //! Logger + std::string logger = "ConvergenceCriterionBase::"; + console_ = std::make_unique(logger, mpm::stdout_sink); + } + + //! Constructor with three arguments + ConvergenceCriterionBase(double tolerance, double abs_tolerance, + unsigned verbosity) { + tolerance_ = tolerance; + abs_tolerance_ = abs_tolerance; + verbosity_ = verbosity; + //! Logger + std::string logger = "ConvergenceCriterionBase::"; + console_ = std::make_unique(logger, mpm::stdout_sink); + } + + // Virtual destructor + virtual ~ConvergenceCriterionBase() = default; + + //! Copy constructor + ConvergenceCriterionBase(const ConvergenceCriterionBase&) = default; + + //! Assignment operator + ConvergenceCriterionBase& operator=(const ConvergenceCriterionBase&) = + default; + + //! Move constructor + ConvergenceCriterionBase(ConvergenceCriterionBase&&) = default; + + //! Set verbosity + void set_verbosity(unsigned v) noexcept { verbosity_ = v; } + + //! Set relative iteration tolerance + void set_tolerance(double tol) noexcept { tolerance_ = tol; } + + //! Set absolute iteration tolerance + void set_abs_tolerance(double tol) noexcept { abs_tolerance_ = tol; } + + //! Assign global active dof for parallel vector + void assign_global_active_dof(unsigned global_active_dof) noexcept { + global_active_dof_ = global_active_dof; + }; + + //! Assign rank to global mapper for parallel vector + //! \param[in] rank_global_mapper maps of local to global vector indices + void assign_rank_global_mapper( + const std::vector& rank_global_mapper) noexcept { + rank_global_mapper_ = rank_global_mapper; + }; + + //! Function to check convergence + //! \param[in] vector vector of interest + //! \param[in] save_settings boolean which determine if any saving of + //! variables is necessary + virtual inline bool check_convergence(const Eigen::VectorXd& vector, + bool save_settings = false) = 0; + + protected: + //! Logger + std::shared_ptr console_; + //! Relative tolerance + double tolerance_; + //! Absolute tolerance + double abs_tolerance_; + //! Verbosity + unsigned verbosity_{0}; + //! Global active dof + unsigned global_active_dof_; + //! Rank to Global mapper + std::vector rank_global_mapper_; +}; +} // namespace mpm + +#endif // MPM_CONVERGENCE_CRITERION_BASE_H_ \ No newline at end of file diff --git a/include/linear_solvers/convergence_criteria/convergence_criterion_residual.h b/include/linear_solvers/convergence_criteria/convergence_criterion_residual.h new file mode 100644 index 000000000..e90bf3ba1 --- /dev/null +++ b/include/linear_solvers/convergence_criteria/convergence_criterion_residual.h @@ -0,0 +1,73 @@ +#ifndef MPM_CONVERGENCE_CRITERION_RESIDUAL_H_ +#define MPM_CONVERGENCE_CRITERION_RESIDUAL_H_ + +#include "convergence_criterion_base.h" + +#ifdef USE_PETSC +#include +#endif + +namespace mpm { + +// Convergence criterion of residual class +//! \brief Class which perform check of convergence of nonlinear iteration +//! residuals +class ConvergenceCriterionResidual : public mpm::ConvergenceCriterionBase { + public: + //! Constructor with two arguments + ConvergenceCriterionResidual(double tolerance, unsigned verbosity) + : mpm::ConvergenceCriterionBase(tolerance, verbosity) { + abs_tolerance_ = tolerance; + //! Logger + std::string logger = "ConvergenceCriterionBase::"; + console_ = std::make_unique(logger, mpm::stdout_sink); + } + + //! Constructor with three arguments + ConvergenceCriterionResidual(double tolerance, double abs_tolerance, + unsigned verbosity) + : mpm::ConvergenceCriterionBase(tolerance, abs_tolerance, verbosity) { + //! Logger + std::string logger = "ConvergenceCriterionResidual::"; + console_ = std::make_unique(logger, mpm::stdout_sink); + } + + // Virtual destructor + virtual ~ConvergenceCriterionResidual() = default; + + //! Copy constructor + ConvergenceCriterionResidual(const ConvergenceCriterionResidual&) = default; + + //! Assignment operator + ConvergenceCriterionResidual& operator=(const ConvergenceCriterionResidual&) = + default; + + //! Move constructor + ConvergenceCriterionResidual(ConvergenceCriterionResidual&&) = default; + + //! Function to check convergence + //! \param[in] residual_vector Residual vector of interest + //! \param[in] initial Boolean to indentify 1st (true) iteration + inline bool check_convergence(const Eigen::VectorXd& residual_vector, + bool initial = false) override; + + protected: + //! Logger + std::shared_ptr console_; + //! Relative tolerance + using ConvergenceCriterionBase::tolerance_; + //! Absolute tolerance + using ConvergenceCriterionBase::abs_tolerance_; + //! Verbosity + using ConvergenceCriterionBase::verbosity_; + //! Global active dof + using ConvergenceCriterionBase::global_active_dof_; + //! Rank to Global mapper + using ConvergenceCriterionBase::rank_global_mapper_; + //! Initial residuals + double initial_residual_norm_; +}; +} // namespace mpm + +#include "convergence_criterion_residual.tcc" +#endif // MPM_CONVERGENCE_CRITERION_RESIDUAL_H_ \ No newline at end of file diff --git a/include/linear_solvers/convergence_criteria/convergence_criterion_residual.tcc b/include/linear_solvers/convergence_criteria/convergence_criterion_residual.tcc new file mode 100644 index 000000000..63884c1e3 --- /dev/null +++ b/include/linear_solvers/convergence_criteria/convergence_criterion_residual.tcc @@ -0,0 +1,65 @@ +//! Function to check convergence +inline bool mpm::ConvergenceCriterionResidual::check_convergence( + const Eigen::VectorXd& residual_vector, bool initial) { + bool convergence = false; + try { + // Check 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 + + // Residual norm + double residual_norm; + + // Perform norm computation: using PETSC Vector for parallel case + if (mpi_size > 1) { +#if USE_PETSC + // Initiate PETSC residual vector across the ranks + Vec petsc_res; + VecCreateMPI(MPI_COMM_WORLD, PETSC_DECIDE, this->global_active_dof_, + &petsc_res); + + // Copying local residual vector to petsc vector + VecSetValues(petsc_res, this->rank_global_mapper_.size(), + this->rank_global_mapper_.data(), residual_vector.data(), + ADD_VALUES); + VecAssemblyBegin(petsc_res); + VecAssemblyEnd(petsc_res); + + // Compute PETSC Vector norm in all rank + PetscScalar res_norm; + VecNorm(petsc_res, NORM_2, &res_norm); + residual_norm = res_norm; + + // Destroy vector + VecDestroy(&petsc_res); +#endif + } else { + residual_norm = residual_vector.norm(); + } + + // Save if this is the initial iteration + if (initial) this->initial_residual_norm_ = residual_norm; + + // Convergence check + if (residual_norm < this->abs_tolerance_) convergence = true; + + // Convergence check with relative residual norm + double relative_residual_norm = residual_norm / initial_residual_norm_; + if (relative_residual_norm < this->tolerance_) convergence = true; + + if (mpi_rank == 0 && this->verbosity_ == 2) { + console_->info("Residual norm: {}.", residual_norm); + console_->info("Relative residual norm: {}.", relative_residual_norm); + } + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + } + return convergence; +} \ No newline at end of file diff --git a/include/linear_solvers/convergence_criteria/convergence_criterion_solution.h b/include/linear_solvers/convergence_criteria/convergence_criterion_solution.h new file mode 100644 index 000000000..bab5a51c4 --- /dev/null +++ b/include/linear_solvers/convergence_criteria/convergence_criterion_solution.h @@ -0,0 +1,61 @@ +#ifndef MPM_CONVERGENCE_CRITERION_SOLUTION_H_ +#define MPM_CONVERGENCE_CRITERION_SOLUTION_H_ + +#include "convergence_criterion_base.h" + +#ifdef USE_PETSC +#include +#endif + +namespace mpm { + +// Convergence criteria of solution class +//! \brief Class which perform check of convergence of nonlinear iteration +//! solution +class ConvergenceCriterionSolution : public mpm::ConvergenceCriterionBase { + public: + //! Constructor + ConvergenceCriterionSolution(double tolerance, unsigned verbosity) + : mpm::ConvergenceCriterionBase(tolerance, verbosity) { + //! Logger + std::string logger = "ConvergenceCriterionSolution::"; + console_ = std::make_unique(logger, mpm::stdout_sink); + } + + // Virtual destructor + virtual ~ConvergenceCriterionSolution() = default; + + //! Copy constructor + ConvergenceCriterionSolution(const ConvergenceCriterionSolution&) = default; + + //! Assignment operator + ConvergenceCriterionSolution& operator=(const ConvergenceCriterionSolution&) = + default; + + //! Move constructor + ConvergenceCriterionSolution(ConvergenceCriterionSolution&&) = default; + + //! Function to check convergence + //! \param[in] solution_vector Solution vector of interest + //! \param[in] save_settings Unused boolean settings + inline bool check_convergence(const Eigen::VectorXd& solution_vector, + bool save_settings = false) override; + + protected: + //! Logger + std::shared_ptr console_; + //! Relative tolerance + using ConvergenceCriterionBase::tolerance_; + //! Absolute tolerance + using ConvergenceCriterionBase::abs_tolerance_; + //! Verbosity + using ConvergenceCriterionBase::verbosity_; + //! Global active dof + using ConvergenceCriterionBase::global_active_dof_; + //! Rank to Global mapper + using ConvergenceCriterionBase::rank_global_mapper_; +}; +} // namespace mpm + +#include "convergence_criterion_solution.tcc" +#endif // MPM_CONVERGENCE_CRITERION_SOLUTION_H_ \ No newline at end of file diff --git a/include/linear_solvers/convergence_criteria/convergence_criterion_solution.tcc b/include/linear_solvers/convergence_criteria/convergence_criterion_solution.tcc new file mode 100644 index 000000000..141d7f337 --- /dev/null +++ b/include/linear_solvers/convergence_criteria/convergence_criterion_solution.tcc @@ -0,0 +1,56 @@ +//! Function to check convergence +inline bool mpm::ConvergenceCriterionSolution::check_convergence( + const Eigen::VectorXd& solution_vector, bool save_settings) { + bool convergence = false; + try { + // Check 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 + + // Residual norm + double solution_norm; + + // Perform norm computation: using PETSC Vector for parallel case + if (mpi_size > 1) { +#if USE_PETSC + // Initiate PETSC solution vector across the ranks + Vec petsc_sol; + VecCreateMPI(MPI_COMM_WORLD, PETSC_DECIDE, this->global_active_dof_, + &petsc_sol); + + // Copying local residual vector to petsc vector + VecSetValues(petsc_sol, this->rank_global_mapper_.size(), + this->rank_global_mapper_.data(), solution_vector.data(), + INSERT_VALUES); + VecAssemblyBegin(petsc_sol); + VecAssemblyEnd(petsc_sol); + + // Compute PETSC Vector norm in all rank + PetscScalar sol_norm; + VecNorm(petsc_sol, NORM_2, &sol_norm); + solution_norm = sol_norm; + + // Destroy vector + VecDestroy(&petsc_sol); +#endif + } else { + solution_norm = solution_vector.norm(); + } + + // Convergence check + if (solution_norm < this->tolerance_) convergence = true; + + if (mpi_rank == 0 && this->verbosity_ == 2) + console_->info("Solution norm: {}.", solution_norm); + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + } + return convergence; +} \ No newline at end of file diff --git a/include/linear_solvers/linear_solvers/direct_eigen.h b/include/linear_solvers/linear_solvers/direct_eigen.h index 2a56586e5..725fd6725 100644 --- a/include/linear_solvers/linear_solvers/direct_eigen.h +++ b/include/linear_solvers/linear_solvers/direct_eigen.h @@ -40,8 +40,8 @@ class DirectEigen : public SolverBase { void assign_global_active_dof(unsigned global_active_dof) override {} //! Assign rank to global mapper - void assign_rank_global_mapper(std::vector rank_global_mapper) override { - } + void assign_rank_global_mapper( + const std::vector& rank_global_mapper) override {} protected: //! Solver type diff --git a/include/linear_solvers/linear_solvers/iterative_eigen.h b/include/linear_solvers/linear_solvers/iterative_eigen.h index 4d5fff70e..9a7761ee5 100644 --- a/include/linear_solvers/linear_solvers/iterative_eigen.h +++ b/include/linear_solvers/linear_solvers/iterative_eigen.h @@ -42,8 +42,8 @@ class IterativeEigen : public SolverBase { void assign_global_active_dof(unsigned global_active_dof) override {} //! Assign rank to global mapper - void assign_rank_global_mapper(std::vector rank_global_mapper) override { - } + void assign_rank_global_mapper( + const std::vector& rank_global_mapper) override {} protected: //! Solver type diff --git a/include/linear_solvers/linear_solvers/krylov_petsc.h b/include/linear_solvers/linear_solvers/krylov_petsc.h index 7e08a2dc4..66b99da4f 100644 --- a/include/linear_solvers/linear_solvers/krylov_petsc.h +++ b/include/linear_solvers/linear_solvers/krylov_petsc.h @@ -52,7 +52,8 @@ class KrylovPETSC : public SolverBase { }; //! Assign rank to global mapper - void assign_rank_global_mapper(std::vector rank_global_mapper) override { + void assign_rank_global_mapper( + const std::vector& rank_global_mapper) override { rank_global_mapper_ = rank_global_mapper; }; diff --git a/include/linear_solvers/linear_solvers/solver_base.h b/include/linear_solvers/linear_solvers/solver_base.h index f40a13d7a..6f35e5ee9 100644 --- a/include/linear_solvers/linear_solvers/solver_base.h +++ b/include/linear_solvers/linear_solvers/solver_base.h @@ -32,7 +32,7 @@ class SolverBase { //! Assign rank to global mapper virtual void assign_rank_global_mapper( - std::vector rank_global_mapper) = 0; + const std::vector& rank_global_mapper) = 0; //! Set sub solver type void set_sub_solver_type(const std::string& type) noexcept { diff --git a/include/mesh.h b/include/mesh/mesh.h similarity index 100% rename from include/mesh.h rename to include/mesh/mesh.h diff --git a/include/mesh.tcc b/include/mesh/mesh.tcc similarity index 100% rename from include/mesh.tcc rename to include/mesh/mesh.tcc diff --git a/include/mesh_multiphase.tcc b/include/mesh/mesh_multiphase.tcc similarity index 100% rename from include/mesh_multiphase.tcc rename to include/mesh/mesh_multiphase.tcc diff --git a/include/mesh_xmpm.tcc b/include/mesh/mesh_xmpm.tcc similarity index 100% rename from include/mesh_xmpm.tcc rename to include/mesh/mesh_xmpm.tcc diff --git a/include/nodal_properties.h b/include/nodes/nodal_properties.h similarity index 100% rename from include/nodal_properties.h rename to include/nodes/nodal_properties.h diff --git a/include/node.h b/include/nodes/node.h similarity index 99% rename from include/node.h rename to include/nodes/node.h index 25d0b8520..c348b21b6 100644 --- a/include/node.h +++ b/include/nodes/node.h @@ -387,6 +387,10 @@ class Node : public NodeBase { //! \ingroup Impolicit void initialise_implicit() noexcept override; + //! Initialise nodal forces + //! \ingroup Impolicit + void initialise_force() noexcept override; + //! Update inertia at the nodes //! \ingroup Implicit //! \param[in] update A boolean to update (true) or assign (false) diff --git a/include/node.tcc b/include/nodes/node.tcc similarity index 100% rename from include/node.tcc rename to include/nodes/node.tcc diff --git a/include/node_base.h b/include/nodes/node_base.h similarity index 99% rename from include/node_base.h rename to include/nodes/node_base.h index d311b9bc0..47fd30b6f 100644 --- a/include/node_base.h +++ b/include/nodes/node_base.h @@ -382,6 +382,10 @@ class NodeBase { //! \ingroup Implicit virtual void initialise_implicit() noexcept = 0; + //! Initialise nodal forces + //! \ingroup Impolicit + virtual void initialise_force() noexcept = 0; + //! Update nodal inertia //! \ingroup Implicit //! \param[in] update A boolean to update (true) or assign (false) diff --git a/include/node_implicit.tcc b/include/nodes/node_implicit.tcc similarity index 92% rename from include/node_implicit.tcc rename to include/nodes/node_implicit.tcc index ce929fa16..79bd8e649 100644 --- a/include/node_implicit.tcc +++ b/include/nodes/node_implicit.tcc @@ -1,4 +1,4 @@ -//! Initialise two-phase nodal properties +//! Initialise implicit nodal properties template void mpm::Node::initialise_implicit() noexcept { this->initialise(); @@ -7,6 +7,14 @@ void mpm::Node::initialise_implicit() noexcept { displacement_.setZero(); } +//! Initialise nodal force during Newton-Raphson iteration +template +void mpm::Node::initialise_force() noexcept { + // nodal forces + external_force_.setZero(); + internal_force_.setZero(); +} + //! Assign nodal inertia template void mpm::Node::update_inertia( diff --git a/include/node_multiphase.tcc b/include/nodes/node_multiphase.tcc similarity index 100% rename from include/node_multiphase.tcc rename to include/nodes/node_multiphase.tcc diff --git a/include/node_xmpm.tcc b/include/nodes/node_xmpm.tcc similarity index 100% rename from include/node_xmpm.tcc rename to include/nodes/node_xmpm.tcc diff --git a/include/particles/particle.h b/include/particles/particle.h index 6a6743897..acba4dada 100644 --- a/include/particles/particle.h +++ b/include/particles/particle.h @@ -185,6 +185,7 @@ class Particle : public ParticleBase { //! \param[in] stress Initial sress void initial_stress(const Eigen::Matrix& stress) override { this->stress_ = stress; + this->previous_stress_ = stress; } //! Compute stress @@ -403,12 +404,25 @@ class Particle : public ParticleBase { //! \ingroup Implicit void compute_strain_newmark() noexcept override; + //! Compute stress using implicit updating scheme + //! \ingroup Implicit + void compute_stress_newmark() noexcept override; + + //! Return stress at the previous time step of the particle + //! \ingroup Implicit + Eigen::Matrix previous_stress() const override { + return previous_stress_; + } + //! Compute updated position of the particle by Newmark scheme //! \ingroup Implicit //! \param[in] dt Analysis time step //! \param[in] velocity_update Update particle velocity from nodal vel void compute_updated_position_newmark(double dt) noexcept override; + //! Update stress and strain after convergence of Newton-Raphson iteration + //! \ingroup Implicit + void update_stress_strain() noexcept override; /**@}*/ protected: @@ -527,6 +541,8 @@ class Particle : public ParticleBase { /**@{*/ //! Acceleration Eigen::Matrix acceleration_; + //! Stresses at the last time step + Eigen::Matrix previous_stress_; /**@}*/ }; // Particle class diff --git a/include/particles/particle.tcc b/include/particles/particle.tcc index 6e3171ccd..8ecceea28 100644 --- a/include/particles/particle.tcc +++ b/include/particles/particle.tcc @@ -86,6 +86,7 @@ bool mpm::Particle::initialise_particle(PODParticle& particle) { this->stress_[3] = particle.tau_xy; this->stress_[4] = particle.tau_yz; this->stress_[5] = particle.tau_xz; + this->previous_stress_ = stress_; // Strain this->strain_[0] = particle.strain_xx; @@ -261,6 +262,7 @@ void mpm::Particle::initialise() { size_.setZero(); strain_rate_.setZero(); strain_.setZero(); + previous_stress_.setZero(); stress_.setZero(); traction_.setZero(); velocity_.setZero(); @@ -1195,6 +1197,7 @@ void mpm::Particle::deserialize( // Stress MPI_Unpack(data_ptr, data.size(), &position, stress_.data(), 6, MPI_DOUBLE, MPI_COMM_WORLD); + this->previous_stress_ = stress_; // Strain MPI_Unpack(data_ptr, data.size(), &position, strain_.data(), 6, MPI_DOUBLE, MPI_COMM_WORLD); diff --git a/include/particles/particle_base.h b/include/particles/particle_base.h index a761146a4..d2510e18d 100644 --- a/include/particles/particle_base.h +++ b/include/particles/particle_base.h @@ -472,12 +472,24 @@ class ParticleBase { //! \ingroup Implicit virtual void compute_strain_newmark() = 0; + //! Compute stress using implicit updating scheme + //! \ingroup Implicit + virtual void compute_stress_newmark() = 0; + + //! Return previous stress + virtual Eigen::Matrix previous_stress() const = 0; + //! Compute updated position by Newmark scheme //! \ingroup Implicit //! \param[in] dt Analysis time step virtual void compute_updated_position_newmark(double dt) = 0; + //! Update stress and strain after convergence of Newton-Raphson iteration + //! \ingroup Implicit + virtual void update_stress_strain() = 0; + //! Assign acceleration to the particle (used for test) + //! \ingroup Implicit //! \param[in] acceleration A vector of particle acceleration //! \retval status Assignment status virtual bool assign_acceleration(const VectorDim& acceleration) = 0; diff --git a/include/particles/particle_implicit.tcc b/include/particles/particle_implicit.tcc index 1270d9ea9..de8555072 100644 --- a/include/particles/particle_implicit.tcc +++ b/include/particles/particle_implicit.tcc @@ -238,19 +238,20 @@ inline Eigen::Matrix mpm::Particle<3>::compute_strain_increment( template void mpm::Particle::compute_strain_newmark() noexcept { // Compute strain increment from previous time step - dstrain_ = this->compute_strain_increment(dn_dx_, mpm::ParticlePhase::Solid); - // Update strain += dstrain - strain_ += dstrain_; - - // Compute at centroid - // Strain rate for reduced integration - const Eigen::Matrix strain_increment_centroid = - this->compute_strain_increment(dn_dx_centroid_, - mpm::ParticlePhase::Solid); - - // Assign volumetric strain at centroid - dvolumetric_strain_ = dstrain_.head(Tdim).sum(); - volumetric_strain_centroid_ += dvolumetric_strain_; + this->dstrain_ = + this->compute_strain_increment(dn_dx_, mpm::ParticlePhase::Solid); +} + +// Compute stress using implicit updating scheme +template +void mpm::Particle::compute_stress_newmark() noexcept { + // Check if material ptr is valid + assert(this->material() != nullptr); + // Calculate stress + this->stress_ = + (this->material()) + ->compute_stress(previous_stress_, dstrain_, this, + &state_variables_[mpm::ParticlePhase::Solid]); } // Compute updated position of the particle by Newmark scheme @@ -282,6 +283,25 @@ void mpm::Particle::compute_updated_position_newmark(double dt) noexcept { this->displacement_ += nodal_displacement; } +// Update stress and strain after convergence of Newton-Raphson iteration +template +void mpm::Particle::update_stress_strain() noexcept { + // Update initial stress of the time step + this->previous_stress_ = this->stress_; + + // Update total strain + this->strain_ += this->dstrain_; + + // Volumetric strain increment + this->dvolumetric_strain_ = this->dstrain_.head(Tdim).sum(); + + // Update volumetric strain at particle position (not at centroid) + this->volumetric_strain_centroid_ += this->dvolumetric_strain_; + + // Reset strain increment + this->dstrain_.setZero(); +} + // Assign acceleration to the particle template bool mpm::Particle::assign_acceleration( diff --git a/include/solvers/mpm_implicit_linear.h b/include/solvers/mpm_implicit.h similarity index 60% rename from include/solvers/mpm_implicit_linear.h rename to include/solvers/mpm_implicit.h index 60e684351..1057bc640 100644 --- a/include/solvers/mpm_implicit_linear.h +++ b/include/solvers/mpm_implicit.h @@ -1,5 +1,5 @@ -#ifndef MPM_MPM_IMPLICIT_LINEAR_H_ -#define MPM_MPM_IMPLICIT_LINEAR_H_ +#ifndef MPM_MPM_IMPLICIT_H_ +#define MPM_MPM_IMPLICIT_H_ #ifdef USE_GRAPH_PARTITIONING #include "graph.h" @@ -8,19 +8,22 @@ #include "mpm_base.h" #include "assembler_base.h" +#include "convergence_criterion_base.h" +#include "convergence_criterion_residual.h" +#include "convergence_criterion_solution.h" #include "solver_base.h" namespace mpm { -//! MPMImplicitLinear class -//! \brief A class that implements the fully implicit linear one phase mpm -//! \details A single-phase implicit linear MPM +//! MPMImplicit class +//! \brief A class that implements the fully implicit one phase mpm +//! \details A single-phase implicit MPM //! \tparam Tdim Dimension template -class MPMImplicitLinear : public MPMBase { +class MPMImplicit : public MPMBase { public: //! Default constructor - MPMImplicitLinear(const std::shared_ptr& io); + MPMImplicit(const std::shared_ptr& io); //! Solve bool solve() override; @@ -39,9 +42,29 @@ class MPMImplicitLinear : public MPMBase { //! \ingroup Implicit bool reinitialise_matrix(); - //! Compute equilibrium equation + //! Reinitialise equilibrium equation //! \ingroup Implicit - bool compute_equilibrium_equation(); + void reinitialise_system_equation(); + + //! Assemble equilibrium equation + //! \ingroup Implicit + bool assemble_system_equation(); + + //! Solve equilibrium equation + //! \ingroup Implicit + bool solve_system_equation(); + + //! Initialisation of Newton-Raphson iteration + //! \ingroup Implicit + void initialise_newton_raphson_iteration(); + + //! Check convergence of Newton-Raphson iteration + //! \ingroup Implicit + bool check_newton_raphson_convergence(); + + //! Finalisation of Newton-Raphson iteration + //! \ingroup Implicit + void finalise_newton_raphson_iteration(); /**@}*/ //! Class private variables @@ -101,21 +124,35 @@ class MPMImplicitLinear : public MPMBase { * \defgroup ImplicitVariables Variables dealing with implicit MPM */ /**@{*/ + //! Phase + const unsigned phase_{mpm::ParticlePhase::SinglePhase}; + //! Boolean of nonlinear analysis + bool nonlinear_{true}; //! Parameter beta of Newmark scheme double newmark_beta_{0.25}; //! Parameter gamma of Newmark scheme double newmark_gamma_{0.5}; + //! Current number of Newton-Raphson iteration + unsigned current_iteration_; + //! Max number of Newton-Raphson iteration + unsigned max_iteration_{20}; + //! Verbosity for Newton-Raphson iteration + unsigned verbosity_{0}; //! Assembler object std::shared_ptr> assembler_; //! Linear solver object tsl::robin_map>>> linear_solver_; + //! Newton-Raphson displacement increment convergence + std::shared_ptr disp_criterion_{nullptr}; + //! Newton-Raphson residual convergence + std::shared_ptr residual_criterion_{nullptr}; /**@}*/ -}; // MPMImplicitLinear class +}; // MPMImplicit class } // namespace mpm -#include "mpm_implicit_linear.tcc" +#include "mpm_implicit.tcc" -#endif // MPM_MPM_IMPLICIT_LINEAR_H_ +#endif // MPM_MPM_IMPLICIT_H_ diff --git a/include/solvers/mpm_implicit_linear.tcc b/include/solvers/mpm_implicit.tcc similarity index 55% rename from include/solvers/mpm_implicit_linear.tcc rename to include/solvers/mpm_implicit.tcc index 9e54b47f4..309b2384a 100644 --- a/include/solvers/mpm_implicit_linear.tcc +++ b/include/solvers/mpm_implicit.tcc @@ -1,9 +1,9 @@ //! Constructor template -mpm::MPMImplicitLinear::MPMImplicitLinear(const std::shared_ptr& io) +mpm::MPMImplicit::MPMImplicit(const std::shared_ptr& io) : mpm::MPMBase(io) { //! Logger - console_ = spdlog::get("MPMImplicitLinear"); + console_ = spdlog::get("MPMImplicit"); // Check if stress update is not newmark if (stress_update_ != "newmark") { @@ -15,19 +15,62 @@ mpm::MPMImplicitLinear::MPMImplicitLinear(const std::shared_ptr& io) } // Initialise scheme + double displacement_tolerance = 1.0e-10; + double residual_tolerance = 1.0e-10; + double relative_residual_tolerance = 1.0e-6; if (stress_update_ == "newmark") { mpm_scheme_ = std::make_shared>(mesh_, dt_); - // Read parameters of Newmark scheme - if (analysis_.contains("newmark") && analysis_["newmark"].contains("beta")) - newmark_beta_ = analysis_["newmark"].at("beta").template get(); - if (analysis_.contains("newmark") && analysis_["newmark"].contains("gamma")) - newmark_gamma_ = analysis_["newmark"].at("gamma").template get(); + // Read boolean of nonlinear analysis + if (analysis_.contains("scheme_settings")) { + if (analysis_["scheme_settings"].contains("nonlinear")) + nonlinear_ = + analysis_["scheme_settings"].at("nonlinear").template get(); + // Read parameters of Newmark scheme + if (analysis_["scheme_settings"].contains("beta")) + newmark_beta_ = + analysis_["scheme_settings"].at("beta").template get(); + if (analysis_["scheme_settings"].contains("gamma")) + newmark_gamma_ = + analysis_["scheme_settings"].at("gamma").template get(); + // Read parameters of Newton-Raphson interation + if (nonlinear_) { + if (analysis_["scheme_settings"].contains("max_iteration")) + max_iteration_ = analysis_["scheme_settings"] + .at("max_iteration") + .template get(); + if (analysis_["scheme_settings"].contains("displacement_tolerance")) + displacement_tolerance = analysis_["scheme_settings"] + .at("displacement_tolerance") + .template get(); + if (analysis_["scheme_settings"].contains("residual_tolerance")) + residual_tolerance = analysis_["scheme_settings"] + .at("residual_tolerance") + .template get(); + if (analysis_["scheme_settings"].contains( + "relative_residual_tolerance")) + relative_residual_tolerance = analysis_["scheme_settings"] + .at("relative_residual_tolerance") + .template get(); + if (analysis_["scheme_settings"].contains("verbosity")) + verbosity_ = analysis_["scheme_settings"] + .at("verbosity") + .template get(); + } + } + + // Initialise convergence criteria + if (nonlinear_) { + residual_criterion_ = std::make_shared( + relative_residual_tolerance, residual_tolerance, verbosity_); + disp_criterion_ = std::make_shared( + displacement_tolerance, verbosity_); + } } } -//! MPM Implicit Linear solver +//! MPM Implicit solver template -bool mpm::MPMImplicitLinear::solve() { +bool mpm::MPMImplicit::solve() { bool status = true; console_->info("MPM analysis type {}", io_->analysis_type()); @@ -43,9 +86,6 @@ bool mpm::MPMImplicitLinear::solve() { MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); #endif - // Phase - const unsigned phase = mpm::ParticlePhase::SinglePhase; - // Test if checkpoint resume is needed bool resume = false; if (analysis_.find("resume") != analysis_.end()) @@ -131,17 +171,12 @@ bool mpm::MPMImplicitLinear::solve() { mpm_scheme_->initialise(); // Mass momentum inertia and compute velocity and acceleration at nodes - mpm_scheme_->compute_nodal_kinematics(phase); + mpm_scheme_->compute_nodal_kinematics(phase_); - // Predict nodal velocity and acceleration -- Predictor step of Newmark - // scheme - mpm_scheme_->update_nodal_kinematics_newmark(phase, newmark_beta_, + // Predict nodal kinematics -- Predictor step of Newmark scheme + mpm_scheme_->update_nodal_kinematics_newmark(phase_, newmark_beta_, newmark_gamma_); - // Compute local residual force - mpm_scheme_->compute_forces(gravity_, phase, step_, - set_node_concentrated_force_); - // Reinitialise system matrix to construct equillibrium equation bool matrix_reinitialization_status = this->reinitialise_matrix(); if (!matrix_reinitialization_status) { @@ -149,27 +184,43 @@ bool mpm::MPMImplicitLinear::solve() { throw std::runtime_error("Reinitialisation of matrix failed"); } - // Compute equilibrium equation - this->compute_equilibrium_equation(); + // Newton-Raphson iteration + current_iteration_ = 0; - // Assign displacement increment to nodes - mesh_->iterate_over_nodes_predicate( - std::bind(&mpm::NodeBase::update_displacement_increment, - std::placeholders::_1, assembler_->displacement_increment(), - phase, assembler_->active_dof()), - std::bind(&mpm::NodeBase::status, std::placeholders::_1)); + // Assemble equilibrium equation + this->assemble_system_equation(); - // Update nodal velocity and acceleration -- Corrector step of Newmark - // scheme - mpm_scheme_->update_nodal_kinematics_newmark(phase, newmark_beta_, - newmark_gamma_); + // Check convergence of residual + bool convergence = false; + if (nonlinear_) + convergence = residual_criterion_->check_convergence( + assembler_->residual_force_rhs_vector(), true); + + // Iterations + while (!convergence && current_iteration_ <= max_iteration_) { + // Initialisation of Newton-Raphson iteration + this->initialise_newton_raphson_iteration(); + + // Solve equilibrium equation + this->solve_system_equation(); - // Update stress and strain - mpm_scheme_->postcompute_stress_strain(phase, pressure_smoothing_); + // Update nodal kinematics -- Corrector step of Newmark scheme + mpm_scheme_->update_nodal_kinematics_newmark(phase_, newmark_beta_, + newmark_gamma_); - // Particle kinematics - mpm_scheme_->compute_particle_kinematics(velocity_update_, phase, "Cundall", - damping_factor_); + // Update stress and strain + mpm_scheme_->postcompute_stress_strain(phase_, pressure_smoothing_); + + // Check convergence of Newton-Raphson iteration + if (nonlinear_) { + convergence = this->check_newton_raphson_convergence(); + } else { + convergence = true; + } + + // Finalisation of Newton-Raphson iteration + if (convergence) this->finalise_newton_raphson_iteration(); + } // Locate particles mpm_scheme_->locate_particles(this->locate_particles_); @@ -195,7 +246,7 @@ bool mpm::MPMImplicitLinear::solve() { } } auto solver_end = std::chrono::steady_clock::now(); - console_->info("Rank {}, Implicit Linear {} solver duration: {} ms", mpi_rank, + console_->info("Rank {}, Implicit {} solver duration: {} ms", mpi_rank, mpm_scheme_->scheme(), std::chrono::duration_cast( solver_end - solver_begin) @@ -206,7 +257,7 @@ bool mpm::MPMImplicitLinear::solve() { // Initialise matrix template -bool mpm::MPMImplicitLinear::initialise_matrix() { +bool mpm::MPMImplicit::initialise_matrix() { bool status = true; try { // Get matrix assembler type @@ -286,8 +337,7 @@ bool mpm::MPMImplicitLinear::initialise_matrix() { // Reinitialise and resize matrices at the beginning of every time step template -bool mpm::MPMImplicitLinear::reinitialise_matrix() { - +bool mpm::MPMImplicit::reinitialise_matrix() { bool status = true; try { // Assigning matrix id (in each MPI rank) @@ -317,9 +367,23 @@ bool mpm::MPMImplicitLinear::reinitialise_matrix() { return status; } -// Compute equilibrium equation +// Reinitialise equilibrium equation +template +void mpm::MPMImplicit::reinitialise_system_equation() { + // Initialise element matrix + mesh_->iterate_over_cells( + std::bind(&mpm::Cell::initialise_element_stiffness_matrix, + std::placeholders::_1)); + + // Initialise nodal forces + mesh_->iterate_over_nodes_predicate( + std::bind(&mpm::NodeBase::initialise_force, std::placeholders::_1), + std::bind(&mpm::NodeBase::status, std::placeholders::_1)); +} + +// Assemble equilibrium equation template -bool mpm::MPMImplicitLinear::compute_equilibrium_equation() { +bool mpm::MPMImplicit::assemble_system_equation() { bool status = true; try { // Compute local cell stiffness matrices @@ -333,39 +397,125 @@ bool mpm::MPMImplicitLinear::compute_equilibrium_equation() { // Assemble global stiffness matrix assembler_->assemble_stiffness_matrix(); + // Compute local residual force + mpm_scheme_->compute_forces(gravity_, phase_, step_, + set_node_concentrated_force_); + // Assemble global residual force RHS vector assembler_->assemble_residual_force_right(); // Apply displacement constraints assembler_->apply_displacement_constraints(); + // Assign rank global mapper to solver and convergence criteria (only + // necessary at the initial iteration) + if (current_iteration_ == 0) { #ifdef USE_MPI - // Assign global active dof to solver - linear_solver_["displacement"]->assign_global_active_dof( - Tdim * assembler_->global_active_dof()); - - // Prepare rank global mapper - std::vector matrix_rgm; - for (unsigned dir = 0; dir < Tdim; ++dir) { - auto dir_rgm = assembler_->rank_global_mapper(); - std::for_each(dir_rgm.begin(), dir_rgm.end(), - [size = assembler_->global_active_dof(), - dir = dir](int& rgm) { rgm += dir * size; }); - matrix_rgm.insert(matrix_rgm.end(), dir_rgm.begin(), dir_rgm.end()); - } - // Assign rank global mapper to solver - linear_solver_["displacement"]->assign_rank_global_mapper(matrix_rgm); + // Assign global active dof to solver + linear_solver_["displacement"]->assign_global_active_dof( + Tdim * assembler_->global_active_dof()); + + // Prepare rank global mapper + std::vector system_rgm; + for (unsigned dir = 0; dir < Tdim; ++dir) { + auto dir_rgm = assembler_->rank_global_mapper(); + std::for_each(dir_rgm.begin(), dir_rgm.end(), + [size = assembler_->global_active_dof(), + dir = dir](int& rgm) { rgm += dir * size; }); + system_rgm.insert(system_rgm.end(), dir_rgm.begin(), dir_rgm.end()); + } + // Assign rank global mapper to solver + linear_solver_["displacement"]->assign_rank_global_mapper(system_rgm); + + if (nonlinear_) { + disp_criterion_->assign_global_active_dof( + Tdim * assembler_->global_active_dof()); + residual_criterion_->assign_global_active_dof( + Tdim * assembler_->global_active_dof()); + disp_criterion_->assign_rank_global_mapper(system_rgm); + residual_criterion_->assign_rank_global_mapper(system_rgm); + } #endif + } + + } catch (std::exception& exception) { + console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); + status = false; + } + return status; +} +// Solve equilibrium equation +template +bool mpm::MPMImplicit::solve_system_equation() { + bool status = true; + try { // Solve matrix equation and assign solution to assembler assembler_->assign_displacement_increment( linear_solver_["displacement"]->solve( assembler_->stiffness_matrix(), assembler_->residual_force_rhs_vector())); + // Assign displacement increment to nodes + mesh_->iterate_over_nodes_predicate( + std::bind(&mpm::NodeBase::update_displacement_increment, + std::placeholders::_1, assembler_->displacement_increment(), + phase_, assembler_->active_dof()), + std::bind(&mpm::NodeBase::status, std::placeholders::_1)); + } catch (std::exception& exception) { console_->error("{} #{}: {}\n", __FILE__, __LINE__, exception.what()); status = false; } return status; +} + +// Initialisation of Newton-Raphson iteration +template +void mpm::MPMImplicit::initialise_newton_raphson_iteration() { + // Initialise MPI rank + int mpi_rank = 0; +#ifdef USE_MPI + // Get MPI rank + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); +#endif + + // Advance iteration + current_iteration_++; + if (mpi_rank == 0 && verbosity_ > 0 && nonlinear_) + console_->info("Newton-Raphson iteration: {} of {}.", current_iteration_, + max_iteration_); +} + +// Check convergnece of Newton-Raphson iteration +template +bool mpm::MPMImplicit::check_newton_raphson_convergence() { + bool convergence; + // Check convergence of solution (displacement increment) + convergence = + disp_criterion_->check_convergence(assembler_->displacement_increment()); + + if (!convergence) { + // Reinitialise equilibrium equation + this->reinitialise_system_equation(); + + // Assemble equilibrium equation + this->assemble_system_equation(); + + // Check convergence of residual + convergence = residual_criterion_->check_convergence( + assembler_->residual_force_rhs_vector()); + } + return convergence; +} + +// finalisation of Newton-Raphson iteration +template +void mpm::MPMImplicit::finalise_newton_raphson_iteration() { + // Particle kinematics and volume + mpm_scheme_->compute_particle_kinematics(velocity_update_, phase_, "Cundall", + damping_factor_); + + // Particle stress, strain and volume + mpm_scheme_->update_particle_stress_strain_volume(); } \ No newline at end of file diff --git a/include/solvers/mpm_scheme/mpm_scheme.h b/include/solvers/mpm_scheme/mpm_scheme.h index 512e8763c..343a5511c 100644 --- a/include/solvers/mpm_scheme/mpm_scheme.h +++ b/include/solvers/mpm_scheme/mpm_scheme.h @@ -99,6 +99,15 @@ class MPMScheme { "Calling the base class function (update_nodal_kinematics_newmark) in " "MPMScheme:: illegal operation!"); }; + + // Update particle stress, strain and volume + //! \ingroup Implicit + virtual inline void update_particle_stress_strain_volume() { + throw std::runtime_error( + "Calling the base class function " + "(update_particle_stress_strain_volume) in " + "MPMScheme:: illegal operation!"); + } /**@}*/ protected: diff --git a/include/solvers/mpm_scheme/mpm_scheme_newmark.h b/include/solvers/mpm_scheme/mpm_scheme_newmark.h index 0f9230fdc..ef2610f91 100644 --- a/include/solvers/mpm_scheme/mpm_scheme_newmark.h +++ b/include/solvers/mpm_scheme/mpm_scheme_newmark.h @@ -25,13 +25,6 @@ class MPMSchemeNewmark : public MPMScheme { //! \param[in] phase Phase to smooth pressure virtual inline void compute_nodal_kinematics(unsigned phase) override; - //! Update nodal kinematics by Newmark scheme - //! \param[in] newmark_beta Parameter beta of Newmark scheme - //! \param[in] newmark_gamma Parameter gamma of Newmark scheme - //! \param[in] phase Phase to smooth pressure - virtual inline void update_nodal_kinematics_newmark( - unsigned phase, double newmark_beta, double newmark_gamma) override; - //! Compute stress and strain //! \param[in] phase Phase to smooth pressure //! \param[in] pressure_smoothing Enable or disable pressure smoothing @@ -75,6 +68,24 @@ class MPMSchemeNewmark : public MPMScheme { //! \retval scheme Stress update scheme virtual inline std::string scheme() const override; + /** + * \defgroup Implicit Functions dealing with implicit MPM + */ + /**@{*/ + //! Update nodal kinematics by Newmark scheme + //! \ingroup Implicit + //! \param[in] newmark_beta Parameter beta of Newmark scheme + //! \param[in] newmark_gamma Parameter gamma of Newmark scheme + //! \param[in] phase Phase to smooth pressure + inline void update_nodal_kinematics_newmark(unsigned phase, + double newmark_beta, + double newmark_gamma) override; + + // Update particle stress, strain and volume + //! \ingroup Implicit + inline void update_particle_stress_strain_volume() override; + /**@}*/ + protected: //! Mesh object using mpm::MPMScheme::mesh_; diff --git a/include/solvers/mpm_scheme/mpm_scheme_newmark.tcc b/include/solvers/mpm_scheme/mpm_scheme_newmark.tcc index e1e63f074..80819e5b7 100644 --- a/include/solvers/mpm_scheme/mpm_scheme_newmark.tcc +++ b/include/solvers/mpm_scheme/mpm_scheme_newmark.tcc @@ -87,16 +87,12 @@ inline void mpm::MPMSchemeNewmark::compute_stress_strain( mesh_->iterate_over_particles(std::bind( &mpm::ParticleBase::compute_strain_newmark, std::placeholders::_1)); - // Iterate over each particle to update particle volume - mesh_->iterate_over_particles(std::bind( - &mpm::ParticleBase::update_volume, std::placeholders::_1)); - // Pressure smoothing if (pressure_smoothing) this->pressure_smoothing(phase); // Iterate over each particle to compute stress mesh_->iterate_over_particles(std::bind( - &mpm::ParticleBase::compute_stress, std::placeholders::_1)); + &mpm::ParticleBase::compute_stress_newmark, std::placeholders::_1)); } //! Precompute stresses and strains @@ -151,7 +147,7 @@ inline void mpm::MPMSchemeNewmark::compute_forces( } // Wait for tasks to finish } -// Compute particle kinematics +// Update particle kinematics template inline void mpm::MPMSchemeNewmark::compute_particle_kinematics( bool velocity_update, unsigned phase, const std::string& damping_type, @@ -163,6 +159,19 @@ inline void mpm::MPMSchemeNewmark::compute_particle_kinematics( std::placeholders::_1, dt_)); } +// Update particle stress, strain and volume +template +inline void + mpm::MPMSchemeNewmark::update_particle_stress_strain_volume() { + // Iterate over each particle to update particle stress and strain + mesh_->iterate_over_particles(std::bind( + &mpm::ParticleBase::update_stress_strain, std::placeholders::_1)); + + // Iterate over each particle to update particle volume + mesh_->iterate_over_particles(std::bind( + &mpm::ParticleBase::update_volume, std::placeholders::_1)); +} + //! Postcompute nodal kinematics - map mass and momentum to nodes template inline void mpm::MPMSchemeNewmark::postcompute_nodal_kinematics( diff --git a/include/affine_transform.h b/include/utilities/affine_transform.h similarity index 100% rename from include/affine_transform.h rename to include/utilities/affine_transform.h diff --git a/include/geometry.h b/include/utilities/geometry.h similarity index 100% rename from include/geometry.h rename to include/utilities/geometry.h diff --git a/include/geometry.tcc b/include/utilities/geometry.tcc similarity index 100% rename from include/geometry.tcc rename to include/utilities/geometry.tcc diff --git a/include/polynomial.h b/include/utilities/polynomial.h similarity index 100% rename from include/polynomial.h rename to include/utilities/polynomial.h diff --git a/include/polynomial.tcc b/include/utilities/polynomial.tcc similarity index 100% rename from include/polynomial.tcc rename to include/utilities/polynomial.tcc diff --git a/references/1985_Davies.pdf b/references/1985_Davies.pdf deleted file mode 100644 index bcffda7065949a8651e04154b884cc97c6d216cc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 404738 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

;O8{X4f}hWotBDH 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 VEH;Ek7p1GMr^}^e;Tv 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΅|=h=_NUByv) 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

kObP7cMuzEsrQfoE5oScc? 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%0Dwe@Ye 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 z�wTdQc7ib$0mW1?3cdWG9|;6*ZDq=T!RUpp>rtMwyLr{i40tz7L{DJF8c^X74&V z^kr3D@VU|sfbm{cwQG?W(RUq~M;$sU-qD!b>N=_7tXW!cDoD;7AKV5NLzPd!H|}r` zZiYYpN(GL#oWOq@*q!C~7Zpq(TEBNw4Wk3PsGv`HZ2=H>Ajm@uVm@Jk!qXAKFZd!; zXu9FvgKipONn?sh(3di02Z4db7#gMlQ^Lk!3+bjo-T;dSRB*>H3_vTvi7TxBWnKuk zI0LO}ZDa3~7vu?$C$dpvaU})# zN29cK(Clh~UErNv0f!=DqWl65p^S{c9z6p5_1iCKl$N#uyUYy~j#+7fPiV2P&u(ae zh9*03%x-A2yRi=h>;?v#u!#v6+uh0cK!9H~N>leo1)6hIgx~G}aDB}8!M^o! z2=EWan@7ZPQrK_ul@&W@`0C9l4hrkHmMFDR`MMVDA83Q_N{oZ+3L^M7+ z0E__c85D{8f~#PDe2RUYfN=i^-vfy6vao*xw~5dQ4g>dw`EhUTCb&EF_nTw4!0n;G z-yORJ?hkN`v+tGN(gCgCqzVqx1+CwnX>gbxX#FvYK4|?hiUCSX>yJ@DS)rEJAH#t0 zwY2^i2T*lsY5g$}xSp2QA0q+$AT8~mh5{04|1=a3>Bnra#Rc+cfk*qB^nh#~%-kPM zAl3hP3_vUl=<}`n|9E`t3$Py_P(w}K?~-bQ>0)=()cro7rrvjCzc(6A2(-yap0aFSgabCC-I$$8fPv%Hoduo6~Jm2BgF8TY? zYyV1~-%k9PpOQqrP3oWI`EjiNxAN#po+Q7=|B$Cdb1m{MA}Q%FB+_G>1op)-KY1X& zsn`FO=vz;=6$%cG4v0c&{LO6r?Gw_HIZ39pNY=tMFa>y$MV#(m)n4iSRuB9?#QE(j z!8V+~DbKf_|6ZIR1JWtqa_vyKcd%}TCFkFX^Sdtp{B-_Gm-YUcF8|%r3DT7?C&7M* zL;72Beplz8)aToG{!f$jpQ&?@mNY*(t0 zZ|otculx&n*lW(8o#8zV-aq`fTK@55DuxKMb@Ln*KLaX7Ia4 z|18g6S?F&){{wk+Bu=Jj?*2YyzVH4{g#cOWpH=AF_T^8{=RZ?vUrp(gWcu$abo=j~ z&+jVzla2nijrx;3|CvfhYKz0uephM5zqio_zbp0660tXaf0F1wQ|cgnaRIB}pOE6; z+Gs8G?>ha*vif~z`M)Ik-t*toh~iSxQR^@u&s=APEqYo=j7e zUz2pz5_alcnFS>YFH4a*HLH0<%0yS(TrtomG;xa`lHY3GNK&`3v|&1z@LGHKF7=Ej z+e?J5eh}A`G=F^hHj1btR&4*_&XHq8bpsK8k}#u`1(2TG9)H4y7Defn@4l+QyCqRn z_*_b$`AGT$yxsNJ%Nsqf8u&_ z{Ik%#)Wj;y;o*r-{W_OvnKhG--|wVqM`=zi9x^8$x%&*bh#bmyA8cbp=t(%_y_FRS zvyz;z)L+i%h?LN}8Nytnm(t46%E+>LbNa6R@;1p^f}Jj`Et@Vc$TU3fI0!fLqdYUn z6ioV{)kKLZOqHLusG?uTrfi(q8dB~3=~PR+A*?T6QyuzGw^rf{ zo5;_$w!OHkv8hz|S;acDX9fa(60bP9E+fZv5q>_;j9$PuKNi>jQo+|petJWzeiv1w zx;-Q1DnpAq`oIH8&9xOG%ok6K!ew+iTk(6ks(W{CgzxgQ%&dJi+OkRc%>CQXpM{Oy zQ)b|E4?NsDmhSs;FZ#kRi5Cv`ZS@}N!yqo=XGYiU{h zCM}(ft!~BVbbP!qj4H#9$ocM6-5k!n-raho{%-}a0bRaZ#5{s!yF@Ou4!%?`m*0y} zyinf@>kYUdW+f06z0Emx>QIIOx@5n|JA>^399ZE*WM*ygp)Ul3sGCM20)C}N2AOe& zr8Q(*D_hYIceLa5OTHdO?0z4wp7hpVNcr694_V{m(!*PsIQI&U+Rd67Gm&Ff!PvsX z+whef3XRmenSFRfUu+`%KCk1e@>U6sh~(|<^;PiiXh|JL^*nrpfAskkxp~@-wCxNHe6wT7qspMePmrVUqm*1{Tx(QK9}%utUOIfPxeAt5oGq;Vx!VV= z8$ucj)lvvVcprVJHZ8wb|H^gWeVTV*p$==+Val!?$l#dD&Z2pTQ;14 z%`V9vV#L1;o-t8rFXKqHL1#g zk-R@e*-{GILX-1$5j#${;(5G2Fev%<7d=C^Y)HbT1vqv6n>Mi9n)!~>~pXHGhtLj(Rv7>>z4ff}$y88!d(cxi9 z2B=a=-eDQ~na6#5+Ba{0XL0QQX}*uQFYIl*c=^jUZV?h7vTQe%)1pxB81Hh-6Cfdm z4IeO7Q0O50rKJ&tYMZxoanP-9S)Woy@v_{*Djx4Ol>oTQWd zZKgMLMG0d+q>2-(1FjWI@QhvF7_iw@X{>nsL8gQ1)~fk)Zh1Ri1!PI-UfQuXyqJF@ zvpfN|FQDV;6?(LE+b^l|u?~}kd$v4uTFu~ETa6}1zM15>v7D3C?pFDk>RHI~;AFG?7L03OyL9fKIB@?;G8bda7)_VX*(b&Kkrpr+p2P1YH*+b zt&+Q$<&PaKA;12$RW)e~_3r%R5wd>G_$ZI_*N(1uj9r*T*KR+&^NaOS#OMKm^X~?? zNg(#BhY>FKoPc?e%Xj&`{(^}VSinEMmgp~e>-xm)M-sWM_cE4Za1Q6_-joA(0?N^9 zyz)ZBN>;lf@+}QxF84Wh^h&qX+mUVZwy0H|_fsQrt5 zxo>=<=E6$A^VvuFyKAENWCZNvGpXKSA!MqdIakQs_?12PoOf=RG3tvD%D-mYzh!%B_S$fdy(oJ-`y`f zSe4@H?Ru);cK2h+14~hYYVQ_1*6+j}GLpXH9Dj4$Lx}fIercJDlhw6T!W2p2k~g_W z?KBHj9mjGb6J0pa&3BV-S3PW@bi*F(bQrp%_BOWraO_N}9lcpXTcN7wifiKw=~MFw z?Usz?s99~{K%F}AduwheX>G2!?Y%YmV!xm9RU>s_p|_GR#*)u|eiUGul79k@*_PDL zb;&ilPCw)-N{_6Ezq>UO(>(XCCOD9KLNdJkjgnM_k58ocn7Ff1M0WP{`u*)U%7V`` z3M$c-CdG4P%kibrHfcMnFkC-Iz@Nhw9UowuD)$wbl(S~`TZ zYcK&a#WVS)eIv(~5qSuiD{5|*tqu-Vy3ds4S>wA;zvb$VywS8v!_Z^uk)@>zXWjy& z>yK@m@HHvN2wxeNer*`_V*dx++w6ZPUDM^v9H=bU{nM)cIIE;AsjAz(2 z(w6giVVmW}EyQsjxf^fJ;16)!wXU_{vHy^zY8rilOX1!2tLeRVul16`1$N53d?~jU zCUy#7;7*)g->%DuL|Q1uDV&@es|@6VonG_2_8omj0v0Adt?O?c!|{q@OG~kQJzxBg^1zPd}Gd0WY1xKa+b`~;w82@LYP|kp2u*_mhL9=Ejz3h*OO12 zkaC(ZT+g>Ue0AximC4I0C;qC*Qk$#r9pvQlXQ8u3SAtdx!avxe$7D}3D%HyOjPBD* z8qTnaI_Bds^AHKw>Q>2m{AH`z*{JZN$DNHrf-W6*KY2oav%OX7vl{ev|4ZA~9n%y$ zxnmvf%=om^bpHA#inF8Ys}jM7>2(yb&AZX%>Q?)+-aev^>VGzs@xjX6dXc$XOF1Qs zga5wIt6r`t%!^-stF%KJ#FFYAGHeKPkNHG0necKIa6 z<++veZTpJb!-HsnwrQ!9o3e{O&y8#b)u+E{-@pvuAJy#wGd# z(T}3G?o^3${&T0%Ea!u}wtKmx`t!C6eEzi8W|K9ygY0w6%bh%BJ9pg@KRc(}dCg7u z#^?7+c6V~mUr}=Bc#KGS9m{{a?F3cjtd3JV&T=%$O$TmoZYM*`(&Jpqarw&zpUw@p z6EEtxYwTJx(pBZU^El^}{_zLS!5WWMKRr^u6R|PS$!$~l%APpYjschbmMvB2OIG&@ zrJ=_nY=&L-?U+7s_r-~XFNVf19xmT_VKS?Zf7%N#e_$Ld>UmOm%h(iIz7OLCKk?7|<8vX$|v9f)zg-BOtU*npsfdaXs zNRwV?%dQ6p`CS4Rs^!+T*@TP2g4Sj4IGe{s!3KqSDFuBBb}jcJ-?q}d>+T%H*n0DF zfa{x*X5Nyxju-UXNCW$++CrguClOQQr;cyp zfBH0_!ou)QS`3NNIA?U{vZ6j>0TYqbm=kW~Gi=eqfcuR3QqKkLtaUYCK3TV}Z9LC? z^Tnq@GS6MVZ0z>4Q;6nEs@(q`t|T_wHfN1hPk(y4YVoCj?(;QA)ZZfR420i+HMq%WKaV?((F%tP2l+|*zOZSSz&J+qgn!BeU>D8px?p@n^O!Sgm6x}~wa zyq4u979Wy=cGdQVrG`vahGLvg9dsFzJZX^H7q(c+1wUpsP9qQ>To8PIT;lmo$2Ih? zCthVnp6z)vb1qJY8^NJBLeVCgiE|e|ix(8>N2H3p*rZg*M|IO`f}=(b`@9w8cs*w} zcy^7M;gRi94hM-I>+B9Eg`Z;0eyFAO3v0N3Jn8U}^e*h=d6?Fz9Y^o#+oB#K#%b{n zPN3+25jWC8|K@em1i=Tk7nSWO`5tKg&1LdEPXAlTTw`~PZ}hjw{kQl&O2ZK!2EzF4 z`1J1)E(;4=7Z)ph+>f9nLc=ZCpB=Z<*95SBHUYu=gFxsVgupe-gQE{Q2Siy!ghfV# zv*Z7oD2*Q<@&v!5L988w+Cw9vc1PmL04}wI3 zu1A& z5oVadv6bEZt_{Ixy1OsZS4_gJ+1K>93$gzl6)+nx`OJ;lGbsmN+tNC{YgM3L^>gCj_Yw9`kwo@LTvx$pJQ~ukE@2aj zDk6!is77w*d-!{i4c$YlHDq*W|mlm;}mft z@!dz|dLu2?Apau9t_2c4zI(Ry0Vu=odh{)?4-2L|O_h@61g(OOjy3|Grngk!%OvNjQ^z>hEW zU1k4M@(fHX(v$09C%cR0v1H`2S2BJl?8KuJo7YR^1JHc$ext0v!U!Eu1|8iD!n5&RX$AY^biQ*#ijx+~IqfZw(kv z$x=d!fvQ#am*HO1zEQty)185u+;Z}cQu@fkIja{p)U6lG!)C=%2FMFuyd=FDb;D!vxU@~@!cE}Bw| z4>VzYWQ3eXB}J6xgl-6O#Efcjb>^=fu9Yo7D|99*R`xgGKo#D6U zKuNVHJ4;5FO4CYd0FGjQ8N!u8%YZPFnOMPYe0v8f1I5ZYfa~CU^LsCr3C)`ZNFqx` zt(Tp8<^VPYc!BJeA;4b`v6~D~m&R@qsO-P?fbwMU!frB_arNw8%geZl8KwqQO4~V2 zo1df2HPPl#ac%%}e42)v7)zW0WC$AH{$+voJb1yP&P)-gP-)Y*(Y{@f%J}PKP%V)8 z_hWLke_lj>&iwg@llxB)p#M9Q`y({?Z#E+oF7le$HeGHqK4~+|4YC8z?Z*_b33s}f z@(=@%kxle~*VoCzeR4RvWj0*a9Ib2-N9_W6$UXhvRDtO>0p9qZbI)#q5_NX&@i$#y zzc|EamGun9Gui(UCdLwwt)k3`2?#)4LJTl-%Uv4r>`A0j_cXHK@K|O>TxTXuKyy&q zvf$hy!R{2nK_Aw&wB2~f20=tySWc+zV{#m&D92fAZj+$ zNf;l1Txk_h^uUUpAH@hRIJX>M$(s9W%8YPqx&*m?r7^=WrZ?3HbzoLKS(OmvolT%F zj`=ZTRt`_}ltDvdrVzntd1#(VT`o$TyB6aaU%@Pc<|l?kdWz220h}l5v1C=_`7dZ? ze(ISuxeJyXv^Y;k9(#%x`d|gh$46yf80`AYO_G_m*vwb_=BnzUW;NrdkxI#4=bh2b zG6Aibl9o}5&%;${%DhS^>fbY16sS zum@pzcW*trBe3TpPf2dnp{+cadtAw_yZuIaeE^S5QV9HpvVojr+lQ!{O;7K^>-2xg zZr#A;)aqk@$4psJpYuU2zZ|HG%O2q_H|yv8IyN&id*9;;*kMu31zUJ2y2OUliUMbK z20Xp)I?#JtL_57qx{fZ;;t7;bOAZMUj9hP?D@4}TI+iKKtX!zPfv>50a*P1ZQ|zBs znd6@&VTBjioI?uDK$ytWuxYcinzK%*$Wdve*(d!?94(uhZ9=f{EAkh4hRHSo{q|bi z$!4Q&^0!*0l7-?DoC(*7KG%`Kfc%p8DWwaP-(TTHFT|b<+Yvlsdno)wfkN^YF$|Z4~*i&4s#Y`CV{h>XpO`v4hgnVl|w<=m(mUIx^4> zsLGk^Zt2t0JyVTg&XITy9+QEFlHl?4L-*D_w_QEvvMcO~P<&;JK6Kxu@HhvX}Qa`FUeTz8Xx`ImQ6e4!F1fvtDb9_k{C0%5-TB1@{enL@ecq$q85o z(k0X5r1Rk&@~3*Yh8iUK46ANM1j2k|W_{jz{mP3ksRhzDSRWH~|-?>Q?yqOAk`Xb5!IGVcj$j*Btb%}`J=G}B6k@O0V#)KJU z@&evIdsG)J-{;!Lj`bGCJbG2^qAE_bgGlIclANi094V!5o6t)=Bn=u>=7N;JatXGJ zm~yR{?ut&iyPr}W)_JAFp?zE3+|`zN-Bk}gV@_!sBfzwZM@U5bhHeb2*0K7vGf!)UH| z{{4Cl`?K6f3n5<9U zOlWB$@AAU72sw*it02ZZ2)ZI$06mEq0wsxFv{l8Ev}PWN$r^%M3Sjvxtjt#N1i)7^ zOp+Uc3{E#=teFQr9C}!^akUlE!35xHB7g%v62_0BurmobwM?qf*}C+Y$Xxg-^4<}LIFM|_+(G5 zPQyZvCy(rkY>U&j0@rh8!H199)}DztP(_cgcMzDVNx}(;h<% z2H?wpq{+~CgJy6gS;DrHN9rhYx_>&qlgjJvH0VL7%5QNT7*oT(Q#c23zyQ9>&>bE? z4_>wop2?jegRYI@l=6?x+pums-6li;BT?bHDHWUAU~vdQMTUv0|-gLziMI660hmx zyNb!@3p^8C9Ofbw+Kx&Isoi{KzSkx>S2w=&a_=h+bg&FLceojC{(p#j)3Bz_we7!^ z5E4ir$UI4K0348rj7|`+A|l|71tA2fg3J~KL0BaTfog?RT19X`Wl#`;mcgPBNgS}P zEe0VN3L(OFivbdq5KLIP-<$6D89qGkar~eDKWscImaMF-gybI1>%7k2QXj&vAvaeM z#_>ZAbTS=lVOmC5D|Ik7EnZ^XJ6OG}b@#!lVrw=JwwOY^-0q-&sypWRqUvRw6$NJ! z)@(EP1>K|vNN6ubX_%q>G@?$t#7ekPbA$5D6snl|nMIkvTfwPZgwP;o! z29#D6NbhqtEt3}28kb7b4mt1I2Qza#x^=oo3r2q*UvJCKa=3+YbC}Jp4ExDGkDHa> zO?A_s{vxBB>K}Kh1ed_iWj_{))8=xr^4s;>>TlI0fHA1@5_iAyLvKP6%Zy)4#` z-f1crs8OfAclu|Ye`cJ^YDcd_>;@34Aw_w*SMq{%+_Dr!_M^wFwT8CgiaiJLoQoIY zwvfgy#5I#oZd}1SxYW3!X9XwyIpz@gB>aR&a-w=XOZ-Rt-%!u&f7T&W0Pxn?zjqVN z_Hi`9*VR^C+wS%8w+FB-GA+v=)cZEr5Kk8~$Jiqih5tKi-+z5)5!q%+v0NcJaYOW*Drx&ANMJzmSU z0rRU=f3FA2&TU)ee2v1?KU*8{myru$MEA9 zCoW?~%6gO6d{NtS*(Mod6Ew^~x{I`$Rv7ZEo<9{Ypjd0n=7uv|=MGPt@N|B1QjH+P z8I?QpTDnXUuOV_N%dQ{P1xp0nu(10mf}+KcqN0@vh4oXQLpG~ElQL1Kb!~c51UcF0 zi(=(Oua-BUM4d9Oh=U{BH7IYSLl^G!M4y@udskDT~tj25SXWxwKv(QxLi40xIXwUODjswX$MQc zIMF$72aX&6=AATFG{c)@*(v6hZuw{^c>)`7$DM(k#zXS$;l%guDqI*RwzKT=W#S3> zynB~WKBNhX{<9oSR*459+axtbYIsB|DD4T9_mt+EvE?@m?O(Uzvwkm(q-pt+l!~cS z;ijFu*|JH?;M8PpGk1Gv#Wx1npI*0m0=8xGhp#_c%> zWya6|vgLOHc$QV#R>GQs(P8o6o-M|B`qTHu33FAw^z9Q#E?0X)zPujYPwq=xpy3FD z*cC^`Ey;lgNwgIzgRieuxi6y#1N&A`R0zCq|pRzK`# zUfxR1w&_fqD=z*-_-1h2O(#VM=QbKzbk=3L2jqOON3)A-*ymEt1*1>}<#C>2Q@dH~ zS{T|+*SNGuY#hJ3Qmnpx=!;>8;A0j68FM9NrVg7O6x(y2!aLh^1&|k;kYQiG?kF2h zFcg^P*5p^**S&WSu?&=p3j#~1l>%E*|l~HsRBZ#_ioe6zf{;8Nyu zmM>}D_`%I(toS33v4Izf7cO8-aE_$uc!w)Sah*C#OMdnut15Bnd``G+u@B+sxEt0- z-+Q0WMo3V^>Q~j9xf_q+mMpY#Q$i^FskO#cUY^@Nc3-*-qsy|X=LEl1et+o9c$kCZ z){C}FGfq7(z*4$lzrT?cRN37}= zcKWeCY&cA04m8>J(qfX-T;WB5dC8qBf~k_~b--$d*$eT<0e?)vaqrI!G)i88=W6OE zrJ?eM;n@ddF<#N_{xX8vlFItps4qBtqF;ET2%QBidktaG*?X-zx%*P;rOjSAuL-?j zmqZUJJeZyBUkHac_2raigwm^WL$RCR?_Ty--F%u zcjmBIjITK0Lxxu9J^j_3AO1UbVW>^K*++@gkU4^x3*m@e-1 zT%ZM<by@P=JlXBT$er{T!d^1ut`int;``?P&7bqapJ zdzcM+c25@jYPZ_C8hyekctHS6vg`q|Q_73w@iY>NCMr)w>!D1c)jaJh5&}d`cMlgq z+-!Lkd;$)7>M89Y-BBcGU(ldjZ5K}~hN+QU`BeTyK5y&V6X40?{H!rv=PdsKFP{#X zq4SiEs1s8)36Zm4I9mL|Ham1`W#zGcr}P7T*sB>2_LBNzZPU50cITQUq)KcukxR%_ zYbqPJI;=XDzS$|nvx3S}lqa0IALMTH)}45qgJ=YP%C

5}qauOPd&g`e^ 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

4v8d&HDQ+jwkbk z!uT^WY`)0$RGL9(7$Vh?@*-Cu)2-Qv$5n=d^o6G!VQ>ki%i}BOBJjY&98Vv?aD3JL zK-Xl*&a|875jOAnfa>R8H8Q%3%}19sX_P9n-_AV48FxbI%Q4B=CoY)-8xCGWqMHLe zKXLgjVdhsJ5c0(=6l75b0r$hTVsz?__l=(!w0~7!U`@a8(cgtm67UR>yYD4p5sWnA z=SKC@47QDSp5`!E`=<@8smr(Lp; ztZ&bz3jwgQAD&+ujI33}nmRQ;Ci5$aNUCgzc~wde7}C|hg~b3_aZ@-S5O}`t;RwrsXx&qb>b(LWx*RtI>yo$%k>0bTRr_R`u6;{(}$q zomCMO2;x52dFJ4*FKsEjXRpF#jF|dE%=pa)3dKsWo<-W?3KLwdW}XlkbHrre`@N9Y^{cW(*WuoRp9U$xQ+ z3WcAJNX!%W9jF>-JTc$!+IY%K|6$inAu6ZP%J;81t2@3%9<;uH@UW4IOyH-sL$6Dp z?drP0IALDGXS-j^y;Is&pw6m-YSu1Q;Zmc?Mv!`T?BKW4vh*yrxxH-JEix)5W*GDO zWHrOj_FeL@-6I|5GgdOLd;(o{O6r<+o&F}dO>z~8GQ>*WVgg1u(3~2lPsQ;bvAic7 zZaDV!ZsE;6PjA_HeJma;@7k0%a`%bCrse~my15hNLj`l*0GrS^8fE5ka6?VC++-8g*=SkaS6Qw!Hu3M^@ z;ztI}$P3Spxu^pFmA-2NU+*>Qn7o*iOFksnq>b9;(0wDilV5duZeM%WDN{T2{wDmj z()$+A5e0W6OqZ<$zUwP-dK_gp-Eh32;hX5eo10w)W*$WDdv(l{!-?00KBs2H8#od- zrfG6y(9C>S%Z?`dY};g?EbnA~QTbM+#*Gfa*AAC-bItXGeQrGZbZqktr!hWf)1Ye@ zp}Bl2<7BSVhm=hw^16pHkM|qNH~7q+-ryd#RRXdRbNsHyUeaNFa_WhUlFBeS6W`I z^ly3ko@b*giGs)6I$}(OtTd=|cC!9UXW5_5qYhVA>fL2J@||`xKObOkT2rH@ZB%mJCT{9E&xP`| z?>-N{)16#0CqBXyzU$P=k!x9d=Dy1ehrtTjZ;e*23sbXLOTswz6`#coV|2-;&6t&Z_TAjmmyzA7+ti6TKfSjm zBDHKf_w38tvbQw9da~T-1;J}CAZ1dq-^We9R<75OaFh{xTvvZ+#YhUFp=nuoI_+ie zj+bGlgSQ>EdCgVvBUFr}tN$fHzmFsH?Y#?(Ga^PZ$y~}eubBBA$p-4yGkb17-|jNz z6khOj)HrlC1bItqyx3w`5fi+-{L@h%$prT>w7x@F;fSf2jn!Ru!E4{+h27)XHeyV| zFv&(uAL-OB2QC_3w=v&+g!DXu8#Yw^J>}7U4%lTUDQAxA*VxL{U20Oh4qYdNrV_d@ zRaVqQYf4}891TFIqqMMtgj zt_OtBait4;2ra2Py5%rLS1z?Xt^c!psDy9f$QR`5P~cadQu{uuY`md)NBOhI7cU&V zzhNq>>g1Ipg=V+z=o%~6Th*O)t5lveH}XusX}j#M@d9>f*P+~fhylE7wqX2%WOR}15q z?5LuA{rl0w(8ZE{?oUY0JK1yI3SYmpoY_Ww+A!rJx*_wiU5r-o<#)^VH}~(2zpnmm zVDGo(i$aq8(?!kw5y^3brzL1@nmldQU5n-EeS(^ex+RTq@7q@_0wq2Ko|t*Ce1t0D zIIzXubqC}8L%l(c__CYUcVA$h_KD%O4Rf|3`t5Ga1hwmY6v-Qxi*d6#aNOh7-Nta9 zJ)v6TpLnh#(ES=i?B#X1h}ys>b;~fjoo{)#_I^mTE57+ixvD-qj`Uc)G&ka+n01v;i#| z%g$k#c;Pr^3&NO9I2knvkdNZ8Obh{icPA+=DjQCbIECGUynAMo4EF)S zEeIHyzu901*Uk1*bM_6HRVw0J+*Gv{n%%i2tR^~-h4b=o-bNT3O16!;A1>NIE-QHE z+NHzS4mr`eO>0vW^DTE_VskXMb6j*7>z-`$-Lt*C@1ttEe%G7B`E8y-$Ln4^q?U5; ze#<3%DZxh+;q1RA%R6wW=BQGNKn`nuTcRuD#=zXGV<}a~oDZ2*x&)Qp`82M^UngjG z^})NReaIsQFAs?$a#LgT`7T!oN$?tfyPwnQ{_J3J;+f1hjs*=LwN%VX*{<*~#$Hj$ zii{x6bep;oNLISj&`=2Qd`z@8{Zoog*j^P9w&x4iNj`Z z?UyjIv~N?5lLo7Zdh;$X#CF)Y^l~b82!+p4C37-A@RGyh7h#FrRV!vMGJQqplGhtr z;5%E@baUgy!ymC=m`+2*9X;aIGg$ z3t+tX-)}il6&S`+jW?{6ZMAyUyu)%&fxTz%3k~=1xV9$we$^JXnlA0WE4xWWoRWdl z6l4Dr+LliaA?~I%-```T(=pz9>=3oQO;grp(#d7S$nNolj3-s_7b^PK1^UITRVr?u zP*mm>^x!~o>uSd}z1W9+Gn)HEVx&90Zl{5=_#*MBclP_x!IGreB$@%rG5M`?9Z$e9 z+oXYnQweV@%R0s_t+$-qdDzUYaWpny)?7zsA?{Lw`l-){k0a_Ft*2kzZOI|Wi$~NCIL*d-i%=h#Xm{utj1`LZXD4>4JZX|M z7R88&y$~CCo-gh$8$~lbQ28LkKckH?!Evapv1Llz`(lPet9rfRW+e{s(wV zuzhM(JLZS>Jy``Re)o=ZrCUF%CS4ypc>xX2vVkT36Ff%a_q{fizuIs8M2h{sf%1Q8 zzoq&oipS8{04wM17jVem+0}jh+&O})yGelad4OB{9iH;@D}cSO-#!Sy ze?Gs#{4CIlpgQpJARphezg-*vzSc2czeAj4*S#oy{Q-!@Fv$#zKAq15^SXI~?13Ii z${Dt+{*qEs289AJY6%1YxPW@efC!P#)>xtoWzV3(F4}MxQ>m876G;jzPa-&xr~;k1 zOUG=~>M`eNOxauaq3-P}r)EP_2yPIPf^yMby?mC~1&lNbbMQ>Dmei2#mg za&9NkG*pQC)e|u{`Mx8X5+6S2b#66*C+_tBc;TaTLvDLRT$4-yCs}Qmo9YUQ7l$E@ zU!!zOCP?N_U_OlU8Ho9NN$Qf#=<8Gjl$+v60R`LOBw_>1M99Fq^sL;d0Wic-6G3-d z892j)VdichffN=F(9+fwO!gXZk~SZBLj!aI@*J6KspTji<~*Ycl*ZI0h}CB3`@Mi|}1dnM`c zEiKK=bh9R1Dc_LMxzRh~ImKAB&WKLyvKsZOq=lr&gxk9j-+y2=2x`S@Tjh>IX0$m# z=>9f$+wc7#Hp+^UGdk6T4KDO8#%kt=i?Wg!7Tv^d7EpUy9nRqD8qQz3Ek}X4C~FgK9afQ5xQaQGiH8#I(}vQEQ%fQ6e(jeV~(#TFo|n?w3tiKS_uAxG7AWAq{BKGP=R9% zC^$LdMi!^_LeRC1dlz593PJ#Rfdo;YIma&iG8772Oy*9mw>5o{YpYt~dO%U@vtF0; z2yLxSkp-v(quWnH!0QcKIDc;Y8oEs^Gy0h)iA3iSfb;Nc&d!0LS50ab^h~DqCgIh--CWkOM7r zNgQ$jo+>jIb5K8{tQYvv68p@$7)xEjWk6LPO+3rP<@A$%4r_#pB8LI|fu-Fu%uz~}7~_36LV4J$oQ@BjBHru| zT6)`a$pvUFddu2;_U->lF1G7KLzh;HWo?)xC5;qbo7o&%AuY^Vz0##7*I~~mYR@I+ zZup+~??&iZ8J14$p1v5AkJ_^{;tn}v!rq*2m$jow{Vr+@pB=7VK8kx`X~@!*7_Um7 zU~!=-LO#;rS8K-!+ZE?Wes$tWMQRbF`&E>5`~ zc5xw;hYq_Kq5QE09CHyBVg<_esBlrpT+Om1*qb9*Yao!-z&<))M))qnF++vKH0SMY>k9gH#YaoH|TC4k*KAsAR;R)V*n$ec*<#{ zbJd|5PxkbM<^abYdRg`svq90DwY;L~(s>el+4k9-a+AP7YhcB5fo~S>Q{q2>tL~RP z3Ctr}QK9G%kL{CW8TAT7r?skmYhT2N<`2H7+`XF}zmv&aU1s1fl|i(+Mdm65EHdBH z>Sm^EXNW-ZZf5!stk)Ka(tm>TsyvbUNrKEjA$9DbrNt+Eb8V#JtQu*pmfPjLcZ%YKSQ=m_Y zn!FX2+dB#af>bcn^U(E1|G>*E0k=T83AJNDN1xB|k&^V-4&Z79SKZtQijg_kf&3zs zngz?OrqBr_N}~Y+y?7ZnwQ2Khn_ar8yL9V;zad?>PWt)k^r)H-5Xt8;*)<(+DM`%y z0eYX!_ef5KD5rarPA6*C!Bj8l&;*Cs3;hvQm>?+D-qu(@cQA|cUxurSK*o- z=oK@=KL0uLXBm`V*Nh305?zNLpoScWYetG0f24azX8UBv&jNYjK&jUc^F-(Ta5@Lr z#StSl)`*dGv+~m%IRgdW*oG4$hSo{vgu8sx4oBpxOMj(jnxBmh|7LQuQg&V zv)X?e$eThz%8>V;mYIIDN%^gal22D;z>CIZ;vjNcL3YdeoW$-mikfEa4W8oicy<#&uOZ3jKT4_n7jVE7I3ipb5)(SRDF zmRQQC4Yd{=(3}J7^Ok`j8WTp>MFqxXuuntKG#II1|&C# zb&o&<9JYaS(g1@7(IDsx_#c|<^HC1|t_w2J3}7HWU!juD9Xqu|t!v9K~C_!+}X zT0{b&l4a(RL=t0J@7%D)%LH4a!nk!8b0OLRPNGV7o6r{jCehI5yap=!^e zdsA|tk6C8TOs)0T_gg_rv_1<4ZE=n19Q|@T6#Dhq(r(8qGS^P_ewL$@sK#`?WzFt2 zu%jf)=k@kE@3T24hF=3d+jCCI(Um=y9`}{CL3T5U0@i1=_u()?7*c6ZRpKd~Kq~b< z?D6Jkl`Tknaz%0tImDem>!g^^ZmY{yIRob1%$h0tzOn7S%%bf<;kXvrCNr)6ZeZbP zO*h?^dXywY_UiP$EhA#pxYNM$h@lyb?AgfOsHhkV#4$YNDB?nbxYct#vfZ`LY)Ezy zOE7q+^OATG3Www@;98kvw^c$W*#*cbie#qa)Wl6?nog!$SBc)?hGWtYvINql1E&If zxijyO;p(5eIm)ZHR04HZpmRh&b%#I^w4$T|Bk#{jy9Bu?^bcJWn^7>zO|?Wjk(Eh^ zT4}12Bti-~nAOA%Y%72bcazgP1+7&x3gvcYleZzmd=9>Y2ujes~daF3>x;uEa-&o*dnm)Wp+Fgjxk!fr;0i zCVG{ADm!@+$ZWis1#X2-q*zJ7s^+Aopt{D+fj(!O=x0)&XCH0?$!0Bp4)Kf+m-mlK zbPM2VFSo*2snI>NfXD`{{{bhpkMbsJq!T482;Xx;DNW<{OmIG|K=z}Cu*PtNNGOr- zNDQ);ybo7oCOgm>5p?eMVAS~5V(h5%9pSg5%Utal=*TZC9?=mccRBbHb-4x)hw@Qd z6f1>XGt>Q^Z5Q4KWD6p<94IR*rPa@@)YjM6*Oo!}#s1aR>3TgVA<-`A`H(^U%}uWy zB%et>+rf^}NqmO#{2W8)i8qHQ;^NSE1trVegpMJ!LkxLOppvBG&$J$Vr7hfQBIo8H znXrEoe^VM;%4u>M%z}l>ZB>ZRQK0~(Rd+X)kyxj)0d{M*D6364)y;EhlA?121b?S$ z>?y#sCV3>vJ9APHvT&d;Cd#+2z~~7xY`{f>sYIm zZAiEflcD_&N6>EOZMWnoHYf~k2<7#*P%zf1W|wtFG`oUQTBy^#ywqKu@#sdiMjnpC zXOVd%Ql7BH9UlD}>~zTZ{p+WUo@;o_r=aIMoZx!%~QJntQ8AV1AJ59IuR#Jzb~ljpiFzA7OENFWFZ0zv|ch*hGD zju2200YOEvAck0$5(YuVp&+CrVW?eV6cq#qlu1DdDuV?fl4!-&0fP_>Vu(^ph!|8R z6O#8l^mo?T>yN#!YoC3t>$hmVMDl$f34D2<_qm^Y=v%mc9tf!KWR?}5@pwEj&rxdh z)WN@oqo!Y3t8EUx1yW{;JH^ee-?1~KswFB-At1Dkry5Q&qygP+mpBByfJRfT;>)#sahxeLUBAyuXKq)$h~)4%NI#bnm|T8-#lkJkmf4tqTI*cBVK#H7PNTbE+5MJGo#WG?fEz0cL>+L1y)%uplZ%SZPswm zrhA^uBYymH>bMG>qM;8tcI0=r=Z(M4VM5Mg*!N6@nt5g((iZSYrviU5ST(q6&}0IM z$d9%XYBi~-K}^#&7SzrZEwH)Q^0T3ujf9<8xo(TPZlpTCQL_6?j~$JtX$2$W#3LdU z$QxIvlAz^7Dil?JCZZK>67@B7Y!vM}<{WAW_u? z-Pj@B5|sW(B0qBW8bPO?2Y$GlwLKoDH7@)|L`FG%F}+I4G&xWqiIPNBGva#}+`7KY z{8(JKV;|K$I8Ii*Web(U-dxuXju9kSYlHPRgPi~*)^~}NqxweIFm}pQL!&$8LefVu|y9E&YHEdKL3I9-ivNUbZplxeQZ%hQ39xj=^Rj4 z7o|LP4=dK+zE;J^s%xwB5nwILEWvU&pssb*2?nRuGAf1VQUd)3-rP+Pk0td3VA%0s2L+0R5ofe#a=mpO(=6D`RuE8d;Vsu*}8H>vts2y~*VbzU(^SA#D`1JfI zmwx#&5J~iAze*#Aq=?cbKd``2supCO-Dxz_%n2Y(!VYdZMJ>+fd=vi_DMm=~0H zsuY*ED7o9iW?;oY^nk6UL*~G5(Ue`wzp1}(g?&-in@srIWxx4uIgn2|VQ)X1_9@Ys z%(XgSAiKLME933?qGRQ-cBcks*gL>mg1cf?j{OQ9qR;42u>bfDTRnept_^#04B?xa z4%-jxKrXmBLZ4=ei<@$eoxz~6e)0L>A(;j>b0;`ooGJ)%KDNs_iz;Wqy1ip8k@=P1 zyo~wX&*Nn>iLf~`hbCm#+IZ6jokn7eu`hZf8)Vn!x^g4ZZ-V!*RnBA*o*dfayyisi zu=6jvb$?Ia_VV}v4O5IXnl(&X6jLmwbsz3#Y7XjE(mIx5j0uaud`r?mdUy5@BdT9* zGw-YJBhr%_*Gnn5DC@KmDyIVXw|Ya9}a=`<@$S z!`{w49`x=H8U7%?a@`*;x!-4kKcivCwli0s(empqOtYVu>aO`_o{rC*po;pT_M&AVi}M5JR1mrJ?9!{Yg}x)!MIJ-%tcCt=qZb$z7vo3w+URf4XRo$rmVBH#5;DQgX6%e?dED0*Fw>kF=LEE0 z@x)kHhil6FMf=+>x}y5lIzc+3dq2SjL}4VjRUhX$ic&AMt~vBxlvq|gR>*9@C=4M0 zaGJs{@2Z!3D-MrTD-mDSmY?F?JdXNy%jwXVX+L~1;LBE`2#t5`M4Nh?iK+t+GsUfI z80q0rsGoUQQKlB!woTP$*YbyUj3B0bSi`S`4oGcRA?JaC`(&PFcFTu!Li%w^vz_{p zwslP!aypbZ=aC9^j%)S<0N2YLb^~_~=9}IuXs@*746UsNddJh+uL8$>HA)LiKRTWB zJG_DT%&}wc-(*cOJr>z4L(`~ijEYC?pvU?7YUo@`aLv_{ACY93tS2R$( z;lDbG;i$9{a6qQAgb&ZPQB`IECm&Rgk1PPoM}&HiRzho1B6*q?>MitHo)BiN;%gP= zYICg%NH)be9SKi@KKxP(LWGD889rVK?H^?*gqC(pU^W znxvtII?XszNL7)va!nsVeJpM>ElQ~ibdkK|9nT|$a+n|;7iJKab6ZRB} zFUQaCPe+O3H$ua-ctq~%wVTXz-H=zW62$u z1(dKiJ72iSjW?(cu4GWyaiZkH;2MAqJu->Ek}+0<6B4iromROldU5{9Xr%jn^#i z3ue3xG0<`C%JdpszL-Gl_?C1?_xqi>gM>|Db>LJq{~;}b#1_z5V-Jqdzx7AxGd8nq z(5jSlYzY;+k#x+um&*N3LkSHn8n)OlVJB=|71_dFJdbh2Vroh?t^$0a_80t*iFV}7 zj>Ri<_jN4bMjs5lfIX$(<1-q;noW4H?5g2%TLSnvrFpU}eP*1W{B*x5E%|%EZUX~i z9Fe|lrVR-#Bp>r9jZ=q-b$P3WFy83%g)phTA6y5bu;6c0Nb95uLKv%@0#~tl$|Elz&(z5N$|ddk8-3LXTse(^EqD=js{H-`5nAHV7IBPZ&N72 zEGHny8#OjJw!M)k08<~CDA+MuEh}$Rbh~J7Zoe7cSZv#Pbbs4o@g8f5{>UClWS&)k zoFT)G_!)EtdorMFUq;p0Q3ugjuU6`3nF)fik2`}FG}8}9wqnhQaY+~g@xTL1GM-GN z6B%GZ7Q>$7Q*W@BA2l}0o@UNGFEsU^TdI2gQy%CEpZ&+?>R;up|IM-Tzb$t7ub1#Y z+g$yBV`VUXI}LsQCr)w4l1w6x8>u&DYTPqArmYz}r%A15YBH)bf`_tyUVt$^qQ$Ld zeW?qoZd(!|SaYgNO7(tTEEiSF5yZ5^G*XHx?I>*$+kF}=KMAMwCYqODRaugrs0)e2f$~MOTxeq!wU^Ijw6V%woAC4P#!Q6<70h5fsl>bb7a#}4GuOD;agkNTO6KE~F? zSdE?!KgwM_=a@OR>MGSYT8J5M=Z9vAJf@PfvI*i2laSGU-}ojg>2)dhymPR}+O%^& zN4Gaq^eBBJh^DNUu|<<8<5BnRxqpl5*z%jri51H_ykt4%N;Iimce*fXlBu=pX`vyt z@nmuVLUr0t7(*zM2A!%FhP#&_?2X`f(1Y0J=x&5Bq%| zm55Z@H|jF|CG)K-;{nLqUzf{JTlJC-&?Y5Yj70PW;U&G>mX zAXJO184(doeNkt|l3Mqsh>;S03Zy%gbCRj?1Y3u!AhIZO=ueR(#k5Mzxi?$mc+Fz$ z`keZEqh`YR2(YQFJ;Os|rwzu+9K-_`^p|@_=&Qnddg|M1Ew?Lo7xeIln7ev&ZjB zVKJm3!T*)0O54`<%Pc*#eZ0f=B0G`GxNUHYyDZ0sO$1cXpZJIvMC$s@jJ0C_x`TFg znOqTTG~4lnF2$_V=E1QQC9&ian;{)#?qV3#b#%}>EDp~7wA{GE7V=YA^9^>9bEn7$ z=i~MgW-mBRdK1{O0C&tyu#k8^G-l0}js=vg)6t}M9mpfF|8c3ML&;JWVL>`(+WDtT z9c+KVJpb=1yrY4s0gh`OX6ek3zdV#CV9l`rNBosn<4!&$SRZ%D?zUM|!sfu*&u^Pg%d?s}1TJW&I_`$qFHc%t}`G{d{-te%A4sy@p!uf!8(` z5!Q1OUdNJpGm7g?OHTz08X3?r&Bm?Trlh|1a(yoxmU|^Xzwo6x`?y3IoUJdOc3mD{ zCjFQ{wXcwt($Mk+&=N$d>4Lc{GRU}+{IK{MVSXMIjrm3q&Nh@b|uUWnDjra}! z$dx1jp@x{!;mMjLr3ejQO1$h=5YoD4rJ}2cuc2v?Vhn7QBlxZTClk|N`LU88(qOwE zP(AtPQQzd@>ghBzR^MFKrOa>{1IU?Kby981lMGLqZ``vAeL`rSdctnJUwl<$HNup~ zKa%g}OT~)q+G=6Vba;-U+?YSg*VZtYOpOAKEk*&UT20#XdcGj1*`dRYu6xE?HBqT%vxw{ zV7mzC!HF{4^VXxMXh~q94_`_aPO6)cs3eazb_O1vnKn%d(a>UP=h9IrD&fOa3m`}u zz>L#bOsy8?QP5U5-R5~+7sMfNkH(cJV#F#^$F^{tF}t>%bY z%>*x9zBG}JCT7EPR4I0d5*Hsu2$C)*kXAHtrEfyagFMdc*%Od#skK~yMg_sV{yMsg zI?+X|j(m4&#Kl!pIYDHaJ?^hRw`Oq?Ozn12&KJaw)Rf(H>*Y1yX))iMzLPh8c9{@k zH@$UK(=f$usc~X6sskGCigOti4{N(4=`Ptf>I4DGh=&QOfsC`>?JOgKN5dR(N`ea!~>W;=Q0>B4F^2z@M1s_8XCkWkXmyB_D=S#Sr##Cz$m1 z#uWzVz_7T2m`14CiZx0JRhXM%ehk?z4gY#wlDGjv)4p21@g-O+Rpc(0G7_H@#* zX69)P!OPd0;wTqVav}YBT{!tde(sFlBLsd}+;7K4bEv29PZMX7mhA~T+(_*AQErV^ zL2fznMJ_Es;E3%?!ACd3_RguE(yP;3#od%!vHqlkx`iF4f6Fs$8DU0f zmX;Y47J`%eS)wNlrgjncvIrl3!URIZafVN?)n@AX4qM$z>jvihT;H+$hgm;5eAT_O zHKQM3tD=a->9&5;>he)Ntg2MB#vQ?40hZ8Uxtv#y1G0LW76?M(4W*jb|Nron2hlSgqKCKEW$`=3V~+8!mph zp`Z#_NYnmGz~E{$sQa+C8Z5BK$Hlt~BFJ3BJPVtHbCb^egY5%2+&@U`x%8)W9rAJ3 z$6Y47?%BWRD{f$aCO2T*m-pnYz~+%!AUx&S*-BF9``e}+hfV`D_XGE#32CqWq1B5D zzq=lI?+ta)WzLepNc){+JPFti*TL)er*_I!tf`n>xYmqK^b1@LklNsfpJOaO8x4Lk z!)_@#MEShzw}VUVGYbvyId`V)lb>R7*#ztZiu-klT(%^0U*1W5Nc??JK=6%*yK9t& z^QP%n&M}06Q(=(#8tcOCPCg;)*aZ)4qjO^t{0@v(JmHckK&Y5$-A#2dFCB5KiFH-_ z6*xbCa~t7p?84)8+g{%nzZqPLEAn(p6c7P&%kSn4^?e|T=bWq?NjKa;D9wI{#m%?Q z{aLJE$;#4a$=qz&P}cHD0*li9d7dr9Cc-$D5s~`-r}&qS-K0C9OrKF! zm?n0;v05Fi&Sq?H6^7oZdv>}kRi~1F> z%H;BF0xmUfb|cUq>Ylt_=c?K?iGR}XaZWaJ6mjI9RDL37O#9ru?8B5#VF=rc_`Kwz zE9*ONBg^^40d1Eq-0=^`e{H+uh{lTPdf|cNCQ~8zmRzl#xRlW)-Q-)f%P9Pc=@1q%H7f z2Yd^baAWi?7Z$%Zt;VG{9=LX2>z>&?&9qCY5bhOe6WrVQPqV|tu-i`#D<@#Zo=|j?PPwRd*FdF!n_D}3 z2EIa?!+^yB0^O7}OmyL)B;{maAAGsq;;$wjj%Y$WW|Jn?gpb5e>Bjs`vBJ2vgJD zFs>16RO-Wuk&n#<+l)0$f6b2(%F~wl+mug0kc(@r! z%j*Q1a{O#MZ)Z71MDChBWBGAC0{tq6 zUi}pq5!Dp}Nx;o2(Tzyg!TaKXSZ3+-b;X49NXC+in%a@Fj~?B1XCCbkQXSdZ`S|(7 z!!v99gg%CF{dz@FNpUd7j)Nz4#ln=zt&8ruszQY16(WWNDn}=9=%C!xLs7U^Si;^5 zN1GKTgzn)cIPXmkkX;zKHpg;1R3)sbp-{i31OnMDeV%4wlFO1kfuP4C9e-=TY9pnX zssjm4ga}4fA}xDPO=x@^&h7UyyrVzW%qu2kR}2v2h)@%U>#)y7*&}@Yf!~ieXamLwN z0XF!wmGnv{`g`15Rs-J4vCz>p$jpMw&Dk_p_bB-WrzEqG5eLNUM#EGXT75fqFh2?n(000f zh}FB#&bYp%*6W=@+g2-nvlx1Cp4{{8Vwwu6G)EO}RX_+tWhiy{OZoh|MArWGhZ(4<`$nE!P7yL&$CT@-5l;mKS+RN%!|8D;YYI{EVCg# zS>$8kwCElY*cH7Soggc2a?sdd(3p@xdV@3JSR8!K88|WP0=w`ZI@?L>mU~(g=Ne-_ z@21|y4G?42un4nt@$4j9@^vU#hODb`21Nuz12Z#Im^7_+G^GXWDY&s8az@u>7UK4- zHQH--(KT47_!K)dW(fzFq41{y=z`vLp->F57YHjV*t)@6e&KkGp4v>g`<(;Mjrii1 z(sTWxFB;#!x%U2P9rdEY5=+k)EdtA6Kz0kM6{foSr9S~7q;R`GWi-!&*zN4+k9VUK zRe1y(;-_*cFMh|n3NWvqdJDarZ;~!yY`l&_6eZ*eUD`#toGwcDO)G^Um2zBcU+gPL zDXS+^1Qrzf)iRs8_cO86q|A%+90wPYt54(udON?Dny_*=(d+oCH*>F4h^D>v4dyFD zuO!L4+sG>1O8xeWvwt%UkjooGwkGC3U1)SpLBDWw2VQ$7`FSC=-%_wclF@twRY(t~ zUyY(o+R-XewRT^4fGF`b1*)1Dzc3KAg^kZCO>&9ZUBB>P?~_pFW($p(Nm^0uFmJe4 z3X`F!;E85+ckPw2H~ni;ylc9(mGeVnuXxA{_!ENTjRQNg!$!x zCTX}4=;)-WTBKBxu0km#YkJNN$nFrQrIDgN-idRqcubxb4hLd zakMiYjc190y^YW=PY#^RL&{OULfm~Q^Uic{Y;+qxb|8U;s+oM?UCf{IF96D$7U5Sx zg9I=de~Qk8R;tyThEz!!?HeLZtD4kgNQYdsHgrAq^O(r~J3?hT zW~Oh^%w&2Dr61m{9*d<7AL|c5vQUtGHW>x;{2YdHhO|#yio4KLSIf2~=4P zbE2SChY^jb(QH+ht0?8CkS2beg zXWXSq;3t&a?r5tRZD0KPk$Tsy56^Fg2YiP)=)ldZ`QVNkhEY;?wuSicIJ9!&V8Sf#B51sOt=EcVy`~?I0M4B6-4Aviaf!lANyD>TD}KA9ZLAjg;6+^$jz_gpL5VHzeFXc!ep zdV`jb1mw&IluQ==TUGW28)$Me2P)p;^X8txmb~r}9Jzefb+u#bsGy*e?i-VW1KwV! zENcY|Yohzw(h<-bivx23tTMmbX>Y$~kG=ESxj!zI=;7xBvF|`fOy)nxT>RJV-RWQt+ThXZNjz{Goa)x?I0NZV$$cR1PP*kleJG&{MrrP zNc2jl-Dl9;pM2Yb^y|`1xMeZ!$?v#(aLYKj&&Cgo35+7n7nfXz!AXD}`{wp-5KH4r@a1&It_o%EtbfsLPJvYWAV;DEPkOm? zm&5sMFB-e|{>gGOdvKh1(S~w?;7uJUq~18RaP4y$mR8d4%iLaC2-}=^ho4%4mu$FE zdT7IIV)n_WHuXcVDD4rHV9ZbiY{d@gZRnSbsEqKv?si3+ZMW1Hy@Zeyx|`jD83htk zRGN4Fb*CcMz0CT(G2~9Vvpvio&bJm0K^RZn-uCMQ>-r4#?dTr-QnSQS5bV9}&-8^d ztSC{a-!tdrMe?D&@B23N84r=hIzgL+@miou?+kuCv~QNS$*6wz(c|80lb??@2wgqS z^Ob_sbRm@=9#G%f#^+aRuP~2>Ap*R1~JRulQAslQtotgb1)^JGa@cq+{>Hg1y9 zqZs2=?w$&1iWm&5^B5v|N{R=A&p*`6j`GseXO@dzgAC!Zketw5DKPa=cXig?`bl^v6d% zAUW!sG<@q2$y3z9t(ha+QSh}c(HIEcuTYiYIBtU&mR1x$?KyCYDf&Z+8COmCwsMsL`^8_$!i;9^Kd>8DdsfjH3&v);rkNb$=~SA5 z7^$~;Wz#|cgYE|oZlNsnV|RWdj4Vi#QB?H z+d1^3XgohVl(9@BREgC39>j>+o0R+sejRKE0=mrGr!_Yls3X8$9n%r@g+7%JD%fozR7f21uBmj3@CMI0+ zHLfV4LX07tdL0-8q4ceBR(pVeOXY|*)uNZp)RJ~==IKsH|8^p~lz!YjTi=UOu~`3> z{`HDj77+bRV;!x6J!%_GBRl|gV;jn|9EJ~I1b7I&(!o(Uei-WQg$~~|0@0WC=P!8f z-ki7BE?fj=!a0aWyf6!*Z)(bk)0es;Kfjd;4XE+c%9>U1h1ls0r?W5?mB}EL69K`Lw`L7C{H+b_Q?3 zNW{)&{%MoUmY1~SPLjsI! zi&t1!{VTIT(F4Cz$dz#%pm`cse{QEiIhjvAfal6f&D?VnMZg}mGEueF(HV`UKHhb&`_S&5TWj3y|S%mCkBx+7@ z8EAiYjIjt~)>L}QGs2FNERG<<6t2)e^oIPveZy1E5=!1YN|s>5;|bP&H)0}X?}J-& zY*sToU{Dj#iYX@S&!=B#-khJaNka9Id%3z_cHaEuVLC0czm*R&p!#I($>Nh3YomFj zDc4NXgf#lAHTc;wp(}ImJ`f983$u?uzan(qyH_;P8#10S-Dq$(WcP-*#K6w8pwx+{{T-eAo(wSLW#^pOQevJN+ihCiWJ zT4jZ{uUtF94}9(Vo|tk)LHDR>s_se+F}U)Phtd_{l`7`&mAK1IOW|Pbi!prB#SEq7U&$wO!*G2&wF*nGe$! zN}i+NcR}i+rwX2<0P#d973g&E68bPvam@`cekAjnCGs>z5-o(*5HIER*o`&7dGHFE z{a7fA3e*n+H7RrA9Iv}JkJa!| z5S*n132M*S<<{N!1&uYVC=Fk$W~A{-kOE$fCcQxfd_+1cB)kQypPUeW>tX7VV|!Y7 zo2LHm{~?XB{$O(9e?iXqr{4gWW_$b#4)m{~DF00y=-(E1?D_xTH*oCR!nwaDZ(|iZ zu)SP`UReB--in7_{u~ci_G$-mPBLzS$rF zZ{zyTYtenmv2EY4c4b}OfFFPm<9*rd=HA*2XU^L=@C-ltOxFXKVm5l{yLq~holO46 z&|H6k3I1YU=Go(Z@SX2>rWYIhaFN*g{PaMqhs}`dvdjB0^Gyn$&a%dzR%v@0-TNYO zUfyTDC-L?Q0)kUlLlm}%USUaf-rwmnQYIi&a1U~dVoCH9ILkeSGt;gT zL2z#H!Vsy3rI)r_vZXn$3qQZ;_*O<`y(y$tuB3tj=ERBEze=pfX4Z_1R{)AE(nJH@ zvBs^CzAb1meX)K;s{}ZQ(EW|f@4|U?;b!8)dO>=OTe)ZU%-)~~I$5uvXBC&~in_B5 zEItZYZ$K3wh(0l|L|_&@+X^UtKpG=v6DjNTUxO0L-)x3qRyLc_5GU9-uu{H3`=q?qIsJP^z}3|7lnq((yWAR#knMkb8)H}W?!^(C`N)!(qpiGu_~-L0eq z{dle`fvYLYskmpkOJ}Na4J?XkMoYbTGuD>6o3xSo}^>W06KJ-`h^{wi-G3r znkl4Le#opR3}pK_)oqwWHPWf+n$A#)(v8?JX$Y{N`3O-fTp6sk79N`>@WnNi^(<4GuLdpNn! zyGHR9-`=tB;N1R$$$qPe-ES@5&WNhK%_jVQN%jkQ;g$85bV_Gqr>~{we497aKgZyz zw?6B~n61!{vAk`Vw^{6h`@Unr@@e*0sPXN0*-_vTK{E02iCI(pf+W*{#;qL-<4iKg z&nxIgK9uNoN}&@BI%_J389t+<)HKRqkk_EQO%pk-gS(%6f~fTi>{xBx;l2%n&jO_d zOv32EM&At^DBy%s*t$43Tm6cwSOe2tj-ati1ENBIiQm|vV_}Ke#QFm{!Rwzs2g=qH zcKdPa82JMBv+eUAGg+3tzkl9s06C=t*WCmF4qSD!EhK|jgd9J|L=NeadGyj^5MRBH z@SvCO0~RIp`JYPnzW7y!?JAL7wy{~MKO?}k?gTCF-itU!y{QbIKxpV+bFGy9Rlu2G zZxYNgd0cwP-x?P|N!sxAYN=k`J{`~CvM*n#dQ|Km2E<)2wi-8YeyqUlJ?tnKCAfM< z2_wsR*GrLhs)LSNT+qjPDT>7e_e?_1jE)&ga)%Nxy6;(nNCJXtqIMrIXyVIhfZb>kOW9{c|KLfpWQ6 z-s@<}@DOCQYKa;0MpI3ivOnFUS&=S9;%=4nuwp8@80KG;=K%}*X|LW}OhbAyznZqY zh^f7zM6{Hm{>WPzbUO#*-|vpT?^e?gf0}u?r!&b8sm%F(5#1UQEoAIB8y99n@5ii1 z!`}Um&{dOnA(Prt1!5v~O?p&sFS66%6I|YPD&DT;o9950BQRCFwRT9YnlX&X{?RtgTNP}S(e0-wOG768XymG&$__NTT-$VjG!o$iN ziu%CKnVJrrF`BF%kD<0y+l_^1g9C>Vsh$G=*rUW}`kjl4?Qpi^ivX z>V%UBLANHA@!?VR=qVc!oU0Aa~CBaX}X*{z|5D9u?Yc7%YZ02s*uin_l|#J`uW6_9r@LdXby#Z_7|K)iY!3 z-=gXOFFYPj!Rq%0#`R3)w1HCW5~Va4E1=dF23-{p%3#!Gs{h-ZMJEUp78VHS)LRCN zN{Z4WvSF2Pbx(M%&*`z;Z5atN%B))z#Wq${Y$1Pb5AZkq+VCaYZw5-#`e)xFqu)aTzA? zBH{b{J^s4bZ&u8TWa+V5xvNLPCg;>Q+jMn5<9AZCrZdYihOczGOS-yr4J@{Ygcfce zjnp0AfZCL@cC=(oT~Ksv@S^7*tYEbZ41 zDSOI)?}n<5eK+jPN2hk8x6Ob+yObKLv~5VkV5+KATA$M$E*U&+^$i{2l8$Bi+-(PQ zwi>O#e1@9P8MAtl{NCR+^z!T#_+JLU1-`@P^|$A6zMTeg$Lfv+vlbHU!uaBa7~E~E zPU?Z*Sr)kq&#o|jK>6ddlP-3a<*5rRu2@ojdcxfxD4KYrTrp?N~>0Uwa; zU9+(3fC}-~Z!8)ZbvXCXusF&~Glvd}@7ST#Qf{J~mA~_fH8$)G{gz%~2V-CH!`u?< ziAjP88gPAYLTd+>6IlHU=rDsE{nkBB<#e|Da;EAn$w0mD!u{cIii>jc?G1Lw-|(g` zFD!W^mXw4&=EF`avyOEKHF@gh{Oac5YW3~(lFL`RMAJ@GR)xt2w*zK-UNp8F>bIHP znHdCi;daKoU^8SGf*=Lw8T~Z#AKV%@mQg<2%QSd>aGUo6?{W z;#M~D2H4`!tY5*z=t{slBilMN zQ#4Hu4c31qYE48N|9}fmyvWPXATDVF2`{)5A=E5bfkyk`fvF_aBPOUB7<1^w#^=fS zfrM;zAOdMWc(18zVcH}e2UM_$i87?O0-yqoj9aEv39~gW=pP)mk==Cm6F%*2J%8F0 z)^`{vt)<$bBa1;%BorIA_9>O({%ecdd|PXSUkmv$^P##l$+t7LJp~9*Lnazr&8#@O zADY9SH)GK_gpd@7fUW#)ruH0vFr2^8?&EbJig*&B0Xr;aM9P@sX@Sfzelt%zR#hV_ zrzJ7tncCh!9(fPTSnjQUue06-H6<>lp$1KTBh2J#619HjVuf1V>Za|bMNan8moTTQ zHP`~+d0as#R3O!;>5F$;(z0i(H3RKSZ$En9wE2npaE35YseW7gva(0idp*`}l0V6y zA@$2)N3|v?TCkb_KJ9JIk`t{bzIw%KmhHIJe@oA*@r)#~tcAWXPQ=)mH!ot-OGXvm zIg!e_ZR2(GAKscJ^;btKwjnIhI}cCNeBV8?Kvvds$?-}9VTs2?ezYKfBf!qoj$7Lw zy0PgXvpPM{NOQQhqNH7q#Llylu{L@vs$Um4%P#=-*4=xYHtXt>x z?xCaA1~J_|Ll9jKnaG7f&A1bP7(FcsCbBOcz?!|sQ40uv%Owsjk3ERJFMiN=2t#_x z!cf1>Ec_m`Zb#Wb5~(u8B%(Sz5Z$Fv8BF?;lc(G1#!qJlb0`gaSPA4#5A##mxC3@@ zPyAP^7q5S6ikB^?{0qV2uTr-gxK`r`>y`LzU zODcb0Q3wTD*Nb#4K6(+JoA4u_+mS)7!o}r#vrf0`2=_Z>9t-kH?jgo3Z#^1Jk!w;} zA61A}dgwdB>K)Y@)fh1$GmpBhwkxc&=d@1ycdB8&#N1A7ASfOW=eVk0mdiRUXmR~kzkX{V?ef`!!uo^RW&f`4` z?UNnnwBN0+#M6O?OU7QV$wqQ(UgcN9lI8nY5j(3M{o7n=>R0oZK*< zB^n}K((USIW)uh%qPKHcRbk|GvBtq%6cDcOEQ&BVBVUr9h>K8FMTo-9&BbdSdGaN4 z=S@`wzV*%J)7G2LElrs;Zg=5#@osGX4pX zRYaJ@!yRX~bc+JzJ6c_aoXa(i4{sq+z*5%s+H(xgoSrj1X9D7GxCAVHR6D12{`oVs z8pizDW7T0SL!5J1RXr;ZbuSQ6bxU%etD>AXwTQ%3D&BD0T~1%>xViaN{rPuURlR9E z`Ff}MH=MhjiD$wC727q8t!1rorbi<-Ws(AQMWHtsD57RoE^U0*(&FwVE)ju>ssImk@Q83&PIDAI@Rd3$!^RxvTMtZsm!w9%F5i!m*JeO|%EjI$lHDAyzmWQjrqzIE55Z-a>wB5#M)nmVyXi~+2ljYsv zqJ#xCOYa5>w08pocP%|*9{*{_oYE7)2lZG_oTzf`8Hr@Lx!Z-lpnPnR=qgSgC>#2x{jOvh#CT7C1Yk-fus z?PX$`$9ac;u1)aweazo{{u47+uYW2RL8bIBz7T&!ng3s|;ShoTe?n*f|Fy*Z>qY!O zF5+Kjbq?eXnr-lTZ)uZdlPL!%Y#nj6MSVLZgtX~2I+i3mbJ~-ev|4@c>P5PD9S!M}uon%}9(W6x5Rk5LpHM%8s*}8~9AQh? zhb1b3+p3l>IvA1kUDNw$Wio9^8X~T0s^07uASLXXkevEDtG$2WQT!5~xgB5A)fv)x zT>==qDn!eFQ-&A1e?GuH2K!uX;$c!7(doAC04qQLw&9bU3wWat++C_o8;KilAC%)| zpBa3XxSHr41!{Wg)ehUE-0s_$12a~w!2JH>mFaDhjvQc`f0_7f8*}|o!4TJJx$X18 zB`mBj7!O(10gY~^$6;gIsg$rzde|HneU)O+7UyK!!N}Vz!1{f~uSi~haP()+;=%bZ zNPB1Hv#g&8gG#nqy1_^@bOxd;VYj>EC^>J48N-ESyg8-H02i_1#S@BO5E<{xIq*x< zhG$KsiLhw~#tLxh2Cr{blqIB`l+WaZQ|p@Oo{_6f)081?QY9l^sg=stj*pFxw4Q2`dE=jc{n9;1$s2z)wM19IOuT4t z18KVD-Ke@IlBX8am?6wQ4Nui`rdcy3JEcoPl9)C!g4=5 zbP7+N(&!>SdRwhjYfsq^ohqQFdc`C^aH)HL|5W20dMOWq`H%*UNMY9X#$xwc;KH@T zMTXY-e`?RLQ`<@oYmNcS4rWE!mQ17sI{E0mUQZ2k25$pP1HqbUPwnIrXOuyt!D$nH z%t?d>_)?^8lG(y@K`KM=aA@Z9$1LDGh}k)S^i2xZqyYq{=%h&zILoQP)1U&cwRHnn}X@L zNQ!2zZAd#@&v#VDAxVQK-32McsB!iisipyVa3rPpm62A8XkcEa)ShIUgVDoyOMiW1 z6GEE$V%k_s6cUZNpphin;Rz{-s3z6C{SDa#!a&qiUp(1xRH^2pZ2r;lIzf22DiV;; zCd5dGpBoeCQeUpuxFjq}aYfYfxz=AqZ{|3GGe& zl{ArZmzQ>};P1v0`Q~_%YESjgi7vhD@fJos?=EBUj>dDh0vgl^Yn~(d5Z;91_;u}i ziJZ`wkHWx4tAIw)5mCa1qBmWZ)RvICLi&7o>krKkBY*{7SW-x3899*>*RRJ2^*t;U z`D5Y{<5Ty5TLB!)J#$V@ z)C=LnE5MzjloS!^Zk=F-gwL~jkeo?e?QWBu`CvmbUbq=&1-w&OEMk}G7s2d0)~g`| zP)y7RM}YD0_IRW9HkRa#EUMuwQajN@_jy#65C>#84hWFA4%|qB(^WfC@DV=m$%}dO zr*f%!^_KQILX5*Hga!?LdcNx1WvtLqkhzYtewY=(n)|l~jIqu?K-_F=V7An!ckT{q zMTgtx=#na+L44}~yN#L(1Jf>Hj-D}R?k>YB&wE}+;ftMLb?ysQ76aqp+ZwuxyPAa5 zU(8lT0ArdeA#({XmAu-vJLw%UEMddjYkVzV{fka}`M90t@VKD1ls8m3;+KG*Ns zkH4?ATxN?c0pTgGXcpF2_637KXLN8HP%*krI~Ld@h8zL27HAhMum@gd=a8&@2ex!JkrZQWP0rH^aoc67P<-w)(b523}WZ5%PfAi7}xo&33l%u5UK^4!IOxF z2BL^@b7!!PWaup@b*$@8HWKR-BvxJt4ksU##z+95^?FUejO(P1?wjRCOv3oBFgO^t z;`hOgFbNWX6FA-7z>L`L9!%Y)3*5m`U%`r%VF&4kIJ##_!bpTiBBpmAdpQg5b_qnP z*?ZCg+KQ;2!+m^xVZ&Mtdu`H{l`7dv?Gh|*r=LGDw(n`n-Ty`0y9YIScYEJ=1ww!X zf_Q*{5Y&QaqMSv6h!rVvupaOhAw;bb4gyw$qL7k=Ky5`Vtx!OL%0Wd8wj3-7F-fi1 zYDJ6$%?51^w+1jXmKu(4-I0Fg)Mv2pKT?7G zz8V%)k<=|H)FgHoe!oQ;gU#%c>dDZq>?MO7Fb1(Wvotv8fjeI7Vql37|1&tPkr7TH zYF*&i$AlC7+f-yE?2OjyHEMwp%`o8o05t?J)9*woJd%T{ zkZJ}54+hskGr?2`>gmnuLA}{HrCMhY^ye>d*-%QF}-?2M<#r&>A#!3AMn_ zM%XFrM`BmZENMpxhS%b5n% z0xloV6zMok;b@m`oFigv^kg&f?TsnIc0K0F~*DOHDZ-Bw0ty}bVQA2;Dm2Q^*U?9A?RoEeCad)$DnITHiw8CdmvXGLqT^X^~+B?ZF z*(s@#MXT&5(FRPJkq(1SKm32PxYfOv+alGd5E$mK2A$ZsLwuu)0cuj*=#WC!@@^mC?j0 zYl8b6_T{U8{D84z+lm5-23Tj8Xc>uKl7iOM9kYQhX1jECm1LGK`M=4-06N5f#J79- z{MU4OXvh9fs{8*-eac!$0NKJ$IriyMNCNr)HI?M=AL8F@!D>sWcWyl!K6onIW{x!> zcwLo=^s|I}={A&SDf71uKS^<{oHs0(Q)VLmcG!VeW!7>>3C7!|nPkU1E|Z$gHjaXY z&zr_@iR-frrd)1V6a&@@&Fc!h=Vx*Nz#BNOSN+pBu?TKa#FFR{>LG?3gVy63xtZ${ z3{0e;xk1AB?tpz=cU90))9dv%@|2mUl}B&3F}UJ1Y32|Wwn)5QuPU14;B491bkOQE zemK4gv3MRuPp;07f@a-E{@m^jp9F~BhI~tB}6|)$x~D62Hwvn z8MJ4N;U}B@9UiPZzL`5yRsw?dZ6HyER{%1E^m4{+{=+{kPfr%7Z5iC&>nG^!%?2WH zO94Oq)zj9D)(mN3UxXy(8jHqb6DH30G5Q!oLa;?URiAy>yBWOVMV=r`A<{3wN{TVF zY}q!q3znzvQCd@5HqHDj7X;q1Vqtm$PsaMbdynVK z_kXc{BXBfsz+`egGg8#l#4J`uu#X5QF^_IkXO}ehSOfRALDms-o|N%Dr55crz^=meX>+xL@tivf}#xa z0}5=gqG!iW?ka%k(#B_)x-hTR-6XaaB}ywi@Fe~c80!C zkC{**W@^`z46=f5QxHHT3W4-GT|K*+1EsQf_oPaeV>O0PmOKw8Ss^o&?f-B8{cGwaMTxPyx2JxGCowsoc#pl z9w(mJnjx=$Q?RHB1cC34I0Bywu2UzHj|NSN;3L`@?Kg{VR*FWb<~H@f{ldEjn{@i| zCIB`h<4UG(;xY$fFS5FG<+u_J%w#n|voy*{ zgAMx?yrg*{&&i_=5{n&zZ^%lE+qnhWRF4yyv7SoQb`Pr`RnAt;?y6G+k7u)ezByj% zXsf)^prNvSmB%AXf}gIBNTJ=PNixEIJZ5J>xc_16?bJuP-(vwlzztj3WiWM0QeHWc zxH4YG7FdLmX<*WwNAY8=D1EiofZS;~w6qm4yw$jfVODi;BjMiV=*q7>0kv=>H3oO#=<^l%4Z{2#+ zP1YGwkWd+`FOcAjQ59zi4|^SWYnvP9rqH=Hylc_l?u-sr)Kn}0eU(#x#LDm^_Tep8 z^7$e0Qh?a4v05TFpW!-RYouc78xU|-iXK}f%eDgjaLX>YJ*^(Q99BL9B zH=@O%W zBX%c=^4wT_m*?++@qGs^`|#KK&nzdurHOa++A)%PSBT93v3d@q@l7ROK%3YQaF)is zxy&v2jM)|$^Q0h{)qBtk_z&~udugXCPX_UOoymd^yv?lgCS0!Os~Z9$8C#EcMWi8X z=*Fr}dP%lrx~Qz3tGq(abX+OYYyCoRcSVkS1vlU3#AWs#bRAlFW2RWd!7p~{Aj;;l zS)!h)W!BSvd~YJLjxD+Qz4ge3Ue@mtr}qt;iZ}fn!rw~zX^x#>YZ?>ny8A0*m7x8g z9nts4HIzFgSsrJD4^^1Co33?n=sR8DIq$v8Tpp2LbQp$Zpm*D0>R~Dw8_%n=KT7&1 z;hNt_P)XXsSjbe0aVk7IQ|P~8F>CJM;YdVhs6vY1-f*DK1F#29?z1ydX2eH8NtJB4 zU|F2vn)v5e*dd!sFG^%w>VeXeh0m$gCD%6jpA0WrYD*hpxP3Xt#5CIB03=vIn=b)H z!`*w}DdLM6>AbIG7Ngut5sp$~d~t-MkD&kJF~96SM*ATkf~S7+c?C-`Q7Vh%OcAn zN7u(No4dWh+j(4z6zU5L=8{JP?oC_QO1oYwdz?U-e$C#U*$5UUyQnB_6UdU2uwy9m zN~>@Pabhs680lJ_uX_HgahQicFvCu8BA5|)nXdV9GIl&@!f?{Fxa$0|pclGYjTV0^ zWU9xJ6m#dp*oi4*J~3!?$9=r9+W-|frKxq|z_Ew-SRexj*6X z2tgJh+y%?)`jHr*nqb@ksL+*B4+P;8$Sr__QjOX;gqck*>JpxSK&3(y4hSLbyG5uC z7u)LMZ{9kLdK(&fwnNM1Q}9Dom(BBCLtcQK9y8@=mOM zfxJum<~j;LaO$~ezi5S`M#*gcg_>dRtoCRVlrD^`H^?UJ*b}G|~y3020Nw zj=a5B$!P7~yI(FicmAWbVKRmf7Y1pmkVH|jp9>T8s6$0dpPpy?ta!2v*0m8wXW|bJ zgm>@Q72mJmwO2$=J@%3nR|vlK`r+?!4*zZ+RFI5qV5Cj;j3CTSahu*@$Oy3h{<2IWhEHVC%(D#V*E0Rr`O z!`D%?c84QdMyUJjBo|$<(f-VLR{OJQvTdth&t#tIeFvuL@-B$#{$8{W>;3_=OM1=LzTIxi1YdO~7PAYzJ22vPHGcsk zrgT|u%&s^vREc}({&UP}_bp0(|Bd$k?6MG_L$!fRI1*qCP!F#21rt!P82-NGav1no z_AyS?pN(ALZsLOPCb?5bRxf@7I%OiqbrNK#c|mEop<9idcCyT+{1-Z zL$#R0GbJsfv8+7qX1m#$%Ha3l(fo~J_vyTC6!9j1ucJpOEdtwis?V_$^&r{N$Kh?u z>B>Ha?s!FB<4bOegP85pEXxa_`SLzD-L%vs`loGWwdB8F+By%KY$rA0^2P7cVJrt( zd`C(;Y-}$c!rU3Yjdg~JiP2a_f3E42Mm9@3Qce16SKVk3moIzxpqaJ(kNHl@MP8>% zK}TIvIRDIZD=3B1N0ZgxR}yk|4xt-|>q>EaY(k{RELA$S)t39O z+^wBFpF1xy9m@BGJippoU$#QF-r!_r9&!DU#AdQQvh*jh7MGli(Q4m8rgE-P{PK>P%{&-2xG#>e{IChyv3<#x(C?` zIfXX*_Z4g8lLJgtWybL{bu^1WnYm{WSY=;@>a^G?G^TxR34FM8HS)2fbg4i4HJhi=eZ!zMdQzmxq3*<(W1#S9=IbJzA*56 zBNOR4c#jIfz-?T`ft(5qMsY!+BPvicHwiHgq;tTt5E7-KDdQxYk=FxH$)qNkPyAvP^y8IMvlp4Tszv-r)LwtkWNba5hF5uUozkki^@fVd+S#zzNcngjcvHy(@ACOdqVK7zG&oI{*W@=y$X?Y=nOU8xJ9l!wn|u6q4|Tgul6OSWR9|ibm&L_qW5W ztX=m%HY_v#5dYq=tmZS4%bbMen{1L@5bB+8bpEKxH+mQOx|TSm2T#f+WakQ!KsaJi zTYr#R>!od-&A${1c}JnNyQb?*hAcZTIzAM^$m(qG0>+&1ZE#T2vVA^qW(zxe&bhdL zL#irYkx+X=hppl*(+Y|{Ju@bpeMpTS4=Cw%gf-P~8Mi~{qmzDlDLX&9DF|NC73mY$ zndi)Foe0@_yeW6f;~126M@H3Qnew*~JrNeS>!?EpLSqe#y~HF2VF{?I%d@s|GYA{) ziuU=JCvni{gl0TfX-UH~OnT{jElv$-O0>ACOHTG#8ZC zlyx=LV2-x9WDH$`T_(#*ylaz z_#uCrnV0#R2WHC%;V{BWsHg=RE9{oUJKZR9(2au@M@EbT4Z_ohcdk*6A1;V24%o07 zw9zRJx7fgjt9wuS`e_> zMu|q#>SZ#_rw0a*QqxtG8|{?DC5LyWwq|tCAwzIQ1P&<{R$)Jf#=z*VKNUJE(t8~f z$}8&HV7qb0V_AnrB;s^FG2}I);ZC-%YFFeUx6$s{sj48rLW%i~Oqjg|qDUE_OxZ!& zsmDUCLeYi?#1XnVXv%|hUjiY6tnY8W9e6yrI@e7H4xS_3sQHK?6J@0V2erU(2U*|g zab9sziy*Ld&=*|LYTw63@=Y1ULMX7>I|mN9KXY)<4*n&11^^DRrduNhoJRnYXm>+rs?*I!AfUH^+ zjI<8^=kPJYXTLUJx=S8iHnXr(!lg#ost6vV8t=549O8m*0yaKTkXpL{6M;X7so)q` zXlfx21qP~X{Yyxg0$O&?xT=xa;fRuN@fs(byy! z!ZAJ4kOKQw%=)ToL}SLzD196rs0)Ydfc8%K-q$+#h6cXXfE5_A#)T8zkMWrt`K+(J z9?gK~_r#8X@^n3tk2i}j;dC1mQ-pN!D#YewzQ6~~r-Xl5JNL$59JDk5C5?4=Lz)LW z86{)&x&dvj;Wb3bj_J^Kgm%3>8=96<;4<3Tk%@4_IBFAo*WF!@lBYYA2C|2O3T6|>3KwO_obA>#>v_Ny@z2xwn}vY$l1~ zCyxiWOhjwzfCX)oUdbHf#2d!zg_&uj4{;GYCP#leG`H^d$y`1;u>84m^IlD3nDk@n z_WpDhE&sRqS7}CeDu7eTbyQY?0b^ovlE=92I!elTb4k@>*riPB?__61F5g7*{%tN) zOc+J|FFAp`(+;oFu-k4DcEbYucq(7ECV!rvVBvIGPIyoIZ3f?ZaJ5_Wj-nS}LW&$; zMPoO}ELW_DO3w#!9;2b}&`Ekt8OcLx)o}joWRZ7zLix7EgjEbK1sWWa-~{=lR1bLK zYid~AysP#f66PivJE*6D`#A&S=={{#~1rW?2S#jQ1?0gBWruu zltV4>@}qAieyxy zF2Ec$BMWX_0FCiSfJOj5^=TpQlCFjR@8t4-R4CTW&te1>qGZ|$7h3jw-e!AeQ-sW| zg%PRVmqy>vr5tl9)SW(PuZ}ug1blbaFPwc2?^xB2SMQF?^xddDgAac+)w zu;WNUF5J?&7P(fJA-UYh^R_HzT@9$sjQ2tNL zblzem?cU764-QWQd$#w}9soS7Szq!iCHW2i=)9xZp}#l-{pZ$~ztEik8dpv`Mri>w z1BsUC%@Fb-Yn=N7b(aRg-z4L1afsSnYHiC1m)LkkJN#yuW=i7aT0ET#%bG8tKca7g zRf~}k2T}{uRkW!i1&oWOq4SnhZn3tN+OX(n+nrCBhB`_Ew|b-3A-+Xx{Fl*wcgSYY z3N9RREjuh(+PnYo(S4!6ES?Z$>XzG3 z(++b-N+-$vE6d`@)nvz1r&Q^yed11Q((o2=91+L`p0C^qpthTE`M5s|yg^zP*ZSI6 z%XyCosfB#1axg8IBR4Ro&fbL`(1Kz|#m8K7!^Gp!jj!DLBFtOVHKj?~z`QZOOIpqm z&`q(tl-*fzzEMb)3JSR>EZ3JI%$e#oW4TQ&P*++QGn4RKspMb94)2dN;}6kNy=q}!$Qr$=p=E^_gzxnZNyz+>liA1k6dqt8DcRnG53iMz(}G0cFb z)}t2&-P>uy{Oy`l;7O!CpSLM)C0~U%L$?MZ=ge>YBijSVIj=ZcII*QjGC8~E%*e4& zYnP@>AIAX1Ngvf|lab+ASHDXij*5!0k2quKC94tx<%EVQKJLPuhVoK~(4|!c!A1$P z8DQSV?_}w%rqMAG5)BOKwCHb09j;BA3>Cpii*eK<%uK-{dbFrSD%5=fE(f7ca0tVX z%jFxV4#a4%l^nSU^mnXgm4W2ZI4)G?PJdT$ zYJX4v?jPEz5&Jl(NiNbpxrW-yCi_J=6=sr?31#T}=atO3Q@Z&63EIT#{vw|%Kn_1% zlFF~JXvNPu9oqu0Er<=V@IqFmn!CHb<2v&&?4wLd1>Db?sO&LV&OAh?#v6Rbv8IbzjYs7>!<6uaza5S6Yc6)C)(8pca9-X6Y*%6J$ zB!oxwQU;w@I@-Wx`OIZERP?dGza=_uw`)x)Y#R<0!v=_w@@20vf!u}&fXyAb>;AYt z;TYznkkwQIK!FVEJ(AnstRpw}(+d_}itW+ee3?ZfnE=lYS(X7CBvVF;Ps`>Q;wG_K z8~AJmKv!rj-(R|yqn!1kDp^pVLIO&BzTz*C9;vVxu3(w$d;{4{<-s8BSnS~1!Ckz5 zkATurL^U}%8`{2*zbJ400lv!~5ZhVSyeK(S5@1pc9J=);+vaeu1uF=XA!4Whz|qaS z%2mMa*9b{+i@~R|OE%7U6uxu#huoB!A}DJpkJ=SIJoL~+oFy}h+TynmpuQ*`as!CurY%iMyLQNfUz%>s7n#YPS|`!eDT?l)At>H ziXBgrmK2v9TSem~m84Dq!rDzsYo-!H!tSa`5%Vk)miv8{FO?S1+3r7a{yZF7a`pjT>3u^lL47%hL8u?hXhAecOL$c`Q0e%^=l zzCT@Ey^-FT_K}IN(~=J?Bx1tOyV={|_NS&6x}Q*=;*|N@e|hPslUyv_nc7m&(jwa% zMUCW=`F1ts8Nd17IL1p{E&u$5>_k)Dl;Us=FR1R?q{O;emN{98F{5{xh1v~HhJ?Bo zZ0Yq{Z3@)_LOZLR{5w6 zCSkX4)Lywkdm?b{6(T4V<~sL5y6v}>ht5Pc7czW=nEA(pD@pDMs~yaIGTPLro8P9- z>pYP;eMSG{)z!stFd=n~x($ghtcV{Cu+U9syF)7gsIW@93Ei|8R}O z;f8yYN%junNVDa)#KWI)tL6=dup%8=XzFFbr&yEjFY&QXalO@-=z6Pg zN&X-3O&o3&n)!Khs~jXg4#3axztu}f8(^XrX#9+k@}QSs5dslMXLa$5j{q2j&=DwJ z2;Bh$D{jB0*d&1ibJ^b}lxhw_VrQltHgg8-xC@L!>ru}_2zrNT+)9L0OtG^;FGMvW z6~aVF$^j+Cd=U_CA;Onl%mH2n>ey>F{$Z9e3YZBiFHXC$w^faSfKrF!3P!GRwWjTh zzwJ{EIfw{-UPuNiI@ZH5UzLtHV?AFVOn+?DQi9kr)nfpDM<-gluX3$*%&BwDB^m<< z+mp4Af99IxQr?AbRa|H%u%jkK94U0GX&Sf{FgT0Ml1qf3h-?BSysjgL$!6vXl^n4K z)ngn^{YYWXbZ-_dPL(rTaH36)Ccpk*z6gQHRMm!bDIX>a+eN~7)$AjOZ|<~;l0@j} ze1s1$`=yvFc`raheEL(Cj_Ksnb6fFlxBkvktncnWxgMj85K1jjN~%!~s$^!uq&H8b zjH^fSo!%sROVS{Ry|-ze^5t>hLmh9wcH8Hh6EV9>*>TsCDzd;Kpu%vafiun_eF%I( zNh~2I@35*(k+Nexo2k5R-bHzl^5Hxfb?%MW0q}H|Ns|4?%OUvPq6NyboqBB?!bPMH zIoNd9{F8JZc4mK1;0<1+k}deIp~^m-=osPk%L>2^?f;=Xg0MoyS{u!acbKu0U1YIp z5^g@27LjPV*MI!1eeSNd{p9%m{e2J^(pr&f>P$&FPva>er;ct+`nbQe(xL*6-3le> z=1U+x+};&dZ-+ncz2Qs}`<-#V%D9rk9{+?T;BKR-`SYq7CajObCWB!SLsKvaeT>H4 z(-Lx`Vyn?g!^r=|!O8U=_<4*&)`YtUFjKO*JG8mhMlh1&PD;urS@UFjSnC3LmKF`= z&}|Oi+C&qRiA8-Gwzj`)J`v8|=^ZagxIlr(!w}PuBgEDD`#he}&q4Y;drR5vgBF>q zRyW9hSw&OC!ARL=+p6QXCgLmRwy=~ltJ!lhKbkzty$|xq+8ZP5%mIw|j?lN`D0#Rb zy&`c)*Xtm-<61Ye?nb`4Ea5VD=$wY%d*~gzK!VFk4rYz-K+p1P*u@votJ_jFaNk=3 z!t|JV3@tlDsq8)E*AN78b0%5j6Ce9QlGDW(fR#X_cpXU`QbNn5b(j1a;`$OI-4DI9 z{+tn^)DK+=o@6@}93?w5fCqT~Z1$O=pJ)@wu72FVXeDX1Dc8i{?rLJ|=6nV}nq+h` zU7#d-OKg}-*SK{KEsXrTViL=kj_bGhXUjj;W;23Mi2-FWZv?5}*|*gWYErPobB>yC z4-TkB4Vyra6)olw4loe*CDCZRm zir3Qt_N}farYIS3!0}H0L3We+&3gbn=|Qg5)568Zm;0yK;$23>uMk^xZ3!R~`%E;!v4v0?9D=B#awr`@fc zeOu4dl&mVdWt;!XI&^kpcv#Ef`^q}SVSUSGXuJl3R_k?7UL`$2k{a=*hSO6=t`zJ% zV$EGJZ;4>^+ko1{r_v3pmMYnS;}JeCF{HT>KW!NulzL9U9Y(@8E%zSWU=er*3;xtt zX7`#td`cO&!4+fXRS#9qx+W%yTX}uy>95#uR7=OzRda{$y(~TAY!scSE=A({SSzM- zVUzZFwb~n(3FCsW9O3v1?X=Z_X1qhAI9Aypf41J@rsu}>%vtyFsq_3%LsL|aesE)( zR@S78Kumel$Et2uv~ZM^eXT%>cc^AP|2#Z$4$}H=btys+7R2o6Ix+|~0UZEtADn!B z(5p3}g4ZtaaYSF!@yB4r66K<{G3-pgR^`%xu$2gUF6_~8%B&(q??+CDxg`gV@FzE3 z%yI-Gw3Q?3ke^V43gYkouqQo2y~H0YL?Wd5Ra(fwU6bMAg;}WOeak}yG+Q7EL6EQ^ z0)BZae5k7@7tSiYVMK|GTC|N=SGa-$q7C>0K6-+qgWu{jcvN1Bm$?m^6v0bLRiczY zOoUo{s^JR=2tfU_ykf^LO)NqKY1-K(-@$VyRiKXdWfr386+^~vI1TehOVG?iiC`wN zq$ny5n7Az}h#b5oQi;@Edr+fF%E9IE*lFS!5$wxYbL4LdoaHDsCkM*Z^Z>%v=wL_q zW(O*KN5r>gp(%?eaN);eV^_Au3gzKgYtMMDhe1E7;HaiV%y&+l{&yiA=;_*lE~W}S z{30Jz8!j<8gJ=UAjOluj+!a<75GiZ7-@`H;t&v56 z7US4$SRg2aCxHPW3;W5Zmi|MFq~&i-FOTjJ*xwF2-Rk*=IW4CgZ}569cI=9zK4v$x zf9GXqAq^|7gWGUBi#MB!DU1d?#!uUzS+r*qWI>XYqm|KT1)Gz=&^{3F^GUX(NtnS| zCH#>rPwE$3C;Oh>aVna3Op+QM@wb2@0^WWWHP0(pdo!YIO66N5A(k0)*k}79C<;Fo zgIEMd4b+huSRwwFESMW{35?YQ87vWf*wKmp4MaB{%d0Z{3ASOedkc>!c+3N5bD|$) zie3v`W~3w?%3euwyXn320S&qtTW}Ci?r|+ILe$jnqcK&+YRR2ptfH5@0(iak!}@ed zeDFE4eb@ZAR>ETnj|48sevQ;LcsN65E4u^vH4twR2qfC!{M#iPtb@!VGF3K(gZz*) z)60>(Sr0jWcVK7ZAnZ*zN>*=O&LWt*AGCjypMTeAWSX1s<*(6)1=%4P;t+_H`s~AB zqI&nvai@qWDKoyLc@&n>nH^n0-nlF~x)yTfYGfY$>1RN_7`kkegbHCt4}U7OhTLyO zs@*Rm1j^-%Q#H!nUf;s zU+YYzg6=;)c(x#|ejKsQ5T4@Y}O(0`a*kg_*h(+dh`6>2(hVpfKP{e#h zi2$VYI&ZuYBKkygPZ1rrZ{M+PE}4(_vrdssmB%X{(Q6seaHCRmlH^8Y@as zH(37vn``3bcFg{3{|!Ti*Z)+5_4g0)Z|<1G$@|s4YSJ8qr!%P}Vc3~?(#9-= zzQG?NYnPH4bw|w$B-EDR$sMiY9aa;tH8w2{{_DrN#1)EV+w3eFEHpe|oe&P2{RnWa zuTwvq^(U1sYQi>MxpqxGiHFdrq1#bMx>`I72KvI|b^wNM!fQvLaW9T~F@kk3&Im;Ju}Qt@{dKICQh=y=f2GUp!9j5>#CV8>A`;- z%``+HG7{e0>E(#t>>s-p?j#6KYkXVJ=c!xi| zS4LSIyqVq?z2kG!n$0h_+HZuYnZzXUvp%Nplx@1Sq>{*Tela5{y@XE#O(6 zetdJuAf&J5ZaLk4`aJ)1r3iv%a#Fz!FYOUV_1`#@7Fk;N=Kl9po}L`skQy|)u|A?t zCYx?cP39lHSXr0a_OSiok9ETjtZaw@t#ipdKL;>qR$irl{MUG)6kA#W9E+AVUP7U80dsBT%~l0 z*Xx?y8}rmb8V*yWNnUjFfY1h5FIPC>;X*xUH=yK@E{;==^tm3|>4hBKj1Zl9EW*^e zqRwNLa&6j)C%#=JAJcfdV=()P^_xnkhc(9-tsi7k|b==9&3w3k59Ou zU7T@i=OEO1>Jlo573YC?XiUtRT?ndKj}95fS%R+z7rh88EP!atIF8v+K4%Qfm$rXu zXKgh?5W>2EboNGpezXu2q3EU}35=2hV$M~MOQ9lRUKx7j4%^-dWw@|Ll$-WaeADB8 z{-Q#-rD?JuzC%V>*u##2x`jF%p_=Yk%p+|SJ0>E(N}gdd(-43IZqk@YS&u+XYV6jL zP^4$pFDhYRZwfPGK}l;6J9oeqVyGHPbC{@`Cc-?XM4-TcKf*DswyhDHLVZk~02!F5 zMGxK(ub$WXHwDMNF@q`7xCh8Ys@*-)J*u?(Tu%QO#|GYqoS&`7VIt7Y^?)64));O~ z&4k-VU1O`LvrVK=HMpw6!Bcs{^}5PnKpNLtDQMLU$;q5)A=2+|*FA0qQ5|+o%#CfD zKi-(vtr_Hi=M>b%T}W=&{2^ASWMcKq@g{P7+j!>hE?u7E@)mhcLqOam-u{VBQL8BL zwSfaKEOjMp2qI@#%joSrS9d6@IIPC`$ynVlP8oz>uX<0=#s#IV?bqa_HKi&@QrnHj zV?`JceB8UDcG6CGC8pS2l5_ze%miO8L0$nI9qCQ>@iKjhb3w)!)JK|mte{0Lp=bGj{`Sr0E@7tBFMz^G6#99lZ zoe@M=Zr@i`?Cu6!BoG@VXZt{T0=EL2z2ZBdA0PRPNPV+|GEuH*_efnjHC@~ENx^;! z+`!pPvl}Sv3YMFsVZoyhrJgX?PinVJvnT)~2T+EM-Foe}$g`fcu~7GCx> z`K@+DA3I9>e8RP9yGTf2ldu?ccrJpml18{9@PUI?9{@MeM4cDbb z2ML4qBV_QKa}_>2LT_tuJ1agW3mIzDjTX?P)iC$nluk7`?=W$Ifeg|0szu1ue zIaf^Iw``YIs#ZZd@tFooOA8L5i3b(T#>Q(d){C%)>*(PrCnw*w_k^;yj#y@v5?+8@ z!Q_mgoD$t7Bp3dZ^hMH962tV~`H?`1{7vCI3&Qh22!knM|G-^F`r;70Z4TOypFz@d zB5;Z$dp({KelBUG6*K3)TlD)oXEK0(mjOGan79ZgDU;>K-Me_l&NPIL*qHuE`X}lA z4@WDDmQs78z*e7lVKdkE_vi5p>rGEz+6Mn&N`Sc!LrpNIowDfL+(Nx1WXHcw+I=PQ zZ#|OZOQ5t72NGEq=9{D5<>EQnuFbzJJUYq6O4h#gKe=UO!@C8aUkWc;_B@bSMWcsA z!Dbb%BCrgHz!&k3Ezef?C|p@iXX(mr!ieQ^+8%dprgbS0RD z`RQs$*0`6t-}-C2;3`kaM)$@>@{e})tnWpzdJfE+I`1akz#vF1S{`^cL+nW1*wkdj z<1yXC`-UiAk<`L!%iWgp2v>+Tq;S}yqq>@j(t5V}<-d4AeUQEpwe3AO)lHc@7{3rb ze&pU*du>Q{4QWMM{0@U)@0ni?Jn#sdTY5isD8D*WT)jS01EorZ3_@9-a5O7oW9Erb zX6C4OcdqZHSVxy!YmYO{R#;&jt{06G&bz1T({Ak5HPvgnb33&tPH50`6ov_ON~L+5 z5}?z{_4rh!COmEG@@S8qGtjKTV%iMznW%VmUXMpMCofQhW3e`xDhDTOB;o7fM95(_ z*u*yWh{muU5Xt1o&!8LfENq2VKa-mW=8C^qH9jsFnWHu2=ILEVcXudf@UEopWYL?z z?zGT<@V;OyHfnA=PysZ*U2w=EmH}j}^HFX#Qz(LkajFOFzJSx!9b*7_Er<9o=w;|q z8xZpX{&D&z)=%GTQFS%+SfOMniD-{31+_no}gujx=`65FZn${SyKw$gI1Bq-)L=2*R2gx*;PGMqxSvs{~zJ7kPAP3+7>an}s` zX<;msu{4nq%|7S6jnOkz^U#Q`VK$KA42b_843~pdUI&i(@zim=D>k0Wlv;2wgX28V zGu=r=*+LH`aldaH8SX{uF#l{KRuM?U>EZlgJFhd5RQW7O)6LCEmAS%Yf&=2{V3-Iv}i#+%V8prvI z0;Q%-yWfNq#x9&c+A3S5WP=NyZR$wjvW$b;R(rl33~J|9TDopt1?G2Fz|Ot|fJ54E z-Z)*hkJE929T0P!?0sN#k212}isd#R#*bhHl({oNCrO~BETv|I3FfLBT0mdaJ4$(R z_KaUX3;@@f(nl6LZH6k7f1lMRVtdIzs?6QRmsm%a7>k=9!$=2|}qLhnt= z_wyat%_UxhJHSy4HIlT5&JOJ%@nVA2A11CDuJmp5=|7u9uYwn`;%9&=_NIiDEGDjT zW?bBf*;j%ZsX@He$=y^OV|h-pRo08t>;K^xAi(dK$&!B=y$+ar(4Z}CUMm__J zT%p+{tLy&Rx7zSTu66Ulb=AA(qh|pdR$5PK3d+eB-pcpNp9SKjJw+s2SmSO|4( z2acC1U=Q5vfp=%&a-<(i`kB;WR6#_^Y1xOi{2V~*aSQQDD9Q*9p@-NG)1!A}(>Ov@ z9Ay4F_@|**-}wtPmN(Jc($a2M5xd{t9DLV>+Y<+%y|QrK>T%FhRatZ{dL(Nk$hPmC z?FOD$xc2T_!W2|M?jjJe8gCUS373H~`D)5zV0qa}$z;$jWwG28vo1PLr#4M$(b{7tY{q<<5ZAelb8@HZP4%#rW$A%;k0Jr3LA(Jz7QKiyjtQbzH$zdG$T53-2#$@@&t=idj zg;CRkhYQFyFQy-H!fTmGhfU-gSA7M>`*g$gLF=Fw8qOwfG&!VX4w?aa<-Xv72(R74 z0b14>50oduSHg#AL+{I`!Onq7vU7@0Rx}f6EeLCq_)BvT8sb7xK>e&)#bG1=p6Y>! zp@b2cm>fOv{(MT%%CyMBx47wM}?h3;BW~X>SA%3hg_bEVr}$Flq|$Mrce@iXJEbB zUN*AwTD2$_t7iqVnlEf@{p_*yD_tqYfMvJMr%!YH- z-;WNiD>S4P7q z?04Erri_9baFdp~^Zo{)r@%sxYjlRM_9nU2658SJkY~Z)1fl3CcA#O!O4_I+IxPou}xyShA#YS$*=5>BllgJ6$ zz{irE(-moCH~XcOW0LgSel(sH%T!{M94U=%k+5|&56zDjZYM416A<&4IhtSx)B-JgWR&YynpZKBop0@5$;ccuP*{=@(Byu}!n(TOQGWP%Be z`W06}Nw@stgH_~_b(H528CrOqaxi@Z^@qjFS9+PPS-cp=+3RXopKvXq?hHY%s4iEW z+#}MZrhX7IJEw2OnUdv#8o-NOgXqgc!LJ?7U7_OLJ!nH%WoPEXqJrW1tDQ?wQ_6c3hf=HPM2Dn#biD{DcBqo0!Q6J+uqdpkd+%b z^7>xqLf1A^us)cSa!K(aJAQQO^&6QyQ?#LXspCV&Jd-`W=O|kITS2goHKQWBlMQ}n*KGz)F<_YBhIY_8rUp!TuGH;2B`OZ8)!x$%Uhw}Jc zm7uOShw_(c3uoD)u&tSVXNweDq<@s=pMcumEqSHCa8 z_KxNJ9a~;fTJxtUsa6c%8eR_LMk^)t+Z6lN{aK9?0IHe0jjW*@==IW<6oV-r^u_$u zmH+F9;eol|$YN12_(^aF5W4cuoA*e4U8J>*HOCDzlVw=@}0VcfI7f~LyrGRv3% zqY3LagP67RtLRa&^_}rwnwj=SLL0ix^_$@cSnzNcfQ;+}I4DaW{t9;ZN{QbQmX!4p zTpm2X`2-MX^+lG}@RDA`V$}HxW~zv>2Bp-ocDoa!0mSusW{2hZBh{EzC?oFm6`US- zT+br=3uIftP3e^AHg#d^uDr^alS_y6F0x5eL zz~uBP?Q*rVFo&(Hv`+oK2)C!9I%RaMTpu-!_dtKr{>^9}I-x+?S0^*~aRze(snzKq z-D+aPZ3%_Z-(Ja#W%-H*n1=Bu9r$3+W$&@$K0z3+!ZKzzroj*Zr|N|=$)f(TD~=$5q=U9hu13Q*6)E=xXD;Sne6x|G?`Rs2*BfT@@SENfK^@3x z;}IAAvmms0Un@rl@?Fjh6M8@>k|AgGGq?-B^3+V+8l=Xhntz%2rJ`||bDr*G#yAz^Kgu%?pO6(usZ!cU6!_bHN3-;?9KY z@PW1g*rFQ7?RP=fHw^LLcrhgY>1T2``R8e{&Pmm{x&!ZMf*XKIU=Nfq zbhH;ZWJBA)W0@GJb0^Dcy8B{>M)Mq1X<3tM5$?0{jsdo?rHfz^Cb4GQIl`0& zo|u78+kGGUeCmF@`WWIDKoys9U=NKToX}ezUTSO{Y$k<@t|_f}+Pco}AHNlw(dne+2*!q zZra_lR^PLQ^fODN_GmDg4WY7%i;~swFvjx=TZ`^Mz;-)^Ta>G313f&u>KD16v;TD0 zjX-}expZP<*WxO=dwMJHWaQ!pUM-Br#`1$3mUGOC`*DP$z{)hzL$s`$5K`m7~(~;WV$5UAI%(!5ds;iw5cz zSA2rmL7AI6N~B9@-S5F`%uXf7sS5!8lekKCAHy5o)ay3dPMal4&-c8cSUd0-X(?wd%8Y!u}p0-Sm$21)|FfvMY@-w~8RtfxIAg zu7Wh1M_~}Wpm;=}8)#(4cxAc)3v!yE1L;@0L&uQ<#-XyME5&`pqJRE`Nd&0Bsw{DX z4W29mKn-{XRc`nX)81`Bu(c1}uVpicJE0xrkik2j_AZ z!P7TH+kwgrg#2&fAym$B)?Uv)=8P@4xamGD{R49tP~o|!Ld?Uo97>b6$&-ks}4QMaZx|~0NKCGxNQUvgMtpw zG$ZQnx#&c{epr;Yu_Z3=>!Q71b+n|N1NKBJ2n(ir`Ai)13|It`IPBDGyMs0mTHnYH zSkaU{UcW4kY#~N1lUzpljG-|fYP&a5D;Y<&8s^$uI#F#4RL^5MZY#8{ucwk$l73j< z5(%w5o5A(fUA8JcceZfGsDz;v9~F43U2G~0h!>BSK2R^7e9+9Mp)_{WEmuNovTQ5e zW{t*@i!Kjj?<>hKzD{NgE|_xRdA57Hv-lo0ex6CgoSnl-pPsZ&G>lEm_|;p)skR~2 zwG-SZlcoBVem7XG8ev?yXk%>;ccQd!#BMdjN=R|9XgY{&Plce$9su^yC9o#W>_t8X ziR)*U+fRLXL{D*CSwV%xjT2|f*B&CF-3^qzJxk4md-N1T8) zQW-)2ED;TDljyb!9J;kz;t>uXi*S@jyMA zyI+HFhIlI@L@-ajT-v5$MVHSm$fA@m=Z>+-Tcj|u#*bAYOr-2i({-|4Q`g~qky`NC zg6B!at`#N&Rv=6B4o|5E3`Zh~(E&|5JLYYHD%^exI2Po zroTZifnA3Nxw4x&>!Gxt&vYOfyMWzOL)J7GVDlT z(!YMwO&z}vdyZ6`Ems!(MaE&P4y`z=arQBMYw(p-!pcU?Dtz>J07cKecBsCr1n08= zFdo-tZ7`oU4onf;N$IzhsdwqY0dqb&PKA9 zhR`aCy9fpLo;DS{L-0|q7J7rhj$>#>FgL-?NFWqs*_o%|9{`s=hCI8kh}2-%Z`yNo zwk}4KVQes4TVaP49yn&?85jsH$QUU>7u_qDb`7#*S6@}x2es>+m$fXQO_Cd33H@`S zi^16KhQ6)h7fgd``ZUc=#pYQ(Q4>v5R|cp~9f35!&~W!8Y_^xGKPx&LD%|Y57DL9q zf;3lIWT(XfeD9@&Df#jw>;46e%j=*~Nx|t;Lt_xW#{A{l3mDYVIo47NHa!}E#i2mB zycWGsO0tSl(*b%I4DO-cwX7tAed}M0d?af}m#OY8xG3AL`6%7meHpnx#M%C(?6O|g zFEpaUo;9K5IvNc-7n4A`(Th@x$#FACC+@ixuT7$<-*ndIsz~Sa5&!WmJ8Mr}J`jA- zZE*MwUkq zVRb~@9%$C2p@uZ;5|XkqST!pHtTgkQcMIKxfyn)q8v`xXY6H~^{3|$6gnm`=g&wy4 zM4s16^yQ+#X%{P647ifGK|w1sbUJbJFju)-aJ_Ks@{{OE5u!FFsYyiUbMAJs`dXql zzI8P2aA$^&u!MnU?Z+;av8MdV_N+2)w4}pDL=C?*0qg0T+A3tfhNON%96bBGuf0I~ z;$nA^qyAu?u>GCA)xyTy_D{`1|AxKQ>VGYPA-#xym%zA^rJbYMo3D8{-=II?B<9f# zR6-^?a?4H=O=nbOCWd!I^J(ysyB;d+G#TR_Ct4op2G63;*4d46wxAoFN&$Q*=n3o9 z!TU<6O?B=WF(;1q>L|r%ok%C=E5u}CdWyK0a6Ma|CYWa`Y&l*9(!@B>C$_=ez+3~= z#UqoLC4Dxy9w)|@<2}TD&7K>xNMpQ&Eh$PWIs0e}&3n(m*Z}@`rtC6aQqo=|77N?k zYQ>ff+KT-0iQZCP!W8HjZ~&-bqrEyNxVFBFI)MmAr+2m#uG|nWNz<_jqrT_7XZJ$z z@`4#8iPW}-yd=%8wtf`p>k})B8X!~?Vbg+osdZZqfMbJ z_L4|T4^+%Zq!m>TQN*T!i~gEiMY?&UWbN@9pxz0s2jTGDy*-x`5mBTif}Vms0G266 zqj1>TERNfTC#sstR%^2#>lV+p|W<^&N=l&3+C-Nd~6PQD8Ag z>SZ6&lpziLR>{79Q@sFacJ@P6?%>We_9SP5ibU6zfLiF}`O)F);`aUZ_WQ}h(dGA* z4~*_|z8g>~kZ?LD2BJFnwH-W{p#9Jgjf}9!43;<$!nN{y4eUz|r5*k#`McYr3QCOW zJ4dn;3R@#UT%j{)SmdiUTrrmuz?=&osMQF%4>i$-JOSB zOnTsB3=LVbu#v8xM-TaEm`z4q&2cll9UwOZiq0?Oo<#b=E+nDsfdj9!>saPgvHvzt zicPUQ3KxwvrVyXN{`ca&yl zP*wr>Gnh`cRGX(I&sZR*fgFR`QlLN|5!1iVFi@hqIX72v84T@aAF} zz~-}w@wPA*P1KgpCHo9Zx%nsafs<2TF9)ZO?pKf1+T(Br+D9o?bCa0rS&bE6WW1tf&1V&HgD(~V)PahxQ1n`RPhq+7id65N$;aJ4u5lO( z^>Csif|WPywz@?~AR0Co3$X+ck;U}N$jOdESf%RS9G<@|Vd+h07Ldo-eGKa>XY8#A z)laDGpcvNWV;<#s=V4lna(ywP+McF~L~6|L>z5e#_J1<#=ObC+C zWjSj*W1p&U4_PclTSr-LS?5v-X8q>vqZ?hzVs=j_P6ZfYBoRTk}_UxE3^7|NIihMjE77lWfS(4|}=9=yX zryw!9_kFqG$+|_bzs9yovde}C`~sArI@K-_`nV@&`*S!QlGINV0IuK+E>!>W=$ZU@ zb>fsbS|oC(p!SvXBxynk7g3wpt0)jhO*HAR36k{^|C(~GSUC?Pg0!Bp95S-7J-Hka zPkj26Sr6M3TybwwOfAq=@T?0Q^;gHUl542!VI6UM69yu|3?yj4zJ?_vMUNy{)^cbP z^%+xF@d{|a9?>{3OdW0}9YRPo0=^IIQxCG==F802o-rK-IyNZtji9GSCxJNuvWEVW z`b0$@i@#?|j7U1&jS%!NP%ec24`?|gB_r_?SjrPC6A@(=_uc}?e1NO^ppJ0;!95gk zxQd925b;AIY0AgUdyHWK<++;fR{I?g6*q%5fF7h{Tyf7=~It zlQBAQ04jmKdQxyB$R$iJ11h!wvH;pikO6A@7X`5?#HA6O2#F|y5;V+UA@n6fi$@U{ zsX?4Y5^Q^>gmh3j6Tqa2NZw2WhEK$r6c;CRuzMbi00x62W;lC_;rlOX>+)ku@r#{Q z1hY6WoevD|^^vNv2*$4d~tEl}{9Q_@3_qu8`sD>=w>wFKf88A}>M^s+*AzzPEj%NK`oB zN3kq+LA5=5ZHTk+;xe>}y>po5oBcL!98R2UuW9cp*->ikG1D~Uoj(%^w7l(cXXs5 zczXMdp=we_3=q~pN=F3?GCFlA0FR?r?wE_QB&R}n`MMT3A*FqOIeHNK={;V%8LLcQ zVct~6+c4czn+s|EaH!RJL2TJkkW%n=<$bq#Eldi{ozc2A0%KTl>qZ^JA*Egx zyvH+T0OEi2#g!C6oEQm3k348LK@H>I6n0KtNDsKSyrglEIW%IFj+g*>{4>9ALSU% zpD{`uEF(wN_bV%{8tj@At2x_-Y&<}Ol2@AEZJUTspA}&pCpNq})BrS_J`yIh<&Cz_ zKA8e3%GX?*J_*)XRkS@YmbE^ldqBwt@`1-fbYc@SWG&EMOO6!wFb#T`DZv?XW}0az z2*+`NwP#*tXkqP%ub!Jb5xi0vuU_<<>*BTpg$%>YQOQ=xRuMIJ6y>2AT(@9W6%Xk6V zF?b+g73N!v%mcy4D?6(?8=|+m=~1tpXt~A&P+%TczPUP1zK4DYIui~QUNn5STBZ;r z$(m!H0|VG$gA=s*xmHnKiWKdYR&EwO!65Zif6PrsN3%{98nIkn^O;7jnPldb#Au|@VF2fF&GWPSg7v5f@PE~toklMusl5?Eak0z&;V6L zEnGz{m*`Pv{L%*RlPlrOGFgpucT7dFx+kU(vdiuu=$4*> zc4`&^+?R6jZ!X!|e*MXsL$7=nn0Tov-)0RGhxy0svs> zhOgNs*(xTq@QMRPMfg4@&SsLkEs}J{vh3M|1M-e-c*eL>b z%MN9aRemnkQL>lv3Flg21B;_kepH*Ire@UYZs86);rpE+;7WObp`T23 zR#@8$BB*?6?6^=g_rNB0MUGFo4fGYk2-5E*-AaKGV`ptO$IFat=`LeH>!B-v@XOk{ zXo?c>&2lyMN)F0+@$DrOo)^V>4R-=8GhQ(;c19ca4>LfB*_|N+3BK}@r<{A zcLe=6qztxy@KRb6|J=v$Z+I!K|JTw0|37#sH_kDjZ;DxFqNlS&NApB_uv2itJY7(7 zq1((!C1S7jglbsG&8c6c6@qp0X!^Aa3W(6J>xIhYy~}NhhCKhznW4 zkaoJwgX)h|rcAnFx68F{CNKOHX~;pg(|=Ac5_bSplEnZ=7a_+q92ZXKg5+8*P(}v0H#;^%E^r&#ngl{)v#~GK_&PwjnMG<{ z^2%o4k-DC`gt5?^lk{8^{=}??o|LS~L|l%loUAfzNYE7g88y;&&`AK7Q|Gsy7o1w8 zPDTL<@2mTXRtZ3}52+c|?(A4bv-|ZzQ5|ZWL#&gLb+STl!$=uzpydxuxK#{aXpnwO zb++3ExbgQZWG%;6XjoV!Fj2Htf=*gu)$V6>`|DVC%H&k1YeA=| zBg{^{a9`Masdg@!K++aoip$k&6Y5^x6ibG!HRDvt8--S_>pJ_nIIN zE~RBaw4ctMSHkF+YU6YSX<311JQZV6H(M!XPJgPrwWoVCa4?4g^NY6Y<(1W*Zel)p zC8ta)pci#nI1x0GI~7q}Dij+%L2X{jktBy1#fV(C!4#S3)mGV*l>spobcNy@#jYI- zk_4rxoZF*Ol**qLtX3{H6=@;-Jv!6}2SPN)51XqifXd2bI~AEe3Anh#mOxL_i7)IX zD$>Is9Z(d5g8>Gx(caq8Zq5(uon0l7Xd5kCb9+wy?3FfJ_E2b{G7e1}v?J9bjs(H- zITAkb8^56MhRQn!{3I~ogU3U50i?BxFUvSOB2r+er zy8rB8Ex7!EcF&Qn6spi)SW(II zh0+itq1xU6S}D35DW8P?^~n|vK&S$_{$!&EWCmyXA*8IdwDjtg8x$x&brrXd9!k32 zeO}zo^M_22ItOS+N;3L_PFA%JuP86e+xVtv1#_+l6-EbWtZKER~R%b6Sv9D+lx}9XNi!hJhCCiR74@Po+#rXRpN|b zu99W#n*_SM&55`-DrkHf`6)3%{U7N|$Puz?i-N>9o=Xpze;r^!)-!h|J{(M~o>v9g#)k&xe4 zDY2)l@-Qa0P>S*}_zD0;aLItJ&LUe~SfjRWu!_QHYo;*9HQav2a1H1MbpT5;pS4?d zuZmio6uX3#1y6~4wq*mPm5QFAcGJifHmZso%yJtt3WP!M720@b5JXOQZ6_xYA=eZV z7rYtBC{<9->t%wa?Fc==K;~b*FfAQ8#pG+&+`aDc5Fch${c%4obB#m4%J@_Rf_KNR z43R&=i^scSsv1|MUO;U-ID4zH*dBy2%Wx+BYQgjnYSuF&e8LhXhcVwD9=&v)V|mPt znT+r3$pgmXhnr*$;}gPY*zM#Wj`aVWs&Kjn3V$Q1J^^exAuCwWO{_ ztyw#vb?bsrs{El5?GoyN_~;p9=UF3|=BWDngeh)Yd)ANCu~6E~QhzS~9O(>|(r8{a zcp|lLP%wHrJn0YTO# z)aQjSLY%T~?M-Jv_cjx{ytwdmTICs9*N!sk6k>ebb#kpfb~ziK$O(&Dk0YfCh2P7h zxhDW6TDx~QN zlNhzkcZy$ekj3D}i&q;J2|oHD-jO^fE?M!*>(x4OD`qPvk}5G{=RB+TY%0S=d(+8x zY(jTW)UR>V99Yy@I1t~?jgLw#J)1ZcbnLokbSJOGls^orCa6faYt%$QFU2Rcu$$Ur zxJp&zl@EQaGn zm6$kQ%HaehS4gTj68n?$R;2CZ2RY8yvF8Ze2R|lX?nNOtT*TE#!~{!#h^a{{;)D3e z%}7Fd#I&!Dr5LH45D3OEMTUWdgn+f3~_%@*t9Mas_|dc^Ns4#p3_U4M#Xst`K6QAOubZ>>3h; z^JcOWZQ3$}XLlZ=!aPJs4ahem(*^>Ba|qVz;dTTOB{A#6OsV7S-q8|h1c!G4d(=f0 zIdEpEL1NQMQ4oA$j2BnK8LxP56IG`IFX12w&J#I_0BT4;1%)rb1lfyiWpzI10iaP5CYG zvvCf%qZXtFi84ik%1ZnLhQW=ER+0-5v9vQ{T*8OH`H;{HJl|f~QHfwpBbSklgU?RB zL8fkq&D^h-T(W8jfCj}rd0RokTiGD3OosH;~m0Os@~f$l*uzFEMH=%|+!?mr)z zj8qTdlR**h-J*QzW8KJYk%TN#3#A)po>mI|WH-=Oxgi6aDeP=FVyjm!5dLz>DswQZ zYYlOSfTv@G6lv*xD5*h`N7-AHHy;;Cq(Mpu&R3)w1^^^d3v{c-q>WXmkuRqJX9q2! z;I~L>SG|LtiWWW`9U;%=l2*zWT|$4vlUL-%aU(CwTj?43R$5R%B0v!vxs-AzMg7+t zeXTKv*5h~>vMiT8r&z7km07^%;vWqeI4n6^+Nftm z9#6R$8U)H+)gkk_TYq)f1&@k|3c6z=guttpS^ap6&RQxkbcAV{;BW_8=wU&THDr9I^00>srM* zSX`+_5UYP4poesnnW@gY?Hhdd`iM6yx5a!y1OO-6h>rN+^a-Qn(OBiQko2y0?ZdF$ z>5s0@nk6j#L5|%{!}9TCP8v?WpwnWEUmv2S^AJB4q3@PvEAP0l>6X0|9!i&!dh0qu z?iaC+x2WAmFOQ*(XW}dMV(6b5^t~8544o^D8%!E6Il0A7pQjmNWa?zr&B}$2K7tc$ z=z%H3E4Y}^yeCJGi~{Md$gFJlFnq6ewAZaHy+*5A(pB_1Cz-5LkH(!+jj&X3f%^JWY-J!vRsBHrW*}-U@UR3qum9aR_8N%7(GT*S=6hF zW`L(YZ)jS=%9)dIqN4gtvvy|8uoT9Qycx3 z<7n!w3Z-Jz1MU-t(lES@zAv<~KCQ*myZf`rmkfRZcVjr(NnZH?4a+vQd9XStU<<3e ztBrT1=cO##>MY%6(W(M^JTnIGUf8XqnMaK2X}S!Qn7_E95?x0`rCg;Z+3M&+!`OIF zWE*5z+NuQZpBk=E8<3KENnZCu3t>ROn`&{9>R6s%+W?}=7e?$k{fR#@SRS?1DKY{& zhnZ;uuy|1GoqugK4dQ$Z7e@pMAQ_*RoI6DIE$$=N>)u3=-i&e1czx*?cDt3f1^L=* zUZkkQUkP_oOcitv{z^nxleMcmKJ`L_7?2QOr~0aMfWKvqmA2_d$SbkjC8_08uVWg9 z6@_)m(d9AFoIsbl}4u2PCQB?NNBrB1A-YtY>(;kPr0^(c|{ex3+b=%Fj?sU}{r=1)n@ygiJ~#fc4Kf zsT{HjXb7PdWAx+CRPO4y`FunKD>;(p3S`It&f&)@t;!++3KTZ?$o_jyY3<{&qm!L1 zDs`Ha)J+?s)l>Py%sK=aoNUDR!a{scC$<4A09`BK#SIb+ch@*7`ix>nk-%CS(jtsO zIA3HJbPf*DpyL@>hucL+TX*}RfI~qeoJ7!g>2#H_0Zt0;VJI!JW&EBK6S+6hn(Va7CaW$-a3!d9VSC>PbqO7!7!UxIqPJS&n zs1k?_k>vB3#fJ$G*uiIf8-S4htkP5x#3UV^kenQq2p}g{0StnEeqt+5cNd%66;V?n zQj2>M_he;xcgrDNmk#$NRyFl{O*OC%B9oV~E24*^SiOuAlcl0!#l3!qC?s$fgBlJK zI~Fjq!`rgw5t0xln|FrtQg)K=(q_R0a}n0dAN#Kw;*PE3V;z%U5)+fc28 zMXf+a=(SP93-Wt)xV_LGt1P#-?o_>7Psps5D!Ni(ny-9@otM*39{vZ2k6PC?}C`jjl$U%qR$Jeg9awUV(ghs0Dw+wD)&1wZShp+jGU zvon8y-w&}uLJ!ly!_6pbr7RS~O#vWu1nAfYZjG3g%YGv7J9oEMYaVe+T`AT9+5fCko1rXn`c?W($Pgfqmx2;lK zutlsr9kcssz1=e5jdv+McR-*jZJ;9&+xw7^en5*qAubqk81vhI_FYQv-6>9(pE&-r zrXI9*JL41R5}ORsusFK3HYekT0MI4EK_`oJg6%4FfnJU+GuZq)7IcwFu4OtcMK4$K zXx^pd^l8q%@6~>KuTkWH1E&AfJhLLtCdTedMZww=9N6dPx5$f0d-I07;28`Dhb*g&@bNkKj&}Gi`ui5o!K~_HLHpBGlUd42eMkl-Vz!OQ+LS4Z3 zg3g2lk^pj~o7?9ZK>F=dSZ9O=2G9?E4iTKp zsV4?kZT88MF7!k#(rJ~&K!`qvp=D$R!Ml9wn3q?sB`S2e5hW2wfSAo(8~5)&HIp8E z2+O=>vp;M+n|a|{1XXOsP4d42!9QFCFl;b1Z9!VXZ@Xa*^rPEUsLE@{MRv~*{;VZ` z9pqtpFUhZe(X!QL86@&H#|+DWBr^vcVA#drdo;y~&Z{`;X~5|y3}di?sKWzX|Nwr>V_r0TBm3e|C-JdE$)yLM4Wx5>jK zQ859`uDbjM-AOHxS{r+1lA>!R(CIs4QeAaZ;8MX6`;SfpO$(DgiTx1{$)0?9jgIE~ zwu$S_iTe}us}Hmn^Ql7WKzkb2@WBKWa=?9xsR&DKL;*!LL2=;ulIlq6&>`0eYTqS| zecXqBLI@L(FOPVYu62pX==jBGWHh;by82{NB(;Wvh{M(ZzsN)j@`W7&R5moEy%p;I z$OIn>NE)uaaDtaID{464-J$9t2JSS3db3arf6t7Cy*hlEQKka%WSxC<`y>QcfQh9_!zCAh4-ziKL3nwUDCQvws+(v!SjS@*GV0t*Ci1?%^ zu>E}r@+?z3QLHT&R54dDY~(j=FZ{ep%v2ZCWlP&y{I@sxaw>ypreB$X9t0TiC0$Um z3UCQLwV>i`d!!_ILQ+wBl}9T?RMs5K#S+84p}HmP|-0YERuH z*48nyUF;U!*^)TcI`k>3MHpUot7s&jkd2w^;Z-8bgDxk?i#ej#NKaKj2RISIRZ==s zKZOjx<-cdUvV&sI-;J1ehj6wO2lb*d;3K$5$l8lGb79|RxA!tM;~+SBHblr~9o&gf zN_WTK=R8^NO}x~Gf8RDZ*w*_LXn2>&>P4BMq4v&&tt~W8Hz!6gt7EuW!a8MJhK3#n z2h0ay(BkaYu8m#XCrUp|)uNQqu}-qN%xohUM!qHF*NGbVNq}rLlQzpSap7Z4k1E*Q zF!PU@D!6B;=PD`-81?doc~D}OuOgMZvmsFjLE2-JC5+Y^YSBWg#f(-aj+qLyi&&W~ zqAH?^byXL)-Z7x+Cc-n%F8pcBo)(&SR{TRdP53n|KXJJXZw=4cQ7Q zS2bsqzSp;(PERjAm+N;M7};)RH7Z+iNprIN<-!-;T9>rgADy@{$2}ez%5~N{15Gb} zYw~B=N1;rRWnMRcBg)_$#=1Le^ye^vUSY>9pR|7Lk%u@+tlS=uxO87F{_$MU!lW5#+AcJBUj~(yE6Eo-2NvG~5t>G` z5XHK==*Wk(9YzX=t(xxHF4XK{^z<3@(9v3YdGggDO0$J@+a||HPM)FRy+;TdGgkAM z{#kq0s4Y*`Nz=I~m5gDi(*sEvIM+3}7TR1alu^?4dQ@dK<;inszyLS@ieosAo#_F@ zypuR4?iD?(vj8NDwFm)HhTP|enfK4E%(C0ASI$t6O&D?fg0Vg91i=e>3#gto?l`=N z4YDv`E_II0q*SlXfk2_>+)Ly##`n&-mP6J#ywWC0dnwT5rWWLhTH-EUe7CY<;bnZn z3b*sK=VaZG#W!Z9Ti9XOKQYD<$b`$%QjwgS+G=8R%bj^RcCIZ7H@=tcDy~`3vX6Db$4z_>-ZZxLsiq3x=q!YZa8*xcr->YEIiX= zxj`0L$L8d1t0-APLEeEgUfG4cS;?Mps&OU79Cy*0HvaWt!X;dZ7|E#aio`ds=OtQ^ zUR2&YYFRj7y~7y)nK4DOds%SNsGe?->s~@1u+o(Da1&c95@rnH7CSpx#>TOEE`r4bt0{&WRxAw3pE2->~ zhUp7t0|aB2#p8<71s(dbOve?)5o0_uBphp@HyGgsS4w}tNCdzS72zlO;(~hR#O>1u z5d6tBK2(09bS{Ip5bvjnIB*=al>r6qXY_{!_my-@+ZU}825~yuc%*pn4`Lw%MBt?W zzk@~u9M%^l`?ikG;;D(w;VERY%IbWQ)J?oq`e>RIG+C#PARS31;D;tTljkOpin)jY z{7tfCf$2~hbxN-xu<-y#Kov`IpaEr-uA{*CE5AwIa%ge6aEv=OwEyz1>i%UjzAl|e z3u~C_ia<+lb^V~3_vbF^rwU!@9xPWd7^gH;f?;l9o3LeUJ zN8yJhnI`!6Z_)>>PFE35V=OU?u}d7Gc~EItZ|cY`=3L=O`K0}D#^e&Fs)$$Y(AMc% z-T}3pd}21GWB-LUxoDls-l~+qC06sc%;VDP6)r4PELs-rlF|R(w+$~&?TBzGYMq}O zesQB3Y6!Xx!2Lv-k)Y#e4#ZksWDAeyV{S_^Gl0*4E*?Dhs>abOUc_v@{8&`*hf0bS zp0+IsKWyl6nk)_Kpr@e&fIMdwslsYQV&-_~kr|akc&->+fz+{)QHm%u(_xo$dM0Q& zF9Chc)(lEPZWIOXU~{rpWA%MT(TbN~M2ZwqejM;@Z z^@4+>pCiZa+7pL2wr6U;4rvUYJR{DWoqfq(6~TL~O>dS%Wv->bWC)*UmURk?_58R`GN-VjQZ^m5>o(n(`YDN*Kl zBJsEDk-oBkSHIsJN)!=K1Zj`okF_KG)ez0U9ccb-K)~*N9l+w-fZrYz(c;^27T+$2Xz}ep; z*+0xvdPRSk$+r%m|CgD}Tl-z>aZH$nCK`pi^4;?=6NVG&T24Z94Bjj+c*n0U6?4~G z(}TaB>wm(fh=kvhF+}q}O+|W7|1yJahZ<@A< z@Rj)OyznspxG!H#>c1!R^+@T;^Z)#W{`S7;-K>fsew$3EhQ4+k8}~QQ2)=-SGne1L z1JcFucWe22{Zx8Yg#2&Ms4N`+k8}Cma*2Pk7s#Fc^&y%4-&yY8-52_%s_MBr ztsXu3kR8Tz_$PZY`@?kqWG`R8-G6yR|K4=zdRbL5Hox18^*`Io-x=@MCFU=a`S-@V zGv!fL_#eh=^N*AH>KUcy{j>3YUFZILGJp8c|L?}Tb8A9l*tairS?oU=jQQUg@7JaF zFLU{ArT;fyq@5~_Rr`K7-kpm7WW45o81J7f=Ie6*m%03V<8?~8Srz&Fec565&kyPE z%=fF$`O9Sfz4>u)7L$~ zUncYK4cLJ6*zxxj@9{scz7~HN@Sj%Sulta{%;n!3uz^a!ANz)XUVSb8&V0Xah5j;? ze{a5hr($@&Zyd^Y{PXH-@rU{T$yW4w=pVSA_7m*8@| zQ${`4{hIOjxNhu`BY(4pA^vW;mbR9EzAt~bbNG7f|J8kIQSs8U&_0n`Zv=-T;-)d+Gm`R(?{z~|Ddh5DqT+IRQi!E zYL+rP?{4Llg%Y)oG1;%e8pBPrum+1r-@UZZKGozrH}Q ztjFs&_dX1LZt@~?-~FSn+y#&dnW2(tO5@J#IN72+qwkoSM%3h4L!@ z(rvBf&w>u%jt)HyHT$sbhVxFB=TDKu8rNyVy9Pg*S^4e>2nD=9}yGQciYDd$)_LS9)>?UUb5`yM&EPHx~d4( zJLZ@)HKi+I`PRqj%a{Ma8Cttb%PebdvPxM`&mZKV9UH`76$tYudRBKwVbc|)8~nK zoiBT7g-@;bjmKT8dj2>$7qy4+gV)1|t*5Oq+3xitmhMJ32(x9A=y5^M&9Fim~F8R{gHHLx83!-azvbY1}{qc z{*r<{I(9JuO`C7{tlkpoQzAzuKWgoX!dZ-$k8bz#`I)VCYw*PN9Uhq3@e%D!i$b)V zT3>%jG`(|um9A~PYJT_Y)8ekcAC*=F9K2_xU*}J9x#W`Um(Ukr+=E4-s(bF3w=;H@ z`l>UV;wtp)t2OQ)^xFN#a?@ESwNU%>KWvtZKGs;h^=5gyt-IvLL)#APoS%BL<#Ky{ z+cX}N-?lkEYaq)#iQO_0^~xk5p)D;TY~pzNp&(5HCF#kw6Jo}-gL~wD*p@@sRN_A? z@`l|n7Q;7AF>jSbJpHNjh0qpbP|$KAI%SS>Awl@$&dXoztZMSfqJ^i~pn$dDncv|X zE1pMW&2fGiKAvXJ{WUUVk}>$)vB`>ZOtoF@M19t)s~%TmqoO7+{_3EGQg@5^7?9#{ z!8}kQDYez}Q`yncbxvw*%}1on;*tGT4>{NaIJK(OR=c3&F8(rSrv7y8>bpNb&6kN$ znnfSC9h=o#6Z7u#++&!fm=qn0Igzc;T8H9{<<76V;VKibitEdIYsyJGFgo{n*GF*7oqD7drm z@G9$qI?Kh4Ibpr&PWB|8`DvLUjrwJ&%qOYL^YKqd$tfv8KSwD&Y+3KLaiia|ACp{V z()5GgY9-pT9~-4U^3s~!YaeH}$Gk4|iTu3IQ0Kd)ggT9PB$I2SLz_BfGwq+&(R zJvSwt&5yU6D>*NCQjFP>PdpZ57JXM=f7?#~<8#dKzIOXz*#f%5(m5?551j}0$z0yN zbn_Mk?Zyl01|bRNhgG<`4<7q0pXHr%a^L=lRd0{)dNrOZrz&^${P)aXx9=QEFtIdf zaJjN_*O>|1&9BdRw7)Vs)gN@mB2?o=wJiDLqV9d030*HW8x|dtN0S~8#(CV@y*7+^ z@qFCUz@{Z1U-=Jp#i(35`V#%t=G>~6i59t3=fqi-3l>pxO3vPI(p>9tGv1h4cKg7F z+y3izk~dr~3)Wae5pMhW$o71PA5VIHJ~qF}ZhrQe5k|$){WP*|NijCYg#4Y;npk2X!Y&RihJI^I&SvU!7uBc9}D>UY(FQ$qWn9E06P@7-bjLPk9 z$h$n+7PapC28|~4iX(+1`x9*YR6ZPLVa+LJM~S){Jlq#!;)>?$eZOku_SdWSy|sLm zSh>aXL%!y@`^l$%N>p6zx5DX4dE~7hS}ptpgrJh}`J5NIqX7{YHx&p@Us*D3{1kVs z>8k3_pcDaJmZQhLsAH>n@R~+(HExqVyw@)5M4L?vdx|>^1 zisJI8>9jd74^$Wm8SH zf6c-fkL6vRr@Ue^SRqFPF5V3n$=@GJFB8S^!ZyACWdYX@xb{vA_L6ce^_K>jO(o3Q z+@nFb)&J3oIli4T+?K=(IL4lo<-9#)`(=3b0n3pMa;F|J%tkgEw%_55Z0)r2>1q@EPge_?HFjJRc^>|CW!{^ntLLqMX6mI+qkfsJxc8Fx+2QBv z)2}x^c8ptdqzBvc0aMU;mvPlf-(&a~tyw7$V_I!_(TlDMt-~pVD>qu_*=*=gx<8w@?sM0`3*+rvleJiF(iG*Q=9>cPR z^%pQ<-77*GF^?Ms4xdwZR{OilU>rgvPHXI%`d0+g2AXCIOVMUUqw@64Sh}!pUAbJk z`TKPdDze@mJztlb6zC}ny)kRndC9s(6&y5pc+?~;Kb?l{;mav7KHkObPS5#_KDWVh z4ffFs)sO6TPbA_Pje)4=13Qn{I6HnaRhPM=6QjTN!^@aECh_Q@0{2b&N5{UCllhR5 ze#b}VJ*J+oKFA>9dygIf_X6x#GtrBY;<&SUTI)6DOe zdKOz833xdfN!T z1#^?F)K{!E=k%vdMKcC#f9bOsyf&d7%ym4yHuawQa{0$ixIvPsfd~jT;U?y^$ySqsB`W%6cMZEi2yp>m3tRj*jgA%~=9*=BUWq9Rht zsfei@O0i5{>8vd#aw?TW4wa$J_WV71y+7~o=Y9EI-oMM`^L_vE`>e~QSle^Y=X1~J zRiuWZL>0ID`PKO`;Uqe zP7)L;73MSs&hu)p@sF_&TKfyt{( z5AIps(TTa+XZX|1s37o{d#xO5#Ae5O+ZV^YISLr6n|ZQ@+ujFq_gH8jmgN?vB_&CI zW?5kmVO4FC;p;swJfA%Gc8EXEar`_QqENPfUKk|VF5im{Y+5@XVC!d1g)`tzDuyjS zy7uVpCodT9D`=kf@m{{L?Xz=iQ{}s+8+}txp1F74#Vs6~_p{zyx!Er+z!MenU2#=? z_0T4Zu}zH2p1D3l^HH0&V0SaDO(pj$9Cb5RuG{lbV_)S}uhA;+?1qyuTIj@a+cJVG z_5DuyS;IFS;qkE%JNy+b4#*d*`s8Uf?==)&dDv~kLC=VBM9%}))zb=z>QJDXdUK%H zkH=rvH@U1)IDG-ylybz)^}FqE7qM@@ zOLpy{>;|bk%SirLytM|Q0X@9PnOYm~=O072N)Gk8&g!kD|GUY89Q8HtqZ^zy&xVpb4odIdKV6;r+3zcC>B~sOkJ-H> ztDxgH^U$_J!RU{4dBbAIMT?@HxAv>PRkBlFQ*iR-(ZAMr`%)zR5u=Forj#GHUGlWlEQ2(BO{r-?Q)xakL4OYtMNDKDVsJo^eZa$rJ8NxwB69B0&K^uf`61%<5;Lzj2Yq}laX>76!nda(~ngHmtq zV9Ls_8ZoNBhYY?VsdzrzXYQPo)R`v%sfmL4>Q|1Rl<0eWLI@*%QZHOC?Azgz?6&-R zs81gX_E>-aqV>J&as^fI&BOLA{e?O9RJC%n>7weEW`6!_TwMKW&*cX@vn9fBpf)~f zM+9$jC};Y-S2LRF$}f*hKjSI;xF7M|DMT%)Xm`Z>!+)Gs6w#je=RQvSL*i`Wdk3mM z&ZKIdzU884BFS7~4u8zGz(%JaUiGv0Hm}RI&Ybk4k0&v~Cg(n$OEa5_QQzj zXYA|TBC*hdtu8uzJm*4OPVaO1g=zg4%;Q#vlO{ehnlGPr9X>0$LH_cdjLj1H_q2Z% z!|dw1@Jb{2I9az-{R-b5Pu=FGT^`caCz@$m{9L9VxB7L>*kQ9x&x>L=|4Ucoi-=LP z@BgezuFO7=%hoHBB41jr^nrPI6|}5Y(z<-E%>vDq^xn=U) z+#mV%UF*9JXWOKBH_I#Ujgw7$#`IBG8U5hh;`7QuE?#3Cb9|I;H|F&Ebao@*{A~3} zd&A+MjERZQgcFb?s(uTDRtwZq?TCm)%t(A;vEpZVyCuH3~NbK_Di$nBeKj1OFLksp0u za=EXSzwgEmtIfwTtb!JXec-3NxngbUBaKR!knG!*L$`gIahGr0UY~I%+hW_hv+TU> z3Vuy%mCzfPZ_IvrbuH_q-r9C=p3!$D%J)m+cjsSJoc*5n*iXipE{{r+9$kQqhD(jE zgs+MU4O$#jsEn99h*)CyS->8Tj%X&(FaKBR?c$D2noUKYdyD2htmb`Yf-Sv&X5CfsI(bheEcsUS;rDMO1A=HJ zms5joF0TH3s|)cld4t2owH9-a@~vOShQ7_2?D(k?H^)vpzb4ImyCU*Id85TinjOCN z-X7stYizi}iOKeUr-mJoZ+G=(Bul(#ka+P$7vYB6eCtWhlXm&!R0WaGO<(1dZT@Ln z9d4D{d5yLZS3NWg{Ig}Nw(SG`u(o66+}d83*SDK82QFog7yi&UJGWv;dA)pLd2gH3 zlG=+fO6=g)P`ly}+ce%j(mA*IHY7eu&r)tU;Ml7?x*!IKyF2r>$EDW3Klw!Z;2Dp{ z?{TZFfPN0>qXusrH}hiN&lvi!kMti)9D&)SOl z*RhVHUAO!?d_xy(wFLVjX3ib_+Nf-z$HR0yxIWaUmtXmG%kT+1X6F0x8~Z+g_J~E` zOcc7xrpD}cpZj>@)A>P3i+z$Y8xUo)!(|_&YGV~vy?u9;W>$7of7`3Wgu*jdpYMym zBNzHkIssRl9yfF~G3dQC!KC>^&7lwD?aA-k_Fe9@%5{Aowshxf*2v2AsO3-dlp6WB z7Z4N7b02ks<~l!0{rsrB_2a(E0T;q}ROxt=52Ag~$%B9Xl#0Akk#S{o_Y+#zXBS&# z$Nb(Wz1Om@F@BcbJiK`6kkyvJcgOPexKiE&qc%=>i3cB1am z6I)Aa^`>yugJbls1?v)C<|b-et6n^sdhvDbkeL2u4r+3!C*KYIRI z%w^JOcZ``feku5R%F77*v6QX*@tFI=Nfwu_-<`jL{xj%F?4p_n`Iy_R#)`RdqG!+B z&&2|_;mc>r-q@Zgic+uncJ$tA=a>05EA~gWhF99;yy%i{kCH#)AE)hkFG5TLJ{ z9fTEMpDlPdb#M0mk%ysp8ru5*&j?}`Ja*4oiSmL6 z_S*~n1fRbQvd7hO^&<9}*k=C`djmbGWWp~fwb$l zfa(8Kaa~*%-rKoLS$4DY73}Hn7a^?68-)>>KaFk zkBj}S3EP4)|F1WNf}hbqj0Lny!t#^VoyPucNj3gO_N?nm**foAHT0tl=Bsx|%N zjX+#R{D+Lp3uOv62i~4cj7|Kn&IN{&(v!B!=pRKyQh|Gw&=PX*lfo3C9a!R!*jc7t#vYaEc&;(nk4hT=xHZoPw|V zw^fmU)~&W!0CCoT7ij)f^zuJE<=_ndQ-SjT^C|zYirRm8%72?NytKbv4f<@h+>*s8 zATqK5&OuiBJax>ep&t+9l~}&M{oO{{Zk<{tX0}A69?lvWRu)e}*`Ouj(>c&{(IR%q z6NDEsMW8Q``^3zt545i9ZfDKBQ659)3F@_$#O7p3_+6w02Q7SnJ?W|_@C91gzE&}_ zz7^Lyw%If@oZGlj)+Gb9-@?%})b+h$nX*6Mp39Xgd&xj<1kD70KYmD-MN_1ETtj{U z>Mn2@w}FpgT!7U7&u#(+;N}0=%j%GhUH}bB(Yio_t!EuCd?<(-8Hpk}YB^z%+f;O) z@;tw*KsfSBMrwC3YKKw;1+VbsiH0^m8HcK-*?k^cb0|pPJ2NpsW*agUbtv^WxQIg2 zM3@gd{{r|UYvR#wS=v2rA7!2(P`TZsD>z9Y==T0V1@iQTbww^cQNuk0Mdl*qkLv`1)j!jBEO7_~8ov_m%P|pqk9|;)>MHNY)nQGm4H_EaZ&S@zp-l-VwF!_bR zo9K5mTvLkpfK%Gw_QWGH;}r1pd8e`$>!`I7qG=1unb8LH@Ime))S#2o7qqV0!4ML9^Q(G&a}#D=F0SH9e+?x%u2dqc|bq}{&79=Z=TL<-9`-S9Y~JD)z&1j zPOQ^<6rx5=FThhK9Py?`LzBP0A{O$erpNY1Hw}@vP2W$FuXC3gMh-{4#$Syrjeql5 zM4S<|5u8T2J@u_Zo^Jp2a((L@)UddOhh4ojHK4{3UmY?AAn#nKB_5z`t6f=Z7NfRg zgGit66fl>j#7hBpx38pp~Gci^6(cQ3Leg)c*bm-RXt4 zC4n6a!i_z$6$=4ebtsG_YHtl-jX?4u(3vV^lG}AfY3xN7fN2kc-WnlE+2_bSZ4pDX#2NA8{a9#F(EJ@*p^-PokBIXHq?)DZU&bT|>cK&GLYJ1)=k6Lb?>GU? zkZk#)Mb02@&`b0~n$igr*Wq2bUk9_;yh~#czYkjSA}vny$0|GJRsxpww?kxTnhe~R zXVh`PQO5J-wj#S2mxl1$@)%`7kj?Z#!CUjowrje}Q!t;&^Izt0%#>P)=rRfPRhRO0F{ zccn92^>+Il+mN87^!a|fd-oUM2WRysUd`=&gK1`VHuOv4z8Z>h0ok35d=u_Gu34}n zf_UF9{*P7vPSt1qPo01T8fc{c&)EOBxcC1u+*vz~9jE8#LMZ!6JUUJ6AWhOK>=Y&5_Y+fkeKeMqb7_K zC~6^r(Ji&#SZe}(-TEwG9{@iEYEQCf!<(&XSbFoCK#i|nyS~+sD@M{?^3EIWIQ5$m z0!DP_zQy^R=A1`Q-cs*bEt8}@`<6Jd*Onrspm5H29ONi%hZhV)&_W`zvV6II55NR1W zAG`#xRGL^gHFTsj=S2EIc;}+{*B!N=5f6Wz+NRMg2eq(7y-wWeP(|h^e0}JJ&x$Po zJSst6oXYy$9+E(YSUpQUEGTZFH7i8vgeKGgiGWL2TLYk<{pxTMkw0@qb0t#4x4<+@ znEc&KI8(-grbkMoc(16s^^3rpo*T+a*NTO5yD^JbGIeLWF-u@vAhV!=B~~3@2l}x# z<(s|(cdkAoMC_Jx0*ZTAGUd6F%oGZu$#e3Rq0m54ykNL30oGZZ9m@FtF02>N&qCxkt+3y zTgH687?6lW2bi3&#v=M+0rCcD@hieeH(W5%JTi2R8|wYTP90MyA@>_+1MKI+20hP4 ze=|hd9wCQf}O6iL&em%_h{SR50P`YgWCz8TIre8MK)mlhn=_s~F$i{nW@lYvXh6Pen&REbfs#S{THz z&$fr#e+g8{v=83v@+f1oT(0-g*o5cWvwJUaJQ+3;&R?}lu020|>%wPypWjbMqCSC% z)1jjqzH0w8k&V>ckhm`vjJB(TRW-ZU$suO<$WpR49Nq9y-{8hG_<;HOpR1LA*y&^x zn9y^gKAL4u^ml*DRd8Q@y&JxkCwBgt>$;g_m+FxPx)Z7BaV= zrXQrufI|t=MiEkORcRqMXVi>dUuWwxwkL2JKrtEak|{{MAC?*IF-T@?Q(bE$GhmCp z<={VH-lyCNEl`hKCi3pw`Uv2GpzhpZ zHDfMPpX;4l8qK85UzgjtnDb39Ca|z8oe|eYh5+e)$a=a`K%EgTM{*SJN6J?S>1kMq zw;5HRY9^c$%Vv%s^_@ z6D|$H&F2PIZ0{Yx99=9cV(Q$~0US0W2CJkPAnIhuZ6EtG(msG}QGOUAL4XsBF=o5~a zJ*W{zx4f4D#SX4nF)&kuF}o{GVP{HVwZ~j!8e7g!RmwvP%7{(j7xMyEcwwT?f>vD3 z&`)57$EB~q=E+S7cHtfL$O3J0D37x^Pn{<7dB$-+PIXJoObn7C{&HxqTqnQ5nGJ($sDWW((m-y~MIL;mbTuhB-YOQa0M&15BM2dg zTV&e|Rq{pY!_2X(L7nvDoTg64OmaO%bgW+}P+Kewug~Ox{yoq$cz>j7>ok+M_z;4+ zj`2yGfcNi+xT-UfTxSkOWuAD#%+-*|nGPc#gO>R4&%M>SU9GGWOfs%fjmJ$tHb*{z z6M=Dy6J|JLn$%`$atyS7he1T6sg3JB=?vckEWXf_WZFO>dmtUpcw1>gP>f0a8tj?& zTECub0rWj^?e%YlaCNlLWO3*J%~G8;N?bWd^6R98t`I;0tb$@ zb^tlA?qV)`S32Imy|Ly0Bjp9^zketax7b+Q{L8fGU)ve}hbiy>7Sz}3?_>B6r#)bm zVO$}8+~O&_lY`2AFVzstmd=P|EOcvU+$F3gGM=rzuUBj@_lI;cWBuy;qg1b$O-HEm zbX82uT6>9g&hvI`#SW|Z&cG5`MnD|MlrNx;qm*|pBGJVaI%d77n;lz8Fl2N{c?|ld z$?ZLWUKA+nnz>YSQZcb`!=07d;)pG&{ z;L*5AQW~y>rdyjPHx!54bBvVSQXb>P^wJfq7*7kq#g6aZZpuh_Z7=ggJ8u#&66;dd z75q{KxwGS|?qE#j**fwxQqE79D93Or|$J zggWh#h2*9Ll{v4mbXE%_BJ(SG;jK`J+(D??4}c3QAzxhmLrCnHnz_)#7YH~*WHBTK zk)|u_Or;)zyF}^pLLJGJ9OglVL_+3ochT6^R*vrpCZLiJ7w`ya?#X>Ul_@;&Y@2yf zcAl_|$r1DowL;zXlVkw^$rQZXgRug9+Y}S=yZc1)jOTzBhmKf7OoMMjS_e{pM_`{R zZWF%d$P`=)d95P*5T*O8j)ywviD#V|gd6ES(Ng;!j1JVlVP%I!Q%`R3=eEIUu1S}u zSXWu9_oA{R>b3Jt3?&9tsHB7(mx;LP7>FoSIQ0~vbI1bYdch(1Y%s*IrnG0Uve^l!rBOR5h!f@Y~(XF+CVWy7vIDFr)bUWa(T~+p~m93%5 zqwi{G`Z9jwN3>n~k$$nzNpt8X^*pP4{ET;eUVZf$j4XeFX@TF_!<&aosGt#2lMQys1w^Wv^dZy{~|w1swFe~l=* zrk6v02k?;8nHYo9nW9RO`lo>fUg|8eF}8jV(-Uin!|Z5 zFo!s-jnjQ5*+I~_dm2lmZ_pMp;CtPxG7~#P9t@o3#Tlf9g;ueBInEh3ohMMl9p*xh zhfT?l3~ggu6P~70$w^Y42i~Vm%aueEndVA`4jOc`?1^#81^gTz_J0bA(%t0)r{_VmljVpo*b#z4QELXG~4h zhj%sw$(}an%nFk4yZ6TyV=K#={O=^?H#WUKGz@&bo z6B#%sGS2Veij4`8tly7{$f%Doew;ybU{3RyyAs;s$ncP)rB^+<;n4KkT-${i_k#jk zQfH;Sxz83G}IEF>>Si|Ufv@&q_9 zQmE)VgnYQjWJ0Vl7PMk^(;UF(3wwcWF^KKU?rO;+9I_Yg11<4Bncp;@5nWls?G*0X~M>*{HC!?7BE8*>7zseU`pjXsFDnw*J%>WaC|vQ?N$YWlOe!#*mRb~ zH=J4%3$Pj`QyCIq>O|Zk$EWAVUMj6s#47q1(M0PjdJdh;qagHU0HLyZ&Dn;Gt~whA ziYhyK`zY*jf3$CNGvd~_y;EHnc#NB2Lk5ja#Gg4FWt4`whS>^|&B||iRd~r)6X;?X z06qYh-Obk}FS#13*=1)}(mf=~4letPNZu4KHlHd}@IcZ>bj|5W5}u>~zq|Gob3 zuZsNtVIcnBg40?3eGLC$AWoDwKpRQ8IjU`U{_1$>n%4<7quCD6cqZSX*Eo&@1|vt| z_qx|)gaF5r4vt*lTKYlI?~jT?G=Na+Q(se~i3cO}7w7qrKO|7|N`Q8Y=W_A!jbd;U zp+G)ygppL5RHyELQ5``g5G6_UDb+fuWKX+EkHwPxXa=hDIGsIPU(@nQlvL1)d7C#G zGGQJD8wjuC=hn0x@kkMjHCH$>E(qF;2Wu8iJ1{HD1}ije+6z7{Rn{w?Va<7}6D4)K z33=~f*{Cky%Tv{U31PF*7}C@J;DX)X@0%eZ>2%;?5~aaSahl3HB8G=3&c1z6ezm#w zSGob8K7h%*!{0f0+b*dD<1ouofmm9Ko!h`DThK?Hu32dL()oudj0{Z@rg@XG3nR0) z%@-T5y?q!^DS(Kg)RB+vg&5XCJF64iI_8yilVsd)%mrHz=G2O-6ua1Gks%!X^FkBJ zgwGN8+Cn1&F^g!HUpr%_=?jU{!X}Z_xk;x|(dJzK0VZ@8HN&hFFi#L{E(DPACP${{ znp&Zg1r@3bSJp37Sh#x7vLp330Q));k#@G3)6}k6l}W7Va`Gg^7=aWDcQR$t4bXM? zfg8|RuD=~ULf$p@Y6;-M+59DN&Y&wH7=}7`)?SFu03%=x!sT+=t}`_B9vo zFf-{>_dv!t*o^JrG;x-^syKX-X(2E>6UAP>6-9M@^?H;M!K8RC3QN*Xn^(403}B|y3tigG6~mSzOT6Yp#=GhQ z+e{7HzI4Qks;hx#eX}}lniIx~6NQWnOfN6Aidp^S<;m2l*5K%&O`PzyHVBeh027wM z3oUi)abtkjw3Ek~u5Vi}?#_)=1O_K+q!R=O!47v|Fa<#zQBq^;YX?tL0jH1#h zdeXg|xXK=$!J9KIad%$wbbD=Cof)I1=An!c@H!M#c&Bi9bL(Z*0y)XO{>TK3#7*WR zn>J&DYr@L1WzMwGE*h4|;#VV#+}Yxfb&WT)@USP2dnJLp#z2iGpxeE(nXI8VbZv|4 zL5xASw@4~VQIx?r z6Ote$#EI$b( zoRf7nYlx|V=gcys16K^bsHgLZCiC}Oca0F@OO9%}HlAA-bEK8SY1`C0Ed%4PrIz`o z;%Z3IJ5?I955U)7NoP*+1#K=nt_oCZi5LlZT6?=SXSyJp*?YoM3#-)@euLAwizUOX z>=R&GNyezRG+hgmV)!pjr3^*7^I<}hSH-1kVWwxQaX%BbOR|9-Eb84_6z_nVAg|Y? z@#5Ul#Gt%ZJUypbV4F-hvT$(t*81=LQ)44ZrJ@owEKhMkkL-D*uM zWb*ynw4^{4L?GIfNsA+etq%zpX@QzV)+1-?Y(->GJ?RhWRaAj$qt!aUAs}9$LnbD@DBaLOushi|64}paoSi1qu+C zCgx3U3L6LtjfMoc_sFDds>r4#q;ewtsfY)>)M~tZTX8Bi^>waceGp4H=)axqji#hc zD53Pd;9A~+L($Qsft5YA@a*aeemF7lMk&d%+M ziB(Q1AVjIV^q=X|jGVtbX}N3?SymK`mzN`$$xBE&7spg?_Q$#p9j0O2e}0~dMTs-mNjbya_N7j)xdt^zoYrTIyw9gqxt_9W9A>n@E=C= zqf)M`FsHtB;xmd641Y5%w+_XO(YqdNUm`j{Rj2leh4YZCiV>UfGX6S@yHDy4SXGKn zkhy^{=*}(nZD7~j1Y zvmy?e6SLw=LFiEkG|kBINn;L9c6(t{b6xuH(fN8gv8i01300iKE!+yYBkHUekP$Tl z`<|A%gn;QeZ6}Bm|3*#}{tyS!?FS8y$;SkIh~wWW=T#{P0gS~Na+AR2Qdcrhe5p

M0$9|u`BI3hUo%KvF*qx*g}my*$n_8P?X%?P7J&hk`9gkp zYo*A83Xre`d@)7LndHQUa2gAnSS*eR`hi;5K{E0BnKv1Aq$@0zwN!%}UK8NS;q;pG zj)Kb$!Xl zM`&w;Bc9kTgJ@341h{pqclY=12;zdDmG==;DqD&^MZ`-gNk+r_gyV|M<$?>U; z1%qN_quq*LLTDP!QhZ6i@$%FCq;!(w`%;7|2I6@^%elJhk@EC359MXN-B??6rXV!V zPF->O`mvEVmdHG8+3!~eAi--csIG5hfk7IADmgfaF8W=EVJ)CQ4Zo*T?kN^js{2erZjM z-7*I~8*k+6s~HAR}?&Q_@ULa0*yv?m>IgizS?}5UEp6oepESR@Ri&9ZzG3vb z#dcqr(X!0NLb2L}Rz;i0MKw!psU-w_=?vnhJ7bxLPkgN(yL#1iU7;v$mea7@@1rrc znl!du3l}C;UjPbuf;3#%#_1H`#cT34D#kix1N7|Zs>26^ji{84Q0dL3>MNR^!hfV6*EfN%_R%@!hLu zHvC)so0auHHC~psz?|m4BlCZt@%rDgnEuBx{D+Y_)iQr{AjUdRLRtc);+tiRV7#-_ zK-Hw`v27G$EWy2CYy(5c?zdRg@!k86BBe+PLDVL+hF(jx7i(ncdtp;0e-bt5LG=@g zx8F(|zMxZq*>)Q1zM$P&_sdvh>w$X9V$E}=_bc=1K+EJizE&X|Szc^;*wyv?{-H7+ zjyIuo;MUR)(9Ln#4AV8P_Ho&`({s{veH)70%lFH?K9Z2Soi*{4glR62Y2Ide-^6mp zcfVcaH5iBYkyU-f?u1eUK#fU`@aUY$Bv#m$PQ|ck@ih`u-x}wc^+paNi#Xw}Oen4z zNXoJuNhI@z5m2>TA~}Ri2GN&vf#l4qlDXKOiwAcLRE=YLEwl)sZaWD0W4~*^_S$JO z2Hh-nRm2Hc!U0)MUt_kp?47_u@Y>4ey6?M+Ju9e3cmdF}owegk{ee)t6i8^l!%+ig z7MP-~GRK(Fcd)&I1z3QBy?>~BAZ;SLnj(#CV5by$DqtRF=OQcA!MZeN%nuJMp$#a- zxb4viEF7pRF4;x1Ty+HT3RK-Lw*~6AMfW*@j~tgR3$#ZbHMuBxx?0K_f*1}N z3EhY2v#uyj9Lih%PPc`E^L!Kqv3wck1w6-XRu}w6DP@ecF%EQZXjC^U0@bMQL#y8* zw{1smlbNw%j|C(h6ay_`aRpZnnick1jVr=hP(#bx40Pw0Q?d!UZ$X~4WV{;h#&rAYJvE0H=#{>C;>2J8jO-6% z1|!`(8>fd7pYC|}SCq!8ef)Q3H5F?QhcU_-4@%&+NA1gwH)MU3AMM$Nmsl^k3%T3b zZPnuls(vtP^x6B(aEnymjNKaRU=r}dA5SVfzv_U=(B7%Qs8Zgj`64}Fk*^m`OH`~o z3U@fP-E2Sd1nS^_?Symp=%QD5umSZ4%sJaJzt}iZ3g)`*cp(6K!?zj9RNV(y5;>oa z-Hqz*%3SytbyvUZ3WNK$Ba`ByhDcgeuv8$ob4vBxwy43M@_(Jv>a^38Kch? zb{aHWEbfXp13T$@yg5o8hP2=M4;hLi`v|ZISKpu~4^SX>SJxUOrd-{;!QED~Jo)3> z2NQ$%k_{MX46LIB@nsML`-TpC*sN~G@Sz-2^wGFOu(fRbiLDsi-Z)$kvyx80UnMS3 z`DI)wZzPwE*c3IwwzazPw(-kiPBZdtR)y8k8hSjuhj>K?CG49pzJ{IblycmY!cxR? z({T7J#}qWak`^b8dPTPU81%JxHaRMY)2!?}Ia>cuq znUG9+y89&gshCA$HI|krPZAXbExbwV_C--Tu!tQHUuVuhdAbl;1%g6n^C1GmHK;Yp!PAtVy@#cWwo6Qz=E5YZ4* zEWoF;*0oKI0OrPbIVcmFWkIYj5;kgJZy?}Lq!g6`Y_0v|y*7$?E*GN|CCzqWMp8F}Ld zi!O>Hrcm6EA&o$Eu=RP6rb8pp(u%F{kUPjJzUfbb5w!^vvXhs|MAOD*o`^i#)~E_# zyC|WE%qSmI;w?hJWj4GRx@#hi1TMa0aw7|z7JAD7*wSJP{)C(mu^xb`=0xXpx!v`; zP;Dsg#|NiMh$l?v37|Mp<#cs&ax)VLMbD`m8JeyokSDi#kO8WmB|| zT@_m>PmXQo%$Q9rv;!=lrca^hN;;Q+_v*KeuJ3oZ_~N>bwLG1BVprE#gg5N;M&}bI zt4gXveeZB$qR?0T_X6wMBp{cdMj4g(JTWJ(bk05se0uD`P;2q_F1L`dp`Eu~{g?X; z&S2@PrB>`%B%xYIQd0qmxn~`P>IZd*q%Na6Fm_&JhooEj84LbF@tZK&RW^7HWuY68WDJAe%(A1JMuL9+vbv8mB`D=t86 zfZ!96jry#xL+82@9!_85VvnHQg`IjA4c8(`cCJO*P=HywU0pVI6VXa@vAENYyP(j1CF2%dq~1WO+gQP&oV6{C!pZ()Y-e0o8mlA6;BoTEJx9Fn7X)XRH}9B zj54{)U38M}q4EH6>O}$oG2#Y8dA-RZayQZCt*u@*p9i5*Q&B~(&f{v2vKeF2{0vAR~cWg#$Ns=U=H>*>1oqG>b$tS=FnRE21ouyG<%i#9 z?bO;if^n2a^w(*{>7CCF%V+C$2iYipRO|MzMIB}byW=IyLAAjnPh*UpL7}PpVKHz# z+P^2&8`%hOdtq9g7dF`x>y#IqG|KfSK9EOoY^@R+zr3NxBvBUxaGM3j@o66l@$!89 zn{r<(|B^w!0pA(s8^`THA`HTm3t*B-T4P;Qm9eCCzJ7T|$i@RzIb(n2yeW#cr_Xl~ z?9iAiYf&SPR?7IH%LB>Ht)7z&Z{9U5CzT);dcR&9t}PqDF0$jwdQy;a$w%6tk!qZa zsaCO4c_OxKHnUuM=WCrYSf>@u|nYU=INI@`tj!W$=>&qexwzv0pEvq4t)g; zC0?S?>fvkrP$rLA)m$>$W%*Yj@8Al~YUddS@p3tq8}pj3d_VH%Y%`NJ#)$#S_^Xb= zk*8YQh%_z_Hz&H!YvI@Pu$(5=oG58=JMZL)uBQOUkf8gi6YBRi_QJ!IE5@oI8kfrh z>Yj(qZN`gg3l3!Fr@AI+nn3O%L*nIhy(Hjw4T-WWACBI3di(fUBlkqoY%LDzsuYp2 zD_e#g@<3Xq0=2Usl|dXBo$!K|@>AR|ov=UhAYsFoPEB^p5^nO?ck+?|Is=KgB0_RG z+IO@)hpG#f=Ak(r6gN2k`;8*jBZE?w2$~Lo>V7pmoyU#zr{_>L8gMphf5G0;322n#e9oG{I)>WZp zfD0T+o(4aGCI1u9>EdwjoP0O`j{q0dRl}jt=3|5p;4PV$;il5n%^knPJ85`E17odHJ)dQD&MSW23 znftW|SZCUw(`O`n2nsVsob2?jCtFjB2u3BfRh_a$K5S2#b`p0jm&OI?SA_A}E;n@X zuE?s5G-YfiL|O^@nu-rdy*WnvhDvlNn#R@{^N;Wed(ZUuIDj}n>jKQ!A+|#Cfr3Cr zQVH^+%|^#-U?A7T!&F;E02|s9iSmRg18sg;_vn685~pvV-7af@xGhwR){i&rN!aa2 zL0FYw04Ca|K&J7-8<`M1zKrX*dj3ts<;g%c!U%6fwdsJlJ5%8_ZFDw}Kt9d}2w9!% z>@zz68KV#2;QPx!PhgL?F;-GD3eB|)JWRPfS$m)$gr?aa8VUjmUQVW=!%7c8E)b_| zDX>#72&9|%bYA0YG^RQNfOY6d0L;b1EgU5EEi>|^`m=N5@51o4hb&fq0u|i2r{8b)o3 zfwngpR*32!m(xBgX#r|fha_x)_M~E5ql_A;CTWSHJ6nyJV9^2CZ5a(93q#5l1AG%- zhBjmEckX!3xP==qsK^;90Jg$Y5~9A6=jiiR}F5pPm-eX;mr6JN$sO! z9%|DNu2+4JMhYg?fFeUe_I#n38SOY~*lkO(b5dq2y}GOlzq;e{YLwXJW!7~-{7}EV z<_*x1AkJn+fJk?G6%|m7(SFn&qmLs_|G|*fNk*kc=elnEv7YhbsKzM3xaUUc|B_@Y zz6aUZnnRWkROLG)j3wh^^<6f;e@tjb9=Z)SgCbF?;8p;s)Pa!$P~3I0%H9CXs4Urw zcA3%k)~iASN_vsYLTvKq2T~vC3EeR-Dd)Pq_4YqpPcui(#yCIo&OoN?t(=a$tA1U3 zwI+i8Tqy?C-ArBo>~{kJ2bq%lqb3t*_OxVv|t{#de~g7 z_$jQK?7X*t#=O7UImeyV_$zgIgnk0o>N9o)FO5J6E2aPj_tAW$4|kHNSlLVJoldUJ zI{UVHp#(7+iH^hAba!E3Uy><7hfB)(3GtJT4*ii=EMIF(nw+SZFEuAsiD<$h(-B{& z2dZ1(`3m~E1lu7usAa}&?kTh!S-O~JdG8e$f0cu67x=tZ_XQCZVeA#T>TLKlmzy*s zPY#F3IPTO`!6y;9N#rCRx!%HJdO-^tgM`9ky&{-0H@au8vi+J*Aui6B6h4{I%H@ih zZVJ>8I7loS6aTJ~K+qV}_hJ5E8tWAWa{nW}md7HWcv_jJc3qq$%ALR=NbiE6ASA07 zM3`NElbtJS^DH1a>Ni^_oNZ_w;fdSCU>oGgXo!^cv%9@n_vfkJ7KqJ%MHvGL)g9H& z74tC?84|JPAU+6RKn?t>;owTYd5IJR8rpQ(N`t*orYFQ|U@J@WBNIa_28AOa!Gc(z z6#`^IVraNc1b&|zgaC>c{3lBuY{lRY;v5asWt<>LQAA!6f*>b$ahijKAf^hT`*EVS z5sVWwd2Bgu4x0Ps#D{P!i1%Izun$9_y9WH>dU$KKm<9F+>^YO1HPwxo9|2txg+R6m zUbPkEVO@sf>N?Qx2oBBcO>auN$`ctk0hA(vOa}cOvQA`1-g~&yu#3}pDT~`3rR|h{ zZMw3>GsRtHIt%RJLlRj8ay3vp5QWzEHa;Be(**qp{a%1N3Gvy2#kP7rftgpt3Mh{iN-^5VRl$+#Rn)%u zPFbWAB))B)-j#rh`Q3jvHJQupQ^)4A6*!H}oNODlrsTS+=Hi4V0A|XUx9aD5qb4i* zd!nq^3LA_{cJKD~J3t}+j&of`J$Om3AKTlAi!5AZM+?07G#BpT@o&diH(WFt*!34! zfWpAKK!=?c__qiP2)tD#VW^&jUBxjF*70f`J`)Oqt=#}vAyHPEgsTd0YAzT!^f&7v zf$p4S_t2-mssK-8*f5Bw9=r_&FWu#4rF;f+&k=oD6o9WHd#~^J=Y?Ve(9PMFcG+}y z#Hk<~=?vK8cN*8h+!MT|7@O_c)L4tJ>y*8TES3Q4KOi8)7UZOy!Z!q%t@w88^42XF()MF0Wlv5hN;@hHO*H&Cd#s z%h}`du67^o!2Hgc3#1T18i-S=sC|<0NWy5@EgG~C*Qf0m>x!})yCJX0=+0WavwLBM zMCS8FE@{8y6TtOCJ1X}c(BtefyY!^Z;E!CtOK7`*c3J$I?4EOnyI;B<+_DZhb(Fx# zsQnbXZO=vxwqU;@0XRMQH(W*kbms4t!?F$+`Mr{+=<9NPHr`qaG;qD`>DMdIwjw&f zLu?ykqdM_gM9>N(RZg5z-;CZJ_2F$xr%Xk}a84^4-%LqD#zz!mY_YW!I@gN#89o0rUMFMSR-y=sq9Iux)T+D4;!kZ%!-+d@n+kD1GYXf!bdbPA`b($eS1^5-Fo)zH zsRF#Tu%ZP-%%w%%&KYnfrx#g}Xk;?qN@6%##aA!u8= zi#(yf9iGQ}p)=wohWLW&Fm-9>du<0{bZst!GhpU zi=6ghbuV{U#QJ%5m${0TN+qf8f{3>6(d%DXy*Ulkfdh5TCjC`yRn45f$(-O`tLabe zMZEaZM$j4119~AqTG=JZR@lTyw8mOZPZ&}0=z{*Brdn@vc^H6p&PZTruPW4yl)#d6 zb`-j~RbB!uTb8LVg9?yO+$Ys=z;Vx)wEnu=mJtCk4{&&{`rxv`gJoaLYL5;HRM@Jb zO=(+_p%^svVd#uK;?4(ZbW=9Y_o);VrX_BjFz4-&wOpahW9BnKHcZ*7r~UrCy@dWR z3GHLXf6J38fhUZ2AWCVv^==KIbpd452qR=x8Q5#nz1|yK-IW`PZ63L@RdZe%6u4|Q zrV*Q~jB*}kf#Cc47D$IDj208jy{f)szqNND#UKGqm_OOMz3D{7a;`=vw*vI8BjY=y zIdRoYVHnM6S`=NI96lnd5%b!Y+BKoSSkT#?ww0tuqyzw(B5AIFV-Tg}%Dj&Q*mf}D z$EdNDG=Ikph$&iFmh{>8k8g>H28yZqn4*=owUVVFm8EFQOi^2!Ei-Tl4q^y&-49ydRr$#Z8W2c3iO#2HzT1{QF@hKe@G9Lr=>mlB(i#9 z7mFRYl6Cgl$cO{$;chATdmA3WzoUxJJzSh|kVU24_AEAToGDIRKUn_*ugCbx#I!N5 z%Ok-e*aC2wT;m&C!TDoeVjv0ey=F)F68dLW^X$@(KKy@3RVe@I0P&>$x3uoR`_KF@ zSKiQinC(H%8z!xl7Dyb zIG=JQ`Sn;<&+Guzko=YUrEYU7d$&mH&8W*Ak)rR|WeB=T&cR!5I^k3FbNw?YoRL;c z6%`=F&@6`e9!-lnW7t~oz^g#XcR_<*SV1AHVKv^9#;#3e{#F{M;Lyy<8 zc7KvbOtzvKv$W$lG_9Rm+ToWI#h|Z`=#92-a8ijRxn`3}HZ|Zkhb<~W_p-gt0<6(P zcqFWRT2cC*Q`{)Q>QiL!f=e_b?Om)$dBj78`i&KEfV$NG*E{|{rPiJl=;ZWY6!70Y zmj1VId5AIj_vCy~{%=Qtf5qz^hv$D#-=Anroa28m^~bPhi6NIs&mQheHe2M+tVmwx zZ}efsu%ltF0m*}qLk04eF&>?&Cf)m|sqec~=kG|qqYp{G3ZueXHVbVRUt1o1zFP47 z7U6;*7-B=pzQI_J*c>~N{r#5x#D~NTV*IhW+}mFm`-QK(|ApY!yfPZrKZHQumK}1) zqpU-4$N2p1$Co+}hW+LKNalPALN=fc;bP|ZqaMEy?vg~reaDjhZI1Sk=4fedab>o# zo?-kuu`8aD{KnR=22ca?HLA-xb{Wzs zKX;_phxxs=#s2dRhU3(Efam=v_@VowewXB`>}zpH9@k)PqFobtNCZ|_=)W(iM)3waWA_92)s28#r8A@FFW%icJcVRQou#w9%pX;#L6M8 znCS>E^s~JI6dZ$hly5G%diK>o#fBAV2VnbFlzaj8jmHF8bXU5{-N z;ojW?J<1iY$M(4~hDy5=-BCItLo+RvBNQ5OqWyx-3#r?OF33go+)PSgk7jmuzZ`nh zLvf-l`z^rfZj!!FvaBuZs?K$`U{>F%(Pgz|T{x+=k6^KH%Er|qyt_Z*e~Mm%e10d0Dr!co_%O#_=JX8`IqpskQRH4DB*N(pkkjAxC251aRb zwGc;=0m}yXu(E7s0EYQpM*m5tns7YE`qey=lf<@pTcx%~YCuw@_q_Z3ofX*)yp_3|5-pp@l zjn@O(tF3IhpklDn*l-@TNN_Ixy;o8cL#IKJfl!jcXM-q_jhe^XYIf^HQH%`zpl}>% zqiUn;24P((Y(9yczida!G;KO_t#pp*uJ3y-9p_?dy>BX42cCgiPk6fx9=w=-!?Q-i zudNggX6P+64ax+`gD*<* z0qpc#Mh)RWJ9;t~qmAybu2$}?>elX{e%n((tM3X?uBVZUO>F`zWYCS3)$*kxE-v1F#(axl*Gq1eU2)__&^Eym zo5&GdG`y2SoIMx8@$o zd%dNGU0KsE($@^Npw}&RB8|RT0Md+H=PSM24=N0UdYm6RKXi+YB0Y?6|HYu=At^oX zyGyaI4k?|UrXigIT9$LJ^S*Xy^gi5iI_L4Q^XZ%y!yUtix7gmY9Ig8D!o9PLxX!~v zpoj1}M=dx<+C?)qpb%}%4i%9yR@fUZyriJD-+m0U0spf4E1BSAr{@>exaB_`r5ljD z{A_GI44*72Htz_<9f7u+F}Bx2JKg;+i8>6NJ#c%Sxey)zcr`iLwTKi`P9ulW$@!=E zdAns<7;~yD;N;?T+BIP7mRdYtwJHokK?J*;&k(Df+^E{RY^v<%D(e7fygulV=uo_Y;SX^lqrXk{(5i%8G{rVf zQZV$Q7s+VdNrBB7w2e5QBZ^DL^}l0y+}i=WXSlbwKkJ6(!1;9hMEeBil(QvC+X(ZY z4L>!x?Amb&-yk#YPN1e$b%jh%zT4vT2RWE~MbUAwb;khzV1M#sIfp@`=znaoedn>s z!)>yCx}Sxhd~lt%IAjLzKBAa9A%6)+fD2GTOx)dg(ToSjNk)uVK0DKNNaUfcoN2p^ zMnny@s~I9uqPtcL%$m&({K{%s0{H@+tv@8{S;d~XCjQE7Q1b^lTUnv}jIu<;|DN`c zc(jJK_P*1yq1qES$Tw_uufFj#zT!qCdNDHdT4`|h%mF7nkt#&3FI9Oxla%EVJv~P@ zHxx^PJqtk}QCwSLZ^zu=$Fm2h2{5Pl2GftuOssUE$r$nMo4X5Ht8G}*4!h`{-FQ-u zv1A8K3Sz=SrIxxX4905!s0c<0mr2|MO+TLrcI8&ZajICDZYJ+?W1u)xS$p<6)8Ba4 z1B^WmfIZmThW31yr8(Zdurk;+goC57WIE5DkdJD@UtALIE(&%(Id%3MCbnLDgPhG% z?aG6ph=2vM0`Fq`B_9&*Al!w<8P%|=ekwj#3=-;Ht!-7@DC06QD+j(nyI@anr&_Gd zn{y4=ni4?Fw=pg^hiApxO3vZ=PCfl#be(@F&W;;+gM1B0KytZf2RWM)n;hd}#HkUa zV`I!raoNLPVDKFwvNz`Dmkh$(rEjriTUX*&Y8)b`yUq48-O65({i|%8@52jBN-@ZF zKKBduW@nlU&7dO)7yIGXSOTpcs zkaP`W%#opY*5VxLJT-X|WF4x|)*T9-fBUjOe@)+$_LC96ToQC z_8m!h(PV>h?y;q@OJd0zytj^6;|_S61`zv?`&PcC^6$G5c9~E8`SO6Bp_}EUr}!!U zOAZ%zX+5C>^c}&Luowv|0dSlKJefCNI4ST8JRk5gVLgya)f%<_TF;`PzxzAPJ><16x(~!kRSN8_s$!W zl9eknD2Zj=8_2m!&o<@T#JzkIH~LIG#VzAj405S%rprkE$zxtgCgYK5EZ6Q6p&OGG z#oO|o@b53S1aBM@B|j}?t{AB7NqB>CAk!K|)1`q;4Hj92sb$=Eli3^hY;4|L81u9g zc1vlS;d)RHjn)Z8x8LrVhubk>Dy%3(=a&Uc7IOetKn%tmhNl5z5Vn?ejh}_GY@=SNeUQLaX@q_nsjn6`}rkvH5I+=*?nAn|qT; zi$EPnu`>|;De<54SHU72H8XT<;B*q-*S~mQ{}1$Pc(pE9sDa4`4KNoj2lc~@C=((6 zAeb&XB9Yz+MpZ3a(S*VzFlxix0o4y0WM~uJt`0%jqE<@v zKdEJEO>M8JsZ}SOscA-s<&!daFj7^YEClIlMZ1^4Gwjnc^rq5=5|qIf@-HakbwV^N zACSSUGnkguRtvrBFT94|bY2onjs7rUO@hrz7CSyZ>&4}QmJ`z1Al35L8S!pW(~?B@ zW?hyTMOm?T-;J2v$q*ib2nZWee+_Et-c9M#chM_TZq_#k@t3Fz>uRsFK__R{b|z!K zhQZ`uWjjr^QHQ%5^H`0nJ%JUJec``EDn6Lm-VZ}WJ(;yBwgMs2^15qF%J~~JpkCy8bBV0qd0qtVRa8H*3bi- z1lNx|?T#9sITJ!;CXfs1Yifd%I9Pz*?Jy2deFT#hiWPccSy7Ig_)Ok*^7HUr9vx9T zO}K%zS_Yr%vk31#zD+DKF4`uEBgOExK?$-Imkr|Ln^80aW1ju4z;!7WRX^8Xtb&9J z=1E39#8r{OVPZLA3@z!+@khEAY1bBU@4O;kq?~7fh_l z75^1WN!)!zZ;u!*$RNFq1yAb3CoHY}hKg3La$VX%0~*cbdW~N3hok6^O}S>$XC|PP z-*=+f$aL9Qr&GR?_{jd-e*Fe~(FxJReM!>j03fT>Qk_&7?SrJDQpi;^rR7NxV5>y% zub=$fuFiiO@mGgqZVspJcAj#+v0=})4gTkrS$uz&Bwc5`&I~(z#*j?BpT1$4x#XOr zkYjB*%u{@SU<>X5brt!u56`D|IxbyzRFFCdacYJQ0!?&O$_F@lta! zp)9A2)?iVgQ`l2__S+7BZxQD@b;xjX8OGjpY;%io+f;Z@fZNq?cJyDg zwV5i_tXh|(K56fi>fgqm63f|0r^uHtn+63WgWk({-4>m%AE&dm50S)jP2E);Qnu=5 zMaWWw^lDL^lXN}{jE1M!VFMz$Q;=w8y0x64Zjlf7XN`OKo^kATSHp;}%bm%`CU;%~ zU8EI?M7p;4UUmjdma6{aF+cw)iPE7ai4MNA5lnNF5`7VSZf!pHcWXI%cJJAYlTZW@ zoi;t1Eu3Z6BPj#+LcMKTf^d#81;6Ma-b#gL8=4&R*&w<|LPwaN!v@5buqTniap4mL zk4zc428y6ra{CaGf!K2iUg)(P{s1ERxdgV@5S1}tCT|*Jz^1X!m~DnC9a|yS-NJc? zvtg6^PFAb)A3hpJCPoD71V_qhE$A0;TOMq2>?DoP(2S7&o#~5QGxck=zTX875IwrX z9{9&HDDOCCawOLYRPO=m>pY6&%CxsfW*TR#(@=NwZlq*^l>zo|Mmyv>_Wtv_HTq^o zuZ%t6F4DJ4K}I^5>C+~vY*wQbIjj?e>i+#A1OVTpNTkgYWoU&;wsIgat9w?rx+YUt zC#L)8IJ-q!#iklYLlb_92x)`RxNZ%^SjyP_@jb!`@&(3JO!G;%pr{~^q48ef^#|-j z1z%=F6qfFGZu;K8Mf#-(Mf0sys(~H))vY4oNL$No(SsvW)~9ry-O>HBhfLRHdu4%= zAeL;Tb}y6H+7mhucqbmagr397oM}ow&|058vt%%(S+D8c#oE+xmF^$3H?7f*DQ4A+ zO@1nZxZ~}hfg~pGCME)eUta{X8fAg_J$8!pz$4f)JdD<8rMvHta^=^{6&6e${GCY> zvn0lwKxqk6D!Igph9#yDz2e*~dpuuJmazCAU1xsw>7IB(R=1MeR&|$LPA&=yF8KMr z1ubWJ2ZZyGxv`omsQ5-TIBJDGk!wsTq*YsWXY~~^*DG@Rrfq^ z2gkW#gJFH57+ZD|>{+YCn6fXPBCU#n^K@e66TcKhExP#zp|^(QSg^Z(LL<0!T5Q{3 z(D4(_v5a$zwsjTQsB|M&Ak*{E$eh6K6ki$ zE}8G`aynOH`0~I7(^Ed;7Y5IXq}0x@ItS{!s^E+`ZqLHn zj8kP<$^q?P3rOu?0--zf1I*`)UoMCnGz>pVULa>AfC)5i8<^Vq=c$5k7mgW*#nIo| z_QOlTFU7}q1G&9)~EeL()?(x}u_Z1Pr_aRV{2 z+qCcvQ#bV_ht`;K+4V(5=ojA0D0NPO^^ad%Y!fBer3kxC9X8rgzUG`FCE^;0M>;Mo zof`PcxZ;(ogi8FqC)0?wrBF5eSUTtyI8>UfDE0U&^Ap=K7K62Az?e5-QK=elkZPi+ zPAFt@nQQmml`)TBlvMIhA-+wr*p!pVU}C%Fz3rv!a;<*QXO8Zp-zd^VuRmGCMkZH8 zNEbEp_4U-OJ7HJqN(b9ZUr)D*TGS`gGIVajmS!|NKG~Sc9uwW16Un>A3GCFlTB$HJ z9vzV&md~_U7Jk+}`mA1h#_7v1)iYw9n`17_BN~A33TAwEt@oQl1zMtf?|1B9k+p7o zL{zUpAmdxCL}Lj)m$u>E#qSiQ9365(j2U~qsJnf9ztddACG3-W!1d-oMvbE8>E(0o zhKkHw&91!s&R2JW`{U;O9#?8(qiu9b#Z1G|!u8?k#zW&057Zfyi$pfuOm4qZ2n#J=J zIh0#%h6A8Ihdc%Cw6zlICv~e@4#=5uQnMHm>-85FC>aIPxpywtF!(Tz&r|$&%0)2# zOET(2vBXoSfMxH?Ex%>eR8t>Cr!DCNr4 z`=tX7qPJ=q^jdI(yJP@2}{k(yE*j$&F1G#%0p_;%S>596}X`0Q1n_Ri4q# zH{in}R9U%N5U6w>_h3=@!F@tBS%E5r+&%$&AAz&?TA8CG<;2$G4 zT$=Hy=_>y@7l(j6MbNjH?ZhtP{bc*ME6hI`qPblG?||cn@LzPX6=QcCqMiEY-s9`E zJW^RIWNGF*e;4YGbH8uLbtZk|x0Lr$=L-90zEz8C3eKb-;&PqI-`+d(A??oG@sk+5 zOZKtS4v42Ky4}9vJz~<_9SewOOiO`H|wuUcfT-_P?vC$ zGTHQJw-4JEl^X?^o-M&o?SK_h+EgLabu$)}Nk?IUIxIcG1QaDzv&eXD*TYk7b;hxgcZc%rkYAjwlt*(&QGz^+((MX#} zD#~cqH>R4&XXER1YuZ*j)uhUtdMkB0#`yJ2&_Pe6_3Zib%lQ*)GMrvIq4_BxdZQO5 zwWB_%Z0s8H7c$SBk;D4Ac|OfdeUmX`hsNiU(1bP8M(3i3BX@*y&@PQ@kQqDI>~-8f z@@)1euis>vOkrp07MK{VEDTNG{rKtVQQ@DGpeY!1g^C44F6n)JmyJ8a3<2ggCDP1J z_{^4I=dC&BXq*Wnw_GVz)}tozW;Fn4NY^q|z(9jGp#(VEk%4rrux*|U^}{^5%YA|3 zpVd`@&xt+g_WuY{ru=8F1oV&i@1mlAAy?wle_QjQzn{dvrlTtt{BDwbh@ZSG=8xgy z*}r=nOtz-rs~0&~DoO~;v*~A&oh#DG$r~ipk2>f%RFA*EUmX7P@o@DbJA>oQ5c7Mv zAJWSBa01RHT(YGdR>Dj0=QtAl4_q=~IS}|_2g~8=4}Q6M$uv11%NqU*4m6}V`@-JK zdC7+isUOvcB|A&JEr*|Y_#P*Fu(eYht$q?-TOCw>ie{}u`U}QM^1>A9kWLB$xo4Ki zP}-#-0S%eXB0Y#Z1OdlQ?KQWSJyw7bVFi^9DTzA!&S6myYHybVZmPd)?i9NTRlj$Z zq`QnW&`kUGAC)P@N?SI|` zEcJD(bXFnElI*Z6L(H5;6(4|6QEOCGRPCAqRpN<{UyDy#F^%3#_=l^MtF;k%o3u^c zX$_*@pk-(Fi;o6JUeujoR%@-|-yWZbYz<=C;F`UWJBD3#+ z*9}`NET52n`bogdv9byaY_#mz!^$zlt#33`)NNa|S4>&jCqDc&=CR9|xzSh8PFGH4 zbFPyf)Yk*%x(v%tzWJPAysAkUA6&@@5~{!WA{HZ7QOiuNh6#EOL2)E*z&h#7#j!vN#`qX?e5U3 zaclpX?{Dh&2EQTQe|=|w+eQ4lr|%d0Y_otg%=ZG;pLsSPAKoYCb-o6jMZm`O zdwVeCFh9rqkm)1rrpm|8=ca;zGFv!eZ>aGYXK7JDA;$Tw9UbF*73wO7VoD;xeoOu` zdkTnS6?3#_O*0nT2Tte znUgK8p{|9+Rn6zTqkX`t{^&Cao3#vo@&;NGBqt^ zThLjcKAGkh>?B-9G}A5`M~wI*GWp5oq5hyo{a^;bT^i*l9L5m9dg|1%L?IMnJ*-p~ ziyb{BO;{nHf3;G<6QQVR{*s)~Dydotph~o2ynM zWy&2@pI!`NiQdWw2@zVW+AHgRs&(}_aQVnU@3*Yzyv)ipjjXDKnB3jO$!ePbC6E?p z*BYO=I=UwC&Ca`?*X_b3+g+Q^CvB%(A}J~qM*Iae!NMnT!xn(6;>@47R1;PyH_`n} zJsmrEL|+-sdtnEeF>l%W2iTvA4=iCCS(dobJWGrV%L>nI>jgqyIPo!dG5+ItC_)~1 z&==vMTwodmdr()r`ZTbSzqF|r%$}e>BgP+Q0Db}-6gNNYpQd!)jv;>=KEF+F} zlo43p!ou1_8Rz6LFo6HxkNFRLF$Ei{V!-%6_g zZSAxEeh&ZI>gWGnXT-^k(XDy??D#%Bt1gXz(4gs=Qb=23LEk23>WLDHat@Y15a;dv~k$?iYsGtds@~MiqzZK0Y$LLx)6xs9W8dp;h+v zjYm!Ys7)2kGGHK)!Y!^sD7_XqW`-IBgo;Mt%xV}Mjg$C3;F}pA%b0p7F|IT9nf@g9 zbf}~N`RgaUr7v?w>=v_;;rzn8Zp2J=-zpajk?btB{(j`UYeI3e2ma|hayU9ZtkEAN z`22J6{A24Zb3KekPOx^0pZ7@xsTo`su=@FxxwG?J161f>FVcy|kXsh*AptmTxqg@{ zhtUpAL+7x-vYF1S12b)H=K@mNJBRe5TRY`-pE=3LE0u{iejm<5vSgudyk(~6WV{yd zKDZv8uvWp^tBv1w(n&41a(bf`GHR^it?Y@aGl^^B=?$%cHQ_TCjx^7chCY&w6eq6e zN~F?m(x}xb;O6fJYIRqHCNYA1abtLoCBHW@MSSoZcL=d>SJdXXgXV}_^!XgDjke+( z@~BKtQU^XCNM>?y{^AdK(15DUVLS9!LjTjpJKD9VC#-->icgr7{fx1XAMz&|fACxJVQY2o&ZYr0eV|qEWVXY;dHmw9 zhfM31=`a6enHDZ|78rgB=```nezNL}Z{62_ZIhCCI8(+XdfNv)*u18x=lQ7&`Of*z z*xe_iBiOpk&8bMeADEo|t*O9bF{0TM*)gN*14sjl&w~k`QwOvId4s*+K~=HftGh=# z9qp2RL2hNvTiP1x7HjkPu5)(hdeg0Mb4gcd-dt#dw9F$v!DR#CNM{zQ4d-pwS$D>S zL7Y0WT=mxWd$-XP=ZU`UqxA*Z7Tlerzb;~^(A|M^sK|xy@4??*a1MZ&JC{o>o&J1l zwvO;U=`ZJy&_`b{dCEJ4!BEr@1(0e6E%rCXz=|2H(7HbjV=Gn#iVIywT>A}^aqcII# zA5#>LGOA?TAD`q_aW-$Zmr)X&YxnqVnT;vl)*rW*l03;V1yVMqn36&yE8Xx@!%vM( zZ50w)MNFxTlITD=TT+rhO@Aig9hI315Oy#=+zMDbZl}Zrk^6`gyln_d6jaNc&nOPIMcH6iU3snv-MtD<#!wpxDgR zcdM$plbkg11GBT`a@8!OG7XBu4Ar=5JV@g-8<;fCND?&%zE%PJJU*t;WvjEmDS|6lrfxqjoPnGh?28l_fphJh=8bL!21S%yB0Rmzc zM4<&^=}7>E&x{YXkE3T0Ic7ZwJ8R8mbYR*EVx!sG_CcKpR7ctwZ7l*5#4GnK7??lt z=}*!bPQYUx*V_YDQ-?Hf7`jUNTu}R!HfXu1PE)kDuv2RK;bB(Z451mxB`9_ijKpvK z`MQiuFiFelY@d zZ*(;XQ)_jt@mg)ft9~-f6cM$N`T>1+;#$$k0o7n5s=pxHEfU5@%4ef@X~$EKAa*7j zjqQ>}w+R_dKjb87+30mQO3du*mbQ0iiTauBx;a+-IJz1J_D=sR7~lUbBi7KcCT)^gh=UBR1`s z1EXhyH0y!CZ~wIs(*ewOR#o525LrXr9q``m{^8+$yJo@)O?XdK0;!p0L~!FTNiL#S z6)`cz$>MNg%5>=-`g+#cDzGQ?-6#3JB8d|}rFnrUuP`{AETA<^fRGh(znIuAxIbYb zX~Z!pjw6j++-PWJj4h#m8dz=F-SBvd?%EX(Wf_iAp<(f!khfD4F12N}*_MlV_wT!861gu#&)+N|;WutYvU;W0daL;c@YEFvohW19!? zJdINp0~%M5CZ&J0he>q79m>Wob@4RyC#}EnIcW!B*B1u9t2x-1n~R%%JZC`ma_T1V zmil%XuOeP!`uANR^0JEi>EtFZhFSn#^;ZOgF+uEiq@oOd=Nit2MJmA~gFNT+Mnr#- zC(UpVDc$B44D9P~WGkw_Au>BZouMT#oJ*%cGULvPwfD~c<@D!SCMFyci^NFvAUo{Z z0HK+ku!*~6i32rxF8s1Y^b4M|Y$)%*vbXrFEjtR+U_?K33X-=sMX=G(wTDsY4P@G8 z%a{B?WA6$e>v1Lo;D7@s-fG6L_l@mn)+`N?C*3X9_TzITH9&=27lC$xRpbA z`J4-R*7gb6*`0?*Y$W+Ka<;ADACOa)3@j^^^Rn@h1bN` z-x;G0YLB)FTw_7GOSKCJj?BGc2>o$g2M8^@9T-5&*$dc1fYe&F5&kxdSL zz40}`U)K3s*R8!AIXLJb+srrD=eu3)k?N`}Xby??DMuR;pWS}abhd^1j&L=%iO7PD zZgxzv>eU~ADisb#ey}HtZTz~P-G;}dz@EJl(;r}(^LUxVk(fd5;yBL%db|>Qjl_*3 z9x?8s)gSuc9$hbL4VSf13MV;pkuLo zgdw$DoP&o)%+s+b{CiJP-R08rL$3#nQ9oVdB&wLUk5nO@QVLBUSBu80Rh8XMRw+=C zinJB#`jYaR>Ve3p=<=YTAcj10R?AMzfMN5bUZz!|lU9ArsnzPi0jR#!sCH`P5M_Z+(}o zM{?j&wbRbbGhvD;g>dq9BWVAnFLhq8bz8=hrHG*oQm)Z8>L5H)t-ZS%zuMHH|4_n) zdr$QU#n0#EpMr2oBm==K6_b^KJDz1&geQGtyptC&$I%xL8rpSV(@is%)Nq2NfZWj}Q6 z=+^Z~JtoMz`=ocDHnk$wUfIwCO7YF$ql`oBl-9+AiM10DIe7^ex0#|1VokW5ogin+ zBA;(;xSV&QkdB4i#6U=j1cj*3kcJ-NmW z7T2yDg3WFdv8cA{;zpWLh~Mi6EBc;z@A7=JGlKY2aqKHsi+ZlHXIIK|i>Tmo_?1;f zr03Ddmp&)t?WE=Hq+{ba^s+A2k-}tgN};YyjDL!;fraAGlsM=FDB+93DyQ)l%YWMs z_0Ot>_B)_xeQ0|hM=s+o1}vo?vJH0IWr2jpi)Zt>H%w;69Jo<2HjuSq=Ui#&;_{3j z@c%Low)nZM$y-M~;QKV&{QlOXAg+n)aNzW(TbY|L{q;QR-cBJx>REB=d&Ar1h8rmt z^zAO^Q7WA@-4k-X5Kx((>*iCjDHl)WbIcdo*`oK01gpyNEhpN(HYhn}nD4*Bz60C* zlcPki<(BPATfCqTq@aM_E*E&O1`HR}Iw7NW>6eH=xn_U){f6P25SeRHVuYnBX~%30 z>capi?O12Tx!}y}AZGVREao}oJhu?%g!fX^Iv+FC+CqLch<|q1$xJB9mE@(`cFzRf>jUPwFARoa?UFioc1F6zT0g!^Y6oNWiLJK?%L{LTKlj9-O+ypyJLxGMyNu^tjXChjn;G-$IGhEur4g?K;uHXt z<{IAzU+5>6uEb1*QMkg9zH?MqgUIh zfq$0Fgf@kCoAHxZx(<#RGIREaWOtN$HEv1##DjA1#K9+yr6BWp?t_qmH|96EMxFdL zNMveT^4xk$M%y1Ae*%o_k#XnXq1O`QmX_hmQ88RTF-54((t-KyTEt{e6pg2wR+`Bx zb)wLj@r;NRAFXk(CZ$vp&qK*2dQg9iYef3m!IkVI;E|}-42jfx$ETYoOM53W+sJKf zNTv~mPY$&sm3BYUmyU~OrQS@Wmqw@?-)JFV*hg2cb_789O+V89s`q(Va0Zp5HcjZ6 z(NHw+2T~n9&s{j-qhj`6SFlx}cj*zfTX#cXq*QyNn2`fz!D6IHNv0&YS8B~>!EOB{ z1l#GZW4BQ4vXMR?duxhOLh#Aa9h4kGqN!++W@^EvXE+V+H^NN2Ir!^zfK8Y3zJ@+0 z|3LcI+AMRGNTu0~bdKP@n-<}Hlu`02&fNbTCFu2^=?)$gum28u{0oirKK-|K();^K z{A-{`xgfxh>Ty5)_YaR}o0%m1j=f3!9S>wF)q@#g`)Bg{vpLj5i|iK|Q-~1{_<$=e zA-?<%KK6nSk z7GO#Tgi~@InuDM>kyfXC4R%WXgA4|$M3ovwuI@}y(zHl-238vGqHa)A!HBj8Z0jtf>qiY8DpCX!4>0> zH-eFs$zjC5%H*l^rZXSCRI=Y+Tj*npbZb`!NkI`66`?+(YaHrUhObPMwD+t!DVprs zu%Tdr#NOxMmf0FuTSr23$-kZ5qiWUGPS)A@s;gS_d}dV*Er}~e2qqEqHtN}wp6L9a zw|J_x#(U!^ii#fK!FbcsBdbHoD_TG*>-wA=Nb&3;Yy@@}6p?=`n{LuKK@@ao8E3(~ zg0Z39N?oY^JRz&lG_)4>fIo4i2a8sf6|-*airP*&w8F87#&hhVmC4ThEunJwJYiK? ziHCqzC1$#ocyNMUixXBrn%Z^z3R%U{rn3*8Ez4l8M^OtEf`Zo*wHUw3HGqQ+pb@#> zZ(4r;Xc0#6X*T3c<6^kD)aitv{WiOB9}ks>9X^V&bpTgo-cA_gaa-4ol$&D%48?z^ zNDuRUzoKC{i9|ML2%2N)yU1k8VMERP-We~*Q5GzZfV+;-E;-tbJ-eb!=j47w3vC ziL`F1Qzb;y1UPHndr7+h_On5c$Y9MZJ+(2BEF~+Hj)*v9sAi$w@JC)`YqmX!i zvce`UmxY1+e>w9HkL+C)ic2Pk8ZKiLl0b^x!E>7fTT(9n;d!A#(nY^ncDb;tBk4Mw z>k*Ndxb_sHOS>{Uu56mF`>~K&>fymGU90m76`K~uC%mc3+A**Nqac@5Ps(2m|J>#V zUWr4$)$%RazZRz01x;VEnk*dB)}+jghx{m{rvL$0!@`T5jw=->lD_@hR7hsYR-O-J8Y=o2Wa`NJ)S5B?HZ~=i^19xf(O% z|5ELTj->C<6ck7x%yD2WH3NY=U5LgUx3LU!=lf$dQkhVpnxFd$9Op=s`R?=+AW4!v z(4QTb`n}ZpX&0+p^n~->aKe1Q*SwFMW2kq8f-If^Uxed2(Ku)G08E-}rUsJ9w1iAH zV+dA(dKk}8reQODolA0>;vh4v9-RU?3m{-n{Xyh2Lh`umfdl~9@z~<`35IvcyZCZk)%$$KBCa-rsQT5g>9v4j;Be580tw)>%F3CnF- zNm)YQ#a}X5T~{%Q~7Ka}G==pj+ zq)NX}A;vRlyT!VGxItO{yEsx_N$i|Uib?Lk z@y(6+<_3~A_iY`l@`lq_pS$OPO%JVF_stJq<4-?15-D8gNB!;@FVW_+kvGe%|8Z;M@^cP$dBfqis7obBM5B1g z;jO59p40zTO1>dU&Xe}2i;~7LYPIlN-PZ<^Al;hHtQESi)7~0=cg)tgwXZOvwo(wb z!FjCH!r;?RifC(iwrlrKfkvcs$_D)Dr?E>xd14-GMi2tMak@-2>Vn%#q>^$<;z#jV zzt6KhJMHH_jwvh85(i$dl5MqeKGdO7u($QFXVO0{>%eC7Z1&>*4{>iE59J#E0aqA< z8Aiy?pb%j&#u71zWNkyl7*Pg;WQ&*>hEymOQBsyfwz5S`wwgLE;)qC6Qg)TC88gp& zYdPn5L%0;9Wd z2Yf2|9p48-M5RKqR*Keu>gFgs1>H01Ce3KUpS&Kz;L&8Om9wIEipEbIGK|gYkn;h= z$Tk^0fI$v1$n7M>2YdeZ4A+)7hc=H~1<|_nQy`+(ipj<&D9{)nR|8^l79ba>jG6^_ zRKWd$PwZJ_Yc{f-Ah0Xqv4>e`wZgE|@*6B5CvH(n ztM+^IqNCq#W2oO)pF+k~cXyj^a>V>OQlgyU-9#+8*4_y}X*Foxo@}o9g6ik@3U}xn zkYeF`kx)2pQuy{6H^4HW`y+FExaN95sm2C9UkAl_7Ja5Oe@Luy}hD>P#MZY zQ@g?gb-xskCypC6$FPm)e3LeH-3u$*AUC(NdA51&r`^q3!^7iHK=EXvdhE6#FlJ;e zHqOuqoSH@t)bqS^&I1soLv1xPvda9?=OHLj3vrUA!6zIR?O_7pq;-iE&B=W@DLSAQc?ChAEZuo1P?CfAQa3ZemT+K`KUiCWv6nf?sbnFP zuFgV(+%ZtMXT~JtVbTW`RWZS55HwrWZ@U1|@cVL1l!U1(me`bqnghIF+-UZu;~j3!3Ov?(18)F2y^M zA}7n7RLE0}e@pF~E~;Dq>G|L)7ypGsIz4Vt%99RF>D8PI9<*hXCz@k5FAPt|?1L%? zZKo-VeL?ib;J{76l&Zc(2^*UD0xfH3H>c69u%`Jq=3;AtXIAVLcKWpGOmySB``^)3J14YdD>yCm@i=>i$6slaLJuY)I?9@0tICgRB*@gqHRhZm9*epp1MP)eSt$qlGDclhPanP!#A<3Jo91r%MZw?D8ZVt*SA zg9G^CwGKUi$H_&mNd$!eLfk?JGZ;ubNcFx?UogG3J)(~}9vdJkq1@?Gn_)y%sC-%X z?p^Y(ag}jReR=tbvhn;{|E%7<_ch~P7NnfV)<$VS5`F!I_m%EeP_J{#X~Ga`zMHwP zyG$`HhYr=fk}eSNIGf&0nAE(Y?sJv-SiZKnk4#n@-zg`Rn8zZ_eLO!HMRu0 zL<_1Lur>5;+{Je-^kVC!cl{g2;8#VsuA%NXBK-eM>Q?{1SA<{7km=tnp%hPD z6D2Bn=j^912G38wEnYMCEKm}GxKEPPJ^N|YD;@Dx7Vq{BplTI1z%5A(QECogVqsP? zKg*;2x!+&l7X6s0Fg(h4f|~J2dQ=CLzwuJj@UGDeIRrH$m|Mpz5AFj4#3*W?kr$~7 z83J;bxOxGSVdpwfHJ6L{(0UYe3|78FBh*I+Zwm-{IU=BF`hZBSLb)Db%NFo2`}B}a zX)Ew;=b8C5G=F7Ss3CTDFp)QZCM&}jA=ur*dO5S9GL%bUvKr|r}u2&c3|*S0B9BZo(grC;FfJJ!Q* zY+s9LJ1=SG%cY5P zt0aw5tJyDCd?HptP1q0YF{3QFR7sy(Q%OD#D$iH$* z>{M_!D*$TMT&e_Yl6W_WtV+Il0REj&A^x;gvd5;HZbNM7h#N_Iz%VSRAeW6dHw3zC z1(8HC>miC}WyTDCaU zs{#vg#lx7GxcrJ{SGX+ggw|p(T)`b$7)<-f_y)d zz;2GFL{m6a-^`(TNUj``gNi8LoIXTsss+#~gV@!R-EX=VdZ2}oblK%} zK_!kU6Cn2c#Mm6!0rUEW%JyOwo3MO@K!--8gQ4N%DN`O=);I7;Kx5WooqR2Ofz!>YV7v20yMRd6 zG*HA@WEBqj4^LA7{sW2|uy=v>t3sUNnwDv;dRo>ZJp$^j7+ylg05EPPr`Mf!0pvLY zD(I|wz!MX9bqNAB<5QRmNsC)CYKk zAXWUeYI65^%R~&hMUu#i{Wg`3_BECGeuvHGH%P%m6{Iyn-PKOH8-bn&h=%@BxU?t= zD~m-Lngd>zR5(^PSft(ahis8dub*QxjsOR9XG2}!;d1+HVeZ;l}>1qg%N z$q?gX$T?;_g5eoHA$Ut+5Ms&(Y>>|s&gBD&k#qb(W}ibu(9tV2GyVJan7yr7hR@o= z2|i*ac(_6avNegnL3N)%5?|?%g$rfrTk4E745f=}Z+bg3GB+{Op6nODJk1p}Dku-O zWa%?6UvRa`4{QW1j27%}5Z-6_z&QpSHG1^YBv`q!hv|Uqucd6Mk~s;29jpIAr5VOU zd#Ql8(pN^)K}YZ_X;e-`Aq}trS2DaA;`c7291OsaPJGmg+=gxd1iYb9__r@DuOW`{ zjOV6AZRgcTJI7xlf~Z*}VUc6|Fg_4A`T_fDA~*nW*S6fU_Q?xK}) zFkz$UYYP$d%MeS0473g(>C=;jybJ!TnZVDNu&9Hq0@NMLk_sDz!!oEamA zTMmw0%{YOIQLuShRbm10&N-_6Di&M$8YtqJw=e*aO%UK3fuTSx`2ff0k;ONM=l+Oe*GYj|x@eOIp>B?feI@&g%s%XLw+DtI%K^p$pqeKCa zg?i1wwn;c>6rX(rlA|)&d&zBHNd@6uH6S?Fe#7dM`4V42aKV|*Pw!)*as7T$q{5Ja zSfw<8&iRBQ3&7C>q)*Bt`h0Z6TdM@*I4`ISM1pOYU#p(g(?R=@;-w;{x(UpN$7G?HgS~o?jsz{b*A|2h1fRb6(VG)3(^)VB5HwD~a-a zQ2^B(6IPzcu95c2_1hgBmY0`z#Us&#%{H3ftZ&a;vK=>dbgWsJW{1tPfqvC|GrfsY zJP=h`2EDmDULPCB{LIz@ZZjSoGw`MkD(z$Ixy<)*@;V_FHs*M2Mg42#<|W!@LT%qd z)6N3=y{LdL`f`iOkaF|xh1prwso8fB=kromdaU~-)JbB|KNFy8w^<0)95-1Rnd00H zo|Q=sot>P-X#zD`d4XCiA&Ni?vw^@FYrQR=i^v#WdF!_){%XqxHZ%(ztNI;m=u99a zK4z@7ZrDHycaeUMuYs^AzpMqlrL#4~K|r9J2W-8-7(TfuCtk6*4I1XO$`cl$Hj`QK z4`R)wc~CgaVE959ozt|y1^|c|KodzX1}p9aQ2mGxpJnpRLURd=&km8txY{TiCMfJF07IS4=7JD`W|E>iv`O@1#FtT~m z@Z?<~**LsBm?$DF=+#Blgy9vfFYs+yqbLfbJi=jqkzFj;huDqKqcpH-&06A^)1mOn z0m5Pv#e)JdF;aApLI%^E8oLG%coC-Kn)ShBy}%+2_kr^An&#Nb;>lp3#uL=i$6*D` zvLlIwv*f z-)VqJt`kv>v1O9As^SNnx(9cH%I)1N(c~={>X~nbi|XE2G~0OXi>fJ+@=c@zpnA=; zHVr+kQ8-ZCFlggEm@>Ud0O@XneNQ_NIK12Wth$NYGVKecW%U+wZ#a2fd@!Au8InV4 zDi-m>w4&pi5_{T+yht@tDp+6%A@|s8gWR-NeARM372lz(3V?Lmw*#S0l5z%7pM>qV zc{JZ6;0HFDfb^@&TV#(7wp000mrY_@0EpwE5<;?V@?RD6Vc*@%@x$isoYEpC#Z5hP zstjpcJgk-kh88EPJ$Bjz2FOM1VRd3oL{OY7fKc85)HH#}W~13}BdD}9$uwd9cM^dA z3rrOX`Jr22*@~-G)(61c1&hzJ4C&^!usec4o#MtH7Z!%W52G!`(D5imC6IuF;de;V zZr%b|2Zap&>Woe6yi%Y-dg*?iJ4Ho9VW^aMs}&xj z$P*<%p!q$>YaB=h)o)5*44b>Lx6dyes5;->EBGybX^dfe;#uqCMG==(y^<4G zOU(e~r4#;Q7#O+LQ~~28LK)@XfG>@*L$?BHAFZk!B!;k80@U{VgN##~VRFIAf=q5O z^n#ID_{rr%i>R7Vzc=mp8`jcRZ?3$jGb4)3?;4jC}q_25Ol)w45= zhS(554Wrw79u<;+oKns(djo`Kf^BNz7jueN^Zim9TX(2j1(H@HHF-?`8j`H16T5J6&G{#@E)3{kmh5c=rL@*;ZaKkS+wF$jsU$Bza9byFSEPY3TNi20@Z9G^QG=H6%XjdFg0x%?P?1GVMh!I_JD*vAQc?^>>630 z;(4XfInC;fi(r!@EA`S_Sz$Uj%A6~pIX1u+@ zt&4gaIvRpnR(M+kULxjpf4g72_HOPrg=+h=NAi%#t0mZZ{0GvxjYaQXM!ikGfA=jQ zPQ9%2-WXJCD`bn~Hs3ZzwL~eLp4PoSiRAN_*J@&H` zpt_2EN%cebCW30#n@QMeKJ2$bfNO2@SAbEmcxMTR9=;oX zn8L927&(ykMs$FI9SG=Xs#==RP$?L5gfLPFq*?3~MH0W4QUMxaZcu=+j1Yc^XoI^k zG^oagT$mX}B@nVx=&)Yc)x(Fxk1*{&&IcohVzd!M!O3yyr4 zFWjw-mXZ(A9)su-P(d8eIKof^5MxC^+Wt1-2}%_RnVeF{;O695o<==xlQN)g9OQP) z;u_=U15%7g#ugnT)XOita{T;Piimn}T-WcST2Seyhuv&rr9NnNk`SR%lU=^G>l#Gb z*TlC|lb0f{GSt)AoA~ls1!+V2%fujP(PB%iW%Td}?>OsWu*(8r-*9(OAD|HHo1ibn zLQ8$Uu@oi?njP+2Il`Q-Ux^>FR;UKUx)AIMAmKHJH_xYd>j?Q^Bg{H8o?qgU0hQcW zG7iGA$GG1KeGs(x47<7;k&Tbk6f{H#nj7+e7~x?t4(AO73UB8IumS2E71XAH?AjTh9)5mMAt}NyiUL<< zGN_vmAjM?bhcM}ChO~PC|7BQ}hI!E_+|g#pThnb!h3{JjC;=bcZ#{yfRa&b=$M#$B z6`Wxj8jL+lD!3Tr_o`RGTH0C-7ibWkYdlz$voMDIguscsYc6k9nIGV*9U1~v ztJBLi^q|}>8(d~ltYa>a0;+E|s&_0Lxl}aLdKGtTV^>^x8;nWTs5|uJY32CQkIwxn zu4?Rl6&G8Z72Pit^_8_{ZO)ZNZgh4)_zVy@pDvo$%Xk^85dN~uXI}TG8$HVI6-8q>o0{gt7MS1!(Nv{@~)@R3F zSR36ucTQ@W^7-9F|3glBOi|ysIVE7}%of~i-*SukWQVoT@#DLtKYwlqs&w7p5GBa)zJeG1(_3t-yY<=|O9?Zz zP~S+bVby?ZIKUe7(+lGBO6F3g&FCS3nP>jb)luOgeAiKwq;FbQT?*kY~nEj zM;-)fmaR=I!GyI0YMWP-dg;CQz#=>*nouyz-ZwOt?zqs#!wRQC_*f3glk+3aGHJni z{dDs(fkUrN2FN5^0Ardwo?tRg0U2{!3$8E9q17(2ZX>pnY4f2DWxy?{*?BsG~ml{xmV=6o>15BSTkX0)U2-7t} z%-Y!iIx9AsK#8rKEsAZ9;hdo!roU<4EdVVL0yvEW&K$Zw$fAcYIA?`T*0nnW)U~?p zQtc!F=3O)b(=&48g&o!Y^vK1m$*(2-1P;)X3ty33NFW69!1_Z-%TzY5FplcRv+0l z-n2`$9CzWfc=Y(2LU*_c&cN#&S?vJkLU9e1kCuu5gvljae5Zsvze>+E9lI6iFlvJb zz3Q$xNKz&akaD6Ddqh$CKH~uC1nOLcY%K!OfmbXx(WVtB1pk|tfp%cd+au~!!bGjK;B_WxpCO4qh%JrpaqEg^fWVP+K79o zd~Z`_FgYlnlY_TF7L{Oy~~Q%Pbt@BdrD?& zBnco;%V`>(o5umSLTSg9O9+kyT3oI*kf0SnSz(>~_{XixxMQ-e{`pNww3UVC2Dyo4G6 z7VqOx)|R4fZ8d507p~aAF9u87jA&5mL}zS&P=Y;EcjlgowS*UqUzmZ7o@om^0)qZW zy=ZCr1xMlU$r!5b!(D!_s`Ad{ngfw0qJV|f6H}|PL}GivVGo%c;~`?nj#o7yU&D{x z@f)c@g=B-^5*(KU665~oVoMzP7O6D}uz6Hampv^C4QOa*9VGAHlDtm~S8w*n?2T+z zx%3>*TOZqgJFMIPmSk(NjhjOTsXg(EhKfD*0&W2wqL+3$@&^pn7kJx zr<0dCrUcgK1p?)bX*UROrnZ+tlwBkB=}QENlL=7>!>bBV03Os1wXxhPp`_sX(u*_k zuCeP@-U=`FUDh$!7N}=>uU~l3kw6)1cUaa+U`+yKaXMgX;%OdhH<_WgwHNg=!=35| z64;ah8zHEaJq~ud2_UQkqW5~NHi*J$P)7t@V~3=Nw0}|>28?*n@KSR$1X*hpWPvRZ z=n5}KkEe%~~a0PYhB7zBeo zZ;KSnZ;%6loMwnlZ{nB&ge$1c9OpoDtf}1sEPCo9bGUmPXhwwB7iNL2&%1(9K~q3O zqg#gs*r5)xTEB0Uj>u9T>7Qh|FZuV?LJO2i zXj+4^0OlbIv~eq?!0QEDy>>nXzSNgI-;zgvLuayC1VT{7%V|)^T004{0WTW@fRa@u zv#Ib6eRyzuliMsIxD>E|QyfX;BB<`d0>IM}py7pa5;>7x+qmzeQx{Y`QvTJcga@U)rAJ^lt9b`@4)pIFV5dYb z4a!!MElu`#ztfcRSO?TxLb~7c75B*3jMtLtHsr)*go*HV`x&L+VV^M6HeOLwpafnU zuG|Ic8^dAiL2x%x)oFF47V*ROn*r`Vhx0Dod+B?hZj#lt2O@374hfS)0BkAlP|miy zvX0bSI9(`36AOHrnD=D#imP{yeVIMx$=vmeJ^lNR#PH>KouyBKA;Z7yu!iX@=v^_U zD#s^Gga!is8UsjTLIesRazNRNqq&5+LZTu<^gUn^(lmGmf;g7C_o>{9TT~S#;)Si+ z+gGbo5DKCxs}+iuBgNzyQtQTU!|wOCf}o482RuEscM}IH8llXOBwkBmLM>{WHMF1- zLZ2(>o>W;xnNF0@B77E>vR5wOvZq6PxvE+oxHIRUx!MhWQF6GWky=icR%orgzENRl zEgLfNu&+59>G2172N3@JgAf3zwf9(vFIvk9G+O;0G1NCG46UPwS>0go2Jh_lJsKPy zdeHYM+SnNEpM$}t-+#e?Mmnp91p8VmZL|)+1N?lU16~-c!tZyZw{1gfxjK6L`yLEK zV-0>(_Jf0j1|Qtx8-~`y{rEm;h19b5^&t_>gQL*y;F}mUR#yj&13I4`;3ErgP+-+j z(8Z5qfVV<}L;krj2vHNmd_fQ3%>2U1-e?`H-s<^+b6GtOpfXt{DEVQ`PpT567Kseb zKu`Bq?euxkk+En!-Jd;z&-B2nKfi|quYR2R>i6`)t3P`& z0I&Y+#SpEB{j(RKrK*Shvm0$~@bb@o0C&C~_Ro$0VVoXNvixP8HZbVdDXyLgut@JO zT>+Ey{?Zk&N$)RR0i*Q((v{)=xD2az8Qh7#U%u4?tX@9gY}lVS8*A{RU#!884zY$m z&JX+3Gq8p~%)lD{Y-jkRogU`rbK3IQ%DMEZ4lqf8v9dFz4pd&TmBWOCyrkjhuLEb`W>Jb1c)Z!^~2j>h=9t z|AR}%;1{F@_`{#3te(=}O!%Z8ti_zeR{b|d9E=m~rwjcfv z#u)w@(f)d2zB|?bH0FED)q#i<80H&_*7}!w^p6)tp`_s;pLVX7_g9-5KlHy{7{fof zRsM35zB~5cZ23uG@*ixWo;}eJg8pfX|G(SvhwuL7CVhXn{$|Vn&UgRmx=?pjHTW6) zx=FZyze#_1?_Z7iC+{`<@7@bQPz~O{ymvtV-;Mbv_x(Q1{O!v8clSLQ-_Q{9hx;1* zn=yKre{kO)W8MES=10r_=Dr7aWj6%;a^KK@a~VC%AMX3-aQ9=l{hKZS-F*)VGaA?b z9PS=$_?O{M4+zQp7)|~%#QYfX|7Oa6_g;&XsJDMSN#5H3evkgadw)zje>3L4d#}Z= z6Ak`uLYt!hcSaKUQUbGv>d$aK`7Vu0NJlA^$q&eczp|9`-LwJiYHL!~bc^ zAN!d9|H}s@c;dzfLr?2@~MB&!`eLbb8^M~IWfbGMdcKnm)esBA~dW^b-ouqVRPSLpVYx=!0;)2}k z)?GtM>7KkGXudWv)Hqc4e&?v)l<@&QX)C+?{Zmd40q^{DFU-`;WY-zz={a&0>-+qS$py0xg=Dq-aE zfV)`Xb7h{LzaR2Z&2`|1Bk_Ah_S3kBTU7Ng)wukY(Q#0v-YPsxt%8?$ zwmi*X;WIw5|FHh$J2Yz0tc|o(@JQq~*&C;Rdo>;L(SqW}L=T%^%V|oFRuGc(E^{R& zKMab%%%AzV=W5QVWc_$q!(w%i>ftqp@V$Z(b?+s*^v@_sJmyr|zw23}2G8t&c^gml zdbMeW6*#7^^`(2BHoYflol0rHKeJUK(X&JIea2&5M0M2=pXF2a%(d;O{k)`GPafTv z%t&wOHavYW24{rDlvNZ~T|2KQ#?XrLmQjB$fYkV{tYHSLt383cR&tvwrTp;=?yb1i zf~WxlQzg|$y4*BHHkDK}k0bNmXsQywlOZ zPg)VX*X>ai#+J|LE;aiNPVm;JH~Nk!BgKW^1Tq6$UX<)J8a(~%^jv?{i+wJ7RZosL zexvE{2~t2Rg*?L|G|Lkp+T7FA0}A+(&~Fy?Uqzcvw|l+0*d-qsW-`$ei+a7sXf zu;_F!^=`t}qOBua4s^FBwHElEbe&$%IOQ|rRbrgRrLpmP(qk^kh+!9_9xKg&hCpM5 zuMdcqRKCgL9=w~{{_1+&yA%DGGtZxS_Kev{*Iu)@)G2d`hEMr?>*GLDb*^{l3XhWa z+3SakNI4NkdGEh%um~KRu?W8MvB?#$sCvfvV5tXkE|d|NE51fe^Bw&2rgSC00iCq8 zj0Ycmr&sn|nutjfziXKDtR5CL_)rBo+d$_nn4P90JB}PUEXxRD#PGMzOvLQ@P4D$X z_$As%!~UxTJE^`F$M_S6WS%}AroGa9?{)P7t3-T}>kvP&CbpJt{ulm`TF z9-o5uJ0;i2J>6Jaw$@)nb2RH?(mShdTZ2Cw%L{$>HL3nFd3?_n`rd=Ly=m=TTBjiFl$e3-yFc$;|6=0?Dr&To>YZnSoZq%NgC=~g zgkc`v>SCq+0WSk0;jWm2SOI6*$~!HHEVs*NVXrrHcNG_&`lgahL$zy*;hyn*t~Yr* zB!1C(%H91qEKsF$V}s<5v)(5(B2S-;?aa)!LO9fjRwXGr5KXtC#~iKN^i`!+ zit@qB zk21A#@BMb6YR#n*l{%#GH|nXbXLj~S-}vLtzczoM>7;tevihT%Xa1%)N1whlesb8| z2lurxY_p-ShRm(`oNm8%#YNL4+%$6AqT&9lOae-mV1kpt$2%!t>j>7GEETmg#x!<$FoT zi*{dJYr|gkewm5sS`g11%cJa-(zjRNhb{i9`nK<3x$f_0;jXEhY&u=fC-aj&De`#3 z#GG#O#X@_Z^P?rP4QoSN3%HcY+D9sL(}`I-E%uu|`z&+6 zZKOT-B{R)oY7-V(T}`xJhTl?#oscjQ?F*XMCG=khvR7e6!YDz5A`yM!Hjn z@@%`V)ZConbi`qdfm=vNrA5GEeb$3Z(xO&bRbLs({^pQFl8{{pA8o6yn9{pDK~h{h zznc5!A+Cy?c=B|cNMo|ti)(!_k6zV-g4Z7HE|TmTj6Xxati`{PE|YVVtAS{qojp8S z2ALXo9_;aL-cK37m@Ew%| zvor99^uYEHuEaZ9Jo&%rg)I3jcB z%U@l2{21oRJ%%33mh8&&IdRXI>zSj}ojqAtW7a00g$v15L0+m>txt?-_s4Il*D+jk z*0j!lsxmK!Z82ym9K5mbfq7V+pvm~r*cgXhk1rNpP3ez}dM6a^v6Nd*-PPn4kfKy> z->?^9K^ls?W%8nzGYIzcf`SwIafF;$P+PSmo@|2sSsqpmgoKfYd3<*wtHOb zR^UtPEV50x=1r4I6*M>Wt_k2Oy1-S!OcgA(J2CdoU&;&_ML8(=UdSgMhH-{}X)<$y zcS%e?*|ly>;8{N#EJ7&%& z0CY+PW^hf&Xh%70`(-!5HkNOq26;_Sh0mC#TnCwXMKG{EgYWgJHQjC@ z3H7wOmt-TyuG0s~9;b2{O_b}e>0HLC`@a!h|Hko4eTFj=(e-jV(8}?2s?hmw>1MY& z%1|Azg#B3}6>&U5RTY&D`g8g`x6Zu}G;5wQ=2`Ph_xb474#6{Hhp0AN{0m#!KQ!uh zbsLr(;8Z)EPv_PF)Ubhtj3eII>cIA@(x*pqQUxy|)9rdHCZ>f;aWiwX4$Bqow}A?^ z*7Rc!r90AVo*+6DkxIIJ`4LkG;~rH=*apdpqEA1-*!^B@4^P%?P|d$_Dk^DO6!x@s z9mWSSl_H4nI`ZKd-{YxUfuk>WwPCc~te&WuAJq9e^8owtUf=xyp;2ExVNI8cl(9)? zTJ?7EF^9f(@2=3@xVMa{HSKbh=4S8LyqgMp^BzH%Qc@AhM3QZlgy&q}PYhB&s$zVs z)g1(P=@^eN2bwK*<}C4)Qg=D7*G7Fj^H~INla+Y}JU_KQIK$WRqRZ`brXSQU zRPGY#Y}|IcM)`d3n(@BV3Lch-_5!JcI<+v`%c|BJaw$;?J%K5xp z@xrfr88a4jSf|()jWYMh^qWXj;XV;|4yGAdaxVCA$sN^+JJ;*f3lADR*t^A?k&*C9 zWnv6BPUQY_=#Z}(wL38Q8H~i0O@`%Sr|dS*s`c``etPslD$iTb?VmiKs#b{LQ6GeG z7154Us&4Dd`ws3he4NDdh2~`^=r!v}*g1N-A}aocIbzes@E!#5!I$pY65QL%$gg~x zx9_&t6E6nO6#6ibYY_y$rL9<0im8(4DfT)4#FFzB+I(J8WM0;s=Yi`vo%v52?K`$x zRu>4jDQy4j&Ew zCp8;+{|zENhw(n{Wq@(f_IoqkFVDd9;rSm_Cr{yn?yO7lYMz!;K63hNV&IcxU!3*p znQ~r7t{}KqKL1TLM$J3&@xdK8D^3Nn&B=bgo4h_AF~=nN+2p_Gc_JFr$=1W}u1z@P z_#l>N(;|<6Uv0+?G+f_yL2JjOPz~z&Tj|~9{KnPVZvE}gO)>><_!BqIh4AXgtq8lp z)`Z!H$L!^uyO%Oix#!loY0S|xn|C3P-?lusKe+-{58&9MIeA@zjpk3weFgoFL}hgH23+sYtL(bU4N_hg7d;r7d|YndAv)tjjP_8 zXhpj_r%Em{xI9BIsAXP0?rXg4NHocJ+Hv88=03~h^C!LhRrb!pc+p z+Bb2;lRxaJUI6O1Oady>cV{cX>>$BeX@e~-R?*(Ibi1cYNKaTuW5VbC!m@62*GtWJ z8L1!JyRX^1EPlH)X2*rSRT0LQac0F4mX{n4dcO?O+ThTo7v{9VweoEktj_a3L#M%4 zGcTgtr{o&(DBZBuXwLVc-v$w>v1z|HDoN}Nz7C`Cm_X_oxYO(IVJljG(R%M4VKtI^ zfb)LUh`Q*7XxK{+$2mP7=cgn+Ov;8kO8dl2!$nW%<@1OsxTQVVS$in@gJ4oy-+JBw zf1Pb>Ii7>nBksaR#Q7e8F|*pZmBxl8@Q=TYL2dD&m~(My|K07x%r9OmIG_ ztheUk`GSy?+QYpg{!zd>=Q|~Qm*qpQ}6EnS!sP*eeBM( zo0z(rsh5wIPaYAQb@2*&@sfUwobKw9NIi4GDWx`wubEQ%f$03EzSju1(YU$u%W~F> z&p|0Vg7l_`8JrlU{f%UGsT)xvIV_YDp}hwlnT+K)_NFCF0PzNR^<)uIC%V ziOLPj+fN#+6)KFW2SrI?oTm>hUP#z3xZObQYN}2r?s|SCkALQ%7p!{))3rXai45*3DG$Q&DH#U{RF;?=}TSDjtdoIP`#N@kHsI=+YX@#1!^~ zc2LBtT_yW>nR}wA_RqeXE<2__H$<&oA{4|(l8>u>Sy4}mz`ZxH#!R^#)7&Z~E+!ah zA$e5un`Q00tKoc_?j0!Rr6jTZSsiTm>_S$cSnj3Ms@A%8M~+4B4E!x*`Si(pPq4BW zyFuBPHu3pY%XGxBJJQKE=*8uSc7l6rW}~hod`z^0@5+Pc^IKj-_^{(irf12=S*I7z?5{bL?7iiMy#Jf*v9FjOi7vR3qs1l1^DB)4XA<5E zZQDIr$RmeT5!V!ceGi@~W3=a@WS#N*9-$0{3)SZMDVpHXh(=^vd%^iOqlk&5_qsV` zi}~brBFoEjo|+$y>|XPTyQs89oTgywf3lGFLSws*#S7x?t}5NP8FS{EU(UeFcT)FS zq>8>evbSGz{=KABu7HM9fW|`kD`LL$y5x((=lhAflW*)2x}IQbZfUziV2vwJlHY-Y z0)_KOwWrLynT^U`=XgF-5|-0F!Ur@IuOez~51^g+2f6MjoagutPxphf<&RWB_QpR&;$d zt-M;?Ax6CLqNC)(?eU6^T)yjRrvn4c_Wia4d4B>~#@hPIx}t{54x4-Ld|r47m^Xu~ z*C#i}#Mp|~-b_<%!fq(t8e+kCnw|UEteSGW|6VGWLQv@T=H2UHb3VM)l#|QoymsZL z8#nGJ9=zWk#1qL&pWtX@EfoDe(S92@d|+!^^d@8)`?zz3pni0h@x}z>-KjF0?_2hq zxQ9CSjjPs2Na?bF+~JE!C-&RGL@hc~dCD{l(5ICjNSr<>b>WOl4A%aEIW@fGu)#hU zf6C54D-HW4W4Gf`+Ck)O9@ibm1@5!t+Vg`OI$u3GVzHZRYZG-*@VI$<^wsEYL!s{d zZZTzQO)i}=gHL2GNv}M(cbsW>q0lDj##8j<)8n_5yi(C^{}@&K6@S$R>FPg&YJbgu z{eW2f0zzo*3HJ{B4!Zab%|L585Xk_6u?jl)BY|mQVY7Fy6*1~(rWvW_Lh=F0Xl(W!4NN~_9bVD1h_47;a;CBoFPyqZyU~uT35aK~_ z6ieR-(m`MAP~tIwZ1@#3*ZCP3{_#bC0U`fDd)T5iKzHEl;pCvBKMoFZ-hWMdEB{nN z0k9P48{)(;Lu(n7+NRl?a1TV+H5=c5Q$ zYyW?x!S~}FK%n)%U3*Z%wKn5GDF15ArSX+BU&MtGRh_g;GHt>mupGbL z66VcVDbe+lD58#?!ds1XPb?`v@8k+?$D!7Bb7pg@p#qK>#*!I$e@%v*NccVS?ce1LRsd3n)d3bkpbuVFH+G0oteVs4YA zb*NM@s}vM5ziVWJig{2y>H|=`voLGk+sWvrV!ZPg$zx{?5{?OuC1|&OXfR{s;oaaO zuhbQfAu4`L5aQn8XZCP2vYv4WKXoe6VDv2w@LKuq=M85B#)h-tk{eoK+pnqGZP=2x z&hG}`z?4AynXCt@Y1zv0BV3BD4J}nvg*@N4XrBWnSw1!cL`)tWbA}tYIXk&C0ik%} zS+IdwtElj2e^9oJW}H|220+1GqwcC9W{gjk*HrPjnD~r}K!r;kS}1fVDpcx##ohc< ziP~$0dygJIlpqv?#0xlG(ZJpg@2NViUl3z8Xd&KVt-P`AIGe)2{=;jnyGhDRF#dP_YC$(u<^%iVauVMp z5F0UHkuNie2`?Hyy&k~x0*3e?GPY#cY7qR)JjGn;x3@H;b=3s>jkUt7R;j717U>BU zBCa)a?e2)L{v+*8J=5bj7R3f9*=qcrb}TP8f?f4Iawima_u-B3u;#_rCOFCJ8;6tX zo*Ox5_J+-m^S<87JwNN_@MOXvgWN;FmVj#=1j( z9)wxvo3-`j%2T_)jqF(n_b}Z@9_j7dxx^~}HgSO_LNdWUe>l|>P7AROpG`(=7<`V) zs(R0oAC6@P7cDtYvMJ@`mE*M|Y1=Bx+FfIgZ#0P&n7?AmUTms{C`qjen)LAypxuCM zo~(G2)fyW+Qp*Ay5gh=UN{2{r!qO~Z#i@h>$rDZoWqD`J#tkf9{48JQ9!#kH+%rpH z8_CH9icjgYH_gxm0Hl*Mb1jxaWbc_Y#^dPElq3|BIf3HrxOTvQLHRVGdFr~6z^B-_ z%jQgG064%L6uj6yoXsLpz#)^MMGjPAKFo%v;{>3wwKw~Omg5FIpcGKGwCouuUk^=w zC7$C8o*Q6S0uc`;0YFH@gn#2SQJ`t?6qf~5Eet~B-Qd@@aY`RhXP9%1WG^t62yLDZ z!T26iN`Pofv$IIhfE^qsKm4Jm5>zBAWzoa>fLH_~JOkzS-b?p6Eea2*Q9O zZDKH4bFiYV?!q)@z#XZn-cNGlEN%esS(d$%s>!mhyG zf+B5*eZ_5Xi2$Us2q_7_l@FF((ndDfmWzjhlIb>^8xfg_()E3Ed8IGS<_^!b#U`bs z(5i@ms8o335n+Td>^%+TpJ*wejPmW;E`(21L^D1qiiWNSTw7g!_$)K3(r8F9GEe~_ zj1ZJfl!{3u!bCO7KcRaoNhvn@fEe*|0O?ZxRiN@P$cL5Q&r{{iZFQSF-z8pH_!^4w zNg0r3oo!!>x<8WG3kPKHiY!;EC00-ZG@QGTB%0#$(yUADsoxPxzAUyL8*}a+CMiEp zDGC%-Jc3m-e7Gz|f_Ko&USk+Ou$~NtW1(lERA9W1@By*gJR9)0+YnR*Zt)YldE+Gx zkT3yWrTqt#Q$x-;%~PX`7nijAV+sUreXb9AIcrOc8ZrW899JS9)Ze28)SklEzdXo} zg5J+;+g3)euN-Es@&$k*>L|A_S|~i@B3_y%WE) zUno(xRg|J=m$hEz8YpPEv~o9t6JH64D1ag1^|9{2r^N z4QYW2vLh1YfmjJ#51%wyI;eRgH5hKBuTP1xA2P6+8>9)?+`WQWkFW23am8jVz%fum zd3@3~sBQ)0DW*IWCK4PRO>fqpb;u+p&Rl%%ue#OYysC=r;Y&;j4G%i2rdee99Y zNN8p)Frn!N7QJuKP8o`A?CP(aEFBz4m8V==+)Q9ibFy4O*)Y?Y$x1CWH5Otqp`G&J ziCXEetQhX3KrMHx6nIz=@o54e*n6?c#|M-svyvcoZ`ftPunesh1_1rsX^uFcS-7Wk zmB3DBK{W6l;0m{GGX(T`tBVftS&lpa@lzm9J@lqCS^#3FzfO$R9OmS*;~43d;<7+8 z2m@mlny0>VJ;G4OYlH+0z2ZIeO~~*cW{8oLTtP+yTszu zwa^R9=nzCIr>&n^A`F(Y_y{YM;mPtMh_Li52{63cE_WYS7t4-dxi@-OT`k)e1JLxc z7oIRA|_@RzEAhgAi_{M2^;L@t@r_i ziWI5Tze8g&)8TOO%_i^loq9Hj(~0NJNjM5$el~`V*o{DE3KSfkzS^7L1H>Y0UxHet zOned^C|0&|DdneJl(3r@=-7=qwC28(oeJO#u!ePiddG9y;IQRJcnT5q%s|J;-XLXE z#{vf)kOL@p*y35Pl0!M|M4o`=?PmWdET^aY3ksx-1*qgd*4f`t(7yl-|I2mu|CQR~ zk8}8s>+GF~HVIjLaqGcVr&}Fe5Tc?Vhz?F;GSv(@X&mZ?>d`c_%xFzeR?zG_S_9ZDw;S0d}j+@VMQ?r`%GD;5(t*ETQwA#B4TTEbt9wpJM%4kx_m@DR5a9-I^$myS0w-pEh0t5jW zg#Z?(Dp6*UAz%e$bU-W!A<9-FAcLR?!dsFM*t9~FRuE933@Qjg8-{`q30h+7fI$cb zAw;PqLugv{@J&eaChzmy_kG>heO;=e=5DdTNmZTKq%y%`dO_Xv2vk*X(t#XV}Jcgbas!8^^+b)m?*ma zXbI=1O}6ft`c$C?MwUY~yMorN!^UEI4?OFTdld?B1okEFdDYrCH4YjPZdbSep6p^$uYY7*Vcj#$?NL;JA&Idh{LIdc@lE zZX}`{jP9N2UYE1KMRvn znyUxYDc3a3Z@PW|d+~2E{(4V}?C;g4nEUEkZdYATH?itDXo&Jl!ewl8jl7jB>X__z zt4wW&D!#s(Sh=FRzoq7He*CpJloe^+sh*!&e_+4bw!dSax$fS2s!k{6SwbYkjh@T3 z&^*p~`~B~(@QO@yJ$~)iHGf^PO0SpB=DD}b#(k__sVrMvR-0DknyR==S{B%A47TdusA`G!^N1hr z6!tQapgJJJ2kJwAngxZz<1)ga4*&hLRbgZpj5)3d;C3VdsGkEzuBOMJOBDbO$c(b( z=V<})tVTNhyfR-ZKLie}OHZLK2i+y^Ck}!Sia?tsnYPf2x)i^>jVX?Q2c~Rqtau*e z7ArE98AgT6Oc^ZR*^_=&-q_>HIazPKmJ+JY@uM~}m&0eemFL7)Q zgeiGp1PxrxgnpiK{*>LESh4@2MBWVL_+&)>T)0&1GzJZ6{qcW|gTfgzfei}&6~PVa$7<>ZY`wc;ZOOqZ{W z_^X;}v{j?7mnWEfLU}zg2^B;@^CNQn{=*C(R@>$VRUMC43ft=(l;Pb#Z|wuok79Bc z9&K1%0AHKqX?yTApH=H(6b;dKEU^E)QV;X?iklYh%o;nc{^zxP0K{Zx0R0dRsanSW zr8CGs=2lk2(~g~Rmgk>Q>p!zb|1YD~zsn8vKW1^UerT1iMS zeNXwo*sZmR@R|Zur)@%C!Hp#ODu(g5H`?>K7^;=+UQBKWGz2t0Y;mi%1&+B5hJ*xe zA^EtB=0)y(cm38VX4ljon&qPV+ja%jUu^r%sri{&JV*PsdaCL!r}Gwb4T4}eK)i2tSff%Z?6k4A10(gtBuCLf% zRveTL$`2XUwUs`~;iOgcFSB3jCmts@70Q&?hS^`eeJ%|G(N}m!*Lkwo3eQ@G8#zRW zpv6>t@odd}k0(%GCX7t&N}t-!TQTZ2CVpTpR3NL8l<1E#AdC7!R1x)P-}*FG5;-R~ z2OF~V$;f?!e(`sEEUuK0bD$I@FG4j;7EmXP2&(96d7pOUx!zS^bFVG$(WP~pR z5z#V#JxjuQROHL;C1f=vAdY2k|L9Zey=&h||MUfS+kwBigb|5pmghjWsws^z=)Wy{ zo9#f+T!CjRVYW1~tlKIgCkyCJDSw>!loc&(&`X=%;i^Vv84S!H`b&(dbLRN{8>%5 zrf1IVyZWG&pOnT*93Tw%jmUcqJZ)aKcAnNB{=u{6vpCgD%2r-dIunlA%BJEC7nmz? z>C2uIb!@!#Y$%C{%2K1wlBRE$+TR1U#;s7qEgzq+Z1qtsomks*#YaUcj2AnL z_0$R2VkH}joA__ZlMLCNzJA$1>%iH|)j~JRby%|4Sz&wZS9`ZE(Z#yE1q|?V7ZaY)n2BIIEqlS z-X30)WlYyU(lE`VtlAEtU>Jjn(M!5lLN0Ap~(| z*+9t#K9jh4L@~T4^-E+rOi=|98H_&k&>psADjqs64)g9+GTG2i?+>$E-%-B=p!S$M zB1`WBV94{maaiW{bv{&BDX~YIc`(meIRKD-Yn-q zM}u|cSMxuDzJ%4yVNPK9ibG48e^D;_7Re5C(7@PgWk)bJIneIdT@>`Dyl-r6;sdb- zEj^;1C7iIX=gS_oj^q`C|5}FH5o%BWgKfXV1=?Hxb8r98RObK7z5U;1`t*-;_!lb@ zT(s9DY8me5aXvAVE}z!KkqN3FwO8`zsaBUU9YxizwyZ@Fj>@1kIn*uKscD1WAmu!9 zy7-L5OEgQ^Les!24I>FoYe|FTBN6^)XOrEx8H=5oWDA0tHKB*b|6E;7 zE(K$VY)2PU4CmbE{5Mn}kvwip<`NJtu*EVfb-uirb)C(&l`TW>;>N~oro5Ia=J{|K z32Cg+ebD!iVAsu`=MDT#Clklx>igiGHW#*(7!uoz(2ke`1oWFWDxvC;3i`m}RXHyzfrH_r_Zq3oa{wJ07B<G+x%Lc%k zFUzrMrY0aO*{yuJOv+TUSAIDU{F8W!JVj*Gx9MHVe5GkT0Q=ZcYUE%It6o_bv3a|RaaSPk3+7}{@@F45 z2=HEDb`kw-mv}FVuR!4pdDtSixpYPmg|v%R3w#@27I?~$fVylcSS*zhWziB)>p#cw zKXqBT_O!5mS^;%`JP#X3<|~|oc#4G^)il2Ggm+FI>6^z|F7A-v`d1Z#D4XecSxvkK~#%pTyx0RF^#X*ZK@lp0C z%G7q>+c(iJoz1(XsqO(Emi*Z%V;h)k#nH^@m3YZW{P1_1RUVpG>h+>|d1?2^KJ>f2uIoO>2jaNzA*Q-FHh8c7i5Qx@6`h=UxJ(RCy{4qs>qp+>~9R#Z1?lp^HKycO9ZaL7FO`K+T1n|xgb`b;r+@1W~ zcWfhhY-7D-!A`35jOqxJXU)ok(uSHu6&n6f=#|;Dy<>>n(L64ZO`m|5dW~Kmgfhvb zhV-_M<4lmEWVFhp#0cQBfub4^Q2Rqzvl#;2p1`AQxI^9s#DL<_)&7Xl3RGqLXaZ~a zjM4})xgF*_fR=*5{SU|zI;D!tAW5C_Hd)UykG!p^#;6_0R)xT2Oa&6n z^46{GY-1AB!pEW$C}g|$>~CWiHwBH zLo`@6VTYKl10;um_{6=9`)P~r*}T~bKYbsmt#_waZWT!@$c0HSui_*+V9BhfYq{I* znKDN{?n&?_&`O(VmR7mkSjODZEx3$8@?x2{OEFYTg1V>;zw4wtPiHuyj^Ivdn?T!y zf%t}%+*@0a;ZhJXWA{dOq=naKSPZXShJh}_6_v|9hTg!9rToB1yo&nr?+;_pzVy{-NjaKg2x$T|O6%_WuvO zj#PCI?5NXT?no^C#ZOL9O*`hqBNyx|Gn?EX%B288vm_)4In?@4XAomO>*m+LEAct7fT0W;t6N zbPIqNtds0nYRdu})axs6ke?e+NJl~^`vZWCxo|pdWUoS{T2CEnR7q-u14-Ek@+e-0 z99}_y*soLxdNvV2h)hR;+=SkdUkRC6d@e}{_>qW`&D}|CV@I?rneAd^sIG4I(xy3{ zgcx2mmVNGKTS*rA2r+o5kU7p8sb6(J_P&pG+RR+OgT-?&-Wcx{h_r3aAm7P1hXTEM zcYHspJ|H^+Xj+MMMn)a$r^ECBm%1jOYo7a^Rl#3C6$Nu;kE?pBH~PzBcp1(^JjfRd zi|TtZ4V61J|KQXl$Bm2B_r8M~gldh=hPDGib!4Yp)PO&!QmZLGe6(?N-%+Qtycao4 z!SwXh7fYooUK@%9;R?X?Ki#9KlO65=;bPC}Tc$e}bQQ?#`jZ(5qXy>m)~`Gkc?E6( zL+W*k<-m;}LVH==k#j)0cxl>f8J1HE$2}DyR9|g}2OqrLC|?x+QAjXf1*6S|a(dW< zuXjbM{D`$zznIc?12l^F}O5BnWkQ1$!29ajZC?w#f97@Sbl;1`F06rR9^nje( zk!)pwyJS&1e5JM9GpCe4J%-Fo@7tB+@I@xGeOln3BRkjW=Wu@m;T~_0mwBvJ-oz>+ zsTqiL_^R54$K#pD+BRRzBOF@?RU9G43B8At|qN3@` zBX{tBz1J$=LM-DF!TxFRfxUT(gAiR5>3ZX=|4ZH6h#GIzPHId8aGF_j(8-*v-2H zMA?XBDH{5v$3q*6LOg77L6NFrz62&hI(sbHa088mR3@~2$g0Z&7#@PxgjSdW$Sf6$ z-;)slc3ek>JDU)oWP}0b_Y;#Y4r~eNVFSJ{ym0^kX-_E#Q+CN^bp?;U_f#msr8CUA z0B^;RTzT75A>IZSI{Al=A)t=&K&r@E3acB-jJ~8N#XZguA|U}YotKK`naz+^)v08Q z+&jg(L@CS>>&9CXZHG4WUdVN@_aoJjHu~)#j@31qVOxCUu-tltGR!f)qlfXL!j?8y z^gR{5_dY%dTT@U_WWDu`jRJz=3i2`G-6N#qFm`;xFrG1>-+-EpbN)(2gixn~J`zL4S1HqVmQg%H-jI zuDVTOlws9whk~h2n|q<^RDwD8Exw@2LhZL7r-}-zEX>gFANoGAj!>t5ZHfPTjK$_N z+l%_uS}w0qgBRd`@x^e^zANP)K=mG_2Uzm*8`^KHJa~xx722o1P~G{t|G*xDYxmTt zvDhS4-8BWc^F;(72JZshm$p+2ZK2&vDBf$3JF#+AyR!V024nYyU^Cc6THdVkprqGf zkOReG{Zx%Zuf;lYzr=?{9ni#%hV>qz$1ZScD&V?f-&CX}x*>BfIt^9LG)v;?a2Gs+ z`0WaYs)V{Bbq$9NZFysYxV&?5bT91O9t+D8(j2e(#OyJyJ)32es(rlXRQKuS<}F*N zhsQzj@^3GjT%rZoxd8A1uA==4-)1w}^ktCA1U<^`b25p1PRVX!zS8<#H;Is{6*Ii6 zK}nc<+|wzMOcU}~OpRXBXnvb7_=Lj@cB56Jw}atM7wgKwFKGK86EsxqKY8N*+>;yd z%Okw`@(Ioc-(ND$oX4b2T5AOM+ubu=B&0kpB6zB5`yp1jk6*2Q;TrVNXr=4fKQ&F}Qz8y=)XQ*&(W7xiU9goA2mhbC_k z)U>6iDc{o*p?o2(R~BrD&t{H9p<9g^V!*%~E_5#530wkuDn- zIT;gZhGu6C*VOB)dB5Q9wjv!Ak8ktb`?Q1PNLi;@7QApKCa+;X$$WI3rrxco*Du-? z+R*2Gn|mf&l&@UsIJt(Wn>IRFJNxph>Z(eU-qRN=dMnpjyr3kenZ?Jm9Fku@pR#@P z2M3z8E+lploP#kFvG8tW_2T)HszFNU#y@}IwLG<3kT00jlE2=4;&eryy+059QPgJA z(%OZ5pIA%fXp3D=q`2$u&TPvTp2}#L26Uu$##=%a`LNl1kA~_-pLRq?0L2QremUbi3IsP0`4m8^6 z-3#3}m!f;RLA+x7ZN3DVJq~7a_?E}(_%h3g!0mH0TGAzjIB8h|io1ye?~z4-3@fjt zvHL%0@)IGn^cH|wLEREuF_I;qD}!uGC9zUbWhCje!>x=>{vcU{8WyhO?y3A1I5$ZDU+p2&! zvPT2n!>7)iQ>05Eyewh^==`@hhCta_X<;Uiy{G6x{Xombtsl`d0Lb}Z5b%{3Zl<@(=I zxP>3PS=VZtw((luuz%ON6F#5wDB|!r`RUU1q>HSQ)6De3AQx)1&0NnF1-@c`J+rmX z&yn2rLpGC4psh`ezQ!BNY_A{sAVO7;wzfi=sOn1JEZ$U=OE>o0v8vz<4TBaT8Dk*OmdY{?x>e7D&OudF zsNpvN?SiZl4$52KKl5|wQ*%{ba~KSQOFB!7oChC;M(xwQUTymj$4TbQoxSf!ZZ_=G zsPF945~1<8@HBf;{q1T!EQh3GGjTP|*9-RQPhZ0HawFCCP_V;Q|8Nh1=5ypsUqRtB z5`^}xG1!9qOTD2T7G{?Q{2pYvXnIlA{;~-)`@CFr&sTT#4DRX~>FI^*nV&V)YQCr1 z@}w$pTly3!9<%lX>&H&jfuMw~^;&v*|BX(dBUHoq2Xt!h==@K~rhkah{SPCs>%WVz z{?|GDixC({oYcvfT=(EUmW%5Bi27z^a$RNa+k0Buy`ESW#9n|du59e?fWX{|A3yiA z&<=rNG=xB5xJ=aQs-1*tkQjOucDtsg*ZdPj*de-?(RZ8nYS$#-i$bE(h1ouNhk2RW zLXl!#Bp%x8&uUIM*{?Hj!DG_EEgCYKlN*%GL(5%^-Nwj=rfvI+54VR0^O-UkQ3L8Z z10rAH8Hi`N3 z=~`6}K)YP3-p_uNf#x5%4aV8D!>4yfswd+L{ZAsB4p!Q50;*hf7V^B=@ z>>MxWXyYr7__jlioXFAFEdt(M=Sy3I?fSm@=pzIX6qNr+LN#Dt{PN;4=Tv!eIeM2% z-$E*hpjGDVlvs~FwattxiM7wD{Aj5WR5d_0-{my*_8i*D+&!mrC87$hRlis47u{2@ z^6}@sh0dM{<4`ZOrbskgL2wH~m6L4fyfppiPfQ*Zxc#~%h;~h|kk@kZS@o{a3P5(> z{egEb`Q+zJ1xQjhO^7(?-Opy5O&(m_h`J5@#VvCVmnBJ~a#=f}JHdrKw3K!G&$#VP z4nvNz$gxcAMg)N8l^(Nfg)`czXXO*`=ZQ9@Bw!xO=x1lO*Yl7?Be4h6XaD7L3ssx<;rUpgxladseYrulm^i5yy+{p+0H=NQ>tLr%_(Zz z*z9;9=;Du#3&G-AnW9zMSSJ85(zlAI3PDsCaU81b185z`rk6061Yv9#jOE&=$9sD1 zhQfu}iNL>gct|Wi1pVNNtuS9T4oLW7eB=l@UfjY79*WOyE=3v*Mj{aU+F>?mlyz;& zj;=WRTp)JeINVku5%g)~bbp<{ye!vvv?J(dTWB>}(?C3>@T^UU z2FnsU9eI@zmaXan6v@25X&TpWh30u>w@Ash`%Htjv{1C0Lra1V zXqS_jP-OR@f$41z7&K?<$&@?LJPBE7opE#ET&#zlcw|bP-mOD}SQZSArb7-xj|YM_ zw(dU!w+n6CVdF!CfrA>*c`YxVk9F#^CAJU`pwCdZ?d(NI|lw3q%$(JU|ym3!+ zKdZ)&kBO*k0b;L#2&+6S6n8|XuCJp#@9Of;s*^ub;Ds8|vKBHJ(H@PT@2E&TNA zM;CHi9AD>F#hX6dvzN9fd)o&ngT6i<4Ak+OTNk=y3M5{_$7~tCem6dVZ7}6yII^m( zyE>u*-8sHYMVaR=V7b~IxI3RPc@L_}Px)AlYzl#|FsAA@Wl8{MGBx`0$NH#X#!Xq> zTwtNa21U?RYc=8fgvnLsTa|fUMz}l9Um)b*e!(71-M`yld3(0s-&{2(XU;$iB-Edd z8X}FI#;HQkyb$P%!$cCTbP|1^KW)YOo3S0w;1< z{~DTqqj&!#h}(@D-1C0fytkxYQy=ZpQfym<jy#zEULKGe#%xruA*pH&x8z6E^IJ9JrIwv@^j;y z#-=rG#5`?JtNbEvqYmb2%QIEEpNCJk!JBeNOBgsc~VLD0Lydumt8=i#U5vM6_2rH*}4+NgcNRx zY)&Loh=8c4c^Vd9@j$+lDgr9BgA^Z#PG)X`I_8BD@=Bbq6xwep#9NoZTn-G5as((k zVP*`|cm8VrE!)9vR)U}N0^ldmhX8OP{LjBb9C9oxT?mt9+*{@QqBep$^tH}E>kg7W zqCrGIn8fC^wkr0xGl7x?mKM9;AB2hcDTy*jK?HLDY5piL(GJYbWU{L3h;w8gHb~rp zEJ|7J(NM8EAaUCfQlthl-b)DqacPnK)0QJ`K}kPuWmOnMFmrv@Yk_%t7W<=c_hezL&9I( ztuaxJg6r`J;d@u}K{N?k6wn@c55ii$ylS3M^Z3$t=$BhHs!3+lFT}Kgn6g0J0N``Z z=r%ypk-bHUo@j^EOsBqN*n~B9x_EtCJ;j}lChhObq$Q6)+7tTSc8BDt*9*qp4v8&! z9ljfl(9Si9@cZ<|m-;E|F1FE&Z7&Xp=6elxIVEvif^6Tw$&Li*mf>MoRk8Oe{X&G3 zK%>tEg-yJUdNb5{zJ4UgTc`1`Nw34$EaNQML7%2S_3DMjfy9#eXP#7?R?OMxhifKHr^;EXFeahm3c-P^9ld8c#h+WQxl*ss$v(lDiWX!hDBQvv) zz^`AZzzm|DgN+HwcS$qq`_@7iw4k3R(N0bDlT|+e8G8_NCg0mO>UmN@Q0^dwtBhnW)~f`t^Ngw!4) zl_N8<_ny#*6>fTMQWgacWkH`wNi@uo7TAef6T6f^8xBJV!Cp9zH3wEaWyGp>&_`>8 z8zCU%JRw$&;BvE)E`Cf;*xR3^53!*acXrOO@fR(ei1$bfPmy!VIOYd-P~EEcWL`IGMbGlWe?2)2wP*i#5$p^_oc|Ah z=r0NO|6vgf)ldITW7~h7#J^SrS2NVrbDwJ_+m{);-`_A3H&F=(DV6re z@g~nq+;-ddS*y6dJVE@Mgzx z!4Wd6ESyP3U2Dy*eS{nA3~C%x59LH8(yD0`a?3!-Kp;*KhZ{(A4D?ooHZdHXA7LyV z53N?w_$k28$x78Ycymc@8G){k)+a+y$cdt@9t5+k$CG7*_nU5!@g;Do6@#Om+I)4Q zjf|q=A!%_zgmN%>Ou0oxPH-o2SGcM|)MX{O(576se+>TtAe&U_nW?37nif}Z5m zmwEGjo%H%S^nsBeo5Z}(YV)$>saG7xrQ*0IU#!@xTT_$=qxnhbY2Fd%XxdO~v5?41 zZ_kOV7(8cxBgxNp#@MOkUQS6BHSVi>w7w~5Y0_JXMmwz+_;)N|6NMQp{j}FB;?|ss z+6wJpPH^zW9o z<%BGs$kb_)iEh~252Rhkre{l&p9@ZRgty5ERdeAAkCJ9h-Ry%>4l>5Oc{8$!nVAvf z?yM}W8xWr!5EEwy54U%xXDJ7ouVwZ~Bj@IV6m5&6LRqU)o;l`OpTb8X8-Rj1DxAH6 z+-*QQ7dRs`nNda3_NJU>K6{aHFIUN~8dh$7d9Ghi<^w=AQU_hl!e^BE$3OJ-zfBtI z0ZWe%?`rCpgjhV>));hCSu!^#B`RvSN>)5)E$ejQ3?Uo5wEJirI(n`X$a|wsst{j} zBuEt5D3;H425 zRYWTCDZ4viY0=!_TdJTd1v``w;TT>Gs}Qwc$O6kra1Jq3W5pT7arl5{q!a>jI*3r~ zBnHfl0vJwfv3Af8I_Zux&1eSn2mmC~>K0o<0s&jGiiOPpIdqyc1KLV6-ioI%-4M1C zAdKOj=!+l{VXT{cayOz_h4;Z*=G;f0d|3iTNAXJMow;Z9E7kRE@kLnmNVknb3Lu0q z#K&4!^1o#!e+A2-Qy?AorQ4PD$x2BQI7RT9P%3f&U(pPRuxBwd-1bA=k`NH%k!C(n zv?`i~hf6ON!zmCTQ!*8GJbx^;izraumXb1)671U6PO}3>0~RG5iBly84DO|DjnSJ2mjth1Q4tZG^rliu8R0}1W5HI>aVrSX|7_|lbg zHwBHD=GNh1_#)i=k1^?&b-L$9>WBrq3VFv`4{wJ2qqQ>^>H4DqjhYALryj27H?9|t zMi8-C7MHWg?iL-*O58HV4kWI*4{YhQHQ+ z)RAy=sE*`R#rxz<6XX-{)MK|fBouT5?Nx~te`U)lEG!hj1K30uB5W%h;1H!Z1~*i1 zdMpOhWVF#f8O}I2cCETF2JYVxGW>YjoIaCQB>TlCt zj+~(2dK{_SH+dT$n6frmqXXx&d~n7h?1{cu%E%T1<{KWzM8zDAFXv9QxN7S_<54F{ zUy-#9liwi1<<9ry!%OKS>cJpIJ$D1v9y5Z=&{K7s$Q3ox*7aWbs1;N985P$GTel7$ zcB)e{&#QS^o17(dGd!=Vc@1(cv^3DMsPK9%ieh>58ryPWgLC*iSSG-c{s^=*KN%by zd9GvbQ4+b^VtvHf0t>bNR1>Q%#?bmZ^w1fUA!%vv)3bf*28krxGJP~2atPmb zY%J|X897nK}|f=Bd^nNyg>7yJ;5Gy)sueI_@KxB{FyR zd(CmrZ@ye}!q`eivN)7VT5ZMRX`V0MSyY=RU|HwYc{D59;NDq%j?3$4xcNV8d1py- zxcGb_p)Aaw1$XKx(R`7MKTDs~*MNq_VEIi{vVrPL+_<@$#}~L6XdlPYVCj>0lk?Rv z6J9OPGziXB)QM*r$6ip<%w0~D-t68Q5b0l~z)^D=-jkh5x`q}6!6nP~jtfm4q3K z{+JQb3vOi3COO#?goks|dFgHXk!WXtL}e*CWZse(61zDh{^&I5G-NA)e{)ZxSe7GB z0z{?w@a4>#WHuP;gyqg46n2;$@5`12$U^`Xz|_MGCwpPZ}#&_5C}xZLn9Xc5C2Qt1f-R_tn(TVdJr0roqAIA0~iBpV4e+J_4+;s6yRj4q6_X!#M0e>h8<_3r^krD2$vG`{)po_ z$m9VNtze)J{sn206E!R#f+3}m7NDI!2NE-3VgmqizBmkU+~Em8z+17(%gk1?(Z6%t zk@?(g<_u7dO5pR#wB!ik91yV=jFe{6Wu$GOUkL~v6uClelrL(7GbCURAPemf2M6*b zg`Hft=+W6y0KqDSU4RS{;dJ@ZRg=;65cRT?!vFU{;#sWA??pn++k5aJ!spHJ$!63j z>=fnr>48{te6u@&LM>3x6;_Xsx zC1tZ?cuB47#okS%jS<6~V5vO*@Xt3`-Rje?U?-S4%lcE7*{NWHK8>^?FlQYw3R%#)m1W zf3XU+!BKpxL;45(LkaXvuyzP-8-RO12A4>n-N6l_&8v@8QAuBY_0>-4ZpV7#s@xW; z{d^VGgO@PK8r0M{667$!5s<&G*Z9#Er9V4V5C4**EQcC8`Wj7nqldO7o_^_V)!>3J zw8Yrv=26j<6=Pcszl?QMEh~muQA(dipAF@kBlxPaAT&giS`r}24MWy`mEJCfwJJU| z&`J-R9J4wXxo7_`XnaAeAw>Hi#Amw3ih)gmQw*0=%;|n>Nf^c3*kp&2fO%W<{`g-W^Dc?1KVLW;qxFLb^hwrdE9t{)qLu^1bkGfDqibqp1tZ03v{UOi{z)fwYi_Z zseg;lUvrgywdJX^IkwWf#K*-hX zaSGF#ou@>`pNP}ode!sP|H@&>xq*J)DKDnweo z`ZV#hp}C;uAdTZR;{AqmD@256461&K<;4B5cN86c@%2Wdn!nfH`ZLpIyof;i(zYDp z0y^fqjD2m3oJ=ORC&-)x>&l(oPze|_my^G&t@*(l4Z|&qFXCnH9n-d*d(jssV(U)5 z>Uz;O5L_avG*pL2o@IDZ$u=ip;NBw(S@)g(&70>2f@()=$4lJA`Hh2WjqIQH{_!+FKq$mK-EchwFGfMSD&`a5LFaasDM2n@?6W^{@~}L7{$yP+ zCFv$F0Xn>j-Lr|EL6YIp8Q;10xaa<7v6(WtvRY>(&gr>hv~n;$ICaOc#4tUxu*T;}*m9KL6O9K;N z&QKVNXcfL;i%1|q3P-%8&rrn?A~|!Ot?ZFLw^3!!COGBjLN-+tDfy_8OtVj!Y#ROy z^<*S&Wg<@IV&*A@yjo(OP^u=6Qngu`IH{|+Z=`7LwK%%n=u?Xw2@qv4I01RHd}?Ep z8Cz)tyR(YLd0*Hyr_2`}wGpn^6bYA<>?I%rP5i~n!aC?1&XmaIIUPxaB*{278h#UH zN0O9tLKtX!lwf^Pg$79tX2LmR=agpbz6`>tE~HMJsRjGY%I+ipp%$ESE}Db3-3oJt zx34L>%zL{gvB)S7-XMivfE=5zt0Y*;t;SyGuePS;v2H+yFy7vkskXE(uoLn!SGBOt zVHeq#e0BN!o2yNcMW5nn;UaUk8%Pw)MQ=}XHgjrZtF?JrjKcxQ>sst0O6?cB7GW5U zg0Dcb2*l}q0sKWC2#`a>G{UNXIo6m(fwLP-MPl8s;P7nel1zMVm2(e=Ic028UCxOA z5t7|Zj)*zCRz&OJB~uqp8P>1!(;en7lkAp6wAL9rsv5}RHydy8aUYD2zvA8?Q}$^@ zjEgczQ5nn3k(knVXSXhs&Tbu%FPc{WSeb#(6+^0)^v>BU{p1}HeOtC|pO`tj*|GJQ zj+@t9>t^}LEozU|`!HT&lHB4htNi`pp{4_;u8E!Q_W3&sj_I}^ZrUK=k=+Z~7Yl=K zk!-ExrtkOm%wfK$A0**&2M8@Cho*1?X#<2Ra;tV#AZ{dthS?~odgZZ-=fR0{ZyF~J zi+>qPc!_U<_}$A;TxvF+qFrz0@MLn(Ven%%JV;w_@46#!5Df$2X8aJuRUr9`H4?Z1 zmVN_=jp(-rU)FYCYNArV1L}GN?BbW$XP=8Ya4}^*yD6|6 zl&We)fm2hvjZ+}8tKdZ6p-p?%^*%jjZEd_q`x~D(9?dRr8f#L!syW`U$qv?Kp{0y3 z=wWMH+OFh_zx1ZsHTPU57lwq8Z4FgN2g*iE??zR3+j;DDYzYCqSMZl2pQ zX>upGJk_MdXM=+f`fxWxhLSTyv(+HgnTPDk3e~-%6;I@fg{De?h z7q7SHv?zxTDt32RXs_?rW<;7zdo2RuTcSXNzn~A>;876FAWEccWEnsjE?98j^K^f? zXQDu9`(%cRNsT%T8G2}Mv2|5NdkLMv1wL4bDAJzJCS6tQJ z9WQ+tY?Z$qeU$E9NpZcfS_Xay-KkrRk?EZvoZI%E@`oMwna_^jINP!P*c_K-n8JBi z6#+Z6-2hj!?N`6DIHWOGUR1~eaSyoo>y7(=a^)Kk$ZB-Cvs{7qji(9ogx zpl1HMqSK9@^_srD?iRsz8nmn?nz2>f@AK8By=@%QE|)SN0_`*{g^p$QYDv+fBy*3V zKtrepXmf(I&cL=PYwu{8=Ld4l2~%Sqw20-}S#%UfO+-=sB4}=2)N?h7RUrbG1Y3%3 za}n_@11G3SY^9JaEXur;~_rEjvz})4m1nLY`^ZlY2Rq=mFH@0KWrNe9zb|( z#dVTrZ4*4-@NT4w2-W8nwrO^u!ELsJL3rX_rK zTJs0c9LiQeR_c<1FNZ{jD%b*x~Ebs z7pL`oY8e23?EL7fa#BI>16^>~?o-RN*JXi5eBnaVf$Dd?4NwU%7XjJGpOE`20s|M3 zC8XyXvTXC4tbN(H6aasSJi?tAl4cd`QCP_(;9;W+4&tpiL62~y`%oNb^;V$#2s>a9 z;DcGVlOp?x9hkCH+^6I&7=fAElB~M)Id~u8;$5&PoPn(1HnX|0O-#UqwO}cD4;4|) zolA#H+?Nds5um$BP}c?LbwJK~cFty?$hl9^(UuY0g_;E^Z@R36sq0_oA**bNrABaX z{S!9?_Uiy+4pDmROd2OcP!QB91y|ha_)Ejzt?7(dXoNjRcB0)l`&^SE!4ndC1swt7 zUAk-~A0Ty-bUu*PHqS71TS}Nf0i_xE@p3ZKRx(+m95#g^O0g>p7MzDm8OJx#E0~I= zk6vd;E#aY@NRsWZ>m!*me#x{vY3^oIMm+QnKeS*83AsBWy3c|3ZbZ_2rB5rnmb#BW zLQ?-Tbb7cyWxpXAAxFHrRv6Q(E+B@)x8Ef;8VJE7#~EnjK2~)b@JTcsUfb4v9RE6! z%HT11zPz<7h{ilZ-eaEjXomJf$+uMk|K_0vaw|C_=xjOKVI*#YXsA|SqlL3jPOits z8j#Hl^lyiaY*Z;wXtn3rBCyMec+lFTrVE#au_7I*C*@Z zyfL;hx-ecChX&$)%N0>S`&CcnK@Hk2w?ggi!#(&tJ29!+I$k3t?cS?cAcWEOATxIK zwLPA&T{RMIvwFS#^XtFSO>p>+sm4_k=zq37{{^vX=(G6ms)_y|rW$d?f4)WVHwbrb zHNX2SY_|dy1E;LoVPOj_gMG?3brZ9HBPF2r)0=s*+*K#dT`t=$V3hJ=xGU-U>RNVOdlfmTY zW@9hD4QZjC7PaZKcZ_8sDJv;jGjf>-k%PT<;A`!6YtPBGYXSEN&R?Bv{j=fIhju48 z76W(!Vy|a1ze6{QXp!w-mDZ>S~6=nJ0#gW0?S@3sph|93u}- zt%R?Ba|I7DPN$*ighm~-qCp3XF*JNa6k^P0Y5=SVq+YYKOXJ27Kt0h8@LYkhvlj@3 zfCY=y8VfErLXtQ-@Cl|&5C{w&kj(&=^Ns{uF-X_OUs|}D0AH7|Haq^aI<~IP&*U{N zt^Ys``~u%NC}IA;nm+%3ve(okVTen2F&0lfU!J>@zu_Z?5s2r%yp(&`C$vC2IV9uU zW6z$K=K$Lz?+c!M;kWt1k8kn5+tjo-zHzGb;FoIz7HxX#IQwzeilcbW;NU}6Q^6r< zVyC;6*QT2l$+zbd3wyeIQgan@ZI#A#M!9YhPr)&M*+jcjL5=%oltlcSF-a;h(Off< zn9|o1n&Q<$)lIfSyL)7%%z?2l2g3b;!*1TRK0OsVBDWb?DFaNtzxU{#%4IC zs<~%h`i}(wWRo9y4x%fOz6JoT7BG8=N+cQC4P*JnuvAP)NZl4VX1ZwfBBvD5<2UQk zCdqS0E&+6AI%*|AA_ zSJ1lo{>=30%#7@S^beTBLuH2Qs23@JMRcHW2vDp9(EKk@)Tn^r(|$B+*6)UbsqtVsc`>MK@a1 zkts7Qh|&!K_bg>oJV=9;J=b6l4UO?{*hHXu$QGX_1>N0eHoQTOYLja(Ym}PpgDEjv zG9M8<#%&;oU@u(SrM2-TyRgB=b{_?*RZepGNm$a3HpoJV>OplJPafI$JV_t5WV#R4 zq3?B}`6w2!Pf<0$3Q;WqUPH@>9dJ=`J_7qQoFt}s1>P)%tt?DQx|zGhM-X_D#84ei zI;)#Z3+d$LX27?y2F(*gwKp&u#X==p+G9Ph@mMUSjJMug2(8M*kEvlLF&PbdI$^9- zf!cNuhX07goY^$M1Mdg1&W==8$Ng&}88c=ayo!T@q3n{pg6P3Bc0xCHBq3f3YkNN$ z%nCsDXnQ`&w`vHxq8F&Nq_!cPFi=Y1il3S6kKO&E<9Z=6(op||CQtY+oYg{p3~>c- zY(Heb;t!Yz&qv17}Ty*cnZyHO?1$t@s>M}GCKDW}ix{0#P)M%gf-#}5N(wi9|{;p<%{WWdNh}o zAZXdcQ|$QKDtKk+i|0|~GLsVbHNpGKy0#^VDJviyA_jfiVGKc!q>Uklo;wH(7`K6L zf!PVQfUgmHfQO`cUpNz*hb91d4{I43S_7PQ%K*QL<8UYhoGixBDtIBCT?vn;K=IVf zBPUWhSIMi+&m*9>0)41@XmyD6n0Zd-TXGze5q6QfYdTqGiS{j{Wp;3AwK)C(h^~

aoEQQY$KZJ!a3zE&_Jm!0^>5WGEdU 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%0Ab+MOf>K{7*w4_4;I;vGZI3>9=Z=|Y%)&_&9nb>a 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 oPNX2f3{<+ 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

WP^S>28c+rLb_6O+B!&>LdhP!!yIa3Fl2Jhq_& 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
vQU8a@-y;P~Hoxzl)!Rwk|^-Xos5L~jV( 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�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±>MBXeEfrd)Xp}nA5 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⪙H+#0ty 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

(%@~Z-(sNn#mr+X3|z}K;lL&7`Sx=#McfE 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%0A;_s8<|BTF(!N?e}+XC?GBbscA{!GO*8Pt5= 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"JIFOxJ%@G` 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 diff --git a/src/io/logger.cc b/src/io/logger.cc index 9ddfd4f02..91fc01931 100644 --- a/src/io/logger.cc +++ b/src/io/logger.cc @@ -43,9 +43,9 @@ const std::shared_ptr mpm::Logger::xmpm_explicit_logger = const std::shared_ptr mpm::Logger::mpm_explicit_musl_logger = spdlog::stdout_color_st("MPMExplicitMUSL"); -// Create a logger for MPM Implicit Linear -const std::shared_ptr mpm::Logger::mpm_implicit_linear_logger = - spdlog::stdout_color_st("MPMImplicitLinear"); +// Create a logger for MPM Implicit +const std::shared_ptr mpm::Logger::mpm_implicit_logger = + spdlog::stdout_color_st("MPMImplicit"); // Create a logger for MPM Implicit Newmark const std::shared_ptr mpm::Logger::mpm_implicit_newmark_logger = diff --git a/src/linear_solver.cc b/src/linear_solver.cc index 215d58e91..d1ac3a8a3 100644 --- a/src/linear_solver.cc +++ b/src/linear_solver.cc @@ -1,5 +1,5 @@ #include "assembler_base.h" -#include "assembler_eigen_implicit_linear.h" +#include "assembler_eigen_implicit.h" #include "assembler_eigen_semi_implicit_navierstokes.h" #include "assembler_eigen_semi_implicit_twophase.h" @@ -9,14 +9,12 @@ #include "solver_base.h" // Assembler collections -// Asssembler 2D for Implicit Linear -static Register, mpm::AssemblerEigenImplicitLinear<2>, - unsigned> - assembler_eigen_implicit_linear_2d("EigenImplicitLinear2D"); -// Asssembler 3D for Implicit Linear -static Register, mpm::AssemblerEigenImplicitLinear<3>, - unsigned> - assembler_eigen_implicit_linear_3d("EigenImplicitLinear3D"); +// Asssembler 2D for Implicit +static Register, mpm::AssemblerEigenImplicit<2>, unsigned> + assembler_eigen_implicit_2d("EigenImplicit2D"); +// Asssembler 3D for Implicit +static Register, mpm::AssemblerEigenImplicit<3>, unsigned> + assembler_eigen_implicit_3d("EigenImplicit3D"); // Asssembler 2D for NavierStokes static Register, diff --git a/src/mpm.cc b/src/mpm.cc index bbc6728d4..bc9a83073 100644 --- a/src/mpm.cc +++ b/src/mpm.cc @@ -5,7 +5,7 @@ #include "mpm.h" #include "mpm_explicit.h" #include "mpm_explicit_twophase.h" -#include "mpm_implicit_linear.h" +#include "mpm_implicit.h" #include "mpm_semi_implicit_navierstokes.h" #include "mpm_semi_implicit_twophase.h" #include "xmpm_explicit.h" @@ -19,18 +19,17 @@ static Register, const std::shared_ptr&> static Register, const std::shared_ptr&> mpm_explicit_3d("MPMExplicit3D"); +// 2D Implicit MPM +static Register, const std::shared_ptr&> + mpm_implicit_2d("MPMImplicit2D"); + +// 3D Implicit MPM +static Register, const std::shared_ptr&> + mpm_implicit_3d("MPMImplicit3D"); + // 3D Explicit XMPM static Register, const std::shared_ptr&> xmpm_explicit_3d("XMPMExplicit3D"); -// 2D Implicit Linear MPM -static Register, - const std::shared_ptr&> - mpm_implicit_linear_2d("MPMImplicitLinear2D"); - -// 3D Implicit Linear MPM -static Register, - const std::shared_ptr&> - mpm_implicit_linear_3d("MPMImplicitLinear3D"); // 2D SemiImplicit Navier Stokes MPM static Register, diff --git a/tests/cell_implicit_linear_test.cc b/tests/cells/cell_implicit_test.cc similarity index 99% rename from tests/cell_implicit_linear_test.cc rename to tests/cells/cell_implicit_test.cc index d7230008c..66c1dbb6d 100644 --- a/tests/cell_implicit_linear_test.cc +++ b/tests/cells/cell_implicit_test.cc @@ -15,8 +15,7 @@ #include "quadrilateral_quadrature.h" //! \brief Check cell class for 2D case -TEST_CASE("Implicit Linear Cell is checked for 2D case", - "[cell][2D][Implicit]") { +TEST_CASE("Implicit Cell is checked for 2D case", "[cell][2D][Implicit]") { // Dimension const unsigned Dim = 2; // Degrees of freedom @@ -259,8 +258,7 @@ TEST_CASE("Implicit Linear Cell is checked for 2D case", } //! \brief Check cell class for 3D case -TEST_CASE("Implicit Linear Cell is checked for 3D case", - "[cell][3D][Implicit]") { +TEST_CASE("Implicit Cell is checked for 3D case", "[cell][3D][Implicit]") { // Dimension const unsigned Dim = 3; // Degrees of freedom diff --git a/tests/cell_test.cc b/tests/cells/cell_test.cc similarity index 100% rename from tests/cell_test.cc rename to tests/cells/cell_test.cc diff --git a/tests/cell_vector_test.cc b/tests/cells/cell_vector_test.cc similarity index 100% rename from tests/cell_vector_test.cc rename to tests/cells/cell_vector_test.cc diff --git a/tests/convergence_criteria_test.cc b/tests/convergence_criteria_test.cc new file mode 100644 index 000000000..2df05734b --- /dev/null +++ b/tests/convergence_criteria_test.cc @@ -0,0 +1,179 @@ +#include +#include + +#include +#include +#include +#include + +#include "catch.hpp" +#include "convergence_criterion_base.h" +#include "convergence_criterion_residual.h" +#include "convergence_criterion_solution.h" + +// Generate random RHS vector with specified dimension and seed +Eigen::VectorXd CreateRandomRHSVectorWithMagnitude(unsigned dim, + double magnitude, + unsigned seed = 0) { + std::srand(seed); + Eigen::VectorXd vector = magnitude * Eigen::VectorXd::Random(dim); + return vector; +} + +TEST_CASE("Convergence criteria test", "[convergence_criteria]") { + // Allowed relative tolerance + double rel_tolerance = 1.E-12; + // Tolerance + const double tolerance = 1.E-12; + // verbosity + unsigned verbosity = 2; + + SECTION("Residual criterion") { + // Construct residual criterion + std::shared_ptr residual_criterion = + std::make_shared( + rel_tolerance, tolerance, verbosity); + + // Convergence false + auto random_vec = CreateRandomRHSVectorWithMagnitude(16, 10); + REQUIRE_FALSE(residual_criterion->check_convergence(random_vec, true)); + + // Check relative tolerance + REQUIRE_NOTHROW(residual_criterion->set_tolerance(1.E-5)); + random_vec = CreateRandomRHSVectorWithMagnitude(16, 1.e-5); + REQUIRE(residual_criterion->check_convergence(random_vec)); + random_vec = CreateRandomRHSVectorWithMagnitude(16, 1.e-7); + REQUIRE_FALSE(residual_criterion->check_convergence(random_vec, true)); + random_vec = CreateRandomRHSVectorWithMagnitude(16, 1.e-8); + REQUIRE_FALSE(residual_criterion->check_convergence(random_vec)); + + // Check abs tolerance + REQUIRE_NOTHROW(residual_criterion->set_abs_tolerance(1.E-6)); + random_vec = CreateRandomRHSVectorWithMagnitude(16, 1.e-7); + REQUIRE(residual_criterion->check_convergence(random_vec, true)); + random_vec = CreateRandomRHSVectorWithMagnitude(16, 1.e-3); + REQUIRE_FALSE(residual_criterion->check_convergence(random_vec)); + + // Constructor + std::shared_ptr residual_criterion2 = + std::make_shared(rel_tolerance, + verbosity); + std::shared_ptr residual_criterion3( + residual_criterion); + residual_criterion3 = residual_criterion2; + residual_criterion3 = std::move(residual_criterion2); + + // Others + residual_criterion3->set_verbosity(0); + random_vec = CreateRandomRHSVectorWithMagnitude(16, 1.e-15); + REQUIRE(residual_criterion3->check_convergence(random_vec, true)); + } + + SECTION("Solution criterion") { + // Construct solution criterion + std::shared_ptr solution_criterion = + std::make_shared(rel_tolerance, + verbosity); + + // Convergence false + auto random_vec = CreateRandomRHSVectorWithMagnitude(16, 10); + REQUIRE_FALSE(solution_criterion->check_convergence(random_vec)); + + // Check tolerance + REQUIRE_NOTHROW(solution_criterion->set_tolerance(1.E-5)); + random_vec = CreateRandomRHSVectorWithMagnitude(16, 1.e-6); + REQUIRE(solution_criterion->check_convergence(random_vec)); + random_vec = CreateRandomRHSVectorWithMagnitude(16, 1.e-4); + REQUIRE_FALSE(solution_criterion->check_convergence(random_vec)); + } +} + +TEST_CASE("Convergence criteria test MPI", "[convergence_criteria][mpi]") { + // Allowed relative tolerance + double rel_tolerance = 1.E-12; + // Tolerance + const double tolerance = 1.E-12; + // verbosity + unsigned verbosity = 2; + + // Get number of MPI ranks + int mpi_size, mpi_rank; +#ifdef USE_PETSC + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + + SECTION("Parallel residual criterion") { + // Construct residual criterion + std::shared_ptr residual_criterion = + std::make_shared( + rel_tolerance, tolerance, verbosity); + + if (mpi_size == 4) { + // Assign MPI attributes + residual_criterion->assign_global_active_dof(16); + std::vector rgm(4); + for (int i = 0; i < rgm.size(); i++) rgm[i] = mpi_rank * mpi_size + i; + residual_criterion->assign_rank_global_mapper(rgm); + + // Convergence false + auto random_vec = CreateRandomRHSVectorWithMagnitude(16, 10); + Eigen::VectorXd my_vec(4); + for (unsigned i = 0; i < my_vec.size(); i++) + my_vec(i) = random_vec(mpi_rank * mpi_size + i); + REQUIRE_FALSE(residual_criterion->check_convergence(my_vec, true)); + + // Check relative tolerance + REQUIRE_NOTHROW(residual_criterion->set_tolerance(1.E-5)); + random_vec = CreateRandomRHSVectorWithMagnitude(16, 1.e-5); + for (unsigned i = 0; i < my_vec.size(); i++) + my_vec(i) = random_vec(mpi_rank * mpi_size + i); + REQUIRE(residual_criterion->check_convergence(random_vec)); + random_vec = CreateRandomRHSVectorWithMagnitude(16, 1.e-7); + for (unsigned i = 0; i < my_vec.size(); i++) + my_vec(i) = random_vec(mpi_rank * mpi_size + i); + REQUIRE_FALSE(residual_criterion->check_convergence(random_vec, true)); + random_vec = CreateRandomRHSVectorWithMagnitude(16, 1.e-8); + for (unsigned i = 0; i < my_vec.size(); i++) + my_vec(i) = random_vec(mpi_rank * mpi_size + i); + REQUIRE_FALSE(residual_criterion->check_convergence(random_vec)); + + // Check abs tolerance + REQUIRE_NOTHROW(residual_criterion->set_abs_tolerance(1.E-6)); + random_vec = CreateRandomRHSVectorWithMagnitude(16, 1.e-7); + for (unsigned i = 0; i < my_vec.size(); i++) + my_vec(i) = random_vec(mpi_rank * mpi_size + i); + REQUIRE(residual_criterion->check_convergence(random_vec, true)); + random_vec = CreateRandomRHSVectorWithMagnitude(16, 1.e-3); + for (unsigned i = 0; i < my_vec.size(); i++) + my_vec(i) = random_vec(mpi_rank * mpi_size + i); + REQUIRE_FALSE(residual_criterion->check_convergence(random_vec)); + } + } + + SECTION("Solution criterion") { + // Construct solution criterion + std::shared_ptr solution_criterion = + std::make_shared(rel_tolerance, + verbosity); + + if (mpi_size == 4) { + // Assign MPI attributes + solution_criterion->assign_global_active_dof(16); + std::vector rgm(16); + for (int i = 0; i < rgm.size(); i++) rgm[i] = i; + solution_criterion->assign_rank_global_mapper(rgm); + + // Convergence false + auto random_vec = CreateRandomRHSVectorWithMagnitude(16, 10); + REQUIRE_FALSE(solution_criterion->check_convergence(random_vec)); + + // Check tolerance + REQUIRE_NOTHROW(solution_criterion->set_tolerance(1.E-5)); + random_vec = CreateRandomRHSVectorWithMagnitude(16, 1.e-6); + REQUIRE(solution_criterion->check_convergence(random_vec)); + random_vec = CreateRandomRHSVectorWithMagnitude(16, 1.e-4); + REQUIRE_FALSE(solution_criterion->check_convergence(random_vec)); + } + } +#endif +} \ No newline at end of file diff --git a/tests/include/write_mesh_particles.h b/tests/include/write_mesh_particles.h index f6ed5eeab..1ddf21ca1 100644 --- a/tests/include/write_mesh_particles.h +++ b/tests/include/write_mesh_particles.h @@ -12,12 +12,12 @@ bool write_json(unsigned dim, bool resume, const std::string& analysis, bool write_json_xmpm(unsigned dim, bool resume, const std::string& analysis, const std::string& mpm_scheme, const std::string& file_name); -// Write JSON Configuration file for implicit linear -bool write_json_implicit_linear(unsigned dim, bool resume, - const std::string& analysis, - const std::string& mpm_scheme, - const std::string& file_name, - const std::string& linear_solver_type = "none"); + +// Write JSON Configuration file for implicit +bool write_json_implicit(unsigned dim, bool resume, const std::string& analysis, + const std::string& mpm_scheme, bool nonlinear, + const std::string& file_name, + const std::string& linear_solver_type = "none"); // Write JSON Configuration file for navierstokes bool write_json_navierstokes(unsigned dim, bool resume, diff --git a/tests/include/write_mesh_particles_unitcell.h b/tests/include/write_mesh_particles_unitcell.h index 0f38dc277..6ff391219 100644 --- a/tests/include/write_mesh_particles_unitcell.h +++ b/tests/include/write_mesh_particles_unitcell.h @@ -9,10 +9,10 @@ bool write_json_unitcell(unsigned dim, const std::string& analysis, const std::string& mpm_scheme, const std::string& file_name); -// Write JSON Configuration file for implicit linear -bool write_json_unitcell_implicit_linear( +// Write JSON Configuration file for implicit +bool write_json_unitcell_implicit( unsigned dim, const std::string& analysis, const std::string& mpm_scheme, - const std::string& file_name, + bool nonlinear, const std::string& file_name, const std::string& linear_solver_type = "none"); // Write JSON Configuration file for navier stokes diff --git a/tests/io/write_mesh_particles.cc b/tests/io/write_mesh_particles.cc index 0d759b83e..7a97489b4 100644 --- a/tests/io/write_mesh_particles.cc +++ b/tests/io/write_mesh_particles.cc @@ -232,12 +232,11 @@ bool write_json_xmpm(unsigned dim, bool resume, const std::string& analysis, return true; } -// Write JSON Configuration file for implicit linear -bool write_json_implicit_linear(unsigned dim, bool resume, - const std::string& analysis, - const std::string& mpm_scheme, - const std::string& file_name, - const std::string& linear_solver_type) { +// Write JSON Configuration file for implicit +bool write_json_implicit(unsigned dim, bool resume, const std::string& analysis, + const std::string& mpm_scheme, bool nonlinear, + const std::string& file_name, + const std::string& linear_solver_type) { // Make json object with input files // 2D std::string dimension = "2d"; @@ -245,7 +244,7 @@ bool write_json_implicit_linear(unsigned dim, bool resume, auto node_type = "N2D"; auto cell_type = "ED2Q4"; auto io_type = "Ascii2D"; - auto assembler_type = "EigenImplicitLinear2D"; + auto assembler_type = "EigenImplicit2D"; std::string entity_set_name = "entity_sets_0"; std::string material = "LinearElastic2D"; std::vector gravity{{0., -9.81}}; @@ -259,7 +258,7 @@ bool write_json_implicit_linear(unsigned dim, bool resume, particle_type = "P3D"; node_type = "N3D"; cell_type = "ED3H8"; - assembler_type = "EigenImplicitLinear3D"; + assembler_type = "EigenImplicit3D"; io_type = "Ascii3D"; material = "LinearElastic3D"; gravity.clear(); @@ -323,6 +322,15 @@ bool write_json_implicit_linear(unsigned dim, bool resume, {"analysis", {{"type", analysis}, {"mpm_scheme", mpm_scheme}, + {"scheme_settings", + {{"nonlinear", nonlinear}, + {"beta", 0.25}, + {"gamma", 0.50}, + {"max_iteration", 20}, + {"displacement_tolerance", 1.0e-10}, + {"residual_tolerance", 1.0e-10}, + {"relative_residual_tolerance", 1.0e-6}, + {"verbosity", 0}}}, {"locate_particles", true}, {"pressure_smoothing", true}, {"dt", 0.0001}, diff --git a/tests/io/write_mesh_particles_unitcell.cc b/tests/io/write_mesh_particles_unitcell.cc index 4f7258aa2..ab1c8cefc 100644 --- a/tests/io/write_mesh_particles_unitcell.cc +++ b/tests/io/write_mesh_particles_unitcell.cc @@ -112,10 +112,11 @@ bool write_json_unitcell(unsigned dim, const std::string& analysis, return true; } -// Write JSON Configuration file for implicit linear -bool write_json_unitcell_implicit_linear( - unsigned dim, const std::string& analysis, const std::string& mpm_scheme, - const std::string& file_name, const std::string& linear_solver_type) { +// Write JSON Configuration file for implicit +bool write_json_unitcell_implicit(unsigned dim, const std::string& analysis, + const std::string& mpm_scheme, bool nonlinear, + const std::string& file_name, + const std::string& linear_solver_type) { // Make json object with input files // 2D std::string dimension = "2d"; @@ -123,7 +124,7 @@ bool write_json_unitcell_implicit_linear( auto node_type = "N2D"; auto cell_type = "ED2Q4"; auto io_type = "Ascii2D"; - auto assembler_type = "EigenImplicitLinear2D"; + auto assembler_type = "EigenImplicit2D"; std::string material = "LinearElastic2D"; std::vector gravity{{0., -9.81}}; std::vector material_id{{1}}; @@ -136,7 +137,7 @@ bool write_json_unitcell_implicit_linear( particle_type = "P3D"; node_type = "N3D"; cell_type = "ED3H8"; - assembler_type = "EigenImplicitLinear3D"; + assembler_type = "EigenImplicit3D"; io_type = "Ascii3D"; material = "LinearElastic3D"; gravity.clear(); @@ -195,6 +196,15 @@ bool write_json_unitcell_implicit_linear( {"analysis", {{"type", analysis}, {"mpm_scheme", mpm_scheme}, + {"scheme_settings", + {{"nonlinear", nonlinear}, + {"beta", 0.25}, + {"gamma", 0.50}, + {"max_iteration", 20}, + {"displacement_tolerance", 1.0e-10}, + {"residual_tolerance", 1.0e-10}, + {"relative_residual_tolerance", 1.0e-6}, + {"verbosity", 0}}}, {"locate_particles", true}, {"pressure_smoothing", false}, {"dt", 0.0001}, diff --git a/tests/mesh_free_surface_test.cc b/tests/mesh/mesh_free_surface_test.cc similarity index 100% rename from tests/mesh_free_surface_test.cc rename to tests/mesh/mesh_free_surface_test.cc diff --git a/tests/mesh_neighbours_test.cc b/tests/mesh/mesh_neighbours_test.cc similarity index 100% rename from tests/mesh_neighbours_test.cc rename to tests/mesh/mesh_neighbours_test.cc diff --git a/tests/mesh_test_2d.cc b/tests/mesh/mesh_test_2d.cc similarity index 100% rename from tests/mesh_test_2d.cc rename to tests/mesh/mesh_test_2d.cc diff --git a/tests/mesh_test_3d.cc b/tests/mesh/mesh_test_3d.cc similarity index 100% rename from tests/mesh_test_3d.cc rename to tests/mesh/mesh_test_3d.cc diff --git a/tests/nodes/node_implicit_linear_test.cc b/tests/nodes/node_implicit_test.cc similarity index 98% rename from tests/nodes/node_implicit_linear_test.cc rename to tests/nodes/node_implicit_test.cc index 8f8eb1e3b..42cf28504 100644 --- a/tests/nodes/node_implicit_linear_test.cc +++ b/tests/nodes/node_implicit_test.cc @@ -10,8 +10,7 @@ #include "node.h" // Check node class for 1D case -TEST_CASE("Implicit Linear Node is checked for 1D case", - "[node][1D][Implicit]") { +TEST_CASE("Implicit Node is checked for 1D case", "[node][1D][Implicit]") { const unsigned Dim = 1; const unsigned Dof = 1; const unsigned Nphases = 1; @@ -170,8 +169,7 @@ TEST_CASE("Implicit Linear Node is checked for 1D case", } // \brief Check node class for 2D case -TEST_CASE("Implicit Linear Node is checked for 2D case", - "[node][2D][Implicit]") { +TEST_CASE("Implicit Node is checked for 2D case", "[node][2D][Implicit]") { const unsigned Dim = 2; const unsigned Dof = 2; const unsigned Nphases = 1; @@ -336,8 +334,7 @@ TEST_CASE("Implicit Linear Node is checked for 2D case", } // \brief Check node class for 3D case -TEST_CASE("Implicit Linear Node is checked for 3D case", - "[node][3D][Implicit]") { +TEST_CASE("Implicit Node is checked for 3D case", "[node][3D][Implicit]") { const unsigned Dim = 3; const unsigned Dof = 3; const unsigned Nphases = 1; diff --git a/tests/particles/particle_implicit_linear_test.cc b/tests/particles/particle_implicit_test.cc similarity index 96% rename from tests/particles/particle_implicit_linear_test.cc rename to tests/particles/particle_implicit_test.cc index 5a859c5d4..9ee42984e 100644 --- a/tests/particles/particle_implicit_linear_test.cc +++ b/tests/particles/particle_implicit_test.cc @@ -14,7 +14,7 @@ #include "quadrilateral_element.h" //! \brief Check particle class for 2D case -TEST_CASE("Implicit Linear Particle is checked for 2D case", +TEST_CASE("Implicit Particle is checked for 2D case", "[particle][2D][Implicit]") { // Dimension const unsigned Dim = 2; @@ -293,27 +293,11 @@ TEST_CASE("Implicit Linear Particle is checked for 2D case", // Check pressure REQUIRE(std::isnan(particle->pressure()) == true); - // Compute strain + // Compute strain increment particle->compute_strain_newmark(); - // 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 updated pressure - const double K = 8333333.333333333; - REQUIRE(std::isnan(particle->pressure()) == true); - - // Update volume - REQUIRE(particle->volume() == Approx(1.0).epsilon(Tolerance)); - REQUIRE_NOTHROW(particle->update_volume()); - REQUIRE(particle->volume() == Approx(1.25).epsilon(Tolerance)); // Compute stress - REQUIRE_NOTHROW(particle->compute_stress()); - + REQUIRE_NOTHROW(particle->compute_stress_newmark()); Eigen::Matrix stress; // clang-format off stress << 721153.8461538460 * 2., @@ -327,6 +311,40 @@ TEST_CASE("Implicit Linear Particle is checked for 2D case", for (unsigned i = 0; i < stress.rows(); ++i) REQUIRE(particle->stress()(i) == Approx(stress(i)).epsilon(Tolerance)); + // Update stress and strain + particle->update_stress_strain(); + + // 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)); + + // Previous stress + Eigen::Matrix previous_stress; + // clang-format off + previous_stress << 721153.8461538460 * 2., + 1682692.3076923075 * 2., + 721153.8461538460 * 2., + 96153.8461538462 * 2., + 0.0000000000 * 2., + 0.0000000000 * 2.; + // clang-format on + // Check previous stress + for (unsigned i = 0; i < stress.rows(); ++i) + REQUIRE(particle->previous_stress()(i) == + Approx(previous_stress(i)).epsilon(Tolerance)); + + // Check updated pressure + const double K = 8333333.333333333; + REQUIRE(std::isnan(particle->pressure()) == true); + + // Check volume + REQUIRE(particle->volume() == Approx(1.0).epsilon(Tolerance)); + REQUIRE_NOTHROW(particle->update_volume()); + REQUIRE(particle->volume() == Approx(1.25).epsilon(Tolerance)); + // Update nodal velocity and acceleration using Newmark scheme for (const auto& node : nodes) node->update_velocity_acceleration_newmark(phase, newmark_beta, @@ -394,7 +412,7 @@ TEST_CASE("Implicit Linear Particle is checked for 2D case", } //! \brief Check particle class for 3D case -TEST_CASE("Implicit Linear Particle is checked for 3D case", +TEST_CASE("Implicit Particle is checked for 3D case", "[particle][3D][Implicit]") { // Dimension const unsigned Dim = 3; @@ -728,27 +746,11 @@ TEST_CASE("Implicit Linear Particle is checked for 3D case", // Check pressure REQUIRE(std::isnan(particle->pressure()) == true); - // Compute strain + // Compute strain increment particle->compute_strain_newmark(); - // 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 updated pressure - REQUIRE(std::isnan(particle->pressure()) == true); - - // Update volume - REQUIRE(particle->volume() == Approx(8.0).epsilon(Tolerance)); - REQUIRE_NOTHROW(particle->update_volume()); - REQUIRE(particle->volume() == Approx(11.8).epsilon(Tolerance)); // Compute stress - REQUIRE_NOTHROW(particle->compute_stress()); - + REQUIRE_NOTHROW(particle->compute_stress_newmark()); Eigen::Matrix stress; // clang-format off stress << 2740384.6153846150, @@ -762,6 +764,26 @@ TEST_CASE("Implicit Linear Particle is checked for 3D case", for (unsigned i = 0; i < stress.rows(); ++i) REQUIRE(particle->stress()(i) == Approx(stress(i)).epsilon(Tolerance)); + // Update stress and strain + particle->update_stress_strain(); + + // Strain + Eigen::Matrix strain; + // clang-format off + strain << 0.00000, 0.07500, 0.40000, -0.02500, 0.35000, -0.05000; + // clang-format on + // Check strains + for (unsigned i = 0; i < strain.rows(); ++i) + REQUIRE(particle->strain()(i) == Approx(strain(i)).epsilon(Tolerance)); + + // Check updated pressure + REQUIRE(std::isnan(particle->pressure()) == true); + + // Update volume + REQUIRE(particle->volume() == Approx(8.0).epsilon(Tolerance)); + REQUIRE_NOTHROW(particle->update_volume()); + REQUIRE(particle->volume() == Approx(11.8).epsilon(Tolerance)); + // Update nodal velocity and acceleration using Newmark scheme for (const auto& node : nodes) node->update_velocity_acceleration_newmark(phase, newmark_beta, diff --git a/tests/solvers/mpm_implicit_linear_test.cc b/tests/solvers/mpm_implicit_test.cc similarity index 62% rename from tests/solvers/mpm_implicit_linear_test.cc rename to tests/solvers/mpm_implicit_test.cc index 7a35c0a56..6744520bf 100644 --- a/tests/solvers/mpm_implicit_linear_test.cc +++ b/tests/solvers/mpm_implicit_test.cc @@ -4,23 +4,25 @@ #include "json.hpp" using Json = nlohmann::json; -#include "mpm_implicit_linear.h" +#include "mpm_implicit.h" #include "write_mesh_particles.h" -// Check MPM Implicit Linear -TEST_CASE("MPM 2D Implicit Linear implementation is checked", +// Check MPM Implicit +TEST_CASE("MPM 2D Implicit implementation is checked", "[MPM][2D][Implicit][1Phase]") { // Dimension const unsigned Dim = 2; // Write JSON file - const std::string fname = "mpm-implicit-linear"; - const std::string analysis = "MPMImplicitLinear2D"; + const std::string fname = "mpm-implicit"; + const std::string analysis = "MPMImplicit2D"; const std::string mpm_scheme = "newmark"; const std::string lin_solver_type = "IterativeEigen"; bool resume = false; - REQUIRE(mpm_test::write_json_implicit_linear(2, resume, analysis, mpm_scheme, - fname, lin_solver_type) == true); + bool nonlinear = true; + REQUIRE(mpm_test::write_json_implicit(2, resume, analysis, mpm_scheme, + nonlinear, fname, + lin_solver_type) == true); // Write JSON Entity Sets file REQUIRE(mpm_test::write_entity_set() == true); @@ -36,14 +38,14 @@ TEST_CASE("MPM 2D Implicit Linear implementation is checked", // clang-format off char* argv[] = {(char*)"./mpm", (char*)"-f", (char*)"./", - (char*)"-i", (char*)"mpm-implicit-linear-2d.json"}; + (char*)"-i", (char*)"mpm-implicit-2d.json"}; // clang-format on SECTION("Check initialisation") { // Create an IO object auto io = std::make_unique(argc, argv); - // Run Implicit Linear MPM - auto mpm = std::make_unique>(std::move(io)); + // Run Implicit MPM + auto mpm = std::make_unique>(std::move(io)); // Initialise materials REQUIRE_NOTHROW(mpm->initialise_materials()); @@ -61,8 +63,8 @@ TEST_CASE("MPM 2D Implicit Linear implementation is checked", SECTION("Check solver") { // Create an IO object auto io = std::make_unique(argc, argv); - // Run Implicit Linear MPM - auto mpm = std::make_unique>(std::move(io)); + // Run Implicit MPM + auto mpm = std::make_unique>(std::move(io)); // Solve REQUIRE(mpm->solve() == true); // Test check point restart @@ -71,19 +73,20 @@ TEST_CASE("MPM 2D Implicit Linear implementation is checked", SECTION("Check resume") { // Write JSON file - const std::string fname = "mpm-implicit-linear"; - const std::string analysis = "MPMImplicitLinear2D"; + const std::string fname = "mpm-implicit"; + const std::string analysis = "MPMImplicit2D"; const std::string mpm_scheme = "newmark"; const std::string lin_solver_type = "IterativeEigen"; bool resume = true; - REQUIRE(mpm_test::write_json_implicit_linear(2, resume, analysis, - mpm_scheme, fname, - lin_solver_type) == true); + bool nonlinear = true; + REQUIRE(mpm_test::write_json_implicit(2, resume, analysis, mpm_scheme, + nonlinear, fname, + lin_solver_type) == true); // Create an IO object auto io = std::make_unique(argc, argv); - // Run Implicit Linear MPM - auto mpm = std::make_unique>(std::move(io)); + // Run Implicit MPM + auto mpm = std::make_unique>(std::move(io)); // Initialise materials REQUIRE_NOTHROW(mpm->initialise_materials()); @@ -95,28 +98,29 @@ TEST_CASE("MPM 2D Implicit Linear implementation is checked", { // Create an IO object auto io = std::make_unique(argc, argv); - // Run Implicit Linear MPM - auto mpm_resume = - std::make_unique>(std::move(io)); + // Run Implicit MPM + auto mpm_resume = std::make_unique>(std::move(io)); REQUIRE(mpm_resume->solve() == true); } } } -// Check MPM Implicit Linear -TEST_CASE("MPM 3D Implicit Linear implementation is checked", +// Check MPM Implicit +TEST_CASE("MPM 3D Implicit implementation is checked", "[MPM][3D][Implicit][1Phase]") { // Dimension const unsigned Dim = 3; // Write JSON file - const std::string fname = "mpm-implicit-linear"; - const std::string analysis = "MPMImplicitLinear3D"; + const std::string fname = "mpm-implicit"; + const std::string analysis = "MPMImplicit3D"; const std::string mpm_scheme = "newmark"; const std::string lin_solver_type = "IterativeEigen"; const bool resume = false; - REQUIRE(mpm_test::write_json_implicit_linear(3, resume, analysis, mpm_scheme, - fname, lin_solver_type) == true); + bool nonlinear = true; + REQUIRE(mpm_test::write_json_implicit(3, resume, analysis, mpm_scheme, + nonlinear, fname, + lin_solver_type) == true); // Write JSON Entity Sets file REQUIRE(mpm_test::write_entity_set() == true); @@ -132,14 +136,14 @@ TEST_CASE("MPM 3D Implicit Linear implementation is checked", // clang-format off char* argv[] = {(char*)"./mpm", (char*)"-f", (char*)"./", - (char*)"-i", (char*)"mpm-implicit-linear-3d.json"}; + (char*)"-i", (char*)"mpm-implicit-3d.json"}; // clang-format on SECTION("Check initialisation") { // Create an IO object auto io = std::make_unique(argc, argv); - // Run Implicit Linear MPM - auto mpm = std::make_unique>(std::move(io)); + // Run Implicit MPM + auto mpm = std::make_unique>(std::move(io)); // Initialise materials REQUIRE_NOTHROW(mpm->initialise_materials()); @@ -155,8 +159,8 @@ TEST_CASE("MPM 3D Implicit Linear implementation is checked", SECTION("Check solver") { // Create an IO object auto io = std::make_unique(argc, argv); - // Run Implicit Linear MPM - auto mpm = std::make_unique>(std::move(io)); + // Run Implicit MPM + auto mpm = std::make_unique>(std::move(io)); // Solve REQUIRE(mpm->solve() == true); // Test check point restart @@ -165,19 +169,20 @@ TEST_CASE("MPM 3D Implicit Linear implementation is checked", SECTION("Check resume") { // Write JSON file - const std::string fname = "mpm-implicit-linear"; - const std::string analysis = "MPMImplicitLinear3D"; + const std::string fname = "mpm-implicit"; + const std::string analysis = "MPMImplicit3D"; const std::string mpm_scheme = "newmark"; const std::string lin_solver_type = "IterativeEigen"; bool resume = true; - REQUIRE(mpm_test::write_json_implicit_linear(3, resume, analysis, - mpm_scheme, fname, - lin_solver_type) == true); + bool nonlinear = true; + REQUIRE(mpm_test::write_json_implicit(3, resume, analysis, mpm_scheme, + nonlinear, fname, + lin_solver_type) == true); // Create an IO object auto io = std::make_unique(argc, argv); - // Run Implicit Linear MPM - auto mpm = std::make_unique>(std::move(io)); + // Run Implicit MPM + auto mpm = std::make_unique>(std::move(io)); // Initialise materials REQUIRE_NOTHROW(mpm->initialise_materials()); @@ -189,9 +194,8 @@ TEST_CASE("MPM 3D Implicit Linear implementation is checked", { // Solve auto io = std::make_unique(argc, argv); - // Run Implicit Linear MPM - auto mpm_resume = - std::make_unique>(std::move(io)); + // Run Implicit MPM + auto mpm_resume = std::make_unique>(std::move(io)); REQUIRE(mpm_resume->solve() == true); } } diff --git a/tests/solvers/mpm_implicit_linear_unitcell_test.cc b/tests/solvers/mpm_implicit_unitcell_test.cc similarity index 64% rename from tests/solvers/mpm_implicit_linear_unitcell_test.cc rename to tests/solvers/mpm_implicit_unitcell_test.cc index 01a82a4be..ca9bf40c1 100644 --- a/tests/solvers/mpm_implicit_linear_unitcell_test.cc +++ b/tests/solvers/mpm_implicit_unitcell_test.cc @@ -4,22 +4,24 @@ #include "json.hpp" using Json = nlohmann::json; -#include "mpm_implicit_linear.h" +#include "mpm_implicit.h" #include "write_mesh_particles_unitcell.h" -// Check MPM Implicit Linear -TEST_CASE("MPM 2D Implicit Linear implementation is checked in unitcells", +// Check MPM Implicit +TEST_CASE("MPM 2D Implicit implementation is checked in unitcells", "[MPM][2D][Implicit][1Phase][unitcell]") { // Dimension const unsigned Dim = 2; // Write JSON file - const std::string fname = "mpm-implicit-linear"; - const std::string analysis = "MPMImplicitLinear2D"; + const std::string fname = "mpm-implicit"; + const std::string analysis = "MPMImplicit2D"; const std::string mpm_scheme = "newmark"; const std::string lin_solver_type = "IterativeEigen"; - REQUIRE(mpm_test::write_json_unitcell_implicit_linear( - 2, analysis, mpm_scheme, fname, lin_solver_type) == true); + bool nonlinear = true; + REQUIRE(mpm_test::write_json_unitcell_implicit(2, analysis, mpm_scheme, + nonlinear, fname, + lin_solver_type) == true); // Write Mesh REQUIRE(mpm_test::write_mesh_2d_unitcell() == true); @@ -32,14 +34,14 @@ TEST_CASE("MPM 2D Implicit Linear implementation is checked in unitcells", // clang-format off char* argv[] = {(char*)"./mpm", (char*)"-f", (char*)"./", - (char*)"-i", (char*)"mpm-implicit-linear-2d-unitcell.json"}; + (char*)"-i", (char*)"mpm-implicit-2d-unitcell.json"}; // clang-format on SECTION("Check initialisation") { // Create an IO object auto io = std::make_unique(argc, argv); - // Run Implicit Linear MPM - auto mpm = std::make_unique>(std::move(io)); + // Run Implicit MPM + auto mpm = std::make_unique>(std::move(io)); // Initialise materials REQUIRE_NOTHROW(mpm->initialise_materials()); @@ -58,26 +60,28 @@ TEST_CASE("MPM 2D Implicit Linear implementation is checked in unitcells", SECTION("Check solver") { // Create an IO object auto io = std::make_unique(argc, argv); - // Run Implicit Linear MPM - auto mpm = std::make_unique>(std::move(io)); + // Run Implicit MPM + auto mpm = std::make_unique>(std::move(io)); // Solve REQUIRE(mpm->solve() == true); } } -// Check MPM Implicit Linear -TEST_CASE("MPM 3D Implicit Linear implementation is checked in unitcells", +// Check MPM Implicit +TEST_CASE("MPM 3D Implicit implementation is checked in unitcells", "[MPM][3D][Implicit][1Phase][unitcell]") { // Dimension const unsigned Dim = 3; // Write JSON file - const std::string fname = "mpm-implicit-linear"; - const std::string analysis = "MPMImplicitLinear3D"; + const std::string fname = "mpm-implicit"; + const std::string analysis = "MPMImplicit3D"; const std::string mpm_scheme = "newmark"; const std::string lin_solver_type = "IterativeEigen"; - REQUIRE(mpm_test::write_json_unitcell_implicit_linear( - 3, analysis, mpm_scheme, fname, lin_solver_type) == true); + bool nonlinear = true; + REQUIRE(mpm_test::write_json_unitcell_implicit(3, analysis, mpm_scheme, + nonlinear, fname, + lin_solver_type) == true); // Write Mesh REQUIRE(mpm_test::write_mesh_3d_unitcell() == true); @@ -90,14 +94,14 @@ TEST_CASE("MPM 3D Implicit Linear implementation is checked in unitcells", // clang-format off char* argv[] = {(char*)"./mpm", (char*)"-f", (char*)"./", - (char*)"-i", (char*)"mpm-implicit-linear-3d-unitcell.json"}; + (char*)"-i", (char*)"mpm-implicit-3d-unitcell.json"}; // clang-format on SECTION("Check initialisation") { // Create an IO object auto io = std::make_unique(argc, argv); - // Run Implicit Linear MPM - auto mpm = std::make_unique>(std::move(io)); + // Run Implicit MPM + auto mpm = std::make_unique>(std::move(io)); // Initialise materials REQUIRE_NOTHROW(mpm->initialise_materials()); @@ -113,8 +117,8 @@ TEST_CASE("MPM 3D Implicit Linear implementation is checked in unitcells", SECTION("Check solver") { // Create an IO object auto io = std::make_unique(argc, argv); - // Run Implicit Linear MPM - auto mpm = std::make_unique>(std::move(io)); + // Run Implicit MPM + auto mpm = std::make_unique>(std::move(io)); // Solve REQUIRE(mpm->solve() == true); } diff --git a/tests/solvers/mpm_scheme_test.cc b/tests/solvers/mpm_scheme_test.cc index a0c9c6562..824b11072 100644 --- a/tests/solvers/mpm_scheme_test.cc +++ b/tests/solvers/mpm_scheme_test.cc @@ -19,6 +19,7 @@ #include "mesh.h" #include "mpm_scheme.h" #include "mpm_scheme_musl.h" +#include "mpm_scheme_newmark.h" #include "mpm_scheme_usf.h" #include "mpm_scheme_usl.h" #include "node.h" @@ -27,7 +28,7 @@ //! \brief Check stress update 3D case TEST_CASE("Stress update is checked for USF, USL and MUSL", - "[MPMScheme][USF][USL][MUSL][3D]") { + "[MPMScheme][USF][USL][MUSL][Newmark][3D]") { // Dimension const unsigned Dim = 3; // Degrees of freedom @@ -293,5 +294,48 @@ TEST_CASE("Stress update is checked for USF, USL and MUSL", // Locate particles REQUIRE_NOTHROW(mpm_scheme->locate_particles(true)); REQUIRE_NOTHROW(mpm_scheme->locate_particles(false)); + + // Illegal Operation + REQUIRE_THROWS(mpm_scheme->update_nodal_kinematics_newmark(0, 0, 0)); + REQUIRE_THROWS(mpm_scheme->update_particle_stress_strain_volume()); + } + + SECTION("Check Newmark") { + auto mpm_scheme = std::make_shared>(mesh, 0.01); + // Phase + unsigned phase = 0; + // Step + unsigned step = 5; + // Gravity + Eigen::Matrix gravity = {0., 0., 9.81}; + // Initialise + REQUIRE_NOTHROW(mpm_scheme->initialise()); + + // Mass momentum and compute velocity at nodes + REQUIRE_NOTHROW(mpm_scheme->compute_nodal_kinematics(phase)); + + // Update stress first + REQUIRE_NOTHROW(mpm_scheme->precompute_stress_strain(phase, false)); + REQUIRE_NOTHROW(mpm_scheme->precompute_stress_strain(phase, true)); + + // Compute forces + REQUIRE_NOTHROW(mpm_scheme->compute_forces(gravity, phase, step, false)); + REQUIRE_NOTHROW(mpm_scheme->compute_forces(gravity, phase, step, true)); + + // Particle kinematics + REQUIRE_NOTHROW( + mpm_scheme->compute_particle_kinematics(true, phase, "None", 0.02)); + + // Update Stress Last + REQUIRE_NOTHROW(mpm_scheme->postcompute_stress_strain(phase, true)); + REQUIRE_NOTHROW(mpm_scheme->postcompute_stress_strain(phase, false)); + + // Locate particles + REQUIRE_NOTHROW(mpm_scheme->locate_particles(true)); + REQUIRE_NOTHROW(mpm_scheme->locate_particles(false)); + + // Specific Operation + REQUIRE_NOTHROW(mpm_scheme->update_nodal_kinematics_newmark(0, 0.25, 0.5)); + REQUIRE_NOTHROW(mpm_scheme->update_particle_stress_strain_volume()); } } From 533f5f8bc8c3e9b8b41611afb8201bd07c44966c Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 16 Nov 2021 09:13:07 -0800 Subject: [PATCH 90/91] clang format --- include/mesh/mesh_multiphase.tcc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mesh/mesh_multiphase.tcc b/include/mesh/mesh_multiphase.tcc index 5fc10999a..7ae0e17e0 100644 --- a/include/mesh/mesh_multiphase.tcc +++ b/include/mesh/mesh_multiphase.tcc @@ -439,7 +439,7 @@ std::set mpm::Mesh::free_surface_particles() { //! Compute cell volume fraction template void mpm::Mesh::compute_cell_vol_fraction() { - this->iterate_over_cells([& map_particles = map_particles_]( + this->iterate_over_cells([&map_particles = map_particles_]( std::shared_ptr> c_ptr) { if (c_ptr->status()) { // Compute volume fraction From 70112b5b19ba00c434cf04eaff8c1263d8ae0eae Mon Sep 17 00:00:00 2001 From: Nanda Date: Tue, 16 Nov 2021 18:11:51 -0800 Subject: [PATCH 91/91] xmpm modification after discussions --- include/mesh/mesh_xmpm.tcc | 2 + include/solvers/xmpm_explicit.h | 6 +- include/solvers/xmpm_explicit.tcc | 127 +++++++++++++----------------- tests/mesh/mesh_test_3d.cc | 4 +- 4 files changed, 60 insertions(+), 79 deletions(-) diff --git a/include/mesh/mesh_xmpm.tcc b/include/mesh/mesh_xmpm.tcc index a7f1d05db..90823c855 100644 --- a/include/mesh/mesh_xmpm.tcc +++ b/include/mesh/mesh_xmpm.tcc @@ -1105,6 +1105,7 @@ bool mpm::Mesh::write_particles_hdf5_xmpm(const std::string& filename) { } //! code for debugging added by yliang start------------------------------- +// FIXME: Remove this before merging to master template void mpm::Mesh::output_celltype(int step) { std::ofstream test("cell_type.txt", std::ios::app); @@ -1145,6 +1146,7 @@ void mpm::Mesh::output_celltype(int step) { } } +// FIXME: Remove this before merging to master template void mpm::Mesh::define_levelset() { // for oso diff --git a/include/solvers/xmpm_explicit.h b/include/solvers/xmpm_explicit.h index 9e01e60c4..508fe36b9 100644 --- a/include/solvers/xmpm_explicit.h +++ b/include/solvers/xmpm_explicit.h @@ -57,8 +57,6 @@ class XMPMExplicit : public MPMBase { using mpm::MPMBase::mpm_scheme_; //! Stress update method using mpm::MPMBase::stress_update_; - //! Interface scheme - using mpm::MPMBase::contact_; //! xmpm solver using mpm::MPMBase::xmpm_; @@ -87,8 +85,6 @@ class XMPMExplicit : public MPMBase { private: //! Pressure smoothing bool pressure_smoothing_{false}; - //! Interface - bool interface_{false}; //! With or without discontinuities bool setdiscontinuity_{false}; //! Discontinuities @@ -96,7 +92,7 @@ class XMPMExplicit : public MPMBase { //! Describe a discontinuity by mesh bool surfacemesh_{false}; //! Initialize the discontinuity by level set values - bool particle_levelet_{false}; + bool particle_levelset_{false}; //! Proparate or not bool propagation_{false}; //! Initiate or not diff --git a/include/solvers/xmpm_explicit.tcc b/include/solvers/xmpm_explicit.tcc index 2b3acde7e..01e6c3466 100644 --- a/include/solvers/xmpm_explicit.tcc +++ b/include/solvers/xmpm_explicit.tcc @@ -10,12 +10,6 @@ mpm::XMPMExplicit::XMPMExplicit(const std::shared_ptr& io) mpm_scheme_ = std::make_shared>(mesh_, dt_); else mpm_scheme_ = std::make_shared>(mesh_, dt_); - - //! Interface scheme - if (this->interface_) - contact_ = std::make_shared>(mesh_); - else - contact_ = std::make_shared>(mesh_); } //! MPM Explicit compute stress strain @@ -63,56 +57,61 @@ bool mpm::XMPMExplicit::solve() { if (analysis_.find("resume") != analysis_.end()) resume = analysis_["resume"]["resume"].template get(); + // Enable repartitioning if resume is done with particles generated outside + // the MPM code. + bool repartition = false; + if (analysis_.find("resume") != analysis_.end() && + analysis_["resume"].find("repartition") != analysis_["resume"].end()) + repartition = analysis_["resume"]["repartition"].template get(); + // Pressure smoothing pressure_smoothing_ = io_->analysis_bool("pressure_smoothing"); - // Interface - interface_ = io_->analysis_bool("interface"); - // Initialise material this->initialise_materials(); // Initialise mesh this->initialise_mesh(); - // Initialise particles - if (!resume) this->initialise_particles(); - - // Create nodal properties - if (interface_) mesh_->create_nodal_properties(); - - // Initialise discontinuity - this->initialise_discontinuity(); - - // Create nodal properties for discontinuity - if (setdiscontinuity_) mesh_->create_nodal_properties_discontinuity(); - - // Compute mass - if (!resume) - mesh_->iterate_over_particles(std::bind( - &mpm::ParticleBase::compute_mass, std::placeholders::_1)); - // Check point resume if (resume) { - this->checkpoint_resume(); - --this->step_; - mesh_->resume_domain_cell_ranks(); + bool check_resume = this->checkpoint_resume(); + if (!check_resume) resume = false; + } + + // Resume or Initialise + bool initial_step = (resume == true) ? false : true; + if (resume) { + if (repartition) { + this->mpi_domain_decompose(initial_step); + } else { + mesh_->resume_domain_cell_ranks(); #ifdef USE_MPI #ifdef USE_GRAPH_PARTITIONING - MPI_Barrier(MPI_COMM_WORLD); + MPI_Barrier(MPI_COMM_WORLD); #endif #endif + } + //! Particle entity sets and velocity constraints + this->particle_entity_sets(false); + this->particle_velocity_constraints(); } else { + // Initialise particles + this->initialise_particles(); + + // Compute mass + mesh_->iterate_over_particles(std::bind( + &mpm::ParticleBase::compute_mass, std::placeholders::_1)); + // Domain decompose - bool initial_step = (resume == true) ? false : true; this->mpi_domain_decompose(initial_step); } - //! Particle entity sets and velocity constraints - if (resume) { - this->particle_entity_sets(false); - this->particle_velocity_constraints(); - } + // Initialise discontinuity + this->initialise_discontinuity(); + + // Create nodal properties for discontinuity + if (setdiscontinuity_) mesh_->create_nodal_properties_discontinuity(); // Initialise loading conditions this->initialise_loads(); @@ -122,23 +121,8 @@ bool mpm::XMPMExplicit::solve() { auto solver_begin = std::chrono::steady_clock::now(); - if (!resume) { - // Main loop - // HDF5 outputs - // HDF5 outputs the initial status - 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 - } - for (; step_ < nsteps_; ++step_) { - // to do + // FIXME: Modify this to a more generic function bool nodal_update = false; if (mpi_rank == 0) console_->info("Step: {} of {}.\n", step_, nsteps_); @@ -157,24 +141,25 @@ bool mpm::XMPMExplicit::solve() { // Initialise nodes, cells and shape functions mpm_scheme_->initialise(); - if (step_ == 0 || resume == true) { - // predefine level set values - mesh_->define_levelset(); - resume = false; - } - // Initialise nodal properties and append material ids to node - contact_->initialise(); + // FIXME: Remove this before merging to master + // if (step_ == 0 || resume == true) { + // // predefine level set values + // mesh_->define_levelset(); + // resume = false; + // } if (initiation_) initiation_ = !mesh_->initiation_discontinuity(); if (setdiscontinuity_ && !initiation_) { // Initialise nodal properties mesh_->initialise_nodal_properties(); + // Initialise element properties mesh_->iterate_over_cells(std::bind( &mpm::Cell::initialise_element_properties_discontinuity, std::placeholders::_1)); - if (!particle_levelet_) { + + if (!particle_levelset_) { // locate points of discontinuity mesh_->locate_discontinuity(); @@ -182,7 +167,7 @@ bool mpm::XMPMExplicit::solve() { mesh_->compute_shapefn_discontinuity(); } - // // obtain nodal volume + // obtain nodal volume mesh_->iterate_over_particles( std::bind(&mpm::ParticleBase::map_volume_to_nodes, @@ -207,7 +192,7 @@ bool mpm::XMPMExplicit::solve() { mesh_->iterate_over_cells(std::bind( &mpm::Cell::potential_tip_element, std::placeholders::_1)); } - if (particle_levelet_) { + if (particle_levelset_) { // determine the celltype by the nodal level set mesh_->iterate_over_cells(std::bind(&mpm::Cell::determine_crossed, std::placeholders::_1)); @@ -226,7 +211,7 @@ bool mpm::XMPMExplicit::solve() { // assign_node_enrich mesh_->assign_node_enrich(friction_coef_average_, nodal_update); - mesh_->check_particle_levelset(particle_levelet_); + mesh_->check_particle_levelset(particle_levelset_); // obtain the normal direction of each cell and enrich nodes mesh_->compute_nodal_normal_vector_discontinuity(); @@ -247,10 +232,7 @@ bool mpm::XMPMExplicit::solve() { // Mass momentum and compute velocity at nodes mpm_scheme_->compute_nodal_kinematics(phase); - if (particle_levelet_ || nodal_update) mesh_->update_node_enrich(); - - // Map material properties to nodes - contact_->compute_contact_forces(); + if (particle_levelset_ || nodal_update) mesh_->update_node_enrich(); // Update stress first mpm_scheme_->precompute_stress_strain(phase, pressure_smoothing_); @@ -288,7 +270,7 @@ bool mpm::XMPMExplicit::solve() { } // Update the discontinuity position - if (!particle_levelet_) + if (!particle_levelset_) mesh_->compute_updated_position_discontinuity(this->dt_); } @@ -347,13 +329,13 @@ void mpm::XMPMExplicit::initialise_discontinuity() { if (!discontinuity_props.empty()) { setdiscontinuity_ = true; // Get discontinuity type - const std::string discontunity_type = + const std::string discontinuity_type = discontinuity_props["type"].template get(); // Create a new discontinuity surface from JSON object auto discontinuity = Factory, const Json&>::instance() - ->create(discontunity_type, discontinuity_props); + ->create(discontinuity_type, discontinuity_props); if (discontinuity_props.contains("initiation")) initiation_ = discontinuity_props.at("initiation").template get(); @@ -375,7 +357,8 @@ void mpm::XMPMExplicit::initialise_discontinuity() { discontinuity_props.contains("file")) { surfacemesh_ = true; - // particle_levelet_ = true; + particle_levelset_ = true; + // Get discontinuity input type auto io_type = discontinuity_props["io_type"].template get(); @@ -392,7 +375,7 @@ void mpm::XMPMExplicit::initialise_discontinuity() { discontunity_io->read_mesh_nodes(discontinuity_file), discontunity_io->read_mesh_cells(discontinuity_file)); } else if (discontinuity_props.contains("particle_levelset")) { - particle_levelet_ = + particle_levelset_ = discontinuity_props.at("particle_levelset").template get(); } diff --git a/tests/mesh/mesh_test_3d.cc b/tests/mesh/mesh_test_3d.cc index 56d40ab1c..a2e9fb4fd 100644 --- a/tests/mesh/mesh_test_3d.cc +++ b/tests/mesh/mesh_test_3d.cc @@ -1551,14 +1551,14 @@ TEST_CASE("Mesh is checked for 3D case", "[mesh][3D]") { std::vector indices{0, 1, 2}; surfs.emplace_back(indices); - const std::string discontunity_type = "tri3d"; + const std::string discontinuity_type = "tri3d"; // Get discontinuity id int discontinuity_id = 0; Json discontinuity_props; // Create a new discontinuity surface from JSON object auto discontinuity = Factory, unsigned, const Json&>::instance() - ->create(discontunity_type, std::move(discontinuity_id), + ->create(discontinuity_type, std::move(discontinuity_id), discontinuity_props); REQUIRE(discontinuity->initialise(points, surfs) == true);

^fsxfNQu||S_9lX_0G^a1 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%0DIug#Me9!A-1V;n;5% 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