// * * * * * * * * * * * * * * * private Member Functions  * * * * * * * * * * * * * //
void Foam::cfdemCloud::getDEMdata()
{
    if(verbose_) Info << "Foam::cfdemCloud::getDEMdata()" << endl;
    dataExchangeM().getData("radius","scalar-atom",radii_);
    dataExchangeM().getData("x","vector-atom",positions_);
    dataExchangeM().getData("v","vector-atom",velocities_);

    if(impDEMdragAcc_)
        dataExchangeM().getData("dragAcc","vector-atom",fAcc_); // array is used twice - might be necessary to clean it first

    if(verbose_) Info << "Foam::cfdemCloud::getDEMdata() - done." << endl;
}
void Foam::cfdemCloud::giveDEMdata()
{
    if(forceM(0).coupleForce())
    {
        dataExchangeM().giveData("dragforce","vector-atom",DEMForces_);

        if(impDEMdrag_)
        {
            dataExchangeM().giveData("Ksl","scalar-atom",Cds_);
            dataExchangeM().giveData("uf","vector-atom",fluidVel_);
        }
    }
    if(verbose_) Info << "giveDEMdata done." << endl;
}
Example #3
0
bool Foam::cfdemCloudIB::evolve()
{
    numberOfParticlesChanged_ = false;
    arraysReallocated_=false;
    bool doCouple=false;

    if (dataExchangeM().couple())
    {
        Info << "\n timeStepFraction() = " << dataExchangeM().timeStepFraction() << endl;
        doCouple=true;

        if(verbose_) Info << "- getDEMdata()" << endl;
        getDEMdata();
        Info << "nr particles = " << numberOfParticles() << endl;

        // search cellID of particles
        if(verbose_) Info << "- findCell()" << endl;
        locateM().findCell(NULL,positions_,cellIDs_,numberOfParticles());
        if(verbose_) Info << "findCell done." << endl;

        // set void fraction field
        if(verbose_) Info << "- setvoidFraction()" << endl;
        voidFractionM().setvoidFraction(NULL,voidfractions_,particleWeights_,particleVolumes_);
        if(verbose_) Info << "setvoidFraction done." << endl;

        // set particles forces
        if(verbose_) Info << "- setForce(forces_)" << endl;
        for(int index = 0;index <  numberOfParticles_; ++index){
            for(int i=0;i<3;i++){
                impForces_[index][i] = 0;
                expForces_[index][i] = 0;
                DEMForces_[index][i] = 0;
            }
        }
        for (int i=0;i<nrForceModels();i++) forceM(i).setForce();
        if(verbose_) Info << "setForce done." << endl;

        // write DEM data
        if(verbose_) Info << " -giveDEMdata()" << endl;
        giveDEMdata();
    }
    Info << "evolve done." << endl;

    //if(verbose_)    #include "debugInfo.H";

    // do particle IO
    IOM().dumpDEMdata();

    return doCouple;
}
Example #4
0
bool Foam::cfdemCloudIB::reAllocArrays() const
{
    if(cfdemCloud::reAllocArrays())
    {
        dataExchangeM().allocateArray(angularVelocities_,0,3);
    }
    return true;
}
//=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
// * * *   write top level fields   * * * //
void Foam::cfdemCloud::giveUSERdata()
{
    if(forceM(0).coupleForce())
    {
        //Handover USER-defined data 
        for(std::vector<word>::iterator it = namesFieldsUserCFDEMToExt.begin(); it != namesFieldsUserCFDEMToExt.end(); ++it) 
        {
            int positionInRegister = std::distance(namesFieldsUserCFDEMToExt.begin(), it);
            dataExchangeM().giveData(namesFieldsUserCFDEMToExt[positionInRegister],"scalar-atom",
                                     particleDatFieldsUserCFDEMToExt[positionInRegister]
                                    );
            Info << "giveData field with name '" << *it << "' at position: " << positionInRegister << endl;
        }
    }
    if(verbose_) Info << "giveUSERdata done." << endl;
}
Example #6
0
void Foam::cfdemCloud::CheckExistanceAndReadDEMData()
{
    int nmr_of_part=IOM().LookForDEMdata(); //IOM().getNumberOfParticles("positions_nh");
    //if these files are not empty
    if(nmr_of_part>0)
    {
        Pout <<"Found "<< nmr_of_part<<" particles."<< endl;

        if(nmr_of_part>numberOfParticles())
        {
            FatalError<< "Amount of memory for "<<nmr_of_part<<" particles from prev. simulation exceeds already allocated memory for "<<numberOfParticles()<<" particle. \nIncrease maxNumberOfParticles in coupllingProperties file." << abort(FatalError);
        }

        reAllocArrays();
        setNumberOfParticles(nmr_of_part);

        Info << "- Starting to upload it."<< endl;
        //fetching data from files into DEM arrays
        IOM().getExistingDEMData("positions_nh","vector-atom",positions_);
        IOM().getExistingDEMData("r_nh","scalar-atom",radii_);
        IOM().getExistingDEMData("m_nh","scalar-atom",mass_);
        IOM().getExistingDEMData("v_nh","vector-atom",velocities_);
        IOM().getExistingDEMData("DEMForces_nh","vector-atom",DEMForces_);


        IOM().getExistingDEMData("tTurbs_nh","scalar-atom",tTurb_);
        IOM().getExistingDEMData("tTurbInts_nh","scalar-atom",tTurbInt_);
        IOM().getExistingDEMData("fluidTurbVels_nh","vector-atom",fluidTurbVel_);


        //pushing data to DEM code
        dataExchangeM().giveDataFromPreviosSimulation(nmr_of_part, positions_, velocities_, radii_, mass_,DEMForces_,tTurb_,tTurbInt_,fluidTurbVel_);
        //Info << "All data is loaded."<< endl<< endl;
    }
    else
    {
        //Info << "************** FILES PRESENT BUT EMPTY. ************************************"<< endl<< endl;
    }
}
bool Foam::cfdemCloud::reAllocArrays() const
{
    if(numberOfParticlesChanged_ && !arraysReallocated_)
    {
        // get arrays of new length
        dataExchangeM().allocateArray(positions_,0.,3);
        dataExchangeM().allocateArray(velocities_,0.,3);
        dataExchangeM().allocateArray(fluidVel_,0.,3);
        dataExchangeM().allocateArray(impForces_,0.,3);
        dataExchangeM().allocateArray(expForces_,0.,3);
        dataExchangeM().allocateArray(DEMForces_,0.,3);
        dataExchangeM().allocateArray(Cds_,0.,1);
        dataExchangeM().allocateArray(radii_,0.,1);
        dataExchangeM().allocateArray(voidfractions_,1.,voidFractionM().maxCellsPerParticle());
        dataExchangeM().allocateArray(cellIDs_,0.,voidFractionM().maxCellsPerParticle());
        dataExchangeM().allocateArray(particleWeights_,0.,voidFractionM().maxCellsPerParticle());
        dataExchangeM().allocateArray(particleVolumes_,0.,voidFractionM().maxCellsPerParticle());
        arraysReallocated_ = true;
        return true;
    }
    return false;
}
// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
Foam::cfdemCloud::cfdemCloud
(
    const fvMesh& mesh
)
:
    mesh_(mesh),
    couplingProperties_
    (
        IOobject
        (
            "couplingProperties",
            mesh_.time().constant(),
            mesh_,
            IOobject::MUST_READ,
            IOobject::NO_WRITE
        )
    ),
    liggghtsCommandDict_
    (
        IOobject
        (
            "liggghtsCommands",
            mesh_.time().constant(),
            mesh_,
            IOobject::MUST_READ,
            IOobject::NO_WRITE
        )
    ),
    verbose_(false),
    ignore_(false),
    modelType_(couplingProperties_.lookup("modelType")),
    positions_(NULL),
    velocities_(NULL),
    fluidVel_(NULL),
    impForces_(NULL),
    expForces_(NULL),
    DEMForces_(NULL),
    Cds_(NULL),
    radii_(NULL),
    voidfractions_(NULL),
    cellIDs_(NULL),
    particleWeights_(NULL),
    particleVolumes_(NULL),
    numberOfParticles_(0),
    numberOfParticlesChanged_(false),
    arraysReallocated_(false),
    forceModels_(couplingProperties_.lookup("forceModels")),
    momCoupleModels_(couplingProperties_.lookup("momCoupleModels")),
    liggghtsCommandModelList_(liggghtsCommandDict_.lookup("liggghtsCommandModels")),
    turbulenceModelType_(couplingProperties_.lookup("turbulenceModelType")),
    cgOK_(true),
    impDEMdrag_(false),
    useDDTvoidfraction_(false),
    ddtVoidfraction_
    (   
        IOobject
        (
            "ddtVoidfraction",
            mesh.time().timeName(),
            mesh,
            IOobject::NO_READ,
            IOobject::AUTO_WRITE
        ),
        mesh,
        dimensionedScalar("zero", dimensionSet(0,0,-1,0,0), 0)  // 1/s
    ),
    turbulence_
    (
        #if defined(version21) || defined(version16ext)
            #ifdef comp
                mesh.lookupObject<compressible::turbulenceModel>
            #else
                mesh.lookupObject<incompressible::turbulenceModel>
            #endif
        #elif defined(version15)
            mesh.lookupObject<incompressible::RASModel>
        #endif
        (
            turbulenceModelType_
        )
    ),
    locateModel_
    (
        locateModel::New
        (
            couplingProperties_,
            *this
        )
    ),
    /*momCoupleModel_
    (
        momCoupleModel::New
        (
            couplingProperties_,
            *this
        )
    ),*/
    dataExchangeModel_
    (
        dataExchangeModel::New
        (
            couplingProperties_,
            *this
        )
    ),
    IOModel_
    (
        IOModel::New
        (
            couplingProperties_,
            *this
        )
    ),
    probeModel_
    (
        probeModel::New
        (
            couplingProperties_,
            *this,
            "none",
            "none"
        )
    ),
    voidFractionModel_
    (
        voidFractionModel::New
        (
            couplingProperties_,
            *this
        )
    ),
    averagingModel_
    (
        averagingModel::New
        (
            couplingProperties_,
            *this
        )
    ),
    clockModel_
    (
        clockModel::New
        (
            couplingProperties_,
            *this
        )
    ),
    smoothingModel_
    (
        smoothingModel::New
        (
            couplingProperties_,
            *this
        )
    ),
    meshMotionModel_
    (
        meshMotionModel::New
        (
            couplingProperties_,
            *this
        )
    )
{
    #include "versionInfo.H"

    Info << "If BC are important, please provide volScalarFields -imp/expParticleForces-" << endl;

    if (couplingProperties_.found("verbose")) verbose_=true;
    if (couplingProperties_.found("ignore")) ignore_=true;
    if (turbulenceModelType_=="LESProperties")
        Info << "WARNING - LES functionality not yet tested!" << endl;

    if (couplingProperties_.found("useDDTvoidfraction"))
        useDDTvoidfraction_=true;
    else        
        Info << "ignoring ddt(voidfraction)" << endl;

    forceModel_ = new autoPtr<forceModel>[nrForceModels()];
    for (int i=0;i<nrForceModels();i++)
    {
        forceModel_[i] = forceModel::New
        (
            couplingProperties_,
            *this,
            forceModels_[i]
        );
    }

    momCoupleModel_ = new autoPtr<momCoupleModel>[momCoupleModels_.size()];
    for (int i=0;i<momCoupleModels_.size();i++)
    {
        momCoupleModel_[i] = momCoupleModel::New
        (
            couplingProperties_,
            *this,
            momCoupleModels_[i]
        );
    }

    // run liggghts commands from cfdem
    liggghtsCommand_ = new autoPtr<liggghtsCommandModel>[liggghtsCommandModelList_.size()];
    for (int i=0;i<liggghtsCommandModelList_.size();i++)
    {
        liggghtsCommand_[i] = liggghtsCommandModel::New
        (
            liggghtsCommandDict_,
            *this,
            liggghtsCommandModelList_[i],
            i
        );
    }

    dataExchangeM().setCG();
    if (!cgOK_ && forceM(0).cg() > 1) FatalError<< "at least one of your models is not fit for cg !!!"<< abort(FatalError); 
}
bool Foam::cfdemCloud::evolve
(
    volScalarField& alpha,
    volVectorField& Us,
    volVectorField& U
)
{
    numberOfParticlesChanged_ = false;
    arraysReallocated_=false;
    bool doCouple=false;

    if(!ignore())
    {
        if (dataExchangeM().couple())
        {
            Info << "\n Coupling..." << endl;
            doCouple=true;

            // reset vol Fields
            clockM().start(16,"resetVolFields");
            if(verbose_)
            {
                Info << "couplingStep:" << dataExchangeM().couplingStep() 
                     << "\n- resetVolFields()" << endl;
            }
            averagingM().resetVectorAverage(averagingM().UsPrev(),averagingM().UsNext());
            voidFractionM().resetVoidFractions();
            averagingM().resetVectorAverage(forceM(0).impParticleForces(),forceM(0).impParticleForces(),true);
            averagingM().resetVectorAverage(forceM(0).expParticleForces(),forceM(0).expParticleForces(),true);
            averagingM().resetWeightFields();
            for (int i=0;i<momCoupleModels_.size(); i++)
                momCoupleM(i).resetMomSourceField();
            if(verbose_) Info << "resetVolFields done." << endl;
            clockM().stop("resetVolFields");

            if(verbose_) Info << "- getDEMdata()" << endl;
            clockM().start(17,"getDEMdata");
            getDEMdata();
            clockM().stop("getDEMdata");
            if(verbose_) Info << "- getDEMdata done." << endl;

            // search cellID of particles
            clockM().start(18,"findCell");
            if(verbose_) Info << "- findCell()" << endl;
            findCells();
            if(verbose_) Info << "findCell done." << endl;
            clockM().stop("findCell");

            // set void fraction field
            clockM().start(19,"setvoidFraction");
            if(verbose_) Info << "- setvoidFraction()" << endl;
            voidFractionM().setvoidFraction(NULL,voidfractions_,particleWeights_,particleVolumes_);
            if(verbose_) Info << "setvoidFraction done." << endl;
            clockM().stop("setvoidFraction");

            // set particles velocity field
            clockM().start(20,"setVectorAverage");
            setVectorAverages();
            clockM().stop("setVectorAverage");

            // set particles forces
            clockM().start(21,"setForce");
            if(verbose_) Info << "- setForce(forces_)" << endl;
            setForces();
            if(verbose_) Info << "setForce done." << endl;
            clockM().stop("setForce");

            // get next force field
            clockM().start(22,"setParticleForceField");
            if(verbose_) Info << "- setParticleForceField()" << endl;
            averagingM().setVectorSum
            (
                forceM(0).impParticleForces(),
                impForces_,
                particleWeights_,
                NULL //mask
            );
            averagingM().setVectorSum
            (
                forceM(0).expParticleForces(),
                expForces_,
                particleWeights_,
                NULL //mask
            );
            if(verbose_) Info << "- setParticleForceField done." << endl;
            clockM().stop("setParticleForceField");

            // write DEM data
            if(verbose_) Info << " -giveDEMdata()" << endl;
            clockM().start(23,"giveDEMdata");
            giveDEMdata();
            clockM().stop("giveDEMdata");
        }//end dataExchangeM().couple()
        Info << "\n timeStepFraction() = " << dataExchangeM().timeStepFraction() << endl;

        clockM().start(24,"interpolateEulerFields");
        // update smoothing model
        smoothingM().dSmoothing();

        //============================================
        // update voidFractionField V1
        alpha = voidFractionM().voidFractionInterp();
        smoothingM().smoothen(alpha);
        if(dataExchangeM().couplingStep() < 2)
        {
            alpha.oldTime() = alpha; // supress volume src
            alpha.oldTime().correctBoundaryConditions();
        }
        alpha.correctBoundaryConditions();

        // calc ddt(voidfraction)
        //calcDdtVoidfraction(voidFractionM().voidFractionNext());
        calcDdtVoidfraction(alpha);

        // update particle velocity Field
        Us = averagingM().UsInterp();
        //smoothingM().smoothenReferenceField(Us);
        Us.correctBoundaryConditions();
        /*//============================================
        // update voidFractionField
        volScalarField oldAlpha = alpha.oldTime(); //save old (smooth) alpha field
        alpha.oldTime().internalField() = voidFractionM().voidFractionInterp();
        smoothingM().smoothen(alpha);
        alpha.correctBoundaryConditions();
        alpha.oldTime() = oldAlpha; //set old (smooth) alpha field to allow correct computation of ddt

        // calc ddt(voidfraction)
        if (doCouple) calcDdtVoidfraction(alpha);
        //calcDdtVoidfraction(alpha); // alternative with scale=1! (does not see change in alpha?)

        // update particle velocity Field
        Us.oldTime().internalField() = averagingM().UsInterp();
        smoothingM().smoothenReferenceField(Us);
        Us.correctBoundaryConditions();
        //============================================*/
        clockM().stop("interpolateEulerFields");

        if(verbose_){
            #include "debugInfo.H"
        }

        clockM().start(25,"dumpDEMdata");
        // do particle IO
        IOM().dumpDEMdata();
        clockM().stop("dumpDEMdata");

    }//end ignore
    return doCouple;
}
// * * * * * * * * * * * * * * * private Member Functions  * * * * * * * * * * * * * //
void Foam::cfdemCloud::getDEMdata()
{
    dataExchangeM().getData("radius","scalar-atom",radii_);
    dataExchangeM().getData("x","vector-atom",positions_);
    dataExchangeM().getData("v","vector-atom",velocities_);
}
// * * * * * * * * * * * * * * * * Destructors  * * * * * * * * * * * * * * //
Foam::cfdemCloud::~cfdemCloud()
{
    clockM().evalPar();
    clockM().normHist();
    dataExchangeM().destroy(positions_,3);
    dataExchangeM().destroy(velocities_,3);
    dataExchangeM().destroy(fluidVel_,3);
    dataExchangeM().destroy(impForces_,3);
    dataExchangeM().destroy(expForces_,3);
    dataExchangeM().destroy(DEMForces_,3);
    dataExchangeM().destroy(Cds_,1);
    dataExchangeM().destroy(radii_,1);
    dataExchangeM().destroy(voidfractions_,1);
    dataExchangeM().destroy(cellIDs_,1);
    dataExchangeM().destroy(particleWeights_,1);
    dataExchangeM().destroy(particleVolumes_,1);
}
bool Foam::cfdemCloud::reAllocArrays(int nP, bool forceRealloc) const
{
    if( (numberOfParticlesChanged_ && !arraysReallocated_) || forceRealloc)
    {
        // get arrays of new length
        dataExchangeM().allocateArray(positions_,0.,3,nP);
        dataExchangeM().allocateArray(velocities_,0.,3,nP);
        dataExchangeM().allocateArray(fluidVel_,0.,3,nP);
        dataExchangeM().allocateArray(impForces_,0.,3,nP);
        dataExchangeM().allocateArray(expForces_,0.,3,nP);
        dataExchangeM().allocateArray(DEMForces_,0.,3,nP);
        dataExchangeM().allocateArray(Cds_,0.,1,nP);
        dataExchangeM().allocateArray(radii_,0.,1,nP);
        dataExchangeM().allocateArray(voidfractions_,1.,voidFractionM().maxCellsPerParticle(),nP);
        dataExchangeM().allocateArray(cellIDs_,0.,voidFractionM().maxCellsPerParticle(),nP);
        dataExchangeM().allocateArray(particleWeights_,0.,voidFractionM().maxCellsPerParticle(),nP);
        dataExchangeM().allocateArray(particleVolumes_,0.,voidFractionM().maxCellsPerParticle(),nP);

        //=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
        if(namesFieldsUserCFDEMToExt.size()!=particleDatFieldsUserCFDEMToExt.size())
            allocateParticleDatFieldsUserCFDEMToExt();
        else
            reAllocateParticleDatFieldsUserCFDEMToExt();
        //=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
        arraysReallocated_ = true;
        return true;
    }
    return false;
}
bool Foam::cfdemCloud::evolve
(
    volScalarField& alpha,
    volVectorField& Us,
    volVectorField& U
)
{
    numberOfParticlesChanged_ = false;
    arraysReallocated_=false;
    bool doCouple=false;

    if(!ignore())
    {
        if (dataExchangeM().doCoupleNow())
        {
            Info << "\n Coupling..." << endl;
            dataExchangeM().couple(0);
            doCouple=true;

            // reset vol Fields
            clockM().start(16,"resetVolFields");
            if(verbose_)
            {
                Info << "couplingStep:" << dataExchangeM().couplingStep() 
                     << "\n- resetVolFields()" << endl;
            }
            averagingM().resetVectorAverage(averagingM().UsPrev(),averagingM().UsNext(),false);
            resetVoidFraction();
            averagingM().resetVectorAverage(forceM(0).impParticleForces(),forceM(0).impParticleForces(),true);
            averagingM().resetVectorAverage(forceM(0).expParticleForces(),forceM(0).expParticleForces(),true);
            averagingM().resetWeightFields();
            for (int i=0;i<momCoupleModels_.size(); i++)
                momCoupleM(i).resetMomSourceField();
            if(verbose_) Info << "resetVolFields done." << endl;
            clockM().stop("resetVolFields");

            if(verbose_) Info << "- getDEMdata()" << endl;
            clockM().start(17,"getDEMdata");
            getDEMdata();
            clockM().stop("getDEMdata");
            if(verbose_) Info << "- getDEMdata done." << endl;

            // search cellID of particles
            clockM().start(18,"findCell");
            if(verbose_) Info << "- findCell()" << endl;
            findCells();
            if(verbose_) Info << "findCell done." << endl;
            clockM().stop("findCell");

            // set void fraction field
            clockM().start(19,"setvoidFraction");
            if(verbose_) Info << "- setvoidFraction()" << endl;
            setVoidFraction();
            if(verbose_) Info << "setvoidFraction done." << endl;
            clockM().stop("setvoidFraction");

            // set average particles velocity field
            clockM().start(20,"setVectorAverage");
            setVectorAverages();


            //Smoothen "next" fields            
            smoothingM().dSmoothing();
            smoothingM().smoothen(voidFractionM().voidFractionNext());

            //only smoothen if we use implicit force coupling in cells void of particles
            //because we need unsmoothened Us field to detect cells for explicit 
            //force coupling
            if(!treatVoidCellsAsExplicitForce())
                smoothingM().smoothenReferenceField(averagingM().UsNext());
            
            clockM().stop("setVectorAverage");
        }
        
        //============================================
        //CHECK JUST TIME-INTERPOATE ALREADY SMOOTHENED VOIDFRACTIONNEXT AND UsNEXT FIELD 
        //      IMPLICIT FORCE CONTRIBUTION AND SOLVER USE EXACTLY THE SAME AVERAGED
        //      QUANTITIES AT THE GRID!
        Info << "\n timeStepFraction() = " << dataExchangeM().timeStepFraction() << endl;
        clockM().start(24,"interpolateEulerFields");

        // update voidFractionField
        setAlpha(alpha);
        if(dataExchangeM().couplingStep() < 2)
        {
            alpha.oldTime() = alpha; // supress volume src
            alpha.oldTime().correctBoundaryConditions();
        }
        alpha.correctBoundaryConditions();

        // calc ddt(voidfraction)
        calcDdtVoidfraction(alpha,Us);

        // update mean particle velocity Field
        Us = averagingM().UsInterp();
        Us.correctBoundaryConditions();

        clockM().stop("interpolateEulerFields");
        //============================================

        if(doCouple)
        {
            // set particles forces
            clockM().start(21,"setForce");
            if(verbose_) Info << "- setForce(forces_)" << endl;
            setForces();
            if(verbose_) Info << "setForce done." << endl;
            calcMultiphaseTurbulence();
            if(verbose_) Info << "calcMultiphaseTurbulence done." << endl;
            clockM().stop("setForce");

            // get next force field
            clockM().start(22,"setParticleForceField");
            if(verbose_) Info << "- setParticleForceField()" << endl;
            setParticleForceField();
            if(verbose_) Info << "- setParticleForceField done." << endl;
            clockM().stop("setParticleForceField");

            // write DEM data
            if(verbose_) Info << " -giveDEMdata()" << endl;
            clockM().start(23,"giveDEMdata");
            giveDEMdata();
            clockM().stop("giveDEMdata");

            dataExchangeM().couple(1);
        }//end dataExchangeM().couple()


        if(verbose_){
            #include "debugInfo.H"
        }

        clockM().start(25,"dumpDEMdata");
        // do particle IO
        IOM().dumpDEMdata();
        clockM().stop("dumpDEMdata");

    }//end ignore
    return doCouple;
}
// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
Foam::cfdemCloud::cfdemCloud
(
    const fvMesh& mesh
)
:
    mesh_(mesh),
    couplingProperties_
    (
        IOobject
        (
            "couplingProperties",
            mesh_.time().constant(),
            mesh_,
            IOobject::MUST_READ,
            IOobject::NO_WRITE
        )
    ),
    liggghtsCommandDict_
    (
        IOobject
        (
            "liggghtsCommands",
            mesh_.time().constant(),
            mesh_,
            IOobject::MUST_READ,
            IOobject::NO_WRITE
        )
    ),
    solveFlow_(true),
    solveScalarTransport_(true),
    verbose_(false),
    debug_(false),
    allowCFDsubTimestep_(true),
    ignore_(false),
    modelType_(couplingProperties_.lookup("modelType")),
    positions_(NULL),
    velocities_(NULL),
    fluidVel_(NULL),
    fAcc_(NULL),
    impForces_(NULL),
    expForces_(NULL),
    DEMForces_(NULL),
    Cds_(NULL),
    radii_(NULL),
    voidfractions_(NULL),
    cellIDs_(NULL),
    particleWeights_(NULL),
    particleVolumes_(NULL),
    particleV_(NULL),
    dragPrev_(NULL),
    numberOfParticles_(0),
    d32_(-1),
    numberOfParticlesChanged_(false),
    arraysReallocated_(false),
    forceModels_(couplingProperties_.lookup("forceModels")),
    momCoupleModels_(couplingProperties_.lookup("momCoupleModels")),
    liggghtsCommandModelList_(liggghtsCommandDict_.lookup("liggghtsCommandModels")),
    turbulenceModelType_(couplingProperties_.lookup("turbulenceModelType")),
    isLES_(false),
    cg_(1.),
    cgOK_(true),
    impDEMdrag_(false),
    impDEMdragAcc_(false),
    imExSplitFactor_(1.0),
    treatVoidCellsAsExplicitForce_(false),
    useDDTvoidfraction_("off"),
    ddtVoidfraction_
    (   
        IOobject
        (
            "ddtVoidfraction",
            mesh.time().timeName(),
            mesh,
            IOobject::NO_READ,
            IOobject::AUTO_WRITE
        ),
        mesh,
        dimensionedScalar("zero", dimensionSet(0,0,-1,0,0), 0)  // 1/s
    ),
    checkPeriodicCells_(false),
    turbulence_
    (
        #if defined(version24Dev)
            mesh.lookupObject<turbulenceModel>
        #elif defined(version21) || defined(version16ext)
            #ifdef compre
                mesh.lookupObject<compressible::turbulenceModel>
            #else
                mesh.lookupObject<incompressible::turbulenceModel>
            #endif
        #elif defined(version15)
            mesh.lookupObject<incompressible::RASModel>
        #endif
        (
            turbulenceModelType_
        )
    ),
    turbulenceMultiphase_
    (   
        IOobject
        (
            "turbulenceMultiphase",
            mesh.time().timeName(),
            mesh,
            IOobject::NO_READ,
            IOobject::AUTO_WRITE
        ),
        mesh,
#ifdef compre
        dimensionedScalar("zero", dimensionSet(1,-1,-1,0,0), 0)  // kg/m/s
#else
        dimensionedScalar("zero", dimensionSet(0,2,-1,0,0), 0)  // m²/s
#endif
    ),    
    locateModel_
    (
        locateModel::New
        (
            couplingProperties_,
            *this
        )
    ),
    /*momCoupleModel_
    (
        momCoupleModel::New
        (
            couplingProperties_,
            *this
        )
    ),*/
    dataExchangeModel_
    (
        dataExchangeModel::New
        (
            couplingProperties_,
            *this
        )
    ),
    IOModel_
    (
        IOModel::New
        (
            couplingProperties_,
            *this
        )
    ),
    probeModel_
    (
        probeModel::New
        (
            couplingProperties_,
            *this,
            (char *)"none",
            (char *)"none"
        )
    ),
    voidFractionModel_
    (
        voidFractionModel::New
        (
            couplingProperties_,
            *this
        )
    ),
    averagingModel_
    (
        averagingModel::New
        (
            couplingProperties_,
            *this
        )
    ),
    clockModel_
    (
        clockModel::New
        (
            couplingProperties_,
            *this
        )
    ),
    smoothingModel_
    (
        smoothingModel::New
        (
            couplingProperties_,
            *this
        )
    ),
    meshMotionModel_
    (
        meshMotionModel::New
        (
            couplingProperties_,
            *this
        )
    )
{
    #include "versionInfo.H"
    global buildInfo(couplingProperties_,*this);
    buildInfo.info();

    //-- apply debug Mode to sub models

    // set debug flag according to env
    debug_ = buildInfo.debugMode();

    // overwrite debug flag if found in dict
    if (couplingProperties_.found("debug"))
        debug_=Switch(couplingProperties_.lookup("debug"));

    // apply flag
    if(!debugMode()) ddtVoidfraction_.writeOpt() = IOobject::NO_WRITE;
    if(!debugMode()) turbulenceMultiphase_.writeOpt() = IOobject::NO_WRITE;
    voidFractionM().applyDebugSettings(debugMode());
    averagingM().applyDebugSettings(debugMode());
    //--

    dataExchangeM().setCG();

    Info << "If BC are important, please provide volScalarFields -imp/expParticleForces-" << endl;
    if (couplingProperties_.found("solveFlow"))
        solveFlow_=Switch(couplingProperties_.lookup("solveFlow"));
    if (couplingProperties_.found("solveScalarTransport"))
        solveScalarTransport_=Switch(couplingProperties_.lookup("solveScalarTransport"));
    if (couplingProperties_.found("imExSplitFactor"))
        imExSplitFactor_ = readScalar(couplingProperties_.lookup("imExSplitFactor"));

    if(imExSplitFactor_>1.0)
            FatalError  << "You have set imExSplitFactor > 1 in your couplingProperties. Must be <=1."
                       << abort(FatalError);
    if(imExSplitFactor_<0.0)
            FatalError  << "You have set imExSplitFactor < 0 in your couplingProperties. Must be >=0"
                       << abort(FatalError);

    if (couplingProperties_.found("treatVoidCellsAsExplicitForce"))
        treatVoidCellsAsExplicitForce_ = readBool(couplingProperties_.lookup("treatVoidCellsAsExplicitForce"));
    if (couplingProperties_.found("verbose")) verbose_=true;
    if (couplingProperties_.found("ignore")) ignore_=true;
    if (turbulenceModelType_=="LESProperties")
    {
        isLES_ = true;
        Info << "WARNING - LES functionality not yet tested!" << endl;
    }

    if (couplingProperties_.found("useDDTvoidfraction"))
    {
        useDDTvoidfraction_=word(couplingProperties_.lookup("useDDTvoidfraction"));

        if(useDDTvoidfraction_==word("a") || 
           useDDTvoidfraction_==word("b") ||
           useDDTvoidfraction_==word("off")
          )
            Info << "choice for ddt(voidfraction) = " << useDDTvoidfraction_ << endl;
        else
            FatalError << "Model " << useDDTvoidfraction_ 
                       << " is not a valid choice for ddt(voidfraction). Choose a or b or off."
                       << abort(FatalError);
    }
    else        
        Info << "ignoring ddt(voidfraction)" << endl;

    forceModel_ = new autoPtr<forceModel>[nrForceModels()];
    for (int i=0;i<nrForceModels();i++)
    {
        forceModel_[i] = forceModel::New
        (
            couplingProperties_,
            *this,
            forceModels_[i]
        );
        forceModel_[i]().applyDebugSettings(debugMode());
    }

    momCoupleModel_ = new autoPtr<momCoupleModel>[momCoupleModels_.size()];
    for (int i=0;i<momCoupleModels_.size();i++)
    {
        momCoupleModel_[i] = momCoupleModel::New
        (
            couplingProperties_,
            *this,
            momCoupleModels_[i]
        );
        momCoupleModel_[i]().applyDebugSettings(debugMode());
    }

    // run liggghts commands from cfdem
    liggghtsCommand_ = new autoPtr<liggghtsCommandModel>[liggghtsCommandModelList_.size()];
    for (int i=0;i<liggghtsCommandModelList_.size();i++)
    {
        liggghtsCommand_[i] = liggghtsCommandModel::New
        (
            liggghtsCommandDict_,
            *this,
            liggghtsCommandModelList_[i],
            i
        );
    }

    Switch cgWarnOnly_(couplingProperties_.lookupOrDefault<Switch>("cgWarnOnly", true));
    if (!cgOK_ && cg_ > 1)
    {
        if(cgWarnOnly_)
            Warning<< "at least one of your models is not fit for cg !!!"<< endl; 
        else
            FatalError<< "at least one of your models is not fit for cg !!!"<< abort(FatalError); 
    }

    // check if sim is fully peridic box
    const polyBoundaryMesh& patches = mesh_.boundaryMesh();
    int nPatchesCyclic(0);
    int nPatchesNonCyclic(0);
    forAll(patches, patchI)
    {
        const polyPatch& pp = patches[patchI];
        #if defined(versionExt32)
        if (isA<cyclicPolyPatch>(pp))
            nPatchesCyclic++;
        else if (!isA<processorPolyPatch>(pp))
            nPatchesNonCyclic++;
        #else
        if (isA<cyclicPolyPatch>(pp) || isA<cyclicAMIPolyPatch>(pp))
            nPatchesCyclic++;
        else if (!isA<processorPolyPatch>(pp))
            nPatchesNonCyclic++;
        #endif
    }
    if(nPatchesNonCyclic==0)
        checkPeriodicCells_=true;
    if(nPatchesCyclic>0 && nPatchesNonCyclic>0)
    {
        if(verbose_) Info << "nPatchesNonCyclic=" << nPatchesNonCyclic << ", nPatchesCyclic=" << nPatchesCyclic << endl;
        Warning << "Periodic handing is disabled because the domain is not fully periodic!\n" << endl;
    }
}
// * * * * * * * * * * * * * * * * Destructors  * * * * * * * * * * * * * * //
Foam::cfdemCloud::~cfdemCloud()
{
    clockM().evalPar();
    clockM().normHist();
    dataExchangeM().destroy(positions_,3);
    dataExchangeM().destroy(velocities_,3);
    dataExchangeM().destroy(fluidVel_,3);
    dataExchangeM().destroy(fAcc_,3);
    dataExchangeM().destroy(impForces_,3);
    dataExchangeM().destroy(expForces_,3);
    dataExchangeM().destroy(DEMForces_,3);
    dataExchangeM().destroy(Cds_,1);
    dataExchangeM().destroy(radii_,1);
    dataExchangeM().destroy(voidfractions_,1);
    dataExchangeM().destroy(cellIDs_,1);
    dataExchangeM().destroy(particleWeights_,1);
    dataExchangeM().destroy(particleVolumes_,1);
    dataExchangeM().destroy(particleV_,1);

    //=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
    int iUser=0;
    for( std::vector<double**>::iterator 
         it  = particleDatFieldsUserCFDEMToExt.begin(); 
         it != particleDatFieldsUserCFDEMToExt.end(); 
       ++it)
    {
        Info << "cfdemCloud destroys UserCFDEM data: " << namesFieldsUserCFDEMToExt[iUser++] << endl;
        dataExchangeM().destroy((*it),1);
    }
    //=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
}