Skip to content

Commit ec16cb1

Browse files
Initial implementation and test case. Works with 1 processor, but fails with multiple processors. Other improvements to make
1 parent 6ae4572 commit ec16cb1

29 files changed

+1050
-67
lines changed

Code/Source/solver/CMakeLists.txt

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

226226
svZeroD_interface/LPNSolverInterface.h svZeroD_interface/LPNSolverInterface.cpp
227+
228+
RobinBCData.h RobinBCData.cpp
227229
)
228230

229231
# Set PETSc interace code.

Code/Source/solver/ComMod.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,9 @@ class bcType
197197
// Robin: damping
198198
double c = 0.0;
199199

200+
// Robin: VTP file path for per-node stiffness and damping
201+
std::string robin_vtp_file = "";
202+
200203
// RIS0D: resistance
201204
double resistance = 0.0;
202205

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;

Code/Source/solver/RobinBCData.cpp

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
#include "RobinBCData.h"
2+
#include "ComMod.h"
3+
#include <stdexcept>
4+
#include <iostream>
5+
6+
RobinBCData::RobinBCData(const std::string& vtp_file_path, const faceType& face)
7+
{
8+
std::cerr << "[RobinBCData] Constructor with VTP file path" << std::endl;
9+
num_nodes_ = face.nNo;
10+
from_vtp_ = true;
11+
vtp_file_path_ = vtp_file_path;
12+
13+
//std::cout << "[RobinBCData] Loading Robin BC from VTP file: " << vtp_file_path << std::endl;
14+
load_from_vtp(vtp_file_path, face);
15+
}
16+
17+
RobinBCData::RobinBCData(double uniform_stiffness, double uniform_damping, int num_nodes)
18+
{
19+
std::cout << "[RobinBCData] Constructor with uniform values" << std::endl;
20+
num_nodes_ = num_nodes;
21+
from_vtp_ = false;
22+
vtp_file_path_ = "";
23+
24+
std::cout << "[RobinBCData] Initializing uniform Robin BC values" << std::endl;
25+
initialize_uniform(uniform_stiffness, uniform_damping, num_nodes);
26+
}
27+
28+
void RobinBCData::load_from_vtp(const std::string& vtp_file_path, const faceType& face)
29+
{
30+
//std::cout << "[load_from_vtp] Loading Robin BC from VTP file: " << vtp_file_path << std::endl;
31+
// Check if file exists
32+
if (FILE *file = fopen(vtp_file_path.c_str(), "r")) {
33+
fclose(file);
34+
//std::cout << "[load_from_vtp] File exists and is readable" << std::endl;
35+
} else {
36+
throw std::runtime_error("Robin BC VTP file '" + vtp_file_path + "' cannot be read.");
37+
}
38+
39+
// Read the VTP file
40+
//std::cout << "[load_from_vtp] About to create VtkVtpData object" << std::endl;
41+
VtkVtpData vtp_data(vtp_file_path, true);
42+
//std::cout << "[load_from_vtp] VtkVtpData object created successfully" << std::endl;
43+
44+
// Validate the VTP data matches the face geometry
45+
validate_vtp_data(vtp_data, face);
46+
47+
// Check for required point arrays
48+
if (!vtp_data.has_point_data("Stiffness")) {
49+
throw std::runtime_error("VTP file '" + vtp_file_path + "' does not contain 'Stiffness' point array.");
50+
}
51+
52+
if (!vtp_data.has_point_data("Damping")) {
53+
throw std::runtime_error("VTP file '" + vtp_file_path + "' does not contain 'Damping' point array.");
54+
}
55+
56+
// Load stiffness array
57+
auto stiffness_data = vtp_data.get_point_data("Stiffness");
58+
if (stiffness_data.nrows() != num_nodes_ || stiffness_data.ncols() != 1) {
59+
throw std::runtime_error("'Stiffness' array in VTP file '" + vtp_file_path +
60+
"' has incorrect dimensions. Expected " + std::to_string(num_nodes_) +
61+
" x 1, got " + std::to_string(stiffness_data.nrows()) + " x " +
62+
std::to_string(stiffness_data.ncols()) + ".");
63+
}
64+
65+
// Load damping array
66+
auto damping_data = vtp_data.get_point_data("Damping");
67+
if (damping_data.nrows() != num_nodes_ || damping_data.ncols() != 1) {
68+
throw std::runtime_error("'Damping' array in VTP file '" + vtp_file_path +
69+
"' has incorrect dimensions. Expected " + std::to_string(num_nodes_) +
70+
" x 1, got " + std::to_string(damping_data.nrows()) + " x " +
71+
std::to_string(damping_data.ncols()) + ".");
72+
}
73+
74+
// Copy data to internal arrays and build global-to-local map
75+
stiffness_array_.resize(num_nodes_);
76+
damping_array_.resize(num_nodes_);
77+
global_to_local_map_.clear();
78+
79+
for (int i = 0; i < num_nodes_; i++) {
80+
stiffness_array_(i) = stiffness_data(i, 0);
81+
damping_array_(i) = damping_data(i, 0);
82+
83+
// Store mapping from global node ID to local index
84+
global_to_local_map_[face.gN(i)] = i;
85+
86+
// Validate that values are non-negative
87+
if (stiffness_array_(i) < 0.0) {
88+
throw std::runtime_error("Negative stiffness value at node " + std::to_string(i) +
89+
" in VTP file '" + vtp_file_path + "'.");
90+
}
91+
if (damping_array_(i) < 0.0) {
92+
throw std::runtime_error("Negative damping value at node " + std::to_string(i) +
93+
" in VTP file '" + vtp_file_path + "'.");
94+
}
95+
}
96+
}
97+
98+
void RobinBCData::initialize_uniform(double stiffness, double damping, int num_nodes)
99+
{
100+
if (stiffness < 0.0) {
101+
throw std::runtime_error("Uniform stiffness value cannot be negative.");
102+
}
103+
if (damping < 0.0) {
104+
throw std::runtime_error("Uniform damping value cannot be negative.");
105+
}
106+
if (num_nodes <= 0) {
107+
throw std::runtime_error("Number of nodes must be positive.");
108+
}
109+
110+
stiffness_array_.resize(num_nodes);
111+
damping_array_.resize(num_nodes);
112+
global_to_local_map_.clear();
113+
114+
for (int i = 0; i < num_nodes; i++) {
115+
stiffness_array_(i) = stiffness;
116+
damping_array_(i) = damping;
117+
// For uniform values, we assume global IDs are sequential starting from 0
118+
global_to_local_map_[i] = i;
119+
}
120+
}
121+
122+
void RobinBCData::validate_vtp_data(const VtkVtpData& vtp_data, const faceType& face)
123+
{
124+
//std::cout << "[validate_vtp_data] Validating VTP data" << std::endl;
125+
int vtp_num_points = vtp_data.num_points();
126+
if (vtp_num_points != face.nNo) {
127+
throw std::runtime_error("Number of points in VTP file (" + std::to_string(vtp_num_points) +
128+
") does not match number of nodes on face '" + face.name +
129+
"' (" + std::to_string(face.nNo) + ").");
130+
}
131+
132+
int vtp_num_elems = vtp_data.num_elems();
133+
if (vtp_num_elems != face.nEl) {
134+
throw std::runtime_error("Number of elements in VTP file (" + std::to_string(vtp_num_elems) +
135+
") does not match number of elements on face '" + face.name +
136+
"' (" + std::to_string(face.nEl) + ").");
137+
}
138+
139+
// Get points from VTP file, (3,N) array
140+
Array<double> vtp_points = vtp_data.get_points();
141+
142+
// Compare each point's coordinates
143+
const double tolerance = 1e-12; // Small tolerance for floating point comparison
144+
for (int i = 0; i < face.nNo; i++) {
145+
double face_x = face.x(0,i);
146+
double face_y = face.x(1,i);
147+
double face_z = face.x(2,i);
148+
double vtp_x = vtp_points(0,i);
149+
double vtp_y = vtp_points(1,i);
150+
double vtp_z = vtp_points(2,i);
151+
double dx = std::abs(vtp_x - face_x);
152+
double dy = std::abs(vtp_y - face_y);
153+
double dz = std::abs(vtp_z - face_z);
154+
155+
if (dx > tolerance || dy > tolerance || dz > tolerance) {
156+
throw std::runtime_error("Node " + std::to_string(i) + " in VTP file is not colocated with " +
157+
"corresponding node in face '" + face.name + "'. " +
158+
"VTP: (" + std::to_string(vtp_x) + ", " +
159+
std::to_string(vtp_y) + ", " +
160+
std::to_string(vtp_z) + ") " +
161+
"Face: (" + std::to_string(face_x) + ", " +
162+
std::to_string(face_y) + ", " +
163+
std::to_string(face_z) + ")");
164+
}
165+
}
166+
}
167+
168+
double RobinBCData::get_stiffness(int node_id) const
169+
{
170+
if (node_id < 0 || node_id >= num_nodes_) {
171+
throw std::runtime_error("Node ID " + std::to_string(node_id) +
172+
" is out of range [0, " + std::to_string(num_nodes_ - 1) + "].");
173+
}
174+
return stiffness_array_(node_id);
175+
}
176+
177+
double RobinBCData::get_damping(int node_id) const
178+
{
179+
if (node_id < 0 || node_id >= num_nodes_) {
180+
throw std::runtime_error("Node ID " + std::to_string(node_id) +
181+
" is out of range [0, " + std::to_string(num_nodes_ - 1) + "].");
182+
}
183+
return damping_array_(node_id);
184+
}
185+
186+
int RobinBCData::get_local_index(int global_node_id) const
187+
{
188+
auto it = global_to_local_map_.find(global_node_id);
189+
if (it == global_to_local_map_.end()) {
190+
throw std::runtime_error("Global node ID " + std::to_string(global_node_id) +
191+
" not found in global-to-local map.");
192+
}
193+
return it->second;
194+
}

