35PreciceCouplingAdapter::PreciceCouplingAdapter()
37 , maxTimeStepSize_(0.0)
42PreciceCouplingAdapter::~PreciceCouplingAdapter() {
48bool PreciceCouplingAdapter::configure(
const std::string& configFile) {
56 std::ifstream file(configFile);
57 if (!file.is_open()) {
58 std::cout <<
"No " << configFile <<
" file found in the current directory" << std::endl;
59 std::cout <<
"preCICE will not be active" << std::endl;
65 while (std::getline(file, line)) {
67 line.erase(0, line.find_first_not_of(
" \t"));
68 line.erase(line.find_last_not_of(
" \t") + 1);
70 if (line.empty() || line[0] ==
'#')
continue;
73 std::vector<std::string> parts;
74 std::istringstream iss(line);
77 while (std::getline(iss, part,
'/')) {
79 parts.push_back(part);
84 if (parts.size() >= 3 && parts[0] ==
"PRECICE") {
85 const auto& key = parts[1];
86 auto value = parts[2];
89 if (parts.size() > 3) {
90 for (
size_t i = 3; i < parts.size(); ++i) {
91 value +=
"/" + parts[i];
95 if (key ==
"PARTICIPANT_NAME") {
96 participantName_ = value;
97 }
else if (key ==
"CONFIG_FILE") {
99 }
else if (key ==
"MESH_NAME") {
101 }
else if (key ==
"READ") {
102 const auto dataType = stringToDataType(value);
103 if (dataType == DataType::NOTHING) {
104 std::cout <<
"Warning: Unknown data type '" << value <<
"' in read configuration." << std::endl;
107 readData_[
static_cast<size_t>(dataType)].isActive =
true;
108 if (DataType::POSITIONS == dataType) {
109 readData_[
static_cast<size_t>(dataType)].mode = Mode::REPLACE;
110 }
else if (DataType::FORCES == dataType) {
111 readData_[
static_cast<size_t>(dataType)].mode = Mode::ADD;
112 }
else if (DataType::DISPLACEMENTS == dataType) {
113 readData_[
static_cast<size_t>(dataType)].mode = Mode::REPLACE;
115 }
else if (key ==
"WRITE") {
116 const auto dataType = stringToDataType(value);
117 if (dataType == DataType::NOTHING) {
118 std::cout <<
"Warning: Unknown data type '" << value <<
"' in write configuration." << std::endl;
121 writeData_[
static_cast<size_t>(dataType)].isActive =
true;
122 }
else if (key ==
"GRNOD") {
124 setGroupNodeId(std::stoi(value));
125 }
catch (
const std::exception& e) {
126 std::cout <<
"Warning: Invalid GRNOD value '" << value <<
"': " << e.what() << std::endl;
130 std::cout <<
"Warning: Ignoring malformed line: " << line << std::endl;
138void PreciceCouplingAdapter::setNodes(
const std::vector<int>& nodeIds) {
139 couplingNodeIds_ = nodeIds;
142 constexpr auto dimensions = getDimensions();
143 const auto bufferSize = couplingNodeIds_.size() * dimensions;
144 vertexIds_.resize(couplingNodeIds_.size());
147 for (
auto& data : readData_) {
149 data.buffer.resize(bufferSize);
154 for (
auto& data : writeData_) {
156 data.buffer.resize(bufferSize);
161bool PreciceCouplingAdapter::initialize(
const double* coordinates,
int totalNodes,
int mpiRank,
int mpiSize) {
162 if (!active_)
return false;
164 std::cerr <<
"Error: coordinates pointer is null" << std::endl;
167 if (totalNodes <= 0) {
168 std::cerr <<
"Error: totalNodes must be positive, got " << totalNodes << std::endl;
174 precice_ = std::make_unique<precice::Participant>(participantName_, configFile_, mpiRank, mpiSize);
177 std::vector<double> meshVertices;
178 meshVertices.reserve(couplingNodeIds_.size() * 3);
180 for (
const auto nodeId : couplingNodeIds_) {
181 if (!isNodeIdValid(nodeId, totalNodes)) {
182 std::cerr <<
"Error: Node ID " << nodeId <<
" out of bounds [1, " << totalNodes <<
"]" << std::endl;
186 const auto idx = nodeId - 1;
187 constexpr auto dimensions = getDimensions();
188 meshVertices.push_back(coordinates[idx * dimensions]);
189 meshVertices.push_back(coordinates[idx * dimensions + 1]);
190 meshVertices.push_back(coordinates[idx * dimensions + 2]);
194 precice_->setMeshVertices(meshName_, meshVertices, vertexIds_);
197 if (precice_->requiresInitialData()) {
198 for (
size_t i = 0; i < writeData_.size(); ++i) {
199 if (writeData_[i].isActive) {
200 const auto& dataName = dataTypeToString(
static_cast<DataType
>(i));
201 precice_->writeData(meshName_, dataName, vertexIds_, writeData_[i].buffer);
207 precice_->initialize();
208 maxTimeStepSize_ = precice_->getMaxTimeStepSize();
210 }
catch (
const std::exception& e) {
211 std::cerr <<
"Error initializing preCICE: " << e.what() << std::endl;
218void PreciceCouplingAdapter::writeData(
const double* values,
int totalNodes,
double dt,
int dataType) {
219 if (!active_)
return;
220 if (!precice_)
return;
221 if (!precice_->isCouplingOngoing())
return;
223 std::cerr <<
"Error: values pointer is null in writeData" << std::endl;
227 const auto& writeDataName = dataTypeToString(
static_cast<DataType
>(dataType));
228 if (!writeData_[
static_cast<size_t>(dataType)].isActive) {
233 extractNodeData(values, totalNodes, dataType);
234 precice_->writeData(meshName_, writeDataName, vertexIds_, writeData_[dataType].buffer);
237void PreciceCouplingAdapter::readData(
double* values,
int totalNodes,
double dt,
int dataType) {
238 if (!active_)
return;
239 if (!precice_)
return;
240 if (!precice_->isCouplingOngoing())
return;
242 std::cerr <<
"Error: values pointer is null in readData" << std::endl;
246 const auto& readDataName = dataTypeToString(
static_cast<DataType
>(dataType));
247 if (!readData_[
static_cast<size_t>(dataType)].isActive) {
251 const auto maxTimeStepSize = precice_->getMaxTimeStepSize();
252 const auto cdt = std::min(dt, maxTimeStepSize);
255 precice_->readData(meshName_, readDataName, vertexIds_, cdt, readData_[dataType].buffer);
258 injectNodeData(values, totalNodes, dataType);
261void PreciceCouplingAdapter::advance(
double& dt) {
262 if (!active_)
return;
263 if (!precice_)
return;
264 if (!precice_->isCouplingOngoing())
return;
266 const auto dtToUse = std::min(dt, maxTimeStepSize_);
269 precice_->advance(dtToUse);
272 maxTimeStepSize_ = precice_->getMaxTimeStepSize();
276bool PreciceCouplingAdapter::isCouplingOngoing()
const {
277 if (!active_)
return false;
278 if (!precice_)
return false;
279 return precice_->isCouplingOngoing();
282bool PreciceCouplingAdapter::requiresWritingCheckpoint()
const {
283 if (!active_)
return false;
284 if (!precice_)
return false;
285 return precice_->requiresWritingCheckpoint();
288bool PreciceCouplingAdapter::requiresReadingCheckpoint()
const {
289 if (!active_)
return false;
290 if (!precice_)
return false;
291 return precice_->requiresReadingCheckpoint();
294void PreciceCouplingAdapter::finalize() {
295 if (!active_)
return;
298 precice_->finalize();
303 couplingNodeIds_.clear();
305 for (
auto& data : readData_) {
307 data.isActive =
false;
309 for (
auto& data : writeData_) {
311 data.isActive =
false;
317bool PreciceCouplingAdapter::isActive()
const {
321double PreciceCouplingAdapter::getMaxTimeStepSize()
const {
322 return maxTimeStepSize_;
325int PreciceCouplingAdapter::getNumberOfCouplingNodes()
const {
326 return static_cast<int>(couplingNodeIds_.size());
329void PreciceCouplingAdapter::extractNodeData(
const double* globalValues,
int totalNodes,
int dataType) {
330 if (!writeData_[dataType].isActive) {
334 constexpr auto dimensions = getDimensions();
335 for (
size_t i = 0; i < couplingNodeIds_.size(); ++i) {
336 const auto nodeId = couplingNodeIds_[i];
337 if (!isNodeIdValid(nodeId, totalNodes)) {
338 std::cerr <<
"Error: Node ID " << nodeId <<
" out of bounds in extractNodeData" << std::endl;
341 const auto idx = nodeId - 1;
342 writeData_[dataType].buffer[i * dimensions] = globalValues[idx * dimensions];
343 writeData_[dataType].buffer[i * dimensions + 1] = globalValues[idx * dimensions + 1];
344 writeData_[dataType].buffer[i * dimensions + 2] = globalValues[idx * dimensions + 2];
348void PreciceCouplingAdapter::injectNodeData(
double* globalValues,
int totalNodes,
int dataType) {
349 if (!readData_[dataType].isActive) {
352 if (readData_[dataType].mode == Mode::ADD) {
353 for (
size_t i = 0; i < couplingNodeIds_.size(); ++i) {
354 int nodeId = couplingNodeIds_[i] - 1;
355 globalValues[nodeId * 3] += readData_[dataType].buffer[i * 3];
356 globalValues[nodeId * 3 + 1] += readData_[dataType].buffer[i * 3 + 1];
357 globalValues[nodeId * 3 + 2] += readData_[dataType].buffer[i * 3 + 2];
359 }
else if (readData_[dataType].mode == Mode::REPLACE) {
360 for (
size_t i = 0; i < couplingNodeIds_.size(); ++i) {
361 int nodeId = couplingNodeIds_[i] - 1;
362 globalValues[nodeId * 3] = readData_[dataType].buffer[i * 3];
363 globalValues[nodeId * 3 + 1] = readData_[dataType].buffer[i * 3 + 1];
364 globalValues[nodeId * 3 + 2] = readData_[dataType].buffer[i * 3 + 2];
367 std::cout <<
"Warning: Unknown mode for data type " << dataTypeToString(
static_cast<DataType
>(dataType))
368 <<
", skipping injection." << std::endl;