1 // Copyright(C) 1999-2021 National Technology & Engineering Solutions 2 // of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with 3 // NTESS, the U.S. Government retains certain rights in this software. 4 // 5 // See packages/seacas/LICENSE for details 6 7 #include <Ioss_CodeTypes.h> 8 #include <Ioss_SmartAssert.h> 9 #include <algorithm> 10 #include <cgns/Iocgns_StructuredZoneData.h> 11 #include <fmt/color.h> 12 #include <fmt/ostream.h> 13 #include <tokenize.h> 14 15 namespace { 16 struct Range 17 { RangeRange18 Range(int a, int b) : m_beg(a < b ? a : b), m_end(a < b ? b : a), m_reversed(b < a) {} 19 beginRange20 int begin() const { return m_reversed ? m_end : m_beg; } endRange21 int end() const { return m_reversed ? m_beg : m_end; } 22 int m_beg; 23 int m_end; 24 bool m_reversed; 25 }; 26 overlaps(const Range & a,const Range & b)27 bool overlaps(const Range &a, const Range &b) { return a.m_beg <= b.m_end && b.m_beg <= a.m_end; } 28 zgc_overlaps(const Iocgns::StructuredZoneData * zone,const Ioss::ZoneConnectivity & zgc)29 bool zgc_overlaps(const Iocgns::StructuredZoneData *zone, const Ioss::ZoneConnectivity &zgc) 30 { 31 // Note that zone range is nodes and m_ordinal[] is cells, so need to add 1 to range. 32 Range z_i(1 + zone->m_offset[0], zone->m_ordinal[0] + zone->m_offset[0] + 1); 33 Range z_j(1 + zone->m_offset[1], zone->m_ordinal[1] + zone->m_offset[1] + 1); 34 Range z_k(1 + zone->m_offset[2], zone->m_ordinal[2] + zone->m_offset[2] + 1); 35 36 Range gc_i(zgc.m_ownerRangeBeg[0], zgc.m_ownerRangeEnd[0]); 37 Range gc_j(zgc.m_ownerRangeBeg[1], zgc.m_ownerRangeEnd[1]); 38 Range gc_k(zgc.m_ownerRangeBeg[2], zgc.m_ownerRangeEnd[2]); 39 40 return overlaps(z_i, gc_i) && overlaps(z_j, gc_j) && overlaps(z_k, gc_k); 41 } 42 zgc_donor_overlaps(const Iocgns::StructuredZoneData * zone,const Ioss::ZoneConnectivity & zgc)43 bool zgc_donor_overlaps(const Iocgns::StructuredZoneData *zone, const Ioss::ZoneConnectivity &zgc) 44 { 45 // Note that zone range is nodes and m_ordinal[] is cells, so need to add 1 to range. 46 Range z_i(1 + zone->m_offset[0], zone->m_ordinal[0] + zone->m_offset[0] + 1); 47 Range z_j(1 + zone->m_offset[1], zone->m_ordinal[1] + zone->m_offset[1] + 1); 48 Range z_k(1 + zone->m_offset[2], zone->m_ordinal[2] + zone->m_offset[2] + 1); 49 50 Range gc_i(zgc.m_donorRangeBeg[0], zgc.m_donorRangeEnd[0]); 51 Range gc_j(zgc.m_donorRangeBeg[1], zgc.m_donorRangeEnd[1]); 52 Range gc_k(zgc.m_donorRangeBeg[2], zgc.m_donorRangeEnd[2]); 53 54 return overlaps(z_i, gc_i) && overlaps(z_j, gc_j) && overlaps(z_k, gc_k); 55 } 56 subset_range(const Range & a,const Range & b)57 Range subset_range(const Range &a, const Range &b) 58 { 59 Range ret(std::max(a.m_beg, b.m_beg), std::min(a.m_end, b.m_end)); 60 ret.m_reversed = a.m_reversed || b.m_reversed; 61 return ret; 62 } 63 zgc_subset_ranges(const Iocgns::StructuredZoneData * zone,Ioss::ZoneConnectivity & zgc)64 void zgc_subset_ranges(const Iocgns::StructuredZoneData *zone, Ioss::ZoneConnectivity &zgc) 65 { 66 if (zgc_overlaps(zone, zgc)) { 67 // NOTE: Updates the range and donor_range in zgc 68 69 // Note that zone range is nodes and m_ordinal[] is cells, so need to add 1 to range. 70 Range z_i(1 + zone->m_offset[0], zone->m_ordinal[0] + zone->m_offset[0] + 1); 71 Range z_j(1 + zone->m_offset[1], zone->m_ordinal[1] + zone->m_offset[1] + 1); 72 Range z_k(1 + zone->m_offset[2], zone->m_ordinal[2] + zone->m_offset[2] + 1); 73 74 Range gc_i(zgc.m_ownerRangeBeg[0], zgc.m_ownerRangeEnd[0]); 75 Range gc_j(zgc.m_ownerRangeBeg[1], zgc.m_ownerRangeEnd[1]); 76 Range gc_k(zgc.m_ownerRangeBeg[2], zgc.m_ownerRangeEnd[2]); 77 78 Range gc_ii = subset_range(z_i, gc_i); 79 Range gc_jj = subset_range(z_j, gc_j); 80 Range gc_kk = subset_range(z_k, gc_k); 81 82 Ioss::IJK_t range_beg; 83 Ioss::IJK_t range_end; 84 range_beg[0] = gc_ii.begin(); 85 range_end[0] = gc_ii.end(); 86 range_beg[1] = gc_jj.begin(); 87 range_end[1] = gc_jj.end(); 88 range_beg[2] = gc_kk.begin(); 89 range_end[2] = gc_kk.end(); 90 91 if (zgc.m_sameRange) { 92 zgc.m_ownerRangeBeg = range_beg; 93 zgc.m_ownerRangeEnd = range_end; 94 zgc.m_donorRangeBeg = zgc.m_ownerRangeBeg; 95 zgc.m_donorRangeEnd = zgc.m_ownerRangeEnd; 96 } 97 else { 98 auto d_range_beg = zgc.transform(range_beg); 99 zgc.m_donorRangeEnd = zgc.transform(range_end); 100 zgc.m_donorRangeBeg = d_range_beg; 101 zgc.m_ownerRangeBeg = range_beg; 102 zgc.m_ownerRangeEnd = range_end; 103 } 104 zgc.m_ownerOffset = {{zone->m_offset[0], zone->m_offset[1], zone->m_offset[2]}}; 105 assert(zgc.is_valid()); 106 zgc.m_isActive = zgc.has_faces(); 107 } 108 else { 109 // This zgc does not overlap on this zone, so set all ranges to 0. 110 // Still need it in list so can write block out correctly in parallel... 111 zgc.m_ownerRangeBeg = {{0, 0, 0}}; 112 zgc.m_ownerRangeEnd = {{0, 0, 0}}; 113 zgc.m_donorRangeBeg = {{0, 0, 0}}; 114 zgc.m_donorRangeEnd = {{0, 0, 0}}; 115 zgc.m_isActive = false; 116 } 117 } 118 zgc_subset_donor_ranges(const Iocgns::StructuredZoneData * don_zone,Ioss::ZoneConnectivity & zgc)119 void zgc_subset_donor_ranges(const Iocgns::StructuredZoneData *don_zone, 120 Ioss::ZoneConnectivity & zgc) 121 { 122 // NOTE: Updates the range and donor_range in zgc 123 124 // Note that zone range is nodes and m_ordinal[] is cells, so need to add 1 to range. 125 Range z_i(1 + don_zone->m_offset[0], don_zone->m_ordinal[0] + don_zone->m_offset[0] + 1); 126 Range z_j(1 + don_zone->m_offset[1], don_zone->m_ordinal[1] + don_zone->m_offset[1] + 1); 127 Range z_k(1 + don_zone->m_offset[2], don_zone->m_ordinal[2] + don_zone->m_offset[2] + 1); 128 129 Range gc_i(zgc.m_donorRangeBeg[0], zgc.m_donorRangeEnd[0]); 130 Range gc_j(zgc.m_donorRangeBeg[1], zgc.m_donorRangeEnd[1]); 131 Range gc_k(zgc.m_donorRangeBeg[2], zgc.m_donorRangeEnd[2]); 132 133 Range gc_ii = subset_range(z_i, gc_i); 134 Range gc_jj = subset_range(z_j, gc_j); 135 Range gc_kk = subset_range(z_k, gc_k); 136 137 Ioss::IJK_t d_range_beg; 138 Ioss::IJK_t d_range_end; 139 d_range_beg[0] = gc_ii.begin(); 140 d_range_end[0] = gc_ii.end(); 141 d_range_beg[1] = gc_jj.begin(); 142 d_range_end[1] = gc_jj.end(); 143 d_range_beg[2] = gc_kk.begin(); 144 d_range_end[2] = gc_kk.end(); 145 146 if (zgc.m_sameRange) { 147 zgc.m_donorRangeBeg = d_range_beg; 148 zgc.m_donorRangeEnd = d_range_end; 149 zgc.m_ownerRangeEnd = zgc.m_donorRangeEnd; 150 zgc.m_ownerRangeBeg = zgc.m_donorRangeBeg; 151 } 152 else { 153 auto range_beg = zgc.inverse_transform(d_range_beg); 154 zgc.m_ownerRangeEnd = zgc.inverse_transform(d_range_end); 155 zgc.m_ownerRangeBeg = range_beg; 156 zgc.m_donorRangeBeg = d_range_beg; 157 zgc.m_donorRangeEnd = d_range_end; 158 } 159 zgc.m_donorOffset = {{don_zone->m_offset[0], don_zone->m_offset[1], don_zone->m_offset[2]}}; 160 assert(zgc.is_valid()); 161 } 162 propogate_zgc(Iocgns::StructuredZoneData * parent,Iocgns::StructuredZoneData * child)163 void propogate_zgc(Iocgns::StructuredZoneData *parent, Iocgns::StructuredZoneData *child) 164 { 165 for (auto zgc : parent->m_zoneConnectivity) { 166 if (!zgc.is_from_decomp() || zgc_overlaps(child, zgc)) { 167 // Modify source and donor range to subset it to new block ranges. 168 zgc_subset_ranges(child, zgc); 169 zgc.m_ownerZone = child->m_zone; 170 child->m_zoneConnectivity.push_back(zgc); 171 } 172 } 173 } 174 175 // Add the zgc corresponding to the new communication path between 176 // two child zones arising from a parent split along ordinal 'ordinal' add_proc_split_zgc(Iocgns::StructuredZoneData * parent,Iocgns::StructuredZoneData * c1,Iocgns::StructuredZoneData * c2,int ordinal)177 void add_proc_split_zgc(Iocgns::StructuredZoneData *parent, Iocgns::StructuredZoneData *c1, 178 Iocgns::StructuredZoneData *c2, int ordinal) 179 { 180 Ioss::IJK_t transform{{1, 2, 3}}; 181 182 // Note that range is specified in terms of 'adam' block i,j,k 183 // space which is converted to local block i,j,k space 184 // via the m_offset[] field on the local block. 185 Ioss::IJK_t range_beg{{1 + c1->m_offset[0], 1 + c1->m_offset[1], 1 + c1->m_offset[2]}}; 186 Ioss::IJK_t range_end{{c1->m_ordinal[0] + c1->m_offset[0] + 1, 187 c1->m_ordinal[1] + c1->m_offset[1] + 1, 188 c1->m_ordinal[2] + c1->m_offset[2] + 1}}; 189 190 Ioss::IJK_t donor_range_beg(range_beg); 191 Ioss::IJK_t donor_range_end(range_end); 192 193 donor_range_end[ordinal] = donor_range_beg[ordinal] = range_beg[ordinal] = range_end[ordinal]; 194 195 auto c1_base = std::to_string(c1->m_adam->m_zone) + "_" + std::to_string(c1->m_zone); 196 auto c2_base = std::to_string(c2->m_adam->m_zone) + "_" + std::to_string(c2->m_zone); 197 198 const auto &adam_name = parent->m_adam->m_name; 199 200 SMART_ASSERT(c1->m_adam->m_zone == c2->m_adam->m_zone)(c1->m_adam->m_zone)(c2->m_adam->m_zone); 201 202 c1->m_zoneConnectivity.emplace_back(c1_base + "--" + c2_base, c1->m_zone, adam_name, c2->m_zone, 203 transform, range_beg, range_end, donor_range_beg, 204 donor_range_end, true, true); 205 auto &zgc1 = c1->m_zoneConnectivity.back(); 206 zgc1.m_sameRange = true; 207 zgc1.m_ownerOffset = {{c1->m_offset[0], c1->m_offset[1], c1->m_offset[2]}}; 208 zgc1.m_donorOffset = {{c2->m_offset[0], c2->m_offset[1], c2->m_offset[2]}}; 209 210 c2->m_zoneConnectivity.emplace_back(c2_base + "--" + c1_base, c2->m_zone, adam_name, c1->m_zone, 211 transform, donor_range_beg, donor_range_end, range_beg, 212 range_end, false, true); 213 auto &zgc2 = c2->m_zoneConnectivity.back(); 214 zgc2.m_sameRange = true; 215 zgc2.m_ownerOffset = {{c2->m_offset[0], c2->m_offset[1], c2->m_offset[2]}}; 216 zgc2.m_donorOffset = {{c1->m_offset[0], c1->m_offset[1], c1->m_offset[2]}}; 217 } 218 } // namespace 219 220 namespace Iocgns { 221 StructuredZoneData(int zone,const std::string & nixnjxnk)222 StructuredZoneData::StructuredZoneData(int zone, const std::string &nixnjxnk) : m_zone(zone) 223 { 224 m_name = "zone_" + std::to_string(zone); 225 226 auto ordinals = Ioss::tokenize(nixnjxnk, "x"); 227 SMART_ASSERT(ordinals.size() == 3)(ordinals.size()); 228 229 m_ordinal[0] = std::stoi(ordinals[0]); 230 m_ordinal[1] = std::stoi(ordinals[1]); 231 m_ordinal[2] = std::stoi(ordinals[2]); 232 233 m_adam = this; 234 } 235 236 // ======================================================================== 237 // Split this StructuredZone along the largest ordinal 238 // into two children and return the created zones. 239 std::pair<StructuredZoneData *, StructuredZoneData *> split(int zone_id,double avg_work,int rank,bool verbose)240 StructuredZoneData::split(int zone_id, double avg_work, int rank, bool verbose) 241 { 242 assert(is_active()); 243 double ratio = avg_work / work(); 244 if (ratio > 1.0) { 245 ratio = 1.0 / ratio; 246 } 247 248 auto ord0 = llround((double)m_ordinal[0] * ratio); 249 auto ord1 = llround((double)m_ordinal[1] * ratio); 250 auto ord2 = llround((double)m_ordinal[2] * ratio); 251 252 size_t work0 = ord0 * m_ordinal[1] * m_ordinal[2]; 253 size_t work1 = ord1 * m_ordinal[0] * m_ordinal[2]; 254 size_t work2 = ord2 * m_ordinal[0] * m_ordinal[1]; 255 256 // Don't decompose along m_lineOrdinal direction and Avoid decompositions 1-cell thick. 257 if (m_lineOrdinal & Ordinal::I || m_ordinal[0] == 1 || ord0 == 1 || m_ordinal[0] - ord0 == 1) { 258 work0 = 0; 259 } 260 if (m_lineOrdinal & Ordinal::J || m_ordinal[1] == 1 || ord1 == 1 || m_ordinal[1] - ord1 == 1) { 261 work1 = 0; 262 } 263 if (m_lineOrdinal & Ordinal::K || m_ordinal[2] == 1 || ord2 == 1 || m_ordinal[2] - ord2 == 1) { 264 work2 = 0; 265 } 266 267 bool enforce_1cell_constraint = true; 268 if (work0 == 0 && work1 == 0 && work2 == 0) { 269 // Need to relax the "cells > 1" constraint... 270 work0 = ord0 * m_ordinal[1] * m_ordinal[2]; 271 work1 = ord1 * m_ordinal[0] * m_ordinal[2]; 272 work2 = ord2 * m_ordinal[0] * m_ordinal[1]; 273 if (m_lineOrdinal & Ordinal::I || m_ordinal[0] == 1) { 274 work0 = 0; 275 } 276 if (m_lineOrdinal & Ordinal::J || m_ordinal[1] == 1) { 277 work1 = 0; 278 } 279 if (m_lineOrdinal & Ordinal::K || m_ordinal[2] == 1) { 280 work2 = 0; 281 } 282 enforce_1cell_constraint = false; 283 } 284 285 auto delta0 = std::make_pair(std::abs((double)work0 - avg_work), -m_ordinal[0]); 286 auto delta1 = std::make_pair(std::abs((double)work1 - avg_work), -m_ordinal[1]); 287 auto delta2 = std::make_pair(std::abs((double)work2 - avg_work), -m_ordinal[2]); 288 289 auto min_ordinal = 0; 290 auto min_delta = delta0; 291 if (delta1 < min_delta) { 292 min_ordinal = 1; 293 min_delta = delta1; 294 } 295 if (delta2 < min_delta) { 296 min_ordinal = 2; 297 min_delta = delta2; 298 } 299 300 unsigned int ordinal = min_ordinal; 301 302 // One more check to try to produce more "squarish" decompositions. 303 // Check the ratio of max ordinal to selected min_ordinal and if > 1.5 (heuristic), choose the 304 // max ordinal instead. 305 int max_ordinal = -1; 306 int max_ordinal_sz = 0; 307 for (int i = 0; i < 3; i++) { 308 unsigned ord = i == 0 ? 1 : 2 * i; 309 if (!(m_lineOrdinal & ord) && m_ordinal[i] > max_ordinal_sz) { 310 max_ordinal = i; 311 max_ordinal_sz = m_ordinal[i]; 312 } 313 } 314 315 if (max_ordinal != -1 && (double)max_ordinal_sz / m_ordinal[ordinal] > 1.5) { 316 ordinal = max_ordinal; 317 } 318 319 if ((m_ordinal[ordinal] <= (enforce_1cell_constraint ? 1 : 0)) || 320 (work0 == 0 && work1 == 0 && work2 == 0)) { 321 return std::make_pair(nullptr, nullptr); 322 } 323 324 // SMART_ASSERT(!(ordinal & m_lineOrdinal))(ordinal)(m_lineOrdinal); 325 326 m_child1 = new StructuredZoneData; 327 m_child2 = new StructuredZoneData; 328 329 m_child1->m_name = m_name + "_c1"; 330 m_child1->m_ordinal = m_ordinal; 331 m_child1->m_ordinal[ordinal] = llround(m_ordinal[ordinal] * ratio); 332 if (m_child1->m_ordinal[ordinal] == 0) { 333 m_child1->m_ordinal[ordinal] = 1; 334 } 335 SMART_ASSERT(!enforce_1cell_constraint || m_child1->m_ordinal[ordinal] != 1) 336 (!enforce_1cell_constraint)(m_child1->m_ordinal[ordinal] != 1); 337 338 m_child1->m_offset = m_offset; // Child1 offsets the same as parent; 339 340 m_child1->m_lineOrdinal = m_lineOrdinal; 341 m_child1->m_zone = zone_id++; 342 m_child1->m_adam = m_adam; 343 m_child1->m_parent = this; 344 m_child1->m_splitOrdinal = ordinal; 345 m_child1->m_sibling = m_child2; 346 347 m_child2->m_name = m_name + "_c2"; 348 m_child2->m_ordinal = m_ordinal; 349 m_child2->m_ordinal[ordinal] = m_ordinal[ordinal] - m_child1->m_ordinal[ordinal]; 350 assert(m_child2->m_ordinal[ordinal] > 0); 351 assert(!enforce_1cell_constraint || m_child2->m_ordinal[ordinal] != 1); 352 m_child2->m_offset = m_offset; 353 m_child2->m_offset[ordinal] += m_child1->m_ordinal[ordinal]; 354 355 m_child2->m_lineOrdinal = m_lineOrdinal; 356 m_child2->m_zone = zone_id++; 357 m_child2->m_adam = m_adam; 358 m_child2->m_parent = this; 359 m_child2->m_splitOrdinal = ordinal; 360 m_child2->m_sibling = m_child1; 361 362 if (rank == 0 && verbose) { 363 fmt::print( 364 Ioss::DEBUG(), "{}", 365 fmt::format( 366 fg(fmt::color::cyan), 367 "\nSplit Zone {} ({}) Adam {} ({}) with intervals {:>12},\twork = {:12L}, offset {} " 368 "{} {}, ordinal {}, ratio {:.3f}\n", 369 m_name, m_zone, m_adam->m_name, m_adam->m_zone, 370 fmt::format("{} {} {}", m_ordinal[0], m_ordinal[1], m_ordinal[2]), work(), 371 m_offset[0], m_offset[1], m_offset[2], ordinal, ratio)); 372 373 fmt::print(Ioss::DEBUG(), 374 "\tChild 1: Zone {} ({}) with intervals {:>12},\twork = {:12L}, offset " 375 "{} {} {}\n" 376 "\tChild 2: Zone {} ({}) with intervals {:>12},\twork = {:12L}, offset " 377 "{} {} {}\n", 378 m_child1->m_name, m_child1->m_zone, 379 fmt::format("{} {} {}", m_child1->m_ordinal[0], m_child1->m_ordinal[1], 380 m_child1->m_ordinal[2]), 381 m_child1->work(), m_child1->m_offset[0], m_child1->m_offset[1], 382 m_child1->m_offset[2], m_child2->m_name, m_child2->m_zone, 383 fmt::format("{} {} {}", m_child2->m_ordinal[0], m_child2->m_ordinal[1], 384 m_child2->m_ordinal[2]), 385 m_child2->work(), m_child2->m_offset[0], m_child2->m_offset[1], 386 m_child2->m_offset[2]); 387 } 388 389 // Add ZoneGridConnectivity instance to account for split... 390 add_proc_split_zgc(this, m_child1, m_child2, ordinal); 391 392 // Propagate parent ZoneGridConnectivities to appropriate children. 393 // Split if needed... 394 propogate_zgc(this, m_child1); 395 propogate_zgc(this, m_child2); 396 397 return std::make_pair(m_child1, m_child2); 398 } 399 400 namespace { update_zgc(Ioss::ZoneConnectivity & zgc,Iocgns::StructuredZoneData * child,std::vector<Ioss::ZoneConnectivity> & zgc_vec,bool new_zgc)401 void update_zgc(Ioss::ZoneConnectivity &zgc, Iocgns::StructuredZoneData *child, 402 std::vector<Ioss::ZoneConnectivity> &zgc_vec, bool new_zgc) 403 { 404 zgc.m_donorZone = child->m_zone; 405 zgc_subset_donor_ranges(child, zgc); 406 // If `!new_zgc`, then the zgc is already in `zgc_vec` 407 if (new_zgc) { 408 zgc_vec.push_back(zgc); 409 } 410 } 411 } // namespace 412 413 // If a zgc points to a donor zone which was split (has non-null children), 414 // then create two zgc that point to each child. Update range and donor_range resolve_zgc_split_donor(const std::vector<Iocgns::StructuredZoneData * > & zones)415 void StructuredZoneData::resolve_zgc_split_donor( 416 const std::vector<Iocgns::StructuredZoneData *> &zones) 417 { 418 // Updates m_zoneConnectivity in place, but in case a new zgc is created, 419 // need a place to store it to avoid invalidating any iterators... 420 // Guess at size to avoid as many reallocations as possible. 421 // At most 1 new zgc per split... 422 std::vector<Ioss::ZoneConnectivity> new_zgc; 423 new_zgc.reserve(m_zoneConnectivity.size()); 424 425 bool did_split = false; 426 do { 427 did_split = false; 428 429 for (auto &zgc : m_zoneConnectivity) { 430 auto &donor_zone = zones[zgc.m_donorZone - 1]; 431 if (!donor_zone->is_active()) { 432 did_split = true; 433 434 bool overlap_1 = zgc_donor_overlaps(donor_zone->m_child1, zgc); 435 bool overlap_2 = zgc_donor_overlaps(donor_zone->m_child2, zgc); 436 bool overlap = overlap_1 || overlap_2; 437 438 // Child 1 439 if (overlap_1) { 440 if (!overlap_2) { 441 // Use `zgc` since don't need it anymore... 442 update_zgc(zgc, donor_zone->m_child1, new_zgc, false); 443 } 444 else { 445 auto c1_zgc(zgc); 446 update_zgc(c1_zgc, donor_zone->m_child1, new_zgc, true); 447 } 448 } 449 450 // Child 2 451 if (overlap_2) { 452 // Use `zgc` since don't need it anymore... 453 update_zgc(zgc, donor_zone->m_child2, new_zgc, false); 454 } 455 456 if (!overlap) { 457 // Need to add at least one copy of this zgc even if no overlap 458 // so can maintain the original (un parallel decomposed) ranges 459 // for use in output... 460 zgc.m_donorZone = donor_zone->m_child1->m_zone; 461 zgc.m_ownerRangeBeg = zgc.m_ownerRangeEnd = {{0, 0, 0}}; 462 zgc.m_donorRangeBeg = zgc.m_donorRangeEnd = {{0, 0, 0}}; 463 } 464 } 465 } 466 if (did_split) { 467 if (!new_zgc.empty()) { 468 m_zoneConnectivity.insert(m_zoneConnectivity.end(), new_zgc.begin(), new_zgc.end()); 469 new_zgc.clear(); 470 } 471 // Filter out all zgc that do not contain any faces unless needed to maintain original zgc 472 // reconstruction... 473 m_zoneConnectivity.erase( 474 std::remove_if(m_zoneConnectivity.begin(), m_zoneConnectivity.end(), 475 [](Ioss::ZoneConnectivity &zgc) { 476 return zgc.get_shared_node_count() <= 2 && !zgc.retain_original(); 477 }), 478 m_zoneConnectivity.end()); 479 } 480 } while (did_split); 481 } 482 483 void update_zgc_processor(const std::vector<Iocgns::StructuredZoneData * > & zones)484 StructuredZoneData::update_zgc_processor(const std::vector<Iocgns::StructuredZoneData *> &zones) 485 { 486 for (auto &zgc : m_zoneConnectivity) { 487 auto &donor_zone = zones[zgc.m_donorZone - 1]; 488 assert(donor_zone->m_proc >= 0); 489 zgc.m_donorProcessor = donor_zone->m_proc; 490 auto &owner_zone = zones[zgc.m_ownerZone - 1]; 491 assert(owner_zone->m_proc >= 0); 492 zgc.m_ownerProcessor = owner_zone->m_proc; 493 } 494 } 495 } // namespace Iocgns 496