Files
LIGGGHTS-PFM/src/fix_nve_asphere_base.cpp
2018-04-09 10:10:11 +02:00

674 lines
25 KiB
C++

/* ----------------------------------------------------------------------
This file is part of the LIGGGHTS DEM simulation engine, released by
DCS Computing Gmbh, Linz, Austria
http://www.dcs-computing.com, office@dcs-computing.com
LIGGGHTS® is part of CFDEM®project:
http://www.liggghts.com | http://www.cfdem.com
Core developer and main author:
Christoph Kloss, christoph.kloss@dcs-computing.com
LIGGGHTS® is open-source, distributed under the terms of the GNU Public
License, version 2 or later. It is distributed in the hope that it will
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. You should have
received a copy of the GNU General Public License along with LIGGGHTS®.
If not, see http://www.gnu.org/licenses . See also top-level README
and LICENSE files.
LIGGGHTS® and CFDEM® are registered trade marks of DCS Computing GmbH,
the producer of the LIGGGHTS® software and the CFDEM®coupling software
See http://www.cfdem.com/terms-trademark-policy for details.
-------------------------------------------------------------------------
Contributing author and copyright for this file:
Alexander Podlozhnyuk, DCS Computing GmbH, Linz
Christoph Kloss, DCS Computing GmbH, Linz
Copyright 2015- DCS Computing GmbH, Linz
------------------------------------------------------------------------- */
#include <cmath>
#include <stdio.h>
#include <string.h>
#include "fix_nve_asphere_base.h"
#include "atom.h"
#include "atom_vec.h"
#include "update.h"
#include "respa.h"
#include "force.h"
#include "error.h"
#include "domain.h"
#include "math_extra_liggghts_nonspherical.h"
#include "fix_property_atom.h"
/* ---------------------------------------------------------------------- */
enum {
INTEGRATION_SCHEME_RICHARDSON = 0,
INTEGRATION_SCHEME_SYMPLECTIC,
INTEGRATION_SCHEME_LEAP_FROG,
INTEGRATION_SCHEME_WOODEM,
INTEGRATION_SCHEME_IMPLICIT
};
FixNVEAsphereBase::FixNVEAsphereBase(LAMMPS *lmp, int narg, char **arg) :
FixNVE(lmp, narg, arg)
{
if (narg < 3) error->all(FLERR,"Illegal fix nve/superquadric command");
time_integrate = 1;
// process extra keywords
integration_scheme = INTEGRATION_SCHEME_SYMPLECTIC;
int iarg = 3;
while (iarg < narg) {
if (strcmp(arg[iarg],"integration_scheme") == 0) {
integration_scheme = force->numeric(FLERR,arg[iarg+1]);
iarg += 2;
}
else error->fix_error(FLERR,this,"unknown keyword");
}
hdtorque = NULL;
orientation = NULL;
ksl_rotation = NULL;
couple_fix_id = -1;
for(int ifix = 0; ifix < modify->nfix; ifix++) {
if(strcmp(modify->fix[ifix]->style, "couple/cfd/force/implicit")==0) {
couple_fix_id = ifix;
break;
}
}
}
/* ---------------------------------------------------------------------- */
void FixNVEAsphereBase::init()
{
FixNVE::init();
// error checks might go here
}
/* ---------------------------------------------------------------------- */
//dynamic Euler equations for angular velocity in body's principal axes
void FixNVEAsphereBase::dynamic_euler(double *wbody, double *tbody, double *inertia, double *result)
{
// result := angular acceleration
result[0] = (tbody[0] + wbody[1]*wbody[2]*(inertia[1] - inertia[2])) / inertia[0];
result[1] = (tbody[1] + wbody[2]*wbody[0]*(inertia[2] - inertia[0])) / inertia[1];
result[2] = (tbody[2] + wbody[0]*wbody[1]*(inertia[0] - inertia[1])) / inertia[2];
}
/* ---------------------------------------------------------------------- */
void FixNVEAsphereBase::integrate_dynamic_euler(double dt, double *wbody, double *tbody, double *inertia)
{
double alpha[3];
const double tol = 1e-12;
if(LAMMPS_NS::vectorMag3D(wbody)*dt > 1.0)
error->one(FLERR, "Timestep is too big for rotation integration!");
dynamic_euler(wbody, tbody, inertia, alpha);
double omega_half_prev[3], delta[3];
double omega_half[] = {0.0, 0.0, 0.0};
while(1) {
LAMMPS_NS::vectorCopy3D(omega_half, omega_half_prev);
omega_half[0] = wbody[0] + 0.5*dt*alpha[0];
omega_half[1] = wbody[1] + 0.5*dt*alpha[1];
omega_half[2] = wbody[2] + 0.5*dt*alpha[2];
LAMMPS_NS::vectorSubtract3D(omega_half_prev, omega_half, delta);
const double omega_half_mag_sqr = LAMMPS_NS::vectorMag3DSquared(omega_half);
if(omega_half_mag_sqr > 0.0) {
double eps = LAMMPS_NS::vectorMag3D(delta) / sqrt(omega_half_mag_sqr);
if(eps < tol)
break;
dynamic_euler(omega_half, tbody, inertia, alpha);
} else
break;
}
wbody[0] += dt*alpha[0];
wbody[1] += dt*alpha[1];
wbody[2] += dt*alpha[2];
}
/* ---------------------------------------------------------------------- */
void FixNVEAsphereBase::integrate_quaternion(double dtq, double *quat, double *wbody)
{
double q2[4];
q2[0] = 1.0;
q2[1] = -wbody[0] * dtq;
q2[2] = -wbody[1] * dtq;
q2[3] = -wbody[2] * dtq;
MathExtraLiggghtsNonspherical::invquat(q2); //using implicit scheme
double q_temp[4];
MathExtra::quatquat(quat, q2, q_temp);
vectorCopy4D(q_temp, quat);
MathExtra::qnormalize(quat);
}
/* ---------------------------------------------------------------------- */
void FixNVEAsphereBase::update_hdtorque(int i, double *rotation_matrix, double *omegaOld, double *omegaNew)
{
if(ksl_rotation && hdtorque) {
double deltaHydrotorquePrime[3], deltaHydrotorque[3];
for(int dirI = 0; dirI < 3; dirI++)
deltaHydrotorquePrime[dirI] = ksl_rotation[i][dirI]*(omegaOld[dirI]-omegaNew[dirI]);
MathExtraLiggghtsNonspherical::matvec(rotation_matrix, deltaHydrotorquePrime, deltaHydrotorque);
for(int dirI=0; dirI<3; dirI++)
hdtorque[i][dirI] += deltaHydrotorque[dirI];
}
}
/* ---------------------------------------------------------------------- */
void FixNVEAsphereBase::implicitRotationUpdate
(
double deltaT, double* inertia,
double *angMom, double *torque, double* KslRot,
double *omegaNew,
double *deltaHydrotorquePrime
)
{
int index1_[3] = { 2, 0, 1 };
int index2_[3] = { 1, 2, 0 };
double omegaOld[3], dtfm, KslMDeltaT;
double omegaAngMomTerm;
for(int dirI=0;dirI<3;dirI++)
{
if (inertia[dirI] == 0.0)
{
omegaOld[dirI] = 0.0;
continue;
}
omegaOld[dirI] = angMom[dirI] / inertia[dirI];
}
for(int dirI=0;dirI<3;dirI++)
{
omegaAngMomTerm = omegaOld[index2_[dirI]]*angMom[index1_[dirI]]
- omegaOld[index1_[dirI]]*angMom[index2_[dirI]];
dtfm = deltaT
/ ( inertia[dirI]);
KslMDeltaT = KslRot[dirI] * dtfm;
//calculate new rotation velocity
omegaNew[dirI] = ( omegaOld[dirI]
+ dtfm
* ( torque[dirI] //this is the TOTAL torque!
- omegaAngMomTerm
+ KslRot[dirI]*omegaOld[dirI]
)
)
/
( 1.0+KslMDeltaT);
//save increment in hdtorque to update torque since particle is now rotation with omegaNew
deltaHydrotorquePrime[dirI] = KslRot[dirI]*(omegaOld[dirI]-omegaNew[dirI]);
//update the angular momentum
angMom[dirI] = omegaNew[dirI] * inertia[dirI]; //update velocity for a half step!
}
}
/* ---------------------------------------------------------------------- */
void FixNVEAsphereBase::rotationUpdate(bool updateQuaternion)
{
double omegaNew[3];
double exone[3],eyone[3],ezone[3];
double angMomPrime[3];
double torquePrime[3];
double omegaNewPrime[3];
double deltaHydrotorquePrime[3];
double deltaHydrotorque[3];
double rot[3][3];
// This is okey only for SPHERICAL particles
// update 1/2 step for omega
double **angmom = atom->angmom;
double **quat = atom->quaternion;
double **inertia = atom->inertia;
double **omega = atom->omega;
double **torque = atom->torque;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double dtq = 0.5 * dtv;
//save rotation rate to array if necessary
orientation = NULL;
ksl_rotation = NULL;
hdtorque = NULL;
if(couple_fix_id > -1) {
ksl_rotation = ((FixCfdCouplingForceImplicit*)modify->fix[couple_fix_id])->fix_KslRotation_->array_atom;
hdtorque = ((FixCfdCouplingForceImplicit*)modify->fix[couple_fix_id])->fix_hdtorque_->array_atom;
orientation = ((FixCfdCouplingForceImplicit*)modify->fix[couple_fix_id])->fix_ex_->array_atom;
}
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit)
{
MathExtra::quat_to_mat(quat[i],rot); //rotation matrix
//Compute all relevant quantities in the particle's coordinate system called 'prime'
MathExtra::transpose_matvec(rot,angmom[i],angMomPrime);
MathExtra::transpose_matvec(rot,torque[i],torquePrime);
//Implicit angmom and omegaNew update in the 'prime' coordinate system
implicitRotationUpdate
(
dtf, inertia[i],
angMomPrime, torquePrime, ksl_rotation[i],
omegaNewPrime,
deltaHydrotorquePrime
);
//Transform result to global coordinate system and update hydro torque (since it is the total!)
MathExtra::matvec(rot,angMomPrime,angmom[i]);
MathExtra::matvec(rot,omegaNewPrime,omegaNew);
MathExtra::matvec(rot,deltaHydrotorquePrime,deltaHydrotorque); //save torque
for(int dirI=0; dirI<3; dirI++)
hdtorque[i][dirI] += deltaHydrotorque[dirI];
// compute omega at 1/2 step from angmom at 1/2 step and current q
// update quaternion a full step via Richardson iteration
// returns new normalized quaternion
if(updateQuaternion)
MathExtra::richardson(quat[i],angmom[i],omegaNew,inertia[i],dtq);
omega[i][0]=omegaNew[0];
omega[i][1]=omegaNew[1];
omega[i][2]=omegaNew[2];
if(ksl_rotation && updateQuaternion)
{
MathExtra::q_to_exyz(quat[i],exone,eyone,ezone);
orientation[i][0] = exone[0];
orientation[i][1] = exone[1];
orientation[i][2] = exone[2];
}
} //end of particle
}
}
/* ---------------------------------------------------------------------- */
void FixNVEAsphereBase::initial_integrate(int vflag)
{
double **x = atom->x;
double **v = atom->v;
double **f = atom->f;
double **omega = atom->omega;
double **torque = atom->torque;
double *rmass = atom->rmass;
double **angmom = atom->angmom;
double **quat = atom->quaternion;
double **inertia = atom->inertia;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (igroup == atom->firstgroup) nlocal = atom->nfirst;
orientation = NULL;
ksl_rotation = NULL;
hdtorque = NULL;
if(couple_fix_id > -1) {
ksl_rotation = ((FixCfdCouplingForceImplicit*)modify->fix[couple_fix_id])->fix_KslRotation_->array_atom;
hdtorque = ((FixCfdCouplingForceImplicit*)modify->fix[couple_fix_id])->fix_hdtorque_->array_atom;
orientation = ((FixCfdCouplingForceImplicit*)modify->fix[couple_fix_id])->fix_ex_->array_atom;
}
double tbody[3], rotation_matrix[9];
double fquat[4], mbody[3], wbody[3], conjqm[4];
double angMomPrime[3];
double omegaNewPrime[3], omegaOldPrime[3];
const double dtf2 = 2.0 * dtf;
const double dtq = 0.5 * dtv;
for (int i = 0; i < nlocal; i++)
{
if (mask[i] & groupbit)
{
#ifdef LIGGGHTS_DEBUG
if(std::isnan(LAMMPS_NS::vectorMag3D(x[i])))
error->fix_error(FLERR,this,"x[i] is NaN!");
if(std::isnan(LAMMPS_NS::vectorMag3D(v[i])))
error->fix_error(FLERR,this,"v[i] is NaN!");
if(std::isnan(LAMMPS_NS::vectorMag3D(f[i])))
error->fix_error(FLERR,this,"f[i] is NaN!");
if(std::isnan(LAMMPS_NS::vectorMag4D(quat[i])))
error->fix_error(FLERR,this,"quat[i] is NaN!");
if(std::isnan(LAMMPS_NS::vectorMag3D(angmom[i])))
error->fix_error(FLERR,this,"angmom[i] is NaN!");
if(std::isnan(LAMMPS_NS::vectorMag3D(omega[i])))
error->fix_error(FLERR,this,"omega[i] is NaN!");
if(std::isnan(LAMMPS_NS::vectorMag3D(torque[i])))
error->fix_error(FLERR,this,"torque[i] is NaN!");
#endif
MathExtraLiggghtsNonspherical::quat_to_mat(quat[i], rotation_matrix);
const double dtfm = dtf / rmass[i];
MathExtraLiggghtsNonspherical::transpose_matvec(rotation_matrix, angmom[i], angMomPrime);
omegaOldPrime[0] = angMomPrime[0] / inertia[i][0];
omegaOldPrime[1] = angMomPrime[1] / inertia[i][1];
omegaOldPrime[2] = angMomPrime[2] / inertia[i][2];
//update velocity by step t+1/2dt
v[i][0] += dtfm * f[i][0];
v[i][1] += dtfm * f[i][1];
v[i][2] += dtfm * f[i][2];
#ifdef LIGGGHTS_DEBUG
if(std::isnan(LAMMPS_NS::vectorMag3D(v[i])))
error->fix_error(FLERR,this,"v[i] is NaN!");
#endif
//update position by step t+dt
x[i][0] += dtv * v[i][0];
x[i][1] += dtv * v[i][1];
x[i][2] += dtv * v[i][2];
#ifdef LIGGGHTS_DEBUG
if(std::isnan(LAMMPS_NS::vectorMag3D(x[i])))
error->fix_error(FLERR,this,"x[i] is NaN!");
#endif
switch(integration_scheme) {
case INTEGRATION_SCHEME_RICHARDSON:
{
//update angular moment by step t+1/2dt
angmom[i][0] += dtf * torque[i][0];
angmom[i][1] += dtf * torque[i][1];
angmom[i][2] += dtf * torque[i][2];
//update angular velocity by step t+1/2dt
MathExtra::mq_to_omega(angmom[i],quat[i],inertia[i],omega[i]);
MathExtraLiggghtsNonspherical::transpose_matvec(rotation_matrix, omega[i], omegaNewPrime);
update_hdtorque(i, rotation_matrix, omegaOldPrime, omegaNewPrime);
//update quaternion by step t+dt
MathExtra::richardson(quat[i],angmom[i],omega[i],inertia[i],dtq);
break;
}
case INTEGRATION_SCHEME_SYMPLECTIC: //symplectic scheme
{
MathExtraLiggghtsNonspherical::transpose_matvec(rotation_matrix, angmom[i],mbody);
MathExtraLiggghtsNonspherical::calc_conjqm(quat[i],mbody,conjqm);
MathExtraLiggghtsNonspherical::transpose_matvec(rotation_matrix, torque[i], tbody);
MathExtra::quatvec(quat[i], tbody, fquat);
conjqm[0] += dtf2 * fquat[0];
conjqm[1] += dtf2 * fquat[1];
conjqm[2] += dtf2 * fquat[2];
conjqm[3] += dtf2 * fquat[3];
MathExtraLiggghtsNonspherical::no_squish_rotate(3,conjqm,quat[i],inertia[i],dtq);
MathExtraLiggghtsNonspherical::no_squish_rotate(2,conjqm,quat[i],inertia[i],dtq);
MathExtraLiggghtsNonspherical::no_squish_rotate(1,conjqm,quat[i],inertia[i],dtv);
MathExtraLiggghtsNonspherical::no_squish_rotate(2,conjqm,quat[i],inertia[i],dtq);
MathExtraLiggghtsNonspherical::no_squish_rotate(3,conjqm,quat[i],inertia[i],dtq);
MathExtra::qnormalize(quat[i]);
MathExtraLiggghtsNonspherical::quat_to_mat(quat[i], rotation_matrix);
MathExtra::invquatvec(quat[i],conjqm,mbody);
mbody[0] *= 0.5;
mbody[1] *= 0.5;
mbody[2] *= 0.5;
wbody[0] = mbody[0] / inertia[i][0];
wbody[1] = mbody[1] / inertia[i][1];
wbody[2] = mbody[2] / inertia[i][2];
MathExtraLiggghtsNonspherical::matvec(rotation_matrix, mbody, angmom[i]);
MathExtraLiggghtsNonspherical::matvec(rotation_matrix, wbody, omega[i]);
break;
}
case INTEGRATION_SCHEME_LEAP_FROG: //direct integration, 2nd order predictor-corrector
{
double omega_half[3];
MathExtraLiggghtsNonspherical::quat_to_mat(quat[i], rotation_matrix); //calculate rotation matrix from quaternion
MathExtraLiggghtsNonspherical::transpose_matvec(rotation_matrix, omega[i],wbody); //angular velocity in body principal axes
MathExtraLiggghtsNonspherical::transpose_matvec(rotation_matrix, torque[i], tbody); //torque in body principal axes
omega_half[0] = wbody[0];
omega_half[1] = wbody[1];
omega_half[2] = wbody[2];
integrate_dynamic_euler(dtf, wbody, tbody, inertia[i]); //calculate angular velocity at step t+dt
omega_half[0] = 0.5*(wbody[0] + omega_half[0]); //angular velocity at step t+dt/2
omega_half[1] = 0.5*(wbody[1] + omega_half[1]);
omega_half[2] = 0.5*(wbody[2] + omega_half[2]);
integrate_quaternion(dtq, quat[i], wbody); //calculate quaternion at step t+dt
update_hdtorque(i, rotation_matrix, omegaOldPrime, wbody);
mbody[0] = inertia[i][0]*wbody[0]; //calculate angular momentum at step t+dt from angular velocity in body's principal axes
mbody[1] = inertia[i][1]*wbody[1];
mbody[2] = inertia[i][2]*wbody[2];
MathExtraLiggghtsNonspherical::matvec(rotation_matrix, mbody, angmom[i]); // angular momentum to global frame
MathExtraLiggghtsNonspherical::matvec(rotation_matrix, wbody, omega[i]); // angular velocity to global frame
break;
}
case INTEGRATION_SCHEME_WOODEM: //woodem scheme
{
double angmom_half[3], angmom_half_local[3], angmom_next_local[3];
for(int j = 0; j < 3; j++)
angmom_half[j] = angmom[i][j] + torque[i][j]*dtf;
MathExtraLiggghtsNonspherical::transpose_matvec(rotation_matrix, angmom_half, angmom_half_local);
for(int j = 0; j < 3; j++)
angmom[i][j] += torque[i][j]*dtf2;
MathExtraLiggghtsNonspherical::transpose_matvec(rotation_matrix, angmom[i], angmom_next_local);
double omega_half_local[3], omega_next_local[3], q_der[4], quat_half[4];
for(int j = 0; j < 3; j++) {
omega_half_local[j] = angmom_half_local[j] / inertia[i][j];
omega_next_local[j] = angmom_next_local[j] / inertia[i][j];
}
update_hdtorque(i, rotation_matrix, omegaOldPrime, omega_next_local);
MathExtra::quatvec(quat[i], omega_half_local, q_der);
for(int j = 0; j < 4; j++)
quat_half[j] = quat[i][j] + q_der[j]*dtq*0.5;
MathExtra::qnormalize(quat_half);
MathExtra::quatvec(quat_half, omega_next_local, q_der);
for(int j = 0; j < 4; j++)
quat[i][j] += q_der[j]*dtq;
MathExtra::qnormalize(quat[i]);
MathExtraLiggghtsNonspherical::quat_to_mat(quat[i], rotation_matrix);
MathExtraLiggghtsNonspherical::matvec(rotation_matrix, omega_next_local, omega[i]);
break;
}
case INTEGRATION_SCHEME_IMPLICIT:
{
rotationUpdate(true);
break;
}
default:
error->one(FLERR,"Invalid integration scheme! Please choose between 0, 1 (default), 2 or 3!");
break;
}
#ifdef LIGGGHTS_DEBUG
if(std::isnan(LAMMPS_NS::vectorMag4D(quat[i])))
error->fix_error(FLERR,this,"quat[i] is NaN!");
if(std::isnan(LAMMPS_NS::vectorMag3D(angmom[i])))
error->fix_error(FLERR,this,"angmom[i] is NaN!");
if(std::isnan(LAMMPS_NS::vectorMag3D(omega[i])))
error->fix_error(FLERR,this,"omega[i] is NaN!");
#endif
if(orientation) {
double exone[3], eyone[3], ezone[3];
MathExtra::q_to_exyz(quat[i],exone,eyone,ezone);
orientation[i][0] = exone[0];
orientation[i][1] = exone[1];
orientation[i][2] = exone[2];
}
}
}
}
/* ---------------------------------------------------------------------- */
void FixNVEAsphereBase::final_integrate()
{
double **v = atom->v;
double **f = atom->f;
double **omega = atom->omega;
double **torque = atom->torque;
double *rmass = atom->rmass;
double **angmom = atom->angmom;
double **quat = atom->quaternion;
double **inertia = atom->inertia;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (igroup == atom->firstgroup) nlocal = atom->nfirst;
double tbody[3], rotation_matrix[9];
double fquat[4], mbody[3], wbody[3];
double dtf2 = dtf * 2.0;
double conjqm[4];
double angMomPrime[3], omegaNewPrime[3], omegaOldPrime[3];
ksl_rotation = 0;
hdtorque = 0;
orientation = 0;
if(couple_fix_id > -1) {
ksl_rotation = ((FixCfdCouplingForceImplicit*)modify->fix[couple_fix_id])->fix_KslRotation_->array_atom;
hdtorque = ((FixCfdCouplingForceImplicit*)modify->fix[couple_fix_id])->fix_hdtorque_->array_atom;
orientation = ((FixCfdCouplingForceImplicit*)modify->fix[couple_fix_id])->fix_ex_->array_atom;
}
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
#ifdef LIGGGHTS_DEBUG
if(std::isnan(LAMMPS_NS::vectorMag3D(v[i])))
error->fix_error(FLERR,this,"v[i] is NaN!");
if(std::isnan(LAMMPS_NS::vectorMag3D(f[i])))
error->fix_error(FLERR,this,"f[i] is NaN!");
if(std::isnan(LAMMPS_NS::vectorMag4D(quat[i])))
error->fix_error(FLERR,this,"quat[i] is NaN!");
if(std::isnan(LAMMPS_NS::vectorMag3D(angmom[i])))
error->fix_error(FLERR,this,"angmom[i] is NaN!");
if(std::isnan(LAMMPS_NS::vectorMag3D(omega[i])))
error->fix_error(FLERR,this,"omega[i] is NaN!");
if(std::isnan(LAMMPS_NS::vectorMag3D(torque[i])))
error->fix_error(FLERR,this,"torque[i] is NaN!");
#endif
const double dtfm = dtf / rmass[i];
MathExtraLiggghtsNonspherical::quat_to_mat(quat[i], rotation_matrix);
MathExtraLiggghtsNonspherical::transpose_matvec(rotation_matrix, angmom[i], angMomPrime);
omegaOldPrime[0] = angMomPrime[0] / inertia[i][0];
omegaOldPrime[1] = angMomPrime[1] / inertia[i][1];
omegaOldPrime[2] = angMomPrime[2] / inertia[i][2];
if(hdtorque) {
vectorAdd3D(torque[i], hdtorque[i], torque[i]);
vectorAdd3D(torque[i], hdtorque[i], torque[i]);
}
//update velocity by step t+dt
v[i][0] += dtfm * f[i][0];
v[i][1] += dtfm * f[i][1];
v[i][2] += dtfm * f[i][2];
#ifdef LIGGGHTS_DEBUG
if(std::isnan(LAMMPS_NS::vectorMag3D(v[i])))
error->fix_error(FLERR,this,"v[i] is NaN!");
#endif
switch(integration_scheme)
{
case INTEGRATION_SCHEME_RICHARDSON:
{
//update angular moment by step t+dt
angmom[i][0] += dtf * torque[i][0];
angmom[i][1] += dtf * torque[i][1];
angmom[i][2] += dtf * torque[i][2];
//update angular velocity by step t+dt
MathExtra::mq_to_omega(angmom[i],quat[i],inertia[i],omega[i]);
MathExtraLiggghtsNonspherical::transpose_matvec(rotation_matrix, omega[i], omegaNewPrime);
update_hdtorque(i, rotation_matrix, omegaOldPrime, omegaNewPrime);
break;
}
case INTEGRATION_SCHEME_SYMPLECTIC:
{
MathExtraLiggghtsNonspherical::transpose_matvec(rotation_matrix, torque[i], tbody);
MathExtraLiggghtsNonspherical::transpose_matvec(rotation_matrix, angmom[i], mbody);
MathExtraLiggghtsNonspherical::calc_conjqm(quat[i], mbody, conjqm);
MathExtra::quatvec(quat[i], tbody, fquat);
conjqm[0] += dtf2 * fquat[0];
conjqm[1] += dtf2 * fquat[1];
conjqm[2] += dtf2 * fquat[2];
conjqm[3] += dtf2 * fquat[3];
MathExtra::invquatvec(quat[i], conjqm, mbody);
mbody[0] *= 0.5;
mbody[1] *= 0.5;
mbody[2] *= 0.5;
wbody[0] = mbody[0] / inertia[i][0];
wbody[1] = mbody[1] / inertia[i][1];
wbody[2] = mbody[2] / inertia[i][2];
MathExtraLiggghtsNonspherical::matvec(rotation_matrix, mbody, angmom[i]);
MathExtraLiggghtsNonspherical::matvec(rotation_matrix, wbody, omega[i]);
update_hdtorque(i, rotation_matrix, omegaOldPrime, wbody);
break;
}
case INTEGRATION_SCHEME_LEAP_FROG:
{
MathExtraLiggghtsNonspherical::quat_to_mat(quat[i], rotation_matrix); //calculate rotation matrix from quaternion
MathExtraLiggghtsNonspherical::transpose_matvec(rotation_matrix, omega[i],wbody); //angular velocity in body principal axes
MathExtraLiggghtsNonspherical::transpose_matvec(rotation_matrix, torque[i], tbody); //torque in body principal axes
integrate_dynamic_euler(dtf, wbody, tbody, inertia[i]); //calculate angular velocity at step t+dt
update_hdtorque(i, rotation_matrix, omegaOldPrime, wbody);
mbody[0] = inertia[i][0]*wbody[0]; //calculate angular momentum at step t+dt from angular velocity in body's principal axes
mbody[1] = inertia[i][1]*wbody[1];
mbody[2] = inertia[i][2]*wbody[2];
MathExtraLiggghtsNonspherical::matvec(rotation_matrix, mbody, angmom[i]); // angular momentum to global frame
MathExtraLiggghtsNonspherical::matvec(rotation_matrix, wbody, omega[i]); // angular velocity to global frame
break;
}
case INTEGRATION_SCHEME_IMPLICIT:
{
rotationUpdate(false);
break;
}
default:
break;
}
#ifdef LIGGGHTS_DEBUG
if(std::isnan(LAMMPS_NS::vectorMag4D(quat[i])))
error->fix_error(FLERR,this,"quat[i] is NaN!");
if(std::isnan(LAMMPS_NS::vectorMag3D(angmom[i])))
error->fix_error(FLERR,this,"angmom[i] is NaN!");
if(std::isnan(LAMMPS_NS::vectorMag3D(omega[i])))
error->fix_error(FLERR,this,"omega[i] is NaN!");
#endif
}
}