Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions Interface.C
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,27 @@ void preciceAdapter::Interface::addCouplingDataWriter(

// Add the CouplingDataUser to the list of writers
couplingDataWriters_.push_back(couplingDataWriter);

// Check whether config mismatch scalar or vector data
unsigned int preciceDataDim = precice_.getDataDimensions(meshName_, fieldConfig.name);
bool isVectorDataConfig = (dim_ == preciceDataDim); // 2d or 3d vectors
bool isVectorDataAdapter = couplingDataWriter->hasVectorData();

// Taking gradient of a scalar field results in a vector field
bool isScalarConfiguredGradient = (!isVectorDataConfig) && (fieldConfig.operation == "gradient");

if (isVectorDataConfig != isVectorDataAdapter)
{
adapterInfo("Data dimension mismatch for field \"" + fieldConfig.name + "\". "
+ "The field is defined as " + (isVectorDataConfig ? "vector" : "scalar")
+ " data in the preCICE configuration, but the data is "
+ (isVectorDataAdapter ? "vector" : "scalar")
+ " in the adapter. Please check your preCICE configuration."
+ (isScalarConfiguredGradient ? " If you are trying to couple the gradient of a scalar field, \
make sure the data is defined vector in the preCICE config."
: ""),
"error");
}
}


Expand Down Expand Up @@ -490,6 +511,21 @@ void preciceAdapter::Interface::addCouplingDataReader(

// Add the CouplingDataUser to the list of readers
couplingDataReaders_.push_back(couplingDataReader);

// Check whether config mismatch scalar or vector data
unsigned int preciceDataDim = precice_.getDataDimensions(meshName_, fieldConfig.name);
bool isVectorDataConfig = (dim_ == preciceDataDim); // 2d or 3d vectors
bool isVectorDataAdapter = couplingDataReader->hasVectorData();

if (isVectorDataConfig != isVectorDataAdapter)
{
adapterInfo("Data dimension mismatch for field \"" + fieldConfig.name + "\". "
+ "The field is defined as " + (isVectorDataConfig ? "vector" : "scalar")
+ " data in the preCICE configuration, but the data is "
+ (isVectorDataAdapter ? "vector" : "scalar")
+ " in the adapter. Please check your preCICE configuration.",
"error");
}
}

void preciceAdapter::Interface::createBuffer()
Expand Down
8 changes: 6 additions & 2 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ interfaces
{
name Velocity; // Data name as defined in preCICE config
solver_name U; // Optional: Field name in OpenFOAM (defaults to same as 'name')
operation value; // Optional: Operation to perform on data (defaults to 'value')
operation value; // Optional: Operation to perform on data (defaults to 'value', other options are `gradient` and `surface-normal-gradient`)
flip-normal false; // Optional: Flip the normal direction (defaults to 'false')
}

Expand All @@ -302,7 +302,11 @@ Explicitly setting `locations volumeCenters;` in preciceDict is required for vol

When reading on the OpenFOAM side, the Generic module automatically detects the boundary condition type of the coupled patch to apply the received data. The boundary condition must be respected, therefore the data received is applied either as a `fixedValue` or `fixedGradient` boundary condition, determined by the type set in the `0/` files.

The `operation surface-normal-gradient;` is currently only supported for scalar field surface writing. The operation `gradient` as well as the option `flip-normal` are not yet supported by the adapter.
Limitations:

- The operation `gradient` is currently only supported for scalar fields (resulting to a vector field).
- The operation `surface-normal-gradient` is currently only supported for surface scalar field writing (resulting to a scalar field).
- The operation `flip-normal` is supported for all field types across all modules, but the most relevant use case might be for surface scalar fields, in order to change the direction of, e.g., a flux.

### Volume coupling

