Files
LIGGGHTS-PFM/src/fix_heat_gran.cpp
2012-09-07 19:24:08 +02:00

407 lines
14 KiB
C++

/* ----------------------------------------------------------------------
LIGGGHTS - LAMMPS Improved for General Granular and Granular Heat
Transfer Simulations
LIGGGHTS is part of the CFDEMproject
www.liggghts.com | www.cfdem.com
Christoph Kloss, christoph.kloss@cfdem.com
Copyright 2009-2012 JKU Linz
Copyright 2012- DCS Computing GmbH, Linz
LIGGGHTS is based on LAMMPS
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
This software is distributed under the GNU General Public License.
See the README file in the top-level directory.
------------------------------------------------------------------------- */
#include "math.h"
#include "stdlib.h"
#include "string.h"
#include "fix_heat_gran.h"
#include "atom.h"
#include "domain.h"
#include "group.h"
#include "force.h"
#include "comm.h"
#include "update.h"
#include "error.h"
#include "modify.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "pair_gran.h"
#include "math_extra.h"
#include "fix_property_global.h"
#include "fix_property_atom.h"
#include "fix_scalar_transport_equation.h"
#include "mech_param_gran.h"
#include "respa.h"
#include "compute_pair_gran_local.h"
using namespace LAMMPS_NS;
using namespace FixConst;
#define SMALL 1e-8
/* ---------------------------------------------------------------------- */
FixHeatGran::FixHeatGran(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg)
{
if ((!atom->radius_flag)||(!atom->rmass_flag)) error->all(FLERR,"Fix heat/gran needs per particle radius and mass");
if (narg < 5)
error->fix_error(FLERR,this,"not enough arguments");
int iarg = 3;
if(strcmp(arg[iarg++],"initial_temperature"))
error->fix_error(FLERR,this,"expecting keyword 'initial_temperature'");
T0 = atof(arg[iarg++]);
area_correction_flag = 0;
bool hasargs = true;
while(iarg < narg && hasargs)
{
hasargs = false;
if(strcmp(arg[iarg],"area_correction") == 0) {
if (iarg+2 > narg) error->fix_error(FLERR,this,"not enough arguments for keyword 'area_correction'");
if(strcmp(arg[iarg+1],"yes") == 0)
area_correction_flag = 1;
else if(strcmp(arg[iarg+1],"no") == 0)
area_correction_flag = 0;
else error->fix_error(FLERR,this,"");
iarg += 2;
hasargs = true;
} else if(strcmp(style,"heat/gran") == 0)
error->fix_error(FLERR,this,"unknown keyword");
}
fix_temp = fix_heatFlux = fix_heatSource = NULL;
fix_conductivity = NULL;
fix_ste = NULL;
conductivity = NULL;
peratom_flag = 1; //NP 0/1 if per-atom data is stored
size_peratom_cols = 0; //NP 0 = scalar, N = columns in peratom array
peratom_freq = 1;
time_depend = 1;
scalar_flag = 1; //NP total thermal energy computed
global_freq = 1; //NP available always
cpl = NULL;
}
/* ---------------------------------------------------------------------- */
FixHeatGran::~FixHeatGran()
{
//NP could delete fixes with no callbacks here since FixHeatGran has no callbacks
if(conductivity) delete []conductivity;
}
/* ---------------------------------------------------------------------- */
void FixHeatGran::post_create()
{
fix_ste = modify->find_fix_scalar_transport_equation("heattransfer");
if(!fix_ste)
{
char **newarg = new char*[15];
newarg[0] = (char *) "ste_heattransfer";
newarg[1] = group->names[igroup];
newarg[2] = (char *) "transportequation/scalar";
newarg[3] = (char *) "equation_id";
newarg[4] = (char *) "heattransfer";
newarg[5] = (char *) "quantity";
newarg[6] = (char *) "Temp";
newarg[7] = (char *) "default_value";
newarg[8] = new char[30];
sprintf(newarg[8],"%f",T0);
newarg[9] = (char *) "flux_quantity";
newarg[10] = (char *) "heatFlux";
newarg[11] = (char *) "source_quantity";
newarg[12] = (char *) "heatSource";
newarg[13] = (char *) "capacity_quantity";
newarg[14] = (char *) "thermalCapacity";
modify->add_fix(15,newarg);
delete [] newarg[8];
delete [] newarg;
}
}
/* ---------------------------------------------------------------------- */
void FixHeatGran::pre_delete(bool unfixflag)
{
// tell cpl that this fix is deleted
if(cpl && unfixflag) cpl->reference_deleted();
}
/* ---------------------------------------------------------------------- */
int FixHeatGran::setmask()
{
int mask = 0;
mask |= POST_FORCE;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixHeatGran::updatePtrs()
{
Temp = fix_temp->vector_atom;
vector_atom = Temp; //NP so that it is possible to access it from the input script
heatFlux = fix_heatFlux->vector_atom;
heatSource = fix_heatSource->vector_atom;
}
/* ---------------------------------------------------------------------- */
void FixHeatGran::init()
{
const double *Y,*nu,*Y_orig;
double expo,Yeff_ij,Yeff_orig_ij,ratio;
Fix* ymo_fix;
if (!atom->radius_flag || !atom->rmass_flag) error->all(FLERR,"Please use a granular atom style for fix heat/gran");
// check if a fix of this style already exists
if(modify->n_fixes_style(style) > 1)
error->fix_error(FLERR,this,"cannot have more than one fix of this style");
if(!force->pair_match("gran", 0)) error->all(FLERR,"Please use a granular pair style for fix heat/gran");
pair_gran = static_cast<PairGran*>(force->pair_match("gran", 0));
history_flag = pair_gran->is_history();
fix_ste = modify->find_fix_scalar_transport_equation("heattransfer");
if(!fix_ste) error->all(FLERR,"Fix heat/gran needs a fix transportequation/scalar to work with");
fix_temp = static_cast<FixPropertyAtom*>(modify->find_fix_property("Temp","property/atom","scalar",0,0,style));
fix_heatFlux = static_cast<FixPropertyAtom*>(modify->find_fix_property("heatFlux","property/atom","scalar",0,0,style));
fix_heatSource = static_cast<FixPropertyAtom*>(modify->find_fix_property("heatSource","property/atom","scalar",0,0,style));
int max_type = pair_gran->mpg->max_type();
if(conductivity) delete []conductivity;
conductivity = new double[max_type];
fix_conductivity = static_cast<FixPropertyGlobal*>(modify->find_fix_property("thermalConductivity","property/global","peratomtype",max_type,0,style));
// pre-calculate conductivity for possible contact material combinations
//NP apply coarse graining
for(int i=1;i< max_type+1; i++)
for(int j=1;j<max_type+1;j++)
{
conductivity[i-1] = force->cg()*force->cg()*fix_conductivity->compute_vector(i-1);
if(conductivity[i-1] < 0.) error->all(FLERR,"Fix heat/gran: Thermal conductivity must not be < 0");
}
// calculate heat transfer correction
ymo_fix = NULL;
if(area_correction_flag)
{
ymo_fix = modify->find_fix_property("youngsModulusOriginal","property/global","peratomtype",0,0,style);
if(force->pair_match("gran/hooke",0)) expo = 1.;
else if(force->pair_match("gran/hertz",0)) expo = 2./3.;
else error->all(FLERR,"Fix heat/gran with area correction could not identify the granular pair style you are using, supported are hooke and hertz types");
Y = static_cast<FixPropertyGlobal*>(modify->find_fix_property("youngsModulus","property/global","peratomtype",max_type,0,style))->get_values();
nu = static_cast<FixPropertyGlobal*>(modify->find_fix_property("poissonsRatio","property/global","peratomtype",max_type,0,style))->get_values();
Y_orig = static_cast<FixPropertyGlobal*>(modify->find_fix_property("youngsModulusOriginal","property/global","peratomtype",max_type,0,style))->get_values();
// allocate a new array within youngsModulusOriginal
static_cast<FixPropertyGlobal*>(modify->find_fix_property("youngsModulusOriginal","property/global","peratomtype",max_type,0,style))->new_array(max_type,max_type);
// feed deltan_ratio into this array
for(int i = 1; i < max_type+1; i++)
{
for(int j = 1; j < max_type+1; j++)
{
Yeff_ij = 1./((1.-pow(nu[i-1],2.))/Y[i-1] +(1.-pow(nu[j-1],2.))/Y[j-1]);
Yeff_orig_ij = 1./((1.-pow(nu[i-1],2.))/Y_orig[i-1]+(1.-pow(nu[j-1],2.))/Y_orig[j-1]);
ratio = pow(Yeff_ij/Yeff_orig_ij,expo);
/*NL*/ //fprintf(screen,"ratio for type pair %d/%d is %f, Yeff_ij %f, Yeff_orig_ij %f, expo %f\n",i,j,ratio,Yeff_ij,Yeff_orig_ij,expo);
static_cast<FixPropertyGlobal*>(modify->find_fix_property("youngsModulusOriginal","property/global","peratomtype",max_type,0,style))->array_modify(i-1,j-1,ratio);
}
}
// get reference to deltan_ratio
deltan_ratio = static_cast<FixPropertyGlobal*>(modify->find_fix_property("youngsModulusOriginal","property/global","peratomtype",max_type,0,style))->get_array_modified();
}
//NP Get pointer to all the fixes (also those that have the material properties)
updatePtrs();
}
/* ---------------------------------------------------------------------- */
void FixHeatGran::post_force(int vflag)
{
//template function for using touchflag or not
if(history_flag == 0) post_force_eval<0>(vflag,0);
if(history_flag == 1) post_force_eval<1>(vflag,0);
}
/* ---------------------------------------------------------------------- */
void FixHeatGran::cpl_evaluate(ComputePairGranLocal *caller)
{
if(caller != cpl) error->all(FLERR,"Illegal situation in FixHeatGran::cpl_evaluate");
if(history_flag == 0) post_force_eval<0>(0,1);
if(history_flag == 1) post_force_eval<1>(0,1);
}
/* ---------------------------------------------------------------------- */
template <int HISTFLAG>
void FixHeatGran::post_force_eval(int vflag,int cpl_flag)
{
double hc,contactArea,delta_n,flux;
int i,j,ii,jj,inum,jnum;
double xtmp,ytmp,ztmp,delx,dely,delz;
double radi,radj,radsum,rsq,r,rinv,rsqinv,tcoi,tcoj;
int *ilist,*jlist,*numneigh,**firstneigh;
int *touch,**firsttouch;
int newton_pair = force->newton_pair;
//NP see implementation of match in atom.cpp, this accounts for hybrid/overlay
if (strcmp(force->pair_style,"hybrid")==0)
error->warning(FLERR,"Fix heat/gran implementation may not be valid for pair style hybrid");
if (strcmp(force->pair_style,"hybrid/overlay")==0)
error->warning(FLERR,"Fix heat/gran implementation may not be valid for pair style hybrid/overlay");
inum = pair_gran->list->inum;
ilist = pair_gran->list->ilist;
numneigh = pair_gran->list->numneigh;
firstneigh = pair_gran->list->firstneigh;
if(HISTFLAG) firsttouch = pair_gran->listgranhistory->firstneigh;
double *radius = atom->radius;
double *rmass = atom->rmass;
double **x = atom->x;
int *type = atom->type;
int nlocal = atom->nlocal;
int *mask = atom->mask;
//NP update because re-allocation might have taken place
updatePtrs();
// 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];
radi = radius[i];
jlist = firstneigh[i];
jnum = numneigh[i];
if(HISTFLAG) touch = firsttouch[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
j &= NEIGHMASK;
if (!(mask[i] & groupbit) && !(mask[j] & groupbit)) continue;
//NP no touch flag available - need to evaluate here
if(!HISTFLAG)
{
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
radj = radius[j];
radsum = radi + radj;
}
//NP touchflag if available or distance if no touchflag available
if (HISTFLAG && touch[jj] || !HISTFLAG && (rsq < radsum*radsum)) { //contact
//NP for history we need to
if(HISTFLAG)
{
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
radj = radius[j];
radsum = radi + radj;
}
r = sqrt(rsq);
//NP adjust overlap that may be superficially large due to softening
if(area_correction_flag)
{
delta_n = radsum - r;
delta_n *= deltan_ratio[type[i]-1][type[j]-1];
r = radsum - delta_n;
}
contactArea = - M_PI/4 * ( (r-radi-radj)*(r+radi-radj)*(r-radi+radj)*(r+radi+radj) )/(r*r); //contact area of the two spheres
tcoi = conductivity[type[i]-1];
tcoj = conductivity[type[j]-1];
if (tcoi < SMALL || tcoj < SMALL) hc = 0.;
else hc = 4.*tcoi*tcoj/(tcoi+tcoj)*sqrt(contactArea);
flux = (Temp[j]-Temp[i])*hc;
if(!cpl_flag)
{
heatFlux[i] += flux;
if (newton_pair || j < nlocal) heatFlux[j] -= flux;
}
if(cpl_flag && cpl) cpl->add_heat(i,j,flux);
}
}
}
//NP reverse comm to send heat fluxes back
//NP only necessary in case of newton_pair=1, since pair stored once on all procs
if(newton_pair) fix_heatFlux->do_reverse_comm();
}
/* ---------------------------------------------------------------------- */
double FixHeatGran::compute_scalar()
{
return fix_ste->compute_scalar();
}
/* ----------------------------------------------------------------------
register and unregister callback to compute
------------------------------------------------------------------------- */
void FixHeatGran::register_compute_pair_local(ComputePairGranLocal *ptr)
{
/*NL*///fprintf(screen,"FixHeatGran::register_compute_pair_local, ptr->id %s\n",ptr->id);
if(cpl != NULL)
error->all(FLERR,"Fix heat/gran allows only one compute of type pair/local");
cpl = ptr;
}
void FixHeatGran::unregister_compute_pair_local(ComputePairGranLocal *ptr)
{
/*NL*///fprintf(screen,"FixHeatGran::unregister_compute_pair_local\n");
if(cpl != ptr)
error->all(FLERR,"Illegal situation in FixHeatGran::unregister_compute_pair_local");
cpl = NULL;
}