31CwipiCouplingAdapter::CwipiCouplingAdapter()
33 , maxTimeStepSize_(1e30)
39 , applicationName_(
"Radioss")
40 , coupledAppName_(
"Radioss")
41 , couplingName_(
"Coupling")
42 , exchangeName_(
"Exchange")
46CwipiCouplingAdapter::~CwipiCouplingAdapter() {
52bool CwipiCouplingAdapter::configure(
const std::string& configFile) {
59 std::cout <<
"Configuring CwipiCouplingAdapter with file: " << configFile << std::endl;
60 std::ifstream file(configFile);
61 if (!file.is_open()) {
62 std::cout <<
"No " << configFile <<
" file found in the current directory" << std::endl;
63 std::cout <<
"CWIPI will not be active" << std::endl;
69 while (std::getline(file, line)) {
71 line.erase(0, line.find_first_not_of(
" \t"));
72 line.erase(line.find_last_not_of(
" \t") + 1);
74 if (line.empty() || line[0] ==
'#')
continue;
78 std::vector<std::string> parts;
79 std::istringstream iss(line);
82 while (std::getline(iss, part,
'/')) {
84 parts.push_back(part);
88 if (parts.size() >= 3 && parts[0] ==
"CWIPI") {
89 std::string key = parts[1];
90 std::string value = parts[2];
93 if (parts.size() > 3) {
94 for (
size_t i = 3; i < parts.size(); ++i) {
95 value +=
"/" + parts[i];
98 if (key ==
"APPLICATION_NAME") {
99 std::cout <<
"Setting applicationName_ to " << value << std::endl;
100 applicationName_ = value;
101 }
else if (key ==
"COUPLED_APP_NAME") {
102 std::cout <<
"Setting coupledAppName_ to " << value << std::endl;
103 coupledAppName_ = value;
104 }
else if (key ==
"COUPLING_NAME") {
105 couplingName_ = value;
106 }
else if (key ==
"EXCHANGE_NAME") {
107 std::cout <<
"Setting exchangeName_ to " << value << std::endl;
108 exchangeName_ = value;
109 }
else if (key ==
"DIMENSION") {
110 dimension_ = std::stoi(value);
111 }
else if (key ==
"TOLERANCE") {
112 tolerance_ = std::stod(value);
113 }
else if (key ==
"ORDER") {
114 order_ = std::stoi(value);
115 }
else if (key ==
"READ") {
116 DataType dataType = stringToDataType(value);
117 if (dataType == DataType::NOTHING) {
118 std::cout <<
"Warning: Unknown data type '" << value <<
"' in read configuration." << std::endl;
121 readData_[
static_cast<size_t>(dataType)].isActive =
true;
122 if (DataType::POSITIONS == dataType) {
123 readData_[
static_cast<size_t>(dataType)].mode = Mode::REPLACE;
124 }
else if (DataType::FORCES == dataType) {
125 readData_[
static_cast<size_t>(dataType)].mode = Mode::ADD;
129 }
else if (key ==
"WRITE") {
130 DataType dataType = stringToDataType(value);
131 if (dataType == DataType::NOTHING) {
132 std::cout <<
"Warning: Unknown data type '" << value <<
"' in write configuration." << std::endl;
135 writeData_[
static_cast<size_t>(dataType)].isActive =
true;
138 }
else if (key ==
"GRNOD") {
140 setGroupNodeId(std::stoi(value));
141 std::cout <<
"Setting group_node_id_ to " << value << std::endl;
143 else if (key ==
"SURF") {
145 setSurfaceId(std::stoi(value));
146 std::cout<<
" Setting surface_id_ to " << value << std::endl;
148 std::cout <<
"Warning: Unknown CWIPI configuration key '" << key <<
"'." << std::endl;
153 std::cout <<
"Initializing CWIPI with application name: " << applicationName_ << std::endl;
154 cwipi_init(
MPI_COMM_WORLD, applicationName_.c_str(), &localComm_);
156 int currentRank, localCommSize;
158 MPI_Comm_size(localComm_, &localCommSize);
159 std::cout <<
"CWIPI initialized on rank " << currentRank
160 <<
" with local communicator size: " << localCommSize << std::endl;
168void CwipiCouplingAdapter::setNodes(
const std::vector<int>& nodeIds) {
169 couplingNodeIds_ = nodeIds;
172 int bufferSize = couplingNodeIds_.size() * 3;
174 for (
size_t i = 0; i < readData_.size(); ++i) {
175 if (readData_[i].isActive) {
176 readData_[i].buffer.resize(bufferSize);
180 for (
size_t i = 0; i < writeData_.size(); ++i) {
181 if (writeData_[i].isActive) {
182 writeData_[i].buffer.resize(bufferSize);
187void CwipiCouplingAdapter::setMesh(
const int* elem_node_offsets,
const int* elem_node_indices,
int num_elements) {
188 numElements_ = num_elements;
189 eltsConnecPointer_.assign(elem_node_offsets, elem_node_offsets + num_elements + 1);
190 eltsConnec_.assign(elem_node_indices, elem_node_indices + elem_node_offsets[num_elements]);
193bool CwipiCouplingAdapter::initialize(
const double* coordinates,
int totalNodes,
int mpiRank,
int mpiSize) {
194 if (!active_)
return false;
198 std::cout <<
"Initializing CWIPI coupling adapter..." << std::endl;
200 cwipi_create_coupling(couplingName_.c_str(),
201 CWIPI_COUPLING_PARALLEL_WITH_PARTITIONING,
202 coupledAppName_.c_str(),
206 CWIPI_SOLVER_CELL_VERTEX,
212 std::vector<double> meshVertices;
213 meshVertices.reserve(couplingNodeIds_.size() * 3);
215 for (
int nodeId : couplingNodeIds_) {
217 int idx = nodeId - 1;
218 meshVertices.push_back(coordinates[idx * 3]);
219 meshVertices.push_back(coordinates[idx * 3 + 1]);
220 meshVertices.push_back(coordinates[idx * 3 + 2]);
225 std::cout <<
"Defining CWIPI mesh with linear elements." << std::endl;
229 cwipi_define_mesh(couplingName_.c_str(),
230 couplingNodeIds_.size(),
233 eltsConnecPointer_.data(),
236 std::cout <<
"Defining CWIPI mesh with higher-order elements." << std::endl;
237 cwipi_ho_define_mesh(couplingName_.c_str(),
238 couplingNodeIds_.size(),
242 eltsConnecPointer_.data(),
247 cwipi_locate(couplingName_.c_str());
248 int nNotLocated = cwipi_get_n_not_located_points(couplingName_.c_str());
249 if (nNotLocated > 0) {
250 std::cout <<
"Warning: " << nNotLocated <<
" points not located in coupling "
251 << couplingName_ << std::endl;
254 }
catch (
const std::exception& e) {
255 std::cerr <<
"Error initializing CWIPI: " << e.what() << std::endl;
262void CwipiCouplingAdapter::writeData(
const double* values,
int totalNodes,
double dt,
int dataType) {
263 if (!active_ || !initialized_)
return;
265 if (!writeData_[
static_cast<size_t>(dataType)].isActive) {
270 extractNodeData(values, totalNodes, dataType);
273 std::string fieldName = getFieldName(
static_cast<DataType
>(dataType));
274 int tag = getTag(
static_cast<DataType
>(dataType));
275 std::cout <<
"Sending data for field: " << fieldName
276 <<
" with tag: " << tag << std::endl;
277 cwipi_issend(couplingName_.c_str(),
278 exchangeName_.c_str(),
284 writeData_[dataType].buffer.data(),
285 &writeData_[dataType].sendRequest);
289 cwipi_wait_issend(couplingName_.c_str(), writeData_[dataType].sendRequest);
304void CwipiCouplingAdapter::readData(
double* values,
int totalNodes,
double dt,
int dataType) {
305 if (!active_ || !initialized_)
return;
307 if (!readData_[
static_cast<size_t>(dataType)].isActive) {
312 std::string fieldName = getFieldName(
static_cast<DataType
>(dataType));
313 int tag = getTag(
static_cast<DataType
>(dataType));
316 cwipi_irecv(couplingName_.c_str(),
317 exchangeName_.c_str(),
323 readData_[dataType].buffer.data(),
324 &readData_[dataType].recvRequest);
328 cwipi_wait_irecv(couplingName_.c_str(), readData_[dataType].recvRequest);
333 injectNodeData(values, totalNodes, dataType);
336void CwipiCouplingAdapter::advance(
double& dt) {
337 if (!active_ || !initialized_)
return;
341 cwipi_locate(couplingName_.c_str());
342 int nNotLocated = cwipi_get_n_not_located_points(couplingName_.c_str());
343 if (nNotLocated > 0) {
344 std::cout <<
"Warning: " << nNotLocated <<
" points not located in coupling "
345 << couplingName_ << std::endl;
350bool CwipiCouplingAdapter::isCouplingOngoing()
const {
351 if (!active_ || !initialized_)
353 std::cout <<
"Warning: Coupling is not active or not initialized." << std::endl;
354 std::cout<<
" active_: " << active_ <<
", initialized_: " << initialized_ << std::endl;
363bool CwipiCouplingAdapter::requiresWritingCheckpoint()
const {
367bool CwipiCouplingAdapter::requiresReadingCheckpoint()
const {
371void CwipiCouplingAdapter::finalize() {
372 if (!active_)
return;
376 std::cout <<
"Finalizing CWIPI coupling adapter..." << std::endl;
377 cwipi_delete_coupling(couplingName_.c_str());
381 initialized_ =
false;
385 couplingNodeIds_.clear();
386 eltsConnecPointer_.clear();
389 for (
auto& data : readData_) {
391 data.isActive =
false;
392 data.sendRequest = -1;
393 data.recvRequest = -1;
395 for (
auto& data : writeData_) {
397 data.isActive =
false;
398 data.sendRequest = -1;
399 data.recvRequest = -1;
406bool CwipiCouplingAdapter::isActive()
const {
410double CwipiCouplingAdapter::getMaxTimeStepSize()
const {
411 return maxTimeStepSize_;
414int CwipiCouplingAdapter::getNumberOfCouplingNodes()
const {
415 return couplingNodeIds_.size();
418void CwipiCouplingAdapter::extractNodeData(
const double* globalValues,
int totalNodes,
int dataType) {
419 if (!writeData_[dataType].isActive) {
423 for (
size_t i = 0; i < couplingNodeIds_.size(); ++i) {
424 int nodeId = couplingNodeIds_[i] - 1;
425 writeData_[dataType].buffer[i * 3] = globalValues[nodeId * 3];
426 writeData_[dataType].buffer[i * 3 + 1] = globalValues[nodeId * 3 + 1];
427 writeData_[dataType].buffer[i * 3 + 2] = globalValues[nodeId * 3 + 2];
431void CwipiCouplingAdapter::injectNodeData(
double* globalValues,
int totalNodes,
int dataType) {
432 if (!readData_[dataType].isActive) {
433 std::cout <<
"Warning: Attempted to read data for inactive data type "
434 << getFieldName(
static_cast<DataType
>(dataType)) << std::endl;
438 if (readData_[dataType].mode == Mode::ADD) {
439 for (
size_t i = 0; i < couplingNodeIds_.size(); ++i) {
440 int nodeId = couplingNodeIds_[i] - 1;
441 globalValues[nodeId * 3] += readData_[dataType].buffer[i * 3];
442 globalValues[nodeId * 3 + 1] += readData_[dataType].buffer[i * 3 + 1];
443 globalValues[nodeId * 3 + 2] += readData_[dataType].buffer[i * 3 + 2];
445 }
else if (readData_[dataType].mode == Mode::REPLACE) {
446 for (
size_t i = 0; i < couplingNodeIds_.size(); ++i) {
447 int nodeId = couplingNodeIds_[i] - 1;
448 globalValues[nodeId * 3] = readData_[dataType].buffer[i * 3];
449 globalValues[nodeId * 3 + 1] = readData_[dataType].buffer[i * 3 + 1];
450 globalValues[nodeId * 3 + 2] = readData_[dataType].buffer[i * 3 + 2];
456std::string CwipiCouplingAdapter::getFieldName(DataType type) {
458 case DataType::POSITIONS:
return "positions";
459 case DataType::FORCES:
return "forces";
460 case DataType::DISPLACEMENTS:
return "displacements";
461 default:
return "unknown";
465int CwipiCouplingAdapter::getTag(DataType type) {
466 return static_cast<int>(type);
LIBSEQ_INT LIBSEQ_CALL MPI_Comm_rank(LIBSEQ_INT comm, LIBSEQ_INT *rank)
static MPI_Comm MPI_COMM_WORLD