Expand Down
98 changes: 92 additions & 6 deletions module-generic/ReadWrite.C
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,14 @@ preciceAdapter::Generic::ScalarFieldCoupler::ScalarFieldCoupler(
mesh_(mesh),
fieldConfig_(fieldConfig)
{
dataType_ = scalar;
if (fieldConfig_.operation == "gradient")
{
dataType_ = vector;
}
else
{
dataType_ = scalar;
}
}

void preciceAdapter::Generic::ScalarFieldCoupler::initialize()
Expand All @@ -30,18 +37,92 @@ void preciceAdapter::Generic::ScalarFieldCoupler::initialize()
adapterInfo("Generic module: The surface-normal-gradient operation is only supported for faceCenters location type.", "error");
}
}

if (fieldConfig_.operation == "gradient")
{
adapterInfo("Generic module: The gradient operation is not yet supported for scalar fields. Maybe you meant surface-normal-gradient?", "error");
}
}


std::size_t preciceAdapter::Generic::ScalarFieldCoupler::write(double* buffer, bool meshConnectivity, const unsigned int dim)
{
int bufferIndex = 0;

if (fieldConfig_.operation == "gradient")
{
// Calculate the full gradient (volVectorField)
// Temporary field discarded afterwards
Foam::tmp<volVectorField> tmpObject(fvc::grad(*scalarField_));
const volVectorField& gradScalarField = tmpObject(); // dereference
Comment on lines +47 to +52
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unlike PressureGradientFull, I don't store the resulting volVectorField as a member variable. I'm using Foam::tmp<volVectorField> to temporarily allocate it and automatically deallocate it once it's out of scope. Would this be a performance problem - allocating and deallocating memory for each write? Alternatively, we could create a shared buffer to store the scalar field gradients if configured.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed in a meeting: This should indeed have performance implications, better allocate in the constructor and reuse.


if (this->locationType_ == LocationType::volumeCenters)
{
if (cellSetNames_.empty())
{
for (const auto& cell : gradScalarField.internalField())
{
// x-dimension
buffer[bufferIndex++] = cell.x();

// y-dimension
buffer[bufferIndex++] = cell.y();

if (dim == 3)
{
// z-dimension
buffer[bufferIndex++] = cell.z();
}
}
}
else
{
for (const auto& cellSetName : cellSetNames_)
{
cellSet overlapRegion(scalarField_->mesh(), cellSetName);
const labelList& cells = overlapRegion.toc();

for (const auto& currentCell : cells)
{
// x-dimension
buffer[bufferIndex++] = gradScalarField.internalField()[currentCell].x();

// y-dimension
buffer[bufferIndex++] = gradScalarField.internalField()[currentCell].y();

if (dim == 3)
{
// z-dimension
buffer[bufferIndex++] = gradScalarField.internalField()[currentCell].z();
}
}
}
}
}

// For every boundary patch of the interface
for (uint j = 0; j < patchIDs_.size(); j++)
{
int patchID = patchIDs_.at(j);

// For every cell of the patch
forAll(gradScalarField.boundaryField()[patchID], i)
{
// Copy the velocity into the buffer
// x-dimension
buffer[bufferIndex++] =
gradScalarField.boundaryField()[patchID][i].x();

// y-dimension
buffer[bufferIndex++] =
gradScalarField.boundaryField()[patchID][i].y();

if (dim == 3)
{
// z-dimension
buffer[bufferIndex++] =
gradScalarField.boundaryField()[patchID][i].z();
}
}
}
return bufferIndex;
}

if (fieldConfig_.operation == "surface-normal-gradient")
{
// For every boundary patch of the interface
Expand Down Expand Up @@ -125,6 +206,11 @@ void preciceAdapter::Generic::ScalarFieldCoupler::read(double* buffer, const uns
{
int bufferIndex = 0;

if (fieldConfig_.operation == "gradient" || fieldConfig_.operation == "surface-normal-gradient")
{
adapterInfo("Generic module: The gradient operation is only supported for writing.", "error");
}

if (this->locationType_ == LocationType::volumeCenters)
{
if (cellSetNames_.empty())
Expand Down