diff --git a/src/USER-SMD/Install.sh b/src/USER-SMD/Install.sh new file mode 100644 index 0000000000..73f6146c4e --- /dev/null +++ b/src/USER-SMD/Install.sh @@ -0,0 +1,64 @@ +# Install/unInstall package files in LAMMPS +# mode = 0/1/2 for uninstall/install/update + +mode=$1 + +# arg1 = file, arg2 = file it depends on + +action () { + if (test $mode = 0) then + rm -f ../$1 + elif (! cmp -s $1 ../$1) then + if (test -z "$2" || test -e ../$2) then + cp $1 .. + if (test $mode = 2) then + echo " updating src/$1" + fi + fi + elif (test -n "$2") then + if (test ! -e ../$2) then + rm -f ../$1 + fi + fi +} + +# all package files with no dependencies + +for file in *.cpp *.h; do + action $file +done + +# edit 2 Makefile.package files to include/exclude package info + +if (test $1 = 1) then + + if (test -e ../Makefile.package) then + sed -i -e 's/[^ \t]*smd[^ \t]* //g' ../Makefile.package + sed -i -e 's|^PKG_INC =[ \t]*|&-I..\/..\/lib\/smd |' ../Makefile.package + sed -i -e 's|^PKG_PATH =[ \t]*|&-L..\/..\/lib\/smd$(LIBOBJDIR) |' ../Makefile.package + #sed -i -e 's|^PKG_LIB =[ \t]*|&-lsmd |' ../Makefile.package + sed -i -e 's|^PKG_SYSINC =[ \t]*|&$(smd_SYSINC) |' ../Makefile.package + sed -i -e 's|^PKG_SYSLIB =[ \t]*|&$(smd_SYSLIB) |' ../Makefile.package + sed -i -e 's|^PKG_SYSPATH =[ \t]*|&$(smd_SYSPATH) |' ../Makefile.package + fi + + if (test -e ../Makefile.package.settings) then + sed -i -e '/^include.*smd.*$/d' ../Makefile.package.settings + # multiline form needed for BSD sed on Macs +# sed -i -e '4 i \ +#include ..\/..\/lib\/smd\/Makefile.lammps +#' ../Makefile.package.settings + + fi + +elif (test $1 = 0) then + + if (test -e ../Makefile.package) then + sed -i -e 's/[^ \t]*smd[^ \t]* //g' ../Makefile.package + fi + + if (test -e ../Makefile.package.settings) then + sed -i -e '/^include.*smd.*$/d' ../Makefile.package.settings + fi + +fi diff --git a/src/USER-SMD/README b/src/USER-SMD/README new file mode 100644 index 0000000000..91961c4923 --- /dev/null +++ b/src/USER-SMD/README @@ -0,0 +1,7 @@ +Smooth Mach Dynamics -- Smooth Particle Hydrodynamics for solids and fluids + +The person who created this package is Georg Ganzenmuller at the +Fraunhofer-Institute for High-Speed Dynamics, Ernst Mach Institute in +Germany (georg.ganzenmueller at emi.fhg.de). Contact him directly if +you have questions. + diff --git a/src/USER-SMD/atom_vec_smd.cpp b/src/USER-SMD/atom_vec_smd.cpp new file mode 100644 index 0000000000..f9af5d3d92 --- /dev/null +++ b/src/USER-SMD/atom_vec_smd.cpp @@ -0,0 +1,1288 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +#include "math.h" +#include "stdlib.h" +#include "string.h" +#include "atom_vec_smd.h" +#include "atom.h" +#include "comm.h" +#include "domain.h" +#include "modify.h" +#include "force.h" +#include "fix.h" +#include "fix_adapt.h" +#include "math_const.h" +#include "memory.h" +#include "error.h" + +using namespace LAMMPS_NS; +using namespace MathConst; +#define NMAT_FULL 9 +#define NMAT_SYMM 6 + +/* ---------------------------------------------------------------------- */ + +AtomVecSMD::AtomVecSMD(LAMMPS *lmp) : + AtomVec(lmp) { + molecular = 0; + + comm_x_only = 0; + comm_f_only = 0; + size_forward = 6; // variables that are changed by time integration + size_reverse = 4; // f[3] + de + size_border = 31; + size_velocity = 6; // v + vest + size_data_atom = 13; // 7 + 3 x0 + 3 x + size_data_vel = 4; + xcol_data = 11; + + atom->radius_flag = 1; + atom->rmass_flag = 1; + atom->vfrac_flag = 1; + atom->contact_radius_flag = 1; + atom->molecule_flag = 1; + atom->smd_data_9_flag = 1; + atom->e_flag = 1; + atom->vest_flag = 1; + atom->smd_stress_flag = 1; + atom->eff_plastic_strain_flag = 1; + atom->x0_flag = 1; + atom->damage_flag = 1; + atom->eff_plastic_strain_rate_flag = 1; + + forceclearflag = 1; + + atom->smd_flag = 1; +} + +/* ---------------------------------------------------------------------- */ + +void AtomVecSMD::init() { + AtomVec::init(); + + // do nothing here +} + +/* ---------------------------------------------------------------------- + grow atom arrays + n = 0 grows arrays by a chunk + n > 0 allocates arrays to size n + ------------------------------------------------------------------------- */ + +void AtomVecSMD::grow(int n) { + if (n == 0) + grow_nmax(); + else + nmax = n; + atom->nmax = nmax; + if (nmax < 0 || nmax > MAXSMALLINT) + error->one(FLERR, "Per-processor system is too big"); + + //printf("in grow, nmax is now %d\n", nmax); + + tag = memory->grow(atom->tag, nmax, "atom:tag"); + type = memory->grow(atom->type, nmax, "atom:type"); + mask = memory->grow(atom->mask, nmax, "atom:mask"); + image = memory->grow(atom->image, nmax, "atom:image"); + x = memory->grow(atom->x, nmax, 3, "atom:x"); + v = memory->grow(atom->v, nmax, 3, "atom:v"); + + f = memory->grow(atom->f, nmax * comm->nthreads, 3, "atom:f"); + de = memory->grow(atom->de, nmax * comm->nthreads, "atom:de"); + + vfrac = memory->grow(atom->vfrac, nmax, "atom:vfrac"); + rmass = memory->grow(atom->rmass, nmax, "atom:rmass"); + x0 = memory->grow(atom->x0, nmax, 3, "atom:x0"); + radius = memory->grow(atom->radius, nmax, "atom:radius"); + contact_radius = memory->grow(atom->contact_radius, nmax, "atom:contact_radius"); + molecule = memory->grow(atom->molecule, nmax, "atom:molecule"); + smd_data_9 = memory->grow(atom->smd_data_9, nmax, NMAT_FULL, "atom:defgrad_old"); + e = memory->grow(atom->e, nmax, "atom:e"); + vest = memory->grow(atom->vest, nmax, 3, "atom:vest"); + tlsph_stress = memory->grow(atom->smd_stress, nmax, NMAT_SYMM, "atom:tlsph_stress"); + eff_plastic_strain = memory->grow(atom->eff_plastic_strain, nmax, "atom:eff_plastic_strain"); + eff_plastic_strain_rate = memory->grow(atom->eff_plastic_strain_rate, nmax, "atom:eff_plastic_strain_rate"); + damage = memory->grow(atom->damage, nmax, "atom:damage"); + + if (atom->nextra_grow) + for (int iextra = 0; iextra < atom->nextra_grow; iextra++) + modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); +} + +/* ---------------------------------------------------------------------- + reset local array ptrs + ------------------------------------------------------------------------- */ + +void AtomVecSMD::grow_reset() { + tag = atom->tag; + type = atom->type; + mask = atom->mask; + image = atom->image; + x = atom->x; + v = atom->v; + f = atom->f; + radius = atom->radius; + rmass = atom->rmass; + + molecule = atom->molecule; + vfrac = atom->vfrac; + x0 = atom->x0; + contact_radius = atom->contact_radius; + molecule = atom->molecule; + smd_data_9 = atom->smd_data_9; + e = atom->e; + de = atom->de; + tlsph_stress = atom->smd_stress; + eff_plastic_strain = atom->eff_plastic_strain; + eff_plastic_strain_rate = atom->eff_plastic_strain_rate; + damage = atom->damage; + vest = atom->vest; +} + +/* ---------------------------------------------------------------------- + copy atom I info to atom J + ------------------------------------------------------------------------- */ + +void AtomVecSMD::copy(int i, int j, int delflag) { + tag[j] = tag[i]; + type[j] = type[i]; + mask[j] = mask[i]; + image[j] = image[i]; + x[j][0] = x[i][0]; + x[j][1] = x[i][1]; + x[j][2] = x[i][2]; + v[j][0] = v[i][0]; + v[j][1] = v[i][1]; + v[j][2] = v[i][2]; + + vfrac[j] = vfrac[i]; + rmass[j] = rmass[i]; + x0[j][0] = x0[i][0]; + x0[j][1] = x0[i][1]; + x0[j][2] = x0[i][2]; + radius[j] = radius[i]; + contact_radius[j] = contact_radius[i]; + molecule[j] = molecule[i]; + e[j] = e[i]; + eff_plastic_strain[j] = eff_plastic_strain[i]; + eff_plastic_strain_rate[j] = eff_plastic_strain_rate[i]; + vest[j][0] = vest[i][0]; + vest[j][1] = vest[i][1]; + vest[j][2] = vest[i][2]; + + for (int k = 0; k < NMAT_FULL; k++) { + smd_data_9[j][k] = smd_data_9[i][k]; + } + + for (int k = 0; k < NMAT_SYMM; k++) { + tlsph_stress[j][k] = tlsph_stress[i][k]; + } + + damage[j] = damage[i]; + + if (atom->nextra_grow) + for (int iextra = 0; iextra < atom->nextra_grow; iextra++) + modify->fix[atom->extra_grow[iextra]]->copy_arrays(i, j, delflag); +} + +/* ---------------------------------------------------------------------- */ + +int AtomVecSMD::pack_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { + error->one(FLERR, "atom vec tlsph can only be used with ghost velocities turned on"); + return -1; +} + +/* ---------------------------------------------------------------------- */ + +int AtomVecSMD::pack_comm_vel(int n, int *list, double *buf, int pbc_flag, int *pbc) { + // communicate quantities to ghosts, which are changed by time-integration AND are required on ghost atoms. + + //no need to pack stress or defgrad information here, as these quantities are not required for ghost atoms. + // Inside pair_style tlsph, these quantities are computed and communicated to ghosts. + + // no need to communicate x0 here, as it is not changed by time integration + // if x0 is changed when the ref config is updated, this communication is performed in the fix_integrate/tlsph + // similarily, rmass could be removed here. + // radius should be communicated here for future time-integration of the radius with ulsph (not implemented yet) + int i, j, m; + double dx, dy, dz, dvx, dvy, dvz; + + m = 0; + if (pbc_flag == 0) { + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = x[j][0]; + buf[m++] = x[j][1]; + buf[m++] = x[j][2]; //3 + buf[m++] = radius[j]; + buf[m++] = vfrac[j]; // 5 + buf[m++] = v[j][0]; + buf[m++] = v[j][1]; + buf[m++] = v[j][2]; // 8 + + buf[m++] = vest[j][0]; + buf[m++] = vest[j][1]; + buf[m++] = vest[j][2]; // 11 + buf[m++] = e[j]; // 12 + + } + } else { + if (domain->triclinic == 0) { + dx = pbc[0] * domain->xprd; + dy = pbc[1] * domain->yprd; + dz = pbc[2] * domain->zprd; + } else { + dx = pbc[0] * domain->xprd + pbc[5] * domain->xy + pbc[4] * domain->xz; + dy = pbc[1] * domain->yprd + pbc[3] * domain->yz; + dz = pbc[2] * domain->zprd; + } + if (!deform_vremap) { + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = x[j][0] + dx; + buf[m++] = x[j][1] + dy; + buf[m++] = x[j][2] + dz; + buf[m++] = radius[j]; + buf[m++] = vfrac[j]; + buf[m++] = v[j][0]; + buf[m++] = v[j][1]; + buf[m++] = v[j][2]; // 8 + + buf[m++] = vest[j][0]; + buf[m++] = vest[j][1]; + buf[m++] = vest[j][2]; // 11 + buf[m++] = e[j]; // 12 + + } + } else { + dvx = pbc[0] * h_rate[0] + pbc[5] * h_rate[5] + pbc[4] * h_rate[4]; + dvy = pbc[1] * h_rate[1] + pbc[3] * h_rate[3]; + dvz = pbc[2] * h_rate[2]; +// printf("\ndvx = %f, dvy=%f, dvz=%f\n", dvx, dvy, dvz); +// printf("dx = %f, dy=%f, dz=%f\n", dx, dy, dz); + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = x[j][0] + dx; + buf[m++] = x[j][1] + dy; + buf[m++] = x[j][2] + dz; + buf[m++] = radius[j]; + buf[m++] = vfrac[j]; + if (mask[i] & deform_groupbit) { + buf[m++] = v[j][0] + dvx; + buf[m++] = v[j][1] + dvy; + buf[m++] = v[j][2] + dvz; + buf[m++] = vest[j][0] + dvx; + buf[m++] = vest[j][1] + dvy; + buf[m++] = vest[j][2] + dvz; + } else { + buf[m++] = v[j][0]; + buf[m++] = v[j][1]; + buf[m++] = v[j][2]; // 8 + buf[m++] = vest[j][0]; + buf[m++] = vest[j][1]; + buf[m++] = vest[j][2]; // 11 + } + + buf[m++] = e[j]; // 12 + + } + } + } + + return m; +} + +/* ---------------------------------------------------------------------- */ + +int AtomVecSMD::pack_comm_hybrid(int n, int *list, double *buf) { + int i, j, m; + + m = 0; + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = radius[j]; + buf[m++] = vfrac[j]; + buf[m++] = vest[j][0]; + buf[m++] = vest[j][1]; + buf[m++] = vest[j][2]; + buf[m++] = e[j]; + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +void AtomVecSMD::unpack_comm(int n, int first, double *buf) { + error->one(FLERR, "atom vec tlsph can only be used with ghost velocities turned on"); +} + +/* ---------------------------------------------------------------------- */ + +void AtomVecSMD::unpack_comm_vel(int n, int first, double *buf) { + int i, m, last; + + m = 0; + last = first + n; + for (i = first; i < last; i++) { + x[i][0] = buf[m++]; + x[i][1] = buf[m++]; + x[i][2] = buf[m++]; //3 + radius[i] = buf[m++]; + vfrac[i] = buf[m++]; // 5 + v[i][0] = buf[m++]; + v[i][1] = buf[m++]; + v[i][2] = buf[m++]; // 8 + + vest[i][0] = buf[m++]; + vest[i][1] = buf[m++]; + vest[i][2] = buf[m++]; // 11 + e[i] = buf[m++]; + + } +} + +/* ---------------------------------------------------------------------- */ + +int AtomVecSMD::unpack_comm_hybrid(int n, int first, double *buf) { + int i, m, last; + + m = 0; + last = first + n; + for (i = first; i < last; i++) { + radius[i] = buf[m++]; + vfrac[i] = buf[m++]; + vest[i][0] = buf[m++]; + vest[i][1] = buf[m++]; + vest[i][2] = buf[m++]; + e[i] = buf[m++]; + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +int AtomVecSMD::pack_reverse(int n, int first, double *buf) { + int i, m, last; + + printf("in pack_reverse\n"); + + m = 0; + last = first + n; + for (i = first; i < last; i++) { + buf[m++] = f[i][0]; + buf[m++] = f[i][1]; + buf[m++] = f[i][2]; + buf[m++] = de[i]; + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +int AtomVecSMD::pack_reverse_hybrid(int n, int first, double *buf) { + int i, m, last; + + m = 0; + last = first + n; + for (i = first; i < last; i++) { + buf[m++] = de[i]; + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +void AtomVecSMD::unpack_reverse(int n, int *list, double *buf) { + int i, j, m; + + m = 0; + for (i = 0; i < n; i++) { + j = list[i]; + f[j][0] += buf[m++]; + f[j][1] += buf[m++]; + f[j][2] += buf[m++]; + de[j] += buf[m++]; + } +} + +/* ---------------------------------------------------------------------- */ + +int AtomVecSMD::unpack_reverse_hybrid(int n, int *list, double *buf) { + int i, j, m; + + m = 0; + for (i = 0; i < n; i++) { + j = list[i]; + de[j] += buf[m++]; + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +int AtomVecSMD::pack_border(int n, int *list, double *buf, int pbc_flag, int *pbc) { + error->one(FLERR, "atom vec tlsph can only be used with ghost velocities turned on"); + return -1; +} + +/* ---------------------------------------------------------------------- */ + +int AtomVecSMD::pack_border_vel(int n, int *list, double *buf, int pbc_flag, int *pbc) { + int i, j, m; + double dx, dy, dz, dvx, dvy, dvz; + + //printf("AtomVecSMD::pack_border_vel\n"); + + m = 0; + if (pbc_flag == 0) { + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = x[j][0]; + buf[m++] = x[j][1]; + buf[m++] = x[j][2]; // 3 + buf[m++] = x0[j][0]; + buf[m++] = x0[j][1]; + buf[m++] = x0[j][2]; // 6 + buf[m++] = ubuf(tag[j]).d; + buf[m++] = ubuf(type[j]).d; + buf[m++] = ubuf(mask[j]).d; + buf[m++] = ubuf(molecule[j]).d; // 10 + buf[m++] = radius[j]; + buf[m++] = rmass[j]; + buf[m++] = vfrac[j]; + buf[m++] = contact_radius[j]; + buf[m++] = e[j]; + buf[m++] = eff_plastic_strain[j]; // 16 + + for (int k = 0; k < NMAT_FULL; k++) { + buf[m++] = smd_data_9[j][k]; + } // 25 + + for (int k = 0; k < NMAT_SYMM; k++) { + buf[m++] = tlsph_stress[j][k]; + } // 31 + + buf[m++] = v[j][0]; + buf[m++] = v[j][1]; + buf[m++] = v[j][2]; // 34 + buf[m++] = vest[j][0]; + buf[m++] = vest[j][1]; + buf[m++] = vest[j][2]; // 37 + } + } else { + + if (domain->triclinic == 0) { + dx = pbc[0] * domain->xprd; + dy = pbc[1] * domain->yprd; + dz = pbc[2] * domain->zprd; + } else { + dx = pbc[0]; + dy = pbc[1]; + dz = pbc[2]; + } + if (!deform_vremap) { + //printf("dx = %f\n", dx); + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = x[j][0] + dx; + buf[m++] = x[j][1] + dy; + buf[m++] = x[j][2] + dz; // 3 + buf[m++] = x0[j][0]; // this is correct + buf[m++] = x0[j][1]; + buf[m++] = x0[j][2]; // 6 + buf[m++] = ubuf(tag[j]).d; + buf[m++] = ubuf(type[j]).d; + buf[m++] = ubuf(mask[j]).d; + buf[m++] = ubuf(molecule[j]).d; // 10 + buf[m++] = radius[j]; + buf[m++] = rmass[j]; + buf[m++] = vfrac[j]; + buf[m++] = contact_radius[j]; + buf[m++] = e[j]; + buf[m++] = eff_plastic_strain[j]; // 17 + + for (int k = 0; k < NMAT_FULL; k++) { + buf[m++] = smd_data_9[j][k]; + } // 26 + + for (int k = 0; k < NMAT_SYMM; k++) { + buf[m++] = tlsph_stress[j][k]; + } // 32 + + buf[m++] = v[j][0]; + buf[m++] = v[j][1]; + buf[m++] = v[j][2]; // 35 + buf[m++] = vest[j][0]; + buf[m++] = vest[j][1]; + buf[m++] = vest[j][2]; // 38 + + } + } else { + dvx = pbc[0] * h_rate[0] + pbc[5] * h_rate[5] + pbc[4] * h_rate[4]; + dvy = pbc[1] * h_rate[1] + pbc[3] * h_rate[3]; + dvz = pbc[2] * h_rate[2]; +// printf("\ndvx = %f, dvy=%f, dvz=%f\n", dvx, dvy, dvz); +// printf("dx = %f, dy=%f, dz=%f\n", dx, dy, dz); + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = x[j][0] + dx; + buf[m++] = x[j][1] + dy; + buf[m++] = x[j][2] + dz; // 3 + buf[m++] = x0[j][0]; + buf[m++] = x0[j][1]; + buf[m++] = x0[j][2]; // 6 + buf[m++] = ubuf(tag[j]).d; + buf[m++] = ubuf(type[j]).d; + buf[m++] = ubuf(mask[j]).d; + buf[m++] = ubuf(molecule[j]).d; // 10 + buf[m++] = radius[j]; + buf[m++] = rmass[j]; + buf[m++] = vfrac[j]; + buf[m++] = contact_radius[j]; + buf[m++] = e[j]; + buf[m++] = eff_plastic_strain[j]; // 16 + + for (int k = 0; k < NMAT_FULL; k++) { + buf[m++] = smd_data_9[j][k]; + } // 25 + + for (int k = 0; k < NMAT_SYMM; k++) { + buf[m++] = tlsph_stress[j][k]; + } // 31 + + if (mask[i] & deform_groupbit) { + buf[m++] = v[j][0] + dvx; + buf[m++] = v[j][1] + dvy; + buf[m++] = v[j][2] + dvz; // 34 + buf[m++] = vest[j][0] + dvx; + buf[m++] = vest[j][1] + dvy; + buf[m++] = vest[j][2] + dvz; // 37 + + } else { + buf[m++] = v[j][0]; + buf[m++] = v[j][1]; + buf[m++] = v[j][2]; // 34 + buf[m++] = vest[j][0]; + buf[m++] = vest[j][1]; + buf[m++] = vest[j][2]; // 37 + } + + } + } + } + + if (atom->nextra_border) + for (int iextra = 0; iextra < atom->nextra_border; iextra++) + m += modify->fix[atom->extra_border[iextra]]->pack_border(n, list, &buf[m]); + + return m; +} + +/* ---------------------------------------------------------------------- */ + +int AtomVecSMD::pack_border_hybrid(int n, int *list, double *buf) { + int i, j, m; + + m = 0; + for (i = 0; i < n; i++) { + j = list[i]; + + buf[m++] = x0[j][0]; + buf[m++] = x0[j][1]; + buf[m++] = x0[j][2]; // 3 + buf[m++] = ubuf(molecule[j]).d; // 4 + buf[m++] = radius[j]; + buf[m++] = rmass[j]; + buf[m++] = vfrac[j]; + buf[m++] = contact_radius[j]; + buf[m++] = e[j]; + buf[m++] = eff_plastic_strain[j]; // 11 + + for (int k = 0; k < NMAT_FULL; k++) { + buf[m++] = smd_data_9[j][k]; + } // 20 + + for (int k = 0; k < NMAT_SYMM; k++) { + buf[m++] = tlsph_stress[j][k]; + } // 26 + + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +void AtomVecSMD::unpack_border(int n, int first, double *buf) { + error->one(FLERR, "atom vec tlsph can only be used with ghost velocities turned on"); +} + +/* ---------------------------------------------------------------------- */ + +void AtomVecSMD::unpack_border_vel(int n, int first, double *buf) { + int i, m, last; + + m = 0; + last = first + n; + for (i = first; i < last; i++) { + if (i == nmax) + grow(0); + x[i][0] = buf[m++]; + x[i][1] = buf[m++]; + x[i][2] = buf[m++]; // 3 + x0[i][0] = buf[m++]; + x0[i][1] = buf[m++]; + x0[i][2] = buf[m++]; // 6 + tag[i] = (tagint) ubuf(buf[m++]).i; + type[i] = (int) ubuf(buf[m++]).i; + mask[i] = (int) ubuf(buf[m++]).i; + molecule[i] = (int) ubuf(buf[m++]).i; // 10 + + radius[i] = buf[m++]; + rmass[i] = buf[m++]; + vfrac[i] = buf[m++]; + contact_radius[i] = buf[m++]; + e[i] = buf[m++]; + eff_plastic_strain[i] = buf[m++]; // 16 + + for (int k = 0; k < NMAT_FULL; k++) { + smd_data_9[i][k] = buf[m++]; + } // 25 + + for (int k = 0; k < NMAT_SYMM; k++) { + tlsph_stress[i][k] = buf[m++]; + } // 31 + + v[i][0] = buf[m++]; + v[i][1] = buf[m++]; + v[i][2] = buf[m++]; // 34 + vest[i][0] = buf[m++]; + vest[i][1] = buf[m++]; + vest[i][2] = buf[m++]; // 37 + } + + if (atom->nextra_border) + for (int iextra = 0; iextra < atom->nextra_border; iextra++) + m += modify->fix[atom->extra_border[iextra]]->unpack_border(n, first, &buf[m]); +} + +/* ---------------------------------------------------------------------- */ + +int AtomVecSMD::unpack_border_hybrid(int n, int first, double *buf) { + int i, m, last; + + m = 0; + last = first + n; + for (i = first; i < last; i++) { + x0[i][0] = buf[m++]; + x0[i][1] = buf[m++]; + x0[i][2] = buf[m++]; // 3 + molecule[i] = (int) ubuf(buf[m++]).i; // 4 + radius[i] = buf[m++]; + rmass[i] = buf[m++]; + vfrac[i] = buf[m++]; + contact_radius[i] = buf[m++]; + e[i] = buf[m++]; + eff_plastic_strain[i] = buf[m++]; // 11 + + for (int k = 0; k < NMAT_FULL; k++) { + smd_data_9[i][k] = buf[m++]; + } // 20 + + for (int k = 0; k < NMAT_SYMM; k++) { + tlsph_stress[i][k] = buf[m++]; + } // 26 + } + return m; +} + +/* ---------------------------------------------------------------------- + pack data for atom I for sending to another proc + xyz must be 1st 3 values, so comm::exchange() can test on them + ------------------------------------------------------------------------- */ + +int AtomVecSMD::pack_exchange(int i, double *buf) { + int m = 1; + + //printf("in AtomVecSMD::pack_exchange tag %d\n", tag[i]); + + buf[m++] = x[i][0]; + buf[m++] = x[i][1]; + buf[m++] = x[i][2]; // 3 + buf[m++] = x0[i][0]; + buf[m++] = x0[i][1]; + buf[m++] = x0[i][2]; // 6 + buf[m++] = ubuf(tag[i]).d; + buf[m++] = ubuf(type[i]).d; + buf[m++] = ubuf(mask[i]).d; + buf[m++] = ubuf(image[i]).d; + buf[m++] = ubuf(molecule[i]).d; // 11 + buf[m++] = radius[i]; + buf[m++] = rmass[i]; + buf[m++] = vfrac[i]; + buf[m++] = contact_radius[i]; + buf[m++] = e[i]; + buf[m++] = eff_plastic_strain[i]; // 18 + buf[m++] = eff_plastic_strain_rate[i]; // 19 + + for (int k = 0; k < NMAT_FULL; k++) { + buf[m++] = smd_data_9[i][k]; + } // 27 + + for (int k = 0; k < NMAT_SYMM; k++) { + buf[m++] = tlsph_stress[i][k]; + } // 33 + + buf[m++] = v[i][0]; + buf[m++] = v[i][1]; + buf[m++] = v[i][2]; // 36 + buf[m++] = vest[i][0]; + buf[m++] = vest[i][1]; + buf[m++] = vest[i][2]; // 39 + + buf[m++] = damage[i]; + + if (atom->nextra_grow) + for (int iextra = 0; iextra < atom->nextra_grow; iextra++) + m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i, &buf[m]); + + buf[0] = m; + return m; +} + +/* ---------------------------------------------------------------------- */ + +int AtomVecSMD::unpack_exchange(double *buf) { + int nlocal = atom->nlocal; + if (nlocal == nmax) + grow(0); + + int m = 1; + + x[nlocal][0] = buf[m++]; + x[nlocal][1] = buf[m++]; + x[nlocal][2] = buf[m++]; // 3 + x0[nlocal][0] = buf[m++]; + x0[nlocal][1] = buf[m++]; + x0[nlocal][2] = buf[m++]; // 6 + tag[nlocal] = (tagint) ubuf(buf[m++]).i; + type[nlocal] = (int) ubuf(buf[m++]).i; + mask[nlocal] = (int) ubuf(buf[m++]).i; + image[nlocal] = (imageint) ubuf(buf[m++]).i; + molecule[nlocal] = (int) ubuf(buf[m++]).i; // 11 + + radius[nlocal] = buf[m++]; + rmass[nlocal] = buf[m++]; + vfrac[nlocal] = buf[m++]; + contact_radius[nlocal] = buf[m++]; + e[nlocal] = buf[m++]; + eff_plastic_strain[nlocal] = buf[m++]; // 18 + eff_plastic_strain_rate[nlocal] = buf[m++]; // 19 + + for (int k = 0; k < NMAT_FULL; k++) { + smd_data_9[nlocal][k] = buf[m++]; + } // 27 + + for (int k = 0; k < NMAT_SYMM; k++) { + tlsph_stress[nlocal][k] = buf[m++]; + } // 33 + + v[nlocal][0] = buf[m++]; + v[nlocal][1] = buf[m++]; + v[nlocal][2] = buf[m++]; // 36 + vest[nlocal][0] = buf[m++]; + vest[nlocal][1] = buf[m++]; + vest[nlocal][2] = buf[m++]; // 39 + + damage[nlocal] = buf[m++]; //40 + + if (atom->nextra_grow) + for (int iextra = 0; iextra < atom->nextra_grow; iextra++) + m += modify->fix[atom->extra_grow[iextra]]->unpack_exchange(nlocal, &buf[m]); + + atom->nlocal++; + return m; +} + +/* ---------------------------------------------------------------------- + size of restart data for all atoms owned by this proc + include extra data stored by fixes + ------------------------------------------------------------------------- */ + +int AtomVecSMD::size_restart() { + int i; + + int nlocal = atom->nlocal; + int n = 43 * nlocal; // count pack_restart + 1 (size of buffer) + + if (atom->nextra_restart) + for (int iextra = 0; iextra < atom->nextra_restart; iextra++) + for (i = 0; i < nlocal; i++) + n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); + + return n; +} + +/* ---------------------------------------------------------------------- + pack atom I's data for restart file including extra quantities + xyz must be 1st 3 values, so that read_restart can test on them + molecular types may be negative, but write as positive + ------------------------------------------------------------------------- */ +int AtomVecSMD::pack_restart(int i, double *buf) { + int m = 1; // 1 + + buf[m++] = x[i][0]; + buf[m++] = x[i][1]; + buf[m++] = x[i][2]; // 4 + buf[m++] = x0[i][0]; + buf[m++] = x0[i][1]; + buf[m++] = x0[i][2]; // 7 + buf[m++] = ubuf(tag[i]).d; + buf[m++] = ubuf(type[i]).d; + buf[m++] = ubuf(mask[i]).d; // 10 + buf[m++] = ubuf(image[i]).d; + buf[m++] = ubuf(molecule[i]).d; + buf[m++] = radius[i]; + buf[m++] = rmass[i]; + buf[m++] = vfrac[i]; // 15 + buf[m++] = contact_radius[i]; + buf[m++] = e[i]; + buf[m++] = eff_plastic_strain[i]; + buf[m++] = eff_plastic_strain_rate[i]; // 19 + + for (int k = 0; k < NMAT_FULL; k++) { + buf[m++] = smd_data_9[i][k]; + } // 28 + + for (int k = 0; k < NMAT_SYMM; k++) { + buf[m++] = tlsph_stress[i][k]; + } // 34 + + buf[m++] = v[i][0]; + buf[m++] = v[i][1]; + buf[m++] = v[i][2]; // 37 + buf[m++] = vest[i][0]; + buf[m++] = vest[i][1]; + buf[m++] = vest[i][2]; // 40 + + buf[m++] = damage[i]; // 41 + + if (atom->nextra_restart) + for (int iextra = 0; iextra < atom->nextra_restart; iextra++) + m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i, &buf[m]); + + buf[0] = m; + return m; +} + +/* ---------------------------------------------------------------------- + unpack data for one atom from restart file including extra quantities + ------------------------------------------------------------------------- */ + +int AtomVecSMD::unpack_restart(double *buf) { + int nlocal = atom->nlocal; + if (nlocal == nmax) { + grow(0); + if (atom->nextra_store) + memory->grow(atom->extra, nmax, atom->nextra_store, "atom:extra"); + } + + int m = 1; + + x[nlocal][0] = buf[m++]; + x[nlocal][1] = buf[m++]; + x[nlocal][2] = buf[m++]; // 3 + x0[nlocal][0] = buf[m++]; + x0[nlocal][1] = buf[m++]; + x0[nlocal][2] = buf[m++]; // 6 + tag[nlocal] = (tagint) ubuf(buf[m++]).i; + type[nlocal] = (int) ubuf(buf[m++]).i; + mask[nlocal] = (int) ubuf(buf[m++]).i; + image[nlocal] = (imageint) ubuf(buf[m++]).i; + molecule[nlocal] = (int) ubuf(buf[m++]).i; // 11 + + radius[nlocal] = buf[m++]; + rmass[nlocal] = buf[m++]; + vfrac[nlocal] = buf[m++]; //14 + contact_radius[nlocal] = buf[m++]; //15 + e[nlocal] = buf[m++]; + eff_plastic_strain[nlocal] = buf[m++]; // 18 + eff_plastic_strain_rate[nlocal] = buf[m++]; // 29 + + for (int k = 0; k < NMAT_FULL; k++) { + smd_data_9[nlocal][k] = buf[m++]; + } // 28 + + for (int k = 0; k < NMAT_SYMM; k++) { + tlsph_stress[nlocal][k] = buf[m++]; + } // 34 + + v[nlocal][0] = buf[m++]; + v[nlocal][1] = buf[m++]; + v[nlocal][2] = buf[m++]; // 37 + vest[nlocal][0] = buf[m++]; + vest[nlocal][1] = buf[m++]; + vest[nlocal][2] = buf[m++]; // 40 + + damage[nlocal] = buf[m++]; //41 + + //printf("nlocal in restart is %d\n", nlocal); + + double **extra = atom->extra; + if (atom->nextra_store) { + int size = static_cast(buf[0]) - m; + for (int i = 0; i < size; i++) + extra[nlocal][i] = buf[m++]; + } + + atom->nlocal++; + + //printf("returning m=%d in unpack_restart\n", m); + + return m; +} + +/* ---------------------------------------------------------------------- + create one atom of itype at coord + set other values to defaults + ------------------------------------------------------------------------- */ + +void AtomVecSMD::create_atom(int itype, double *coord) { + int nlocal = atom->nlocal; + if (nlocal == nmax) { + printf("nlocal = %d, nmax = %d, calling grow\n", nlocal, nmax); + grow(0); + printf("... finished growing\n"); + } + + tag[nlocal] = 0; + type[nlocal] = itype; + x[nlocal][0] = coord[0]; + x[nlocal][1] = coord[1]; + x[nlocal][2] = coord[2]; + x0[nlocal][0] = coord[0]; + x0[nlocal][1] = coord[1]; + x0[nlocal][2] = coord[2]; + mask[nlocal] = 1; + image[nlocal] = ((imageint) IMGMAX << IMG2BITS) | ((imageint) IMGMAX << IMGBITS) | IMGMAX; + v[nlocal][0] = 0.0; + v[nlocal][1] = 0.0; + v[nlocal][2] = 0.0; + vest[nlocal][0] = 0.0; + vest[nlocal][1] = 0.0; + vest[nlocal][2] = 0.0; + + vfrac[nlocal] = 1.0; + rmass[nlocal] = 1.0; + radius[nlocal] = 0.5; + contact_radius[nlocal] = 0.5; + molecule[nlocal] = 1; + e[nlocal] = 0.0; + eff_plastic_strain[nlocal] = 0.0; + eff_plastic_strain_rate[nlocal] = 0.0; + + for (int k = 0; k < NMAT_FULL; k++) { + smd_data_9[nlocal][k] = 0.0; + } + smd_data_9[nlocal][0] = 1.0; // xx + smd_data_9[nlocal][4] = 1.0; // yy + smd_data_9[nlocal][8] = 1.0; // zz + + for (int k = 0; k < NMAT_SYMM; k++) { + tlsph_stress[nlocal][k] = 0.0; + } + + damage[nlocal] = 0.0; + + atom->nlocal++; +} + +/* ---------------------------------------------------------------------- + unpack one line from Atoms section of data file + initialize other atom quantities + ------------------------------------------------------------------------- */ + +void AtomVecSMD::data_atom(double *coord, imageint imagetmp, char **values) { + int nlocal = atom->nlocal; + if (nlocal == nmax) + grow(0); + + tag[nlocal] = ATOTAGINT(values[0]); + + type[nlocal] = atoi(values[1]); + if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) + error->one(FLERR, "Invalid atom type in Atoms section of data file"); + + molecule[nlocal] = atoi(values[2]); + if (molecule[nlocal] <= 0) + error->one(FLERR, "Invalid molecule in Atoms section of data file"); + + vfrac[nlocal] = atof(values[3]); + if (vfrac[nlocal] < 0.0) + error->one(FLERR, "Invalid volume in Atoms section of data file"); + + rmass[nlocal] = atof(values[4]); + if (rmass[nlocal] == 0.0) + error->one(FLERR, "Invalid mass in Atoms section of data file"); + + radius[nlocal] = atof(values[5]); + if (radius[nlocal] < 0.0) + error->one(FLERR, "Invalid radius in Atoms section of data file"); + + contact_radius[nlocal] = atof(values[6]); + if (contact_radius[nlocal] < 0.0) + error->one(FLERR, "Invalid contact radius in Atoms section of data file"); + + e[nlocal] = 0.0; + + x0[nlocal][0] = atof(values[7]); + x0[nlocal][1] = atof(values[8]); + x0[nlocal][2] = atof(values[9]); + + x[nlocal][0] = coord[0]; + x[nlocal][1] = coord[1]; + x[nlocal][2] = coord[2]; + + image[nlocal] = imagetmp; + + mask[nlocal] = 1; + v[nlocal][0] = 0.0; + v[nlocal][1] = 0.0; + v[nlocal][2] = 0.0; + vest[nlocal][0] = 0.0; + vest[nlocal][1] = 0.0; + vest[nlocal][2] = 0.0; + + damage[nlocal] = 0.0; + + eff_plastic_strain[nlocal] = 0.0; + eff_plastic_strain_rate[nlocal] = 0.0; + + for (int k = 0; k < NMAT_FULL; k++) { + smd_data_9[nlocal][k] = 0.0; + } + + for (int k = 0; k < NMAT_SYMM; k++) { + tlsph_stress[nlocal][k] = 0.0; + } + + smd_data_9[nlocal][0] = 1.0; // xx + smd_data_9[nlocal][4] = 1.0; // yy + smd_data_9[nlocal][8] = 1.0; // zz + + atom->nlocal++; +} + +/* ---------------------------------------------------------------------- + unpack hybrid quantities from one line in Atoms section of data file + initialize other atom quantities for this sub-style + ------------------------------------------------------------------------- */ + +int AtomVecSMD::data_atom_hybrid(int nlocal, char **values) { + error->one(FLERR, "hybrid atom style functionality not yet implemented for atom style tlsph"); + return -1; +} + +/* ---------------------------------------------------------------------- + unpack one line from Velocities section of data file + ------------------------------------------------------------------------- */ + +void AtomVecSMD::data_vel(int m, char **values) { + v[m][0] = atof(values[0]); + v[m][1] = atof(values[1]); + v[m][2] = atof(values[2]); + vest[m][0] = atof(values[0]); + vest[m][1] = atof(values[1]); + vest[m][2] = atof(values[2]); +} + +/* ---------------------------------------------------------------------- + unpack hybrid quantities from one line in Velocities section of data file + ------------------------------------------------------------------------- */ + +int AtomVecSMD::data_vel_hybrid(int m, char **values) { + error->one(FLERR, "hybrid atom style functionality not yet implemented for atom style tlsph"); + return 0; +} + +/* ---------------------------------------------------------------------- + pack atom info for data file including 3 image flags + ------------------------------------------------------------------------- */ + +void AtomVecSMD::pack_data(double **buf) { + int nlocal = atom->nlocal; + for (int i = 0; i < nlocal; i++) { + buf[i][0] = ubuf(tag[i]).d; + buf[i][1] = ubuf(type[i]).d; + buf[i][2] = ubuf(molecule[i]).d; + buf[i][3] = vfrac[i]; + buf[i][4] = rmass[i]; + buf[i][5] = radius[i]; + buf[i][6] = contact_radius[i]; + + buf[i][7] = x[i][0]; + buf[i][8] = x[i][1]; + buf[i][9] = x[i][2]; + + buf[i][10] = ubuf((image[i] & IMGMASK) - IMGMAX).d; + buf[i][11] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d; + buf[i][12] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d; + } +} + +/* ---------------------------------------------------------------------- + pack hybrid atom info for data file + ------------------------------------------------------------------------- */ + +int AtomVecSMD::pack_data_hybrid(int i, double *buf) { + error->one(FLERR, "hybrid atom style functionality not yet implemented for atom style tlsph"); + return -1; +} + +/* ---------------------------------------------------------------------- + write atom info to data file including 3 image flags + ------------------------------------------------------------------------- */ + +void AtomVecSMD::write_data(FILE *fp, int n, double **buf) { + for (int i = 0; i < n; i++) + fprintf(fp, + TAGINT_FORMAT + " %d %d %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d\n", (tagint) ubuf(buf[i][0]).i, + (int) ubuf(buf[i][1]).i, (int) ubuf(buf[i][2]).i, buf[i][3], buf[i][4], buf[i][5], buf[i][6], buf[i][7], buf[i][8], + buf[i][9], (int) ubuf(buf[i][7]).i, (int) ubuf(buf[i][8]).i, (int) ubuf(buf[i][9]).i); +} + +/* ---------------------------------------------------------------------- + write hybrid atom info to data file + ------------------------------------------------------------------------- */ + +int AtomVecSMD::write_data_hybrid(FILE *fp, double *buf) { + error->one(FLERR, "hybrid atom style functionality not yet implemented for atom style tlsph"); + return -1; +} + +/* ---------------------------------------------------------------------- + pack velocity info for data file + ------------------------------------------------------------------------- */ + +void AtomVecSMD::pack_vel(double **buf) { + int nlocal = atom->nlocal; + for (int i = 0; i < nlocal; i++) { + buf[i][0] = ubuf(tag[i]).d; + buf[i][1] = v[i][0]; + buf[i][2] = v[i][1]; + buf[i][3] = v[i][2]; + } +} + +/* ---------------------------------------------------------------------- + pack hybrid velocity info for data file + ------------------------------------------------------------------------- */ + +int AtomVecSMD::pack_vel_hybrid(int i, double *buf) { + error->one(FLERR, "hybrid atom style functionality not yet implemented for atom style tlsph"); + return 0; +} + +/* ---------------------------------------------------------------------- + write velocity info to data file + ------------------------------------------------------------------------- */ + +void AtomVecSMD::write_vel(FILE *fp, int n, double **buf) { + for (int i = 0; i < n; i++) + fprintf(fp, TAGINT_FORMAT + " %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e\n", (tagint) ubuf(buf[i][0]).i, buf[i][1], buf[i][2], buf[i][3], + buf[i][4], buf[i][5], buf[i][6]); +} + +/* ---------------------------------------------------------------------- + write hybrid velocity info to data file + ------------------------------------------------------------------------- */ + +int AtomVecSMD::write_vel_hybrid(FILE *fp, double *buf) { + error->one(FLERR, "hybrid atom style functionality not yet implemented for atom style tlsph"); + return 3; +} + +/* ---------------------------------------------------------------------- + return # of bytes of allocated memory + ------------------------------------------------------------------------- */ + +bigint AtomVecSMD::memory_usage() { + bigint bytes = 0; + + if (atom->memcheck("tag")) + bytes += memory->usage(tag, nmax); + if (atom->memcheck("type")) + bytes += memory->usage(type, nmax); + if (atom->memcheck("molecule")) + bytes += memory->usage(molecule, nmax); + if (atom->memcheck("mask")) + bytes += memory->usage(mask, nmax); + if (atom->memcheck("image")) + bytes += memory->usage(image, nmax); + if (atom->memcheck("x")) + bytes += memory->usage(x, nmax, 3); + if (atom->memcheck("v")) + bytes += memory->usage(v, nmax, 3); + if (atom->memcheck("vest")) + bytes += memory->usage(vest, nmax, 3); + if (atom->memcheck("f")) + bytes += memory->usage(f, nmax * comm->nthreads, 3); + + if (atom->memcheck("radius")) + bytes += memory->usage(radius, nmax); + if (atom->memcheck("contact_radius")) + bytes += memory->usage(contact_radius, nmax); + if (atom->memcheck("vfrac")) + bytes += memory->usage(vfrac, nmax); + if (atom->memcheck("rmass")) + bytes += memory->usage(rmass, nmax); + if (atom->memcheck("eff_plastic_strain")) + bytes += memory->usage(eff_plastic_strain, nmax); + if (atom->memcheck("eff_plastic_strain_rate")) + bytes += memory->usage(eff_plastic_strain_rate, nmax); + if (atom->memcheck("e")) + bytes += memory->usage(e, nmax); + if (atom->memcheck("de")) + bytes += memory->usage(de, nmax); + + if (atom->memcheck("smd_data_9")) + bytes += memory->usage(smd_data_9, nmax, NMAT_FULL); + if (atom->memcheck("tlsph_stress")) + bytes += memory->usage(tlsph_stress, nmax, NMAT_SYMM); + + if (atom->memcheck("damage")) + bytes += memory->usage(damage, nmax); + + return bytes; +} + +/* ---------------------------------------------------------------------- */ + +void AtomVecSMD::force_clear(int n, size_t nbytes) { + //printf("clearing force on atom %d", n); + memset(&de[n], 0, nbytes); + memset(&f[0][0], 0, 3 * nbytes); +} diff --git a/src/USER-SMD/atom_vec_smd.h b/src/USER-SMD/atom_vec_smd.h new file mode 100644 index 0000000000..c79c60c352 --- /dev/null +++ b/src/USER-SMD/atom_vec_smd.h @@ -0,0 +1,125 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef ATOM_CLASS + +AtomStyle(smd,AtomVecSMD) + +#else + +#ifndef LMP_ATOM_VEC_SMD_H +#define LMP_ATOM_VEC_SMD_H + +#include "atom_vec.h" + +namespace LAMMPS_NS { + +class AtomVecSMD : public AtomVec { + public: + AtomVecSMD(class LAMMPS *); + ~AtomVecSMD() {} + void init(); + void grow(int); + void grow_reset(); + void copy(int, int, int); + void force_clear(int, size_t); + int pack_comm(int, int *, double *, int, int *); + int pack_comm_vel(int, int *, double *, int, int *); + int pack_comm_hybrid(int, int *, double *); + void unpack_comm(int, int, double *); + void unpack_comm_vel(int, int, double *); + int unpack_comm_hybrid(int, int, double *); + int pack_reverse(int, int, double *); + int pack_reverse_hybrid(int, int, double *); + void unpack_reverse(int, int *, double *); + int unpack_reverse_hybrid(int, int *, double *); + int pack_border(int, int *, double *, int, int *); + int pack_border_vel(int, int *, double *, int, int *); + int pack_border_hybrid(int, int *, double *); + void unpack_border(int, int, double *); + void unpack_border_vel(int, int, double *); + int unpack_border_hybrid(int, int, double *); + int pack_exchange(int, double *); + int unpack_exchange(double *); + int size_restart(); + int pack_restart(int, double *); + int unpack_restart(double *); + void create_atom(int, double *); + void data_atom(double *, imageint, char **); + int data_atom_hybrid(int, char **); + void data_vel(int, char **); + int data_vel_hybrid(int, char **); + void pack_data(double **); + int pack_data_hybrid(int, double *); + void write_data(FILE *, int, double **); + int write_data_hybrid(FILE *, double *); + void pack_vel(double **); + int pack_vel_hybrid(int, double *); + void write_vel(FILE *, int, double **); + int write_vel_hybrid(FILE *, double *); + bigint memory_usage(); + + private: + tagint *tag; + int *type,*mask; + imageint *image; + double **x,**v,**f; + double *radius,*rmass; + + int *molecule; + double *vfrac,**x0,*contact_radius, **smd_data_9, *e, *de, **vest; + double **tlsph_stress; + double *eff_plastic_strain; + double *damage; + double *eff_plastic_strain_rate; + + +}; + +} + +#endif +#endif + +/* ERROR/WARNING messages: + +E: Per-processor system is too big + +The number of owned atoms plus ghost atoms on a single +processor must fit in 32-bit integer. + +E: Invalid atom type in Atoms section of data file + +Atom types must range from 1 to specified # of types. + +E: Invalid radius in Atoms section of data file + +Radius must be >= 0.0. + +E: Invalid density in Atoms section of data file + +Density value cannot be <= 0.0. + +*/ diff --git a/src/USER-SMD/compute_smd_contact_radius.cpp b/src/USER-SMD/compute_smd_contact_radius.cpp new file mode 100644 index 0000000000..865031addb --- /dev/null +++ b/src/USER-SMD/compute_smd_contact_radius.cpp @@ -0,0 +1,109 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#include "string.h" +#include "compute_smd_contact_radius.h" +#include "atom.h" +#include "update.h" +#include "modify.h" +#include "comm.h" +#include "force.h" +#include "memory.h" +#include "error.h" + +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +ComputeSMDContactRadius::ComputeSMDContactRadius(LAMMPS *lmp, int narg, char **arg) : + Compute(lmp, narg, arg) +{ + if (narg != 3) error->all(FLERR,"Illegal compute smd/contact_radius command"); + if (atom->contact_radius_flag != 1) error->all(FLERR,"compute smd/contact_radius command requires atom_style with contact_radius (e.g. smd)"); + + peratom_flag = 1; + size_peratom_cols = 0; + + nmax = 0; + contact_radius_vector = NULL; +} + +/* ---------------------------------------------------------------------- */ + +ComputeSMDContactRadius::~ComputeSMDContactRadius() +{ + memory->sfree(contact_radius_vector); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDContactRadius::init() +{ + + int count = 0; + for (int i = 0; i < modify->ncompute; i++) + if (strcmp(modify->compute[i]->style,"smd/contact_radius") == 0) count++; + if (count > 1 && comm->me == 0) + error->warning(FLERR,"More than one compute smd/contact_radius"); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDContactRadius::compute_peratom() +{ + invoked_peratom = update->ntimestep; + + // grow rhoVector array if necessary + + if (atom->nlocal > nmax) { + memory->sfree(contact_radius_vector); + nmax = atom->nmax; + contact_radius_vector = (double *) memory->smalloc(nmax*sizeof(double),"atom:contact_radius_vector"); + vector_atom = contact_radius_vector; + } + + double *contact_radius = atom->contact_radius; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + contact_radius_vector[i] = contact_radius[i]; + } + else { + contact_radius_vector[i] = 0.0; + } + } +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based array +------------------------------------------------------------------------- */ + +double ComputeSMDContactRadius::memory_usage() +{ + double bytes = nmax * sizeof(double); + return bytes; +} diff --git a/src/USER-SMD/compute_smd_contact_radius.h b/src/USER-SMD/compute_smd_contact_radius.h new file mode 100644 index 0000000000..9acb8e3b17 --- /dev/null +++ b/src/USER-SMD/compute_smd_contact_radius.h @@ -0,0 +1,55 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef COMPUTE_CLASS + +ComputeStyle(smd/contact_radius,ComputeSMDContactRadius) + +#else + +#ifndef LMP_COMPUTE_SMD_CONTACT_RADIUS_H +#define LMP_COMPUTE_SMD_CONTACT_RADIUS_H + +#include "compute.h" + +namespace LAMMPS_NS { + +class ComputeSMDContactRadius : public Compute { + public: + ComputeSMDContactRadius(class LAMMPS *, int, char **); + ~ComputeSMDContactRadius(); + void init(); + void compute_peratom(); + double memory_usage(); + + private: + int nmax; + double *contact_radius_vector; +}; + +} + +#endif +#endif diff --git a/src/USER-SMD/compute_smd_damage.cpp b/src/USER-SMD/compute_smd_damage.cpp new file mode 100644 index 0000000000..95d7bee3be --- /dev/null +++ b/src/USER-SMD/compute_smd_damage.cpp @@ -0,0 +1,109 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#include "string.h" +#include "compute_smd_damage.h" +#include "atom.h" +#include "update.h" +#include "modify.h" +#include "comm.h" +#include "force.h" +#include "memory.h" +#include "error.h" + +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +ComputeSMDDamage::ComputeSMDDamage(LAMMPS *lmp, int narg, char **arg) : + Compute(lmp, narg, arg) +{ + if (narg != 3) error->all(FLERR,"Illegal compute smd/damage command"); + if (atom->damage_flag != 1) error->all(FLERR,"compute smd/damage command requires atom_style with damage (e.g. smd)"); + + peratom_flag = 1; + size_peratom_cols = 0; + + nmax = 0; + damage_vector = NULL; +} + +/* ---------------------------------------------------------------------- */ + +ComputeSMDDamage::~ComputeSMDDamage() +{ + memory->sfree(damage_vector); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDDamage::init() +{ + + int count = 0; + for (int i = 0; i < modify->ncompute; i++) + if (strcmp(modify->compute[i]->style,"smd/damage") == 0) count++; + if (count > 1 && comm->me == 0) + error->warning(FLERR,"More than one compute smd/damage"); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDDamage::compute_peratom() +{ + invoked_peratom = update->ntimestep; + + // grow rhoVector array if necessary + + if (atom->nlocal > nmax) { + memory->sfree(damage_vector); + nmax = atom->nmax; + damage_vector = (double *) memory->smalloc(nmax*sizeof(double),"atom:damage_vector"); + vector_atom = damage_vector; + } + + double *damage = atom->damage; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + damage_vector[i] = damage[i]; + } + else { + damage_vector[i] = 0.0; + } + } +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based array +------------------------------------------------------------------------- */ + +double ComputeSMDDamage::memory_usage() +{ + double bytes = nmax * sizeof(double); + return bytes; +} diff --git a/src/USER-SMD/compute_smd_damage.h b/src/USER-SMD/compute_smd_damage.h new file mode 100644 index 0000000000..1259788ec4 --- /dev/null +++ b/src/USER-SMD/compute_smd_damage.h @@ -0,0 +1,55 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef COMPUTE_CLASS + +ComputeStyle(smd/damage,ComputeSMDDamage) + +#else + +#ifndef LMP_COMPUTE_SMD_DAMAGE_H +#define LMP_COMPUTE_SMD_DAMAGE_H + +#include "compute.h" + +namespace LAMMPS_NS { + +class ComputeSMDDamage : public Compute { + public: + ComputeSMDDamage(class LAMMPS *, int, char **); + ~ComputeSMDDamage(); + void init(); + void compute_peratom(); + double memory_usage(); + + private: + int nmax; + double *damage_vector; +}; + +} + +#endif +#endif diff --git a/src/USER-SMD/compute_smd_hourglass_error.cpp b/src/USER-SMD/compute_smd_hourglass_error.cpp new file mode 100644 index 0000000000..ae6ffee0e1 --- /dev/null +++ b/src/USER-SMD/compute_smd_hourglass_error.cpp @@ -0,0 +1,112 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +#include "string.h" +#include "compute_smd_hourglass_error.h" +#include "atom.h" +#include "update.h" +#include "modify.h" +#include "comm.h" +#include "force.h" +#include "memory.h" +#include "error.h" +#include "pair.h" + +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +ComputeSMDHourglassError::ComputeSMDHourglassError(LAMMPS *lmp, int narg, char **arg) : + Compute(lmp, narg, arg) { + if (narg != 3) + error->all(FLERR, "Illegal compute smd/hourglass_error command"); + if (atom->smd_flag != 1) + error->all(FLERR, "compute smd/hourglass_error command requires atom_style with hourglass_error (e.g. smd)"); + + peratom_flag = 1; + size_peratom_cols = 0; + + nmax = 0; + hourglass_error_vector = NULL; +} + +/* ---------------------------------------------------------------------- */ + +ComputeSMDHourglassError::~ComputeSMDHourglassError() { + memory->sfree(hourglass_error_vector); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDHourglassError::init() { + + int count = 0; + for (int i = 0; i < modify->ncompute; i++) + if (strcmp(modify->compute[i]->style, "smd/hourglass_error") == 0) + count++; + if (count > 1 && comm->me == 0) + error->warning(FLERR, "More than one compute smd/hourglass_error"); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDHourglassError::compute_peratom() { + invoked_peratom = update->ntimestep; + + // grow output Vector array if necessary + + if (atom->nlocal > nmax) { + memory->sfree(hourglass_error_vector); + nmax = atom->nmax; + hourglass_error_vector = (double *) memory->smalloc(nmax * sizeof(double), "atom:hourglass_error_vector"); + vector_atom = hourglass_error_vector; + } + + int itmp = 0; + double *hourglass_error = (double *) force->pair->extract("smd/tlsph/hourglass_error_ptr", itmp); + if (hourglass_error == NULL) { + error->all(FLERR, "compute smd/hourglass_error failed to access hourglass_error array"); + } + + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + hourglass_error_vector[i] = hourglass_error[i]; + } else { + hourglass_error_vector[i] = 0.0; + } + } +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based array + ------------------------------------------------------------------------- */ + +double ComputeSMDHourglassError::memory_usage() { + double bytes = nmax * sizeof(double); + return bytes; +} diff --git a/src/USER-SMD/compute_smd_hourglass_error.h b/src/USER-SMD/compute_smd_hourglass_error.h new file mode 100644 index 0000000000..fdfbfae641 --- /dev/null +++ b/src/USER-SMD/compute_smd_hourglass_error.h @@ -0,0 +1,55 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef COMPUTE_CLASS + +ComputeStyle(smd/hourglass_error,ComputeSMDHourglassError) + +#else + +#ifndef LMP_COMPUTE_SMD_HOURGLASS_ERROR_H +#define LMP_COMPUTE_SMD_HOURGLASS_ERROR_H + +#include "compute.h" + +namespace LAMMPS_NS { + +class ComputeSMDHourglassError : public Compute { + public: + ComputeSMDHourglassError(class LAMMPS *, int, char **); + ~ComputeSMDHourglassError(); + void init(); + void compute_peratom(); + double memory_usage(); + + private: + int nmax; + double *hourglass_error_vector; +}; + +} + +#endif +#endif diff --git a/src/USER-SMD/compute_smd_internal_energy.cpp b/src/USER-SMD/compute_smd_internal_energy.cpp new file mode 100644 index 0000000000..9116df7011 --- /dev/null +++ b/src/USER-SMD/compute_smd_internal_energy.cpp @@ -0,0 +1,109 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#include "string.h" +#include "compute_smd_internal_energy.h" +#include "atom.h" +#include "update.h" +#include "modify.h" +#include "comm.h" +#include "force.h" +#include "memory.h" +#include "error.h" + +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +ComputeSMDInternalEnergy::ComputeSMDInternalEnergy(LAMMPS *lmp, int narg, char **arg) : + Compute(lmp, narg, arg) +{ + if (narg != 3) error->all(FLERR,"Illegal compute smd/internal_energy command"); + if (atom->e_flag != 1) error->all(FLERR,"compute smd/internal_energy command requires atom_style with internal_energy (e.g. smd)"); + + peratom_flag = 1; + size_peratom_cols = 0; + + nmax = 0; + internal_energy_vector = NULL; +} + +/* ---------------------------------------------------------------------- */ + +ComputeSMDInternalEnergy::~ComputeSMDInternalEnergy() +{ + memory->sfree(internal_energy_vector); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDInternalEnergy::init() +{ + + int count = 0; + for (int i = 0; i < modify->ncompute; i++) + if (strcmp(modify->compute[i]->style,"smd/internal_energy") == 0) count++; + if (count > 1 && comm->me == 0) + error->warning(FLERR,"More than one compute smd/internal_energy"); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDInternalEnergy::compute_peratom() +{ + invoked_peratom = update->ntimestep; + + // grow rhoVector array if necessary + + if (atom->nlocal > nmax) { + memory->sfree(internal_energy_vector); + nmax = atom->nmax; + internal_energy_vector = (double *) memory->smalloc(nmax*sizeof(double),"atom:internal_energy_vector"); + vector_atom = internal_energy_vector; + } + + double *e = atom->e; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + internal_energy_vector[i] = e[i]; + } + else { + internal_energy_vector[i] = 0.0; + } + } +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based array +------------------------------------------------------------------------- */ + +double ComputeSMDInternalEnergy::memory_usage() +{ + double bytes = nmax * sizeof(double); + return bytes; +} diff --git a/src/USER-SMD/compute_smd_internal_energy.h b/src/USER-SMD/compute_smd_internal_energy.h new file mode 100644 index 0000000000..4276a6ee60 --- /dev/null +++ b/src/USER-SMD/compute_smd_internal_energy.h @@ -0,0 +1,55 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef COMPUTE_CLASS + +ComputeStyle(smd/internal_energy,ComputeSMDInternalEnergy) + +#else + +#ifndef LMP_COMPUTE_SMD_INTERNAL_ENERGY_H +#define LMP_COMPUTE_SMD_INTERNAL_ENERGY_H + +#include "compute.h" + +namespace LAMMPS_NS { + +class ComputeSMDInternalEnergy : public Compute { + public: + ComputeSMDInternalEnergy(class LAMMPS *, int, char **); + ~ComputeSMDInternalEnergy(); + void init(); + void compute_peratom(); + double memory_usage(); + + private: + int nmax; + double *internal_energy_vector; +}; + +} + +#endif +#endif diff --git a/src/USER-SMD/compute_smd_plastic_strain.cpp b/src/USER-SMD/compute_smd_plastic_strain.cpp new file mode 100644 index 0000000000..734f40e267 --- /dev/null +++ b/src/USER-SMD/compute_smd_plastic_strain.cpp @@ -0,0 +1,109 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#include "string.h" +#include "compute_smd_plastic_strain.h" +#include "atom.h" +#include "update.h" +#include "modify.h" +#include "comm.h" +#include "force.h" +#include "memory.h" +#include "error.h" + +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +ComputeSMDPlasticStrain::ComputeSMDPlasticStrain(LAMMPS *lmp, int narg, char **arg) : + Compute(lmp, narg, arg) +{ + if (narg != 3) error->all(FLERR,"Illegal compute smd/plastic_strain command"); + if (atom->eff_plastic_strain_flag != 1) error->all(FLERR,"compute smd/plastic_strain command requires atom_style with plastic_strain (e.g. smd)"); + + peratom_flag = 1; + size_peratom_cols = 0; + + nmax = 0; + plastic_strain_vector = NULL; +} + +/* ---------------------------------------------------------------------- */ + +ComputeSMDPlasticStrain::~ComputeSMDPlasticStrain() +{ + memory->sfree(plastic_strain_vector); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDPlasticStrain::init() +{ + + int count = 0; + for (int i = 0; i < modify->ncompute; i++) + if (strcmp(modify->compute[i]->style,"smd/plastic_strain") == 0) count++; + if (count > 1 && comm->me == 0) + error->warning(FLERR,"More than one compute smd/plastic_strain"); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDPlasticStrain::compute_peratom() +{ + invoked_peratom = update->ntimestep; + + // grow rhoVector array if necessary + + if (atom->nlocal > nmax) { + memory->sfree(plastic_strain_vector); + nmax = atom->nmax; + plastic_strain_vector = (double *) memory->smalloc(nmax*sizeof(double),"atom:plastic_strain_vector"); + vector_atom = plastic_strain_vector; + } + + double *plastic_strain = atom->eff_plastic_strain; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + plastic_strain_vector[i] = plastic_strain[i]; + } + else { + plastic_strain_vector[i] = 0.0; + } + } +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based array +------------------------------------------------------------------------- */ + +double ComputeSMDPlasticStrain::memory_usage() +{ + double bytes = nmax * sizeof(double); + return bytes; +} diff --git a/src/USER-SMD/compute_smd_plastic_strain.h b/src/USER-SMD/compute_smd_plastic_strain.h new file mode 100644 index 0000000000..30b191ee2e --- /dev/null +++ b/src/USER-SMD/compute_smd_plastic_strain.h @@ -0,0 +1,55 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef COMPUTE_CLASS + +ComputeStyle(smd/plastic_strain,ComputeSMDPlasticStrain) + +#else + +#ifndef LMP_COMPUTE_SMD_PLASTIC_STRAIN_H +#define LMP_COMPUTE_SMD_PLASTIC_STRAIN_H + +#include "compute.h" + +namespace LAMMPS_NS { + +class ComputeSMDPlasticStrain : public Compute { + public: + ComputeSMDPlasticStrain(class LAMMPS *, int, char **); + ~ComputeSMDPlasticStrain(); + void init(); + void compute_peratom(); + double memory_usage(); + + private: + int nmax; + double *plastic_strain_vector; +}; + +} + +#endif +#endif diff --git a/src/USER-SMD/compute_smd_plastic_strain_rate.cpp b/src/USER-SMD/compute_smd_plastic_strain_rate.cpp new file mode 100644 index 0000000000..44a890bf82 --- /dev/null +++ b/src/USER-SMD/compute_smd_plastic_strain_rate.cpp @@ -0,0 +1,109 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#include "string.h" +#include "compute_smd_plastic_strain_rate.h" +#include "atom.h" +#include "update.h" +#include "modify.h" +#include "comm.h" +#include "force.h" +#include "memory.h" +#include "error.h" + +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +ComputeSMDPlasticStrainRate::ComputeSMDPlasticStrainRate(LAMMPS *lmp, int narg, char **arg) : + Compute(lmp, narg, arg) +{ + if (narg != 3) error->all(FLERR,"Illegal compute smd/plastic_strain command"); + if (atom->eff_plastic_strain_rate_flag != 1) error->all(FLERR,"compute smd/plastic_strain_rate command requires atom_style with plastic_strain_rate (e.g. smd)"); + + peratom_flag = 1; + size_peratom_cols = 0; + + nmax = 0; + plastic_strain_rate_vector = NULL; +} + +/* ---------------------------------------------------------------------- */ + +ComputeSMDPlasticStrainRate::~ComputeSMDPlasticStrainRate() +{ + memory->sfree(plastic_strain_rate_vector); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDPlasticStrainRate::init() +{ + + int count = 0; + for (int i = 0; i < modify->ncompute; i++) + if (strcmp(modify->compute[i]->style,"smd/plastic_strain_rate") == 0) count++; + if (count > 1 && comm->me == 0) + error->warning(FLERR,"More than one compute smd/plastic_strain_rate"); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDPlasticStrainRate::compute_peratom() +{ + invoked_peratom = update->ntimestep; + + // grow rhoVector array if necessary + + if (atom->nlocal > nmax) { + memory->sfree(plastic_strain_rate_vector); + nmax = atom->nmax; + plastic_strain_rate_vector = (double *) memory->smalloc(nmax*sizeof(double),"atom:plastic_strain_rate_vector"); + vector_atom = plastic_strain_rate_vector; + } + + double *plastic_strain_rate = atom->eff_plastic_strain_rate; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + plastic_strain_rate_vector[i] = plastic_strain_rate[i]; + } + else { + plastic_strain_rate_vector[i] = 0.0; + } + } +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based array +------------------------------------------------------------------------- */ + +double ComputeSMDPlasticStrainRate::memory_usage() +{ + double bytes = nmax * sizeof(double); + return bytes; +} diff --git a/src/USER-SMD/compute_smd_plastic_strain_rate.h b/src/USER-SMD/compute_smd_plastic_strain_rate.h new file mode 100644 index 0000000000..1d99ac0baa --- /dev/null +++ b/src/USER-SMD/compute_smd_plastic_strain_rate.h @@ -0,0 +1,55 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef COMPUTE_CLASS + +ComputeStyle(smd/plastic_strain_rate,ComputeSMDPlasticStrainRate) + +#else + +#ifndef LMP_COMPUTE_SMD_PLASTIC_STRAIN_RATE_H +#define LMP_COMPUTE_SMD_PLASTIC_STRAIN_RATE_H + +#include "compute.h" + +namespace LAMMPS_NS { + +class ComputeSMDPlasticStrainRate : public Compute { + public: + ComputeSMDPlasticStrainRate(class LAMMPS *, int, char **); + ~ComputeSMDPlasticStrainRate(); + void init(); + void compute_peratom(); + double memory_usage(); + + private: + int nmax; + double *plastic_strain_rate_vector; +}; + +} + +#endif +#endif diff --git a/src/USER-SMD/compute_smd_rho.cpp b/src/USER-SMD/compute_smd_rho.cpp new file mode 100644 index 0000000000..0e9ee9bb27 --- /dev/null +++ b/src/USER-SMD/compute_smd_rho.cpp @@ -0,0 +1,107 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +#include "string.h" +#include "compute_smd_rho.h" +#include "atom.h" +#include "update.h" +#include "modify.h" +#include "comm.h" +#include "force.h" +#include "memory.h" +#include "error.h" + +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +ComputeSMDRho::ComputeSMDRho(LAMMPS *lmp, int narg, char **arg) : + Compute(lmp, narg, arg) { + if (narg != 3) + error->all(FLERR, "Illegal compute smd/rho command"); + if (atom->vfrac_flag != 1) + error->all(FLERR, "compute smd/rho command requires atom_style with volume (e.g. smd)"); + + peratom_flag = 1; + size_peratom_cols = 0; + + nmax = 0; + rhoVector = NULL; +} + +/* ---------------------------------------------------------------------- */ + +ComputeSMDRho::~ComputeSMDRho() { + memory->sfree(rhoVector); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDRho::init() { + + int count = 0; + for (int i = 0; i < modify->ncompute; i++) + if (strcmp(modify->compute[i]->style, "smd/rho") == 0) + count++; + if (count > 1 && comm->me == 0) + error->warning(FLERR, "More than one compute smd/rho"); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDRho::compute_peratom() { + invoked_peratom = update->ntimestep; + + // grow rhoVector array if necessary + + if (atom->nlocal > nmax) { + memory->sfree(rhoVector); + nmax = atom->nmax; + rhoVector = (double *) memory->smalloc(nmax * sizeof(double), "atom:rhoVector"); + vector_atom = rhoVector; + } + + double *vfrac = atom->vfrac; + double *rmass = atom->rmass; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + rhoVector[i] = rmass[i] / vfrac[i]; + } else { + rhoVector[i] = 0.0; + } + } + +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based array + ------------------------------------------------------------------------- */ + +double ComputeSMDRho::memory_usage() { + double bytes = nmax * sizeof(double); + return bytes; +} diff --git a/src/USER-SMD/compute_smd_rho.h b/src/USER-SMD/compute_smd_rho.h new file mode 100644 index 0000000000..ce749c6466 --- /dev/null +++ b/src/USER-SMD/compute_smd_rho.h @@ -0,0 +1,55 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef COMPUTE_CLASS + +ComputeStyle(smd/rho,ComputeSMDRho) + +#else + +#ifndef LMP_COMPUTE_SMD_RHO_H +#define LMP_COMPUTE_SMD_RHO_H + +#include "compute.h" + +namespace LAMMPS_NS { + +class ComputeSMDRho : public Compute { + public: + ComputeSMDRho(class LAMMPS *, int, char **); + ~ComputeSMDRho(); + void init(); + void compute_peratom(); + double memory_usage(); + + private: + int nmax; + double *rhoVector; +}; + +} + +#endif +#endif diff --git a/src/USER-SMD/compute_smd_tlsph_defgrad.cpp b/src/USER-SMD/compute_smd_tlsph_defgrad.cpp new file mode 100644 index 0000000000..7dcd7faca0 --- /dev/null +++ b/src/USER-SMD/compute_smd_tlsph_defgrad.cpp @@ -0,0 +1,138 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +#include "string.h" +#include "compute_smd_tlsph_defgrad.h" +#include "atom.h" +#include "update.h" +#include "modify.h" +#include "comm.h" +#include "force.h" +#include "memory.h" +#include "error.h" +#include "pair.h" +#include +#include +#include "stdlib.h" +#include "string.h" +#include +using namespace Eigen; +using namespace std; +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +ComputeSMDTLSPHDefgrad::ComputeSMDTLSPHDefgrad(LAMMPS *lmp, int narg, char **arg) : + Compute(lmp, narg, arg) { + if (narg != 3) + error->all(FLERR, "Illegal compute smd/tlsph_defgrad command"); + + peratom_flag = 1; + size_peratom_cols = 10; + + nmax = 0; + defgradVector = NULL; +} + +/* ---------------------------------------------------------------------- */ + +ComputeSMDTLSPHDefgrad::~ComputeSMDTLSPHDefgrad() { + memory->sfree(defgradVector); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDTLSPHDefgrad::init() { + + int count = 0; + for (int i = 0; i < modify->ncompute; i++) + if (strcmp(modify->compute[i]->style, "smd/tlsph_defgrad") == 0) + count++; + if (count > 1 && comm->me == 0) + error->warning(FLERR, "More than one compute smd/tlsph_defgrad"); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDTLSPHDefgrad::compute_peratom() { + double **defgrad = atom->smd_data_9; + Matrix3d F; + invoked_peratom = update->ntimestep; + + // grow vector array if necessary + if (atom->nlocal > nmax) { + memory->destroy(defgradVector); + nmax = atom->nmax; + memory->create(defgradVector, nmax, size_peratom_cols, "defgradVector"); + array_atom = defgradVector; + } + + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + F(0, 0) = defgrad[i][0]; + F(0, 1) = defgrad[i][1]; + F(0, 2) = defgrad[i][2]; + F(1, 0) = defgrad[i][3]; + F(1, 1) = defgrad[i][4]; + F(1, 2) = defgrad[i][5]; + F(2, 0) = defgrad[i][6]; + F(2, 1) = defgrad[i][7]; + F(2, 2) = defgrad[i][8]; + + defgradVector[i][0] = F(0, 0); + defgradVector[i][1] = F(0, 1); + defgradVector[i][2] = F(0, 2); + defgradVector[i][3] = F(1, 0); + defgradVector[i][4] = F(1, 1); + defgradVector[i][5] = F(1, 2); + defgradVector[i][6] = F(2, 0); + defgradVector[i][7] = F(2, 1); + defgradVector[i][8] = F(2, 2); + defgradVector[i][9] = F.determinant(); + } else { + defgradVector[i][0] = 1.0; + defgradVector[i][1] = 0.0; + defgradVector[i][2] = 0.0; + defgradVector[i][3] = 0.0; + defgradVector[i][4] = 1.0; + defgradVector[i][5] = 0.0; + defgradVector[i][6] = 0.0; + defgradVector[i][7] = 0.0; + defgradVector[i][8] = 1.0; + defgradVector[i][9] = 1.0; + } + } +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based array + ------------------------------------------------------------------------- */ + +double ComputeSMDTLSPHDefgrad::memory_usage() { + double bytes = size_peratom_cols * nmax * sizeof(double); + return bytes; +} diff --git a/src/USER-SMD/compute_smd_tlsph_defgrad.h b/src/USER-SMD/compute_smd_tlsph_defgrad.h new file mode 100644 index 0000000000..c58fc5148d --- /dev/null +++ b/src/USER-SMD/compute_smd_tlsph_defgrad.h @@ -0,0 +1,55 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef COMPUTE_CLASS + +ComputeStyle(smd/tlsph_defgrad,ComputeSMDTLSPHDefgrad) + +#else + +#ifndef LMP_COMPUTE_SMD_TLSPH_DEFGRAD_H +#define LMP_COMPUTE_SMD_TLSPH_DEFGRAD_H + +#include "compute.h" + +namespace LAMMPS_NS { + +class ComputeSMDTLSPHDefgrad : public Compute { + public: + ComputeSMDTLSPHDefgrad(class LAMMPS *, int, char **); + ~ComputeSMDTLSPHDefgrad(); + void init(); + void compute_peratom(); + double memory_usage(); + + private: + int nmax; + double **defgradVector; +}; + +} + +#endif +#endif diff --git a/src/USER-SMD/compute_smd_tlsph_dt.cpp b/src/USER-SMD/compute_smd_tlsph_dt.cpp new file mode 100644 index 0000000000..fdb3c4feeb --- /dev/null +++ b/src/USER-SMD/compute_smd_tlsph_dt.cpp @@ -0,0 +1,115 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +#include "string.h" +#include "compute_smd_tlsph_dt.h" +#include "atom.h" +#include "update.h" +#include "modify.h" +#include "comm.h" +#include "force.h" +#include "memory.h" +#include "error.h" +#include "pair.h" + +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +ComputeSMDTlsphDt::ComputeSMDTlsphDt(LAMMPS *lmp, int narg, char **arg) : + Compute(lmp, narg, arg) { + if (narg != 3) + error->all(FLERR, "Illegal compute smd/tlsph_dt command"); + if (atom->contact_radius_flag != 1) + error->all(FLERR, + "compute smd/tlsph_dt command requires atom_style with contact_radius (e.g. smd)"); + + peratom_flag = 1; + size_peratom_cols = 0; + + nmax = 0; + dt_vector = NULL; +} + +/* ---------------------------------------------------------------------- */ + +ComputeSMDTlsphDt::~ComputeSMDTlsphDt() { + memory->sfree(dt_vector); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDTlsphDt::init() { + + int count = 0; + for (int i = 0; i < modify->ncompute; i++) + if (strcmp(modify->compute[i]->style, "smd/tlsph_dt") == 0) + count++; + if (count > 1 && comm->me == 0) + error->warning(FLERR, "More than one compute smd/tlsph_dt"); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDTlsphDt::compute_peratom() { + invoked_peratom = update->ntimestep; + + // grow rhoVector array if necessary + + if (atom->nlocal > nmax) { + memory->sfree(dt_vector); + nmax = atom->nmax; + dt_vector = (double *) memory->smalloc(nmax * sizeof(double), + "atom:tlsph_dt_vector"); + vector_atom = dt_vector; + } + + int itmp = 0; + double *particle_dt = (double *) force->pair->extract("smd/tlsph/particle_dt_ptr", + itmp); + if (particle_dt == NULL) { + error->all(FLERR, + "compute smd/tlsph_dt failed to access particle_dt array"); + } + + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + dt_vector[i] = particle_dt[i]; + } else { + dt_vector[i] = 0.0; + } + } +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based array + ------------------------------------------------------------------------- */ + +double ComputeSMDTlsphDt::memory_usage() { + double bytes = nmax * sizeof(double); + return bytes; +} diff --git a/src/USER-SMD/compute_smd_tlsph_dt.h b/src/USER-SMD/compute_smd_tlsph_dt.h new file mode 100644 index 0000000000..0b258a1a7f --- /dev/null +++ b/src/USER-SMD/compute_smd_tlsph_dt.h @@ -0,0 +1,55 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef COMPUTE_CLASS + +ComputeStyle(smd/tlsph_dt,ComputeSMDTlsphDt) + +#else + +#ifndef LMP_COMPUTE_SMD_TLSPH_DT_H +#define LMP_COMPUTE_SMD_TLSPH_DT_H + +#include "compute.h" + +namespace LAMMPS_NS { + +class ComputeSMDTlsphDt : public Compute { + public: + ComputeSMDTlsphDt(class LAMMPS *, int, char **); + ~ComputeSMDTlsphDt(); + void init(); + void compute_peratom(); + double memory_usage(); + + private: + int nmax; + double *dt_vector; +}; + +} + +#endif +#endif diff --git a/src/USER-SMD/compute_smd_tlsph_num_neighs.cpp b/src/USER-SMD/compute_smd_tlsph_num_neighs.cpp new file mode 100644 index 0000000000..7b7b2ce07c --- /dev/null +++ b/src/USER-SMD/compute_smd_tlsph_num_neighs.cpp @@ -0,0 +1,107 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +#include "string.h" +#include "compute_smd_tlsph_num_neighs.h" +#include "atom.h" +#include "update.h" +#include "modify.h" +#include "comm.h" +#include "force.h" +#include "memory.h" +#include "error.h" +#include "pair.h" + +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +ComputeSMDTLSPHNumNeighs::ComputeSMDTLSPHNumNeighs(LAMMPS *lmp, int narg, char **arg) : + Compute(lmp, narg, arg) { + if (narg != 3) + error->all(FLERR, "Illegal compute smd/tlsph_num_neighs command"); + + peratom_flag = 1; + size_peratom_cols = 0; + + nmax = 0; + numNeighsRefConfigOutput = NULL; +} + +/* ---------------------------------------------------------------------- */ + +ComputeSMDTLSPHNumNeighs::~ComputeSMDTLSPHNumNeighs() { + memory->destroy(numNeighsRefConfigOutput); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDTLSPHNumNeighs::init() { + int count = 0; + for (int i = 0; i < modify->ncompute; i++) + if (strcmp(modify->compute[i]->style, "smd/tlsph_num_neighs") == 0) + count++; + if (count > 1 && comm->me == 0) + error->warning(FLERR, "More than one compute smd/tlsph_num_neighs"); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDTLSPHNumNeighs::compute_peratom() { + invoked_peratom = update->ntimestep; + + if (atom->nlocal > nmax) { + memory->destroy(numNeighsRefConfigOutput); + nmax = atom->nmax; + memory->create(numNeighsRefConfigOutput, nmax, "tlsph/num_neighs:numNeighsRefConfigOutput"); + vector_atom = numNeighsRefConfigOutput; + } + + int *mask = atom->mask; + int nlocal = atom->nlocal; + + int itmp = 0; + int *numNeighsRefConfig = (int *) force->pair->extract("smd/tlsph/numNeighsRefConfig_ptr", itmp); + if (numNeighsRefConfig == NULL) { + error->all(FLERR, "compute smd/tlsph_num_neighs failed to access numNeighsRefConfig array"); + } + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + numNeighsRefConfigOutput[i] = numNeighsRefConfig[i]; + } else { + numNeighsRefConfigOutput[i] = 0.0; + } + } +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based array + ------------------------------------------------------------------------- */ + +double ComputeSMDTLSPHNumNeighs::memory_usage() { + double bytes = nmax * sizeof(double); + return bytes; +} diff --git a/src/USER-SMD/compute_smd_tlsph_num_neighs.h b/src/USER-SMD/compute_smd_tlsph_num_neighs.h new file mode 100644 index 0000000000..5b3613e05c --- /dev/null +++ b/src/USER-SMD/compute_smd_tlsph_num_neighs.h @@ -0,0 +1,69 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef COMPUTE_CLASS + +ComputeStyle(smd/tlsph_num_neighs,ComputeSMDTLSPHNumNeighs) + +#else + +#ifndef LMP_COMPUTE_SMD_TLSPH_NUM_NEIGHS_H +#define LMP_COMPUTE_SMD_TLSPH_NUM_NEIGHS_H + +#include "compute.h" + +namespace LAMMPS_NS { + +class ComputeSMDTLSPHNumNeighs : public Compute { + public: + ComputeSMDTLSPHNumNeighs(class LAMMPS *, int, char **); + ~ComputeSMDTLSPHNumNeighs(); + void init(); + void compute_peratom(); + double memory_usage(); + + private: + int nmax; + double *numNeighsRefConfigOutput; +}; + +} + +#endif +#endif + +/* ERROR/WARNING messages: + +E: Illegal ... command + +Self-explanatory. Check the input script syntax and compare to the +documentation for the command. You can use -echo screen as a +command-line option when running LAMMPS to see the offending line. + +W: More than one compute ke/atom + +It is not efficient to use compute ke/atom more than once. + +*/ diff --git a/src/USER-SMD/compute_smd_tlsph_shape.cpp b/src/USER-SMD/compute_smd_tlsph_shape.cpp new file mode 100644 index 0000000000..d4e8c14b37 --- /dev/null +++ b/src/USER-SMD/compute_smd_tlsph_shape.cpp @@ -0,0 +1,137 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +#include "string.h" +#include "compute_smd_tlsph_shape.h" +#include "atom.h" +#include "update.h" +#include "modify.h" +#include "comm.h" +#include "force.h" +#include "memory.h" +#include "error.h" +#include "pair.h" +#include +#include +#include "stdlib.h" +#include "string.h" +#include +#include +using namespace Eigen; +using namespace std; +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +ComputeSmdTlsphShape::ComputeSmdTlsphShape(LAMMPS *lmp, int narg, char **arg) : + Compute(lmp, narg, arg) { + if (narg != 3) + error->all(FLERR, "Illegal compute smd/tlsph_strain command"); + + peratom_flag = 1; + size_peratom_cols = 7; + + nmax = 0; + strainVector = NULL; +} + +/* ---------------------------------------------------------------------- */ + +ComputeSmdTlsphShape::~ComputeSmdTlsphShape() { + memory->sfree(strainVector); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSmdTlsphShape::init() { + + int count = 0; + for (int i = 0; i < modify->ncompute; i++) + if (strcmp(modify->compute[i]->style, "smd/tlsph_strain") == 0) + count++; + if (count > 1 && comm->me == 0) + error->warning(FLERR, "More than one compute smd/tlsph_strain"); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSmdTlsphShape::compute_peratom() { + double *contact_radius = atom->contact_radius; + invoked_peratom = update->ntimestep; + + // grow vector array if necessary + + if (atom->nlocal > nmax) { + memory->destroy(strainVector); + nmax = atom->nmax; + memory->create(strainVector, nmax, size_peratom_cols, "strainVector"); + array_atom = strainVector; + } + + int itmp = 0; + Matrix3d *R = (Matrix3d *) force->pair->extract("smd/tlsph/rotation_ptr", itmp); + if (R == NULL) { + error->all(FLERR, "compute smd/tlsph_shape failed to access rotation array"); + } + + Matrix3d *F = (Matrix3d *) force->pair->extract("smd/tlsph/Fincr_ptr", itmp); + if (F == NULL) { + error->all(FLERR, "compute smd/tlsph_shape failed to access deformation gradient array"); + } + + int *mask = atom->mask; + int nlocal = atom->nlocal; + Matrix3d E, eye; + eye.setIdentity(); + Quaterniond q; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + + E = 0.5 * (F[i].transpose() * F[i] - eye); // Green-Lagrange strain + strainVector[i][0] = contact_radius[i] * (1.0 + E(0, 0)); + strainVector[i][1] = contact_radius[i] * (1.0 + E(1, 1)); + strainVector[i][2] = contact_radius[i] * (1.0 + E(2, 2)); + + q = R[i]; // convert pure rotation matrix to quaternion + strainVector[i][3] = q.w(); + strainVector[i][4] = q.x(); + strainVector[i][5] = q.y(); + strainVector[i][6] = q.z(); + } else { + for (int j = 0; j < size_peratom_cols; j++) { + strainVector[i][j] = 0.0; + } + } + } +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based array + ------------------------------------------------------------------------- */ + +double ComputeSmdTlsphShape::memory_usage() { + double bytes = size_peratom_cols * nmax * sizeof(double); + return bytes; +} diff --git a/src/USER-SMD/compute_smd_tlsph_shape.h b/src/USER-SMD/compute_smd_tlsph_shape.h new file mode 100644 index 0000000000..673080e232 --- /dev/null +++ b/src/USER-SMD/compute_smd_tlsph_shape.h @@ -0,0 +1,55 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef COMPUTE_CLASS + +ComputeStyle(smd/tlsph_shape,ComputeSmdTlsphShape) + +#else + +#ifndef LMP_COMPUTE_SMD_TLSPH_SHAPE_H +#define LMP_COMPUTE_SMD_TLSPH_SHAPE_H + +#include "compute.h" + +namespace LAMMPS_NS { + +class ComputeSmdTlsphShape : public Compute { + public: + ComputeSmdTlsphShape(class LAMMPS *, int, char **); + ~ComputeSmdTlsphShape(); + void init(); + void compute_peratom(); + double memory_usage(); + + private: + int nmax; + double **strainVector; +}; + +} + +#endif +#endif diff --git a/src/USER-SMD/compute_smd_tlsph_strain.cpp b/src/USER-SMD/compute_smd_tlsph_strain.cpp new file mode 100644 index 0000000000..f191afeb2c --- /dev/null +++ b/src/USER-SMD/compute_smd_tlsph_strain.cpp @@ -0,0 +1,145 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +#include "string.h" +#include "compute_smd_tlsph_strain.h" +#include "atom.h" +#include "update.h" +#include "modify.h" +#include "comm.h" +#include "force.h" +#include "memory.h" +#include "error.h" +#include "pair.h" +#include +#include +#include "stdlib.h" +#include "string.h" +#include +using namespace Eigen; +using namespace std; +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +ComputeSMDTLSPHstrain::ComputeSMDTLSPHstrain(LAMMPS *lmp, int narg, char **arg) : + Compute(lmp, narg, arg) { + if (narg != 3) + error->all(FLERR, "Illegal compute smd/tlsph_strain command"); + + peratom_flag = 1; + size_peratom_cols = 6; + + nmax = 0; + strainVector = NULL; +} + +/* ---------------------------------------------------------------------- */ + +ComputeSMDTLSPHstrain::~ComputeSMDTLSPHstrain() { + memory->sfree(strainVector); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDTLSPHstrain::init() { + + int count = 0; + for (int i = 0; i < modify->ncompute; i++) + if (strcmp(modify->compute[i]->style, "smd/tlsph_strain") == 0) + count++; + if (count > 1 && comm->me == 0) + error->warning(FLERR, "More than one compute smd/tlsph_strain"); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDTLSPHstrain::compute_peratom() { + double **defgrad0 = atom->smd_data_9; + + invoked_peratom = update->ntimestep; + + // grow vector array if necessary + + if (atom->nlocal > nmax) { + memory->destroy(strainVector); + nmax = atom->nmax; + memory->create(strainVector, nmax, size_peratom_cols, "strainVector"); + array_atom = strainVector; + } + + // copy data to output array + int itmp = 0; + Matrix3d *Fincr = (Matrix3d *) force->pair->extract("smd/tlsph/Fincr_ptr", itmp); + if (Fincr == NULL) { + error->all(FLERR, "compute smd/tlsph_strain failed to access Fincr array"); + } + + int *mask = atom->mask; + int nlocal = atom->nlocal; + Matrix3d E, eye, Ftotal, F0; + eye.setIdentity(); + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + + // old deformation gradient + F0(0, 0) = defgrad0[i][0]; + F0(0, 1) = defgrad0[i][1]; + F0(0, 2) = defgrad0[i][2]; + F0(1, 0) = defgrad0[i][3]; + F0(1, 1) = defgrad0[i][4]; + F0(1, 2) = defgrad0[i][5]; + F0(2, 0) = defgrad0[i][6]; + F0(2, 1) = defgrad0[i][7]; + F0(2, 2) = defgrad0[i][8]; + + // compute current total deformation gradient + Ftotal = F0 * Fincr[i]; // this is the total deformation gradient: reference deformation times incremental deformation + + + E = 0.5 * (Ftotal.transpose() * Ftotal - eye); // Green-Lagrange strain + strainVector[i][0] = E(0, 0); + strainVector[i][1] = E(1, 1); + strainVector[i][2] = E(2, 2); + strainVector[i][3] = E(0, 1); + strainVector[i][4] = E(0, 2); + strainVector[i][5] = E(1, 2); + } else { + for (int j = 0; j < size_peratom_cols; j++) { + strainVector[i][j] = 0.0; + } + } + } +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based array + ------------------------------------------------------------------------- */ + +double ComputeSMDTLSPHstrain::memory_usage() { + double bytes = size_peratom_cols * nmax * sizeof(double); + return bytes; +} diff --git a/src/USER-SMD/compute_smd_tlsph_strain.h b/src/USER-SMD/compute_smd_tlsph_strain.h new file mode 100644 index 0000000000..a42fcddde2 --- /dev/null +++ b/src/USER-SMD/compute_smd_tlsph_strain.h @@ -0,0 +1,55 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef COMPUTE_CLASS + +ComputeStyle(smd/tlsph_strain,ComputeSMDTLSPHstrain) + +#else + +#ifndef LMP_COMPUTE_SMD_TLSPH_STRAIN_H +#define LMP_COMPUTE_SMD_TLSPH_STRAIN_H + +#include "compute.h" + +namespace LAMMPS_NS { + +class ComputeSMDTLSPHstrain : public Compute { + public: + ComputeSMDTLSPHstrain(class LAMMPS *, int, char **); + ~ComputeSMDTLSPHstrain(); + void init(); + void compute_peratom(); + double memory_usage(); + + private: + int nmax; + double **strainVector; +}; + +} + +#endif +#endif diff --git a/src/USER-SMD/compute_smd_tlsph_strain_rate.cpp b/src/USER-SMD/compute_smd_tlsph_strain_rate.cpp new file mode 100644 index 0000000000..a9e909db10 --- /dev/null +++ b/src/USER-SMD/compute_smd_tlsph_strain_rate.cpp @@ -0,0 +1,126 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +#include "string.h" +#include "compute_smd_tlsph_strain_rate.h" +#include "atom.h" +#include "update.h" +#include "modify.h" +#include "comm.h" +#include "force.h" +#include "memory.h" +#include "error.h" +#include "pair.h" +#include +using namespace Eigen; +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +ComputeSMDTLSPHStrainRate::ComputeSMDTLSPHStrainRate(LAMMPS *lmp, int narg, char **arg) : + Compute(lmp, narg, arg) { + if (narg != 3) + error->all(FLERR, "Illegal compute smd/ulsph_strain_rate command"); + + peratom_flag = 1; + size_peratom_cols = 6; + + nmax = 0; + strain_rate_array = NULL; +} + +/* ---------------------------------------------------------------------- */ + +ComputeSMDTLSPHStrainRate::~ComputeSMDTLSPHStrainRate() { + memory->sfree(strain_rate_array); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDTLSPHStrainRate::init() { + + int count = 0; + for (int i = 0; i < modify->ncompute; i++) + if (strcmp(modify->compute[i]->style, "smd/ulsph_strain_rate") == 0) + count++; + if (count > 1 && comm->me == 0) + error->warning(FLERR, "More than one compute smd/ulsph_strain_rate"); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDTLSPHStrainRate::compute_peratom() { + invoked_peratom = update->ntimestep; + int *mol = atom->molecule; + + // grow vector array if necessary + + if (atom->nlocal > nmax) { + memory->destroy(strain_rate_array); + nmax = atom->nmax; + memory->create(strain_rate_array, nmax, size_peratom_cols, "stresstensorVector"); + array_atom = strain_rate_array; + } + + int ulsph_flag = 0; + int tlsph_flag = 0; + int itmp = 0; + Matrix3d *D = (Matrix3d *) force->pair->extract("smd/tlsph/strain_rate_ptr", itmp); + if (D == NULL) { + error->all(FLERR, + "compute smd/tlsph_strain_rate could not access strain rate. Are the matching pair styles present?"); + } + + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + + strain_rate_array[i][0] = D[i](0, 0); // xx + strain_rate_array[i][1] = D[i](1, 1); // yy + strain_rate_array[i][2] = D[i](2, 2); // zz + strain_rate_array[i][3] = D[i](0, 1); // xy + strain_rate_array[i][4] = D[i](0, 2); // xz + strain_rate_array[i][5] = D[i](1, 2); // yz + } +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based array + ------------------------------------------------------------------------- */ + +double ComputeSMDTLSPHStrainRate::memory_usage() { + double bytes = size_peratom_cols * nmax * sizeof(double); + return bytes; +} + +/* + * deviator of a tensor + */ +Matrix3d ComputeSMDTLSPHStrainRate::Deviator(Matrix3d M) { + Matrix3d eye; + eye.setIdentity(); + eye *= M.trace() / 3.0; + return M - eye; +} diff --git a/src/USER-SMD/compute_smd_tlsph_strain_rate.h b/src/USER-SMD/compute_smd_tlsph_strain_rate.h new file mode 100644 index 0000000000..6332f03764 --- /dev/null +++ b/src/USER-SMD/compute_smd_tlsph_strain_rate.h @@ -0,0 +1,58 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef COMPUTE_CLASS + +ComputeStyle(smd/tlsph_strain_rate,ComputeSMDTLSPHStrainRate) + +#else + +#ifndef LMP_COMPUTE_SMD_TLSPH_STRAIN_RATE_H +#define LMP_COMPUTE_SMD_TLSPH_STRAIN_RATE_H + +#include "compute.h" +#include +using namespace Eigen; + +namespace LAMMPS_NS { + +class ComputeSMDTLSPHStrainRate : public Compute { + public: + ComputeSMDTLSPHStrainRate(class LAMMPS *, int, char **); + ~ComputeSMDTLSPHStrainRate(); + void init(); + void compute_peratom(); + double memory_usage(); + Matrix3d Deviator(Matrix3d); + + private: + int nmax; + double **strain_rate_array; +}; + +} + +#endif +#endif diff --git a/src/USER-SMD/compute_smd_tlsph_stress.cpp b/src/USER-SMD/compute_smd_tlsph_stress.cpp new file mode 100644 index 0000000000..bd38b6af33 --- /dev/null +++ b/src/USER-SMD/compute_smd_tlsph_stress.cpp @@ -0,0 +1,131 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +#include "string.h" +#include "compute_smd_tlsph_stress.h" +#include "atom.h" +#include "update.h" +#include "modify.h" +#include "comm.h" +#include "force.h" +#include "memory.h" +#include "error.h" +#include "pair.h" +#include +using namespace Eigen; +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +ComputeSMDTLSPHStress::ComputeSMDTLSPHStress(LAMMPS *lmp, int narg, char **arg) : + Compute(lmp, narg, arg) { + if (narg != 3) + error->all(FLERR, "Illegal compute smd/tlsph_stress command"); + + peratom_flag = 1; + size_peratom_cols = 7; + + nmax = 0; + stress_array = NULL; +} + +/* ---------------------------------------------------------------------- */ + +ComputeSMDTLSPHStress::~ComputeSMDTLSPHStress() { + memory->sfree(stress_array); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDTLSPHStress::init() { + + int count = 0; + for (int i = 0; i < modify->ncompute; i++) + if (strcmp(modify->compute[i]->style, "smd/tlsph_stress") == 0) + count++; + if (count > 1 && comm->me == 0) + error->warning(FLERR, "More than one compute smd/tlsph_stress"); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDTLSPHStress::compute_peratom() { + invoked_peratom = update->ntimestep; + Matrix3d stress_deviator; + double von_mises_stress; + + // grow vector array if necessary + + if (atom->nlocal > nmax) { + memory->destroy(stress_array); + nmax = atom->nmax; + memory->create(stress_array, nmax, size_peratom_cols, "stresstensorVector"); + array_atom = stress_array; + } + + int itmp = 0; + Matrix3d *T = (Matrix3d *) force->pair->extract("smd/tlsph/stressTensor_ptr", itmp); + if (T == NULL) { + error->all(FLERR, "compute smd/tlsph_stress could not access stress tensors. Are the matching pair styles present?"); + } + int nlocal = atom->nlocal; + int *mask = atom->mask; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + stress_deviator = Deviator(T[i]); + von_mises_stress = sqrt(3. / 2.) * stress_deviator.norm(); + stress_array[i][0] = T[i](0, 0); // xx + stress_array[i][1] = T[i](1, 1); // yy + stress_array[i][2] = T[i](2, 2); // zz + stress_array[i][3] = T[i](0, 1); // xy + stress_array[i][4] = T[i](0, 2); // xz + stress_array[i][5] = T[i](1, 2); // yz + stress_array[i][6] = von_mises_stress; + } else { + for (int j = 0; j < size_peratom_cols; j++) { + stress_array[i][j] = 0.0; + } + } + } +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based array + ------------------------------------------------------------------------- */ + +double ComputeSMDTLSPHStress::memory_usage() { + double bytes = size_peratom_cols * nmax * sizeof(double); + return bytes; +} + +/* + * deviator of a tensor + */ +Matrix3d ComputeSMDTLSPHStress::Deviator(Matrix3d M) { + Matrix3d eye; + eye.setIdentity(); + eye *= M.trace() / 3.0; + return M - eye; +} diff --git a/src/USER-SMD/compute_smd_tlsph_stress.h b/src/USER-SMD/compute_smd_tlsph_stress.h new file mode 100644 index 0000000000..5348584d04 --- /dev/null +++ b/src/USER-SMD/compute_smd_tlsph_stress.h @@ -0,0 +1,58 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef COMPUTE_CLASS + +ComputeStyle(smd/tlsph_stress, ComputeSMDTLSPHStress) + +#else + +#ifndef LMP_COMPUTE_SMD_TLSPH_STRESS_H +#define LMP_COMPUTE_SMD_TLSPH_STRESS_H + +#include "compute.h" +#include +using namespace Eigen; + +namespace LAMMPS_NS { + +class ComputeSMDTLSPHStress : public Compute { + public: + ComputeSMDTLSPHStress(class LAMMPS *, int, char **); + ~ComputeSMDTLSPHStress(); + void init(); + void compute_peratom(); + double memory_usage(); + Matrix3d Deviator(Matrix3d); + + private: + int nmax; + double **stress_array; +}; + +} + +#endif +#endif diff --git a/src/USER-SMD/compute_smd_triangle_mesh_vertices.cpp b/src/USER-SMD/compute_smd_triangle_mesh_vertices.cpp new file mode 100644 index 0000000000..6e7bac76bc --- /dev/null +++ b/src/USER-SMD/compute_smd_triangle_mesh_vertices.cpp @@ -0,0 +1,130 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +#include "string.h" +#include "compute_smd_triangle_mesh_vertices.h" +#include "atom.h" +#include "update.h" +#include "modify.h" +#include "comm.h" +#include "force.h" +#include "memory.h" +#include "error.h" +#include "pair.h" +#include +#include +#include "stdlib.h" +#include "string.h" +#include +using namespace Eigen; +using namespace std; +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +ComputeSMDTriangleVertices::ComputeSMDTriangleVertices(LAMMPS *lmp, int narg, char **arg) : + Compute(lmp, narg, arg) { + if (narg != 3) + error->all(FLERR, "Illegal compute smd/triangle_vertices command"); + + peratom_flag = 1; + size_peratom_cols = 9; + + nmax = 0; + outputVector = NULL; +} + +/* ---------------------------------------------------------------------- */ + +ComputeSMDTriangleVertices::~ComputeSMDTriangleVertices() { + memory->sfree(outputVector); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDTriangleVertices::init() { + + int count = 0; + for (int i = 0; i < modify->ncompute; i++) + if (strcmp(modify->compute[i]->style, "smd/triangle_vertices") == 0) + count++; + if (count > 1 && comm->me == 0) + error->warning(FLERR, "More than one compute smd/triangle_vertices"); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDTriangleVertices::compute_peratom() { + + double **smd_data_9 = atom->smd_data_9; + tagint *mol = atom->molecule; + + invoked_peratom = update->ntimestep; + + // grow vector array if necessary + + if (atom->nlocal > nmax) { + memory->destroy(outputVector); + nmax = atom->nmax; + memory->create(outputVector, nmax, size_peratom_cols, "defgradVector"); + array_atom = outputVector; + } + + /* + * triangle vertices are stored using the smd_data_9 array ... + * this is a hack but ok for now as I do not have to create additional storage space + * all triangle particles have molecule id >= 65535 + */ + + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if ((mask[i] & groupbit) && (mol[i] >= 65535) ){ + outputVector[i][0] = smd_data_9[i][0]; + outputVector[i][1] = smd_data_9[i][1]; + outputVector[i][2] = smd_data_9[i][2]; + outputVector[i][3] = smd_data_9[i][3]; + outputVector[i][4] = smd_data_9[i][4]; + outputVector[i][5] = smd_data_9[i][5]; + outputVector[i][6] = smd_data_9[i][6]; + outputVector[i][7] = smd_data_9[i][7]; + outputVector[i][8] = smd_data_9[i][8]; + } else { + for (int j = 0; j < size_peratom_cols; j++) { + outputVector[i][j] = 0.0; + } + } + } +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based array + ------------------------------------------------------------------------- */ + +double ComputeSMDTriangleVertices::memory_usage() { + double bytes = size_peratom_cols * nmax * sizeof(double); + return bytes; +} diff --git a/src/USER-SMD/compute_smd_triangle_mesh_vertices.h b/src/USER-SMD/compute_smd_triangle_mesh_vertices.h new file mode 100644 index 0000000000..7514622714 --- /dev/null +++ b/src/USER-SMD/compute_smd_triangle_mesh_vertices.h @@ -0,0 +1,55 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef COMPUTE_CLASS + +ComputeStyle(smd/triangle_vertices,ComputeSMDTriangleVertices) + +#else + +#ifndef LMP_COMPUTE_SMD_TRIANGLE_VERTICES_H +#define LMP_COMPUTE_SMD_TRIANGLE_VERTICES_H + +#include "compute.h" + +namespace LAMMPS_NS { + +class ComputeSMDTriangleVertices : public Compute { + public: + ComputeSMDTriangleVertices(class LAMMPS *, int, char **); + ~ComputeSMDTriangleVertices(); + void init(); + void compute_peratom(); + double memory_usage(); + + private: + int nmax; + double **outputVector; +}; + +} + +#endif +#endif diff --git a/src/USER-SMD/compute_smd_ulsph_effm.cpp b/src/USER-SMD/compute_smd_ulsph_effm.cpp new file mode 100644 index 0000000000..313c259632 --- /dev/null +++ b/src/USER-SMD/compute_smd_ulsph_effm.cpp @@ -0,0 +1,115 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +#include "string.h" +#include "compute_smd_ulsph_effm.h" +#include "atom.h" +#include "update.h" +#include "modify.h" +#include "comm.h" +#include "force.h" +#include "memory.h" +#include "error.h" +#include "pair.h" + +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +ComputeSMD_Ulsph_Effm::ComputeSMD_Ulsph_Effm(LAMMPS *lmp, int narg, char **arg) : + Compute(lmp, narg, arg) { + if (narg != 3) + error->all(FLERR, "Illegal compute smd/ulsph_effm command"); + if (atom->contact_radius_flag != 1) + error->all(FLERR, + "compute smd/ulsph_effm command requires atom_style with contact_radius (e.g. smd)"); + + peratom_flag = 1; + size_peratom_cols = 0; + + nmax = 0; + dt_vector = NULL; +} + +/* ---------------------------------------------------------------------- */ + +ComputeSMD_Ulsph_Effm::~ComputeSMD_Ulsph_Effm() { + memory->sfree(dt_vector); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMD_Ulsph_Effm::init() { + + int count = 0; + for (int i = 0; i < modify->ncompute; i++) + if (strcmp(modify->compute[i]->style, "smd/ulsph_effm") == 0) + count++; + if (count > 1 && comm->me == 0) + error->warning(FLERR, "More than one compute smd/ulsph_effm"); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMD_Ulsph_Effm::compute_peratom() { + invoked_peratom = update->ntimestep; + + // grow rhoVector array if necessary + + if (atom->nlocal > nmax) { + memory->sfree(dt_vector); + nmax = atom->nmax; + dt_vector = (double *) memory->smalloc(nmax * sizeof(double), + "atom:tlsph_dt_vector"); + vector_atom = dt_vector; + } + + int itmp = 0; + double *particle_dt = (double *) force->pair->extract("smd/ulsph/effective_modulus_ptr", + itmp); + if (particle_dt == NULL) { + error->all(FLERR, + "compute smd/ulsph_effm failed to access particle_dt array"); + } + + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + dt_vector[i] = particle_dt[i]; + } else { + dt_vector[i] = 0.0; + } + } +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based array + ------------------------------------------------------------------------- */ + +double ComputeSMD_Ulsph_Effm::memory_usage() { + double bytes = nmax * sizeof(double); + return bytes; +} diff --git a/src/USER-SMD/compute_smd_ulsph_effm.h b/src/USER-SMD/compute_smd_ulsph_effm.h new file mode 100644 index 0000000000..d4fb9180fe --- /dev/null +++ b/src/USER-SMD/compute_smd_ulsph_effm.h @@ -0,0 +1,55 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef COMPUTE_CLASS + +ComputeStyle(smd/ulsph_effm,ComputeSMD_Ulsph_Effm) + +#else + +#ifndef LMP_COMPUTE_SMD_ULSPH_EFFM_H +#define LMP_COMPUTE_SMD_ULSPH_EFFM_H + +#include "compute.h" + +namespace LAMMPS_NS { + +class ComputeSMD_Ulsph_Effm : public Compute { + public: + ComputeSMD_Ulsph_Effm(class LAMMPS *, int, char **); + ~ComputeSMD_Ulsph_Effm(); + void init(); + void compute_peratom(); + double memory_usage(); + + private: + int nmax; + double *dt_vector; +}; + +} + +#endif +#endif diff --git a/src/USER-SMD/compute_smd_ulsph_num_neighs.cpp b/src/USER-SMD/compute_smd_ulsph_num_neighs.cpp new file mode 100644 index 0000000000..c50db61bb1 --- /dev/null +++ b/src/USER-SMD/compute_smd_ulsph_num_neighs.cpp @@ -0,0 +1,107 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +#include "string.h" +#include "compute_smd_ulsph_num_neighs.h" +#include "atom.h" +#include "update.h" +#include "modify.h" +#include "comm.h" +#include "force.h" +#include "memory.h" +#include "error.h" +#include "pair.h" + +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +ComputeSMDULSPHNumNeighs::ComputeSMDULSPHNumNeighs(LAMMPS *lmp, int narg, char **arg) : + Compute(lmp, narg, arg) { + if (narg != 3) + error->all(FLERR, "Illegal compute smd/ulsph_num_neighs command"); + + peratom_flag = 1; + size_peratom_cols = 0; + + nmax = 0; + numNeighsOutput = NULL; +} + +/* ---------------------------------------------------------------------- */ + +ComputeSMDULSPHNumNeighs::~ComputeSMDULSPHNumNeighs() { + memory->destroy(numNeighsOutput); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDULSPHNumNeighs::init() { + int count = 0; + for (int i = 0; i < modify->ncompute; i++) + if (strcmp(modify->compute[i]->style, "smd/ulsph_num_neighs") == 0) + count++; + if (count > 1 && comm->me == 0) + error->warning(FLERR, "More than one compute smd/ulsph_num_neighs"); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDULSPHNumNeighs::compute_peratom() { + invoked_peratom = update->ntimestep; + + if (atom->nlocal > nmax) { + memory->destroy(numNeighsOutput); + nmax = atom->nmax; + memory->create(numNeighsOutput, nmax, "ulsph/num_neighs:numNeighsRefConfigOutput"); + vector_atom = numNeighsOutput; + } + + int *mask = atom->mask; + int nlocal = atom->nlocal; + + int itmp = 0; + int *numNeighs = (int *) force->pair->extract("smd/ulsph/numNeighs_ptr", itmp); + if (numNeighs == NULL) { + error->all(FLERR, "compute smd/ulsph_num_neighs failed to access numNeighs array"); + } + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + numNeighsOutput[i] = numNeighs[i]; + } else { + numNeighsOutput[i] = 0.0; + } + } +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based array + ------------------------------------------------------------------------- */ + +double ComputeSMDULSPHNumNeighs::memory_usage() { + double bytes = nmax * sizeof(double); + return bytes; +} diff --git a/src/USER-SMD/compute_smd_ulsph_num_neighs.h b/src/USER-SMD/compute_smd_ulsph_num_neighs.h new file mode 100644 index 0000000000..c16d178666 --- /dev/null +++ b/src/USER-SMD/compute_smd_ulsph_num_neighs.h @@ -0,0 +1,69 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef COMPUTE_CLASS + +ComputeStyle(smd/ulsph_num_neighs,ComputeSMDULSPHNumNeighs) + +#else + +#ifndef LMP_COMPUTE_SMD_ULSPH_NUM_NEIGHS_H +#define LMP_COMPUTE_SMD_ULSPH_NUM_NEIGHS_H + +#include "compute.h" + +namespace LAMMPS_NS { + +class ComputeSMDULSPHNumNeighs : public Compute { + public: + ComputeSMDULSPHNumNeighs(class LAMMPS *, int, char **); + ~ComputeSMDULSPHNumNeighs(); + void init(); + void compute_peratom(); + double memory_usage(); + + private: + int nmax; + double *numNeighsOutput; +}; + +} + +#endif +#endif + +/* ERROR/WARNING messages: + +E: Illegal ... command + +Self-explanatory. Check the input script syntax and compare to the +documentation for the command. You can use -echo screen as a +command-line option when running LAMMPS to see the offending line. + +W: More than one compute ke/atom + +It is not efficient to use compute ke/atom more than once. + +*/ diff --git a/src/USER-SMD/compute_smd_ulsph_strain.cpp b/src/USER-SMD/compute_smd_ulsph_strain.cpp new file mode 100644 index 0000000000..5cf4fa53fa --- /dev/null +++ b/src/USER-SMD/compute_smd_ulsph_strain.cpp @@ -0,0 +1,120 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +#include "string.h" +#include "compute_smd_ulsph_strain.h" +#include "atom.h" +#include "update.h" +#include "modify.h" +#include "comm.h" +#include "force.h" +#include "memory.h" +#include "error.h" +#include "pair.h" +#include +#include +#include "stdlib.h" +#include "string.h" +#include +using namespace Eigen; +using namespace std; +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +ComputeSMDULSPHstrain::ComputeSMDULSPHstrain(LAMMPS *lmp, int narg, char **arg) : + Compute(lmp, narg, arg) { + if (narg != 3) + error->all(FLERR, "Illegal compute smd/tlsph_strain command"); + + peratom_flag = 1; + size_peratom_cols = 6; + + nmax = 0; + strainVector = NULL; +} + +/* ---------------------------------------------------------------------- */ + +ComputeSMDULSPHstrain::~ComputeSMDULSPHstrain() { + memory->sfree(strainVector); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDULSPHstrain::init() { + + int count = 0; + for (int i = 0; i < modify->ncompute; i++) + if (strcmp(modify->compute[i]->style, "smd/tlsph_strain") == 0) + count++; + if (count > 1 && comm->me == 0) + error->warning(FLERR, "More than one compute smd/tlsph_strain"); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDULSPHstrain::compute_peratom() { + double **atom_data9 = atom->smd_data_9; // ULSPH strain is stored in the first 6 entries of this data field + + invoked_peratom = update->ntimestep; + + // grow vector array if necessary + + if (atom->nlocal > nmax) { + memory->destroy(strainVector); + nmax = atom->nmax; + memory->create(strainVector, nmax, size_peratom_cols, "strainVector"); + array_atom = strainVector; + } + + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + + strainVector[i][0] = atom_data9[i][0]; + strainVector[i][1] = atom_data9[i][1]; + strainVector[i][2] = atom_data9[i][2]; + strainVector[i][3] = atom_data9[i][3]; + strainVector[i][4] = atom_data9[i][4]; + strainVector[i][5] = atom_data9[i][5]; + } else { + for (int j = 0; j < size_peratom_cols; j++) { + strainVector[i][j] = 0.0; + } + } + } +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based array + ------------------------------------------------------------------------- */ + +double ComputeSMDULSPHstrain::memory_usage() { + double bytes = size_peratom_cols * nmax * sizeof(double); + return bytes; +} diff --git a/src/USER-SMD/compute_smd_ulsph_strain.h b/src/USER-SMD/compute_smd_ulsph_strain.h new file mode 100644 index 0000000000..820b2450a8 --- /dev/null +++ b/src/USER-SMD/compute_smd_ulsph_strain.h @@ -0,0 +1,55 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef COMPUTE_CLASS + +ComputeStyle(smd/ulsph_strain,ComputeSMDULSPHstrain) + +#else + +#ifndef LMP_COMPUTE_SMD_ULSPH_STRAIN_H +#define LMP_COMPUTE_SMD_ULSPH_STRAIN_H + +#include "compute.h" + +namespace LAMMPS_NS { + +class ComputeSMDULSPHstrain : public Compute { + public: + ComputeSMDULSPHstrain(class LAMMPS *, int, char **); + ~ComputeSMDULSPHstrain(); + void init(); + void compute_peratom(); + double memory_usage(); + + private: + int nmax; + double **strainVector; +}; + +} + +#endif +#endif diff --git a/src/USER-SMD/compute_smd_ulsph_strain_rate.cpp b/src/USER-SMD/compute_smd_ulsph_strain_rate.cpp new file mode 100644 index 0000000000..542c87bc32 --- /dev/null +++ b/src/USER-SMD/compute_smd_ulsph_strain_rate.cpp @@ -0,0 +1,132 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +#include "string.h" +#include "compute_smd_ulsph_strain_rate.h" +#include "atom.h" +#include "update.h" +#include "modify.h" +#include "comm.h" +#include "force.h" +#include "memory.h" +#include "error.h" +#include "pair.h" +#include +using namespace Eigen; +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +ComputeSMDULSPHStrainRate::ComputeSMDULSPHStrainRate(LAMMPS *lmp, int narg, char **arg) : + Compute(lmp, narg, arg) { + if (narg != 3) + error->all(FLERR, "Illegal compute smd/ulsph_strain_rate command"); + + peratom_flag = 1; + size_peratom_cols = 6; + + nmax = 0; + strain_rate_array = NULL; +} + +/* ---------------------------------------------------------------------- */ + +ComputeSMDULSPHStrainRate::~ComputeSMDULSPHStrainRate() { + memory->sfree(strain_rate_array); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDULSPHStrainRate::init() { + + int count = 0; + for (int i = 0; i < modify->ncompute; i++) + if (strcmp(modify->compute[i]->style, "smd/ulsph_strain_rate") == 0) + count++; + if (count > 1 && comm->me == 0) + error->warning(FLERR, "More than one compute smd/ulsph_strain_rate"); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDULSPHStrainRate::compute_peratom() { + invoked_peratom = update->ntimestep; + int *mask = atom->mask; + + // grow vector array if necessary + + if (atom->nlocal > nmax) { + memory->destroy(strain_rate_array); + nmax = atom->nmax; + memory->create(strain_rate_array, nmax, size_peratom_cols, "stresstensorVector"); + array_atom = strain_rate_array; + } + + int itmp = 0; + Matrix3d *L = (Matrix3d *) force->pair->extract("smd/ulsph/velocityGradient_ptr", itmp); + if (L == NULL) { + error->all(FLERR, + "compute smd/ulsph_strain_rate could not access any velocity gradients. Are the matching pair styles present?"); + } + int nlocal = atom->nlocal; + Matrix3d D; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + D = 0.5 * (L[i] + L[i].transpose()); + strain_rate_array[i][0] = D(0, 0); // xx + strain_rate_array[i][1] = D(1, 1); // yy + strain_rate_array[i][2] = D(2, 2); // zz + strain_rate_array[i][3] = D(0, 1); // xy + strain_rate_array[i][4] = D(0, 2); // xz + strain_rate_array[i][5] = D(1, 2); // yz + } else { + strain_rate_array[i][0] = 0.0; + strain_rate_array[i][1] = 0.0; + strain_rate_array[i][2] = 0.0; + strain_rate_array[i][3] = 0.0; + strain_rate_array[i][4] = 0.0; + strain_rate_array[i][5] = 0.0; + } + } +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based array + ------------------------------------------------------------------------- */ + +double ComputeSMDULSPHStrainRate::memory_usage() { + double bytes = size_peratom_cols * nmax * sizeof(double); + return bytes; +} + +/* + * deviator of a tensor + */ +Matrix3d ComputeSMDULSPHStrainRate::Deviator(Matrix3d M) { + Matrix3d eye; + eye.setIdentity(); + eye *= M.trace() / 3.0; + return M - eye; +} diff --git a/src/USER-SMD/compute_smd_ulsph_strain_rate.h b/src/USER-SMD/compute_smd_ulsph_strain_rate.h new file mode 100644 index 0000000000..b200e15722 --- /dev/null +++ b/src/USER-SMD/compute_smd_ulsph_strain_rate.h @@ -0,0 +1,58 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef COMPUTE_CLASS + +ComputeStyle(smd/ulsph_strain_rate,ComputeSMDULSPHStrainRate) + +#else + +#ifndef LMP_COMPUTE_SMD_ULSPH_STRAIN_RATE_H +#define LMP_COMPUTE_SMD_ULSPH_STRAIN_RATE_H + +#include "compute.h" +#include +using namespace Eigen; + +namespace LAMMPS_NS { + +class ComputeSMDULSPHStrainRate : public Compute { + public: + ComputeSMDULSPHStrainRate(class LAMMPS *, int, char **); + ~ComputeSMDULSPHStrainRate(); + void init(); + void compute_peratom(); + double memory_usage(); + Matrix3d Deviator(Matrix3d); + + private: + int nmax; + double **strain_rate_array; +}; + +} + +#endif +#endif diff --git a/src/USER-SMD/compute_smd_ulsph_stress.cpp b/src/USER-SMD/compute_smd_ulsph_stress.cpp new file mode 100644 index 0000000000..26b323e7ee --- /dev/null +++ b/src/USER-SMD/compute_smd_ulsph_stress.cpp @@ -0,0 +1,133 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +#include "string.h" +#include "compute_smd_ulsph_stress.h" +#include "atom.h" +#include "update.h" +#include "modify.h" +#include "comm.h" +#include "force.h" +#include "memory.h" +#include "error.h" +#include "pair.h" +#include +using namespace Eigen; +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +ComputeSMDULSPHStress::ComputeSMDULSPHStress(LAMMPS *lmp, int narg, char **arg) : + Compute(lmp, narg, arg) { + if (narg != 3) + error->all(FLERR, "Illegal compute smd/ulsph_stress command"); + + peratom_flag = 1; + size_peratom_cols = 7; + + nmax = 0; + stress_array = NULL; +} + +/* ---------------------------------------------------------------------- */ + +ComputeSMDULSPHStress::~ComputeSMDULSPHStress() { + memory->sfree(stress_array); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDULSPHStress::init() { + + int count = 0; + for (int i = 0; i < modify->ncompute; i++) + if (strcmp(modify->compute[i]->style, "smd/ulsph_stress") == 0) + count++; + if (count > 1 && comm->me == 0) + error->warning(FLERR, "More than one compute smd/ulsph_stress"); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDULSPHStress::compute_peratom() { + invoked_peratom = update->ntimestep; + int *mask = atom->mask; + Matrix3d stress_deviator; + double von_mises_stress; + + // grow vector array if necessary + + if (atom->nlocal > nmax) { + memory->destroy(stress_array); + nmax = atom->nmax; + memory->create(stress_array, nmax, size_peratom_cols, "stresstensorVector"); + array_atom = stress_array; + } + + int itmp = 0; + Matrix3d *T = (Matrix3d *) force->pair->extract("smd/ulsph/stressTensor_ptr", itmp); + if (T == NULL) { + error->all(FLERR, "compute smd/ulsph_stress could not access stress tensors. Are the matching pair styles present?"); + } + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + + if (mask[i] & groupbit) { + stress_deviator = Deviator(T[i]); + von_mises_stress = sqrt(3. / 2.) * stress_deviator.norm(); + stress_array[i][0] = T[i](0, 0); // xx + stress_array[i][1] = T[i](1, 1); // yy + stress_array[i][2] = T[i](2, 2); // zz + stress_array[i][3] = T[i](0, 1); // xy + stress_array[i][4] = T[i](0, 2); // xz + stress_array[i][5] = T[i](1, 2); // yz + stress_array[i][6] = von_mises_stress; + + } else { + for (int j = 0; j < size_peratom_cols; j++) { + stress_array[i][j] = 0.0; + } + } + } +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based array + ------------------------------------------------------------------------- */ + +double ComputeSMDULSPHStress::memory_usage() { + double bytes = size_peratom_cols * nmax * sizeof(double); + return bytes; +} + +/* + * deviator of a tensor + */ +Matrix3d ComputeSMDULSPHStress::Deviator(Matrix3d M) { + Matrix3d eye; + eye.setIdentity(); + eye *= M.trace() / 3.0; + return M - eye; +} diff --git a/src/USER-SMD/compute_smd_ulsph_stress.h b/src/USER-SMD/compute_smd_ulsph_stress.h new file mode 100644 index 0000000000..5b31a111a4 --- /dev/null +++ b/src/USER-SMD/compute_smd_ulsph_stress.h @@ -0,0 +1,58 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef COMPUTE_CLASS + +ComputeStyle(smd/ulsph_stress, ComputeSMDULSPHStress) + +#else + +#ifndef LMP_COMPUTE_SMD_ULSPH_STRESS_H +#define LMP_COMPUTE_SMD_ULSPH_STRESS_H + +#include "compute.h" +#include +using namespace Eigen; + +namespace LAMMPS_NS { + +class ComputeSMDULSPHStress : public Compute { + public: + ComputeSMDULSPHStress(class LAMMPS *, int, char **); + ~ComputeSMDULSPHStress(); + void init(); + void compute_peratom(); + double memory_usage(); + Matrix3d Deviator(Matrix3d); + + private: + int nmax; + double **stress_array; +}; + +} + +#endif +#endif diff --git a/src/USER-SMD/compute_smd_vol.cpp b/src/USER-SMD/compute_smd_vol.cpp new file mode 100644 index 0000000000..1826e3d976 --- /dev/null +++ b/src/USER-SMD/compute_smd_vol.cpp @@ -0,0 +1,130 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +#include "string.h" +#include "compute_smd_vol.h" +#include "atom.h" +#include "update.h" +#include "modify.h" +#include "comm.h" +#include "force.h" +#include "memory.h" +#include "error.h" + +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +ComputeSMDVol::ComputeSMDVol(LAMMPS *lmp, int narg, char **arg) : + Compute(lmp, narg, arg) { + if (narg != 3) + error->all(FLERR, "Illegal compute smd/volume command"); + if (atom->vfrac_flag != 1) + error->all(FLERR, "compute smd/volume command requires atom_style with density (e.g. smd)"); + + scalar_flag = 1; + peratom_flag = 1; + size_peratom_cols = 0; + + nmax = 0; + volVector = NULL; +} + +/* ---------------------------------------------------------------------- */ + +ComputeSMDVol::~ComputeSMDVol() { + memory->sfree(volVector); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDVol::init() { + + int count = 0; + for (int i = 0; i < modify->ncompute; i++) + if (strcmp(modify->compute[i]->style, "smd/volume") == 0) + count++; + if (count > 1 && comm->me == 0) + error->warning(FLERR, "More than one compute smd/volume"); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeSMDVol::compute_peratom() { + invoked_peratom = update->ntimestep; + + // grow volVector array if necessary + + if (atom->nlocal > nmax) { + memory->sfree(volVector); + nmax = atom->nmax; + volVector = (double *) memory->smalloc(nmax * sizeof(double), "atom:volVector"); + vector_atom = volVector; + } + + double *vfrac = atom->vfrac; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + volVector[i] = vfrac[i]; + } else { + volVector[i] = 0.0; + } + } +} + +/* ---------------------------------------------------------------------- */ + +double ComputeSMDVol::compute_scalar() { + + invoked_scalar = update->ntimestep; + double *vfrac = atom->vfrac; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + double this_proc_sum_volumes = 0.0; + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + this_proc_sum_volumes += vfrac[i]; + } + } + + //printf("this_proc_sum_volumes = %g\n", this_proc_sum_volumes); + MPI_Allreduce(&this_proc_sum_volumes, &scalar, 1, MPI_DOUBLE, MPI_SUM, world); + //if (comm->me == 0) printf("global sum_volumes = %g\n", scalar); + + return scalar; + +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based array + ------------------------------------------------------------------------- */ + +double ComputeSMDVol::memory_usage() { + double bytes = nmax * sizeof(double); + return bytes; +} diff --git a/src/USER-SMD/compute_smd_vol.h b/src/USER-SMD/compute_smd_vol.h new file mode 100644 index 0000000000..e946ed85ca --- /dev/null +++ b/src/USER-SMD/compute_smd_vol.h @@ -0,0 +1,56 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef COMPUTE_CLASS + +ComputeStyle(smd/volume,ComputeSMDVol) + +#else + +#ifndef LMP_COMPUTE_SMD_VOL_H +#define LMP_COMPUTE_SMD_VOL_H + +#include "compute.h" + +namespace LAMMPS_NS { + +class ComputeSMDVol : public Compute { + public: + ComputeSMDVol(class LAMMPS *, int, char **); + ~ComputeSMDVol(); + void init(); + void compute_peratom(); + double compute_scalar(); + double memory_usage(); + + private: + int nmax; + double *volVector; +}; + +} + +#endif +#endif diff --git a/src/USER-SMD/fix_smd_adjust_dt.cpp b/src/USER-SMD/fix_smd_adjust_dt.cpp new file mode 100644 index 0000000000..48d5835059 --- /dev/null +++ b/src/USER-SMD/fix_smd_adjust_dt.cpp @@ -0,0 +1,233 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +#include "math.h" +#include "stdlib.h" +#include "string.h" +#include "fix_smd_adjust_dt.h" +#include "atom.h" +#include "update.h" +#include "integrate.h" +#include "domain.h" +#include "lattice.h" +#include "force.h" +#include "pair.h" +#include "modify.h" +#include "fix.h" +#include "output.h" +#include "dump.h" +#include "comm.h" +#include "error.h" + +using namespace LAMMPS_NS; +using namespace FixConst; + +#define BIG 1.0e20 + +/* ---------------------------------------------------------------------- */ + +FixSMDTlsphDtReset::FixSMDTlsphDtReset(LAMMPS *lmp, int narg, char **arg) : + Fix(lmp, narg, arg) { + if (narg != 4) + error->all(FLERR, "Illegal fix smd/adjust_dt command"); + + // set time_depend, else elapsed time accumulation can be messed up + + time_depend = 1; + scalar_flag = 1; + vector_flag = 1; + size_vector = 2; + global_freq = 1; + extscalar = 0; + extvector = 0; + restart_global = 1; // this fix stores global (i.e., not per-atom) info: elaspsed time + + safety_factor = atof(arg[3]); + + // initializations + t_elapsed = 0.0; +} + +/* ---------------------------------------------------------------------- */ + +int FixSMDTlsphDtReset::setmask() { + int mask = 0; + mask |= INITIAL_INTEGRATE; + mask |= END_OF_STEP; + return mask; +} + +/* ---------------------------------------------------------------------- */ + +void FixSMDTlsphDtReset::init() { + dt = update->dt; +} + +/* ---------------------------------------------------------------------- */ + +void FixSMDTlsphDtReset::setup(int vflag) { + end_of_step(); +} + +/* ---------------------------------------------------------------------- */ + +void FixSMDTlsphDtReset::initial_integrate(int vflag) { + + //printf("in adjust_dt: dt = %20.10f\n", update->dt); + + t_elapsed += update->dt; +} + +/* ---------------------------------------------------------------------- */ + +void FixSMDTlsphDtReset::end_of_step() { + double dtmin = BIG; + int itmp = 0; + + /* + * extract minimum CFL timestep from TLSPH and ULSPH pair styles + */ + + double *dtCFL_TLSPH = (double *) force->pair->extract("smd/tlsph/dtCFL_ptr", itmp); + double *dtCFL_ULSPH = (double *) force->pair->extract("smd/ulsph/dtCFL_ptr", itmp); + double *dt_TRI = (double *) force->pair->extract("smd/tri_surface/stable_time_increment_ptr", itmp); + double *dt_HERTZ = (double *) force->pair->extract("smd/hertz/stable_time_increment_ptr", itmp); + double *dt_PERI_IPMB = (double *) force->pair->extract("smd/peri_ipmb/stable_time_increment_ptr", itmp); + + if ((dtCFL_TLSPH == NULL) && (dtCFL_ULSPH == NULL) && (dt_TRI == NULL) && (dt_HERTZ == NULL) + && (dt_PERI_IPMB == NULL)) { + error->all(FLERR, "fix smd/adjust_dt failed to access a valid dtCFL"); + } + + if (dtCFL_TLSPH != NULL) { + dtmin = MIN(dtmin, *dtCFL_TLSPH); + } + + if (dtCFL_ULSPH != NULL) { + dtmin = MIN(dtmin, *dtCFL_ULSPH); + } + + if (dt_TRI != NULL) { + dtmin = MIN(dtmin, *dt_TRI); + } + + if (dt_HERTZ != NULL) { + dtmin = MIN(dtmin, *dt_HERTZ); + } + + if (dt_PERI_IPMB != NULL) { + dtmin = MIN(dtmin, *dt_PERI_IPMB); + } + +// double **v = atom->v; +// double **f = atom->f; +// double *rmass = atom->rmass; +// double *radius = atom->radius; +// int *mask = atom->mask; +// int nlocal = atom->nlocal; +// double dtv, dtf, dtsq; +// double vsq, fsq, massinv, xmax; +// double delx, dely, delz, delr; + +// for (int i = 0; i < nlocal; i++) { +// if (mask[i] & groupbit) { +// xmax = 0.005 * radius[i]; +// massinv = 1.0 / rmass[i]; +// vsq = v[i][0] * v[i][0] + v[i][1] * v[i][1] + v[i][2] * v[i][2]; +// fsq = f[i][0] * f[i][0] + f[i][1] * f[i][1] + f[i][2] * f[i][2]; +// dtv = dtf = BIG; +// if (vsq > 0.0) +// dtv = xmax / sqrt(vsq); +// if (fsq > 0.0) +// dtf = sqrt(2.0 * xmax / (sqrt(fsq) * massinv)); +// dt = MIN(dtv, dtf); +// dtmin = MIN(dtmin, dt); +// dtsq = dt * dt; +// delx = dt * v[i][0] + 0.5 * dtsq * massinv * f[i][0]; +// dely = dt * v[i][1] + 0.5 * dtsq * massinv * f[i][1]; +// delz = dt * v[i][2] + 0.5 * dtsq * massinv * f[i][2]; +// delr = sqrt(delx * delx + dely * dely + delz * delz); +// if (delr > xmax) +// dt *= xmax / delr; +// dtmin = MIN(dtmin, dt); +// +//// xmax = 0.05 * radius[i]; +//// massinv = 1.0 / rmass[i]; +//// fsq = f[i][0] * f[i][0] + f[i][1] * f[i][1] + f[i][2] * f[i][2]; +//// dtf = BIG; +//// if (fsq > 0.0) +//// dtf = sqrt(2.0 * xmax / (sqrt(fsq) * massinv)); +//// dtmin = MIN(dtmin, dtf); +// } +// } + + dtmin *= safety_factor; // apply safety factor + MPI_Allreduce(&dtmin, &dt, 1, MPI_DOUBLE, MPI_MIN, world); + + if (update->ntimestep == 0) { + dt = 1.0e-16; + } + + //printf("dtmin is now: %f, dt is now%f\n", dtmin, dt); + + + update->dt = dt; + if (force->pair) + force->pair->reset_dt(); + for (int i = 0; i < modify->nfix; i++) + modify->fix[i]->reset_dt(); +} + +/* ---------------------------------------------------------------------- */ + +double FixSMDTlsphDtReset::compute_scalar() { + return t_elapsed; +} + +/* ---------------------------------------------------------------------- + pack entire state of Fix into one write + ------------------------------------------------------------------------- */ + +void FixSMDTlsphDtReset::write_restart(FILE *fp) { + int n = 0; + double list[1]; + list[n++] = t_elapsed; + + if (comm->me == 0) { + int size = n * sizeof(double); + fwrite(&size, sizeof(int), 1, fp); + fwrite(list, sizeof(double), n, fp); + } +} + +/* ---------------------------------------------------------------------- + use state info from restart file to restart the Fix + ------------------------------------------------------------------------- */ + +void FixSMDTlsphDtReset::restart(char *buf) { + int n = 0; + double *list = (double *) buf; + t_elapsed = list[n++]; +} + diff --git a/src/USER-SMD/fix_smd_adjust_dt.h b/src/USER-SMD/fix_smd_adjust_dt.h new file mode 100644 index 0000000000..3b96d76d76 --- /dev/null +++ b/src/USER-SMD/fix_smd_adjust_dt.h @@ -0,0 +1,80 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +#ifdef FIX_CLASS + +FixStyle(smd/adjust_dt,FixSMDTlsphDtReset) + +#else + +#ifndef LMP_FIX_TLSPH_DT_RESET_H +#define LMP_FIX_TLSPH_DT_RESET_H + +#include "fix.h" + +namespace LAMMPS_NS { + +class FixSMDTlsphDtReset: public Fix { +public: + FixSMDTlsphDtReset(class LAMMPS *, int, char **); + ~FixSMDTlsphDtReset() { + } + int setmask(); + void init(); + void setup(int); + void initial_integrate(int); + void end_of_step(); + double compute_scalar(); + void write_restart(FILE *); + void restart(char *); + +private: + double safety_factor; + double dt, t_elapsed; +}; + +} + +#endif +#endif + +/* ERROR/WARNING messages: + + E: Illegal ... command + + Self-explanatory. Check the input script syntax and compare to the + documentation for the command. You can use -echo screen as a + command-line option when running LAMMPS to see the offending line. + + E: Use of fix dt/reset with undefined lattice + + Must use lattice command with fix dt/reset command if units option is + set to lattice. + + W: Dump dcd/xtc timestamp may be wrong with fix dt/reset + + If the fix changes the timestep, the dump dcd file will not + reflect the change. + + */ diff --git a/src/USER-SMD/fix_smd_integrate_tlsph.cpp b/src/USER-SMD/fix_smd_integrate_tlsph.cpp new file mode 100644 index 0000000000..a26ffede0d --- /dev/null +++ b/src/USER-SMD/fix_smd_integrate_tlsph.cpp @@ -0,0 +1,254 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +#include "stdio.h" +#include "stdlib.h" +#include "string.h" +#include "fix_smd_integrate_tlsph.h" +#include "atom.h" +#include "force.h" +#include "update.h" +#include "error.h" +#include "pair.h" +#include "neigh_list.h" +#include +#include "domain.h" +#include "neighbor.h" +#include "comm.h" +#include "modify.h" +#include "stdio.h" +#include + +using namespace Eigen; +using namespace LAMMPS_NS; +using namespace FixConst; +using namespace std; + +/* ---------------------------------------------------------------------- */ + +FixSMDIntegrateTlsph::FixSMDIntegrateTlsph(LAMMPS *lmp, int narg, char **arg) : + Fix(lmp, narg, arg) { + if (narg < 3) { + printf("narg=%d\n", narg); + error->all(FLERR, "Illegal fix smd/integrate_tlsph command"); + } + + xsphFlag = false; + vlimit = -1.0; + int iarg = 3; + + if (comm->me == 0) { + printf("\n>>========>>========>>========>>========>>========>>========>>========>>========\n"); + printf("fix smd/integrate_tlsph is active for group: %s \n", arg[1]); + } + + while (true) { + + if (iarg >= narg) { + break; + } + + if (strcmp(arg[iarg], "xsph") == 0) { + xsphFlag = true; + if (comm->me == 0) { + error->one(FLERR, "XSPH is currently not available"); + printf("... will use XSPH time integration\n"); + } + } else if (strcmp(arg[iarg], "limit_velocity") == 0) { + iarg++; + if (iarg == narg) { + error->all(FLERR, "expected number following limit_velocity"); + } + + vlimit = force->numeric(FLERR, arg[iarg]); + if (comm->me == 0) { + printf("... will limit velocities to <= %g\n", vlimit); + } + } else { + char msg[128]; + sprintf(msg, "Illegal keyword for smd/integrate_tlsph: %s\n", arg[iarg]); + error->all(FLERR, msg); + } + + iarg++; + } + + if (comm->me == 0) { + printf(">>========>>========>>========>>========>>========>>========>>========>>========\n"); + } + + time_integrate = 1; + + // set comm sizes needed by this fix + + atom->add_callback(0); + +} + +/* ---------------------------------------------------------------------- */ + +int FixSMDIntegrateTlsph::setmask() { + int mask = 0; + mask |= INITIAL_INTEGRATE; + mask |= FINAL_INTEGRATE; + return mask; +} + +/* ---------------------------------------------------------------------- */ + +void FixSMDIntegrateTlsph::init() { + dtv = update->dt; + dtf = 0.5 * update->dt * force->ftm2v; + vlimitsq = vlimit * vlimit; +} + +/* ---------------------------------------------------------------------- + ------------------------------------------------------------------------- */ + +void FixSMDIntegrateTlsph::initial_integrate(int vflag) { + double dtfm, vsq, scale; + + // update v and x of atoms in group + + double **x = atom->x; + double **v = atom->v; + double **vest = atom->vest; + double **f = atom->f; + double *rmass = atom->rmass; + int *mask = atom->mask; + int nlocal = atom->nlocal; + int itmp; + double vxsph_x, vxsph_y, vxsph_z; + if (igroup == atom->firstgroup) + nlocal = atom->nfirst; + + Vector3d *smoothVelDifference = (Vector3d *) force->pair->extract("smd/tlsph/smoothVel_ptr", itmp); + + if (xsphFlag) { + if (smoothVelDifference == NULL) { + error->one(FLERR, + "fix smd/integrate_tlsph failed to access smoothVel array. Check if a pair style exist which calculates this quantity."); + } + } + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + dtfm = dtf / rmass[i]; + + // 1st part of Velocity_Verlet: push velocties 1/2 time increment ahead + v[i][0] += dtfm * f[i][0]; + v[i][1] += dtfm * f[i][1]; + v[i][2] += dtfm * f[i][2]; + + if (vlimit > 0.0) { + vsq = v[i][0] * v[i][0] + v[i][1] * v[i][1] + v[i][2] * v[i][2]; + if (vsq > vlimitsq) { + scale = sqrt(vlimitsq / vsq); + v[i][0] *= scale; + v[i][1] *= scale; + v[i][2] *= scale; + } + } + + if (xsphFlag) { + + // construct XSPH velocity + vxsph_x = v[i][0] + 0.5 * smoothVelDifference[i](0); + vxsph_y = v[i][1] + 0.5 * smoothVelDifference[i](1); + vxsph_z = v[i][2] + 0.5 * smoothVelDifference[i](2); + + vest[i][0] = vxsph_x + dtfm * f[i][0]; + vest[i][1] = vxsph_y + dtfm * f[i][1]; + vest[i][2] = vxsph_z + dtfm * f[i][2]; + + x[i][0] += dtv * vxsph_x; + x[i][1] += dtv * vxsph_y; + x[i][2] += dtv * vxsph_z; + } else { + + // extrapolate velocity from half- to full-step + vest[i][0] = v[i][0] + dtfm * f[i][0]; + vest[i][1] = v[i][1] + dtfm * f[i][1]; + vest[i][2] = v[i][2] + dtfm * f[i][2]; + + x[i][0] += dtv * v[i][0]; // 2nd part of Velocity-Verlet: push positions one full time increment ahead + x[i][1] += dtv * v[i][1]; + x[i][2] += dtv * v[i][2]; + } + } + } + +} + +/* ---------------------------------------------------------------------- */ + +void FixSMDIntegrateTlsph::final_integrate() { + double dtfm, vsq, scale; + +// update v of atoms in group + + double **v = atom->v; + double **f = atom->f; + double *e = atom->e; + double *de = atom->de; + double *rmass = atom->rmass; + int *mask = atom->mask; + int nlocal = atom->nlocal; + if (igroup == atom->firstgroup) + nlocal = atom->nfirst; + int i; + + for (i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + dtfm = dtf / rmass[i]; + + v[i][0] += dtfm * f[i][0]; // 3rd part of Velocity-Verlet: push velocities another half time increment ahead + v[i][1] += dtfm * f[i][1]; // both positions and velocities are now defined at full time-steps. + v[i][2] += dtfm * f[i][2]; + + // limit velocity + if (vlimit > 0.0) { + vsq = v[i][0] * v[i][0] + v[i][1] * v[i][1] + v[i][2] * v[i][2]; + if (vsq > vlimitsq) { + scale = sqrt(vlimitsq / vsq); + v[i][0] *= scale; + v[i][1] *= scale; + v[i][2] *= scale; + } + } + + e[i] += dtv * de[i]; + } + } +} + +/* ---------------------------------------------------------------------- */ + +void FixSMDIntegrateTlsph::reset_dt() { + dtv = update->dt; + dtf = 0.5 * update->dt * force->ftm2v; + vlimitsq = vlimit * vlimit; +} + +/* ---------------------------------------------------------------------- */ diff --git a/src/USER-SMD/fix_smd_integrate_tlsph.h b/src/USER-SMD/fix_smd_integrate_tlsph.h new file mode 100644 index 0000000000..7119f8d919 --- /dev/null +++ b/src/USER-SMD/fix_smd_integrate_tlsph.h @@ -0,0 +1,73 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +#ifdef FIX_CLASS + +FixStyle(smd/integrate_tlsph,FixSMDIntegrateTlsph) + +#else + +#ifndef LMP_FIX_SMD_INTEGRATE_TLSPH_H +#define LMP_FIX_SMD_INTEGRATE_TLSPH_H + +#include "fix.h" + +namespace LAMMPS_NS { + +class FixSMDIntegrateTlsph: public Fix { + friend class Neighbor; + friend class PairTlsph; +public: + FixSMDIntegrateTlsph(class LAMMPS *, int, char **); + virtual ~FixSMDIntegrateTlsph() { + } + int setmask(); + virtual void init(); + virtual void initial_integrate(int); + virtual void final_integrate(); + virtual void reset_dt(); + +protected: + double dtv, dtf, vlimit, vlimitsq; + int mass_require; + bool xsphFlag; + + class Pair *pair; +}; + +} + +#endif +#endif + +/* ERROR/WARNING messages: + + E: Illegal ... command + + Self-explanatory. Check the input script syntax and compare to the + documentation for the command. You can use -echo screen as a + command-line option when running LAMMPS to see the offending line. + + */ diff --git a/src/USER-SMD/fix_smd_integrate_ulsph.cpp b/src/USER-SMD/fix_smd_integrate_ulsph.cpp new file mode 100644 index 0000000000..91b974b400 --- /dev/null +++ b/src/USER-SMD/fix_smd_integrate_ulsph.cpp @@ -0,0 +1,325 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +#include "stdio.h" +#include "string.h" +#include "fix_smd_integrate_ulsph.h" +#include "math.h" +#include "stdlib.h" +#include "string.h" +#include "atom.h" +#include "comm.h" +#include "force.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "neigh_request.h" +#include "update.h" +#include "integrate.h" +#include "respa.h" +#include "memory.h" +#include "error.h" +#include "pair.h" +#include "domain.h" +#include + +using namespace Eigen; +using namespace LAMMPS_NS; +using namespace FixConst; + +/* ---------------------------------------------------------------------- */ + +FixSMDIntegrateUlsph::FixSMDIntegrateUlsph(LAMMPS *lmp, int narg, char **arg) : + Fix(lmp, narg, arg) { + + if ((atom->e_flag != 1) || (atom->vfrac_flag != 1)) + error->all(FLERR, "fix smd/integrate_ulsph command requires atom_style with both energy and volume"); + + if (narg < 3) + error->all(FLERR, "Illegal number of arguments for fix smd/integrate_ulsph command"); + + adjust_radius_flag = false; + xsphFlag = false; + vlimit = -1.0; + int iarg = 3; + + if (comm->me == 0) { + printf("\n>>========>>========>>========>>========>>========>>========>>========>>========\n"); + printf("fix smd/integrate_ulsph is active for group: %s \n", arg[1]); + } + while (true) { + + if (iarg >= narg) { + break; + } + + if (strcmp(arg[iarg], "xsph") == 0) { + xsphFlag = true; + if (comm->me == 0) { + error->one(FLERR, "XSPH is currently not available"); + printf("... will use XSPH time integration\n"); + } + } else if (strcmp(arg[iarg], "adjust_radius") == 0) { + adjust_radius_flag = true; + + iarg++; + if (iarg == narg) { + error->all(FLERR, "expected three numbers following adjust_radius: factor, min, max"); + } + + adjust_radius_factor = force->numeric(FLERR, arg[iarg]); + + iarg++; + if (iarg == narg) { + error->all(FLERR, "expected three numbers following adjust_radius: factor, min, max"); + } + + min_nn = force->inumeric(FLERR, arg[iarg]); + + iarg++; + if (iarg == narg) { + error->all(FLERR, "expected three numbers following adjust_radius: factor, min, max"); + } + + max_nn = force->inumeric(FLERR, arg[iarg]); + + if (comm->me == 0) { + printf("... will adjust smoothing length dynamically with factor %g to achieve %d to %d neighbors per particle.\n ", + adjust_radius_factor, min_nn, max_nn); + } + + } else if (strcmp(arg[iarg], "limit_velocity") == 0) { + iarg++; + if (iarg == narg) { + error->all(FLERR, "expected number following limit_velocity"); + } + vlimit = force->numeric(FLERR, arg[iarg]); + + if (comm->me == 0) { + printf("... will limit velocities to <= %g\n", vlimit); + } + } else { + char msg[128]; + sprintf(msg, "Illegal keyword for smd/integrate_ulsph: %s\n", arg[iarg]); + error->all(FLERR, msg); + } + + iarg++; + + } + + if (comm->me == 0) { + printf(">>========>>========>>========>>========>>========>>========>>========>>========\n\n"); + } + + // set comm sizes needed by this fix + atom->add_callback(0); + + time_integrate = 1; +} + +/* ---------------------------------------------------------------------- */ + +int FixSMDIntegrateUlsph::setmask() { + int mask = 0; + mask |= INITIAL_INTEGRATE; + mask |= FINAL_INTEGRATE; + return mask; +} + +/* ---------------------------------------------------------------------- */ + +void FixSMDIntegrateUlsph::init() { + dtv = update->dt; + dtf = 0.5 * update->dt * force->ftm2v; + vlimitsq = vlimit * vlimit; +} + +/* ---------------------------------------------------------------------- + allow for both per-type and per-atom mass + ------------------------------------------------------------------------- */ + +void FixSMDIntegrateUlsph::initial_integrate(int vflag) { + double **x = atom->x; + double **v = atom->v; + double **f = atom->f; + double **vest = atom->vest; + double *rmass = atom->rmass; + + int *mask = atom->mask; + int nlocal = atom->nlocal; + int i, itmp; + double dtfm, vsq, scale; + double vxsph_x, vxsph_y, vxsph_z; + + //printf("initial_integrate at timestep %d\n", update->ntimestep); + + /* + * get smoothed velocities from ULSPH pair style + */ + + Vector3d *smoothVel = (Vector3d *) force->pair->extract("smd/ulsph/smoothVel_ptr", itmp); + + if (xsphFlag) { + if (smoothVel == NULL) { + error->one(FLERR, "fix smd/integrate_ulsph failed to access smoothVel array"); + } + } + + if (igroup == atom->firstgroup) + nlocal = atom->nfirst; + + for (i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + dtfm = dtf / rmass[i]; + + v[i][0] += dtfm * f[i][0]; + v[i][1] += dtfm * f[i][1]; + v[i][2] += dtfm * f[i][2]; + + if (vlimit > 0.0) { + vsq = v[i][0] * v[i][0] + v[i][1] * v[i][1] + v[i][2] * v[i][2]; + if (vsq > vlimitsq) { + scale = sqrt(vlimitsq / vsq); + v[i][0] *= scale; + v[i][1] *= scale; + v[i][2] *= scale; + + vest[i][0] = v[i][0]; + vest[i][1] = v[i][1]; + vest[i][2] = v[i][2]; + } + } + + if (xsphFlag) { + + // construct XSPH velocity + vxsph_x = v[i][0] - 0.5 * smoothVel[i](0); + vxsph_y = v[i][1] - 0.5 * smoothVel[i](1); + vxsph_z = v[i][2] - 0.5 * smoothVel[i](2); + + vest[i][0] = vxsph_x + dtfm * f[i][0]; + vest[i][1] = vxsph_y + dtfm * f[i][1]; + vest[i][2] = vxsph_z + dtfm * f[i][2]; + + x[i][0] += dtv * vxsph_x; + x[i][1] += dtv * vxsph_y; + x[i][2] += dtv * vxsph_z; + + + + + } else { + + // extrapolate velocity from half- to full-step + vest[i][0] = v[i][0] + dtfm * f[i][0]; + vest[i][1] = v[i][1] + dtfm * f[i][1]; + vest[i][2] = v[i][2] + dtfm * f[i][2]; + + x[i][0] += dtv * v[i][0]; + x[i][1] += dtv * v[i][1]; + x[i][2] += dtv * v[i][2]; + } + } + } +} + +/* ---------------------------------------------------------------------- */ + +void FixSMDIntegrateUlsph::final_integrate() { + double **v = atom->v; + double **f = atom->f; + double *e = atom->e; + double *de = atom->de; + double *vfrac = atom->vfrac; + double *radius = atom->radius; + double *contact_radius = atom->contact_radius; + int *mask = atom->mask; + int nlocal = atom->nlocal; + if (igroup == atom->firstgroup) + nlocal = atom->nfirst; + double dtfm, vsq, scale; + double *rmass = atom->rmass; + double vol_increment; + Matrix3d D; + + /* + * get current number of SPH neighbors from ULSPH pair style + */ + + int itmp; + int *nn = (int *) force->pair->extract("smd/ulsph/numNeighs_ptr", itmp); + if (nn == NULL) { + error->one(FLERR, "fix smd/integrate_ulsph failed to accesss num_neighs array"); + } + + Matrix3d *L = (Matrix3d *) force->pair->extract("smd/ulsph/velocityGradient_ptr", itmp); + if (L == NULL) { + error->one(FLERR, "fix smd/integrate_ulsph failed to accesss velocityGradient array"); + } + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + + dtfm = dtf / rmass[i]; + v[i][0] += dtfm * f[i][0]; + v[i][1] += dtfm * f[i][1]; + v[i][2] += dtfm * f[i][2]; + + if (vlimit > 0.0) { + vsq = v[i][0] * v[i][0] + v[i][1] * v[i][1] + v[i][2] * v[i][2]; + if (vsq > vlimitsq) { + scale = sqrt(vlimitsq / vsq); + v[i][0] *= scale; + v[i][1] *= scale; + v[i][2] *= scale; + } + } + + e[i] += dtf * de[i]; + + if (adjust_radius_flag) { + if (nn[i] < min_nn) { + radius[i] *= adjust_radius_factor; + } else if (nn[i] > max_nn) { + radius[i] /= adjust_radius_factor; + } + radius[i] = MAX(radius[i], 1.25 * contact_radius[i]); + radius[i] = MIN(radius[i], 4.0 * contact_radius[i]); + + } + + D = 0.5 * (L[i] + L[i].transpose()); + vol_increment = vfrac[i] * update->dt * D.trace(); // Jacobian of deformation + vfrac[i] += vol_increment; + } + } +} + +/* ---------------------------------------------------------------------- */ + +void FixSMDIntegrateUlsph::reset_dt() { + dtv = update->dt; + dtf = 0.5 * update->dt * force->ftm2v; +} + diff --git a/src/USER-SMD/fix_smd_integrate_ulsph.h b/src/USER-SMD/fix_smd_integrate_ulsph.h new file mode 100644 index 0000000000..19ae31a59e --- /dev/null +++ b/src/USER-SMD/fix_smd_integrate_ulsph.h @@ -0,0 +1,64 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef FIX_CLASS + +FixStyle(smd/integrate_ulsph,FixSMDIntegrateUlsph) + +#else + +#ifndef LMP_FIX_SMD_INTEGRATE_ULSPH_H +#define LMP_FIX_SMD_INTEGRATE_ULSPH_H + +#include "fix.h" + +namespace LAMMPS_NS { + +class FixSMDIntegrateUlsph : public Fix { + public: + FixSMDIntegrateUlsph(class LAMMPS *, int, char **); + int setmask(); + virtual void init(); + virtual void initial_integrate(int); + virtual void final_integrate(); + void reset_dt(); + + private: + class NeighList *list; + protected: + double dtv,dtf, vlimit, vlimitsq;; + int mass_require; + bool xsphFlag; + bool adjust_radius_flag; + double adjust_radius_factor; + int min_nn, max_nn; // number of SPH neighbors should lie within this interval + + class Pair *pair; +}; + +} + +#endif +#endif diff --git a/src/USER-SMD/fix_smd_move_triangulated_surface.cpp b/src/USER-SMD/fix_smd_move_triangulated_surface.cpp new file mode 100644 index 0000000000..407eabf452 --- /dev/null +++ b/src/USER-SMD/fix_smd_move_triangulated_surface.cpp @@ -0,0 +1,517 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +#include "stdio.h" +#include "string.h" +#include "fix_smd_move_triangulated_surface.h" +#include "math.h" +#include "stdlib.h" +#include "string.h" +#include "atom.h" +#include "comm.h" +#include "force.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "neigh_request.h" +#include "update.h" +#include "integrate.h" +#include "respa.h" +#include "memory.h" +#include "error.h" +#include "pair.h" +#include "domain.h" +#include +#include "math_const.h" + +using namespace Eigen; +using namespace LAMMPS_NS; +using namespace FixConst; +using namespace MathConst; +using namespace std; + +/* ---------------------------------------------------------------------- */ + +FixSMDMoveTriSurf::FixSMDMoveTriSurf(LAMMPS *lmp, int narg, char **arg) : + Fix(lmp, narg, arg) { + + if (atom->smd_flag != 1) { + error->all(FLERR, "fix fix smd/move_tri_surf command requires atom_style smd"); + } + + if (narg < 3) + error->all(FLERR, "Illegal number of arguments for fix fix smd/move_tri_surf command"); + + rotateFlag = linearFlag = wiggleFlag = false; + wiggle_direction = 1.0; + wiggle_max_travel = 0.0; + + int iarg = 3; + + if (comm->me == 0) { + printf("\n>>========>>========>>========>>========>>========>>========>>========>>========\n"); + printf("fix fix smd/move_tri_surf is active for group: %s \n", arg[1]); + } + while (true) { + + if (iarg >= narg) { + break; + } + + if (strcmp(arg[iarg], "*LINEAR") == 0) { + linearFlag = true; + if (comm->me == 0) { + printf("... will move surface in a linear fashion\n"); + } + + iarg++; + if (iarg == narg) { + error->all(FLERR, "expected three floats for velocity following *LINEAR"); + } + vx = force->numeric(FLERR, arg[iarg]); + + iarg++; + if (iarg == narg) { + error->all(FLERR, "expected three floats for velocity following *LINEAR"); + } + vy = force->numeric(FLERR, arg[iarg]); + + iarg++; + if (iarg == narg) { + error->all(FLERR, "expected three floats for velocity following *LINEAR"); + } + vz = force->numeric(FLERR, arg[iarg]); + + } else if (strcmp(arg[iarg], "*WIGGLE") == 0) { + wiggleFlag = true; + if (comm->me == 0) { + printf("... will move surface in wiggle fashion\n"); + } + + iarg++; + if (iarg == narg) { + error->all(FLERR, "expected 4 floats following *WIGGLE : vx vy vz max_travel"); + } + vx = force->numeric(FLERR, arg[iarg]); + + iarg++; + if (iarg == narg) { + error->all(FLERR, "expected 4 floats following *WIGGLE : vx vy vz max_travel"); + } + vy = force->numeric(FLERR, arg[iarg]); + + iarg++; + if (iarg == narg) { + error->all(FLERR, "expected 4 floats following *WIGGLE : vx vy vz max_travel"); + } + vz = force->numeric(FLERR, arg[iarg]); + + iarg++; + if (iarg == narg) { + error->all(FLERR, "expected 4 floats following *WIGGLE : vx vy vz max_travel"); + } + wiggle_max_travel = force->numeric(FLERR, arg[iarg]); + + } else if (strcmp(arg[iarg], "*ROTATE") == 0) { + rotateFlag = true; + + iarg++; + if (iarg == narg) { + error->all(FLERR, "expected 7 floats following *ROTATE: origin, rotation axis, and rotation period"); + } + origin(0) = force->numeric(FLERR, arg[iarg]); + + iarg++; + if (iarg == narg) { + error->all(FLERR, "expected 7 floats following *ROTATE: origin, rotation axis, and rotation period"); + } + origin(1) = force->numeric(FLERR, arg[iarg]); + + iarg++; + if (iarg == narg) { + error->all(FLERR, "expected 7 floats following *ROTATE: origin, rotation axis, and rotation period"); + } + origin(2) = force->numeric(FLERR, arg[iarg]); + + iarg++; + if (iarg == narg) { + error->all(FLERR, "expected 7 floats following *ROTATE: origin, rotation axis, and rotation period"); + } + rotation_axis(0) = force->numeric(FLERR, arg[iarg]); + + iarg++; + if (iarg == narg) { + error->all(FLERR, "expected 7 floats following *ROTATE: origin, rotation axis, and rotation period"); + } + rotation_axis(1) = force->numeric(FLERR, arg[iarg]); + + iarg++; + if (iarg == narg) { + error->all(FLERR, "expected 7 floats following *ROTATE: origin, rotation axis, and rotation period"); + } + rotation_axis(2) = force->numeric(FLERR, arg[iarg]); + + iarg++; + if (iarg == narg) { + error->all(FLERR, "expected 7 floats following *ROTATE: origin, rotation axis, and rotation period"); + } + rotation_period = force->numeric(FLERR, arg[iarg]); + + /* + * construct rotation matrix + */ + + u_cross(0, 0) = 0.0; + u_cross(0, 1) = -rotation_axis(2); + u_cross(0, 2) = rotation_axis(1); + + u_cross(1, 0) = rotation_axis(2); + u_cross(1, 1) = 0.0; + u_cross(1, 2) = -rotation_axis(0); + + u_cross(2, 0) = -rotation_axis(1); + u_cross(2, 1) = rotation_axis(0); + u_cross(2, 2) = 0.0; + + uxu = rotation_axis * rotation_axis.transpose(); + + if (comm->me == 0) { + printf("will rotate with period %f\n", rotation_period); + } + + } else { + char msg[128]; + sprintf(msg, "Illegal keyword for fix smd/move_tri_surf: %s\n", arg[iarg]); + error->all(FLERR, msg); + } + + iarg++; + + } + + if (comm->me == 0) { + printf(">>========>>========>>========>>========>>========>>========>>========>>========\n\n"); + } + + // set comm sizes needed by this fix + comm_forward = 12; + + //atom->add_callback(0); + //atom->add_callback(1); + + time_integrate = 1; +} + +/* ---------------------------------------------------------------------- */ + +FixSMDMoveTriSurf::~FixSMDMoveTriSurf() +{ + // unregister callbacks to this fix from Atom class + //atom->delete_callback(id,0); + //atom->delete_callback(id,1); +} + +/* ---------------------------------------------------------------------- */ + +int FixSMDMoveTriSurf::setmask() { + int mask = 0; + mask |= INITIAL_INTEGRATE; + //mask |= PRE_EXCHANGE; + return mask; +} + +/* ---------------------------------------------------------------------- */ + +void FixSMDMoveTriSurf::init() { + dtv = update->dt; +} + +/* ---------------------------------------------------------------------- + ------------------------------------------------------------------------- */ + +void FixSMDMoveTriSurf::initial_integrate(int vflag) { + double **x = atom->x; + double **x0 = atom->x0; + double **v = atom->v; + double **vest = atom->vest; + double **smd_data_9 = atom->smd_data_9; + int *mol = atom->molecule; + + int *mask = atom->mask; + int nlocal = atom->nlocal; + double phi; + int i; + Matrix3d eye, Rot; + eye.setIdentity(); + + Vector3d v1, v2, v3, n, point, rotated_point, R, vel; + + if (igroup == atom->firstgroup) + nlocal = atom->nfirst; + + if (linearFlag) { // translate particles + for (i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + + v[i][0] = vx; + v[i][1] = vy; + v[i][2] = vz; + + vest[i][0] = vx; + vest[i][1] = vy; + vest[i][2] = vz; + + x[i][0] += dtv * vx; + x[i][1] += dtv * vy; + x[i][2] += dtv * vz; + + /* + * if this is a triangle, move the vertices as well + */ + + if (mol[i] >= 65535) { + smd_data_9[i][0] += dtv * vx; + smd_data_9[i][1] += dtv * vy; + smd_data_9[i][2] += dtv * vz; + + smd_data_9[i][3] += dtv * vx; + smd_data_9[i][4] += dtv * vy; + smd_data_9[i][5] += dtv * vz; + + smd_data_9[i][6] += dtv * vx; + smd_data_9[i][7] += dtv * vy; + smd_data_9[i][8] += dtv * vz; + } + + } + } + } + + if (wiggleFlag) { // wiggle particles forward and backward + + wiggle_travel += sqrt(vx * vx + vy * vy + vz * vz ) * dtv; + double wiggle_vx = wiggle_direction * vx; + double wiggle_vy = wiggle_direction * vy; + double wiggle_vz = wiggle_direction * vz; + + //printf("wiggle vz is %f, wiggle_max_travel is %f, dir=%f\n", wiggle_vz, wiggle_max_travel, wiggle_direction); + + for (i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + + v[i][0] = wiggle_vx; + v[i][1] = wiggle_vy; + v[i][2] = wiggle_vz; + + vest[i][0] = wiggle_vx; + vest[i][1] = wiggle_vy; + vest[i][2] = wiggle_vz; + + x[i][0] += dtv * wiggle_vx; + x[i][1] += dtv * wiggle_vy; + x[i][2] += dtv * wiggle_vz; + + /* + * if this is a triangle, move the vertices as well + */ + + if (mol[i] >= 65535) { + smd_data_9[i][0] += dtv * wiggle_vx; + smd_data_9[i][1] += dtv * wiggle_vy; + smd_data_9[i][2] += dtv * wiggle_vz; + + smd_data_9[i][3] += dtv * wiggle_vx; + smd_data_9[i][4] += dtv * wiggle_vy; + smd_data_9[i][5] += dtv * wiggle_vz; + + smd_data_9[i][6] += dtv * wiggle_vx; + smd_data_9[i][7] += dtv * wiggle_vy; + smd_data_9[i][8] += dtv * wiggle_vz; + } + + } + } + + if (wiggle_travel >= wiggle_max_travel) { + wiggle_direction *= -1.0; + wiggle_travel = 0.0; + } + } + + if (rotateFlag) { // rotate particles + Vector3d xnew, R_new, x_correct; + + /* + * rotation angle and matrix form of Rodrigues' rotation formula + */ + + phi = MY_2PI * dtv / rotation_period; + //printf("dt=%f, phi =%f, T=%f\n", dtv, phi, rotation_period); + Rot = cos(phi) * eye + sin(phi) * u_cross + (1.0 - cos(phi)) * uxu; + + for (i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + + /* + * generate vector R from origin to point which is to be rotated + */ + point << x[i][0], x[i][1], x[i][2]; + R = point - origin; + + /* + * rotate vector and shift away from origin + */ + rotated_point = Rot * R + origin; + + /* + * determine velocity + */ + vel = (rotated_point - point) / update->dt; + + /* + * assign new velocities and coordinates + */ + v[i][0] = vel(0); + v[i][1] = vel(1); + v[i][2] = vel(2); + + vest[i][0] = vel(0); + vest[i][1] = vel(1); + vest[i][2] = vel(2); + + x[i][0] = rotated_point(0); + x[i][1] = rotated_point(1); + x[i][2] = rotated_point(2); + + /* + * if this is a triangle, rotate the vertices as well + */ + + if (mol[i] >= 65535) { + + v1 << smd_data_9[i][0], smd_data_9[i][1], smd_data_9[i][2]; + R = v1 - origin; + rotated_point = Rot * R + origin; + vel = (rotated_point - v1) / update->dt; + smd_data_9[i][0] = rotated_point(0); + smd_data_9[i][1] = rotated_point(1); + smd_data_9[i][2] = rotated_point(2); + v1 = rotated_point; + + v2 << smd_data_9[i][3], smd_data_9[i][4], smd_data_9[i][5]; + R = v2 - origin; + rotated_point = Rot * R + origin; + vel = (rotated_point - v2) / update->dt; + smd_data_9[i][3] = rotated_point(0); + smd_data_9[i][4] = rotated_point(1); + smd_data_9[i][5] = rotated_point(2); + v2 = rotated_point; + + v3 << smd_data_9[i][6], smd_data_9[i][7], smd_data_9[i][8]; + R = v3 - origin; + rotated_point = Rot * R + origin; + vel = (rotated_point - v3) / update->dt; + smd_data_9[i][6] = rotated_point(0); + smd_data_9[i][7] = rotated_point(1); + smd_data_9[i][8] = rotated_point(2); + v3 = rotated_point; + + // recalculate triangle normal + n = (v2 - v1).cross(v2 - v3); + n /= n.norm(); + x0[i][0] = n(0); + x0[i][1] = n(1); + x0[i][2] = n(2); + + } + + } + } + } + + // we changed smd_data_9, x0. perform communication to ghosts + comm->forward_comm_fix(this); + +} + +/* ---------------------------------------------------------------------- */ + +void FixSMDMoveTriSurf::reset_dt() { + dtv = update->dt; +} + +/* ---------------------------------------------------------------------- */ + +int FixSMDMoveTriSurf::pack_forward_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { + int i, j, m; + double **x0 = atom->x0; + double **smd_data_9 = atom->smd_data_9; + + //printf("in FixSMDIntegrateTlsph::pack_forward_comm\n"); + m = 0; + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = x0[j][0]; + buf[m++] = x0[j][1]; + buf[m++] = x0[j][2]; + + buf[m++] = smd_data_9[j][0]; + buf[m++] = smd_data_9[j][1]; + buf[m++] = smd_data_9[j][2]; + buf[m++] = smd_data_9[j][3]; + buf[m++] = smd_data_9[j][4]; + buf[m++] = smd_data_9[j][5]; + buf[m++] = smd_data_9[j][6]; + buf[m++] = smd_data_9[j][7]; + buf[m++] = smd_data_9[j][8]; + + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +void FixSMDMoveTriSurf::unpack_forward_comm(int n, int first, double *buf) { + int i, m, last; + double **x0 = atom->x0; + double **smd_data_9 = atom->smd_data_9; + + //printf("in FixSMDMoveTriSurf::unpack_forward_comm\n"); + m = 0; + last = first + n; + for (i = first; i < last; i++) { + x0[i][0] = buf[m++]; + x0[i][1] = buf[m++]; + x0[i][2] = buf[m++]; + + smd_data_9[i][0] = buf[m++]; + smd_data_9[i][1] = buf[m++]; + smd_data_9[i][2] = buf[m++]; + smd_data_9[i][3] = buf[m++]; + smd_data_9[i][4] = buf[m++]; + smd_data_9[i][5] = buf[m++]; + smd_data_9[i][6] = buf[m++]; + smd_data_9[i][7] = buf[m++]; + smd_data_9[i][8] = buf[m++]; + } +} diff --git a/src/USER-SMD/fix_smd_move_triangulated_surface.h b/src/USER-SMD/fix_smd_move_triangulated_surface.h new file mode 100644 index 0000000000..e6593ea8b0 --- /dev/null +++ b/src/USER-SMD/fix_smd_move_triangulated_surface.h @@ -0,0 +1,65 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +#ifdef FIX_CLASS + +FixStyle(smd/move_tri_surf,FixSMDMoveTriSurf) + +#else + +#ifndef LMP_FIX_SMD_INTEGRATE_TRIANGULAR_SURFACE_H +#define LMP_FIX_SMD_INTEGRATE_TRIANGULAR_SURFACE_H + +#include "fix.h" +#include + +using namespace Eigen; + +namespace LAMMPS_NS { + +class FixSMDMoveTriSurf: public Fix { +public: + FixSMDMoveTriSurf(class LAMMPS *, int, char **); + ~FixSMDMoveTriSurf(); + int setmask(); + virtual void init(); + virtual void initial_integrate(int); + void reset_dt(); + int pack_forward_comm(int, int *, double *, int, int *); + void unpack_forward_comm(int, int, double *); + +protected: + double dtv; + bool linearFlag, wiggleFlag, rotateFlag; + double vx, vy, vz; + Vector3d rotation_axis, origin; + double rotation_period; + Matrix3d u_cross, uxu; + double wiggle_travel, wiggle_max_travel, wiggle_direction; +}; + +} + +#endif +#endif diff --git a/src/USER-SMD/fix_smd_setvel.cpp b/src/USER-SMD/fix_smd_setvel.cpp new file mode 100644 index 0000000000..dbf21670f9 --- /dev/null +++ b/src/USER-SMD/fix_smd_setvel.cpp @@ -0,0 +1,375 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +#include "string.h" +#include "stdlib.h" +#include "fix_smd_setvel.h" +#include "atom.h" +#include "update.h" +#include "modify.h" +#include "domain.h" +#include "region.h" +#include "respa.h" +#include "input.h" +#include "variable.h" +#include "memory.h" +#include "error.h" +#include "force.h" + +using namespace LAMMPS_NS; +using namespace FixConst; + +enum { + NONE, CONSTANT, EQUAL, ATOM +}; + +/* ---------------------------------------------------------------------- */ + +FixSMDSetVel::FixSMDSetVel(LAMMPS *lmp, int narg, char **arg) : + Fix(lmp, narg, arg) { + if (narg < 6) + error->all(FLERR, "Illegal fix setvelocity command"); + + dynamic_group_allow = 1; + vector_flag = 1; + size_vector = 3; + global_freq = 1; + extvector = 1; + + xstr = ystr = zstr = NULL; + + if (strstr(arg[3], "v_") == arg[3]) { + int n = strlen(&arg[3][2]) + 1; + xstr = new char[n]; + strcpy(xstr, &arg[3][2]); + } else if (strcmp(arg[3], "NULL") == 0) { + xstyle = NONE; + } else { + xvalue = force->numeric(FLERR, arg[3]); + xstyle = CONSTANT; + } + if (strstr(arg[4], "v_") == arg[4]) { + int n = strlen(&arg[4][2]) + 1; + ystr = new char[n]; + strcpy(ystr, &arg[4][2]); + } else if (strcmp(arg[4], "NULL") == 0) { + ystyle = NONE; + } else { + yvalue = force->numeric(FLERR, arg[4]); + ystyle = CONSTANT; + } + if (strstr(arg[5], "v_") == arg[5]) { + int n = strlen(&arg[5][2]) + 1; + zstr = new char[n]; + strcpy(zstr, &arg[5][2]); + } else if (strcmp(arg[5], "NULL") == 0) { + zstyle = NONE; + } else { + zvalue = force->numeric(FLERR, arg[5]); + zstyle = CONSTANT; + } + + // optional args + + iregion = -1; + idregion = NULL; + + int iarg = 6; + while (iarg < narg) { + if (strcmp(arg[iarg], "region") == 0) { + if (iarg + 2 > narg) + error->all(FLERR, "Illegal fix setvelocity command"); + iregion = domain->find_region(arg[iarg + 1]); + if (iregion == -1) + error->all(FLERR, "Region ID for fix setvelocity does not exist"); + int n = strlen(arg[iarg + 1]) + 1; + idregion = new char[n]; + strcpy(idregion, arg[iarg + 1]); + iarg += 2; + } else + error->all(FLERR, "Illegal fix setvelocity command"); + } + + force_flag = 0; + foriginal[0] = foriginal[1] = foriginal[2] = 0.0; + + maxatom = atom->nmax; + memory->create(sforce, maxatom, 3, "setvelocity:sforce"); +} + +/* ---------------------------------------------------------------------- */ + +FixSMDSetVel::~FixSMDSetVel() { + delete[] xstr; + delete[] ystr; + delete[] zstr; + delete[] idregion; + memory->destroy(sforce); +} + +/* ---------------------------------------------------------------------- */ + +int FixSMDSetVel::setmask() { + int mask = 0; + //mask |= INITIAL_INTEGRATE; + mask |= POST_FORCE; + return mask; +} + +/* ---------------------------------------------------------------------- */ + +void FixSMDSetVel::init() { + // check variables + + if (xstr) { + xvar = input->variable->find(xstr); + if (xvar < 0) + error->all(FLERR, "Variable name for fix setvelocity does not exist"); + if (input->variable->equalstyle(xvar)) + xstyle = EQUAL; + else if (input->variable->atomstyle(xvar)) + xstyle = ATOM; + else + error->all(FLERR, "Variable for fix setvelocity is invalid style"); + } + if (ystr) { + yvar = input->variable->find(ystr); + if (yvar < 0) + error->all(FLERR, "Variable name for fix setvelocity does not exist"); + if (input->variable->equalstyle(yvar)) + ystyle = EQUAL; + else if (input->variable->atomstyle(yvar)) + ystyle = ATOM; + else + error->all(FLERR, "Variable for fix setvelocity is invalid style"); + } + if (zstr) { + zvar = input->variable->find(zstr); + if (zvar < 0) + error->all(FLERR, "Variable name for fix setvelocity does not exist"); + if (input->variable->equalstyle(zvar)) + zstyle = EQUAL; + else if (input->variable->atomstyle(zvar)) + zstyle = ATOM; + else + error->all(FLERR, "Variable for fix setvelocity is invalid style"); + } + + // set index and check validity of region + + if (iregion >= 0) { + iregion = domain->find_region(idregion); + if (iregion == -1) + error->all(FLERR, "Region ID for fix setvelocity does not exist"); + } + + if (xstyle == ATOM || ystyle == ATOM || zstyle == ATOM) + varflag = ATOM; + else if (xstyle == EQUAL || ystyle == EQUAL || zstyle == EQUAL) + varflag = EQUAL; + else + varflag = CONSTANT; + + if (strstr(update->integrate_style, "respa")) + nlevels_respa = ((Respa *) update->integrate)->nlevels; + + // cannot use non-zero forces for a minimization since no energy is integrated + // use fix addforce instead + + int flag = 0; + if (update->whichflag == 2) { + if (xstyle == EQUAL || xstyle == ATOM) + flag = 1; + if (ystyle == EQUAL || ystyle == ATOM) + flag = 1; + if (zstyle == EQUAL || zstyle == ATOM) + flag = 1; + if (xstyle == CONSTANT && xvalue != 0.0) + flag = 1; + if (ystyle == CONSTANT && yvalue != 0.0) + flag = 1; + if (zstyle == CONSTANT && zvalue != 0.0) + flag = 1; + } + if (flag) + error->all(FLERR, "Cannot use non-zero forces in an energy minimization"); +} + +/* ---------------------------------------------------------------------- */ + +void FixSMDSetVel::setup(int vflag) { + if (strstr(update->integrate_style, "verlet")) + post_force(vflag); + else + for (int ilevel = 0; ilevel < nlevels_respa; ilevel++) { + ((Respa *) update->integrate)->copy_flevel_f(ilevel); + post_force_respa(vflag, ilevel, 0); + ((Respa *) update->integrate)->copy_f_flevel(ilevel); + } +} + +/* ---------------------------------------------------------------------- */ + +void FixSMDSetVel::min_setup(int vflag) { + post_force(vflag); +} + +/* ---------------------------------------------------------------------- */ + +//void FixSMDSetVel::initial_integrate(int vflag) { +void FixSMDSetVel::post_force(int vflag) { + double **x = atom->x; + double **f = atom->f; + double **v = atom->v; + double **vest = atom->vest; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + // update region if necessary + + Region *region = NULL; + if (iregion >= 0) { + region = domain->regions[iregion]; + region->prematch(); + } + + // reallocate sforce array if necessary + + if (varflag == ATOM && nlocal > maxatom) { + maxatom = atom->nmax; + memory->destroy(sforce); + memory->create(sforce, maxatom, 3, "setvelocity:sforce"); + } + + foriginal[0] = foriginal[1] = foriginal[2] = 0.0; + force_flag = 0; + + if (varflag == CONSTANT) { + for (int i = 0; i < nlocal; i++) + if (mask[i] & groupbit) { + if (region && !region->match(x[i][0], x[i][1], x[i][2])) + continue; + foriginal[0] += f[i][0]; + foriginal[1] += f[i][1]; + foriginal[2] += f[i][2]; + if (xstyle) { + v[i][0] = xvalue; + vest[i][0] = xvalue; + f[i][0] = 0.0; + } + if (ystyle) { + v[i][1] = yvalue; + vest[i][1] = yvalue; + f[i][1] = 0.0; + } + if (zstyle) { + v[i][2] = zvalue; + vest[i][2] = zvalue; + f[i][2] = 0.0; + } + } + + // variable force, wrap with clear/add + + } else { + + modify->clearstep_compute(); + + if (xstyle == EQUAL) + xvalue = input->variable->compute_equal(xvar); + else if (xstyle == ATOM) + input->variable->compute_atom(xvar, igroup, &sforce[0][0], 3, 0); + if (ystyle == EQUAL) + yvalue = input->variable->compute_equal(yvar); + else if (ystyle == ATOM) + input->variable->compute_atom(yvar, igroup, &sforce[0][1], 3, 0); + if (zstyle == EQUAL) + zvalue = input->variable->compute_equal(zvar); + else if (zstyle == ATOM) + input->variable->compute_atom(zvar, igroup, &sforce[0][2], 3, 0); + + modify->addstep_compute(update->ntimestep + 1); + + //printf("setting velocity at timestep %d\n", update->ntimestep); + + for (int i = 0; i < nlocal; i++) + if (mask[i] & groupbit) { + if (region && !region->match(x[i][0], x[i][1], x[i][2])) + continue; + foriginal[0] += f[i][0]; + foriginal[1] += f[i][1]; + foriginal[2] += f[i][2]; + if (xstyle == ATOM) { + vest[i][0] = v[i][0] = sforce[i][0]; + f[i][0] = 0.0; + } else if (xstyle) { + vest[i][0] = v[i][0] = xvalue; + f[i][0] = 0.0; + } + + if (ystyle == ATOM) { + vest[i][1] = v[i][1] = sforce[i][1]; + f[i][1] = 0.0; + } else if (ystyle) { + vest[i][1] = v[i][1] = yvalue; + f[i][1] = 0.0; + } + + if (zstyle == ATOM) { + vest[i][2] = v[i][2] = sforce[i][2]; + f[i][2] = 0.0; + } else if (zstyle) { + vest[i][2] = v[i][2] = zvalue; + f[i][2] = 0.0; + } + + } + } +} + +/* ---------------------------------------------------------------------- + return components of total force on fix group before force was changed + ------------------------------------------------------------------------- */ + +double FixSMDSetVel::compute_vector(int n) { +// only sum across procs one time + + if (force_flag == 0) { + MPI_Allreduce(foriginal, foriginal_all, 3, MPI_DOUBLE, MPI_SUM, world); + force_flag = 1; + } + return foriginal_all[n]; +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based array + ------------------------------------------------------------------------- */ + +double FixSMDSetVel::memory_usage() { + double bytes = 0.0; + if (varflag == ATOM) + bytes = atom->nmax * 3 * sizeof(double); + return bytes; +} diff --git a/src/USER-SMD/fix_smd_setvel.h b/src/USER-SMD/fix_smd_setvel.h new file mode 100644 index 0000000000..9e5fe642eb --- /dev/null +++ b/src/USER-SMD/fix_smd_setvel.h @@ -0,0 +1,95 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef FIX_CLASS + +FixStyle(smd/setvelocity,FixSMDSetVel) + +#else + +#ifndef LMP_FIX_SMD_SET_VELOCITY_H +#define LMP_FIX_SMD_SET_VELOCITY_H + +#include "fix.h" + +namespace LAMMPS_NS { + +class FixSMDSetVel : public Fix { + public: + FixSMDSetVel(class LAMMPS *, int, char **); + ~FixSMDSetVel(); + int setmask(); + void init(); + void setup(int); + void min_setup(int); + //void initial_integrate(int); + void post_force(int); + double compute_vector(int); + double memory_usage(); + + private: + double xvalue,yvalue,zvalue; + int varflag,iregion; + char *xstr,*ystr,*zstr; + char *idregion; + int xvar,yvar,zvar,xstyle,ystyle,zstyle; + double foriginal[3],foriginal_all[3]; + int force_flag; + int nlevels_respa; + + int maxatom; + double **sforce; +}; + +} + +#endif +#endif + +/* ERROR/WARNING messages: + +E: Illegal ... command + +Self-explanatory. Check the input script syntax and compare to the +documentation for the command. You can use -echo screen as a +command-line option when running LAMMPS to see the offending line. + +E: Region ID for fix setforce does not exist + +Self-explanatory. + +E: Variable name for fix setforce does not exist + +Self-explanatory. + +E: Variable for fix setforce is invalid style + +Only equal-style variables can be used. + +E: Cannot use non-zero forces in an energy minimization + +Fix setforce cannot be used in this manner. Use fix addforce +instead. + +*/ diff --git a/src/USER-SMD/fix_smd_tlsph_reference_configuration.cpp b/src/USER-SMD/fix_smd_tlsph_reference_configuration.cpp new file mode 100644 index 0000000000..bbfd1ec22b --- /dev/null +++ b/src/USER-SMD/fix_smd_tlsph_reference_configuration.cpp @@ -0,0 +1,613 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * This file is based on the FixShearHistory class. + * + * ----------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +#include "lattice.h" +#include "mpi.h" +#include "string.h" +#include "stdio.h" +#include "fix_smd_tlsph_reference_configuration.h" +#include "atom.h" +#include "comm.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "force.h" +#include "pair.h" +#include "update.h" +#include "modify.h" +#include "memory.h" +#include "error.h" +#include "domain.h" +#include +#include "smd_kernels.h" +#include "smd_math.h" + +using namespace Eigen; +using namespace LAMMPS_NS; +using namespace FixConst; +using namespace SMD_Kernels; +using namespace std; +using namespace SMD_Math; +#define DELTA 16384 + +#define INSERT_PREDEFINED_CRACKS false + +/* ---------------------------------------------------------------------- */ + +FixSMD_TLSPH_ReferenceConfiguration::FixSMD_TLSPH_ReferenceConfiguration(LAMMPS *lmp, int narg, char **arg) : + Fix(lmp, narg, arg) { + + if (atom->map_style == 0) + error->all(FLERR, "Pair tlsph with partner list requires an atom map, see atom_modify"); + + maxpartner = 1; + npartner = NULL; + partner = NULL; + wfd_list = NULL; + wf_list = NULL; + energy_per_bond = NULL; + degradation_ij = NULL; + grow_arrays(atom->nmax); + atom->add_callback(0); + + // initialize npartner to 0 so neighbor list creation is OK the 1st time + int nlocal = atom->nlocal; + for (int i = 0; i < nlocal; i++) { + npartner[i] = 0; + } + + comm_forward = 14; + updateFlag = 1; +} + +/* ---------------------------------------------------------------------- */ + +FixSMD_TLSPH_ReferenceConfiguration::~FixSMD_TLSPH_ReferenceConfiguration() { + // unregister this fix so atom class doesn't invoke it any more + + atom->delete_callback(id, 0); +// delete locally stored arrays + + memory->destroy(npartner); + memory->destroy(partner); + memory->destroy(wfd_list); + memory->destroy(wf_list); + memory->destroy(degradation_ij); + memory->destroy(energy_per_bond); +} + +/* ---------------------------------------------------------------------- */ + +int FixSMD_TLSPH_ReferenceConfiguration::setmask() { + int mask = 0; + mask |= PRE_EXCHANGE; + return mask; +} + +/* ---------------------------------------------------------------------- */ + +void FixSMD_TLSPH_ReferenceConfiguration::init() { + if (atom->tag_enable == 0) + error->all(FLERR, "Pair style tlsph requires atoms have IDs"); +} + +/* ---------------------------------------------------------------------- */ + +void FixSMD_TLSPH_ReferenceConfiguration::pre_exchange() { + //return; + + //printf("in FixSMD_TLSPH_ReferenceConfiguration::pre_exchange()\n"); + double **defgrad = atom->smd_data_9; + double *radius = atom->radius; + double *rho = atom->rho; + double *vfrac = atom->vfrac; + double **x = atom->x; + double **x0 = atom->x0; + double *rmass = atom->rmass; + int nlocal = atom->nlocal; + int i, itmp; + int *mask = atom->mask; + if (igroup == atom->firstgroup) { + nlocal = atom->nfirst; + } + + int *updateFlag_ptr = (int *) force->pair->extract("smd/tlsph/updateFlag_ptr", itmp); + if (updateFlag_ptr == NULL) { + error->one(FLERR, + "fix FixSMD_TLSPH_ReferenceConfiguration failed to access updateFlag pointer. Check if a pair style exist which calculates this quantity."); + } + + int *nn = (int *) force->pair->extract("smd/tlsph/numNeighsRefConfig_ptr", itmp); + if (nn == NULL) { + error->all(FLERR, "FixSMDIntegrateTlsph::updateReferenceConfiguration() failed to access numNeighsRefConfig_ptr array"); + } + + // sum all update flag across processors + MPI_Allreduce(updateFlag_ptr, &updateFlag, 1, MPI_INT, MPI_MAX, world); + + if (updateFlag > 0) { + if (comm->me == 0) { + printf("**** updating ref config at step: %ld\n", update->ntimestep); + } + + for (i = 0; i < nlocal; i++) { + + if (mask[i] & groupbit) { + + // re-set x0 coordinates + x0[i][0] = x[i][0]; + x0[i][1] = x[i][1]; + x0[i][2] = x[i][2]; + + // re-set deformation gradient + defgrad[i][0] = 1.0; + defgrad[i][1] = 0.0; + defgrad[i][2] = 0.0; + defgrad[i][3] = 0.0; + defgrad[i][4] = 1.0; + defgrad[i][5] = 0.0; + defgrad[i][6] = 0.0; + defgrad[i][7] = 0.0; + defgrad[i][8] = 1.0; + /* + * Adjust particle volume as the reference configuration is changed. + * We safeguard against excessive deformations by limiting the adjustment range + * to the intervale J \in [0.9..1.1] + */ + vfrac[i] = rmass[i] / rho[i]; +// + if (nn[i] < 15) { + radius[i] *= 1.2; + } // else //{ + // radius[i] *= pow(J, 1.0 / domain->dimension); + //} + } + } + + // update of reference config could have changed x0, vfrac, radius + // communicate these quantities now to ghosts: x0, vfrac, radius + comm->forward_comm_fix(this); + + setup(0); + } +} + +/* ---------------------------------------------------------------------- + copy partner info from neighbor lists to atom arrays + so can be migrated or stored with atoms + ------------------------------------------------------------------------- */ + +void FixSMD_TLSPH_ReferenceConfiguration::setup(int vflag) { + int i, j, ii, jj, n, inum, jnum; + int *ilist, *jlist, *numneigh, **firstneigh; + int itype, jtype; + double r, h, wf, wfd; + Vector3d dx; + + if (updateFlag == 0) + return; + + int nlocal = atom->nlocal; + nmax = atom->nmax; + grow_arrays(nmax); + +// 1st loop over neighbor list +// calculate npartner for each owned atom +// nlocal_neigh = nlocal when neigh list was built, may be smaller than nlocal + + double **x0 = atom->x; + double *radius = atom->radius; + int *type = atom->type; + int *mask = atom->mask; + tagint *tag = atom->tag; + NeighList *list = pair->list; + inum = list->inum; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + + // zero npartner for all current atoms + for (i = 0; i < nlocal; i++) + npartner[i] = 0; + + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + itype = type[i]; + jlist = firstneigh[i]; + jnum = numneigh[i]; + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + j &= NEIGHMASK; + jtype = type[j]; + + if (INSERT_PREDEFINED_CRACKS) { + if (!crack_exclude(i, j)) + continue; + } + + dx(0) = x0[i][0] - x0[j][0]; + dx(1) = x0[i][1] - x0[j][1]; + dx(2) = x0[i][2] - x0[j][2]; + r = dx.norm(); + h = radius[i] + radius[j]; + + if (r <= h) { + npartner[i]++; + if (j < nlocal) { + npartner[j]++; + } + } + } + } + + maxpartner = 0; + for (i = 0; i < nlocal; i++) + maxpartner = MAX(maxpartner, npartner[i]); + int maxall; + MPI_Allreduce(&maxpartner, &maxall, 1, MPI_INT, MPI_MAX, world); + maxpartner = maxall; + + grow_arrays(nmax); + + for (i = 0; i < nlocal; i++) { + npartner[i] = 0; + for (jj = 0; jj < maxpartner; jj++) { + wfd_list[i][jj] = 0.0; + wf_list[i][jj] = 0.0; + degradation_ij[i][jj] = 0.0; + energy_per_bond[i][jj] = 0.0; + } + } + + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + itype = type[i]; + jlist = firstneigh[i]; + jnum = numneigh[i]; + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + j &= NEIGHMASK; + + dx(0) = x0[i][0] - x0[j][0]; + dx(1) = x0[i][1] - x0[j][1]; + dx(2) = x0[i][2] - x0[j][2]; + r = dx.norm(); + jtype = type[j]; + h = radius[i] + radius[j]; + + if (INSERT_PREDEFINED_CRACKS) { + if (!crack_exclude(i, j)) + continue; + } + + if (r < h) { + spiky_kernel_and_derivative(h, r, domain->dimension, wf, wfd); + + partner[i][npartner[i]] = tag[j]; + wfd_list[i][npartner[i]] = wfd; + wf_list[i][npartner[i]] = wf; + npartner[i]++; + if (j < nlocal) { + partner[j][npartner[j]] = tag[i]; + wfd_list[j][npartner[j]] = wfd; + wf_list[j][npartner[j]] = wf; + npartner[j]++; + } + } + } + } + + // count number of particles for which this group is active + + // bond statistics + if (update->ntimestep > -1) { + n = 0; + int count = 0; + for (i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + n += npartner[i]; + count += 1; + } + } + int nall, countall; + MPI_Allreduce(&n, &nall, 1, MPI_INT, MPI_SUM, world); + MPI_Allreduce(&count, &countall, 1, MPI_INT, MPI_SUM, world); + + if (comm->me == 0) { + if (screen) { + printf("\n>>========>>========>>========>>========>>========>>========>>========>>========\n"); + fprintf(screen, "TLSPH neighbors:\n"); + fprintf(screen, " max # of neighbors for a single particle = %d\n", maxpartner); + fprintf(screen, " average # of neighbors/particle in group tlsph = %g\n", (double) nall / countall); + printf(">>========>>========>>========>>========>>========>>========>>========>>========\n\n"); + } + if (logfile) { + fprintf(logfile, "\nTLSPH neighbors:\n"); + fprintf(logfile, " max # of neighbors for a single particle = %d\n", maxpartner); + fprintf(logfile, " average # of neighbors/particle in group tlsph = %g\n", (double) nall / countall); + } + } + } + + updateFlag = 0; // set update flag to zero after the update + +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based arrays + ------------------------------------------------------------------------- */ + +double FixSMD_TLSPH_ReferenceConfiguration::memory_usage() { + int nmax = atom->nmax; + int bytes = nmax * sizeof(int); + bytes += nmax * maxpartner * sizeof(tagint); // partner array + bytes += nmax * maxpartner * sizeof(float); // wf_list + bytes += nmax * maxpartner * sizeof(float); // wfd_list + bytes += nmax * maxpartner * sizeof(float); // damage_per_interaction array + bytes += nmax * sizeof(int); // npartner array + return bytes; + +} + +/* ---------------------------------------------------------------------- + allocate local atom-based arrays + ------------------------------------------------------------------------- */ + +void FixSMD_TLSPH_ReferenceConfiguration::grow_arrays(int nmax) { + //printf("in FixSMD_TLSPH_ReferenceConfiguration::grow_arrays\n"); + memory->grow(npartner, nmax, "tlsph_refconfig_neigh:npartner"); + memory->grow(partner, nmax, maxpartner, "tlsph_refconfig_neigh:partner"); + memory->grow(wfd_list, nmax, maxpartner, "tlsph_refconfig_neigh:wfd"); + memory->grow(wf_list, nmax, maxpartner, "tlsph_refconfig_neigh:wf"); + memory->grow(degradation_ij, nmax, maxpartner, "tlsph_refconfig_neigh:degradation_ij"); + memory->grow(energy_per_bond, nmax, maxpartner, "tlsph_refconfig_neigh:damage_onset_strain"); +} + +/* ---------------------------------------------------------------------- + copy values within local atom-based arrays + ------------------------------------------------------------------------- */ + +void FixSMD_TLSPH_ReferenceConfiguration::copy_arrays(int i, int j, int delflag) { + npartner[j] = npartner[i]; + for (int m = 0; m < npartner[j]; m++) { + partner[j][m] = partner[i][m]; + wfd_list[j][m] = wfd_list[i][m]; + wf_list[j][m] = wf_list[i][m]; + degradation_ij[j][m] = degradation_ij[i][m]; + energy_per_bond[j][m] = energy_per_bond[i][m]; + } +} + +/* ---------------------------------------------------------------------- + pack values in local atom-based arrays for exchange with another proc + ------------------------------------------------------------------------- */ + +int FixSMD_TLSPH_ReferenceConfiguration::pack_exchange(int i, double *buf) { +// NOTE: how do I know comm buf is big enough if extreme # of touching neighs +// Comm::BUFEXTRA may need to be increased + +//printf("pack_exchange ...\n"); + + int m = 0; + buf[m++] = npartner[i]; + for (int n = 0; n < npartner[i]; n++) { + buf[m++] = partner[i][n]; + buf[m++] = wfd_list[i][n]; + buf[m++] = wf_list[i][n]; + buf[m++] = degradation_ij[i][n]; + buf[m++] = energy_per_bond[i][n]; + } + return m; + +} + +/* ---------------------------------------------------------------------- + unpack values in local atom-based arrays from exchange with another proc + ------------------------------------------------------------------------- */ + +int FixSMD_TLSPH_ReferenceConfiguration::unpack_exchange(int nlocal, double *buf) { + if (nlocal == nmax) { + //printf("nlocal=%d, nmax=%d\n", nlocal, nmax); + nmax = nmax / DELTA * DELTA; + nmax += DELTA; + grow_arrays(nmax); + + error->message(FLERR, + "in Fixtlsph_refconfigNeighGCG::unpack_exchange: local arrays too small for receiving partner information; growing arrays"); + } +//printf("nlocal=%d, nmax=%d\n", nlocal, nmax); + + int m = 0; + npartner[nlocal] = static_cast(buf[m++]); + for (int n = 0; n < npartner[nlocal]; n++) { + partner[nlocal][n] = static_cast(buf[m++]); + wfd_list[nlocal][n] = static_cast(buf[m++]); + wf_list[nlocal][n] = static_cast(buf[m++]); + degradation_ij[nlocal][n] = static_cast(buf[m++]); + energy_per_bond[nlocal][n] = static_cast(buf[m++]); + } + return m; +} + +/* ---------------------------------------------------------------------- + pack values in local atom-based arrays for restart file + ------------------------------------------------------------------------- */ + +int FixSMD_TLSPH_ReferenceConfiguration::pack_restart(int i, double *buf) { + int m = 0; + buf[m++] = 4 * npartner[i] + 2; + buf[m++] = npartner[i]; + for (int n = 0; n < npartner[i]; n++) { + buf[m++] = partner[i][n]; + buf[m++] = wfd_list[i][n]; + buf[m++] = wf_list[i][n]; + buf[m++] = degradation_ij[i][n]; + buf[m++] = energy_per_bond[i][n]; + } + return m; +} + +/* ---------------------------------------------------------------------- + unpack values from atom->extra array to restart the fix + ------------------------------------------------------------------------- */ + +void FixSMD_TLSPH_ReferenceConfiguration::unpack_restart(int nlocal, int nth) { +// ipage = NULL if being called from granular pair style init() + +// skip to Nth set of extra values + +// double **extra = atom->extra; +// +// int m = 0; +// for (int i = 0; i < nth; i++) +// m += static_cast(extra[nlocal][m]); +// m++; +// +// // allocate new chunks from ipage,dpage for incoming values +// +// npartner[nlocal] = static_cast(extra[nlocal][m++]); +// for (int n = 0; n < npartner[nlocal]; n++) { +// partner[nlocal][n] = static_cast(extra[nlocal][m++]); +// } +} + +/* ---------------------------------------------------------------------- + maxsize of any atom's restart data + ------------------------------------------------------------------------- */ + +int FixSMD_TLSPH_ReferenceConfiguration::maxsize_restart() { +// maxtouch_all = max # of touching partners across all procs + + int maxtouch_all; + MPI_Allreduce(&maxpartner, &maxtouch_all, 1, MPI_INT, MPI_MAX, world); + return 4 * maxtouch_all + 2; +} + +/* ---------------------------------------------------------------------- + size of atom nlocal's restart data + ------------------------------------------------------------------------- */ + +int FixSMD_TLSPH_ReferenceConfiguration::size_restart(int nlocal) { + return 4 * npartner[nlocal] + 2; +} + +/* ---------------------------------------------------------------------- */ + +int FixSMD_TLSPH_ReferenceConfiguration::pack_forward_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { + int i, j, m; + double *radius = atom->radius; + double *vfrac = atom->vfrac; + double **x0 = atom->x0; + double **defgrad0 = atom->smd_data_9; + + //printf("FixSMD_TLSPH_ReferenceConfiguration:::pack_forward_comm\n"); + m = 0; + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = x0[j][0]; + buf[m++] = x0[j][1]; + buf[m++] = x0[j][2]; + + buf[m++] = vfrac[j]; + buf[m++] = radius[j]; + + buf[m++] = defgrad0[i][0]; + buf[m++] = defgrad0[i][1]; + buf[m++] = defgrad0[i][2]; + buf[m++] = defgrad0[i][3]; + buf[m++] = defgrad0[i][4]; + buf[m++] = defgrad0[i][5]; + buf[m++] = defgrad0[i][6]; + buf[m++] = defgrad0[i][7]; + buf[m++] = defgrad0[i][8]; + + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +void FixSMD_TLSPH_ReferenceConfiguration::unpack_forward_comm(int n, int first, double *buf) { + int i, m, last; + double *radius = atom->radius; + double *vfrac = atom->vfrac; + double **x0 = atom->x0; + double **defgrad0 = atom->smd_data_9; + + m = 0; + last = first + n; + for (i = first; i < last; i++) { + x0[i][0] = buf[m++]; + x0[i][1] = buf[m++]; + x0[i][2] = buf[m++]; + + vfrac[i] = buf[m++]; + radius[i] = buf[m++]; + + defgrad0[i][0] = buf[m++]; + defgrad0[i][1] = buf[m++]; + defgrad0[i][2] = buf[m++]; + defgrad0[i][3] = buf[m++]; + defgrad0[i][4] = buf[m++]; + defgrad0[i][5] = buf[m++]; + defgrad0[i][6] = buf[m++]; + defgrad0[i][7] = buf[m++]; + defgrad0[i][8] = buf[m++]; + } +} + +/* ---------------------------------------------------------------------- + routine for excluding bonds across a hardcoded slit crack + Note that everything is scaled by lattice constant l0 to avoid + numerical inaccuracies. + ------------------------------------------------------------------------- */ + +bool FixSMD_TLSPH_ReferenceConfiguration::crack_exclude(int i, int j) { + + double **x = atom->x; + double l0 = domain->lattice->xlattice; + + // line between pair of atoms i,j + double x1 = x[i][0] / l0; + double y1 = x[i][1] / l0; + + double x2 = x[j][0] / l0; + double y2 = x[j][1] / l0; + + // hardcoded crack line + double x3 = -0.1 / l0; + double y3 = ((int) 1.0 / l0) + 0.5; + //printf("y3 = %f\n", y3); + double x4 = 0.1 / l0 - 1.0 + 0.1; + double y4 = y3; + + bool retVal = DoLineSegmentsIntersect(x1, y1, x2, y2, x3, y3, x4, y4); + + return !retVal; + //return 1; +} + diff --git a/src/USER-SMD/fix_smd_tlsph_reference_configuration.h b/src/USER-SMD/fix_smd_tlsph_reference_configuration.h new file mode 100644 index 0000000000..ede06151ee --- /dev/null +++ b/src/USER-SMD/fix_smd_tlsph_reference_configuration.h @@ -0,0 +1,86 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * This file is based on the FixShearHistory class. + * + * ----------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + + +#ifdef FIX_CLASS + +FixStyle(SMD_TLSPH_NEIGHBORS,FixSMD_TLSPH_ReferenceConfiguration) + +#else + +#ifndef LMP_FIX_SMD_TLSPH_REFERENCE_H +#define LMP_FIX_SMD_TLSPH_REFERENCE_H + +#include "fix.h" +#include "my_page.h" + +namespace LAMMPS_NS { + +class FixSMD_TLSPH_ReferenceConfiguration: public Fix { + friend class Neighbor; + friend class PairTlsph; + +public: + FixSMD_TLSPH_ReferenceConfiguration(class LAMMPS *, int, char **); + ~FixSMD_TLSPH_ReferenceConfiguration(); + int setmask(); + void init(); + void setup(int); + void pre_exchange(); + int pack_forward_comm(int, int *, double *, int, int *); + void unpack_forward_comm(int, int, double *); + + double memory_usage(); + void grow_arrays(int); + void copy_arrays(int, int, int); + int pack_exchange(int, double *); + int unpack_exchange(int, double *); + int pack_restart(int, double *); + void unpack_restart(int, int); + int size_restart(int); + int maxsize_restart(); + + bool crack_exclude(int i, int j); + bool get_line_intersection(int i, int j); + +protected: + int updateFlag; // flag to update reference configuration + int nmax; + int maxpartner; + int *npartner; // # of touching partners of each atom + tagint **partner; // global atom IDs for the partners + float **wfd_list, **wf_list, **energy_per_bond; + float **degradation_ij; // per-pair interaction degradation status + + class Pair *pair; + +}; + +} + +#endif +#endif + diff --git a/src/USER-SMD/fix_smd_wall_surface.cpp b/src/USER-SMD/fix_smd_wall_surface.cpp new file mode 100644 index 0000000000..16bd1c7809 --- /dev/null +++ b/src/USER-SMD/fix_smd_wall_surface.cpp @@ -0,0 +1,507 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing authors: Mike Parks (SNL), Ezwanur Rahman, J.T. Foster (UTSA) + ------------------------------------------------------------------------- */ + +#include "math.h" +#include "fix_smd_wall_surface.h" +#include "atom.h" +#include "domain.h" +#include "force.h" +#include "comm.h" +#include "update.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "neigh_request.h" +#include "pair.h" +#include "lattice.h" +#include "memory.h" +#include "error.h" +#include +#include +#include +#include "atom_vec.h" + +using namespace LAMMPS_NS; +using namespace FixConst; +using namespace Eigen; +using namespace std; +#define DELTA 16384 +#define EPSILON 1.0e-6 +enum { + LAYOUT_UNIFORM, LAYOUT_NONUNIFORM, LAYOUT_TILED +}; +// several files + +/* ---------------------------------------------------------------------- */ + +FixSMDWallSurface::FixSMDWallSurface(LAMMPS *lmp, int narg, char **arg) : + Fix(lmp, narg, arg) { + + restart_global = 0; + restart_peratom = 0; + first = 1; + + //atom->add_callback(0); + //atom->add_callback(1); + + if (narg != 6) + error->all(FLERR, "Illegal number of arguments for fix smd/wall_surface"); + + filename.assign(arg[3]); + wall_particle_type = force->inumeric(FLERR, arg[4]); + wall_molecule_id = force->inumeric(FLERR, arg[5]); + if (wall_molecule_id < 65535) { + error->one(FLERR, "wall molcule id must be >= 65535\n"); + } + + if (comm->me == 0) { + printf("\n>>========>>========>>========>>========>>========>>========>>========>>========\n"); + printf("fix smd/wall_surface reads trianglulated surface from file: %s\n", filename.c_str()); + printf("fix smd/wall_surface has particle type %d \n", wall_particle_type); + printf("fix smd/wall_surface has molecule id %d \n", wall_molecule_id); + printf(">>========>>========>>========>>========>>========>>========>>========>>========\n"); + } +} + +/* ---------------------------------------------------------------------- */ + +FixSMDWallSurface::~FixSMDWallSurface() { + // unregister this fix so atom class doesn't invoke it any more + + //atom->delete_callback(id, 0); + //atom->delete_callback(id, 1); +} + +/* ---------------------------------------------------------------------- */ + +int FixSMDWallSurface::setmask() { + int mask = 0; + return mask; +} + +/* ---------------------------------------------------------------------- */ + +void FixSMDWallSurface::init() { + if (!first) + return; +} + +/* ---------------------------------------------------------------------- + For minimization: setup as with dynamics + ------------------------------------------------------------------------- */ + +void FixSMDWallSurface::min_setup(int vflag) { + setup(vflag); +} + +/* ---------------------------------------------------------------------- + create initial list of neighbor partners via call to neighbor->build() + must be done in setup (not init) since fix init comes before neigh init + ------------------------------------------------------------------------- */ + +void FixSMDWallSurface::setup(int vflag) { + + if (!first) + return; + first = 0; + + // set bounds for my proc + // if periodic and I am lo/hi proc, adjust bounds by EPSILON + // insures all data atoms will be owned even with round-off + + int triclinic = domain->triclinic; + + double epsilon[3]; + if (triclinic) + epsilon[0] = epsilon[1] = epsilon[2] = EPSILON; + else { + epsilon[0] = domain->prd[0] * EPSILON; + epsilon[1] = domain->prd[1] * EPSILON; + epsilon[2] = domain->prd[2] * EPSILON; + } + + if (triclinic == 0) { + sublo[0] = domain->sublo[0]; + subhi[0] = domain->subhi[0]; + sublo[1] = domain->sublo[1]; + subhi[1] = domain->subhi[1]; + sublo[2] = domain->sublo[2]; + subhi[2] = domain->subhi[2]; + } else { + sublo[0] = domain->sublo_lamda[0]; + subhi[0] = domain->subhi_lamda[0]; + sublo[1] = domain->sublo_lamda[1]; + subhi[1] = domain->subhi_lamda[1]; + sublo[2] = domain->sublo_lamda[2]; + subhi[2] = domain->subhi_lamda[2]; + } + + if (comm->layout != LAYOUT_TILED) { + if (domain->xperiodic) { + if (comm->myloc[0] == 0) + sublo[0] -= epsilon[0]; + if (comm->myloc[0] == comm->procgrid[0] - 1) + subhi[0] += epsilon[0]; + } + if (domain->yperiodic) { + if (comm->myloc[1] == 0) + sublo[1] -= epsilon[1]; + if (comm->myloc[1] == comm->procgrid[1] - 1) + subhi[1] += epsilon[1]; + } + if (domain->zperiodic) { + if (comm->myloc[2] == 0) + sublo[2] -= epsilon[2]; + if (comm->myloc[2] == comm->procgrid[2] - 1) + subhi[2] += epsilon[2]; + } + + } else { + if (domain->xperiodic) { + if (comm->mysplit[0][0] == 0.0) + sublo[0] -= epsilon[0]; + if (comm->mysplit[0][1] == 1.0) + subhi[0] += epsilon[0]; + } + if (domain->yperiodic) { + if (comm->mysplit[1][0] == 0.0) + sublo[1] -= epsilon[1]; + if (comm->mysplit[1][1] == 1.0) + subhi[1] += epsilon[1]; + } + if (domain->zperiodic) { + if (comm->mysplit[2][0] == 0.0) + sublo[2] -= epsilon[2]; + if (comm->mysplit[2][1] == 1.0) + subhi[2] += epsilon[2]; + } + } + + read_triangles(0); +} + +/* ---------------------------------------------------------------------- + function to determine number of values in a text line + ------------------------------------------------------------------------- */ + +int FixSMDWallSurface::count_words(const char *line) { + int n = strlen(line) + 1; + char *copy; + memory->create(copy, n, "atom:copy"); + strcpy(copy, line); + + char *ptr; + if ((ptr = strchr(copy, '#'))) + *ptr = '\0'; + + if (strtok(copy, " \t\n\r\f") == NULL) { + memory->destroy(copy); + return 0; + } + n = 1; + while (strtok(NULL, " \t\n\r\f")) + n++; + + memory->destroy(copy); + return n; +} + +/* ---------------------------------------------------------------------- + size of atom nlocal's restart data + ------------------------------------------------------------------------- */ + +void FixSMDWallSurface::read_triangles(int pass) { + + double coord[3]; + + int nlocal_previous = atom->nlocal; + int ilocal = nlocal_previous; + int m; + int me; + + bigint natoms_previous = atom->natoms; + Vector3d *vert; + vert = new Vector3d[3]; + Vector3d normal, center; + + FILE *fp = fopen(filename.c_str(), "r"); + if (fp == NULL) { + char str[128]; + sprintf(str, "Cannot open file %s", filename.c_str()); + error->one(FLERR, str); + } + + MPI_Comm_rank(world, &me); + if (me == 0) { + if (screen) { + if (pass == 0) { + printf("\n>>========>>========>>========>>========>>========>>========>>========>>========\n"); + fprintf(screen, " scanning triangle pairs ...\n"); + } else { + fprintf(screen, " reading triangle pairs ...\n"); + } + } + if (logfile) { + if (pass == 0) { + fprintf(logfile, " scanning triangle pairs ...\n"); + } else { + fprintf(logfile, " reading triangle pairs ...\n"); + } + } + } + + char str[128]; + char line[256]; + char *retpointer; + char **values; + int nwords; + + // read STL solid name + retpointer = fgets(line, sizeof(line), fp); + if (retpointer == NULL) { + sprintf(str, "error reading number of triangle pairs"); + error->one(FLERR, str); + } + + nwords = count_words(line); + if (nwords < 1) { + sprintf(str, "first line of file is incorrect"); + error->one(FLERR, str); + } + +// values = new char*[nwords]; +// values[0] = strtok(line, " \t\n\r\f"); +// if (values[0] == NULL) +// error->all(FLERR, "Incorrect atom format in data file"); +// for (m = 1; m < nwords; m++) { +// values[m] = strtok(NULL, " \t\n\r\f"); +// if (values[m] == NULL) +// error->all(FLERR, "Incorrect atom format in data file"); +// } +// delete[] values; +// +// if (comm->me == 0) { +// cout << "STL file contains solid body with name: " << values[1] << endl; +// } + + // iterate over STL facets util end of body is reached + + while (fgets(line, sizeof(line), fp)) { // read a line, should be the facet line + + // evaluate facet line + nwords = count_words(line); + if (nwords != 5) { + //sprintf(str, "found end solid line"); + //error->message(FLERR, str); + break; + } else { + // should be facet line + } + + values = new char*[nwords]; + values[0] = strtok(line, " \t\n\r\f"); + if (values[0] == NULL) + error->all(FLERR, "Incorrect atom format in data file"); + for (m = 1; m < nwords; m++) { + values[m] = strtok(NULL, " \t\n\r\f"); + if (values[m] == NULL) + error->all(FLERR, "Incorrect atom format in data file"); + } + + normal << force->numeric(FLERR, values[2]), force->numeric(FLERR, values[3]), force->numeric(FLERR, values[4]); + //cout << "normal is " << normal << endl; + + delete[] values; + + // read outer loop line + retpointer = fgets(line, sizeof(line), fp); + if (retpointer == NULL) { + sprintf(str, "error reading outer loop"); + error->one(FLERR, str); + } + + nwords = count_words(line); + if (nwords != 2) { + sprintf(str, "error reading outer loop"); + error->one(FLERR, str); + } + + // read vertex lines + + for (int k = 0; k < 3; k++) { + retpointer = fgets(line, sizeof(line), fp); + if (retpointer == NULL) { + sprintf(str, "error reading vertex line"); + error->one(FLERR, str); + } + + nwords = count_words(line); + if (nwords != 4) { + sprintf(str, "error reading vertex line"); + error->one(FLERR, str); + } + + values = new char*[nwords]; + values[0] = strtok(line, " \t\n\r\f"); + if (values[0] == NULL) + error->all(FLERR, "Incorrect vertex line"); + for (m = 1; m < nwords; m++) { + values[m] = strtok(NULL, " \t\n\r\f"); + if (values[m] == NULL) + error->all(FLERR, "Incorrect vertex line"); + } + + vert[k] << force->numeric(FLERR, values[1]), force->numeric(FLERR, values[2]), force->numeric(FLERR, values[3]); + //cout << "vertex is " << vert[k] << endl; + //printf("%s %s %s\n", values[1], values[2], values[3]); + delete[] values; + //exit(1); + + } + + // read end loop line + retpointer = fgets(line, sizeof(line), fp); + if (retpointer == NULL) { + sprintf(str, "error reading endloop"); + error->one(FLERR, str); + } + + nwords = count_words(line); + if (nwords != 1) { + sprintf(str, "error reading endloop"); + error->one(FLERR, str); + } + + // read end facet line + retpointer = fgets(line, sizeof(line), fp); + if (retpointer == NULL) { + sprintf(str, "error reading endfacet"); + error->one(FLERR, str); + } + + nwords = count_words(line); + if (nwords != 1) { + sprintf(str, "error reading endfacet"); + error->one(FLERR, str); + } + + // now we have a normal and three vertices ... proceed with adding triangle + + center = (vert[0] + vert[1] + vert[2]) / 3.0; + + // cout << "center is " << center << endl; + + double r1 = (center - vert[0]).norm(); + double r2 = (center - vert[1]).norm(); + double r3 = (center - vert[2]).norm(); + double r = MAX(r1, r2); + r = MAX(r, r3); + + /* + * if atom/molecule is in my subbox, create it + * ... use x0 to hold triangle normal. + * ... use smd_data_9 to hold the three vertices + * ... use x to hold triangle center + * ... radius is the mmaximal distance from triangle center to all vertices + */ + + // printf("coord: %f %f %f\n", coord[0], coord[1], coord[2]); + // printf("sublo: %f %f %f\n", sublo[0], sublo[1], sublo[2]); + // printf("subhi: %f %f %f\n", subhi[0], subhi[1], subhi[2]); + //printf("ilocal = %d\n", ilocal); + if (center(0) >= sublo[0] && center(0) < subhi[0] && center(1) >= sublo[1] && center(1) < subhi[1] && center(2) >= sublo[2] + && center(2) < subhi[2]) { + //printf("******* KERATIN nlocal=%d ***\n", nlocal); + coord[0] = center(0); + coord[1] = center(1); + coord[2] = center(2); + atom->avec->create_atom(wall_particle_type, coord); + + /* + * need to initialize pointers to atom vec arrays here, because they could have changed + * due to calling grow() in create_atoms() above; + */ + + int *mol = atom->molecule; + int *type = atom->type; + double *radius = atom->radius; + double *contact_radius = atom->contact_radius; + double **smd_data_9 = atom->smd_data_9; + double **x0 = atom->x0; + + radius[ilocal] = r; //ilocal; + contact_radius[ilocal] = r; //ilocal; + mol[ilocal] = wall_molecule_id; + type[ilocal] = wall_particle_type; + x0[ilocal][0] = normal(0); + x0[ilocal][1] = normal(1); + x0[ilocal][2] = normal(2); + smd_data_9[ilocal][0] = vert[0](0); + smd_data_9[ilocal][1] = vert[0](1); + smd_data_9[ilocal][2] = vert[0](2); + smd_data_9[ilocal][3] = vert[1](0); + smd_data_9[ilocal][4] = vert[1](1); + smd_data_9[ilocal][5] = vert[1](2); + smd_data_9[ilocal][6] = vert[2](0); + smd_data_9[ilocal][7] = vert[2](1); + smd_data_9[ilocal][8] = vert[2](2); + + ilocal++; + } + + } + +// set new total # of atoms and error check + + bigint nblocal = atom->nlocal; + MPI_Allreduce(&nblocal, &atom->natoms, 1, MPI_LMP_BIGINT, MPI_SUM, world); + if (atom->natoms < 0 || atom->natoms >= MAXBIGINT) + error->all(FLERR, "Too many total atoms"); + +// add IDs for newly created atoms +// check that atom IDs are valid + + if (atom->tag_enable) + atom->tag_extend(); + atom->tag_check(); + +// create global mapping of atoms +// zero nghost in case are adding new atoms to existing atoms + + if (atom->map_style) { + atom->nghost = 0; + atom->map_init(); + atom->map_set(); + } + +// print status + if (comm->me == 0) { + if (screen) { + printf("... fix smd/wall_surface finished reading triangulated surface\n"); + fprintf(screen, "fix smd/wall_surface created " BIGINT_FORMAT " atoms\n", atom->natoms - natoms_previous); + printf(">>========>>========>>========>>========>>========>>========>>========>>========\n"); + } + if (logfile) { + fprintf(logfile, "... fix smd/wall_surface finished reading triangulated surface\n"); + fprintf(logfile, "fix smd/wall_surface created " BIGINT_FORMAT " atoms\n", atom->natoms - natoms_previous); + fprintf(logfile, ">>========>>========>>========>>========>>========>>========>>========>>========\n"); + } + } + + delete[] vert; + fclose(fp); +} + diff --git a/src/USER-SMD/fix_smd_wall_surface.h b/src/USER-SMD/fix_smd_wall_surface.h new file mode 100644 index 0000000000..32fb934d63 --- /dev/null +++ b/src/USER-SMD/fix_smd_wall_surface.h @@ -0,0 +1,53 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +#ifdef FIX_CLASS + +FixStyle(smd/wall_surface,FixSMDWallSurface) + +#else + +#ifndef LMP_FIX_SMD_WALL_SURFACE_H +#define LMP_FIX_SMD_WALL_SURFACE_H + +#include "fix.h" +#include +using namespace std; + +namespace LAMMPS_NS { + +class FixSMDWallSurface: public Fix { + +public: + FixSMDWallSurface(class LAMMPS *, int, char **); + virtual ~FixSMDWallSurface(); + int setmask(); + void init(); + void setup(int); + void min_setup(int); + + int count_words(const char *line); + void read_triangles(int pass); + +private: + int first; // flag for first time initialization + double sublo[3], subhi[3]; // epsilon-extended proc sub-box for adding atoms; + std::string filename; + int wall_particle_type; + int wall_molecule_id; +}; +} + +#endif +#endif + diff --git a/src/USER-SMD/pair_smd_hertz.cpp b/src/USER-SMD/pair_smd_hertz.cpp new file mode 100644 index 0000000000..b39ea946c0 --- /dev/null +++ b/src/USER-SMD/pair_smd_hertz.cpp @@ -0,0 +1,385 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing author: Mike Parks (SNL) + ------------------------------------------------------------------------- */ + +#include "math.h" +#include "float.h" +#include "stdlib.h" +#include "string.h" +#include "pair_smd_hertz.h" +#include "atom.h" +#include "domain.h" +#include "force.h" +#include "update.h" +#include "modify.h" +#include "fix.h" +#include "comm.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "neigh_request.h" +#include "memory.h" +#include "error.h" + +using namespace LAMMPS_NS; + +#define SQRT2 1.414213562e0 + +/* ---------------------------------------------------------------------- */ + +PairHertz::PairHertz(LAMMPS *lmp) : + Pair(lmp) { + + onerad_dynamic = onerad_frozen = maxrad_dynamic = maxrad_frozen = NULL; + bulkmodulus = NULL; + kn = NULL; + scale = 1.0; +} + +/* ---------------------------------------------------------------------- */ + +PairHertz::~PairHertz() { + + if (allocated) { + memory->destroy(setflag); + memory->destroy(cutsq); + memory->destroy(bulkmodulus); + memory->destroy(kn); + + delete[] onerad_dynamic; + delete[] onerad_frozen; + delete[] maxrad_dynamic; + delete[] maxrad_frozen; + } +} + +/* ---------------------------------------------------------------------- */ + +void PairHertz::compute(int eflag, int vflag) { + int i, j, ii, jj, inum, jnum, itype, jtype; + double xtmp, ytmp, ztmp, delx, dely, delz; + double rsq, r, evdwl, fpair; + int *ilist, *jlist, *numneigh, **firstneigh; + double rcut, r_geom, delta, ri, rj, dt_crit; + double *rmass = atom->rmass; + + evdwl = 0.0; + if (eflag || vflag) + ev_setup(eflag, vflag); + else + evflag = vflag_fdotr = 0; + + double **f = atom->f; + double **x = atom->x; + double **x0 = atom->x0; + int *type = atom->type; + int nlocal = atom->nlocal; + double *radius = atom->contact_radius; + double *sph_radius = atom->radius; + double rcutSq; + double delx0, dely0, delz0, rSq0, sphCut; + + int newton_pair = force->newton_pair; + int periodic = (domain->xperiodic || domain->yperiodic || domain->zperiodic); + + inum = list->inum; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + + stable_time_increment = 1.0e22; + + // loop over neighbors of my atoms + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; + itype = type[i]; + ri = scale * radius[i]; + jlist = firstneigh[i]; + jnum = numneigh[i]; + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + j &= NEIGHMASK; + + jtype = type[j]; + + delx = xtmp - x[j][0]; + dely = ytmp - x[j][1]; + delz = ztmp - x[j][2]; + + rsq = delx * delx + dely * dely + delz * delz; + + rj = scale * radius[j]; + rcut = ri + rj; + rcutSq = rcut * rcut; + + if (rsq < rcutSq) { + + /* + * self contact option: + * if pair of particles was initially close enough to interact via a bulk continuum mechanism (e.g. SPH), exclude pair from contact forces. + * this approach should work well if no updates of the reference configuration are performed. + */ + + if (itype == jtype) { + delx0 = x0[j][0] - x0[i][0]; + dely0 = x0[j][1] - x0[i][1]; + delz0 = x0[j][2] - x0[i][2]; + if (periodic) { + domain->minimum_image(delx0, dely0, delz0); + } + rSq0 = delx0 * delx0 + dely0 * dely0 + delz0 * delz0; // initial distance + sphCut = sph_radius[i] + sph_radius[j]; + if (rSq0 < sphCut * sphCut) { + rcut = 0.5 * rcut; + rcutSq = rcut * rcut; + if (rsq > rcutSq) { + continue; + } + } + } + + r = sqrt(rsq); + //printf("hertz interaction, r=%f, cut=%f, h=%f\n", r, rcut, sqrt(rSq0)); + + // Hertzian short-range forces + delta = rcut - r; // overlap distance + r_geom = ri * rj / rcut; + //assuming poisson ratio = 1/4 for 3d + fpair = 1.066666667e0 * bulkmodulus[itype][jtype] * delta * sqrt(delta * r_geom); // units: N + evdwl = fpair * 0.4e0 * delta; // GCG 25 April: this expression conserves total energy + dt_crit = 3.14 * sqrt(0.5 * (rmass[i] + rmass[j]) / (fpair / delta)); + + stable_time_increment = MIN(stable_time_increment, dt_crit); + if (r > 2.0e-16) { + fpair /= r; // divide by r and multiply with non-normalized distance vector + } else { + fpair = 0.0; + } + + /* + * contact viscosity -- needs to be done, see GRANULAR package for normal & shear damping + * for now: no damping and thus no viscous energy deltaE + */ + + if (evflag) { + ev_tally(i, j, nlocal, newton_pair, evdwl, 0.0, fpair, delx, dely, delz); + } + + f[i][0] += delx * fpair; + f[i][1] += dely * fpair; + f[i][2] += delz * fpair; + + if (newton_pair || j < nlocal) { + f[j][0] -= delx * fpair; + f[j][1] -= dely * fpair; + f[j][2] -= delz * fpair; + } + + } + } + } + +// double stable_time_increment_all = 0.0; +// MPI_Allreduce(&stable_time_increment, &stable_time_increment_all, 1, MPI_DOUBLE, MPI_MIN, world); +// if (comm->me == 0) { +// printf("stable time step for pair smd/hertz is %f\n", stable_time_increment_all); +// } +} + +/* ---------------------------------------------------------------------- + allocate all arrays + ------------------------------------------------------------------------- */ + +void PairHertz::allocate() { + allocated = 1; + int n = atom->ntypes; + + memory->create(setflag, n + 1, n + 1, "pair:setflag"); + for (int i = 1; i <= n; i++) + for (int j = i; j <= n; j++) + setflag[i][j] = 0; + + memory->create(bulkmodulus, n + 1, n + 1, "pair:kspring"); + memory->create(kn, n + 1, n + 1, "pair:kn"); + + memory->create(cutsq, n + 1, n + 1, "pair:cutsq"); // always needs to be allocated, even with granular neighborlist + + onerad_dynamic = new double[n + 1]; + onerad_frozen = new double[n + 1]; + maxrad_dynamic = new double[n + 1]; + maxrad_frozen = new double[n + 1]; +} + +/* ---------------------------------------------------------------------- + global settings + ------------------------------------------------------------------------- */ + +void PairHertz::settings(int narg, char **arg) { + if (narg != 1) + error->all(FLERR, "Illegal number of args for pair_style hertz"); + + scale = force->numeric(FLERR, arg[0]); + if (comm->me == 0) { + printf("\n>>========>>========>>========>>========>>========>>========>>========>>========\n"); + printf("SMD/HERTZ CONTACT SETTINGS:\n"); + printf("... effective contact radius is scaled by %f\n", scale); + printf(">>========>>========>>========>>========>>========>>========>>========>>========\n"); + } + +} + +/* ---------------------------------------------------------------------- + set coeffs for one or more type pairs + ------------------------------------------------------------------------- */ + +void PairHertz::coeff(int narg, char **arg) { + if (narg != 3) + error->all(FLERR, "Incorrect args for pair coefficients"); + if (!allocated) + allocate(); + + int ilo, ihi, jlo, jhi; + force->bounds(arg[0], atom->ntypes, ilo, ihi); + force->bounds(arg[1], atom->ntypes, jlo, jhi); + + double bulkmodulus_one = atof(arg[2]); + + // set short-range force constant + double kn_one = 0.0; + if (domain->dimension == 3) { + kn_one = (16. / 15.) * bulkmodulus_one; //assuming poisson ratio = 1/4 for 3d + } else { + kn_one = 0.251856195 * (2. / 3.) * bulkmodulus_one; //assuming poisson ratio = 1/3 for 2d + } + + int count = 0; + for (int i = ilo; i <= ihi; i++) { + for (int j = MAX(jlo, i); j <= jhi; j++) { + bulkmodulus[i][j] = bulkmodulus_one; + kn[i][j] = kn_one; + setflag[i][j] = 1; + count++; + } + } + + if (count == 0) + error->all(FLERR, "Incorrect args for pair coefficients"); +} + +/* ---------------------------------------------------------------------- + init for one type pair i,j and corresponding j,i + ------------------------------------------------------------------------- */ + +double PairHertz::init_one(int i, int j) { + + if (!allocated) + allocate(); + + if (setflag[i][j] == 0) + error->all(FLERR, "All pair coeffs are not set"); + + bulkmodulus[j][i] = bulkmodulus[i][j]; + kn[j][i] = kn[i][j]; + + // cutoff = sum of max I,J radii for + // dynamic/dynamic & dynamic/frozen interactions, but not frozen/frozen + + double cutoff = maxrad_dynamic[i] + maxrad_dynamic[j]; + cutoff = MAX(cutoff, maxrad_frozen[i] + maxrad_dynamic[j]); + cutoff = MAX(cutoff, maxrad_dynamic[i] + maxrad_frozen[j]); + + if (comm->me == 0) { + printf("cutoff for pair smd/hertz = %f\n", cutoff); + } + return cutoff; +} + +/* ---------------------------------------------------------------------- + init specific to this pair style + ------------------------------------------------------------------------- */ + +void PairHertz::init_style() { + int i; + + // error checks + + if (!atom->contact_radius_flag) + error->all(FLERR, "Pair style smd/hertz requires atom style with contact_radius"); + + int irequest = neighbor->request(this); + neighbor->requests[irequest]->half = 0; + neighbor->requests[irequest]->gran = 1; + + // set maxrad_dynamic and maxrad_frozen for each type + // include future Fix pour particles as dynamic + + for (i = 1; i <= atom->ntypes; i++) + onerad_dynamic[i] = onerad_frozen[i] = 0.0; + + double *radius = atom->radius; + int *type = atom->type; + int nlocal = atom->nlocal; + + for (i = 0; i < nlocal; i++) { + onerad_dynamic[type[i]] = MAX(onerad_dynamic[type[i]], radius[i]); + } + + MPI_Allreduce(&onerad_dynamic[1], &maxrad_dynamic[1], atom->ntypes, MPI_DOUBLE, MPI_MAX, world); + MPI_Allreduce(&onerad_frozen[1], &maxrad_frozen[1], atom->ntypes, MPI_DOUBLE, MPI_MAX, world); +} + +/* ---------------------------------------------------------------------- + neighbor callback to inform pair style of neighbor list to use + optional granular history list + ------------------------------------------------------------------------- */ + +void PairHertz::init_list(int id, NeighList *ptr) { + if (id == 0) + list = ptr; +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based arrays + ------------------------------------------------------------------------- */ + +double PairHertz::memory_usage() { + + return 0.0; +} + +void *PairHertz::extract(const char *str, int &i) { + //printf("in PairTriSurf::extract\n"); + if (strcmp(str, "smd/hertz/stable_time_increment_ptr") == 0) { + return (void *) &stable_time_increment; + } + + return NULL; + +} diff --git a/src/USER-SMD/pair_smd_hertz.h b/src/USER-SMD/pair_smd_hertz.h new file mode 100644 index 0000000000..8a207709ad --- /dev/null +++ b/src/USER-SMD/pair_smd_hertz.h @@ -0,0 +1,69 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef PAIR_CLASS + +PairStyle(smd/hertz,PairHertz) + +#else + +#ifndef LMP_SMD_HERTZ_H +#define LMP_SMD_HERTZ_H + +#include "pair.h" + +namespace LAMMPS_NS { + +class PairHertz : public Pair { + public: + PairHertz(class LAMMPS *); + virtual ~PairHertz(); + virtual void compute(int, int); + void settings(int, char **); + void coeff(int, char **); + double init_one(int, int); + void init_style(); + void init_list(int, class NeighList *); + virtual double memory_usage(); + void *extract(const char *, int &); + + protected: + double **bulkmodulus; + double **kn; + + double *onerad_dynamic,*onerad_frozen; + double *maxrad_dynamic,*maxrad_frozen; + + double scale; + double stable_time_increment; // stable time step size + + void allocate(); +}; + +} + +#endif +#endif + diff --git a/src/USER-SMD/pair_smd_tlsph.cpp b/src/USER-SMD/pair_smd_tlsph.cpp new file mode 100644 index 0000000000..73adf2ed31 --- /dev/null +++ b/src/USER-SMD/pair_smd_tlsph.cpp @@ -0,0 +1,2165 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +#include "group.h" +#include "math.h" +#include "float.h" +#include "stdlib.h" +#include "string.h" +#include "pair_smd_tlsph.h" +#include "fix_smd_tlsph_reference_configuration.h" +#include "atom.h" +#include "domain.h" +#include "force.h" +#include "update.h" +#include "modify.h" +#include "fix.h" +#include "comm.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "neigh_request.h" +#include "memory.h" +#include "error.h" +#include +#include +#include "math_special.h" +#include +#include "update.h" +#include +#include +#include "smd_material_models.h" +#include "smd_kernels.h" +#include "smd_math.h" +using namespace SMD_Kernels; +using namespace Eigen; +using namespace std; +using namespace LAMMPS_NS; +using namespace SMD_Math; + +#define JAUMANN false +#define DETF_MIN 0.2 // maximum compression deformation allow +#define DETF_MAX 2.0 // maximum tension deformation allowed +#define TLSPH_DEBUG 0 +#define PLASTIC_STRAIN_AVERAGE_WINDOW 100.0 + +/* ---------------------------------------------------------------------- */ + +PairTlsph::PairTlsph(LAMMPS *lmp) : + Pair(lmp) { + + onerad_dynamic = onerad_frozen = maxrad_dynamic = maxrad_frozen = NULL; + + failureModel = NULL; + strengthModel = eos = NULL; + + nmax = 0; // make sure no atom on this proc such that initial memory allocation is correct + Fdot = Fincr = K = PK1 = NULL; + R = FincrInv = W = D = NULL; + detF = NULL; + smoothVelDifference = NULL; + numNeighsRefConfig = NULL; + CauchyStress = NULL; + hourglass_error = NULL; + Lookup = NULL; + particle_dt = NULL; + + updateFlag = 0; + first = true; + dtCFL = 0.0; // initialize dtCFL so it is set to safe value if extracted on zero-th timestep + + comm_forward = 22; // this pair style communicates 20 doubles to ghost atoms : PK1 tensor + F tensor + shepardWeight + fix_tlsph_reference_configuration = NULL; + + cut_comm = MAX(neighbor->cutneighmax, comm->cutghostuser); // cutoff radius within which ghost atoms are communicated. +} + +/* ---------------------------------------------------------------------- */ + +PairTlsph::~PairTlsph() { + //printf("in PairTlsph::~PairTlsph()\n"); + + if (allocated) { + memory->destroy(setflag); + memory->destroy(cutsq); + memory->destroy(strengthModel); + memory->destroy(eos); + memory->destroy(Lookup); + + delete[] onerad_dynamic; + delete[] onerad_frozen; + delete[] maxrad_dynamic; + delete[] maxrad_frozen; + + delete[] Fdot; + delete[] Fincr; + delete[] K; + delete[] detF; + delete[] PK1; + delete[] smoothVelDifference; + delete[] R; + delete[] FincrInv; + delete[] W; + delete[] D; + delete[] numNeighsRefConfig; + delete[] CauchyStress; + delete[] hourglass_error; + delete[] particle_dt; + + delete[] failureModel; + } +} + +/* ---------------------------------------------------------------------- + * + * use half neighbor list to re-compute shape matrix + * + ---------------------------------------------------------------------- */ + +void PairTlsph::PreCompute() { + int *mol = atom->molecule; + double *vfrac = atom->vfrac; + double *radius = atom->radius; + double **x0 = atom->x0; + double **x = atom->x; + double **v = atom->vest; // extrapolated velocities corresponding to current positions + double **vint = atom->v; // Velocity-Verlet algorithm velocities + double *damage = atom->damage; + int *tag = atom->tag; + int *type = atom->type; + int nlocal = atom->nlocal; + int jnum, jj, i, j, itype, idim; + + tagint **partner = ((FixSMD_TLSPH_ReferenceConfiguration *) modify->fix[ifix_tlsph])->partner; + int *npartner = ((FixSMD_TLSPH_ReferenceConfiguration *) modify->fix[ifix_tlsph])->npartner; + float **wfd_list = ((FixSMD_TLSPH_ReferenceConfiguration *) modify->fix[ifix_tlsph])->wfd_list; + float **wf_list = ((FixSMD_TLSPH_ReferenceConfiguration *) modify->fix[ifix_tlsph])->wf_list; + float **degradation_ij = ((FixSMD_TLSPH_ReferenceConfiguration *) modify->fix[ifix_tlsph])->degradation_ij; + double r0, r0Sq, wf, wfd, h, irad, voli, volj, scale, shepardWeight; + Vector3d dx, dx0, dv, g; + Matrix3d Ktmp, Ftmp, Fdottmp, L, U, eye; + Vector3d vi, vj, vinti, vintj, xi, xj, x0i, x0j, dvint; + int periodic = (domain->xperiodic || domain->yperiodic || domain->zperiodic); + bool status; + Matrix3d F0; + + eye.setIdentity(); + + for (i = 0; i < nlocal; i++) { + + itype = type[i]; + if (setflag[itype][itype] == 1) { + + K[i].setZero(); + Fincr[i].setZero(); + Fdot[i].setZero(); + numNeighsRefConfig[i] = 0; + smoothVelDifference[i].setZero(); + hourglass_error[i] = 0.0; + + if (mol[i] < 0) { // valid SPH particle have mol > 0 + continue; + } + + // initialize aveage mass density + h = 2.0 * radius[i]; + r0 = 0.0; + spiky_kernel_and_derivative(h, r0, domain->dimension, wf, wfd); + shepardWeight = wf * voli; + + jnum = npartner[i]; + irad = radius[i]; + voli = vfrac[i]; + + // initialize Eigen data structures from LAMMPS data structures + for (idim = 0; idim < 3; idim++) { + xi(idim) = x[i][idim]; + x0i(idim) = x0[i][idim]; + vi(idim) = v[i][idim]; + vinti(idim) = vint[i][idim]; + } + + for (jj = 0; jj < jnum; jj++) { + + if (partner[i][jj] == 0) + continue; + j = atom->map(partner[i][jj]); + if (j < 0) { // // check if lost a partner without first breaking bond + partner[i][jj] = 0; + continue; + } + + if (mol[j] < 0) { // particle has failed. do not include it for computing any property + continue; + } + + if (mol[i] != mol[j]) { + continue; + } + + // initialize Eigen data structures from LAMMPS data structures + for (idim = 0; idim < 3; idim++) { + xj(idim) = x[j][idim]; + x0j(idim) = x0[j][idim]; + vj(idim) = v[j][idim]; + vintj(idim) = vint[j][idim]; + } + dx0 = x0j - x0i; + dx = xj - xi; + + if (periodic) + domain->minimum_image(dx0(0), dx0(1), dx0(2)); + + r0Sq = dx0.squaredNorm(); + h = irad + radius[j]; + + r0 = sqrt(r0Sq); + volj = vfrac[j]; + + // distance vectors in current and reference configuration, velocity difference + dv = vj - vi; + dvint = vintj - vinti; + + // scale the interaction according to the damage variable + scale = 1.0 - degradation_ij[i][jj]; + wf = wf_list[i][jj] * scale; + wfd = wfd_list[i][jj] * scale; + g = (wfd / r0) * dx0; + + /* build matrices */ + Ktmp = -g * dx0.transpose(); + Fdottmp = -dv * g.transpose(); + Ftmp = -(dx - dx0) * g.transpose(); + + K[i] += volj * Ktmp; + Fdot[i] += volj * Fdottmp; + Fincr[i] += volj * Ftmp; + shepardWeight += volj * wf; + smoothVelDifference[i] += volj * wf * dvint; + numNeighsRefConfig[i]++; + } // end loop over j + + // normalize average velocity field around an integration point + if (shepardWeight > 0.0) { + smoothVelDifference[i] /= shepardWeight; + } else { + smoothVelDifference[i].setZero(); + } + + pseudo_inverse_SVD(K[i]); + Fdot[i] *= K[i]; + Fincr[i] *= K[i]; + Fincr[i] += eye; + + if (JAUMANN) { + R[i].setIdentity(); // for Jaumann stress rate, we do not need a subsequent rotation back into the reference configuration + } else { + status = PolDec(Fincr[i], R[i], U, false); // polar decomposition of the deformation gradient, F = R * U + if (!status) { + error->message(FLERR, "Polar decomposition of deformation gradient failed.\n"); + mol[i] = -1; + } else { + Fincr[i] = R[i] * U; + } + } + + detF[i] = Fincr[i].determinant(); + FincrInv[i] = Fincr[i].inverse(); + + // velocity gradient + L = Fdot[i] * FincrInv[i]; + + // symmetric (D) and asymmetric (W) parts of L + D[i] = 0.5 * (L + L.transpose()); + W[i] = 0.5 * (L - L.transpose()); // spin tensor:: need this for Jaumann rate + + // unrotated rate-of-deformation tensor d, see right side of Pronto2d, eqn.(2.1.7) + // convention: unrotated frame is that one, where the true rotation of an integration point has been subtracted. + // stress in the unrotated frame of reference is denoted sigma (stress seen by an observer doing rigid body rotations along with the material) + // stress in the true frame of reference (a stationary observer) is denoted by T, "true stress" + D[i] = (R[i].transpose() * D[i] * R[i]).eval(); + + // limit strain rate + //double limit = 1.0e-3 * Lookup[SIGNAL_VELOCITY][itype] / radius[i]; + //D[i] = LimitEigenvalues(D[i], limit); + + /* + * make sure F stays within some limits + */ + + if ((detF[i] < DETF_MIN) || (detF[i] > DETF_MAX) || (numNeighsRefConfig[i] == 0)) { + printf("deleting particle [%d] because det(F)=%f is outside stable range %f -- %f \n", tag[i], + Fincr[i].determinant(), + DETF_MIN, DETF_MAX); + printf("nn = %d, damage=%f\n", numNeighsRefConfig[i], damage[i]); + cout << "Here is matrix F:" << endl << Fincr[i] << endl; + cout << "Here is matrix F-1:" << endl << FincrInv[i] << endl; + cout << "Here is matrix K-1:" << endl << K[i] << endl; + cout << "Here is matrix K:" << endl << K[i].inverse() << endl; + cout << "Here is det of K" << endl << (K[i].inverse()).determinant() << endl; + cout << "Here is matrix R:" << endl << R[i] << endl; + cout << "Here is det of R" << endl << R[i].determinant() << endl; + cout << "Here is matrix U:" << endl << U << endl; + mol[i] = -1; + //error->one(FLERR, ""); + } + + if (mol[i] < 0) { + D[i].setZero(); + Fdot[i].setZero(); + Fincr[i].setIdentity(); + smoothVelDifference[i].setZero(); + detF[i] = 1.0; + K[i].setIdentity(); + + vint[i][0] = 0.0; + vint[i][1] = 0.0; + vint[i][2] = 0.0; + } + } // end loop over i + } // end check setflag +} + +/* ---------------------------------------------------------------------- */ + +void PairTlsph::compute(int eflag, int vflag) { + + if (atom->nmax > nmax) { + nmax = atom->nmax; + delete[] Fdot; + Fdot = new Matrix3d[nmax]; // memory usage: 9 doubles + delete[] Fincr; + Fincr = new Matrix3d[nmax]; // memory usage: 9 doubles + delete[] K; + K = new Matrix3d[nmax]; // memory usage: 9 doubles + delete[] PK1; + PK1 = new Matrix3d[nmax]; // memory usage: 9 doubles; total 5*9=45 doubles + delete[] detF; + detF = new double[nmax]; // memory usage: 1 double; total 46 doubles + delete[] smoothVelDifference; + smoothVelDifference = new Vector3d[nmax]; // memory usage: 3 doubles; total 49 doubles + delete[] R; + R = new Matrix3d[nmax]; // memory usage: 9 doubles; total 67 doubles + delete[] FincrInv; + FincrInv = new Matrix3d[nmax]; // memory usage: 9 doubles; total 85 doubles + delete[] W; + W = new Matrix3d[nmax]; // memory usage: 9 doubles; total 94 doubles + delete[] D; + D = new Matrix3d[nmax]; // memory usage: 9 doubles; total 103 doubles + delete[] numNeighsRefConfig; + numNeighsRefConfig = new int[nmax]; // memory usage: 1 int; total 108 doubles + delete[] CauchyStress; + CauchyStress = new Matrix3d[nmax]; // memory usage: 9 doubles; total 118 doubles + delete[] hourglass_error; + hourglass_error = new double[nmax]; + delete[] particle_dt; + particle_dt = new double[nmax]; + } + + if (first) { // return on first call, because reference connectivity lists still needs to be built. Also zero quantities which are otherwise undefined. + first = false; + + for (int i = 0; i < atom->nlocal; i++) { + Fincr[i].setZero(); + detF[i] = 0.0; + smoothVelDifference[i].setZero(); + D[i].setZero(); + numNeighsRefConfig[i] = 0; + CauchyStress[i].setZero(); + hourglass_error[i] = 0.0; + particle_dt[i] = 0.0; + } + + return; + } + + /* + * calculate deformations and rate-of-deformations + */ + PairTlsph::PreCompute(); + + /* + * calculate stresses from constitutive models + */ + PairTlsph::AssembleStress(); + + /* + * QUANTITIES ABOVE HAVE ONLY BEEN CALCULATED FOR NLOCAL PARTICLES. + * NEED TO DO A FORWARD COMMUNICATION TO GHOST ATOMS NOW + */ + comm->forward_comm_pair(this); + + /* + * compute forces between particles + */ + updateFlag = 0; + ComputeForces(eflag, vflag); +} + +void PairTlsph::ComputeForces(int eflag, int vflag) { + int *mol = atom->molecule; + double **x = atom->x; + double **v = atom->vest; + double **x0 = atom->x0; + double **f = atom->f; + double *vfrac = atom->vfrac; + double *de = atom->de; + double *rmass = atom->rmass; + double *radius = atom->radius; + double *damage = atom->damage; + double *plastic_strain = atom->eff_plastic_strain; + int *type = atom->type; + int nlocal = atom->nlocal; + int i, j, jj, jnum, itype, idim; + double r, hg_mag, wf, wfd, h, r0, r0Sq, voli, volj; + double delVdotDelR, visc_magnitude, deltaE, mu_ij, hg_err, gamma_dot_dx, delta, scale; + double strain1d, strain1d_max, softening_strain, shepardWeight; + char str[128]; + Vector3d fi, fj, dx0, dx, dv, f_stress, f_hg, dxp_i, dxp_j, gamma, g, gamma_i, gamma_j, x0i, x0j; + Vector3d xi, xj, vi, vj, f_visc, sumForces, f_spring; + int periodic = (domain->xperiodic || domain->yperiodic || domain->zperiodic); + + tagint **partner = ((FixSMD_TLSPH_ReferenceConfiguration *) modify->fix[ifix_tlsph])->partner; + int *npartner = ((FixSMD_TLSPH_ReferenceConfiguration *) modify->fix[ifix_tlsph])->npartner; + float **wfd_list = ((FixSMD_TLSPH_ReferenceConfiguration *) modify->fix[ifix_tlsph])->wfd_list; + float **wf_list = ((FixSMD_TLSPH_ReferenceConfiguration *) modify->fix[ifix_tlsph])->wf_list; + float **degradation_ij = ((FixSMD_TLSPH_ReferenceConfiguration *) modify->fix[ifix_tlsph])->degradation_ij; + float **energy_per_bond = ((FixSMD_TLSPH_ReferenceConfiguration *) modify->fix[ifix_tlsph])->energy_per_bond; + Matrix3d eye; + eye.setIdentity(); + + if (eflag || vflag) + ev_setup(eflag, vflag); + else + evflag = vflag_fdotr = 0; + + /* + * iterate over pairs of particles i, j and assign forces using PK1 stress tensor + */ + + //updateFlag = 0; + hMin = 1.0e22; + dtRelative = 1.0e22; + + for (i = 0; i < nlocal; i++) { + + if (mol[i] < 0) { + continue; // Particle i is not a valid SPH particle (anymore). Skip all interactions with this particle. + } + + itype = type[i]; + jnum = npartner[i]; + voli = vfrac[i]; + + // initialize aveage mass density + h = 2.0 * radius[i]; + r = 0.0; + spiky_kernel_and_derivative(h, r, domain->dimension, wf, wfd); + shepardWeight = wf * voli; + + for (idim = 0; idim < 3; idim++) { + x0i(idim) = x0[i][idim]; + xi(idim) = x[i][idim]; + vi(idim) = v[i][idim]; + } + + for (jj = 0; jj < jnum; jj++) { + if (partner[i][jj] == 0) + continue; + j = atom->map(partner[i][jj]); + if (j < 0) { // // check if lost a partner without first breaking bond + partner[i][jj] = 0; + continue; + } + + if (mol[j] < 0) { + continue; // Particle j is not a valid SPH particle (anymore). Skip all interactions with this particle. + } + + if (mol[i] != mol[j]) { + continue; + } + + if (type[j] != itype) { + sprintf(str, "particle pair is not of same type!"); + error->all(FLERR, str); + } + + for (idim = 0; idim < 3; idim++) { + x0j(idim) = x0[j][idim]; + xj(idim) = x[j][idim]; + vj(idim) = v[j][idim]; + } + + if (periodic) + domain->minimum_image(dx0(0), dx0(1), dx0(2)); + + // check that distance between i and j (in the reference config) is less than cutoff + dx0 = x0j - x0i; + r0Sq = dx0.squaredNorm(); + h = radius[i] + radius[j]; + hMin = MIN(hMin, h); + r0 = sqrt(r0Sq); + volj = vfrac[j]; + + // distance vectors in current and reference configuration, velocity difference + dx = xj - xi; + dv = vj - vi; + r = dx.norm(); // current distance + + // scale the interaction according to the damage variable + scale = 1.0 - degradation_ij[i][jj]; + wf = wf_list[i][jj] * scale; + wfd = wfd_list[i][jj] * scale; + + g = (wfd / r0) * dx0; // uncorrected kernel gradient + + /* + * force contribution -- note that the kernel gradient correction has been absorbed into PK1 + */ + + f_stress = -voli * volj * (PK1[i] + PK1[j]) * g; + + /* + * artificial viscosity + */ + delVdotDelR = dx.dot(dv) / (r + 0.1 * h); // project relative velocity onto unit particle distance vector [m/s] + LimitDoubleMagnitude(delVdotDelR, 0.01 * Lookup[SIGNAL_VELOCITY][itype]); + mu_ij = h * delVdotDelR / (r + 0.1 * h); // units: [m * m/s / m = m/s] + visc_magnitude = (-Lookup[VISCOSITY_Q1][itype] * Lookup[SIGNAL_VELOCITY][itype] * mu_ij + + Lookup[VISCOSITY_Q2][itype] * mu_ij * mu_ij) / Lookup[REFERENCE_DENSITY][itype]; // units: m^5/(s^2 kg)) + f_visc = rmass[i] * rmass[j] * visc_magnitude * wfd * dx / (r + 1.0e-2 * h); // units: kg^2 * m^5/(s^2 kg) * m^-4 = kg m / s^2 = N + + /* + * hourglass deviation of particles i and j + */ + + gamma = 0.5 * (Fincr[i] + Fincr[j]) * dx0 - dx; + hg_err = gamma.norm() / r0; + hourglass_error[i] += volj * wf * hg_err; + + /* SPH-like hourglass formulation */ + + if (MAX(plastic_strain[i], plastic_strain[j]) > 1.0e-3) { + /* + * viscous hourglass formulation for particles with plastic deformation + */ + delta = gamma.dot(dx); + if (delVdotDelR * delta < 0.0) { + hg_err = MAX(hg_err, 0.05); // limit hg_err to avoid numerical instabilities + hg_mag = -hg_err * Lookup[HOURGLASS_CONTROL_AMPLITUDE][itype] * Lookup[SIGNAL_VELOCITY][itype] * mu_ij + / Lookup[REFERENCE_DENSITY][itype]; // this has units of pressure + } else { + hg_mag = 0.0; + } + f_hg = rmass[i] * rmass[j] * hg_mag * wfd * dx / (r + 1.0e-2 * h); + + } else { + /* + * stiffness hourglass formulation for particle in the elastic regime + */ + + gamma_dot_dx = gamma.dot(dx); // project hourglass error vector onto pair distance vector + LimitDoubleMagnitude(gamma_dot_dx, 0.1 * r); // limit projected vector to avoid numerical instabilities + delta = 0.5 * gamma_dot_dx / (r + 0.1 * h); // delta has dimensions of [m] + hg_mag = Lookup[HOURGLASS_CONTROL_AMPLITUDE][itype] * delta / (r0Sq + 0.01 * h * h); // hg_mag has dimensions [m^(-1)] + hg_mag *= -voli * volj * wf * Lookup[YOUNGS_MODULUS][itype]; // hg_mag has dimensions [J*m^(-1)] = [N] + f_hg = (hg_mag / (r + 0.01 * h)) * dx; + } + + // scale hourglass force with damage + f_hg *= (1.0 - damage[i]) * (1.0 - damage[j]); + + // sum stress, viscous, and hourglass forces + sumForces = f_stress + f_visc + f_hg; // + f_spring; + + // energy rate -- project velocity onto force vector + deltaE = 0.5 * sumForces.dot(dv); + + // apply forces to pair of particles + f[i][0] += sumForces(0); + f[i][1] += sumForces(1); + f[i][2] += sumForces(2); + de[i] += deltaE; + + // tally atomistic stress tensor + if (evflag) { + ev_tally_xyz(i, j, nlocal, 0, 0.0, 0.0, sumForces(0), sumForces(1), sumForces(2), dx(0), dx(1), dx(2)); + } + + shepardWeight += wf * volj; + + // check if a particle has moved too much w.r.t another particle + if (r > r0) { + if (update_method == UPDATE_CONSTANT_THRESHOLD) { + if (r - r0 > update_threshold) { + updateFlag = 1; + } + } else if (update_method == UPDATE_PAIRWISE_RATIO) { + if ((r - r0) / h > update_threshold) { + updateFlag = 1; + } + } + } + + if (failureModel[itype].failure_max_pairwise_strain) { + + strain1d = (r - r0) / r0; + strain1d_max = Lookup[FAILURE_MAX_PAIRWISE_STRAIN_THRESHOLD][itype]; + softening_strain = 2.0 * strain1d_max; + + if (strain1d > strain1d_max) { + degradation_ij[i][jj] = (strain1d - strain1d_max) / softening_strain; + } else { + degradation_ij[i][jj] = 0.0; + } + + if (degradation_ij[i][jj] >= 1.0) { // delete interaction if fully damaged + partner[i][jj] = 0; + } + } + + if (failureModel[itype].failure_energy_release_rate) { + + // integration approach + energy_per_bond[i][jj] += update->dt * f_stress.dot(dv) / (voli * volj); + double Vic = (2.0 / 3.0) * h * h * h; // interaction volume for 2d plane strain + double critical_energy_per_bond = Lookup[CRITICAL_ENERGY_RELEASE_RATE][itype] / (2.0 * Vic); + + if (energy_per_bond[i][jj] > critical_energy_per_bond) { + //degradation_ij[i][jj] = 1.0; + partner[i][jj] = 0; + } + } + + if (failureModel[itype].integration_point_wise) { + + strain1d = (r - r0) / r0; + + if (strain1d > 0.0) { + + if ((damage[i] == 1.0) && (damage[j] == 1.0)) { + // check if damage_onset is already defined + if (energy_per_bond[i][jj] == 0.0) { // pair damage not defined yet + energy_per_bond[i][jj] = strain1d; + } else { // damage initiation strain already defined + strain1d_max = energy_per_bond[i][jj]; + softening_strain = 2.0 * strain1d_max; + + if (strain1d > strain1d_max) { + degradation_ij[i][jj] = (strain1d - strain1d_max) / softening_strain; + } else { + degradation_ij[i][jj] = 0.0; + } + } + } + + if (degradation_ij[i][jj] >= 1.0) { // delete interaction if fully damaged + partner[i][jj] = 0; + } + + } else { + degradation_ij[i][jj] = 0.0; + } // end failureModel[itype].integration_point_wise + + } + + } // end loop over jj neighbors of i + + if (shepardWeight != 0.0) { + hourglass_error[i] /= shepardWeight; + } + + } // end loop over i + + if (vflag_fdotr) + virial_fdotr_compute(); +} + +/* ---------------------------------------------------------------------- + assemble unrotated stress tensor using deviatoric and pressure components. + Convert to corotational Cauchy stress, then to PK1 stress and apply + shape matrix correction + ------------------------------------------------------------------------- */ +void PairTlsph::AssembleStress() { + int *mol = atom->molecule; + double *eff_plastic_strain = atom->eff_plastic_strain; + double *eff_plastic_strain_rate = atom->eff_plastic_strain_rate; + double **tlsph_stress = atom->smd_stress; + int *type = atom->type; + double *radius = atom->radius; + double *damage = atom->damage; + double *rmass = atom->rmass; + double *vfrac = atom->vfrac; + double *e = atom->e; + double pInitial, d_iso, pFinal, p_rate, plastic_strain_increment; + int i, itype; + int nlocal = atom->nlocal; + double dt = update->dt; + double M_eff, p_wave_speed, mass_specific_energy, vol_specific_energy, rho; + Matrix3d sigma_rate, eye, sigmaInitial, sigmaFinal, T, T_damaged, Jaumann_rate, sigma_rate_check; + Matrix3d d_dev, sigmaInitial_dev, sigmaFinal_dev, sigma_dev_rate, strain; + Vector3d x0i, xi, xp; + + eye.setIdentity(); + dtCFL = 1.0e22; + pFinal = 0.0; + + for (i = 0; i < nlocal; i++) { + particle_dt[i] = 0.0; + + itype = type[i]; + if (setflag[itype][itype] == 1) { + if (mol[i] > 0) { // only do the following if particle has not failed -- mol < 0 means particle has failed + + /* + * initial stress state: given by the unrotateted Cauchy stress. + * Assemble Eigen 3d matrix from stored stress state + */ + sigmaInitial(0, 0) = tlsph_stress[i][0]; + sigmaInitial(0, 1) = tlsph_stress[i][1]; + sigmaInitial(0, 2) = tlsph_stress[i][2]; + sigmaInitial(1, 1) = tlsph_stress[i][3]; + sigmaInitial(1, 2) = tlsph_stress[i][4]; + sigmaInitial(2, 2) = tlsph_stress[i][5]; + sigmaInitial(1, 0) = sigmaInitial(0, 1); + sigmaInitial(2, 0) = sigmaInitial(0, 2); + sigmaInitial(2, 1) = sigmaInitial(1, 2); + + //cout << "this is sigma initial" << endl << sigmaInitial << endl; + + pInitial = sigmaInitial.trace() / 3.0; // isotropic part of initial stress + sigmaInitial_dev = Deviator(sigmaInitial); + d_iso = D[i].trace(); // volumetric part of stretch rate + d_dev = Deviator(D[i]); // deviatoric part of stretch rate + strain = 0.5 * (Fincr[i].transpose() * Fincr[i] - eye); + mass_specific_energy = e[i] / rmass[i]; // energy per unit mass + rho = rmass[i] / (detF[i] * vfrac[i]); + vol_specific_energy = mass_specific_energy * rho; // energy per current volume + + /* + * pressure: compute pressure rate p_rate and final pressure pFinal + */ + + ComputePressure(i, rho, mass_specific_energy, vol_specific_energy, pInitial, d_iso, pFinal, p_rate); + + /* + * material strength + */ + + //cout << "this is the strain deviator rate" << endl << d_dev << endl; + ComputeStressDeviator(i, sigmaInitial_dev, d_dev, sigmaFinal_dev, sigma_dev_rate, plastic_strain_increment); + //cout << "this is the stress deviator rate" << endl << sigma_dev_rate << endl; + + // keep a rolling average of the plastic strain rate over the last 100 or so timesteps + eff_plastic_strain[i] += plastic_strain_increment; + + // compute a characteristic time over which to average the plastic strain + double tav = 1000 * radius[i] / (Lookup[SIGNAL_VELOCITY][itype]); + eff_plastic_strain_rate[i] -= eff_plastic_strain_rate[i] / tav; + eff_plastic_strain_rate[i] += (plastic_strain_increment / dt) / tav; + eff_plastic_strain_rate[i] = MAX(0.0, eff_plastic_strain_rate[i]); + + /* + * assemble total stress from pressure and deviatoric stress + */ + sigmaFinal = pFinal * eye + sigmaFinal_dev; // this is the stress that is kept + + if (JAUMANN) { + /* + * sigma is already the co-rotated Cauchy stress. + * The stress rate, however, needs to be made objective. + */ + + if (dt > 1.0e-16) { + sigma_rate = (1.0 / dt) * (sigmaFinal - sigmaInitial); + } else { + sigma_rate.setZero(); + } + + Jaumann_rate = sigma_rate + W[i] * sigmaInitial + sigmaInitial * W[i].transpose(); + sigmaFinal = sigmaInitial + dt * Jaumann_rate; + T = sigmaFinal; + } else { + /* + * sigma is the unrotated stress. + * need to do forward rotation of the unrotated stress sigma to the current configuration + */ + T = R[i] * sigmaFinal * R[i].transpose(); + } + + /* + * store unrotated stress in atom vector + * symmetry is exploited + */ + tlsph_stress[i][0] = sigmaFinal(0, 0); + tlsph_stress[i][1] = sigmaFinal(0, 1); + tlsph_stress[i][2] = sigmaFinal(0, 2); + tlsph_stress[i][3] = sigmaFinal(1, 1); + tlsph_stress[i][4] = sigmaFinal(1, 2); + tlsph_stress[i][5] = sigmaFinal(2, 2); + + /* + * Damage due to failure criteria. + */ + + if (failureModel[itype].integration_point_wise) { + ComputeDamage(i, strain, T, T_damaged); + //T = T_damaged; Do not do this, it is undefined as of now + } + + // store rotated, "true" Cauchy stress + CauchyStress[i] = T; + + /* + * We have the corotational Cauchy stress. + * Convert to PK1. Note that reference configuration used for computing the forces is linked via + * the incremental deformation gradient, not the full deformation gradient. + */ + PK1[i] = detF[i] * T * FincrInv[i].transpose(); + + /* + * pre-multiply stress tensor with shape matrix to save computation in force loop + */ + PK1[i] = PK1[i] * K[i]; + + /* + * compute stable time step according to Pronto 2d + */ + + Matrix3d deltaSigma; + deltaSigma = sigmaFinal - sigmaInitial; + p_rate = deltaSigma.trace() / (3.0 * dt + 1.0e-16); + sigma_dev_rate = Deviator(deltaSigma) / (dt + 1.0e-16); + + double K_eff, mu_eff; + effective_longitudinal_modulus(itype, dt, d_iso, p_rate, d_dev, sigma_dev_rate, damage[i], K_eff, mu_eff, M_eff); + p_wave_speed = sqrt(M_eff / rho); + + if (mol[i] < 0) { + error->one(FLERR, "this should not happen"); + } + + particle_dt[i] = 2.0 * radius[i] / p_wave_speed; + dtCFL = MIN(dtCFL, particle_dt[i]); + + } else { // end if mol > 0 + PK1[i].setZero(); + K[i].setIdentity(); + CauchyStress[i].setZero(); + sigma_rate.setZero(); + tlsph_stress[i][0] = 0.0; + tlsph_stress[i][1] = 0.0; + tlsph_stress[i][2] = 0.0; + tlsph_stress[i][3] = 0.0; + tlsph_stress[i][4] = 0.0; + tlsph_stress[i][5] = 0.0; + } // end if mol > 0 + } // end setflag + } // end for +} + +/* ---------------------------------------------------------------------- + allocate all arrays + ------------------------------------------------------------------------- */ + +void PairTlsph::allocate() { + allocated = 1; + int n = atom->ntypes; + + memory->create(setflag, n + 1, n + 1, "pair:setflag"); + for (int i = 1; i <= n; i++) + for (int j = i; j <= n; j++) + setflag[i][j] = 0; + + memory->create(strengthModel, n + 1, "pair:strengthmodel"); + memory->create(eos, n + 1, "pair:eosmodel"); + failureModel = new failure_types[n + 1]; + memory->create(Lookup, MAX_KEY_VALUE, n + 1, "pair:LookupTable"); + + memory->create(cutsq, n + 1, n + 1, "pair:cutsq"); // always needs to be allocated, even with granular neighborlist + + onerad_dynamic = new double[n + 1]; + onerad_frozen = new double[n + 1]; + maxrad_dynamic = new double[n + 1]; + maxrad_frozen = new double[n + 1]; + +} + +/* ---------------------------------------------------------------------- + global settings + ------------------------------------------------------------------------- */ + +void PairTlsph::settings(int narg, char **arg) { + + if (comm->me == 0) { + printf( + "\n>>========>>========>>========>>========>>========>>========>>========>>========>>========>>========>>========>>========\n"); + printf("TLSPH settings\n"); + } + + /* + * default value for update_threshold for updates of reference configuration: + * The maximum relative displacement which is tracked by the construction of LAMMPS' neighborlists + * is the folowing. + */ + + cut_comm = MAX(neighbor->cutneighmax, comm->cutghostuser); // cutoff radius within which ghost atoms are communicated. + update_threshold = cut_comm; + update_method = UPDATE_NONE; + + int iarg = 0; + + while (true) { + + if (iarg >= narg) { + break; + } + + if (strcmp(arg[iarg], "*UPDATE_CONSTANT") == 0) { + iarg++; + if (iarg == narg) { + error->all(FLERR, "expected number following *UPDATE_CONSTANT keyword"); + } + + update_method = UPDATE_CONSTANT_THRESHOLD; + update_threshold = force->numeric(FLERR, arg[iarg]); + + } else if (strcmp(arg[iarg], "*UPDATE_PAIRWISE") == 0) { + iarg++; + if (iarg == narg) { + error->all(FLERR, "expected number following *UPDATE_PAIRWISE keyword"); + } + + update_method = UPDATE_PAIRWISE_RATIO; + update_threshold = force->numeric(FLERR, arg[iarg]); + + } else { + char msg[128]; + sprintf(msg, "Illegal keyword for smd/integrate_tlsph: %s\n", arg[iarg]); + error->all(FLERR, msg); + } + + iarg++; + } + + if ((update_threshold > cut_comm) && (update_method == UPDATE_CONSTANT_THRESHOLD)) { + if (comm->me == 0) { + printf("\n ***** WARNING ***\n"); + printf("requested reference configuration update threshold is %g length units\n", update_threshold); + printf("This value exceeds the maximum value %g beyond which TLSPH displacements can be tracked at current settings.\n", + cut_comm); + printf("Expect loss of neighbors!\n"); + } + } + + if (comm->me == 0) { + + if (update_method == UPDATE_CONSTANT_THRESHOLD) { + printf("... will update reference configuration if magnitude of relative displacement exceeds %g length units\n", + update_threshold); + } else if (update_method == UPDATE_PAIRWISE_RATIO) { + printf("... will update reference configuration if ratio pairwise distance / smoothing length exceeds %g\n", + update_threshold); + } else if (update_method == UPDATE_NONE) { + printf("... will never update reference configuration"); + } + printf( + ">>========>>========>>========>>========>>========>>========>>========>>========>>========>>========>>========>>========\n"); + + } + +} + +/* ---------------------------------------------------------------------- + set coeffs for one or more type pairs + ------------------------------------------------------------------------- */ + +void PairTlsph::coeff(int narg, char **arg) { + int ioffset, iarg, iNextKwd, itype; + char str[128]; + std::string s, t; + + if (narg < 3) { + sprintf(str, "number of arguments for pair tlsph is too small!"); + error->all(FLERR, str); + } + if (!allocated) + allocate(); + + /* + * check that TLSPH parameters are given only in i,i form + */ + if (force->inumeric(FLERR, arg[0]) != force->inumeric(FLERR, arg[1])) { + sprintf(str, "TLSPH coefficients can only be specified between particles of same type!"); + error->all(FLERR, str); + } + itype = force->inumeric(FLERR, arg[0]); + +// set all eos, strength and failure models to inactive by default + eos[itype] = EOS_NONE; + strengthModel[itype] = STRENGTH_NONE; + + if (comm->me == 0) { + printf( + "\n>>========>>========>>========>>========>>========>>========>>========>>========>>========>>========>>========>>========\n"); + printf("SMD / TLSPH PROPERTIES OF PARTICLE TYPE %d:\n", itype); + } + + /* + * read parameters which are common -- regardless of material / eos model + */ + + ioffset = 2; + if (strcmp(arg[ioffset], "*COMMON") != 0) { + sprintf(str, "common keyword missing!"); + error->all(FLERR, str); + } + + t = string("*"); + iNextKwd = -1; + for (iarg = ioffset + 1; iarg < narg; iarg++) { + s = string(arg[iarg]); + if (s.compare(0, t.length(), t) == 0) { + iNextKwd = iarg; + break; + } + } + +//printf("keyword following *COMMON is %s\n", arg[iNextKwd]); + + if (iNextKwd < 0) { + sprintf(str, "no *KEYWORD terminates *COMMON"); + error->all(FLERR, str); + } + + if (iNextKwd - ioffset != 7 + 1) { + sprintf(str, "expected 7 arguments following *COMMON but got %d\n", iNextKwd - ioffset - 1); + error->all(FLERR, str); + } + + Lookup[REFERENCE_DENSITY][itype] = force->numeric(FLERR, arg[ioffset + 1]); + Lookup[YOUNGS_MODULUS][itype] = force->numeric(FLERR, arg[ioffset + 2]); + Lookup[POISSON_RATIO][itype] = force->numeric(FLERR, arg[ioffset + 3]); + Lookup[VISCOSITY_Q1][itype] = force->numeric(FLERR, arg[ioffset + 4]); + Lookup[VISCOSITY_Q2][itype] = force->numeric(FLERR, arg[ioffset + 5]); + Lookup[HOURGLASS_CONTROL_AMPLITUDE][itype] = force->numeric(FLERR, arg[ioffset + 6]); + Lookup[HEAT_CAPACITY][itype] = force->numeric(FLERR, arg[ioffset + 7]); + + Lookup[LAME_LAMBDA][itype] = Lookup[YOUNGS_MODULUS][itype] * Lookup[POISSON_RATIO][itype] + / ((1.0 + Lookup[POISSON_RATIO][itype] * (1.0 - 2.0 * Lookup[POISSON_RATIO][itype]))); + Lookup[SHEAR_MODULUS][itype] = Lookup[YOUNGS_MODULUS][itype] / (2.0 * (1.0 + Lookup[POISSON_RATIO][itype])); + Lookup[M_MODULUS][itype] = Lookup[LAME_LAMBDA][itype] + 2.0 * Lookup[SHEAR_MODULUS][itype]; + Lookup[SIGNAL_VELOCITY][itype] = sqrt( + (Lookup[LAME_LAMBDA][itype] + 2.0 * Lookup[SHEAR_MODULUS][itype]) / Lookup[REFERENCE_DENSITY][itype]); + Lookup[BULK_MODULUS][itype] = Lookup[LAME_LAMBDA][itype] + 2.0 * Lookup[SHEAR_MODULUS][itype] / 3.0; + + if (comm->me == 0) { + printf("\n material unspecific properties for SMD/TLSPH definition of particle type %d:\n", itype); + printf("%60s : %g\n", "reference density", Lookup[REFERENCE_DENSITY][itype]); + printf("%60s : %g\n", "Young's modulus", Lookup[YOUNGS_MODULUS][itype]); + printf("%60s : %g\n", "Poisson ratio", Lookup[POISSON_RATIO][itype]); + printf("%60s : %g\n", "linear viscosity coefficient", Lookup[VISCOSITY_Q1][itype]); + printf("%60s : %g\n", "quadratic viscosity coefficient", Lookup[VISCOSITY_Q2][itype]); + printf("%60s : %g\n", "hourglass control coefficient", Lookup[HOURGLASS_CONTROL_AMPLITUDE][itype]); + printf("%60s : %g\n", "heat capacity [energy / (mass * temperature)]", Lookup[HEAT_CAPACITY][itype]); + printf("%60s : %g\n", "Lame constant lambda", Lookup[LAME_LAMBDA][itype]); + printf("%60s : %g\n", "shear modulus", Lookup[SHEAR_MODULUS][itype]); + printf("%60s : %g\n", "bulk modulus", Lookup[BULK_MODULUS][itype]); + printf("%60s : %g\n", "signal velocity", Lookup[SIGNAL_VELOCITY][itype]); + + } + + /* + * read following material cards + */ + +//printf("next kwd is %s\n", arg[iNextKwd]); + eos[itype] = EOS_NONE; + strengthModel[itype] = STRENGTH_NONE; + + while (true) { + if (strcmp(arg[iNextKwd], "*END") == 0) { + if (comm->me == 0) { + printf("found *END keyword"); + printf( + "\n>>========>>========>>========>>========>>========>>========>>========>>========>>========>>========>>========>>========\n\n"); + } + break; + } + + /* + * Linear Elasticity model based on deformation gradient + */ + ioffset = iNextKwd; + if (strcmp(arg[ioffset], "*LINEAR_DEFGRAD") == 0) { + strengthModel[itype] = LINEAR_DEFGRAD; + + if (comm->me == 0) { + printf("reading *LINEAR_DEFGRAD\n"); + } + + t = string("*"); + iNextKwd = -1; + for (iarg = ioffset + 1; iarg < narg; iarg++) { + s = string(arg[iarg]); + if (s.compare(0, t.length(), t) == 0) { + iNextKwd = iarg; + break; + } + } + + if (iNextKwd < 0) { + sprintf(str, "no *KEYWORD terminates *LINEAR_DEFGRAD"); + error->all(FLERR, str); + } + + if (iNextKwd - ioffset != 1) { + sprintf(str, "expected 0 arguments following *LINEAR_DEFGRAD but got %d\n", iNextKwd - ioffset - 1); + error->all(FLERR, str); + } + + if (comm->me == 0) { + printf("\n%60s\n", "Linear Elasticity model based on deformation gradient"); + } + } else if (strcmp(arg[ioffset], "*STRENGTH_LINEAR") == 0) { + + /* + * Linear Elasticity strength only model based on strain rate + */ + + strengthModel[itype] = STRENGTH_LINEAR; + if (comm->me == 0) { + printf("reading *STRENGTH_LINEAR\n"); + } + + t = string("*"); + iNextKwd = -1; + for (iarg = ioffset + 1; iarg < narg; iarg++) { + s = string(arg[iarg]); + if (s.compare(0, t.length(), t) == 0) { + iNextKwd = iarg; + break; + } + } + + if (iNextKwd < 0) { + sprintf(str, "no *KEYWORD terminates *STRENGTH_LINEAR"); + error->all(FLERR, str); + } + + if (iNextKwd - ioffset != 1) { + sprintf(str, "expected 0 arguments following *STRENGTH_LINEAR but got %d\n", iNextKwd - ioffset - 1); + error->all(FLERR, str); + } + + if (comm->me == 0) { + printf("%60s\n", "Linear Elasticity strength based on strain rate"); + } + } // end Linear Elasticity strength only model based on strain rate + + else if (strcmp(arg[ioffset], "*STRENGTH_LINEAR_PLASTIC") == 0) { + + /* + * Linear Elastic / perfectly plastic strength only model based on strain rate + */ + + strengthModel[itype] = STRENGTH_LINEAR_PLASTIC; + if (comm->me == 0) { + printf("reading *STRENGTH_LINEAR_PLASTIC\n"); + } + + t = string("*"); + iNextKwd = -1; + for (iarg = ioffset + 1; iarg < narg; iarg++) { + s = string(arg[iarg]); + if (s.compare(0, t.length(), t) == 0) { + iNextKwd = iarg; + break; + } + } + + if (iNextKwd < 0) { + sprintf(str, "no *KEYWORD terminates *STRENGTH_LINEAR_PLASTIC"); + error->all(FLERR, str); + } + + if (iNextKwd - ioffset != 2 + 1) { + sprintf(str, "expected 2 arguments following *STRENGTH_LINEAR_PLASTIC but got %d\n", iNextKwd - ioffset - 1); + error->all(FLERR, str); + } + + Lookup[YIELD_STRESS][itype] = force->numeric(FLERR, arg[ioffset + 1]); + Lookup[HARDENING_PARAMETER][itype] = force->numeric(FLERR, arg[ioffset + 2]); + + if (comm->me == 0) { + printf("%60s\n", "Linear elastic / perfectly plastic strength based on strain rate"); + printf("%60s : %g\n", "Young's modulus", Lookup[YOUNGS_MODULUS][itype]); + printf("%60s : %g\n", "Poisson ratio", Lookup[POISSON_RATIO][itype]); + printf("%60s : %g\n", "shear modulus", Lookup[SHEAR_MODULUS][itype]); + printf("%60s : %g\n", "constant yield stress", Lookup[YIELD_STRESS][itype]); + printf("%60s : %g\n", "constant hardening parameter", Lookup[HARDENING_PARAMETER][itype]); + } + } // end Linear Elastic / perfectly plastic strength only model based on strain rate + + else if (strcmp(arg[ioffset], "*JOHNSON_COOK") == 0) { + + /* + * JOHNSON - COOK + */ + + strengthModel[itype] = STRENGTH_JOHNSON_COOK; + if (comm->me == 0) { + printf("reading *JOHNSON_COOK\n"); + } + + t = string("*"); + iNextKwd = -1; + for (iarg = ioffset + 1; iarg < narg; iarg++) { + s = string(arg[iarg]); + if (s.compare(0, t.length(), t) == 0) { + iNextKwd = iarg; + break; + } + } + + if (iNextKwd < 0) { + sprintf(str, "no *KEYWORD terminates *JOHNSON_COOK"); + error->all(FLERR, str); + } + + if (iNextKwd - ioffset != 8 + 1) { + sprintf(str, "expected 8 arguments following *JOHNSON_COOK but got %d\n", iNextKwd - ioffset - 1); + error->all(FLERR, str); + } + + Lookup[JC_A][itype] = force->numeric(FLERR, arg[ioffset + 1]); + Lookup[JC_B][itype] = force->numeric(FLERR, arg[ioffset + 2]); + Lookup[JC_a][itype] = force->numeric(FLERR, arg[ioffset + 3]); + Lookup[JC_C][itype] = force->numeric(FLERR, arg[ioffset + 4]); + Lookup[JC_epdot0][itype] = force->numeric(FLERR, arg[ioffset + 5]); + Lookup[JC_T0][itype] = force->numeric(FLERR, arg[ioffset + 6]); + Lookup[JC_Tmelt][itype] = force->numeric(FLERR, arg[ioffset + 7]); + Lookup[JC_M][itype] = force->numeric(FLERR, arg[ioffset + 8]); + + if (comm->me == 0) { + printf("%60s\n", "Johnson Cook material strength model"); + printf("%60s : %g\n", "A: initial yield stress", Lookup[JC_A][itype]); + printf("%60s : %g\n", "B : proportionality factor for plastic strain dependency", Lookup[JC_B][itype]); + printf("%60s : %g\n", "a : exponent for plastic strain dependency", Lookup[JC_a][itype]); + printf("%60s : %g\n", "C : proportionality factor for logarithmic plastic strain rate dependency", + Lookup[JC_C][itype]); + printf("%60s : %g\n", "epdot0 : dimensionality factor for plastic strain rate dependency", + Lookup[JC_epdot0][itype]); + printf("%60s : %g\n", "T0 : reference (room) temperature", Lookup[JC_T0][itype]); + printf("%60s : %g\n", "Tmelt : melting temperature", Lookup[JC_Tmelt][itype]); + printf("%60s : %g\n", "M : exponent for temperature dependency", Lookup[JC_M][itype]); + } + + } else if (strcmp(arg[ioffset], "*EOS_NONE") == 0) { + + /* + * no eos + */ + + eos[itype] = EOS_NONE; + if (comm->me == 0) { + printf("reading *EOS_NONE\n"); + } + + t = string("*"); + iNextKwd = -1; + for (iarg = ioffset + 1; iarg < narg; iarg++) { + s = string(arg[iarg]); + if (s.compare(0, t.length(), t) == 0) { + iNextKwd = iarg; + break; + } + } + + if (iNextKwd < 0) { + sprintf(str, "no *KEYWORD terminates *EOS_NONE"); + error->all(FLERR, str); + } + + if (iNextKwd - ioffset != 1) { + sprintf(str, "expected 0 arguments following *EOS_NONE but got %d\n", iNextKwd - ioffset - 1); + error->all(FLERR, str); + } + + if (comm->me == 0) { + printf("\n%60s\n", "no EOS selected"); + } + + } else if (strcmp(arg[ioffset], "*EOS_LINEAR") == 0) { + + /* + * linear eos + */ + + eos[itype] = EOS_LINEAR; + if (comm->me == 0) { + printf("reading *EOS_LINEAR\n"); + } + + t = string("*"); + iNextKwd = -1; + for (iarg = ioffset + 1; iarg < narg; iarg++) { + s = string(arg[iarg]); + if (s.compare(0, t.length(), t) == 0) { + iNextKwd = iarg; + break; + } + } + + if (iNextKwd < 0) { + sprintf(str, "no *KEYWORD terminates *EOS_LINEAR"); + error->all(FLERR, str); + } + + if (iNextKwd - ioffset != 1) { + sprintf(str, "expected 0 arguments following *EOS_LINEAR but got %d\n", iNextKwd - ioffset - 1); + error->all(FLERR, str); + } + + if (comm->me == 0) { + printf("\n%60s\n", "linear EOS based on strain rate"); + printf("%60s : %g\n", "bulk modulus", Lookup[BULK_MODULUS][itype]); + } + } // end linear eos + else if (strcmp(arg[ioffset], "*EOS_SHOCK") == 0) { + + /* + * shock eos + */ + + eos[itype] = EOS_SHOCK; + if (comm->me == 0) { + printf("reading *EOS_SHOCK\n"); + } + + t = string("*"); + iNextKwd = -1; + for (iarg = ioffset + 1; iarg < narg; iarg++) { + s = string(arg[iarg]); + if (s.compare(0, t.length(), t) == 0) { + iNextKwd = iarg; + break; + } + } + + if (iNextKwd < 0) { + sprintf(str, "no *KEYWORD terminates *EOS_SHOCK"); + error->all(FLERR, str); + } + + if (iNextKwd - ioffset != 3 + 1) { + sprintf(str, "expected 3 arguments (c0, S, Gamma) following *EOS_SHOCK but got %d\n", iNextKwd - ioffset - 1); + error->all(FLERR, str); + } + + Lookup[EOS_SHOCK_C0][itype] = force->numeric(FLERR, arg[ioffset + 1]); + Lookup[EOS_SHOCK_S][itype] = force->numeric(FLERR, arg[ioffset + 2]); + Lookup[EOS_SHOCK_GAMMA][itype] = force->numeric(FLERR, arg[ioffset + 3]); + if (comm->me == 0) { + printf("\n%60s\n", "shock EOS based on strain rate"); + printf("%60s : %g\n", "reference speed of sound", Lookup[EOS_SHOCK_C0][itype]); + printf("%60s : %g\n", "Hugoniot parameter S", Lookup[EOS_SHOCK_S][itype]); + printf("%60s : %g\n", "Grueneisen Gamma", Lookup[EOS_SHOCK_GAMMA][itype]); + } + } // end shock eos + + else if (strcmp(arg[ioffset], "*EOS_POLYNOMIAL") == 0) { + /* + * polynomial eos + */ + + eos[itype] = EOS_POLYNOMIAL; + if (comm->me == 0) { + printf("reading *EOS_POLYNOMIAL\n"); + } + + t = string("*"); + iNextKwd = -1; + for (iarg = ioffset + 1; iarg < narg; iarg++) { + s = string(arg[iarg]); + if (s.compare(0, t.length(), t) == 0) { + iNextKwd = iarg; + break; + } + } + + if (iNextKwd < 0) { + sprintf(str, "no *KEYWORD terminates *EOS_POLYNOMIAL"); + error->all(FLERR, str); + } + + if (iNextKwd - ioffset != 7 + 1) { + sprintf(str, "expected 7 arguments following *EOS_POLYNOMIAL but got %d\n", iNextKwd - ioffset - 1); + error->all(FLERR, str); + } + + Lookup[EOS_POLYNOMIAL_C0][itype] = force->numeric(FLERR, arg[ioffset + 1]); + Lookup[EOS_POLYNOMIAL_C1][itype] = force->numeric(FLERR, arg[ioffset + 2]); + Lookup[EOS_POLYNOMIAL_C2][itype] = force->numeric(FLERR, arg[ioffset + 3]); + Lookup[EOS_POLYNOMIAL_C3][itype] = force->numeric(FLERR, arg[ioffset + 4]); + Lookup[EOS_POLYNOMIAL_C4][itype] = force->numeric(FLERR, arg[ioffset + 5]); + Lookup[EOS_POLYNOMIAL_C5][itype] = force->numeric(FLERR, arg[ioffset + 6]); + Lookup[EOS_POLYNOMIAL_C6][itype] = force->numeric(FLERR, arg[ioffset + 7]); + if (comm->me == 0) { + printf("\n%60s\n", "polynomial EOS based on strain rate"); + printf("%60s : %g\n", "parameter c0", Lookup[EOS_POLYNOMIAL_C0][itype]); + printf("%60s : %g\n", "parameter c1", Lookup[EOS_POLYNOMIAL_C1][itype]); + printf("%60s : %g\n", "parameter c2", Lookup[EOS_POLYNOMIAL_C2][itype]); + printf("%60s : %g\n", "parameter c3", Lookup[EOS_POLYNOMIAL_C3][itype]); + printf("%60s : %g\n", "parameter c4", Lookup[EOS_POLYNOMIAL_C4][itype]); + printf("%60s : %g\n", "parameter c5", Lookup[EOS_POLYNOMIAL_C5][itype]); + printf("%60s : %g\n", "parameter c6", Lookup[EOS_POLYNOMIAL_C6][itype]); + } + } // end polynomial eos + + else if (strcmp(arg[ioffset], "*FAILURE_MAX_PLASTIC_STRAIN") == 0) { + + /* + * maximum plastic strain failure criterion + */ + + if (comm->me == 0) { + printf("reading *FAILURE_MAX_PLASTIC_SRTRAIN\n"); + } + + t = string("*"); + iNextKwd = -1; + for (iarg = ioffset + 1; iarg < narg; iarg++) { + s = string(arg[iarg]); + if (s.compare(0, t.length(), t) == 0) { + iNextKwd = iarg; + break; + } + } + + if (iNextKwd < 0) { + sprintf(str, "no *KEYWORD terminates *FAILURE_MAX_PLASTIC_STRAIN"); + error->all(FLERR, str); + } + + if (iNextKwd - ioffset != 1 + 1) { + sprintf(str, "expected 1 arguments following *FAILURE_MAX_PLASTIC_STRAIN but got %d\n", iNextKwd - ioffset - 1); + error->all(FLERR, str); + } + + failureModel[itype].failure_max_plastic_strain = true; + failureModel[itype].integration_point_wise = true; + Lookup[FAILURE_MAX_PLASTIC_STRAIN_THRESHOLD][itype] = force->numeric(FLERR, arg[ioffset + 1]); + + if (comm->me == 0) { + printf("\n%60s\n", "maximum plastic strain failure criterion"); + printf("%60s : %g\n", "failure occurs when plastic strain reaches limit", + Lookup[FAILURE_MAX_PLASTIC_STRAIN_THRESHOLD][itype]); + } + } // end maximum plastic strain failure criterion + else if (strcmp(arg[ioffset], "*FAILURE_MAX_PAIRWISE_STRAIN") == 0) { + + /* + * failure criterion based on maximum strain between a pair of TLSPH particles. + */ + + if (comm->me == 0) { + printf("reading *FAILURE_MAX_PAIRWISE_STRAIN\n"); + } + + if (update_method != UPDATE_NONE) { + error->all(FLERR, "cannot use *FAILURE_MAX_PAIRWISE_STRAIN with updated Total-Lagrangian formalism"); + } + + t = string("*"); + iNextKwd = -1; + for (iarg = ioffset + 1; iarg < narg; iarg++) { + s = string(arg[iarg]); + if (s.compare(0, t.length(), t) == 0) { + iNextKwd = iarg; + break; + } + } + + if (iNextKwd < 0) { + sprintf(str, "no *KEYWORD terminates *FAILURE_MAX_PAIRWISE_STRAIN"); + error->all(FLERR, str); + } + + if (iNextKwd - ioffset != 1 + 1) { + sprintf(str, "expected 1 arguments following *FAILURE_MAX_PAIRWISE_STRAIN but got %d\n", iNextKwd - ioffset - 1); + error->all(FLERR, str); + } + + failureModel[itype].failure_max_pairwise_strain = true; + failureModel[itype].integration_point_wise = true; + Lookup[FAILURE_MAX_PAIRWISE_STRAIN_THRESHOLD][itype] = force->numeric(FLERR, arg[ioffset + 1]); + + if (comm->me == 0) { + printf("\n%60s\n", "maximum pairwise strain failure criterion"); + printf("%60s : %g\n", "failure occurs when pairwise strain reaches limit", + Lookup[FAILURE_MAX_PAIRWISE_STRAIN_THRESHOLD][itype]); + } + } // end pair based maximum strain failure criterion + else if (strcmp(arg[ioffset], "*FAILURE_MAX_PRINCIPAL_STRAIN") == 0) { + error->all(FLERR, "this failure model is currently unsupported"); + + /* + * maximum principal strain failure criterion + */ + if (comm->me == 0) { + printf("reading *FAILURE_MAX_PRINCIPAL_STRAIN\n"); + } + + t = string("*"); + iNextKwd = -1; + for (iarg = ioffset + 1; iarg < narg; iarg++) { + s = string(arg[iarg]); + if (s.compare(0, t.length(), t) == 0) { + iNextKwd = iarg; + break; + } + } + + if (iNextKwd < 0) { + sprintf(str, "no *KEYWORD terminates *FAILURE_MAX_PRINCIPAL_STRAIN"); + error->all(FLERR, str); + } + + if (iNextKwd - ioffset != 1 + 1) { + sprintf(str, "expected 1 arguments following *FAILURE_MAX_PRINCIPAL_STRAIN but got %d\n", iNextKwd - ioffset - 1); + error->all(FLERR, str); + } + + failureModel[itype].failure_max_principal_strain = true; + failureModel[itype].integration_point_wise = true; + Lookup[FAILURE_MAX_PRINCIPAL_STRAIN_THRESHOLD][itype] = force->numeric(FLERR, arg[ioffset + 1]); + + if (comm->me == 0) { + printf("\n%60s\n", "maximum principal strain failure criterion"); + printf("%60s : %g\n", "failure occurs when principal strain reaches limit", + Lookup[FAILURE_MAX_PRINCIPAL_STRAIN_THRESHOLD][itype]); + } + } // end maximum principal strain failure criterion + else if (strcmp(arg[ioffset], "*FAILURE_JOHNSON_COOK") == 0) { + error->all(FLERR, "this failure model is currently unsupported"); + if (comm->me == 0) { + printf("reading *FAILURE_JOHNSON_COOK\n"); + } + + t = string("*"); + iNextKwd = -1; + for (iarg = ioffset + 1; iarg < narg; iarg++) { + s = string(arg[iarg]); + if (s.compare(0, t.length(), t) == 0) { + iNextKwd = iarg; + break; + } + } + + if (iNextKwd < 0) { + sprintf(str, "no *KEYWORD terminates *FAILURE_JOHNSON_COOK"); + error->all(FLERR, str); + } + + if (iNextKwd - ioffset != 5 + 1) { + sprintf(str, "expected 5 arguments following *FAILURE_JOHNSON_COOK but got %d\n", iNextKwd - ioffset - 1); + error->all(FLERR, str); + } + + failureModel[itype].failure_johnson_cook = true; + failureModel[itype].integration_point_wise = true; + + Lookup[FAILURE_JC_D1][itype] = force->numeric(FLERR, arg[ioffset + 1]); + Lookup[FAILURE_JC_D2][itype] = force->numeric(FLERR, arg[ioffset + 2]); + Lookup[FAILURE_JC_D3][itype] = force->numeric(FLERR, arg[ioffset + 3]); + Lookup[FAILURE_JC_D4][itype] = force->numeric(FLERR, arg[ioffset + 4]); + Lookup[FAILURE_JC_EPDOT0][itype] = force->numeric(FLERR, arg[ioffset + 5]); + + if (comm->me == 0) { + printf("\n%60s\n", "Johnson-Cook failure criterion"); + printf("%60s : %g\n", "parameter d1", Lookup[FAILURE_JC_D1][itype]); + printf("%60s : %g\n", "parameter d2", Lookup[FAILURE_JC_D2][itype]); + printf("%60s : %g\n", "parameter d3", Lookup[FAILURE_JC_D3][itype]); + printf("%60s : %g\n", "parameter d4", Lookup[FAILURE_JC_D4][itype]); + printf("%60s : %g\n", "reference plastic strain rate", Lookup[FAILURE_JC_EPDOT0][itype]); + } + + } else if (strcmp(arg[ioffset], "*FAILURE_MAX_PRINCIPAL_STRESS") == 0) { + error->all(FLERR, "this failure model is currently unsupported"); + + /* + * maximum principal stress failure criterion + */ + + if (comm->me == 0) { + printf("reading *FAILURE_MAX_PRINCIPAL_STRESS\n"); + } + + t = string("*"); + iNextKwd = -1; + for (iarg = ioffset + 1; iarg < narg; iarg++) { + s = string(arg[iarg]); + if (s.compare(0, t.length(), t) == 0) { + iNextKwd = iarg; + break; + } + } + + if (iNextKwd < 0) { + sprintf(str, "no *KEYWORD terminates *FAILURE_MAX_PRINCIPAL_STRESS"); + error->all(FLERR, str); + } + + if (iNextKwd - ioffset != 1 + 1) { + sprintf(str, "expected 1 arguments following *FAILURE_MAX_PRINCIPAL_STRESS but got %d\n", iNextKwd - ioffset - 1); + error->all(FLERR, str); + } + + failureModel[itype].failure_max_principal_stress = true; + failureModel[itype].integration_point_wise = true; + Lookup[FAILURE_MAX_PRINCIPAL_STRESS_THRESHOLD][itype] = force->numeric(FLERR, arg[ioffset + 1]); + + if (comm->me == 0) { + printf("\n%60s\n", "maximum principal stress failure criterion"); + printf("%60s : %g\n", "failure occurs when principal stress reaches limit", + Lookup[FAILURE_MAX_PRINCIPAL_STRESS_THRESHOLD][itype]); + } + } // end maximum principal stress failure criterion + + else if (strcmp(arg[ioffset], "*FAILURE_ENERGY_RELEASE_RATE") == 0) { + if (comm->me == 0) { + printf("reading *FAILURE_ENERGY_RELEASE_RATE\n"); + } + + t = string("*"); + iNextKwd = -1; + for (iarg = ioffset + 1; iarg < narg; iarg++) { + s = string(arg[iarg]); + if (s.compare(0, t.length(), t) == 0) { + iNextKwd = iarg; + break; + } + } + + if (iNextKwd < 0) { + sprintf(str, "no *KEYWORD terminates *FAILURE_ENERGY_RELEASE_RATE"); + error->all(FLERR, str); + } + + if (iNextKwd - ioffset != 1 + 1) { + sprintf(str, "expected 1 arguments following *FAILURE_ENERGY_RELEASE_RATE but got %d\n", iNextKwd - ioffset - 1); + error->all(FLERR, str); + } + + failureModel[itype].failure_energy_release_rate = true; + Lookup[CRITICAL_ENERGY_RELEASE_RATE][itype] = force->numeric(FLERR, arg[ioffset + 1]); + + if (comm->me == 0) { + printf("\n%60s\n", "critical energy release rate failure criterion"); + printf("%60s : %g\n", "failure occurs when energy release rate reaches limit", + Lookup[CRITICAL_ENERGY_RELEASE_RATE][itype]); + } + } // end energy release rate failure criterion + + else { + sprintf(str, "unknown *KEYWORD: %s", arg[ioffset]); + error->all(FLERR, str); + } + + } + + setflag[itype][itype] = 1; + +} + +/* ---------------------------------------------------------------------- + init for one type pair i,j and corresponding j,i + ------------------------------------------------------------------------- */ + +double PairTlsph::init_one(int i, int j) { + + if (!allocated) + allocate(); + + if (setflag[i][j] == 0) + error->all(FLERR, "All pair coeffs are not set"); + + if (force->newton == 1) + error->all(FLERR, "Pair style tlsph requires newton off"); + +// cutoff = sum of max I,J radii for +// dynamic/dynamic & dynamic/frozen interactions, but not frozen/frozen + + double cutoff = maxrad_dynamic[i] + maxrad_dynamic[j]; + cutoff = MAX(cutoff, maxrad_frozen[i] + maxrad_dynamic[j]); + cutoff = MAX(cutoff, maxrad_dynamic[i] + maxrad_frozen[j]); +//printf("cutoff for pair pair tlsph = %f\n", cutoff); + return cutoff; +} + +/* ---------------------------------------------------------------------- + init specific to this pair style + ------------------------------------------------------------------------- */ + +void PairTlsph::init_style() { + int i; + + if (force->newton_pair == 1) { + error->all(FLERR, "Pair style tlsph requires newton pair off"); + } + +// request a granular neighbor list + int irequest = neighbor->request(this); + neighbor->requests[irequest]->half = 0; + neighbor->requests[irequest]->gran = 1; + +// set maxrad_dynamic and maxrad_frozen for each type +// include future Fix pour particles as dynamic + + for (i = 1; i <= atom->ntypes; i++) + onerad_dynamic[i] = onerad_frozen[i] = 0.0; + + double *radius = atom->radius; + int *type = atom->type; + int nlocal = atom->nlocal; + + for (i = 0; i < nlocal; i++) + onerad_dynamic[type[i]] = MAX(onerad_dynamic[type[i]], radius[i]); + + MPI_Allreduce(&onerad_dynamic[1], &maxrad_dynamic[1], atom->ntypes, MPI_DOUBLE, MPI_MAX, world); + MPI_Allreduce(&onerad_frozen[1], &maxrad_frozen[1], atom->ntypes, MPI_DOUBLE, MPI_MAX, world); + +// if first init, create Fix needed for storing reference configuration neighbors + + int igroup = group->find("tlsph"); + if (igroup == -1) + error->all(FLERR, "Pair style tlsph requires its particles to be part of a group named tlsph. This group does not exist."); + + if (fix_tlsph_reference_configuration == NULL) { + char **fixarg = new char*[3]; + fixarg[0] = (char *) "SMD_TLSPH_NEIGHBORS"; + fixarg[1] = (char *) "tlsph"; + fixarg[2] = (char *) "SMD_TLSPH_NEIGHBORS"; + modify->add_fix(3, fixarg); + delete[] fixarg; + fix_tlsph_reference_configuration = (FixSMD_TLSPH_ReferenceConfiguration *) modify->fix[modify->nfix - 1]; + fix_tlsph_reference_configuration->pair = this; + } + +// find associated SMD_TLSPH_NEIGHBORS fix that must exist +// could have changed locations in fix list since created + + ifix_tlsph = -1; + for (int i = 0; i < modify->nfix; i++) + if (strcmp(modify->fix[i]->style, "SMD_TLSPH_NEIGHBORS") == 0) + ifix_tlsph = i; + if (ifix_tlsph == -1) + error->all(FLERR, "Fix SMD_TLSPH_NEIGHBORS does not exist"); + +} + +/* ---------------------------------------------------------------------- + neighbor callback to inform pair style of neighbor list to use + optional granular history list + ------------------------------------------------------------------------- */ + +void PairTlsph::init_list(int id, NeighList *ptr) { + if (id == 0) + list = ptr; +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based arrays + ------------------------------------------------------------------------- */ + +double PairTlsph::memory_usage() { + + return 118 * nmax * sizeof(double); +} + +/* ---------------------------------------------------------------------- + extract method to provide access to this class' data structures + ------------------------------------------------------------------------- */ + +void *PairTlsph::extract(const char *str, int &i) { +//printf("in PairTlsph::extract\n"); + if (strcmp(str, "smd/tlsph/Fincr_ptr") == 0) { + return (void *) Fincr; + } else if (strcmp(str, "smd/tlsph/detF_ptr") == 0) { + return (void *) detF; + } else if (strcmp(str, "smd/tlsph/PK1_ptr") == 0) { + return (void *) PK1; + } else if (strcmp(str, "smd/tlsph/smoothVel_ptr") == 0) { + return (void *) smoothVelDifference; + } else if (strcmp(str, "smd/tlsph/numNeighsRefConfig_ptr") == 0) { + return (void *) numNeighsRefConfig; + } else if (strcmp(str, "smd/tlsph/stressTensor_ptr") == 0) { + return (void *) CauchyStress; + } else if (strcmp(str, "smd/tlsph/updateFlag_ptr") == 0) { + return (void *) &updateFlag; + } else if (strcmp(str, "smd/tlsph/strain_rate_ptr") == 0) { + return (void *) D; + } else if (strcmp(str, "smd/tlsph/hMin_ptr") == 0) { + return (void *) &hMin; + } else if (strcmp(str, "smd/tlsph/dtCFL_ptr") == 0) { + return (void *) &dtCFL; + } else if (strcmp(str, "smd/tlsph/dtRelative_ptr") == 0) { + return (void *) &dtRelative; + } else if (strcmp(str, "smd/tlsph/hourglass_error_ptr") == 0) { + return (void *) hourglass_error; + } else if (strcmp(str, "smd/tlsph/particle_dt_ptr") == 0) { + return (void *) particle_dt; + } else if (strcmp(str, "smd/tlsph/rotation_ptr") == 0) { + return (void *) R; + } + + return NULL; +} + +/* ---------------------------------------------------------------------- */ + +int PairTlsph::pack_forward_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { + int i, j, m; + int *mol = atom->molecule; + double *damage = atom->damage; + double *eff_plastic_strain = atom->eff_plastic_strain; + double *eff_plastic_strain_rate = atom->eff_plastic_strain_rate; + +//printf("in PairTlsph::pack_forward_comm\n"); + + m = 0; + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = PK1[j](0, 0); // PK1 is not symmetric + buf[m++] = PK1[j](0, 1); + buf[m++] = PK1[j](0, 2); + buf[m++] = PK1[j](1, 0); + buf[m++] = PK1[j](1, 1); + buf[m++] = PK1[j](1, 2); + buf[m++] = PK1[j](2, 0); + buf[m++] = PK1[j](2, 1); + buf[m++] = PK1[j](2, 2); // 9 + + buf[m++] = Fincr[j](0, 0); // Fincr is not symmetric + buf[m++] = Fincr[j](0, 1); + buf[m++] = Fincr[j](0, 2); + buf[m++] = Fincr[j](1, 0); + buf[m++] = Fincr[j](1, 1); + buf[m++] = Fincr[j](1, 2); + buf[m++] = Fincr[j](2, 0); + buf[m++] = Fincr[j](2, 1); + buf[m++] = Fincr[j](2, 2); // 9 + 9 = 18 + + buf[m++] = mol[j]; //19 + buf[m++] = damage[j]; //20 + buf[m++] = eff_plastic_strain[j]; //21 + buf[m++] = eff_plastic_strain_rate[j]; //22 + + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +void PairTlsph::unpack_forward_comm(int n, int first, double *buf) { + int i, m, last; + int *mol = atom->molecule; + double *damage = atom->damage; + double *eff_plastic_strain = atom->eff_plastic_strain; + double *eff_plastic_strain_rate = atom->eff_plastic_strain_rate; + +//printf("in PairTlsph::unpack_forward_comm\n"); + + m = 0; + last = first + n; + for (i = first; i < last; i++) { + + PK1[i](0, 0) = buf[m++]; // PK1 is not symmetric + PK1[i](0, 1) = buf[m++]; + PK1[i](0, 2) = buf[m++]; + PK1[i](1, 0) = buf[m++]; + PK1[i](1, 1) = buf[m++]; + PK1[i](1, 2) = buf[m++]; + PK1[i](2, 0) = buf[m++]; + PK1[i](2, 1) = buf[m++]; + PK1[i](2, 2) = buf[m++]; + + Fincr[i](0, 0) = buf[m++]; + Fincr[i](0, 1) = buf[m++]; + Fincr[i](0, 2) = buf[m++]; + Fincr[i](1, 0) = buf[m++]; + Fincr[i](1, 1) = buf[m++]; + Fincr[i](1, 2) = buf[m++]; + Fincr[i](2, 0) = buf[m++]; + Fincr[i](2, 1) = buf[m++]; + Fincr[i](2, 2) = buf[m++]; + + mol[i] = static_cast(buf[m++]); + damage[i] = buf[m++]; + eff_plastic_strain[i] = buf[m++]; //22 + eff_plastic_strain_rate[i] = buf[m++]; //23 + } +} + +/* ---------------------------------------------------------------------- + compute effective P-wave speed + determined by longitudinal modulus + ------------------------------------------------------------------------- */ + +void PairTlsph::effective_longitudinal_modulus(const int itype, const double dt, const double d_iso, const double p_rate, + const Matrix3d d_dev, const Matrix3d sigma_dev_rate, const double damage, double &K_eff, double &mu_eff, double &M_eff) { + double M0; // initial longitudinal modulus + double shear_rate_sq; + +// if (damage >= 0.5) { +// M_eff = Lookup[M_MODULUS][itype]; +// K_eff = Lookup[BULK_MODULUS][itype]; +// mu_eff = Lookup[SHEAR_MODULUS][itype]; +// return; +// } + + M0 = Lookup[M_MODULUS][itype]; + + if (dt * d_iso > 1.0e-6) { + K_eff = p_rate / d_iso; + if (K_eff < 0.0) { // it is possible for K_eff to become negative due to strain softening +// if (damage == 0.0) { +// error->one(FLERR, "computed a negative effective bulk modulus but particle is not damaged."); +// } + K_eff = Lookup[BULK_MODULUS][itype]; + } + } else { + K_eff = Lookup[BULK_MODULUS][itype]; + } + + if (domain->dimension == 3) { +// Calculate 2 mu by looking at ratio shear stress / shear strain. Use numerical softening to avoid divide-by-zero. + mu_eff = 0.5 + * (sigma_dev_rate(0, 1) / (d_dev(0, 1) + 1.0e-16) + sigma_dev_rate(0, 2) / (d_dev(0, 2) + 1.0e-16) + + sigma_dev_rate(1, 2) / (d_dev(1, 2) + 1.0e-16)); + +// Calculate magnitude of deviatoric strain rate. This is used for deciding if shear modulus should be computed from current rate or be taken as the initial value. + shear_rate_sq = d_dev(0, 1) * d_dev(0, 1) + d_dev(0, 2) * d_dev(0, 2) + d_dev(1, 2) * d_dev(1, 2); + } else { + mu_eff = 0.5 * (sigma_dev_rate(0, 1) / (d_dev(0, 1) + 1.0e-16)); + shear_rate_sq = d_dev(0, 1) * d_dev(0, 1); + } + + if (dt * dt * shear_rate_sq < 1.0e-8) { + mu_eff = Lookup[SHEAR_MODULUS][itype]; + } + + if (mu_eff < Lookup[SHEAR_MODULUS][itype]) { // it is possible for mu_eff to become negative due to strain softening +// if (damage == 0.0) { +// printf("mu_eff = %f, tau=%f, gamma=%f\n", mu_eff, sigma_dev_rate(0, 1), d_dev(0, 1)); +// error->message(FLERR, "computed a negative effective shear modulus but particle is not damaged."); +// } + mu_eff = Lookup[SHEAR_MODULUS][itype]; + } + +//mu_eff = Lookup[SHEAR_MODULUS][itype]; + + if (K_eff < 0.0) { + printf("K_eff = %f, p_rate=%f, vol_rate=%f\n", K_eff, p_rate, d_iso); + } + + if (mu_eff < 0.0) { + printf("mu_eff = %f, tau=%f, gamma=%f\n", mu_eff, sigma_dev_rate(0, 1), d_dev(0, 1)); + error->one(FLERR, ""); + } + + M_eff = (K_eff + 4.0 * mu_eff / 3.0); // effective dilational modulus, see Pronto 2d eqn 3.4.8 + + if (M_eff < M0) { // do not allow effective dilatational modulus to decrease beyond its initial value + M_eff = M0; + } +} + +/* ---------------------------------------------------------------------- + compute pressure. Called from AssembleStress(). + ------------------------------------------------------------------------- */ +void PairTlsph::ComputePressure(const int i, const double rho, const double mass_specific_energy, const double vol_specific_energy, + const double pInitial, const double d_iso, double &pFinal, double &p_rate) { + int *type = atom->type; + double dt = update->dt; + + int itype; + + itype = type[i]; + + switch (eos[itype]) { + case EOS_LINEAR: + LinearEOS(Lookup[BULK_MODULUS][itype], pInitial, d_iso, dt, pFinal, p_rate); + break; + case EOS_NONE: + pFinal = 0.0; + p_rate = 0.0; + break; + case EOS_SHOCK: +// rho, rho0, e, e0, c0, S, Gamma, pInitial, dt, &pFinal, &p_rate); + ShockEOS(rho, Lookup[REFERENCE_DENSITY][itype], mass_specific_energy, 0.0, Lookup[EOS_SHOCK_C0][itype], + Lookup[EOS_SHOCK_S][itype], Lookup[EOS_SHOCK_GAMMA][itype], pInitial, dt, pFinal, p_rate); + break; + case EOS_POLYNOMIAL: + polynomialEOS(rho, Lookup[REFERENCE_DENSITY][itype], vol_specific_energy, Lookup[EOS_POLYNOMIAL_C0][itype], + Lookup[EOS_POLYNOMIAL_C1][itype], Lookup[EOS_POLYNOMIAL_C2][itype], Lookup[EOS_POLYNOMIAL_C3][itype], + Lookup[EOS_POLYNOMIAL_C4][itype], Lookup[EOS_POLYNOMIAL_C5][itype], Lookup[EOS_POLYNOMIAL_C6][itype], pInitial, dt, + pFinal, p_rate); + + break; + default: + error->one(FLERR, "unknown EOS."); + break; + } +} + +/* ---------------------------------------------------------------------- + Compute stress deviator. Called from AssembleStress(). + ------------------------------------------------------------------------- */ +void PairTlsph::ComputeStressDeviator(const int i, const Matrix3d sigmaInitial_dev, const Matrix3d d_dev, Matrix3d &sigmaFinal_dev, + Matrix3d &sigma_dev_rate, double &plastic_strain_increment) { + double *eff_plastic_strain = atom->eff_plastic_strain; + double *eff_plastic_strain_rate = atom->eff_plastic_strain_rate; + int *type = atom->type; + double *rmass = atom->rmass; +//double *vfrac = atom->vfrac; + double *e = atom->e; + double dt = update->dt; + double yieldStress; + int itype; + + double mass_specific_energy = e[i] / rmass[i]; // energy per unit mass + plastic_strain_increment = 0.0; + itype = type[i]; + + switch (strengthModel[itype]) { + case STRENGTH_LINEAR: + + sigma_dev_rate = 2.0 * Lookup[SHEAR_MODULUS][itype] * d_dev; + sigmaFinal_dev = sigmaInitial_dev + dt * sigma_dev_rate; + + break; + case LINEAR_DEFGRAD: +//LinearStrengthDefgrad(Lookup[LAME_LAMBDA][itype], Lookup[SHEAR_MODULUS][itype], Fincr[i], &sigmaFinal_dev); +//eff_plastic_strain[i] = 0.0; +//p_rate = pInitial - sigmaFinal_dev.trace() / 3.0; +//sigma_dev_rate = sigmaInitial_dev - Deviator(sigmaFinal_dev); + error->one(FLERR, "LINEAR_DEFGRAD is only for debugging purposes and currently deactivated."); + R[i].setIdentity(); + break; + case STRENGTH_LINEAR_PLASTIC: + + yieldStress = Lookup[YIELD_STRESS][itype] + Lookup[HARDENING_PARAMETER][itype] * eff_plastic_strain[i]; + LinearPlasticStrength(Lookup[SHEAR_MODULUS][itype], yieldStress, sigmaInitial_dev, d_dev, dt, sigmaFinal_dev, + sigma_dev_rate, plastic_strain_increment); + break; + case STRENGTH_JOHNSON_COOK: + JohnsonCookStrength(Lookup[SHEAR_MODULUS][itype], Lookup[HEAT_CAPACITY][itype], mass_specific_energy, Lookup[JC_A][itype], + Lookup[JC_B][itype], Lookup[JC_a][itype], Lookup[JC_C][itype], Lookup[JC_epdot0][itype], Lookup[JC_T0][itype], + Lookup[JC_Tmelt][itype], Lookup[JC_M][itype], dt, eff_plastic_strain[i], eff_plastic_strain_rate[i], + sigmaInitial_dev, d_dev, sigmaFinal_dev, sigma_dev_rate, plastic_strain_increment); + break; + case STRENGTH_NONE: + sigmaFinal_dev.setZero(); + sigma_dev_rate.setZero(); + break; + default: + error->one(FLERR, "unknown strength model."); + break; + } + +} + +/* ---------------------------------------------------------------------- + Compute damage. Called from AssembleStress(). + ------------------------------------------------------------------------- */ +void PairTlsph::ComputeDamage(const int i, const Matrix3d strain, const Matrix3d stress, Matrix3d &stress_damaged) { + double *eff_plastic_strain = atom->eff_plastic_strain; + double *eff_plastic_strain_rate = atom->eff_plastic_strain_rate; + double *radius = atom->radius; + double *damage = atom->damage; + int *type = atom->type; + int itype = type[i]; + bool damage_flag = false; + double jc_failure_strain; +//double damage_gap, damage_rate; + Matrix3d eye, stress_deviator; + + eye.setIdentity(); + stress_deviator = Deviator(stress); + double pressure = -stress.trace() / 3.0; + + if (failureModel[itype].failure_max_principal_stress) { + error->one(FLERR, "not yet implemented"); + /* + * maximum stress failure criterion: + */ + damage_flag = IsotropicMaxStressDamage(stress, Lookup[FAILURE_MAX_PRINCIPAL_STRESS_THRESHOLD][itype]); + } else if (failureModel[itype].failure_max_principal_strain) { + error->one(FLERR, "not yet implemented"); + /* + * maximum strain failure criterion: + */ + damage_flag = IsotropicMaxStrainDamage(strain, Lookup[FAILURE_MAX_PRINCIPAL_STRAIN_THRESHOLD][itype]); + } else if (failureModel[itype].failure_max_plastic_strain) { + if (eff_plastic_strain[i] >= Lookup[FAILURE_MAX_PLASTIC_STRAIN_THRESHOLD][itype]) { + damage_flag = true; + damage[i] = 1.0; + //double damage_gap = 0.5 * Lookup[FAILURE_MAX_PLASTIC_STRAIN_THRESHOLD][itype]; + //damage[i] = (eff_plastic_strain[i] - Lookup[FAILURE_MAX_PLASTIC_STRAIN_THRESHOLD][itype]) / damage_gap; + } + } else if (failureModel[itype].failure_johnson_cook) { + + //cout << "this is stress deviator" << stress_deviator << endl; + + jc_failure_strain = JohnsonCookFailureStrain(pressure, stress_deviator, Lookup[FAILURE_JC_D1][itype], + Lookup[FAILURE_JC_D2][itype], Lookup[FAILURE_JC_D3][itype], Lookup[FAILURE_JC_D4][itype], + Lookup[FAILURE_JC_EPDOT0][itype], eff_plastic_strain_rate[i]); + + //cout << "plastic strain increment is " << plastic_strain_increment << " jc fs is " << jc_failure_strain << endl; + //printf("JC failure strain is: %f\n", jc_failure_strain); + + if (eff_plastic_strain[i] >= jc_failure_strain) { + damage_flag = true; + double damage_rate = Lookup[SIGNAL_VELOCITY][itype] / (100.0 * radius[i]); + damage[i] += damage_rate * update->dt; + //damage[i] = 1.0; + } + } + + /* + * Apply damage to integration point + */ + +// damage[i] = MIN(damage[i], 0.8); +// +// if (pressure > 0.0) { // compression: particle can carry compressive load but reduced shear +// stress_damaged = -pressure * eye + (1.0 - damage[i]) * Deviator(stress); +// } else { // tension: particle has reduced tensile and shear load bearing capability +// stress_damaged = (1.0 - damage[i]) * (-pressure * eye + Deviator(stress)); +// } + +} + diff --git a/src/USER-SMD/pair_smd_tlsph.h b/src/USER-SMD/pair_smd_tlsph.h new file mode 100644 index 0000000000..b02a1c585e --- /dev/null +++ b/src/USER-SMD/pair_smd_tlsph.h @@ -0,0 +1,229 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +#ifdef PAIR_CLASS + +PairStyle(smd/tlsph,PairTlsph) + +#else + +#ifndef LMP_TLSPH_NEW_H +#define LMP_TLSPH_NEW_H + +#include "pair.h" +#include +#include +#include +#include + +using namespace std; +using namespace Eigen; +namespace LAMMPS_NS { + +class PairTlsph: public Pair { +public: + + PairTlsph(class LAMMPS *); + virtual ~PairTlsph(); + virtual void compute(int, int); + void settings(int, char **); + void coeff(int, char **); + double init_one(int, int); + void init_style(); + void init_list(int, class NeighList *); + void write_restart_settings(FILE *) { + } + void read_restart_settings(FILE *) { + } + virtual double memory_usage(); + void compute_shape_matrix(void); + void material_model(void); + void *extract(const char *, int &); + int pack_forward_comm(int, int *, double *, int, int *); + void unpack_forward_comm(int, int, double *); + void AssembleStress(); + + void PreCompute(); + void ComputeForces(int eflag, int vflag); + void effective_longitudinal_modulus(const int itype, const double dt, const double d_iso, const double p_rate, + const Matrix3d d_dev, const Matrix3d sigma_dev_rate, const double damage, double &K_eff, double &mu_eff, double &M_eff); + + void ComputePressure(const int i, const double rho, const double mass_specific_energy, const double vol_specific_energy, + const double pInitial, const double d_iso, double &pFinal, double &p_rate); + void ComputeStressDeviator(const int i, const Matrix3d sigmaInitial_dev, const Matrix3d d_dev, Matrix3d &sigmaFinal_dev, + Matrix3d &sigma_dev_rate, double &plastic_strain_increment); + void ComputeDamage(const int i, const Matrix3d strain, const Matrix3d sigmaFinal, Matrix3d &sigma_damaged); + + +protected: + void allocate(); + char *suffix; + + /* + * per-type arrays + */ + int *strengthModel, *eos; + double *onerad_dynamic, *onerad_frozen, *maxrad_dynamic, *maxrad_frozen; + + /* + * per atom arrays + */ + Matrix3d *K, *PK1, *Fdot, *Fincr; + Matrix3d *R; // rotation matrix + Matrix3d *FincrInv; + Matrix3d *D, *W; // strain rate and spin tensor + Vector3d *smoothVelDifference; + Matrix3d *CauchyStress; + double *detF, *particle_dt; + double *hourglass_error; + int *numNeighsRefConfig; + + int nmax; // max number of atoms on this proc + double hMin; // minimum kernel radius for two particles + double dtCFL; + double dtRelative; // relative velocity of two particles, divided by sound speed + int updateFlag; + double update_threshold; // updateFlage is set to one if the relative displacement of a pair exceeds update_threshold + double cut_comm; + + enum { + UPDATE_NONE = 5000, UPDATE_CONSTANT_THRESHOLD = 5001, UPDATE_PAIRWISE_RATIO = 5002, + }; + + enum { + LINEAR_DEFGRAD = 0, + STRENGTH_LINEAR = 1, + STRENGTH_LINEAR_PLASTIC = 2, + STRENGTH_JOHNSON_COOK = 3, + STRENGTH_NONE = 4, + EOS_LINEAR = 5, + EOS_SHOCK = 6, + EOS_POLYNOMIAL = 7, + EOS_NONE = 8, + REFERENCE_DENSITY = 9, + YOUNGS_MODULUS = 10, + POISSON_RATIO = 11, + HOURGLASS_CONTROL_AMPLITUDE = 12, + HEAT_CAPACITY = 13, + LAME_LAMBDA = 14, + SHEAR_MODULUS = 15, + M_MODULUS = 16, + SIGNAL_VELOCITY = 17, + BULK_MODULUS = 18, + VISCOSITY_Q1 = 19, + VISCOSITY_Q2 = 20, + YIELD_STRESS = 21, + FAILURE_MAX_PLASTIC_STRAIN_THRESHOLD = 22, + JC_A = 23, + JC_B = 24, + JC_a = 25, + JC_C = 26, + JC_epdot0 = 27, + JC_T0 = 28, + JC_Tmelt = 29, + JC_M = 30, + EOS_SHOCK_C0 = 31, + EOS_SHOCK_S = 32, + EOS_SHOCK_GAMMA = 33, + HARDENING_PARAMETER = 34, + FAILURE_MAX_PRINCIPAL_STRAIN_THRESHOLD = 35, + FAILURE_MAX_PRINCIPAL_STRESS_THRESHOLD = 36, + FAILURE_MAX_PAIRWISE_STRAIN_THRESHOLD = 37, + EOS_POLYNOMIAL_C0 = 38, + EOS_POLYNOMIAL_C1 = 39, + EOS_POLYNOMIAL_C2 = 40, + EOS_POLYNOMIAL_C3 = 41, + EOS_POLYNOMIAL_C4 = 42, + EOS_POLYNOMIAL_C5 = 43, + EOS_POLYNOMIAL_C6 = 44, + + FAILURE_JC_D1 = 45, + FAILURE_JC_D2 = 46, + FAILURE_JC_D3 = 47, + FAILURE_JC_D4 = 48, + FAILURE_JC_EPDOT0 = 49, + + CRITICAL_ENERGY_RELEASE_RATE = 50, + + MAX_KEY_VALUE = 51 + }; + + struct failure_types { // this is defined per type and determines which failure/damage model is active + bool failure_none; + bool failure_max_principal_strain; + bool failure_max_principal_stress; + bool failure_max_plastic_strain; + bool failure_johnson_cook; + bool failure_max_pairwise_strain; + bool integration_point_wise; // true if failure model applies to stress/strain state of integration point + bool failure_energy_release_rate; + + failure_types() { + failure_none = true; + failure_max_principal_strain = false; + failure_max_principal_stress = false; + failure_max_plastic_strain = false; + failure_johnson_cook = false; + failure_max_pairwise_strain = false; + integration_point_wise = false; + failure_energy_release_rate = false; + //printf("constructed failure type\n"); + } + }; + failure_types *failureModel; + + int ifix_tlsph; + int update_method; + + class FixSMD_TLSPH_ReferenceConfiguration *fix_tlsph_reference_configuration; + +private: + double **Lookup; // holds per-type material parameters for the quantities defined in enum statement above. + bool first; // if first is true, do not perform any computations, beacuse reference configuration is not ready yet. +}; + +} + +#endif +#endif + +/* + * materialCoeffs array for EOS parameters: + * 1: rho0 + * + * + * materialCoeffs array for strength parameters: + * + * Common + * 10: maximum strain threshold for damage model + * 11: maximum stress threshold for damage model + * + * Linear Plasticity model: + * 12: plastic yield stress + * + * + * Blei: rho = 11.34e-6, c0=2000, s=1.46, Gamma=2.77 + * Stahl 1403: rho = 7.86e-3, c=4569, s=1.49, Gamma=2.17 + */ + diff --git a/src/USER-SMD/pair_smd_triangulated_surface.cpp b/src/USER-SMD/pair_smd_triangulated_surface.cpp new file mode 100644 index 0000000000..9fc057e1db --- /dev/null +++ b/src/USER-SMD/pair_smd_triangulated_surface.cpp @@ -0,0 +1,846 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing author: Mike Parks (SNL) + ------------------------------------------------------------------------- */ + +#include "math.h" +#include "float.h" +#include "stdlib.h" +#include "string.h" +#include "pair_smd_triangulated_surface.h" +#include "atom.h" +#include "domain.h" +#include "force.h" +#include "update.h" +#include "modify.h" +#include "fix.h" +#include "comm.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "neigh_request.h" +#include "memory.h" +#include "error.h" +#include +#include +#include + +using namespace std; +using namespace LAMMPS_NS; +using namespace Eigen; + +#define SQRT2 1.414213562e0 + +/* ---------------------------------------------------------------------- */ + +PairTriSurf::PairTriSurf(LAMMPS *lmp) : + Pair(lmp) { + + onerad_dynamic = onerad_frozen = maxrad_dynamic = maxrad_frozen = NULL; + bulkmodulus = NULL; + kn = NULL; + scale = 1.0; +} + +/* ---------------------------------------------------------------------- */ + +PairTriSurf::~PairTriSurf() { + + if (allocated) { + memory->destroy(setflag); + memory->destroy(cutsq); + memory->destroy(bulkmodulus); + memory->destroy(kn); + + delete[] onerad_dynamic; + delete[] onerad_frozen; + delete[] maxrad_dynamic; + delete[] maxrad_frozen; + } +} + +/* ---------------------------------------------------------------------- */ + +void PairTriSurf::compute(int eflag, int vflag) { + int i, j, ii, jj, inum, jnum, itype, jtype; + double rsq, r, evdwl, fpair; + int *ilist, *jlist, *numneigh, **firstneigh; + double rcut, r_geom, delta, r_tri, r_particle, touch_distance, dt_crit; + int tri, particle; + Vector3d normal, x1, x2, x3, x4, x13, x23, x43, w, cp, x4cp, vnew, v_old; + ; + Vector3d xi, x_center, dx; + Matrix2d C; + Vector2d w2d, rhs; + + evdwl = 0.0; + if (eflag || vflag) + ev_setup(eflag, vflag); + else + evflag = vflag_fdotr = 0; + + int *mol = atom->molecule; + double **f = atom->f; + double **smd_data_9 = atom->smd_data_9; + double **x = atom->x; + double **x0 = atom->x0; + double **v = atom->v; + double *rmass = atom->rmass; + int *type = atom->type; + int nlocal = atom->nlocal; + double *radius = atom->contact_radius; + double rcutSq; + Vector3d offset; + + int newton_pair = force->newton_pair; + int periodic = (domain->xperiodic || domain->yperiodic || domain->zperiodic); + + inum = list->inum; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + + int max_neighs = 0; + stable_time_increment = 1.0e22; + + // loop over neighbors of my atoms using a half neighbor list + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + itype = type[i]; + jlist = firstneigh[i]; + jnum = numneigh[i]; + max_neighs = MAX(max_neighs, jnum); + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + + j &= NEIGHMASK; + + jtype = type[j]; + + /* + * decide which one of i, j is triangle and which is particle + */ + if ((mol[i] < 65535) && (mol[j] >= 65535)) { + particle = i; + tri = j; + } else if ((mol[j] < 65535) && (mol[i] >= 65535)) { + particle = j; + tri = i; + } else { + error->one(FLERR, "unknown case"); + } + + //x_center << x[tri][0], x[tri][1], x[tri][2]; // center of triangle + x_center(0) = x[tri][0]; + x_center(1) = x[tri][1]; + x_center(2) = x[tri][2]; + //x4 << x[particle][0], x[particle][1], x[particle][2]; + x4(0) = x[particle][0]; + x4(1) = x[particle][1]; + x4(2) = x[particle][2]; + dx = x_center - x4; // + if (periodic) { + domain->minimum_image(dx(0), dx(1), dx(2)); + } + rsq = dx.squaredNorm(); + + r_tri = scale * radius[tri]; + r_particle = scale * radius[particle]; + rcut = r_tri + r_particle; + rcutSq = rcut * rcut; + + //printf("type i=%d, type j=%d, r=%f, ri=%f, rj=%f\n", itype, jtype, sqrt(rsq), ri, rj); + + if (rsq < rcutSq) { + + /* + * gather triangle information + */ + normal(0) = x0[tri][0]; + normal(1) = x0[tri][1]; + normal(2) = x0[tri][2]; + + /* + * distance check: is particle closer than its radius to the triangle plane? + */ + if (fabs(dx.dot(normal)) < radius[particle]) { + /* + * get other two triangle vertices + */ + x1(0) = smd_data_9[tri][0]; + x1(1) = smd_data_9[tri][1]; + x1(2) = smd_data_9[tri][2]; + x2(0) = smd_data_9[tri][3]; + x2(1) = smd_data_9[tri][4]; + x2(2) = smd_data_9[tri][5]; + x3(0) = smd_data_9[tri][6]; + x3(1) = smd_data_9[tri][7]; + x3(2) = smd_data_9[tri][8]; + + PointTriangleDistance(x4, x1, x2, x3, cp, r); + + /* + * distance to closest point + */ + x4cp = x4 - cp; + + /* + * flip normal to point in direction of x4cp + */ + + if (x4cp.dot(normal) < 0.0) { + normal *= -1.0; + } + + /* + * penalty force pushes particle away from triangle + */ + if (r < 1.0 * radius[particle]) { + + delta = radius[particle] - r; // overlap distance + r_geom = radius[particle]; + fpair = 1.066666667e0 * bulkmodulus[itype][jtype] * delta * sqrt(delta * r_geom); + dt_crit = 3.14 * sqrt(rmass[particle] / (fpair / delta)); + stable_time_increment = MIN(stable_time_increment, dt_crit); + + evdwl = r * fpair * 0.4e0 * delta; // GCG 25 April: this expression conserves total energy + + fpair /= (r + 1.0e-2 * radius[particle]); // divide by r + softening and multiply with non-normalized distance vector + + if (particle < nlocal) { + f[particle][0] += x4cp(0) * fpair; + f[particle][1] += x4cp(1) * fpair; + f[particle][2] += x4cp(2) * fpair; + } + + if (tri < nlocal) { + f[tri][0] -= x4cp(0) * fpair; + f[tri][1] -= x4cp(1) * fpair; + f[tri][2] -= x4cp(2) * fpair; + } + + if (evflag) { + ev_tally(i, j, nlocal, newton_pair, evdwl, 0.0, fpair, x4cp(0), x4cp(1), x4cp(2)); + } + + } + + /* + * if particle comes too close to triangle, reflect its velocity and explicitely move it away + */ + + touch_distance = 1.0 * radius[particle]; + if (r < touch_distance) { + + /* + * reflect velocity if it points toward triangle + */ + + normal = x4cp / r; + + //v_old << v[particle][0], v[particle][1], v[particle][2]; + v_old(0) = v[particle][0]; + v_old(1) = v[particle][1]; + v_old(2) = v[particle][2]; + if (v_old.dot(normal) < 0.0) { + //printf("flipping velocity\n"); + vnew = 1.0 * (-2.0 * v_old.dot(normal) * normal + v_old); + v[particle][0] = vnew(0); + v[particle][1] = vnew(1); + v[particle][2] = vnew(2); + } + + //printf("moving particle on top of triangle\n"); + x[particle][0] = cp(0) + touch_distance * normal(0); + x[particle][1] = cp(1) + touch_distance * normal(1); + x[particle][2] = cp(2) + touch_distance * normal(2); + } + + } + } + } + } + +// int max_neighs_all = 0; +// MPI_Allreduce(&max_neighs, &max_neighs_all, 1, MPI_INT, MPI_MAX, world); +// if (comm->me == 0) { +// printf("max. neighs in tri pair is %d\n", max_neighs_all); +// } +// +// double stable_time_increment_all = 0.0; +// MPI_Allreduce(&stable_time_increment, &stable_time_increment_all, 1, MPI_DOUBLE, MPI_MIN, world); +// if (comm->me == 0) { +// printf("stable time step tri pair is %f\n", stable_time_increment_all); +// } +} + +/* ---------------------------------------------------------------------- + allocate all arrays + ------------------------------------------------------------------------- */ + +void PairTriSurf::allocate() { + allocated = 1; + int n = atom->ntypes; + + memory->create(setflag, n + 1, n + 1, "pair:setflag"); + for (int i = 1; i <= n; i++) + for (int j = i; j <= n; j++) + setflag[i][j] = 0; + + memory->create(bulkmodulus, n + 1, n + 1, "pair:kspring"); + memory->create(kn, n + 1, n + 1, "pair:kn"); + + memory->create(cutsq, n + 1, n + 1, "pair:cutsq"); // always needs to be allocated, even with granular neighborlist + + onerad_dynamic = new double[n + 1]; + onerad_frozen = new double[n + 1]; + maxrad_dynamic = new double[n + 1]; + maxrad_frozen = new double[n + 1]; +} + +/* ---------------------------------------------------------------------- + global settings + ------------------------------------------------------------------------- */ + +void PairTriSurf::settings(int narg, char **arg) { + if (narg != 1) + error->all(FLERR, "Illegal number of args for pair_style smd/tri_surface"); + + scale = force->numeric(FLERR, arg[0]); + if (comm->me == 0) { + printf("\n>>========>>========>>========>>========>>========>>========>>========>>========\n"); + printf("SMD/TRI_SURFACE CONTACT SETTINGS:\n"); + printf("... effective contact radius is scaled by %f\n", scale); + printf(">>========>>========>>========>>========>>========>>========>>========>>========\n"); + } + +} + +/* ---------------------------------------------------------------------- + set coeffs for one or more type pairs + ------------------------------------------------------------------------- */ + +void PairTriSurf::coeff(int narg, char **arg) { + if (narg != 3) + error->all(FLERR, "Incorrect args for pair coefficients"); + if (!allocated) + allocate(); + + int ilo, ihi, jlo, jhi; + force->bounds(arg[0], atom->ntypes, ilo, ihi); + force->bounds(arg[1], atom->ntypes, jlo, jhi); + + double bulkmodulus_one = atof(arg[2]); + + // set short-range force constant + double kn_one = 0.0; + if (domain->dimension == 3) { + kn_one = (16. / 15.) * bulkmodulus_one; //assuming poisson ratio = 1/4 for 3d + } else { + kn_one = 0.251856195 * (2. / 3.) * bulkmodulus_one; //assuming poisson ratio = 1/3 for 2d + } + + int count = 0; + for (int i = ilo; i <= ihi; i++) { + for (int j = MAX(jlo, i); j <= jhi; j++) { + bulkmodulus[i][j] = bulkmodulus_one; + kn[i][j] = kn_one; + setflag[i][j] = 1; + count++; + } + } + + if (count == 0) + error->all(FLERR, "Incorrect args for pair coefficients"); +} + +/* ---------------------------------------------------------------------- + init for one type pair i,j and corresponding j,i + ------------------------------------------------------------------------- */ + +double PairTriSurf::init_one(int i, int j) { + + if (!allocated) + allocate(); + + if (setflag[i][j] == 0) + error->all(FLERR, "All pair coeffs are not set"); + + bulkmodulus[j][i] = bulkmodulus[i][j]; + kn[j][i] = kn[i][j]; + + // cutoff = sum of max I,J radii for + // dynamic/dynamic & dynamic/frozen interactions, but not frozen/frozen + + double cutoff = maxrad_dynamic[i] + maxrad_dynamic[j]; + cutoff = MAX(cutoff, maxrad_frozen[i] + maxrad_dynamic[j]); + cutoff = MAX(cutoff, maxrad_dynamic[i] + maxrad_frozen[j]); + + if (comm->me == 0) { + printf("cutoff for pair smd/smd/tri_surface = %f\n", cutoff); + } + return cutoff; +} + +/* ---------------------------------------------------------------------- + init specific to this pair style + ------------------------------------------------------------------------- */ + +void PairTriSurf::init_style() { + int i; + + // error checks + + if (!atom->contact_radius_flag) + error->all(FLERR, "Pair style smd/smd/tri_surface requires atom style with contact_radius"); + + // old: half list + int irequest = neighbor->request(this); + neighbor->requests[irequest]->half = 0; + neighbor->requests[irequest]->gran = 1; + + // need a full neighbor list +// int irequest = neighbor->request(this); +// neighbor->requests[irequest]->half = 0; +// neighbor->requests[irequest]->full = 1; + + // set maxrad_dynamic and maxrad_frozen for each type + // include future Fix pour particles as dynamic + + for (i = 1; i <= atom->ntypes; i++) + onerad_dynamic[i] = onerad_frozen[i] = 0.0; + + double *radius = atom->radius; + int *type = atom->type; + int nlocal = atom->nlocal; + + for (i = 0; i < nlocal; i++) { + onerad_dynamic[type[i]] = MAX(onerad_dynamic[type[i]], radius[i]); + } + + MPI_Allreduce(&onerad_dynamic[1], &maxrad_dynamic[1], atom->ntypes, MPI_DOUBLE, MPI_MAX, world); + MPI_Allreduce(&onerad_frozen[1], &maxrad_frozen[1], atom->ntypes, MPI_DOUBLE, MPI_MAX, world); +} + +/* ---------------------------------------------------------------------- + neighbor callback to inform pair style of neighbor list to use + optional granular history list + ------------------------------------------------------------------------- */ + +void PairTriSurf::init_list(int id, NeighList *ptr) { + if (id == 0) + list = ptr; +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based arrays + ------------------------------------------------------------------------- */ + +double PairTriSurf::memory_usage() { + + return 0.0; +} + +/* + * distance between triangle and point + */ +/* + function [dist,PP0] = pointTriangleDistance(TRI,P) + % calculate distance between a point and a triangle in 3D + % SYNTAX + % dist = pointTriangleDistance(TRI,P) + % [dist,PP0] = pointTriangleDistance(TRI,P) + % + % DESCRIPTION + % Calculate the distance of a given point P from a triangle TRI. + % Point P is a row vector of the form 1x3. The triangle is a matrix + % formed by three rows of points TRI = [P1;P2;P3] each of size 1x3. + % dist = pointTriangleDistance(TRI,P) returns the distance of the point P + % to the triangle TRI. + % [dist,PP0] = pointTriangleDistance(TRI,P) additionally returns the + % closest point PP0 to P on the triangle TRI. + % + % Author: Gwendolyn Fischer + % Release: 1.0 + % Release date: 09/02/02 + % Release: 1.1 Fixed Bug because of normalization + % Release: 1.2 Fixed Bug because of typo in region 5 20101013 + % Release: 1.3 Fixed Bug because of typo in region 2 20101014 + + % Possible extention could be a version tailored not to return the distance + % and additionally the closest point, but instead return only the closest + % point. Could lead to a small speed gain. + + % Example: + % %% The Problem + % P0 = [0.5 -0.3 0.5]; + % + % P1 = [0 -1 0]; + % P2 = [1 0 0]; + % P3 = [0 0 0]; + % + % vertices = [P1; P2; P3]; + % faces = [1 2 3]; + % + % %% The Engine + % [dist,PP0] = pointTriangleDistance([P1;P2;P3],P0); + % + % %% Visualization + % [x,y,z] = sphere(20); + % x = dist*x+P0(1); + % y = dist*y+P0(2); + % z = dist*z+P0(3); + % + % figure + % hold all + % patch('Vertices',vertices,'Faces',faces,'FaceColor','r','FaceAlpha',0.8); + % plot3(P0(1),P0(2),P0(3),'b*'); + % plot3(PP0(1),PP0(2),PP0(3),'*g') + % surf(x,y,z,'FaceColor','b','FaceAlpha',0.3) + % view(3) + + % The algorithm is based on + % "David Eberly, 'Distance Between Point and Triangle in 3D', + % Geometric Tools, LLC, (1999)" + % http:\\www.geometrictools.com/Documentation/DistancePoint3Triangle3.pdf + % + % ^t + % \ | + % \reg2| + % \ | + % \ | + % \ | + % \| + % *P2 + % |\ +% | \ +% reg3 | \ reg1 + % | \ +% |reg0\ +% | \ +% | \ P1 + % -------*-------*------->s + % |P0 \ +% reg4 | reg5 \ reg6 + */ + +//void PairTriSurf::PointTriangleDistance(const Vector3d P, const Vector3d TRI1, const Vector3d TRI2, const Vector3d TRI3, +// Vector3d &CP, double &dist) { +// +// Vector3d B, E0, E1, D; +// double a, b, c, d, e, f; +// double det, s, t, sqrDistance, tmp0, tmp1, numer, denom, invDet; +// +// // rewrite triangle in normal form +// B = TRI1; +// E0 = TRI2 - B; +// E1 = TRI3 - B; +// +// D = B - P; +// a = E0.dot(E0); +// b = E0.dot(E1); +// c = E1.dot(E1); +// d = E0.dot(D); +// e = E1.dot(D); +// f = D.dot(D); +// +// det = a * c - b * b; +// //% do we have to use abs here? +// s = b * e - c * d; +// t = b * d - a * e; +// +// //% Terible tree of conditionals to determine in which region of the diagram +// //% shown above the projection of the point into the triangle-plane lies. +// if ((s + t) <= det) { +// if (s < 0) { +// if (t < 0) { +// // %region4 +// if (d < 0) { +// t = 0; +// if (-d >= a) { +// s = 1; +// sqrDistance = a + 2 * d + f; +// } else { +// s = -d / a; +// sqrDistance = d * s + f; +// } +// } else { +// s = 0; +// if (e >= 0) { +// t = 0; +// sqrDistance = f; +// } else { +// if (-e >= c) { +// t = 1; +// sqrDistance = c + 2 * e + f; +// } else { +// t = -e / c; +// sqrDistance = e * t + f; +// } +// } +// } +// // end % of region 4 +// } else { +// // % region 3 +// s = 0; +// if (e >= 0) { +// t = 0; +// sqrDistance = f; +// } else { +// if (-e >= c) { +// t = 1; +// sqrDistance = c + 2 * e + f; +// } else { +// t = -e / c; +// sqrDistance = e * t + f; +// } +// } +// } +// // end of region 3 +// } else { +// if (t < 0) { +// //% region 5 +// t = 0; +// if (d >= 0) { +// s = 0; +// sqrDistance = f; +// } else { +// if (-d >= a) { +// s = 1; +// sqrDistance = a + 2 * d + f; +// } else { +// s = -d / a; +// sqrDistance = d * s + f; +// } +// } +// } else { +// // region 0 +// invDet = 1 / det; +// s = s * invDet; +// t = t * invDet; +// sqrDistance = s * (a * s + b * t + 2 * d) + t * (b * s + c * t + 2 * e) + f; +// } +// } +// } else { +// if (s < 0) { +// // % region 2 +// tmp0 = b + d; +// tmp1 = c + e; +// if (tmp1 > tmp0) { //% minimum on edge s+t=1 +// numer = tmp1 - tmp0; +// denom = a - 2 * b + c; +// if (numer >= denom) { +// s = 1; +// t = 0; +// sqrDistance = a + 2 * d + f; +// } else { +// s = numer / denom; +// t = 1 - s; +// sqrDistance = s * (a * s + b * t + 2 * d) + t * (b * s + c * t + 2 * e) + f; +// } +// } else +// // % minimum on edge s=0 +// s = 0; +// if (tmp1 <= 0) { +// t = 1; +// sqrDistance = c + 2 * e + f; +// } else { +// if (e >= 0) { +// t = 0; +// sqrDistance = f; +// } else { +// t = -e / c; +// sqrDistance = e * t + f; +// } +// } +// } //end % of region 2 +// else { +// if (t < 0) { +// // %region6 +// tmp0 = b + e; +// tmp1 = a + d; +// if (tmp1 > tmp0) { +// numer = tmp1 - tmp0; +// denom = a - 2 * b + c; +// if (numer >= denom) { +// t = 1; +// s = 0; +// sqrDistance = c + 2 * e + f; +// } else { +// t = numer / denom; +// s = 1 - t; +// sqrDistance = s * (a * s + b * t + 2 * d) + t * (b * s + c * t + 2 * e) + f; +// } +// } else { +// t = 0; +// if (tmp1 <= 0) { +// s = 1; +// sqrDistance = a + 2 * d + f; +// } else { +// if (d >= 0) { +// s = 0; +// sqrDistance = f; +// } else { +// s = -d / a; +// sqrDistance = d * s + f; +// } +// } +// } // % end region 6 +// } else { +// //% region 1 +// numer = c + e - b - d; +// if (numer <= 0) { +// s = 0; +// t = 1; +// sqrDistance = c + 2 * e + f; +// } else { +// denom = a - 2 * b + c; +// if (numer >= denom) { +// s = 1; +// t = 0; +// sqrDistance = a + 2 * d + f; +// } else { +// s = numer / denom; +// t = 1 - s; +// sqrDistance = s * (a * s + b * t + 2 * d) + t * (b * s + c * t + 2 * e) + f; +// } +// } //% end of region 1 +// } +// } +// } +// +// // % account for numerical round-off error +// if (sqrDistance < 0) { +// sqrDistance = 0; +// } +// +// dist = sqrt(sqrDistance); +// +// // closest point +// CP = B + s * E0 + t * E1; +// +//} +/* + * % The algorithm is based on + % "David Eberly, 'Distance Between Point and Triangle in 3D', + % Geometric Tools, LLC, (1999)" + % http:\\www.geometrictools.com/Documentation/DistancePoint3Triangle3.pdf + */ + +void PairTriSurf::PointTriangleDistance(const Vector3d sourcePosition, const Vector3d TRI0, const Vector3d TRI1, + const Vector3d TRI2, Vector3d &CP, double &dist) { + + Vector3d edge0 = TRI1 - TRI0; + Vector3d edge1 = TRI2 - TRI0; + Vector3d v0 = TRI0 - sourcePosition; + + double a = edge0.dot(edge0); + double b = edge0.dot(edge1); + double c = edge1.dot(edge1); + double d = edge0.dot(v0); + double e = edge1.dot(v0); + + double det = a * c - b * b; + double s = b * e - c * d; + double t = b * d - a * e; + + if (s + t < det) { + if (s < 0.f) { + if (t < 0.f) { + if (d < 0.f) { + s = clamp(-d / a, 0.f, 1.f); + t = 0.f; + } else { + s = 0.f; + t = clamp(-e / c, 0.f, 1.f); + } + } else { + s = 0.f; + t = clamp(-e / c, 0.f, 1.f); + } + } else if (t < 0.f) { + s = clamp(-d / a, 0.f, 1.f); + t = 0.f; + } else { + float invDet = 1.f / det; + s *= invDet; + t *= invDet; + } + } else { + if (s < 0.f) { + float tmp0 = b + d; + float tmp1 = c + e; + if (tmp1 > tmp0) { + float numer = tmp1 - tmp0; + float denom = a - 2 * b + c; + s = clamp(numer / denom, 0.f, 1.f); + t = 1 - s; + } else { + t = clamp(-e / c, 0.f, 1.f); + s = 0.f; + } + } else if (t < 0.f) { + if (a + d > b + e) { + float numer = c + e - b - d; + float denom = a - 2 * b + c; + s = clamp(numer / denom, 0.f, 1.f); + t = 1 - s; + } else { + s = clamp(-e / c, 0.f, 1.f); + t = 0.f; + } + } else { + float numer = c + e - b - d; + float denom = a - 2 * b + c; + s = clamp(numer / denom, 0.f, 1.f); + t = 1.f - s; + } + } + + CP = TRI0 + s * edge0 + t * edge1; + dist = (CP - sourcePosition).norm(); + +} + +double PairTriSurf::clamp(const double a, const double min, const double max) { + if (a < min) { + return min; + } else if (a > max) { + return max; + } else { + return a; + } +} + +void *PairTriSurf::extract(const char *str, int &i) { + //printf("in PairTriSurf::extract\n"); + if (strcmp(str, "smd/tri_surface/stable_time_increment_ptr") == 0) { + return (void *) &stable_time_increment; + } + + return NULL; + +} diff --git a/src/USER-SMD/pair_smd_triangulated_surface.h b/src/USER-SMD/pair_smd_triangulated_surface.h new file mode 100644 index 0000000000..1cfd88f1fa --- /dev/null +++ b/src/USER-SMD/pair_smd_triangulated_surface.h @@ -0,0 +1,75 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef PAIR_CLASS + +PairStyle(smd/tri_surface,PairTriSurf) + +#else + +#ifndef LMP_SMD_TRI_SURFACE_H +#define LMP_SMD_TRI_SURFACE_H + +#include "pair.h" +#include +using namespace Eigen; + + +namespace LAMMPS_NS { + +class PairTriSurf : public Pair { + public: + PairTriSurf(class LAMMPS *); + virtual ~PairTriSurf(); + virtual void compute(int, int); + void settings(int, char **); + void coeff(int, char **); + double init_one(int, int); + void init_style(); + void init_list(int, class NeighList *); + virtual double memory_usage(); + void PointTriangleDistance(const Vector3d P, const Vector3d TRI1, const Vector3d TRI2, const Vector3d TRI3, + Vector3d &CP, double &dist); + double clamp(const double a, const double min, const double max); + void *extract(const char *, int &); + + protected: + double **bulkmodulus; + double **kn; + + double *onerad_dynamic,*onerad_frozen; + double *maxrad_dynamic,*maxrad_frozen; + + double scale; + double stable_time_increment; // stable time step size + + void allocate(); +}; + +} + +#endif +#endif + diff --git a/src/USER-SMD/pair_smd_ulsph.cpp b/src/USER-SMD/pair_smd_ulsph.cpp new file mode 100644 index 0000000000..92b6a6c0fd --- /dev/null +++ b/src/USER-SMD/pair_smd_ulsph.cpp @@ -0,0 +1,1655 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +#include "math.h" +#include "float.h" +#include "stdlib.h" +#include "string.h" +#include "pair_smd_ulsph.h" +#include "atom.h" +#include "domain.h" +#include "force.h" +#include "update.h" +#include "modify.h" +#include "fix.h" +#include "comm.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "neigh_request.h" +#include "memory.h" +#include "error.h" +#include +#include +#include "smd_material_models.h" +#include "smd_math.h" +#include "smd_kernels.h" + +using namespace SMD_Kernels; +using namespace std; +using namespace LAMMPS_NS; +using namespace SMD_Math; + +#include +#include +using namespace Eigen; + +#define ARTIFICIAL_STRESS false +#define FORMAT1 "%60s : %g\n" +#define FORMAT2 "\n.............................. %s \n" + +PairULSPH::PairULSPH(LAMMPS *lmp) : + Pair(lmp) { + + // per-type arrays + Q1 = NULL; + eos = viscosity = strength = NULL; + c0_type = NULL; + c0 = NULL; + Lookup = NULL; + artificial_stress = NULL; + artificial_pressure = NULL; + + nmax = 0; // make sure no atom on this proc such that initial memory allocation is correct + stressTensor = L = K = NULL; + shepardWeight = NULL; + smoothVel = NULL; + numNeighs = NULL; + F = NULL; + rho = NULL; + effm = NULL; + + velocity_gradient_required = false; // turn off computation of velocity gradient by default + density_summation = velocity_gradient = false; + + comm_forward = 18; // this pair style communicates 18 doubles to ghost atoms + updateFlag = 0; +} + +/* ---------------------------------------------------------------------- */ + +PairULSPH::~PairULSPH() { + if (allocated) { + //printf("... deallocating\n"); + memory->destroy(Q1); + memory->destroy(rho0); + memory->destroy(eos); + memory->destroy(viscosity); + memory->destroy(strength); + memory->destroy(c0_type); + memory->destroy(Lookup); + memory->destroy(artificial_pressure); + memory->destroy(artificial_stress); + + delete[] onerad_dynamic; + delete[] onerad_frozen; + delete[] maxrad_dynamic; + delete[] maxrad_frozen; + + delete[] K; + delete[] shepardWeight; + delete[] c0; + delete[] smoothVel; + delete[] stressTensor; + delete[] L; + delete[] numNeighs; + delete[] F; + delete[] rho; + delete[] effm; + + } +} + +/* ---------------------------------------------------------------------- + * + * Re-compute mass density from scratch. + * Only used for plain fluid SPH with no physical viscosity models. + * + ---------------------------------------------------------------------- */ + +void PairULSPH::PreCompute_DensitySummation() { + double *radius = atom->radius; + double **x = atom->x; + double *rmass = atom->rmass; + int *type = atom->type; + int *ilist, *jlist, *numneigh; + int **firstneigh; + int nlocal = atom->nlocal; + int inum, jnum, ii, jj, i, itype, jtype, j; + double h, irad, hsq, rSq, wf; + Vector3d dx, xi, xj; + + // set up neighbor list variables + inum = list->inum; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + + // zero accumulators + for (i = 0; i < nlocal; i++) { + rho[i] = 0.0; + //shepardWeight[i] = 0.0; + } + + /* + * only recompute mass density if density summation is used. + * otherwise, change in mass density is time-integrated + */ + for (i = 0; i < nlocal; i++) { + itype = type[i]; + if (setflag[itype][itype] == 1) { + // initialize particle density with self-contribution. + h = 2.0 * radius[i]; + hsq = h * h; + Poly6Kernel(hsq, h, 0.0, domain->dimension, wf); + rho[i] = wf * rmass[i]; // / shepardWeight[i]; + //printf("SIC to rho is %f\n", rho[i]); + } + } + + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + itype = type[i]; + jlist = firstneigh[i]; + jnum = numneigh[i]; + irad = radius[i]; + + xi << x[i][0], x[i][1], x[i][2]; + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + j &= NEIGHMASK; + + xj << x[j][0], x[j][1], x[j][2]; + dx = xj - xi; + rSq = dx.squaredNorm(); + h = irad + radius[j]; + hsq = h * h; + if (rSq < hsq) { + + jtype = type[j]; + Poly6Kernel(hsq, h, rSq, domain->dimension, wf); + + if (setflag[itype][itype] == 1) { + rho[i] += wf * rmass[j]; // / shepardWeight[i]; + } + + if (j < nlocal) { + if (setflag[jtype][jtype] == 1) { + rho[j] += wf * rmass[i]; // / shepardWeight[j]; + } + } + } // end if check distance + } // end loop over j + } // end loop over i +} + +/* ---------------------------------------------------------------------- + * + * Compute shape matrix for kernel gradient correction and velocity gradient. + * This is used if material strength or viscosity models are employed. + * + ---------------------------------------------------------------------- */ + +void PairULSPH::PreCompute() { + double **atom_data9 = atom->smd_data_9; + double *radius = atom->radius; + double **x = atom->x; + double **x0 = atom->x0; + double **v = atom->vest; + double *vfrac = atom->vfrac; + int *type = atom->type; + int *ilist, *jlist, *numneigh; + int **firstneigh; + int nlocal = atom->nlocal; + int inum, jnum, ii, jj, i, itype, jtype, j, idim; + double wfd, h, irad, r, rSq, wf, ivol, jvol; + Vector3d dx, dv, g, du; + Matrix3d Ktmp, Ltmp, Ftmp, K3di, D; + Vector3d xi, xj, vi, vj, x0i, x0j, dx0; + Matrix2d K2di, K2d; + + // zero accumulators + for (i = 0; i < nlocal; i++) { + itype = type[i]; + if (setflag[itype][itype]) { + if (gradient_correction_flag) { + K[i].setZero(); + } else { + K[i].setIdentity(); + } + L[i].setZero(); + F[i].setZero(); + } + } + + // set up neighbor list variables + inum = list->inum; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + itype = type[i]; + jlist = firstneigh[i]; + jnum = numneigh[i]; + irad = radius[i]; + ivol = vfrac[i]; + + // initialize Eigen data structures from LAMMPS data structures + for (idim = 0; idim < 3; idim++) { + x0i(idim) = x0[i][idim]; + xi(idim) = x[i][idim]; + vi(idim) = v[i][idim]; + } + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + j &= NEIGHMASK; + + for (idim = 0; idim < 3; idim++) { + x0j(idim) = x0[j][idim]; + xj(idim) = x[j][idim]; + vj(idim) = v[j][idim]; + } + + dx = xj - xi; + + rSq = dx.squaredNorm(); + h = irad + radius[j]; + if (rSq < h * h) { + + r = sqrt(rSq); + jtype = type[j]; + jvol = vfrac[j]; + + // distance vectors in current and reference configuration, velocity difference + dv = vj - vi; + dx0 = x0j - x0i; + + // kernel and derivative + spiky_kernel_and_derivative(h, r, domain->dimension, wf, wfd); + //barbara_kernel_and_derivative(h, r, domain->dimension, wf, wfd); + + // uncorrected kernel gradient + g = (wfd / r) * dx; + + /* build correction matrix for kernel derivatives */ + if (gradient_correction_flag) { + Ktmp = -g * dx.transpose(); + K[i] += jvol * Ktmp; + } + + // velocity gradient L + Ltmp = -dv * g.transpose(); + L[i] += jvol * Ltmp; + + // deformation gradient F in Eulerian frame + du = dx - dx0; + Ftmp = dv * g.transpose(); + F[i] += jvol * Ftmp; + + if (j < nlocal) { + + if (gradient_correction_flag) { + K[j] += ivol * Ktmp; + } + + L[j] += ivol * Ltmp; + F[j] += ivol * Ftmp; + } + } // end if check distance + } // end loop over j + } // end loop over i + + /* + * invert shape matrix and compute corrected quantities + */ + + for (i = 0; i < nlocal; i++) { + itype = type[i]; + if (setflag[itype][itype]) { + if (gradient_correction_flag) { + pseudo_inverse_SVD(K[i]); + K[i] = LimitEigenvalues(K[i], 2.0); + L[i] *= K[i]; + F[i] *= K[i]; + } // end if (gradient_correction[itype]) { + + /* + * accumulate strain increments + * we abuse the atom array "atom_data_9" for this purpose, which was originally designed to hold the deformation gradient. + */ + D = update->dt * 0.5 * (L[i] + L[i].transpose()); + atom_data9[i][0] += D(0, 0); // xx + atom_data9[i][1] += D(1, 1); // yy + atom_data9[i][2] += D(2, 2); // zz + atom_data9[i][3] += D(0, 1); // xy + atom_data9[i][4] += D(0, 2); // xz + atom_data9[i][5] += D(1, 2); // yz + + } // end if (setflag[itype][itype]) + } // end loop over i = 0 to nlocal + +} + +/* ---------------------------------------------------------------------- */ + +void PairULSPH::compute(int eflag, int vflag) { + double **x = atom->x; + double **v = atom->vest; + double **vint = atom->v; // Velocity-Verlet algorithm velocities + double **f = atom->f; + double *vfrac = atom->vfrac; + double *de = atom->de; + double *rmass = atom->rmass; + double *radius = atom->radius; + double *contact_radius = atom->contact_radius; + double **atom_data9 = atom->smd_data_9; + + int *type = atom->type; + int nlocal = atom->nlocal; + int i, j, ii, jj, jnum, itype, jtype, iDim, inum; + double r, wf, wfd, h, rSq, ivol, jvol; + double mu_ij, c_ij, rho_ij; + double delVdotDelR, visc_magnitude, deltaE; + int *ilist, *jlist, *numneigh; + int **firstneigh; + Vector3d fi, fj, dx, dv, f_stress, g, vinti, vintj, dvint; + Vector3d xi, xj, vi, vj, f_visc, sumForces, f_stress_new; + Vector3d gamma, f_hg, dx0, du_est, du; + double r_ref, weight, p; + //int periodic = (domain->xperiodic || domain->yperiodic || domain->zperiodic); + + double ini_dist; + Matrix3d S, D, V, eye; + eye.setIdentity(); + int k; + SelfAdjointEigenSolver < Matrix3d > es; + + if (eflag || vflag) + ev_setup(eflag, vflag); + else + evflag = vflag_fdotr = 0; + + if (atom->nmax > nmax) { +//printf("... allocating in compute with nmax = %d\n", atom->nmax); + nmax = atom->nmax; + delete[] K; + K = new Matrix3d[nmax]; + delete[] shepardWeight; + shepardWeight = new double[nmax]; + delete[] c0; + c0 = new double[nmax]; + delete[] smoothVel; + smoothVel = new Vector3d[nmax]; + delete[] stressTensor; + stressTensor = new Matrix3d[nmax]; + delete[] L; + L = new Matrix3d[nmax]; + delete[] numNeighs; + numNeighs = new int[nmax]; + delete[] F; + F = new Matrix3d[nmax]; + delete[] rho; + rho = new double[nmax]; + delete[] effm; + effm = new double[nmax]; + } + +// zero accumulators + for (i = 0; i < nlocal; i++) { + shepardWeight[i] = 0.0; + smoothVel[i].setZero(); + numNeighs[i] = 0; + + h = 2.0 * radius[i]; + r = 0.0; + spiky_kernel_and_derivative(h, r, domain->dimension, wf, wfd); + } + + /* + * if this is the very first step, zero the array which holds the accumulated strain + */ + if (update->ntimestep == 0) { + for (i = 0; i < nlocal; i++) { + itype = type[i]; + if (setflag[itype][itype]) { + for (j = 0; j < 9; j++) { + atom_data9[i][j] = 0.0; + } + } + } + } + + if (density_summation) { + //printf("dens summ\n"); + PreCompute_DensitySummation(); + + for (i = 0; i < nlocal; i++) { //compute volumes from rho + itype = type[i]; + if (setflag[itype][itype]) { + vfrac[i] = rmass[i] / rho[i]; + } + } + + } + + if (velocity_gradient) { + PairULSPH::PreCompute(); // get velocity gradient and kernel gradient correction + } + + PairULSPH::AssembleStressTensor(); + + /* + * QUANTITIES ABOVE HAVE ONLY BEEN CALCULATED FOR NLOCAL PARTICLES. + * NEED TO DO A FORWARD COMMUNICATION TO GHOST ATOMS NOW + */ + comm->forward_comm_pair(this); + + updateFlag = 0; + + /* + * iterate over pairs of particles i, j and assign forces using pre-computed pressure + */ + +// set up neighbor list variables + inum = list->inum; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + itype = type[i]; + jlist = firstneigh[i]; + jnum = numneigh[i]; + ivol = vfrac[i]; + + // initialize Eigen data structures from LAMMPS data structures + for (iDim = 0; iDim < 3; iDim++) { + xi(iDim) = x[i][iDim]; + vi(iDim) = v[i][iDim]; + vinti(iDim) = vint[i][iDim]; + } + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + j &= NEIGHMASK; + + xj(0) = x[j][0]; + xj(1) = x[j][1]; + xj(2) = x[j][2]; + + dx = xj - xi; + rSq = dx.squaredNorm(); + h = radius[i] + radius[j]; + if (rSq < h * h) { + + // initialize Eigen data structures from LAMMPS data structures + for (iDim = 0; iDim < 3; iDim++) { + vj(iDim) = v[j][iDim]; + vintj(iDim) = vint[j][iDim]; + } + + r = sqrt(rSq); + jtype = type[j]; + jvol = vfrac[j]; + + // distance vectors in current and reference configuration, velocity difference + dv = vj - vi; + dvint = vintj - vinti; + + // kernel and derivative + spiky_kernel_and_derivative(h, r, domain->dimension, wf, wfd); + //barbara_kernel_and_derivative(h, r, domain->dimension, wf, wfd); + + // uncorrected kernel gradient + g = (wfd / r) * dx; + + delVdotDelR = dx.dot(dv) / (r + 0.1 * h); // project relative velocity onto unit particle distance vector [m/s] + + S = stressTensor[i] + stressTensor[j]; + + if (artificial_pressure[itype][jtype] > 0.0) { + p = S.trace(); + if (p > 0.0) { // we are in tension + r_ref = contact_radius[i] + contact_radius[j]; + weight = Kernel_Cubic_Spline(r, h) / Kernel_Cubic_Spline(r_ref, h); + weight = pow(weight, 4.0); + S -= artificial_pressure[itype][jtype] * weight * p * eye; + } + } + + /* + * artificial stress to control tensile instability + * Only works if particles are uniformly spaced initially. + */ + if (artificial_stress[itype][jtype] > 0.0) { + ini_dist = contact_radius[i] + contact_radius[j]; + weight = Kernel_Cubic_Spline(r, h) / Kernel_Cubic_Spline(ini_dist, h); + weight = pow(weight, 4.0); + + es.compute(S); + D = es.eigenvalues().asDiagonal(); + for (k = 0; k < 3; k++) { + if (D(k, k) > 0.0) { + D(k, k) -= weight * artificial_stress[itype][jtype] * D(k, k); + } + } + V = es.eigenvectors(); + S = V * D * V.inverse(); + } + + // compute forces + f_stress = -ivol * jvol * S * g; // DO NOT TOUCH SIGN + + /* + * artificial viscosity -- alpha is dimensionless + * MonaghanBalsara form of the artificial viscosity + */ + + c_ij = 0.5 * (c0[i] + c0[j]); + LimitDoubleMagnitude(delVdotDelR, 1.1 * c_ij); + + mu_ij = h * delVdotDelR / (r + 0.1 * h); // units: [m * m/s / m = m/s] + rho_ij = 0.5 * (rmass[i] / ivol + rmass[j] / jvol); + visc_magnitude = 0.5 * (Q1[itype] + Q1[jtype]) * c_ij * mu_ij / rho_ij; + f_visc = -rmass[i] * rmass[j] * visc_magnitude * g; + + if ((Lookup[HOURGLASS_CONTROL_AMPLITUDE][itype] > 0.0) && (Lookup[HOURGLASS_CONTROL_AMPLITUDE][jtype] > 0.0)) { + f_hg = ComputeHourglassForce(i, itype, j, jtype, dv, dx, g, c_ij, mu_ij, rho_ij); + + } else { + f_hg.setZero(); + } + + sumForces = f_stress + f_visc + f_hg; + + // energy rate -- project velocity onto force vector + deltaE = sumForces.dot(dv); + + // apply forces to pair of particles + f[i][0] += sumForces(0); + f[i][1] += sumForces(1); + f[i][2] += sumForces(2); + de[i] += deltaE; + + // accumulate smooth velocities + shepardWeight[i] += jvol * wf; + smoothVel[i] += jvol * wf * dvint; + numNeighs[i] += 1; + + if (j < nlocal) { + f[j][0] -= sumForces(0); + f[j][1] -= sumForces(1); + f[j][2] -= sumForces(2); + de[j] += deltaE; + + shepardWeight[j] += ivol * wf; + smoothVel[j] -= ivol * wf * dvint; + numNeighs[j] += 1; + } + + // tally atomistic stress tensor + if (evflag) { + ev_tally_xyz(i, j, nlocal, 0, 0.0, 0.0, sumForces(0), sumForces(1), sumForces(2), dx(0), dx(1), dx(2)); + } + } + + } + } + + for (i = 0; i < nlocal; i++) { + itype = type[i]; + if (setflag[itype][itype] == 1) { + if (shepardWeight[i] != 0.0) { + smoothVel[i] /= shepardWeight[i]; + } else { + smoothVel[i].setZero(); + } + } // end check if particle is SPH-type + } // end loop over i = 0 to nlocal + + if (vflag_fdotr) + virial_fdotr_compute(); + +} + +/* ---------------------------------------------------------------------- + Assemble total stress tensor with pressure, material sterength, and + viscosity contributions. + ------------------------------------------------------------------------- */ +void PairULSPH::AssembleStressTensor() { + double *radius = atom->radius; + double *vfrac = atom->vfrac; + double *rmass = atom->rmass; + double *eff_plastic_strain = atom->eff_plastic_strain; + double **tlsph_stress = atom->smd_stress; + double *e = atom->e; + int *type = atom->type; + double pFinal; + int i, itype; + int nlocal = atom->nlocal; + Matrix3d D, Ddev, W, V, sigma_diag; + Matrix3d eye, stressRate, StressRateDevJaumann; + Matrix3d sigmaInitial_dev, d_dev, sigmaFinal_dev, stressRateDev, oldStressDeviator, newStressDeviator; + double plastic_strain_increment, yieldStress; + double dt = update->dt; + double vol, newPressure; + double G_eff = 0.0; // effective shear modulus + double K_eff; // effective bulk modulus + double M, p_wave_speed; + double rho, effectiveViscosity; + Matrix3d deltaStressDev; + + dtCFL = 1.0e22; + eye.setIdentity(); + + for (i = 0; i < nlocal; i++) { + itype = type[i]; + if (setflag[itype][itype] == 1) { + newStressDeviator.setZero(); + newPressure = 0.0; + stressTensor[i].setZero(); + vol = vfrac[i]; + rho = rmass[i] / vfrac[i]; + effectiveViscosity = 0.0; + K_eff = 0.0; + G_eff = 0.0; + + //printf("rho = %f\n", rho); + + switch (eos[itype]) { + default: + error->one(FLERR, "unknown EOS."); + break; + case NONE: + pFinal = 0.0; + c0[i] = 1.0; + break; + case EOS_TAIT: + TaitEOS_density(Lookup[EOS_TAIT_EXPONENT][itype], Lookup[REFERENCE_SOUNDSPEED][itype], + Lookup[REFERENCE_DENSITY][itype], rho, newPressure, c0[i]); + //printf("new pressure =%f\n", newPressure); + + break; + case EOS_PERFECT_GAS: + PerfectGasEOS(Lookup[EOS_PERFECT_GAS_GAMMA][itype], vol, rmass[i], e[i], newPressure, c0[i]); + break; + case EOS_LINEAR: + newPressure = Lookup[BULK_MODULUS][itype] * (rho / Lookup[REFERENCE_DENSITY][itype] - 1.0); + //printf("p=%f, rho0=%f, rho=%f\n", newPressure, Lookup[REFERENCE_DENSITY][itype], rho); + c0[i] = Lookup[REFERENCE_SOUNDSPEED][itype]; + break; + } + + K_eff = c0[i] * c0[i] * rho; // effective bulk modulus + + /* + * ******************************* STRENGTH MODELS ************************************************ + */ + + if (strength[itype] != NONE) { + /* + * initial stress state: given by the unrotateted Cauchy stress. + * Assemble Eigen 3d matrix from stored stress state + */ + oldStressDeviator(0, 0) = tlsph_stress[i][0]; + oldStressDeviator(0, 1) = tlsph_stress[i][1]; + oldStressDeviator(0, 2) = tlsph_stress[i][2]; + oldStressDeviator(1, 1) = tlsph_stress[i][3]; + oldStressDeviator(1, 2) = tlsph_stress[i][4]; + oldStressDeviator(2, 2) = tlsph_stress[i][5]; + oldStressDeviator(1, 0) = oldStressDeviator(0, 1); + oldStressDeviator(2, 0) = oldStressDeviator(0, 2); + oldStressDeviator(2, 1) = oldStressDeviator(1, 2); + + D = 0.5 * (L[i] + L[i].transpose()); + W = 0.5 * (L[i] - L[i].transpose()); // spin tensor:: need this for Jaumann rate + d_dev = Deviator(D); + + switch (strength[itype]) { + default: + error->one(FLERR, "unknown strength model."); + break; + case STRENGTH_LINEAR: + + // here in a version with pressure part +// stressRateDev = Lookup[BULK_MODULUS][itype] * d_iso * eye + 2.0 * Lookup[SHEAR_MODULUS][itype] * d_dev; +// c0[i] = Lookup[REFERENCE_SOUNDSPEED][itype]; +// newPressure = 0.0; + + // here only stress deviator + stressRateDev = 2.0 * Lookup[SHEAR_MODULUS][itype] * d_dev; + //cout << "stress rate deviator is " << endl << stressRateDev << endl; + break; + + case STRENGTH_LINEAR_PLASTIC: + yieldStress = Lookup[YIELD_STRENGTH][itype] + Lookup[HARDENING_PARAMETER][itype] * eff_plastic_strain[i]; + LinearPlasticStrength(Lookup[SHEAR_MODULUS][itype], yieldStress, oldStressDeviator, d_dev, dt, + newStressDeviator, stressRateDev, plastic_strain_increment); + eff_plastic_strain[i] += plastic_strain_increment; + + break; + } + + //double m = effective_longitudinal_modulus(itype, dt, d_iso, p_rate, d_dev, stressRate_dev, damage); + + StressRateDevJaumann = stressRateDev - W * oldStressDeviator + oldStressDeviator * W; + newStressDeviator = oldStressDeviator + dt * StressRateDevJaumann; + + tlsph_stress[i][0] = newStressDeviator(0, 0); + tlsph_stress[i][1] = newStressDeviator(0, 1); + tlsph_stress[i][2] = newStressDeviator(0, 2); + tlsph_stress[i][3] = newStressDeviator(1, 1); + tlsph_stress[i][4] = newStressDeviator(1, 2); + tlsph_stress[i][5] = newStressDeviator(2, 2); + + // estimate effective shear modulus for time step stability + deltaStressDev = oldStressDeviator - newStressDeviator; + G_eff = effective_shear_modulus(d_dev, deltaStressDev, dt, itype); + + } // end if (strength[itype] != NONE) + + if (viscosity[itype] != NONE) { + D = 0.5 * (L[i] + L[i].transpose()); + d_dev = Deviator(D); + + switch (viscosity[itype]) { + default: + error->one(FLERR, "unknown viscosity model."); + break; + case VISCOSITY_NEWTON: + effectiveViscosity = Lookup[VISCOSITY_MU][itype]; +// double shear_rate = 2.0 +// * sqrt(d_dev(0, 1) * d_dev(0, 1) + d_dev(0, 2) * d_dev(0, 2) + d_dev(1, 2) * d_dev(1, 2)); // 3d + //cout << "shear rate: " << shear_rate << endl; + //effectiveViscosity = PA6_270C(shear_rate); + //if (effectiveViscosity > 178.062e-6) { + // printf("effective visc is %f\n", effectiveViscosity); + //} + newStressDeviator = 2.0 * effectiveViscosity * d_dev; // newton original + //cout << "this is Ddev " << endl << d_dev << endl << endl; + break; + } + } // end if (viscosity[itype] != NONE) + + /* + * assemble stress Tensor from pressure and deviatoric parts + */ + + stressTensor[i] = -newPressure * eye + newStressDeviator; + + /* + * stable timestep based on speed-of-sound + */ + + M = K_eff + 4.0 * G_eff / 3.0; + p_wave_speed = sqrt(M / rho); + effm[i] = G_eff; + dtCFL = MIN(2 * radius[i] / p_wave_speed, dtCFL); + + /* + * stable timestep based on viscosity + */ + if (viscosity[itype] != NONE) { + dtCFL = MIN(4 * radius[i] * radius[i] * rho / effectiveViscosity, dtCFL); + } + + /* + * kernel gradient correction + */ + if (gradient_correction_flag) { + stressTensor[i] *= K[i]; + } + } + // end if (setflag[itype][itype] == 1) + } // end loop over nlocal + +//printf("stable timestep = %g\n", 0.1 * hMin * MaxBulkVelocity); +} + +/* ---------------------------------------------------------------------- + allocate all arrays + ------------------------------------------------------------------------- */ + +void PairULSPH::allocate() { + + allocated = 1; + int n = atom->ntypes; + + memory->create(setflag, n + 1, n + 1, "pair:setflag"); + + memory->create(Q1, n + 1, "pair:Q1"); + memory->create(rho0, n + 1, "pair:Q2"); + memory->create(c0_type, n + 1, "pair:c0_type"); + memory->create(eos, n + 1, "pair:eosmodel"); + memory->create(viscosity, n + 1, "pair:viscositymodel"); + memory->create(strength, n + 1, "pair:strengthmodel"); + + memory->create(Lookup, MAX_KEY_VALUE, n + 1, "pair:LookupTable"); + + memory->create(artificial_pressure, n + 1, n + 1, "pair:artificial_pressure"); + memory->create(artificial_stress, n + 1, n + 1, "pair:artificial_stress"); + memory->create(cutsq, n + 1, n + 1, "pair:cutsq"); // always needs to be allocated, even with granular neighborlist + + /* + * initialize arrays to default values + */ + + for (int i = 1; i <= n; i++) { + for (int j = i; j <= n; j++) { + artificial_pressure[i][j] = 0.0; + artificial_stress[i][j] = 0.0; + setflag[i][j] = 0; + } + } + + onerad_dynamic = new double[n + 1]; + onerad_frozen = new double[n + 1]; + maxrad_dynamic = new double[n + 1]; + maxrad_frozen = new double[n + 1]; + +} + +/* ---------------------------------------------------------------------- + global settings + ------------------------------------------------------------------------- */ + +void PairULSPH::settings(int narg, char **arg) { + if (narg != 3) { + printf("narg = %d\n", narg); + error->all(FLERR, "Illegal number of arguments for pair_style ulsph"); + } + + if (comm->me == 0) { + printf("\n>>========>>========>>========>>========>>========>>========>>========>>========\n"); + printf("... SMD / ULSPH PROPERTIES\n\n"); + } + + if (strcmp(arg[0], "*DENSITY_SUMMATION") == 0) { + density_summation = true; + density_continuity = false; + if (comm->me == 0) + printf("... density summation active\n"); + } else if (strcmp(arg[0], "*DENSITY_CONTINUITY") == 0) { + density_continuity = true; + density_summation = false; + if (comm->me == 0) + printf("... density continuity active\n"); + } else { + error->all(FLERR, + "Illegal settings keyword for first keyword of pair style ulsph. Must be either *DENSITY_SUMMATION or *DENSITY_CONTINUITY"); + } + + if (strcmp(arg[1], "*VELOCITY_GRADIENT") == 0) { + velocity_gradient = true; + if (comm->me == 0) + printf("... computation of velocity gradients active\n"); + } else if (strcmp(arg[1], "*NO_VELOCITY_GRADIENT") == 0) { + velocity_gradient = false; + if (comm->me == 0) + printf("... computation of velocity gradients NOT active\n"); + } else { + error->all(FLERR, + "Illegal settings keyword for first keyword of pair style ulsph. Must be either *VELOCITY_GRADIENT or *NO_VELOCITY_GRADIENT"); + } + + if (strcmp(arg[2], "*GRADIENT_CORRECTION") == 0) { + gradient_correction_flag = true; + if (comm->me == 0) + printf("... first order correction of kernel gradients is active\n"); + } else if (strcmp(arg[2], "*NO_GRADIENT_CORRECTION") == 0) { + gradient_correction_flag = false; + if (comm->me == 0) + printf("... first order correction of kernel gradients is NOT active\n"); + } else { + error->all(FLERR, "Illegal settings keyword for pair style ulsph"); + } + +// error check + //if ((gradient_correction_flag == true) && (density_summation)) { + // error->all(FLERR, "Cannot use *DENSITY_SUMMATION in combination with *YES_GRADIENT_CORRECTION"); + //} + + if (comm->me == 0) + printf(">>========>>========>>========>>========>>========>>========>>========>>========\n"); + +} + +/* ---------------------------------------------------------------------- + set coeffs for one or more type pairs + ------------------------------------------------------------------------- */ + +void PairULSPH::coeff(int narg, char **arg) { + int ioffset, iarg, iNextKwd, itype, jtype; + char str[128]; + std::string s, t; + + if (narg < 3) { + sprintf(str, "number of arguments for pair ulsph is too small!"); + error->all(FLERR, str); + } + if (!allocated) + allocate(); + + /* + * if parameters are give in i,i form, i.e., no a cross interaction, set material parameters + */ + + if (force->inumeric(FLERR, arg[0]) == force->inumeric(FLERR, arg[1])) { + + itype = force->inumeric(FLERR, arg[0]); + eos[itype] = viscosity[itype] = strength[itype] = NONE; + + if (comm->me == 0) { + printf("\n>>========>>========>>========>>========>>========>>========>>========>>========\n"); + printf("...SMD / ULSPH PROPERTIES OF PARTICLE TYPE %d\n\n", itype); + } + + /* + * read parameters which are common -- regardless of material / eos model + */ + + ioffset = 2; + if (strcmp(arg[ioffset], "*COMMON") != 0) { + sprintf(str, "common keyword missing!"); + error->all(FLERR, str); + } else { + } + + t = string("*"); + iNextKwd = -1; + for (iarg = ioffset + 1; iarg < narg; iarg++) { + s = string(arg[iarg]); + if (s.compare(0, t.length(), t) == 0) { + iNextKwd = iarg; + break; + } + } + + //printf("keyword following *COMMON is %s\n", arg[iNextKwd]); + + if (iNextKwd < 0) { + sprintf(str, "no *KEYWORD terminates *COMMON"); + error->all(FLERR, str); + } + + if (iNextKwd - ioffset != 5 + 1) { + sprintf(str, "expected 5 arguments following *COMMON but got %d\n", iNextKwd - ioffset - 1); + error->all(FLERR, str); + } + + Lookup[REFERENCE_DENSITY][itype] = force->numeric(FLERR, arg[ioffset + 1]); + Lookup[REFERENCE_SOUNDSPEED][itype] = force->numeric(FLERR, arg[ioffset + 2]); + Q1[itype] = force->numeric(FLERR, arg[ioffset + 3]); + Lookup[HEAT_CAPACITY][itype] = force->numeric(FLERR, arg[ioffset + 4]); + Lookup[HOURGLASS_CONTROL_AMPLITUDE][itype] = force->numeric(FLERR, arg[ioffset + 5]); + + Lookup[BULK_MODULUS][itype] = Lookup[REFERENCE_SOUNDSPEED][itype] * Lookup[REFERENCE_SOUNDSPEED][itype] + * Lookup[REFERENCE_DENSITY][itype]; + + if (comm->me == 0) { + printf("material unspecific properties for SMD/ULSPH definition of particle type %d:\n", itype); + printf(FORMAT1, "reference density", Lookup[REFERENCE_DENSITY][itype]); + printf(FORMAT1, "reference speed of sound", Lookup[REFERENCE_SOUNDSPEED][itype]); + printf(FORMAT1, "linear viscosity coefficient", Q1[itype]); + printf(FORMAT1, "heat capacity [energy / (mass * temperature)]", Lookup[HEAT_CAPACITY][itype]); + printf(FORMAT1, "bulk modulus", Lookup[BULK_MODULUS][itype]); + printf(FORMAT1, "hourglass control amplitude", Lookup[HOURGLASS_CONTROL_AMPLITUDE][itype]); + } + + /* + * read following material cards + */ + +// if (comm->me == 0) { +// printf("next kwd is %s\n", arg[iNextKwd]); +// } + while (true) { + if (strcmp(arg[iNextKwd], "*END") == 0) { +// if (comm->me == 0) { +// sprintf(str, "found *END"); +// error->message(FLERR, str); +// } + break; + } + + ioffset = iNextKwd; + if (strcmp(arg[ioffset], "*EOS_TAIT") == 0) { + + /* + * Tait EOS + */ + + eos[itype] = EOS_TAIT; + //printf("reading *EOS_TAIT\n"); + + t = string("*"); + iNextKwd = -1; + for (iarg = ioffset + 1; iarg < narg; iarg++) { + s = string(arg[iarg]); + if (s.compare(0, t.length(), t) == 0) { + iNextKwd = iarg; + break; + } + } + + if (iNextKwd < 0) { + sprintf(str, "no *KEYWORD terminates *EOS_TAIT"); + error->all(FLERR, str); + } + + if (iNextKwd - ioffset != 1 + 1) { + sprintf(str, "expected 1 arguments following *EOS_TAIT but got %d\n", iNextKwd - ioffset - 1); + error->all(FLERR, str); + } + + Lookup[EOS_TAIT_EXPONENT][itype] = force->numeric(FLERR, arg[ioffset + 1]); + + if (comm->me == 0) { + printf(FORMAT2, "Tait EOS"); + printf(FORMAT1, "Exponent", Lookup[EOS_TAIT_EXPONENT][itype]); + } + } // end Tait EOS + + else if (strcmp(arg[ioffset], "*EOS_PERFECT_GAS") == 0) { + + /* + * Perfect Gas EOS + */ + + eos[itype] = EOS_PERFECT_GAS; + //printf("reading *EOS_PERFECT_GAS\n"); + + t = string("*"); + iNextKwd = -1; + for (iarg = ioffset + 1; iarg < narg; iarg++) { + s = string(arg[iarg]); + if (s.compare(0, t.length(), t) == 0) { + iNextKwd = iarg; + break; + } + } + + if (iNextKwd < 0) { + sprintf(str, "no *KEYWORD terminates *EOS_PERFECT_GAS"); + error->all(FLERR, str); + } + + if (iNextKwd - ioffset != 1 + 1) { + sprintf(str, "expected 1 arguments following *EOS_PERFECT_GAS but got %d\n", iNextKwd - ioffset - 1); + error->all(FLERR, str); + } + + Lookup[EOS_PERFECT_GAS_GAMMA][itype] = force->numeric(FLERR, arg[ioffset + 1]); + + if (comm->me == 0) { + printf(FORMAT2, "Perfect Gas EOS"); + printf(FORMAT1, "Heat Capacity Ratio Gamma", Lookup[EOS_PERFECT_GAS_GAMMA][itype]); + } + } // end Perfect Gas EOS + else if (strcmp(arg[ioffset], "*EOS_LINEAR") == 0) { + + /* + * Linear EOS + */ + + eos[itype] = EOS_LINEAR; + + t = string("*"); + iNextKwd = -1; + for (iarg = ioffset + 1; iarg < narg; iarg++) { + s = string(arg[iarg]); + if (s.compare(0, t.length(), t) == 0) { + iNextKwd = iarg; + break; + } + } + + if (iNextKwd < 0) { + sprintf(str, "no *KEYWORD terminates *EOS_LINEAR"); + error->all(FLERR, str); + } + + if (iNextKwd - ioffset != 0 + 1) { + sprintf(str, "expected 0 arguments following *EOS_LINEAR but got %d\n", iNextKwd - ioffset - 1); + error->all(FLERR, str); + } + + if (comm->me == 0) { + printf(FORMAT2, "Linear EOS"); + printf(FORMAT1, "Bulk modulus", Lookup[BULK_MODULUS][itype]); + } + } // end Linear EOS + else if (strcmp(arg[ioffset], "*STRENGTH_LINEAR_PLASTIC") == 0) { + + if (velocity_gradient != true) { + error->all(FLERR, "A strength model was requested but *VELOCITY_GRADIENT is not set"); + } + + /* + * linear elastic / ideal plastic material model with strength + */ + + strength[itype] = STRENGTH_LINEAR_PLASTIC; + velocity_gradient_required = true; + //printf("reading *LINEAR_PLASTIC\n"); + + t = string("*"); + iNextKwd = -1; + for (iarg = ioffset + 1; iarg < narg; iarg++) { + s = string(arg[iarg]); + if (s.compare(0, t.length(), t) == 0) { + iNextKwd = iarg; + break; + } + } + + if (iNextKwd < 0) { + sprintf(str, "no *KEYWORD terminates *STRENGTH_LINEAR_PLASTIC"); + error->all(FLERR, str); + } + + if (iNextKwd - ioffset != 3 + 1) { + sprintf(str, "expected 3 arguments following *STRENGTH_LINEAR_PLASTIC but got %d\n", iNextKwd - ioffset - 1); + error->all(FLERR, str); + } + + Lookup[SHEAR_MODULUS][itype] = force->numeric(FLERR, arg[ioffset + 1]); + Lookup[YIELD_STRENGTH][itype] = force->numeric(FLERR, arg[ioffset + 2]); + Lookup[HARDENING_PARAMETER][itype] = force->numeric(FLERR, arg[ioffset + 3]); + + if (comm->me == 0) { + printf(FORMAT2, "linear elastic / ideal plastic material mode"); + printf(FORMAT1, "yield_strength", Lookup[YIELD_STRENGTH][itype]); + printf(FORMAT1, "constant hardening parameter", Lookup[HARDENING_PARAMETER][itype]); + printf(FORMAT1, "shear modulus", Lookup[SHEAR_MODULUS][itype]); + } + } // end *STRENGTH_LINEAR_PLASTIC + else if (strcmp(arg[ioffset], "*STRENGTH_LINEAR") == 0) { + + if (velocity_gradient != true) { + error->all(FLERR, "A strength model was requested but *VELOCITY_GRADIENT is not set"); + } + + /* + * linear elastic / ideal plastic material model with strength + */ + + strength[itype] = STRENGTH_LINEAR; + t = string("*"); + iNextKwd = -1; + for (iarg = ioffset + 1; iarg < narg; iarg++) { + s = string(arg[iarg]); + if (s.compare(0, t.length(), t) == 0) { + iNextKwd = iarg; + break; + } + } + + if (iNextKwd < 0) { + sprintf(str, "no *KEYWORD terminates *STRENGTH_LINEAR"); + error->all(FLERR, str); + } + + if (iNextKwd - ioffset != 1 + 1) { + sprintf(str, "expected 1 arguments following *STRENGTH_LINEAR but got %d\n", iNextKwd - ioffset - 1); + error->all(FLERR, str); + } + + Lookup[SHEAR_MODULUS][itype] = force->numeric(FLERR, arg[ioffset + 1]); + + if (comm->me == 0) { + printf(FORMAT2, "linear elastic strength model"); + printf(FORMAT1, "shear modulus", Lookup[SHEAR_MODULUS][itype]); + } + } // end *STRENGTH_LINEAR + else if (strcmp(arg[ioffset], "*VISCOSITY_NEWTON") == 0) { + + if (velocity_gradient != true) { + error->all(FLERR, "A viscosity model was requested but *VELOCITY_GRADIENT is not set"); + } + + /* + * linear elastic / ideal plastic material model with strength + */ + + viscosity[itype] = VISCOSITY_NEWTON; + t = string("*"); + iNextKwd = -1; + for (iarg = ioffset + 1; iarg < narg; iarg++) { + s = string(arg[iarg]); + if (s.compare(0, t.length(), t) == 0) { + iNextKwd = iarg; + break; + } + } + + if (iNextKwd < 0) { + sprintf(str, "no *KEYWORD terminates *VISCOSITY_NEWTON"); + error->all(FLERR, str); + } + + if (iNextKwd - ioffset != 1 + 1) { + sprintf(str, "expected 1 arguments following *VISCOSITY_NEWTON but got %d\n", iNextKwd - ioffset - 1); + error->all(FLERR, str); + } + + Lookup[VISCOSITY_MU][itype] = force->numeric(FLERR, arg[ioffset + 1]); + + if (comm->me == 0) { + printf(FORMAT2, "Newton viscosity model"); + printf(FORMAT1, "viscosity mu", Lookup[VISCOSITY_MU][itype]); + } + } // end *STRENGTH_VISCOSITY_NEWTON + + else if (strcmp(arg[ioffset], "*ARTIFICIAL_PRESSURE") == 0) { + + /* + * use Monaghan's artificial pressure to prevent particle clumping + */ + + t = string("*"); + iNextKwd = -1; + for (iarg = ioffset + 1; iarg < narg; iarg++) { + s = string(arg[iarg]); + if (s.compare(0, t.length(), t) == 0) { + iNextKwd = iarg; + break; + } + } + + if (iNextKwd < 0) { + sprintf(str, "no *KEYWORD terminates *ARTIFICIAL_PRESSURE"); + error->all(FLERR, str); + } + + if (iNextKwd - ioffset != 1 + 1) { + sprintf(str, "expected 1 arguments following *ARTIFICIAL_PRESSURE but got %d\n", iNextKwd - ioffset - 1); + error->all(FLERR, str); + } + + artificial_pressure[itype][itype] = force->numeric(FLERR, arg[ioffset + 1]); + + if (comm->me == 0) { + printf(FORMAT2, "Artificial Pressure is enabled."); + printf(FORMAT1, "Artificial Pressure amplitude", artificial_pressure[itype][itype]); + } + } // end *ARTIFICIAL_PRESSURE + + else if (strcmp(arg[ioffset], "*ARTIFICIAL_STRESS") == 0) { + + /* + * use Monaghan's artificial stress to prevent particle clumping + */ + + t = string("*"); + iNextKwd = -1; + for (iarg = ioffset + 1; iarg < narg; iarg++) { + s = string(arg[iarg]); + if (s.compare(0, t.length(), t) == 0) { + iNextKwd = iarg; + break; + } + } + + if (iNextKwd < 0) { + sprintf(str, "no *KEYWORD terminates *ARTIFICIAL_STRESS"); + error->all(FLERR, str); + } + + if (iNextKwd - ioffset != 1 + 1) { + sprintf(str, "expected 1 arguments following *ARTIFICIAL_STRESS but got %d\n", iNextKwd - ioffset - 1); + error->all(FLERR, str); + } + + artificial_stress[itype][itype] = force->numeric(FLERR, arg[ioffset + 1]); + + if (comm->me == 0) { + printf(FORMAT2, "Artificial Stress is enabled."); + printf(FORMAT1, "Artificial Stress amplitude", artificial_stress[itype][itype]); + } + } // end *ARTIFICIAL_STRESS + + else { + sprintf(str, "unknown *KEYWORD: %s", arg[ioffset]); + error->all(FLERR, str); + } + + } + + /* + * copy data which is looked up in inner pairwise loops from slow maps to fast arrays + */ + + rho0[itype] = Lookup[REFERENCE_DENSITY][itype]; + c0_type[itype] = Lookup[REFERENCE_SOUNDSPEED][itype]; + setflag[itype][itype] = 1; + + /* + * error checks + */ + + if ((viscosity[itype] != NONE) && (strength[itype] != NONE)) { + sprintf(str, "cannot have both a strength and viscosity model for particle type %d", itype); + error->all(FLERR, str); + } + + if (eos[itype] == NONE) { + sprintf(str, "must specify an EOS for particle type %d", itype); + error->all(FLERR, str); + } + + } else { + /* + * we are reading a cross-interaction line for particle types i, j + */ + + itype = force->inumeric(FLERR, arg[0]); + jtype = force->inumeric(FLERR, arg[1]); + + if (strcmp(arg[2], "*CROSS") != 0) { + sprintf(str, "ulsph cross interaction between particle type %d and %d requested, however, *CROSS keyword is missing", + itype, jtype); + error->all(FLERR, str); + } + + if (setflag[itype][itype] != 1) { + sprintf(str, + "ulsph cross interaction between particle type %d and %d requested, however, properties of type %d have not yet been specified", + itype, jtype, itype); + error->all(FLERR, str); + } + + if (setflag[jtype][jtype] != 1) { + sprintf(str, + "ulsph cross interaction between particle type %d and %d requested, however, properties of type %d have not yet been specified", + itype, jtype, jtype); + error->all(FLERR, str); + } + + setflag[itype][jtype] = 1; + setflag[jtype][itype] = 1; + + if ((artificial_pressure[itype][itype] > 0.0) && (artificial_pressure[jtype][jtype] > 0.0)) { + artificial_pressure[itype][jtype] = 0.5 * (artificial_pressure[itype][itype] + artificial_pressure[jtype][jtype]); + artificial_pressure[jtype][itype] = artificial_pressure[itype][jtype]; + } else { + artificial_pressure[itype][jtype] = artificial_pressure[jtype][itype] = 0.0; + } + + if ((artificial_stress[itype][itype] > 0.0) && (artificial_stress[jtype][jtype] > 0.0)) { + artificial_stress[itype][jtype] = 0.5 * (artificial_stress[itype][itype] + artificial_stress[jtype][jtype]); + artificial_stress[jtype][itype] = artificial_stress[itype][jtype]; + } else { + artificial_stress[itype][jtype] = artificial_stress[jtype][itype] = 0.0; + } + + if (comm->me == 0) { + printf(">>========>>========>>========>>========>>========>>========>>========>>========\n"); + } + + } +} + +/* ---------------------------------------------------------------------- + init for one type pair i,j and corresponding j,i + ------------------------------------------------------------------------- */ + +double PairULSPH::init_one(int i, int j) { + + if (!allocated) + allocate(); + + if (setflag[i][j] == 0) + error->all(FLERR, "All pair coeffs are not set"); + +// cutoff = sum of max I,J radii for +// dynamic/dynamic & dynamic/frozen interactions, but not frozen/frozen + + double cutoff = maxrad_dynamic[i] + maxrad_dynamic[j]; + cutoff = MAX(cutoff, maxrad_frozen[i] + maxrad_dynamic[j]); + cutoff = MAX(cutoff, maxrad_dynamic[i] + maxrad_frozen[j]); +//printf("cutoff for pair sph/fluid = %f\n", cutoff); + return cutoff; +} + +/* ---------------------------------------------------------------------- + init specific to this pair style + ------------------------------------------------------------------------- */ + +void PairULSPH::init_style() { + int i; + +//printf(" in init style\n"); +// request a granular neighbor list + int irequest = neighbor->request(this); + neighbor->requests[irequest]->half = 0; + neighbor->requests[irequest]->gran = 1; + +// set maxrad_dynamic and maxrad_frozen for each type +// include future Fix pour particles as dynamic + + for (i = 1; i <= atom->ntypes; i++) + onerad_dynamic[i] = onerad_frozen[i] = 0.0; + + double *radius = atom->radius; + int *type = atom->type; + int nlocal = atom->nlocal; + + for (i = 0; i < nlocal; i++) + onerad_dynamic[type[i]] = MAX(onerad_dynamic[type[i]], radius[i]); + + MPI_Allreduce(&onerad_dynamic[1], &maxrad_dynamic[1], atom->ntypes, MPI_DOUBLE, MPI_MAX, world); + MPI_Allreduce(&onerad_frozen[1], &maxrad_frozen[1], atom->ntypes, MPI_DOUBLE, MPI_MAX, world); + +} + +/* ---------------------------------------------------------------------- + neighbor callback to inform pair style of neighbor list to use + optional granular history list + ------------------------------------------------------------------------- */ + +void PairULSPH::init_list(int id, NeighList *ptr) { + if (id == 0) + list = ptr; +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based arrays + ------------------------------------------------------------------------- */ + +double PairULSPH::memory_usage() { + +//printf("in memory usage\n"); + + return 11 * nmax * sizeof(double); + +} + +/* ---------------------------------------------------------------------- */ + +int PairULSPH::pack_forward_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { + double *vfrac = atom->vfrac; + double *eff_plastic_strain = atom->eff_plastic_strain; + int i, j, m; + +//printf("packing comm\n"); + m = 0; + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = vfrac[j]; + buf[m++] = c0[j]; //2 + + buf[m++] = stressTensor[j](0, 0); // pack symmetric stress tensor + buf[m++] = stressTensor[j](1, 1); + buf[m++] = stressTensor[j](2, 2); + buf[m++] = stressTensor[j](0, 1); + buf[m++] = stressTensor[j](0, 2); + buf[m++] = stressTensor[j](1, 2); // 2 + 6 = 8 + + buf[m++] = F[j](0, 0); // F is not symmetric + buf[m++] = F[j](0, 1); + buf[m++] = F[j](0, 2); + buf[m++] = F[j](1, 0); + buf[m++] = F[j](1, 1); + buf[m++] = F[j](1, 2); + buf[m++] = F[j](2, 0); + buf[m++] = F[j](2, 1); + buf[m++] = F[j](2, 2); // 8 + 9 = 17 + + buf[m++] = eff_plastic_strain[j]; // 18 + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +void PairULSPH::unpack_forward_comm(int n, int first, double *buf) { + double *vfrac = atom->vfrac; + double *eff_plastic_strain = atom->eff_plastic_strain; + int i, m, last; + + m = 0; + last = first + n; + for (i = first; i < last; i++) { + vfrac[i] = buf[m++]; + c0[i] = buf[m++]; // 2 + + stressTensor[i](0, 0) = buf[m++]; + stressTensor[i](1, 1) = buf[m++]; + stressTensor[i](2, 2) = buf[m++]; + stressTensor[i](0, 1) = buf[m++]; + stressTensor[i](0, 2) = buf[m++]; + stressTensor[i](1, 2) = buf[m++]; // 2 + 6 = 8 + stressTensor[i](1, 0) = stressTensor[i](0, 1); + stressTensor[i](2, 0) = stressTensor[i](0, 2); + stressTensor[i](2, 1) = stressTensor[i](1, 2); + + F[i](0, 0) = buf[m++]; + F[i](0, 1) = buf[m++]; + F[i](0, 2) = buf[m++]; + F[i](1, 0) = buf[m++]; + F[i](1, 1) = buf[m++]; + F[i](1, 2) = buf[m++]; + F[i](2, 0) = buf[m++]; + F[i](2, 1) = buf[m++]; + F[i](2, 2) = buf[m++]; // 8 + 9 = 17 + + eff_plastic_strain[i] = buf[m++]; // 18 + } +} + +/* + * EXTRACT + */ + +void *PairULSPH::extract(const char *str, int &i) { +//printf("in extract\n"); + if (strcmp(str, "smd/ulsph/smoothVel_ptr") == 0) { + return (void *) smoothVel; + } else if (strcmp(str, "smd/ulsph/stressTensor_ptr") == 0) { + return (void *) stressTensor; + } else if (strcmp(str, "smd/ulsph/velocityGradient_ptr") == 0) { + return (void *) L; + } else if (strcmp(str, "smd/ulsph/numNeighs_ptr") == 0) { + return (void *) numNeighs; + } else if (strcmp(str, "smd/ulsph/dtCFL_ptr") == 0) { +//printf("dtcfl = %f\n", dtCFL); + return (void *) &dtCFL; + } else if (strcmp(str, "smd/ulsph/updateFlag_ptr") == 0) { + return (void *) &updateFlag; + } else if (strcmp(str, "smd/ulsph/effective_modulus_ptr") == 0) { + return (void *) effm; + } else if (strcmp(str, "smd/ulsph/shape_matrix_ptr") == 0) { + return (void *) K; + } + + return NULL; +} + +/* ---------------------------------------------------------------------- + compute effective shear modulus by dividing rate of deviatoric stress with rate of shear deformation + ------------------------------------------------------------------------- */ + +double PairULSPH::effective_shear_modulus(const Matrix3d d_dev, const Matrix3d deltaStressDev, const double dt, const int itype) { + double G_eff; // effective shear modulus, see Pronto 2d eq. 3.4.7 + double deltaStressDevSum, shearRateSq, strain_increment; + + if (domain->dimension == 3) { + deltaStressDevSum = deltaStressDev(0, 1) * deltaStressDev(0, 1) + deltaStressDev(0, 2) * deltaStressDev(0, 2) + + deltaStressDev(1, 2) * deltaStressDev(1, 2); + shearRateSq = d_dev(0, 1) * d_dev(0, 1) + d_dev(0, 2) * d_dev(0, 2) + d_dev(1, 2) * d_dev(1, 2); + } else { + deltaStressDevSum = deltaStressDev(0, 1) * deltaStressDev(0, 1); + shearRateSq = d_dev(0, 1) * d_dev(0, 1); + } + + strain_increment = dt * dt * shearRateSq; + + if (strain_increment > 1.0e-12) { + G_eff = 0.5 * sqrt(deltaStressDevSum / strain_increment); + } else { + if (strength[itype] != NONE) { + G_eff = Lookup[SHEAR_MODULUS][itype]; + } else { + G_eff = 0.0; + } + } + + return G_eff; + +} + +/* ---------------------------------------------------------------------- + hourglass force for updated Lagrangian SPH + input: particles indices i, j, particle types ityep, jtype + ------------------------------------------------------------------------- */ + +Vector3d PairULSPH::ComputeHourglassForce(const int i, const int itype, const int j, const int jtype, const Vector3d dv, + const Vector3d xij, const Vector3d g, const double c_ij, const double mu_ij, const double rho_ij) { + + double *rmass = atom->rmass; + Vector3d dv_est, f_hg; + double visc_magnitude; + + dv_est = -0.5 * (F[i] + F[j]) * xij; + double hurz = dv_est.dot(dv) / (dv_est.norm() * dv.norm() + 1.0e-16); + if (hurz < 0.0) { + + visc_magnitude = 0.5 * (Q1[itype] + Q1[jtype]) * c_ij * mu_ij / rho_ij; + f_hg = -rmass[i] * rmass[j] * visc_magnitude * g; +// printf(" f_hg = %f %f %f\n", f_hg(0), f_hg(1), f_hg(2)); +// printf("\nnegative\n"); +// printf(" dv_est = %f %f %f\n", dv_est(0), dv_est(1), dv_est(2)); +// printf(" dv = %f %f %f\n", dv(0), dv(1), dv(2)); + } else { + f_hg.setZero(); + } + + return f_hg; + +} diff --git a/src/USER-SMD/pair_smd_ulsph.h b/src/USER-SMD/pair_smd_ulsph.h new file mode 100644 index 0000000000..81919afdb0 --- /dev/null +++ b/src/USER-SMD/pair_smd_ulsph.h @@ -0,0 +1,140 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +#ifdef PAIR_CLASS + +PairStyle(smd/ulsph,PairULSPH) + +#else + +#ifndef LMP_ULSPH_H +#define LMP_ULSPH_H + +#include "pair.h" +#include +#include +#include + +using namespace Eigen; +using namespace std; +namespace LAMMPS_NS { + +class PairULSPH: public Pair { +public: + PairULSPH(class LAMMPS *); + virtual ~PairULSPH(); + virtual void compute(int, int); + void settings(int, char **); + void coeff(int, char **); + double init_one(int, int); + void init_style(); + void init_list(int, class NeighList *); + virtual double memory_usage(); + int pack_forward_comm(int, int *, double *, int, int *); + void unpack_forward_comm(int, int, double *); + void AssembleStressTensor(); + void *extract(const char *, int &); + void PreCompute(); + void PreCompute_DensitySummation(); + double effective_shear_modulus(const Matrix3d d_dev, const Matrix3d deltaStressDev, const double dt, const int itype); + + Vector3d ComputeHourglassForce(const int i, const int itype, const int j, const int jtype, const Vector3d dv, + const Vector3d xij, const Vector3d g, const double c_ij, const double mu_ij, const double rho_ij); + +protected: + + double *c0_type; // reference speed of sound defined per particle type + double *rho0; // reference mass density per type + double *Q1; // linear artificial viscosity coeff + int *eos, *viscosity, *strength; // eos and strength material models + double **artificial_pressure; // true/false: use Monaghan's artificial pressure correction? + double **artificial_stress; // artificial stress amplitude + + double *onerad_dynamic, *onerad_frozen; + double *maxrad_dynamic, *maxrad_frozen; + + void allocate(); + + int nmax; // max number of atoms on this proc + int *numNeighs; + Matrix3d *K; + double *shepardWeight, *c0, *rho; + Vector3d *smoothVel; + Matrix3d *stressTensor, *L, *F; + + double dtCFL; + +private: + + // enumerate EOSs. MUST BE IN THE RANGE [1000, 2000) + enum { + EOS_LINEAR = 1000, EOS_PERFECT_GAS = 1001, EOS_TAIT = 1002, + }; + + // enumerate physical viscosity models. MUST BE IN THE RANGE [2000, 3000) + enum { + VISCOSITY_NEWTON = 2000 + }; + + // enumerate strength models. MUST BE IN THE RANGE [3000, 4000) + enum { + STRENGTH_LINEAR = 3000, STRENGTH_LINEAR_PLASTIC = 3001 + }; + + // enumerate some quantitities and associate these with integer values such that they can be used for lookup in an array structure + enum { + NONE = 0, + BULK_MODULUS = 1, + HOURGLASS_CONTROL_AMPLITUDE = 2, + EOS_TAIT_EXPONENT = 3, + REFERENCE_SOUNDSPEED = 4, + REFERENCE_DENSITY = 5, + EOS_PERFECT_GAS_GAMMA = 6, + SHEAR_MODULUS = 7, + YIELD_STRENGTH = 8, + YOUNGS_MODULUS = 9, + POISSON_RATIO = 10, + LAME_LAMBDA = 11, + HEAT_CAPACITY = 12, + M_MODULUS = 13, + HARDENING_PARAMETER = 14, + VISCOSITY_MU = 15, + MAX_KEY_VALUE = 16 + }; + double **Lookup; // holds per-type material parameters for the quantities defined in enum statement above. + + bool velocity_gradient_required; + int updateFlag; // indicates if any relative particle pair movement is significant compared to smoothing length + + + bool density_summation, density_continuity, velocity_gradient, gradient_correction_flag; + double *effm; + +}; + +} + +#endif +#endif + diff --git a/src/USER-SMD/smd_kernels.h b/src/USER-SMD/smd_kernels.h new file mode 100644 index 0000000000..ba40699fc7 --- /dev/null +++ b/src/USER-SMD/smd_kernels.h @@ -0,0 +1,146 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + +#ifndef SMD_KERNEL_FUNCTIONS_H_ +#define SMD_KERNEL_FUNCTIONS_H_ + +namespace SMD_Kernels { +static inline double Kernel_Wendland_Quintic_NotNormalized(const double r, const double h) { + if (r < h) { + double q = 2.0 * r / h; + return pow(1.0 - 0.5 * q, 4) * (2.0 * q + 1.0); + } else { + return 0.0; + } +} + +static inline double Kernel_Cubic_Spline(const double r, const double h) { + double q = 2.0 * r / h; + if (q > 2.0) { + return 0.0; + } else if ((q <= 2.0) && (q > 1.0)) { + return pow(2.0 - q, 3.0) / 6.0; + } else if ((q >= 0.0) && (q <= 1.0)) { + return 2. / 3. - q * q + 0.5 * q * q * q; + } else { + return 0.0; + } +} + +static inline double Kernel_Barbara(const double r, const double h) { + double arg = (1.570796327 * (r + h)) / h; + double hsq = h * h; + //wf = (1.680351548 * (cos(arg) + 1.)) / hsq; + return -2.639490040 * sin(arg) / (hsq * h); +} + +static inline void spiky_kernel_and_derivative(const double h, const double r, const int dimension, double &wf, double &wfd) { + + /* + * Spiky kernel + */ + + if (r > h) { + printf("r=%f > h=%f in Spiky kernel\n", r, h); + wf = wfd = 0.0; + return; + } + + double hr = h - r; // [m] + if (dimension == 2) { + double n = 0.3141592654e0 * h * h * h * h * h; // [m^5] + wfd = -3.0e0 * hr * hr / n; // [m*m/m^5] = [1/m^3] ==> correct for dW/dr in 2D + wf = -0.333333333333e0 * hr * wfd; // [m/m^3] ==> [1/m^2] correct for W in 2D + } else { + wfd = -14.0323944878e0 * hr * hr / (h * h * h * h * h * h); // [1/m^4] ==> correct for dW/dr in 3D + wf = -0.333333333333e0 * hr * wfd; // [m/m^4] ==> [1/m^3] correct for W in 3D + } + + // alternative formulation +// double hr = h - r; +// +// /* +// * Spiky kernel +// */ +// +// if (domain->dimension == 2) { +// double h5 = h * h * h * h * h; +// wf = 3.183098861e0 * hr * hr * hr / h5; +// wfd = -9.549296583 * hr * hr / h5; +// +// } else { +// double h6 = h * h * h * h * h * h; +// wf = 4.774648292 * hr * hr * hr / h6; +// wfd = -14.32394487 * hr * hr / h6; +// } +// } + +} + +static inline void barbara_kernel_and_derivative(const double h, const double r, const int dimension, double &wf, double &wfd) { + + /* + * Barbara kernel + */ + + double arg = (1.570796327 * (r + h)) / h; + double hsq = h * h; + + if (r > h) { + printf("r = %f > h = %f in barbara kernel function\n", r, h); + exit(1); + //wf = wfd = 0.0; + //return; + } + + if (dimension == 2) { + wf = (1.680351548 * (cos(arg) + 1.)) / hsq; + wfd = -2.639490040 * sin(arg) / (hsq * h); + } else { + wf = 2.051578323 * (cos(arg) + 1.) / (hsq * h); + wfd = -3.222611694 * sin(arg) / (hsq * hsq); + } +} + +/* + * compute a normalized smoothing kernel only + */ +static inline void Poly6Kernel(const double hsq, const double h, const double rsq, const int dimension, double &wf) { + + double tmp = hsq - rsq; + if (dimension == 2) { + wf = tmp * tmp * tmp / (0.7853981635e0 * hsq * hsq * hsq * hsq); + } else { + wf = tmp * tmp * tmp / (0.6382918409e0 * hsq * hsq * hsq * hsq * h); + } +} + +/* + * M4 Prime Kernel + */ + +static inline void M4PrimeKernel(const double s, double &wf) { + if (s < 1.0) { + //wf = 1.0 - 2.5 * s * s + (3./2.) * s * s * s; + wf = 1.0 - s * s *(2.5 -1.5 *s); + } else if (s < 2.0) { + //wf = 0.5 * (1.0 - s) * ((2.0 - s) * (2.0 - s)); + wf = 2.0 + (-4.0 + (2.5 - 0.5 * s)*s)*s; + } else { + wf = 0.0; + } +} + +} + + + +#endif /* SMD_KERNEL_FUNCTIONS_H_ */ diff --git a/src/USER-SMD/smd_material_models.cpp b/src/USER-SMD/smd_material_models.cpp new file mode 100644 index 0000000000..fd06d4c3bb --- /dev/null +++ b/src/USER-SMD/smd_material_models.cpp @@ -0,0 +1,476 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ +#include +#include "math_special.h" +#include "stdio.h" + +#include +#include +#include + +using namespace LAMMPS_NS::MathSpecial; +using namespace std; +using namespace Eigen; + +#define MIN(A,B) ((A) < (B) ? (A) : (B)) +#define MAX(A,B) ((A) > (B) ? (A) : (B)) + +/* ---------------------------------------------------------------------- + linear EOS for use with linear elasticity + input: initial pressure pInitial, isotropic part of the strain rate d, time-step dt + output: final pressure pFinal, pressure rate p_rate + ------------------------------------------------------------------------- */ +void LinearEOS(double lambda, double pInitial, double d, double dt, double &pFinal, double &p_rate) { + + /* + * pressure rate + */ + p_rate = lambda * d; + + pFinal = pInitial + dt * p_rate; // increment pressure using pressure rate + //cout << "hurz" << endl; + +} + +/* ---------------------------------------------------------------------- + shock EOS + input: + current density rho + reference density rho0 + current energy density e + reference energy density e0 + reference speed of sound c0 + shock Hugoniot parameter S + Grueneisen parameter Gamma + initial pressure pInitial + time step dt + + output: + pressure rate p_rate + final pressure pFinal + + ------------------------------------------------------------------------- */ +void ShockEOS(double rho, double rho0, double e, double e0, double c0, double S, double Gamma, double pInitial, double dt, + double &pFinal, double &p_rate) { + + double mu = rho / rho0 - 1.0; + double pH = rho0 * square(c0) * mu * (1.0 + mu) / square(1.0 - (S - 1.0) * mu); + + pFinal = (pH + rho * Gamma * (e - e0)); + + //printf("shock EOS: rho = %g, rho0 = %g, Gamma=%f, c0=%f, S=%f, e=%f, e0=%f\n", rho, rho0, Gamma, c0, S, e, e0); + //printf("pFinal = %f\n", pFinal); + p_rate = (pFinal - pInitial) / dt; + +} + +/* ---------------------------------------------------------------------- + polynomial EOS + input: + current density rho + reference density rho0 + coefficients 0 .. 6 + initial pressure pInitial + time step dt + + output: + pressure rate p_rate + final pressure pFinal + + ------------------------------------------------------------------------- */ +void polynomialEOS(double rho, double rho0, double e, double C0, double C1, double C2, double C3, double C4, double C5, double C6, + double pInitial, double dt, double &pFinal, double &p_rate) { + + double mu = rho / rho0 - 1.0; + + if (mu > 0.0) { + pFinal = C0 + C1 * mu + C2 * mu * mu + C3 * mu * mu * mu; // + (C4 + C5 * mu + C6 * mu * mu) * e; + } else { + pFinal = C0 + C1 * mu + C3 * mu * mu * mu; // + (C4 + C5 * mu) * e; + } + pFinal = -pFinal; // we want the mean stress, not the pressure. + + + //printf("pFinal = %f\n", pFinal); + p_rate = (pFinal - pInitial) / dt; + +} + +/* ---------------------------------------------------------------------- + Tait EOS based on current density vs. reference density. + + input: (1) reference sound speed + (2) equilibrium mass density + (3) current mass density + + output:(1) pressure + (2) current speed of sound + ------------------------------------------------------------------------- */ +void TaitEOS_density(const double exponent, const double c0_reference, const double rho_reference, const double rho_current, + double &pressure, double &sound_speed) { + + double B = rho_reference * c0_reference * c0_reference / exponent; + double tmp = pow(rho_current / rho_reference, exponent); + pressure = B * (tmp - 1.0); + double bulk_modulus = B * tmp * exponent; // computed as rho * d(pressure)/d(rho) + sound_speed = sqrt(bulk_modulus / rho_current); + +// if (fabs(pressure) > 0.01) { +// printf("tmp = %f, press=%f, K=%f\n", tmp, pressure, bulk_modulus); +// } + +} + +/* ---------------------------------------------------------------------- + perfect gas EOS + input: gamma -- adiabatic index (ratio of specific heats) + J -- determinant of deformation gradient + volume0 -- reference configuration volume of particle + energy -- energy of particle + pInitial -- initial pressure of the particle + d -- isotropic part of the strain rate tensor, + dt -- time-step size + + output: final pressure pFinal, pressure rate p_rate + ------------------------------------------------------------------------- */ +void PerfectGasEOS(const double gamma, const double vol, const double mass, const double energy, double &pFinal, double &c0) { + + /* + * perfect gas EOS is p = (gamma - 1) rho e + */ + + if (energy > 0.0) { + + pFinal = (1.0 - gamma) * energy / vol; +//printf("gamma = %f, vol%f, e=%g ==> p=%g\n", gamma, vol, energy, *pFinal__/1.0e-9); + + c0 = sqrt((gamma - 1.0) * energy / mass); + + } else { + pFinal = c0 = 0.0; + } + +} + +/* ---------------------------------------------------------------------- + linear strength model for use with linear elasticity + input: lambda, mu : Lame parameters + input: sigmaInitial_dev, d_dev: initial stress deviator, deviatoric part of the strain rate tensor + input: dt: time-step + output: sigmaFinal_dev, sigmaFinal_dev_rate__: final stress deviator and its rate. + ------------------------------------------------------------------------- */ +void LinearStrength(const double mu, const Matrix3d sigmaInitial_dev, const Matrix3d d_dev, const double dt, + Matrix3d &sigmaFinal_dev__, Matrix3d &sigma_dev_rate__) { + + /* + * deviatoric rate of unrotated stress + */ + sigma_dev_rate__ = 2.0 * mu * d_dev; + + /* + * elastic update to the deviatoric stress + */ + sigmaFinal_dev__ = sigmaInitial_dev + dt * sigma_dev_rate__; +} + +/* ---------------------------------------------------------------------- + linear strength model for use with linear elasticity + input: lambda, mu : Lame parameters + input: F: deformation gradient + output: total stress tensor, deviator + pressure + ------------------------------------------------------------------------- */ +//void PairTlsph::LinearStrengthDefgrad(double lambda, double mu, Matrix3d F, Matrix3d *T) { +// Matrix3d E, PK2, eye, sigma, S, tau; +// +// eye.setIdentity(); +// +// E = 0.5 * (F * F.transpose() - eye); // strain measure E = 0.5 * (B - I) = 0.5 * (F * F^T - I) +// tau = lambda * E.trace() * eye + 2.0 * mu * E; // Kirchhoff stress, work conjugate to above strain +// sigma = tau / F.determinant(); // convert Kirchhoff stress to Cauchy stress +// +////printf("l=%f, mu=%f, sigma xy = %f\n", lambda, mu, sigma(0,1)); +// +//// E = 0.5 * (F.transpose() * F - eye); // Green-Lagrange Strain E = 0.5 * (C - I) +//// S = lambda * E.trace() * eye + 2.0 * mu * Deviator(E); // PK2 stress +//// tau = F * S * F.transpose(); // convert PK2 to Kirchhoff stress +//// sigma = tau / F.determinant(); +// +// //*T = sigma; +// +// /* +// * neo-hookean model due to Bonet +// */ +//// lambda = mu = 100.0; +//// // left Cauchy-Green Tensor, b = F.F^T +// double J = F.determinant(); +// double logJ = log(J); +// Matrix3d b; +// b = F * F.transpose(); +// +// sigma = (mu / J) * (b - eye) + (lambda / J) * logJ * eye; +// *T = sigma; +//} +/* ---------------------------------------------------------------------- + linear strength model for use with linear elasticity + input: lambda, mu : Lame parameters + input: sigmaInitial_dev, d_dev: initial stress deviator, deviatoric part of the strain rate tensor + input: dt: time-step + output: sigmaFinal_dev, sigmaFinal_dev_rate__: final stress deviator and its rate. + ------------------------------------------------------------------------- */ +void LinearPlasticStrength(const double G, const double yieldStress, const Matrix3d sigmaInitial_dev, const Matrix3d d_dev, + const double dt, Matrix3d &sigmaFinal_dev__, Matrix3d &sigma_dev_rate__, double &plastic_strain_increment) { + + Matrix3d sigmaTrial_dev, dev_rate; + double J2; + + /* + * deviatoric rate of unrotated stress + */ + dev_rate = 2.0 * G * d_dev; + + /* + * perform a trial elastic update to the deviatoric stress + */ + sigmaTrial_dev = sigmaInitial_dev + dt * dev_rate; // increment stress deviator using deviatoric rate + + /* + * check yield condition + */ + J2 = sqrt(3. / 2.) * sigmaTrial_dev.norm(); + + if (J2 < yieldStress) { + /* + * no yielding has occured. + * final deviatoric stress is trial deviatoric stress + */ + sigma_dev_rate__ = dev_rate; + sigmaFinal_dev__ = sigmaTrial_dev; + plastic_strain_increment = 0.0; + //printf("no yield\n"); + + } else { + //printf("yiedl\n"); + /* + * yielding has occured + */ + plastic_strain_increment = (J2 - yieldStress) / (3.0 * G); + + /* + * new deviatoric stress: + * obtain by scaling the trial stress deviator + */ + sigmaFinal_dev__ = (yieldStress / J2) * sigmaTrial_dev; + + /* + * new deviatoric stress rate + */ + sigma_dev_rate__ = sigmaFinal_dev__ - sigmaInitial_dev; + //printf("yielding has occured.\n"); + } +} + +/* ---------------------------------------------------------------------- + Johnson Cook Material Strength model + input: + G : shear modulus + cp : heat capacity + espec : energy / mass + A : initial yield stress under quasi-static / room temperature conditions + B : proportionality factor for plastic strain dependency + a : exponent for plastic strain dpendency + C : proportionality factor for logarithmic plastic strain rate dependency + epdot0 : dimensionality factor for plastic strain rate dependency + T : current temperature + T0 : reference (room) temperature + Tmelt : melting temperature + input: sigmaInitial_dev, d_dev: initial stress deviator, deviatoric part of the strain rate tensor + input: dt: time-step + output: sigmaFinal_dev, sigmaFinal_dev_rate__: final stress deviator and its rate. + ------------------------------------------------------------------------- */ +void JohnsonCookStrength(const double G, const double cp, const double espec, const double A, const double B, const double a, + const double C, const double epdot0, const double T0, const double Tmelt, const double M, const double dt, const double ep, + const double epdot, const Matrix3d sigmaInitial_dev, const Matrix3d d_dev, Matrix3d &sigmaFinal_dev__, + Matrix3d &sigma_dev_rate__, double &plastic_strain_increment) { + + Matrix3d sigmaTrial_dev, dev_rate; + double J2, yieldStress; + + double deltaT = espec / cp; + double TH = deltaT / (Tmelt - T0); + TH = MAX(TH, 0.0); + double epdot_ratio = epdot / epdot0; + epdot_ratio = MAX(epdot_ratio, 1.0); + //printf("current temperature delta is %f, TH=%f\n", deltaT, TH); + + yieldStress = (A + B * pow(ep, a)) * (1.0 + C * log(epdot_ratio)); // * (1.0 - pow(TH, M)); + + /* + * deviatoric rate of unrotated stress + */ + dev_rate = 2.0 * G * d_dev; + + /* + * perform a trial elastic update to the deviatoric stress + */ + sigmaTrial_dev = sigmaInitial_dev + dt * dev_rate; // increment stress deviator using deviatoric rate + + /* + * check yield condition + */ + J2 = sqrt(3. / 2.) * sigmaTrial_dev.norm(); + + if (J2 < yieldStress) { + /* + * no yielding has occured. + * final deviatoric stress is trial deviatoric stress + */ + sigma_dev_rate__ = dev_rate; + sigmaFinal_dev__ = sigmaTrial_dev; + plastic_strain_increment = 0.0; + //printf("no yield\n"); + + } else { + //printf("yiedl\n"); + /* + * yielding has occured + */ + plastic_strain_increment = (J2 - yieldStress) / (3.0 * G); + + /* + * new deviatoric stress: + * obtain by scaling the trial stress deviator + */ + sigmaFinal_dev__ = (yieldStress / J2) * sigmaTrial_dev; + + /* + * new deviatoric stress rate + */ + sigma_dev_rate__ = sigmaFinal_dev__ - sigmaInitial_dev; + //printf("yielding has occured.\n"); + } +} + +/* ---------------------------------------------------------------------- + isotropic maximum strain damage model + input: + current strain + maximum value of allowed principal strain + + output: + return value is true if any eigenvalue of the current strain exceeds the allowed principal strain + + ------------------------------------------------------------------------- */ + +bool IsotropicMaxStrainDamage(const Matrix3d E, const double maxStrain) { + + /* + * compute Eigenvalues of strain matrix + */ + SelfAdjointEigenSolver < Matrix3d > es; + es.compute(E); // compute eigenvalue and eigenvectors of strain + + double max_eigenvalue = es.eigenvalues().maxCoeff(); + + if (max_eigenvalue > maxStrain) { + return true; + } else { + return false; + } +} + +/* ---------------------------------------------------------------------- + isotropic maximum stress damage model + input: + current stress + maximum value of allowed principal stress + + output: + return value is true if any eigenvalue of the current stress exceeds the allowed principal stress + + ------------------------------------------------------------------------- */ + +bool IsotropicMaxStressDamage(const Matrix3d S, const double maxStress) { + + /* + * compute Eigenvalues of strain matrix + */ + SelfAdjointEigenSolver < Matrix3d > es; + es.compute(S); // compute eigenvalue and eigenvectors of strain + + double max_eigenvalue = es.eigenvalues().maxCoeff(); + + if (max_eigenvalue > maxStress) { + return true; + } else { + return false; + } +} + +/* ---------------------------------------------------------------------- + Johnson-Cook failure model + input: + + + output: + + + ------------------------------------------------------------------------- */ + +double JohnsonCookFailureStrain(const double p, const Matrix3d Sdev, const double d1, const double d2, const double d3, + const double d4, const double epdot0, const double epdot) { + + + + double vm = sqrt(3. / 2.) * Sdev.norm(); // von-Mises equivalent stress + if (vm < 0.0) { + cout << "this is sdev " << endl << Sdev << endl; + printf("vm=%f < 0.0, surely must be an error\n", vm); + exit(1); + } + + // determine stress triaxiality + double triax = p / (vm + 0.01 * fabs(p)); // have softening in denominator to avoid divison by zero + if (triax < 0.0) { + triax = 0.0; + } else if (triax > 3.0) { + triax = 3.0; + } + + // Johnson-Cook failure strain, dependence on stress triaxiality + double jc_failure_strain = d1 + d2 * exp(d3 * triax); + + // include strain rate dependency if parameter d4 is defined and current plastic strain rate exceeds reference strain rate + if (d4 > 0.0) { // + if (epdot > epdot0) { + double epdot_ratio = epdot / epdot0; + jc_failure_strain *= (1.0 + d4 * log(epdot_ratio)); + //printf("epsdot=%f, epsdot0=%f, factor = %f\n", epdot, epdot0, (1.0 + d4 * log(epdot_ratio))); + //exit(1); + + } + } + + return jc_failure_strain; + +} diff --git a/src/USER-SMD/smd_material_models.h b/src/USER-SMD/smd_material_models.h new file mode 100644 index 0000000000..858c5bbbdf --- /dev/null +++ b/src/USER-SMD/smd_material_models.h @@ -0,0 +1,65 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +#ifndef SMD_MATERIAL_MODELS_H_ +#define SMD_MATERIAL_MODELS_H_ + +using namespace Eigen; + +/* + * EOS models + */ +void LinearEOS(double lambda, double pInitial, double d, double dt, double &pFinal, double &p_rate); +void ShockEOS(double rho, double rho0, double e, double e0, double c0, double S, double Gamma, double pInitial, double dt, + double &pFinal, double &p_rate); +void polynomialEOS(double rho, double rho0, double e, double C0, double C1, double C2, double C3, double C4, double C5, double C6, + double pInitial, double dt, double &pFinal, double &p_rate); +void TaitEOS_density(const double exponent, const double c0_reference, const double rho_reference, const double rho_current, + double &pressure, double &sound_speed); +void PerfectGasEOS(const double gamma, const double vol, const double mass, const double energy, double &pFinal__, double &c0); + +/* + * Material strength models + */ +void LinearStrength(const double mu, const Matrix3d sigmaInitial_dev, const Matrix3d d_dev, const double dt, + Matrix3d &sigmaFinal_dev__, Matrix3d &sigma_dev_rate__); +void LinearPlasticStrength(const double G, const double yieldStress, const Matrix3d sigmaInitial_dev, const Matrix3d d_dev, + const double dt, Matrix3d &sigmaFinal_dev__, Matrix3d &sigma_dev_rate__, double &plastic_strain_increment); +void JohnsonCookStrength(const double G, const double cp, const double espec, const double A, const double B, const double a, + const double C, const double epdot0, const double T0, const double Tmelt, const double M, const double dt, const double ep, + const double epdot, const Matrix3d sigmaInitial_dev, const Matrix3d d_dev, Matrix3d &sigmaFinal_dev__, + Matrix3d &sigma_dev_rate__, double &plastic_strain_increment); + +/* + * Damage models + */ + +bool IsotropicMaxStrainDamage(const Matrix3d E, const double maxStrain); +bool IsotropicMaxStressDamage(const Matrix3d E, const double maxStrain); +double JohnsonCookFailureStrain(const double p, const Matrix3d Sdev, const double d1, const double d2, const double d3, + const double d4, const double epdot0, const double epdot); + + + +#endif /* SMD_MATERIAL_MODELS_H_ */ diff --git a/src/USER-SMD/smd_math.h b/src/USER-SMD/smd_math.h new file mode 100644 index 0000000000..5352cfccf9 --- /dev/null +++ b/src/USER-SMD/smd_math.h @@ -0,0 +1,287 @@ +/* ---------------------------------------------------------------------- + * + * *** Smooth Mach Dynamics *** + * + * This file is part of the USER-SMD package for LAMMPS. + * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de + * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, + * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. + * + * ----------------------------------------------------------------------- */ + +//test +#ifndef SMD_MATH_H_ +#define SMD_MATH_H_ + +#include +#include +using namespace Eigen; +using namespace std; + +namespace SMD_Math { +static inline void LimitDoubleMagnitude(double &x, const double limit) { + /* + * if |x| exceeds limit, set x to limit with the sign of x + */ + if (fabs(x) > limit) { // limit delVdotDelR to a fraction of speed of sound + x = limit * copysign(1, x); + } +} + +/* + * deviator of a tensor + */ +static inline Matrix3d Deviator(const Matrix3d M) { + Matrix3d eye; + eye.setIdentity(); + eye *= M.trace() / 3.0; + return M - eye; +} + +/* + * Polar Decomposition M = R * T + * where R is a rotation and T a pure translation/stretch matrix. + * + * The decomposition is achieved using SVD, i.e. M = U S V^T, + * where U = R V and S is diagonal. + * + * + * For any physically admissible deformation gradient, the determinant of R must equal +1. + * However, scenerios can arise, where the particles interpenetrate and cause inversion, leading to a determinant of R equal to -1. + * In this case, the inversion direction is heuristically identified with the eigenvector of the smallest entry of S, which should work for most cases. + * The sign of this corresponding eigenvalue is flipped, the original matrix M is recomputed using the flipped S, and the rotation and translation matrices are + * obtained again from an SVD. The rotation should proper now, i.e., det(R) = +1. + */ + +static inline bool PolDec(Matrix3d M, Matrix3d &R, Matrix3d &T, bool scaleF) { + + JacobiSVD svd(M, ComputeFullU | ComputeFullV); // SVD(A) = U S V* + Vector3d S_eigenvalues = svd.singularValues(); + Matrix3d S = svd.singularValues().asDiagonal(); + Matrix3d U = svd.matrixU(); + Matrix3d V = svd.matrixV(); + Matrix3d eye; + eye.setIdentity(); + + // now do polar decomposition into M = R * T, where R is rotation + // and T is translation matrix + R = U * V.transpose(); + T = V * S * V.transpose(); + + if (R.determinant() < 0.0) { // this is an improper rotation + // identify the smallest entry in S and flip its sign + int imin; + S_eigenvalues.minCoeff(&imin); + S(imin, imin) *= -1.0; + + R = M * V * S.inverse() * V.transpose(); // recompute R using flipped stretch eigenvalues + } + + /* + * scale S to avoid small principal strains + */ + + if (scaleF) { + double min = 0.3; // 0.3^2 = 0.09, should suffice for most problems + double max = 2.0; + for (int i = 0; i < 3; i++) { + if (S(i, i) < min) { + S(i, i) = min; + } else if (S(i, i) > max) { + S(i, i) = max; + } + } + T = V * S * V.transpose(); + } + + if (R.determinant() > 0.0) { + return true; + } else { + return false; + } +} + +/* + * Pseudo-inverse via SVD + */ + +static inline void pseudo_inverse_SVD(Matrix3d &M) { + + //JacobiSVD < Matrix3d > svd(M, ComputeFullU | ComputeFullV); + JacobiSVD svd(M, ComputeFullU); // one Eigevector base is sufficient because matrix is square and symmetric + + Vector3d singularValuesInv; + Vector3d singularValues = svd.singularValues(); + +//cout << "Here is the matrix V:" << endl << V * singularValues.asDiagonal() * U << endl; +//cout << "Its singular values are:" << endl << singularValues << endl; + + double pinvtoler = 1.0e-16; // 2d machining example goes unstable if this value is increased (1.0e-16). + for (int row = 0; row < 3; row++) { + if (singularValues(row) > pinvtoler) { + singularValuesInv(row) = 1.0 / singularValues(row); + } else { + singularValuesInv(row) = 0.0; + } + } + + M = svd.matrixU() * singularValuesInv.asDiagonal() * svd.matrixU().transpose(); + +// JacobiSVD < Matrix3d > svd(M, ComputeFullU | ComputeFullV); +// +// Vector3d singularValuesInv; +// Vector3d singularValues = svd.singularValues(); +// +// //cout << "Here is the matrix V:" << endl << V * singularValues.asDiagonal() * U << endl; +// //cout << "Its singular values are:" << endl << singularValues << endl; +// +// double pinvtoler = 1.0e-16; // 2d machining example goes unstable if this value is increased (1.0e-16). +// for (int row = 0; row < 3; row++) { +// if (singularValues(row) > pinvtoler) { +// singularValuesInv(row) = 1.0 / singularValues(row); +// } else { +// singularValuesInv(row) = 0.0; +// } +// } +// +// M = svd.matrixU() * singularValuesInv.asDiagonal() * svd.matrixV().transpose(); + +} + +/* + * test if two matrices are equal + */ +static inline double TestMatricesEqual(Matrix3d A, Matrix3d B, double eps) { + Matrix3d diff; + diff = A - B; + double norm = diff.norm(); + if (norm > eps) { + printf("Matrices A and B are not equal! The L2-norm difference is: %g\n", norm); + cout << "Here is matrix A:" << endl << A << endl; + cout << "Here is matrix B:" << endl << B << endl; + } + return norm; +} + +/* ---------------------------------------------------------------------- + Limit eigenvalues of a matrix to upper and lower bounds. + ------------------------------------------------------------------------- */ + +static inline Matrix3d LimitEigenvalues(Matrix3d S, double limitEigenvalue) { + + /* + * compute Eigenvalues of matrix S + */ + SelfAdjointEigenSolver < Matrix3d > es; + es.compute(S); + + double max_eigenvalue = es.eigenvalues().maxCoeff(); + double min_eigenvalue = es.eigenvalues().minCoeff(); + double amax_eigenvalue = fabs(max_eigenvalue); + double amin_eigenvalue = fabs(min_eigenvalue); + + if ((amax_eigenvalue > limitEigenvalue) || (amin_eigenvalue > limitEigenvalue)) { + if (amax_eigenvalue > amin_eigenvalue) { // need to scale with max_eigenvalue + double scale = amax_eigenvalue / limitEigenvalue; + Matrix3d V = es.eigenvectors(); + Matrix3d S_diag = V.inverse() * S * V; // diagonalized input matrix + S_diag /= scale; + Matrix3d S_scaled = V * S_diag * V.inverse(); // undiagonalize matrix + return S_scaled; + } else { // need to scale using min_eigenvalue + double scale = amin_eigenvalue / limitEigenvalue; + Matrix3d V = es.eigenvectors(); + Matrix3d S_diag = V.inverse() * S * V; // diagonalized input matrix + S_diag /= scale; + Matrix3d S_scaled = V * S_diag * V.inverse(); // undiagonalize matrix + return S_scaled; + } + } else { // limiting does not apply + return S; + } +} + +static inline bool LimitMinMaxEigenvalues(Matrix3d &S, double min, double max) { + + /* + * compute Eigenvalues of matrix S + */ + SelfAdjointEigenSolver < Matrix3d > es; + es.compute(S); + + if ((es.eigenvalues().maxCoeff() > max) || (es.eigenvalues().minCoeff() < min)) { + Matrix3d S_diag = es.eigenvalues().asDiagonal(); + Matrix3d V = es.eigenvectors(); + for (int i = 0; i < 3; i++) { + if (S_diag(i, i) < min) { + //printf("limiting eigenvalue %f --> %f\n", S_diag(i, i), min); + //printf("these are the eigenvalues of U: %f %f %f\n", es.eigenvalues()(0), es.eigenvalues()(1), es.eigenvalues()(2)); + S_diag(i, i) = min; + } else if (S_diag(i, i) > max) { + //printf("limiting eigenvalue %f --> %f\n", S_diag(i, i), max); + S_diag(i, i) = max; + } + } + S = V * S_diag * V.inverse(); // undiagonalize matrix + return true; + } else { + return false; + } +} + +static inline void reconstruct_rank_deficient_shape_matrix(Matrix3d &K) { + + JacobiSVD svd(K, ComputeFullU | ComputeFullV); + Vector3d singularValues = svd.singularValues(); + + for (int i = 0; i < 3; i++) { + if (singularValues(i) < 1.0e-8) { + singularValues(i) = 1.0; + } + } + +// int imin; +// double minev = singularValues.minCoeff(&imin); +// +// printf("min eigenvalue=%f has index %d\n", minev, imin); +// Vector3d singularVec = U.col(0).cross(U.col(1)); +// cout << "the eigenvalues are " << endl << singularValues << endl; +// cout << "the singular vector is " << endl << singularVec << endl; +// +// // reconstruct original K +// +// singularValues(2) = 1.0; + + K = svd.matrixU() * singularValues.asDiagonal() * svd.matrixV().transpose(); + //cout << "the reconstructed K is " << endl << K << endl; + //exit(1); +} + +/* ---------------------------------------------------------------------- + helper functions for crack_exclude + ------------------------------------------------------------------------- */ +static inline bool IsOnSegment(double xi, double yi, double xj, double yj, double xk, double yk) { + return (xi <= xk || xj <= xk) && (xk <= xi || xk <= xj) && (yi <= yk || yj <= yk) && (yk <= yi || yk <= yj); +} + +static inline char ComputeDirection(double xi, double yi, double xj, double yj, double xk, double yk) { + double a = (xk - xi) * (yj - yi); + double b = (xj - xi) * (yk - yi); + return a < b ? -1.0 : a > b ? 1.0 : 0; +} + +/** Do line segments (x1, y1)--(x2, y2) and (x3, y3)--(x4, y4) intersect? */ +static inline bool DoLineSegmentsIntersect(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) { + char d1 = ComputeDirection(x3, y3, x4, y4, x1, y1); + char d2 = ComputeDirection(x3, y3, x4, y4, x2, y2); + char d3 = ComputeDirection(x1, y1, x2, y2, x3, y3); + char d4 = ComputeDirection(x1, y1, x2, y2, x4, y4); + return (((d1 > 0 && d2 < 0) || (d1 < 0 && d2 > 0)) && ((d3 > 0 && d4 < 0) || (d3 < 0 && d4 > 0))) + || (d1 == 0 && IsOnSegment(x3, y3, x4, y4, x1, y1)) || (d2 == 0 && IsOnSegment(x3, y3, x4, y4, x2, y2)) + || (d3 == 0 && IsOnSegment(x1, y1, x2, y2, x3, y3)) || (d4 == 0 && IsOnSegment(x1, y1, x2, y2, x4, y4)); +} + +} + +#endif /* SMD_MATH_H_ */ + diff --git a/src/set.cpp b/src/set.cpp index 5f3af82122..737568a085 100644 --- a/src/set.cpp +++ b/src/set.cpp @@ -43,7 +43,7 @@ enum{ATOM_SELECT,MOL_SELECT,TYPE_SELECT,GROUP_SELECT,REGION_SELECT}; enum{TYPE,TYPE_FRACTION,MOLECULE,X,Y,Z,CHARGE,MASS,SHAPE,LENGTH,TRI, DIPOLE,DIPOLE_RANDOM,QUAT,QUAT_RANDOM,THETA,ANGMOM, DIAMETER,DENSITY,VOLUME,IMAGE,BOND,ANGLE,DIHEDRAL,IMPROPER, - MESO_E,MESO_CV,MESO_RHO,INAME,DNAME}; + MESO_E,MESO_CV,MESO_RHO,SMD_MASS_DENSITY,SMD_CONTACT_RADIUS,INAME,DNAME}; #define BIG INT_MAX @@ -384,6 +384,24 @@ void Set::command(int narg, char **arg) set(MESO_RHO); iarg += 2; + } else if (strcmp(arg[iarg],"smd_mass_density") == 0) { + if (iarg+2 > narg) error->all(FLERR,"Illegal set command"); + if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1); + else dvalue = force->numeric(FLERR,arg[iarg+1]); + if (!atom->smd_flag) + error->all(FLERR,"Cannot set smd_mass_density for this atom style"); + set(SMD_MASS_DENSITY); + iarg += 2; + + } else if (strcmp(arg[iarg],"smd_contact_radius") == 0) { + if (iarg+2 > narg) error->all(FLERR,"Illegal set command"); + if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1); + else dvalue = force->numeric(FLERR,arg[iarg+1]); + if (!atom->smd_flag) + error->all(FLERR,"Cannot set smd_contact_radius for this atom style"); + set(SMD_CONTACT_RADIUS); + iarg += 2; + } else if (strstr(arg[iarg],"i_") == arg[iarg]) { if (iarg+2 > narg) error->all(FLERR,"Illegal set command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1); @@ -571,6 +589,10 @@ void Set::set(int keyword) else if (keyword == MESO_E) atom->e[i] = dvalue; else if (keyword == MESO_CV) atom->cv[i] = dvalue; else if (keyword == MESO_RHO) atom->rho[i] = dvalue; + else if (keyword == SMD_MASS_DENSITY) { // set mass from volume and supplied mass density + atom->rmass[i] = atom->vfrac[i] * dvalue; + } + else if (keyword == SMD_CONTACT_RADIUS) atom->contact_radius[i] = dvalue; // set shape of ellipsoidal particle