Skip to content

Commit

Permalink
Configure gradient data requirement automatically (#1371)
Browse files Browse the repository at this point in the history
* Increase test coverage of isGradientDataRequired in tests
* Port unit and export tests to new gradient handling
* Make requireGradient function public in order to use it for data config
* Fix error message to show correct arguments
* Remove 'hasGradient' from data constructor
* Implement autoconfig in participant configuration
* Remove hasGradient internally from DataConfiguration
* Remove gradient flag from xml config
* Add changelog
* Move function call chain into MappingContext
* Update export tests due to new data constructor
* Transform check into an assert

Co-authored-by: Benjamin Uekermann <benjamin.uekermann@gmail.com>
  • Loading branch information
davidscn and uekerman committed Jul 20, 2022
1 parent 64e6403 commit 8931247
Show file tree
Hide file tree
Showing 33 changed files with 125 additions and 107 deletions.
1 change: 1 addition & 0 deletions docs/changelog/1371.md
@@ -0,0 +1 @@
- Removed the explicit gradient data flag (`<data: ... gradient="on" />`) for nearest-neighbor-gradient mapping. The gradient data requirement is now deduced automatically by preCICE.
6 changes: 4 additions & 2 deletions src/io/tests/ExportVTKTest.cpp
Expand Up @@ -27,8 +27,10 @@ BOOST_AUTO_TEST_CASE(ExportDataWithGradient)
int dimensions = 2;
// Create mesh to map from
mesh::Mesh mesh("MyMesh", dimensions, testing::nextMeshID());
mesh::PtrData dataScalar = mesh.createData("dataScalar", 1, 0_dataID, true);
mesh::PtrData dataVector = mesh.createData("dataVector", 2, 1_dataID, true);
mesh::PtrData dataScalar = mesh.createData("dataScalar", 1, 0_dataID);
mesh::PtrData dataVector = mesh.createData("dataVector", 2, 1_dataID);
dataScalar->requireDataGradient();
dataVector->requireDataGradient();
mesh.createVertex(Eigen::Vector2d::Constant(0.0));
mesh.createVertex(Eigen::Vector2d::Constant(1.0));

Expand Down
13 changes: 8 additions & 5 deletions src/io/tests/ExportVTPTest.cpp
Expand Up @@ -31,9 +31,10 @@ BOOST_AUTO_TEST_CASE(ExportDataWithGradient2D)
const int dimensions = 2;
// Create mesh to map from
mesh::Mesh mesh("MyMesh", dimensions, testing::nextMeshID());
mesh::PtrData dataScalar = mesh.createData("dataScalar", 1, 0_dataID, true);
mesh::PtrData dataVector = mesh.createData("dataVector", dimensions, 1_dataID, true);

mesh::PtrData dataScalar = mesh.createData("dataScalar", 1, 0_dataID);
mesh::PtrData dataVector = mesh.createData("dataVector", dimensions, 1_dataID);
dataScalar->requireDataGradient();
dataVector->requireDataGradient();
mesh.createVertex(Eigen::Vector2d::Constant(0.0));
mesh.createVertex(Eigen::Vector2d::Constant(1.0));

Expand Down Expand Up @@ -61,8 +62,10 @@ BOOST_AUTO_TEST_CASE(ExportDataWithGradient3D)
const int dimensions = 3;
// Create mesh to map from
mesh::Mesh mesh("MyMesh", dimensions, testing::nextMeshID());
mesh::PtrData dataScalar = mesh.createData("dataScalar", 1, 0_dataID, true);
mesh::PtrData dataVector = mesh.createData("dataVector", dimensions, 1_dataID, true);
mesh::PtrData dataScalar = mesh.createData("dataScalar", 1, 0_dataID);
mesh::PtrData dataVector = mesh.createData("dataVector", dimensions, 1_dataID);
dataScalar->requireDataGradient();
dataVector->requireDataGradient();
mesh.createVertex(Eigen::Vector3d::Constant(0.0));
mesh.createVertex(Eigen::Vector3d::Constant(1.0));

Expand Down
12 changes: 8 additions & 4 deletions src/io/tests/ExportVTUTest.cpp
Expand Up @@ -32,8 +32,10 @@ BOOST_AUTO_TEST_CASE(ExportDataWithGradient2D)
// Create mesh to map from
int dimensions = 2;
mesh::Mesh mesh("MyMesh", dimensions, testing::nextMeshID());
mesh::PtrData dataScalar = mesh.createData("dataScalar", 1, 0_dataID, true);
mesh::PtrData dataVector = mesh.createData("dataVector", dimensions, 1_dataID, true);
mesh::PtrData dataScalar = mesh.createData("dataScalar", 1, 0_dataID);
mesh::PtrData dataVector = mesh.createData("dataVector", dimensions, 1_dataID);
dataScalar->requireDataGradient();
dataVector->requireDataGradient();

mesh.createVertex(Eigen::Vector2d::Constant(0.0));
mesh.createVertex(Eigen::Vector2d::Constant(1.0));
Expand Down Expand Up @@ -62,8 +64,10 @@ BOOST_AUTO_TEST_CASE(ExportDataWithGradient3D)
int dimensions = 3;
// Create mesh to map from
mesh::Mesh mesh("MyMesh", dimensions, testing::nextMeshID());
mesh::PtrData dataScalar = mesh.createData("dataScalar", 1, 0_dataID, true);
mesh::PtrData dataVector = mesh.createData("dataVector", dimensions, 1_dataID, true);
mesh::PtrData dataScalar = mesh.createData("dataScalar", 1, 0_dataID);
mesh::PtrData dataVector = mesh.createData("dataVector", dimensions, 1_dataID);
dataScalar->requireDataGradient();
dataVector->requireDataGradient();

mesh.createVertex(Eigen::Vector3d::Constant(0.0));
mesh.createVertex(Eigen::Vector3d::Constant(1.0));
Expand Down
8 changes: 4 additions & 4 deletions src/mapping/Mapping.cpp
Expand Up @@ -11,8 +11,8 @@ namespace mapping {
Mapping::Mapping(
Constraint constraint,
int dimensions,
bool requireGradient)
: _requireGradient(requireGradient),
bool requiresGradientData)
: _requiresGradientData(requiresGradientData),
_constraint(constraint),
_inputRequirement(MeshRequirement::UNDEFINED),
_outputRequirement(MeshRequirement::UNDEFINED),
Expand Down Expand Up @@ -82,9 +82,9 @@ int Mapping::getDimensions() const
return _dimensions;
}