Code/Source/solver/RobinBCData.h

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#ifndef ROBIN_BC_DATA_H
2+
#define ROBIN_BC_DATA_H
3+
4+
#include "Array.h"
5+
#include "Vector.h"
6+
#include "VtkData.h"
7+
#include "ComMod.h"
8+
#include <string>
9+
#include <memory>
10+
11+
12+
/// @brief Class to handle Robin boundary condition data with per-node stiffness and damping
13+
///
14+
/// This class reads stiffness and damping arrays from a VTP file and provides
15+
/// efficient access to per-node values during boundary condition assembly.
16+
class RobinBCData {
17+
public:
18+
/// @brief Constructor - reads data from VTP file
19+
/// @param vtp_file_path Path to VTP file containing Stiffness and Damping point arrays
20+
/// @param face Reference to the face for validation
21+
/// @throws std::runtime_error if file cannot be read or arrays are missing
22+
RobinBCData(const std::string& vtp_file_path, const faceType& face);
23+
24+
/// @brief Default constructor for uniform values
25+
/// @param uniform_stiffness Uniform stiffness value for all nodes
26+
/// @param uniform_damping Uniform damping value for all nodes
27+
/// @param num_nodes Number of nodes on the face
28+
RobinBCData(double uniform_stiffness, double uniform_damping, int num_nodes);
29+
30+
/// @brief Destructor
31+
~RobinBCData() = default;
32+
33+
/// @brief Get stiffness value for a specific node
34+
/// @param node_id Node index on the face
35+
/// @return Stiffness value for the node
36+
double get_stiffness(int node_id) const;
37+
38+
/// @brief Get damping value for a specific node
39+
/// @param node_id Node index on the face
40+
/// @return Damping value for the node
41+
double get_damping(int node_id) const;
42+
43+
/// @brief Get number of nodes
44+
/// @return Number of nodes on the face
45+
int get_num_nodes() const { return num_nodes_; }
46+
47+
/// @brief Get local array index for a global node ID
48+
/// @param global_node_id The global node ID defined on the face
49+
/// @return Local array index for stiffness_array_ and damping_array_
50+
/// @throws std::runtime_error if global_node_id is not found in the map
51+
int get_local_index(int global_node_id) const;
52+
53+
/// @brief Check if data is loaded from VTP file
54+
/// @return true if loaded from VTP, false if using uniform values
55+
bool is_from_vtp() const { return from_vtp_; }
56+
57+
/// @brief Get the VTP file path (empty if using uniform values)
58+
/// @return VTP file path
59+
const std::string& get_vtp_path() const { return vtp_file_path_; }
60+
61+
private:
62+
/// @brief Load stiffness and damping arrays from VTP file
63+
/// @param vtp_file_path Path to VTP file
64+
/// @param face Reference to face for validation
65+
void load_from_vtp(const std::string& vtp_file_path, const faceType& face);
66+
67+
/// @brief Initialize uniform values
68+
/// @param stiffness Uniform stiffness value
69+
/// @param damping Uniform damping value
70+
/// @param num_nodes Number of nodes
71+
void initialize_uniform(double stiffness, double damping, int num_nodes);
72+
73+
/// @brief Validate that VTP data matches face geometry
74+
/// @param vtp_data VTP data object
75+
/// @param face Reference to face
76+
void validate_vtp_data(const VtkVtpData& vtp_data, const faceType& face);
77+
78+
int num_nodes_; ///< Number of nodes on the face
79+
Vector<double> stiffness_array_; ///< Stiffness values for each node
80+
Vector<double> damping_array_; ///< Damping values for each node
81+
bool from_vtp_; ///< Flag indicating if data is from VTP file
82+
std::string vtp_file_path_; ///< Path to VTP file (empty if uniform)
83+
std::map<int, int> global_to_local_map_; ///< Maps global node IDs to local array indices
84+
};
85+
86+
#endif // ROBIN_BC_DATA_H

0 commit comments

Comments
 (0)