NEMoSys  0.63.0
A modular, extensible resource with robust automated mesh generation, mesh quality analysis, adaptive mesh refinement, and data transfer between arbitrary meshes.
cgnsAnalyzer.C
Go to the documentation of this file.
1 /*******************************************************************************
2 * Promesh *
3 * Copyright (C) 2022, IllinoisRocstar LLC. All rights reserved. *
4 * *
5 * Promesh is the property of IllinoisRocstar LLC. *
6 * *
7 * IllinoisRocstar LLC *
8 * Champaign, IL *
9 * www.illinoisrocstar.com *
10 * promesh@illinoisrocstar.com *
11 *******************************************************************************/
12 /*******************************************************************************
13 * This file is part of Promesh *
14 * *
15 * This version of Promesh is free software: you can redistribute it and/or *
16 * modify it under the terms of the GNU Lesser General Public License as *
17 * published by the Free Software Foundation, either version 3 of the License, *
18 * or (at your option) any later version. *
19 * *
20 * Promesh is distributed in the hope that it will be useful, but WITHOUT ANY *
21 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS *
22 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more *
23 * details. *
24 * *
25 * You should have received a copy of the GNU Lesser General Public License *
26 * along with this program. If not, see <https://www.gnu.org/licenses/>. *
27 * *
28 *******************************************************************************/
29 #include "IO/cgnsAnalyzer.H"
30 
31 #include <vtkCellTypes.h>
32 #include <vtkIdList.h>
33 #include <vtkUnstructuredGrid.h>
34 
35 /********************************************
36  solutionData class implementation
37 *********************************************/
38 
39 void solutionData::appendData(const vecSlnType &inBuff, int inNData,
40  int inNDim) {
41  // sanity check
42  if (!slnData.empty()) {
43  if (nDim != inNDim || inNDim == 0) {
44  std::cerr << "Incompatible data size can not be appended."
45  << "Current nDim = " << nDim << " Requested nDim = " << inNDim
46  << std::endl;
47  return;
48  }
49  } else {
50  nDim = inNDim;
51  }
52 
53  // deep copy data
54  slnData.insert(slnData.end(), inBuff.begin(), inBuff.end());
55  nData += inNData;
56 }
57 
58 void solutionData::getData(vecSlnType &outBuff, int &outNData,
59  int &outNDim) const {
60  // deep copy data
61  outBuff.insert(outBuff.begin(), slnData.begin(), slnData.end());
62  outNData = nData;
63  outNDim = nDim;
64 }
65 
66 // only copies data that are defined in the given mask
67 void solutionData::getData(vecSlnType &outBuff, int &outNData, int &outNDim,
68  const std::vector<bool> &mask) const {
69  // deep copy data
70  int cntr1 = 0;
71  int cntr2 = 0;
72  for (const auto &id : mask) {
73  if (id) {
74  outBuff.insert(outBuff.end(), slnData[cntr1]);
75  cntr2++;
76  }
77  cntr1++;
78  }
79  outNData = cntr2;
80  outNDim = nDim;
81 }
82 
83 void solutionData::rmvDataIdx(const std::vector<int> &rmvIdx) {
84  vecSlnType nsdv;
85  int nnd = 0;
86  for (int id = 0; id < nData; id++) {
87  auto it = std::find(rmvIdx.begin(), rmvIdx.end(), id);
88  if (it != rmvIdx.end())
89  continue;
90  else {
91  nnd++;
92  for (int iDim = 0; iDim < nDim; iDim++)
93  nsdv.push_back(slnData[id * nDim + iDim]);
94  }
95  }
96  slnData = nsdv;
97  nData = nnd;
98 }
99 
100 /********************************************
101  cgnsAnalyzer class implementation
102 *********************************************/
103 
104 void cgnsAnalyzer::loadGrid(int verb) {
105  // cgns related variables
106  // int i, j, k;
107  char basename[33] /*, zonename[33]*/;
108 
109  // open CGNS file for read
110  if (cg_open(cgFileName.c_str(), CG_MODE_MODIFY, &indexFile)) cg_error_exit();
111 
112  // reading base information
113  cg_nbases(indexFile, &nBase);
114  if (nBase > 1)
115  std::cerr << "There are " << nBase
116  << " bases in the file (not supported).\n";
117  else
118  indexBase = 1;
119  if (cg_base_read(indexFile, indexBase, basename, &cellDim, &physDim))
120  cg_error_exit();
121  baseName = basename;
122 
123  // reading units
124  if (cg_goto(indexFile, indexBase, "end")) cg_error_exit();
125  if (cg_units_read(&massU, &lengthU, &timeU, &tempU, &angleU)) cg_error_exit();
126  if (verb > 0)
127  std::cout << " ------------------------------------------------\n"
128  << "Base name = " << baseName << "\ncellDim = " << cellDim
129  << "\nphysDim = " << physDim << "\nUnits " << massU << " "
130  << lengthU << " " << timeU << " " << tempU << " " << angleU
131  << std::endl;
132 
133  // reading base iterative data
134  char bitername[33];
135  if (cg_biter_read(indexFile, indexBase, bitername, &nTStep)) cg_error_exit();
136  baseItrName = bitername;
137  if (nTStep != 1) std::cerr << "More than one time step is not supported.\n";
138  // int nArrays;
139  std::cout << baseItrName << std::endl;
140  if (cg_goto(indexFile, indexBase, bitername, 0, "end")) cg_error_exit();
141  if (cg_array_read_as(1, CGNS_ENUMV(RealDouble), &timeLabel)) cg_error_exit();
142  if (verb > 0) std::cout << "Time label = " << timeLabel << std::endl;
143 
144  // reading zone information
145  cg_nzones(indexFile, indexBase, &nZone);
146  if (nZone > 1) {
147  // std::cout << "There are " << nZone << " zones in the file (not
148  // supported).\n";
149  isMltZone = true;
150  }
151  loadZone(1, verb);
152 }
153 
154 void cgnsAnalyzer::loadZone(int zIdx, int verb) {
155  char zonename[33];
156  indexZone = zIdx;
157  // reading zone type and name
158  cg_zone_read(indexFile, indexBase, indexZone, zonename, cgCoreSize);
159  cg_zone_type(indexFile, indexBase, indexZone, &zoneType);
160  zoneName = zonename;
161  zoneNames.push_back(zoneName);
162  if (verb) std::cout << "Zone name = " << zoneName << std::endl;
163 
164  // type of zone
165  if (zoneType == CGNS_ENUMV(ZoneTypeNull)) {
166  if (verb) std::cout << "Zone type = CG_ZoneTypeNull\n";
167  } else if (zoneType == CGNS_ENUMV(Structured)) {
168  isUnstructured = false;
169  if (verb) std::cout << "Zone type = CG_Structured\n";
170  std::cerr << "Warning: Structured meshes only supported experimentally.\n";
171  } else if (zoneType == CGNS_ENUMV(Unstructured)) {
172  isUnstructured = true;
173  if (verb) std::cout << "Zone type = CG_Unstructured\n";
174  } else if (zoneType == CGNS_ENUMV(ZoneTypeUserDefined)) {
175  if (verb) std::cout << "Zone type = CG_ZoneTypeUserDefined\n";
176  }
177 
178  // reading zone iterative data, in the case of Rocstar outputs
179  // there should be two additional nodes bellow this
180  // containing grid coordinate pointer and flow solution pointer
181  char zitername[33];
182  if (cg_ziter_read(indexFile, indexBase, indexZone, zitername))
183  cg_error_exit();
184  zoneItrName = zitername;
185  if (verb) std::cout << "Zone iterative name = " << zoneItrName << std::endl;
186  char gridcoorpntr[33], flowslnpntr[33];
187  if (cg_goto(indexFile, indexBase, zonename, 0, zitername, 0, "end"))
188  cg_error_exit();
189  // readin flow solution and grid coordiate pointers if they exist at all
190  // if (!cg_goto(indexFile, indexBase, zonename, 0, zitername, 0,
191  // "GridCoordiatesPointers", 0, "end"))
192  if (!cg_goto(indexFile, indexBase, "Zone_t", indexZone, "ZoneIterativeData_t",
193  1, "end")) {
194  if (!cg_array_read_as(1, CGNS_ENUMV(Character), gridcoorpntr))
195  gridCrdPntr = gridcoorpntr;
196  else
197  gridCrdPntr = "NA";
198  if (verb)
199  std::cout << "Grid coordinate pointer = " << gridcoorpntr << std::endl;
200  if (!cg_array_read_as(2, CGNS_ENUMV(Character), flowslnpntr))
201  flowSlnPntr = flowslnpntr;
202  else
203  flowSlnPntr = "NA";
204  if (verb)
205  std::cout << "Flow solution pointer = " << flowslnpntr << std::endl;
206  } else {
207  std::cout << "This zone does not containing grid/flow pointers.\n";
208  }
209 
210  // finding number of vertices and elements
211  if (zoneType == CGNS_ENUMV(Unstructured)) {
212  nVertex = cgCoreSize[0];
213  nElem = cgCoreSize[1];
214  rmax[0] = nVertex;
215  rmax[1] = nVertex;
216  rmax[2] = nVertex;
217  } else {
218  // for strucutred meshes we have to
219  // take into account number of rind nodes in each
220  // direction. In rocstar case they are equal in each direction
221  int rdata[2];
222  if (cg_goto(indexFile, indexBase, "Zone_t", zIdx, "GridCoordinates", 0,
223  "end"))
224  cg_error_exit();
225  if (cg_rind_read(rdata)) cg_error_exit();
226  nRindNdeStr = rdata[1];
227  // assuming same number in each direction and same number
228  // of rind cells layers as the number of rind node layers
229  // (true condition for Rocflo)
230  std::cout << "nRindNdeStr = " << nRindNdeStr << "\n";
231  // number of real vertices + nRindNode in each direction
232  cgCoreSize[0] += 2 * nRindNdeStr;
233  cgCoreSize[1] += 2 * nRindNdeStr;
234  cgCoreSize[2] += 2 * nRindNdeStr;
235  // each rind node adds a row of elements as well
236  cgCoreSize[3] += 2 * nRindNdeStr;
237  cgCoreSize[4] += 2 * nRindNdeStr;
238  cgCoreSize[5] += 2 * nRindNdeStr;
239  nVertex = cgCoreSize[0] * cgCoreSize[1] * cgCoreSize[2];
240  nElem = cgCoreSize[3] * cgCoreSize[4] * cgCoreSize[5];
241  rmin[0] = 1;
242  rmin[1] = 1;
243  rmin[2] = 1;
244  rmax[0] = cgCoreSize[0];
245  rmax[1] = cgCoreSize[1];
246  rmax[2] = cgCoreSize[2];
247  std::cout << " Number of rind node for structured zone = " << nRindNdeStr
248  << std::endl;
249  }
250  if (verb)
251  std::cout << "Number of vertex = " << nVertex
252  << "\nNumber of elements = " << nElem << std::endl;
253 
254  // capturing rinde node ids
255  int ndId = 0;
256  if (nRindNdeStr != 0)
257  for (int i = rmin[2]; i <= rmax[2]; i++)
258  for (int j = rmin[1]; j <= rmax[1]; j++)
259  for (int k = rmin[0]; k <= rmax[0]; k++) {
260  ndId++;
261  if ((i <= nRindNdeStr || (rmax[2] - i) < nRindNdeStr) ||
262  (j <= nRindNdeStr || (rmax[1] - j) < nRindNdeStr) ||
263  (k <= nRindNdeStr || (rmax[0] - k) < nRindNdeStr))
264  cgRindNodeIds.push_back(ndId);
265  }
266  std::cout << "Total number of rind nodes = " << cgRindNodeIds.size() << "\n";
267 
268  // reading coordinates
269  cgsize_t one = 1;
270  if (zoneType == CGNS_ENUMV(Unstructured)) {
271  // reading coordinates X
272  xCrd.resize(nVertex, 0);
273  if (cg_coord_read(indexFile, indexBase, indexZone, "CoordinateX",
274  CGNS_ENUMV(RealDouble), &one, &rmax[0],
275  &xCrd[0]) != CG_OK)
276  std::cerr << "Error in load, " << cg_get_error() << std::endl;
277 
278  // reading coordinates Y
279  yCrd.resize(nVertex, 0);
280  if (cg_coord_read(indexFile, indexBase, indexZone, "CoordinateY",
281  CGNS_ENUMV(RealDouble), &one, &rmax[1],
282  &yCrd[0]) != CG_OK)
283  std::cerr << "Error in load, " << cg_get_error() << std::endl;
284 
285  // reading coordinates Z
286  zCrd.resize(nVertex, 0);
287  if (cg_coord_read(indexFile, indexBase, indexZone, "CoordinateZ",
288  CGNS_ENUMV(RealDouble), &one, &rmax[2],
289  &zCrd[0]) != CG_OK)
290  std::cerr << "Error in load, " << cg_get_error() << std::endl;
291  } else if (zoneType == CGNS_ENUMV(Structured)) {
292  // rind information in case any (testing)
293 
294  // reading coordinates X
295  xCrd.resize(nVertex, 0);
296  if (cg_coord_read(indexFile, indexBase, indexZone, "CoordinateX",
297  CGNS_ENUMV(RealDouble), &rmin[0], &rmax[0],
298  &xCrd[0]) != CG_OK)
299  std::cerr << "Error in load, " << cg_get_error() << std::endl;
300 
301  // reading coordinates Y
302  yCrd.resize(nVertex, 0);
303  if (cg_coord_read(indexFile, indexBase, indexZone, "CoordinateY",
304  CGNS_ENUMV(RealDouble), &rmin[0], &rmax[0],
305  &yCrd[0]) != CG_OK)
306  std::cerr << "Error in load, " << cg_get_error() << std::endl;
307 
308  // reading coordinates Z
309  zCrd.resize(nVertex, 0);
310  if (cg_coord_read(indexFile, indexBase, indexZone, "CoordinateZ",
311  CGNS_ENUMV(RealDouble), &rmin[0], &rmax[0],
312  &zCrd[0]) != CG_OK)
313  std::cerr << "Error in load, " << cg_get_error() << std::endl;
314  } else {
315  std::cerr << "Error in load, only CG_Structured and CG_Unstructured girds "
316  "are supported.\n ";
317  exit(0);
318  }
319 
320  // reading connectivity only if CG_Unstructured
321  if (zoneType == CGNS_ENUMV(Unstructured)) {
322  int indexSection, nBdry, parentFlag;
323  cgsize_t eBeg, eEnd;
324  char sectionname[33];
325  if (cg_nsections(indexFile, indexBase, indexZone, &nSection) != CG_OK)
326  std::cerr << "Error in load, " << cg_get_error();
327  if (nSection > 1)
328  if (verb)
329  std::cout << nSection
330  << " element connectivity sections were found (real+virtual "
331  "in case of rocstar)"
332  << ", only first section will be read for now." << std::endl;
333  indexSection = 1;
334  if (cg_section_read(indexFile, indexBase, indexZone, indexSection,
335  sectionname, &sectionType, &eBeg, &eEnd, &nBdry,
336  &parentFlag) != CG_OK)
337  std::cerr << "Error in load, " << cg_get_error() << std::endl;
338  sectionName = sectionname;
339  if (verb)
340  std::cout << "Section " << sectionname << " eBeg = " << eBeg
341  << " eEnd = " << eEnd << " nBdry = " << nBdry << std::endl;
342  switch (sectionType) {
343  case CGNS_ENUMV(TETRA_4): nVrtxElem = 4; break;
344  case CGNS_ENUMV(HEXA_8): nVrtxElem = 8; break;
345  case CGNS_ENUMV(TRI_3): nVrtxElem = 3; break;
346  case CGNS_ENUMV(QUAD_4): nVrtxElem = 4; break;
347  case CGNS_ENUMV(TETRA_10): nVrtxElem = 10; break;
348  default:
349  std::cerr << "Unknown element type " << sectionType << std::endl;
350  break;
351  }
352  elemConn.resize(nVrtxElem * nElem, -1);
353  if (cg_elements_read(indexFile, indexBase, indexZone, indexSection,
354  &elemConn[0], nullptr) != CG_OK)
355  std::cerr << "Error in load, " << cg_get_error() << std::endl;
356  // reduce by 1 to base the node index to zero
357  // using lambda function
358  // std::for_each(elemConn.begin(), elemConn.end(), [](int& d) { d -= 1; });
359  if (verb)
360  std::cout << "Size of connectivity vector = " << elemConn.size()
361  << std::endl;
362  } else if (zoneType == CGNS_ENUMV(Structured)) {
363  // Generating connectivity for structured meshes since file does not contain
364  // data
365  std::cerr << "Warning: converting implicit structured connectivity to "
366  "8-Node hexahedrals.\n";
367  sectionType = CGNS_ENUMV(HEXA_8);
368  elemConn.resize(8 * nElem, -1);
369  int iElm;
370  int bs, d1, d2, d3, d4 /*,d5*/;
371  iElm = 0;
372  bs = 0;
373  d4 = cgCoreSize[1] * cgCoreSize[0];
374  for (int k = 1; k < cgCoreSize[2]; k++) {
375  d1 = d4 * (k - 1);
376  for (int j = 1; j < cgCoreSize[1]; j++) {
377  d2 = d1 + (cgCoreSize[0]) * (j - 1);
378  for (int i = 1; i < cgCoreSize[0]; i++) {
379  // rind detector
380  d3 = d2 + i;
381  elemConn[bs] = d3;
382  elemConn[bs + 1] = d3 + 1;
383  elemConn[bs + 2] = d3 + 1 + cgCoreSize[0];
384  elemConn[bs + 3] = d3 + cgCoreSize[0];
385  elemConn[bs + 4] = d3 + d4;
386  elemConn[bs + 5] = d3 + 1 + d4;
387  elemConn[bs + 6] = d3 + 1 + cgCoreSize[0] + d4;
388  elemConn[bs + 7] = d3 + cgCoreSize[0] + d4;
389  // std::cout << "Elem conn = "
390  // << elemConn[bs] << " "
391  // << elemConn[bs+1] << " "
392  // << elemConn[bs+2] << " "
393  // << elemConn[bs+3] << " "
394  // << elemConn[bs+4] << " "
395  // << elemConn[bs+5] << " "
396  // << elemConn[bs+6] << " "
397  // << elemConn[bs+7] << "\n";
398  bs += 8;
399  iElm += 1;
400  if ((k <= nRindNdeStr || (cgCoreSize[2] - k) <= nRindNdeStr) ||
401  (j <= nRindNdeStr || (cgCoreSize[1] - j) <= nRindNdeStr) ||
402  (i <= nRindNdeStr || (cgCoreSize[0] - i) <= nRindNdeStr))
403  cgRindCellIds.push_back(iElm);
404  }
405  }
406  }
407  // auto it1 = max_element(std::begin(elemConn), std::end(elemConn));
408  // auto it2 = min_element(std::begin(elemConn), std::end(elemConn));
409  // std::cout << "Max Conn = " << *it1 << std::endl;
410  // std::cout << "Min Conn = " << *it2 << std::endl;
411  // std::cerr << "nElm = " << iElm << "\n";
412  }
413 }
414 
415 int cgnsAnalyzer::getIndexFile() { return indexFile; }
416 
417 int cgnsAnalyzer::getIndexBase() { return indexBase; }
418 
419 int cgnsAnalyzer::getCellDim() { return cellDim; }
420 
421 std::string cgnsAnalyzer::getFileName() { return cgFileName; }
422 
423 std::string cgnsAnalyzer::getBaseName() { return baseName; }
424 
425 std::string cgnsAnalyzer::getZoneName() { return zoneName; }
426 
427 std::string cgnsAnalyzer::getZoneName(int iCgFile) {
428  return zoneNames[iCgFile];
429 }
430 
431 std::string cgnsAnalyzer::getSectionName() { return sectionName; }
432 
433 std::string cgnsAnalyzer::getBaseItrName() { return baseItrName; }
434 
435 int cgnsAnalyzer::getNZone() { return nZone; }
436 
437 int cgnsAnalyzer::getNTStep() { return nTStep; }
438 
439 std::string cgnsAnalyzer::getZoneItrName() { return zoneItrName; }
440 
441 std::string cgnsAnalyzer::getGridCrdPntr() { return gridCrdPntr; }
442 
443 std::string cgnsAnalyzer::getSolutionPntr() { return flowSlnPntr; }
444 
445 int cgnsAnalyzer::getNVertex() { return nVertex; }
446 
447 int cgnsAnalyzer::getNElement() { return nElem; }
448 
449 int cgnsAnalyzer::getPhysDim() { return physDim; }
450 
451 int cgnsAnalyzer::getElementType() { return sectionType; }
452 
453 int cgnsAnalyzer::getNVrtxElem() { return nVrtxElem; }
454 
455 double cgnsAnalyzer::getTimeStep() { return timeLabel; }
456 
457 CGNS_ENUMT(MassUnits_t) cgnsAnalyzer::getMassUnit() { return massU; }
458 
459 CGNS_ENUMT(LengthUnits_t) cgnsAnalyzer::getLengthUnit() { return lengthU; }
460 
461 CGNS_ENUMT(TimeUnits_t) cgnsAnalyzer::getTimeUnit() { return timeU; }
462 
463 CGNS_ENUMT(TemperatureUnits_t) cgnsAnalyzer::getTemperatureUnit() {
464  return tempU;
465 }
466 
467 CGNS_ENUMT(AngleUnits_t) cgnsAnalyzer::getAngleUnit() { return angleU; }
468 
469 CGNS_ENUMT(ZoneType_t) cgnsAnalyzer::getZoneType() { return zoneType; }
470 
471 bool cgnsAnalyzer::isStructured() { return !isUnstructured; }
472 
473 vtkSmartPointer<vtkDataSet> cgnsAnalyzer::getVTKMesh() {
474  if (vtkMesh)
475  return vtkMesh;
476  else {
477  exportToVTKMesh();
478  return vtkMesh;
479  }
480 }
481 
482 std::vector<double> cgnsAnalyzer::getVertexCoords() {
483  std::vector<double> crd;
484  for (int iVrt = 0; iVrt < nVertex; ++iVrt) {
485  crd.push_back(xCrd[iVrt]);
486  crd.push_back(yCrd[iVrt]);
487  crd.push_back(zCrd[iVrt]);
488  }
489  return crd;
490 }
491 
492 std::vector<double> cgnsAnalyzer::getVertexCoords(int vrtxId) {
493  std::vector<double> crd;
494  if (vrtxId > nVertex || vrtxId < 0) {
495  std::cerr << "Requested index is out of bounds." << std::endl;
496  return crd;
497  }
498  crd.push_back(xCrd[vrtxId]);
499  crd.push_back(yCrd[vrtxId]);
500  crd.push_back(zCrd[vrtxId]);
501  return crd;
502 }
503 
504 double cgnsAnalyzer::getVrtXCrd(int vrtxId) { return xCrd[vrtxId]; }
505 
506 std::vector<double> cgnsAnalyzer::getVrtXCrd() { return xCrd; }
507 
508 double cgnsAnalyzer::getVrtYCrd(int vrtxId) { return yCrd[vrtxId]; }
509 
510 std::vector<double> cgnsAnalyzer::getVrtYCrd() { return yCrd; }
511 
512 double cgnsAnalyzer::getVrtZCrd(int vrtxId) { return zCrd[vrtxId]; }
513 
514 std::vector<double> cgnsAnalyzer::getVrtZCrd() { return zCrd; }
515 
516 /*
517  Returns element connectivity for given element index.
518  Input
519  elemId : element index (-1 all elements)
520 
521  Output
522  connectivity of the element.
523 
524 */
525 std::vector<cgsize_t> cgnsAnalyzer::getElementConnectivity(int elemId) {
526  std::vector<cgsize_t> elmConn;
527  int nNdeElm = 0;
528  if (elemId > nElem) {
529  std::cerr << "Element index is out of bounds.\n";
530  return elmConn;
531  }
532  // return the whole connectivity if requested
533  if (elemId == -1) { return elemConn; }
534  // returning individual element connectivity
535  switch (sectionType) {
536  case CGNS_ENUMV(TETRA_4): nNdeElm = 4; break;
537  case CGNS_ENUMV(HEXA_8): nNdeElm = 8; break;
538  case CGNS_ENUMV(TRI_3):
539  nNdeElm = 3;
540  elemConn.resize(3 * nElem, -1);
541  break;
542  case CGNS_ENUMV(QUAD_4): nNdeElm = 4; break;
543  case CGNS_ENUMV(TETRA_10): nNdeElm = 10; break;
544  default:
545  std::cerr << "Unknown element type " << sectionType << std::endl;
546  break;
547  }
548  for (int iNde = elemId * nNdeElm; iNde < (elemId + 1) * nNdeElm; ++iNde)
549  elmConn.push_back(elemConn[iNde]);
550 
551  return elmConn;
552 }
553 
554 void cgnsAnalyzer::getSectionNames(std::vector<std::string> &names) {
555  // reading section names
556  int nBdry, parentFlag;
557  cgsize_t eBeg, eEnd;
558  CGNS_ENUMT(ElementType_t) secTyp;
559  char sectionname[33];
560  if (cg_nsections(indexFile, indexBase, indexZone, &nSection) != CG_OK)
561  std::cerr << "Error in reading sections, " << cg_get_error();
562  for (int iSec = 1; iSec <= nSection; iSec++) {
563  if (cg_section_read(indexFile, indexBase, indexZone, iSec, sectionname,
564  &secTyp, &eBeg, &eEnd, &nBdry, &parentFlag) != CG_OK)
565  std::cerr << "Error in load, " << cg_get_error() << std::endl;
566  names.push_back(sectionname);
567  if (_verb)
568  std::cout << "Section " << names[iSec] << " Type = " << secTyp
569  << " eBeg = " << eBeg << " eEnd = " << eEnd
570  << " nBdry = " << nBdry << std::endl;
571  }
572 }
573 
574 CGNS_ENUMT(ElementType_t) cgnsAnalyzer::getSectionType(std::string secName) {
575  std::vector<std::string> secNames;
576  getSectionNames(secNames);
577  auto it = std::find(secNames.begin(), secNames.end(), secName);
578  if (it == secNames.end()) {
579  std::cerr << "No section found named " << secName << "\n";
580  throw;
581  }
582  int iSec = it - secNames.begin();
583 
584  // reading section info
585  int nBdry, parentFlag;
586  cgsize_t eBeg, eEnd;
587  CGNS_ENUMT(ElementType_t) secTyp;
588  char sectionname[33];
589  if (cg_section_read(indexFile, indexBase, indexZone, iSec, sectionname,
590  &secTyp, &eBeg, &eEnd, &nBdry, &parentFlag) != CG_OK)
591  std::cerr << "Error in load, " << cg_get_error() << std::endl;
592  return secTyp;
593 }
594 
595 void cgnsAnalyzer::getSectionConn(std::string secName,
596  std::vector<cgsize_t> &conn, int &nElm) {
597  std::vector<std::string> secNames;
598  getSectionNames(secNames);
599  auto it = std::find(secNames.begin(), secNames.end(), secName);
600  if (it == secNames.end()) {
601  std::cerr << "No section found named " << secName << "\n";
602  nElm = 0;
603  return;
604  }
605  // reading connectivities
606  int nBdry, parentFlag, nVrtxElem;
607  cgsize_t eBeg, eEnd;
608  char sectionname[33];
609  CGNS_ENUMT(ElementType_t) secTyp;
610  int iSec = it - secNames.begin() + 1;
611  if (cg_section_read(indexFile, indexBase, indexZone, iSec, sectionname,
612  &secTyp, &eBeg, &eEnd, &nBdry, &parentFlag) != CG_OK)
613  std::cerr << "Error in load, " << cg_get_error() << std::endl;
614  switch (secTyp) {
615  case CGNS_ENUMV(TETRA_4): nVrtxElem = 4; break;
616  case CGNS_ENUMV(HEXA_8): nVrtxElem = 8; break;
617  case CGNS_ENUMV(TRI_3): nVrtxElem = 3; break;
618  case CGNS_ENUMV(QUAD_4): nVrtxElem = 4; break;
619  case CGNS_ENUMV(TETRA_10): nVrtxElem = 10; break;
620  default: std::cerr << "Unknown element type " << secTyp << std::endl; break;
621  }
622  nElm = eEnd - eBeg + 1;
623  conn.resize(nVrtxElem * nElm, -1);
624  if (cg_elements_read(indexFile, indexBase, indexZone, iSec, &conn[0],
625  nullptr) != CG_OK)
626  std::cerr << "Error in load, " << cg_get_error() << std::endl;
627  if (_verb)
628  std::cout << "Size of connectivity vector = " << conn.size() << std::endl;
629 }
630 
631 vtkSmartPointer<vtkDataSet> cgnsAnalyzer::getSectionMesh(std::string secName) {
632  // rind information test
633  int rdata[2];
634  if (cg_goto(indexFile, indexBase, "Zone_t", indexZone, "GridCoordinates", 0,
635  "end"))
636  cg_error_exit();
637  if (cg_rind_read(rdata)) cg_error_exit();
638  int nRindNde = rdata[1];
639  cgsize_t one = 1;
640  cgsize_t rmax = nVertex + nRindNde;
641  // reading all coordinates
642  std::vector<double> xCrdR, yCrdR, zCrdR;
643  xCrdR.resize(rmax, 0);
644  yCrdR.resize(rmax, 0);
645  zCrdR.resize(rmax, 0);
646  if (cg_coord_read(indexFile, indexBase, indexZone, "CoordinateX",
647  CGNS_ENUMV(RealDouble), &one, &rmax, &xCrdR[0]) != CG_OK)
648  std::cerr << "Error in load, " << cg_get_error() << std::endl;
649  if (cg_coord_read(indexFile, indexBase, indexZone, "CoordinateY",
650  CGNS_ENUMV(RealDouble), &one, &rmax, &yCrdR[0]) != CG_OK)
651  std::cerr << "Error in load, " << cg_get_error() << std::endl;
652  if (cg_coord_read(indexFile, indexBase, indexZone, "CoordinateZ",
653  CGNS_ENUMV(RealDouble), &one, &rmax, &zCrdR[0]) != CG_OK)
654  std::cerr << "Error in load, " << cg_get_error() << std::endl;
655  int nElmSec;
656  std::vector<cgsize_t> connSec;
657  getSectionConn(secName, connSec, nElmSec);
658  CGNS_ENUMT(ElementType_t) secTyp = getSectionType(secName);
659 
660  // points to be pushed into dataSet
661  vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
662  // declare vtk dataset
663  vtkSmartPointer<vtkUnstructuredGrid> dataSet_tmp =
665 
666  // allocate size for vtk point container
667  points->SetNumberOfPoints(rmax);
668  for (int i = 0; i < rmax; ++i)
669  points->SetPoint(i, xCrdR[i], yCrdR[i], zCrdR[i]);
670 
671  // add points to vtk mesh data structure
672  dataSet_tmp->SetPoints(points);
673 
674  // allocate space for elements
675  dataSet_tmp->Allocate(nElmSec);
676  // add the elements
677  int nNdeElm = connSec.size() / nElmSec;
678  for (int i = 0; i < nElmSec; i++) {
679  vtkSmartPointer<vtkIdList> vtkElmIds = vtkSmartPointer<vtkIdList>::New();
680  vtkElmIds->SetNumberOfIds(nNdeElm);
681  for (int j = 0; j < nNdeElm; ++j)
682  vtkElmIds->SetId(j, connSec[i * nNdeElm + j] - 1);
683  switch (secTyp) {
684  case CGNS_ENUMV(TETRA_4):
685  dataSet_tmp->InsertNextCell(VTK_TETRA, vtkElmIds);
686  break;
687  case CGNS_ENUMV(HEXA_8):
688  dataSet_tmp->InsertNextCell(VTK_HEXAHEDRON, vtkElmIds);
689  break;
690  case CGNS_ENUMV(TRI_3):
691  dataSet_tmp->InsertNextCell(VTK_TRIANGLE, vtkElmIds);
692  break;
693  case CGNS_ENUMV(QUAD_4):
694  dataSet_tmp->InsertNextCell(VTK_QUAD, vtkElmIds);
695  break;
696  case CGNS_ENUMV(TETRA_10):
697  dataSet_tmp->InsertNextCell(VTK_QUADRATIC_TETRA, vtkElmIds);
698  break;
699  default:
700  std::cerr << "Unknown element type " << sectionType << std::endl;
701  break;
702  }
703  }
704  return (dataSet_tmp);
705 }
706 
708  /*
709  dimension statements (note that tri-dimensional arrays
710  x,y,z must be dimensioned exactly as [N][17][21] (N>=9)
711  for this particular case or else they will be written to
712  the CGNS file incorrectly! Other options are to use 1-D
713  arrays, use dynamic memory, or pass index values to a
714  subroutine and dimension exactly there):
715  */
716  double x[9][17][21], y[9][17][21], z[9][17][21];
717  cgsize_t isize[3][3];
718  int ni, nj, nk, i, j, k;
719  int indexFile, icelldim, iphysdim, indexBase;
720  int indexZone, indexCoord;
721  char basename[33], zonename[33];
722 
723  /* create grid points for simple example: */
724  ni = 21;
725  nj = 17;
726  nk = 9;
727  for (k = 0; k < nk; ++k) {
728  for (j = 0; j < nj; ++j) {
729  for (i = 0; i < ni; ++i) {
730  x[k][j][i] = i;
731  y[k][j][i] = j;
732  z[k][j][i] = k;
733  }
734  }
735  }
736  printf("\ncreated simple 3-D grid points");
737 
738  /* WRITE X, Y, Z GRID POINTS TO CGNS FILE */
739  /* open CGNS file for write */
740  if (cg_open(cgFileName.c_str(), CG_MODE_WRITE, &indexFile)) cg_error_exit();
741  /* create base (user can give any name) */
742  strcpy(basename, "Base");
743  icelldim = 3;
744  iphysdim = 3;
745  cg_base_write(indexFile, basename, icelldim, iphysdim, &indexBase);
746  /* define zone name (user can give any name) */
747  strcpy(zonename, "Zone 1");
748  /* vertex size */
749  isize[0][0] = 21;
750  isize[0][1] = 17;
751  isize[0][2] = 9;
752  /* cell size */
753  isize[1][0] = isize[0][0] - 1;
754  isize[1][1] = isize[0][1] - 1;
755  isize[1][2] = isize[0][2] - 1;
756  /* boundary vertex size (always zero for structured grids) */
757  isize[2][0] = 0;
758  isize[2][1] = 0;
759  isize[2][2] = 0;
760  /* create zone */
761  cg_zone_write(indexFile, indexBase, zonename, *isize, CGNS_ENUMV(Structured),
762  &indexZone);
763  /* write grid coordinates (user must use SIDS-standard names here) */
764  cg_coord_write(indexFile, indexBase, indexZone, CGNS_ENUMV(RealDouble),
765  "CoordinateX", x, &indexCoord);
766  cg_coord_write(indexFile, indexBase, indexZone, CGNS_ENUMV(RealDouble),
767  "CoordinateY", y, &indexCoord);
768  cg_coord_write(indexFile, indexBase, indexZone, CGNS_ENUMV(RealDouble),
769  "CoordinateZ", z, &indexCoord);
770 }
771 
773  /*
774  dimension statements (note that tri-dimensional arrays
775  x,y,z must be dimensioned exactly as [N][17][21] (N>=9)
776  for this particular case or else they will be written to
777  the CGNS file incorrectly! Other options are to use 1-D
778  arrays, use dynamic memory, or pass index values to a
779  subroutine and dimension exactly there):
780  */
781  double x[9][17][21], y[9][17][21], z[9][17][21];
782  cgsize_t isize[3][3];
783  int ni, nj, nk, i, j, k;
784  int indexFile, icelldim, iphysdim, indexBase;
785  int indexZone, indexCoord, indexSection;
786  int index_flow, index_field;
787  char basename[33], zonename[33];
788 
789  /* create gridpoints for simple example: */
790  ni = 21;
791  nj = 17;
792  nk = 9;
793  for (k = 0; k < nk; ++k) {
794  for (j = 0; j < nj; ++j) {
795  for (i = 0; i < ni; ++i) {
796  x[k][j][i] = i;
797  y[k][j][i] = j;
798  z[k][j][i] = k;
799  }
800  }
801  }
802  printf("\nCreated simple 3-D grid points");
803 
804  /* WRITE X, Y, Z GRID POINTS TO CGNS FILE */
805  /* open CGNS file for write */
806  if (cg_open(cgFileName.c_str(), CG_MODE_WRITE, &indexFile)) cg_error_exit();
807  /* create base (user can give any name) */
808  strcpy(basename, "Base");
809  icelldim = 3;
810  iphysdim = 3;
811  cg_base_write(indexFile, basename, icelldim, iphysdim, &indexBase);
812  /* define zone name (user can give any name) */
813  strcpy(zonename, "Zone 1");
814  /* vertex size */
815  isize[0][0] = 21 * 17 * 9;
816  isize[0][1] = 20 * 16 * 8;
817  isize[0][2] = 0;
818  /* create zone */
819  cg_zone_write(indexFile, indexBase, zonename, *isize,
820  CGNS_ENUMV(Unstructured), &indexZone);
821  /* write grid coordinates (user must use SIDS-standard names here) */
822  cg_coord_write(indexFile, indexBase, indexZone, CGNS_ENUMV(RealDouble),
823  "CoordinateX", x, &indexCoord);
824  cg_coord_write(indexFile, indexBase, indexZone, CGNS_ENUMV(RealDouble),
825  "CoordinateY", y, &indexCoord);
826  cg_coord_write(indexFile, indexBase, indexZone, CGNS_ENUMV(RealDouble),
827  "CoordinateZ", z, &indexCoord);
828  /* write connectivities */
829  cgsize_t elemConn[8][20 * 16 * 8];
830  int iElem = -1;
831  /* index of first element */
832  int nElemStart = 1;
833  for (k = 1; k < nk; ++k) {
834  for (j = 1; j < nj; ++j) {
835  for (i = 1; i < ni; ++i) {
836  iElem++;
837  int ifirstNode = i + (j - 1) * ni + (k - 1) * ni * nj;
838  elemConn[0][iElem] = ifirstNode;
839  elemConn[1][iElem] = ifirstNode + 1;
840  elemConn[2][iElem] = ifirstNode + 1 + ni;
841  elemConn[3][iElem] = ifirstNode + ni;
842  elemConn[4][iElem] = ifirstNode + ni * nj;
843  elemConn[5][iElem] = ifirstNode + ni * nj + 1;
844  elemConn[6][iElem] = ifirstNode + ni * nj + 1 + ni;
845  elemConn[7][iElem] = ifirstNode + ni * nj + ni;
846  }
847  }
848  }
849  /* index of last element */
850  int nElemEnd = iElem;
851  /* unsorted boundary elements */
852  int nBdyElem = 0;
853  /* write HEX_8 element connectivity (user can give any name) */
854  cg_section_write(indexFile, indexBase, indexZone, "Elem", CGNS_ENUMV(HEXA_8),
855  nElemStart, nElemEnd, nBdyElem, elemConn[0], &indexSection);
856  /* write vertex based field data */
857  std::string solName = "solution";
858  cg_sol_write(indexFile, indexBase, indexZone, solName.c_str(),
859  CGNS_ENUMV(Vertex), &index_flow);
860  std::vector<double> T;
861  T.resize(isize[0][0], 10);
862  cg_field_write(indexFile, indexBase, indexZone, index_flow,
863  CGNS_ENUMV(RealDouble), "T", &T[0], &index_field);
864  /* close CGNS file */
865  cg_close(indexFile);
866 }
867 
869  // clearing all data related maps and fields
870  nSolution = 0;
871  nField = 0;
872  solutionNameLocMap.clear();
873  solutionName.clear();
874  solutionGridLocation.clear();
875  solutionMap.clear();
876  appendedSolutionName.clear();
877  // clearing all solution data objects
878  for (auto &it : slnDataCont) delete it;
879  slnDataCont.clear();
880  solutionDataPopulated = false;
881 }
882 
883 // lists all solution based data
885  // only one time needed for each zone
886  if (solutionDataPopulated) return;
887  // populating solution data
888  char fieldName[33];
889  char solName[33];
890  CGNS_ENUMT(GridLocation_t) gloc;
891  int nFlds;
892  int cntr = 0;
893  CGNS_ENUMT(DataType_t) dt;
894  // number of solution fields
895  cg_nsols(indexFile, indexBase, indexZone, &nSolution);
896  for (int iSol = 1; iSol <= nSolution; ++iSol) {
897  std::pair<int, keyValueList> slnPair;
898  keyValueList fldIndxSln;
899  cg_sol_info(indexFile, indexBase, indexZone, iSol, solName, &gloc);
900  cg_nfields(indexFile, indexBase, indexZone, iSol, &nFlds);
901  solutionNameLocMap[solName] = gloc;
902  for (int iFld = 1; iFld <= nFlds; ++iFld) {
903  // name and location
904  solutionName.push_back(solName);
905  solutionGridLocation.push_back(gloc);
906  // field information
907  cg_field_info(indexFile, indexBase, indexZone, iSol, iFld, &dt,
908  fieldName);
909  fldIndxSln[iFld] = fieldName;
910  }
911  slnPair.first = iSol;
912  slnPair.second = fldIndxSln;
913  solutionMap[cntr++] = slnPair;
914  }
915  solutionDataPopulated = true;
916 }
917 
918 void cgnsAnalyzer::getSolutionDataNames(std::vector<std::string> &list) {
919  populateSolutionDataNames();
920  for (auto &it : solutionMap) {
921  std::pair<int, keyValueList> slnIndxListPair = it.second;
922  keyValueList fldIndxSln = slnIndxListPair.second;
923  for (auto &it2 : fldIndxSln) { list.push_back(it2.second); }
924  }
925 }
926 
927 /*
928  Given solution name provides solution vector by reading from the CGNS file
929  and processing it. Also passes the type of solution in the return. The
930  solution type (2) for CG_Vertex based and (3) for the element based. Types
931  are in agreement with CG_GridLocation_t definition provided by CGNS API.
932  NOTE: It is assumed that vector-valued nodal and element data are
933  decomposed into scalar fields.
934 */
936  std::vector<double> &slnData) {
937  CGNS_ENUMT(DataType_t) dt;
938  char fieldName[33];
939  int slnCntr = -1;
940  int slnIndx = -1;
941  int fldIndx = -1;
942  int dataType = -1;
943  // find the solution index
944  for (auto &it : solutionMap) {
945  std::pair<int, keyValueList> slnIndxListPair = it.second;
946  keyValueList fldIndxSln = slnIndxListPair.second;
947  for (auto &it2 : fldIndxSln) {
948  slnCntr++;
949  if (!((it2.second).compare(sName))) {
950  fldIndx = it2.first;
951  slnIndx = slnIndxListPair.first;
952  break;
953  }
954  }
955  if (slnIndx != -1) break;
956  }
957  // fail check
958  if (slnIndx == -1) {
959  std::cerr << "The solution name " << sName << " does not exist.\n";
961  }
962  // check if data exists
963  if (cg_field_info(indexFile, indexBase, indexZone, slnIndx, fldIndx, &dt,
964  fieldName) != CG_OK)
965  std::cerr << "Error in reading solution, " << cg_get_error() << std::endl;
966  // reading actual data from the file
967  cgsize_t one = 1;
968  dataType = solutionGridLocation[slnCntr];
969  if (isUnstructured) {
970  if (dataType == CGNS_ENUMV(Vertex)) {
971  slnData.resize(nVertex, -1.0);
972  rmax[0] = nVertex;
973  } else if (dataType == CGNS_ENUMV(CellCenter)) {
974  slnData.resize(nElem, -1.0);
975  rmax[0] = nElem;
976  } else {
977  std::cerr << "Unknown data gird location "
978  << solutionGridLocation[slnCntr] << std::endl;
980  }
981  } else {
982  if (dataType == CGNS_ENUMV(Vertex)) {
983  slnData.resize(nVertex, -1.0);
984  rmax[0] = cgCoreSize[0];
985  rmax[1] = cgCoreSize[1];
986  rmax[2] = cgCoreSize[2];
987  } else if (dataType == CGNS_ENUMV(CellCenter)) {
988  slnData.resize(nElem, -1.0);
989  rmax[0] = cgCoreSize[3];
990  rmax[1] = cgCoreSize[4];
991  rmax[2] = cgCoreSize[5];
992  } else {
993  std::cerr << "Unknown data gird location "
994  << solutionGridLocation[slnCntr] << std::endl;
996  }
997  }
998 
999  if (isUnstructured) {
1000  if (dt == CGNS_ENUMV(RealDouble)) {
1001  // for double solution data
1002  if (cg_field_read(indexFile, indexBase, indexZone, slnIndx, fieldName, dt,
1003  &one, &rmax[0], &slnData[0]) != CG_OK)
1004  std::cerr << "Error in reading solution data, " << cg_get_error()
1005  << std::endl;
1006  } else if (dt == CGNS_ENUMV(Integer)) {
1007  // for integer solution data
1008  std::vector<int> tmpSlnData;
1009  tmpSlnData.resize(rmax[0], -1);
1010  if (cg_field_read(indexFile, indexBase, indexZone, slnIndx, fieldName, dt,
1011  &one, &rmax[0], &tmpSlnData[0]) != CG_OK)
1012  std::cerr << "Error in reading solution data, " << cg_get_error()
1013  << std::endl;
1014  slnData.clear();
1015  for (int &it : tmpSlnData) slnData.push_back(it);
1016  }
1017  } else {
1018  if (cg_field_read(indexFile, indexBase, indexZone, slnIndx, fieldName, dt,
1019  &rmin[0], &rmax[0], &slnData[0]) != CG_OK)
1020  std::cerr << "Error in reading solution data, " << cg_get_error()
1021  << std::endl;
1022  }
1023 
1024  // returns the type of the data
1025  return (dataType == 2 ? solution_type_t::NODAL : solution_type_t::ELEMENTAL);
1026 }
1027 
1028 /*
1029  Returns pointer to the solutionData class containing solution
1030  information with the given name.
1031 */
1033  // return pointer if already loaded
1034  if (!slnDataCont.empty()) {
1035  for (auto &is : slnDataCont) {
1036  if (!strcmp((is->getDataName()).c_str(), sName.c_str())) { return is; }
1037  }
1038  }
1039  // load if needed
1040  std::vector<double> slnData;
1041  solution_type_t dataType = getSolutionData(sName, slnData);
1042  if (dataType == solution_type_t::UNKNOWN) {
1043  std::cerr << "Unknown data type is not supported.!\n";
1044  return nullptr;
1045  }
1046  // allocating new data object
1047  solutionData *slnDataObjPtr = new solutionData(sName, dataType);
1048  if (dataType == solution_type_t::NODAL) {
1049  slnDataObjPtr->appendData(slnData, slnData.size(), 1);
1050  } else {
1051  slnDataObjPtr->appendData(slnData, slnData.size(), 1);
1052  }
1053  return slnDataObjPtr;
1054 }
1055 
1057  int nVrtData = 0;
1058 
1059  // loading data if not yet
1060  if (slnDataCont.empty()) loadSolutionDataContainer();
1061 
1062  // number of vertex solution data
1063  for (auto &is : slnDataCont)
1064  if (is->getDataType() == solution_type_t::NODAL) nVrtData++;
1065 
1066  return nVrtData;
1067 }
1068 
1070  int nCellData = 0;
1071 
1072  // loading data if not yet
1073  if (slnDataCont.empty()) loadSolutionDataContainer();
1074 
1075  // number of vertex solution data
1076  for (auto &is : slnDataCont)
1077  if (is->getDataType() == solution_type_t::ELEMENTAL) nCellData++;
1078 
1079  return nCellData;
1080 }
1081 
1083  std::string sName, std::vector<double> &slnData, int &outNData,
1084  int &outNDim) {
1085  // load data if needed
1086  if (slnDataCont.empty()) loadSolutionDataContainer();
1087 
1088  for (auto &is : slnDataCont) {
1089  if (!strcmp((is->getDataName()).c_str(), sName.c_str())) {
1090  is->getData(slnData, outNData, outNDim);
1091  return (is->getDataType());
1092  }
1093  }
1094  return solution_type_t::UNKNOWN;
1095 }
1096 
1097 void cgnsAnalyzer::appendSolutionData(std::string sName,
1098  std::vector<double> &slnData,
1099  solution_type_t dt, int inNData,
1100  int inNDim) {
1101  // load data if needed
1102  if (slnDataCont.empty()) loadSolutionDataContainer();
1103 
1104  solutionData *nwSlnPtr = new solutionData(sName, dt);
1105  nwSlnPtr->appendData(slnData, inNData, inNDim);
1106  slnDataCont.push_back(nwSlnPtr);
1107  appendedSolutionName.push_back(sName);
1108 }
1109 
1110 void cgnsAnalyzer::appendSolutionData(std::string sName, double slnData,
1111  solution_type_t dt, int inNData,
1112  int inNDim) {
1113  // load data if needed
1114  if (slnDataCont.empty()) loadSolutionDataContainer();
1115  solutionData *nwSlnPtr = new solutionData(sName, dt);
1116  // convert to vector
1117  std::vector<double> slnDataVec;
1118  slnDataVec.resize(inNData, slnData);
1119  nwSlnPtr->appendData(slnDataVec, inNData, inNDim);
1120  // register
1121  slnDataCont.push_back(nwSlnPtr);
1122  appendedSolutionName.push_back(sName);
1123 }
1124 
1125 bool cgnsAnalyzer::delAppSlnData(std::string sName) {
1126  for (auto is = appendedSolutionName.begin(); is != appendedSolutionName.end();
1127  ++is)
1128  if (strcmp(sName.c_str(), (*is).c_str()) == 0) {
1129  delete getSolutionDataObj(sName);
1130  appendedSolutionName.erase(is);
1131  return true;
1132  }
1133  return false;
1134 }
1135 
1137  std::vector<std::string> &appSName) {
1138  appSName.insert(appSName.end(), appendedSolutionName.begin(),
1139  appendedSolutionName.end());
1140 }
1141 
1142 /* provides node names in which solution data are stored in */
1143 std::vector<std::string> cgnsAnalyzer::getSolutionNodeNames() {
1144  return solutionName;
1145 }
1146 
1147 /* provides the list of solution types */
1148 std::vector<CGNS_ENUMT(GridLocation_t)>
1150  return solutionGridLocation;
1151 }
1152 
1153 /* provides solution map */
1154 std::map<int, std::pair<int, keyValueList>> cgnsAnalyzer::getSolutionMap() {
1155  return solutionMap;
1156 }
1157 
1158 /* gets a map between solution node name and solution location type */
1159 std::map<std::string, CGNS_ENUMT(GridLocation_t)>
1161  return solutionNameLocMap;
1162 }
1163 
1165  if (!vtkMesh) {
1166  // remove rind data if any
1167  cleanRind();
1168  // points to be pushed into dataSet
1169  vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
1170  // declare vtk dataset
1171  vtkSmartPointer<vtkUnstructuredGrid> dataSet_tmp =
1173  // allocate size for vtk point container
1174  points->SetNumberOfPoints(nVertex);
1175  for (int i = 0; i < nVertex; ++i) {
1176  points->SetPoint(i, xCrd[i], yCrd[i], zCrd[i]);
1177  }
1178  // add points to vtk mesh data structure
1179  dataSet_tmp->SetPoints(points);
1180  // allocate space for elements
1181  dataSet_tmp->Allocate(nElem);
1182  // add the elements
1183  for (int i = 0; i < nElem; ++i) {
1184  vtkSmartPointer<vtkIdList> vtkElmIds = vtkSmartPointer<vtkIdList>::New();
1185  std::vector<cgsize_t> cgnsElmIds(getElementConnectivity(i));
1186  vtkElmIds->SetNumberOfIds(cgnsElmIds.size());
1187  for (int j = 0; j < cgnsElmIds.size(); ++j) {
1188  vtkElmIds->SetId(j, cgnsElmIds[j] - 1);
1189  }
1190  switch (sectionType) {
1191  case CGNS_ENUMV(TETRA_4):
1192  dataSet_tmp->InsertNextCell(VTK_TETRA, vtkElmIds);
1193  break;
1194  case CGNS_ENUMV(HEXA_8):
1195  dataSet_tmp->InsertNextCell(VTK_HEXAHEDRON, vtkElmIds);
1196  break;
1197  case CGNS_ENUMV(TRI_3):
1198  dataSet_tmp->InsertNextCell(VTK_TRIANGLE, vtkElmIds);
1199  break;
1200  case CGNS_ENUMV(QUAD_4):
1201  dataSet_tmp->InsertNextCell(VTK_QUAD, vtkElmIds);
1202  break;
1203  case CGNS_ENUMV(TETRA_10):
1204  dataSet_tmp->InsertNextCell(VTK_QUADRATIC_TETRA, vtkElmIds);
1205  break;
1206  default:
1207  std::cerr << "Unknown element type " << sectionType << std::endl;
1208  break;
1209  }
1210  }
1211  vtkMesh = dataSet_tmp;
1212  }
1213 }
1214 
1216  // loading data if not yet
1217  if (slnDataCont.empty()) loadSolutionDataContainer();
1218  // write individual data fields
1219  int iSol = -1;
1220  for (auto &is : solutionMap) {
1221  std::pair<int, keyValueList> slnPair = is.second;
1222  int slnIdx = slnPair.first;
1223  keyValueList fldLst = slnPair.second;
1224  for (auto &ifl : fldLst) {
1225  iSol++;
1226  std::vector<double> newData;
1227  if (solutionGridLocation[iSol] == CGNS_ENUMV(Vertex)) {
1228  mbObj->getPointDataArray(ifl.second, newData);
1229  } else {
1230  // gs field is weird in irocstar files we don't write it back
1231  // if (/*!(ifl->second).compare("gs") ||*/
1232  // !(ifl.second).compare("mdot_old"))
1233  //
1234  // TJW: Removed condition above because we now write out gs
1235  // We don't write out mdot_old because it is only on burning surfaces;
1236  // when we stitch burning with non-interacting surfaces (which don't
1237  // have mdot_old), the VTK stitcher utility only keeps fields that both
1238  // surfaces have
1239  if (!(ifl.second).compare("mdot_old")) { continue; }
1240  mbObj->getCellDataArray(ifl.second, newData);
1241  }
1242  std::cout << "Writing " << newData.size() << " to " << ifl.second
1243  << " located in " << solutionName[iSol] << std::endl;
1244  // write to file
1245  if (!(ifl.second)
1246  .compare(
1247  "bflag")) // cg_io complains if this isn't CG_Integer type
1248  // if (slnDataCont[slnIdx]->getDataType() == CGNS_ENUMV(Integer) ||
1249  // !(ifl.second).compare("bflag"))
1250  {
1251  // need to cast to int before passing as void*
1252  std::vector<int> newDataToInt(newData.begin(), newData.end());
1253  overwriteSolData(ifl.second, solutionName[iSol], slnIdx,
1254  CGNS_ENUMV(Integer), &newDataToInt[0]);
1255  } else
1256  overwriteSolData(ifl.second, solutionName[iSol], slnIdx,
1257  CGNS_ENUMV(RealDouble), &newData[0]);
1258  }
1259  }
1260 }
1261 
1262 void cgnsAnalyzer::overwriteSolData(const std::string &fname,
1263  const std::string &ndeName, int slnIdx,
1264  CGNS_ENUMT(DataType_t) dt, void *data) {
1265  // write solution to file
1266  CGNS_ENUMT(GridLocation_t) gloc(solutionNameLocMap[fname]);
1267  int fldIdx;
1268  if (cg_field_write(indexFile, indexBase, indexZone, slnIdx, dt, fname.c_str(),
1269  data, &fldIdx))
1270  cg_error_exit();
1271  // finding range of data
1272  double *tmpData = (double *)data;
1273  double min = tmpData[0];
1274  double max = tmpData[0];
1275  int nItr = 0;
1276  if (gloc == CGNS_ENUMV(Vertex)) {
1277  nItr = nVertex;
1278  } else {
1279  nItr = nElem;
1280  }
1281  for (int it = 0; it < nItr; ++it) {
1282  min = std::min(tmpData[it], min);
1283  max = std::max(tmpData[it], max);
1284  }
1285  // writing range descriptor
1286  std::ostringstream os;
1287  os << min << ", " << max;
1288  std::string range = os.str();
1289  if (cg_goto(indexFile, indexBase, "Zone_t", indexZone, "FlowSolution_t",
1290  slnIdx, "DataArray_t", fldIdx, "end"))
1291  cg_error_exit();
1292  if (cg_descriptor_write("Range", range.c_str())) cg_error_exit();
1293  // write DimensionalExponents and units for cell data
1294  if (gloc == CGNS_ENUMV(CellCenter)) {
1295  if (cg_goto(indexFile, indexBase, "Zone_t", indexZone, "FlowSolution_t",
1296  slnIdx, "DataArray_t", fldIdx, "end"))
1297  cg_error_exit();
1298  // dummy exponents and units
1299  float exponents[5] = {0, 0, 0, 0, 0};
1300  if (cg_exponents_write(CGNS_ENUMV(RealSingle), exponents)) cg_error_exit();
1301  if (cg_descriptor_write("Units", "dmy")) cg_error_exit();
1302  }
1303 }
1304 
1305 void cgnsAnalyzer::exportToMAdMesh(const MAd::pMesh MAdMesh) {
1306  // --- Build the vertices ---
1307  MAdToCgnsIds.clear();
1308  cgnsToMAdIds.clear();
1309  for (int iV = 0; iV < nVertex; ++iV) {
1310  MAdMesh->add_point(iV + 1, xCrd[iV], yCrd[iV], zCrd[iV]);
1311  cgnsToMAdIds[iV] = iV + 1;
1312  MAdToCgnsIds[iV + 1] = iV;
1313  }
1314 
1315  // --- Build the elements ---
1316  if (physDim == 3) switch (sectionType) {
1317  case CGNS_ENUMV(TETRA_4): {
1318  for (int iC = 0; iC < nElem; ++iC) {
1319  int iN = iC * 4;
1320  // the last argument for the next function is just a dummy now
1321  MAd::pGEntity geom =
1322  (MAd::pGEntity)MAd::GM_regionByTag(MAdMesh->model, 0);
1323  // geom->setPhysical(3,1);
1324  MAd::MDB_Tet *tet =
1325  MAdMesh->add_tet(elemConn[iN], elemConn[iN + 1], elemConn[iN + 2],
1326  elemConn[iN + 3], geom);
1327  // changing tet ID
1328  tet->iD = iC + 1;
1329  }
1330  } break;
1331  case CGNS_ENUMV(TRI_3): {
1332  for (int iC = 0; iC < nElem; ++iC) {
1333  int iN = iC * 3;
1334  // the last argument for the next function is just a dummy now
1335  MAd::pGEntity geom =
1336  (MAd::pGEntity)MAd::GM_faceByTag(MAdMesh->model, 0);
1337  MAdMesh->add_triangle(elemConn[iN], elemConn[iN + 1],
1338  elemConn[iN + 2], geom);
1339  }
1340  } break;
1341  default:
1342  std::cerr << "Current version only works for TRI and TET elements. "
1343  "Element type "
1344  << sectionType << " is not supported." << std::endl;
1345  break;
1346  }
1347 }
1348 
1349 void cgnsAnalyzer::classifyMAdMeshOpt(const MAd::pMesh MAdMesh) {
1350  /*
1351  Here, the entities of the MAdLib mesh should be classified
1352  on their corresponding geometrical entities, like for boundary
1353  faces in 3D for instance. The implementation of this step
1354  is highly dependent on the implementation of Solver_mesh and
1355  Solver_model so it is up to the reader to add the right
1356  instructions here.
1357 
1358  Note that the geometrical entities have been created in the
1359  execution of 'exportToMAdModel'. Any mesh entity can be
1360  associated to a geometrical entity using the EN_setWhatIn(...)
1361  function of the MAdLib mesh interface.
1362 
1363  Note that all the steps involving geometrical entities can be
1364  replaced by appropriate constraints on boundary mesh entities
1365  (see AdaptInterface.h) but no mesh modification will therefore
1366  be applied on the boundaries, which can be problematic for some
1367  computations.
1368  */
1369  // finding boundary faces and classifying them as 2 dimensional
1370  // MAd::pGEntity bnd = (MAd::pGEntity) MAd::GM_faceByTag(MAdMesh->model, 0);
1371  // MAdMesh->classify_grid_boundaries(bnd);
1372  // classifying the rest of the domain (faces, edges, vertices)
1373  // the element geometric region properties will be used by them.
1374  MAdMesh->classify_unclassified_entities();
1375  MAdMesh->destroyStandAloneEntities();
1376 }
1377 
1378 void cgnsAnalyzer::classifyMAdMeshBnd(const MAd::pMesh MAdMesh) {
1379  // finding boundary faces and classifying them as 2 dimensional
1380  MAd::pGEntity bnd = (MAd::pGEntity)MAd::GM_faceByTag(MAdMesh->model, 0);
1381  MAdMesh->classify_grid_boundaries(bnd);
1382 }
1383 
1384 void cgnsAnalyzer::unclassifyMAdMeshBnd(const MAd::pMesh MAdMesh) {
1385  // finding boundary faces and classifying them as 2 dimensional
1386  MAdMesh->unclassify_grid_boundaries();
1387 }
1388 
1390  // ANNpointArray vrtxCrd;
1391  if (vrtxCrd) annDeallocPts(vrtxCrd);
1392  // clearing onld instance
1393  vrtxCrd = annAllocPts(nVertex, physDim);
1394  if (kdTree) { delete kdTree; }
1395 
1396  // filling up vertex coordinate array for the current mesh
1397  for (int iVrt = 0; iVrt < nVertex; ++iVrt) {
1398  vrtxCrd[iVrt][0] = xCrd[iVrt];
1399  vrtxCrd[iVrt][1] = yCrd[iVrt];
1400  vrtxCrd[iVrt][2] = zCrd[iVrt];
1401  }
1402  // building kdTree
1403  kdTree = new ANNkd_tree(vrtxCrd, nVertex, physDim);
1404 }
1405 
1407  // ANNpointArray vrtxIdx;
1408  if (vrtxIdx) annDeallocPts(vrtxIdx);
1409  // clearing onld instance
1410  vrtxIdx = annAllocPts(nElem, nVrtxElem);
1411  if (kdTreeElem) delete kdTreeElem;
1412 
1413  // filling up vertex coordinate array for the current mesh
1414  for (int iElem = 0; iElem < nElem; ++iElem) {
1415  for (int iVrtx = 1; iVrtx <= nVrtxElem; ++iVrtx) {
1416  vrtxIdx[iElem][iVrtx] = elemConn[(iElem - 1) * nVrtxElem + iVrtx];
1417  }
1418  }
1419  // building kdTree
1420  kdTreeElem = new ANNkd_tree(vrtxIdx, nElem, nVrtxElem);
1421 }
1422 
1423 /*
1424  Check for duplicated vertices in the grid.
1425 */
1427  // (re)building the kdTree
1428  buildVertexKDTree();
1429  // loop through vertices to find duplicated ones
1430  int nDupVer = 0;
1431  for (int iVrt = 0; iVrt < getNVertex(); ++iVrt) {
1432  ANNpoint qryVrtx;
1433  ANNidxArray nnIdx;
1434  ANNdistArray dists;
1435  qryVrtx = annAllocPt(physDim);
1436  qryVrtx[0] = getVrtXCrd(iVrt);
1437  qryVrtx[1] = getVrtYCrd(iVrt);
1438  qryVrtx[2] = getVrtZCrd(iVrt);
1439  nnIdx = new ANNidx[1];
1440  dists = new ANNdist[1];
1441  kdTree->annkSearch(qryVrtx, 2, nnIdx, dists);
1442  if (dists[1] < 1e-10) {
1443  nDupVer++;
1444  std::cout << "Vertex " << iVrt << " is duplicated."
1445  << " Distances = " << dists[0] << " " << dists[1] << std::endl;
1446  }
1447  delete[] nnIdx;
1448  delete[] dists;
1449  annDeallocPt(qryVrtx);
1450  }
1451  std::cout << "Found " << nDupVer << " duplicate vertex.\n";
1452 }
1453 
1454 /*
1455  Check element to element connectivity making sure there is at least
1456  given number of nodes shared between neighboring elements.
1457 */
1458 bool cgnsAnalyzer::checkElmConn(int nSharedNde) {
1459  /*
1460  MatrixInt eConn(nElem, nVrtxElem);
1461  MatrixInt dummy(nElem, nElem);
1462  VectorInt elmIdx(nElem);
1463  for (int iElm = 0; iElm < nElem; ++iElm)
1464  {
1465  elmIdx(iElm) = iElm;
1466  for (int iNde = 0; iNde < nVrtxElem; ++iNde)
1467  eConn(iElm, iNde) = elemConn[iElm * nVrtxElem + iNde];
1468  }
1469  clock_t startTime = clock();
1470  dummy = eConn * eConn.transpose();
1471  std::cout << double(clock() - startTime) / (double) CLOCKS_PER_SEC << "
1472  seconds." << std::endl;
1473  */
1474 
1475  // building node to element map
1476  std::map<int, std::set<int>> nde2Elm;
1477  for (int iElm = 0; iElm < nElem; ++iElm)
1478  for (int iNde = 0; iNde < nVrtxElem; ++iNde)
1479  nde2Elm[elemConn[iElm * nVrtxElem + iNde]].insert(iElm);
1480 
1481  /*
1482  std::cout << "nde2Elm = " << std::endl;
1483  for (auto it = nde2Elm.begin(); it != nde2Elm.end(); ++it)
1484  {
1485  std::set<int> tmp = it->second;
1486  for (auto it2 = tmp.begin(); it2 != tmp.end(); ++it2)
1487  std::cout << *it2 << " ";
1488  std::cout << std::endl;
1489  }
1490  */
1491 
1492  // going through the list of elements and finding
1493  // those with less than nSharedNde
1494  std::vector<int> hangingElmIdx;
1495  for (int iElm = 0; iElm < nElem; ++iElm) {
1496  int nShrdNde = 0;
1497  for (int iNde = 0; iNde < nVrtxElem; ++iNde)
1498  nShrdNde += nde2Elm[iNde].size() > 1;
1499  if (nShrdNde < nSharedNde) hangingElmIdx.push_back(iElm);
1500  }
1501 
1502  std::cout << "Number of elements with less than " << nSharedNde
1503  << " shared node is " << hangingElmIdx.size() << std::endl;
1504  return !hangingElmIdx.empty();
1505 }
1506 
1507 /*
1508  Gets element center coordinates.
1509 */
1510 std::vector<double> cgnsAnalyzer::getElmCntCoords(MAd::pMesh msh) {
1511  std::vector<double> elmCntCrds;
1512  MAd::RIter ri = M_regionIter(msh);
1513  // int rCnt = 0;
1514  while (MAd::pRegion pr = RIter_next(ri)) {
1515  double xc[3];
1516  MAd::R_center(pr, xc);
1517  elmCntCrds.push_back(xc[0]);
1518  elmCntCrds.push_back(xc[1]);
1519  elmCntCrds.push_back(xc[2]);
1520  }
1521  return elmCntCrds;
1522 }
1523 
1524 /*
1525  Stitches the mesh of the given instance to the current one.
1526 */
1527 void cgnsAnalyzer::stitchMesh(cgnsAnalyzer *inCg, bool withFields) {
1528  // sanity check
1529  if (physDim != inCg->getPhysDim()) {
1530  std::cerr << "Error : Stitching mesh should have same dimensions."
1531  << std::endl;
1532  return;
1533  }
1534 
1535  // removing rind data (if any)
1536  cleanRind();
1537  inCg->cleanRind();
1538 
1539  // (re)building the kdTree
1540  buildVertexKDTree();
1541 
1542  // clear old masks
1543  vrtDataMask.clear();
1544  elmDataMask.clear();
1545 
1546  // adding new mesh non-repeating vertices
1547  std::vector<int> newVrtIdx;
1548  std::vector<int> rptVrtIdx;
1549  std::map<int, int> rptVrtMap; // <newMeshIdx, currentMeshIdx>
1550  std::vector<double> newXCrd;
1551  std::vector<double> newYCrd;
1552  std::vector<double> newZCrd;
1553  int nNewVrt = 0;
1554  for (int iVrt = 0; iVrt < inCg->getNVertex(); ++iVrt) {
1555  ANNpoint qryVrtx;
1556  ANNidxArray nnIdx;
1557  ANNdistArray dists;
1558  qryVrtx = annAllocPt(physDim);
1559  qryVrtx[0] = inCg->getVrtXCrd(iVrt);
1560  qryVrtx[1] = inCg->getVrtYCrd(iVrt);
1561  qryVrtx[2] = inCg->getVrtZCrd(iVrt);
1562  nnIdx = new ANNidx[1];
1563  dists = new ANNdist[1];
1564  kdTree->annkSearch(qryVrtx, 1, nnIdx, dists);
1565  if (dists[0] > searchEps) {
1566  nNewVrt++;
1567  vrtDataMask.push_back(true);
1568  newVrtIdx.push_back(nVertex + nNewVrt);
1569  newXCrd.push_back(qryVrtx[0]);
1570  newYCrd.push_back(qryVrtx[1]);
1571  newZCrd.push_back(qryVrtx[2]);
1572  } else {
1573  vrtDataMask.push_back(false);
1574  newVrtIdx.push_back(nnIdx[0] + 1);
1575  rptVrtIdx.push_back(iVrt);
1576  rptVrtMap[iVrt] = nnIdx[0] + 1;
1577  }
1578  delete[] nnIdx;
1579  delete[] dists;
1580  annDeallocPt(qryVrtx);
1581  }
1582  std::cout << "Found " << nNewVrt << " new vertices.\n";
1583  std::cout << "Number of repeating index " << rptVrtIdx.size() << std::endl;
1584 
1585  // currently implemented to add all new elements
1586  std::vector<int> newElemConn;
1587  int nNewElem = 0;
1588  for (int iElem = 0; iElem < inCg->getNElement(); ++iElem) {
1589  std::vector<cgsize_t> rmtElemConn = inCg->getElementConnectivity(iElem);
1590 
1591  // just adding all elements
1592  elmDataMask.push_back(true);
1593  nNewElem++;
1594  newElemConn.insert(newElemConn.end(), rmtElemConn.begin(),
1595  rmtElemConn.end());
1596  }
1597  std::cout << "Found " << nNewElem << " new elements.\n";
1598 
1599  // switching connectivity table to global
1600  for (int iIdx = 0; iIdx < newElemConn.size(); ++iIdx) {
1601  newElemConn[iIdx] = newVrtIdx[newElemConn[iIdx] - 1];
1602  }
1603 
1604  // stitching field values if requested
1605  if (withFields) stitchFields(inCg);
1606 
1607  // updating internal data structure
1608  nVertex += nNewVrt;
1609  nElem += nNewElem;
1610  xCrd.insert(xCrd.end(), newXCrd.begin(), newXCrd.end());
1611  yCrd.insert(yCrd.end(), newYCrd.begin(), newYCrd.end());
1612  zCrd.insert(zCrd.end(), newZCrd.begin(), newZCrd.end());
1613  elemConn.insert(elemConn.end(), newElemConn.begin(), newElemConn.end());
1614  zoneNames.push_back(inCg->getZoneName());
1615 }
1616 
1618  // look at the solution names of current grid
1619  std::vector<std::string> crntCgList;
1620  getSolutionDataNames(crntCgList);
1621  if (verb > 0)
1622  for (auto &it : crntCgList) std::cout << it << std::endl;
1623  // load solution data container if empty
1624  if (slnDataCont.empty()) {
1625  for (auto &is : crntCgList) {
1626  solutionData *slnDataPtr = getSolutionDataObj(is);
1627  if (verb > 0)
1628  std::cout << is << " number of data read " << slnDataPtr->getNData()
1629  << " " << slnDataPtr->getNDim() << std::endl;
1630  slnDataCont.push_back(slnDataPtr);
1631  }
1632  }
1633  // information
1634  std::cout << " Number of Solution Field = " << slnDataCont.size()
1635  << std::endl;
1636 }
1637 
1639  // look at the solution names of current grid
1640  std::vector<std::string> crntCgList;
1641  getSolutionDataNames(crntCgList);
1642 
1643  // load solution data container if empty
1644  if (slnDataCont.empty()) loadSolutionDataContainer();
1645 
1646  // now going through the list of inCg and stitch only repeating data
1647  std::vector<std::string> inCgList;
1648  inCg->getSolutionDataNames(inCgList);
1649  for (auto &id : inCgList) {
1650  bool isRptData = false;
1651  for (auto &is : crntCgList)
1652  if (!strcmp(id.c_str(), is.c_str())) {
1653  isRptData = true;
1654  std::cout << id << " is an existing field.\n";
1655  break;
1656  }
1657 
1658  if (isRptData) {
1659  std::vector<double> inCgSlnData;
1660  int outNData, outNDim;
1661  solutionData *inCgSlnDataPtr = inCg->getSolutionDataObj(id);
1662  if (inCgSlnDataPtr->getDataType() == solution_type_t::NODAL) {
1663  inCgSlnDataPtr->getData(inCgSlnData, outNData, outNDim, vrtDataMask);
1664  // testing
1665  // std::cout << " will append " << outNData << " data points.\n";
1666  } else {
1667  inCgSlnDataPtr->getData(inCgSlnData, outNData, outNDim, elmDataMask);
1668  // testing
1669  // std::cout << " will append " << outNData << " data points.\n";
1670  }
1671  // attaching data
1672  int nData = slnDataCont.size();
1673  for (int icd = 0; icd < nData; icd++) {
1674  if (!strcmp((slnDataCont[icd]->getDataName()).c_str(), id.c_str())) {
1675  std::cout << "To -> " << slnDataCont[icd]->getDataName() << std::endl;
1676  // std::cout << "Current size = " << icnt->getNData() << std::endl;
1677  slnDataCont[icd]->appendData(inCgSlnData, inCgSlnData.size(), 1);
1678  // std::cout << "Size after = " << icnt->getNData() << std::endl;
1679  }
1680  }
1681  }
1682  }
1683 
1684  // now go through appended data to the current grid and see if they
1685  // also existing in inCg and thus stitch them as well.
1686  std::vector<std::string> inCgAppLst;
1687  inCg->getAppendedSolutionDataName(inCgAppLst);
1688  if (appendedSolutionName.empty() || inCgAppLst.empty()) return;
1689  for (auto &id : inCgAppLst) {
1690  bool isRptData = false;
1691  // std::cout << "Remote CG field name = " << id.c_str() << std::endl;
1692  for (auto &is : appendedSolutionName) {
1693  // std::cout << "Current CG field name = " << is.c_str() << std::endl;
1694  // std::cout << " strcmp = " << strcmp(id.c_str(), is.c_str()) <<
1695  // std::endl;
1696  if (strcmp(id.c_str(), is.c_str()) == 0) {
1697  isRptData = true;
1698  // std::cout << id << " is an existing field.\n";
1699  break;
1700  }
1701  }
1702 
1703  if (isRptData) {
1704  std::vector<double> inCgSlnData;
1705  int outNData, outNDim;
1706  solutionData *inCgSlnDataPtr = inCg->getSolutionDataObj(id);
1707  if (inCgSlnDataPtr->getDataType() == solution_type_t::NODAL) {
1708  inCgSlnDataPtr->getData(inCgSlnData, outNData, outNDim, vrtDataMask);
1709  // testing
1710  // std::cout << " will append " << outNData << " data points.\n";
1711  } else {
1712  inCgSlnDataPtr->getData(inCgSlnData, outNData, outNDim, elmDataMask);
1713  // testing
1714  std::cout << " will append " << outNData << " data points.\n";
1715  }
1716  // attaching data
1717  for (auto &icnt : slnDataCont) {
1718  if (!strcmp((icnt->getDataName()).c_str(), id.c_str())) {
1719  // std::cout << "To -> " << icnt->getDataName() << std::endl;
1720  // std::cout << "Current size = " << icnt->getNData() << std::endl;
1721  icnt->appendData(inCgSlnData, inCgSlnData.size(), 1);
1722  // std::cout << "Size after = " << icnt->getNData() << std::endl;
1723  }
1724  }
1725  }
1726  }
1727 }
1728 
1729 bool cgnsAnalyzer::isCgRindNode(int cgNodeId) {
1730  // for structured zones we should avoid writing rind cells
1731  if (!cgRindNodeIds.empty()) {
1732  auto it = std::find(cgRindNodeIds.begin(), cgRindNodeIds.end(), cgNodeId);
1733  return (it != cgRindNodeIds.end());
1734  } else
1735  return false;
1736 }
1737 
1738 bool cgnsAnalyzer::isCgRindCell(int cgCellId) {
1739  // for structured zones we should avoid writing rind cells
1740  if (!cgRindCellIds.empty()) {
1741  auto it = std::find(cgRindCellIds.begin(), cgRindCellIds.end(), cgCellId);
1742  return (it != cgRindCellIds.end());
1743  } else
1744  return false;
1745 }
1746 
1748  // sanity check
1749  // only supports structured meshes for now
1750  if (!isStructured()) return;
1751  if (_rindOff) return;
1752  std::cout << "Cleaning up rind data from the grid.\n";
1753  // create map btw real and rind node ids
1754  std::map<int, int> old2NewNdeIds;
1755  int nNewNde = 1;
1756  int nRindNde = 0;
1757  for (int iNde = 1; iNde <= nVertex; iNde++)
1758  if (isCgRindNode(iNde)) {
1759  old2NewNdeIds[iNde] = -1;
1760  nRindNde++;
1761  } else
1762  old2NewNdeIds[iNde] = nNewNde++;
1763  // sanity check
1764  if (nRindNde != cgRindNodeIds.size()) {
1765  std::cerr << "Problem occured during rind node removal.\n";
1766  throw;
1767  }
1768  // remove rind node coords
1769  nRindNde = 0;
1770  std::vector<double> nxCrd, nyCrd, nzCrd;
1771  for (int iVrt = 0; iVrt < nVertex; iVrt++) {
1772  if (old2NewNdeIds[iVrt + 1] < 0) {
1773  nRindNde++;
1774  continue;
1775  } else {
1776  nxCrd.push_back(xCrd[iVrt]);
1777  nyCrd.push_back(yCrd[iVrt]);
1778  nzCrd.push_back(zCrd[iVrt]);
1779  }
1780  }
1781  xCrd = nxCrd;
1782  yCrd = nyCrd;
1783  zCrd = nzCrd;
1784  // sanity check
1785  if (nRindNde != cgRindNodeIds.size()) {
1786  std::cerr << "Problem occured during rind coord removal.\n";
1787  throw;
1788  }
1789  // remove rind elements
1790  std::vector<cgsize_t> newElemConn;
1791  for (int iElm = 0; iElm < nElem; iElm++) {
1792  if (isCgRindCell(iElm + 1)) continue;
1793  for (int id = 0; id < 8; id++)
1794  newElemConn.push_back(old2NewNdeIds[elemConn[iElm * 8 + id]]);
1795  }
1796  elemConn = newElemConn;
1797  // update connectivity
1798  for (auto i : elemConn) i = old2NewNdeIds[i];
1799  // remove rind nodal data
1800  // remove rind elemental data
1801  if (!slnDataCont.empty()) {
1802  // internal data index start from zero
1803  std::vector<int> intRindCellId, intRindNodeId;
1804  for (auto i : cgRindNodeIds) intRindNodeId.push_back(i - 1);
1805  for (auto i : cgRindCellIds) intRindCellId.push_back(i - 1);
1806  // removing rind data
1807  std::cout << "Cleaning up rind solution data ";
1808  int cntr = 29;
1809  for (auto sd : slnDataCont) {
1810  std::cout << "..";
1811  cntr += 2;
1812  if (cntr > 70) {
1813  cntr = 0;
1814  std::cout << "\n";
1815  }
1816  // std::cerr << sd->getDataName() << std::endl;
1817  if (sd->getDataType() == solution_type_t::NODAL)
1818  sd->rmvDataIdx(intRindNodeId);
1819  else if (sd->getDataType() == solution_type_t::ELEMENTAL)
1820  sd->rmvDataIdx(intRindCellId);
1821  }
1822  std::cout << "\n";
1823  }
1824  // fix number of nodes
1825  nVertex -= cgRindNodeIds.size();
1826  // fix number of elements
1827  nElem -= cgRindCellIds.size();
1828  // setting flag
1829  _rindOff = true;
1830 }
void writeSampleStructured()
Definition: cgnsAnalyzer.C:707
int getNVertex()
Definition: cgnsAnalyzer.C:445
std::vector< double > vecSlnType
Definition: cgnsAnalyzer.H:67
void rmvDataIdx(const std::vector< int > &rmvIdx)
Definition: cgnsAnalyzer.C:83
data_type data
Edge/face with sorted point ids (a, b, c, ...) is located at some index i in data[b], with data[b][i].first == [a, c] (for edges, third point id treated as -1).
std::vector< cgsize_t > getElementConnectivity(int elemId)
Definition: cgnsAnalyzer.C:525
solutionData(std::string sName, solution_type_t inDataType)
Definition: cgnsAnalyzer.H:70
void buildVertexKDTree()
vecSlnType slnData
Definition: cgnsAnalyzer.H:95
void populateSolutionDataNames()
Definition: cgnsAnalyzer.C:884
std::vector< double > getVrtZCrd()
Definition: cgnsAnalyzer.C:514
bool isStructured()
Definition: cgnsAnalyzer.C:471
virtual void getPointDataArray(const std::string &name, std::vector< double > &data)
get scalar point or cell data array.
Definition: meshBase.H:349
void checkVertex()
double getVrtYCrd(int vrtxId)
Definition: cgnsAnalyzer.C:508
void cleanRind()
virtual void stitchMesh(cgnsAnalyzer *inCg, bool withFields=false)
int getNElement()
Definition: cgnsAnalyzer.C:447
int getNVertexSolution()
std::vector< double > getElmCntCoords(MAd::pMesh msh)
std::string getSolutionPntr()
Definition: cgnsAnalyzer.C:443
void loadZone(int zIdx, int verb=0)
Definition: cgnsAnalyzer.C:154
std::vector< double > getVertexCoords()
Definition: cgnsAnalyzer.C:482
std::vector< double > getVrtXCrd()
Definition: cgnsAnalyzer.C:506
solutionData * getSolutionDataObj(std::string sName)
void overwriteSolData(meshBase *mbObj)
A brief description of meshBase.
Definition: meshBase.H:64
void getAppendedSolutionDataName(std::vector< std::string > &appSName)
double getVrtZCrd(int vrtxId)
Definition: cgnsAnalyzer.C:512
geoMeshBase * New(MeshType meshType)
Create a new mesh object.
int getNDim() const
Definition: cgnsAnalyzer.H:83
void loadSolutionDataContainer(int verb=0)
void unclassifyMAdMeshBnd(MAd::pMesh MAdMesh)
void appendData(const vecSlnType &data, int inNData, int inNDim)
Definition: cgnsAnalyzer.C:39
void buildElementKDTree()
std::vector< double > getVrtYCrd()
Definition: cgnsAnalyzer.C:510
void getSectionConn(std::string secName, std::vector< cgsize_t > &conn, int &nElm)
Definition: cgnsAnalyzer.C:595
std::vector< std::string > getSolutionNodeNames()
int getNCellSolution()
void getSectionNames(std::vector< std::string > &secNames)
Definition: cgnsAnalyzer.C:554
std::string getZoneItrName()
Definition: cgnsAnalyzer.C:439
void classifyMAdMeshOpt(MAd::pMesh MAdMesh)
std::map< int, std::pair< int, keyValueList > > getSolutionMap()
int getIndexBase()
Definition: cgnsAnalyzer.C:417
std::string getGridCrdPntr()
Definition: cgnsAnalyzer.C:441
int getIndexFile()
Definition: cgnsAnalyzer.C:415
std::string getBaseItrName()
Definition: cgnsAnalyzer.C:433
solution_type_t
Definition: cgnsAnalyzer.H:58
void classifyMAdMeshBnd(MAd::pMesh MAdMesh)
vtkSmartPointer< vtkDataSet > getSectionMesh(std::string secName)
Definition: cgnsAnalyzer.C:631
void exportToMAdMesh(MAd::pMesh MAdMesh)
vtkIdType id
id in .inp file
Definition: inpGeoMesh.C:128
solution_type_t dataType
Definition: cgnsAnalyzer.H:102
double getTimeStep()
Definition: cgnsAnalyzer.C:455
void writeSampleUnstructured()
Definition: cgnsAnalyzer.C:772
std::string getSectionName()
Definition: cgnsAnalyzer.C:431
std::string getZoneName()
Definition: cgnsAnalyzer.C:425
int getNData() const
Definition: cgnsAnalyzer.H:85
std::string getBaseName()
Definition: cgnsAnalyzer.C:423
int getNVrtxElem()
Definition: cgnsAnalyzer.C:453
void clearAllSolutionData()
Definition: cgnsAnalyzer.C:868
int getCellDim()
Definition: cgnsAnalyzer.C:419
CGNS_ENUMT(MassUnits_t)
Definition: cgnsAnalyzer.C:457
std::vector< vtkIdType > points
points given by id in .inp file
Definition: inpGeoMesh.C:133
bool isCgRindCell(int cgCellId)
void loadGrid(const std::string &fname, int verb=0)
Definition: cgnsAnalyzer.H:147
void appendSolutionData(std::string sName, std::vector< double > &slnData, solution_type_t dt, int inNData, int inNDim)
std::string getDataName() const
Definition: cgnsAnalyzer.H:81
void getSolutionDataNames(std::vector< std::string > &list)
Definition: cgnsAnalyzer.C:918
virtual void getCellDataArray(const std::string &name, std::vector< double > &data)
<>
Definition: meshBase.H:369
solution_type_t getSolutionDataStitched(std::string sName, std::vector< double > &slnData, int &outNData, int &outNDim)
std::string getFileName()
Definition: cgnsAnalyzer.C:421
virtual void stitchFields(cgnsAnalyzer *inCg)
bool delAppSlnData(std::string sName)
solution_type_t getSolutionData(std::string sName, std::vector< double > &slnData)
Definition: cgnsAnalyzer.C:935
vtkSmartPointer< vtkDataSet > getVTKMesh()
Definition: cgnsAnalyzer.C:473
bool checkElmConn(int nSharedNde)
bool isCgRindNode(int cgNdeId)
std::map< int, std::string > keyValueList
Definition: cgnsAnalyzer.H:61
solution_type_t getDataType() const
Definition: cgnsAnalyzer.H:87
void exportToVTKMesh()
double getVrtXCrd(int vrtxId)
Definition: cgnsAnalyzer.C:504
std::vector< CGNS_ENUMT(GridLocation_t)> getSolutionGridLocations()
int getElementType()
Definition: cgnsAnalyzer.C:451
int getPhysDim()
Definition: cgnsAnalyzer.C:449
std::map< std::string, CGNS_ENUMT(GridLocation_t)> getSolutionNameLocMap()
void getData(vecSlnType &inBuff, int &outNData, int &outNDim) const
Definition: cgnsAnalyzer.C:58