|
[Sponsors] |
December 9, 2014, 09:45 |
Trying to understand outletInlet BC
|
#1 |
Member
Thomas Vossel
Join Date: Aug 2013
Location: Germany
Posts: 45
Rep Power: 13 |
Hi!
I have some problems understanding how exactly the outletInlet BC works. What is done in its class is this: Code:
template<class Type> void Foam::outletInletFvPatchField<Type>::updateCoeffs() { // this exits the method if the updateCoeffs() method already did run... // Out of curiosity: where exactly is this switched back to false again? if (this->updated()) { return; } // this creates the phip fvsPatchField (I guess the "p" stands for phi_patch) // the flux in the patch node is assigned to phip const fvsPatchField<scalar>& phip = this->patch().template lookupPatchField<surfaceScalarField, scalar> ( phiName_ ); // This assigns the absolute value of phip to the valueFraction w this->valueFraction() = pos(phip); // this basically just sets updated() to true mixedFvPatchField<Type>::updateCoeffs(); } Code:
this->valueFraction() = 1.0 - pos(phip); With = patch value although I think the second that's multiplied with should have gotten a variable name of its own as it's the constant number from the Dirichlet boundary condition if I got this right while the initial stands for the patch node value which is a mix of the Dirichlet and Neumann BC = cell value = weight field i.e. valueFraction = inverse distance cell center <-> cell face where the patch is This can be found in the mixedFvPatchField's operator= method: Code:
Field<Type>::operator= ( valueFraction_*refValue_ + (1.0 - valueFraction_)* ( this->patchInternalField() + refGrad_/this->patch().deltaCoeffs() ) ); I would have expected some if-statements checking whether the flux goes inside or outside the domain and then some appropiate calculations depending on the case... It would be nice if someone could give me some hints to understand the idea behind the given approach as I don't get why making the flux the valueFraction solves the problem... |
|
December 9, 2014, 09:59 |
|
#2 |
Senior Member
|
Hi,
You're not quite correct about Code:
// This assigns the absolute value of phip to the valueFraction w this->valueFraction() = pos(phip); Code:
inline Scalar pos(const Scalar s) { return (s >= 0)? 1: 0; } Code:
Sign conventions: - positive flux (out of domain): apply the user-specified fixed value - negative flux (into of domain): apply zero-gradient condition |
|
December 9, 2014, 10:11 |
|
#3 |
Member
Thomas Vossel
Join Date: Aug 2013
Location: Germany
Posts: 45
Rep Power: 13 |
Ah I see - so pos(x) and neg(x) are meant as booleans. I had thought they'd just let you change the sign of a number to either a positive or negative one...
Thanks for clarifying this! |
|
January 14, 2015, 08:43 |
|
#4 |
Member
Thomas Vossel
Join Date: Aug 2013
Location: Germany
Posts: 45
Rep Power: 13 |
So now I'm having another question concerning this method / equation I already did mention:
Code:
Field<Type>::operator= ( valueFraction_*refValue_ + (1.0 - valueFraction_)* ( this->patchInternalField() + refGrad_/this->patch().deltaCoeffs() ) ); |
|
January 14, 2015, 08:52 |
Long shot...
|
#5 |
Senior Member
|
It is a long shot, but there is some reading of closeby fields within the mixed-BCs, e.g. the wallHeatTransfer-BC. MAYBE that gives further clues where you could proceed looking for a solution to your question/problem?
|
|
January 14, 2015, 09:39 |
|
#6 |
Senior Member
|
Hi,
1. There's fixedInternalValueFvPatchField. It accesses internal field. 2. There's totalPressure BC. It is BC for pressure and it accesses patch values of velocity. 3. And finally there's, for example, flowRateInletVelocity, and here's how it accesses rho volume field: Code:
... // mass flow-rate if (db().foundObject<volScalarField>(rhoName_)) { const fvPatchField<scalar>& rhop = patch().lookupPatchField<volScalarField, scalar>(rhoName_); operator==(n*avgU/rhop); } ... |
|
January 14, 2015, 12:00 |
|
#7 |
Member
Thomas Vossel
Join Date: Aug 2013
Location: Germany
Posts: 45
Rep Power: 13 |
Thanks for your suggestions - I'll have a look at them!
|
|
January 19, 2015, 13:35 |
|
#8 |
Member
Thomas Vossel
Join Date: Aug 2013
Location: Germany
Posts: 45
Rep Power: 13 |
So I had some time to work on the BC again and while I can reproduce the examples mentioned here those just give me the patch values via the "lookupPatchField" method. I need to use the internal cell values though. The "patchInternalField" function seems to do just that but I can't figure out how to tell OpenFOAM which field it should read from. I found some examples where a simple "this->patchInternalField()"; is used but if I got this right this is just about reading the values for the property you applied the BC to. The function itself asks for a "UList" but I didn't find any examples yet which might give me a clue how to read the values of a specific field of my choice...
Any suggestions on that? Does "patchInternalField" give me the needed functionality after all? It might not be able to read a "named field" after all but if that's the case I don't see how to read a cell value of my choice after all as the fvPatch class doesn't seem to deliver another interesting method meant for a purpose like this... |
|
January 20, 2015, 04:05 |
|
#9 |
Senior Member
|
Hi,
Maybe I did not quite get your question but... 1. What is wrong with the example no. 3 from my last post? It will provide you with the patch field of any other volume fiend. 2. Also you have another way, maybe it is not quite idiomatic. Every fvPatchField has db() method, which returns constant reference to objectRegistry. Through this object you can lookup volume fields (lookupObject<Type>("field name")). Also fvPatchField has patch() method, which returns constant reference to fvPatch object, which has faceCells() method. So you can lookup volume field you need, then iterate over faces of the patch, use faceCells() to find face-cell correspondence and extract value using cell index. |
|
January 20, 2015, 04:57 |
|
#10 |
Member
Thomas Vossel
Join Date: Aug 2013
Location: Germany
Posts: 45
Rep Power: 13 |
Well I basically created a clone of the outletInlet BC (together with a custom mixedFvPatchField) and what it does is that upon starting my solver the variable in the style of example #3 gets initialized and also has the value of the internal cell. In the course of the solving process its values won't get updated though. In order to test this I created a new field that isn't used anywhere but for a simple function that increases its value by 1 in every timestep. When using "Info" commands to print the values the BC condition always will tell...
TempBC = type calculated; value uniform 1400; ... while the actual Temp volume field is increased in every timestep and e.g. will lead to: internalField uniform 1434; 1400 was the value I assigned in the createFields.H: Code:
volScalarField Temp ( IOobject ( "Temp", runTime.timeName(), mesh, IOobject::NO_READ, IOobject::AUTO_WRITE ), mesh, dimensionedScalar("zero", dimensionSet(0, 0, 0, 1, 0, 0, 0), 1400) ); |
|
January 20, 2015, 05:10 |
|
#11 |
Senior Member
|
Hi,
Unfortunately I did not get what was updated, why it should be updated etc. Can you post the code of your modified BC? Can you post a code of modified solver (you just do Temp = Temp + dimensionedScalar("One", dimTemperature, 1) on every timestep?)? |
|
January 20, 2015, 09:54 |
|
#12 |
Member
Thomas Vossel
Join Date: Aug 2013
Location: Germany
Posts: 45
Rep Power: 13 |
Well my approach was to mimic the behaviour of the outletInlet BC just with my own function in an altered mixedFVPatchField BC (c.f. formula from the opening posting here). There I made some additions in order to create objects which should read certain cell values (adjacent to the patch). I put them into the evaluate function of the former mixedFvPatchField which now looks like this:
Code:
template<class Type> void diffPressFvPatchField<Type>::evaluate(const Pstream::commsTypes) { if (!this->updated()) { this->updateCoeffs(); } const fvPatchField<scalar>& TempBC = this->patch().template lookupPatchField<volScalarField, scalar>(TempName_); const fvPatchField<scalar>& TestFieldBC = this->patch().template lookupPatchField<volScalarField, scalar>(TestFieldName_); Info << "TempBC = " << TempBC << endl; Info << "TestFieldBC= " << TestFieldBC << endl; Field<Type>::operator= ( valueFraction_*refValue_ + (1.0 - valueFraction_)* TempBC * TestFieldBC * ( this->patchInternalField() + refGrad_/this->patch().deltaCoeffs() ) ); fvPatchField<Type>::evaluate(); } I of course also added the needed words for the two fields to the mixedField's constructors which I won't list here now... The two fields themselves are created via the createFields.H file like this: Code:
Info<< "Initializing temperature field >>Temp<<\n" << endl; volScalarField Temp ( IOobject ( "Temp", runTime.timeName(), mesh, IOobject::NO_READ, IOobject::AUTO_WRITE ), mesh, dimensionedScalar("zero", dimensionSet(0, 0, 0, 1, 0, 0, 0), 1400) ); Info<< "Initializing field >>TestField<<\n" << endl; volScalarField TestField ( IOobject ( "TestField", runTime.timeName(), mesh, IOobject::NO_READ, // values are calculated and thus needn't an initial case file with start values IOobject::AUTO_WRITE ), mesh, dimensionedScalar("zero", dimensionSet(0, 0, 0, 0, 0, 0, 0), 9999.0) ); Code:
forAll(Temp, celli) { Temp[celli] = Temp[celli] + 1; } Info << "Temp = " << Temp << endl; Well what else is there to say? My BC is applied to one wall for alpha like this: Code:
rightWall { type diffPressOutletInlet; phi phi; // name of flux field (default = phi) outletValue uniform 0; // reverse flow (inlet) value value uniform 0; // initial value } Code:
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // Create time Create mesh for time = 0 PIMPLE: Operating solver in PISO mode Reading field p_rgh Reading field U Reading/calculating face flux field phi Reading transportProperties Selecting incompressible transport model Newtonian Selecting incompressible transport model Newtonian Selecting turbulence model type laminar Reading g Calculating field g.h No finite volume options present Initializing temperature field >>Temp<< Initializing field >>TestField<< time step continuity errors : sum local = 0, global = 0, cumulative = 0 DICPCG: Solving for pcorr, Initial residual = 0, Final residual = 0, No Iterations 0 time step continuity errors : sum local = 0, global = 0, cumulative = 0 Courant Number mean: 0 max: 0 Starting time loop Courant Number mean: 0 max: 0 Interface Courant Number mean: 0 max: 0 deltaT = 0.00119048 Time = 0.00119048 smoothSolver: Solving for alpha.water, Initial residual = 0, Final residual = 0, No Iterations 0 TempBC = type calculated; value uniform 1400; TestFieldBC= type calculated; value uniform 9999; Phase-1 volume fraction = 0 Min(alpha1) = 0 Max(alpha1) = 0 MULES: Correcting alpha.water TempBC = type calculated; value uniform 1400; TestFieldBC= type calculated; value uniform 9999; MULES: Correcting alpha.water TempBC = type calculated; value uniform 1400; TestFieldBC= type calculated; value uniform 9999; Phase-1 volume fraction = 0 Min(alpha1) = 0 Max(alpha1) = 0 DICPCG: Solving for p_rgh, Initial residual = 0, Final residual = 0, No Iterations 0 time step continuity errors : sum local = 0, global = 0, cumulative = 0 DICPCG: Solving for p_rgh, Initial residual = 0, Final residual = 0, No Iterations 0 time step continuity errors : sum local = 0, global = 0, cumulative = 0 DICPCG: Solving for p_rgh, Initial residual = 0, Final residual = 0, No Iterations 0 time step continuity errors : sum local = 0, global = 0, cumulative = 0 Temp = dimensions [0 0 0 1 0 0 0]; internalField uniform 1401; boundaryField { leftWall { type calculated; value uniform 1400; } rightWall { type calculated; value uniform 1400; } lowerWall { type calculated; value uniform 1400; } upperWall { type calculated; value uniform 1400; } defaultFaces { type empty; } } ExecutionTime = 0 s ClockTime = 0 s Courant Number mean: 0 max: 0 Interface Courant Number mean: 0 max: 0 deltaT = 0.00141156 Time = 0.00260204 smoothSolver: Solving for alpha.water, Initial residual = 0, Final residual = 0, No Iterations 0 TempBC = type calculated; value uniform 1400; TestFieldBC= type calculated; value uniform 9999; Phase-1 volume fraction = 0 Min(alpha1) = 0 Max(alpha1) = 0 MULES: Correcting alpha.water TempBC = type calculated; value uniform 1400; TestFieldBC= type calculated; value uniform 9999; MULES: Correcting alpha.water TempBC = type calculated; value uniform 1400; TestFieldBC= type calculated; value uniform 9999; Phase-1 volume fraction = 0 Min(alpha1) = 0 Max(alpha1) = 0 DICPCG: Solving for p_rgh, Initial residual = 0, Final residual = 0, No Iterations 0 time step continuity errors : sum local = 0, global = 0, cumulative = 0 DICPCG: Solving for p_rgh, Initial residual = 0, Final residual = 0, No Iterations 0 time step continuity errors : sum local = 0, global = 0, cumulative = 0 DICPCG: Solving for p_rgh, Initial residual = 0, Final residual = 0, No Iterations 0 time step continuity errors : sum local = 0, global = 0, cumulative = 0 Temp = dimensions [0 0 0 1 0 0 0]; internalField uniform 1402; boundaryField { leftWall { type calculated; value uniform 1400; } rightWall { type calculated; value uniform 1400; } lowerWall { type calculated; value uniform 1400; } upperWall { type calculated; value uniform 1400; } defaultFaces { type empty; } } ExecutionTime = 0 s ClockTime = 0 s |
|
January 20, 2015, 10:25 |
|
#13 |
Senior Member
|
Well, (maybe) my bad,
Code:
const fvPatchField<scalar>& rhop = patch().lookupPatchField<volScalarField, scalar>(rhoName_); There's still a way I've described in the last message. And it is actually implemented in Foam::fvPatch::patchInternalField method. I.e. your code should look like: Code:
const label patchi = patch().index(); const volScalarField Temp = db().lookupObject<volScalarField>(TempName_); const scalarField TempIntF(Temp.boundaryField()[patchi].patchInternalField()); Info<< TempIntF << endl; |
|
January 21, 2015, 12:08 |
|
#14 |
Member
Thomas Vossel
Join Date: Aug 2013
Location: Germany
Posts: 45
Rep Power: 13 |
Well due to all the template stuff used in the fvPatchField things are a bit more complicated here. Using your code results in this error:
Code:
diffPressBC/diffPressFvPatchField.C: In member function ‘virtual void Foam::diffPressFvPatchField<Type>::evaluate(Foam::UPstream::commsTypes)’: diffPressBC/diffPressFvPatchField.C:188:28: error: there are no arguments to ‘patch’ that depend on a template parameter, so a declaration of ‘patch’ must be available [-fpermissive] const label patchi = patch().index(); ^ diffPressBC/diffPressFvPatchField.C:188:28: note: (if you use ‘-fpermissive’, G++ will accept your code, but allowing the use of an undeclared name is deprecated) diffPressBC/diffPressFvPatchField.C:189:32: error: there are no arguments to ‘db’ that depend on a template parameter, so a declaration of ‘db’ must be available [-fpermissive] const volScalarField Temp = db().lookupObject<volScalarField>(TempName_); ^ diffPressBC/diffPressFvPatchField.C:189:61: error: expected primary-expression before ‘>’ token const volScalarField Temp = db().lookupObject<volScalarField>(TempName_); ^ diffPressBC/diffPressFvPatchField.C:190:32: error: invalid use of incomplete type ‘const volScalarField {aka const class Foam::GeometricField<double, Foam::fvPatchField, Foam::volMesh>}’ const scalarField TempIntF(Temp.boundaryField()[patchi].patchInternalField()); ^ In file included from /opt/OpenFOAM-2.3.0/src/finiteVolume/lnInclude/surfaceInterpolation.H:40:0, from /opt/OpenFOAM-2.3.0/src/finiteVolume/lnInclude/fvMesh.H:54, from /opt/OpenFOAM-2.3.0/src/finiteVolume/lnInclude/fvPatchField.C:28, from /opt/OpenFOAM-2.3.0/src/finiteVolume/lnInclude/fvPatchField.H:588, from diffPressBC/diffPressFvPatchField.H:75, from diffPressBC/diffPressFvPatchFields.H:29, from diffPressBC/diffPressFvPatchFields.C:26: /opt/OpenFOAM-2.3.0/src/finiteVolume/lnInclude/volFieldsFwd.H:52:7: error: declaration of ‘const volScalarField {aka const class Foam::GeometricField<double, Foam::fvPatchField, Foam::volMesh>}’ class GeometricField; Code:
const label patchi = this->patch().template index(); const volScalarField Temp = this->db().template lookupObject<volScalarField>(TempName_); I wasn't able to find a sound formulation for the final line of your code though... |
|
January 21, 2015, 12:21 |
|
#15 |
Senior Member
|
Hi,
Yes, I forgot & after volScalarField in the code. Surely you do not need to create copy of the volScalarField, reference should be enough. So code shall be something like: Code:
const label patchi = this->patch().template index(); const volScalarField& Temp = this->db().template lookupObject<volScalarField>(TempName_); |
|
January 21, 2015, 12:30 |
|
#16 |
Senior Member
|
Btw, if you post code here, it'll be easier for me to check my propositions for errors. As currently I'm writing the code quite "theoretically".
|
|
January 22, 2015, 06:16 |
|
#17 |
Member
Thomas Vossel
Join Date: Aug 2013
Location: Germany
Posts: 45
Rep Power: 13 |
I finally got things working. I dont really understand why but the proposed command...
Code:
const scalarField TempIntF(Temp.boundaryField()[patchi].patchInternalField()); As a workaround I just skipped the definition of the volScalarField Temp and did put everything into TempIntF: Code:
const scalarField TempIntF = this->db().template lookupObject<volScalarField>(TempName_).boundaryField()[patchi].patchInternalField(); |
|
January 22, 2015, 06:22 |
|
#18 |
Senior Member
|
Good to know.
Still I do not get why Temp should be Temp(), was not able to find definition of () operator neither for GeometricField (which volScalarField is), nor for its parents. Also not quite get why do you need template BC instead of just fvPatchScalarField as your BC is for pressure (deducing it from the name ) |
|
January 22, 2015, 07:43 |
|
#19 |
Member
Thomas Vossel
Join Date: Aug 2013
Location: Germany
Posts: 45
Rep Power: 13 |
Well when you don't add template code you get an error like this (if I got right what you wanted to express):
Code:
error: there are no arguments to ‘db’ that depend on a template parameter, so a declaration of ‘db’ must be available [-fpermissive] Code:
error: invalid use of incomplete type ‘const volScalarField {aka const class Foam::GeometricField<double, Foam::fvPatchField, Foam::volMesh>}’ const scalarField TempIntF2(Temp.boundaryField()[patchi].patchInternalField()); ^ In file included from /opt/OpenFOAM-2.3.0/src/finiteVolume/lnInclude/surfaceInterpolation.H:40:0, |
|
January 22, 2015, 08:57 |
|
#20 |
Senior Member
|
Well, I understand why you need to add template to your code, I do not understand why diffPressFvPatchField should be template. Whole BC is template (that means you plan to use BC for scalars, vectors, tensors etc.), while according to the name you plan to use it for pressure (which is scalar).
Concerning your Code:
error: invalid use of incomplete type |
|
|
|