diff --git a/OFsolvers/OF13/birdmultiphaseEuler/Allwmake b/OFsolvers/OF13/birdmultiphaseEuler/Allwmake index fc432ad1..30e5094b 100755 --- a/OFsolvers/OF13/birdmultiphaseEuler/Allwmake +++ b/OFsolvers/OF13/birdmultiphaseEuler/Allwmake @@ -13,5 +13,6 @@ wmake $targetType wmake -j 20 $targetType fvModels wmake -j 20 $targetType functionObjects +wmake -j 20 $targetType boundaryConditions #------------------------------------------------------------------------------ diff --git a/OFsolvers/OF13/birdmultiphaseEuler/boundaryConditions/Make/files b/OFsolvers/OF13/birdmultiphaseEuler/boundaryConditions/Make/files new file mode 100644 index 00000000..9279f1a1 --- /dev/null +++ b/OFsolvers/OF13/birdmultiphaseEuler/boundaryConditions/Make/files @@ -0,0 +1,3 @@ +recirculatedSpecies/recirculatedSpeciesFvPatchScalarField.C + +LIB = $(FOAM_USER_LIBBIN)/libbirdBoundaryConditions diff --git a/OFsolvers/OF13/birdmultiphaseEuler/boundaryConditions/Make/options b/OFsolvers/OF13/birdmultiphaseEuler/boundaryConditions/Make/options new file mode 100644 index 00000000..ad2b36e5 --- /dev/null +++ b/OFsolvers/OF13/birdmultiphaseEuler/boundaryConditions/Make/options @@ -0,0 +1,14 @@ +EXE_INC = \ + -I$(LIB_SRC)/finiteVolume/lnInclude \ + -I$(LIB_SRC)/meshTools/lnInclude \ + -I../phaseSystem/lnInclude \ + -I$(LIB_SRC)/physicalProperties/lnInclude \ + -I$(LIB_SRC)/thermophysicalModels/basic/lnInclude \ + -I$(LIB_SRC)/twoPhaseModels/twoPhaseMixture/lnInclude \ + + +LIB_LIBS = \ + -lfiniteVolume \ + -lmeshTools \ + -L$(FOAM_USER_LIBBIN) \ + -lbirdphaseSystem diff --git a/OFsolvers/OF13/birdmultiphaseEuler/boundaryConditions/recirculatedSpecies/recirculatedSpeciesFvPatchScalarField.C b/OFsolvers/OF13/birdmultiphaseEuler/boundaryConditions/recirculatedSpecies/recirculatedSpeciesFvPatchScalarField.C new file mode 100644 index 00000000..aafc13f9 --- /dev/null +++ b/OFsolvers/OF13/birdmultiphaseEuler/boundaryConditions/recirculatedSpecies/recirculatedSpeciesFvPatchScalarField.C @@ -0,0 +1,226 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | Website: https://openfoam.org + \\ / A nd | Copyright (C) 2026 OpenFOAM Foundation + \\/ 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 "recirculatedSpeciesFvPatchScalarField.H" +#include "addToRunTimeSelectionTable.H" +#include "fieldMapper.H" +#include "volFields.H" +#include "surfaceFields.H" + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +Foam::scalar Foam::recirculatedSpeciesFvPatchScalarField::t() const +{ + return db().time().value(); +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::recirculatedSpeciesFvPatchScalarField:: +recirculatedSpeciesFvPatchScalarField +( + const fvPatch& p, + const DimensionedField& iF, + const dictionary& dict +) +: + fixedValueFvPatchScalarField(p, iF), + Y0_ + ( + Function1::New + ( + "Y0", + db().time().userUnits(), + unitAny, + dict + ) + ), + r_ + ( + Function1::New + ( + "r", + db().time().userUnits(), + unitAny, + dict + ) + ), + phaseName_(dict.lookupOrDefault("phase","gas")), + otherPatchName_(dict.lookup("otherPatch")) +{ + + +// fixedValueFvPatchScalarField::evaluate(); + + + // Initialise with the value entry if evaluation is not possible + fvPatchScalarField::operator= + ( + scalarField("value", iF.dimensions(), dict, p.size()) + ); + +} + + +Foam::recirculatedSpeciesFvPatchScalarField:: +recirculatedSpeciesFvPatchScalarField +( + const recirculatedSpeciesFvPatchScalarField& ptf, + const fvPatch& p, + const DimensionedField& iF, + const fieldMapper& mapper +) +: + fixedValueFvPatchScalarField(ptf, p, iF, mapper), + Y0_(ptf.Y0_, false), + r_(ptf.r_, false), + phaseName_(ptf.phaseName_), + otherPatchName_(ptf.otherPatchName_) +{} + + +Foam::recirculatedSpeciesFvPatchScalarField:: +recirculatedSpeciesFvPatchScalarField +( + const recirculatedSpeciesFvPatchScalarField& ptf, + const DimensionedField& iF +) +: + fixedValueFvPatchScalarField(ptf, iF), + Y0_(ptf.Y0_, false), + r_(ptf.r_, false), + phaseName_(ptf.phaseName_), + otherPatchName_(ptf.otherPatchName_) +{} + + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +void Foam::recirculatedSpeciesFvPatchScalarField::map +( + const fvPatchScalarField& ptf, + const fieldMapper& mapper +) +{ + fixedValueFvPatchScalarField::map(ptf, mapper); +} + + +void Foam::recirculatedSpeciesFvPatchScalarField::reset +( + const fvPatchScalarField& ptf +) +{ + fixedValueFvPatchScalarField::reset(ptf); +} + + +void Foam::recirculatedSpeciesFvPatchScalarField::updateCoeffs() +{ + if (updated()) + { + return; + } + + const phaseModel& phase + ( + db().lookupObject + ( + IOobject::groupName("alpha", phaseName_) + ) + ); + + + if ( !db().foundObject("alphaRhoPhi." + phase.name()) ) + { + return; + } + + // Since we're inside initEvaluate/evaluate there might be processor + // comms underway. Change the tag we use. + int oldTag = UPstream::msgType(); + UPstream::msgType() = oldTag+1; + + const fvMesh& mesh = this->internalField().mesh(); + + label patchID = mesh.boundaryMesh().findIndex(otherPatchName_); + + scalar alphaRhoPhiYr = 0.; + scalar alphaRhoPhiTot = 1e-16; + + if ( patchID != 1 ) + { + const fvPatch& nbrPatch = mesh.boundary()[patchID]; + const scalarField& alphaRhoPhip = nbrPatch.lookupPatchField("alphaRhoPhi." + phase.name()); + const scalarField& Yp = nbrPatch.lookupPatchField(this->internalField().name()); + + alphaRhoPhiTot = max( mag( sum(alphaRhoPhip)),1e-16 ); + alphaRhoPhiYr = mag( sum(alphaRhoPhip*Yp) ); + } + + reduce(alphaRhoPhiTot, sumOp()); + reduce(alphaRhoPhiYr, sumOp()); + + const scalar Yr = min(max( alphaRhoPhiYr/alphaRhoPhiTot, 0.), 1.); + + scalar rf = min(max(r_->value(t()),0.),1.); + + // Restore tag + UPstream::msgType() = oldTag; + + fixedValueFvPatchScalarField::operator==( (1. - rf)*Y0_->value(t()) + rf*Yr ); + + fixedValueFvPatchScalarField::updateCoeffs(); +} + + +void Foam::recirculatedSpeciesFvPatchScalarField::write +( + Ostream& os +) const +{ + fvPatchScalarField::write(os); + writeEntry(os, db().time().userUnits(), unitAny, Y0_()); + writeEntry(os, db().time().userUnits(), unitAny, r_()); + writeEntry(os, "phase", phaseName_); + writeEntry(os, "otherPatch", otherPatchName_); + writeEntry(os, "value", *this); +} + + +// * * * * * * * * * * * * * * Build Macro Function * * * * * * * * * * * * // + +namespace Foam +{ + makePatchTypeField + ( + fvPatchScalarField, + recirculatedSpeciesFvPatchScalarField + ); +} + +// ************************************************************************* // diff --git a/OFsolvers/OF13/birdmultiphaseEuler/boundaryConditions/recirculatedSpecies/recirculatedSpeciesFvPatchScalarField.H b/OFsolvers/OF13/birdmultiphaseEuler/boundaryConditions/recirculatedSpecies/recirculatedSpeciesFvPatchScalarField.H new file mode 100644 index 00000000..ab8f9052 --- /dev/null +++ b/OFsolvers/OF13/birdmultiphaseEuler/boundaryConditions/recirculatedSpecies/recirculatedSpeciesFvPatchScalarField.H @@ -0,0 +1,203 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | Website: https://openfoam.org + \\ / A nd | Copyright (C) 2026 OpenFOAM Foundation + \\/ 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::recirculatedSpeciesFvPatchScalarField + +Description + This boundary condition provides a recirculatedSpecies condition, + calculated as: + + \f[ + Y = Y_{0}*(1-r) + r*Y_{r} + \f] + and + \f[ + Y_{r} = sum(\alphaRhoPhi_{pr} Y_{pr}) / sum(\alphaRhoPhi_{pr}) + \f] + + where + \vartable + r | recirculation factor [-] + Y_{0} | base patch value [-] + Y_{r} | recirculating patch mean [-] + alphaRhoPhi_{pr}| mass flow rate at recirculating patch [Kg/s] + Y_{pr}| mass fraction at recirculating patch [Kg/Kg] + \endtable + +Usage + \table + Property | Description | Req'd? | Default + Y0 | base value | yes | + r | recirculation factor | yes | + otherPatch | name of other patch | yes | + \endtable + + Example of the boundary condition specification: + \verbatim + + { + type recirculatedSpecies; + Y0 1; //Initial stream only has this species + r table ( + (0 0) + (1 1) + ); // Switch to full recirculation after one second + otherPatch outlet; + value uniform 1; // optional initial value + } + \endverbatim + +SourceFiles + recirculatedSpeciesFvPatchScalarField.C + +\*---------------------------------------------------------------------------*/ + +#ifndef BC_H +#define BC_H + +#include "fixedValueFvPatchFields.H" +#include "Function1.H" +#include "phaseModel.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class recirculatedSpeciesFvPatchScalarField Declaration +\*---------------------------------------------------------------------------*/ + +class recirculatedSpeciesFvPatchScalarField +: + public fixedValueFvPatchScalarField +{ + // Private Data + + //- Base value + autoPtr> Y0_; + + //- Recirculation factor + autoPtr> r_; + + word phaseName_; + + word otherPatchName_; + + + // Private Member Functions + + //- Return current time + scalar t() const; + + +public: + + //- Runtime type information + TypeName("recirculatedSpecies"); + + + // Constructors + + //- Construct from patch, internal field and dictionary + recirculatedSpeciesFvPatchScalarField + ( + const fvPatch&, + const DimensionedField&, + const dictionary& + ); + + //- Construct by mapping given fixedValueTypeFvPatchField + // onto a new patch + recirculatedSpeciesFvPatchScalarField + ( + const recirculatedSpeciesFvPatchScalarField&, + const fvPatch&, + const DimensionedField&, + const fieldMapper& + ); + + //- Disallow copy without setting internal field reference + recirculatedSpeciesFvPatchScalarField + ( + const recirculatedSpeciesFvPatchScalarField& + ) = delete; + + //- Copy constructor setting internal field reference + recirculatedSpeciesFvPatchScalarField + ( + const recirculatedSpeciesFvPatchScalarField&, + const DimensionedField& + ); + + //- Construct and return a clone setting internal field reference + virtual tmp clone + ( + const DimensionedField& iF + ) const + { + return tmp + ( + new recirculatedSpeciesFvPatchScalarField + ( + *this, + iF + ) + ); + } + + + // Member Functions + + // Mapping functions + + //- Map the given fvPatchField onto this fvPatchField + virtual void map(const fvPatchScalarField&, const fieldMapper&); + + //- Reset the fvPatchField to the given fvPatchField + // Used for mesh to mesh mapping + virtual void reset(const fvPatchScalarField&); + + + // Evaluation functions + + //- Update the coefficients associated with the patch field + virtual void updateCoeffs(); + + + //- Write + virtual void write(Ostream&) const; +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + + +#endif + +// ************************************************************************* // diff --git a/OFsolvers/OF13/birdmultiphaseEuler/phaseSystem/phaseModels/BioReactingPhaseModel/BioReactingPhaseModel.C b/OFsolvers/OF13/birdmultiphaseEuler/phaseSystem/phaseModels/BioReactingPhaseModel/BioReactingPhaseModel.C index 695c4892..5caab092 100644 --- a/OFsolvers/OF13/birdmultiphaseEuler/phaseSystem/phaseModels/BioReactingPhaseModel/BioReactingPhaseModel.C +++ b/OFsolvers/OF13/birdmultiphaseEuler/phaseSystem/phaseModels/BioReactingPhaseModel/BioReactingPhaseModel.C @@ -43,7 +43,6 @@ Foam::BioReactingPhaseModel::BioReactingPhaseModel species_(dict_.lookup("species")), maxUptakeRate_(), K_(), - M_(), URSp_() // DCW_ // ( @@ -63,9 +62,7 @@ Foam::BioReactingPhaseModel::BioReactingPhaseModel dictionary subsp(dict_.subDict(species_[specieI])); maxUptakeRate_.append(readScalar(subsp.lookup("maxUptakeRate"))); - K_.append(readScalar(subsp.lookup("K"))); - M_.append(readScalar(subsp.lookup("molWeight"))); - + K_.append(readScalar(subsp.lookup("K"))), URSp_.append( new volScalarField::Internal ( @@ -100,7 +97,9 @@ void Foam::BioReactingPhaseModel::correctReactions() scalar kg_to_g = 1000.; scalar hr_to_sec = 3600.; - const volScalarField& rho = this->thermo().rho(); + const volScalarField& rho = this->rho(); + const volScalarField& alpha = *this; + const volScalarField alphaRho = alpha * rho; forAll(this->Y(), speciei) { @@ -109,7 +108,8 @@ void Foam::BioReactingPhaseModel::correctReactions() if ( this->Y()[speciei].name() == IOobject::groupName(species_[speciej], this->name()) ) { Info << "Updating enzymatic reaction of species " << this->Y()[speciei].name() << endl; - scalar kg_m3_to_mol_m3 = kg_to_g / M_[speciej]; + + scalar kg_m3_to_mol_m3 = kg_to_g / this->thermo_->Wi(speciei).value(); scalar mol_m3_to_kg_m3 = 1./kg_m3_to_mol_m3; scalar Kp = K_[speciej] * mol_m3_to_kg_m3; scalar maxUR = maxUptakeRate_[speciej] * mol_m3_to_kg_m3 / hr_to_sec; @@ -117,9 +117,8 @@ void Foam::BioReactingPhaseModel::correctReactions() volScalarField::Internal& URSp = URSp_[speciej]; forAll(URSp, cellI) { - URSp[cellI] = - maxUR / ( Kp + rho[cellI] * this->Y()[speciei][cellI] ); - } - + URSp[cellI] = - ( maxUR * alphaRho[cellI] ) / ( Kp + alphaRho[cellI] * this->Y()[speciei][cellI] ); + } } } } diff --git a/OFsolvers/OF13/birdmultiphaseEuler/phaseSystem/phaseModels/BioReactingPhaseModel/BioReactingPhaseModel.H b/OFsolvers/OF13/birdmultiphaseEuler/phaseSystem/phaseModels/BioReactingPhaseModel/BioReactingPhaseModel.H index fc7dd8d7..54afdee3 100644 --- a/OFsolvers/OF13/birdmultiphaseEuler/phaseSystem/phaseModels/BioReactingPhaseModel/BioReactingPhaseModel.H +++ b/OFsolvers/OF13/birdmultiphaseEuler/phaseSystem/phaseModels/BioReactingPhaseModel/BioReactingPhaseModel.H @@ -81,9 +81,6 @@ protected: // Half saturation constant List K_; - // Molar weights - List M_; - // Uptake rates Sp PtrList URSp_; diff --git a/tutorial_cases/OF13/bubble_column/0/CO2.gas b/tutorial_cases/OF13/bubble_column/0/CO2.gas index 9da26d4c..253399df 100644 --- a/tutorial_cases/OF13/bubble_column/0/CO2.gas +++ b/tutorial_cases/OF13/bubble_column/0/CO2.gas @@ -25,7 +25,10 @@ boundaryField inlet { - type fixedValue; + type recirculatedSpecies; + Y0 $CO2_in; + otherPatch outlet; + r 0.5; value uniform $CO2_in; } diff --git a/tutorial_cases/OF13/bubble_column/0/N2.gas b/tutorial_cases/OF13/bubble_column/0/N2.gas index 61cacdbd..18df0be0 100644 --- a/tutorial_cases/OF13/bubble_column/0/N2.gas +++ b/tutorial_cases/OF13/bubble_column/0/N2.gas @@ -25,8 +25,10 @@ boundaryField inlet { - type fixedValue; + type recirculatedSpecies; value uniform $N2_in; + Y0 $N2_in; + r 0.5; } outlet diff --git a/tutorial_cases/OF13/bubble_column/0/O2.gas b/tutorial_cases/OF13/bubble_column/0/O2.gas index c79b66c7..6f0957da 100644 --- a/tutorial_cases/OF13/bubble_column/0/O2.gas +++ b/tutorial_cases/OF13/bubble_column/0/O2.gas @@ -25,8 +25,11 @@ boundaryField inlet { - type fixedValue; + type recirculatedSpecies; value uniform $O2_in; + Y0 $O2_in; + otherPatch outlet; + r 0.5; } outlet diff --git a/tutorial_cases/OF13/bubble_column/README.md b/tutorial_cases/OF13/bubble_column/README.md index 250c354b..4ebc8027 100644 --- a/tutorial_cases/OF13/bubble_column/README.md +++ b/tutorial_cases/OF13/bubble_column/README.md @@ -5,6 +5,7 @@ Features demonstrated: * Basic bubble column settings with LES and bubble size distribution * Air sparged in water * Oxygen mass transfer +* 50% recirculation (half of the sparged gas is recirculated) Used for: * Bubble column simulations with mass transfer diff --git a/tutorial_cases/OF13/bubble_column/system/controlDict b/tutorial_cases/OF13/bubble_column/system/controlDict index ee70fba0..752da6e5 100644 --- a/tutorial_cases/OF13/bubble_column/system/controlDict +++ b/tutorial_cases/OF13/bubble_column/system/controlDict @@ -14,7 +14,7 @@ FoamFile } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -libs ( "libbirdmultiphaseEuler.so" ); +libs ( "libbirdmultiphaseEuler.so" "libbirdBoundaryConditions.so" ); solver birdmultiphaseEuler;