Skip to content
Merged
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
6 changes: 6 additions & 0 deletions cyprecice/Participant.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ cdef extern from "precice/precice.hpp" namespace "precice":

void readData (const string& meshName, const string& dataName, vector[int] vertices, const double relativeReadTime, vector[double]& values) except +

# Just-in-time mapping

void writeAndMapData (const string& meshName, const string& dataName, vector[double] coordinates, vector[double] values) except +

void mapAndReadData (const string& meshName, const string& dataName, vector[double] coordinates, double relativeReadTime, vector[double]& values) except +

# direct access

void setMeshAccessRegion (const string& meshName, vector[double] boundingBox) except +
Expand Down
109 changes: 108 additions & 1 deletion cyprecice/cyprecice.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -830,7 +830,7 @@ cdef class Participant:
mesh_name : str
Name of the mesh to write to.
data_name : str
ID to read from.
Name of the data to read from.
vertex_ids : array_like
Indices of the vertices.
relative_read_time : double
Expand Down Expand Up @@ -903,6 +903,113 @@ cdef class Participant:
else:
return np_values.reshape((size, dimensions))

def write_and_map_data (self, mesh_name, data_name, coordinates, values):
"""
This function writes values at temporary locations to data of a mesh.
As opposed to the writeData function using VertexIDs, this function allows to write data via coordinates,
which don't have to be specified during the initialization. This is particularly useful for meshes, which
vary over time. Note that using this function comes at a performance cost, since the specified mapping
needs to be computed locally for the given locations, whereas the other variant (writeData) can typically
exploit the static interface mesh and pre-compute data structures more efficiently.

Values are passed identically to write_data.

Parameters
----------
mesh_name : str
name of the mesh to write to.
data_name : str
Data name to write to.
coordinates : array_like
The coordinates of the vertices in a numpy array [N x D] where
N = number of vertices and D = dimensions of geometry.
values : array_like
Values of data

Examples
--------
Write scalar data for a 2D problem with 5 vertices:
>>> mesh_name = "MeshOne"
>>> data_name = "DataOne"
>>> coordinates = np.array([[c1_x, c1_y], [c2_x, c2_y], [c3_x, c3_y], [c4_x, c4_y], [c5_x, c5_y]])
>>> values = np.array([v1, v2, v3, v4, v5])
>>> participant.write_and_map_data(mesh_name, data_name, coordinates, values)
"""

check_array_like(coordinates, "coordinates", "write_and_map_data")
check_array_like(values, "values", "write_and_map_data")

if not isinstance(coordinates, np.ndarray):
coordinates = np.asarray(coordinates)

if not isinstance(values, np.ndarray):
values = np.asarray(values)

cdef vector[double] cpp_coordinates = coordinates.flatten()
cdef vector[double] cpp_values = values.flatten()

self.thisptr.writeAndMapData (convert(mesh_name), convert(data_name), cpp_coordinates, cpp_values)

def map_and_read_data (self, mesh_name, data_name, coordinates, relative_read_time):
"""
This function reads values at temporary locations from data of a mesh.
As opposed to the readData function using VertexIDs, this function allows reading data via coordinates,
which don't have to be specified during the initialization. This is particularly useful for meshes, which
vary over time. Note that using this function comes at a performance cost, since the specified mapping
needs to be computed locally for the given locations, whereas the other variant (readData) can typically
exploit the static interface mesh and pre-compute data structures more efficient.

Values are read identically to read_data.

Parameters
----------
mesh_name : str
Name of the mesh to write to.
data_name : str
Name of the data to read from.
coordinates : array_like
Coordinates of the vertices.
relative_read_time : double
Point in time where data is read relative to the beginning of the current time step

Returns
-------
values : numpy.ndarray
Contains the read data.

Examples
--------
Read scalar data for a 2D problem with 2 vertices:
>>> mesh_name = "MeshOne"
>>> data_name = "DataOne"
>>> coordinates = [(1.0, 1.0), (2.0, 2.0)]
>>> dt = 1.0
>>> values = map_and_read_data(mesh_name, data_name, coordinates, dt)
>>> values.shape
>>> (2, )
"""

check_array_like(coordinates, "coordinates", "map_and_read_data")

if not isinstance(coordinates, np.ndarray):
coordinates = np.asarray(coordinates)

size = coordinates.shape[0]
dimensions = self.get_data_dimensions(mesh_name, data_name)

cdef vector[double] cpp_coordinates = coordinates
cdef vector[double] cpp_values = [-1 for _ in range(size * dimensions)]

self.thisptr.mapAndReadData (convert(mesh_name), convert(data_name), cpp_coordinates, relative_read_time, cpp_values)

cdef np.ndarray[double, ndim=1] np_values = np.array(cpp_values, dtype=np.double)

if len(coordinates) == 0:
return np_values.reshape((size))
elif self.get_data_dimensions(mesh_name, data_name) == 1:
return np_values.reshape((size))
else:
return np_values.reshape((size, dimensions))

def write_gradient_data (self, mesh_name, data_name, vertex_ids, gradients):
"""
Expand Down
25 changes: 25 additions & 0 deletions test/Participant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,31 @@ void Participant:: readData
}
}

void Participant:: writeAndMapData
(
precice::string_view meshName,
precice::string_view dataName,
precice::span<const double> coordinates,
precice::span<const double> values)
{
fake_read_write_buffer.clear();

for(const double value: values) {
fake_read_write_buffer.push_back(value);
}
}

void Participant:: mapAndReadData
(
precice::string_view meshName,
precice::string_view dataName,
precice::span<const double> coordinates,
double relativeReadTime,
precice::span<double> values) const
{
std::copy(fake_read_write_buffer.begin(), fake_read_write_buffer.end(), values.begin());
}

void Participant:: setMeshAccessRegion
(
precice::string_view meshName,
Expand Down
8 changes: 8 additions & 0 deletions test/test_bindings_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,14 @@ def test_read_write_vector_data_non_contiguous(self):
read_data = participant.read_data("FakeMesh", "FakeVectorData", [0], dt)
self.assertTrue(np.array_equal(write_data, read_data))

def test_jit_mapping(self):
participant = precice.Participant("test", "dummy.xml", 0, 1)
write_data = [1, 2, 3]
participant.write_and_map_data("FakeMesh", "FakeScalarData", [0, 1, 2], write_data)
dt = 1
read_data = participant.map_and_read_data("FakeMesh", "FakeScalarData", [0, 1, 2], dt)
self.assertTrue(np.array_equal(write_data, read_data))

def test_get_version_information(self):
version_info = precice.get_version_information()
fake_version_info = b"dummy" # compare to test/SolverInterface.cpp
Expand Down