From 027a03fbcb382011c3ff194ff7d3fa45972d2f48 Mon Sep 17 00:00:00 2001 From: "Christoph Goniva, DCS Computing GmbH" Date: Wed, 25 Feb 2015 18:52:32 +0100 Subject: [PATCH] release on 2015-02-25_18-52-32 --- README | 26 +- applications/.gitignore | 7 + .../solvers/cfdemSolverIB/Make/options | 8 +- .../solvers/cfdemSolverIB/cfdemSolverIB.C | 6 +- .../solvers/cfdemSolverPiso/Make/options | 6 +- .../solvers/cfdemSolverPiso/cfdemSolverPiso.C | 52 ++- .../cfdemSolverPisoScalar/Make/options | 6 +- .../cfdemSolverPisoScalar.C | 211 +++++------ .../utilities/cfdemPostproc/Make/options | 4 + .../utilities/cfdemPostproc/cfdemPostproc.C | 5 +- .../utilities/cfdemPostproc/createFields.H | 4 +- doc/.gitignore | 7 + doc/CFDEMcoupling_Manual.html | 10 +- doc/CFDEMcoupling_Manual.pdf | Bin 506666 -> 514316 bytes doc/CFDEMcoupling_Manual.txt | 10 +- doc/cfdemSolverPisoScalar.html | 4 +- doc/cfdemSolverPisoScalar.txt | 5 +- doc/clockModel_standardClock.html | 2 +- doc/clockModel_standardClock.txt | 2 +- doc/forceModel.html | 2 +- doc/forceModel.txt | 2 +- doc/forceModel_Archimedes.html | 6 +- doc/forceModel_Archimedes.txt | 5 +- doc/forceModel_ArchimedesIB.html | 6 +- doc/forceModel_ArchimedesIB.txt | 5 +- doc/forceModel_DiFeliceDrag.html | 10 +- doc/forceModel_DiFeliceDrag.txt | 9 +- doc/forceModel_GidaspowDrag.html | 16 +- doc/forceModel_GidaspowDrag.txt | 14 +- doc/forceModel_KochHillDrag.html | 12 +- doc/forceModel_KochHillDrag.txt | 11 +- doc/forceModel_LaEuScalarTemp.html | 18 +- doc/forceModel_LaEuScalarTemp.txt | 16 +- doc/forceModel_MeiLift.html | 16 +- doc/forceModel_MeiLift.txt | 15 +- doc/forceModel_SchillerNaumannDrag.html | 4 - doc/forceModel_SchillerNaumannDrag.txt | 3 - doc/forceModel_ShirgaonkarIB.html | 4 - doc/forceModel_ShirgaonkarIB.txt | 3 - doc/forceModel_fieldStore.html | 68 ++++ doc/forceModel_fieldStore.txt | 63 ++++ doc/forceModel_gradPForce.html | 10 +- doc/forceModel_gradPForce.txt | 9 +- doc/forceModel_virtualMassForce.html | 4 - doc/forceModel_virtualMassForce.txt | 3 - doc/forceModel_viscForce.html | 8 +- doc/forceModel_viscForce.txt | 7 +- doc/forceSubModel.html | 49 +++ doc/forceSubModel.txt | 45 +++ doc/forceSubModel_ImEx.html | 45 +++ doc/forceSubModel_ImEx.txt | 42 +++ doc/forceSubModel_ImExCorr.html | 46 +++ doc/forceSubModel_ImExCorr.txt | 43 +++ doc/githubAccess_public.pdf | Bin 362748 -> 362748 bytes doc/liggghtsCommandModel_writeLiggghts.html | 10 +- doc/liggghtsCommandModel_writeLiggghts.txt | 10 +- doc/momCoupleModel.html | 3 +- doc/momCoupleModel.txt | 1 + src/.gitignore | 7 + .../cfdemParticle/cfdTools/checkModelType.H | 38 +- .../cfdTools/compressibleContinuityErrsPU.H | 53 +++ .../cfdemParticle/cfdTools/global.C | 80 +++++ .../cfdemParticle/cfdTools/global.H | 128 +++++++ .../cfdemParticle/cfdTools/mathExtra.H | 265 ++++++++++++++ .../cfdemParticle/cfdTools/newGlobal.C | 84 +++++ .../cfdemParticle/cfdTools/versionInfo.H | 47 ++- .../cfdemParticle/cfdemCloud/cfdemCloud.C | 77 +++- .../cfdemParticle/cfdemCloud/cfdemCloud.H | 41 ++- .../cfdemParticle/cfdemCloud/cfdemCloudI.H | 38 +- .../derived/cfdemCloudIB/cfdemCloudIB.C | 8 +- .../cfdemParticle/etc/additionalLibs | 8 + src/lagrangian/cfdemParticle/etc/bashrc | 38 +- .../cfdemParticle/etc/cfdemSystemTest.sh | 26 +- .../etc/compileCFDEMcoupling_sol.sh | 19 +- .../etc/compileCFDEMcoupling_src.sh | 84 ++--- .../etc/compileCFDEMcoupling_uti.sh | 117 +++++- .../cfdemParticle/etc/compileLIGGGHTS_lib.sh | 4 +- src/lagrangian/cfdemParticle/etc/cshrc | 23 ++ src/lagrangian/cfdemParticle/etc/functions.sh | 82 ++++- .../subModels/IOModel/IOModel/IOModel.C | 9 + .../subModels/IOModel/IOModel/IOModel.H | 2 + .../subModels/IOModel/basicIO/basicIO.C | 2 +- .../subModels/IOModel/sophIO/sophIO.C | 2 +- .../subModels/IOModel/trackIO/trackIO.C | 2 +- .../subModels/averagingModel/dense/dense.C | 3 + .../clockModel/clockModel/clockModel.C | 6 +- .../clockModel/clockModel/clockModel.H | 14 +- .../dataExchangeModel/dataExchangeModel.C | 17 +- .../dataExchangeModel/dataExchangeModel.H | 11 +- .../dataExchangeModel/twoWayMPI/twoWayMPI.C | 39 +- .../dataExchangeModel/twoWayMPI/twoWayMPI.H | 10 +- .../forceModel/Archimedes/Archimedes.C | 48 ++- .../forceModel/Archimedes/Archimedes.H | 4 - .../forceModel/ArchimedesIB/ArchimedesIB.C | 28 +- .../forceModel/ArchimedesIB/ArchimedesIB.H | 4 - .../forceModel/DiFeliceDrag/DiFeliceDrag.C | 92 ++--- .../forceModel/DiFeliceDrag/DiFeliceDrag.H | 10 - .../forceModel/GidaspowDrag/GidaspowDrag.C | 106 +++--- .../forceModel/GidaspowDrag/GidaspowDrag.H | 14 +- .../forceModel/KochHillDrag/KochHillDrag.C | 94 +++-- .../forceModel/KochHillDrag/KochHillDrag.H | 10 +- .../LaEuScalarTemp/LaEuScalarTemp.C | 45 +-- .../LaEuScalarTemp/LaEuScalarTemp.H | 8 - .../subModels/forceModel/MeiLift/MeiLift.C | 45 +-- .../subModels/forceModel/MeiLift/MeiLift.H | 12 - .../SchillerNaumannDrag/SchillerNaumannDrag.C | 34 +- .../SchillerNaumannDrag/SchillerNaumannDrag.H | 4 - .../forceModel/ShirgaonkarIB/ShirgaonkarIB.C | 28 +- .../forceModel/ShirgaonkarIB/ShirgaonkarIB.H | 4 - .../checkCouplingInterval.C | 24 +- .../checkCouplingInterval.H | 4 - .../forceModel/fieldStore/fieldStore.C | 164 +++++++++ .../forceModel/fieldStore/fieldStore.H | 106 ++++++ .../forceModel/forceModel/forceModel.C | 55 ++- .../forceModel/forceModel/forceModel.H | 28 +- .../forceModel/forceSubModels/ImEx/ImEx.C | 81 +++++ .../forceModel/forceSubModels/ImEx/ImEx.H | 95 +++++ .../forceSubModel/forceSubModel.C | 338 ++++++++++++++++++ .../forceSubModel/forceSubModel.H | 183 ++++++++++ .../forceSubModel/newForceSubModel.C | 79 ++++ .../forceModel/gradPForce/gradPForce.C | 58 +-- .../forceModel/gradPForce/gradPForce.H | 8 - .../forceModel/interface/interface.C | 16 +- .../subModels/forceModel/noDrag/noDrag.C | 20 +- .../virtualMassForce/virtualMassForce.C | 133 +++++-- .../virtualMassForce/virtualMassForce.H | 13 +- .../forceModel/viscForce/viscForce.C | 75 ++-- .../forceModel/viscForce/viscForce.H | 7 - .../liggghtsCommandModel.C | 17 +- .../liggghtsCommandModel.H | 2 + .../writeLiggghts/writeLiggghts.C | 17 +- .../meshMotionModel/meshMotionModel.C | 69 ++++ .../meshMotionModel/meshMotionModel.H | 10 + .../probeModel/particleProbe/particleProbe.C | 99 ++++- .../probeModel/particleProbe/particleProbe.H | 17 +- .../probeModel/probeModel/probeModel.H | 5 + .../constDiffSmoothing/constDiffSmoothing.C | 95 ++--- .../smoothingModel/smoothingModel.C | 50 ++- .../smoothingModel/smoothingModel.H | 6 + .../GaussVoidFraction/GaussVoidFraction.C | 5 +- .../GaussVoidFraction/GaussVoidFraction.H | 2 +- .../IBVoidFraction/IBVoidFraction.C | 3 +- .../IBVoidFraction/IBVoidFraction.H | 2 +- .../bigParticleVoidFraction.C | 5 +- .../bigParticleVoidFraction.H | 2 +- .../centreVoidFraction/centreVoidFraction.C | 3 +- .../centreVoidFraction/centreVoidFraction.H | 2 +- .../dividedVoidFraction/dividedVoidFraction.C | 19 +- .../dividedVoidFraction/dividedVoidFraction.H | 4 +- .../dividedVoidFraction/setWeightedSource.H | 1 + .../voidFractionModel/voidFractionModel.C | 9 + .../voidFractionModel/voidFractionModel.H | 4 +- tutorials/.gitignore | 8 + .../cfdemPostproc/fillCylinder/Allrun.sh | 2 +- .../twoSpheresGlowinskiMPI/Allrun.sh | 8 +- .../CFD/constant/couplingProperties | 4 +- .../DEM/in.liggghts_run | 95 +++++ .../DEM/post/.gitignore | 0 .../twoSpheresGlowinskiMPI/parCFDDEMrun.sh | 25 +- .../cfdemSolverPiso/ErgunTestMPI/Allrun.sh | 12 +- .../cfdemSolverPiso/ErgunTestMPI/CFD/0/p | 4 +- .../CFD/constant/couplingProperties | 79 ++-- .../CFD/constant/liggghtsCommands | 8 + .../CFD/octave/totalPressureDrop.m | 6 +- .../ErgunTestMPI/CFD/system/controlDict | 42 +-- .../ErgunTestMPI/DEM/in.liggghts_init | 88 ++--- .../ErgunTestMPI/DEM/in.liggghts_run | 68 ++++ .../ErgunTestMPI/DEM/post/restart/.gitignore | 0 .../ErgunTestMPI/parCFDDEMrun.sh | 11 +- .../cfdemSolverPiso/ErgunTestMPI/parDEMrun.sh | 30 ++ .../ErgunTestMPI_cgs/Allrun.sh | 22 +- .../CFD/constant/couplingProperties | 16 +- .../CFD/octave/totalPressureDrop.m | 7 +- .../ErgunTestMPI_cgs/CFD/system/controlDict | 101 +++++- .../ErgunTestMPI_cgs/DEM/in.liggghts_init | 89 ++--- .../ErgunTestMPI_cgs/DEM/in.liggghts_run | 66 ++++ .../DEM/post/restart/.gitignore | 0 .../ErgunTestMPI_cgs/parCFDDEMrun.sh | 26 +- .../ErgunTestMPI_cgs/parDEMrun.sh | 28 ++ .../ErgunTestMPI_restart/Allrun.sh | 27 +- .../CFD/constant/couplingProperties_restart | 13 +- .../CFD/constant/couplingProperties_run | 226 ++++++++++++ .../CFD/constant/liggghtsCommands_run | 45 +++ .../CFD/octave/totalPressureDrop.m | 4 - .../CFD/system/controlDict_run | 117 ++++++ .../ErgunTestMPI_restart/DEM/in.liggghts_init | 88 ++--- .../DEM/in.liggghts_restart | 96 +++-- .../ErgunTestMPI_restart/DEM/in.liggghts_run | 65 ++++ .../DEM/post/restart/.gitignore | 0 .../ErgunTestMPI_restart/parDEMrun.sh | 28 ++ .../cfdemSolverPiso/settlingTestMPI/Allrun.sh | 6 +- .../cfdemSolverPiso/settlingTestMPI/CFD/0/f | 30 ++ .../settlingTestMPI/CFD/0/sSmoothField | 31 ++ .../settlingTestMPI/CFD/0/vSmoothField | 31 ++ .../CFD/constant/couplingProperties | 13 +- .../CFD/constant/liggghtsCommands | 11 +- .../settlingTestMPI/CFD/system/fvSolution | 2 +- .../settlingTestMPI/DEM/in.liggghts_run | 73 ++++ .../settlingTestMPI/DEM/post/.gitignore | 0 .../settlingTestMPI/parCFDDEMrun.sh | 9 +- .../packedBedTemp/Allrun.sh | 13 +- .../CFD/constant/couplingProperties | 17 +- .../CFD/octave/totalPressureDropAndNusselt.m | 3 - .../packedBedTemp/DEM/in.liggghts_init | 120 +++---- .../packedBedTemp/DEM/in.liggghts_run | 75 ++++ .../packedBedTemp/DEM/post/restart/.gitignore | 0 .../packedBedTemp/parCFDDEMrun.sh | 26 +- .../packedBedTemp/parDEMrun.sh | 28 ++ 208 files changed, 5511 insertions(+), 1458 deletions(-) create mode 100644 applications/.gitignore create mode 100644 doc/.gitignore create mode 100644 doc/forceModel_fieldStore.html create mode 100644 doc/forceModel_fieldStore.txt create mode 100644 doc/forceSubModel.html create mode 100644 doc/forceSubModel.txt create mode 100644 doc/forceSubModel_ImEx.html create mode 100644 doc/forceSubModel_ImEx.txt create mode 100644 doc/forceSubModel_ImExCorr.html create mode 100644 doc/forceSubModel_ImExCorr.txt create mode 100644 src/.gitignore create mode 100644 src/lagrangian/cfdemParticle/cfdTools/compressibleContinuityErrsPU.H create mode 100644 src/lagrangian/cfdemParticle/cfdTools/global.C create mode 100644 src/lagrangian/cfdemParticle/cfdTools/global.H create mode 100644 src/lagrangian/cfdemParticle/cfdTools/mathExtra.H create mode 100644 src/lagrangian/cfdemParticle/cfdTools/newGlobal.C create mode 100644 src/lagrangian/cfdemParticle/etc/additionalLibs create mode 100644 src/lagrangian/cfdemParticle/subModels/forceModel/fieldStore/fieldStore.C create mode 100644 src/lagrangian/cfdemParticle/subModels/forceModel/fieldStore/fieldStore.H create mode 100644 src/lagrangian/cfdemParticle/subModels/forceModel/forceSubModels/ImEx/ImEx.C create mode 100644 src/lagrangian/cfdemParticle/subModels/forceModel/forceSubModels/ImEx/ImEx.H create mode 100644 src/lagrangian/cfdemParticle/subModels/forceModel/forceSubModels/forceSubModel/forceSubModel.C create mode 100644 src/lagrangian/cfdemParticle/subModels/forceModel/forceSubModels/forceSubModel/forceSubModel.H create mode 100644 src/lagrangian/cfdemParticle/subModels/forceModel/forceSubModels/forceSubModel/newForceSubModel.C create mode 100644 tutorials/.gitignore create mode 100644 tutorials/cfdemSolverIB/twoSpheresGlowinskiMPI/DEM/in.liggghts_run create mode 100644 tutorials/cfdemSolverIB/twoSpheresGlowinskiMPI/DEM/post/.gitignore create mode 100644 tutorials/cfdemSolverPiso/ErgunTestMPI/DEM/in.liggghts_run create mode 100644 tutorials/cfdemSolverPiso/ErgunTestMPI/DEM/post/restart/.gitignore create mode 100755 tutorials/cfdemSolverPiso/ErgunTestMPI/parDEMrun.sh create mode 100644 tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/DEM/in.liggghts_run create mode 100644 tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/DEM/post/restart/.gitignore create mode 100755 tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/parDEMrun.sh create mode 100644 tutorials/cfdemSolverPiso/ErgunTestMPI_restart/CFD/constant/couplingProperties_run create mode 100644 tutorials/cfdemSolverPiso/ErgunTestMPI_restart/CFD/constant/liggghtsCommands_run create mode 100644 tutorials/cfdemSolverPiso/ErgunTestMPI_restart/CFD/system/controlDict_run create mode 100644 tutorials/cfdemSolverPiso/ErgunTestMPI_restart/DEM/in.liggghts_run create mode 100644 tutorials/cfdemSolverPiso/ErgunTestMPI_restart/DEM/post/restart/.gitignore create mode 100755 tutorials/cfdemSolverPiso/ErgunTestMPI_restart/parDEMrun.sh create mode 100644 tutorials/cfdemSolverPiso/settlingTestMPI/CFD/0/f create mode 100755 tutorials/cfdemSolverPiso/settlingTestMPI/CFD/0/sSmoothField create mode 100644 tutorials/cfdemSolverPiso/settlingTestMPI/CFD/0/vSmoothField create mode 100644 tutorials/cfdemSolverPiso/settlingTestMPI/DEM/in.liggghts_run create mode 100644 tutorials/cfdemSolverPiso/settlingTestMPI/DEM/post/.gitignore create mode 100644 tutorials/cfdemSolverPisoScalar/packedBedTemp/DEM/in.liggghts_run create mode 100644 tutorials/cfdemSolverPisoScalar/packedBedTemp/DEM/post/restart/.gitignore create mode 100755 tutorials/cfdemSolverPisoScalar/packedBedTemp/parDEMrun.sh diff --git a/README b/README index fd2ca75..2a7f869 100755 --- a/README +++ b/README @@ -25,16 +25,17 @@ License Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Description - This code is designed to realize coupled CFD-DEM simulations using LIGGGHTS - and OpenFOAM. Note: this code is not part of OpenFOAM (see DISCLAIMER). + This code provides models and solvers to realize coupled CFD-DEM simulations + using LIGGGHTS and OpenFOAM. + Note: this code is not part of OpenFOAM (see DISCLAIMER). \*---------------------------------------------------------------------------*/ -CFDEM coupling provides an open source parallel coupled CFD-DEM framework -combining the strengths of LIGGGHTS DEM code and the Open Source -CFD package OpenFOAM(R)(*). The CFDEMcoupling toolbox allows to expand +CFDEM(R) coupling provides an open source parallel coupled CFD-DEM framework +combining the strengths of LIGGGHTS(R) DEM code and the Open Source +CFD package OpenFOAM(R)(*). The CFDEM(R)coupling toolbox allows to expand standard CFD solvers of OpenFOAM(R)(*) to include a coupling to the DEM -code LIGGGHTS. In this toolbox the particle representation within the +code LIGGGHTS(R). In this toolbox the particle representation within the CFD solver is organized by "cloud" classes. Key functionalities are organised in sub-models (e.g. force models, data exchange models, etc.) which can easily be selected and combined by dictionary settings. @@ -54,7 +55,7 @@ The file structure: - "src" directory including the source files of the coupling toolbox and models - "applications" directory including the solver files for coupled CFD-DEM simulations -- "doc" directory including the documentation of CFDEMcoupling +- "doc" directory including the documentation of CFDEM(R)coupling - "tutorials" directory including basic tutorial cases showing the functionality @@ -64,18 +65,17 @@ Details on installation are given on the "www.cfdem.com" The functionality of this CFD-DEM framwork is described via "tutorial cases" showing how to use different solvers and models. -CFDEMcoupling stands for Computational Fluid Dynamics (CFD) - +CFDEM(R)coupling stands for Computational Fluid Dynamics (CFD) - Discrete Element Method (DEM) coupling. -CFDEMcoupling is an open-source code, distributed freely under the terms of the +CFDEM(R)coupling is an open-source code, distributed freely under the terms of the GNU Public License (GPL). -Core development of CFDEMcoupling is done by +Core development of CFDEM(R)coupling is done by Christoph Goniva and Christoph Kloss, both at DCS Computing GmbH, 2012 \*---------------------------------------------------------------------------*/ -(*) "OpenFOAM(R)"_of is a registered trade mark of the ESI Group. -This offering is not affiliated, approved or endorsed by ESI Group, -the producer of the OpenFOAM® software and owner of the OpenFOAM® trade mark. +(*) "OpenFOAM(R)"_of is a registered trade mark of OpenCFD Limited, a wholly owned subsidiary of the ESI Group. +This offering is not approved or endorsed by OpenCFD Limited, the producer of the OpenFOAM software and owner of the OPENFOAM® and OpenCFD® trade marks. \*---------------------------------------------------------------------------*/ diff --git a/applications/.gitignore b/applications/.gitignore new file mode 100644 index 0000000..4459954 --- /dev/null +++ b/applications/.gitignore @@ -0,0 +1,7 @@ +*.o +*.d +*.a +*.dep +log_* +log.* +*~ diff --git a/applications/solvers/cfdemSolverIB/Make/options b/applications/solvers/cfdemSolverIB/Make/options index c32ff59..a51d1da 100755 --- a/applications/solvers/cfdemSolverIB/Make/options +++ b/applications/solvers/cfdemSolverIB/Make/options @@ -1,3 +1,5 @@ +include $(CFDEM_ADD_LIBS_DIR)/additionalLibs + EXE_INC = \ -I$(LIB_SRC)/turbulenceModels/incompressible/turbulenceModel \ -I$(LIB_SRC)/transportModels \ @@ -11,7 +13,6 @@ EXE_INC = \ -I$(LIB_SRC)/dynamicMesh/dynamicFvMesh/lnInclude \ -I$(LIB_SRC)/dynamicMesh/dynamicMesh/lnInclude \ -I$(LIB_SRC)/fvOptions/lnInclude - EXE_LIBS = \ -L$(CFDEM_LIB_DIR)\ -lincompressibleRASModels \ @@ -21,4 +22,7 @@ EXE_LIBS = \ -ldynamicFvMesh \ -ldynamicMesh \ -lfvOptions \ - -l$(CFDEM_LIB_NAME) + -l$(CFDEM_LIB_NAME) \ + $(CFDEM_ADD_LIB_PATHS) \ + $(CFDEM_ADD_LIBS) + diff --git a/applications/solvers/cfdemSolverIB/cfdemSolverIB.C b/applications/solvers/cfdemSolverIB/cfdemSolverIB.C index 93f0d41..9c930e6 100755 --- a/applications/solvers/cfdemSolverIB/cfdemSolverIB.C +++ b/applications/solvers/cfdemSolverIB/cfdemSolverIB.C @@ -72,7 +72,7 @@ int main(int argc, char *argv[]) #include "initContinuityErrs.H" #if defined(version22) - #include "createFvOptions.H" + #include "createFvOptions.H" #endif // create cfdemCloud @@ -128,10 +128,12 @@ int main(int argc, char *argv[]) for (int corr=0; corr()); + Info << "TotalForceExp: " << fTotal << endl; + Info << "TotalForceImp: " << fImpTotal << endl; + #include "solverDebugInfo.H" particleCloud.clockM().stop("Coupling"); @@ -91,23 +102,19 @@ int main(int argc, char *argv[]) // Momentum predictor fvVectorMatrix UEqn ( - fvm::ddt(voidfraction,U) + fvm::Sp(fvc::ddt(voidfraction),U) - + fvm::div(phi,U) + fvm::Sp(fvc::div(phi),U) + fvm::ddt(voidfraction,U) - fvm::Sp(fvc::ddt(voidfraction),U) + + fvm::div(phi,U) - fvm::Sp(fvc::div(phi),U) // + turbulence->divDevReff(U) + particleCloud.divVoidfractionTau(U, voidfraction) == - fvm::Sp(Ksl/rho,U) ); - if (modelType=="B") - UEqn == - fvc::grad(p) + Ksl/rho*Us; - else - UEqn == - voidfraction*fvc::grad(p) + Ksl/rho*Us; - UEqn.relax(); - - if (momentumPredictor) - solve(UEqn); + if (momentumPredictor && (modelType=="B" || modelType=="Bfull")) + solve(UEqn == - fvc::grad(p) + Ksl/rho*Us); + else if (momentumPredictor) + solve(UEqn == - voidfraction*fvc::grad(p) + Ksl/rho*Us); // --- PISO loop @@ -120,11 +127,17 @@ int main(int argc, char *argv[]) surfaceScalarField rUAf("(1|A(U))", fvc::interpolate(rUA)); volScalarField rUAvoidfraction("(voidfraction2|A(U))",rUA*voidfraction); + surfaceScalarField rUAfvoidfraction("(voidfraction2|A(U)F)", fvc::interpolate(rUAvoidfraction)); U = rUA*UEqn.H(); - phi = (fvc::interpolate(U*voidfraction) & mesh.Sf() ); - //+ fvc::ddtPhiCorr(rUAvoidfraction, U, phi); + #ifdef version23 + phi = ( fvc::interpolate(U*voidfraction) & mesh.Sf() ) + + rUAfvoidfraction*fvc::ddtCorr(U, phi); + #else + phi = ( fvc::interpolate(U*voidfraction) & mesh.Sf() ) + + fvc::ddtPhiCorr(rUAvoidfraction, U, phi); + #endif surfaceScalarField phiS(fvc::interpolate(Us*voidfraction) & mesh.Sf()); surfaceScalarField phiGes = phi + rUAf*(fvc::interpolate(Ksl/rho) * phiS); @@ -157,13 +170,14 @@ int main(int argc, char *argv[]) if (nonOrth == nNonOrthCorr) { phiGes -= pEqn.flux(); + phi = phiGes; } } // end non-orthogonal corrector loop #include "continuityErrorPhiPU.H" - if (modelType=="B") + if (modelType=="B" || modelType=="Bfull") U -= rUA*fvc::grad(p) - Ksl/rho*Us*rUA; else U -= voidfraction*rUA*fvc::grad(p) - Ksl/rho*Us*rUA; @@ -191,7 +205,7 @@ int main(int argc, char *argv[]) } Info<< "End\n" << endl; - + return 0; } diff --git a/applications/solvers/cfdemSolverPisoScalar/Make/options b/applications/solvers/cfdemSolverPisoScalar/Make/options index e79c26f..68aecd1 100644 --- a/applications/solvers/cfdemSolverPisoScalar/Make/options +++ b/applications/solvers/cfdemSolverPisoScalar/Make/options @@ -1,3 +1,5 @@ +include $(CFDEM_ADD_LIBS_DIR)/additionalLibs + EXE_INC = \ -I$(LIB_SRC)/turbulenceModels/incompressible/turbulenceModel \ -I$(LIB_SRC)/transportModels \ @@ -12,4 +14,6 @@ EXE_LIBS = \ -lincompressibleLESModels \ -lincompressibleTransportModels \ -lfiniteVolume \ - -l$(CFDEM_LIB_NAME) + -l$(CFDEM_LIB_NAME) \ + $(CFDEM_ADD_LIB_PATHS) \ + $(CFDEM_ADD_LIBS) diff --git a/applications/solvers/cfdemSolverPisoScalar/cfdemSolverPisoScalar.C b/applications/solvers/cfdemSolverPisoScalar/cfdemSolverPisoScalar.C index ac01594..2a3e49a 100644 --- a/applications/solvers/cfdemSolverPisoScalar/cfdemSolverPisoScalar.C +++ b/applications/solvers/cfdemSolverPisoScalar/cfdemSolverPisoScalar.C @@ -30,7 +30,7 @@ Application Description Transient solver for incompressible flow. Turbulence modelling is generic, i.e. laminar, RAS or LES may be selected. - The code is an evolution of the solver pisoFoam in OpenFOAM(R) 1.6, + The code is an evolution of the solver pisoFoam in OpenFOAM(R) 1.6, where additional functionality for CFD-DEM coupling is added. \*---------------------------------------------------------------------------*/ @@ -40,30 +40,26 @@ Description #include "cfdemCloud.H" #include "implicitCouple.H" -#include "forceModel.H" #include "smoothingModel.H" +#include "forceModel.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // int main(int argc, char *argv[]) { #include "setRootCase.H" - #include "createTime.H" #include "createMesh.H" #include "createFields.H" - #include "initContinuityErrs.H" // create cfdemCloud #include "readGravitationalAcceleration.H" cfdemCloud particleCloud(mesh); - #include "checkModelType.H" + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - Info<< "\nStarting time loop\n" << endl; - while (runTime.loop()) { Info<< "Time = " << runTime.timeName() << nl << endl; @@ -72,11 +68,15 @@ int main(int argc, char *argv[]) #include "CourantNo.H" // do particle stuff - Info << "- evolve()" << endl; - particleCloud.evolve(voidfraction,Us,U); + bool hasEvolved = particleCloud.evolve(voidfraction,Us,U); - Ksl.internalField() = particleCloud.momCoupleM(0).impMomSource(); - particleCloud.smoothingM().smoothen(Ksl); + if(hasEvolved) + { + particleCloud.smoothingM().smoothen(particleCloud.forceM(0).impParticleForces()); + } + + Info << "update Ksl.internalField()" << endl; + Ksl = particleCloud.momCoupleM(0).impMomSource(); Ksl.correctBoundaryConditions(); @@ -87,107 +87,116 @@ int main(int argc, char *argv[]) Tsource.correctBoundaryConditions(); // solve scalar transport equation - phi = fvc::interpolate(U*voidfraction) & mesh.Sf(); - - solve + fvScalarMatrix TEqn ( - fvm::ddt(voidfraction,T) - + fvm::div(phi, T) - - fvm::laplacian(DT*voidfraction, T) - == - Tsource + fvm::ddt(voidfraction,T) - fvm::Sp(fvc::ddt(voidfraction),T) + + fvm::div(phi, T) - fvm::Sp(fvc::div(phi),T) + - fvm::laplacian(DT*voidfraction, T) + == + Tsource ); + TEqn.relax(); + TEqn.solve(); - // Pressure-velocity PISO corrector + if(particleCloud.solveFlow()) { - // Momentum predictor - fvVectorMatrix UEqn - ( - fvm::ddt(voidfraction,U) - + fvm::div(phi, U) - + turbulence->divDevReff(U) - == - - fvm::Sp(Ksl/rho,U) - ); - - UEqn.relax(); - - if (momentumPredictor) + // Pressure-velocity PISO corrector { - //solve UEqn - if (modelType=="B") + // Momentum predictor + fvVectorMatrix UEqn + ( + fvm::ddt(voidfraction,U) - fvm::Sp(fvc::ddt(voidfraction),U) + + fvm::div(phi,U) - fvm::Sp(fvc::div(phi),U) +// + turbulence->divDevReff(U) + + particleCloud.divVoidfractionTau(U, voidfraction) + == + - fvm::Sp(Ksl/rho,U) + ); + + UEqn.relax(); + if (momentumPredictor && (modelType=="B" || modelType=="Bfull")) solve(UEqn == - fvc::grad(p) + Ksl/rho*Us); - else + else if (momentumPredictor) solve(UEqn == - voidfraction*fvc::grad(p) + Ksl/rho*Us); + + // --- PISO loop + + //for (int corr=0; corrcorrect(); + }// end solveFlow + else + { + Info << "skipping flow solution." << endl; } - turbulence->correct(); - runTime.write(); Info<< "ExecutionTime = " << runTime.elapsedCpuTime() << " s" diff --git a/applications/utilities/cfdemPostproc/Make/options b/applications/utilities/cfdemPostproc/Make/options index c961d2d..c6a8758 100644 --- a/applications/utilities/cfdemPostproc/Make/options +++ b/applications/utilities/cfdemPostproc/Make/options @@ -1,3 +1,5 @@ +include $(CFDEM_ADD_LIBS_DIR)/additionalLibs + EXE_INC = \ -I$(LIB_SRC)/turbulenceModels/incompressible/turbulenceModel \ -I$(LIB_SRC)/transportModels \ @@ -14,4 +16,6 @@ EXE_LIBS = \ -lincompressibleTransportModels \ -lfiniteVolume \ -l$(CFDEM_LIB_NAME) \ + $(CFDEM_ADD_LIB_PATHS) \ + $(CFDEM_ADD_LIBS) diff --git a/applications/utilities/cfdemPostproc/cfdemPostproc.C b/applications/utilities/cfdemPostproc/cfdemPostproc.C index 8db48d8..478136e 100644 --- a/applications/utilities/cfdemPostproc/cfdemPostproc.C +++ b/applications/utilities/cfdemPostproc/cfdemPostproc.C @@ -71,6 +71,7 @@ int main(int argc, char *argv[]) double **voidfractions_; double **particleWeights_; double **particleVolumes_; + double **particleV_; double **cellIDs_; particleCloud.dataExchangeM().allocateArray(positions_,0.,3); @@ -80,6 +81,7 @@ int main(int argc, char *argv[]) particleCloud.dataExchangeM().allocateArray(voidfractions_,0.,1); particleCloud.dataExchangeM().allocateArray(particleWeights_,0.,1); particleCloud.dataExchangeM().allocateArray(particleVolumes_,0.,1); + particleCloud.dataExchangeM().allocateArray(particleV_,0.,1); particleCloud.get_cellIDs(cellIDs_); // get ref to cellIDs //particleCloud.dataExchangeM().allocateArray(cellIDs_,0.,1); @@ -105,7 +107,7 @@ int main(int argc, char *argv[]) particleCloud.locateM().findCell(NULL,positions_,cellIDs_,particleCloud.numberOfParticles()); particleCloud.setPos(positions_); - particleCloud.voidFractionM().setvoidFraction(NULL,voidfractions_,particleWeights_,particleVolumes_); + particleCloud.voidFractionM().setvoidFraction(NULL,voidfractions_,particleWeights_,particleVolumes_,particleV_); voidfraction.internalField() = particleCloud.voidFractionM().voidFractionInterp(); voidfraction.correctBoundaryConditions(); @@ -135,6 +137,7 @@ int main(int argc, char *argv[]) particleCloud.dataExchangeM().destroy(voidfractions_,1); particleCloud.dataExchangeM().destroy(particleWeights_,1); particleCloud.dataExchangeM().destroy(particleVolumes_,1); + particleCloud.dataExchangeM().destroy(particleV_,1); //particleCloud.dataExchangeM().destroy(cellIDs_); // destroyed in cloud Info<< "End\n" << endl; diff --git a/applications/utilities/cfdemPostproc/createFields.H b/applications/utilities/cfdemPostproc/createFields.H index ab0ae8a..6856c6f 100644 --- a/applications/utilities/cfdemPostproc/createFields.H +++ b/applications/utilities/cfdemPostproc/createFields.H @@ -26,7 +26,7 @@ IOobject::NO_WRITE ), mesh, - dimensionedVector("0", dimensionSet(0, 1, -1, 0, 0), vector::zero) + dimensionedVector("0", dimensionSet(0, 1, -1, 0, 0), Foam::vector::zero) ); //======================== @@ -62,7 +62,7 @@ IOobject::AUTO_WRITE ), mesh, - dimensionedVector("0", dimensionSet(0, 1, -1, 0, 0), vector::zero) + dimensionedVector("0", dimensionSet(0, 1, -1, 0, 0), Foam::vector::zero) ); //======================== diff --git a/doc/.gitignore b/doc/.gitignore new file mode 100644 index 0000000..4459954 --- /dev/null +++ b/doc/.gitignore @@ -0,0 +1,7 @@ +*.o +*.d +*.a +*.dep +log_* +log.* +*~ diff --git a/doc/CFDEMcoupling_Manual.html b/doc/CFDEMcoupling_Manual.html index 4bce9e4..2af4e1b 100644 --- a/doc/CFDEMcoupling_Manual.html +++ b/doc/CFDEMcoupling_Manual.html @@ -164,7 +164,7 @@ In order to get the latest code version, please use the git repository at http:/

modelType 
 
-

"modelType" refers to the formulation of the equations to be solved. Choose "A" or "B", according to Zhou et al. (2010): "Discrete particle simulation of particle-fluid flow: model formulations and their applicability", JFM. "A" requires the use of the force models gradPForce and viscForce, whereas "B" requires the force model "Archimedes". +

"modelType" refers to the formulation of the equations to be solved. Choose "A", "B" or "Bfull", according to Zhou et al. (2010): "Discrete particle simulation of particle-fluid flow: model formulations and their applicability", JFM. "A" requires the use of the force models gradPForce and viscForce, whereas "B" requires the force model "Archimedes". "Bfull" refers to model type I.

couplingInterval 
 
@@ -217,9 +217,11 @@ listing below of styles within certain commands. forceModel_DiFeliceDragforceModel_GidaspowDrag forceModel_KochHillDragforceModel_LaEuScalarTemp forceModel_MeiLiftforceModel_SchillerNaumannDrag -forceModel_ShirgaonkarIBforceModel_gradPForce -forceModel_noDragforceModel_particleCellVolume -forceModel_virtualMassForceforceModel_viscForce +forceModel_ShirgaonkarIBforceModel_fieldStore +forceModel_gradPForceforceModel_noDrag +forceModel_particleCellVolumeforceModel_virtualMassForce +forceModel_viscForceforceSubModel +forceSubModel_ImExforceSubModel_ImExCorr liggghtsCommandModelliggghtsCommandModel_execute liggghtsCommandModel_readLiggghtsDataliggghtsCommandModel_runLiggghts liggghtsCommandModel_writeLiggghtslocateModel diff --git a/doc/CFDEMcoupling_Manual.pdf b/doc/CFDEMcoupling_Manual.pdf index 11f58f247c48b751f210dd22269eae310b037145..95cb01e4f3b63645a475b0c427b66a22d80de760 100644 GIT binary patch delta 75578 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%0A1YCc4qOKsWLK;U$%+XxlFR)yt}t{UJ|b&=q~5 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 diff --git a/doc/CFDEMcoupling_Manual.txt b/doc/CFDEMcoupling_Manual.txt index 65da209..2f80b73 100644 --- a/doc/CFDEMcoupling_Manual.txt +++ b/doc/CFDEMcoupling_Manual.txt @@ -133,7 +133,7 @@ Reasonable example settings for the "couplingProperties" dictionary are given in modelType :pre -"modelType" refers to the formulation of the equations to be solved. Choose "A" or "B", according to Zhou et al. (2010): "Discrete particle simulation of particle-fluid flow: model formulations and their applicability", JFM. "A" requires the use of the force models gradPForce and viscForce, whereas "B" requires the force model "Archimedes". +"modelType" refers to the formulation of the equations to be solved. Choose "A", "B" or "Bfull", according to Zhou et al. (2010): "Discrete particle simulation of particle-fluid flow: model formulations and their applicability", JFM. "A" requires the use of the force models gradPForce and viscForce, whereas "B" requires the force model "Archimedes". "Bfull" refers to model type I. couplingInterval :pre @@ -221,6 +221,10 @@ Reasonable example settings for the "liggghtsCommands" dictionary are given in t + + + + @@ -261,11 +265,15 @@ listing below of styles within certain commands. "forceModel_MeiLift"_forceModel_MeiLift.html, "forceModel_SchillerNaumannDrag"_forceModel_SchillerNaumannDrag.html, "forceModel_ShirgaonkarIB"_forceModel_ShirgaonkarIB.html, +"forceModel_fieldStore"_forceModel_fieldStore.html, "forceModel_gradPForce"_forceModel_gradPForce.html, "forceModel_noDrag"_forceModel_noDrag.html, "forceModel_particleCellVolume"_forceModel_particleCellVolume.html, "forceModel_virtualMassForce"_forceModel_virtualMassForce.html, "forceModel_viscForce"_forceModel_viscForce.html, +"forceSubModel"_forceSubModel.html, +"forceSubModel_ImEx"_forceSubModel_ImEx.html, +"forceSubModel_ImExCorr"_forceSubModel_ImExCorr.html, "liggghtsCommandModel"_liggghtsCommandModel.html, "liggghtsCommandModel_execute"_liggghtsCommandModel_execute.html, "liggghtsCommandModel_readLiggghtsData"_liggghtsCommandModel_readLiggghtsData.html, diff --git a/doc/cfdemSolverPisoScalar.html b/doc/cfdemSolverPisoScalar.html index 599a219..191cd84 100644 --- a/doc/cfdemSolverPisoScalar.html +++ b/doc/cfdemSolverPisoScalar.html @@ -11,12 +11,14 @@

Description:

-

"cfdemSolverPisoScalar" is a coupled CFD-DEM solver using CFDEMcoupling, an open source parallel coupled CFD-DEM framework. Based on pisoFoam(R)(*), a finite volume based solver for turbulent Navier-Stokes equations applying PISO algorithm, "cfdemSolverPisoScalar" has additional functionality for a coupling to the DEM code "LIGGGHTS" as well as a scalar transport equation. The volume averaged Navier-Stokes Equations are solved accounting for momentum exchange and volume displacement of discrete particles whose trajectories are calculated in the DEM code LIGGGHTS. The scalar transport equation is coupled to scalar properties of the particle phase, thus convective heat transfer in a fluid granular system can be modeled with "cfdemSolverPisoScalar". +

"cfdemSolverPisoScalar" is a coupled CFD-DEM solver using CFDEMcoupling, an open source parallel coupled CFD-DEM framework. Based on pisoFoam(R)(*), a finite volume based solver for turbulent Navier-Stokes equations applying PISO algorithm, "cfdemSolverPisoScalar" has additional functionality for a coupling to the DEM code "LIGGGHTS" as well as a scalar transport equation. The volume averaged Navier-Stokes Equations are solved accounting for momentum exchange and volume displacement of discrete particles, whose trajectories are calculated in the DEM code LIGGGHTS. The scalar transport equation is coupled to scalar properties of the particle phase, thus convective heat transfer in a fluid granular system can be modeled with "cfdemSolverPisoScalar".

see:

GONIVA, C., KLOSS, C., HAGER,A. and PIRKER, S. (2010): "An Open Source CFD-DEM Perspective", Proc. of OpenFOAM Workshop, Göteborg, June 22.-24.

+

The heat transfer equation is implemented according to Nield & Bejan (2013), Convection in Porous Media, DOI 10.1007/978-1-4614-5541-7_2, Springer +


(*) This offering is not approved or endorsed by OpenCFD Limited, the producer of the OpenFOAM software and owner of the OPENFOAM® and OpenCFD® trade marks. OPENFOAM® is a registered trade mark of OpenCFD Limited, a wholly owned subsidiary of the ESI Group. diff --git a/doc/cfdemSolverPisoScalar.txt b/doc/cfdemSolverPisoScalar.txt index 41126c4..f05ca93 100644 --- a/doc/cfdemSolverPisoScalar.txt +++ b/doc/cfdemSolverPisoScalar.txt @@ -9,12 +9,15 @@ cfdemSolverPisoScalar command :h3 [Description:] -"cfdemSolverPisoScalar" is a coupled CFD-DEM solver using CFDEMcoupling, an open source parallel coupled CFD-DEM framework. Based on pisoFoam(R)(*), a finite volume based solver for turbulent Navier-Stokes equations applying PISO algorithm, "cfdemSolverPisoScalar" has additional functionality for a coupling to the DEM code "LIGGGHTS" as well as a scalar transport equation. The volume averaged Navier-Stokes Equations are solved accounting for momentum exchange and volume displacement of discrete particles whose trajectories are calculated in the DEM code LIGGGHTS. The scalar transport equation is coupled to scalar properties of the particle phase, thus convective heat transfer in a fluid granular system can be modeled with "cfdemSolverPisoScalar". +"cfdemSolverPisoScalar" is a coupled CFD-DEM solver using CFDEMcoupling, an open source parallel coupled CFD-DEM framework. Based on pisoFoam(R)(*), a finite volume based solver for turbulent Navier-Stokes equations applying PISO algorithm, "cfdemSolverPisoScalar" has additional functionality for a coupling to the DEM code "LIGGGHTS" as well as a scalar transport equation. The volume averaged Navier-Stokes Equations are solved accounting for momentum exchange and volume displacement of discrete particles, whose trajectories are calculated in the DEM code LIGGGHTS. The scalar transport equation is coupled to scalar properties of the particle phase, thus convective heat transfer in a fluid granular system can be modeled with "cfdemSolverPisoScalar". see: GONIVA, C., KLOSS, C., HAGER,A. and PIRKER, S. (2010): "An Open Source CFD-DEM Perspective", Proc. of OpenFOAM Workshop, Göteborg, June 22.-24. +The heat transfer equation is implemented according to Nield & Bejan (2013), Convection in Porous Media, DOI 10.1007/978-1-4614-5541-7_2, Springer + + :line (*) This offering is not approved or endorsed by OpenCFD Limited, the producer of the OpenFOAM software and owner of the OPENFOAM® and OpenCFD® trade marks. OPENFOAM® is a registered trade mark of OpenCFD Limited, a wholly owned subsidiary of the ESI Group. diff --git a/doc/clockModel_standardClock.html b/doc/clockModel_standardClock.html index 57ec9ee..b757df1 100644 --- a/doc/clockModel_standardClock.html +++ b/doc/clockModel_standardClock.html @@ -23,7 +23,7 @@

The "standardClock" model is a basic clockModel model which measures the run time between every ".start(int arrayPos,string name)" and ".stop(string name)" statement placed in the code. If a ".start(name)" is called more than once (e.g. in a loop) the accumulated times are calculated. After the simulation has finished, the data is stored in $caseDir/CFD/clockData/$startTime/*.txt . Since the measurements are stored in an array, it is necessary to put a variable arrayPos (type integer) at the start command. Those do not need to be in ascending order and positions may be omitted. The standard size of this array is 30 and can be changed at the initialization of the standardClock class. If arrayPos is out of bounds, the array size will be doubled. The stop command does not need arrayPos, since the class remembers the positions. The string name is intended for easier evaluation afterwards an may be omitted like ".start(int arrayPos)" and ".stop()". The command ".stop(string name)" is a safety feature, because if the name is not equal to the started name, output will be produced for information. -After the case ran you may use the matPlot.py script located in $CFDEM_UT_DIR/vizClock/ to produce a graphical output of your measurements. The usage is like 'python < matPlot.py' and you have to be in the directory of the desired time step, where there is a file called "timeEvalFull.txt", which contains averaged and maximum data with respect to the number of processes. +After the case ran you may use the matPlot.py script located in $CFDEM_UT_DIR/vizClock/ to produce a graphical output of your measurements. The usage is like 'python < matPlot.py' and you have to be in the directory of the desired time step, where there is a file called "timeEvalFull.txt", which contains averaged and maximum data with respect to the number of processes. There is an alias called "vizClock" to run this python routine for visualizing the data.

Restrictions: none.

diff --git a/doc/clockModel_standardClock.txt b/doc/clockModel_standardClock.txt index 30d675c..bae9832 100644 --- a/doc/clockModel_standardClock.txt +++ b/doc/clockModel_standardClock.txt @@ -21,7 +21,7 @@ clockModel standardClock; :pre The "standardClock" model is a basic clockModel model which measures the run time between every ".start(int arrayPos,string name)" and ".stop(string name)" statement placed in the code. If a ".start(name)" is called more than once (e.g. in a loop) the accumulated times are calculated. After the simulation has finished, the data is stored in $caseDir/CFD/clockData/$startTime/*.txt . Since the measurements are stored in an array, it is necessary to put a variable {arrayPos} (type integer) at the start command. Those do not need to be in ascending order and positions may be omitted. The standard size of this array is 30 and can be changed at the initialization of the standardClock class. If {arrayPos} is out of bounds, the array size will be doubled. The stop command does not need {arrayPos}, since the class remembers the positions. The string name is intended for easier evaluation afterwards an may be omitted like ".start(int arrayPos)" and ".stop()". The command ".stop(string name)" is a safety feature, because if the name is not equal to the started name, output will be produced for information. -After the case ran you may use the matPlot.py script located in $CFDEM_UT_DIR/vizClock/ to produce a graphical output of your measurements. The usage is like 'python < matPlot.py' and you have to be in the directory of the desired time step, where there is a file called "timeEvalFull.txt", which contains averaged and maximum data with respect to the number of processes. +After the case ran you may use the matPlot.py script located in $CFDEM_UT_DIR/vizClock/ to produce a graphical output of your measurements. The usage is like 'python < matPlot.py' and you have to be in the directory of the desired time step, where there is a file called "timeEvalFull.txt", which contains averaged and maximum data with respect to the number of processes. There is an alias called "vizClock" to run this python routine for visualizing the data. [Restrictions:] none. diff --git a/doc/forceModel.html b/doc/forceModel.html index 411ada2..0e71fa5 100644 --- a/doc/forceModel.html +++ b/doc/forceModel.html @@ -33,7 +33,7 @@

Description:

-

The force model performs the calculation of forces (e.g. fluid-particle interaction forces) acting on each DEM particle. All force models selected are executed sequentially and the forces on the particles are superposed. +

The force model performs the calculation of forces (e.g. fluid-particle interaction forces) acting on each DEM particle. All force models selected are executed sequentially and the forces on the particles are superposed. If the fluid density field is needed, by default a field named "rho" will be used. Via the forceSubModel an alternative field can be chosen.

Restrictions:

diff --git a/doc/forceModel.txt b/doc/forceModel.txt index 790b110..4ae3a1a 100644 --- a/doc/forceModel.txt +++ b/doc/forceModel.txt @@ -31,7 +31,7 @@ Note: This examples list might not be complete - please look for other models (f [Description:] -The force model performs the calculation of forces (e.g. fluid-particle interaction forces) acting on each DEM particle. All force models selected are executed sequentially and the forces on the particles are superposed. +The force model performs the calculation of forces (e.g. fluid-particle interaction forces) acting on each DEM particle. All force models selected are executed sequentially and the forces on the particles are superposed. If the fluid density field is needed, by default a field named "rho" will be used. Via the forceSubModel an alternative field can be chosen. [Restrictions:] diff --git a/doc/forceModel_Archimedes.html b/doc/forceModel_Archimedes.html index 95e5156..8301478 100644 --- a/doc/forceModel_Archimedes.html +++ b/doc/forceModel_Archimedes.html @@ -19,13 +19,10 @@ ); ArchimedesProps { - densityFieldName "density"; gravityFieldName "gravity"; }; -
  • density = name of the finite volume density field - -
  • gravity = name of the finite volume gravity field +
    • gravity = name of the finite volume gravity field
    @@ -37,7 +34,6 @@ ArchimedesProps ); ArchimedesProps { - densityFieldName "rho"; gravityFieldName "g"; } diff --git a/doc/forceModel_Archimedes.txt b/doc/forceModel_Archimedes.txt index cd3f765..41c18ae 100644 --- a/doc/forceModel_Archimedes.txt +++ b/doc/forceModel_Archimedes.txt @@ -17,12 +17,10 @@ forceModels ); ArchimedesProps \{ - densityFieldName "density"; gravityFieldName "gravity"; \}; :pre -{density} = name of the finite volume density field :ulb,l -{gravity} = name of the finite volume gravity field :l +{gravity} = name of the finite volume gravity field :ulb,l :ule [Examples:] @@ -33,7 +31,6 @@ forceModels ); ArchimedesProps \{ - densityFieldName "rho"; gravityFieldName "g"; \} :pre diff --git a/doc/forceModel_ArchimedesIB.html b/doc/forceModel_ArchimedesIB.html index 0146856..9f43172 100644 --- a/doc/forceModel_ArchimedesIB.html +++ b/doc/forceModel_ArchimedesIB.html @@ -19,14 +19,11 @@ ); ArchimedesIBProps { - densityFieldName "density"; gravityFieldName "gravity"; voidfractionFieldName "voidfraction"; }; -
    • density = name of the finite volume density field - -
    • gravity = name of the finite volume gravity field +
      • gravity = name of the finite volume gravity field
      • voidfraction = name of the finite volume voidfraction field @@ -40,7 +37,6 @@ ArchimedesIBProps ); ArchimedesIBProps { - densityFieldName "rho"; gravityFieldName "g"; voidfractionFieldName "voidfractionNext"; } diff --git a/doc/forceModel_ArchimedesIB.txt b/doc/forceModel_ArchimedesIB.txt index b9aca33..041d737 100644 --- a/doc/forceModel_ArchimedesIB.txt +++ b/doc/forceModel_ArchimedesIB.txt @@ -17,13 +17,11 @@ forceModels ); ArchimedesIBProps \{ - densityFieldName "density"; gravityFieldName "gravity"; voidfractionFieldName "voidfraction"; \}; :pre -{density} = name of the finite volume density field :ulb,l -{gravity} = name of the finite volume gravity field :l +{gravity} = name of the finite volume gravity field :ulb,l {voidfraction} = name of the finite volume voidfraction field :l :ule @@ -35,7 +33,6 @@ forceModels ); ArchimedesIBProps \{ - densityFieldName "rho"; gravityFieldName "g"; voidfractionFieldName "voidfractionNext"; \} :pre diff --git a/doc/forceModel_DiFeliceDrag.html b/doc/forceModel_DiFeliceDrag.html index 9b02164..53a2aeb 100644 --- a/doc/forceModel_DiFeliceDrag.html +++ b/doc/forceModel_DiFeliceDrag.html @@ -20,15 +20,12 @@ DiFeliceDragProps { velFieldName "U"; - densityFieldName "density"; - interpolation; + interpolation switch1; };
        • U = name of the finite volume fluid velocity field -
        • density = name of the finite volume gravity field - -
        • interpolation = flag to use interpolated voidfraction and velocity values (normally off) +
        • switch1 = flag to use interpolated voidfraction and velocity values (normally off)
        @@ -41,8 +38,7 @@ DiFeliceDragProps DiFeliceDragProps { velFieldName "U"; - densityFieldName "rho"; - interpolation; + interpolation true; }

        Description: diff --git a/doc/forceModel_DiFeliceDrag.txt b/doc/forceModel_DiFeliceDrag.txt index 7180d17..77e6e4b 100644 --- a/doc/forceModel_DiFeliceDrag.txt +++ b/doc/forceModel_DiFeliceDrag.txt @@ -18,13 +18,11 @@ forceModels DiFeliceDragProps \{ velFieldName "U"; - densityFieldName "density"; - interpolation; + interpolation switch1; \}; :pre {U} = name of the finite volume fluid velocity field :ulb,l -{density} = name of the finite volume gravity field :l -{interpolation} = flag to use interpolated voidfraction and velocity values (normally off) :l +{switch1} = flag to use interpolated voidfraction and velocity values (normally off) :l :ule [Examples:] @@ -36,8 +34,7 @@ forceModels DiFeliceDragProps \{ velFieldName "U"; - densityFieldName "rho"; - interpolation; + interpolation true; \} :pre [Description:] diff --git a/doc/forceModel_GidaspowDrag.html b/doc/forceModel_GidaspowDrag.html index 0523427..9aa7318 100644 --- a/doc/forceModel_GidaspowDrag.html +++ b/doc/forceModel_GidaspowDrag.html @@ -20,24 +20,24 @@ GidaspowDragProps { velFieldName "U"; - densityFieldName "density"; voidfractionFieldName "voidfraction"; + granVelFieldName "Us"; phi "scalar"; - interpolation; - implDEM; + interpolation switch1; + implForceDEM switch2; };

        • U = name of the finite volume fluid velocity field -
        • density = name of the finite volume gravity field -
        • voidfraction = name of the finite volume voidfraction field +
        • Us = name of the finite volume cell averaged particle velocity field +
        • phi = drag correction factor (in doubt 1) -
        • interpolation = (optional, normally off) flag to use interpolated voidfraction and fluid velocity values +
        • switch1 = (optional, normally off) flag to use interpolated voidfraction and fluid velocity values -implDEM = (optional, normally off) flag to use implicit formulation of drag on DEM side:l +switch2 = (optional, normally off) flag to use implicit formulation of drag on DEM side:l

        Examples: @@ -49,8 +49,8 @@ GidaspowDragProps GidaspowDragProps { velFieldName "U"; - densityFieldName "rho"; voidfractionFieldName "voidfraction"; + granVelFieldName "Us"; }

        Description: diff --git a/doc/forceModel_GidaspowDrag.txt b/doc/forceModel_GidaspowDrag.txt index 8357170..452c67f 100644 --- a/doc/forceModel_GidaspowDrag.txt +++ b/doc/forceModel_GidaspowDrag.txt @@ -18,19 +18,19 @@ forceModels GidaspowDragProps \{ velFieldName "U"; - densityFieldName "density"; voidfractionFieldName "voidfraction"; + granVelFieldName "Us"; phi "scalar"; - interpolation; - implDEM; + interpolation switch1; + implForceDEM switch2; \}; :pre {U} = name of the finite volume fluid velocity field :ulb,l -{density} = name of the finite volume gravity field :l {voidfraction} = name of the finite volume voidfraction field :l +{Us} = name of the finite volume cell averaged particle velocity field :l {phi} = drag correction factor (in doubt 1) :l -{interpolation} = (optional, normally off) flag to use interpolated voidfraction and fluid velocity values :l -{implDEM} = (optional, normally off) flag to use implicit formulation of drag on DEM side:l +{switch1} = (optional, normally off) flag to use interpolated voidfraction and fluid velocity values :l +{switch2} = (optional, normally off) flag to use implicit formulation of drag on DEM side:l :ule [Examples:] @@ -42,8 +42,8 @@ forceModels GidaspowDragProps \{ velFieldName "U"; - densityFieldName "rho"; voidfractionFieldName "voidfraction"; + granVelFieldName "Us"; \} :pre [Description:] diff --git a/doc/forceModel_KochHillDrag.html b/doc/forceModel_KochHillDrag.html index db34b8a..1cf16d9 100644 --- a/doc/forceModel_KochHillDrag.html +++ b/doc/forceModel_KochHillDrag.html @@ -20,21 +20,18 @@ KochHillDragProps { velFieldName "U"; - densityFieldName "density"; voidfractionFieldName "voidfraction"; - interpolation; - implDEM; + interpolation "bool1"; + implForceDEM "bool2"; };

        • U = name of the finite volume fluid velocity field -
        • density = name of the finite volume gravity field -
        • voidfraction = name of the finite volume voidfraction field -
        • interpolation = (optional, normally off) flag to use interpolated voidfraction and fluid velocity values +
        • bool1 = (optional, normally off) flag to use interpolated voidfraction and fluid velocity values -implDEM = (optional, normally off) flag to use implicit formulation of drag on DEM side:l +bool2 = (optional, normally off) flag to use implicit formulation of drag on DEM side:l

        Examples: @@ -46,7 +43,6 @@ KochHillDragProps KochHillDragProps { velFieldName "U"; - densityFieldName "rho"; voidfractionFieldName "voidfraction"; } diff --git a/doc/forceModel_KochHillDrag.txt b/doc/forceModel_KochHillDrag.txt index 5a783fe..0737bb2 100644 --- a/doc/forceModel_KochHillDrag.txt +++ b/doc/forceModel_KochHillDrag.txt @@ -18,17 +18,15 @@ forceModels KochHillDragProps \{ velFieldName "U"; - densityFieldName "density"; voidfractionFieldName "voidfraction"; - interpolation; - implDEM; + interpolation "bool1"; + implForceDEM "bool2"; \}; :pre {U} = name of the finite volume fluid velocity field :ulb,l -{density} = name of the finite volume gravity field :l {voidfraction} = name of the finite volume voidfraction field :l -{interpolation} = (optional, normally off) flag to use interpolated voidfraction and fluid velocity values :l -{implDEM} = (optional, normally off) flag to use implicit formulation of drag on DEM side:l +{bool1} = (optional, normally off) flag to use interpolated voidfraction and fluid velocity values :l +{bool2} = (optional, normally off) flag to use implicit formulation of drag on DEM side:l :ule [Examples:] @@ -40,7 +38,6 @@ forceModels KochHillDragProps \{ velFieldName "U"; - densityFieldName "rho"; voidfractionFieldName "voidfraction"; \} :pre diff --git a/doc/forceModel_LaEuScalarTemp.html b/doc/forceModel_LaEuScalarTemp.html index c0075c9..778d3e3 100644 --- a/doc/forceModel_LaEuScalarTemp.html +++ b/doc/forceModel_LaEuScalarTemp.html @@ -21,23 +21,19 @@ LaEuScalarTempProps { velFieldName "U"; tempFieldName "T"; - tempSourceFieldName "Tsource"; voidfractionFieldName "voidfraction"; partTempName "Temp"; partHeatFluxName "convectiveHeatFlux"; lambda value; Cp value1; - densityFieldName "density"; - interpolation; - verbose; + interpolation "switch1"; + verbose "switch2"; };

        • U = name of the finite volume fluid velocity field
        • T = name of the finite volume scalar temperature field -
        • Tsource = name of the finite volume scalar temperature source field -
        • voidfraction = name of the finite volume voidfraction field
        • Temp = name of the DEM data representing the particles temperature @@ -48,11 +44,9 @@ LaEuScalarTempProps
        • value1 = fluid specific heat capacity [W*s/(kg*K)] -
        • density = name of the finite volume fluid density field +
        • switch1 = (optional, normally off) flag to use interpolated voidfraction and fluid velocity values -
        • interpolation = (optional, normally off) flag to use interpolated voidfraction and fluid velocity values - -
        • verbose = (normally off) for verbose run +
        • switch2 = (normally off) for verbose run
        @@ -66,13 +60,11 @@ LaEuScalarTempProps { velFieldName "U"; tempFieldName "T"; - tempSourceFieldName "Tsource"; voidfractionFieldName "voidfraction"; partTempName "Temp"; partHeatFluxName "convectiveHeatFlux"; lambda 0.0256; Cp 1007; - densityFieldName "rho"; }

        Description: @@ -81,7 +73,7 @@ LaEuScalarTempProps

        Restrictions:

        -

        Goes only with cfdemSolverScalar. +

        Goes only with cfdemSolverScalar. The force model has to be the second (!!!) model in the forces list.

        Related commands:

        diff --git a/doc/forceModel_LaEuScalarTemp.txt b/doc/forceModel_LaEuScalarTemp.txt index a2b8690..307693c 100644 --- a/doc/forceModel_LaEuScalarTemp.txt +++ b/doc/forceModel_LaEuScalarTemp.txt @@ -19,28 +19,24 @@ LaEuScalarTempProps \{ velFieldName "U"; tempFieldName "T"; - tempSourceFieldName "Tsource"; voidfractionFieldName "voidfraction"; partTempName "Temp"; partHeatFluxName "convectiveHeatFlux"; lambda value; Cp value1; - densityFieldName "density"; - interpolation; - verbose; + interpolation "switch1"; + verbose "switch2"; \}; :pre {U} = name of the finite volume fluid velocity field :ulb,l {T} = name of the finite volume scalar temperature field :l -{Tsource} = name of the finite volume scalar temperature source field :l {voidfraction} = name of the finite volume voidfraction field :l {Temp} = name of the DEM data representing the particles temperature :l {convectiveHeatFlux} = name of the DEM data representing the particle-fluid convective heat flux :l {value} = fluid thermal conductivity \[W/(m*K)\] :l {value1} = fluid specific heat capacity \[W*s/(kg*K)\] :l -{density} = name of the finite volume fluid density field :l -{interpolation} = (optional, normally off) flag to use interpolated voidfraction and fluid velocity values :l -{verbose} = (normally off) for verbose run :l +{switch1} = (optional, normally off) flag to use interpolated voidfraction and fluid velocity values :l +{switch2} = (normally off) for verbose run :l :ule [Examples:] @@ -53,13 +49,11 @@ LaEuScalarTempProps \{ velFieldName "U"; tempFieldName "T"; - tempSourceFieldName "Tsource"; voidfractionFieldName "voidfraction"; partTempName "Temp"; partHeatFluxName "convectiveHeatFlux"; lambda 0.0256; Cp 1007; - densityFieldName "rho"; \} :pre [Description:] @@ -68,7 +62,7 @@ This "forceModel" does not influence the particles or the fluid flow! Using the [Restrictions:] -Goes only with cfdemSolverScalar. +Goes only with cfdemSolverScalar. The force model has to be the second (!!!) model in the forces list. [Related commands:] diff --git a/doc/forceModel_MeiLift.html b/doc/forceModel_MeiLift.html index b1045e5..e21aa8b 100644 --- a/doc/forceModel_MeiLift.html +++ b/doc/forceModel_MeiLift.html @@ -20,21 +20,18 @@ MeiLiftProps { velFieldName "U"; - densityFieldName "density"; useSecondOrderTerms; - interpolation; - verbose; + interpolation "switch1"; + verbose "switch2"; };
        • U = name of the finite volume fluid velocity field -
        • density = name of the finite volume fluid density field -
        • useSecondOrderTerms = switch to activate second order terms in the lift force model -
        • interpolation = switch to activate tri-linear interpolation of the flow quantities at the particle position +
        • switch1 = switch to activate tri-linear interpolation of the flow quantities at the particle position -
        • verbose = switch to activate the report of per-particle quantities to the screen +
        • switch2 = switch to activate the report of per-particle quantities to the screen
        @@ -47,10 +44,9 @@ MeiLiftProps MeiLiftProps { velFieldName "U"; - densityFieldName "rho"; useSecondOrderTerms; - interpolation; - verbose; + interpolation true; + verbose true; }

        Description: diff --git a/doc/forceModel_MeiLift.txt b/doc/forceModel_MeiLift.txt index 4513065..205a597 100644 --- a/doc/forceModel_MeiLift.txt +++ b/doc/forceModel_MeiLift.txt @@ -18,17 +18,15 @@ forceModels MeiLiftProps \{ velFieldName "U"; - densityFieldName "density"; useSecondOrderTerms; - interpolation; - verbose; + interpolation "switch1"; + verbose "switch2"; \}; :pre {U} = name of the finite volume fluid velocity field :ulb,l -{density} = name of the finite volume fluid density field :l {useSecondOrderTerms} = switch to activate second order terms in the lift force model :l -{interpolation} = switch to activate tri-linear interpolation of the flow quantities at the particle position :l -{verbose} = switch to activate the report of per-particle quantities to the screen :l +{switch1} = switch to activate tri-linear interpolation of the flow quantities at the particle position :l +{switch2} = switch to activate the report of per-particle quantities to the screen :l :ule [Examples:] @@ -40,10 +38,9 @@ forceModels MeiLiftProps \{ velFieldName "U"; - densityFieldName "rho"; useSecondOrderTerms; - interpolation; - verbose; + interpolation true; + verbose true; \} :pre [Description:] diff --git a/doc/forceModel_SchillerNaumannDrag.html b/doc/forceModel_SchillerNaumannDrag.html index acd2fa3..7ff1eca 100644 --- a/doc/forceModel_SchillerNaumannDrag.html +++ b/doc/forceModel_SchillerNaumannDrag.html @@ -20,13 +20,10 @@ SchillerNaumannDragProps { velFieldName "U"; - densityFieldName "density"; };

        • U = name of the finite volume fluid velocity field -
        • density = name of the finite volume gravity field -

        Examples: @@ -38,7 +35,6 @@ SchillerNaumannDragProps SchillerNaumannDragProps { velFieldName "U"; - densityFieldName "rho"; }

        Description: diff --git a/doc/forceModel_SchillerNaumannDrag.txt b/doc/forceModel_SchillerNaumannDrag.txt index 4357264..aaa1c8a 100644 --- a/doc/forceModel_SchillerNaumannDrag.txt +++ b/doc/forceModel_SchillerNaumannDrag.txt @@ -18,11 +18,9 @@ forceModels SchillerNaumannDragProps \{ velFieldName "U"; - densityFieldName "density"; \}; :pre {U} = name of the finite volume fluid velocity field :ulb,l -{density} = name of the finite volume gravity field :l :ule [Examples:] @@ -34,7 +32,6 @@ forceModels SchillerNaumannDragProps \{ velFieldName "U"; - densityFieldName "rho"; \} :pre [Description:] diff --git a/doc/forceModel_ShirgaonkarIB.html b/doc/forceModel_ShirgaonkarIB.html index 5e198cf..27e0ddc 100644 --- a/doc/forceModel_ShirgaonkarIB.html +++ b/doc/forceModel_ShirgaonkarIB.html @@ -20,14 +20,11 @@ ShirgaonkarIBProps { velFieldName "U"; - densityFieldName "density"; pressureFieldName "pressure"; };

        • U = name of the finite volume fluid velocity field -
        • density = name of the finite volume density field -
        • pressure = name of the finite volume pressure field @@ -41,7 +38,6 @@ ShirgaonkarIBProps ShirgaonkarIBProps { velFieldName "U"; - densityFieldName "rho"; pressureFieldName "p"; } diff --git a/doc/forceModel_ShirgaonkarIB.txt b/doc/forceModel_ShirgaonkarIB.txt index 9f488cf..87cae6c 100644 --- a/doc/forceModel_ShirgaonkarIB.txt +++ b/doc/forceModel_ShirgaonkarIB.txt @@ -18,12 +18,10 @@ forceModels ShirgaonkarIBProps \{ velFieldName "U"; - densityFieldName "density"; pressureFieldName "pressure"; \}; :pre {U} = name of the finite volume fluid velocity field :ulb,l -{density} = name of the finite volume density field :l {pressure} = name of the finite volume pressure field :l :ule @@ -36,7 +34,6 @@ forceModels ShirgaonkarIBProps \{ velFieldName "U"; - densityFieldName "rho"; pressureFieldName "p"; \} :pre diff --git a/doc/forceModel_fieldStore.html b/doc/forceModel_fieldStore.html new file mode 100644 index 0000000..d21cbcb --- /dev/null +++ b/doc/forceModel_fieldStore.html @@ -0,0 +1,68 @@ + +
          CFDEMproject WWW Site - CFDEM Commands +
          + + + + +
          + +

          forceModel_fieldStore command +

          +

          Syntax: +

          +

          Defined in couplingProperties dictionary. +

          +
          forceModels
          +(
          +    fieldStore
          +);
          +fieldStoreProps
          +{
          +    scalarFieldNames
          +    (
          +        "scalarField"
          +    );
          +    vectorFieldNames
          +    (
          +        "vectorField"
          +    );
          +}; 
          +
          +
          • scalarField = names of the finite volume scalar fields to be stored + +
          • vectorField = names of the finite volume vector fields to be stored + + +
          +

          Examples: +

          +
          forceModels
          +(
          +    fieldStore
          +);
          +fieldStoreProps
          +{
          +    scalarFieldNames
          +    (
          +        "voidfraction"
          +    );
          +    vectorFieldNames
          +    (
          +        "U"
          +    );
          +} 
          +
          +

          Description: +

          +

          This "forceModel" does not influence the particles or the flow - it is a tool to store a scalar/vector field! This is especially useful if you use a boundary condition which cannot interpreted correctly in your postporcessor (e.g. paraview). +

          +

          Restrictions: +

          +

          none. +

          +

          Related commands: +

          +

          forceModel +

          + diff --git a/doc/forceModel_fieldStore.txt b/doc/forceModel_fieldStore.txt new file mode 100644 index 0000000..2e8af44 --- /dev/null +++ b/doc/forceModel_fieldStore.txt @@ -0,0 +1,63 @@ +"CFDEMproject WWW Site"_lws - "CFDEM Commands"_lc :c + +:link(lws,http://www.cfdem.com) +:link(lc,CFDEMcoupling_Manual.html#comm) + +:line + +forceModel_fieldStore command :h3 + +[Syntax:] + +Defined in couplingProperties dictionary. + +forceModels +( + fieldStore +); +fieldStoreProps +\{ + scalarFieldNames + ( + "scalarField" + ); + vectorFieldNames + ( + "vectorField" + ); +\}; :pre + +{scalarField} = names of the finite volume scalar fields to be stored :ulb,l +{vectorField} = names of the finite volume vector fields to be stored :l +:ule + +[Examples:] + +forceModels +( + fieldStore +); +fieldStoreProps +\{ + scalarFieldNames + ( + "voidfraction" + ); + vectorFieldNames + ( + "U" + ); +\} :pre + +[Description:] + +This "forceModel" does not influence the particles or the flow - it is a tool to store a scalar/vector field! This is especially useful if you use a boundary condition which cannot interpreted correctly in your postporcessor (e.g. paraview). + +[Restrictions:] + +none. + +[Related commands:] + +"forceModel"_forceModel.html + diff --git a/doc/forceModel_gradPForce.html b/doc/forceModel_gradPForce.html index f555313..661b4a0 100644 --- a/doc/forceModel_gradPForce.html +++ b/doc/forceModel_gradPForce.html @@ -20,18 +20,15 @@ gradPForceProps { pFieldName "pressure"; - densityFieldName "density"; velocityFieldName "U"; - interpolation; + interpolation switch1; };
          • pressure = name of the finite volume fluid pressure field -
          • density = name of the finite volume gravity field -
          • U = name of the finite volume fluid velocity field -
          • interpolation = flag to use interpolated pressure values (normally off) +
          • switch1 = flag to use interpolated pressure values (normally off)
          @@ -44,9 +41,8 @@ gradPForceProps gradPForceProps { pFieldName "p"; - densityFieldName "rho"; velocityFieldName "U"; - interpolation; + interpolation true; }

          Description: diff --git a/doc/forceModel_gradPForce.txt b/doc/forceModel_gradPForce.txt index 7a0801d..68a8b30 100644 --- a/doc/forceModel_gradPForce.txt +++ b/doc/forceModel_gradPForce.txt @@ -18,15 +18,13 @@ forceModels gradPForceProps \{ pFieldName "pressure"; - densityFieldName "density"; velocityFieldName "U"; - interpolation; + interpolation switch1; \}; :pre {pressure} = name of the finite volume fluid pressure field :ulb,l -{density} = name of the finite volume gravity field :l {U} = name of the finite volume fluid velocity field :l -{interpolation} = flag to use interpolated pressure values (normally off) :l +{switch1} = flag to use interpolated pressure values (normally off) :l :ule [Examples:] @@ -38,9 +36,8 @@ forceModels gradPForceProps \{ pFieldName "p"; - densityFieldName "rho"; velocityFieldName "U"; - interpolation; + interpolation true; \} :pre [Description:] diff --git a/doc/forceModel_virtualMassForce.html b/doc/forceModel_virtualMassForce.html index 98202c4..8c7499f 100644 --- a/doc/forceModel_virtualMassForce.html +++ b/doc/forceModel_virtualMassForce.html @@ -20,13 +20,10 @@ virtualMassForceProps { velFieldName "U"; - densityFieldName "density"; };

          • U = name of the finite volume fluid velocity field -
          • density = name of the finite volume fluid density field -

          Examples: @@ -38,7 +35,6 @@ virtualMassForceProps virtualMassForceProps { velFieldName "U"; - densityFieldName "rho"; }

          Description: diff --git a/doc/forceModel_virtualMassForce.txt b/doc/forceModel_virtualMassForce.txt index af55780..084371f 100644 --- a/doc/forceModel_virtualMassForce.txt +++ b/doc/forceModel_virtualMassForce.txt @@ -18,11 +18,9 @@ forceModels virtualMassForceProps \{ velFieldName "U"; - densityFieldName "density"; \}; :pre {U} = name of the finite volume fluid velocity field :ulb,l -{density} = name of the finite volume fluid density field :l :ule [Examples:] @@ -34,7 +32,6 @@ forceModels virtualMassForceProps \{ velFieldName "U"; - densityFieldName "rho"; \} :pre [Description:] diff --git a/doc/forceModel_viscForce.html b/doc/forceModel_viscForce.html index ebd76ec..cb233bf 100644 --- a/doc/forceModel_viscForce.html +++ b/doc/forceModel_viscForce.html @@ -20,15 +20,12 @@ viscForceProps { velocityFieldName "U"; - densityFieldName "density"; - interpolation; + interpolation "switch"; };

          • U = name of the finite volume fluid velocity field -
          • density = name of the finite volume gravity field - -
          • interpolation = flag to use interpolated stress values (normally off) +
          • switch = flag to use interpolated stress values (normally off)
          @@ -41,7 +38,6 @@ viscForceProps viscForceProps { velocityFieldName "U"; - densityFieldName "density"; }

          Description: diff --git a/doc/forceModel_viscForce.txt b/doc/forceModel_viscForce.txt index 8577846..6bcd3cb 100644 --- a/doc/forceModel_viscForce.txt +++ b/doc/forceModel_viscForce.txt @@ -18,13 +18,11 @@ forceModels viscForceProps \{ velocityFieldName "U"; - densityFieldName "density"; - interpolation; + interpolation "switch"; \}; :pre {U} = name of the finite volume fluid velocity field :ulb,l -{density} = name of the finite volume gravity field :l -{interpolation} = flag to use interpolated stress values (normally off) :l +{switch} = flag to use interpolated stress values (normally off) :l :ule [Examples:] @@ -36,7 +34,6 @@ forceModels viscForceProps \{ velocityFieldName "U"; - densityFieldName "density"; \} :pre [Description:] diff --git a/doc/forceSubModel.html b/doc/forceSubModel.html new file mode 100644 index 0000000..090c1c9 --- /dev/null +++ b/doc/forceSubModel.html @@ -0,0 +1,49 @@ + +

          CFDEMproject WWW Site - CFDEM Commands +
          + + + + +
          + +

          forceSubModel command +

          +

          Syntax: +

          +

          Defined in couplingProperties sub-dictionary of the force model in use. If no force sub-model is applied ImEx is used as default. If the keyword "forceSubModels" is provided, a choice of sub model is demanded. +

          +
          forceSubModels
          +(
          +    model_x
          +    model_y
          +); 
          +
          +
          • model = name of force sub-model to be applied +
          +

          Examples: +

          +
          forceSubModels
          +(
          +    ImEx
          +); 
          +
          +

          Note: This examples list might not be complete - please look for other models (forceSubModel_XY) in this documentation. +

          +

          Description: +

          +

          The force sub model is designed to hold the settings a force model can have. For now it handles the treatExplicit, treatDEM and implDEM option. +

          +

          Restrictions: +

          +

          None. +

          +

          Related commands: +

          +

          ImEx +

          +

          Note: This examples list may be incomplete - please look for other models (forceSubModel_XY) in this documentation. +

          +

          Default: none. +

          + diff --git a/doc/forceSubModel.txt b/doc/forceSubModel.txt new file mode 100644 index 0000000..8d150a9 --- /dev/null +++ b/doc/forceSubModel.txt @@ -0,0 +1,45 @@ +"CFDEMproject WWW Site"_lws - "CFDEM Commands"_lc :c + +:link(lws,http://www.cfdem.com) +:link(lc,CFDEMcoupling_Manual.html#comm) + +:line + +forceSubModel command :h3 + +[Syntax:] + +Defined in couplingProperties sub-dictionary of the force model in use. If no force sub-model is applied ImEx is used as default. If the keyword "forceSubModels" is provided, a choice of sub model is demanded. + +forceSubModels +( + model_x + model_y +); :pre + +model = name of force sub-model to be applied :ul + +[Examples:] + +forceSubModels +( + ImEx +); :pre + +Note: This examples list might not be complete - please look for other models (forceSubModel_XY) in this documentation. + +[Description:] + +The force sub model is designed to hold the settings a force model can have. For now it handles the treatExplicit, treatDEM and implDEM option. + +[Restrictions:] + +None. + +[Related commands:] + +"ImEx"_forceSubModel_ImEx.html + +Note: This examples list may be incomplete - please look for other models (forceSubModel_XY) in this documentation. + +[Default:] none. diff --git a/doc/forceSubModel_ImEx.html b/doc/forceSubModel_ImEx.html new file mode 100644 index 0000000..43b92d4 --- /dev/null +++ b/doc/forceSubModel_ImEx.html @@ -0,0 +1,45 @@ + +
          CFDEMproject WWW Site - CFDEM Commands +
          + + + + +
          + +

          forceSubModel_ImEx command +

          +

          Syntax: +

          +

          Defined in couplingProperties sub-dictionary of the force model in use. +

          +

          forceSubModels +( + ImEx; +); +

          +

          treatExplicit true; // optional for some force models. +treatDEM true; // optional for some force models. +implDEM true; // optional for some force models. +

          +

          Examples: +

          +

          forceSubModels +( + ImEx; +); +treatExplicit true; // optional for some force models. +

          +

          Description: +

          +

          If no force sub-model is applied ImEx is used as default. If the keyword "forceSubModels" is provided, a choice of sub model is demanded. Depending on the force model different keywords are read and can therefrore be set (see the log file). If the keyword is provided, its value is used. +

          +

          Restrictions: +

          +

          none. +

          +

          Related commands: +

          +

          forceSubModel +

          + diff --git a/doc/forceSubModel_ImEx.txt b/doc/forceSubModel_ImEx.txt new file mode 100644 index 0000000..e81f55e --- /dev/null +++ b/doc/forceSubModel_ImEx.txt @@ -0,0 +1,42 @@ +"CFDEMproject WWW Site"_lws - "CFDEM Commands"_lc :c + +:link(lws,http://www.cfdem.com) +:link(lc,CFDEMcoupling_Manual.html#comm) + +:line + +forceSubModel_ImEx command :h3 + +[Syntax:] + +Defined in couplingProperties sub-dictionary of the force model in use. + +forceSubModels +( + ImEx; +); + +treatExplicit true; // optional for some force models. +treatDEM true; // optional for some force models. +implDEM true; // optional for some force models. + +[Examples:] + +forceSubModels +( + ImEx; +); +treatExplicit true; // optional for some force models. + +[Description:] + + If no force sub-model is applied ImEx is used as default. If the keyword "forceSubModels" is provided, a choice of sub model is demanded. Depending on the force model different keywords are read and can therefrore be set (see the log file). If the keyword is provided, its value is used. + +[Restrictions:] + +none. + +[Related commands:] + +"forceSubModel"_forceSubModel.html + diff --git a/doc/forceSubModel_ImExCorr.html b/doc/forceSubModel_ImExCorr.html new file mode 100644 index 0000000..a593c81 --- /dev/null +++ b/doc/forceSubModel_ImExCorr.html @@ -0,0 +1,46 @@ + +
          CFDEMproject WWW Site - CFDEM Commands +
          + + + + +
          + +

          forceSubModel_ImExCorr command +

          +

          Syntax: +

          +

          Defined in couplingProperties sub-dictionary of the force model in use. +

          +

          forceSubModels +( + ImExCorr; +); +

          +

          treatExplicit true; // optional for some force models. +treatDEM true; // optional for some force models. +implDEM true; // optional for some force models. +explicitCorr true; // optional for some force models. +

          +

          Examples: +

          +

          forceSubModels +( + ImExCorr; +); +treatExplicit true; // optional for some force models. +

          +

          Description: +

          +

          Same as ImEx, but it additionally reads "explicitCorr" to correct the error steming from interpolation of Ufluid and averaging of Uparticles. +

          +

          Restrictions: +

          +

          none. +

          +

          Related commands: +

          +

          forceSubModel +

          + diff --git a/doc/forceSubModel_ImExCorr.txt b/doc/forceSubModel_ImExCorr.txt new file mode 100644 index 0000000..4913551 --- /dev/null +++ b/doc/forceSubModel_ImExCorr.txt @@ -0,0 +1,43 @@ +"CFDEMproject WWW Site"_lws - "CFDEM Commands"_lc :c + +:link(lws,http://www.cfdem.com) +:link(lc,CFDEMcoupling_Manual.html#comm) + +:line + +forceSubModel_ImExCorr command :h3 + +[Syntax:] + +Defined in couplingProperties sub-dictionary of the force model in use. + +forceSubModels +( + ImExCorr; +); + +treatExplicit true; // optional for some force models. +treatDEM true; // optional for some force models. +implDEM true; // optional for some force models. +explicitCorr true; // optional for some force models. + +[Examples:] + +forceSubModels +( + ImExCorr; +); +treatExplicit true; // optional for some force models. + +[Description:] + + Same as ImEx, but it additionally reads "explicitCorr" to correct the error steming from interpolation of Ufluid and averaging of Uparticles. + +[Restrictions:] + +none. + +[Related commands:] + +"forceSubModel"_forceSubModel.html + diff --git a/doc/githubAccess_public.pdf b/doc/githubAccess_public.pdf index f184f26d465a77e71bbb50c16ff6b701f8916bb6..8cd384fd46e6947f7feba02ce06963ae4b2938ad 100644 GIT binary patch delta 114 zcmew}QS8q|u?ekwrUphvriK=#Mn-1328NB3TPHKNPG)MI%-lMeW$R>C?hdE4L^E?s p%fu7|Gs6_q#3WNQvlLSU%T!B4vos?kBNJmg8$v3kKj>hU0RSItB02y7 delta 114 zcmew}QS8q|u?ekwCI)7PMn;B4CI$w&21bpOTPHKNPG)MI%-lMeW$R>C?hdCEljM{% pqcn39gH%(q#N=c{<5Wu{bAx1a^Hg)=RD%>d8$v3kKj>hU0RT&DBcA{O diff --git a/doc/liggghtsCommandModel_writeLiggghts.html b/doc/liggghtsCommandModel_writeLiggghts.html index 3a96aaf..00e06cc 100644 --- a/doc/liggghtsCommandModel_writeLiggghts.html +++ b/doc/liggghtsCommandModel_writeLiggghts.html @@ -21,18 +21,20 @@ writeLiggghtsProps { writeLast switch1; + path "path"; writeName "name"; overwrite switch2; verbose; } -
          • switch1 = switch (choose on/off) to select if only last step is stored or every write step. +
            • switch1 = switch (choose on/off) to select if only last step is stored or every write step (default on). -
            • name = name of the restart file to be written in /$caseDir/DEM/ default default "liggghts.restartCFDEM" +
            • path = optionally an alternative path for saving the restart file can be defined (default "../DEM"). -
            • switch2 = switch (choose on/off) to select if only one restart file $name or many files $name_$timeStamp are written +
            • name = name of the restart file to be written in /$caseDir/DEM/ default (default "liggghts.restartCFDEM") -
            • verbose = (normally off) for verbose run +
            • switch2 = switch (choose on/off) to select if only one restart file $name or many files $name_$timeStamp are written (default off):l +verbose = (default off) for verbose run
            diff --git a/doc/liggghtsCommandModel_writeLiggghts.txt b/doc/liggghtsCommandModel_writeLiggghts.txt index 77f4f46..ede5e12 100644 --- a/doc/liggghtsCommandModel_writeLiggghts.txt +++ b/doc/liggghtsCommandModel_writeLiggghts.txt @@ -19,15 +19,17 @@ liggghtsCommandModels writeLiggghtsProps \{ writeLast switch1; + path "path"; writeName "name"; overwrite switch2; verbose; \} :pre -{switch1} = switch (choose on/off) to select if only last step is stored or every write step. :ulb,l -{name} = name of the restart file to be written in /$caseDir/DEM/ default default "liggghts.restartCFDEM" :l -{switch2} = switch (choose on/off) to select if only one restart file $name or many files $name_$timeStamp are written :l -{verbose} = (normally off) for verbose run :l +{switch1} = switch (choose on/off) to select if only last step is stored or every write step (default on). :ulb,l +{path} = optionally an alternative path for saving the restart file can be defined (default "../DEM"). :l +{name} = name of the restart file to be written in /$caseDir/DEM/ default (default "liggghts.restartCFDEM") :l +{switch2} = switch (choose on/off) to select if only one restart file $name or many files $name_$timeStamp are written (default off):l +{verbose} = (default off) for verbose run :l :ule [Examples:] diff --git a/doc/momCoupleModel.html b/doc/momCoupleModel.html index 2acae6a..3a37c23 100644 --- a/doc/momCoupleModel.html +++ b/doc/momCoupleModel.html @@ -33,7 +33,8 @@

            Note that the variable "imExSplitFactor" can be set in the couplingProperties in order to treat implicitly defined forces (in the implementation of the force model) as explicit ones. "imExSplitFactor 1.0;" is set by default, meaning that all implicit forces will be considered implicitly, whereas "imExSplitFactor 0.0;" would mean that implicitly defined forces will be treated in an explicit fashion.

            -

            Description: +

            Note that the switch "treatVoidCellsAsExplicitForce true;" can be set in the couplingProperties in order to change the treatment of cells which are void of particles. This is only relevant if (i) smoothing is used, and (ii) implicit force coupling is performed. By default, the particle veloctiy field (Us) will be smoothed to obtain a meaningful reference quantity for the implicit force coupling. In case "treatVoidCellsAsExplicitForce true;" is set, however, Us will not be smoothed and implicit forces (after the smoothing has been performed) in cells void of particles be treated as explicit ones. This avoids the problem of defining Us in cells that are void of particles, but for which an implicit coupling force is obtained in the smoothing process. +Description:

            The momCoupleModel is the base class for momentum exchange between DEM and CFD simulation.

            diff --git a/doc/momCoupleModel.txt b/doc/momCoupleModel.txt index 05db72e..0a7dbf2 100644 --- a/doc/momCoupleModel.txt +++ b/doc/momCoupleModel.txt @@ -31,6 +31,7 @@ Forces can be coupled in an implicit way to the fluid solver (i.e., when solving Note that the variable "imExSplitFactor" can be set in the couplingProperties in order to treat implicitly defined forces (in the implementation of the force model) as explicit ones. "imExSplitFactor 1.0;" is set by default, meaning that all implicit forces will be considered implicitly, whereas "imExSplitFactor 0.0;" would mean that implicitly defined forces will be treated in an explicit fashion. +Note that the switch "treatVoidCellsAsExplicitForce true;" can be set in the couplingProperties in order to change the treatment of cells which are void of particles. This is only relevant if (i) smoothing is used, and (ii) implicit force coupling is performed. By default, the particle veloctiy field (Us) will be smoothed to obtain a meaningful reference quantity for the implicit force coupling. In case "treatVoidCellsAsExplicitForce true;" is set, however, Us will not be smoothed and implicit forces (after the smoothing has been performed) in cells void of particles be treated as explicit ones. This avoids the problem of defining Us in cells that are void of particles, but for which an implicit coupling force is obtained in the smoothing process. [Description:] The momCoupleModel is the base class for momentum exchange between DEM and CFD simulation. diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..4459954 --- /dev/null +++ b/src/.gitignore @@ -0,0 +1,7 @@ +*.o +*.d +*.a +*.dep +log_* +log.* +*~ diff --git a/src/lagrangian/cfdemParticle/cfdTools/checkModelType.H b/src/lagrangian/cfdemParticle/cfdTools/checkModelType.H index 9a6ddf5..a91bb78 100644 --- a/src/lagrangian/cfdemParticle/cfdTools/checkModelType.H +++ b/src/lagrangian/cfdemParticle/cfdTools/checkModelType.H @@ -4,8 +4,7 @@ word modelType = particleCloud.modelType(); //Warning << "model type not being checked" << endl; - - if (modelType=="B"){ + if (modelType=="Bfull"){ Info << "solving volume averaged Navier Stokes equations of type B\n"<< endl; // check if Archimedes is used @@ -18,6 +17,41 @@ if(!found) FatalError <<"Archimedes model not found!\n" << abort(FatalError); + // check if gradPForce is used + found=false; + forAll(particleCloud.forceModels(),i) + { + if(particleCloud.forceModels()[i]=="gradPForce") + found=true; + } + if(!found) + FatalError <<"gradPForce model not found!\n" << abort(FatalError); + + // check if viscForce is used + found=false; + forAll(particleCloud.forceModels(),i) + { + if(particleCloud.forceModels()[i]=="viscForce") + found=true; + } + if(!found) + FatalError <<"viscForce model not found!\n" << abort(FatalError); + + }else if(modelType=="B"){ + Info << "solving volume averaged Navier Stokes equations of type B\n"<< endl; + + // check if Archimedes is used + bool found=false; + forAll(particleCloud.forceModels(),i) + { + if(particleCloud.forceModels()[i]=="Archimedes") + found=true; + } + if(!found) + FatalError <<"Archimedes model not found!\n" << abort(FatalError); + + + // check if gradP and viscForce are used found=false; forAll(particleCloud.forceModels(),i) diff --git a/src/lagrangian/cfdemParticle/cfdTools/compressibleContinuityErrsPU.H b/src/lagrangian/cfdemParticle/cfdTools/compressibleContinuityErrsPU.H new file mode 100644 index 0000000..67d0f08 --- /dev/null +++ b/src/lagrangian/cfdemParticle/cfdTools/compressibleContinuityErrsPU.H @@ -0,0 +1,53 @@ +/*---------------------------------------------------------------------------*\ + CFDEMcoupling - Open Source CFD-DEM coupling + + CFDEMcoupling is part of the CFDEMproject + www.cfdem.com + Christoph Goniva, christoph.goniva@cfdem.com + Copyright (C) 1991-2009 OpenCFD Ltd. + Copyright (C) 2009-2012 JKU, Linz + Copyright (C) 2012- DCS Computing GmbH,Linz +------------------------------------------------------------------------------- +License + This file is part of CFDEMcoupling. + + CFDEMcoupling is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + CFDEMcoupling 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. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with CFDEMcoupling. If not, see . + +Global + continuityErrs + +Description + Calculates and prints the continuity errors. + The code is an evolution of compressibleContinuityErrs.H in OpenFOAM(R) 2.3.x, + where additional functionality for CFD-DEM coupling is added. +\*---------------------------------------------------------------------------*/ + +{ + dimensionedScalar totalMass = fvc::domainIntegrate(rho*voidfraction); + + scalar sumLocalContErr = + (fvc::domainIntegrate(mag(rho - thermo.rho())*voidfraction)/totalMass).value(); + + scalar globalContErr = + (fvc::domainIntegrate((rho - thermo.rho())*voidfraction)/totalMass).value(); + + cumulativeContErr += globalContErr; + + Info<< "time step continuity errors : sum local = " << sumLocalContErr + << ", global = " << globalContErr + << ", cumulative = " << cumulativeContErr + << endl; +} + +// ************************************************************************* // diff --git a/src/lagrangian/cfdemParticle/cfdTools/global.C b/src/lagrangian/cfdemParticle/cfdTools/global.C new file mode 100644 index 0000000..1e97aec --- /dev/null +++ b/src/lagrangian/cfdemParticle/cfdTools/global.C @@ -0,0 +1,80 @@ +/*---------------------------------------------------------------------------*\ + CFDEMcoupling - Open Source CFD-DEM coupling + + CFDEMcoupling is part of the CFDEMproject + www.cfdem.com + Christoph Goniva, christoph.goniva@cfdem.com + Copyright 2009-2012 JKU Linz + Copyright 2012- DCS Computing GmbH, Linz +------------------------------------------------------------------------------- +License + This file is part of CFDEMcoupling. + + CFDEMcoupling is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3 of the License, or (at your + option) any later version. + + CFDEMcoupling 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. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with CFDEMcoupling; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Description + This code is designed to realize coupled CFD-DEM simulations using LIGGGHTS + and OpenFOAM(R). Note: this code is not part of OpenFOAM(R) (see DISCLAIMER). +\*---------------------------------------------------------------------------*/ + +#include "error.H" +#include "global.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +defineTypeNameAndDebug(global, 0); + +defineRunTimeSelectionTable(global, dictionary); + +// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // +void global::info() +{ + Info << "\nYou are currently using:" << endl; + Info << "OF version: " << FOAMversion << endl; + Info << "OF build: " << FOAMbuild << endl; + Info << "CFDEM build: " << CFDEMversion << "\n" << endl; +} + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +// Construct from components +global::global +( + const dictionary& dict, + cfdemCloud& sm +) +: + dict_(dict), + particleCloud_(sm), + CFDEMversion(GITVERSION) +{} + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // + +global::~global() +{} + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// ************************************************************************* // diff --git a/src/lagrangian/cfdemParticle/cfdTools/global.H b/src/lagrangian/cfdemParticle/cfdTools/global.H new file mode 100644 index 0000000..afaaf44 --- /dev/null +++ b/src/lagrangian/cfdemParticle/cfdTools/global.H @@ -0,0 +1,128 @@ +/*---------------------------------------------------------------------------*\ + CFDEMcoupling - Open Source CFD-DEM coupling + + CFDEMcoupling is part of the CFDEMproject + www.cfdem.com + Christoph Goniva, christoph.goniva@cfdem.com + Copyright 2009-2012 JKU Linz + Copyright 2012- DCS Computing GmbH, Linz +------------------------------------------------------------------------------- +License + This file is part of CFDEMcoupling. + + CFDEMcoupling is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3 of the License, or (at your + option) any later version. + + CFDEMcoupling 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. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with CFDEMcoupling; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Description + This code is designed to realize coupled CFD-DEM simulations using LIGGGHTS + and OpenFOAM(R). Note: this code is not part of OpenFOAM(R) (see DISCLAIMER). + +Class + global + +SourceFiles + global.Cver + +\*---------------------------------------------------------------------------*/ + +#ifndef global_H +#define global_H + +#include "fvCFD.H" +#include "cfdemCloud.H" +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class global Declaration +\*---------------------------------------------------------------------------*/ + +class global +{ + +protected: + + // Protected data + const dictionary& dict_; + + cfdemCloud& particleCloud_; + + const char* const CFDEMversion; + + + // Protected member functions + +public: + + //- Runtime type information + TypeName("global"); + + // Declare runtime constructor selection table + + declareRunTimeSelectionTable + ( + autoPtr, + global, + dictionary, + ( + const dictionary& dict, + cfdemCloud& sm + ), + (dict,sm) + ); + + + // Constructors + + //- Construct from components + global + ( + const dictionary& dict, + cfdemCloud& sm + ); + + + // Destructor + + virtual ~global(); + + + // Selector + + static autoPtr New + ( + const dictionary& dict, + cfdemCloud& sm + ); + + // Member Function + + void info(); + + // Access + +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/lagrangian/cfdemParticle/cfdTools/mathExtra.H b/src/lagrangian/cfdemParticle/cfdTools/mathExtra.H new file mode 100644 index 0000000..a7c6067 --- /dev/null +++ b/src/lagrangian/cfdemParticle/cfdTools/mathExtra.H @@ -0,0 +1,265 @@ +/* ---------------------------------------------------------------------- + CFDEMcoupling - Open Source CFD-DEM coupling + + CFDEMcoupling is part of the CFDEMproject + www.cfdem.com + Christoph Goniva, christoph.goniva@cfdem.com + Copyright 2009-2012 JKU Linz + Copyright 2012- DCS Computing GmbH, Linz +------------------------------------------------------------------------------- +License + This file is part of CFDEMcoupling. + + CFDEMcoupling is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3 of the License, or (at your + option) any later version. + + CFDEMcoupling 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. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with CFDEMcoupling; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Description + This code is designed to realize coupled CFD-DEM simulations using LIGGGHTS + and OpenFOAM(R). Note: this code is not part of OpenFOAM(R) (see DISCLAIMER). + + Copyright of this contribution: + Copyright 2014- TU Graz, IPPT +------------------------------------------------------------------------- */ + +#ifndef CFDEM_MATH_EXTRA_H +#define CFDEM_MATH_EXTRA_H + +#include +//#include "math.h" +#include "stdio.h" +#include "string.h" +#include "error.h" +#include "ctype.h" + +#define TOLERANCE_ORTHO 1e-10 + +namespace MathExtra +{ + +// inline void outerProduct(double *vec1, double *vec2, double **m); +// inline double spheroidGeometry(int index, double bi, double ai); + + + +//-------------------------------------------------------------------- +// Outer Product of two vectors +inline void outerProduct(double *vec1, double *vec2, double **m) +{ + int i, j; + //debug output + for( i = 0; i < 3; ++i ) +// printf("OUTER PRODUCT: Input: vec1 element %d = %g", i, vec1[i]); + for( i = 0; i < 3; ++i ) +// printf("OUTER PRODUCT: Input: vec2 element %d=%g", i, vec2[i]); + + //calculation + for( i = 0; i < 3; ++i ) + for( j = 0; j < 3; ++j ) + { + m[i][j] = vec1[i] * vec2[j]; + printf("OUTER PRODUCT: Result: m[%d][%d]=%g", i, j, m[i][j]); + } + + +} +//-------------------------------------------------------------------- +// Compute the major, minor axis and eccentricity parameters of a prolate spheroid +inline bool spheroidGeometry(double radius, double aspectRatio, //inputs + double& ai, double& bi, //outputs + double& ei, double& Le //outputs + ) // +{ + //INPUT + // radius ...volume-equivalent radius of the spheroid + // aspectRatio ...major/minor aspect ratio + + //OUTPUT + // ai ... + // bi ... + // ei ... + // Le ... + + if(radius<=0.0) //avoid troubles in case radius is 0 or negative + return false; + + ai = radius * std::pow(aspectRatio*aspectRatio,0.33333333333333333333333); + bi = ai / aspectRatio; + ei = std::sqrt( + 1.0 + - 1.0 / (aspectRatio*aspectRatio) + ); + Le = std::log( + (1.0+ei) + /(1.0-ei) + ); + + return true; +} + +//-------------------------------------------------------------------- +// Compute the major, minor axis and eccentricity parameters of a prolate spheroid +inline double Pi() +{ + return 3.1415926535897932384626433832795; +} + + +//-------------------------------------------------------------------- +// Compute the major, minor axis and eccentricity parameters of a prolate spheroid +inline bool spheroidGeometry2(double radius, double aspectRatio, //inputs + double& ai, double& bi, //outputs + double& XAe, double& YAe, //outputs + double& XCe, double& YCe, //outputs + double& YHe + ) // +{ + //INPUT + // radius ...volume-equivalent radius of the spheroid + // aspectRatio ...major/minor aspect ratio + + //OUTPUT + // XAe ...Eccentricity dependet parameter + // YAe ...Eccentricity dependet parameter + // XCe ...Eccentricity dependet parameter + // XCe ...Eccentricity dependet parameter + // YCe ...Eccentricity dependet parameter + // YHe ...Eccentricity dependet parameter + + + double ei(0.0), Le(0.0); + bool result = + spheroidGeometry(radius, aspectRatio, //inputs + ai, bi, //outputs + ei, Le //outputs + ); + if(!result) + return false; + + XAe= 2.6666666666666666666666667 + *ei*ei*ei + /(-2.0*ei+(1.0+ei*ei)*Le); + YAe= 5.333333333333333333333333333 + *ei*ei*ei + /(2.0*ei+(3*ei*ei-1.0)*Le); + XCe= 1.333333333333333333333333333 + *ei*ei*ei + *(1.0-ei*ei) + /(2.0*ei-(1.0-ei*ei)*Le); + YCe= 1.3333333333333333333333 + *ei*ei*ei + *(2.0-ei*ei) + /(-2.0*ei+(1.0+ei*ei)*Le); + YHe= 1.3333333333333333333333 + *ei*ei*ei*ei*ei + /(-2.0*ei+(1.0+ei*ei)*Le); + + return true; + +} + +//-------------------------------------------------------------------- +// zeroize a 3x3x3 tensor +inline void zeroize333(double tensor[3][3][3] ) +{ + for(int iX=0; iX<3; iX++) + for(int iY=0; iY<3; iY++) + for(int iZ=0; iZ<3; iZ++) + tensor[iX][iY][iZ] = 0.0; +} + +//-------------------------------------------------------------------- +// zeroize a 3x3 tensor +inline void zeroize33(double tensor[3][3] ) +{ + for(int iX=0; iX<3; iX++) + for(int iY=0; iY<3; iY++) + tensor[iX][iY] = 0.0; +} + +//-------------------------------------------------------------------- +// multiply a 3x3x3 tensor with a scalar +inline void multiply333(double scalar, double tensor[3][3][3] ) +{ + for(int iX=0; iX<3; iX++) + for(int iY=0; iY<3; iY++) + for(int iZ=0; iZ<3; iZ++) + tensor[iX][iY][iZ] *= scalar; +} +//-------------------------------------------------------------------- +// Compute a dot and dyadic product of with a vector +inline void permutationTensor(double tensor[3][3][3] ) +{ + zeroize333(tensor); + tensor[0][1][2] = 1.0; + tensor[1][2][0] = 1.0; + tensor[2][0][1] = 1.0; + tensor[0][2][1] =-1.0; + tensor[2][1][0] =-1.0; + tensor[1][0][2] =-1.0; +} + + + +//-------------------------------------------------------------------- +// Compute a dot product of the permutation tensor and +// then a dyadic product of with a vector +inline bool permutationDotDyadic( + double vector[3], + double tensor[3][3][3] + ) +{ + //Generate permutation tensor + double permutationT[3][3][3]; + permutationTensor(permutationT); + + //Step 1: compute dot prodcut of permutation tensor + double permutationDotProd[3][3]; + zeroize33(permutationDotProd); + + for(int iX=0; iX<3; iX++) + for(int iY=0; iY<3; iY++) + for(int iZ=0; iZ<3; iZ++) + permutationDotProd[iX][iY] += permutationT[iX][iY][iZ] + * vector[iZ]; + + for(int iX=0; iX<3; iX++) + for(int iY=0; iY<3; iY++) + for(int iZ=0; iZ<3; iZ++) + tensor[iX][iY][iZ] = permutationDotProd[iX][iY] + * vector[iZ]; + return true; + +} + +//-------------------------------------------------------------------- +// Compute a dot and dyadic product of with a vector +inline bool doubleDotTensor333Tensor33(double tensor333[3][3][3], + double tensor33[3][3], + double result[3] + ) +{ + result[0]=0.0;result[1]=0.0;result[2]=0.0; + + for(int iX=0; iX<3; iX++) + for(int iY=0; iY<3; iY++) + for(int iZ=0; iZ<3; iZ++) + result[iX] += tensor333[iX][iY][iZ] * tensor33[iY][iZ]; + + return true; +} + + +}; //end of namespace + +#endif diff --git a/src/lagrangian/cfdemParticle/cfdTools/newGlobal.C b/src/lagrangian/cfdemParticle/cfdTools/newGlobal.C new file mode 100644 index 0000000..73c4eac --- /dev/null +++ b/src/lagrangian/cfdemParticle/cfdTools/newGlobal.C @@ -0,0 +1,84 @@ +/*---------------------------------------------------------------------------*\ + CFDEMcoupling - Open Source CFD-DEM coupling + + CFDEMcoupling is part of the CFDEMproject + www.cfdem.com + Christoph Goniva, christoph.goniva@cfdem.com + Copyright 2009-2012 JKU Linz + Copyright 2012- DCS Computing GmbH, Linz +------------------------------------------------------------------------------- +License + This file is part of CFDEMcoupling. + + CFDEMcoupling is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3 of the License, or (at your + option) any later version. + + CFDEMcoupling 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. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with CFDEMcoupling; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Description + This code is designed to realize coupled CFD-DEM simulations using LIGGGHTS + and OpenFOAM(R). Note: this code is not part of OpenFOAM(R) (see DISCLAIMER). +\*---------------------------------------------------------------------------*/ + +#include "error.H" + +#include "global.H" +#include "dilute.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +autoPtr global::New +( + const dictionary& dict, + cfdemCloud& sm +) +{ + word globalType + ( + dict.lookup("global") + ); + + Info<< "Selecting global " + << globalType << endl; + + + dictionaryConstructorTable::iterator cstrIter = + dictionaryConstructorTablePtr_->find(globalType); + + if (cstrIter == dictionaryConstructorTablePtr_->end()) + { + FatalError + << "global::New(const dictionary&, const spray&) : " + << endl + << " unknown globalType type " + << globalType + << ", constructor not in hash table" << endl << endl + << " Valid global types are :" + << endl; + Info<< dictionaryConstructorTablePtr_->toc() + << abort(FatalError); + } + + return autoPtr(cstrIter()(dict,sm)); +} + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// ************************************************************************* // diff --git a/src/lagrangian/cfdemParticle/cfdTools/versionInfo.H b/src/lagrangian/cfdemParticle/cfdTools/versionInfo.H index 4fbc1be..f4bfe4a 100755 --- a/src/lagrangian/cfdemParticle/cfdTools/versionInfo.H +++ b/src/lagrangian/cfdemParticle/cfdTools/versionInfo.H @@ -1,9 +1,44 @@ -word CFDEMversion="cfdem-2.7.1"; -word compatibleLIGGGHTSversion="3.0.2"; +/*---------------------------------------------------------------------------*\ + CFDEMcoupling - Open Source CFD-DEM coupling + + CFDEMcoupling is part of the CFDEMproject + www.cfdem.com + Christoph Goniva, christoph.goniva@cfdem.com + Copyright 2009-2012 JKU Linz + Copyright 2012- DCS Computing GmbH, Linz +------------------------------------------------------------------------------- +License + This file is part of CFDEMcoupling. + + CFDEMcoupling is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3 of the License, or (at your + option) any later version. + + CFDEMcoupling 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. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with CFDEMcoupling; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Description + This code is designed to realize coupled CFD-DEM simulations using LIGGGHTS + and OpenFOAM(R). Note: this code is not part of OpenFOAM(R) (see DISCLAIMER). + +\*---------------------------------------------------------------------------*/ + +#ifndef versionInfo_H +#define versionInfo_H + +word CFDEMversion="cfdem-2.9.0"; +word compatibleLIGGGHTSversion="3.1.0"; word OFversion="2.3.x-commit-4d6f4a3115ff76ec4154c580eb041bc95ba4ec09"; -Info << "\nCFDEMcoupling version: " << CFDEMversion << "\n" << endl; -Info << "\n, compatible to LIGGGHTS version: " << compatibleLIGGGHTSversion << "\n" << endl; -Info << "\n, compatible to OF version: " << OFversion << "\n" << endl; - +Info << "\nCFDEMcoupling version: " << CFDEMversion << endl; +Info << ", compatible to LIGGGHTS version: " << compatibleLIGGGHTSversion << endl; +Info << ", compatible to OF version and build: " << OFversion << endl; +#endif diff --git a/src/lagrangian/cfdemParticle/cfdemCloud/cfdemCloud.C b/src/lagrangian/cfdemParticle/cfdemCloud/cfdemCloud.C index a56df91..4820d62 100644 --- a/src/lagrangian/cfdemParticle/cfdemCloud/cfdemCloud.C +++ b/src/lagrangian/cfdemParticle/cfdemCloud/cfdemCloud.C @@ -31,6 +31,7 @@ Description #include "fileName.H" #include "cfdemCloud.H" +#include "global.H" #include "forceModel.H" #include "locateModel.H" #include "momCoupleModel.H" @@ -80,6 +81,7 @@ Foam::cfdemCloud::cfdemCloud positions_(NULL), velocities_(NULL), fluidVel_(NULL), + fAcc_(NULL), impForces_(NULL), expForces_(NULL), DEMForces_(NULL), @@ -89,7 +91,9 @@ Foam::cfdemCloud::cfdemCloud cellIDs_(NULL), particleWeights_(NULL), particleVolumes_(NULL), + particleV_(NULL), numberOfParticles_(0), + d32_(-1), numberOfParticlesChanged_(false), arraysReallocated_(false), forceModels_(couplingProperties_.lookup("forceModels")), @@ -99,7 +103,9 @@ Foam::cfdemCloud::cfdemCloud cg_(1.), cgOK_(true), impDEMdrag_(false), + impDEMdragAcc_(false), imExSplitFactor_(1.0), + treatVoidCellsAsExplicitForce_(false), useDDTvoidfraction_(false), ddtVoidfraction_ ( @@ -117,7 +123,7 @@ Foam::cfdemCloud::cfdemCloud turbulence_ ( #if defined(version21) || defined(version16ext) - #ifdef comp + #ifdef compre mesh.lookupObject #else mesh.lookupObject @@ -213,12 +219,16 @@ Foam::cfdemCloud::cfdemCloud ) { #include "versionInfo.H" + global buildInfo(couplingProperties_,*this); + buildInfo.info(); Info << "If BC are important, please provide volScalarFields -imp/expParticleForces-" << endl; if (couplingProperties_.found("solveFlow")) solveFlow_=Switch(couplingProperties_.lookup("solveFlow")); if (couplingProperties_.found("imExSplitFactor")) imExSplitFactor_ = readScalar(couplingProperties_.lookup("imExSplitFactor")); + if (couplingProperties_.found("treatVoidCellsAsExplicitForce")) + treatVoidCellsAsExplicitForce_ = readBool(couplingProperties_.lookup("treatVoidCellsAsExplicitForce")); if (couplingProperties_.found("verbose")) verbose_=true; if (couplingProperties_.found("ignore")) ignore_=true; if (turbulenceModelType_=="LESProperties") @@ -276,6 +286,7 @@ Foam::cfdemCloud::~cfdemCloud() 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); @@ -285,6 +296,7 @@ Foam::cfdemCloud::~cfdemCloud() dataExchangeM().destroy(cellIDs_,1); dataExchangeM().destroy(particleWeights_,1); dataExchangeM().destroy(particleVolumes_,1); + dataExchangeM().destroy(particleV_,1); } // * * * * * * * * * * * * * * * private Member Functions * * * * * * * * * * * * * // void Foam::cfdemCloud::getDEMdata() @@ -292,6 +304,9 @@ void Foam::cfdemCloud::getDEMdata() 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 } void Foam::cfdemCloud::giveDEMdata() @@ -302,6 +317,7 @@ void Foam::cfdemCloud::giveDEMdata() if(impDEMdrag_) { + if(verbose_) Info << "sending Ksl and uf" << endl; dataExchangeM().giveData("Ksl","scalar-atom",Cds_); dataExchangeM().giveData("uf","vector-atom",fluidVel_); } @@ -441,6 +457,16 @@ label Foam::cfdemCloud::liggghtsCommandModelIndex(word name) return index; } +std::vector< std::vector >* Foam::cfdemCloud::getVprobe() +{ + return probeModel_->getVprobe(); +} + +std::vector< std::vector >* Foam::cfdemCloud::getSprobe() +{ + return probeModel_->getSprobe(); +} + // * * * * * * * * * * * * * * * WRITE * * * * * * * * * * * * * // // * * * write cfdemCloud internal data * * * // @@ -458,9 +484,10 @@ bool Foam::cfdemCloud::evolve if(!ignore()) { - if (dataExchangeM().couple()) + if (dataExchangeM().doCoupleNow()) { Info << "\n Coupling..." << endl; + dataExchangeM().couple(0); doCouple=true; // reset vol Fields @@ -496,7 +523,7 @@ bool Foam::cfdemCloud::evolve // set void fraction field clockM().start(19,"setvoidFraction"); if(verbose_) Info << "- setvoidFraction()" << endl; - voidFractionM().setvoidFraction(NULL,voidfractions_,particleWeights_,particleVolumes_); + voidFractionM().setvoidFraction(NULL,voidfractions_,particleWeights_,particleVolumes_,particleV_); if(verbose_) Info << "setvoidFraction done." << endl; clockM().stop("setvoidFraction"); @@ -508,7 +535,12 @@ bool Foam::cfdemCloud::evolve //Smoothen "next" fields smoothingM().dSmoothing(); smoothingM().smoothen(voidFractionM().voidFractionNext()); - smoothingM().smoothenReferenceField(averagingM().UsNext()); + + //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"); } @@ -560,6 +592,8 @@ bool Foam::cfdemCloud::evolve clockM().start(23,"giveDEMdata"); giveDEMdata(); clockM().stop("giveDEMdata"); + + dataExchangeM().couple(1); }//end dataExchangeM().couple() @@ -584,15 +618,40 @@ bool Foam::cfdemCloud::reAllocArrays() const dataExchangeM().allocateArray(positions_,0.,3); dataExchangeM().allocateArray(velocities_,0.,3); dataExchangeM().allocateArray(fluidVel_,0.,3); + dataExchangeM().allocateArray(fAcc_,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(cellIDs_,-1.,voidFractionM().maxCellsPerParticle()); dataExchangeM().allocateArray(particleWeights_,0.,voidFractionM().maxCellsPerParticle()); dataExchangeM().allocateArray(particleVolumes_,0.,voidFractionM().maxCellsPerParticle()); + dataExchangeM().allocateArray(particleV_,0.,1); + arraysReallocated_ = true; + return true; + } + return false; +} + +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); arraysReallocated_ = true; return true; } @@ -604,7 +663,7 @@ tmp cfdemCloud::divVoidfractionTau(volVectorField& U,volScalarFi return ( - fvm::laplacian(voidfractionNuEff(voidfraction), U) - - fvc::div(voidfractionNuEff(voidfraction)*dev(fvc::grad(U)().T())) + - fvc::div(voidfractionNuEff(voidfraction)*dev2(fvc::grad(U)().T())) ); } @@ -637,11 +696,11 @@ void cfdemCloud::calcDdtVoidfraction(volScalarField& voidfraction) const tmp cfdemCloud::voidfractionNuEff(volScalarField& voidfraction) const { - if (modelType_=="B") + if (modelType_=="B" || modelType_=="Bfull") { return tmp ( - #ifdef comp + #ifdef compre new volScalarField("viscousTerm", (turbulence_.mut() + turbulence_.mu())) #else new volScalarField("viscousTerm", (turbulence_.nut() + turbulence_.nu())) @@ -652,7 +711,7 @@ tmp cfdemCloud::voidfractionNuEff(volScalarField& voidfraction) { return tmp ( - #ifdef comp + #ifdef compre new volScalarField("viscousTerm", voidfraction*(turbulence_.mut() + turbulence_.mu())) #else new volScalarField("viscousTerm", voidfraction*(turbulence_.nut() + turbulence_.nu())) diff --git a/src/lagrangian/cfdemParticle/cfdemCloud/cfdemCloud.H b/src/lagrangian/cfdemParticle/cfdemCloud/cfdemCloud.H index 31b98f1..6feff1d 100644 --- a/src/lagrangian/cfdemParticle/cfdemCloud/cfdemCloud.H +++ b/src/lagrangian/cfdemParticle/cfdemCloud/cfdemCloud.H @@ -44,6 +44,7 @@ SourceFiles // choose version #include "OFversion.H" +#include #include "fvCFD.H" #include "IFstream.H" @@ -102,6 +103,8 @@ protected: mutable double **fluidVel_; + mutable double **fAcc_; + mutable double **impForces_; mutable double **expForces_; @@ -120,8 +123,12 @@ protected: mutable double **particleVolumes_; + mutable double **particleV_; + int numberOfParticles_; + scalar d32_; + bool numberOfParticlesChanged_; mutable bool arraysReallocated_; @@ -140,14 +147,18 @@ protected: bool impDEMdrag_; + bool impDEMdragAcc_; + mutable scalar imExSplitFactor_; + mutable bool treatVoidCellsAsExplicitForce_; //will treat the coupling force in cells with no Us data explicitly + bool useDDTvoidfraction_; mutable volScalarField ddtVoidfraction_; #if defined(version21) || defined(version16ext) - #ifdef comp + #ifdef compre const compressible::turbulenceModel& turbulence_; #else const incompressible::turbulenceModel& turbulence_; @@ -200,6 +211,7 @@ public: friend class dataExchangeModel; friend class voidFractionModel; friend class forceModel; + friend class forceSubModel; // Constructors @@ -243,8 +255,12 @@ public: inline const bool& impDEMdrag() const; + inline const bool& impDEMdragAcc() const; + inline const scalar& imExSplitFactor() const; + inline const bool& treatVoidCellsAsExplicitForce() const; + inline const bool& ignore() const; inline const fvMesh& mesh() const; @@ -261,6 +277,8 @@ public: inline double ** fluidVels() const; + inline double ** fAccs() const; + inline double ** impForces() const; inline double ** expForces() const; @@ -289,6 +307,7 @@ public: virtual inline double d(int); + inline scalar d32(bool recalc=true); virtual inline double dMin() {return -1;} virtual inline double dMax() {return -1;} virtual inline int minType() {return -1;} @@ -298,9 +317,19 @@ public: virtual inline double ** particleDensity() const {return NULL;}; virtual inline int ** particleTypes() const {return NULL;}; virtual label particleType(label index) const {return -1;}; + + //access to the particle's rotation and torque data + virtual inline double ** DEMTorques() const {return NULL;}; + virtual inline double ** omegaArray() const {return NULL;}; + virtual vector omega(int) const {return Foam::vector(0,0,0);}; + + //access to the particles' orientation information virtual inline double ** exArray() const {return NULL;}; virtual vector ex(int) const {return Foam::vector(0,0,0);}; + //Detector if SRF module is enable or not + virtual inline bool SRFOn(){return false;} + inline int numberOfParticles() const; inline bool numberOfParticlesChanged() const; @@ -336,7 +365,7 @@ public: inline autoPtr* liggghtsCommand() const; #if defined(version21) || defined(version16ext) - #ifdef comp + #ifdef compre inline const compressible::turbulenceModel& turbulence() const; #else inline const incompressible::turbulenceModel& turbulence() const; @@ -352,6 +381,9 @@ public: virtual bool reAllocArrays() const; + virtual bool reAllocArrays(int nP, bool forceRealloc) const; //force number of particles during reallocation + + // IO void writeScalarFieldToTerminal(double**&); @@ -369,6 +401,11 @@ public: tmp voidfractionNuEff(volScalarField&) const; void resetArray(double**&,int,int,double resetVal=0.); + + std::vector< std::vector >* getVprobe(); + + std::vector< std::vector >* getSprobe(); + }; diff --git a/src/lagrangian/cfdemParticle/cfdemCloud/cfdemCloudI.H b/src/lagrangian/cfdemParticle/cfdemCloud/cfdemCloudI.H index 91b7b10..dae69d8 100644 --- a/src/lagrangian/cfdemParticle/cfdemCloud/cfdemCloudI.H +++ b/src/lagrangian/cfdemParticle/cfdemCloud/cfdemCloudI.H @@ -55,11 +55,21 @@ inline const bool& cfdemCloud::impDEMdrag() const return impDEMdrag_; }; +inline const bool& cfdemCloud::impDEMdragAcc() const +{ + return impDEMdragAcc_; +}; + inline const scalar& cfdemCloud::imExSplitFactor() const { return imExSplitFactor_; }; +inline const bool& cfdemCloud::treatVoidCellsAsExplicitForce() const +{ + return treatVoidCellsAsExplicitForce_; +} + inline const scalar& cfdemCloud::cg() const { return cg_; @@ -105,6 +115,11 @@ inline double ** cfdemCloud::fluidVels() const return fluidVel_; } +inline double ** cfdemCloud::fAccs() const +{ + return fAcc_; +} + inline double ** cfdemCloud::impForces() const { return impForces_; @@ -169,7 +184,7 @@ inline label Foam::cfdemCloud::body(int index) inline double cfdemCloud::particleVolume(int index) { - return particleVolumes_[index][0]; + return particleV_[index][0]; } inline scalar cfdemCloud::radius(int index) @@ -182,6 +197,25 @@ inline double cfdemCloud::d(int index) return 2*radii_[index][0]; } +inline double cfdemCloud::d32(bool recalc) +{ + if(d32_<0 || recalc) + { + scalar Ntot(0); + scalar Dtot(0); + scalar r(0); + for(int index = 0;index < numberOfParticles(); ++index) + { + r=radii_[index][0]; + Ntot+=2*r*r*r; + Dtot+=r*r; + } + d32_=Ntot/Dtot; + } + + return d32_; +} + inline int cfdemCloud::numberOfParticles() const { return numberOfParticles_; @@ -269,7 +303,7 @@ inline autoPtr* cfdemCloud::liggghtsCommand() const } #if defined(version21) || defined(version16ext) - #ifdef comp + #ifdef compre inline const compressible::turbulenceModel& cfdemCloud::turbulence() const #else inline const incompressible::turbulenceModel& cfdemCloud::turbulence() const diff --git a/src/lagrangian/cfdemParticle/derived/cfdemCloudIB/cfdemCloudIB.C b/src/lagrangian/cfdemParticle/derived/cfdemCloudIB/cfdemCloudIB.C index 828a859..19d9d07 100644 --- a/src/lagrangian/cfdemParticle/derived/cfdemCloudIB/cfdemCloudIB.C +++ b/src/lagrangian/cfdemParticle/derived/cfdemCloudIB/cfdemCloudIB.C @@ -101,9 +101,10 @@ bool Foam::cfdemCloudIB::evolve() arraysReallocated_=false; bool doCouple=false; - if (dataExchangeM().couple()) + if (dataExchangeM().doCoupleNow()) { Info << "\n timeStepFraction() = " << dataExchangeM().timeStepFraction() << endl; + dataExchangeM().couple(0); doCouple=true; // Info << "skipLagrangeToEulerMapping_: " << skipLagrangeToEulerMapping_ @@ -121,7 +122,7 @@ bool Foam::cfdemCloudIB::evolve() // set void fraction field if(verbose_) Info << "- setvoidFraction()" << endl; - voidFractionM().setvoidFraction(NULL,voidfractions_,particleWeights_,particleVolumes_); + voidFractionM().setvoidFraction(NULL,voidfractions_,particleWeights_,particleVolumes_,particleV_); if(verbose_) Info << "setvoidFraction done." << endl; } @@ -140,6 +141,8 @@ bool Foam::cfdemCloudIB::evolve() // write DEM data if(verbose_) Info << " -giveDEMdata()" << endl; giveDEMdata(); + + dataExchangeM().couple(1); haveEvolvedOnce_=true; } @@ -190,6 +193,7 @@ void Foam::cfdemCloudIB::calcVelocityCorrection } //} } + U.correctBoundaryConditions(); // make field divergence free - set reference value in case it is needed fvScalarMatrix phiIBEqn diff --git a/src/lagrangian/cfdemParticle/etc/additionalLibs b/src/lagrangian/cfdemParticle/etc/additionalLibs new file mode 100644 index 0000000..771640a --- /dev/null +++ b/src/lagrangian/cfdemParticle/etc/additionalLibs @@ -0,0 +1,8 @@ +# paths for additional libraries +CFDEM_ADD_LIB_PATHS = \ + +# additional libraries to be linked to solvers +CFDEM_ADD_LIBS = \ + +# additional static libraries to be linked to lagrangian library +CFDEM_ADD_STATICLIBS = \ diff --git a/src/lagrangian/cfdemParticle/etc/bashrc b/src/lagrangian/cfdemParticle/etc/bashrc index 0e9b3fb..141ec10 100755 --- a/src/lagrangian/cfdemParticle/etc/bashrc +++ b/src/lagrangian/cfdemParticle/etc/bashrc @@ -37,12 +37,32 @@ #- export environment variables (adapt to your paths) #------------------------------------------------------------------------------ +#check if default lammps lib path should be used +if [[ $CFDEM_LAMMPS_LIB_DIR == "" ]]; then + export CFDEM_LAMMPS_LIB_DIR=$CFDEM_LIGGGHTS_SRC_DIR/../lib/ +else + echo "using CFDEM_LAMMPS_LIB_DIR=$CFDEM_LAMMPS_LIB_DIR defined by user." +fi + #- LIGGGHTS lib name export CFDEM_LIGGGHTS_LIB_NAME=lmp_$CFDEM_LIGGGHTS_MAKEFILE_NAME #- CFDEM lib name export CFDEM_LIB_NAME=lagrangianCFDEM-$CFDEM_VERSION-$WM_PROJECT_VERSION +#- CFDEM compressible lib name +export CFDEM_LIB_COMP_NAME=lagrangianCFDEMcomp-$CFDEM_VERSION-$WM_PROJECT_VERSION + +#check if additional libraries should be compiled together with solvers +if [[ $CFDEM_ADD_LIBS_DIR == "" ]]; then + export CFDEM_ADD_LIBS_DIR=$CFDEM_SRC_DIR/lagrangian/cfdemParticle/etc +else + echo "using CFDEM_ADD_LIBS_DIR=$CFDEM_ADD_LIBS_DIR defined by user." +fi + +#----------------------------------------------------- +# additional libraries + #- LMP Many2Many lib path and makefile export CFDEM_Many2ManyLIB_PATH=$CFDEM_SRC_DIR/lagrangian/cfdemParticle/subModels/dataExchangeModel/twoWayMany2Many/library export CFDEM_Many2ManyLIB_MAKEFILENAME=$CFDEM_LIGGGHTS_MAKEFILE_NAME @@ -52,9 +72,17 @@ export CFDEM_M2MLIB_PATH=$CFDEM_SRC_DIR/lagrangian/cfdemParticle/subModels/dataE export CFDEM_M2MLIB_MAKEFILENAME=$CFDEM_LIGGGHTS_MAKEFILE_NAME #- LMP POEMS lib path and makefile -export CFDEM_POEMSLIB_PATH=$CFDEM_LIGGGHTS_SRC_DIR/../lib/poems +export CFDEM_POEMSLIB_PATH=$CFDEM_LAMMPS_LIB_DIR/poems export CFDEM_POEMSLIB_MAKEFILENAME=g++ +#- LMP ASPHERE lib path and makefile +export CFDEM_ASPHERELIB_PATH=$CFDEM_LAMMPS_LIB_DIR/poems +export CFDEM_ASPHERELIB_MAKEFILENAME=g++ + +#-C3PO library +export C3PO_SRC_DIR=$CFDEM_SRC_DIR/c3po +#----------------------------------------------------- + #- path to test harness export CFDEM_TEST_HARNESS_PATH=$CFDEM_PROJECT_USER_DIR/log/logFilesCFDEM-$CFDEM_VERSION-$WM_PROJECT_VERSION @@ -145,6 +173,9 @@ alias cfdemCompCFDEMuti='bash $CFDEM_SRC_DIR/lagrangian/cfdemParticle/etc/compil #- shortcut to test basic tutorials alias cfdemTestTUT='bash $CFDEM_SRC_DIR/lagrangian/cfdemParticle/etc/testTutorials.sh' +#- shortcut to visualize the clock model data +alias vizClock='python $CFDEM_UT_DIR/vizClock/matPlot.py' + #- recursive touch of current directory alias touchRec='find ./* -exec touch {} \;' @@ -160,6 +191,11 @@ export -f cfdemLiggghtsPar cfdemGrep() { grep -rl "$1" ./* | xargs gedit; } export -f cfdemGrep +#- shortcut lo list files in a directory +#cfdemListFiles() { find $1 | sed s:""$1"":: > listOfFiles.txt; } #leave out the dir iteslf in list +cfdemListFiles() { find $1 > listOfFiles.txt; } #keep the dir in list +export -f cfdemListFiles + # check if the run directory exists if [ -d "$CFDEM_PROJECT_USER_DIR" ]; then : diff --git a/src/lagrangian/cfdemParticle/etc/cfdemSystemTest.sh b/src/lagrangian/cfdemParticle/etc/cfdemSystemTest.sh index c3da9ab..66b686a 100755 --- a/src/lagrangian/cfdemParticle/etc/cfdemSystemTest.sh +++ b/src/lagrangian/cfdemParticle/etc/cfdemSystemTest.sh @@ -11,10 +11,15 @@ source $CFDEM_SRC_DIR/lagrangian/cfdemParticle/etc/functions.sh #- show gcc settings checkGPP="true" +#- sys check for add on +checkAddOn="true" + #- system settings -echo "*******************" -echo "system settings:" -echo "*******************" +printHeader + +echo "*********************************" +echo "CFDEM(R)coupling system settings:" +echo "*********************************" echo "CFDEM_VERSION=$CFDEM_VERSION" echo "couple to OF_VERSION=$WM_PROJECT_VERSION" @@ -29,8 +34,10 @@ checkDirComment "$CFDEM_SOLVER_DIR" '$CFDEM_SOLVER_DIR' "yes" checkDirComment "$CFDEM_TUT_DIR" '$CFDEM_TUT_DIR' "yes" checkDirComment "$CFDEM_LIGGGHTS_SRC_DIR" '$CFDEM_LIGGGHTS_SRC_DIR' "yes" checkDirComment "$CFDEM_LPP_DIR" '$CFDEM_LPP_DIR' "yes" +checkDirComment "$CFDEM_ADD_LIBS_DIR" '$CFDEM_ADD_LIBS_DIR' "yes" checkDirComment "$CFDEM_PIZZA_DIR" '$CFDEM_PIZZA_DIR' "no" checkDirComment "$CFDEM_TEST_HARNESS_PATH" '$CFDEM_TEST_HARNESS_PATH' "no" +checkDirComment "$C3PO_SRC_DIR" '$C3PO_SRC_DIR' "no" echo "" echo "library names" @@ -61,3 +68,16 @@ if [ $checkGPP == "true" ] mpirun --version fi +echo "**********************" +echo "additional packages..." + +if [ $checkAddOn == "true" ] + then + packageName=c3po + filePath=$CFDEM_SRC_DIR/$packageName + if [ $(checkDir $filePath) == "true" ]; then + source $filePath/etc/$packageName"SystemTest.sh" + else + echo "$packageName does not exist." + fi +fi diff --git a/src/lagrangian/cfdemParticle/etc/compileCFDEMcoupling_sol.sh b/src/lagrangian/cfdemParticle/etc/compileCFDEMcoupling_sol.sh index a8aa9c5..6dbbb3a 100755 --- a/src/lagrangian/cfdemParticle/etc/compileCFDEMcoupling_sol.sh +++ b/src/lagrangian/cfdemParticle/etc/compileCFDEMcoupling_sol.sh @@ -51,15 +51,16 @@ else logpath="$(dirname "$(readlink -f ${BASH_SOURCE[0]})")/$logDir" ##number of solvers compiled at a time - nsteps=$WM_NCOMPPROCS - echo "do compilation on $nsteps procs" - nchunk=`echo $njobs/$nsteps+1 | bc` - if [[ $WM_NCOMPPROCS == "" ]]; then - echo "do compilation in serial" + + if [[ $WM_NCOMPPROCS == "" ]] || [ $WM_NCOMPPROCS -eq 1 ]; then nsteps=1 - nchunk=1 - else - echo "do compilation on $nsteps procs in $nchunk chunks" + let nchunk=$njobs+1 # +1, to wait for the last compilation too + echo "do compilation in serial" + else + nsteps=$WM_NCOMPPROCS + nchunk=`echo $njobs/$nsteps+1 | bc` + echo "do compilation on $nsteps procs in $nchunk chunks" + let nchunk++ # +1, to wait for the last compilation too fi counter=0 @@ -108,6 +109,8 @@ else let counter++ fi done + + sleep 1 # wait a second until compilation starts done echo "compilation done." diff --git a/src/lagrangian/cfdemParticle/etc/compileCFDEMcoupling_src.sh b/src/lagrangian/cfdemParticle/etc/compileCFDEMcoupling_src.sh index a763dac..a4b531c 100755 --- a/src/lagrangian/cfdemParticle/etc/compileCFDEMcoupling_src.sh +++ b/src/lagrangian/cfdemParticle/etc/compileCFDEMcoupling_src.sh @@ -20,48 +20,48 @@ mkdir -p $logDir #================================================================================# # compile src #================================================================================# - whitelist="$CFDEM_SRC_DIR/lagrangian/cfdemParticle/etc/library-list.txt" - echo "" - echo "Please provide the libraries to be compiled in the $CWD/$whitelist file." +whitelist="$CFDEM_SRC_DIR/lagrangian/cfdemParticle/etc/library-list.txt" +echo "" +echo "Please provide the libraries to be compiled in the $CWD/$whitelist file." - if [ ! -f "$CWD/$whitelist" ];then - echo "$whitelist does not exist in $CWD. Nothing will be done." - NLINES=0 - COUNT=0 - else - NLINES=`wc -l < $CWD/$whitelist` - COUNT=0 - fi +if [ ! -f "$CWD/$whitelist" ];then + echo "$whitelist does not exist in $CWD. Nothing will be done." + NLINES=0 + COUNT=0 +else + NLINES=`wc -l < $CWD/$whitelist` + COUNT=0 +fi - while [ $COUNT -lt $NLINES ] - do - let COUNT++ - LINE=`head -n $COUNT $CWD/$whitelist | tail -1` - - # white lines - if [[ "$LINE" == "" ]]; then - echo "compile $LINE" - continue - # comments - elif [[ "$LINE" == \#* ]]; then - continue - # paths - elif [[ "$LINE" == */dir ]]; then - echo "will change path..." - LINE=$(echo "${LINE%????}") - path="$CFDEM_SRC_DIR/$LINE" - cd $path - #continue - fi - #--------------------------------------------------------------------------------# - #- define variables - logpath="$(dirname "$(readlink -f ${BASH_SOURCE[0]})")/$logDir" - logfileName="log_compileCFDEMcoupling_"$(basename $LINE)"" - casePath="$path" - headerText="$logfileName""-$NOW" - #--------------------------------------------------------------------------------# - # remove old log file - rm "$logpath/$logfileName"* - compileLib $logpath $logfileName $casePath $headerText - done +while [ $COUNT -lt $NLINES ] +do + let COUNT++ + LINE=`head -n $COUNT $CWD/$whitelist | tail -1` + + # white lines + if [[ "$LINE" == "" ]]; then + echo "compile $LINE" + continue + # comments + elif [[ "$LINE" == \#* ]]; then + continue + # paths + elif [[ "$LINE" == */dir ]]; then + echo "will change path..." + LINE=$(echo "${LINE%????}") + path="$CFDEM_SRC_DIR/$LINE" + cd $path + #continue + fi + #--------------------------------------------------------------------------------# + #- define variables + logpath="$(dirname "$(readlink -f ${BASH_SOURCE[0]})")/$logDir" + logfileName="log_compileCFDEMcoupling_"$(basename $LINE)"" + casePath="$path" + headerText="$logfileName""-$NOW" + #--------------------------------------------------------------------------------# + # remove old log file + rm "$logpath/$logfileName"* + compileLib $logpath $logfileName $casePath $headerText +done diff --git a/src/lagrangian/cfdemParticle/etc/compileCFDEMcoupling_uti.sh b/src/lagrangian/cfdemParticle/etc/compileCFDEMcoupling_uti.sh index 8b91bfe..d4e0306 100644 --- a/src/lagrangian/cfdemParticle/etc/compileCFDEMcoupling_uti.sh +++ b/src/lagrangian/cfdemParticle/etc/compileCFDEMcoupling_uti.sh @@ -1,36 +1,115 @@ #!/bin/bash #===================================================================# -# compile routine for CFDEMcoupling solvers, part of CFDEMproject +# compile routine for CFDEMcoupling utilities, part of CFDEMproject # Christoph Goniva - May. 2012, DCS Computing GmbH #===================================================================# +whitelist="utilities-list.txt" + #- include functions source $CFDEM_SRC_DIR/lagrangian/cfdemParticle/etc/functions.sh - -NOW="$(date +"%Y-%m-%d-%H:%M")" logDir="log" - - cd $CFDEM_SRC_DIR/lagrangian/cfdemParticle/etc mkdir -p $logDir -#================================================================================# -# compile utilities -#================================================================================# +CWD="$(dirname "$(readlink -f ${BASH_SOURCE[0]})")" +NOW="$(date +"%Y-%m-%d-%H:%M")" +echo "" +echo "This routine will compile the utilities specified in utilities-list.txt" +echo "" +#echo "Are the variables CFDEM_UT_DIR=$CFDEM_UT_DIR" +#echo "and CFDEM_SRC_DIR=$CFDEM_SRC_DIR/lagrangian/cfdemParticle correct? (y/n)" +#read YN +#if [ "$YN" != "y" ];then +# echo "Aborted by user." +# exit 1 +#fi + +echo "" +echo "Please provide the utilities to be compiled in the $CWD/$whitelist file." +echo "structure:" +echo "path to provide the path relative to CFDEM_UT_DIR" +echo "" +echo "example:" +echo "cfdemPostproc/dir" +echo "" + +if [ ! -f "$CWD/$whitelist" ];then + echo "$whitelist does not exist in $CWD" +else + njobs=`wc -l < $CWD/$whitelist` + echo "" + echo "running compilation in pseudo-parallel mode of $njobs utilities" -for utName in "cfdemPostproc" -do #--------------------------------------------------------------------------------# - #- define variables logpath="$(dirname "$(readlink -f ${BASH_SOURCE[0]})")/$logDir" - logfileName="log_compileCFDEMcoupling""_$utName" - casePath="$CFDEM_UT_DIR/$utName" - headerText="$logfileName""_$utName""-$NOW" - #--------------------------------------------------------------------------------# - compileSolver $logpath $logfileName $casePath $headerText -done -echo "Note: the list of utilities compiled might be incomplete." -echo "please check $CFDEM_UT_DIR for more utilities available" + ##number of utilities compiled at a time + + if [[ $WM_NCOMPPROCS == "" ]] || [ $WM_NCOMPPROCS -eq 1 ]; then + nsteps=1 + let nchunk=$njobs+1 # +1, to wait for the last compilation too + echo "do compilation in serial" + else + nsteps=$WM_NCOMPPROCS + nchunk=`echo $njobs/$nsteps+1 | bc` + echo "do compilation on $nsteps procs in $nchunk chunks" + let nchunk++ # +1, to wait for the last compilation too + fi + + counter=0 + for i in `seq $nchunk` + do + + #wait until prev. compilation is finished + echo "waiting..." + until [ `ps -C make | wc -l` -eq 1 ]; + do + sleep 2 + done + + for j in `seq $nsteps` + do + let solNr=($i-1)*$nsteps+$j + LINE=`head -n $solNr $CWD/$whitelist | tail -1` + + # white lines + if [[ "$LINE" == "" ]]; then + continue + # comments + elif [[ "$LINE" == \#* ]]; then + continue + # paths + elif [[ "$LINE" == */dir ]]; then + #echo "change path" + LINE=$(echo "${LINE%????}") + path="$CFDEM_UT_DIR/$LINE" + #cd $path + let solNr++ + fi + + if [[ "$counter" -lt "$njobs" ]]; then + #--------------------------------------------------------------------------------# + #- define variables + #logpath="$(dirname "$(readlink -f ${BASH_SOURCE[0]})")/$logDir" + logfileName="log_compileCFDEMcoupling""_$LINE" + casePath="$CFDEM_UT_DIR/$LINE" + headerText="$logfileName""_$LINE""-$NOW" + parallel="true" + #--------------------------------------------------------------------------------# + + #echo "compiling $LINE" + compileSolver $logpath $logfileName $casePath $headerText $parallel + let counter++ + fi + done + + sleep 1 # wait a second until compilation starts + done + + echo "compilation done." +fi + + diff --git a/src/lagrangian/cfdemParticle/etc/compileLIGGGHTS_lib.sh b/src/lagrangian/cfdemParticle/etc/compileLIGGGHTS_lib.sh index ac9f18d..4461d7d 100755 --- a/src/lagrangian/cfdemParticle/etc/compileLIGGGHTS_lib.sh +++ b/src/lagrangian/cfdemParticle/etc/compileLIGGGHTS_lib.sh @@ -33,6 +33,8 @@ mkdir -p $logDir COUNT=0 fi + logpath="$(dirname "$(readlink -f ${BASH_SOURCE[0]})")/$logDir" + while [ $COUNT -lt $NLINES ] do let COUNT++ @@ -57,7 +59,7 @@ mkdir -p $logDir #--------------------------------------------------------------------------------# #- define variables - logpath="$(dirname "$(readlink -f ${BASH_SOURCE[0]})")/$logDir" + #logpath="$(dirname "$(readlink -f ${BASH_SOURCE[0]})")/$logDir" logfileName="log_compile$LINE""lib" headerText="$logfileName""-$NOW" libVarMakefileName="CFDEM_$LINE""LIB_MAKEFILENAME" diff --git a/src/lagrangian/cfdemParticle/etc/cshrc b/src/lagrangian/cfdemParticle/etc/cshrc index 1bc6818..54154df 100755 --- a/src/lagrangian/cfdemParticle/etc/cshrc +++ b/src/lagrangian/cfdemParticle/etc/cshrc @@ -37,12 +37,32 @@ #- export environment variables (adapt to your paths) #------------------------------------------------------------------------------ +#check if default lammps lib path should be used +if ( ! ($?CFDEM_LAMMPS_LIB_DIR) ) then + setenv CFDEM_LAMMPS_LIB_DIR $CFDEM_LIGGGHTS_SRC_DIR"/../lib/" +else + echo "using CFDEM_LAMMPS_LIB_DIR=$CFDEM_LAMMPS_LIB_DIR defined by user." +endif + #- LIGGGHTS lib name setenv CFDEM_LIGGGHTS_LIB_NAME lmp_$CFDEM_LIGGGHTS_MAKEFILE_NAME #- CFDEM lib name setenv CFDEM_LIB_NAME lagrangianCFDEM-$CFDEM_VERSION-$WM_PROJECT_VERSION +#- CFDEM compressible lib name +setenv CFDEM_LIB_COMP_NAME lagrangianCFDEMcomp-$CFDEM_VERSION-$WM_PROJECT_VERSION + +#check if additional libraries should be compiled together with solvers +if ( ! ($?CFDEM_ADD_LIBS_DIR) ) then + setenv CFDEM_ADD_LIBS_DIR $CFDEM_SRC_DIR/lagrangian/cfdemParticle/etc +else + echo "using CFDEM_ADD_LIBS_DIR=$CFDEM_ADD_LIBS_DIR defined by user." +endif + +#----------------------------------------------------- +# additional libraries + #- LMP Many2Many lib path and makefile setenv CFDEM_Many2ManyLIB_PATH $CFDEM_SRC_DIR/lagrangian/cfdemParticle/subModels/dataExchangeModel/twoWayMany2Many/library setenv CFDEM_Many2ManyLIB_MAKEFILENAME $CFDEM_LIGGGHTS_MAKEFILE_NAME @@ -143,6 +163,9 @@ alias cfdemCompCFDEMuti 'bash $CFDEM_SRC_DIR/lagrangian/cfdemParticle/etc/compil #- shortcut to test basic tutorials alias cfdemTestTUT 'bash $CFDEM_SRC_DIR/lagrangian/cfdemParticle/etc/testTutorials.sh' +#- shortcut to visualize the clock model data +alias vizClock 'python $CFDEM_UT_DIR/vizClock/matPlot.py' + #- shortcut to run liggghts in serial alias cfdemLiggghts '$CFDEM_LIGGGHTS_SRC_DIR/lmp_$CFDEM_LIGGGHTS_MAKEFILE_NAME' diff --git a/src/lagrangian/cfdemParticle/etc/functions.sh b/src/lagrangian/cfdemParticle/etc/functions.sh index c0286cc..e9dd946 100755 --- a/src/lagrangian/cfdemParticle/etc/functions.sh +++ b/src/lagrangian/cfdemParticle/etc/functions.sh @@ -71,6 +71,21 @@ compileLib() #- wclean and wmake #if [ $doClean != "noClean" ]; then + # check library to compile is compressible + str=$casePath + i=$((${#str}-4)) + ending=${str:$i:4} + if [[ $ending == "Comp" ]]; then + echo "Compiling a compressible library - so doing an rmdepall of incomp library first." + echo "Please make sure to have the compressible libraries first in the library-list.txt!" + cd $CFDEM_SRC_DIR/lagrangian/cfdemParticle + echo "changing to $PWD" + rmdepall 2>&1 | tee -a $logpath/$logfileName + cd $casePath + echo "changing to $PWD" + else + echo "Compiling a incompressible library." + fi rmdepall 2>&1 | tee -a $logpath/$logfileName wclean 2>&1 | tee -a $logpath/$logfileName #fi @@ -139,6 +154,7 @@ compileLIGGGHTS() logpath="$1" logfileName="$2" headerText="$3" + clean="$4" #--------------------------------------------------------------------------------# #- clean up old log file @@ -157,9 +173,14 @@ compileLIGGGHTS() echo 2>&1 | tee -a $logpath/$logfileName #- wclean and wmake - rm $CFDEM_LIGGGHTS_SRC_DIR/"lmp_"$CFDEM_LIGGGHTS_MAKEFILE_NAME - rm $CFDEM_LIGGGHTS_SRC_DIR/"lib"$CFDEM_LIGGGHTS_LIB_NAME".a" - make clean-all 2>&1 | tee -a $logpath/$logfileName + if [[ $clean == "false" ]]; then + echo "not cleaning LIGGGHTS" + else + rm $CFDEM_LIGGGHTS_SRC_DIR/"lmp_"$CFDEM_LIGGGHTS_MAKEFILE_NAME + rm $CFDEM_LIGGGHTS_SRC_DIR/"lib"$CFDEM_LIGGGHTS_LIB_NAME".a" + make clean-all 2>&1 | tee -a $logpath/$logfileName + echo "cleaning LIGGGHTS" + fi if [[ $WM_NCOMPPROCS == "" ]]; then echo "compiling LIGGGHTS on one CPU" make $CFDEM_LIGGGHTS_MAKEFILE_NAME 2>&1 | tee -a $logpath/$logfileName @@ -189,7 +210,13 @@ compileLMPlib() rm $logpath/$logfileName #- change path - cd $libraryPath + if [ -d "$libraryPath" ]; then + cd $libraryPath + else + echo "" + echo "lib path $libraryPath does not exist - check settings in .../etc/bashrc." + read + fi #- header echo 2>&1 | tee -a $logpath/$logfileName @@ -550,6 +577,7 @@ parCFDDEMrun() machineFileName="$7" debugMode="$8" reconstuctCase="$9" + cleanCase="$10" #--------------------------------------------------------------------------------# if [ $debugMode == "on" ]; then @@ -903,6 +931,52 @@ checkDirComment() fi } +#========================================# +#- function to check if a variable exits +checkEnv() +{ + #--------------------------------------------------------------------------------# + #- define variables + var="$1" + #--------------------------------------------------------------------------------# + if [[ $var == "" ]]; then + echo "false" + else + echo "true" + fi +} + +#========================================# +#- function to check if a variable exits +checkEnvComment() +{ + #--------------------------------------------------------------------------------# + #- define variables + var="$1" + varName="$2" + critical="$3" + #--------------------------------------------------------------------------------# + if [ $(checkEnv $var) == "true" ]; then + echo "valid:yes critical:$critical - $varName = $var" + else + echo "valid:NO critical:$critical - $varName = $var variable not set!" + fi +} + +#========================================# +#- function to print a header to terminal +printHeader() +{ + echo "" + echo "*********************************************" + echo "* C F D E M (R) c o u p l i n g *" + echo "* *" + echo "* by DCS Computing GmbH *" + echo "* www.dcs-computing.com *" + echo "*********************************************" + echo "" +} + #========================================# #- track memory usage trackMem() diff --git a/src/lagrangian/cfdemParticle/subModels/IOModel/IOModel/IOModel.C b/src/lagrangian/cfdemParticle/subModels/IOModel/IOModel/IOModel.C index c2fd0e6..0883d0e 100644 --- a/src/lagrangian/cfdemParticle/subModels/IOModel/IOModel/IOModel.C +++ b/src/lagrangian/cfdemParticle/subModels/IOModel/IOModel/IOModel.C @@ -50,6 +50,15 @@ int IOModel::dumpDEMdata() const return -1; } +bool IOModel::dumpNow() const +{ + //bool dmp(false); + //if (time_.value()+SMALL > time_.endTime().value()-time_.deltaT().value() || time_.outputTime()) + // dmp=true; + + return time_.outputTime(); +} + fileName IOModel::createTimeDir(fileName path) const { fileName timeDirPath(path/time_.timeName()); diff --git a/src/lagrangian/cfdemParticle/subModels/IOModel/IOModel/IOModel.H b/src/lagrangian/cfdemParticle/subModels/IOModel/IOModel/IOModel.H index 2824333..d266fc0 100644 --- a/src/lagrangian/cfdemParticle/subModels/IOModel/IOModel/IOModel.H +++ b/src/lagrangian/cfdemParticle/subModels/IOModel/IOModel/IOModel.H @@ -113,6 +113,8 @@ public: virtual int dumpDEMdata() const; + bool dumpNow() const; + fileName createTimeDir(fileName) const; fileName createLagrangianDir(fileName) const; diff --git a/src/lagrangian/cfdemParticle/subModels/IOModel/basicIO/basicIO.C b/src/lagrangian/cfdemParticle/subModels/IOModel/basicIO/basicIO.C index c229bef..37214e6 100644 --- a/src/lagrangian/cfdemParticle/subModels/IOModel/basicIO/basicIO.C +++ b/src/lagrangian/cfdemParticle/subModels/IOModel/basicIO/basicIO.C @@ -84,7 +84,7 @@ basicIO::~basicIO() int basicIO::dumpDEMdata() const { - if (time_.outputTime()) + if (dumpNow()) { // make time directory if (parOutput_) lagPath_=buildFilePath(dirName_); diff --git a/src/lagrangian/cfdemParticle/subModels/IOModel/sophIO/sophIO.C b/src/lagrangian/cfdemParticle/subModels/IOModel/sophIO/sophIO.C index 98014ee..e540c5a 100644 --- a/src/lagrangian/cfdemParticle/subModels/IOModel/sophIO/sophIO.C +++ b/src/lagrangian/cfdemParticle/subModels/IOModel/sophIO/sophIO.C @@ -79,7 +79,7 @@ int sophIO::dumpDEMdata() const { int npProcs(-1); - if (time_.outputTime()) + if (dumpNow()) { npProcs=basicIO::dumpDEMdata(); diff --git a/src/lagrangian/cfdemParticle/subModels/IOModel/trackIO/trackIO.C b/src/lagrangian/cfdemParticle/subModels/IOModel/trackIO/trackIO.C index 2f981e2..888a08f 100644 --- a/src/lagrangian/cfdemParticle/subModels/IOModel/trackIO/trackIO.C +++ b/src/lagrangian/cfdemParticle/subModels/IOModel/trackIO/trackIO.C @@ -77,7 +77,7 @@ int trackIO::dumpDEMdata() const { int npProcs(-1); - if (time_.outputTime()) + if (dumpNow()) { npProcs = sophIO::dumpDEMdata(); diff --git a/src/lagrangian/cfdemParticle/subModels/averagingModel/dense/dense.C b/src/lagrangian/cfdemParticle/subModels/averagingModel/dense/dense.C index 374ef8e..7789244 100644 --- a/src/lagrangian/cfdemParticle/subModels/averagingModel/dense/dense.C +++ b/src/lagrangian/cfdemParticle/subModels/averagingModel/dense/dense.C @@ -150,6 +150,9 @@ void dense::setVectorAverage { for(int i=0;i<3;i++) valueVec[i] = value[index][i]; weightP = weight[index][subCell]; + + if(weightP calcShift() const; //detects empty indices in vector, when times are evaluated - void Hist() const; //calc Histogram - virtual void normHist() const; //calc normalized Histogram + std::vector calcShift() const; //detects empty indices in vector, when times are evaluated + void Hist() const; //calc Histogram + virtual void normHist() const; //calc normalized Histogram void plotHist(double,std::string,int,int) const; //plot histogramm to terminal void getRAMUsage() const; diff --git a/src/lagrangian/cfdemParticle/subModels/dataExchangeModel/dataExchangeModel/dataExchangeModel.C b/src/lagrangian/cfdemParticle/subModels/dataExchangeModel/dataExchangeModel/dataExchangeModel.C index c932fda..7bb5d3e 100755 --- a/src/lagrangian/cfdemParticle/subModels/dataExchangeModel/dataExchangeModel/dataExchangeModel.C +++ b/src/lagrangian/cfdemParticle/subModels/dataExchangeModel/dataExchangeModel/dataExchangeModel.C @@ -137,7 +137,7 @@ void Foam::dataExchangeModel::allocateArray { int len=0; if(strcmp(length,"nparticles")==0) len = particleCloud_.numberOfParticles(); - else if (strcmp(length,"nbodies")==0) len = nClumpTypes_; + else if (strcmp(length,"nbodies")==0) len = particleCloud_.numberOfClumps(); else FatalError<<"call allocateArray with length, nparticles or nbodies!\n" << abort(FatalError); allocateArray(array,initVal,width,len); } @@ -203,7 +203,7 @@ void Foam::dataExchangeModel::destroy(double* array) const //==== -bool Foam::dataExchangeModel::couple() const +bool Foam::dataExchangeModel::couple(int i) const { bool coupleNow = false; if (doCoupleNow()) @@ -226,7 +226,7 @@ scalar Foam::dataExchangeModel::timeStepFraction() const } int Foam::dataExchangeModel::getNumberOfParticles() const { - Warning << "ask for nr of clumps - which is not supported for this dataExchange model" << endl; + Warning << "ask for nr of particles - which is not supported for this dataExchange model" << endl; return -1; } @@ -235,7 +235,17 @@ int Foam::dataExchangeModel::getNumberOfClumps() const Warning << "ask for nr of clumps - which is not supported for this dataExchange model" << endl; return -1; } +int Foam::dataExchangeModel::getNumberOfTypes() const +{ + Warning << "ask for nr of types - which is not supported for this dataExchange model" << endl; + return -1; +} +double* Foam::dataExchangeModel::getTypeVol() const +{ + Warning << "ask for type volume - which is not supported for this dataExchange model" << endl; + return NULL; +} // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // Construct from components @@ -248,7 +258,6 @@ dataExchangeModel::dataExchangeModel dict_(dict), particleCloud_(sm), maxNumberOfParticles_(0), - nClumpTypes_(1), couplingStep_(0), DEMts_(-1.), couplingInterval_(readScalar(dict_.lookup("couplingInterval"))) diff --git a/src/lagrangian/cfdemParticle/subModels/dataExchangeModel/dataExchangeModel/dataExchangeModel.H b/src/lagrangian/cfdemParticle/subModels/dataExchangeModel/dataExchangeModel/dataExchangeModel.H index db14e44..a1794f6 100755 --- a/src/lagrangian/cfdemParticle/subModels/dataExchangeModel/dataExchangeModel/dataExchangeModel.H +++ b/src/lagrangian/cfdemParticle/subModels/dataExchangeModel/dataExchangeModel/dataExchangeModel.H @@ -62,8 +62,6 @@ protected: int maxNumberOfParticles_; - int nClumpTypes_; - mutable int couplingStep_; scalar DEMts_; @@ -71,7 +69,6 @@ protected: int couplingInterval_; // Protected member functions - void setNumberOfParticles(int) const; public: @@ -118,9 +115,9 @@ public: // Member Function - inline const int& maxNumberOfParticles() const {return maxNumberOfParticles_;}; + void setNumberOfParticles(int) const; - inline int nClumpTypes() const {return nClumpTypes_;}; + inline const int& maxNumberOfParticles() const {return maxNumberOfParticles_;}; template void getData @@ -179,7 +176,7 @@ public: virtual void destroy(double*) const; //==== - virtual bool couple() const; + virtual bool couple(int) const; virtual scalar timeStepFraction() const; @@ -240,6 +237,8 @@ public: virtual int getNumberOfParticles() const; virtual int getNumberOfClumps() const; + virtual int getNumberOfTypes() const; + virtual double* getTypeVol() const; inline void setPositions(label n,double* pos) const { diff --git a/src/lagrangian/cfdemParticle/subModels/dataExchangeModel/twoWayMPI/twoWayMPI.C b/src/lagrangian/cfdemParticle/subModels/dataExchangeModel/twoWayMPI/twoWayMPI.C index 1947682..cedbb9d 100644 --- a/src/lagrangian/cfdemParticle/subModels/dataExchangeModel/twoWayMPI/twoWayMPI.C +++ b/src/lagrangian/cfdemParticle/subModels/dataExchangeModel/twoWayMPI/twoWayMPI.C @@ -112,8 +112,9 @@ twoWayMPI::twoWayMPI // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // twoWayMPI::~twoWayMPI() -{} - +{ + if (liggghts == 1) delete lmp; +} // * * * * * * * * * * * * * * * private Member Functions * * * * * * * * * * * * * // char* twoWayMPI::wordToChar(word& inWord) const @@ -124,6 +125,7 @@ char* twoWayMPI::wordToChar(word& inWord) const // * * * * * * * * * * * * * * * public Member Functions * * * * * * * * * * * * * // + void twoWayMPI::getData ( word name, @@ -251,10 +253,10 @@ void Foam::twoWayMPI::destroy(double* array) const } //============ -bool Foam::twoWayMPI::couple() const +bool Foam::twoWayMPI::couple(int i) const { bool coupleNow = false; - if (doCoupleNow()) + if (i==0) { couplingStep_++; coupleNow = true; @@ -306,9 +308,9 @@ bool Foam::twoWayMPI::couple() const DEMstepsToInterrupt[ind] -= DEMstepsToInterrupt[ind-1]; } - Info << "Foam::twoWayMPI::couple(): interruptTimes=" << interruptTimes << endl; - Info << "Foam::twoWayMPI::couple(): DEMstepsToInterrupt=" << DEMstepsToInterrupt << endl; - Info << "Foam::twoWayMPI::couple(): lcModel=" << lcModel << endl; + Info << "Foam::twoWayMPI::couple(i): interruptTimes=" << interruptTimes << endl; + Info << "Foam::twoWayMPI::couple(i): DEMstepsToInterrupt=" << DEMstepsToInterrupt << endl; + Info << "Foam::twoWayMPI::couple(i): lcModel=" << lcModel << endl; } if(particleCloud_.liggghtsCommand()[i]().type()=="runLiggghts") @@ -391,7 +393,6 @@ bool Foam::twoWayMPI::couple() const // give nr of particles to cloud double newNpart = liggghts_get_maxtag(lmp); - setNumberOfParticles(newNpart); // re-allocate arrays of cloud @@ -414,9 +415,29 @@ int Foam::twoWayMPI::getNumberOfClumps() const return liggghts_get_maxtag_ms(lmp); #endif - Warning << "liggghts_get_maxtag_ms(lmp) is commented here!" << endl; + Warning << "liggghts_get_maxtag_ms(lmp) is not available here!" << endl; return -1; } + +int Foam::twoWayMPI::getNumberOfTypes() const +{ + #ifdef multisphere + return liggghts_get_ntypes_ms(lmp); + #endif + Warning << "liggghts_get_maxtag_ms(lmp) is not available here!" << endl; + return -1; +} + +double* Foam::twoWayMPI::getTypeVol() const +{ + #ifdef multisphere + return liggghts_get_vclump_ms(lmp); + #endif + + Warning << "liggghts_get_vclump_ms(lmp) is not available here!" << endl; + return NULL; +} + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // } // End namespace Foam diff --git a/src/lagrangian/cfdemParticle/subModels/dataExchangeModel/twoWayMPI/twoWayMPI.H b/src/lagrangian/cfdemParticle/subModels/dataExchangeModel/twoWayMPI/twoWayMPI.H index 2efc605..1c06d5e 100644 --- a/src/lagrangian/cfdemParticle/subModels/dataExchangeModel/twoWayMPI/twoWayMPI.H +++ b/src/lagrangian/cfdemParticle/subModels/dataExchangeModel/twoWayMPI/twoWayMPI.H @@ -91,12 +91,13 @@ private: MPI_Comm comm_liggghts; - LAMMPS_NS::LAMMPS *lmp; - // private member functions char* wordToChar(word&) const; +protected: + LAMMPS_NS::LAMMPS *lmp; + public: //- Runtime type information @@ -118,6 +119,7 @@ public: // Member Functions + void getData ( word name, @@ -160,10 +162,12 @@ public: void destroy(int*) const; //============== - bool couple() const; + bool couple(int) const; int getNumberOfParticles() const; int getNumberOfClumps() const; + int getNumberOfTypes() const; + double* getTypeVol() const; word myType() const{return typeName; }; diff --git a/src/lagrangian/cfdemParticle/subModels/forceModel/Archimedes/Archimedes.C b/src/lagrangian/cfdemParticle/subModels/forceModel/Archimedes/Archimedes.C index b65f483..05120ce 100644 --- a/src/lagrangian/cfdemParticle/subModels/forceModel/Archimedes/Archimedes.C +++ b/src/lagrangian/cfdemParticle/subModels/forceModel/Archimedes/Archimedes.C @@ -63,8 +63,6 @@ Archimedes::Archimedes forceModel(dict,sm), propsDict_(dict.subDict(typeName + "Props")), twoDimensional_(false), - densityFieldName_(propsDict_.lookup("densityFieldName")), - rho_(sm.mesh().lookupObject (densityFieldName_)), gravityFieldName_(propsDict_.lookup("gravityFieldName")), #if defined(version21) || defined(version16ext) g_(sm.mesh().lookupObject (gravityFieldName_)) @@ -86,14 +84,25 @@ Archimedes::Archimedes Info << "2-dimensional simulation - make sure DEM side is 2D" << endl; } - if (propsDict_.found("treatExplicit")) treatExplicit_=true; - if (modelType_=="A"){ - treatDEM_=true; - Info << "accounting for Archimedes only on DEM side!" << endl; + // init force sub model + setForceSubModels(propsDict_); + + // define switches which can be read from dict + forceSubM(0).setSwitchesList(0,true); // activate treatExplicit switch + forceSubM(0).setSwitchesList(1,true); // activate treatForceDEM switch + forceSubM(0).readSwitches(); + + if (modelType_=="A" || modelType_=="Bfull"){ + if(!forceSubM(0).switches()[1]) // treatDEM != true + { + Warning << "Usually model type A and Bfull need Archimedes only on DEM side only (treatForceDEM=true)! are you sure about your settings?" << endl; + } } if (modelType_=="B"){ - treatDEM_=false; - Info << "accounting for Archimedes on DEM and CFD side!" << endl; + if(forceSubM(0).switches()[1]) // treatDEM = true + { + Warning << "Usually model type B needs Archimedes on CFD and DEM side (treatForceDEM=false)! are you sure about your settings?" << endl; + } } particleCloud_.checkCG(true); @@ -127,12 +136,21 @@ void Archimedes::setForce() const if(twoDimensional_) { - force = -g_.value()*rho_[cellI]*pow(dp,2)/4*M_PI; + force = -g_.value()*forceSubM(0).rhoField()[cellI]*pow(dp,2)/4*M_PI; Warning << "Archimedes::setForce() : this functionality is not tested!" << endl; }else{ - force = -g_.value()*rho_[cellI]*particleCloud_.particleVolume(index); + force = -g_.value()*forceSubM(0).rhoField()[cellI]*particleCloud_.particleVolume(index); } + //if(index >=0 && index <100) + //{ + // Pout << "cellI = " << cellI << endl; + // Pout << "index = " << index << endl; + // Pout << "forceSubM(0).rhoField()[cellI] = " << forceSubM(0).rhoField()[cellI] << endl; + // Pout << "particleCloud_.particleVolume(index) = " << particleCloud_.particleVolume(index) << endl; + // Pout << "force = " << force << endl; + //} + //Set value fields and write the probe if(probeIt_) { @@ -143,14 +161,8 @@ void Archimedes::setForce() const } } - if(!treatDEM_) - { - if(treatExplicit_) - for(int j=0;j<3;j++) expForces()[index][j] += force[j]; - else - for(int j=0;j<3;j++) impForces()[index][j] += force[j]; - } - for(int j=0;j<3;j++) DEMForces()[index][j] += force[j]; + // write particle based data to global array + forceSubM(0).partToArray(index,force,vector::zero); //} } } diff --git a/src/lagrangian/cfdemParticle/subModels/forceModel/Archimedes/Archimedes.H b/src/lagrangian/cfdemParticle/subModels/forceModel/Archimedes/Archimedes.H index 59747b8..41d3c51 100644 --- a/src/lagrangian/cfdemParticle/subModels/forceModel/Archimedes/Archimedes.H +++ b/src/lagrangian/cfdemParticle/subModels/forceModel/Archimedes/Archimedes.H @@ -63,10 +63,6 @@ private: bool twoDimensional_; - word densityFieldName_; - - const volScalarField& rho_; // ref to fluid density - word gravityFieldName_; #ifdef version21 diff --git a/src/lagrangian/cfdemParticle/subModels/forceModel/ArchimedesIB/ArchimedesIB.C b/src/lagrangian/cfdemParticle/subModels/forceModel/ArchimedesIB/ArchimedesIB.C index d2ab3da..846f43a 100644 --- a/src/lagrangian/cfdemParticle/subModels/forceModel/ArchimedesIB/ArchimedesIB.C +++ b/src/lagrangian/cfdemParticle/subModels/forceModel/ArchimedesIB/ArchimedesIB.C @@ -63,8 +63,6 @@ ArchimedesIB::ArchimedesIB forceModel(dict,sm), propsDict_(dict.subDict(typeName + "Props")), twoDimensional_(false), - densityFieldName_(propsDict_.lookup("densityFieldName")), - rho_(sm.mesh().lookupObject (densityFieldName_)), voidfractionFieldName_(propsDict_.lookup("voidfractionFieldName")), //mod by alice voidfractions_(sm.mesh().lookupObject (voidfractionFieldName_)),//mod by alice gravityFieldName_(propsDict_.lookup("gravityFieldName")), @@ -85,9 +83,18 @@ ArchimedesIB::ArchimedesIB Info << "2-dimensional simulation - make sure DEM side is 2D" << endl; } - if (propsDict_.found("treatExplicit")) treatExplicit_=true; - treatDEM_=true; + // init force sub model + setForceSubModels(propsDict_); + + // define switches which can be read from dict + forceSubM(0).setSwitchesList(0,true); // activate treatExplicit switch + + // read those switches defined above, if provided in dict + forceSubM(0).readSwitches(); + + forceSubM(0).setSwitches(1,true); // treatDEM = true Info << "accounting for Archimedes only on DEM side!" << endl; + particleCloud_.checkCG(true); } @@ -116,8 +123,8 @@ void ArchimedesIB::setForce() const label cellI = particleCloud_.cellIDs()[index][subCell]; if (cellI > -1) // particle Found { - //force += -g_.value()*rho_[cellI]*rho_.mesh().V()[cellI]*(1-particleCloud_.voidfractions()[index][subCell]);//mod by alice - force += -g_.value()*rho_[cellI]*rho_.mesh().V()[cellI]*(1-voidfractions_[cellI]);//mod by alice + //force += -g_.value()*forceSubM(0).rhoField()[cellI]*forceSubM(0).rhoField().mesh().V()[cellI]*(1-particleCloud_.voidfractions()[index][subCell]);//mod by alice + force += -g_.value()*forceSubM(0).rhoField()[cellI]*particleCloud_.mesh().V()[cellI]*(1-voidfractions_[cellI]);//mod by alice } } @@ -131,12 +138,9 @@ void ArchimedesIB::setForce() const // set force on particle if(twoDimensional_) Warning<<"ArchimedesIB model doesn't work for 2D right now!!\n"<< endl; - if(!treatDEM_) - { - if(treatExplicit_) for(int j=0;j<3;j++) expForces()[index][j] += force[j]; - else for(int j=0;j<3;j++) impForces()[index][j] += force[j]; - } - for(int j=0;j<3;j++) DEMForces()[index][j] += force[j]; + + // write particle based data to global array + forceSubM(0).partToArray(index,force,vector::zero); //} } } diff --git a/src/lagrangian/cfdemParticle/subModels/forceModel/ArchimedesIB/ArchimedesIB.H b/src/lagrangian/cfdemParticle/subModels/forceModel/ArchimedesIB/ArchimedesIB.H index a117e52..7b1ff8e 100644 --- a/src/lagrangian/cfdemParticle/subModels/forceModel/ArchimedesIB/ArchimedesIB.H +++ b/src/lagrangian/cfdemParticle/subModels/forceModel/ArchimedesIB/ArchimedesIB.H @@ -65,10 +65,6 @@ private: bool twoDimensional_; - word densityFieldName_; - - const volScalarField& rho_; // ref to fluid density - word voidfractionFieldName_; const volScalarField& voidfractions_; diff --git a/src/lagrangian/cfdemParticle/subModels/forceModel/DiFeliceDrag/DiFeliceDrag.C b/src/lagrangian/cfdemParticle/subModels/forceModel/DiFeliceDrag/DiFeliceDrag.C index b5b7c4c..674b0b3 100644 --- a/src/lagrangian/cfdemParticle/subModels/forceModel/DiFeliceDrag/DiFeliceDrag.C +++ b/src/lagrangian/cfdemParticle/subModels/forceModel/DiFeliceDrag/DiFeliceDrag.C @@ -64,15 +64,10 @@ DiFeliceDrag::DiFeliceDrag : forceModel(dict,sm), propsDict_(dict.subDict(typeName + "Props")), - verbose_(false), velFieldName_(propsDict_.lookup("velFieldName")), U_(sm.mesh().lookupObject (velFieldName_)), - densityFieldName_(propsDict_.lookup("densityFieldName")), - rho_(sm.mesh().lookupObject (densityFieldName_)), voidfractionFieldName_(propsDict_.lookup("voidfractionFieldName")), voidfraction_(sm.mesh().lookupObject (voidfractionFieldName_)), - interpolation_(false), - splitImplicitExplicit_(false), UsFieldName_(propsDict_.lookup("granVelFieldName")), UsField_(sm.mesh().lookupObject (UsFieldName_)), scaleDia_(1.), @@ -87,25 +82,24 @@ DiFeliceDrag::DiFeliceDrag particleCloud_.probeM().scalarFields_.append("voidfraction"); //other are debug particleCloud_.probeM().writeHeader(); - if (propsDict_.found("verbose")) verbose_=true; - if (propsDict_.found("treatExplicit")) treatExplicit_=true; - if (propsDict_.found("interpolation")) - { - Info << "using interpolated value of U." << endl; - interpolation_=true; - } - if (propsDict_.found("splitImplicitExplicit")) - { - Info << "will split implicit / explicit force contributions." << endl; - splitImplicitExplicit_ = true; - if(!interpolation_) - Info << "WARNING: will only consider fluctuating particle velocity in implicit / explicit force split!" << endl; - } particleCloud_.checkCG(true); if (propsDict_.found("scale")) scaleDia_=scalar(readScalar(propsDict_.lookup("scale"))); if (propsDict_.found("scaleDrag")) scaleDrag_=scalar(readScalar(propsDict_.lookup("scaleDrag"))); + + // init force sub model + setForceSubModels(propsDict_); + + // define switches which can be read from dict + forceSubM(0).setSwitchesList(0,true); // activate treatExplicit switch + forceSubM(0).setSwitchesList(2,true); // activate implDEM switch + forceSubM(0).setSwitchesList(3,true); // activate search for verbose switch + forceSubM(0).setSwitchesList(4,true); // activate search for interpolate switch + forceSubM(0).setSwitchesList(8,true); // activate scalarViscosity switch + + // read those switches defined above, if provided in dict + forceSubM(0).readSwitches(); } @@ -125,18 +119,16 @@ void DiFeliceDrag::setForce() const scaleDia_=particleCloud_.cg(); Info << "DiFeliceDrag using scale from liggghts cg = " << scaleDia_ << endl; } - - // get viscosity field - #ifdef comp - const volScalarField nufField = particleCloud_.turbulence().mu() / rho_; - #else - const volScalarField& nufField = particleCloud_.turbulence().nu(); - #endif + const volScalarField& nufField = forceSubM(0).nuField(); + const volScalarField& rhoField = forceSubM(0).rhoField(); + vector position(0,0,0); scalar voidfraction(1); vector Ufluid(0,0,0); vector drag(0,0,0); + vector dragExplicit(0,0,0); + scalar dragCoefficient(0); label cellI=0; vector Us(0,0,0); vector Ur(0,0,0); @@ -147,11 +139,6 @@ void DiFeliceDrag::setForce() const scalar Rep(0); scalar Cd(0); - vector UfluidFluct(0,0,0); - vector UsFluct(0,0,0); - vector dragExplicit(0,0,0); - scalar dragCoefficient(0); - interpolationCellPoint voidfractionInterpolator_(voidfraction_); interpolationCellPoint UInterpolator_(U_); @@ -159,15 +146,15 @@ void DiFeliceDrag::setForce() const for(int index = 0;index < particleCloud_.numberOfParticles(); index++) { - //if(mask[index][0]) - //{ - cellI = particleCloud_.cellIDs()[index][0]; drag = vector(0,0,0); + dragExplicit = vector(0,0,0); + dragCoefficient=0; + Ufluid =vector(0,0,0); if (cellI > -1) // particle Found { - if(interpolation_) + if(forceSubM(0).interpolation()) { position = particleCloud_.position(index); voidfraction = voidfractionInterpolator_.interpolate(position,cellI); @@ -182,11 +169,10 @@ void DiFeliceDrag::setForce() const Ur = Ufluid-Us; ds = 2*particleCloud_.radius(index); nuf = nufField[cellI]; - rho = rho_[cellI]; + rho = rhoField[cellI]; magUr = mag(Ur); Rep = 0; Cd = 0; - dragCoefficient = 0; if (magUr > 0) { @@ -212,16 +198,10 @@ void DiFeliceDrag::setForce() const drag = dragCoefficient*Ur; //total drag force! - //Split forces - if(splitImplicitExplicit_) - { - UfluidFluct = Ufluid - U_[cellI]; - UsFluct = Us - UsField_[cellI]; - dragExplicit = dragCoefficient*(UfluidFluct - UsFluct); //explicit part of force - } + forceSubM(0).explicitCorr(drag,dragExplicit,dragCoefficient,Ufluid,U_[cellI],Us,UsField_[cellI],forceSubM(0).verbose(),index); } - if(verbose_ && index >-1 && index <102) + if(forceSubM(0).verbose() && index >-1 && index <102) { Pout << "index = " << index << endl; Pout << "Us = " << Us << endl; @@ -233,12 +213,6 @@ void DiFeliceDrag::setForce() const Pout << "Rep = " << Rep << endl; Pout << "Cd = " << Cd << endl; Pout << "drag (total) = " << drag << endl; - if(splitImplicitExplicit_) - { - Pout << "UfluidFluct = " << UfluidFluct << endl; - Pout << "UsFluct = " << UsFluct << endl; - Pout << "dragExplicit = " << dragExplicit << endl; - } } //Set value fields and write the probe @@ -253,20 +227,10 @@ void DiFeliceDrag::setForce() const particleCloud_.probeM().writeProbe(index, sValues, vValues); } } - // set force on particle - if(treatExplicit_) for(int j=0;j<3;j++) expForces()[index][j] += drag[j]; - else //implicit treatment, taking explicit force contribution into account - { - for(int j=0;j<3;j++) - { - impForces()[index][j] += drag[j] - dragExplicit[j]; //only consider implicit part! - expForces()[index][j] += dragExplicit[j]; - } - } - - for(int j=0;j<3;j++) DEMForces()[index][j] += drag[j]; + + // write particle based data to global array + forceSubM(0).partToArray(index,drag,dragExplicit,Ufluid,dragCoefficient); } - //} } diff --git a/src/lagrangian/cfdemParticle/subModels/forceModel/DiFeliceDrag/DiFeliceDrag.H b/src/lagrangian/cfdemParticle/subModels/forceModel/DiFeliceDrag/DiFeliceDrag.H index 5d788bf..a043b28 100644 --- a/src/lagrangian/cfdemParticle/subModels/forceModel/DiFeliceDrag/DiFeliceDrag.H +++ b/src/lagrangian/cfdemParticle/subModels/forceModel/DiFeliceDrag/DiFeliceDrag.H @@ -60,24 +60,14 @@ class DiFeliceDrag private: dictionary propsDict_; - bool verbose_; - word velFieldName_; const volVectorField& U_; - word densityFieldName_; - - const volScalarField& rho_; - word voidfractionFieldName_; const volScalarField& voidfraction_; - bool interpolation_; // use interpolated U field values - - bool splitImplicitExplicit_; // use splitting of implicit and explict force contribution - word UsFieldName_; const volVectorField& UsField_; // the average particle velocity field (for implicit/expliti force split) diff --git a/src/lagrangian/cfdemParticle/subModels/forceModel/GidaspowDrag/GidaspowDrag.C b/src/lagrangian/cfdemParticle/subModels/forceModel/GidaspowDrag/GidaspowDrag.C index c4f8e88..eaaeb94 100644 --- a/src/lagrangian/cfdemParticle/subModels/forceModel/GidaspowDrag/GidaspowDrag.C +++ b/src/lagrangian/cfdemParticle/subModels/forceModel/GidaspowDrag/GidaspowDrag.C @@ -63,17 +63,16 @@ GidaspowDrag::GidaspowDrag : forceModel(dict,sm), propsDict_(dict.subDict(typeName + "Props")), - verbose_(false), velFieldName_(propsDict_.lookup("velFieldName")), U_(sm.mesh().lookupObject (velFieldName_)), - densityFieldName_(propsDict_.lookup("densityFieldName")), - rho_(sm.mesh().lookupObject (densityFieldName_)), voidfractionFieldName_(propsDict_.lookup("voidfractionFieldName")), voidfraction_(sm.mesh().lookupObject (voidfractionFieldName_)), phi_(readScalar(propsDict_.lookup("phi"))), - interpolation_(false), + UsFieldName_(propsDict_.lookup("granVelFieldName")), + UsField_(sm.mesh().lookupObject (UsFieldName_)), scaleDia_(1.), - scaleDrag_(1.) + scaleDrag_(1.), + switchingVoidfraction_(0.8) { //Append the field names to be probed particleCloud_.probeM().initialize(typeName, "gidaspowDrag.logDat"); @@ -84,23 +83,24 @@ GidaspowDrag::GidaspowDrag particleCloud_.probeM().scalarFields_.append("voidfraction"); particleCloud_.probeM().writeHeader(); - if (propsDict_.found("verbose")) verbose_=true; - if (propsDict_.found("treatExplicit")) treatExplicit_=true; - if (propsDict_.found("interpolation")) interpolation_=true; - if (propsDict_.found("implDEM")) - { - treatExplicit_=false; - implDEM_=true; - setImpDEMdrag(); - Info << "Using implicit DEM drag formulation." << endl; - } + // init force sub model + setForceSubModels(propsDict_); + // define switches which can be read from dict + forceSubM(0).setSwitchesList(0,true); // activate treatExplicit switch + forceSubM(0).setSwitchesList(2,true); // activate implDEM switch + forceSubM(0).setSwitchesList(3,true); // activate search for verbose switch + forceSubM(0).setSwitchesList(4,true); // activate search for interpolate switch + forceSubM(0).setSwitchesList(8,true); // activate scalarViscosity switch + forceSubM(0).readSwitches(); + particleCloud_.checkCG(true); if (propsDict_.found("scale")) scaleDia_=scalar(readScalar(propsDict_.lookup("scale"))); if (propsDict_.found("scaleDrag")) scaleDrag_=scalar(readScalar(propsDict_.lookup("scaleDrag"))); - Info << "Gidaspow - interpolation switch: " << interpolation_ << endl; + if (propsDict_.found("switchingVoidfraction")) + switchingVoidfraction_ = readScalar(propsDict_.lookup("switchingVoidfraction")); } @@ -121,12 +121,8 @@ void GidaspowDrag::setForce() const Info << "Gidaspow using scale from liggghts cg = " << scaleDia_ << endl; } - // get viscosity field - #ifdef comp - const volScalarField nufField = particleCloud_.turbulence().mu() / rho_; - #else - const volScalarField& nufField = particleCloud_.turbulence().nu(); - #endif + const volScalarField& nufField = forceSubM(0).nuField(); + const volScalarField& rhoField = forceSubM(0).rhoField(); vector position(0,0,0); scalar voidfraction(1); @@ -145,9 +141,11 @@ void GidaspowDrag::setForce() const scalar localPhiP(0); scalar CdMagUrLag(0); //Cd of the very particle - scalar KslLag(0); //momentum exchange of the very particle (per unit volume) scalar betaP(0); //momentum exchange of the very particle + vector dragExplicit(0,0,0); + scalar dragCoefficient(0); + interpolationCellPoint voidfractionInterpolator_(voidfraction_); interpolationCellPoint UInterpolator_(U_); @@ -159,15 +157,17 @@ void GidaspowDrag::setForce() const //{ cellI = particleCloud_.cellIDs()[index][0]; drag = vector(0,0,0); + dragExplicit = vector(0,0,0); betaP = 0; Vs = 0; Ufluid =vector(0,0,0); voidfraction=0; + dragCoefficient = 0; if (cellI > -1) // particle Found { - if(interpolation_) + if( forceSubM(0).interpolation() ) { position = particleCloud_.position(index); voidfraction = voidfractionInterpolator_.interpolate(position,cellI); @@ -186,46 +186,47 @@ void GidaspowDrag::setForce() const Us = particleCloud_.velocity(index); Ur = Ufluid-Us; magUr = mag(Ur); - ds = 2*particleCloud_.radius(index)*phi_; - rho = rho_[cellI]; + ds = 2*particleCloud_.radius(index); + rho = rhoField[cellI]; nuf = nufField[cellI]; Rep=0.0; localPhiP = 1.0f-voidfraction+SMALL; Vs = ds*ds*ds*M_PI/6; - //Compute specific drag coefficient (i.e., Force per unit slip velocity and per m³ SUSPENSION) - if(voidfraction > 0.8) //dilute + // calc particle's drag coefficient (i.e., Force per unit slip velocity and per m³ PARTICLE) + if(voidfraction > switchingVoidfraction_) //dilute { Rep=ds/scaleDia_*voidfraction*magUr/nuf; - CdMagUrLag = (24.0*nuf/(ds/scaleDia_*voidfraction)) //1/magUr missing here, but compensated in expression for KslLag! - *(scalar(1)+0.15*Foam::pow(Rep, 0.687)); + CdMagUrLag = (24.0*nuf/(ds/scaleDia_*voidfraction)) //1/magUr missing here, but compensated in expression for betaP! + *(scalar(1.0)+0.15*Foam::pow(Rep, 0.687)); - KslLag = 0.75*( - rho*localPhiP*voidfraction*CdMagUrLag + betaP = 0.75*( //this is betaP = beta / localPhiP! + rho*voidfraction*CdMagUrLag / (ds/scaleDia_*Foam::pow(voidfraction,2.65)) ); } else //dense { - KslLag = (150*Foam::pow(localPhiP,2)*nuf*rho)/ - (voidfraction*ds/scaleDia_*ds/scaleDia_+SMALL) + betaP = (150 * localPhiP*nuf*rho) //this is betaP = beta / localPhiP! + / (voidfraction*ds/scaleDia_*phi_*ds/scaleDia_*phi_) + - (1.75*(localPhiP) * magUr * rho)/ - ((ds/scaleDia_)); + (1.75 * magUr * rho) + /((ds/scaleDia_*phi_)); } - // calc particle's drag coefficient (i.e., Force per unit slip velocity and per m³ PARTICLE) - betaP = KslLag / localPhiP; - // calc particle's drag - drag = Vs * betaP * Ur * scaleDrag_; - + dragCoefficient = Vs*betaP*scaleDrag_; if (modelType_=="B") - drag /= voidfraction; + dragCoefficient /= voidfraction; - if(verbose_ && index >=0 && index <2) + drag = dragCoefficient * Ur; + + // explicitCorr + forceSubM(0).explicitCorr(drag,dragExplicit,dragCoefficient,Ufluid,U_[cellI],Us,UsField_[cellI],forceSubM(0).verbose()); + + if(forceSubM(0).verbose() && index >=0 && index <2) { Pout << "cellI = " << cellI << endl; Pout << "index = " << index << endl; @@ -255,23 +256,8 @@ void GidaspowDrag::setForce() const } } - // set force on particle - if(treatExplicit_) for(int j=0;j<3;j++) expForces()[index][j] += drag[j]; - else for(int j=0;j<3;j++) impForces()[index][j] += drag[j]; - - // set Cd - if(implDEM_) - { - for(int j=0;j<3;j++) fluidVel()[index][j]=Ufluid[j]; - - if (modelType_=="B" && cellI > -1) - Cds()[index][0] = Vs*betaP/voidfraction*scaleDrag_; - else - Cds()[index][0] = Vs*betaP*scaleDrag_; - - }else{ - for(int j=0;j<3;j++) DEMForces()[index][j] += drag[j]; - } + // write particle based data to global array + forceSubM(0).partToArray(index,drag,dragExplicit,Ufluid,dragCoefficient); //}// end if mask }// end loop particles diff --git a/src/lagrangian/cfdemParticle/subModels/forceModel/GidaspowDrag/GidaspowDrag.H b/src/lagrangian/cfdemParticle/subModels/forceModel/GidaspowDrag/GidaspowDrag.H index 978ca69..61c7d19 100644 --- a/src/lagrangian/cfdemParticle/subModels/forceModel/GidaspowDrag/GidaspowDrag.H +++ b/src/lagrangian/cfdemParticle/subModels/forceModel/GidaspowDrag/GidaspowDrag.H @@ -31,6 +31,8 @@ Description Gidaspow drag law - only valid for low-Reynolds number systems (Re_p<1000) - including interpolation of the velocity to the exact position + - splits off explicit drag component due to fluctuation in fluid and particle + velocity (optional via forceSubModel "ImExCorr") Class GidaspowDrag @@ -62,28 +64,26 @@ class GidaspowDrag private: dictionary propsDict_; - bool verbose_; - word velFieldName_; const volVectorField& U_; - word densityFieldName_; - - const volScalarField& rho_; - word voidfractionFieldName_; const volScalarField& voidfraction_; const scalar phi_; - bool interpolation_; // use interpolated field values + word UsFieldName_; + + const volVectorField& UsField_; // the average particle velocity field mutable scalar scaleDia_; mutable scalar scaleDrag_; + mutable scalar switchingVoidfraction_; //voidfraction above which dilute formulation will be used + public: //- Runtime type information diff --git a/src/lagrangian/cfdemParticle/subModels/forceModel/KochHillDrag/KochHillDrag.C b/src/lagrangian/cfdemParticle/subModels/forceModel/KochHillDrag/KochHillDrag.C index 4dc7802..e722e9a 100644 --- a/src/lagrangian/cfdemParticle/subModels/forceModel/KochHillDrag/KochHillDrag.C +++ b/src/lagrangian/cfdemParticle/subModels/forceModel/KochHillDrag/KochHillDrag.C @@ -64,14 +64,12 @@ KochHillDrag::KochHillDrag : forceModel(dict,sm), propsDict_(dict.subDict(typeName + "Props")), - verbose_(false), velFieldName_(propsDict_.lookup("velFieldName")), U_(sm.mesh().lookupObject (velFieldName_)), - densityFieldName_(propsDict_.lookup("densityFieldName")), - rho_(sm.mesh().lookupObject (densityFieldName_)), voidfractionFieldName_(propsDict_.lookup("voidfractionFieldName")), voidfraction_(sm.mesh().lookupObject (voidfractionFieldName_)), - interpolation_(false), + UsFieldName_(propsDict_.lookupOrDefault("granVelFieldName",word("Us"))), + UsField_(sm.mesh().lookupObject (UsFieldName_)), scaleDia_(1.), scaleDrag_(1.) { @@ -84,16 +82,20 @@ KochHillDrag::KochHillDrag particleCloud_.probeM().scalarFields_.append("voidfraction"); //other are debug particleCloud_.probeM().writeHeader(); - if (propsDict_.found("verbose")) verbose_=true; - if (propsDict_.found("treatExplicit")) treatExplicit_=true; - if (propsDict_.found("interpolation")) interpolation_=true; - if (propsDict_.found("implDEM")) - { - treatExplicit_=false; - implDEM_=true; - setImpDEMdrag(); - Info << "Using implicit DEM drag formulation." << endl; - } + // init force sub model + setForceSubModels(propsDict_); + + // define switches which can be read from dict + forceSubM(0).setSwitchesList(0,true); // activate treatExplicit switch + forceSubM(0).setSwitchesList(2,true); // activate implDEM switch + forceSubM(0).setSwitchesList(3,true); // activate search for verbose switch + forceSubM(0).setSwitchesList(4,true); // activate search for interpolate switch + forceSubM(0).setSwitchesList(7,true); // activate implForceDEMacc switch + forceSubM(0).setSwitchesList(8,true); // activate scalarViscosity switch + + // read those switches defined above, if provided in dict + forceSubM(0).readSwitches(); + particleCloud_.checkCG(true); if (propsDict_.found("scale")) @@ -120,17 +122,15 @@ void KochHillDrag::setForce() const Info << "KochHill using scale from liggghts cg = " << scaleDia_ << endl; } - // get viscosity field - #ifdef comp - const volScalarField nufField = particleCloud_.turbulence().mu()/rho_; - #else - const volScalarField& nufField = particleCloud_.turbulence().nu(); - #endif + const volScalarField& nufField = forceSubM(0).nuField(); + const volScalarField& rhoField = forceSubM(0).rhoField(); vector position(0,0,0); scalar voidfraction(1); vector Ufluid(0,0,0); vector drag(0,0,0); + vector dragExplicit(0,0,0); + scalar dragCoefficient(0); label cellI=0; vector Us(0,0,0); @@ -144,6 +144,8 @@ void KochHillDrag::setForce() const scalar volumefraction(0); scalar betaP(0); + int couplingInterval(particleCloud_.dataExchangeM().couplingInterval()); + interpolationCellPoint voidfractionInterpolator_(voidfraction_); interpolationCellPoint UInterpolator_(U_); @@ -151,10 +153,10 @@ void KochHillDrag::setForce() const for(int index = 0;index < particleCloud_.numberOfParticles(); index++) { - //if(mask[index][0]) - //{ cellI = particleCloud_.cellIDs()[index][0]; drag = vector(0,0,0); + dragExplicit = vector(0,0,0); + dragCoefficient=0; betaP = 0; Vs = 0; Ufluid =vector(0,0,0); @@ -162,7 +164,7 @@ void KochHillDrag::setForce() const if (cellI > -1) // particle Found { - if(interpolation_) + if(forceSubM(0).interpolation()) { position = particleCloud_.position(index); voidfraction = voidfractionInterpolator_.interpolate(position,cellI); @@ -181,11 +183,11 @@ void KochHillDrag::setForce() const Ur = Ufluid-Us; ds = particleCloud_.d(index); nuf = nufField[cellI]; - rho = rho_[cellI]; + rho = rhoField[cellI]; magUr = mag(Ur); Rep = 0; Vs = ds*ds*ds*M_PI/6; - volumefraction = 1-voidfraction+SMALL; + volumefraction = max(SMALL,min(1-SMALL,1-voidfraction)); if (magUr > 0) { @@ -209,20 +211,32 @@ void KochHillDrag::setForce() const // calc model coefficient F3 scalar F3 = 0.0673+0.212*volumefraction+0.0232/pow(voidfraction,5); - //Calculate F + //Calculate F (the factor 0.5 is introduced, since Koch and Hill, ARFM 33:619–47, use the radius + //to define Rep, and we use the particle diameter, see vanBuijtenen et al., CES 66:2368–2376. scalar F = voidfraction * (F0 + 0.5*F3*Rep); // calc drag model coefficient betaP betaP = 18.*nuf*rho/(ds/scaleDia_*ds/scaleDia_)*voidfraction*F; // calc particle's drag - drag = Vs*betaP*Ur*scaleDrag_; - + dragCoefficient = Vs*betaP*scaleDrag_; if (modelType_=="B") - drag /= voidfraction; + dragCoefficient /= voidfraction; + + if(forceSubM(0).switches()[7]) // implForceDEMaccumulated=true + { + //get drag from the particle itself + for (int j=0 ; j<3 ; j++) drag[j] = particleCloud_.fAccs()[index][j]/couplingInterval; + }else + { + drag = dragCoefficient * Ur; + + // explicitCorr + forceSubM(0).explicitCorr(drag,dragExplicit,dragCoefficient,Ufluid,U_[cellI],Us,UsField_[cellI],forceSubM(0).verbose()); + } } - if(verbose_ && index >=0 && index <2) + if(forceSubM(0).verbose() && index >=0 && index <2) { Pout << "cellI = " << cellI << endl; Pout << "index = " << index << endl; @@ -250,25 +264,9 @@ void KochHillDrag::setForce() const particleCloud_.probeM().writeProbe(index, sValues, vValues); } } - // set force on particle - if(treatExplicit_) for(int j=0;j<3;j++) expForces()[index][j] += drag[j]; - else for(int j=0;j<3;j++) impForces()[index][j] += drag[j]; - // set Cd - if(implDEM_) - { - for(int j=0;j<3;j++) fluidVel()[index][j]=Ufluid[j]; - - if (modelType_=="B" && cellI > -1) - Cds()[index][0] = Vs*betaP/voidfraction*scaleDrag_; - else - Cds()[index][0] = Vs*betaP*scaleDrag_; - - }else{ - for(int j=0;j<3;j++) DEMForces()[index][j] += drag[j]; - } - - //} + // write particle based data to global array + forceSubM(0).partToArray(index,drag,dragExplicit,Ufluid,dragCoefficient); } } diff --git a/src/lagrangian/cfdemParticle/subModels/forceModel/KochHillDrag/KochHillDrag.H b/src/lagrangian/cfdemParticle/subModels/forceModel/KochHillDrag/KochHillDrag.H index 8937a45..95d6712 100644 --- a/src/lagrangian/cfdemParticle/subModels/forceModel/KochHillDrag/KochHillDrag.H +++ b/src/lagrangian/cfdemParticle/subModels/forceModel/KochHillDrag/KochHillDrag.H @@ -64,21 +64,17 @@ class KochHillDrag private: dictionary propsDict_; - bool verbose_; - word velFieldName_; const volVectorField& U_; - word densityFieldName_; - - const volScalarField& rho_; - word voidfractionFieldName_; const volScalarField& voidfraction_; - bool interpolation_; // use interpolated field values + word UsFieldName_; + + const volVectorField& UsField_; mutable scalar scaleDia_; diff --git a/src/lagrangian/cfdemParticle/subModels/forceModel/LaEuScalarTemp/LaEuScalarTemp.C b/src/lagrangian/cfdemParticle/subModels/forceModel/LaEuScalarTemp/LaEuScalarTemp.C index d92e225..57a5da6 100644 --- a/src/lagrangian/cfdemParticle/subModels/forceModel/LaEuScalarTemp/LaEuScalarTemp.C +++ b/src/lagrangian/cfdemParticle/subModels/forceModel/LaEuScalarTemp/LaEuScalarTemp.C @@ -63,7 +63,6 @@ LaEuScalarTemp::LaEuScalarTemp : forceModel(dict,sm), propsDict_(dict.subDict(typeName + "Props")), - verbose_(false), tempFieldName_(propsDict_.lookup("tempFieldName")), tempField_(sm.mesh().lookupObject (tempFieldName_)), voidfractionFieldName_(propsDict_.lookup("voidfractionFieldName")), @@ -76,10 +75,7 @@ LaEuScalarTemp::LaEuScalarTemp partHeatFluxName_(propsDict_.lookup("partHeatFluxName")), partHeatFlux_(NULL), lambda_(readScalar(propsDict_.lookup("lambda"))), - Cp_(readScalar(propsDict_.lookup("Cp"))), - densityFieldName_(propsDict_.lookup("densityFieldName")), - rho_(sm.mesh().lookupObject (densityFieldName_)), - interpolation_(false) + Cp_(readScalar(propsDict_.lookup("Cp"))) { allocateMyArrays(); @@ -88,10 +84,18 @@ LaEuScalarTemp::LaEuScalarTemp maxSource_=readScalar(propsDict_.lookup ("maxSource")); Info << "limiting eulerian source field to: " << maxSource_ << endl; } - if (propsDict_.found("interpolation")) interpolation_=true; - if (propsDict_.found("verbose")) verbose_=true; -Info << "verbose_" << verbose_ << endl; + // init force sub model + setForceSubModels(propsDict_); + + // define switches which can be read from dict + forceSubM(0).setSwitchesList(3,true); // activate search for verbose switch + forceSubM(0).setSwitchesList(4,true); // activate search for interpolate switch + forceSubM(0).setSwitchesList(8,true); // activate scalarViscosity switch + + // read those switches defined above, if provided in dict + forceSubM(0).readSwitches(); + particleCloud_.checkCG(false); } @@ -131,12 +135,8 @@ void LaEuScalarTemp::manipulateScalarField(volScalarField& EuField) const // get DEM data particleCloud_.dataExchangeM().getData(partTempName_,"scalar-atom",partTemp_); - // get viscosity field - #ifdef comp - const volScalarField& nufField = particleCloud_.turbulence().mu() / rho_; - #else - const volScalarField& nufField = particleCloud_.turbulence().nu(); - #endif + const volScalarField& nufField = forceSubM(0).nuField(); + const volScalarField& rhoField = forceSubM(0).rhoField(); // calc La based heat flux vector position(0,0,0); @@ -158,6 +158,8 @@ void LaEuScalarTemp::manipulateScalarField(volScalarField& EuField) const interpolationCellPoint UInterpolator_(U_); interpolationCellPoint TInterpolator_(tempField_); + scalar h1(0); + scalar h2(0); for(int index = 0;index < particleCloud_.numberOfParticles(); ++index) { //if(particleCloud_.regionM().inRegion()[index][0]) @@ -165,7 +167,7 @@ void LaEuScalarTemp::manipulateScalarField(volScalarField& EuField) const cellI = particleCloud_.cellIDs()[index][0]; if(cellI >= 0) { - if(interpolation_) + if(forceSubM(0).interpolation()) { position = particleCloud_.position(index); voidfraction = voidfractionInterpolator_.interpolate(position,cellI); @@ -185,7 +187,7 @@ void LaEuScalarTemp::manipulateScalarField(volScalarField& EuField) const As = ds*ds*M_PI; nuf = nufField[cellI]; Rep = ds*magUr/nuf; - Pr = Cp_*nuf*rho_[cellI]/lambda_; + Pr = max(SMALL,Cp_*nuf*rhoField[cellI]/lambda_); if (Rep < 200) { @@ -193,8 +195,9 @@ void LaEuScalarTemp::manipulateScalarField(volScalarField& EuField) const } else if (Rep < 1500) { - Nup = 2+0.5*pow(voidfraction,n)*sqrt(Rep)*pow(Pr,0.33) - +0.02*pow(voidfraction,n)*pow(Rep,0.8)*pow(Pr,0.33); + h1=pow(voidfraction,n); + h2=pow(Pr,0.33); + Nup = 2+0.5*h1*sqrt(Rep)*h2+0.02*h1*pow(Rep,0.8)*h2; } else { @@ -207,7 +210,7 @@ void LaEuScalarTemp::manipulateScalarField(volScalarField& EuField) const partHeatFlux_[index][0] = partHeatFlux; - if(verbose_ && index >=0 && index <2) + if(forceSubM(0).verbose() && index >=0 && index <2) { Info << "partHeatFlux = " << partHeatFlux << endl; Info << "magUr = " << magUr << endl; @@ -233,7 +236,7 @@ void LaEuScalarTemp::manipulateScalarField(volScalarField& EuField) const ); // scale with -1/(Vcell*rho*Cp) - EuField.internalField() /= -rho_.internalField()*Cp_*EuField.mesh().V(); + EuField.internalField() /= -rhoField.internalField()*Cp_*EuField.mesh().V(); // limit source term scalar EuFieldInCell; @@ -247,7 +250,7 @@ void LaEuScalarTemp::manipulateScalarField(volScalarField& EuField) const } } - Info << "total convective particle-fluid heat flux [W] (Eulerian) = " << gSum(EuField*rho_*Cp_*EuField.mesh().V()) << endl; + Info << "total convective particle-fluid heat flux [W] (Eulerian) = " << gSum(EuField*rhoField*Cp_*EuField.mesh().V()) << endl; // give DEM data particleCloud_.dataExchangeM().giveData(partHeatFluxName_,"scalar-atom", partHeatFlux_); diff --git a/src/lagrangian/cfdemParticle/subModels/forceModel/LaEuScalarTemp/LaEuScalarTemp.H b/src/lagrangian/cfdemParticle/subModels/forceModel/LaEuScalarTemp/LaEuScalarTemp.H index fe72dc0..01e6354 100644 --- a/src/lagrangian/cfdemParticle/subModels/forceModel/LaEuScalarTemp/LaEuScalarTemp.H +++ b/src/lagrangian/cfdemParticle/subModels/forceModel/LaEuScalarTemp/LaEuScalarTemp.H @@ -65,8 +65,6 @@ private: dictionary propsDict_; - bool verbose_; - word tempFieldName_; const volScalarField& tempField_; // ref to temperature field @@ -93,12 +91,6 @@ private: scalar Cp_; // specific heat capacity [W*s/(kg*K)] - word densityFieldName_; - - const volScalarField& rho_; // ref to fluid density field - - bool interpolation_; // use interpolated field values - void allocateMyArrays() const; public: diff --git a/src/lagrangian/cfdemParticle/subModels/forceModel/MeiLift/MeiLift.C b/src/lagrangian/cfdemParticle/subModels/forceModel/MeiLift/MeiLift.C index 38d5527..cc745a4 100644 --- a/src/lagrangian/cfdemParticle/subModels/forceModel/MeiLift/MeiLift.C +++ b/src/lagrangian/cfdemParticle/subModels/forceModel/MeiLift/MeiLift.C @@ -66,22 +66,20 @@ MeiLift::MeiLift propsDict_(dict.subDict(typeName + "Props")), velFieldName_(propsDict_.lookup("velFieldName")), U_(sm.mesh().lookupObject (velFieldName_)), - densityFieldName_(propsDict_.lookup("densityFieldName")), - rho_(sm.mesh().lookupObject (densityFieldName_)), - useSecondOrderTerms_(false), - interpolation_(false), - verbose_(false) -/*, - vorticityFieldName_(propsDict_.lookup("vorticityFieldName")), - vorticity_(sm.mesh().lookupObject (vorticityFieldName_))*/ + useSecondOrderTerms_(false) { if (propsDict_.found("useSecondOrderTerms")) useSecondOrderTerms_=true; - if (propsDict_.found("treatExplicit")) treatExplicit_=true; - if (propsDict_.found("interpolation")) interpolation_=true; - if (propsDict_.found("verbose")) verbose_=true; + // init force sub model + setForceSubModels(propsDict_); + // define switches which can be read from dict + forceSubM(0).setSwitchesList(0,true); // activate treatExplicit switch + forceSubM(0).setSwitchesList(3,true); // activate search for verbose switch + forceSubM(0).setSwitchesList(4,true); // activate search for interpolate switch + forceSubM(0).setSwitchesList(8,true); // activate scalarViscosity switch + forceSubM(0).readSwitches(); - particleCloud_.checkCG(false); + particleCloud_.checkCG(false); //Append the field names to be probed particleCloud_.probeM().initialize(typeName, "meiLift.logDat"); @@ -106,12 +104,8 @@ MeiLift::~MeiLift() void MeiLift::setForce() const { - // get viscosity field - #ifdef comp - const volScalarField nufField = particleCloud_.turbulence().mu() / rho_; - #else - const volScalarField& nufField = particleCloud_.turbulence().nu(); - #endif + const volScalarField& nufField = forceSubM(0).nuField(); + const volScalarField& rhoField = forceSubM(0).rhoField(); vector position(0,0,0); vector lift(0,0,0); @@ -151,7 +145,7 @@ void MeiLift::setForce() const { Us = particleCloud_.velocity(index); - if(interpolation_) + if( forceSubM(0).interpolation() ) { position = particleCloud_.position(index); Ur = UInterpolator_.interpolate(position,cellI) @@ -172,7 +166,7 @@ void MeiLift::setForce() const { ds = 2*particleCloud_.radius(index); nuf = nufField[cellI]; - rho = rho_[cellI]; + rho = rhoField[cellI]; // calc dimensionless properties Rep = ds*magUr/nuf; @@ -228,7 +222,7 @@ void MeiLift::setForce() const //********************************** //SAMPLING AND VERBOSE OUTOUT - if(verbose_ ) + if( forceSubM(0).verbose() ) { Pout << "index = " << index << endl; Pout << "Us = " << Us << endl; @@ -261,13 +255,8 @@ void MeiLift::setForce() const //********************************** } - // set force on particle - if(!treatDEM_) - { - if(!treatExplicit_) for(int j=0;j<3;j++) impForces()[index][j] += lift[j]; - else for(int j=0;j<3;j++) expForces()[index][j] += lift[j]; - } - for(int j=0;j<3;j++) DEMForces()[index][j] += lift[j]; + // write particle based data to global array + forceSubM(0).partToArray(index,lift,vector::zero); //} } diff --git a/src/lagrangian/cfdemParticle/subModels/forceModel/MeiLift/MeiLift.H b/src/lagrangian/cfdemParticle/subModels/forceModel/MeiLift/MeiLift.H index 86eb066..6a6016b 100644 --- a/src/lagrangian/cfdemParticle/subModels/forceModel/MeiLift/MeiLift.H +++ b/src/lagrangian/cfdemParticle/subModels/forceModel/MeiLift/MeiLift.H @@ -80,20 +80,8 @@ private: const volVectorField& U_; - word densityFieldName_; - - const volScalarField& rho_; - bool useSecondOrderTerms_; - bool interpolation_; - - bool verbose_; - - /*word vorticityFieldName_; - - volVectorField& vorticity_;*/ - public: //- Runtime type information diff --git a/src/lagrangian/cfdemParticle/subModels/forceModel/SchillerNaumannDrag/SchillerNaumannDrag.C b/src/lagrangian/cfdemParticle/subModels/forceModel/SchillerNaumannDrag/SchillerNaumannDrag.C index 0630b0f..6aa7f20 100644 --- a/src/lagrangian/cfdemParticle/subModels/forceModel/SchillerNaumannDrag/SchillerNaumannDrag.C +++ b/src/lagrangian/cfdemParticle/subModels/forceModel/SchillerNaumannDrag/SchillerNaumannDrag.C @@ -66,9 +66,7 @@ SchillerNaumannDrag::SchillerNaumannDrag propsDict_(dict.subDict(typeName + "Props")), verbose_(false), velFieldName_(propsDict_.lookup("velFieldName")), - U_(sm.mesh().lookupObject (velFieldName_)), - densityFieldName_(propsDict_.lookup("densityFieldName")), - rho_(sm.mesh().lookupObject (densityFieldName_)) + U_(sm.mesh().lookupObject (velFieldName_)) { //Append the field names to be probed particleCloud_.probeM().initialize(typeName, "schillerNaumannDrag.logDat"); @@ -79,7 +77,16 @@ SchillerNaumannDrag::SchillerNaumannDrag particleCloud_.probeM().writeHeader(); if (propsDict_.found("verbose")) verbose_=true; - if (propsDict_.found("treatExplicit")) treatExplicit_=true; + + // init force sub model + setForceSubModels(propsDict_); + + // define switches which can be read from dict + forceSubM(0).setSwitchesList(0,true); // activate treatExplicit switch + + // read those switches defined above, if provided in dict + forceSubM(0).readSwitches(); + particleCloud_.checkCG(false); } @@ -94,15 +101,11 @@ SchillerNaumannDrag::~SchillerNaumannDrag() void SchillerNaumannDrag::setForce() const { - // get viscosity field - #ifdef comp - const volScalarField nufField = particleCloud_.turbulence().mu() / rho_; - #else - const volScalarField& nufField = particleCloud_.turbulence().nu(); - #endif - #include "setupProbeModel.H" + const volScalarField& nufField = forceSubM(0).nuField(); + const volScalarField& rhoField = forceSubM(0).rhoField(); + for(int index = 0;index < particleCloud_.numberOfParticles(); index++) { //if(mask[index][0]) @@ -117,7 +120,7 @@ void SchillerNaumannDrag::setForce() const vector Ur = U_[cellI]-Us; scalar ds = 2*particleCloud_.radius(index); scalar nuf = nufField[cellI]; - scalar rho = rho_[cellI]; + scalar rho = rhoField[cellI]; scalar voidfraction = particleCloud_.voidfraction(index); scalar magUr = mag(Ur); scalar Rep = 0; @@ -163,10 +166,9 @@ void SchillerNaumannDrag::setForce() const particleCloud_.probeM().writeProbe(index, sValues, vValues); } } - // set force on particle - if(treatExplicit_) for(int j=0;j<3;j++) expForces()[index][j] += drag[j]; - else for(int j=0;j<3;j++) impForces()[index][j] += drag[j]; - for(int j=0;j<3;j++) DEMForces()[index][j] += drag[j]; + + // write particle based data to global array + forceSubM(0).partToArray(index,drag,vector::zero); //} } diff --git a/src/lagrangian/cfdemParticle/subModels/forceModel/SchillerNaumannDrag/SchillerNaumannDrag.H b/src/lagrangian/cfdemParticle/subModels/forceModel/SchillerNaumannDrag/SchillerNaumannDrag.H index f898a66..4b7dc8d 100644 --- a/src/lagrangian/cfdemParticle/subModels/forceModel/SchillerNaumannDrag/SchillerNaumannDrag.H +++ b/src/lagrangian/cfdemParticle/subModels/forceModel/SchillerNaumannDrag/SchillerNaumannDrag.H @@ -66,10 +66,6 @@ private: const volVectorField& U_; - word densityFieldName_; - - const volScalarField& rho_; - public: //- Runtime type information diff --git a/src/lagrangian/cfdemParticle/subModels/forceModel/ShirgaonkarIB/ShirgaonkarIB.C b/src/lagrangian/cfdemParticle/subModels/forceModel/ShirgaonkarIB/ShirgaonkarIB.C index 4396869..59569a4 100644 --- a/src/lagrangian/cfdemParticle/subModels/forceModel/ShirgaonkarIB/ShirgaonkarIB.C +++ b/src/lagrangian/cfdemParticle/subModels/forceModel/ShirgaonkarIB/ShirgaonkarIB.C @@ -68,8 +68,6 @@ ShirgaonkarIB::ShirgaonkarIB depth_(1), velFieldName_(propsDict_.lookup("velFieldName")), U_(sm.mesh().lookupObject (velFieldName_)), - densityFieldName_(propsDict_.lookup("densityFieldName")), - rho_(sm.mesh().lookupObject (densityFieldName_)), pressureFieldName_(propsDict_.lookup("pressureFieldName")), p_(sm.mesh().lookupObject (pressureFieldName_)) { @@ -86,7 +84,16 @@ ShirgaonkarIB::ShirgaonkarIB Info << "2-dimensional simulation - make sure DEM side is 2D" << endl; Info << "depth of domain is assumed to be :" << depth_ << endl; } - if (propsDict_.found("treatExplicit")) treatExplicit_=true; + + // init force sub model + setForceSubModels(propsDict_); + + // define switches which can be read from dict + forceSubM(0).setSwitchesList(0,true); // activate treatExplicit switch + + // read those switches defined above, if provided in dict + forceSubM(0).readSwitches(); + particleCloud_.checkCG(false); } @@ -105,15 +112,7 @@ void ShirgaonkarIB::setForce() const label cellI; vector drag; - #ifdef comp - // get viscosity field - const volScalarField& mufField = particleCloud_.turbulence().mu(); - volVectorField h = (mufField*fvc::laplacian(U_)-fvc::grad(p_)); - #else - // get viscosity field - const volScalarField& nufField = particleCloud_.turbulence().nu(); - volVectorField h = rho_*(nufField*fvc::laplacian(U_)-fvc::grad(p_)); - #endif + volVectorField h=forceSubM(0).IBDragPerV(U_,p_); #include "setupProbeModel.H" @@ -146,9 +145,8 @@ void ShirgaonkarIB::setForce() const particleCloud_.probeM().writeProbe(index, sValues, vValues); } - if(treatExplicit_) for(int j=0;j<3;j++) expForces()[index][j] += drag[j]; - else for(int j=0;j<3;j++) impForces()[index][j] += drag[j]; - for(int j=0;j<3;j++) DEMForces()[index][j] += drag[j]; + // write particle based data to global array + forceSubM(0).partToArray(index,drag,vector::zero); if(verbose_) Info << "impForces = " << impForces()[index][0]<<","< (densityFieldName_)), rhoP_(readScalar(propsDict_.lookup("rhoP"))) -{} +{ + // init force sub model + setForceSubModels(propsDict_); + + // read those switches defined above, if provided in dict + forceSubM(0).readSwitches(); +} // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // @@ -82,12 +86,9 @@ void checkCouplingInterval::setForce() const { if(particleCloud_.mesh().time().write()) { - // get viscosity field - #ifdef comp - const volScalarField nufField = particleCloud_.turbulence().mu() / rho_; - #else - const volScalarField& nufField = particleCloud_.turbulence().nu(); - #endif + + const volScalarField& nufField = forceSubM(0).nuField(); + const volScalarField& rhoField = forceSubM(0).rhoField(); // find min particle relaxation time scalar minTauP = 1000; @@ -101,7 +102,7 @@ void checkCouplingInterval::setForce() const { scaledRad = particleCloud_.radius(index)/particleCloud_.cg(); tauP = rhoP_*4*scaledRad*scaledRad/ - (18 * nufField[cellI] * rho_[cellI]); + (18 * nufField[cellI] * rhoField[cellI]); minTauP = min(minTauP,tauP); } } @@ -113,7 +114,8 @@ void checkCouplingInterval::setForce() const double accNrAll=-1.; MPI_Allreduce(&accNr, &accNrAll, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); - + Info << "min. occurring particle relaxation time [s]: " << minTauP << endl; + Info << "coupling interval [s]: " << DEMtime << endl; Info << "max. occurring acceleration nr: " << accNrAll << endl; if(accNrAll > 0.1) Warning << "you should use a smaller coupling interval!" << endl; } diff --git a/src/lagrangian/cfdemParticle/subModels/forceModel/checkCouplingInterval/checkCouplingInterval.H b/src/lagrangian/cfdemParticle/subModels/forceModel/checkCouplingInterval/checkCouplingInterval.H index 0ff44ac..01d1943 100644 --- a/src/lagrangian/cfdemParticle/subModels/forceModel/checkCouplingInterval/checkCouplingInterval.H +++ b/src/lagrangian/cfdemParticle/subModels/forceModel/checkCouplingInterval/checkCouplingInterval.H @@ -62,10 +62,6 @@ class checkCouplingInterval private: dictionary propsDict_; - word densityFieldName_; - - const volScalarField& rho_; - const scalar rhoP_; public: diff --git a/src/lagrangian/cfdemParticle/subModels/forceModel/fieldStore/fieldStore.C b/src/lagrangian/cfdemParticle/subModels/forceModel/fieldStore/fieldStore.C new file mode 100644 index 0000000..24a299b --- /dev/null +++ b/src/lagrangian/cfdemParticle/subModels/forceModel/fieldStore/fieldStore.C @@ -0,0 +1,164 @@ +/*---------------------------------------------------------------------------*\ + CFDEMcoupling - Open Source CFD-DEM coupling + + CFDEMcoupling is part of the CFDEMproject + www.cfdem.com + Christoph Goniva, christoph.goniva@cfdem.com + Copyright 2009-2012 JKU Linz + Copyright 2012- DCS Computing GmbH, Linz +------------------------------------------------------------------------------- +License + This file is part of CFDEMcoupling. + + CFDEMcoupling is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3 of the License, or (at your + option) any later version. + + CFDEMcoupling 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. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with CFDEMcoupling; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Description + This code is designed to realize coupled CFD-DEM simulations using LIGGGHTS + and OpenFOAM(R). Note: this code is not part of OpenFOAM(R) (see DISCLAIMER). +\*---------------------------------------------------------------------------*/ + +#include "error.H" + +#include "fieldStore.H" +#include "addToRunTimeSelectionTable.H" +#include "dataExchangeModel.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +defineTypeNameAndDebug(fieldStore, 0); + +addToRunTimeSelectionTable +( + forceModel, + fieldStore, + dictionary +); + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +// Construct from components +fieldStore::fieldStore +( + const dictionary& dict, + cfdemCloud& sm +) +: + forceModel(dict,sm), + propsDict_(dict.subDict(typeName + "Props")), + mesh_(particleCloud_.mesh()), + scalarFieldNames_(propsDict_.lookup("scalarFieldNames")), + vectorFieldNames_(propsDict_.lookup("vectorFieldNames")), + scalarFields_(NULL), + vectorFields_(NULL) +{ + // create time average scalar fields + scalarFields_.setSize(scalarFieldNames_.size()); + + for (int i=0;i < scalarFieldNames_.size(); i++) + { + word fieldName = "stored_" + scalarFieldNames_[i]; + + Info<< "Creating field " << fieldName << endl; + scalarFields_.set + ( + i, + new volScalarField + ( + IOobject + ( + fieldName, + mesh_.time().timeName(), + mesh_, + IOobject::NO_READ, + IOobject::AUTO_WRITE + ), + mesh_, + dimensionedScalar("0", mesh_.lookupObject(scalarFieldNames_[i]).dimensions(), 0) + ) + ); + } + + // create time average vector fields + vectorFields_.setSize(vectorFieldNames_.size()); + + for (int i=0;i < vectorFieldNames_.size(); i++) + { + word fieldName = "stored_" + vectorFieldNames_[i]; + + Info<< "Creating field " << fieldName << endl; + vectorFields_.set + ( + i, + new volVectorField + ( + IOobject + ( + fieldName, + mesh_.time().timeName(), + mesh_, + IOobject::NO_READ, + IOobject::AUTO_WRITE + ), + mesh_, + dimensionedVector("0", mesh_.lookupObject(vectorFieldNames_[i]).dimensions(), vector::zero) + ) + ); + } +} + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // + +fieldStore::~fieldStore() +{} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +void fieldStore::setForce() const +{ + if(particleCloud_.verbose()) Info << "fieldStore.C - setForce()" << endl; + + for (int i=0;i < scalarFieldNames_.size(); i++) + { + // get reference to actual field + volScalarField& field = (volScalarField&) mesh_.lookupObject(scalarFieldNames_[i]); + + // save field + scalarFields_[i] = field; + } + + for (int i=0;i < vectorFieldNames_.size(); i++) + { + // get reference to actual field + volVectorField& field = (volVectorField&) mesh_.lookupObject(vectorFieldNames_[i]); + + // save field + vectorFields_[i] = field; + } +} + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// ************************************************************************* // diff --git a/src/lagrangian/cfdemParticle/subModels/forceModel/fieldStore/fieldStore.H b/src/lagrangian/cfdemParticle/subModels/forceModel/fieldStore/fieldStore.H new file mode 100644 index 0000000..f9caf1d --- /dev/null +++ b/src/lagrangian/cfdemParticle/subModels/forceModel/fieldStore/fieldStore.H @@ -0,0 +1,106 @@ +/*---------------------------------------------------------------------------*\ + CFDEMcoupling - Open Source CFD-DEM coupling + + CFDEMcoupling is part of the CFDEMproject + www.cfdem.com + Christoph Goniva, christoph.goniva@cfdem.com + Copyright 2009-2012 JKU Linz + Copyright 2012- DCS Computing GmbH, Linz +------------------------------------------------------------------------------- +License + This file is part of CFDEMcoupling. + + CFDEMcoupling is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3 of the License, or (at your + option) any later version. + + CFDEMcoupling 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. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with CFDEMcoupling; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Description + This code is designed to realize coupled CFD-DEM simulations using LIGGGHTS + and OpenFOAM(R). Note: this code is not part of OpenFOAM(R) (see DISCLAIMER). + + calc time average of scalar or vector field + +Class + fieldStore + +SourceFiles + fieldStore.C + +\*---------------------------------------------------------------------------*/ + +#ifndef fieldStore_H +#define fieldStore_H + +#include "forceModel.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class fieldStore Declaration +\*---------------------------------------------------------------------------*/ + +class fieldStore +: + public forceModel +{ +private: + + dictionary propsDict_; + + const fvMesh& mesh_; + + const wordList scalarFieldNames_; + + const wordList vectorFieldNames_; + + mutable PtrList scalarFields_; + + mutable PtrList vectorFields_; + +public: + + //- Runtime type information + TypeName("fieldStore"); + + + // Constructors + + //- Construct from components + fieldStore + ( + const dictionary& dict, + cfdemCloud& sm + ); + + // Destructor + + ~fieldStore(); + + + // Member Functions + void setForce() const; +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/lagrangian/cfdemParticle/subModels/forceModel/forceModel/forceModel.C b/src/lagrangian/cfdemParticle/subModels/forceModel/forceModel/forceModel.C index d87a304..0930df4 100644 --- a/src/lagrangian/cfdemParticle/subModels/forceModel/forceModel/forceModel.C +++ b/src/lagrangian/cfdemParticle/subModels/forceModel/forceModel/forceModel.C @@ -31,7 +31,7 @@ Description #include "error.H" #include "forceModel.H" - +#include "mathExtra.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // namespace Foam @@ -56,9 +56,9 @@ forceModel::forceModel : dict_(dict), particleCloud_(sm), - treatExplicit_(false), - treatDEM_(false), - implDEM_(false), + //treatExplicit_(false), + //treatDEM_(false), + //implDEM_(false), impParticleForces_ ( IOobject ( @@ -86,7 +86,9 @@ forceModel::forceModel coupleForce_(true), modelType_(sm.modelType()), probeIt_(sm.probeM().active()), - requiresEx_(false) + requiresEx_(false), + forceSubModels_(wordList(0)), + forceSubModel_(new autoPtr[nrForceSubModels()]) {} @@ -145,6 +147,49 @@ void forceModel::repartitionImExForces() const } } +void forceModel::treatVoidCells() const +{ + //force coupling force in cells where there are no particles to be explicit force + if(particleCloud_.treatVoidCellsAsExplicitForce()) + { + int counter(0); + volVectorField& Us = particleCloud_.averagingM().UsNext(); + forAll(Us,cellI) + { + if ( mag(Us[cellI]) == 0.0) // cell is void of particles + { + expParticleForces_[cellI] += impParticleForces_[cellI]; + impParticleForces_[cellI] *= 0.0; + counter +=1; + } + } + Info << "Re-partitioned "<< counter << " cells void of particles" << endl; + } +} + +void forceModel::setForceSubModels(dictionary& dict) +{ + if (dict.found("forceSubModels")) + forceSubModels_ = wordList(dict.lookup("forceSubModels")); + else{ + forceSubModels_ = wordList(1); + forceSubModels_[0] = "ImEx"; + } + + delete[] forceSubModel_; + forceSubModel_ = new autoPtr[nrForceSubModels()]; + Info << "nrForceSubModels()=" << nrForceSubModels() << endl; + for (int i=0;i* forceSubModel_; + public: //- Runtime type information @@ -150,12 +153,19 @@ public: inline const bool& coupleForce() const { return coupleForce_;}; - void const setImpDEMdrag() const {particleCloud_.impDEMdrag_=true;}; - virtual inline bool& requiresEx() { return requiresEx_;}; - //Repartition Implixit/Explicit forces - void repartitionImExForces() const; + void repartitionImExForces() const; //Repartition Implixit/Explicit forces + + void treatVoidCells() const; + + inline const wordList& forceSubModels(){ return forceSubModels_; }; + + inline const forceSubModel& forceSubM(int i) const { return forceSubModel_[i]; }; + + inline int nrForceSubModels(){ return forceSubModels_.size(); }; + + void setForceSubModels(dictionary& dict); }; diff --git a/src/lagrangian/cfdemParticle/subModels/forceModel/forceSubModels/ImEx/ImEx.C b/src/lagrangian/cfdemParticle/subModels/forceModel/forceSubModels/ImEx/ImEx.C new file mode 100644 index 0000000..63595bb --- /dev/null +++ b/src/lagrangian/cfdemParticle/subModels/forceModel/forceSubModels/ImEx/ImEx.C @@ -0,0 +1,81 @@ +/*---------------------------------------------------------------------------*\ + CFDEMcoupling - Open Source CFD-DEM coupling + + CFDEMcoupling is part of the CFDEMproject + www.cfdem.com + Christoph Goniva, christoph.goniva@cfdem.com + Copyright 2009-2012 JKU Linz + Copyright 2012- DCS Computing GmbH, Linz +------------------------------------------------------------------------------- +License + This file is part of CFDEMcoupling. + + CFDEMcoupling is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3 of the License, or (at your + option) any later version. + + CFDEMcoupling 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. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with CFDEMcoupling; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Description + This code is designed to realize coupled CFD-DEM simulations using LIGGGHTS + and OpenFOAM(R). Note: this code is not part of OpenFOAM(R) (see DISCLAIMER). +\*---------------------------------------------------------------------------*/ + +#include "error.H" + +#include "ImEx.H" +#include "addToRunTimeSelectionTable.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +defineTypeNameAndDebug(ImEx, 0); + +addToRunTimeSelectionTable +( + forceSubModel, + ImEx, + dictionary +); + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +// Construct from components +ImEx::ImEx +( + const dictionary& dict, + cfdemCloud& sm, + forceModel& fm +) +: + forceSubModel(dict,sm,fm) +{} + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // + +ImEx::~ImEx() +{} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// ************************************************************************* // diff --git a/src/lagrangian/cfdemParticle/subModels/forceModel/forceSubModels/ImEx/ImEx.H b/src/lagrangian/cfdemParticle/subModels/forceModel/forceSubModels/ImEx/ImEx.H new file mode 100644 index 0000000..7d017b9 --- /dev/null +++ b/src/lagrangian/cfdemParticle/subModels/forceModel/forceSubModels/ImEx/ImEx.H @@ -0,0 +1,95 @@ +/*---------------------------------------------------------------------------*\ + CFDEMcoupling - Open Source CFD-DEM coupling + + CFDEMcoupling is part of the CFDEMproject + www.cfdem.com + Christoph Goniva, christoph.goniva@cfdem.com + Copyright 2009-2012 JKU Linz + Copyright 2012- DCS Computing GmbH, Linz +------------------------------------------------------------------------------- +License + This file is part of CFDEMcoupling. + + CFDEMcoupling is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3 of the License, or (at your + option) any later version. + + CFDEMcoupling 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. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with CFDEMcoupling; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Description + This code is designed to realize coupled CFD-DEM simulations using LIGGGHTS + and OpenFOAM(R). Note: this code is not part of OpenFOAM(R) (see DISCLAIMER). + +Class + ImEx + +SourceFiles + ImEx.C + +\*---------------------------------------------------------------------------*/ + +#ifndef ImEx_H +#define ImEx_H + +#include "forceSubModel.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class ImEx Declaration +\*---------------------------------------------------------------------------*/ + +class ImEx +: + public forceSubModel +{ +private: + + +public: + + //- Runtime type information + TypeName("ImEx"); + + + // Constructors + + //- Construct from components + ImEx + ( + const dictionary& dict, + cfdemCloud& sm, + forceModel& fm + ); + + // Destructor + + ~ImEx(); + + + // Member Functions + + word myType() const{return typeName; }; +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/lagrangian/cfdemParticle/subModels/forceModel/forceSubModels/forceSubModel/forceSubModel.C b/src/lagrangian/cfdemParticle/subModels/forceModel/forceSubModels/forceSubModel/forceSubModel.C new file mode 100644 index 0000000..7548a91 --- /dev/null +++ b/src/lagrangian/cfdemParticle/subModels/forceModel/forceSubModels/forceSubModel/forceSubModel.C @@ -0,0 +1,338 @@ +/*---------------------------------------------------------------------------*\ + CFDEMcoupling - Open Source CFD-DEM coupling + + CFDEMcoupling is part of the CFDEMproject + www.cfdem.com + Christoph Goniva, christoph.goniva@cfdem.com + Copyright 2009-2012 JKU Linz + Copyright 2012- DCS Computing GmbH, Linz +------------------------------------------------------------------------------- +License + This file is part of CFDEMcoupling. + + CFDEMcoupling is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3 of the License, or (at your + option) any later version. + + CFDEMcoupling 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. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with CFDEMcoupling; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Description + This code is designed to realize coupled CFD-DEM simulations using LIGGGHTS + and OpenFOAM(R). Note: this code is not part of OpenFOAM(R) (see DISCLAIMER). +\*---------------------------------------------------------------------------*/ + +#include "error.H" +#include "forceSubModel.H" +#include "forceModel.H" +#include "mathExtra.H" +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +defineTypeNameAndDebug(forceSubModel, 0); + +defineRunTimeSelectionTable(forceSubModel, dictionary); + +// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +// Construct from components +forceSubModel::forceSubModel +( + const dictionary& dict, + cfdemCloud& sm, + forceModel& fm +) +: + dict_(dict), + particleCloud_(sm), + forceModel_(fm), + nrDefaultSwitches_(9), // !!! + switchesNameList_(wordList(nrDefaultSwitches_)), + switchesList_(List(nrDefaultSwitches_)), + switches_(List(nrDefaultSwitches_)), + nu_ + ( + IOobject + ( + "scalarViscosity", + sm.mesh().time().timeName(), + sm.mesh(), + IOobject::NO_READ, + IOobject::NO_WRITE + ), + sm.mesh(), + dimensionedScalar("nu0", dimensionSet(0, 2, -1, 0, 0), 1.) + ), + divTau_ + ( + IOobject + ( + "divTau", + sm.mesh().time().timeName(), + sm.mesh(), + IOobject::NO_READ, + IOobject::NO_WRITE + ), + sm.mesh(), + dimensionedVector("divTau", dimensionSet(1, -2, -2, 0, 0), vector::zero) + ), + IBDragPerV_ + ( + IOobject + ( + "IBDragPerV", + sm.mesh().time().timeName(), + sm.mesh(), + IOobject::NO_READ, + IOobject::NO_WRITE + ), + sm.mesh(), + dimensionedVector("IBDragPerV", dimensionSet(1, -2, -2, 0, 0), vector::zero) + ), + densityFieldName_(dict_.lookupOrDefault("densityFieldName","rho")), + rho_(sm.mesh().lookupObject (densityFieldName_)) +{ + // init standard switch list + int iCounter(0); + switchesNameList_[iCounter]="treatForceExplicit"; iCounter++; //0 + switchesNameList_[iCounter]="treatForceDEM";iCounter++; //1 + switchesNameList_[iCounter]="implForceDEM";iCounter++; //2 + switchesNameList_[iCounter]="verbose";iCounter++; //3 + switchesNameList_[iCounter]="interpolation";iCounter++; //4 + switchesNameList_[iCounter]="useFilteredDragModel";iCounter++; //5 + switchesNameList_[iCounter]="useParcelSizeDependentFilteredDrag";iCounter++; //6 + switchesNameList_[iCounter]="implForceDEMaccumulated";iCounter++; //7 + switchesNameList_[iCounter]="scalarViscosity";iCounter++; //8 + + for(int i=0;i 0+SMALL) //check if switch is required + { + Info << " looking for " << switchesNameList_[i] << " ..." << endl; + if (dict_.found(switchesNameList_[i])) + switches_[i]=Switch(dict_.lookup(switchesNameList_[i])); + + Info << "\t" << switchesNameList_[i] << " = " << switches_[i] << endl; + } + } + Info << endl; + + if(switches_[2]) // implForceDEM=true + { + // communicate implForceDEM to particleCloud + particleCloud_.impDEMdrag_=true; + + // do sanity check + // This can work if the accumulator is used, but is explicitely applied on the CFD side + // Sanity check is therefore not necessary here + /* + if(switches_[0]) // treatExplicit=true + { + FatalError << "Please check your settings, treatExplicit together with implForceDEM does not work!." + << abort(FatalError); + } + */ + } + + if(switches_[7]) // implForceDEMaccumulated=true + { + // sanity check for implForceDEMaccumulated + if(!switches_[2]) //implForceDEM=false + { + Warning<< "please check your settings, implForceDEMaccumulated without implForceDEM does not work! (using implForceDEMaccumulated=false)" << endl; + switches_[3]=false; + }else + { + particleCloud_.impDEMdragAcc_=true; + } + } + + if(switches_[8]) // scalarViscosity=true + { + Info << "Using a constant viscosity for this force model." << endl; + dimensionedScalar nu0_("nu", dimensionSet(0, 2, -1, 0, 0), dict_.lookup("nu")); + nu_=volScalarField + ( + IOobject + ( + "scalarViscosity", + particleCloud_.mesh().time().timeName(), + particleCloud_.mesh(), + IOobject::NO_READ, + IOobject::NO_WRITE + ), + particleCloud_.mesh(), + nu0_ + ); + } + + // look for old nomenclature + if (dict_.found("treatExplicit") || dict_.found("treatDEM") || dict_.found("implDEM")) + FatalError<< "You are using an old nomenclature for force model settings, please have a look at the forceSubModel doc." << abort(FatalError); + + // look for old nomenclature + if (dict_.found("verbose")) + Warning<< "Please make sure you use the new nomenclature for verbose force model settings, please have a look at the forceSubModel doc." << endl; + + //if (dict_.found("interpolation")) + // FatalError<< "Please make sure you use the new nomenclature for interpolation in force model settings, please have a look at the forceSubModel doc." << endl; +} + +const volScalarField& forceSubModel::nuField() const +{ + #ifdef compre + nu_=particleCloud_.turbulence().mu() / rho_; + return nu_; + #else + if(switches_[8]) // scalarViscosity=true + return nu_; + else + return particleCloud_.turbulence().nu(); + #endif +} + +const volScalarField& forceSubModel::muField() const +{ + #ifdef compre + return particleCloud_.turbulence().mu(); + #else + // passing the ref to nu*rho will not work->generate a mu_ field like nu_ + FatalError<< "implementation not complete!" << abort(FatalError); + + if(switches_[8]) // scalarViscosity=true + return nu_*rho_; + else + return particleCloud_.turbulence().nu()*rho_; + #endif +} + +const volScalarField& forceSubModel::rhoField() const +{ + return rho_; +} + +const volVectorField& forceSubModel::divTauField(const volVectorField& U) const +{ + // calc div(Tau) + #ifdef compre + const volScalarField& mu_ = muField(); + divTau_ = -fvc::laplacian(mu_, U) - fvc::div(mu_*dev(fvc::grad(U)().T())); + return divTau_; + #else + const volScalarField& nu_ = nuField(); + const volScalarField& rho_ = rhoField(); + divTau_ = -fvc::laplacian(nu_*rho_, U)- fvc::div(nu_*rho_*dev(fvc::grad(U)().T())); + return divTau_; + #endif +} + +const volVectorField& forceSubModel::IBDragPerV(const volVectorField& U,const volScalarField& p) const +{ + #ifdef compre + IBDragPerV_ = muField()*fvc::laplacian(U)-fvc::grad(p); + #else + IBDragPerV_ = rhoField()*(nuField()*fvc::laplacian(U)-fvc::grad(p)); + #endif + return IBDragPerV_; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// ************************************************************************* // diff --git a/src/lagrangian/cfdemParticle/subModels/forceModel/forceSubModels/forceSubModel/forceSubModel.H b/src/lagrangian/cfdemParticle/subModels/forceModel/forceSubModels/forceSubModel/forceSubModel.H new file mode 100644 index 0000000..935adac --- /dev/null +++ b/src/lagrangian/cfdemParticle/subModels/forceModel/forceSubModels/forceSubModel/forceSubModel.H @@ -0,0 +1,183 @@ +/*---------------------------------------------------------------------------*\ + CFDEMcoupling - Open Source CFD-DEM coupling + + CFDEMcoupling is part of the CFDEMproject + www.cfdem.com + Christoph Goniva, christoph.goniva@cfdem.com + Copyright 2009-2012 JKU Linz + Copyright 2012- DCS Computing GmbH, Linz +------------------------------------------------------------------------------- +License + This file is part of CFDEMcoupling. + + CFDEMcoupling is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3 of the License, or (at your + option) any later version. + + CFDEMcoupling 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. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with CFDEMcoupling; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Description + This code is designed to realize coupled CFD-DEM simulations using LIGGGHTS + and OpenFOAM(R). Note: this code is not part of OpenFOAM(R) (see DISCLAIMER). + +Class + forceSubModel + +SourceFiles + forceSubModel.C + +\*---------------------------------------------------------------------------*/ + +#ifndef forceSubModel_H +#define forceSubModel_H + +#include "fvCFD.H" +#include "cfdemCloud.H" +#include "probeModel.H" +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class forceSubModel Declaration +\*---------------------------------------------------------------------------*/ + +class forceSubModel +{ + +protected: + + // Protected data + const dictionary& dict_; + + cfdemCloud& particleCloud_; + + forceModel& forceModel_; + + label nrDefaultSwitches_; // nr of switches defined in mother class + + wordList switchesNameList_; // names of switches available + + mutable List switchesList_; // switches which are requested in dict + + mutable List switches_; + + mutable volScalarField nu_; + + mutable volVectorField divTau_; + + mutable volVectorField IBDragPerV_; + + word densityFieldName_; + + const volScalarField& rho_; + +public: + + //- Runtime type information + TypeName("forceSubModel"); + + // Declare runtime constructor selection table + + declareRunTimeSelectionTable + ( + autoPtr, + forceSubModel, + dictionary, + ( + const dictionary& dict, + cfdemCloud& sm, + forceModel& fm + ), + (dict,sm,fm) + ); + + + // Constructors + + //- Construct from components + forceSubModel + ( + const dictionary& dict, + cfdemCloud& sm, + forceModel& fm + ); + + + // Destructor + + virtual ~forceSubModel(); + + + // Selector + + static autoPtr New + ( + const dictionary& dict, + cfdemCloud& sm, + forceModel& fm, + word forceType + ); + + + // Member Functions + void partToArray(label&, vector&, const vector&, const vector& Ufluid=vector::zero, scalar Cd=scalar(0)) const; + + virtual void explicitCorr(vector&, vector&, scalar&, vector&, const vector&, vector&, const vector&, bool,label index=100) const; + + // Access + + inline bool verbose() const { return switches_[3]; }; + + inline bool interpolation() const { return switches_[4]; }; + + inline bool useFilteredDragModel() const { return switches_[5]; }; + + inline bool useParcelSizeDependentFilteredDrag() const { return switches_[6]; }; + + virtual word myType() const=0; + + inline forceModel& myForceM() const { return forceModel_;}; + + inline const List& switches() const { return switches_;}; + + inline const wordList& switchesNameList() const { return switchesNameList_;}; + + void setSwitchesList(label i, bool v) const { switchesList_[i] = label(v);}; + + void setSwitches(label i, Switch v) const { switches_[i] = v;}; + + virtual void readSwitches() const; + + const label& nrDefaultSwitches() const {return nrDefaultSwitches_;}; + + const volScalarField& nuField() const; + + const volScalarField& muField() const; + + const volScalarField& rhoField() const; + + const volVectorField& divTauField(const volVectorField&) const; + + const volVectorField& IBDragPerV(const volVectorField&,const volScalarField&) const; +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/lagrangian/cfdemParticle/subModels/forceModel/forceSubModels/forceSubModel/newForceSubModel.C b/src/lagrangian/cfdemParticle/subModels/forceModel/forceSubModels/forceSubModel/newForceSubModel.C new file mode 100644 index 0000000..cc2d34f --- /dev/null +++ b/src/lagrangian/cfdemParticle/subModels/forceModel/forceSubModels/forceSubModel/newForceSubModel.C @@ -0,0 +1,79 @@ +/*---------------------------------------------------------------------------*\ + CFDEMcoupling - Open Source CFD-DEM coupling + + CFDEMcoupling is part of the CFDEMproject + www.cfdem.com + Christoph Goniva, christoph.goniva@cfdem.com + Copyright 2009-2012 JKU Linz + Copyright 2012- DCS Computing GmbH, Linz +------------------------------------------------------------------------------- +License + This file is part of CFDEMcoupling. + + CFDEMcoupling is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3 of the License, or (at your + option) any later version. + + CFDEMcoupling 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. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with CFDEMcoupling; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Description + This code is designed to realize coupled CFD-DEM simulations using LIGGGHTS + and OpenFOAM(R). Note: this code is not part of OpenFOAM(R) (see DISCLAIMER). +\*---------------------------------------------------------------------------*/ + +#include "error.H" + +#include "forceSubModel.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +autoPtr forceSubModel::New +( + const dictionary& dict, + cfdemCloud& sm, + forceModel& fm, + word forceType +) +{ + Info<< "Selecting forceSubModel " + << forceType << endl; + + dictionaryConstructorTable::iterator cstrIter = + dictionaryConstructorTablePtr_->find(forceType); + + if (cstrIter == dictionaryConstructorTablePtr_->end()) + { + FatalError + << "forceSubModel::New(const dictionary&, const spray&) : " + << endl + << " unknown forceSubModelType type " + << forceType + << ", constructor not in hash table" << endl << endl + << " Valid forceSubModel types are :" + << endl; + Info<< dictionaryConstructorTablePtr_->toc() + << abort(FatalError); + } + + return autoPtr(cstrIter()(dict,sm,fm)); +} + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// ************************************************************************* // diff --git a/src/lagrangian/cfdemParticle/subModels/forceModel/gradPForce/gradPForce.C b/src/lagrangian/cfdemParticle/subModels/forceModel/gradPForce/gradPForce.C index a4db6cd..1885294 100644 --- a/src/lagrangian/cfdemParticle/subModels/forceModel/gradPForce/gradPForce.C +++ b/src/lagrangian/cfdemParticle/subModels/forceModel/gradPForce/gradPForce.C @@ -62,28 +62,44 @@ gradPForce::gradPForce : forceModel(dict,sm), propsDict_(dict.subDict(typeName + "Props")), - verbose_(false), pFieldName_(propsDict_.lookup("pFieldName")), p_(sm.mesh().lookupObject (pFieldName_)), velocityFieldName_(propsDict_.lookup("velocityFieldName")), U_(sm.mesh().lookupObject (velocityFieldName_)), - densityFieldName_(propsDict_.lookup("densityFieldName")), - rho_(sm.mesh().lookupObject (densityFieldName_)), useRho_(false), useU_(false), - addedMassCoeff_(0.0), - interpolation_(false) + addedMassCoeff_(0.0) { + // init force sub model + setForceSubModels(propsDict_); + + // define switches which can be read from dict + forceSubM(0).setSwitchesList(0,true); // activate treatExplicit switch + forceSubM(0).setSwitchesList(1,true); // activate treatForceDEM switch + forceSubM(0).setSwitchesList(4,true); // activate search for interpolate switch + + // read those switches defined above, if provided in dict + forceSubM(0).readSwitches(); + if (modelType_ == "B") { FatalError <<"using model gradPForce with model type B is not valid\n" << abort(FatalError); - }else + }else if (modelType_ == "Bfull") { - treatDEM_=true; - Info << "gradPForce is applied only to DEM side" << endl; + if(forceSubM(0).switches()[1]) + { + Info << "Using treatForceDEM false!" << endl; + forceSubM(0).setSwitches(1,false); // treatForceDEM = false + } + }else // modelType_=="A" + { + if(!forceSubM(0).switches()[1]) + { + Info << "Using treatForceDEM true!" << endl; + forceSubM(0).setSwitches(1,true); // treatForceDEM = true + } } - if (propsDict_.found("verbose")) verbose_=true; - if (propsDict_.found("treatExplicit")) treatExplicit_=true; + if (propsDict_.found("useU")) useU_=true; if (propsDict_.found("useAddedMass")) { @@ -91,11 +107,6 @@ gradPForce::gradPForce Info << "gradP will also include added mass with coefficient: " << addedMassCoeff_ << endl; Info << "WARNING: use fix nve/sphere/addedMass in LIGGGHTS input script to correctly account for added mass effects!" << endl; } - if (propsDict_.found("interpolation")) - { - Info << "using interpolated value of pressure gradient." << endl; - interpolation_=true; - } if(p_.dimensions()==dimensionSet(0,2,-2,0,0)) useRho_ = true; @@ -128,10 +139,9 @@ void gradPForce::setForce() const if (useRho_) gradPField = fvc::grad(0.5*U2); else - gradPField = fvc::grad(0.5*rho_*U2); + gradPField = fvc::grad(0.5*forceSubM(0).rhoField()*U2); }*/ vector gradP; - scalar ds; scalar Vs; scalar rho; vector position; @@ -153,7 +163,7 @@ void gradPForce::setForce() const { position = particleCloud_.position(index); - if(interpolation_) // use intepolated values for alpha (normally off!!!) + if(forceSubM(0).interpolation()) // use intepolated values for alpha (normally off!!!) { gradP = gradPInterpolator_.interpolate(position,cellI); }else @@ -162,7 +172,7 @@ void gradPForce::setForce() const } Vs = particleCloud_.particleVolume(index); - rho = rho_[cellI]; + rho = forceSubM(0).rhoField()[cellI]; // calc particle's pressure gradient force if (useRho_) @@ -170,7 +180,7 @@ void gradPForce::setForce() const else force = -Vs*gradP*(1.0+addedMassCoeff_); - if(verbose_ && index >=0 && index <2) + if(forceSubM(0).verbose() && index >=0 && index <2) { Info << "index = " << index << endl; Info << "gradP = " << gradP << endl; @@ -188,12 +198,8 @@ void gradPForce::setForce() const } } - // set force on particle - if(!treatDEM_){ - if(!treatExplicit_) for(int j=0;j<3;j++) impForces()[index][j] += force[j]; - else for(int j=0;j<3;j++) expForces()[index][j] += force[j]; - } - for(int j=0;j<3;j++) DEMForces()[index][j] += force[j]; + // write particle based data to global array + forceSubM(0).partToArray(index,force,vector::zero); //} } diff --git a/src/lagrangian/cfdemParticle/subModels/forceModel/gradPForce/gradPForce.H b/src/lagrangian/cfdemParticle/subModels/forceModel/gradPForce/gradPForce.H index 85ffe18..68001a6 100644 --- a/src/lagrangian/cfdemParticle/subModels/forceModel/gradPForce/gradPForce.H +++ b/src/lagrangian/cfdemParticle/subModels/forceModel/gradPForce/gradPForce.H @@ -63,8 +63,6 @@ class gradPForce private: dictionary propsDict_; - bool verbose_; - word pFieldName_; const volScalarField& p_; @@ -73,18 +71,12 @@ private: const volVectorField& U_; - word densityFieldName_; - - const volScalarField& rho_; - bool useRho_; bool useU_; // if false: substitution p=0.5*rho*U^2 mutable double addedMassCoeff_; //added mass coefficient - bool interpolation_; // use interpolated field values - public: //- Runtime type information diff --git a/src/lagrangian/cfdemParticle/subModels/forceModel/interface/interface.C b/src/lagrangian/cfdemParticle/subModels/forceModel/interface/interface.C index 23d2c7f..3507f08 100644 --- a/src/lagrangian/cfdemParticle/subModels/forceModel/interface/interface.C +++ b/src/lagrangian/cfdemParticle/subModels/forceModel/interface/interface.C @@ -78,7 +78,15 @@ interface::interface { if (propsDict_.found("C")) C_=readScalar(propsDict_.lookup("C")); if (propsDict_.found("interpolation")) interpolation_=true; - if (propsDict_.found("treatExplicit")) treatExplicit_=true; + + // init force sub model + setForceSubModels(propsDict_); + + // define switches which can be read from dict + forceSubM(0).setSwitchesList(0,true); // activate treatExplicit switch + + // read those switches defined above, if provided in dict + forceSubM(0).readSwitches(); Info << "check if interpolation really works - use directly interpolationCellPoint ???" << endl; particleCloud_.checkCG(false); @@ -179,9 +187,9 @@ Info << "interface::setForce" << endl; Info << "interface force is limited to " << interfaceForce << endl; }*/ - if(treatExplicit_) for(int j=0;j<3;j++) expForces()[index][j] += interfaceForce[j]; - else for(int j=0;j<3;j++) impForces()[index][j] += interfaceForce[j]; - for(int j=0;j<3;j++) DEMForces()[index][j] += interfaceForce[j]; + // write particle based data to global array + forceSubM(0).partToArray(index,interfaceForce,vector::zero); + } // end if particle found on proc domain //}// end if in mask }// end loop particles diff --git a/src/lagrangian/cfdemParticle/subModels/forceModel/noDrag/noDrag.C b/src/lagrangian/cfdemParticle/subModels/forceModel/noDrag/noDrag.C index e3073a2..0a403a0 100644 --- a/src/lagrangian/cfdemParticle/subModels/forceModel/noDrag/noDrag.C +++ b/src/lagrangian/cfdemParticle/subModels/forceModel/noDrag/noDrag.C @@ -68,6 +68,15 @@ noDrag::noDrag if(dict.found(word(typeName + "Props"))) propsDict_=dictionary(dict.subDict(typeName + "Props")); + // init force sub model + setForceSubModels(propsDict_); + + // define switches which can be read from dict + forceSubM(0).setSwitchesList(0,true); // activate treatExplicit + + // read those switches defined above, if provided in dict + forceSubM(0).readSwitches(); + if (propsDict_.found("noDEMForce")) noDEMForce_=true; if (propsDict_.found("keepCFDForce")) keepCFDForce_=true; @@ -89,15 +98,21 @@ void noDrag::setForce() const // Do nothing Info << "noDrag::setForce" << endl; label cellI=0; + bool treatExplicit=forceSubM(0).switches()[0]; for(int index = 0;index < particleCloud_.numberOfParticles(); ++index) { cellI = particleCloud_.cellIDs()[index][0]; if (cellI > -1) // particle Found { - // set force on particle + //========================== + // set force on particle (new code) + // write particle based data to global array + //forceSubM(0).partToArray(index,drag,dragExplicit); + //========================== + // set force on particle (old code) if(!keepCFDForce_) { - if(treatExplicit_) for(int j=0;j<3;j++) expForces()[index][j] = 0.; + if(treatExplicit) for(int j=0;j<3;j++) expForces()[index][j] = 0.; else for(int j=0;j<3;j++) impForces()[index][j] = 0.; } if(noDEMForce_) @@ -109,6 +124,7 @@ void noDrag::setForce() const for(int j=0;j<3;j++) fluidVel()[index][j] = 0.; } } + //========================== } } } diff --git a/src/lagrangian/cfdemParticle/subModels/forceModel/virtualMassForce/virtualMassForce.C b/src/lagrangian/cfdemParticle/subModels/forceModel/virtualMassForce/virtualMassForce.C index 89ab4a7..5443d94 100644 --- a/src/lagrangian/cfdemParticle/subModels/forceModel/virtualMassForce/virtualMassForce.C +++ b/src/lagrangian/cfdemParticle/subModels/forceModel/virtualMassForce/virtualMassForce.C @@ -40,6 +40,8 @@ Description namespace Foam { +#define NOTONCPU 9999 + // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // defineTypeNameAndDebug(virtualMassForce, 0); @@ -63,21 +65,42 @@ virtualMassForce::virtualMassForce : forceModel(dict,sm), propsDict_(dict.subDict(typeName + "Props")), - verbose_(false), velFieldName_(propsDict_.lookup("velFieldName")), U_(sm.mesh().lookupObject (velFieldName_)), - densityFieldName_(propsDict_.lookup("densityFieldName")), - rho_(sm.mesh().lookupObject (densityFieldName_)), - UrelOld_(NULL) + phiFieldName_(propsDict_.lookup("phiFieldName")), + phi_(sm.mesh().lookupObject (phiFieldName_)), + UrelOld_(NULL), + splitUrelCalculation_(false), + Cadd_(0.5) { - if (propsDict_.found("verbose")) verbose_=true; if (particleCloud_.dataExchangeM().maxNumberOfParticles() > 0) { // get memory for 2d array - particleCloud_.dataExchangeM().allocateArray(UrelOld_,0.,3); + particleCloud_.dataExchangeM().allocateArray(UrelOld_,NOTONCPU,3); } - if (propsDict_.found("treatExplicit")) treatExplicit_=true; + + // init force sub model + setForceSubModels(propsDict_); + // define switches which can be read from dict + forceSubM(0).setSwitchesList(0,true); // activate treatExplicit switch + forceSubM(0).setSwitchesList(4,true); // activate search for interpolate switch + forceSubM(0).readSwitches(); + + //Extra switches/settings + if(propsDict_.found("splitUrelCalculation")) + { + splitUrelCalculation_ = readBool(propsDict_.lookup("splitUrelCalculation")); + if(splitUrelCalculation_) + Info << "Virtual mass model: will split the Urel calculation\n"; + Info << "WARNING: be sure that LIGGGHTS integration takes ddtv_p implicitly into account! \n"; + } + if(propsDict_.found("Cadd")) + { + Cadd_ = readScalar(propsDict_.lookup("Cadd")); + Info << "Virtual mass model: using non-standard Cadd = " << Cadd_ << endl; + } + particleCloud_.checkCG(true); //Append the field names to be probed @@ -85,6 +108,7 @@ virtualMassForce::virtualMassForce particleCloud_.probeM().vectorFields_.append("virtualMassForce"); //first entry must the be the force particleCloud_.probeM().vectorFields_.append("Urel"); particleCloud_.probeM().vectorFields_.append("UrelOld"); + particleCloud_.probeM().vectorFields_.append("ddtUrel"); particleCloud_.probeM().scalarFields_.append("Vs"); particleCloud_.probeM().scalarFields_.append("rho"); particleCloud_.probeM().writeHeader(); @@ -107,32 +131,88 @@ void virtualMassForce::setForce() const scalar dt = U_.mesh().time().deltaT().value(); + vector position(0,0,0); + vector Ufluid(0,0,0); + vector Ur(0,0,0); + vector DDtU(0,0,0); + + //Compute extra vfields in case it is needed + volVectorField DDtU_(0.0*U_/U_.mesh().time().deltaT()); + if(splitUrelCalculation_) + DDtU_ = fvc::ddt(U_) + fvc::div(phi_, U_); //Total Derivative of fluid velocity + + interpolationCellPoint UInterpolator_( U_); + interpolationCellPoint DDtUInterpolator_(DDtU_); + #include "setupProbeModel.H" + bool haveUrelOld_(false); + for(int index = 0;index < particleCloud_.numberOfParticles(); index++) { - //if(mask[index][0]) - //{ vector virtualMassForce(0,0,0); label cellI = particleCloud_.cellIDs()[index][0]; if (cellI > -1) // particle Found { - vector Us = particleCloud_.velocity(index); - vector Ur = U_[cellI]-Us; - vector UrelOld; - for(int j=0;j<3;j++) + + if(forceSubM(0).interpolation()) { - UrelOld[j] = UrelOld_[index][j]; - UrelOld_[index][j] = Ur[j]; + position = particleCloud_.position(index); + Ufluid = UInterpolator_.interpolate(position,cellI); + } + else + { + Ufluid = U_[cellI]; + } + + + if(splitUrelCalculation_) //if split, just use total derivative of fluid velocity + if(forceSubM(0).interpolation()) + { + DDtU = DDtUInterpolator_.interpolate(position,cellI); + } + else + { + DDtU = DDtU_[cellI]; + } + else + { + vector Us = particleCloud_.velocity(index); + Ur = Ufluid - Us; } - vector ddtUrel = (Ur-UrelOld)/dt; + + //Check of particle was on this CPU the last step + if(UrelOld_[index][0]==NOTONCPU) //use 1. element to indicate that particle was on this CPU the last time step + haveUrelOld_ = false; + else + haveUrelOld_ = true; + + vector UrelOld(0.,0.,0.); + vector ddtUrel(0.,0.,0.); + for(int j=0;j<3;j++) + { + UrelOld[j] = UrelOld_[index][j]; + UrelOld_[index][j] = Ur[j]; + } + if(haveUrelOld_ ) //only compute force if we have old (relative) velocity + ddtUrel = (Ur-UrelOld)/dt; + + if(splitUrelCalculation_) //we can always compute the total derivative in case we split + ddtUrel = DDtU; + scalar ds = 2*particleCloud_.radius(index); scalar Vs = ds*ds*ds*M_PI/6; - scalar rho = rho_[cellI]; + scalar rho = forceSubM(0).rhoField()[cellI]; - virtualMassForce = 0.5 * rho * Vs * ddtUrel; + virtualMassForce = Cadd_ * rho * Vs * ddtUrel; + + if( forceSubM(0).verbose() ) //&& index>100 && index < 105) + { + Pout << "index / cellI = " << index << tab << cellI << endl; + Pout << "position = " << particleCloud_.position(index) << endl; + } //Set value fields and write the probe if(probeIt_) @@ -141,26 +221,27 @@ void virtualMassForce::setForce() const vValues.append(virtualMassForce); //first entry must the be the force vValues.append(Ur); vValues.append(UrelOld); + vValues.append(ddtUrel); sValues.append(Vs); sValues.append(rho); particleCloud_.probeM().writeProbe(index, sValues, vValues); } } - // set force on particle - if(treatExplicit_) for(int j=0;j<3;j++) expForces()[index][j] += virtualMassForce[j]; - else for(int j=0;j<3;j++) impForces()[index][j] += virtualMassForce[j]; - for(int j=0;j<3;j++) DEMForces()[index][j] += virtualMassForce[j]; - //} + else //particle not on this CPU + UrelOld_[index][0]=NOTONCPU; + + // write particle based data to global array + forceSubM(0).partToArray(index,virtualMassForce,vector::zero); } - } +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // void Foam::virtualMassForce::reAllocArrays() const { if(particleCloud_.numberOfParticlesChanged()) { - // get arrays of new length - particleCloud_.dataExchangeM().allocateArray(UrelOld_,1.,1); + Pout << "virtualMassForce::reAllocArrays..." << endl; + particleCloud_.dataExchangeM().allocateArray(UrelOld_,NOTONCPU,3); } } diff --git a/src/lagrangian/cfdemParticle/subModels/forceModel/virtualMassForce/virtualMassForce.H b/src/lagrangian/cfdemParticle/subModels/forceModel/virtualMassForce/virtualMassForce.H index 7eb5d62..ff2ee4d 100644 --- a/src/lagrangian/cfdemParticle/subModels/forceModel/virtualMassForce/virtualMassForce.H +++ b/src/lagrangian/cfdemParticle/subModels/forceModel/virtualMassForce/virtualMassForce.H @@ -41,6 +41,7 @@ SourceFiles #include "forceModel.H" #include "dataExchangeModel.H" +#include "interpolationCellPoint.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -58,18 +59,22 @@ class virtualMassForce private: dictionary propsDict_; - bool verbose_; - word velFieldName_; const volVectorField& U_; - word densityFieldName_; + word phiFieldName_; - const volScalarField& rho_; + const surfaceScalarField& phi_; mutable double **UrelOld_; + mutable bool splitUrelCalculation_; //indicator to split calculation of Urel between CFDEM and LIGGGHTS + //requires the integration fix to take dv/dt into account! + + mutable double Cadd_; //indicator to split calculation of Urel between CFDEM and LIGGGHTS + //requires the integration fix to take dv/dt into account! + public: //- Runtime type information diff --git a/src/lagrangian/cfdemParticle/subModels/forceModel/viscForce/viscForce.C b/src/lagrangian/cfdemParticle/subModels/forceModel/viscForce/viscForce.C index a35ed3e..571915a 100644 --- a/src/lagrangian/cfdemParticle/subModels/forceModel/viscForce/viscForce.C +++ b/src/lagrangian/cfdemParticle/subModels/forceModel/viscForce/viscForce.C @@ -62,24 +62,42 @@ viscForce::viscForce : forceModel(dict,sm), propsDict_(dict.subDict(typeName + "Props")), - verbose_(false), velocityFieldName_(propsDict_.lookup("velocityFieldName")), U_(sm.mesh().lookupObject (velocityFieldName_)), - densityFieldName_(propsDict_.lookup("densityFieldName")), - rho_(sm.mesh().lookupObject (densityFieldName_)), - addedMassCoeff_(0.0), - interpolation_(false) + addedMassCoeff_(0.0) { + + // init force sub model + setForceSubModels(propsDict_); + + // define switches which can be read from dict + forceSubM(0).setSwitchesList(0,true); // activate treatExplicit switch + forceSubM(0).setSwitchesList(1,true); // activate treatForceDEM switch + forceSubM(0).setSwitchesList(4,true); // activate search for interpolate switch + forceSubM(0).setSwitchesList(8,true); // activate scalarViscosity switch + + // read those switches defined above, if provided in dict + forceSubM(0).readSwitches(); + if (modelType_ == "B") { FatalError <<"using model viscForce with model type B is not valid\n" << abort(FatalError); - }else + }else if (modelType_ == "Bfull") { - treatDEM_=true; - Info << "viscForce is applied only to DEM side" << endl; + if(forceSubM(0).switches()[1]) + { + Info << "Using treatForceDEM false!" << endl; + forceSubM(0).setSwitches(1,false); // treatForceDEM = false + } + + }else // modelType_=="A" + { + if(!forceSubM(0).switches()[1]) + { + Info << "Using treatForceDEM true!" << endl; + forceSubM(0).setSwitches(1,true); // treatForceDEM = true + } } - if (propsDict_.found("verbose")) verbose_=true; - if (propsDict_.found("treatExplicit")) treatExplicit_=true; if (propsDict_.found("useAddedMass")) { @@ -88,11 +106,6 @@ viscForce::viscForce Info << "WARNING: use fix nve/sphere/addedMass in LIGGGHTS input script to correctly account for added mass effects!" << endl; } - if (propsDict_.found("interpolation")) - { - Info << "using interpolated value of pressure gradient." << endl; - interpolation_=true; - } particleCloud_.checkCG(true); //Append the field names to be probed @@ -113,26 +126,9 @@ viscForce::~viscForce() void viscForce::setForce() const { - - // get viscosity field - #ifdef comp - const volScalarField& mufField = particleCloud_.turbulence().mu(); - - // calc div(Tau) - volVectorField divTauField = - - fvc::laplacian(mufField, U_) - - fvc::div(mufField*dev(fvc::grad(U_)().T())); - #else - const volScalarField& nufField = particleCloud_.turbulence().nu(); - - // calc div(Tau) - volVectorField divTauField = - - fvc::laplacian(nufField*rho_, U_) - - fvc::div(nufField*rho_*dev(fvc::grad(U_)().T())); - #endif + const volVectorField& divTauField = forceSubM(0).divTauField(U_); vector divTau; - scalar ds; scalar Vs; vector position; vector force; @@ -154,7 +150,7 @@ void viscForce::setForce() const position = particleCloud_.position(index); - if(interpolation_) // use intepolated values for alpha (normally off!!!) + if(forceSubM(0).interpolation()) // use intepolated values for alpha (normally off!!!) { divTau = divTauInterpolator_.interpolate(position,cellI); }else @@ -168,7 +164,7 @@ void viscForce::setForce() const // to the generalized buoyancy force force = -Vs*divTau*(1.0+addedMassCoeff_); - if(verbose_ && index >0 && index <2) + if(forceSubM(0).verbose() && index >0 && index <2) { Info << "index = " << index << endl; Info << "gradP = " << divTau << endl; @@ -185,13 +181,8 @@ void viscForce::setForce() const } } - // set force on particle - if(!treatDEM_){ - if(!treatExplicit_) for(int j=0;j<3;j++) impForces()[index][j] += force[j]; - else for(int j=0;j<3;j++) expForces()[index][j] += force[j]; - } - for(int j=0;j<3;j++) DEMForces()[index][j] += force[j]; - + // write particle based data to global array + forceSubM(0).partToArray(index,force,vector::zero); //} } } diff --git a/src/lagrangian/cfdemParticle/subModels/forceModel/viscForce/viscForce.H b/src/lagrangian/cfdemParticle/subModels/forceModel/viscForce/viscForce.H index 2632fbd..772556c 100644 --- a/src/lagrangian/cfdemParticle/subModels/forceModel/viscForce/viscForce.H +++ b/src/lagrangian/cfdemParticle/subModels/forceModel/viscForce/viscForce.H @@ -59,19 +59,12 @@ class viscForce private: dictionary propsDict_; - bool verbose_; - word velocityFieldName_; const volVectorField& U_; - word densityFieldName_; - - const volScalarField& rho_; - mutable double addedMassCoeff_; //added mass coefficient - bool interpolation_; // use interpolated field values public: diff --git a/src/lagrangian/cfdemParticle/subModels/liggghtsCommandModel/liggghtsCommandModel/liggghtsCommandModel.C b/src/lagrangian/cfdemParticle/subModels/liggghtsCommandModel/liggghtsCommandModel/liggghtsCommandModel.C index ae85ed1..409ea3e 100644 --- a/src/lagrangian/cfdemParticle/subModels/liggghtsCommandModel/liggghtsCommandModel/liggghtsCommandModel.C +++ b/src/lagrangian/cfdemParticle/subModels/liggghtsCommandModel/liggghtsCommandModel/liggghtsCommandModel.C @@ -30,6 +30,7 @@ Description \*---------------------------------------------------------------------------*/ #include "error.H" +#include #include "liggghtsCommandModel.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -115,14 +116,14 @@ void liggghtsCommandModel::checkTimeSettings(const dictionary& propsDict) if(runLast_) // last run { // read time options from subdict - endTime_ = particleCloud_.mesh().time().endTime().value(); + endTime_ = particleCloud_.mesh().time().endTime().value()-particleCloud_.mesh().time().startTime().value(); startTime_ = endTime_; - timeInterval_ = 1; + timeInterval_ = -1; // calculate coupling times firstCouplingStep_ = floor(startTime_/DEMts/couplingInterval); lastCouplingStep_ = floor(endTime_/DEMts/couplingInterval); - couplingStepInterval_ = floor(timeInterval_/DEMts/couplingInterval); + couplingStepInterval_ = -1; } else //runEveryCouplingStep of every n steps or every writeStep { @@ -150,7 +151,7 @@ void liggghtsCommandModel::checkTimeSettings(const dictionary& propsDict) { firstCouplingStep_ =1; lastCouplingStep_ =1; - couplingStepInterval_ =1; + couplingStepInterval_ =-1; } if(verbose_){ @@ -238,6 +239,14 @@ DynamicList liggghtsCommandModel::executionsWithinPeriod(scalar TSstart, return executions; } +bool liggghtsCommandModel::checkPath(fileName path) +{ + string strPath = string(path); + struct stat buffer; + return (stat (strPath.c_str(), &buffer) == 0); +} + + void liggghtsCommandModel::parseCommandList(wordList& commandList,labelList& labelList,scalarList& scalarList,word& command, dictionary& propsDict, bool timeStamp) { bool addBlank = true; // std no blanks after each word diff --git a/src/lagrangian/cfdemParticle/subModels/liggghtsCommandModel/liggghtsCommandModel/liggghtsCommandModel.H b/src/lagrangian/cfdemParticle/subModels/liggghtsCommandModel/liggghtsCommandModel/liggghtsCommandModel.H index cba3288..57144f5 100644 --- a/src/lagrangian/cfdemParticle/subModels/liggghtsCommandModel/liggghtsCommandModel/liggghtsCommandModel.H +++ b/src/lagrangian/cfdemParticle/subModels/liggghtsCommandModel/liggghtsCommandModel/liggghtsCommandModel.H @@ -160,6 +160,8 @@ public: DynamicList executionsWithinPeriod(scalar,scalar); + bool checkPath(fileName); + // Access int nextRun(){return nextRun_;}; diff --git a/src/lagrangian/cfdemParticle/subModels/liggghtsCommandModel/writeLiggghts/writeLiggghts.C b/src/lagrangian/cfdemParticle/subModels/liggghtsCommandModel/writeLiggghts/writeLiggghts.C index 4d63958..0f6b23d 100644 --- a/src/lagrangian/cfdemParticle/subModels/liggghtsCommandModel/writeLiggghts/writeLiggghts.C +++ b/src/lagrangian/cfdemParticle/subModels/liggghtsCommandModel/writeLiggghts/writeLiggghts.C @@ -67,7 +67,7 @@ writeLiggghts::writeLiggghts path_(word("..")/word("DEM")), writeName_("liggghts.restartCFDEM"), writeLast_(true), - overwrite_(true) + overwrite_(false) { if (dict.found(typeName + "Props")) { @@ -81,10 +81,25 @@ writeLiggghts::writeLiggghts writeLast_=Switch(propsDict_.lookup("writeLast")); } + if (propsDict_.found("path")) + { + path_=fileName(propsDict_.lookup("path")); + if (!checkPath(path_)) + FatalError<<"The path you provided in writeLiggghtsProps is incorrect: " << path_ << "\n" << abort(FatalError); + else + Info << "Using user defined path to write LIGGGHTS restart file: " << path_ << endl; + } + + if(propsDict_.found("writeName")) + { + propsDict_.lookup("writeName") >> writeName_; + } + if (!writeLast_ && propsDict_.found("overwrite")) { overwrite_=Switch(propsDict_.lookup("overwrite")); } + } if(writeLast_) runLast_=true; diff --git a/src/lagrangian/cfdemParticle/subModels/meshMotionModel/meshMotionModel/meshMotionModel.C b/src/lagrangian/cfdemParticle/subModels/meshMotionModel/meshMotionModel/meshMotionModel.C index 450fbd2..bb0f850 100644 --- a/src/lagrangian/cfdemParticle/subModels/meshMotionModel/meshMotionModel/meshMotionModel.C +++ b/src/lagrangian/cfdemParticle/subModels/meshMotionModel/meshMotionModel/meshMotionModel.C @@ -68,6 +68,75 @@ meshMotionModel::~meshMotionModel() // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +volVectorField& meshMotionModel::f() const +{ + volVectorField tmp + ( + IOobject + ( + "xxx", + particleCloud_.mesh().time().timeName(), + particleCloud_.mesh(), + IOobject::NO_READ, + IOobject::NO_WRITE + ), + particleCloud_.mesh(), + dimensionedVector + ( + "zero", + dimensionSet(0, 1, -1, 0, 0), + vector::zero + ) + ); + return tmp; +} + +volScalarField& meshMotionModel::body() const +{ + volScalarField tmp + ( + IOobject + ( + "xxx", + particleCloud_.mesh().time().timeName(), + particleCloud_.mesh(), + IOobject::NO_READ, + IOobject::NO_WRITE + ), + particleCloud_.mesh(), + dimensionedScalar + ( + "zero", + dimensionSet(0, 1, -1, 0, 0), + 0. + ) + ); + return tmp; +} + +volScalarField& meshMotionModel::inside() const +{ + volScalarField tmp + ( + IOobject + ( + "xxx", + particleCloud_.mesh().time().timeName(), + particleCloud_.mesh(), + IOobject::NO_READ, + IOobject::NO_WRITE + ), + particleCloud_.mesh(), + dimensionedScalar + ( + "zero", + dimensionSet(0, 1, -1, 0, 0), + 0. + ) + ); + return tmp; +} + } // End namespace Foam // ************************************************************************* // diff --git a/src/lagrangian/cfdemParticle/subModels/meshMotionModel/meshMotionModel/meshMotionModel.H b/src/lagrangian/cfdemParticle/subModels/meshMotionModel/meshMotionModel/meshMotionModel.H index cf3da10..41d80d8 100644 --- a/src/lagrangian/cfdemParticle/subModels/meshMotionModel/meshMotionModel/meshMotionModel.H +++ b/src/lagrangian/cfdemParticle/subModels/meshMotionModel/meshMotionModel/meshMotionModel.H @@ -109,6 +109,16 @@ public: // Member Function virtual tmp setMotion() const=0; + virtual void correctF(volVectorField&) const {}; + + virtual void correctUo(volVectorField&) const {}; + + virtual volVectorField& f() const; + + virtual volScalarField& body() const; + + virtual volScalarField& inside() const; + // Access }; diff --git a/src/lagrangian/cfdemParticle/subModels/probeModel/particleProbe/particleProbe.C b/src/lagrangian/cfdemParticle/subModels/probeModel/particleProbe/particleProbe.C index dc480bd..b36752e 100644 --- a/src/lagrangian/cfdemParticle/subModels/probeModel/particleProbe/particleProbe.C +++ b/src/lagrangian/cfdemParticle/subModels/probeModel/particleProbe/particleProbe.C @@ -101,7 +101,9 @@ particleProbe::particleProbe // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // particleProbe::~particleProbe() -{} +{ + clearProbes(); +} // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // @@ -114,6 +116,7 @@ void particleProbe::setOutputFile() const else currItemId_+=1; sPtr = sPtrList_[currItemId_-1]; //set the pointer to the output file from list + probeIndex_=currItemId_-1; } @@ -127,7 +130,7 @@ void particleProbe::initialize(word typeName, word logFileName) const //propsDict_ = particleCloud_.couplingProperties().subDict(typeName + "Props"); name_ = typeName; const char* fileNameOut_ = wordToChar(logFileName); - + if(verboseToFile_) { @@ -204,7 +207,7 @@ void particleProbe::writeHeader() const *sPtr<<"|| scalarData: " << " "; forAll(scalarFields_, iter) { - *sPtr << scalarFields_(iter) << " "; + *sPtr << scalarFields_(iter) << " "; } } @@ -214,8 +217,86 @@ void particleProbe::writeHeader() const } +void particleProbe::clearProbes() const +{ + for (unsigned int i=0; i sValues, Field vValues) const +{ + int vSize_=vProbes_.size(); + int sSize_=sProbes_.size(); + + //check if the particle already has an allocated vector. If not, create it. It should be only called at the beginning. + while(index >= vSize_) + { + std::vector particleVector_; + vProbes_.push_back(particleVector_); + vSize_=vProbes_.size(); + } + + while(index >= sSize_) + { + std::vector particleScalar_; + sProbes_.push_back(particleScalar_); + sSize_=sProbes_.size(); + } + + //register vector probes on the corresponding vector + forAll(vValues, iter) + { + int ProbeSize_=vProbes_[index].size(); + + if(probeIndex_ sValues, Field vValues) const { + updateProbes(index,sValues,vValues); //update probe vectors + + if(printNow_ && checkIDForPrint(index) && verboseToFile_) { @@ -224,15 +305,16 @@ void particleProbe::writeProbe(int index, Field sValues, Field v *sPtr << index << tab << particleCloud_.mesh().time().value() << " " ; *sPtr << "|| "; - + //vectorFields *sPtr << setprecision(writePrecision_) ; forAll(vValues, iter) { - if(!probeDebug_ && iter>0) break; + // if(!probeDebug_ && iter>0) break; *sPtr << vValues[iter][0] << " "; - *sPtr << vValues[iter][1] << " "; - *sPtr << vValues[iter][2] << " "; + *sPtr << vValues[iter][1] << " "; + *sPtr << vValues[iter][2] << " "; + } //scalarFields @@ -256,8 +338,9 @@ void particleProbe::writeProbe(int index, Field sValues, Field v else *sPtr << endl; } - + return; + } bool particleProbe::checkIDForPrint(int index) const diff --git a/src/lagrangian/cfdemParticle/subModels/probeModel/particleProbe/particleProbe.H b/src/lagrangian/cfdemParticle/subModels/probeModel/particleProbe/particleProbe.H index 6d07f23..4f30eeb 100644 --- a/src/lagrangian/cfdemParticle/subModels/probeModel/particleProbe/particleProbe.H +++ b/src/lagrangian/cfdemParticle/subModels/probeModel/particleProbe/particleProbe.H @@ -44,7 +44,7 @@ SourceFiles #include "polyMesh.H" #include "cfdemCloud.H" #include "OFstream.H" - +#include // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // namespace Foam @@ -101,6 +101,15 @@ private: mutable bool printNow_; + mutable std::vector< std::vector > sProbes_; + + mutable std::vector< std::vector > vProbes_; + + mutable std::vector probeName_; + + mutable int probeIndex_; + + public: //- Runtime type information @@ -123,12 +132,18 @@ public: ~particleProbe(); // Member Functions + void updateProbes(int index, Field sValues, Field vValues) const; void initialize(word typeName, word logFileName) const; void setOutputFile() const; void writeHeader() const; void writeProbe(int index, Field sValues, Field vValues) const; bool checkIDForPrint(int) const; void setCounter() const; + void clearProbes() const; + std::vector< std::vector >* getVprobe() { return &vProbes_; }; + std::vector< std::vector >* getSprobe() {return &sProbes_; }; + + }; diff --git a/src/lagrangian/cfdemParticle/subModels/probeModel/probeModel/probeModel.H b/src/lagrangian/cfdemParticle/subModels/probeModel/probeModel/probeModel.H index 0330dc1..d917d1d 100644 --- a/src/lagrangian/cfdemParticle/subModels/probeModel/probeModel/probeModel.H +++ b/src/lagrangian/cfdemParticle/subModels/probeModel/probeModel/probeModel.H @@ -41,6 +41,7 @@ SourceFiles #include "fvCFD.H" #include "cfdemCloud.H" +#include // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // namespace Foam @@ -139,7 +140,11 @@ public: virtual bool checkIDForPrint(int) const {return false;}; virtual void setCounter() const {}; virtual bool active() const {return true;}; + virtual std::vector< std::vector >* getVprobe() {return NULL;}; + virtual std::vector< std::vector >* getSprobe() {return NULL;}; + virtual void clearProbes() const {}; const char* wordToChar(word&) const; + // Access diff --git a/src/lagrangian/cfdemParticle/subModels/smoothingModel/constDiffSmoothing/constDiffSmoothing.C b/src/lagrangian/cfdemParticle/subModels/smoothingModel/constDiffSmoothing/constDiffSmoothing.C index 17844f7..695e515 100644 --- a/src/lagrangian/cfdemParticle/subModels/smoothingModel/constDiffSmoothing/constDiffSmoothing.C +++ b/src/lagrangian/cfdemParticle/subModels/smoothingModel/constDiffSmoothing/constDiffSmoothing.C @@ -77,6 +77,8 @@ constDiffSmoothing::constDiffSmoothing if(propsDict_.found("smoothingLengthReferenceField")) smoothingLengthReferenceField_.value() = double(readScalar(propsDict_.lookup("smoothingLengthReferenceField"))); + checkFields(sSmoothField_); + checkFields(vSmoothField_); } // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // @@ -94,65 +96,74 @@ bool constDiffSmoothing::doSmoothing() const void Foam::constDiffSmoothing::smoothen(volScalarField& fieldSrc) const { - // transfer data to working field to not mess up ddt - volScalarField field=fieldSrc; - field.correctBoundaryConditions(); - field.oldTime()=fieldSrc; - field.oldTime().correctBoundaryConditions(); + // Create scalar smooth field from virgin scalar smooth field template + volScalarField sSmoothField = sSmoothField_; - double deltaT = field.mesh().time().deltaTValue(); + sSmoothField.dimensions().reset(fieldSrc.dimensions()); + sSmoothField.internalField()=fieldSrc.internalField(); + sSmoothField.correctBoundaryConditions(); + sSmoothField.oldTime().dimensions().reset(fieldSrc.dimensions()); + sSmoothField.oldTime()=fieldSrc; + sSmoothField.oldTime().correctBoundaryConditions(); + + double deltaT = sSmoothField.mesh().time().deltaTValue(); DT_.value() = smoothingLength_.value() * smoothingLength_.value() / deltaT; // do smoothing solve ( - fvm::ddt(field) - -fvm::laplacian(DT_, field) + fvm::ddt(sSmoothField) + -fvm::laplacian(DT_, sSmoothField) ); - // bound field - forAll(field,cellI) + // bound sSmoothField_ + forAll(sSmoothField,cellI) { - field[cellI]=max(lowerLimit_,min(upperLimit_,field[cellI])); + sSmoothField[cellI]=max(lowerLimit_,min(upperLimit_,sSmoothField[cellI])); } - // get data from working field - will copy only values at new time - fieldSrc=field; + // get data from working sSmoothField - will copy only values at new time + fieldSrc=sSmoothField; fieldSrc.correctBoundaryConditions(); if(verbose_) { - Info << "min/max(fieldoldTime) (unsmoothed): " << min(field.oldTime()) << tab << max(field.oldTime()) << endl; + Info << "min/max(fieldoldTime) (unsmoothed): " << min(sSmoothField.oldTime()) << tab << max(sSmoothField.oldTime()) << endl; Info << "min/max(fieldSrc): " << min(fieldSrc) << tab << max(fieldSrc) << endl; Info << "min/max(fieldSrc.oldTime): " << min(fieldSrc.oldTime()) << tab << max(fieldSrc.oldTime()) << endl; } + } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // void Foam::constDiffSmoothing::smoothen(volVectorField& fieldSrc) const { - // transfer data to working field to not mess up ddt - volVectorField field=fieldSrc; - field.correctBoundaryConditions(); - field.oldTime()=fieldSrc; - field.oldTime().correctBoundaryConditions(); + // Create scalar smooth field from virgin scalar smooth field template + volVectorField vSmoothField = vSmoothField_; - double deltaT = field.mesh().time().deltaTValue(); + vSmoothField.dimensions().reset(fieldSrc.dimensions()); + vSmoothField.internalField()=fieldSrc.internalField(); + vSmoothField.correctBoundaryConditions(); + vSmoothField.oldTime().dimensions().reset(fieldSrc.dimensions()); + vSmoothField.oldTime()=fieldSrc; + vSmoothField.oldTime().correctBoundaryConditions(); + + double deltaT = vSmoothField_.mesh().time().deltaTValue(); DT_.value() = smoothingLength_.value() * smoothingLength_.value() / deltaT; // do smoothing solve ( - fvm::ddt(field) - -fvm::laplacian(DT_, field) + fvm::ddt(vSmoothField) + -fvm::laplacian(DT_, vSmoothField) ); - // get data from working field - fieldSrc=field; + // get data from working vSmoothField + fieldSrc=vSmoothField; fieldSrc.correctBoundaryConditions(); if(verbose_) { - Info << "min/max(fieldoldTime) (unsmoothed): " << min(field.oldTime()) << tab << max(field.oldTime()) << endl; + Info << "min/max(fieldoldTime) (unsmoothed): " << min(vSmoothField.oldTime()) << tab << max(vSmoothField.oldTime()) << endl; Info << "min/max(fieldSrc): " << min(fieldSrc) << tab << max(fieldSrc) << endl; Info << "min/max(fieldSrc.oldTime): " << min(fieldSrc.oldTime()) << tab << max(fieldSrc.oldTime()) << endl; } @@ -161,15 +172,19 @@ void Foam::constDiffSmoothing::smoothen(volVectorField& fieldSrc) const // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // void Foam::constDiffSmoothing::smoothenReferenceField(volVectorField& fieldSrc) const { - // transfer data to working field to not mess up ddt - volVectorField field=fieldSrc; - field.correctBoundaryConditions(); - field.oldTime()=fieldSrc; - field.oldTime().correctBoundaryConditions(); + // Create scalar smooth field from virgin scalar smooth field template + volVectorField vSmoothField = vSmoothField_; + + vSmoothField.dimensions().reset(fieldSrc.dimensions()); + vSmoothField.internalField()=fieldSrc.internalField(); + vSmoothField.correctBoundaryConditions(); + vSmoothField.oldTime().dimensions().reset(fieldSrc.dimensions()); + vSmoothField.oldTime()=fieldSrc; + vSmoothField.oldTime().correctBoundaryConditions(); double sourceStrength = 1e5; //large number to keep reference values constant - dimensionedScalar deltaT = field.mesh().time().deltaT(); + dimensionedScalar deltaT = vSmoothField.mesh().time().deltaT(); DT_.value() = smoothingLengthReferenceField_.value() * smoothingLengthReferenceField_.value() / deltaT.value(); @@ -192,29 +207,29 @@ void Foam::constDiffSmoothing::smoothenReferenceField(volVectorField& fieldSrc) //loop over particles and map max particle diameter to Euler Grid - forAll(field,cellI) + forAll(vSmoothField,cellI) { - if ( mag(field.oldTime().internalField()[cellI]) > 0.0f) // have a vector in the OLD field, so keep it! + if ( mag(vSmoothField.oldTime().internalField()[cellI]) > 0.0f) // have a vector in the OLD vSmoothField, so keep it! NLarge()[cellI] = sourceStrength; } // do the smoothing solve ( - fvm::ddt(field) - -fvm::laplacian( DT_, field) + fvm::ddt(vSmoothField) + -fvm::laplacian( DT_, vSmoothField) == - NLarge() / deltaT * field.oldTime() //add source to keep cell values constant - -fvm::Sp( NLarge() / deltaT, field) //add sink to keep cell values constant + NLarge() / deltaT * vSmoothField.oldTime() //add source to keep cell values constant + -fvm::Sp( NLarge() / deltaT, vSmoothField) //add sink to keep cell values constant ); - // get data from working field - fieldSrc=field; + // get data from working vSmoothField + fieldSrc=vSmoothField; fieldSrc.correctBoundaryConditions(); if(verbose_) { - Info << "min/max(fieldoldTime) (unsmoothed): " << min(field.oldTime()) << tab << max(field.oldTime()) << endl; + Info << "min/max(fieldoldTime) (unsmoothed): " << min(vSmoothField.oldTime()) << tab << max(vSmoothField.oldTime()) << endl; Info << "min/max(fieldSrc): " << min(fieldSrc) << tab << max(fieldSrc) << endl; Info << "min/max(fieldSrc.oldTime): " << min(fieldSrc.oldTime()) << tab << max(fieldSrc.oldTime()) << endl; } diff --git a/src/lagrangian/cfdemParticle/subModels/smoothingModel/smoothingModel/smoothingModel.C b/src/lagrangian/cfdemParticle/subModels/smoothingModel/smoothingModel/smoothingModel.C index 6eb3407..b906a16 100644 --- a/src/lagrangian/cfdemParticle/subModels/smoothingModel/smoothingModel/smoothingModel.C +++ b/src/lagrangian/cfdemParticle/subModels/smoothingModel/smoothingModel/smoothingModel.C @@ -57,7 +57,33 @@ Foam::smoothingModel::smoothingModel ) : dict_(dict), - particleCloud_(sm) + particleCloud_(sm), + vSmoothField_ + ( + IOobject + ( + "vSmoothField", + particleCloud_.mesh().time().timeName(), + particleCloud_.mesh(), + IOobject::READ_IF_PRESENT, + IOobject::NO_WRITE + ), + particleCloud_.mesh(), + dimensionedVector("zero", dimensionSet(0,0,0,0,0), vector::zero) + ), + sSmoothField_ + ( + IOobject + ( + "sSmoothField", + particleCloud_.mesh().time().timeName(), + particleCloud_.mesh(), + IOobject::READ_IF_PRESENT, + IOobject::NO_WRITE + ), + particleCloud_.mesh(), + dimensionedScalar("zero", dimensionSet(0,0,0,0,0), 0) + ) {} @@ -69,6 +95,28 @@ Foam::smoothingModel::~smoothingModel() // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +void smoothingModel::checkFields(volScalarField& sSmoothField_) const +{ + // currently it is detected if field was auto generated or defined + // improvement would be changing the type here automatically + forAll(sSmoothField_.boundaryField(),patchI) + if(sSmoothField_.boundaryField()[patchI].type()=="calculated") + FatalError <<"Scalar field:"<< sSmoothField_.name() << " must be defined.\n" << abort(FatalError); + + sSmoothField_.writeOpt() = IOobject::AUTO_WRITE; +} + +void smoothingModel::checkFields(volVectorField& vSmoothField_) const +{ + // currently it is detected if field was auto generated or defined + // improvement would be changing the type here automatically + forAll(vSmoothField_.boundaryField(),patchI) + if(vSmoothField_.boundaryField()[patchI].type()=="calculated") + FatalError <<"Vector field:"<< vSmoothField_.name() << " must be defined.\n" << abort(FatalError); + + vSmoothField_.writeOpt() = IOobject::AUTO_WRITE; +} + // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // bool smoothingModel::doSmoothing() const { diff --git a/src/lagrangian/cfdemParticle/subModels/smoothingModel/smoothingModel/smoothingModel.H b/src/lagrangian/cfdemParticle/subModels/smoothingModel/smoothingModel/smoothingModel.H index 336bf75..d0c56a6 100644 --- a/src/lagrangian/cfdemParticle/subModels/smoothingModel/smoothingModel/smoothingModel.H +++ b/src/lagrangian/cfdemParticle/subModels/smoothingModel/smoothingModel/smoothingModel.H @@ -59,6 +59,12 @@ protected: const dictionary& dict_; cfdemCloud& particleCloud_; + mutable volVectorField vSmoothField_; + mutable volScalarField sSmoothField_; + + void checkFields(volScalarField&) const; + void checkFields(volVectorField&) const; + public: //- Runtime type information diff --git a/src/lagrangian/cfdemParticle/subModels/voidFractionModel/GaussVoidFraction/GaussVoidFraction.C b/src/lagrangian/cfdemParticle/subModels/voidFractionModel/GaussVoidFraction/GaussVoidFraction.C index a00514b..60a8eb8 100644 --- a/src/lagrangian/cfdemParticle/subModels/voidFractionModel/GaussVoidFraction/GaussVoidFraction.C +++ b/src/lagrangian/cfdemParticle/subModels/voidFractionModel/GaussVoidFraction/GaussVoidFraction.C @@ -87,7 +87,7 @@ GaussVoidFraction::~GaussVoidFraction() // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // -void GaussVoidFraction::setvoidFraction(double** const& mask,double**& voidfractions,double**& particleWeights,double**& particleVolumes) const +void GaussVoidFraction::setvoidFraction(double** const& mask,double**& voidfractions,double**& particleWeights,double**& particleVolumes,double**& particleV) const { reAllocArrays(); @@ -109,6 +109,7 @@ void GaussVoidFraction::setvoidFraction(double** const& mask,double**& voidfract particleVolumes[index][subcell]=0; } cellsPerParticle_[index][0]=1.0; + particleV[index][0]=0; //collecting data label particleCenterCellID=particleCloud_.cellIDs()[index][0]; @@ -161,6 +162,7 @@ void GaussVoidFraction::setvoidFraction(double** const& mask,double**& voidfract particleWeights[index][0] += core; particleVolumes[index][0] += occupiedVolume; + particleV[index][0] += occupiedVolume; //Info << "Centre:set voidfraction in cellI=" << particleCenterCellID // << ", voidfraction =" << voidfractionNext_[particleCenterCellID] << endl; @@ -177,6 +179,7 @@ void GaussVoidFraction::setvoidFraction(double** const& mask,double**& voidfract voidfractionNext_[cellI] -=occupiedVolume/particleCloud_.mesh().V()[cellI]; particleWeights[index][i+1] += core; particleVolumes[index][i+1] += occupiedVolume; + particleV[index][0] += occupiedVolume; //Info << "AFTER:set voidfraction in cellI=" << cellI // << ", voidfraction =" << voidfractionNext_[cellI] << endl; diff --git a/src/lagrangian/cfdemParticle/subModels/voidFractionModel/GaussVoidFraction/GaussVoidFraction.H b/src/lagrangian/cfdemParticle/subModels/voidFractionModel/GaussVoidFraction/GaussVoidFraction.H index 23aee91..535166b 100644 --- a/src/lagrangian/cfdemParticle/subModels/voidFractionModel/GaussVoidFraction/GaussVoidFraction.H +++ b/src/lagrangian/cfdemParticle/subModels/voidFractionModel/GaussVoidFraction/GaussVoidFraction.H @@ -86,7 +86,7 @@ public: // Member Functions - void setvoidFraction(double** const& ,double**&, double**&, double**&) const; + void setvoidFraction(double** const& ,double**&, double**&, double**&, double**&) const; void buildLabelHashSet ( diff --git a/src/lagrangian/cfdemParticle/subModels/voidFractionModel/IBVoidFraction/IBVoidFraction.C b/src/lagrangian/cfdemParticle/subModels/voidFractionModel/IBVoidFraction/IBVoidFraction.C index a0fb584..a5d327e 100755 --- a/src/lagrangian/cfdemParticle/subModels/voidFractionModel/IBVoidFraction/IBVoidFraction.C +++ b/src/lagrangian/cfdemParticle/subModels/voidFractionModel/IBVoidFraction/IBVoidFraction.C @@ -90,7 +90,7 @@ IBVoidFraction::~IBVoidFraction() // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // -void IBVoidFraction::setvoidFraction(double** const& mask,double**& voidfractions,double**& particleWeights,double**& particleVolumes) const +void IBVoidFraction::setvoidFraction(double** const& mask,double**& voidfractions,double**& particleWeights,double**& particleVolumes,double**& particleV) const { int numprocs, me; @@ -113,6 +113,7 @@ void IBVoidFraction::setvoidFraction(double** const& mask,double**& voidfraction particleVolumes[index][subcell]=0; } cellsPerParticle_[index][0]=1.0; + particleV[index][0]=0; //collecting data label particleCenterCellID=particleCloud_.cellIDs()[index][0]; diff --git a/src/lagrangian/cfdemParticle/subModels/voidFractionModel/IBVoidFraction/IBVoidFraction.H b/src/lagrangian/cfdemParticle/subModels/voidFractionModel/IBVoidFraction/IBVoidFraction.H index 4ca146f..7862071 100755 --- a/src/lagrangian/cfdemParticle/subModels/voidFractionModel/IBVoidFraction/IBVoidFraction.H +++ b/src/lagrangian/cfdemParticle/subModels/voidFractionModel/IBVoidFraction/IBVoidFraction.H @@ -91,7 +91,7 @@ public: // Member Functions - void setvoidFraction(double** const& ,double**&, double**&, double**&) const; + void setvoidFraction(double** const& ,double**&, double**&, double**&, double**&) const; void buildLabelHashSet ( diff --git a/src/lagrangian/cfdemParticle/subModels/voidFractionModel/bigParticleVoidFraction/bigParticleVoidFraction.C b/src/lagrangian/cfdemParticle/subModels/voidFractionModel/bigParticleVoidFraction/bigParticleVoidFraction.C index 3859153..2fd72ea 100644 --- a/src/lagrangian/cfdemParticle/subModels/voidFractionModel/bigParticleVoidFraction/bigParticleVoidFraction.C +++ b/src/lagrangian/cfdemParticle/subModels/voidFractionModel/bigParticleVoidFraction/bigParticleVoidFraction.C @@ -86,7 +86,7 @@ bigParticleVoidFraction::~bigParticleVoidFraction() // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // -void bigParticleVoidFraction::setvoidFraction(double** const& mask,double**& voidfractions,double**& particleWeights,double**& particleVolumes) const +void bigParticleVoidFraction::setvoidFraction(double** const& mask,double**& voidfractions,double**& particleWeights,double**& particleVolumes,double**& particleV) const { reAllocArrays(); @@ -108,6 +108,7 @@ void bigParticleVoidFraction::setvoidFraction(double** const& mask,double**& voi particleVolumes[index][subcell]=0; } cellsPerParticle_[index][0]=1.0; + particleV[index][0]=0; //collecting data label particleCenterCellID=particleCloud_.cellIDs()[index][0]; @@ -153,6 +154,7 @@ void bigParticleVoidFraction::setvoidFraction(double** const& mask,double**& voi particleWeights[index][0] += 1.0/hashSetLength; particleVolumes[index][0] += occupiedVolume; + particleV[index][0] += occupiedVolume; //Info << "Centre:set voidfraction in cellI=" << particleCenterCellID // << ", voidfraction =" << voidfractionNext_[particleCenterCellID] << endl; @@ -166,6 +168,7 @@ void bigParticleVoidFraction::setvoidFraction(double** const& mask,double**& voi voidfractionNext_[cellI] -=occupiedVolume/particleCloud_.mesh().V()[cellI]; particleWeights[index][i+1] += 1.0/hashSetLength; particleVolumes[index][i+1] += occupiedVolume; + particleV[index][0] += occupiedVolume; //Info << "AFTER:set voidfraction in cellI=" << cellI // << ", voidfraction =" << voidfractionNext_[cellI] << endl; diff --git a/src/lagrangian/cfdemParticle/subModels/voidFractionModel/bigParticleVoidFraction/bigParticleVoidFraction.H b/src/lagrangian/cfdemParticle/subModels/voidFractionModel/bigParticleVoidFraction/bigParticleVoidFraction.H index e4a56ba..8e470a4 100644 --- a/src/lagrangian/cfdemParticle/subModels/voidFractionModel/bigParticleVoidFraction/bigParticleVoidFraction.H +++ b/src/lagrangian/cfdemParticle/subModels/voidFractionModel/bigParticleVoidFraction/bigParticleVoidFraction.H @@ -83,7 +83,7 @@ public: // Member Functions - void setvoidFraction(double** const& ,double**&, double**&, double**&) const; + void setvoidFraction(double** const& ,double**&, double**&, double**&, double**&) const; void buildLabelHashSet ( diff --git a/src/lagrangian/cfdemParticle/subModels/voidFractionModel/centreVoidFraction/centreVoidFraction.C b/src/lagrangian/cfdemParticle/subModels/voidFractionModel/centreVoidFraction/centreVoidFraction.C index 9edd105..f04cfc0 100644 --- a/src/lagrangian/cfdemParticle/subModels/voidFractionModel/centreVoidFraction/centreVoidFraction.C +++ b/src/lagrangian/cfdemParticle/subModels/voidFractionModel/centreVoidFraction/centreVoidFraction.C @@ -78,7 +78,7 @@ centreVoidFraction::~centreVoidFraction() // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // -void centreVoidFraction::setvoidFraction(double** const& mask,double**& voidfractions,double**& particleWeights,double**& particleVolumes) const +void centreVoidFraction::setvoidFraction(double** const& mask,double**& voidfractions,double**& particleWeights,double**& particleVolumes,double**& particleV) const { reAllocArrays(); @@ -105,6 +105,7 @@ void centreVoidFraction::setvoidFraction(double** const& mask,double**& voidfrac // store volume for each particle particleVolumes[index][0] = volume; + particleV[index][0] = volume; voidfractionNext_[cellI] -= volume/cellVol; diff --git a/src/lagrangian/cfdemParticle/subModels/voidFractionModel/centreVoidFraction/centreVoidFraction.H b/src/lagrangian/cfdemParticle/subModels/voidFractionModel/centreVoidFraction/centreVoidFraction.H index c84291b..1519992 100644 --- a/src/lagrangian/cfdemParticle/subModels/voidFractionModel/centreVoidFraction/centreVoidFraction.H +++ b/src/lagrangian/cfdemParticle/subModels/voidFractionModel/centreVoidFraction/centreVoidFraction.H @@ -83,7 +83,7 @@ public: // Member Functions - void setvoidFraction(double** const& ,double**&, double**&, double**&) const; + void setvoidFraction(double** const& ,double**&, double**&, double**&, double**&) const; }; diff --git a/src/lagrangian/cfdemParticle/subModels/voidFractionModel/dividedVoidFraction/dividedVoidFraction.C b/src/lagrangian/cfdemParticle/subModels/voidFractionModel/dividedVoidFraction/dividedVoidFraction.C index 384bc8b..88ba06a 100644 --- a/src/lagrangian/cfdemParticle/subModels/voidFractionModel/dividedVoidFraction/dividedVoidFraction.C +++ b/src/lagrangian/cfdemParticle/subModels/voidFractionModel/dividedVoidFraction/dividedVoidFraction.C @@ -69,7 +69,8 @@ dividedVoidFraction::dividedVoidFraction alphaMin_(readScalar(propsDict_.lookup("alphaMin"))), alphaLimited_(0), tooMuch_(0.0), - interpolation_(false) + interpolation_(false), + cfdemUseOnly_(false) { maxCellsPerParticle_ = 29; @@ -83,6 +84,11 @@ dividedVoidFraction::dividedVoidFraction checkWeightNporosity(propsDict_); if (propsDict_.found("verbose")) verbose_=true; + + if (propsDict_.found("cfdemUseOnly")) + { + cfdemUseOnly_ = readBool(propsDict_.lookup("cfdemUseOnly")); + } } @@ -94,9 +100,13 @@ dividedVoidFraction::~dividedVoidFraction() // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // -void dividedVoidFraction::setvoidFraction(double** const& mask,double**& voidfractions,double**& particleWeights,double**& particleVolumes) const +void dividedVoidFraction::setvoidFraction(double** const& mask,double**& voidfractions,double**& particleWeights,double**& particleVolumes, double**& particleV) const { - reAllocArrays(); + + if(cfdemUseOnly_) + reAllocArrays(particleCloud_.numberOfParticles()); + else + reAllocArrays(); scalar pi = M_PI; vector position(0,0,0); @@ -114,11 +124,13 @@ void dividedVoidFraction::setvoidFraction(double** const& mask,double**& voidfra //if(mask[index][0]) //{ // reset + for(int subcell=0;subcell(nPoints); particleVolumes[index][storeInIndex] += particleVolume; + particleV[index][0] += particleVolume; //====================================================// } } diff --git a/src/lagrangian/cfdemParticle/subModels/voidFractionModel/voidFractionModel/voidFractionModel.C b/src/lagrangian/cfdemParticle/subModels/voidFractionModel/voidFractionModel/voidFractionModel.C index c600606..d6276c3 100644 --- a/src/lagrangian/cfdemParticle/subModels/voidFractionModel/voidFractionModel/voidFractionModel.C +++ b/src/lagrangian/cfdemParticle/subModels/voidFractionModel/voidFractionModel/voidFractionModel.C @@ -177,6 +177,15 @@ void Foam::voidFractionModel::reAllocArrays() const } } +void Foam::voidFractionModel::reAllocArrays(int nP) const +{ + if(particleCloud_.numberOfParticlesChanged()) + { + // get arrays of new length + particleCloud_.dataExchangeM().allocateArray(cellsPerParticle_,1,1,nP); + } +} + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // } // End namespace Foam diff --git a/src/lagrangian/cfdemParticle/subModels/voidFractionModel/voidFractionModel/voidFractionModel.H b/src/lagrangian/cfdemParticle/subModels/voidFractionModel/voidFractionModel/voidFractionModel.H index 9f76616..4491cb7 100644 --- a/src/lagrangian/cfdemParticle/subModels/voidFractionModel/voidFractionModel/voidFractionModel.H +++ b/src/lagrangian/cfdemParticle/subModels/voidFractionModel/voidFractionModel/voidFractionModel.H @@ -122,7 +122,7 @@ public: // public member functions - virtual void setvoidFraction(double** const&,double**&,double**&,double**&) const = 0; + virtual void setvoidFraction(double** const&,double**&,double**&,double**&,double**&) const = 0; tmp voidFractionInterp() const; @@ -150,6 +150,8 @@ public: void reAllocArrays() const; + void reAllocArrays(int nP) const; //force number of particles during reallocation, for CFD offline-use + virtual void setParticleType(label type) const {}; virtual bool checkParticleType(label) const {return true;}; //consider all particles by default diff --git a/tutorials/.gitignore b/tutorials/.gitignore new file mode 100644 index 0000000..6154fde --- /dev/null +++ b/tutorials/.gitignore @@ -0,0 +1,8 @@ +*.vtk +*.o +*.d +*.a +*.dep +log_* +log.* +*~ diff --git a/tutorials/cfdemPostproc/fillCylinder/Allrun.sh b/tutorials/cfdemPostproc/fillCylinder/Allrun.sh index 24c64a6..3ebdb7d 100755 --- a/tutorials/cfdemPostproc/fillCylinder/Allrun.sh +++ b/tutorials/cfdemPostproc/fillCylinder/Allrun.sh @@ -19,7 +19,7 @@ cfdemPostProc="true" postproc="true" # check if mesh was built -if [ -d "$casePath/CFD/constant/polyMesh/boundary" ]; then +if [ -f "$casePath/CFD/constant/polyMesh/points" ]; then echo "mesh was built before - using old mesh" else echo "mesh needs to be built" diff --git a/tutorials/cfdemSolverIB/twoSpheresGlowinskiMPI/Allrun.sh b/tutorials/cfdemSolverIB/twoSpheresGlowinskiMPI/Allrun.sh index f05a3d2..0c5232c 100755 --- a/tutorials/cfdemSolverIB/twoSpheresGlowinskiMPI/Allrun.sh +++ b/tutorials/cfdemSolverIB/twoSpheresGlowinskiMPI/Allrun.sh @@ -14,7 +14,7 @@ casePath="$(dirname "$(readlink -f ${BASH_SOURCE[0]})")" echo $casePath # check if mesh was built -if [ -d "$casePath/CFD/constant/polyMesh/boundary" ]; then +if [ -f "$casePath/CFD/constant/polyMesh/points" ]; then echo "mesh was built before - using old mesh" else echo "mesh needs to be built" @@ -23,7 +23,5 @@ else fi -#gnome-terminal --title='cfdemSolverIB two settling disks CFD' -e "CFDrun()" -gnome-terminal --title='cfdemSolverIB twoSpheresGlowinskiMPI CFD' -e "bash $casePath/parCFDDEMrun.sh" -#gnome-terminal --title='cfdemSolverIB two settling disks DEM' -e "DEMrun()" -#gnome-terminal --title='cfdemSolverIB twoSpheresGlowinskiMPI DEM' -e "bash $casePath/DEMrun.sh" +#gnome-terminal --title='cfdemSolverIB twoSpheresGlowinskiMPI CFD' -e "bash $casePath/parCFDDEMrun.sh" +bash $casePath/parCFDDEMrun.sh diff --git a/tutorials/cfdemSolverIB/twoSpheresGlowinskiMPI/CFD/constant/couplingProperties b/tutorials/cfdemSolverIB/twoSpheresGlowinskiMPI/CFD/constant/couplingProperties index a4d8f86..f50b696 100644 --- a/tutorials/cfdemSolverIB/twoSpheresGlowinskiMPI/CFD/constant/couplingProperties +++ b/tutorials/cfdemSolverIB/twoSpheresGlowinskiMPI/CFD/constant/couplingProperties @@ -70,14 +70,12 @@ turbulenceModelType RASProperties;//LESProperties; // ShirgaonkarIBProps { velFieldName "U"; - densityFieldName "rho"; pressureFieldName "p"; verbose; } ArchimedesIBProps { - densityFieldName "rho"; gravityFieldName "g"; voidfractionFieldName "voidfractionNext"; } @@ -91,7 +89,7 @@ twoWayFilesProps twoWayMPIProps { maxNumberOfParticles 10100; - liggghtsPath "../DEM/in.liggghts_init"; + liggghtsPath "../DEM/in.liggghts_run"; } IBProps diff --git a/tutorials/cfdemSolverIB/twoSpheresGlowinskiMPI/DEM/in.liggghts_run b/tutorials/cfdemSolverIB/twoSpheresGlowinskiMPI/DEM/in.liggghts_run new file mode 100644 index 0000000..9259bbe --- /dev/null +++ b/tutorials/cfdemSolverIB/twoSpheresGlowinskiMPI/DEM/in.liggghts_run @@ -0,0 +1,95 @@ +#echo both +log ../DEM/log.liggghts +thermo_log ../DEM/post/thermo.txt + +atom_style granular +atom_modify map array +communicate single vel yes + +boundary f f f +newton off + +units si +processors 2 2 1 + +region reg block 0. 1. 0. 1. 0. 4. units box +create_box 1 reg + +neighbor 0.3 bin +neigh_modify delay 0 binsize 0.01 + + +# Material properties required for new pair styles + +fix m1 all property/global youngsModulus peratomtype 5.e7 +fix m2 all property/global poissonsRatio peratomtype 0.45 +fix m3 all property/global coefficientRestitution peratomtypepair 1 0.9 +fix m4 all property/global coefficientFriction peratomtypepair 1 0.5 + +# pair style +pair_style gran model hertz tangential history #Hertzian without cohesion +pair_coeff * * + +# timestep, gravity +timestep 0.00003 + +fix gravi all gravity 981 vector 0.0 0.0 -1.0 + +# walls +fix xwalls1 all wall/gran model hertz tangential history primitive type 1 xplane 0. +fix xwalls2 all wall/gran model hertz tangential history primitive type 1 xplane 1. +fix ywalls1 all wall/gran model hertz tangential history primitive type 1 yplane 0. +fix ywalls2 all wall/gran model hertz tangential history primitive type 1 yplane 1. +fix zwalls1 all wall/gran model hertz tangential history primitive type 1 zplane 0. +fix zwalls2 all wall/gran model hertz tangential history primitive type 1 zplane 4. + +# cfd coupling +fix cfd all couple/cfd couple_every 10 mpi +fix cfd2 all couple/cfd/force + + +# create single partciles +create_atoms 1 single .5 .5 3.5 units box +create_atoms 1 single .5 .5 3.16 units box +set atom 1 diameter 0.167 density 1.5 vx 0 vy 0 vz 0 +set atom 2 diameter 0.167 density 1.5 vx 0 vy 0 vz 0 + +variable vx1 equal vx[1] +variable vy1 equal vy[1] +variable vz1 equal vz[1] +variable vx2 equal vx[2] +variable vy2 equal vy[2] +variable vz2 equal vz[2] +variable x1 equal x[1] +variable y1 equal y[1] +variable z1 equal z[1] +variable x2 equal x[2] +variable y2 equal y[2] +variable z2 equal z[2] +variable time equal step*dt + +fix extra1 all print 100 "${time} ${vx1} ${vy1} ${vz1}" file ../DEM/post/velocity_particle_1.txt title "%" screen no +fix extra2 all print 100 "${time} ${vx2} ${vy2} ${vz2}" file ../DEM/post/velocity_particle_2.txt title "%" screen no +fix extra3 all print 100 "${time} ${x1} ${y1} ${z1}" file ../DEM/post/position_particle_1.txt title "%" screen no +fix extra4 all print 100 "${time} ${x2} ${y2} ${z2}" file ../DEM/post/position_particle_2.txt title "%" screen no + + +# apply nve integration to all particles that are inserted as single particles +fix integr all nve/sphere #wenn das ausgeblendet, dann kein vel update + +# screen output +compute rke all erotate/sphere +thermo_style custom step atoms ke c_rke vol +thermo 1000 +thermo_modify lost ignore norm no +compute_modify thermo_temp dynamic yes + +# insert the first particles so that dump is not empty +dump dmp all custom 100 ../DEM/post/dump.liggghts_run id type x y z ix iy iz vx vy vz fx fy fz omegax omegay omegaz radius + +#force : f_couple_cfd[0] f_couple_cfd[1] f_couple_cfd[2] +#node : f_couple_cfd[6] +#cell id : f_couple_cfd[7] + +run 1 + diff --git a/tutorials/cfdemSolverIB/twoSpheresGlowinskiMPI/DEM/post/.gitignore b/tutorials/cfdemSolverIB/twoSpheresGlowinskiMPI/DEM/post/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/tutorials/cfdemSolverIB/twoSpheresGlowinskiMPI/parCFDDEMrun.sh b/tutorials/cfdemSolverIB/twoSpheresGlowinskiMPI/parCFDDEMrun.sh index d22d9e4..47d3b2c 100644 --- a/tutorials/cfdemSolverIB/twoSpheresGlowinskiMPI/parCFDDEMrun.sh +++ b/tutorials/cfdemSolverIB/twoSpheresGlowinskiMPI/parCFDDEMrun.sh @@ -45,7 +45,7 @@ if [ $postproc == "true" ] then #- get VTK data from liggghts dump file cd $casePath/DEM/post - python -i $CFDEM_LPP_DIR/lpp.py dump.liggghts_init + python -i $CFDEM_LPP_DIR/lpp.py dump.liggghts_run #- get VTK data from CFD sim cd $casePath/CFD @@ -65,20 +65,13 @@ cp ../../$logfileName $testHarnessPath #- clean up case echo "deleting data at: $casePath" -rm -r $casePath/CFD/0.* -rm -r $casePath/CFD/callgrind.* -rm -r $casePath/CFD/*.out -rm -r $casePath/CFD/VTK -rm -r $casePath/CFD/couplingFiles/* -rm -r $casePath/CFD/processor* -rm -r $casePath/CFD/particles* -rm -r $casePath/CFD/probes -rm -r $casePath/DEM/post/* -rm -r $casePath/DEM/log.* -rm -r $casePath/log_* +source $WM_PROJECT_DIR/bin/tools/CleanFunctions +cd $casePath/CFD +cleanCase +rm -r $casePath/CFD/clockData +rm $casePath/DEM/post/*.* +#rm -r $casePath/DEM/post/restart/*.* +#- preserve post directory +touch $casePath/DEM/post/.gitignore echo "done" -#- preserve post directory -echo "dummyfile" >> $casePath/DEM/post/dummy - - diff --git a/tutorials/cfdemSolverPiso/ErgunTestMPI/Allrun.sh b/tutorials/cfdemSolverPiso/ErgunTestMPI/Allrun.sh index 7ef8738..fdfed50 100755 --- a/tutorials/cfdemSolverPiso/ErgunTestMPI/Allrun.sh +++ b/tutorials/cfdemSolverPiso/ErgunTestMPI/Allrun.sh @@ -10,7 +10,7 @@ casePath="$(dirname "$(readlink -f ${BASH_SOURCE[0]})")" # check if mesh was built -if [ -d "$casePath/CFD/constant/polyMesh/boundary" ]; then +if [ -f "$casePath/CFD/constant/polyMesh/points" ]; then echo "mesh was built before - using old mesh" else echo "mesh needs to be built" @@ -18,5 +18,13 @@ else blockMesh fi +if [ -f "$casePath/DEM/post/restart/liggghts.restart" ]; then + echo "LIGGGHTS init was run before - using existing restart file" +else + #- run DEM in new terminal + $casePath/parDEMrun.sh +fi + #- run parallel CFD-DEM in new terminal -gnome-terminal --title='cfdemSolverPiso ErgunTestMPI CFD' -e "bash $casePath/parCFDDEMrun.sh" +#gnome-terminal --title='cfdemSolverPiso ErgunTestMPI CFD' -e "bash $casePath/parCFDDEMrun.sh" +bash $casePath/parCFDDEMrun.sh diff --git a/tutorials/cfdemSolverPiso/ErgunTestMPI/CFD/0/p b/tutorials/cfdemSolverPiso/ErgunTestMPI/CFD/0/p index be1cbf5..3a45674 100644 --- a/tutorials/cfdemSolverPiso/ErgunTestMPI/CFD/0/p +++ b/tutorials/cfdemSolverPiso/ErgunTestMPI/CFD/0/p @@ -16,7 +16,7 @@ FoamFile dimensions [0 2 -2 0 0 0 0]; -internalField uniform 1.0e5; +internalField uniform 1; boundaryField { @@ -37,7 +37,7 @@ boundaryField //type zeroGradient; type fixedValue; - value uniform 1.0e5; + value $internalField; } } diff --git a/tutorials/cfdemSolverPiso/ErgunTestMPI/CFD/constant/couplingProperties b/tutorials/cfdemSolverPiso/ErgunTestMPI/CFD/constant/couplingProperties index aa9fa97..2c6aee7 100644 --- a/tutorials/cfdemSolverPiso/ErgunTestMPI/CFD/constant/couplingProperties +++ b/tutorials/cfdemSolverPiso/ErgunTestMPI/CFD/constant/couplingProperties @@ -26,6 +26,9 @@ FoamFile //===========================================================================// // sub-models & settings +syncMode false; +//verbose; + modelType "A"; // A or B couplingInterval 100; @@ -55,9 +58,11 @@ forceModels //GidaspowDrag //BeetstraDrag //DiFeliceDrag - KochHillDrag gradPForce viscForce + KochHillDrag + //DEMbasedDrag + //RongDrag //Archimedes //volWeightedAverage //totalMomentumExchange @@ -99,23 +104,20 @@ implicitCoupleProps ArchimedesProps { - densityFieldName "rho"; gravityFieldName "g"; } gradPForceProps { pFieldName "p"; - densityFieldName "rho"; voidfractionFieldName "voidfraction"; velocityFieldName "U"; - interpolation; + interpolation true; } viscForceProps { velocityFieldName "U"; - densityFieldName "rho"; - interpolation; + interpolation true; } volWeightedAverageProps { @@ -128,7 +130,7 @@ volWeightedAverageProps ); upperThreshold 0.999; lowerThreshold 0; - verbose; + verbose true; } totalMomentumExchangeProps { @@ -136,37 +138,48 @@ totalMomentumExchangeProps explicitMomExFieldName "none"; fluidVelFieldName "U"; granVelFieldName "Us"; - densityFieldName "rho"; } GidaspowDragProps { - verbose; + verbose true; velFieldName "U"; - densityFieldName "rho"; voidfractionFieldName "voidfraction"; - interpolation; + interpolation true; phi 1; } -DiFeliceDragProps +DEMbasedDragProps { velFieldName "U"; - densityFieldName "rho"; voidfractionFieldName "voidfraction"; } +DiFeliceDragProps +{ + //verbose true; + velFieldName "U"; + voidfractionFieldName "voidfraction"; + granVelFieldName "Us"; + interpolation true; +} + KochHillDragProps { - //verbose; + //verbose true; velFieldName "U"; - densityFieldName "rho"; voidfractionFieldName "voidfraction"; - interpolation; + interpolation true; + //forceSubModels + //( + // ImExCorr + //); + implForceDEM true; + //implForceDEMaccumulated true; + //explicitCorr true; } BeetstraDragProps { velFieldName "U"; - densityFieldName "rho"; gravityFieldName "g"; rhoParticle 2000.; voidfractionFieldName "voidfraction"; @@ -175,20 +188,42 @@ BeetstraDragProps useParcelSizeDependentFilteredDrag ; k 0.05; aLimit 0.0; -// verbose ; +// verbose true; +} + +RongDragProps +{ + verbose true; + velFieldName "U"; + voidfractionFieldName "voidfraction"; + interpolation true; + implForceDEM true; + implForceDEMaccumulated true; + granVelFieldName "Us"; } virtualMassForceProps { velFieldName "U"; - densityFieldName "rho"; } particleCellVolumeProps { upperThreshold 0.999; lowerThreshold 0.; - verbose; + verbose true; +} + +fieldStoreProps +{ + scalarFieldNames + ( + ); + + vectorFieldNames + ( + "U" + ); } oneWayVTKProps @@ -228,11 +263,11 @@ dividedProps twoWayMPIProps { - liggghtsPath "../DEM/in.liggghts_resume"; + liggghtsPath "../DEM/in.liggghts_run"; } twoWayM2MProps { maxNumberOfParticles 10100; - liggghtsPath "../DEM/in.liggghts_resume"; + liggghtsPath "../DEM/in.liggghts_run"; } // ************************************************************************* // diff --git a/tutorials/cfdemSolverPiso/ErgunTestMPI/CFD/constant/liggghtsCommands b/tutorials/cfdemSolverPiso/ErgunTestMPI/CFD/constant/liggghtsCommands index a5ffcae..d9e1ce8 100644 --- a/tutorials/cfdemSolverPiso/ErgunTestMPI/CFD/constant/liggghtsCommands +++ b/tutorials/cfdemSolverPiso/ErgunTestMPI/CFD/constant/liggghtsCommands @@ -26,6 +26,7 @@ FoamFile liggghtsCommandModels ( runLiggghts + writeLiggghts ); // ************************************************************************* // @@ -33,3 +34,10 @@ liggghtsCommandModels { preNo false; }*/ + +writeLiggghtsProps +{ + writeLast off; + writeName "post/restart/liggghts.restartCFDEM"; + overwrite on; +} diff --git a/tutorials/cfdemSolverPiso/ErgunTestMPI/CFD/octave/totalPressureDrop.m b/tutorials/cfdemSolverPiso/ErgunTestMPI/CFD/octave/totalPressureDrop.m index b6ec7d7..5a7d1a3 100644 --- a/tutorials/cfdemSolverPiso/ErgunTestMPI/CFD/octave/totalPressureDrop.m +++ b/tutorials/cfdemSolverPiso/ErgunTestMPI/CFD/octave/totalPressureDrop.m @@ -53,7 +53,7 @@ fprintf('so the result does not depend on density\n') %================================== % min fluidization velocity in m/s %================================== -rhoP = 2000 % particle density in kg/m3 +rhoP = 2000 % particle density in kg/m3 g = 9.81 % gravity m/s2 Umf = dp^2*(rhoP-rhoG)*g/(150*muG)*(epsilon^3*phip^2)/(1-epsilon); @@ -96,8 +96,4 @@ axis([0,Uend,0,dpErgun(length(dpErgun))]) %print('cfdemSolverPiso_settlingTest.eps','-deps2') print -color "cfdemSolverPiso_ErgunTestMPI.eps" -replot; - - - diff --git a/tutorials/cfdemSolverPiso/ErgunTestMPI/CFD/system/controlDict b/tutorials/cfdemSolverPiso/ErgunTestMPI/CFD/system/controlDict index 55a2adb..596886d 100644 --- a/tutorials/cfdemSolverPiso/ErgunTestMPI/CFD/system/controlDict +++ b/tutorials/cfdemSolverPiso/ErgunTestMPI/CFD/system/controlDict @@ -63,27 +63,27 @@ functions name probes; probeLocations ( - (0 0 0.0001) - (0 0 0.0026) - (0 0 0.0051) - (0 0 0.0076) - (0 0 0.0101) - (0 0 0.0126) - (0 0 0.0151) - (0 0 0.0176) - (0 0 0.0201) - (0 0 0.0226) - (0 0 0.0251) - (0 0 0.0276) - (0 0 0.0301) - (0 0 0.0326) - (0 0 0.0351) - (0 0 0.0375) - (0 0 0.0401) - (0 0 0.0426) - (0 0 0.0451) - (0 0 0.0476) - (0 0 0.0529) + (0.00003 0 0.0001) + (0.00003 0 0.0026) + (0.00003 0 0.0051) + (0.00003 0 0.0076) + (0.00003 0 0.0101) + (0.00003 0 0.0126) + (0.00003 0 0.0151) + (0.00003 0 0.0176) + (0.00003 0 0.0201) + (0.00003 0 0.0226) + (0.00003 0 0.0251) + (0.00003 0 0.0276) + (0.00003 0 0.0301) + (0.00003 0 0.0326) + (0.00003 0 0.0351) + (0.00003 0 0.0375) + (0.00003 0 0.0401) + (0.00003 0 0.0426) + (0.00003 0 0.0451) + (0.00003 0 0.0476) + (0.00003 0 0.0529) ); // Fields to be probed diff --git a/tutorials/cfdemSolverPiso/ErgunTestMPI/DEM/in.liggghts_init b/tutorials/cfdemSolverPiso/ErgunTestMPI/DEM/in.liggghts_init index e6f325c..363df49 100644 --- a/tutorials/cfdemSolverPiso/ErgunTestMPI/DEM/in.liggghts_init +++ b/tutorials/cfdemSolverPiso/ErgunTestMPI/DEM/in.liggghts_init @@ -1,64 +1,64 @@ # Pour granular particles into chute container, then induce flow -echo both -atom_style granular -atom_modify map array -communicate single vel yes +echo both +atom_style granular +atom_modify map array +communicate single vel yes -boundary m m m -newton off +boundary m m m +newton off -units si +units si -region reg block -0.015 0.015 -0.015 0.015 -0.001 0.0554 units box -create_box 1 reg +region reg block -0.015 0.015 -0.015 0.015 -0.001 0.0554 units box +create_box 1 reg -neighbor 0.001 bin -neigh_modify delay 0 +neighbor 0.001 bin +neigh_modify delay 0 -#Material properties required for new pair styles +# Material properties required for granular pair styles -fix m1 all property/global youngsModulus peratomtype 5.e6 -fix m2 all property/global poissonsRatio peratomtype 0.45 -fix m3 all property/global coefficientRestitution peratomtypepair 1 0.3 -fix m4 all property/global coefficientFriction peratomtypepair 1 0.5 +fix m1 all property/global youngsModulus peratomtype 5.e6 +fix m2 all property/global poissonsRatio peratomtype 0.45 +fix m3 all property/global coefficientRestitution peratomtypepair 1 0.3 +fix m4 all property/global coefficientFriction peratomtypepair 1 0.5 -#pair style -pair_style gran model hertz tangential history #Hertzian without cohesion -pair_coeff * * +# pair style +pair_style gran model hertz tangential history # Hertzian without cohesion +pair_coeff * * -#timestep, gravity -timestep 0.00001 -fix gravi all gravity 9.81 vector 0.0 0.0 -1.0 +# timestep, gravity +timestep 0.00001 +fix gravi all gravity 9.81 vector 0.0 0.0 -1.0 -#walls -fix zwalls1 all wall/gran model hertz tangential history primitive type 1 zplane 0.0 -fix zwalls2 all wall/gran model hertz tangential history primitive type 1 zplane 0.0553 -fix cylwalls all wall/gran model hertz tangential history primitive type 1 zcylinder 0.01385 0. 0. +# walls +fix zwalls1 all wall/gran model hertz tangential history primitive type 1 zplane 0.0 +fix zwalls2 all wall/gran model hertz tangential history primitive type 1 zplane 0.0553 +fix cylwalls all wall/gran model hertz tangential history primitive type 1 zcylinder 0.01385 0. 0. -#particle distributions and insertion -region bc cylinder z 0.0 0.0 0.012 0. 0.055 units box -fix pts1 all particletemplate/sphere 1 atom_type 1 density constant 2000 radius constant 0.0005 -fix pdd1 all particledistribution/discrete 1. 1 pts1 1.0 +# particle distributions and insertion +region bc cylinder z 0.0 0.0 0.012 0. 0.055 units box +fix pts1 all particletemplate/sphere 1 atom_type 1 density constant 2000 radius constant 0.0005 +fix pdd1 all particledistribution/discrete 1 1 pts1 1.0 -fix ins all insert/pack seed 100001 distributiontemplate pdd1 vel constant 0. 0. -1. insert_every once overlapcheck yes all_in yes particles_in_region 10000 region bc +fix ins all insert/pack seed 100001 distributiontemplate pdd1 vel constant 0. 0. -1. insert_every once overlapcheck yes all_in yes particles_in_region 10000 region bc -#apply nve integration to all particles that are inserted as single particles -fix integr all nve/sphere +# apply nve integration to all particles that are inserted as single particles +fix integr all nve/sphere -#screen output -compute 1 all erotate/sphere -thermo_style custom step atoms ke c_1 vol -thermo 1000 -thermo_modify lost ignore norm no -compute_modify thermo_temp dynamic yes +# screen output +compute rke all erotate/sphere +thermo_style custom step atoms ke c_rke vol +thermo 1000 +thermo_modify lost ignore norm no +compute_modify thermo_temp dynamic yes -#insert the first particles so that dump is not empty -run 1 -dump dmp all custom 5000 post/dump.liggghts_init id type type x y z ix iy iz vx vy vz fx fy fz omegax omegay omegaz radius +# insert the first particles so that dump is not empty +run 1 +dump dmp all custom 5000 post/dump.liggghts_init id type x y z ix iy iz vx vy vz fx fy fz omegax omegay omegaz radius #force : f_couple_cfd[0] f_couple_cfd[1] f_couple_cfd[2] #node : f_couple_cfd[6] #cell id : f_couple_cfd[7] -run 10000 upto -write_restart liggghts.restart +run 10000 upto +write_restart post/restart/liggghts.restart diff --git a/tutorials/cfdemSolverPiso/ErgunTestMPI/DEM/in.liggghts_run b/tutorials/cfdemSolverPiso/ErgunTestMPI/DEM/in.liggghts_run new file mode 100644 index 0000000..2d49863 --- /dev/null +++ b/tutorials/cfdemSolverPiso/ErgunTestMPI/DEM/in.liggghts_run @@ -0,0 +1,68 @@ +# Pour granular particles into chute container, then induce flow +log ../DEM/log.liggghts +thermo_log ../DEM/post/thermo.txt + +atom_style granular +atom_modify map array +communicate single vel yes + +boundary m m m +newton off + +units si +processors 2 2 1 + +# read the restart file +read_restart ../DEM/post/restart/liggghts.restart + +neighbor 0.0005 bin +neigh_modify delay 0 + +# Material properties required for granular pair styles + +fix m1 all property/global youngsModulus peratomtype 5.e6 +fix m2 all property/global poissonsRatio peratomtype 0.45 +fix m3 all property/global coefficientRestitution peratomtypepair 1 0.3 +fix m4 all property/global coefficientFriction peratomtypepair 1 0.5 + +# pair style +pair_style gran model hertz tangential history # Hertzian without cohesion +pair_coeff * * + +# timestep, gravity +timestep 0.00001 +fix gravi all gravity 9.81 vector 0.0 0.0 -1.0 + +# walls +fix zwalls1 all wall/gran model hertz tangential history primitive type 1 zplane 0.0 +fix zwalls2 all wall/gran model hertz tangential history primitive type 1 zplane 0.0553 +fix cylwalls all wall/gran model hertz tangential history primitive type 1 zcylinder 0.01385 0. 0. + +# change the particles density +set group all density 2000 + +# cfd coupling +fix cfd all couple/cfd couple_every 100 mpi +fix cfd2 all couple/cfd/force/implicit +#fix cfd2 all couple/cfd/force/accumulator RongDrag 10 1.5e-3 +#fix cfd2 all couple/cfd/force/implicit/accumulated #CrankNicolson 0.5 + +# apply nve integration to all particles that are inserted as single particles +fix integr all nve/sphere + +# center of mass +compute centerOfMass all com + +# compute total dragforce +compute dragtotal all reduce sum f_dragforce[1] f_dragforce[2] f_dragforce[3] + +# screen output +compute rke all erotate/sphere +thermo_style custom step atoms ke c_rke vol c_centerOfMass[3] c_dragtotal[1] c_dragtotal[2] c_dragtotal[3] +thermo 10 +thermo_modify lost ignore norm no +compute_modify thermo_temp dynamic yes + +dump dmp all custom 5000 ../DEM/post/dump*.liggghts_run id type x y z vx vy vz fx fy fz f_dragforce[1] f_dragforce[2] f_dragforce[3] radius + +run 1 diff --git a/tutorials/cfdemSolverPiso/ErgunTestMPI/DEM/post/restart/.gitignore b/tutorials/cfdemSolverPiso/ErgunTestMPI/DEM/post/restart/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/tutorials/cfdemSolverPiso/ErgunTestMPI/parCFDDEMrun.sh b/tutorials/cfdemSolverPiso/ErgunTestMPI/parCFDDEMrun.sh index de2c30b..73c92d2 100644 --- a/tutorials/cfdemSolverPiso/ErgunTestMPI/parCFDDEMrun.sh +++ b/tutorials/cfdemSolverPiso/ErgunTestMPI/parCFDDEMrun.sh @@ -21,7 +21,7 @@ logfileName="log_$headerText" solverName="cfdemSolverPiso" nrProcs="4" machineFileName="none" # yourMachinefileName | none -debugMode="off" # on | off| strict # on | off| strict +debugMode="off" # on | off| strict testHarnessPath="$CFDEM_TEST_HARNESS_PATH" runOctave="true" postproc="false" @@ -62,7 +62,7 @@ if [ $postproc == "true" ] #- get VTK data from liggghts dump file cd $casePath/DEM/post - python -i $CFDEM_LPP_DIR/lpp.py dump*.liggghts_restart + python -i $CFDEM_LPP_DIR/lpp.py dump*.liggghts_run #- get VTK data from CFD sim cd $casePath/CFD @@ -86,6 +86,9 @@ source $WM_PROJECT_DIR/bin/tools/CleanFunctions cd $casePath/CFD cleanCase rm -r $casePath/CFD/clockData -rm -r $casePath/DEM/post/* -(cd $casePath/DEM/post && touch dummy) +rm $casePath/DEM/post/*.* +touch $casePath/DEM/post/.gitignore +#rm $casePath/DEM/post/restart/*.* +rm $casePath/DEM/post/restart/liggghts.restartCFDEM* +touch $casePath/DEM/post/restart/.gitignore echo "done" diff --git a/tutorials/cfdemSolverPiso/ErgunTestMPI/parDEMrun.sh b/tutorials/cfdemSolverPiso/ErgunTestMPI/parDEMrun.sh new file mode 100755 index 0000000..d1e3a03 --- /dev/null +++ b/tutorials/cfdemSolverPiso/ErgunTestMPI/parDEMrun.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +#===================================================================# +# DEMrun script for ErgunTestMPI testcase +# init ErgunTestMPI +# Christoph Goniva - July 2014 +#===================================================================# + +#- source CFDEM env vars +. ~/.bashrc + +#- include functions +source $CFDEM_SRC_DIR/lagrangian/cfdemParticle/etc/functions.sh + +echo "starting DEM run in parallel..." +#--------------------------------------------------------------------------------# +#- define variables +casePath="$(dirname "$(readlink -f ${BASH_SOURCE[0]})")" +logpath="$casePath" +headerText="run_liggghts_init_DEM" +logfileName="log_$headerText" +solverName="in.liggghts_init" +nrProcs=4 +machineFileName="none" +debugMode="off" +#--------------------------------------------------------------------------------# + +#- call function to run DEM case +parDEMrun $logpath $logfileName $casePath $headerText $solverName $nrProcs $machineFileName $debugMode + diff --git a/tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/Allrun.sh b/tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/Allrun.sh index bfbb0e2..8a87b18 100755 --- a/tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/Allrun.sh +++ b/tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/Allrun.sh @@ -10,7 +10,7 @@ casePath="$(dirname "$(readlink -f ${BASH_SOURCE[0]})")" # check if mesh was built -if [ -d "$casePath/CFD/constant/polyMesh/boundary" ]; then +if [ -f "$casePath/CFD/constant/polyMesh/points" ]; then echo "mesh was built before - using old mesh" else echo "mesh needs to be built" @@ -18,17 +18,13 @@ else blockMesh fi -echo "WARNING:copying a CGS based controlDict to $HOME/.OpenFOAM/$WM_PROJECT_VERSION" -echo "this will make your simulations use CGS unit system" -read -echo "Make sure $HOME/.OpenFOAM/$WM_PROJECT_VERSION/controlDict is removed after this simulation." - -mkdir -p $FOAM_INST_DIR/.OpenFOAM//$WM_PROJECT_VERSION -cp $CFDEM_SRC_DIR/lagrangian/cfdemParticle/etc/controlDict_cgs_$WM_PROJECT_VERSION $FOAM_INST_DIR/.OpenFOAM/$WM_PROJECT_VERSION/controlDict +if [ -f "$casePath/DEM/post/restart/liggghts.restart" ]; then + echo "LIGGGHTS init was run before - using existing restart file" +else + #- run DEM + $casePath/parDEMrun.sh +fi #- run parallel CFD-DEM in new terminal -gnome-terminal --title='cfdemSolverPiso ErgunTestMPI CFD' -e "bash $casePath/parCFDDEMrun.sh" - -echo "removing $FOAM_INST_DIR/.OpenFOAM/$WM_PROJECT_VERSION/controlDict?" -read -rm -r $FOAM_INST_DIR/.OpenFOAM/$WM_PROJECT_VERSION/controlDict* +#gnome-terminal --title='cfdemSolverPiso ErgunTestMPI_cgs CFD' -e "bash $casePath/parCFDDEMrun.sh" +bash $casePath/parCFDDEMrun.sh diff --git a/tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/CFD/constant/couplingProperties b/tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/CFD/constant/couplingProperties index 558e491..c3ca876 100644 --- a/tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/CFD/constant/couplingProperties +++ b/tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/CFD/constant/couplingProperties @@ -81,23 +81,20 @@ implicitCoupleProps ArchimedesProps { - densityFieldName "rho"; gravityFieldName "g"; } gradPForceProps { pFieldName "p"; - densityFieldName "rho"; voidfractionFieldName "voidfraction"; velocityFieldName "U"; - //interpolation; + //interpolation true; } viscForceProps { velocityFieldName "U"; - densityFieldName "rho"; - interpolation; + interpolation true; } volWeightedAverageProps { @@ -118,17 +115,14 @@ totalMomentumExchangeProps explicitMomExFieldName "none"; fluidVelFieldName "U"; granVelFieldName "Us"; - densityFieldName "rho"; } GidaspowDragProps { velFieldName "U"; - densityFieldName "rho"; } DiFeliceDragProps { velFieldName "U"; - densityFieldName "rho"; voidfractionFieldName "voidfraction"; granVelFieldName "Us"; } @@ -136,14 +130,12 @@ DiFeliceDragProps KochHillDragProps { velFieldName "U"; - densityFieldName "rho"; voidfractionFieldName "voidfraction"; } virtualMassForceProps { velFieldName "U"; - densityFieldName "rho"; } oneWayVTKProps @@ -184,11 +176,11 @@ dividedProps twoWayMPIProps { //maxNumberOfParticles 10100; - liggghtsPath "../DEM/in.liggghts_resume"; + liggghtsPath "../DEM/in.liggghts_run"; } twoWayM2MProps { maxNumberOfParticles 10100; - liggghtsPath "../DEM/in.liggghts_resume"; + liggghtsPath "../DEM/in.liggghts_run"; } // ************************************************************************* // diff --git a/tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/CFD/octave/totalPressureDrop.m b/tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/CFD/octave/totalPressureDrop.m index 15cf540..d1e329f 100644 --- a/tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/CFD/octave/totalPressureDrop.m +++ b/tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/CFD/octave/totalPressureDrop.m @@ -5,6 +5,7 @@ clc; %====================================% % simulation data 1 %====================================% +rhoG = 0.01 % density in g/cm3 %path = '../probes/0/p'; % 2.1.x path = '../postProcessing/probes/0/p'; % 2.2.x columns=22; @@ -12,7 +13,7 @@ headerlines=4; data = loaddata(path,columns,headerlines); data=transpose(data); [x,y]=size(data) -dp_sim = (data(:,2)-data(:,y))*0.01/10; % *rhoG to get pressure, then *10 to get from Ba in Pa +dp_sim = (data(:,2)-data(:,y))*rhoG*0.1; % *rhoG to get pressure, then *0.1 to get from Ba in Pa t_sim = data(:,1); %fprintf('final pressureDrop of sim = %f Pa\n',dp_sim(length(dp_sim)) ) @@ -96,8 +97,4 @@ ylabel("pressure drop [Pa]") %print('cfdemSolverPiso_settlingTest.eps','-deps2') print -color "cfdemSolverPiso_ErgunTestMPI.eps" -replot; - - - diff --git a/tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/CFD/system/controlDict b/tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/CFD/system/controlDict index 1b7262f..6fcc089 100644 --- a/tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/CFD/system/controlDict +++ b/tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/CFD/system/controlDict @@ -23,7 +23,7 @@ startTime 0; stopAt endTime; -endTime 0.1;//0.1; +endTime 0.1; deltaT 0.001; @@ -49,7 +49,104 @@ adjustTimeStep no; maxCo 0.1; -libs ( "libgroovyBC.so" ); +//libs ( "libgroovyBC.so" ); +DimensionedConstants +{ + unitSet CGS; // SI; // USCS; // + + CGSCoeffs + { + universal + { + c c [ 0 1 -1 0 0 0 0 ] 2.99792e+10; // speed of light in vacuum (cm/s) + G G [ -1 3 -2 0 0 0 0 ] 6.67429e-8; // gravitational constant (cm^3/(gs^2)) + h h [ 1 2 -1 0 0 0 0 ] 6.62607e-27; // Planck's constant (erg.s) + } + electromagnetic + { + e e [ 0 0 1 0 0 1 0 ] 4.803204e-10; // elementary charge (statcoulomb) + } + atomic + { + me me [ 1 0 0 0 0 0 0 ] 9.10938e-28; // electron mass (g) + mp mp [ 1 0 0 0 0 0 0 ] 1.67262e-24; // proton mass (g) + } + physicoChemical + { + mu mu [ 1 0 0 0 0 0 0 ] 1.66054e-24; // atomic mass unit (g) + k k [ 1 2 -2 -1 0 0 0 ] 1.38065e-16; // Boltzman constant (erg/K) + } + standard + { + //- Standard pressure [bar] + Pstd Pstd [ 1 -1 -2 0 0 0 0 ] 1000000; // 1 bar (barye) + //- Standard temperature [degK] + Tstd Tstd [ 0 0 0 1 0 0 0 ] 298.15; // should be same as in SI unit system + } + } + + SICoeffs + { + universal + { + c c [ 0 1 -1 0 0 0 0 ] 2.99792e+08; + G G [ -1 3 -2 0 0 0 0 ] 6.67429e-11; + h h [ 1 2 -1 0 0 0 0 ] 6.62607e-34; + } + electromagnetic + { + e e [ 0 0 1 0 0 1 0 ] 1.60218e-19; + } + atomic + { + me me [ 1 0 0 0 0 0 0 ] 9.10938e-31; + mp mp [ 1 0 0 0 0 0 0 ] 1.67262e-27; + } + physicoChemical + { + mu mu [ 1 0 0 0 0 0 0 ] 1.66054e-27; + k k [ 1 2 -2 -1 0 0 0 ] 1.38065e-23; + } + standard + { + //- Standard pressure [Pa] + Pstd Pstd [ 1 -1 -2 0 0 0 0 ] 100000; + //- Standard temperature [degK] + Tstd Tstd [ 0 0 0 1 0 0 0 ] 298.15; + } + } + + USCSCoeffs + { + universal + { + c c [ 0 1 -1 0 0 0 0 ] 9.83558e+08; + G G [ -1 3 -2 0 0 0 0 ] 1.06909e-09; + h h [ 1 2 -1 0 0 0 0 ] 1.57234e-32; + } + electromagnetic + { + e e [ 0 0 1 0 0 1 0 ] 1.60218e-19; + } + atomic + { + me me [ 1 0 0 0 0 0 0 ] 2.00825e-30; + mp mp [ 1 0 0 0 0 0 0 ] 3.68746e-27; + } + physicoChemical + { + mu mu [ 1 0 0 0 0 0 0 ] 3.66083e-27; + k k [ 1 2 -2 -1 0 0 0 ] 1.82012e-22; + } + standard + { + //- Standard pressure [lbm/ft^2] + Pstd Pstd [ 1 -1 -2 0 0 0 0 ] 2088.6; + //- Standard temperature [degR] + Tstd Tstd [ 0 0 0 1 0 0 0 ] 536.67; + } + } +} functions ( diff --git a/tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/DEM/in.liggghts_init b/tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/DEM/in.liggghts_init index 72bda98..dbb6f11 100644 --- a/tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/DEM/in.liggghts_init +++ b/tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/DEM/in.liggghts_init @@ -1,63 +1,64 @@ # Pour granular particles into chute container, then induce flow -echo both -atom_style granular -atom_modify map array -communicate single vel yes +echo both +atom_style granular +atom_modify map array +communicate single vel yes -boundary m m m -newton off -units cgs +boundary m m m +newton off -region reg block -1.5 1.5 -1.5 1.5 -0.1 5.54 units box -create_box 1 reg +units cgs -neighbor 0.1 bin -neigh_modify delay 0 +region reg block -1.5 1.5 -1.5 1.5 -0.1 5.54 units box +create_box 1 reg + +neighbor 0.1 bin +neigh_modify delay 0 -#Material properties required for new pair styles +# Material properties required for granular pair styles -fix m1 all property/global youngsModulus peratomtype 5.e6 -fix m2 all property/global poissonsRatio peratomtype 0.45 -fix m3 all property/global coefficientRestitution peratomtypepair 1 0.3 -fix m4 all property/global coefficientFriction peratomtypepair 1 0.5 +fix m1 all property/global youngsModulus peratomtype 5.e6 +fix m2 all property/global poissonsRatio peratomtype 0.45 +fix m3 all property/global coefficientRestitution peratomtypepair 1 0.3 +fix m4 all property/global coefficientFriction peratomtypepair 1 0.5 -#pair style -pair_style gran model hertz tangential history #Hertzian without cohesion -pair_coeff * * +# pair style +pair_style gran model hertz tangential history # Hertzian without cohesion +pair_coeff * * -#timestep, gravity -timestep 0.00001 -fix gravi all gravity 981 vector 0.0 0.0 -1.0 +# timestep, gravity +timestep 0.00001 +fix gravi all gravity 981 vector 0.0 0.0 -1.0 -#walls -fix zwalls1 all wall/gran model hertz tangential history primitive type 1 zplane 0.0 -fix zwalls2 all wall/gran model hertz tangential history primitive type 1 zplane 5.53 -fix cylwalls all wall/gran model hertz tangential history primitive type 1 zcylinder 1.385 0. 0. +# walls +fix zwalls1 all wall/gran model hertz tangential history primitive type 1 zplane 0.0 +fix zwalls2 all wall/gran model hertz tangential history primitive type 1 zplane 5.53 +fix cylwalls all wall/gran model hertz tangential history primitive type 1 zcylinder 1.385 0. 0. -#particle distributions and insertion -region bc cylinder z 0.0 0.0 1.2 0. 5.5 units box -fix pts1 all particletemplate/sphere 1 atom_type 1 density constant 2. radius constant 0.05 -fix pdd1 all particledistribution/discrete 1. 1 pts1 1.0 +# particle distributions and insertion +region bc cylinder z 0.0 0.0 1.2 0. 5.5 units box +fix pts1 all particletemplate/sphere 1 atom_type 1 density constant 2. radius constant 0.05 +fix pdd1 all particledistribution/discrete 1 1 pts1 1.0 -fix ins all insert/pack seed 100001 distributiontemplate pdd1 vel constant 0. 0. -100. insert_every once overlapcheck yes all_in yes particles_in_region 10000 region bc +fix ins all insert/pack seed 100001 distributiontemplate pdd1 vel constant 0. 0. -100. insert_every once overlapcheck yes all_in yes particles_in_region 10000 region bc -#apply nve integration to all particles that are inserted as single particles -fix integr all nve/sphere +# apply nve integration to all particles that are inserted as single particles +fix integr all nve/sphere -#screen output -compute 1 all erotate/sphere -thermo_style custom step atoms ke c_1 vol -thermo 1000 -thermo_modify lost ignore norm no -compute_modify thermo_temp dynamic yes +# screen output +compute rke all erotate/sphere +thermo_style custom step atoms ke c_rke vol +thermo 1000 +thermo_modify lost ignore norm no +compute_modify thermo_temp dynamic yes -#insert the first particles so that dump is not empty -run 1 -dump dmp all custom 5000 post/dump.liggghts_init id type type x y z ix iy iz vx vy vz fx fy fz omegax omegay omegaz radius +# insert the first particles so that dump is not empty +run 1 +dump dmp all custom 5000 post/dump.liggghts_init id type x y z ix iy iz vx vy vz fx fy fz omegax omegay omegaz radius #force : f_couple_cfd[0] f_couple_cfd[1] f_couple_cfd[2] #node : f_couple_cfd[6] #cell id : f_couple_cfd[7] -run 10000 upto -write_restart liggghts.restart +run 10000 upto +write_restart post/restart/liggghts.restart diff --git a/tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/DEM/in.liggghts_run b/tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/DEM/in.liggghts_run new file mode 100644 index 0000000..1eeccc1 --- /dev/null +++ b/tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/DEM/in.liggghts_run @@ -0,0 +1,66 @@ +# Pour granular particles into chute container, then induce flow +log ../DEM/log.liggghts +thermo_log ../DEM/post/thermo.txt + +atom_style granular +atom_modify map array +communicate single vel yes + +boundary m m m +newton off + +units cgs +processors 2 2 1 + +# read the restart file +read_restart ../DEM/post/restart/liggghts.restart + +neighbor 0.1 bin +neigh_modify delay 0 + +# Material properties required for granular pair styles + +fix m1 all property/global youngsModulus peratomtype 5.e6 +fix m2 all property/global poissonsRatio peratomtype 0.45 +fix m3 all property/global coefficientRestitution peratomtypepair 1 0.3 +fix m4 all property/global coefficientFriction peratomtypepair 1 0.5 + +# pair style +pair_style gran model hertz tangential history # Hertzian without cohesion +pair_coeff * * + +# timestep, gravity +timestep 0.00001 +fix gravi all gravity 981 vector 0.0 0.0 -1.0 + +# walls +fix zwalls1 all wall/gran model hertz tangential history primitive type 1 zplane 0.0 +fix zwalls2 all wall/gran model hertz tangential history primitive type 1 zplane 5.53 +fix cylwalls all wall/gran model hertz tangential history primitive type 1 zcylinder 1.385 0. 0. + +# change the particles density +set group all density 2.0 + +# cfd coupling +fix cfd all couple/cfd couple_every 100 mpi +fix cfd2 all couple/cfd/force + +# apply nve integration to all particles that are inserted as single particles +fix integr all nve/sphere + +# center of mass +compute centerOfMass all com + +# compute total dragforce +compute dragtotal all reduce sum f_dragforce[1] f_dragforce[2] f_dragforce[3] + +# screen output +compute rke all erotate/sphere +thermo_style custom step atoms ke c_rke vol c_centerOfMass[3] c_dragtotal[1] c_dragtotal[2] c_dragtotal[3] +thermo 10 +thermo_modify lost ignore norm no +compute_modify thermo_temp dynamic yes + +dump dmp all custom 5000 ../DEM/post/dump*.liggghts_run id type x y z vx vy vz fx fy fz f_dragforce[1] f_dragforce[2] f_dragforce[3] radius + +run 1 diff --git a/tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/DEM/post/restart/.gitignore b/tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/DEM/post/restart/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/parCFDDEMrun.sh b/tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/parCFDDEMrun.sh index a5145f8..e6c4a06 100644 --- a/tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/parCFDDEMrun.sh +++ b/tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/parCFDDEMrun.sh @@ -62,7 +62,7 @@ if [ $postproc == "true" ] #- get VTK data from liggghts dump file cd $casePath/DEM/post - python -i $CFDEM_LPP_DIR/lpp.py dump*.liggghts_restart + python -i $CFDEM_LPP_DIR/lpp.py dump*.liggghts_run #- get VTK data from CFD sim cd $casePath/CFD @@ -82,22 +82,12 @@ fi #- clean up case echo "deleting data at: $casePath :\n" -rm -r $casePath/CFD/0.* -rm -r $casePath/CFD/callgrind.* -rm -r $casePath/CFD/*.out -rm -r $casePath/CFD/log.* -rm -r $casePath/CFD/octave/octave-core -rm -r $casePath/CFD/VTK -rm -r $casePath/CFD/processor* -rm -r $casePath/CFD/couplingFiles/* -rm -r $casePath/DEM/post/* -rm -r $casePath/DEM/log.* -rm -r $casePath/DEM/liggghts.restartCFDEM* -rm -r $casePath/CFD/probes -rm -r $casePath/CFD/postProcessing -rm -r $casePath/CFD/lagrangian +source $WM_PROJECT_DIR/bin/tools/CleanFunctions +cd $casePath/CFD +cleanCase rm -r $casePath/CFD/clockData +rm $casePath/DEM/post/*.* +#rm -r $casePath/DEM/post/restart/*.* +touch $casePath/DEM/post/.gitignore +touch $casePath/DEM/post/restart/.gitignore echo "done" - -#- preserve post directory -echo "dummyfile" >> $casePath/DEM/post/dummy diff --git a/tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/parDEMrun.sh b/tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/parDEMrun.sh new file mode 100755 index 0000000..9b431c5 --- /dev/null +++ b/tutorials/cfdemSolverPiso/ErgunTestMPI_cgs/parDEMrun.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +#===================================================================# +# DEMrun script for ErgunTestMPI testcase +# init ErgunTestMPI +# Daniel Queteschiner - June 2014 +#===================================================================# + +#- source CFDEM env vars +. ~/.bashrc + +#- include functions +source $CFDEM_SRC_DIR/lagrangian/cfdemParticle/etc/functions.sh + +#--------------------------------------------------------------------------------# +#- define variables +casePath="$(dirname "$(readlink -f ${BASH_SOURCE[0]})")" +logpath="$casePath" +headerText="run_liggghts_init_DEM" +logfileName="log_$headerText" +solverName="in.liggghts_init" +nrProcs="4" +machineFileName="none" # yourMachinefileName | none +#--------------------------------------------------------------------------------# + +#- call function to run DEM case +parDEMrun $logpath $logfileName $casePath $headerText $solverName $nrProcs $machineFileName + diff --git a/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/Allrun.sh b/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/Allrun.sh index 9141759..a5564ad 100755 --- a/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/Allrun.sh +++ b/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/Allrun.sh @@ -12,7 +12,7 @@ runOctave="true" postproc="false" # check if mesh was built -if [ -d "$casePath/CFD/constant/polyMesh/boundary" ]; then +if [ -f "$casePath/CFD/constant/polyMesh/points" ]; then echo "mesh was built before - using old mesh" else echo "mesh needs to be built" @@ -20,11 +20,18 @@ else blockMesh fi +if [ -f "$casePath/DEM/post/restart/liggghts.restart" ]; then + echo "LIGGGHTS init was run before - using existing restart file" +else + #- run DEM in new terminal + $casePath/parDEMrun.sh +fi + #-------------------------------------------------------# # adapt settings for init run -cp $casePath/CFD/constant/liggghtsCommands_init $casePath/CFD/constant/liggghtsCommands -cp $casePath/CFD/constant/couplingProperties_init $casePath/CFD/constant/couplingProperties -cp $casePath/CFD/system/controlDict_init $casePath/CFD/system/controlDict +cp $casePath/CFD/constant/liggghtsCommands_run $casePath/CFD/constant/liggghtsCommands +cp $casePath/CFD/constant/couplingProperties_run $casePath/CFD/constant/couplingProperties +cp $casePath/CFD/system/controlDict_run $casePath/CFD/system/controlDict #-------------------------------------------------------# #- run parallel CFD-DEM in new terminal @@ -42,7 +49,8 @@ cp $casePath/CFD/constant/couplingProperties_restart $casePath/CFD/constant/coup cp $casePath/CFD/system/controlDict_restart $casePath/CFD/system/controlDict #- run parallel CFD-DEM in new terminal -gnome-terminal --title='cfdemSolverPiso ErgunTestMPI_restart CFD' -e "bash $casePath/parCFDDEMrun.sh" +#gnome-terminal --title='cfdemSolverPiso ErgunTestMPI_restart CFD' -e "bash $casePath/parCFDDEMrun.sh" +bash $casePath/parCFDDEMrun.sh #- wait until sim has finished then run octave @@ -102,7 +110,8 @@ source $WM_PROJECT_DIR/bin/tools/CleanFunctions cd $casePath/CFD cleanCase rm -r $casePath/CFD/clockData -rm -r $casePath/DEM/post/* -rm $casePath/DEM/liggghts.restartCFDEM* -(cd $casePath/DEM/post && touch dummy) -echo "done" \ No newline at end of file +rm -r $casePath/DEM/post/*.* +#rm -r $casePath/DEM/post/restart/*.* +touch $casePath/DEM/post/.gitignore +touch $casePath/DEM/post/restart/.gitignore +echo "done" diff --git a/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/CFD/constant/couplingProperties_restart b/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/CFD/constant/couplingProperties_restart index 311b8ac..4dae9fb 100644 --- a/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/CFD/constant/couplingProperties_restart +++ b/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/CFD/constant/couplingProperties_restart @@ -98,23 +98,20 @@ implicitCoupleProps ArchimedesProps { - densityFieldName "rho"; gravityFieldName "g"; } gradPForceProps { pFieldName "p"; - densityFieldName "rho"; voidfractionFieldName "voidfraction"; velocityFieldName "U"; - //interpolation; + //interpolation true; } viscForceProps { velocityFieldName "U"; - densityFieldName "rho"; - interpolation; + interpolation true; } volWeightedAverageProps { @@ -135,20 +132,17 @@ totalMomentumExchangeProps explicitMomExFieldName "none"; fluidVelFieldName "U"; granVelFieldName "Us"; - densityFieldName "rho"; } GidaspowDragProps { verbose; velFieldName "U"; - densityFieldName "rho"; voidfractionFieldName "voidfraction"; phi 1; } DiFeliceDragProps { velFieldName "U"; - densityFieldName "rho"; voidfractionFieldName "voidfraction"; } @@ -156,14 +150,12 @@ KochHillDragProps { //verbose; velFieldName "U"; - densityFieldName "rho"; voidfractionFieldName "voidfraction"; } BeetstraDragProps { velFieldName "U"; - densityFieldName "rho"; gravityFieldName "g"; rhoParticle 2000.; voidfractionFieldName "voidfraction"; @@ -178,7 +170,6 @@ BeetstraDragProps virtualMassForceProps { velFieldName "U"; - densityFieldName "rho"; } particleCellVolumeProps diff --git a/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/CFD/constant/couplingProperties_run b/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/CFD/constant/couplingProperties_run new file mode 100644 index 0000000..95b9fe7 --- /dev/null +++ b/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/CFD/constant/couplingProperties_run @@ -0,0 +1,226 @@ +/*---------------------------------------------------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: 1.4 | +| \\ / A nd | Web: http://www.openfoam.org | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ + + +FoamFile +{ + version 2.0; + format ascii; + + root ""; + case ""; + instance ""; + local ""; + + class dictionary; + object couplingProperties; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +//===========================================================================// +// sub-models & settings + +modelType "A"; // A or B + +couplingInterval 100; + +voidFractionModel divided;//centre;// + +locateModel engine;//turboEngineM2M;// + +meshMotionModel noMeshMotion; + +regionModel allRegion; + +IOModel basicIO; + +probeModel off; + +dataExchangeModel twoWayMPI;//twoWayM2M;//twoWayFiles;//oneWayVTK;// + +averagingModel dense;//dilute;// + +clockModel standardClock;//off; + +smoothingModel off;// localPSizeDiffSmoothing;// constDiffSmoothing; // + +forceModels +( + //GidaspowDrag + //BeetstraDrag + //DiFeliceDrag + KochHillDrag + gradPForce + viscForce + //Archimedes + //volWeightedAverage + //totalMomentumExchange + //particleCellVolume +); + +momCoupleModels +( + implicitCouple +); + +turbulenceModelType "RASProperties";//"LESProperties";// + +//===========================================================================// +// sub-model properties + +localPSizeDiffSmoothingProps +{ + lowerLimit 0.1; + upperLimit 1e10; + dSmoothingLength 1.5e-3; + Csmoothing 1.0; +} + +constDiffSmoothingProps +{ + lowerLimit 0.1; + upperLimit 1e10; + smoothingLength 1.5e-3; +} + +implicitCoupleProps +{ + velFieldName "U"; + granVelFieldName "Us"; + voidfractionFieldName "voidfraction"; +} + +ArchimedesProps +{ + gravityFieldName "g"; +} +gradPForceProps +{ + pFieldName "p"; + voidfractionFieldName "voidfraction"; + velocityFieldName "U"; + //interpolation true; +} + +viscForceProps +{ + velocityFieldName "U"; + interpolation true; +} +volWeightedAverageProps +{ + scalarFieldNames + ( + voidfraction + ); + vectorFieldNames + ( + ); + upperThreshold 0.999; + lowerThreshold 0; + verbose; +} +totalMomentumExchangeProps +{ + implicitMomExFieldName "Ksl"; + explicitMomExFieldName "none"; + fluidVelFieldName "U"; + granVelFieldName "Us"; +} +GidaspowDragProps +{ + verbose; + velFieldName "U"; + voidfractionFieldName "voidfraction"; + phi 1; +} +DiFeliceDragProps +{ + velFieldName "U"; + voidfractionFieldName "voidfraction"; +} + +KochHillDragProps +{ + //verbose; + velFieldName "U"; + voidfractionFieldName "voidfraction"; +} + +BeetstraDragProps +{ + velFieldName "U"; + gravityFieldName "g"; + rhoParticle 2000.; + voidfractionFieldName "voidfraction"; + interpolation ; + useFilteredDragModel ; + useParcelSizeDependentFilteredDrag ; + k 0.05; + aLimit 0.0; +// verbose ; +} + +virtualMassForceProps +{ + velFieldName "U"; +} + +particleCellVolumeProps +{ + upperThreshold 0.999; + lowerThreshold 0.; + verbose; +} + +oneWayVTKProps +{ + couplingFilename "vtk_out%4.4d.vtk"; + maxNumberOfParticles 30000; +} + +twoWayFilesProps +{ + maxNumberOfParticles 10100; +} + +centreProps +{ + alphaMin 0.10; +} + +engineProps +{ + treeSearch true; +} + +turboEngineM2MProps +{ + turboEngineProps + { + treeSearch true; + } +} + +dividedProps +{ + alphaMin 0.01; + scaleUpVol 1.0; +} + +twoWayMPIProps +{ + liggghtsPath "../DEM/in.liggghts_run"; +} +twoWayM2MProps +{ + maxNumberOfParticles 10100; + liggghtsPath "../DEM/in.liggghts_run"; +} +// ************************************************************************* // diff --git a/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/CFD/constant/liggghtsCommands_run b/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/CFD/constant/liggghtsCommands_run new file mode 100644 index 0000000..ebd482f --- /dev/null +++ b/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/CFD/constant/liggghtsCommands_run @@ -0,0 +1,45 @@ +/*---------------------------------------------------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: 1.4 | +| \\ / A nd | Web: http://www.openfoam.org | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ + + +FoamFile +{ + version 2.0; + format ascii; + + root ""; + case ""; + instance ""; + local ""; + + class dictionary; + object liggghtsCommands; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +liggghtsCommandModels +( + runLiggghts + writeLiggghts +); + +runLiggghtsProps +{ + preNo false; +} + +//- optional +writeLiggghtsProps +{ + writeLast off; + writeName "post/restart/liggghts.restartCFDEM"; + overwrite on; +} + +// ************************************************************************* // diff --git a/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/CFD/octave/totalPressureDrop.m b/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/CFD/octave/totalPressureDrop.m index c04819d..a687301 100644 --- a/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/CFD/octave/totalPressureDrop.m +++ b/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/CFD/octave/totalPressureDrop.m @@ -112,8 +112,4 @@ axis([0,Uend,0,dpErgun(length(dpErgun))]) %print('cfdemSolverPiso_settlingTest.eps','-deps2') print -color "cfdemSolverPiso_ErgunTestMPI.eps" -replot; - - - diff --git a/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/CFD/system/controlDict_run b/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/CFD/system/controlDict_run new file mode 100644 index 0000000..1d2f9b5 --- /dev/null +++ b/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/CFD/system/controlDict_run @@ -0,0 +1,117 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: 1.6 | +| \\ / A nd | Web: www.OpenFOAM.org | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "system"; + object controlDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +application pisoFoam; + +startFrom startTime; + +startTime 0; + +stopAt endTime; + +endTime 0.05; + +deltaT 0.001; + +writeControl adjustableRunTime; + +writeInterval 0.01; + +purgeWrite 0; + +writeFormat ascii; + +writePrecision 6; + +writeCompression uncompressed; + +timeFormat general; + +timePrecision 6; + +runTimeModifiable yes; + +adjustTimeStep no; + +maxCo 0.1; + +//libs ( "libgroovyBC.so" "libfiniteVolumeCFDEM.so"); + +functions +( + + probes + { + type probes; + // Where to load it from + functionObjectLibs ( "libsampling.so" ); + // Name of the directory for probe data + name probes; + probeLocations + ( + (0 0 0.0001) + (0 0 0.0026) + (0 0 0.0051) + (0 0 0.0076) + (0 0 0.0101) + (0 0 0.0126) + (0 0 0.0151) + (0 0 0.0176) + (0 0 0.0201) + (0 0 0.0226) + (0 0 0.0251) + (0 0 0.0276) + (0 0 0.0301) + (0 0 0.0326) + (0 0 0.0351) + (0 0 0.0375) + (0 0 0.0401) + (0 0 0.0426) + (0 0 0.0451) + (0 0 0.0476) + (0 0 0.0529) + ); + + // Fields to be probed + fields ( p U voidfraction volAverage_voidfraction voidfractionNext voidfractionPrev); + + // Write at same frequency as fields + outputControl timeStep;//outputTime; + outputInterval 1; + } + + /*pressureDrop + { + type patchAverage; + functionObjectLibs + ( + "libsimpleFunctionObjects.so" + ); + verbose true; + patches + ( + inlet + outlet + ); + fields + ( + p + ); + factor 1; + }*/ +); +// ************************************************************************* // diff --git a/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/DEM/in.liggghts_init b/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/DEM/in.liggghts_init index e6f325c..5f28012 100644 --- a/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/DEM/in.liggghts_init +++ b/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/DEM/in.liggghts_init @@ -1,64 +1,64 @@ # Pour granular particles into chute container, then induce flow -echo both -atom_style granular -atom_modify map array -communicate single vel yes +echo both +atom_style granular +atom_modify map array +communicate single vel yes -boundary m m m -newton off +boundary m m m +newton off -units si +units si -region reg block -0.015 0.015 -0.015 0.015 -0.001 0.0554 units box -create_box 1 reg +region reg block -0.015 0.015 -0.015 0.015 -0.001 0.0554 units box +create_box 1 reg -neighbor 0.001 bin -neigh_modify delay 0 +neighbor 0.001 bin +neigh_modify delay 0 -#Material properties required for new pair styles +# Material properties required for granular pair styles -fix m1 all property/global youngsModulus peratomtype 5.e6 -fix m2 all property/global poissonsRatio peratomtype 0.45 -fix m3 all property/global coefficientRestitution peratomtypepair 1 0.3 -fix m4 all property/global coefficientFriction peratomtypepair 1 0.5 +fix m1 all property/global youngsModulus peratomtype 5.e6 +fix m2 all property/global poissonsRatio peratomtype 0.45 +fix m3 all property/global coefficientRestitution peratomtypepair 1 0.3 +fix m4 all property/global coefficientFriction peratomtypepair 1 0.5 -#pair style -pair_style gran model hertz tangential history #Hertzian without cohesion -pair_coeff * * +# pair style +pair_style gran model hertz tangential history # Hertzian without cohesion +pair_coeff * * -#timestep, gravity -timestep 0.00001 -fix gravi all gravity 9.81 vector 0.0 0.0 -1.0 +# timestep, gravity +timestep 0.00001 +fix gravi all gravity 9.81 vector 0.0 0.0 -1.0 -#walls -fix zwalls1 all wall/gran model hertz tangential history primitive type 1 zplane 0.0 -fix zwalls2 all wall/gran model hertz tangential history primitive type 1 zplane 0.0553 -fix cylwalls all wall/gran model hertz tangential history primitive type 1 zcylinder 0.01385 0. 0. +# walls +fix zwalls1 all wall/gran model hertz tangential history primitive type 1 zplane 0.0 +fix zwalls2 all wall/gran model hertz tangential history primitive type 1 zplane 0.0553 +fix cylwalls all wall/gran model hertz tangential history primitive type 1 zcylinder 0.01385 0. 0. -#particle distributions and insertion -region bc cylinder z 0.0 0.0 0.012 0. 0.055 units box -fix pts1 all particletemplate/sphere 1 atom_type 1 density constant 2000 radius constant 0.0005 -fix pdd1 all particledistribution/discrete 1. 1 pts1 1.0 +# particle distributions and insertion +region bc cylinder z 0.0 0.0 0.012 0. 0.055 units box +fix pts1 all particletemplate/sphere 1 atom_type 1 density constant 2000 radius constant 0.0005 +fix pdd1 all particledistribution/discrete 1 1 pts1 1.0 -fix ins all insert/pack seed 100001 distributiontemplate pdd1 vel constant 0. 0. -1. insert_every once overlapcheck yes all_in yes particles_in_region 10000 region bc +fix ins all insert/pack seed 100001 distributiontemplate pdd1 vel constant 0. 0. -1. insert_every once overlapcheck yes all_in yes particles_in_region 10000 region bc -#apply nve integration to all particles that are inserted as single particles -fix integr all nve/sphere +# apply nve integration to all particles that are inserted as single particles +fix integr all nve/sphere -#screen output -compute 1 all erotate/sphere -thermo_style custom step atoms ke c_1 vol -thermo 1000 -thermo_modify lost ignore norm no -compute_modify thermo_temp dynamic yes +# screen output +compute rke all erotate/sphere +thermo_style custom step atoms ke c_rke vol +thermo 1000 +thermo_modify lost ignore norm no +compute_modify thermo_temp dynamic yes -#insert the first particles so that dump is not empty -run 1 -dump dmp all custom 5000 post/dump.liggghts_init id type type x y z ix iy iz vx vy vz fx fy fz omegax omegay omegaz radius +# insert the first particles so that dump is not empty +run 1 +dump dmp all custom 5000 post/dump.liggghts_init id type x y z ix iy iz vx vy vz fx fy fz omegax omegay omegaz radius #force : f_couple_cfd[0] f_couple_cfd[1] f_couple_cfd[2] #node : f_couple_cfd[6] #cell id : f_couple_cfd[7] -run 10000 upto -write_restart liggghts.restart +run 10000 upto +write_restart post/restart/liggghts.restart diff --git a/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/DEM/in.liggghts_restart b/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/DEM/in.liggghts_restart index 5dc462e..251ce3e 100644 --- a/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/DEM/in.liggghts_restart +++ b/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/DEM/in.liggghts_restart @@ -1,71 +1,65 @@ # Pour granular particles into chute container, then induce flow +log ../DEM/log.liggghts +thermo_log ../DEM/post/thermo.txt -atom_style granular -atom_modify map array -communicate single vel yes +atom_style granular +atom_modify map array +communicate single vel yes -boundary m m m -newton off +boundary m m m +newton off -units si -processors 2 2 1 +units si +processors 2 2 1 -#read the restart file -read_restart ../DEM/liggghts.restartCFDEM_0.050000 +# read the restart file +read_restart ../DEM/post/restart/liggghts.restartCFDEM -#do not do this here, the simulation box is in the restart file! -#region reg block -0.015 0.015 -0.015 0.015 -0.001 0.0554 units box -#create_box 1 reg +neighbor 0.0005 bin +neigh_modify delay 0 -neighbor 0.0005 bin -neigh_modify delay 0 +# Material properties required for granular pair styles -#Material properties required for new pair styles +fix m1 all property/global youngsModulus peratomtype 5.e6 +fix m2 all property/global poissonsRatio peratomtype 0.45 +fix m3 all property/global coefficientRestitution peratomtypepair 1 0.3 +fix m4 all property/global coefficientFriction peratomtypepair 1 0.5 -fix m1 all property/global youngsModulus peratomtype 5.e6 -fix m2 all property/global poissonsRatio peratomtype 0.45 -fix m3 all property/global coefficientRestitution peratomtypepair 1 0.3 -fix m4 all property/global coefficientFriction peratomtypepair 1 0.5 +# pair style +pair_style gran model hertz tangential history # Hertzian without cohesion +pair_coeff * * -#pair style -pair_style gran model hertz tangential history #Hertzian without cohesion -pair_coeff * * +# timestep, gravity +timestep 0.00001 +fix gravi all gravity 9.81 vector 0.0 0.0 -1.0 -#timestep, gravity -timestep 0.00001 -fix gravi all gravity 9.81 vector 0.0 0.0 -1.0 - -fix zwalls1 all wall/gran model hertz tangential history primitive type 1 zplane 0.0 -fix zwalls2 all wall/gran model hertz tangential history primitive type 1 zplane 0.0553 -fix cylwalls all wall/gran model hertz tangential history primitive type 1 zcylinder 0.01385 0. 0. +fix zwalls1 all wall/gran model hertz tangential history primitive type 1 zplane 0.0 +fix zwalls2 all wall/gran model hertz tangential history primitive type 1 zplane 0.0553 +fix cylwalls all wall/gran model hertz tangential history primitive type 1 zcylinder 0.01385 0. 0. # change the particles density -set group all density 2000 +set group all density 2000 -#cfd coupling -fix cfd all couple/cfd couple_every 100 mpi -fix cfd2 all couple/cfd/force +# cfd coupling +fix cfd all couple/cfd couple_every 100 mpi +fix cfd2 all couple/cfd/force -#apply nve integration to all particles that are inserted as single particles -fix integr all nve/sphere +# apply nve integration to all particles that are inserted as single particles +fix integr all nve/sphere -#center of mass -compute centerOfMass all com +# center of mass +compute centerOfMass all com -#compute total dragforce -compute dragtotal all reduce sum f_dragforce[1] f_dragforce[2] f_dragforce[3] +# compute total dragforce +compute dragtotal all reduce sum f_dragforce[1] f_dragforce[2] f_dragforce[3] -#screen output -compute 1 all erotate/sphere -thermo_style custom step atoms ke c_1 vol c_centerOfMass[3] c_dragtotal[1] c_dragtotal[2] c_dragtotal[3] -thermo 10 -thermo_modify lost ignore norm no -compute_modify thermo_temp dynamic yes +# screen output +compute rke all erotate/sphere +thermo_style custom step atoms ke c_rke vol c_centerOfMass[3] c_dragtotal[1] c_dragtotal[2] c_dragtotal[3] +thermo 10 +thermo_modify lost ignore norm no +compute_modify thermo_temp dynamic yes -#insert the first particles so that dump is not empty -dump myDump all stl 1 post/dump_*.stl -#run 1 -dump dmp all custom 5000 ../DEM/post/dump*.liggghts_restart id type type x y z vx vy vz fx fy fz f_dragforce[1] f_dragforce[2] f_dragforce[3] radius -undump myDump +dump dmp all custom 5000 ../DEM/post/dump*.liggghts_restart id type x y z vx vy vz fx fy fz f_dragforce[1] f_dragforce[2] f_dragforce[3] radius -run 1 +run 1 diff --git a/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/DEM/in.liggghts_run b/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/DEM/in.liggghts_run new file mode 100644 index 0000000..1a1d48c --- /dev/null +++ b/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/DEM/in.liggghts_run @@ -0,0 +1,65 @@ +# Pour granular particles into chute container, then induce flow +log ../DEM/log.liggghts +thermo_log ../DEM/post/thermo.txt + +atom_style granular +atom_modify map array +communicate single vel yes + +boundary m m m +newton off + +units si +processors 2 2 1 + +# read the restart file +read_restart ../DEM/post/restart/liggghts.restart + +neighbor 0.0005 bin +neigh_modify delay 0 + +# Material properties required for granular pair styles + +fix m1 all property/global youngsModulus peratomtype 5.e6 +fix m2 all property/global poissonsRatio peratomtype 0.45 +fix m3 all property/global coefficientRestitution peratomtypepair 1 0.3 +fix m4 all property/global coefficientFriction peratomtypepair 1 0.5 + +# pair style +pair_style gran model hertz tangential history # Hertzian without cohesion +pair_coeff * * + +# timestep, gravity +timestep 0.00001 +fix gravi all gravity 9.81 vector 0.0 0.0 -1.0 + +fix zwalls1 all wall/gran model hertz tangential history primitive type 1 zplane 0.0 +fix zwalls2 all wall/gran model hertz tangential history primitive type 1 zplane 0.0553 +fix cylwalls all wall/gran model hertz tangential history primitive type 1 zcylinder 0.01385 0. 0. + +# change the particles density +set group all density 2000 + +# cfd coupling +fix cfd all couple/cfd couple_every 100 mpi +fix cfd2 all couple/cfd/force + +# apply nve integration to all particles that are inserted as single particles +fix integr all nve/sphere + +# center of mass +compute centerOfMass all com + +# compute total dragforce +compute dragtotal all reduce sum f_dragforce[1] f_dragforce[2] f_dragforce[3] + +# screen output +compute rke all erotate/sphere +thermo_style custom step atoms ke c_rke vol c_centerOfMass[3] c_dragtotal[1] c_dragtotal[2] c_dragtotal[3] +thermo 10 +thermo_modify lost ignore norm no +compute_modify thermo_temp dynamic yes + +dump dmp all custom 5000 ../DEM/post/dump*.liggghts_restart id type x y z vx vy vz fx fy fz f_dragforce[1] f_dragforce[2] f_dragforce[3] radius + +run 1 diff --git a/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/DEM/post/restart/.gitignore b/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/DEM/post/restart/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/parDEMrun.sh b/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/parDEMrun.sh new file mode 100755 index 0000000..138c740 --- /dev/null +++ b/tutorials/cfdemSolverPiso/ErgunTestMPI_restart/parDEMrun.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +#===================================================================# +# DEMrun script for ErgunTestMPI_restart testcase +# init ErgunTestMPI_restart +# Daniel Queteschiner - June 2014, DCS Computing GmbH +#===================================================================# + +#- source CFDEM env vars +. ~/.bashrc + +#- include functions +source $CFDEM_SRC_DIR/lagrangian/cfdemParticle/etc/functions.sh + +#--------------------------------------------------------------------------------# +#- define variables +casePath="$(dirname "$(readlink -f ${BASH_SOURCE[0]})")" +logpath="$casePath" +headerText="run_liggghts_init_DEM" +logfileName="log_$headerText" +solverName="in.liggghts_init" +nrProcs="2" +machineFileName="none" # yourMachinefileName | none +#--------------------------------------------------------------------------------# + +#- call function to run DEM case +parDEMrun $logpath $logfileName $casePath $headerText $solverName $nrProcs $machineFileName + diff --git a/tutorials/cfdemSolverPiso/settlingTestMPI/Allrun.sh b/tutorials/cfdemSolverPiso/settlingTestMPI/Allrun.sh index 3425265..3ccf874 100755 --- a/tutorials/cfdemSolverPiso/settlingTestMPI/Allrun.sh +++ b/tutorials/cfdemSolverPiso/settlingTestMPI/Allrun.sh @@ -10,7 +10,7 @@ casePath="$(dirname "$(readlink -f ${BASH_SOURCE[0]})")" # check if mesh was built -if [ -d "$casePath/CFD/constant/polyMesh/boundary" ]; then +if [ -f "$casePath/CFD/constant/polyMesh/points" ]; then echo "mesh was built before - using old mesh" else echo "mesh needs to be built" @@ -19,5 +19,5 @@ else fi #- run parallel CFD-DEM in new terminal -gnome-terminal --title='cfdemSolverPiso settlingTest CFD' -e "bash $casePath/parCFDDEMrun.sh" - +#gnome-terminal --title='cfdemSolverPiso settlingTest CFD' -e "bash $casePath/parCFDDEMrun.sh" +bash $casePath/parCFDDEMrun.sh diff --git a/tutorials/cfdemSolverPiso/settlingTestMPI/CFD/0/f b/tutorials/cfdemSolverPiso/settlingTestMPI/CFD/0/f new file mode 100644 index 0000000..2599795 --- /dev/null +++ b/tutorials/cfdemSolverPiso/settlingTestMPI/CFD/0/f @@ -0,0 +1,30 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: 1.6 | +| \\ / A nd | Web: http://www.OpenFOAM.org | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class volVectorField; + object f; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +dimensions [1 -2 -2 0 0 0 0]; + +internalField uniform (0 0 0); + +boundaryField +{ + "(inlet|outlet|walls)" + { + type zeroGradient; + value uniform (0 0 0); + } +} + +// ************************************************************************* // diff --git a/tutorials/cfdemSolverPiso/settlingTestMPI/CFD/0/sSmoothField b/tutorials/cfdemSolverPiso/settlingTestMPI/CFD/0/sSmoothField new file mode 100755 index 0000000..447a450 --- /dev/null +++ b/tutorials/cfdemSolverPiso/settlingTestMPI/CFD/0/sSmoothField @@ -0,0 +1,31 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: 1.6 | +| \\ / A nd | Web: www.OpenFOAM.org | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class volScalarField; + location "0"; + object sSmoothField; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +dimensions [0 0 0 0 0 0 0]; + +internalField uniform 0; + +boundaryField +{ + ".*" + { + type zeroGradient; + } +} + + +// ************************************************************************* // diff --git a/tutorials/cfdemSolverPiso/settlingTestMPI/CFD/0/vSmoothField b/tutorials/cfdemSolverPiso/settlingTestMPI/CFD/0/vSmoothField new file mode 100644 index 0000000..afefb5e --- /dev/null +++ b/tutorials/cfdemSolverPiso/settlingTestMPI/CFD/0/vSmoothField @@ -0,0 +1,31 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: 1.6 | +| \\ / A nd | Web: www.OpenFOAM.org | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class volVectorField; + location "0"; + object vSmoothField; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +dimensions [0 0 0 0 0 0 0]; + +internalField uniform (0 0 0); + +boundaryField +{ + ".*" + { + type zeroGradient; + } +} + + +// ************************************************************************* // diff --git a/tutorials/cfdemSolverPiso/settlingTestMPI/CFD/constant/couplingProperties b/tutorials/cfdemSolverPiso/settlingTestMPI/CFD/constant/couplingProperties index 50e6c9d..491ba5d 100755 --- a/tutorials/cfdemSolverPiso/settlingTestMPI/CFD/constant/couplingProperties +++ b/tutorials/cfdemSolverPiso/settlingTestMPI/CFD/constant/couplingProperties @@ -25,7 +25,6 @@ FoamFile //===========================================================================// // sub-models & settings - modelType B; // A or B couplingInterval 100; @@ -91,10 +90,13 @@ implicitCoupleProps DiFeliceDragProps { velFieldName "U"; - densityFieldName "rho"; voidfractionFieldName "voidfraction"; granVelFieldName "Us"; - verbose; + verbose true; + + //- use of scalar viscosity for drag + //scalarViscosity true; + //nu nu [ 0 2 -1 0 0 0 0 ] 1e-04; } SchillerNaumannDragProps @@ -120,7 +122,6 @@ ArchimedesProps { densityFieldName "rho"; gravityFieldName "g"; - treatDEM; } virtualMassForceProps @@ -137,7 +138,7 @@ oneWayVTKProps twoWayMPIProps { - liggghtsPath "../DEM/in.liggghts_init"; + liggghtsPath "../DEM/in.liggghts_run"; } twoWayFilesProps @@ -166,7 +167,7 @@ bigParticleProps engineProps { - treeSearch true; + treeSearch true; } // ************************************************************************* // diff --git a/tutorials/cfdemSolverPiso/settlingTestMPI/CFD/constant/liggghtsCommands b/tutorials/cfdemSolverPiso/settlingTestMPI/CFD/constant/liggghtsCommands index 7431b21..6517f08 100644 --- a/tutorials/cfdemSolverPiso/settlingTestMPI/CFD/constant/liggghtsCommands +++ b/tutorials/cfdemSolverPiso/settlingTestMPI/CFD/constant/liggghtsCommands @@ -25,7 +25,16 @@ FoamFile liggghtsCommandModels ( - runLiggghts + runLiggghts + writeLiggghts ); // ************************************************************************* // + +writeLiggghtsProps +{ + writeLast off; + //writeName "name"; + overwrite on; + verbose; +} diff --git a/tutorials/cfdemSolverPiso/settlingTestMPI/CFD/system/fvSolution b/tutorials/cfdemSolverPiso/settlingTestMPI/CFD/system/fvSolution index 96a1d5c..276538b 100644 --- a/tutorials/cfdemSolverPiso/settlingTestMPI/CFD/system/fvSolution +++ b/tutorials/cfdemSolverPiso/settlingTestMPI/CFD/system/fvSolution @@ -41,7 +41,7 @@ solvers relTol 0; } - "(voidfraction|Ksl|UsNext|voidfractionNext)" + "(voidfraction|Ksl|UsNext|voidfractionNext|sSmoothField|vSmoothField|fSmooth)" { solver PCG; preconditioner DIC; diff --git a/tutorials/cfdemSolverPiso/settlingTestMPI/DEM/in.liggghts_run b/tutorials/cfdemSolverPiso/settlingTestMPI/DEM/in.liggghts_run new file mode 100644 index 0000000..fbb0636 --- /dev/null +++ b/tutorials/cfdemSolverPiso/settlingTestMPI/DEM/in.liggghts_run @@ -0,0 +1,73 @@ +# Pour granular particles into chute container, then induce flow +echo both +log ../DEM/log.liggghts +thermo_log ../DEM/post/thermo.txt + +atom_style granular +atom_modify map array sort 0 0 +communicate single vel yes + +boundary f f f +newton off + +units si + +region reg block 0 0.1 0 0.1 0 0.1 units box +create_box 1 reg + +neighbor 0.003 bin +neigh_modify delay 0 binsize 0.01 + + +# Material properties required for granular pair styles +fix m1 all property/global youngsModulus peratomtype 5.e6 +fix m2 all property/global poissonsRatio peratomtype 0.45 +fix m3 all property/global coefficientRestitution peratomtypepair 1 0.3 +fix m4 all property/global coefficientFriction peratomtypepair 1 0.5 +#fix m5 all property/global characteristicVelocity scalar 2.0 + +# pair style +pair_style gran model hertz tangential history # hertz without cohesion +pair_coeff * * + +# timestep, gravity +timestep 0.00001 +fix gravi all gravity 9.81 vector 0.0 -1.0 0.0 + +# walls +fix xwalls1 all wall/gran model hertz tangential history primitive type 1 xplane 0.0 +fix xwalls2 all wall/gran model hertz tangential history primitive type 1 xplane 0.1 +fix ywalls1 all wall/gran model hertz tangential history primitive type 1 yplane 0.0 +fix ywalls2 all wall/gran model hertz tangential history primitive type 1 yplane 0.1 +fix zwalls1 all wall/gran model hertz tangential history primitive type 1 zplane 0.0 +fix zwalls2 all wall/gran model hertz tangential history primitive type 1 zplane 0.01 + +# create single partciles +create_atoms 1 single 0.05 0.025 0.05 units box +set group all diameter 0.0001 density 3000 + +# cfd coupling +fix cfd all couple/cfd couple_every 100 mpi +fix cfd2 all couple/cfd/force + +variable vx equal vx[1] +variable vy equal vy[1] +variable vz equal vz[1] +variable time equal step*dt +fix extra all print 100 "${time} ${vx} ${vy} ${vz}" file ../DEM/post/velocity.txt title "#" screen no + +# apply nve integration to all particles that are inserted as single particles +fix integr all nve/sphere + +# screen output +compute rke all erotate/sphere +thermo_style custom step atoms ke c_rke vol +thermo 1000 +thermo_modify lost ignore norm no +compute_modify thermo_temp dynamic yes + +# insert the first particles so that dump is not empty +run 0 +dump dmp all custom 1000 ../DEM/post/dump.liggghts_run id type x y z ix iy iz vx vy vz fx fy fz omegax omegay omegaz radius + +run 0 upto diff --git a/tutorials/cfdemSolverPiso/settlingTestMPI/DEM/post/.gitignore b/tutorials/cfdemSolverPiso/settlingTestMPI/DEM/post/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/tutorials/cfdemSolverPiso/settlingTestMPI/parCFDDEMrun.sh b/tutorials/cfdemSolverPiso/settlingTestMPI/parCFDDEMrun.sh index 5d20182..2d622d7 100644 --- a/tutorials/cfdemSolverPiso/settlingTestMPI/parCFDDEMrun.sh +++ b/tutorials/cfdemSolverPiso/settlingTestMPI/parCFDDEMrun.sh @@ -24,7 +24,7 @@ machineFileName="none" # yourMachinefileName | none debugMode="off" # on | off| strict testHarnessPath="$CFDEM_TEST_HARNESS_PATH" runOctave="true" -cleanCase="true" +cleanUp="true" postproc="false" #--------------------------------------------------------------------------------# @@ -59,7 +59,7 @@ if [ $postproc == "true" ] #- get VTK data from liggghts dump file cd $casePath/DEM/post - python -i $CFDEM_LPP_DIR/lpp.py dump.liggghts_init + python -i $CFDEM_LPP_DIR/lpp.py dump.liggghts_run #- get VTK data from CFD sim cd $casePath/CFD @@ -77,7 +77,7 @@ if [ $postproc == "true" ] fi #- clean up case -if [ $cleanCase == "true" ] +if [ $cleanUp == "true" ] then echo "deleting data at: $casePath :\n" source $WM_PROJECT_DIR/bin/tools/CleanFunctions @@ -86,9 +86,10 @@ if [ $cleanCase == "true" ] cd $casePath rm -r $casePath/CFD/clockData rm -r $casePath/DEM/post/* + rm -r $casePath/DEM/liggghts.restartCFDEM* echo "done" fi #- preserve post directory -echo "dummyfile" >> $casePath/DEM/post/dummy +touch $casePath/DEM/post/.gitignore diff --git a/tutorials/cfdemSolverPisoScalar/packedBedTemp/Allrun.sh b/tutorials/cfdemSolverPisoScalar/packedBedTemp/Allrun.sh index 0aad13d..4bb0814 100755 --- a/tutorials/cfdemSolverPisoScalar/packedBedTemp/Allrun.sh +++ b/tutorials/cfdemSolverPisoScalar/packedBedTemp/Allrun.sh @@ -10,7 +10,7 @@ casePath="$(dirname "$(readlink -f ${BASH_SOURCE[0]})")" # check if mesh was built -if [ -d "$casePath/CFD/constant/polyMesh/boundary" ]; then +if [ -f "$casePath/CFD/constant/polyMesh/points" ]; then echo "mesh was built before - using old mesh" else echo "mesh needs to be built" @@ -18,6 +18,13 @@ else blockMesh fi -#- run parallel CFD-DEM in new terminal -gnome-terminal --title='cfdemSolverPisoScalar packedBedTemp CFD' -e "bash $casePath/parCFDDEMrun.sh" +if [ -f "$casePath/DEM/post/restart/liggghts.restart" ]; then + echo "LIGGGHTS init was run before - using existing restart file" +else + #- run DEM init + $casePath/parDEMrun.sh +fi +#- run parallel CFD-DEM in new terminal +#gnome-terminal --title='cfdemSolverPisoScalar packedBedTemp CFD' -e "bash $casePath/parCFDDEMrun.sh" +bash $casePath/parCFDDEMrun.sh diff --git a/tutorials/cfdemSolverPisoScalar/packedBedTemp/CFD/constant/couplingProperties b/tutorials/cfdemSolverPisoScalar/packedBedTemp/CFD/constant/couplingProperties index a609b6d..8bb9002 100644 --- a/tutorials/cfdemSolverPisoScalar/packedBedTemp/CFD/constant/couplingProperties +++ b/tutorials/cfdemSolverPisoScalar/packedBedTemp/CFD/constant/couplingProperties @@ -53,7 +53,7 @@ smoothingModel off; forceModels ( KochHillDrag - LaEuScalarTemp + LaEuScalarTemp // must be 2nd pos! Archimedes ); @@ -72,12 +72,10 @@ LaEuScalarTempProps velFieldName "U"; tempFieldName "T"; voidfractionFieldName "voidfraction"; - tempSourceFieldName "Tsource"; partTempName "Temp"; partHeatFluxName "convectiveHeatFlux"; lambda 0.0256; Cp 1007; - densityFieldName "rho"; } implicitCoupleProps @@ -91,36 +89,31 @@ implicitCoupleProps KochHillDragProps { velFieldName "U"; - densityFieldName "rho"; voidfractionFieldName "voidfraction"; } DiFeliceDragProps { velFieldName "U"; - densityFieldName "rho"; - //verbose; + //verbose true; } ArchimedesProps { - densityFieldName "rho"; gravityFieldName "g"; } gradPForceProps { pFieldName "p"; - densityFieldName "rho"; voidfractionFieldName "voidfraction"; velocityFieldName "U"; - //interpolation; + //interpolation true; } viscForceProps { velocityFieldName "U"; - densityFieldName "rho"; - interpolation; + interpolation true; } oneWayVTKProps @@ -132,7 +125,7 @@ oneWayVTKProps twoWayMPIProps { maxNumberOfParticles 10000; - liggghtsPath "../DEM/in.liggghts_init"; + liggghtsPath "../DEM/in.liggghts_run"; } centreProps diff --git a/tutorials/cfdemSolverPisoScalar/packedBedTemp/CFD/octave/totalPressureDropAndNusselt.m b/tutorials/cfdemSolverPisoScalar/packedBedTemp/CFD/octave/totalPressureDropAndNusselt.m index b572108..e60ef38 100644 --- a/tutorials/cfdemSolverPisoScalar/packedBedTemp/CFD/octave/totalPressureDropAndNusselt.m +++ b/tutorials/cfdemSolverPisoScalar/packedBedTemp/CFD/octave/totalPressureDropAndNusselt.m @@ -51,7 +51,6 @@ legend("analytical - Ergun","simulation") %print('cfdemSolverPiso_settlingTest.eps','-deps2') print -color "cfdemSolverPisoScalar_pressureDrop.eps" -replot; %*********************************************************************% % heat transfer @@ -126,7 +125,6 @@ legend("analytical - ","simulation") %print('cfdemSolverPisoScalar_NusseltNr.eps','-deps2') print -color "cfdemSolverPisoScalar_Nusselt.eps" -replot; figure(3) plot(t_sim,Tin_sim,t_sim,Tout_sim) @@ -135,5 +133,4 @@ legend("inlet","outlet") %print('cfdemSolverPisoScalar_NusseltNr.eps','-deps2') print -color "cfdemSolverPisoScalar_temperatures.eps" -replot; diff --git a/tutorials/cfdemSolverPisoScalar/packedBedTemp/DEM/in.liggghts_init b/tutorials/cfdemSolverPisoScalar/packedBedTemp/DEM/in.liggghts_init index 423e05e..f739d16 100644 --- a/tutorials/cfdemSolverPisoScalar/packedBedTemp/DEM/in.liggghts_init +++ b/tutorials/cfdemSolverPisoScalar/packedBedTemp/DEM/in.liggghts_init @@ -1,83 +1,73 @@ +# Particle packing by insertion and successive growing of particles -# read packed bed and calc convective heat transfer +atom_style granular +atom_modify map array +boundary m m m +newton off +echo both -atom_style granular -atom_modify map array -communicate single vel yes -boundary m m m -newton off -echo both -units si -processors 1 1 2 +communicate single vel yes -#read the restart file -read_restart ../DEM/liggghts.restart +units si +processors 1 1 2 -neighbor 0.003 bin -neigh_modify delay 0 binsize 0.01 +region reg block 0. 0.1 0. 0.1 0. 1.1 units box +create_box 1 reg + +neighbor 0.002 bin +neigh_modify delay 0 -#Material properties required for new pair styles +# Material properties required for granular pair styles -fix m1 all property/global youngsModulus peratomtype 5.e6 -fix m2 all property/global poissonsRatio peratomtype 0.45 -fix m3 all property/global coefficientRestitution peratomtypepair 1 0.3 -fix m4 all property/global coefficientFriction peratomtypepair 1 0.5 +fix m1 all property/global youngsModulus peratomtype 5.e6 +fix m2 all property/global poissonsRatio peratomtype 0.45 +fix m3 all property/global coefficientRestitution peratomtypepair 1 0.3 +fix m4 all property/global coefficientFriction peratomtypepair 1 0.5 -#pair style -pair_style gran model hertz tangential history #Hertzian without cohesion -pair_coeff * * +# pair style +pair_style gran model hertz tangential history #Hertzian without cohesion +pair_coeff * * -#timestep, gravity -timestep 0.00001 -fix gravi all gravity 9.81 vector 0. 0. -1. +timestep 0.00001 -#walls -#walls -fix xwalls1 all wall/gran model hertz tangential history primitive type 1 xplane 0. -fix xwalls2 all wall/gran model hertz tangential history primitive type 1 xplane 0.1 -fix ywalls1 all wall/gran model hertz tangential history primitive type 1 yplane 0. -fix ywalls2 all wall/gran model hertz tangential history primitive type 1 yplane 0.1 -fix zwalls1 all wall/gran model hertz tangential history primitive type 1 zplane 0. -fix zwalls2 all wall/gran model hertz tangential history primitive type 1 zplane 1.1 +# walls +fix xwalls1 all wall/gran model hertz tangential history primitive type 1 xplane 0.0 +fix xwalls2 all wall/gran model hertz tangential history primitive type 1 xplane 0.1 +fix ywalls1 all wall/gran model hertz tangential history primitive type 1 yplane 0.0 +fix ywalls2 all wall/gran model hertz tangential history primitive type 1 yplane 0.1 +fix zwalls1 all wall/gran model hertz tangential history primitive type 1 zplane 0.0 +fix zwalls2 all wall/gran model hertz tangential history primitive type 1 zplane 1.1 +fix gravi all gravity 9.81 vector 0.0 0.0 -1.0 -#heat transfer -fix ftco all property/global thermalConductivity peratomtype 5. # lambda in [W/(K*m)] -fix ftca all property/global thermalCapacity peratomtype 0.1 # cp in [J/(kg*K)] -fix heattransfer all heat/gran initial_temperature 600. +# heat transfer +fix ftco all property/global thermalConductivity peratomtype 5. +fix ftca all property/global thermalCapacity peratomtype 10. +fix heattransfer all heat/gran initial_temperature 263. -#set particle temperature for the bed -run 0 -region total block INF INF INF INF INF INF units box -set region total property/atom Temp 600. # former property/paratom +# particle distributions and insertion +region bc block 0. 0.1 0. 0.1 0. 1.1 units box +fix pts1 all particletemplate/sphere 1 atom_type 1 density constant 2500 radius constant 0.011 +fix pdd1 all particledistribution/discrete 1 1 pts1 1.0 -#cfd coupling -fix cfd all couple/cfd couple_every 100 mpi -fix cfd2 all couple/cfd/force +fix ins all insert/pack seed 100001 distributiontemplate pdd1 vel constant 0. 0. -3. insert_every 10000 overlapcheck yes all_in yes particles_in_region 1005 region bc -#this one invokes heat transfer calculation, transfers per-particle temperature and adds convective heat flux to particles -fix cfd3 all couple/cfd/convection T0 600 +# apply nve integration to all particles that are inserted as single particles +fix integr all nve/sphere -#variable vx equal vx[1] -#variable vy equal vy[1] -#variable vz equal vz[1] -#variable time equal step*dt -#fix extra all print 500 "${time} ${vx} ${vy} ${vz}" file ../DEM/post/velocity.txt title "%" screen no - -#apply nve integration to all particles that are inserted as single particles -fix integr all nve/sphere - - -#screen output -compute 1 all erotate/sphere -thermo_style custom step atoms ke c_1 vol -thermo 1000 -thermo_modify lost ignore norm no -compute_modify thermo_temp dynamic yes - -#insert the first particles so that dump is not empty -run 1 -dump dmp all custom 100 ../DEM/post/dump.liggghts_init id type type x y z ix iy iz vx vy vz fx fy fz omegax omegay omegaz radius f_Temp[0] f_heatFlux[0] +# output settings, include total thermal energy +compute rke all erotate/sphere +thermo_style custom step atoms ke c_rke f_heattransfer vol +thermo 1000 +thermo_modify lost ignore norm no +compute_modify thermo_temp dynamic yes +#insert the first particles run 1 +dump dmp all custom 1000 post/dump.liggghts_init id type x y z ix iy iz vx vy vz fx fy fz omegax omegay omegaz radius f_heattransfer[0] f_heatFlux[0] + +run 150000 + +write_restart post/restart/liggghts.restart + diff --git a/tutorials/cfdemSolverPisoScalar/packedBedTemp/DEM/in.liggghts_run b/tutorials/cfdemSolverPisoScalar/packedBedTemp/DEM/in.liggghts_run new file mode 100644 index 0000000..7350ff1 --- /dev/null +++ b/tutorials/cfdemSolverPisoScalar/packedBedTemp/DEM/in.liggghts_run @@ -0,0 +1,75 @@ +# read packed bed and calc convective heat transfer +log ../DEM/log.liggghts +thermo_log ../DEM/post/thermo.txt + +atom_style granular +atom_modify map array +communicate single vel yes +boundary m m m +newton off +echo both +units si +processors 1 1 2 + +# read the restart file +read_restart ../DEM/post/restart/liggghts.restart + +neighbor 0.003 bin +neigh_modify delay 0 binsize 0.01 + + +# Material properties required for granular pair styles + +fix m1 all property/global youngsModulus peratomtype 5.e6 +fix m2 all property/global poissonsRatio peratomtype 0.45 +fix m3 all property/global coefficientRestitution peratomtypepair 1 0.3 +fix m4 all property/global coefficientFriction peratomtypepair 1 0.5 + +# pair style +pair_style gran model hertz tangential history # Hertzian without cohesion +pair_coeff * * + +# timestep, gravity +timestep 0.00001 +fix gravi all gravity 9.81 vector 0. 0. -1. + +# walls +fix xwalls1 all wall/gran model hertz tangential history primitive type 1 xplane 0.0 +fix xwalls2 all wall/gran model hertz tangential history primitive type 1 xplane 0.1 +fix ywalls1 all wall/gran model hertz tangential history primitive type 1 yplane 0.0 +fix ywalls2 all wall/gran model hertz tangential history primitive type 1 yplane 0.1 +fix zwalls1 all wall/gran model hertz tangential history primitive type 1 zplane 0.0 +fix zwalls2 all wall/gran model hertz tangential history primitive type 1 zplane 1.1 + + +# heat transfer +fix ftco all property/global thermalConductivity peratomtype 5. # lambda in [W/(K*m)] +fix ftca all property/global thermalCapacity peratomtype 0.1 # cp in [J/(kg*K)] +fix heattransfer all heat/gran initial_temperature 600. + +# set particle temperature for the bed +run 0 +region total block INF INF INF INF INF INF units box +set region total property/atom Temp 600. + +# cfd coupling +fix cfd all couple/cfd couple_every 100 mpi +fix cfd2 all couple/cfd/force + +# this one invokes heat transfer calculation, transfers per-particle temperature and adds convective heat flux to particles +fix cfd3 all couple/cfd/convection T0 600 + +# apply nve integration to all particles that are inserted as single particles +fix integr all nve/sphere + + +# screen output +compute rke all erotate/sphere +thermo_style custom step atoms ke c_rke vol +thermo 1000 +thermo_modify lost ignore norm no +compute_modify thermo_temp dynamic yes + +dump dmp all custom 100 ../DEM/post/dump.liggghts_run id type x y z ix iy iz vx vy vz fx fy fz omegax omegay omegaz radius f_Temp[0] f_heatFlux[0] + +run 1 diff --git a/tutorials/cfdemSolverPisoScalar/packedBedTemp/DEM/post/restart/.gitignore b/tutorials/cfdemSolverPisoScalar/packedBedTemp/DEM/post/restart/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/tutorials/cfdemSolverPisoScalar/packedBedTemp/parCFDDEMrun.sh b/tutorials/cfdemSolverPisoScalar/packedBedTemp/parCFDDEMrun.sh index 5ab664b..c0073d9 100644 --- a/tutorials/cfdemSolverPisoScalar/packedBedTemp/parCFDDEMrun.sh +++ b/tutorials/cfdemSolverPisoScalar/packedBedTemp/parCFDDEMrun.sh @@ -65,7 +65,7 @@ if [ $postproc == "true" ] #- get VTK data from liggghts dump file cd $casePath/DEM/post - python -i $CFDEM_LPP_DIR/lpp.py dump.liggghts_init + python -i $CFDEM_LPP_DIR/lpp.py dump.liggghts_run #- get VTK data from CFD sim cd $casePath/CFD @@ -84,24 +84,16 @@ fi #- clean up case echo "deleting data at: $casePath : ???\n" -rm -r $casePath/CFD/0.* -rm -r $casePath/CFD/1 -rm -r $casePath/CFD/callgrind.* -rm -r $casePath/CFD/*.out -rm -r $casePath/CFD/octave/*.eps -rm -r $casePath/CFD/octave/octave-core -rm -r $casePath/CFD/VTK -rm -r $casePath/CFD/processor* -rm -r $casePath/DEM/post/* -rm -r $casePath/DEM/log.* -rm -r $casePath/CFD/log.* -rm -r $casePath/DEM/log.* -rm -r $casePath/CFD/probes -rm -r $casePath/CFD/postProcessing -rm -r $casePath/log_* +source $WM_PROJECT_DIR/bin/tools/CleanFunctions +cd $casePath/CFD +cleanCase +rm -r $casePath/CFD/clockData +rm $casePath/DEM/post/*.* +#rm -r $casePath/DEM/post/restart/*.* echo "done" #- preserve post directory -echo "dummyfile" >> $casePath/DEM/post/dummy +touch $casePath/DEM/post/.gitignore +touch $casePath/DEM/post/restart/.gitignore diff --git a/tutorials/cfdemSolverPisoScalar/packedBedTemp/parDEMrun.sh b/tutorials/cfdemSolverPisoScalar/packedBedTemp/parDEMrun.sh new file mode 100755 index 0000000..660b45a --- /dev/null +++ b/tutorials/cfdemSolverPisoScalar/packedBedTemp/parDEMrun.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +#===================================================================# +# DEMrun script for ErgunTestMPI testcase +# init ErgunTestMPI +# Daniel Queteschiner - June 2014 +#===================================================================# + +#- source CFDEM env vars +. ~/.bashrc + +#- include functions +source $CFDEM_SRC_DIR/lagrangian/cfdemParticle/etc/functions.sh + +#--------------------------------------------------------------------------------# +#- define variables +casePath="$(dirname "$(readlink -f ${BASH_SOURCE[0]})")" +logpath="$casePath" +headerText="run_liggghts_init_DEM" +logfileName="log_$headerText" +solverName="in.liggghts_init" +nrProcs="2" +machineFileName="none" # yourMachinefileName | none +#--------------------------------------------------------------------------------# + +#- call function to run DEM case +parDEMrun $logpath $logfileName $casePath $headerText $solverName $nrProcs $machineFileName +