|
| 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 | +} |
0 commit comments