diff --git a/applications/solvers/combustion/XiFoam/XiDyMFoam/Make/files b/applications/solvers/combustion/XiFoam/XiDyMFoam/Make/files
new file mode 100644
index 0000000000..55ea77cbdf
--- /dev/null
+++ b/applications/solvers/combustion/XiFoam/XiDyMFoam/Make/files
@@ -0,0 +1,3 @@
+XiDyMFoam.C
+
+EXE = $(FOAM_APPBIN)/XiDyMFoam
diff --git a/applications/solvers/combustion/XiFoam/XiDyMFoam/Make/options b/applications/solvers/combustion/XiFoam/XiDyMFoam/Make/options
new file mode 100644
index 0000000000..a726de69b3
--- /dev/null
+++ b/applications/solvers/combustion/XiFoam/XiDyMFoam/Make/options
@@ -0,0 +1,33 @@
+EXE_INC = \
+ -I.. \
+ -I$(LIB_SRC)/finiteVolume/lnInclude \
+ -I$(LIB_SRC)/fvOptions/lnInclude \
+ -I$(LIB_SRC)/dynamicFvMesh/lnInclude \
+ -I$(LIB_SRC)/dynamicMesh/lnInclude \
+ -I$(LIB_SRC)/meshTools/lnInclude \
+ -I$(LIB_SRC)/sampling/lnInclude \
+ -I$(LIB_SRC)/engine/lnInclude \
+ -I$(LIB_SRC)/thermophysicalModels/specie/lnInclude \
+ -I$(LIB_SRC)/transportModels/compressible/lnInclude \
+ -I$(LIB_SRC)/thermophysicalModels/basic/lnInclude \
+ -I$(LIB_SRC)/thermophysicalModels/reactionThermo/lnInclude \
+ -I$(LIB_SRC)/TurbulenceModels/turbulenceModels/lnInclude \
+ -I$(LIB_SRC)/TurbulenceModels/compressible/lnInclude \
+ -I$(LIB_SRC)/thermophysicalModels/laminarFlameSpeed/lnInclude
+
+EXE_LIBS = \
+ -lfiniteVolume \
+ -lfvOptions \
+ -ldynamicFvMesh \
+ -ltopoChangerFvMesh \
+ -ldynamicMesh \
+ -lmeshTools \
+ -lsampling \
+ -lengine \
+ -lturbulenceModels \
+ -lcompressibleTurbulenceModels \
+ -lcompressibleTransportModels \
+ -lfluidThermophysicalModels \
+ -lreactionThermophysicalModels \
+ -lspecie \
+ -llaminarFlameSpeedModels
diff --git a/applications/solvers/combustion/XiFoam/XiDyMFoam/XiDyMFoam.C b/applications/solvers/combustion/XiFoam/XiDyMFoam/XiDyMFoam.C
new file mode 100644
index 0000000000..d4cb0666e2
--- /dev/null
+++ b/applications/solvers/combustion/XiFoam/XiDyMFoam/XiDyMFoam.C
@@ -0,0 +1,180 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration |
+ \\ / A nd | Copyright (C) 2011-2015 OpenFOAM Foundation
+ \\/ M anipulation | Copyright (C) 2015 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+ This file is part of OpenFOAM.
+
+ OpenFOAM 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.
+
+ OpenFOAM 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 OpenFOAM. If not, see .
+
+Application
+ XiFoam
+
+Description
+ Solver for compressible premixed/partially-premixed combustion with
+ turbulence modelling.
+
+ Combusting RANS code using the b-Xi two-equation model.
+ Xi may be obtained by either the solution of the Xi transport
+ equation or from an algebraic exression. Both approaches are
+ based on Gulder's flame speed correlation which has been shown
+ to be appropriate by comparison with the results from the
+ spectral model.
+
+ Strain effects are encorporated directly into the Xi equation
+ but not in the algebraic approximation. Further work need to be
+ done on this issue, particularly regarding the enhanced removal rate
+ caused by flame compression. Analysis using results of the spectral
+ model will be required.
+
+ For cases involving very lean Propane flames or other flames which are
+ very strain-sensitive, a transport equation for the laminar flame
+ speed is present. This equation is derived using heuristic arguments
+ involving the strain time scale and the strain-rate at extinction.
+ the transport velocity is the same as that for the Xi equation.
+
+\*---------------------------------------------------------------------------*/
+
+#include "fvCFD.H"
+#include "dynamicFvMesh.H"
+#include "psiuReactionThermo.H"
+#include "turbulentFluidThermoModel.H"
+#include "laminarFlameSpeed.H"
+#include "ignition.H"
+#include "Switch.H"
+#include "pimpleControl.H"
+#include "CorrectPhi.H"
+#include "fvIOoptionList.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+int main(int argc, char *argv[])
+{
+ #include "setRootCase.H"
+
+ #include "createTime.H"
+ #include "createDynamicFvMesh.H"
+ #include "initContinuityErrs.H"
+
+ pimpleControl pimple(mesh);
+
+ #include "readCombustionProperties.H"
+ #include "readGravitationalAcceleration.H"
+ #include "createFields.H"
+ #include "createMRF.H"
+ #include "createFvOptions.H"
+ #include "createRhoUf.H"
+ #include "createControls.H"
+ #include "initContinuityErrs.H"
+ #include "compressibleCourantNo.H"
+ #include "setInitialDeltaT.H"
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+ Info<< "\nStarting time loop\n" << endl;
+
+ while (runTime.run())
+ {
+ #include "createTimeControls.H"
+
+ {
+ // Store divrhoU from the previous mesh so that it can be mapped
+ // and used in correctPhi to ensure the corrected phi has the
+ // same divergence
+ volScalarField divrhoU
+ (
+ "divrhoU",
+ fvc::div(fvc::absolute(phi, rho, U))
+ );
+
+ #include "compressibleCourantNo.H"
+ #include "setDeltaT.H"
+
+ runTime++;
+
+ Info<< "Time = " << runTime.timeName() << nl << endl;
+
+ // Store momentum to set rhoUf for introduced faces.
+ volVectorField rhoU("rhoU", rho*U);
+
+ // Do any mesh changes
+ mesh.update();
+
+ if (mesh.changing() && correctPhi)
+ {
+ // Calculate absolute flux from the mapped surface velocity
+ phi = mesh.Sf() & rhoUf;
+
+ #include "correctPhi.H"
+
+ // Make the fluxes relative to the mesh-motion
+ fvc::makeRelative(phi, rho, U);
+ }
+ }
+
+ if (mesh.changing() && checkMeshCourantNo)
+ {
+ #include "meshCourantNo.H"
+ }
+
+ #include "rhoEqn.H"
+ Info<< "rhoEqn max/min : " << max(rho).value()
+ << " " << min(rho).value() << endl;
+
+ // --- Pressure-velocity PIMPLE corrector loop
+ while (pimple.loop())
+ {
+ #include "UEqn.H"
+
+ #include "ftEqn.H"
+ #include "bEqn.H"
+ #include "EauEqn.H"
+ #include "EaEqn.H"
+
+ if (!ign.ignited())
+ {
+ thermo.heu() == thermo.he();
+ }
+
+ // --- Pressure corrector loop
+ while (pimple.correct())
+ {
+ #include "pEqn.H"
+ }
+
+ if (pimple.turbCorr())
+ {
+ turbulence->correct();
+ }
+ }
+
+ rho = thermo.rho();
+
+ runTime.write();
+
+ Info<< "ExecutionTime = " << runTime.elapsedCpuTime() << " s"
+ << " ClockTime = " << runTime.elapsedClockTime() << " s"
+ << nl << endl;
+ }
+
+ Info<< "End\n" << endl;
+
+ return 0;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/solvers/combustion/XiFoam/XiDyMFoam/correctPhi.H b/applications/solvers/combustion/XiFoam/XiDyMFoam/correctPhi.H
new file mode 100644
index 0000000000..37072312ff
--- /dev/null
+++ b/applications/solvers/combustion/XiFoam/XiDyMFoam/correctPhi.H
@@ -0,0 +1,11 @@
+CorrectPhi
+(
+ U,
+ phi,
+ p,
+ rho,
+ psi,
+ dimensionedScalar("rAUf", dimTime, 1),
+ divrhoU,
+ pimple
+);
diff --git a/applications/solvers/combustion/XiFoam/XiDyMFoam/createControls.H b/applications/solvers/combustion/XiFoam/XiDyMFoam/createControls.H
new file mode 100644
index 0000000000..aed0e76956
--- /dev/null
+++ b/applications/solvers/combustion/XiFoam/XiDyMFoam/createControls.H
@@ -0,0 +1,11 @@
+#include "createTimeControls.H"
+
+bool correctPhi
+(
+ pimple.dict().lookupOrDefault("correctPhi", true)
+);
+
+bool checkMeshCourantNo
+(
+ pimple.dict().lookupOrDefault("checkMeshCourantNo", false)
+);
diff --git a/applications/solvers/combustion/XiFoam/XiDyMFoam/pEqn.H b/applications/solvers/combustion/XiFoam/XiDyMFoam/pEqn.H
new file mode 100644
index 0000000000..438396ae90
--- /dev/null
+++ b/applications/solvers/combustion/XiFoam/XiDyMFoam/pEqn.H
@@ -0,0 +1,99 @@
+rho = thermo.rho();
+
+volScalarField rAU(1.0/UEqn.A());
+surfaceScalarField rhorAUf("rhorAUf", fvc::interpolate(rho*rAU));
+
+volVectorField HbyA("HbyA", U);
+HbyA = rAU*UEqn.H();
+
+if (pimple.transonic())
+{
+ surfaceScalarField phid
+ (
+ "phid",
+ fvc::interpolate(psi)
+ *(
+ (fvc::interpolate(HbyA) & mesh.Sf())
+ + rhorAUf*fvc::ddtCorr(rho, U, phi)/fvc::interpolate(rho)
+ )
+ );
+
+ fvc::makeRelative(phid, psi, U);
+ MRF.makeRelative(fvc::interpolate(psi), phid);
+
+ while (pimple.correctNonOrthogonal())
+ {
+ fvScalarMatrix pEqn
+ (
+ fvm::ddt(psi, p)
+ + fvm::div(phid, p)
+ - fvm::laplacian(rhorAUf, p)
+ ==
+ fvOptions(psi, p, rho.name())
+ );
+
+ pEqn.solve(mesh.solver(p.select(pimple.finalInnerIter())));
+
+ if (pimple.finalNonOrthogonalIter())
+ {
+ phi == pEqn.flux();
+ }
+ }
+}
+else
+{
+ surfaceScalarField phiHbyA
+ (
+ "phiHbyA",
+ (
+ (fvc::interpolate(rho*HbyA) & mesh.Sf())
+ + rhorAUf*fvc::ddtCorr(rho, U, rhoUf)
+ )
+ );
+
+ fvc::makeRelative(phiHbyA, rho, U);
+ MRF.makeRelative(phiHbyA);
+
+ while (pimple.correctNonOrthogonal())
+ {
+ fvScalarMatrix pEqn
+ (
+ fvm::ddt(psi, p)
+ + fvc::div(phiHbyA)
+ - fvm::laplacian(rhorAUf, p)
+ ==
+ fvOptions(psi, p, rho.name())
+ );
+
+ pEqn.solve(mesh.solver(p.select(pimple.finalInnerIter())));
+
+ if (pimple.finalNonOrthogonalIter())
+ {
+ phi = phiHbyA + pEqn.flux();
+ }
+ }
+}
+
+#include "rhoEqn.H"
+#include "compressibleContinuityErrs.H"
+
+U = HbyA - rAU*fvc::grad(p);
+U.correctBoundaryConditions();
+fvOptions.correct(U);
+K = 0.5*magSqr(U);
+
+{
+ rhoUf = fvc::interpolate(rho*U);
+ surfaceVectorField n(mesh.Sf()/mesh.magSf());
+ rhoUf += n*(fvc::absolute(phi, rho, U)/mesh.magSf() - (n & rhoUf));
+}
+
+if (thermo.dpdt())
+{
+ dpdt = fvc::ddt(p);
+
+ if (mesh.moving())
+ {
+ dpdt -= fvc::div(fvc::meshPhi(rho, U), p);
+ }
+}
diff --git a/applications/solvers/combustion/XiFoam/XiDyMFoam/readControls.H b/applications/solvers/combustion/XiFoam/XiDyMFoam/readControls.H
new file mode 100644
index 0000000000..cf50980460
--- /dev/null
+++ b/applications/solvers/combustion/XiFoam/XiDyMFoam/readControls.H
@@ -0,0 +1,7 @@
+ #include "readTimeControls.H"
+
+ bool correctPhi =
+ pimple.dict().lookupOrDefault("correctPhi", true);
+
+ bool checkMeshCourantNo =
+ pimple.dict().lookupOrDefault("checkMeshCourantNo", false);
diff --git a/src/finiteVolume/fvMesh/fvPatches/constraint/cyclicAMI/cyclicAMIFvPatch.C b/src/finiteVolume/fvMesh/fvPatches/constraint/cyclicAMI/cyclicAMIFvPatch.C
index 5d8935139d..0f6064471f 100644
--- a/src/finiteVolume/fvMesh/fvPatches/constraint/cyclicAMI/cyclicAMIFvPatch.C
+++ b/src/finiteVolume/fvMesh/fvPatches/constraint/cyclicAMI/cyclicAMIFvPatch.C
@@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
- \\ / A nd | Copyright (C) 2011-2014 OpenFOAM Foundation
+ \\ / A nd | Copyright (C) 2011-2015 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@@ -34,6 +34,13 @@ namespace Foam
{
defineTypeNameAndDebug(cyclicAMIFvPatch, 0);
addToRunTimeSelectionTable(fvPatch, cyclicAMIFvPatch, polyPatch);
+ addNamedToRunTimeSelectionTable
+ (
+ fvPatch,
+ cyclicAMIFvPatch,
+ polyPatch,
+ cyclicPeriodicAMI
+ );
}
diff --git a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIInterpolation.C b/src/meshTools/AMIInterpolation/AMIInterpolation/AMIInterpolation.C
index 0e7a762423..7bad5f58c8 100644
--- a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIInterpolation.C
+++ b/src/meshTools/AMIInterpolation/AMIInterpolation/AMIInterpolation.C
@@ -327,9 +327,30 @@ void Foam::AMIInterpolation::agglomerate
// So now we have agglomeration of the target side in
// allRestrict:
- // 0..size-1 : local agglomeration (= targetRestrictAddressing)
+ // 0..size-1 : local agglomeration (= targetRestrictAddressing
+ // (but potentially permutated))
// size.. : agglomeration data from other processors
+
+ // The trickiness in this algorithm is finding out the compaction
+ // of the remote data (i.e. allocation of the coarse 'slots'). We could
+ // either send across the slot compaction maps or just make sure
+ // that we allocate the slots in exactly the same order on both sending
+ // and receiving side (e.g. if the submap is set up to send 4 items,
+ // the constructMap is also set up to receive 4 items.
+
+
+ // Short note about the various types of indices:
+ // - face indices : indices into the geometry.
+ // - coarse face indices : how the faces get agglomerated
+ // - transferred data : how mapDistribute sends/receives data,
+ // - slots : indices into data after distribution (e.g. stencil,
+ // srcAddress/tgtAddress). Note: for fully local addressing
+ // the slots are equal to face indices.
+ // A mapDistribute has:
+ // - a subMap : these are face indices
+ // - a constructMap : these are from 'transferred-date' to slots
+
labelListList tgtSubMap(Pstream::nProcs());
// Local subMap is just identity
@@ -341,11 +362,17 @@ void Foam::AMIInterpolation::agglomerate
{
if (procI != Pstream::myProcNo())
{
- // Combine entries that point to the same coarse element. All
- // the elements refer to local data so index into
- // targetRestrictAddressing or allRestrict (since the same
- // for local data).
+ // Combine entries that point to the same coarse element.
+ // The important bit is to loop over the data (and hand out
+ // compact indices ) in 'transferred data' order. This
+ // guarantees that we're doing exactly the
+ // same on sending and receiving side - e.g. the fourth element
+ // in the subMap is the fourth element received in the
+ // constructMap
+
const labelList& elems = map.subMap()[procI];
+ const labelList& elemsMap =
+ map.constructMap()[Pstream::myProcNo()];
labelList& newSubMap = tgtSubMap[procI];
newSubMap.setSize(elems.size());
@@ -354,7 +381,7 @@ void Foam::AMIInterpolation::agglomerate
forAll(elems, i)
{
- label fineElem = elems[i];
+ label fineElem = elemsMap[elems[i]];
label coarseElem = allRestrict[fineElem];
if (oldToNew[coarseElem] == -1)
{
@@ -372,16 +399,31 @@ void Foam::AMIInterpolation::agglomerate
// the sending map
labelListList tgtConstructMap(Pstream::nProcs());
- labelList tgtCompactMap;
// Local constructMap is just identity
{
tgtConstructMap[Pstream::myProcNo()] =
identity(targetCoarseSize);
-
- tgtCompactMap = targetRestrictAddressing;
}
- tgtCompactMap.setSize(map.constructSize());
+
+ labelList tgtCompactMap(map.constructSize());
+
+ {
+ // Note that in special cases (e.g. 'appending' two AMIs) the
+ // local size after distributing can be longer than the number
+ // of faces. I.e. it duplicates elements.
+ // Since we don't know this size instead we loop over all
+ // reachable elements (using the local constructMap)
+
+ const labelList& elemsMap = map.constructMap()[Pstream::myProcNo()];
+ forAll(elemsMap, i)
+ {
+ label fineElem = elemsMap[i];
+ label coarseElem = allRestrict[fineElem];
+ tgtCompactMap[fineElem] = coarseElem;
+ }
+ }
+
label compactI = targetCoarseSize;
// Compact data from other processors
@@ -440,7 +482,6 @@ void Foam::AMIInterpolation::agglomerate
}
}
-
srcAddress.setSize(sourceCoarseSize);
srcWeights.setSize(sourceCoarseSize);
@@ -493,7 +534,7 @@ void Foam::AMIInterpolation::agglomerate
forAll(fineSrcAddress, faceI)
{
// All the elements contributing to faceI. Are slots in
- // mapDistribute'd data.
+ // target data.
const labelList& elems = fineSrcAddress[faceI];
const scalarList& weights = fineSrcWeights[faceI];
const scalar fineArea = fineSrcMagSf[faceI];
@@ -1041,28 +1082,7 @@ void Foam::AMIInterpolation::update
);
// weights normalisation
- normaliseWeights
- (
- srcMagSf_,
- "source",
- srcAddress_,
- srcWeights_,
- srcWeightsSum_,
- AMIPtr->conformal(),
- true,
- lowWeightCorrection_
- );
- normaliseWeights
- (
- tgtMagSf_,
- "target",
- tgtAddress_,
- tgtWeights_,
- tgtWeightsSum_,
- AMIPtr->conformal(),
- true,
- lowWeightCorrection_
- );
+ normaliseWeights(AMIPtr->conformal(), true);
// cache maps and reset addresses
List