Files
LIGGGHTS-PFM/src/fix_massflow_mesh.cpp
dqueteschiner 7278189c0c fix string comparison in argument parsing of massflow/mesh
This line should actually compare the style variable of the fix class to
"massflow/mesh"
2015-08-20 13:38:08 +02:00

618 lines
21 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 "atom.h"
#include "atom_vec.h"
#include "comm.h"
#include "modify.h"
#include "force.h"
#include "memory.h"
#include "update.h"
#include "error.h"
#include "fix_mesh_surface.h"
#include "fix_neighlist_mesh.h"
#include "fix_multisphere.h"
#include "fix_property_atom.h"
#include "mpi_liggghts.h"
#include "math_extra_liggghts.h"
#include "fix_massflow_mesh.h"
#include <algorithm>
using namespace LAMMPS_NS;
using namespace MathExtraLiggghts;
using namespace FixConst;
/* ---------------------------------------------------------------------- */
FixMassflowMesh::FixMassflowMesh(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg),
once_(false),
delete_atoms_(false),
mass_deleted_(0.),
nparticles_deleted_(0),
fix_orientation_(0),
fix_mesh_(0),
fix_counter_(0),
fix_neighlist_(0),
havePointAtOutlet_(false),
insideOut_(false),
mass_(0.),
nparticles_(0),
fix_property_(0),
property_sum_(0.),
screenflag_(false),
fp_(0),
mass_last_(0.),
nparticles_last_(0.),
t_count_(0.),
delta_t_(0.),
reset_t_count_(true),
fix_ms_(0),
ms_(0),
ms_counter_(0)
{
vectorZeroize3D(nvec_);
vectorZeroize3D(pref_);
vectorZeroize3D(sidevec_);
vectorZeroize3D(pointAtOutlet_);
// parse args for this class
int iarg = 3;
bool hasargs = true;
while(iarg < narg && hasargs)
{
hasargs = false;
if(strcmp(arg[iarg],"vec_side") == 0) {
if(narg < iarg+4)
error->fix_error(FLERR,this,"not enough arguments for 'vec_side'");
iarg++;
sidevec_[0] = atof(arg[iarg++]);
sidevec_[1] = atof(arg[iarg++]);
sidevec_[2] = atof(arg[iarg++]);
if(vectorMag3D(sidevec_) == 0.)
error->fix_error(FLERR,this,"vec_side > 0 required");
hasargs = true;
} else if(strcmp(arg[iarg],"mesh") == 0) {
if(narg < iarg+2)
error->fix_error(FLERR,this,"not enough arguments for 'insert_stream'");
iarg++;
fix_mesh_ = static_cast<FixMeshSurface*>(modify->find_fix_id_style(arg[iarg++],"mesh/surface"));
if(!fix_mesh_)
error->fix_error(FLERR,this,"fix mesh ID does not exist");
hasargs = true;
} else if(strcmp(arg[iarg],"sum_property") == 0) {
if(narg < iarg+2)
error->fix_error(FLERR,this,"not enough arguments for 'sum_property'");
iarg++;
fix_property_ = static_cast<FixPropertyAtom*>(modify->find_fix_property(arg[iarg++],"property/atom","scalar",0,0,style));
hasargs = true;
} else if(strcmp(arg[iarg],"count") == 0) {
if(narg < iarg+2)
error->fix_error(FLERR,this,"not enough arguments for 'insert_stream'");
iarg++;
if(strcmp(arg[iarg],"once") == 0)
once_ = true;
else if(strcmp(arg[iarg],"multiple") == 0)
once_ = false;
else
error->fix_error(FLERR,this,"expecting 'once' or 'multiple' after 'count'");
iarg++;
hasargs = true;
} else if(strcmp(arg[iarg],"point_at_outlet") == 0) {
if(narg < iarg+4)
error->fix_error(FLERR,this,"not enough arguments for 'point_at_outlet'");
havePointAtOutlet_ = true;
iarg++;
pointAtOutlet_[0] = atof(arg[iarg++]);
pointAtOutlet_[1] = atof(arg[iarg++]);
pointAtOutlet_[2] = atof(arg[iarg++]);
hasargs = true;
} else if(strcmp(arg[iarg],"inside_out") == 0) {
insideOut_ = true;
iarg++;
if(!havePointAtOutlet_)
error->fix_error(FLERR,this,"the setting 'inside_out' has no meaning in case you do not use 'point_at_outlet'");
hasargs = true;
} else if (strcmp(arg[iarg],"file") == 0 || strcmp(arg[iarg],"append") == 0)
{
if(narg < iarg+2)
error->fix_error(FLERR,this,"Illegal keyword entry");
char* filecurrent = new char[strlen(arg[iarg+1]) + 8];
if (1 < comm->nprocs) //open a separate file for each processor
sprintf(filecurrent,"%s%s%d",arg[iarg+1],".",comm->me);
else //open one file for proc 0
sprintf(filecurrent,"%s",arg[iarg+1]);
if (strcmp(arg[iarg],"file") == 0)
fp_ = fopen(filecurrent,"w");
else
fp_ = fopen(filecurrent,"a");
if (fp_ == NULL) {
char str[128];
sprintf(str,"Cannot open file %s",arg[iarg+1]);
error->fix_error(FLERR,this,str);
}
iarg += 2;
hasargs = true;
} else if (strcmp(arg[iarg],"screen") == 0) {
if(narg < iarg+2)
error->fix_error(FLERR,this,"Illegal keyword entry");
if (strcmp(arg[iarg+1],"yes") == 0) screenflag_ = true;
else if (strcmp(arg[iarg+1],"no") == 0) screenflag_ = false;
else error->all(FLERR,"Illegal fix print command");
iarg += 2;
hasargs = true;
} else if (strcmp(arg[iarg],"delete_atoms") == 0) {
if(narg < iarg+2)
error->fix_error(FLERR,this,"Illegal keyword entry");
if (strcmp(arg[iarg+1],"yes") == 0) delete_atoms_ = true;
else if (strcmp(arg[iarg+1],"no") == 0) delete_atoms_ = false;
else error->all(FLERR,"Illegal delete command");
iarg += 2;
hasargs = true;
} else if(strcmp(style,"massflow/mesh") == 0)
error->fix_error(FLERR,this,"unknown keyword");
}
if(fp_ && 1 < comm->nprocs && 0 == comm->me)
fprintf(screen,"**FixMassflowMesh: > 1 process - "
" will write to multiple files\n");
// error checks on necessary args
if(!once_ && delete_atoms_)
error->fix_error(FLERR,this,"using 'delete_atoms yes' requires 'count once'");
if( !once_ && havePointAtOutlet_)
error->fix_error(FLERR,this,"setting 'point_at_outlet' requires 'count once'");
if( vectorMag3D(sidevec_)==0. && !havePointAtOutlet_)
error->fix_error(FLERR,this,"expecting keyword 'vec_side'");
if (!fix_mesh_)
error->fix_error(FLERR,this,"expecting keyword 'mesh'");
// get reference point on face
// calculate normalvec
fix_mesh_->triMesh()->node(0,0,pref_);
fix_mesh_->triMesh()->surfaceNorm(0,nvec_);
double dot = vectorDot3D(nvec_,sidevec_);
/*NL*/ //printVec3D(screen,"nvec_",nvec_);
/*NL*/ //printVec3D(screen,"sidevec_",sidevec_);
if(fabs(dot) < 1e-6 && !havePointAtOutlet_ )
error->fix_error(FLERR,this,"need to change 'vec_side', it is currently in or to close to the mesh plane");
else if(dot < 0.)
vectorScalarMult3D(nvec_,-1.);
restart_global = 1;
vector_flag = 1;
size_vector = 6;
if(fix_property_)
size_vector = 7;
global_freq = 1; //NP available always
}
/* ---------------------------------------------------------------------- */
FixMassflowMesh::~FixMassflowMesh()
{
if(fp_) fclose(fp_);
}
/* ---------------------------------------------------------------------- */
void FixMassflowMesh::post_create()
{
// add per-particle count flag
const char * fixarg[9];
sprintf(fixid_,"massflow_%s",id);
fixarg[0]=fixid_;
fixarg[1]="all";
fixarg[2]="property/atom";
fixarg[3]=fixid_;
fixarg[4]="scalar"; //NP 1 scalar per particle to be registered
fixarg[5]="yes"; //NP restart yes
fixarg[6]="no"; //NP communicate ghost yes
fixarg[7]="no"; //NP communicate rev no
fixarg[8]="-1."; //NP take 0 as default
modify->add_fix(9,const_cast<char**>(fixarg));
fix_counter_ = static_cast<FixPropertyAtom*>(modify->find_fix_property(fixid_,"property/atom","scalar",0,0,style));
// add neighbor list
fix_neighlist_ = fix_mesh_->createOtherNeighList(igroup,id);
// need to find multisphere here to be able to add property
fix_ms_ = static_cast<FixMultisphere*>(modify->find_fix_style_strict("multisphere",0));
if(fix_ms_)
{
ms_ = &fix_ms_->data();
ms_counter_ = ms_->prop().addElementProperty< ScalarContainer<int> >("counter_ms","comm_exchange_borders","frame_invariant", "restart_yes");
ms_counter_->setDefaultValue(-1);
if(delete_atoms_)
error->fix_error(FLERR,this,"can not use 'delete_atoms' with fix multisphere");
if(!once_)
error->fix_error(FLERR,this,"must use 'count once' with fix multisphere");
}
}
/* ---------------------------------------------------------------------- */
void FixMassflowMesh::pre_delete(bool unfixflag)
{
if (unfixflag) modify->delete_fix(fixid_);
}
/* ----------------------------------------------------------------------
initialize this fix
------------------------------------------------------------------------- */
void FixMassflowMesh::init()
{
if (atom->rmass_flag == 0)
error->fix_error(FLERR,this,"requires atoms have mass");
if(delete_atoms_ && 1 != atom->map_style)
error->fix_error(FLERR,this,"requires an atom map of type 'array', via an 'atom_modify map array' command");
if(!fix_ms_ && static_cast<FixMultisphere*>(modify->find_fix_style_strict("multisphere",0)))
error->fix_error(FLERR,this,"fix multisphere must come before fix massflow/mesh in input script");
}
/* ---------------------------------------------------------------------- */
void FixMassflowMesh::setup(int vflag)
{
// check if face planar
//NP do this here since may only do this after mesh setup
if(!fix_mesh_->triMesh()->isPlanar() && !havePointAtOutlet_)
error->fix_error(FLERR,this,"requires a planar face mass flow measurement or using 'point_at_outlet'");
}
/* ---------------------------------------------------------------------- */
int FixMassflowMesh::setmask()
{
int mask = 0;
mask |= POST_INTEGRATE;
if(delete_atoms_) mask |= PRE_EXCHANGE;
return mask;
}
/* ----------------------------------------------------------------------
evaluate mass which went thru face
all nearby particles
-1 = default value for counter, set if particle is not
a neighbor of the TriMesh
0 = was not on nvec_ last step and is thus eligible
1 = was on nvec_ side last step
2 = do not re-count, was counted already
------------------------------------------------------------------------- */
void FixMassflowMesh::post_integrate()
{
int nlocal = atom->nlocal;
double **x = atom->x;
double **v = atom->v;
double *radius = atom->radius;
double *rmass = atom->rmass;
double *counter = fix_counter_->vector_atom;
double dot,delta[3]={};
double mass_this = 0.;
int nparticles_this = 0.;
double property_this = 0.;
double deltan;
int *tag = atom->tag;
class FixPropertyAtom* fix_color=static_cast<FixPropertyAtom*>(modify->find_fix_property("color","property/atom","scalar",0,0,style,false));
bool fixColFound = false;
if (fix_color) fixColFound=true;
fix_orientation_ = static_cast<FixPropertyAtom*>(modify->find_fix_property("ex",
"property/atom","vector",0,0,style,false));
TriMesh *mesh = fix_mesh_->triMesh();
int nTriAll = mesh->sizeLocal() + mesh->sizeGhost();
// update time for counter
// also store values for last invokation
t_count_ += update->dt;
if(!reset_t_count_)
{
nparticles_last_ = nparticles_;
mass_last_ = mass_;
reset_t_count_ = true;
}
/*NL*///if(fix_property_)
/*NL*/// fprintf(screen,"FOUNDE PROP, id %s style %s\n",fix_property_->id,fix_property_->style);
// loop owned and ghost triangles
// count only if owned particle
for(int iTri = 0; iTri < nTriAll; iTri++)
{
//NP TODO.... maybe some particles are double-counted if they are in the
//NP neighlist multiple times (for different triangles)?? (for case multiple)
const std::vector<int> & neighborList = fix_neighlist_->get_contact_list(iTri);
const int numneigh = neighborList.size();
for(int iNeigh = 0; iNeigh < numneigh; iNeigh++)
{
const int iPart = neighborList[iNeigh];
/*NL*/ //if(523 == atom->tag[iPart]) fprintf(screen,"step " BIGINT_FORMAT ": checking particle tag %d\n",update->ntimestep,atom->tag[iPart]);
// skip ghost particles
if(iPart >= nlocal) continue;
const int ibody = fix_ms_ ? ( (fix_ms_->belongs_to(iPart) > -1) ? (ms_->map(fix_ms_->belongs_to(iPart))) : -1 ) : -1;
// in case of once_ == true, ignore everything which has been already counted
if((ibody > -1) ? ((*ms_counter_)(ibody) == 2) : (compDouble(counter[iPart],2.)) ) continue;
if(havePointAtOutlet_)
{
//get the vector from the particle center
//to the next triangle
deltan = fix_mesh_->triMesh()->resolveTriSphereContact(iPart,iTri,radius[iPart],x[iPart],delta);
if(deltan < radius[iPart])
{
vectorSubtract3D(x[iPart],pointAtOutlet_,nvec_); //vector pointing to the particle location
dot = vectorDot3D(delta,nvec_);
}
else //particle is not overlapping with mesh, so continue
continue;
if(insideOut_) dot =-dot;
}
else
{
vectorSubtract3D(x[iPart],pref_,delta);
dot = vectorDot3D(delta,nvec_);
}
// first-time, just set 0 or 1 depending on what side of the mesh
if((ibody > -1) ? ((*ms_counter_)(ibody) == -1) : (compDouble(counter[iPart],-1.)) )
{
if(ibody > -1)
(*ms_counter_)(ibody) = (dot <= 0.) ? 0. : 1.;
else
counter[iPart] = (dot <= 0.) ? 0. : 1.;
/*NL*/ //if(523 == atom->tag[iPart]) fprintf(screen," 1 counter set to %f\n",counter[iPart]);
continue;
}
// particle is now on nvec_ side
if(dot > 0.)
{
//particle was not on nvec_ side before
if((ibody > -1) ? ((*ms_counter_)(ibody) == 0) : (compDouble(counter[iPart],0.)) ) // compDouble(counter[iPart],0.))
{
//NP each particle holds whole MS mass
mass_this += rmass[iPart];
nparticles_this ++;
if(fix_property_)
{
/*NL*/ //fprintf(screen,"adding %e\n",fix_property_->vector_atom[iPart]);
property_this += fix_property_->vector_atom[iPart];
}
if(delete_atoms_)
{
atom_tags_delete_.push_back(atom->tag[iPart]);
}
if (screenflag_ && screen)
fprintf(screen," %d %4.4g %4.4g %4.4g %4.4g %4.4g %4.4g %4.4g \n ",
tag[iPart],2.*radius[iPart]/force->cg(),
x[iPart][0],x[iPart][1],x[iPart][2],
v[iPart][0],v[iPart][1],v[iPart][2]);
if(fp_)
{
fprintf(fp_," %d %4.4g %4.4g %4.4g %4.4g %4.4g %4.4g %4.4g",
tag[iPart],2.*radius[iPart]/force->cg(),
x[iPart][0],x[iPart][1],x[iPart][2],
v[iPart][0],v[iPart][1],v[iPart][2]);
if (fixColFound)
fprintf(fp_," %4.0g ", fix_color->vector_atom[iPart]);
if(fix_orientation_)
{
double **orientation = NULL;
orientation = fix_orientation_->array_atom;
fprintf(fp_," %4.4g %4.4g %4.4g ",
orientation[iPart][0], orientation[iPart][1], orientation[iPart][2]);
}
fprintf(fp_,"\n");
fflush(fp_);
}
}
if(ibody > -1)
(*ms_counter_)(ibody) = once_ ? 2. : 1.;
else
counter[iPart] = once_ ? 2. : 1.;
/*NL*/ //if(523 == atom->tag[iPart]) fprintf(screen," 2 counter set to %f\n",counter[iPart]);
}
else // dot <= 0
{
if(ibody > -1)
(*ms_counter_)(ibody) = 0;
else
counter[iPart] = 0.;
/*NL*/ //if(523 == atom->tag[iPart]) fprintf(screen," 3 counter set to %f\n",counter[iPart]);
}
}
}
MPI_Sum_Scalar(mass_this,world);
MPI_Sum_Scalar(nparticles_this,world);
if(fix_property_) MPI_Sum_Scalar(property_this,world);
/*NL*/ //fprintf(screen,"property_this %e\n",property_this);
mass_ += mass_this;
nparticles_ += nparticles_this;
property_sum_ += property_this;
}
/* ----------------------------------------------------------------------
perform particle deletion of marked particles
done before exchange, borders, reneighbor
so that ghost atoms and neighbor lists will be correct
------------------------------------------------------------------------- */
void FixMassflowMesh::pre_exchange()
{
if (delete_atoms_)
{
double mass_deleted_this_ = 0.;
int nparticles_deleted_this_ = 0.;
int *atom_map_array = atom->get_map_array();
// delete particles
while (atom_tags_delete_.size() > 0)
{
int iPart = atom->map(atom_tags_delete_[0]);
mass_deleted_this_ += atom->rmass[iPart];
nparticles_deleted_this_++;
atom->avec->copy(atom->nlocal-1,iPart,1);
//NP manipulate atom map array
//NP need to do this since atom map is needed for deletion
atom_map_array[atom->tag[atom->nlocal-1]] = iPart;
atom->nlocal--;
atom_tags_delete_.erase(atom_tags_delete_.begin());
}
atom_tags_delete_.clear();
MPI_Sum_Scalar(mass_deleted_this_,world);
MPI_Sum_Scalar(nparticles_deleted_this_,world);
mass_deleted_ += mass_deleted_this_;
nparticles_deleted_ += nparticles_deleted_this_;
//NP tags and maps
if(nparticles_deleted_this_)
{
if (atom->tag_enable) {
if (atom->map_style) {
atom->nghost = 0;
atom->map_init();
atom->map_set();
}
}
}
}
}
/* ----------------------------------------------------------------------
pack entire state of Fix into one write
------------------------------------------------------------------------- */
void FixMassflowMesh::write_restart(FILE *fp)
{
int n = 0;
double list[6];
list[n++] = mass_;
list[n++] = t_count_;
list[n++] = mass_last_;
list[n++] = static_cast<double>(nparticles_last_);
list[n++] = mass_deleted_;
list[n++] = static_cast<double>(nparticles_deleted_);
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 FixMassflowMesh::restart(char *buf)
{
int n = 0;
double *list = (double *) buf;
mass_ = list[n++];
t_count_ = list[n++];
mass_last_ = list[n++];
nparticles_last_ = static_cast<int>(list[n++]);
mass_deleted_ = list[n++];
nparticles_deleted_ = static_cast<int>(list[n++]);
}
/* ----------------------------------------------------------------------
output mass
------------------------------------------------------------------------- */
double FixMassflowMesh::compute_vector(int index)
{
if(reset_t_count_)
{
delta_t_ = t_count_;
t_count_ = 0.;
reset_t_count_ = false;
}
if(index == 0)
return mass_;
if(index == 1)
return static_cast<double>(nparticles_);
if(index == 2)
return delta_t_ == 0. ? 0. : (mass_-mass_last_)/delta_t_;
if(index == 3)
return delta_t_ == 0. ? 0. : static_cast<double>(nparticles_-nparticles_last_)/delta_t_;
if(index == 4)
return mass_deleted_;
if(index == 5)
return static_cast<double>(nparticles_deleted_);
if(index == 6 && fix_property_)
return property_sum_;
return 0.;
}