diff --git a/src/fvOptions/Make/files b/src/fvOptions/Make/files
index eaa52105a7..75062525b3 100644
--- a/src/fvOptions/Make/files
+++ b/src/fvOptions/Make/files
@@ -48,6 +48,7 @@ $(interRegion)/interRegionHeatTransfer/interRegionHeatTransferModel/interRegionH
$(interRegion)/interRegionHeatTransfer/interRegionHeatTransferModel/interRegionHeatTransferModelIO.C
$(interRegion)/interRegionHeatTransfer/constantHeatTransfer/constantHeatTransfer.C
$(interRegion)/interRegionHeatTransfer/tabulatedHeatTransfer/tabulatedHeatTransfer.C
+$(interRegion)/interRegionHeatTransfer/tabulatedNTUHeatTransfer/tabulatedNTUHeatTransfer.C
$(interRegion)/interRegionHeatTransfer/variableHeatTransfer/variableHeatTransfer.C
$(interRegion)/interRegionExplicitPorositySource/interRegionExplicitPorositySource.C
diff --git a/src/fvOptions/interRegionOption/interRegionOption.C b/src/fvOptions/interRegionOption/interRegionOption.C
index 332d02dfeb..c26a54cc2d 100644
--- a/src/fvOptions/interRegionOption/interRegionOption.C
+++ b/src/fvOptions/interRegionOption/interRegionOption.C
@@ -49,7 +49,7 @@ void Foam::fv::interRegionOption::setMapper()
if (mesh_.name() == nbrMesh.name())
{
- FatalErrorIn("interRegionOption::setCellIds()")
+ FatalErrorIn("interRegionOption::setMapper()")
<< "Inter-region model selected, but local and "
<< "neighbour regions are the same: " << nl
<< " local region: " << mesh_.name() << nl
@@ -75,7 +75,7 @@ void Foam::fv::interRegionOption::setMapper()
}
else
{
- FatalErrorIn("interRegionOption::setCellSet()")
+ FatalErrorIn("interRegionOption::setMapper()")
<< "regions " << mesh_.name() << " and "
<< nbrMesh.name() << " do not intersect"
<< exit(FatalError);
diff --git a/src/fvOptions/sources/interRegion/interRegionHeatTransfer/tabulatedNTUHeatTransfer/tabulatedNTUHeatTransfer.C b/src/fvOptions/sources/interRegion/interRegionHeatTransfer/tabulatedNTUHeatTransfer/tabulatedNTUHeatTransfer.C
new file mode 100644
index 0000000000..08d3ccdbc9
--- /dev/null
+++ b/src/fvOptions/sources/interRegion/interRegionHeatTransfer/tabulatedNTUHeatTransfer/tabulatedNTUHeatTransfer.C
@@ -0,0 +1,320 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration |
+ \\ / A nd | Copyright (C) 2015 OpenCFD Ltd
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+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 .
+
+\*---------------------------------------------------------------------------*/
+
+#include "tabulatedNTUHeatTransfer.H"
+#include "addToRunTimeSelectionTable.H"
+#include "surfaceFields.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+ namespace fv
+ {
+ defineTypeNameAndDebug(tabulatedNTUHeatTransfer, 0);
+ addToRunTimeSelectionTable
+ (
+ option,
+ tabulatedNTUHeatTransfer,
+ dictionary
+ );
+ }
+
+ template<>
+ const char* Foam::NamedEnum
+ <
+ Foam::fv::tabulatedNTUHeatTransfer::geometryModeType,
+ 2
+ >::names[] =
+ {
+ "calculated",
+ "user"
+ };
+}
+
+const Foam::NamedEnum
+Foam::fv::tabulatedNTUHeatTransfer::geometryModelNames_;
+
+
+// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
+
+const Foam::interpolation2DTable&
+Foam::fv::tabulatedNTUHeatTransfer::ntuTable()
+{
+ if (!ntuTable_.valid())
+ {
+ ntuTable_.reset(new interpolation2DTable(coeffs_));
+ }
+
+ return ntuTable_();
+}
+
+
+const Foam::basicThermo& Foam::fv::tabulatedNTUHeatTransfer::thermo
+(
+ const fvMesh& mesh
+) const
+{
+ if (!mesh.foundObject("thermophysicalProperties"))
+ {
+ FatalErrorIn
+ (
+ "void Foam::fv::tabulatedHeatTransferMassFlow::thermo"
+ "("
+ "const fvMesh&"
+ ")"
+ ) << " on mesh " << mesh.name()
+ << " could not find thermophysicalProperties "
+ << exit(FatalError);
+ }
+
+ return mesh.lookupObject("thermophysicalProperties");
+}
+
+
+void Foam::fv::tabulatedNTUHeatTransfer::initialiseGeometry()
+{
+ if (Ain_ < 0)
+ {
+ geometryMode_ =
+ geometryModelNames_.read(coeffs_.lookup("geometryMode"));
+
+ Info<< "Region " << mesh_.name() << " " << type() << " " << name_ << " "
+ << geometryModelNames_[geometryMode_] << " geometry:" << nl;
+
+ switch (geometryMode_)
+ {
+ case gmCalculated:
+ {
+ const fvMesh& nbrMesh =
+ mesh_.time().lookupObject(nbrRegionName());
+
+ word inletPatchName(coeffs_.lookup("inletPatch"));
+ word inletPatchNbrName(coeffs_.lookup("inletPatchNbr"));
+
+ Info<< " Inlet patch : " << inletPatchName << nl
+ << " Inlet patch neighbour : " << inletPatchNbrName
+ << nl;
+
+ label patchI = mesh_.boundary().findPatchID(inletPatchName);
+ label patchINbr =
+ nbrMesh.boundary().findPatchID(inletPatchNbrName);
+
+ scalar alpha(readScalar(coeffs_.lookup("inletBlockageRatio")));
+
+ if ((alpha < 0) || (alpha > 1))
+ {
+ FatalErrorIn
+ (
+ "void "
+ "Foam::fv::tabulatedNTUHeatTransfer::"
+ "initialiseGeometry()"
+ )
+ << "Inlet patch blockage ratio must be between 0 and 1"
+ << ". Current value: " << alpha
+ << abort(FatalError);
+ }
+
+ scalar alphaNbr
+ (
+ readScalar(coeffs_.lookup("inletBlockageRatioNbr"))
+ );
+
+ if ((alphaNbr < 0) || (alphaNbr > 1))
+ {
+ FatalErrorIn
+ (
+ "void "
+ "Foam::fv::tabulatedNTUHeatTransfer::"
+ "initialiseGeometry()"
+ )
+ << "Inlet patch neighbour blockage ratio must be "
+ << "between 0 and 1. Current value: " << alphaNbr
+ << abort(FatalError);
+ }
+
+ Info<< " Inlet blockage ratio : " << alpha << nl
+ << " Inlet blockage ratio neighbour : " << alphaNbr
+ << nl;
+
+ Ain_ =
+ (scalar(1) - alpha)
+ *gSum(mesh_.magSf().boundaryField()[patchI]);
+
+ AinNbr_ =
+ (scalar(1) - alphaNbr)
+ *gSum(nbrMesh.magSf().boundaryField()[patchINbr]);
+
+ scalar beta(readScalar(coeffs_.lookup("coreBlockageRatio")));
+
+ if ((beta < 0) || (beta > 1))
+ {
+ FatalErrorIn
+ (
+ "void "
+ "Foam::fv::tabulatedNTUHeatTransfer::"
+ "initialiseGeometry()"
+ )
+ << "Core volume blockage ratio must be between 0 and 1"
+ << ". Current value: " << beta
+ << abort(FatalError);
+ }
+
+ Info<< " Core volume blockage ratio : " << beta << nl;
+
+ Vcore_ = (scalar(1) - beta)*meshInterp().V();
+
+ break;
+ }
+ case gmUser:
+ {
+ coeffs_.lookup("Ain") >> Ain_;
+ coeffs_.lookup("AinNbr") >> AinNbr_;
+
+ if (!coeffs_.readIfPresent("Vcore", Vcore_))
+ {
+ Vcore_ = meshInterp().V();
+ }
+
+ break;
+ }
+ default:
+ {
+ FatalErrorIn
+ (
+ "void "
+ "Foam::fv::tabulatedNTUHeatTransfer::initialiseGeometry()"
+ )
+ << "Unhandled enumeration " << geometryMode_
+ << abort(FatalError);
+ }
+ }
+
+ Info<< " Inlet area local : " << Ain_ << nl
+ << " Inlet area neighbour : " << AinNbr_ << nl
+ << " Core volume : " << Vcore_ << nl
+ << endl;
+ }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
+
+Foam::fv::tabulatedNTUHeatTransfer::tabulatedNTUHeatTransfer
+(
+ const word& name,
+ const word& modelType,
+ const dictionary& dict,
+ const fvMesh& mesh
+)
+:
+ interRegionHeatTransferModel(name, modelType, dict, mesh),
+ UName_(coeffs_.lookupOrDefault("UName", "U")),
+ UNbrName_(coeffs_.lookupOrDefault("UNbrName", "U")),
+ rhoName_(coeffs_.lookupOrDefault("rhoName", "rho")),
+ rhoNbrName_(coeffs_.lookupOrDefault("rhoNbrName", "rho")),
+ ntuTable_(),
+ geometryMode_(gmCalculated),
+ Ain_(-1),
+ AinNbr_(-1),
+ Vcore_(-1)
+{}
+
+
+// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
+
+Foam::fv::tabulatedNTUHeatTransfer::~tabulatedNTUHeatTransfer()
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
+
+void Foam::fv::tabulatedNTUHeatTransfer::calculateHtc()
+{
+ initialiseGeometry();
+
+ const fvMesh& nbrMesh = mesh_.time().lookupObject(nbrRegionName());
+
+ const basicThermo& thermo = this->thermo(mesh_);
+ const basicThermo& thermoNbr = this->thermo(nbrMesh);
+ const volScalarField Cp(thermo.Cp());
+ const volScalarField CpNbr(thermoNbr.Cp());
+
+ // Calculate scaled mass flow for primary region
+ const volVectorField& U = mesh_.lookupObject(UName_);
+ const volScalarField& rho = mesh_.lookupObject(rhoName_);
+ const scalarField mDot(mag(U)*rho*Ain_);
+
+ // Calculate scaled mass flow for neighbour region
+ const volVectorField& UNbr =
+ nbrMesh.lookupObject(UNbrName_);
+ const scalarField UMagNbr(mag(UNbr));
+ const scalarField UMagNbrMapped(interpolate(UMagNbr));
+ const scalarField& rhoNbr =
+ nbrMesh.lookupObject(rhoNbrName_).internalField();
+ const scalarField rhoNbrMapped(interpolate(rhoNbr));
+ const scalarField mDotNbr(UMagNbrMapped*rhoNbrMapped*AinNbr_);
+
+
+ scalarField& htcc = htc_.internalField();
+ const interpolation2DTable& ntuTable = this->ntuTable();
+
+ forAll(htcc, cellI)
+ {
+ scalar Cpc = Cp[cellI];
+ scalar CpcNbr = CpNbr[cellI];
+ scalar mDotc = mDot[cellI];
+ scalar mDotcNbr = mDotNbr[cellI];
+ scalar Cmin = min(Cpc*mDotc, CpcNbr*mDotcNbr);
+ scalar ntu = ntuTable(mDotc, mDotcNbr);
+
+ htcc[cellI] = Cmin*ntu/Vcore_;
+ }
+}
+
+
+bool Foam::fv::tabulatedNTUHeatTransfer::read(const dictionary& dict)
+{
+ if (option::read(dict))
+ {
+ coeffs_.readIfPresent("UName", UName_);
+ coeffs_.readIfPresent("UNbrName", UNbrName_);
+ coeffs_.readIfPresent("rhoName", rhoName_);
+ coeffs_.readIfPresent("rhoNbrName", rhoNbrName_);
+
+ // Force geometry re-initialisation
+ Ain_ = -1;
+ initialiseGeometry();
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+// ************************************************************************* //
diff --git a/src/fvOptions/sources/interRegion/interRegionHeatTransfer/tabulatedNTUHeatTransfer/tabulatedNTUHeatTransfer.H b/src/fvOptions/sources/interRegion/interRegionHeatTransfer/tabulatedNTUHeatTransfer/tabulatedNTUHeatTransfer.H
new file mode 100644
index 0000000000..611b4b1ebc
--- /dev/null
+++ b/src/fvOptions/sources/interRegion/interRegionHeatTransfer/tabulatedNTUHeatTransfer/tabulatedNTUHeatTransfer.H
@@ -0,0 +1,225 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration |
+ \\ / A nd | Copyright (C) 2015 OpenCFD Ltd
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+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 .
+
+Class
+ Foam::fv::tabulatedNTUHeatTransfer
+
+Description
+ Tabulated heat transfer model.
+
+ The heat flux is calculated based on the Number of Thermal Units (NTU).
+ A 2-D table of NTU as functions of the primary and secondary mass flow
+ rates is required.
+
+ The exchanger geometry can be specified using either:
+ - \c calculated:
+ - inlet area of each region and core volume determined by interrogating
+ mesh patches, and mesh-to-mesh interpolation volume
+ - calculated core volume canbe partially blocked by specifying a
+ \c coreBlockageRatio [0-1] entry
+ - \c user:
+ - inlet area of each region privided by the user
+ - core volume automatically calculated by the mesh-to-mesh
+ interpolation volume if not provided by user
+
+ Heat transfer coefficient calculated by:
+
+ \f[
+ htc = C_{min} \frac{NTU}{V_{core}}
+ \f]
+
+ Where \f$ C_{min} \f$ is given by:
+
+ \f[
+ C_{min} = min \left(Cp_1 \dot{m}_1, Cp_2 \dot{m}_2 \right)
+ \f]
+
+ \heading Example usage
+
+ \verbatim
+ coolerToAir
+ {
+ type tabulatedNTUHeatTransfer;
+ active yes;
+
+ tabulatedNTUHeatTransferCoeffs
+ {
+ interpolationMethod cellVolumeWeight;
+ nbrRegionName air;
+ master true;
+
+ fieldNames (h);
+ outOfBounds clamp;
+ fileName "ntuTable";
+ nbrModelName airToCooler;
+ semiImplicit no;
+
+
+ geometryMode user;
+ Ain 0.01728;
+ AinNbr 0.3456;
+ Vcore 0.01244; // Optional
+
+ // geometryMode calculated;
+ // inletPatch inlet_HWK;
+ // inletPatchNbr inlet_air;
+ // inletBlockageRatio 0.10;
+ // inletBlockageRatioNbr 0.04;
+ // coreBlockageRatio 0;
+ }
+ }
+
+SourceFiles
+ tabulatedNTUHeatTransfer.C
+
+SeeAlso
+ interRegionHeatTransferModel.H
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef tabulatedNTUHeatTransfer_H
+#define tabulatedNTUHeatTransfer_H
+
+#include "interRegionHeatTransferModel.H"
+#include "autoPtr.H"
+#include "interpolation2DTable.H"
+#include "NamedEnum.H"
+#include "basicThermo.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace fv
+{
+
+/*---------------------------------------------------------------------------*\
+ Class tabulatedNTUHeatTransfer Declaration
+\*---------------------------------------------------------------------------*/
+
+class tabulatedNTUHeatTransfer
+:
+ public interRegionHeatTransferModel
+{
+public:
+
+ // Public enumerations
+
+ enum geometryModeType
+ {
+ gmCalculated,
+ gmUser
+ };
+
+ static const NamedEnum geometryModelNames_;
+
+
+private:
+
+ // Private data
+
+ //- Name of velocity field; default = U
+ word UName_;
+
+ //- Name of neighbour velocity field; default = U
+ word UNbrName_;
+
+ //- Name of density field; default = rho
+ word rhoName_;
+
+ //- Name of neighbour density field; default = rho
+ word rhoNbrName_;
+
+ //- Pointer to 2-D look-up table of NTU f(mDot1, mDot2)
+ autoPtr > ntuTable_;
+
+ //- Geometry input mode
+ geometryModeType geometryMode_;
+
+ //- Inlet area [m2]
+ scalar Ain_;
+
+ //- Neighbour region inlet area [m2]
+ scalar AinNbr_;
+
+ //- Heat exchanger core volume
+ scalar Vcore_;
+
+
+ // Private Member functions
+
+ //- NTU table helper
+ const interpolation2DTable& ntuTable();
+
+ //- Thermophysical properties helper
+ const basicThermo& thermo(const fvMesh& mesh) const;
+
+ //- Initialise geometry
+ void initialiseGeometry();
+
+
+public:
+
+ //- Runtime type information
+ TypeName("tabulatedNTUHeatTransfer");
+
+
+ // Constructors
+
+ //- Construct from dictionary
+ tabulatedNTUHeatTransfer
+ (
+ const word& name,
+ const word& modelType,
+ const dictionary& dict,
+ const fvMesh& mesh
+ );
+
+
+ //- Destructor
+ virtual ~tabulatedNTUHeatTransfer();
+
+
+ // Public Functions
+
+ //- Calculate the heat transfer coefficient
+ virtual void calculateHtc();
+
+
+ // I-O
+
+ //- Read dictionary
+ virtual bool read(const dictionary& dict);
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace fv
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //