Skip to content

Commit aac9182

Browse files
Variable Robin boundary condition and generic boundary condition class (SimVascular#437)
* Initial implementation and test case. Works with 1 processor, but fails with multiple processors. Other improvements to make * Put debugging statements inside debugging blocks * Add spatially_variable_robin test to pytest suite * Rename to VariableRobinBCData, initial VariableRobinBCData once, instead of at every Newton iteration * Add copyright statement * Renamed to RobinBC, partial implementation of parallelization * Refactored distribute method to use gatherv and scatterv. Dealing with some compilation issues now. * Passes test in parallel, fails with index error with 1 proc * Fixed bug, now passes test in serial * clean up debugging statements to make code more readable * Refactor vtp file reading to accept vector of array names, more generic this way * Split implementation into a BC base class and a RobinBC derived class * Update README.md and add ustruct test case. ustruct result is fairly different from struct result, so could not use result_002.vtu from the struct case * Refactor BC class to improve error handling and code clarity. Introduced custom exception classes for VTP file errors and node count mismatches. Updated point matching logic to use squared distance for efficiency. Removed redundant map clearing operations during initialization. Also, put test cases number of timesteps back to 2 * Rename BC and RobinBC classes as BoundaryCondition and RobinBoundaryCondition classes. * Clean up constructors * Remove extraneous comments and debugging statements * Reformat code * Move flag to apply in normal direction only inside RobinBoundaryCondition. Add generic flag handling in BoundaryCondition * Split up distribute method into smaller functions * Add copyrights * Implement copy-and-swap idiom, add noexcept to appropriate methods * Catch exceptions in constructors * Move generate_load.py and generate_spatially_variable_robin.py into utilities/generate_boundary_condition_data/ directory, and update READMEs to reflect new location * Initialize members with default values and use default default constructor * Remove defined_ flag, just check if arrays are allocated, add new exception classes
1 parent 949d1a6 commit aac9182

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+2110
-100
lines changed

Code/Source/solver/BoundaryCondition.cpp

Lines changed: 509 additions & 0 deletions
Large diffs are not rendered by default.

Code/Source/solver/BoundaryCondition.h

Lines changed: 340 additions & 0 deletions
Large diffs are not rendered by default.

Code/Source/solver/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,9 @@ set(CSRCS
224224
SPLIT.c
225225

226226
svZeroD_interface/LPNSolverInterface.h svZeroD_interface/LPNSolverInterface.cpp
227+
228+
BoundaryCondition.h BoundaryCondition.cpp
229+
RobinBoundaryCondition.h RobinBoundaryCondition.cpp
227230
)
228231

229232
# Set PETSc interace code.

Code/Source/solver/CmMod.cpp

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,4 +163,84 @@ void cmType::bcast(const CmMod& cm_mod, int* data) const
163163
void cmType::bcast(const CmMod& cm_mod, Vector<int>& data) const
164164
{
165165
MPI_Bcast(data.data(), data.size(), cm_mod::mpint, cm_mod.master, com());
166+
}
167+
168+
/// @brief gather int array
169+
void cmType::gather(const CmMod& cm_mod, const int* send_data, int send_count, int* recv_data, int recv_count, int root) const
170+
{
171+
MPI_Gather(send_data, send_count, cm_mod::mpint, recv_data, recv_count, cm_mod::mpint, root, com());
172+
}
173+
174+
/// @brief gather double array
175+
void cmType::gather(const CmMod& cm_mod, const double* send_data, int send_count, double* recv_data, int recv_count, int root) const
176+
{
177+
MPI_Gather(send_data, send_count, cm_mod::mpreal, recv_data, recv_count, cm_mod::mpreal, root, com());
178+
}
179+
180+
/// @brief gather int Vector
181+
void cmType::gather(const CmMod& cm_mod, const Vector<int>& send_data, Vector<int>& recv_data, int root) const
182+
{
183+
MPI_Gather(send_data.data(), send_data.size(), cm_mod::mpint,
184+
recv_data.data(), send_data.size(), cm_mod::mpint, root, com());
185+
}
186+
187+
/// @brief gather double Vector
188+
void cmType::gather(const CmMod& cm_mod, const Vector<double>& send_data, Vector<double>& recv_data, int root) const
189+
{
190+
MPI_Gather(send_data.data(), send_data.size(), cm_mod::mpreal,
191+
recv_data.data(), send_data.size(), cm_mod::mpreal, root, com());
192+
}
193+
194+
/// @brief scatter int array
195+
void cmType::scatter(const CmMod& cm_mod, const int* send_data, int send_count, int* recv_data, int recv_count, int root) const
196+
{
197+
MPI_Scatter(send_data, send_count, cm_mod::mpint, recv_data, recv_count, cm_mod::mpint, root, com());
198+
}
199+
200+
/// @brief scatter double array
201+
void cmType::scatter(const CmMod& cm_mod, const double* send_data, int send_count, double* recv_data, int recv_count, int root) const
202+
{
203+
MPI_Scatter(send_data, send_count, cm_mod::mpreal, recv_data, recv_count, cm_mod::mpreal, root, com());
204+
}
205+
206+
/// @brief scatter int Vector
207+
void cmType::scatter(const CmMod& cm_mod, const Vector<int>& send_data, Vector<int>& recv_data, int root) const
208+
{
209+
MPI_Scatter(send_data.data(), send_data.size() / nProcs, cm_mod::mpint,
210+
recv_data.data(), send_data.size() / nProcs, cm_mod::mpint, root, com());
211+
}
212+
213+
/// @brief scatter double Vector
214+
void cmType::scatter(const CmMod& cm_mod, const Vector<double>& send_data, Vector<double>& recv_data, int root) const
215+
{
216+
MPI_Scatter(send_data.data(), send_data.size() / nProcs, cm_mod::mpreal,
217+
recv_data.data(), send_data.size() / nProcs, cm_mod::mpreal, root, com());
218+
}
219+
220+
/// @brief gatherv int Vector
221+
void cmType::gatherv(const CmMod& cm_mod, const Vector<int>& send_data, Vector<int>& recv_data, const Vector<int>& recv_counts, const Vector<int>& displs, int root) const
222+
{
223+
MPI_Gatherv(send_data.data(), send_data.size(), cm_mod::mpint,
224+
recv_data.data(), recv_counts.data(), displs.data(), cm_mod::mpint, root, com());
225+
}
226+
227+
/// @brief gatherv double Vector
228+
void cmType::gatherv(const CmMod& cm_mod, const Vector<double>& send_data, Vector<double>& recv_data, const Vector<int>& recv_counts, const Vector<int>& displs, int root) const
229+
{
230+
MPI_Gatherv(send_data.data(), send_data.size(), cm_mod::mpreal,
231+
recv_data.data(), recv_counts.data(), displs.data(), cm_mod::mpreal, root, com());
232+
}
233+
234+
/// @brief scatterv int Vector
235+
void cmType::scatterv(const CmMod& cm_mod, const Vector<int>& send_data, const Vector<int>& send_counts, const Vector<int>& displs, Vector<int>& recv_data, int root) const
236+
{
237+
MPI_Scatterv(send_data.data(), send_counts.data(), displs.data(), cm_mod::mpint,
238+
recv_data.data(), recv_data.size(), cm_mod::mpint, root, com());
239+
}
240+
241+
/// @brief scatterv double Vector
242+
void cmType::scatterv(const CmMod& cm_mod, const Vector<double>& send_data, const Vector<int>& send_counts, const Vector<int>& displs, Vector<double>& recv_data, int root) const
243+
{
244+
MPI_Scatterv(send_data.data(), send_counts.data(), displs.data(), cm_mod::mpreal,
245+
recv_data.data(), recv_data.size(), cm_mod::mpreal, root, com());
166246
}

Code/Source/solver/CmMod.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,26 @@ class cmType {
112112

113113
void bcast(const CmMod& cm_mod, Array<int>& data, const std::string& name="") const;
114114

115+
// Gather operations
116+
void gather(const CmMod& cm_mod, const int* send_data, int send_count, int* recv_data, int recv_count, int root) const;
117+
void gather(const CmMod& cm_mod, const double* send_data, int send_count, double* recv_data, int recv_count, int root) const;
118+
void gather(const CmMod& cm_mod, const Vector<int>& send_data, Vector<int>& recv_data, int root) const;
119+
void gather(const CmMod& cm_mod, const Vector<double>& send_data, Vector<double>& recv_data, int root) const;
120+
121+
// Gatherv operations
122+
void gatherv(const CmMod& cm_mod, const Vector<int>& send_data, Vector<int>& recv_data, const Vector<int>& recv_counts, const Vector<int>& displs, int root) const;
123+
void gatherv(const CmMod& cm_mod, const Vector<double>& send_data, Vector<double>& recv_data, const Vector<int>& recv_counts, const Vector<int>& displs, int root) const;
124+
125+
// Scatterv operations
126+
void scatterv(const CmMod& cm_mod, const Vector<int>& send_data, const Vector<int>& send_counts, const Vector<int>& displs, Vector<int>& recv_data, int root) const;
127+
void scatterv(const CmMod& cm_mod, const Vector<double>& send_data, const Vector<int>& send_counts, const Vector<int>& displs, Vector<double>& recv_data, int root) const;
128+
129+
// Scatter operations
130+
void scatter(const CmMod& cm_mod, const int* send_data, int send_count, int* recv_data, int recv_count, int root) const;
131+
void scatter(const CmMod& cm_mod, const double* send_data, int send_count, double* recv_data, int recv_count, int root) const;
132+
void scatter(const CmMod& cm_mod, const Vector<int>& send_data, Vector<int>& recv_data, int root) const;
133+
void scatter(const CmMod& cm_mod, const Vector<double>& send_data, Vector<double>& recv_data, int root) const;
134+
115135
//------------
116136
// bcast_enum
117137
//------------

Code/Source/solver/ComMod.h

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include "ChnlMod.h"
4444
#include "CmMod.h"
4545
#include "Parameters.h"
46+
#include "RobinBoundaryCondition.h"
4647
#include "Timer.h"
4748
#include "Vector.h"
4849

@@ -58,6 +59,7 @@
5859

5960
#include <array>
6061
#include <iostream>
62+
#include <memory>
6163
#include <string>
6264
#include <vector>
6365
#include <fstream>
@@ -150,17 +152,13 @@ class rcrType
150152
class bcType
151153
{
152154
public:
153-
154155
// Strong/Weak application of Dirichlet BC
155156
bool weakDir = false;
156157

157158
// Whether load vector changes with deformation
158159
// (Neu - struct/ustruct only)
159160
bool flwP = false;
160161

161-
// Robin: apply only in normal direction
162-
bool rbnN = false;
163-
164162
// Strong/Weak application of Dirichlet BC
165163
int clsFlgRis = 0;
166164

@@ -191,11 +189,8 @@ class bcType
191189
// Neu: defined resistance
192190
double r = 0.0;
193191

194-
// Robin: stiffness
195-
double k = 0.0;
196-
197-
// Robin: damping
198-
double c = 0.0;
192+
// Robin: VTP file path for per-node stiffness and damping
193+
std::string robin_vtp_file = "";
199194

200195
// RIS0D: resistance
201196
double resistance = 0.0;
@@ -227,6 +222,9 @@ class bcType
227222

228223
// Neu: RCR
229224
rcrType RCR;
225+
226+
// Robin BC class
227+
RobinBoundaryCondition robin_bc;
230228
};
231229

232230
/// @brief Class storing data for B-Splines.

Code/Source/solver/Parameters.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,7 @@ BoundaryConditionParameters::BoundaryConditionParameters()
443443
set_parameter("Spatial_profile_file_path", "", !required, spatial_profile_file_path);
444444
set_parameter("Spatial_values_file_path", "", !required, spatial_values_file_path);
445445
set_parameter("Stiffness", 1.0, !required, stiffness);
446+
set_parameter("Robin_vtp_file_path", "", !required, robin_vtp_file_path);
446447
set_parameter("svZeroDSolver_block", "", !required, svzerod_solver_block);
447448

448449
set_parameter("Temporal_and_spatial_values_file_path", "", !required, temporal_and_spatial_values_file_path);

Code/Source/solver/Parameters.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -806,6 +806,7 @@ class BoundaryConditionParameters : public ParameterLists
806806
Parameter<std::string> spatial_profile_file_path;
807807
Parameter<std::string> spatial_values_file_path;
808808
Parameter<double> stiffness;
809+
Parameter<std::string> robin_vtp_file_path;
809810
Parameter<std::string> svzerod_solver_block;
810811

811812
Parameter<std::string> temporal_and_spatial_values_file_path;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/* Copyright (c) Stanford University, The Regents of the University of California, and others.
2+
*
3+
* All Rights Reserved.
4+
*
5+
* See Copyright-SimVascular.txt for additional details.
6+
*
7+
* Permission is hereby granted, free of charge, to any person obtaining
8+
* a copy of this software and associated documentation files (the
9+
* "Software"), to deal in the Software without restriction, including
10+
* without limitation the rights to use, copy, modify, merge, publish,
11+
* distribute, sublicense, and/or sell copies of the Software, and to
12+
* permit persons to whom the Software is furnished to do so, subject
13+
* to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included
16+
* in all copies or substantial portions of the Software.
17+
*
18+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
19+
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20+
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
21+
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
22+
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23+
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24+
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25+
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26+
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27+
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28+
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29+
*/
30+
31+
#include "RobinBoundaryCondition.h"
32+
33+
#define n_debug_robin_bc
34+
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/* Copyright (c) Stanford University, The Regents of the University of California, and others.
2+
*
3+
* All Rights Reserved.
4+
*
5+
* See Copyright-SimVascular.txt for additional details.
6+
*
7+
* Permission is hereby granted, free of charge, to any person obtaining
8+
* a copy of this software and associated documentation files (the
9+
* "Software"), to deal in the Software without restriction, including
10+
* without limitation the rights to use, copy, modify, merge, publish,
11+
* distribute, sublicense, and/or sell copies of the Software, and to
12+
* permit persons to whom the Software is furnished to do so, subject
13+
* to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included
16+
* in all copies or substantial portions of the Software.
17+
*
18+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
19+
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20+
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
21+
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
22+
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23+
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24+
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25+
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26+
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27+
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28+
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29+
*/
30+
31+
#ifndef ROBIN_BOUNDARY_CONDITION_H
32+
#define ROBIN_BOUNDARY_CONDITION_H
33+
34+
#include "BoundaryCondition.h"
35+
#include <string>
36+
#include <map>
37+
#include <vector>
38+
39+
/// @brief Class to handle Robin boundary condition with potentially spatially variable arrays
40+
///
41+
/// This class extends the generic BoundaryCondition class to handle Robin boundary conditions, which require
42+
/// stiffness and damping arrays. While it supports any number of named arrays through its base class,
43+
/// it provides specific validation and convenience methods for stiffness and damping values.
44+
///
45+
/// Example usage:
46+
/// ```cpp
47+
/// // Read multiple arrays from VTP file
48+
/// std::vector<std::string> array_names = {"Stiffness", "Damping"};
49+
/// RobinBoundaryCondition bc(vtp_file_path, array_names, face);
50+
///
51+
/// // Access values
52+
/// double stiffness = bc.get_stiffness(node_id); // Convenience method
53+
/// double damping = bc.get_damping(node_id); // Convenience method
54+
///
55+
/// // Create with uniform values
56+
/// std::map<std::string, double> uniform_values = {
57+
/// {"Stiffness", 1.0},
58+
/// {"Damping", 0.5},
59+
/// };
60+
/// RobinBoundaryCondition bc(uniform_values, face);
61+
/// ```
62+
63+
#define debug_robin_bc
64+
class RobinBoundaryCondition : public BoundaryCondition {
65+
public:
66+
/// @brief Default constructor - creates an empty RobinBoundaryCondition
67+
RobinBoundaryCondition() : BoundaryCondition() {}
68+
69+
/// @brief Constructor - reads stiffness and damping from VTP file
70+
/// @param vtp_file_path Path to VTP file containing Stiffness and Damping point arrays
71+
/// @param normal_only Flag to apply only along normal direction
72+
/// @param face Face associated with the Robin BC
73+
/// @throws BoundaryConditionFileException if file cannot be read
74+
/// @throws BoundaryConditionVtpArrayException if arrays are missing
75+
/// @throws BoundaryConditionValidationException if values are invalid
76+
RobinBoundaryCondition(const std::string& vtp_file_path, bool normal_only, const faceType& face)
77+
: BoundaryCondition(vtp_file_path, std::vector<std::string>{"Stiffness", "Damping"}, StringBoolMap{{"normal_direction_only", normal_only}}, face) {}
78+
79+
80+
/// @brief Constructor for uniform values
81+
/// @param uniform_stiffness Uniform stiffness value for all nodes
82+
/// @param uniform_damping Uniform damping value for all nodes
83+
/// @param normal_only Flag to apply only along normal direction
84+
/// @param face Face associated with the Robin BC
85+
/// @throws BoundaryConditionValidationException if values are invalid
86+
RobinBoundaryCondition(double uniform_stiffness, double uniform_damping, bool normal_only, const faceType& face)
87+
: BoundaryCondition({{"Stiffness", uniform_stiffness}, {"Damping", uniform_damping}}, StringBoolMap{{"normal_direction_only", normal_only}}, face) {}
88+
89+
/// @brief Apply only along normal direction (getter)
90+
/// @return true if BC should be applied only along normal direction
91+
/// @throws BoundaryConditionFlagException if "normal_direction_only" flag not found
92+
bool normal_direction_only() const { return this->get_flag("normal_direction_only"); }
93+
94+
/// @brief Get stiffness value for a specific node (convenience method)
95+
/// @param node_id Node index on the face
96+
/// @return Stiffness value for the node
97+
/// @throws BoundaryConditionArrayException if "Stiffness" array not found
98+
/// @throws BoundaryConditionNodeIdException if node_id is out of range
99+
double get_stiffness(int node_id) const {
100+
return get_value("Stiffness", node_id);
101+
}
102+
103+
/// @brief Get damping value for a specific node (convenience method)
104+
/// @param node_id Node index on the face
105+
/// @return Damping value for the node
106+
/// @throws BoundaryConditionArrayException if "Damping" array not found
107+
/// @throws BoundaryConditionNodeIdException if node_id is out of range
108+
double get_damping(int node_id) const {
109+
return get_value("Damping", node_id);
110+
}
111+
112+
/// @brief Assemble the Robin BC into the global residual vector and stiffness matrix
113+
/// Currently not implemented
114+
/// @return 0
115+
double assemble() const { return 0; }
116+
117+
protected:
118+
/// @brief Validate array values for Robin BC
119+
/// @param array_name Name of the array being validated
120+
/// @param value Value to validate
121+
/// @throws BoundaryConditionValidationException if validation fails
122+
void validate_array_value(const std::string& array_name, double value) const override {
123+
if (value < 0.0) {
124+
throw BoundaryConditionValidationException(array_name, value);
125+
}
126+
}
127+
};
128+
129+
#endif // ROBIN_BOUNDARY_CONDITION_H

0 commit comments

Comments
 (0)