Page MenuHomec4science

pair_smd_ulsph.cpp
No OneTemporary

File Metadata

Created
Sun, Nov 10, 16:11

pair_smd_ulsph.cpp

/* ----------------------------------------------------------------------
*
* *** 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 <stdio.h>
#include <iostream>
#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 <Eigen/Eigen>
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, 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);
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;
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:
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;
}

Event Timeline