bool Mapping::requireGradient() const
bool Mapping::requiresGradientData() const
{
return _requireGradient;
return _requiresGradientData;
}

void Mapping::map(int inputDataID,
Expand Down
10 changes: 5 additions & 5 deletions src/mapping/Mapping.hpp
Expand Up @@ -47,7 +47,7 @@ class Mapping {
};

/// Constructor, takes mapping constraint.
Mapping(Constraint constraint, int dimensions, bool requireGradient = false);
Mapping(Constraint constraint, int dimensions, bool requiresGradientData = false);

Mapping &operator=(Mapping &&) = delete;

Expand Down Expand Up @@ -119,6 +119,9 @@ class Mapping {
*/
virtual void scaleConsistentMapping(int inputDataID, int outputDataID) const;

/// Returns whether the mapping requires gradient data
bool requiresGradientData() const;

protected:
/// Returns pointer to input mesh.
mesh::PtrMesh input() const;
Expand All @@ -132,16 +135,13 @@ class Mapping {
/// Sets the mesh requirement for the output mesh.
void setOutputRequirement(MeshRequirement requirement);

/// Returns if the mapping needs gradient data
bool requireGradient() const;

int getDimensions() const;

/// Flag to indicate whether computeMapping() has been called.
bool _hasComputedMapping = false;

/// Flag if gradient data is required for the mapping
bool _requireGradient;
bool _requiresGradientData;

/**
* @brief Maps data using a conservative constraint
Expand Down
6 changes: 3 additions & 3 deletions src/mapping/NearestNeighborBaseMapping.cpp
Expand Up @@ -20,10 +20,10 @@ namespace mapping {
NearestNeighborBaseMapping::NearestNeighborBaseMapping(
Constraint constraint,
int dimensions,
bool requireGradient,
bool requiresGradientData,
std::string mappingName,
std::string mappingNameShort)
: Mapping(constraint, dimensions, requireGradient),
: Mapping(constraint, dimensions, requiresGradientData),
mappingName(mappingName),
mappingNameShort(mappingNameShort)
{
Expand Down Expand Up @@ -86,7 +86,7 @@ void NearestNeighborBaseMapping::clear()
_vertexIndices.clear();
_hasComputedMapping = false;

if (requireGradient())
if (requiresGradientData())
_offsetsMatched.clear();

if (getConstraint() == CONSISTENT) {
Expand Down
5 changes: 2 additions & 3 deletions src/mapping/NearestNeighborGradientMapping.cpp
Expand Up @@ -59,9 +59,8 @@ void NearestNeighborGradientMapping::mapConsistent(DataID inputDataID, DataID ou
PRECICE_TRACE(inputDataID, outputDataID);
precice::utils::Event e("map." + mappingNameShort + ".mapData.From" + input()->getName() + "To" + output()->getName(), precice::syncMode);

PRECICE_CHECK(input()->data(inputDataID)->hasGradient(), "Mesh \"{}\" does not contain gradient data. Using Nearest Neighbor Gradient requires gradient data for each vertices.",
"Check if hasGradient flag in the Data object was successfully initialized.",
input()->getName());
PRECICE_ASSERT(input()->data(inputDataID)->hasGradient(), "Mesh \"{}\" does not contain gradient data. Using Nearest Neighbor Gradient requires gradient data.",
input()->getName());

/// Check if input has gradient data, else send Error
if (input()->vertices().empty()) {
Expand Down
16 changes: 10 additions & 6 deletions src/mapping/tests/NearestNeighborGradientMappingTest.cpp
Expand Up @@ -24,8 +24,10 @@ BOOST_AUTO_TEST_CASE(ConsistentNonIncremental)

// Create mesh to map from
PtrMesh inMesh(new Mesh("InMesh", dimensions, testing::nextMeshID()));
PtrData inDataScalar = inMesh->createData("InDataScalar", 1, 0_dataID, true);
PtrData inDataVector = inMesh->createData("InDataVector", 2, 1_dataID, true);
PtrData inDataScalar = inMesh->createData("InDataScalar", 1, 0_dataID);
PtrData inDataVector = inMesh->createData("InDataVector", 2, 1_dataID);
inDataScalar->requireDataGradient();
inDataVector->requireDataGradient();
int inDataScalarID = inDataScalar->getID();
int inDataVectorID = inDataVector->getID();
Vertex &inVertex0 = inMesh->createVertex(Eigen::Vector2d::Constant(0.0));
Expand Down Expand Up @@ -113,8 +115,10 @@ BOOST_AUTO_TEST_CASE(ConsistentGradientNotConstant)

// Create mesh to map from
PtrMesh inMesh(new Mesh("InMesh", dimensions, testing::nextMeshID()));
PtrData inDataScalar = inMesh->createData("InDataScalar", 1, 0_dataID, true);
PtrData inDataVector = inMesh->createData("InDataVector", 2, 1_dataID, true);
PtrData inDataScalar = inMesh->createData("InDataScalar", 1, 0_dataID);
PtrData inDataVector = inMesh->createData("InDataVector", 2, 1_dataID);
inDataScalar->requireDataGradient();
inDataVector->requireDataGradient();
int inDataScalarID = inDataScalar->getID();
int inDataVectorID = inDataVector->getID();
Vertex &inVertex0 = inMesh->createVertex(Eigen::Vector2d::Constant(0.0));
Expand Down Expand Up @@ -145,8 +149,8 @@ BOOST_AUTO_TEST_CASE(ConsistentGradientNotConstant)
PtrData outDataVector = outMesh->createData("OutDataVector", 2, 3_dataID);
int outDataScalarID = outDataScalar->getID();
int outDataVectorID = outDataVector->getID();
Vertex &outVertex0 = outMesh->createVertex(Eigen::Vector2d::Constant(0.1));
Vertex &outVertex1 = outMesh->createVertex(Eigen::Vector2d::Constant(1.1));
outMesh->createVertex(Eigen::Vector2d::Constant(0.1));
outMesh->createVertex(Eigen::Vector2d::Constant(1.1));
outMesh->allocateDataValues();

// Setup mapping with mapping coordinates and geometry used
Expand Down
14 changes: 8 additions & 6 deletions src/mesh/Data.cpp
Expand Up @@ -13,8 +13,7 @@ Data::Data()
: _name(""),
_id(-1),
_dimensions(0),
_spatialDimensions(-1),
_hasGradient(false)
_spatialDimensions(-1)
{
PRECICE_ASSERT(false);
}
Expand All @@ -23,14 +22,12 @@ Data::Data(
std::string name,
DataID id,
int dimensions,
int spacialDimensions,
bool hasGradient)
int spatialDimensions)
: _values(),
_name(std::move(name)),
_id(id),
_dimensions(dimensions),
_spatialDimensions(spacialDimensions),
_hasGradient(hasGradient)
_spatialDimensions(spatialDimensions)
{
PRECICE_ASSERT(dimensions > 0, dimensions);
}
Expand Down Expand Up @@ -78,6 +75,11 @@ bool Data::hasGradient() const
return _hasGradient;
}

void Data::requireDataGradient()
{
_hasGradient = true;
};

int Data::getDimensions() const
{
return _dimensions;
Expand Down
12 changes: 7 additions & 5 deletions src/mesh/Data.hpp
Expand Up @@ -49,8 +49,7 @@ class Data {
std::string name,
DataID id,
int dimension,
int spacialDimensions = -1,
bool hasGradient = false);
int spatialDimensions = -1);

/// Returns a reference to the data values.
Eigen::VectorXd &values();
Expand All @@ -76,6 +75,9 @@ class Data {
/// Returns if the data contains gradient data
bool hasGradient() const;

/// Set the additional requirement of gradient data
void requireDataGradient();

/// Returns the mesh dimension (i.e., number of rows) of one gradient data value .
int getSpatialDimensions() const;

Expand All @@ -98,11 +100,11 @@ class Data {
/// Dimensionality of one data value.
int _dimensions;

/// Spacial Dimension of one element -> number of rows (only 2, 3 allowed for 2D, 3D).
/// Spatial Dimension of one element -> number of rows (only 2, 3 allowed for 2D, 3D).
int _spatialDimensions;

/// Flag if the gradient data is available
bool _hasGradient;
/// Whether gradient data is available or not
bool _hasGradient = false;
};

} // namespace mesh
Expand Down
5 changes: 2 additions & 3 deletions src/mesh/Mesh.cpp
Expand Up @@ -156,8 +156,7 @@ Tetrahedron &Mesh::createTetrahedron(
PtrData &Mesh::createData(
const std::string &name,
int dimension,
DataID id,
bool withGradient)
DataID id)
{
PRECICE_TRACE(name, dimension);
for (const PtrData &data : _data) {
Expand All @@ -167,7 +166,7 @@ PtrData &Mesh::createData(
name, _name, name);
}
//#rows = dimensions of current mesh #columns = dimensions of corresponding data set
PtrData data(new Data(name, id, dimension, _dimensions, withGradient));
PtrData data(new Data(name, id, dimension, _dimensions));
_data.push_back(data);
return _data.back();
}
Expand Down
3 changes: 1 addition & 2 deletions src/mesh/Mesh.hpp
Expand Up @@ -176,8 +176,7 @@ class Mesh {
/// Create only data for vertex
PtrData &createData(const std::string &name,
int dimension,
DataID id,
bool withGradient = false);
DataID id);

/// Allows access to all data
const DataContainer &data() const;
Expand Down
39 changes: 9 additions & 30 deletions src/mesh/config/DataConfiguration.cpp
Expand Up @@ -15,22 +15,16 @@ DataConfiguration::DataConfiguration(xml::XMLTag &parent)
auto attrName = XMLAttribute<std::string>(ATTR_NAME)
.setDocumentation("Unique name for the data set.");

auto attrHasGradient = makeXMLAttribute(ATTR_HAS_GRADIENT, false)
.setDocumentation(
"If this attribute is set to \"on\", the data must have gradient values");

XMLTag tagScalar(*this, VALUE_SCALAR, XMLTag::OCCUR_ARBITRARY, TAG);
tagScalar.setDocumentation("Defines a scalar data set to be assigned to meshes.");
tagScalar.addAttribute(attrName);
tagScalar.addAttribute(attrHasGradient);
parent.addSubtag(tagScalar);

XMLTag tagVector(*this, VALUE_VECTOR, XMLTag::OCCUR_ARBITRARY, TAG);
tagVector.setDocumentation("Defines a vector data set to be assigned to meshes. The number of "
"components of each data entry depends on the spatial dimensions set "
"in tag <solver-interface>.");
tagVector.addAttribute(attrName);
tagVector.addAttribute(attrHasGradient);
parent.addSubtag(tagVector);
}

Expand Down Expand Up @@ -63,10 +57,9 @@ void DataConfiguration::xmlTagCallback(
if (tag.getNamespace() == TAG) {
PRECICE_ASSERT(_dimensions != 0);
const std::string &name = tag.getStringAttributeValue(ATTR_NAME);
bool hasGradient = tag.getBooleanAttributeValue(ATTR_HAS_GRADIENT);
const std::string &typeName = tag.getName();
int dataDimensions = getDataDimensions(typeName);
addData(name, dataDimensions, hasGradient);
addData(name, dataDimensions);
} else {
PRECICE_ASSERT(false, "Received callback from an unknown tag.", tag.getName());
}
Expand All @@ -80,30 +73,16 @@ void DataConfiguration::xmlEndTagCallback(

void DataConfiguration::addData(
const std::string &name,
int dataDimensions,
bool hasGradient)
int dataDimensions)
{
if (hasGradient) {

ConfiguredData data(name, dataDimensions, hasGradient);
// Check if data with same name has been added already
for (auto &elem : _data) {
PRECICE_CHECK(elem.name != data.name,
"Data \"{0}\" has already been defined. Please rename or remove one of the data tags with name=\"{0}\".",
data.name);
}
_data.push_back(data);
} else {

// Check if data with same name has been added already
for (auto &elem : _data) {
PRECICE_CHECK(elem.name != name,
"Data \"{0}\" has already been defined. Please rename or remove one of the data tags with name=\"{0}\".",
name);
}

_data.push_back({name, dataDimensions});
// Check if data with same name has been added already
for (auto &elem : _data) {
PRECICE_CHECK(elem.name != name,
"Data \"{0}\" has already been defined. Please rename or remove one of the data tags with name=\"{0}\".",
name);
}

_data.push_back({name, dataDimensions});
}

int DataConfiguration::getDataDimensions(
Expand Down

0 comments on commit 8931247

Please sign in to comment.