OpenFOAM adapter with special Boundary Condition

I am using compressible solver in addition to a special type of boundary condition that we define. When implementing this BC, we split the field at that boundary into wave components - one going in and other going out. The wave going in is provided externally and OpenFOAM gives the wave going out. Now, we want to make a coupling where the externally provided in-going wave is the output of the other computation. So, I am creating a new adapter where the exchange of these values occur. The problem is that I don’t want to change how the BC is implemented because there are many other functions used there. The splitting into wave-components happen only in one function there. I want a way where I can simply add a line in there, where precice does the exchange of wave components. From CHT Module, I defined similar functions like addWriters and addReaders. But, I don’t know where to call them.

This is an interesting use case, @namanpurwar93!

The OpenFOAM adapter assumes that the user sets a “simple” boundary condition (e.g. fixedValue, fixedGradient, mixed), sets a dummy value, and then it overwrites it after each advance(), to be used in the next timestep.

How do your code changes look like? Does your boundary condition derive from a basic one?

Can you set values to your boundary patches in a way similar to this?

T_->boundaryFieldRef()[patchID][i] = buffer[bufferIndex++];

Keep in mind that the adapter reads and writes values in a different stage than the calls to boundary conditions. It is implemented as a function object, not as a boundary condition (for flexibility).

We are ultimately using mixed time-varying boundary condition with mixedFvPatchScalarField::updateCoeffs(). We calculate refValue(), valueFraction() and refGrad(). For a particular boundary, for example, current time step field values gives wave component g and reads another wave component f provided externally. Now, refValue, valueFRaction and refGrad are calculated and mixedFvPatchScalarField::updateCoeffs() is called.

Now, we want that the wave component f comes from other participant (lets say LEE) and g is the output of OpenFOAM to be shared with LEE. So, we are not coupling using the field variables, but variables derived from field variables at the boundary. And then rest of the implementation of mixedFvPatchScalarField remains unchanged.

If I understand correctly, it looks like this is possible and that you can follow a similar approach to what we use for our robin-robin (i.e. mixed BC) coupling in CHT (see Sink Temperature and Heat Transfer Coefficient).

You don’t need to couple the field variables. You could move your computation inside the two readers and writers for f and g (and write and read both). You could then use a mixed boundary condition in your case files.

I understand that you want to keep your boundary condition and not modify much, but I think moving your changes into the readers/writers would be the most straight-forward way to do it. Is there much more happening there that you think it could not be moved to the adapter?

The boundary condition I want to use is modified every PIMPLE loop because of correctBoundaryCondition and also at every iteration of time loop. As far as I understood, precice couples only every iteration of the time loop. Is it correct? If so, then how can I make changes in the fields of the interface in every iteration of the PIMPLE loop also?

I think that function objects are not called in every internal iteration of the PIMPLE loop (this would actually be a good OpenFOAM-specific question for CFD Online). However, you could maybe modify your solver to explicitly trigger all function objects’ execute(). I could expect this to explode, however.

If this helps, the adapter also works with steady-state solvers, such as buoyantSimpleFoam (SIMPLE loop). In that case, function objects are being triggered in every iteration, as there is no real time.

You could also just directly modify your solver and use the Adapter class, instead of going through the function objects interface. I have never tried this with today’s adapter, but this is how the adapter used to be, before we convert it to a function object.

@namanpurwar93 do you by any chance have any news regarding this, or suggestions for future readers? Which approach did you choose?

@MakisH Yes, I was able to solve this problem. I explain my problem here once again with an example.

In my Boundary condition code, I calculate a scalar value ‘f’/‘g’ that needs to be coupled to other domain/solver and a scalar ‘g’/‘f’ is received from the other domain/solver. Boundary condition itself is a mixed BC which is a function of ‘g’ or ‘f’. In BC code, ‘f’/‘g’ is added to mesh object-registry using mesh.thisDb().store(). For more details,

In the precice adapter code, I use the same method to add the read data to mesh objectregistry.

In this way, the read data by precice is accessed by the BC code and the data to be written by the BC code is accessed in adapter code and written to buffer variable.

1 Like