Nektar++
OutputTecplot.cpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////
2 //
3 // File: OutputTecplot.cpp
4 //
5 // For more information, please see: http://www.nektar.info/
6 //
7 // The MIT License
8 //
9 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10 // Department of Aeronautics, Imperial College London (UK), and Scientific
11 // Computing and Imaging Institute, University of Utah (USA).
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining a
14 // copy of this software and associated documentation files (the "Software"),
15 // to deal in the Software without restriction, including without limitation
16 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 // and/or sell copies of the Software, and to permit persons to whom the
18 // Software is furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included
21 // in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 // DEALINGS IN THE SOFTWARE.
30 //
31 // Description: Dat file format output.
32 //
33 ////////////////////////////////////////////////////////////////////////////////
34 
35 #include <iomanip>
36 #include <set>
37 #include <string>
38 using namespace std;
39 
40 #include <boost/core/ignore_unused.hpp>
41 
44 
45 #include "OutputTecplot.h"
46 
47 namespace Nektar
48 {
49 namespace FieldUtils
50 {
51 
52 std::string TecplotZoneTypeMap[] = {"ORDERED", "LINESEG", "TRIANGLE",
53  "QUADRILATERAL", "TETRAHEDRON", "BRICK",
54  "POLYGON", "POLYHEDRON"};
55 
56 ModuleKey OutputTecplot::m_className =
58  OutputTecplot::create,
59  "Writes a Tecplot file.");
60 ModuleKey OutputTecplotBinary::m_className =
62  ModuleKey(eOutputModule, "plt"), OutputTecplotBinary::create,
63  "Writes a Tecplot file in binary plt format.");
64 
65 OutputTecplot::OutputTecplot(FieldSharedPtr f)
66  : OutputFileBase(f), m_binary(false), m_oneOutputFile(false)
67 {
68  m_requireEquiSpaced = true;
69  m_config["double"] = ConfigOption(true, "0",
70  "Write double-precision format data:"
71  "more accurate but more disk space"
72  " required");
73 }
74 
76 {
77 }
78 
79 void OutputTecplot::v_Process(po::variables_map &vm)
80 {
81 
82  if (m_config["writemultiplefiles"].as<bool>())
83  {
84  m_oneOutputFile = false;
85  }
86  else
87  {
88  m_oneOutputFile = (m_f->m_comm->GetSpaceComm()->GetSize() > 1);
89  }
90 
92 }
93 
94 /**
95  * @brief Helper function to write binary data to stream.
96  */
97 template <typename T> void WriteStream(std::ostream &outfile, T data)
98 {
99  T tmp = data;
100  outfile.write(reinterpret_cast<char *>(&tmp), sizeof(T));
101 }
102 
103 /**
104  * @brief Specialisation of WriteStream to support writing std::string.
105  *
106  * Tecplot binary formats represent all strings by writing out their characters
107  * as 32-bit integers, followed by a 32-bit integer null (0) character to denote
108  * the end of the string.
109  */
110 template <> void WriteStream(std::ostream &outfile, std::string data)
111 {
112  // Convert string to array of int32_t
113  for (std::string::size_type i = 0; i < data.size(); ++i)
114  {
115  char strChar = data[i];
116  NekInt32 strCharInt = strChar;
117  WriteStream(outfile, strCharInt);
118  }
119 
120  // Now dump out zero character to terminate
121  WriteStream(outfile, 0);
122 }
123 
124 /**
125  * @brief Specialisation of WriteStream to support writing Nektar::Array
126  * datatype.
127  */
128 template <typename T>
129 void WriteStream(std::ostream &outfile, Array<OneD, T> data)
130 {
131  if (data.size())
132  {
133  outfile.write(reinterpret_cast<char *>(&data[0]),
134  data.size() * sizeof(T));
135  }
136 }
137 
138 /**
139  * @brief Specialisation of WriteStream to support writing std::vector datatype.
140  */
141 template <typename T>
142 void WriteStream(std::ostream &outfile, std::vector<T> data)
143 {
144  if (data.size())
145  {
146  outfile.write(reinterpret_cast<char *>(&data[0]),
147  data.size() * sizeof(T));
148  }
149 }
150 
151 void OutputTecplot::v_OutputFromPts(po::variables_map &vm)
152 {
153  LibUtilities::PtsFieldSharedPtr fPts = m_f->m_fieldPts;
154 
155  // do not output if zone is empty
156  if (fPts->GetNpoints() == 0)
157  {
158  return;
159  }
160 
161  int rank = m_f->m_comm->GetSpaceComm()->GetRank();
162  m_numBlocks = 0;
163 
164  m_coordim = fPts->GetDim();
165 
166  // Grab connectivity information.
167  fPts->GetConnectivity(m_conn);
168 
169  switch (fPts->GetPtsType())
170  {
172  m_numPoints.resize(1);
173  m_numPoints[0] = fPts->GetNpoints();
174  m_f->m_comm->GetSpaceComm()->AllReduce(m_numPoints[0],
177  break;
179  m_numPoints.resize(1);
180  m_numPoints[0] = fPts->GetPointsPerEdge(0);
182  break;
184  m_numPoints.resize(2);
185  m_numPoints[0] = fPts->GetPointsPerEdge(0);
186  m_numPoints[1] = fPts->GetPointsPerEdge(1);
188  break;
190  m_numPoints.resize(3);
191  m_numPoints[0] = fPts->GetPointsPerEdge(0);
192  m_numPoints[1] = fPts->GetPointsPerEdge(1);
193  m_numPoints[2] = fPts->GetPointsPerEdge(2);
195  break;
197  {
199  for (int i = 0; i < m_conn.size(); ++i)
200  {
201  m_numBlocks += m_conn[i].size() / 3;
202  }
203  break;
204  }
206  {
208  for (int i = 0; i < m_conn.size(); ++i)
209  {
210  m_numBlocks += m_conn[i].size() / 4;
211  }
212  break;
213  }
214  default:
215  ASSERTL0(false, "This points type is not supported yet.");
216  }
217 
218  // Get fields and coordinates
219  m_fields = Array<OneD, Array<OneD, NekDouble>>(m_f->m_variables.size() +
220  m_coordim);
221 
222  // We can just grab everything from points. This should be a
223  // reference, not a copy.
224  fPts->GetPts(m_fields);
225 
226  // Only write header if we're root or FE block; binary files always
227  // write header
228  m_writeHeader = (m_zoneType != eOrdered || rank == 0) || m_binary;
229 
230  WriteTecplotFile(vm);
231 }
232 
233 void OutputTecplot::v_OutputFromExp(po::variables_map &vm)
234 {
235  m_numBlocks = 0;
236  m_writeHeader = true;
237 
238  // Calculate number of FE blocks
240 
241  // Calculate coordinate dimension
242  int nBases = m_f->m_exp[0]->GetExp(0)->GetNumBases();
243 
244  m_coordim = m_f->m_exp[0]->GetExp(0)->GetCoordim();
245  int totpoints = m_f->m_exp[0]->GetTotPoints();
246 
247  if (m_f->m_numHomogeneousDir > 0)
248  {
249  int nPlanes = m_f->m_exp[0]->GetZIDs().size();
250  if (nPlanes == 1) // halfMode case
251  {
252  // do nothing
253  }
254  else
255  {
256  // If Fourier points, output extra plane to fill domain
257  if (m_f->m_exp[0]->GetExpType() == MultiRegions::e3DH1D)
258  {
259  nPlanes += 1;
260  totpoints += m_f->m_exp[0]->GetPlane(0)->GetTotPoints();
261  }
262  nBases += m_f->m_numHomogeneousDir;
263  m_coordim += m_f->m_numHomogeneousDir;
264  NekDouble tmp = m_numBlocks * (nPlanes - 1);
265  m_numBlocks = (int)tmp;
266  }
267  }
268 
269  m_zoneType = (TecplotZoneType)(2 * (nBases - 1) + 1);
270 
271  // Calculate connectivity
273 
274  // Set up storage for output fields
275  m_fields = Array<OneD, Array<OneD, NekDouble>>(m_f->m_variables.size() +
276  m_coordim);
277 
278  // Get coordinates
279  for (int i = 0; i < m_coordim; ++i)
280  {
281  m_fields[i] = Array<OneD, NekDouble>(totpoints);
282  }
283 
284  if (m_coordim == 1)
285  {
286  m_f->m_exp[0]->GetCoords(m_fields[0]);
287  }
288  else if (m_coordim == 2)
289  {
290  m_f->m_exp[0]->GetCoords(m_fields[0], m_fields[1]);
291  }
292  else
293  {
294  m_f->m_exp[0]->GetCoords(m_fields[0], m_fields[1], m_fields[2]);
295  }
296 
297  if (m_f->m_exp[0]->GetExpType() == MultiRegions::e3DH1D)
298  {
299  // Copy values
300  for (int i = 0; i < m_f->m_variables.size(); ++i)
301  {
302  m_fields[i + m_coordim] = Array<OneD, NekDouble>(totpoints);
303 
304  Vmath::Vcopy(m_f->m_exp[0]->GetTotPoints(),
305  m_f->m_exp[i]->UpdatePhys(), 1,
306  m_fields[i + m_coordim], 1);
307  }
308  }
309  else
310  {
311  // Add references to m_fields
312  for (int i = 0; i < m_f->m_variables.size(); ++i)
313  {
314  m_fields[i + m_coordim] = m_f->m_exp[i]->UpdatePhys();
315  }
316  }
317 
318  // If Fourier, fill extra plane with data
319  if (m_f->m_exp[0]->GetExpType() == MultiRegions::e3DH1D)
320  {
321  int points_on_plane = m_f->m_exp[0]->GetPlane(0)->GetTotPoints();
322  const int offset = totpoints - points_on_plane;
323  NekDouble z = m_fields[m_coordim - 1][totpoints - 2 * points_on_plane] +
324  (m_fields[m_coordim - 1][points_on_plane] -
325  m_fields[m_coordim - 1][0]);
326  // x and y
327  Array<OneD, NekDouble> tmp = m_fields[0] + offset;
328  Vmath::Vcopy(points_on_plane, m_fields[0], 1, tmp, 1);
329  tmp = m_fields[1] + offset;
330  Vmath::Vcopy(points_on_plane, m_fields[1], 1, tmp, 1);
331  // z coordinate
332  tmp = m_fields[2] + offset;
333  Vmath::Vcopy(points_on_plane, m_fields[2], 1, tmp, 1);
334  Vmath::Sadd(points_on_plane, z, m_fields[2], 1, tmp, 1);
335 
336  // variables
337  for (int i = 0; i < m_f->m_variables.size(); ++i)
338  {
339  tmp = m_fields[i + m_coordim] + offset;
340  Vmath::Vcopy(points_on_plane, m_fields[i + m_coordim], 1, tmp, 1);
341  }
342  }
343 
344  WriteTecplotFile(vm);
345 }
346 
347 void OutputTecplot::v_OutputFromData(po::variables_map &vm)
348 {
349  boost::ignore_unused(vm);
350 
352  "OutputTecplot can't write using only FieldData.");
353 }
354 
355 fs::path OutputTecplot::v_GetPath(std::string &filename, po::variables_map &vm)
356 {
357  boost::ignore_unused(vm);
358 
359  int nprocs = m_f->m_comm->GetSpaceComm()->GetSize();
360  string returnstr(filename);
361 
362  // Amend for parallel output if required
363  if (nprocs != 1 && !m_oneOutputFile)
364  {
365  int rank = m_f->m_comm->GetSpaceComm()->GetRank();
366  int dot = filename.find_last_of('.');
367  string ext = filename.substr(dot, filename.length() - dot);
368  string procId = "_P" + boost::lexical_cast<std::string>(rank);
369  string start = filename.substr(0, dot);
370  returnstr = start + procId + ext;
371  }
372  return fs::path(returnstr);
373 }
374 
375 fs::path OutputTecplot::v_GetFullOutName(std::string &filename,
376  po::variables_map &vm)
377 {
378  return GetPath(filename, vm);
379 }
380 
381 void OutputTecplot::WriteTecplotFile(po::variables_map &vm)
382 {
383  // Variable names
384  std::string coordVars[] = {"x", "y", "z"};
385  std::vector<string> variables = m_f->m_variables;
386  variables.insert(variables.begin(), coordVars, coordVars + m_coordim);
387 
388  int nprocs = m_f->m_comm->GetSpaceComm()->GetSize();
389  int rank = m_f->m_comm->GetSpaceComm()->GetRank();
390 
391  // Extract the output filename and extension
392  string filename = m_config["outfile"].as<string>();
393  string outFile = LibUtilities::PortablePath(GetFullOutName(filename, vm));
394  // Open output file
395  ofstream outfile;
396  if ((m_oneOutputFile && rank == 0) || !m_oneOutputFile)
397  {
398  outfile.open(outFile.c_str(), m_binary ? ios::binary : ios::out);
399  }
400 
401  if (m_oneOutputFile)
402  {
403  // Reduce on number of blocks and number of points.
404  m_f->m_comm->GetSpaceComm()->AllReduce(m_numBlocks,
406 
407  // Root process needs to know how much data everyone else has for
408  // writing in parallel.
409  m_rankFieldSizes = Array<OneD, int>(nprocs, 0);
410  m_rankConnSizes = Array<OneD, int>(nprocs, 0);
411  m_rankFieldSizes[rank] = m_fields[0].size();
412 
413  m_totConn = 0;
414  for (int i = 0; i < m_conn.size(); ++i)
415  {
416  m_totConn += m_conn[i].size();
417  }
418 
419  m_rankConnSizes[rank] = m_totConn;
420 
421  m_f->m_comm->GetSpaceComm()->AllReduce(m_rankFieldSizes,
423  m_f->m_comm->GetSpaceComm()->AllReduce(m_rankConnSizes,
425  }
426 
427  if (m_writeHeader)
428  {
429  WriteTecplotHeader(outfile, variables);
430  }
431 
432  // Write zone data.
433  WriteTecplotZone(outfile);
434 
435  // If we're a FE block format, write connectivity (m_conn will be empty for
436  // point data).
437  WriteTecplotConnectivity(outfile);
438 
439  if ((m_oneOutputFile && rank == 0) || !m_oneOutputFile)
440  {
441  cout << "Written file: " << GetFullOutName(filename, vm) << endl;
442  }
443 }
444 
445 /**
446  * @brief Write Tecplot files header
447  *
448  * @param outfile Output file name
449  * @param var Variables names
450  */
451 void OutputTecplot::v_WriteTecplotHeader(std::ofstream &outfile,
452  std::vector<std::string> &var)
453 {
454  outfile << "Variables = " << var[0];
455 
456  for (int i = 1; i < var.size(); ++i)
457  {
458  outfile << ", " << var[i];
459  }
460 
461  outfile << std::endl << std::endl;
462 }
463 
464 /**
465  * @brief Write Tecplot files header in binary format
466  *
467  * @param outfile Output file name
468  * @param var Variables names
469  */
470 void OutputTecplotBinary::v_WriteTecplotHeader(std::ofstream &outfile,
471  std::vector<std::string> &var)
472 {
473  if (m_oneOutputFile && m_f->m_comm->GetSpaceComm()->GetRank() > 0)
474  {
475  return;
476  }
477 
478  // Version number
479  outfile << "#!TDV112";
480 
481  // Int value of 1 for endian check
482  WriteStream(outfile, 1);
483 
484  // We'll probably write a full solution field
485  WriteStream(outfile, 0);
486 
487  // Title
488  std::string title = "";
489  WriteStream(outfile, title);
490 
491  // Number of variables
492  WriteStream(outfile, (int)var.size());
493 
494  for (int i = 0; i < var.size(); ++i)
495  {
496  WriteStream(outfile, var[i]);
497  }
498 }
499 
500 /**
501  * Write Tecplot zone output in ASCII
502  *
503  * @param outfile Output file name.
504  * @param expansion Expansion that is considered
505  */
506 void OutputTecplot::v_WriteTecplotZone(std::ofstream &outfile)
507 {
508  bool useDoubles = m_config["double"].as<bool>();
509 
510  if (useDoubles)
511  {
512  int precision = std::numeric_limits<double>::max_digits10;
513  outfile << std::setprecision(precision);
514  }
515 
516  // Write either points or finite element block
517  if (m_zoneType != eOrdered)
518  {
519  if ((m_oneOutputFile && m_f->m_comm->GetSpaceComm()->GetRank() == 0) ||
521  {
522  // Number of points in zone
523  int nPoints =
525  ? Vmath::Vsum(m_f->m_comm->GetSpaceComm()->GetSize(),
526  m_rankFieldSizes, 1)
527  : m_fields[0].size();
528 
529  outfile << "Zone, N=" << nPoints << ", E=" << m_numBlocks
530  << ", F=FEBlock, ET=" << TecplotZoneTypeMap[m_zoneType];
531  if (m_f->m_fieldMetaDataMap.count("Time"))
532  {
533  outfile << ", SOLUTIONTIME=" << m_f->m_fieldMetaDataMap["Time"];
534  }
535  outfile << std::endl;
536  }
537 
538  if (m_oneOutputFile && m_f->m_comm->GetSpaceComm()->GetRank() == 0)
539  {
540  for (int j = 0; j < m_fields.size(); ++j)
541  {
542  for (int i = 0; i < m_fields[j].size(); ++i)
543  {
544  if ((!(i % 1000)) && i)
545  {
546  outfile << std::endl;
547  }
548  outfile << m_fields[j][i] << " ";
549  }
550 
551  for (int n = 1; n < m_f->m_comm->GetSpaceComm()->GetSize(); ++n)
552  {
553  if (m_rankFieldSizes[n])
554  {
556  m_f->m_comm->GetSpaceComm()->Recv(n, tmp);
557 
558  for (int i = 0; i < m_rankFieldSizes[n]; ++i)
559  {
560  if ((!(i % 1000)) && i)
561  {
562  outfile << std::endl;
563  }
564  outfile << tmp[i] << " ";
565  }
566  }
567  }
568  outfile << std::endl;
569  }
570  }
571  else if (m_oneOutputFile && m_f->m_comm->GetSpaceComm()->GetRank() > 0)
572  {
573  if (m_fields[0].size())
574  {
575  for (int i = 0; i < m_fields.size(); ++i)
576  {
577  m_f->m_comm->GetSpaceComm()->Send(0, m_fields[i]);
578  }
579  }
580  }
581  else
582  {
583  // Write out coordinates and field data: ordered by field
584  // and then its data.
585  for (int j = 0; j < m_fields.size(); ++j)
586  {
587  for (int i = 0; i < m_fields[j].size(); ++i)
588  {
589  if ((!(i % 1000)) && i)
590  {
591  outfile << std::endl;
592  }
593  outfile << m_fields[j][i] << " ";
594  }
595  outfile << std::endl;
596  }
597  }
598  }
599  else
600  {
601  if ((m_oneOutputFile && m_f->m_comm->GetSpaceComm()->GetRank() == 0) ||
603  {
604  std::string dirs[] = {"I", "J", "K"};
605  outfile << "Zone";
606  for (int i = 0; i < m_numPoints.size(); ++i)
607  {
608  outfile << ", " << dirs[i] << "=" << m_numPoints[i];
609  }
610  outfile << ", F=POINT" << std::endl;
611  }
612 
613  if (m_oneOutputFile && m_f->m_comm->GetSpaceComm()->GetRank() == 0)
614  {
615  Array<OneD, NekDouble> tmp(m_fields.size());
616  for (int i = 0; i < m_fields[0].size(); ++i)
617  {
618  for (int j = 0; j < m_fields.size(); ++j)
619  {
620  outfile << setw(12) << m_fields[j][i] << " ";
621  }
622  outfile << std::endl;
623  }
624 
625  for (int n = 1; n < m_f->m_comm->GetSpaceComm()->GetSize(); ++n)
626  {
627  for (int i = 0; i < m_rankFieldSizes[n]; ++i)
628  {
629  m_f->m_comm->GetSpaceComm()->Recv(n, tmp);
630  for (int j = 0; j < m_fields.size(); ++j)
631  {
632  outfile << setw(12) << tmp[j] << " ";
633  }
634  outfile << std::endl;
635  }
636  }
637  }
638  else if (m_oneOutputFile && m_f->m_comm->GetSpaceComm()->GetRank() > 0)
639  {
640  Array<OneD, NekDouble> tmp(m_fields.size());
641  for (int i = 0; i < m_fields[0].size(); ++i)
642  {
643  for (int j = 0; j < m_fields.size(); ++j)
644  {
645  tmp[j] = m_fields[j][i];
646  }
647  m_f->m_comm->GetSpaceComm()->Send(0, tmp);
648  }
649  }
650  else
651  {
652  // Write out coordinates and field data: ordered by each
653  // point then each field.
654  for (int i = 0; i < m_fields[0].size(); ++i)
655  {
656  for (int j = 0; j < m_fields.size(); ++j)
657  {
658  outfile << setw(12) << m_fields[j][i] << " ";
659  }
660  outfile << std::endl;
661  }
662  }
663  }
664 }
665 
666 /**
667  * @brief Write either double-precision or single-precision output of field
668  * data.
669  *
670  * @param outfile Output file name.
671  * @param expansion Expansion that is considered
672  */
673 void OutputTecplotBinary::WriteDoubleOrFloat(std::ofstream &outfile,
675 {
676  // Data format: either double or single depending on user options
677  bool useDoubles = m_config["double"].as<bool>();
678 
679  if (useDoubles)
680  {
681  // For doubles, we can just write data.
682  WriteStream(outfile, data);
683  }
684  else
685  {
686  // For single precision, needs typecast first.
687  int nPts = data.size();
688  std::vector<float> tmp(data.size());
689  std::copy(&data[0], &data[0] + nPts, &tmp[0]);
690  WriteStream(outfile, tmp);
691  }
692 }
693 
694 /**
695  * Write Tecplot zone output in binary
696  *
697  * @param outfile Output file name.
698  * @param expansion Expansion that is considered
699  */
700 void OutputTecplotBinary::v_WriteTecplotZone(std::ofstream &outfile)
701 {
702  Array<OneD, NekDouble> fieldMin(m_fields.size());
703  Array<OneD, NekDouble> fieldMax(m_fields.size());
704 
705  // Data format: either double or single depending on user options
706  bool useDoubles = m_config["double"].as<bool>();
707 
708  if ((m_oneOutputFile && m_f->m_comm->GetSpaceComm()->GetRank() == 0) ||
710  {
711  // Don't bother naming zone
712  WriteStream(outfile, 299.0f); // Zone marker
713 
714  // Write same name as preplot
715  int rank = m_f->m_comm->GetSpaceComm()->GetRank();
716  string zonename = "ZONE " + boost::lexical_cast<string>(rank);
717  WriteStream(outfile, zonename);
718 
719  WriteStream(outfile, -1); // No parent zone
720  WriteStream(outfile, -1); // No strand ID
721  WriteStream(outfile, 0.0); // Solution time
722  WriteStream(outfile, -1); // Unused, set to -1
723 
724  // Zone type: 1 = lineseg, 3 = quad, 5 = brick
725  WriteStream(outfile, (int)m_zoneType);
726 
727  WriteStream(outfile, 0); // Data at nodes
728  WriteStream(outfile, 0); // No 1-1 face neighbours
729  WriteStream(outfile, 0); // No user-defined connections
730 
731  if (m_zoneType == eOrdered)
732  {
733  for (int i = 0; i < m_numPoints.size(); ++i)
734  {
735  WriteStream(outfile, m_numPoints[i]);
736  }
737 
738  for (int i = m_numPoints.size(); i < 3; ++i)
739  {
740  WriteStream(outfile, 0);
741  }
742  }
743  else
744  {
745  // Number of points in zone
746  int nPoints =
748  ? Vmath::Vsum(m_f->m_comm->GetSpaceComm()->GetSize(),
749  m_rankFieldSizes, 1)
750  : m_fields[0].size();
751 
752  WriteStream(outfile, nPoints); // Total number of points
753  WriteStream(outfile, m_numBlocks); // Number of blocks
754  WriteStream(outfile, 0); // Unused
755  WriteStream(outfile, 0); // Unused
756  WriteStream(outfile, 0); // Unused
757  }
758 
759  WriteStream(outfile, 0); // No auxiliary data names
760 
761  // Finalise header
762  WriteStream(outfile, 357.0f);
763 
764  // Now start to write data section so that we can dump geometry
765  // information
766 
767  // Data marker
768  WriteStream(outfile, 299.0f);
769 
770  for (int j = 0; j < m_fields.size(); ++j)
771  {
772  WriteStream(outfile, useDoubles ? 2 : 1);
773  }
774 
775  // No passive variables or variable sharing, no zone connectivity
776  // sharing (we only dump one zone)
777  WriteStream(outfile, 0);
778  WriteStream(outfile, 0);
779  WriteStream(outfile, -1);
780  }
781 
782  for (int i = 0; i < m_fields.size(); ++i)
783  {
784  fieldMin[i] = Vmath::Vmin(m_fields[i].size(), m_fields[i], 1);
785  fieldMax[i] = Vmath::Vmax(m_fields[i].size(), m_fields[i], 1);
786  }
787 
788  m_f->m_comm->GetSpaceComm()->AllReduce(fieldMin, LibUtilities::ReduceMin);
789  m_f->m_comm->GetSpaceComm()->AllReduce(fieldMax, LibUtilities::ReduceMax);
790 
791  // Write out min/max of field data
792  if ((m_oneOutputFile && m_f->m_comm->GetSpaceComm()->GetRank() == 0) ||
794  {
795  for (int i = 0; i < m_fields.size(); ++i)
796  {
797  WriteStream(outfile, fieldMin[i]);
798  WriteStream(outfile, fieldMax[i]);
799  }
800  }
801 
802  if (m_oneOutputFile && m_f->m_comm->GetSpaceComm()->GetRank() == 0)
803  {
804  for (int i = 0; i < m_fields.size(); ++i)
805  {
806  WriteDoubleOrFloat(outfile, m_fields[i]);
807 
808  for (int n = 1; n < m_f->m_comm->GetSpaceComm()->GetSize(); ++n)
809  {
811  m_f->m_comm->GetSpaceComm()->Recv(n, tmp);
812  WriteDoubleOrFloat(outfile, tmp);
813  }
814  }
815  }
816  else if (m_oneOutputFile && m_f->m_comm->GetSpaceComm()->GetRank() > 0)
817  {
818  for (int i = 0; i < m_fields.size(); ++i)
819  {
820  m_f->m_comm->GetSpaceComm()->Send(0, m_fields[i]);
821  }
822  }
823  else
824  {
825  for (int i = 0; i < m_fields.size(); ++i)
826  {
827  WriteDoubleOrFloat(outfile, m_fields[i]);
828  }
829  }
830 }
831 
832 /**
833  * @brief Write Tecplot connectivity information (ASCII)
834  *
835  * @param outfile Output file
836  */
837 void OutputTecplot::v_WriteTecplotConnectivity(std::ofstream &outfile)
838 {
839  // Ordered data have no connectivity information.
840  if (m_zoneType == eOrdered)
841  {
842  return;
843  }
844 
845  if (m_oneOutputFile && m_f->m_comm->GetSpaceComm()->GetRank() > 0)
846  {
847  // Need to amalgamate connectivity information
848  if (m_totConn)
849  {
851  for (int i = 0, cnt = 0; i < m_conn.size(); ++i)
852  {
853  if (m_conn[i].size())
854  {
855  Vmath::Vcopy(m_conn[i].size(), &m_conn[i][0], 1, &conn[cnt],
856  1);
857  cnt += m_conn[i].size();
858  }
859  }
860  m_f->m_comm->GetSpaceComm()->Send(0, conn);
861  }
862  }
863  else
864  {
865  int cnt = 1;
866  for (int i = 0; i < m_conn.size(); ++i)
867  {
868  const int nConn = m_conn[i].size();
869  for (int j = 0; j < nConn; ++j, ++cnt)
870  {
871  outfile << m_conn[i][j] + 1 << " ";
872  if (!(cnt % 1000))
873  {
874  outfile << std::endl;
875  }
876  }
877  }
878  outfile << endl;
879 
880  if (m_oneOutputFile && m_f->m_comm->GetSpaceComm()->GetRank() == 0)
881  {
882  int offset = m_rankFieldSizes[0];
883 
884  for (int n = 1; n < m_f->m_comm->GetSpaceComm()->GetSize(); ++n)
885  {
886  if (m_rankConnSizes[n])
887  {
889  m_f->m_comm->GetSpaceComm()->Recv(n, conn);
890  for (int j = 0; j < conn.size(); ++j)
891  {
892  outfile << conn[j] + offset + 1 << " ";
893  if ((!(j % 1000)) && j)
894  {
895  outfile << std::endl;
896  }
897  }
898  }
899  offset += m_rankFieldSizes[n];
900  }
901  }
902  }
903 }
904 
906 {
907  if (m_oneOutputFile && m_f->m_comm->GetSpaceComm()->GetRank() > 0)
908  {
909  // Need to amalgamate connectivity information
911  for (int i = 0, cnt = 0; i < m_conn.size(); ++i)
912  {
913  Vmath::Vcopy(m_conn[i].size(), &m_conn[i][0], 1, &conn[cnt], 1);
914  cnt += m_conn[i].size();
915  }
916  m_f->m_comm->GetSpaceComm()->Send(0, conn);
917  }
918  else
919  {
920  for (int i = 0; i < m_conn.size(); ++i)
921  {
922  WriteStream(outfile, m_conn[i]);
923  }
924 
925  if (m_oneOutputFile && m_f->m_comm->GetSpaceComm()->GetRank() == 0)
926  {
927  int offset = m_rankFieldSizes[0];
928 
929  for (int n = 1; n < m_f->m_comm->GetSpaceComm()->GetSize(); ++n)
930  {
932  m_f->m_comm->GetSpaceComm()->Recv(n, conn);
933 
934  for (int j = 0; j < conn.size(); ++j)
935  {
936  conn[j] += offset;
937  }
938 
939  WriteStream(outfile, conn);
940  offset += m_rankFieldSizes[n];
941  }
942  }
943  }
944 }
945 
946 /**
947  * @brief Calculate number of Tecplot blocks.
948  *
949  * @param outfile Output file
950  */
952 {
953  int returnval = 0;
954 
955  if (m_f->m_exp[0]->GetExp(0)->GetNumBases() == 1)
956  {
957  for (int i = 0; i < m_f->m_exp[0]->GetNumElmts(); ++i)
958  {
959  returnval += (m_f->m_exp[0]->GetExp(i)->GetNumPoints(0) - 1);
960  }
961  }
962  else if (m_f->m_exp[0]->GetExp(0)->GetNumBases() == 2)
963  {
964  for (int i = 0; i < m_f->m_exp[0]->GetNumElmts(); ++i)
965  {
966  returnval += (m_f->m_exp[0]->GetExp(i)->GetNumPoints(0) - 1) *
967  (m_f->m_exp[0]->GetExp(i)->GetNumPoints(1) - 1);
968  }
969  }
970  else
971  {
972  for (int i = 0; i < m_f->m_exp[0]->GetNumElmts(); ++i)
973  {
974  returnval += (m_f->m_exp[0]->GetExp(i)->GetNumPoints(0) - 1) *
975  (m_f->m_exp[0]->GetExp(i)->GetNumPoints(1) - 1) *
976  (m_f->m_exp[0]->GetExp(i)->GetNumPoints(2) - 1);
977  }
978  }
979 
980  return returnval;
981 }
982 
983 /**
984  * @brief Calculate connectivity information for each expansion dimension.
985  *
986  * @param outfile Output file
987  */
989 {
990  int i, j, k, l;
991  int nbase = m_f->m_exp[0]->GetExp(0)->GetNumBases();
992  int cnt = 0;
993 
994  m_conn.resize(m_f->m_exp[0]->GetNumElmts());
995 
996  for (i = 0; i < m_f->m_exp[0]->GetNumElmts(); ++i)
997  {
998  cnt = m_f->m_exp[0]->GetPhys_Offset(i);
999 
1000  if (nbase == 1)
1001  {
1002  int cnt2 = 0;
1003  int np0 = m_f->m_exp[0]->GetExp(i)->GetNumPoints(0);
1004  int nPlanes = 1;
1005 
1006  if (m_f->m_exp[0]->GetExpType() == MultiRegions::e2DH1D)
1007  {
1008  nPlanes = m_f->m_exp[0]->GetZIDs().size();
1009 
1010  if (nPlanes > 1)
1011  {
1012  int totPoints = m_f->m_exp[0]->GetPlane(0)->GetTotPoints();
1013 
1014  Array<OneD, int> conn(4 * (np0 - 1) * (nPlanes - 1));
1015  for (int n = 1; n < nPlanes; ++n)
1016  {
1017  for (k = 1; k < np0; ++k)
1018  {
1019  conn[cnt2++] = cnt + (n - 1) * totPoints + k;
1020  conn[cnt2++] = cnt + (n - 1) * totPoints + k - 1;
1021  conn[cnt2++] = cnt + n * totPoints + k - 1;
1022  conn[cnt2++] = cnt + n * totPoints + k;
1023  }
1024  }
1025  m_conn[i] = conn;
1026  }
1027  }
1028 
1029  if (nPlanes == 1)
1030  {
1031  Array<OneD, int> conn(2 * (np0 - 1));
1032 
1033  for (k = 1; k < np0; ++k)
1034  {
1035  conn[cnt2++] = cnt + k;
1036  conn[cnt2++] = cnt + k - 1;
1037  }
1038 
1039  m_conn[i] = conn;
1040  }
1041  }
1042  else if (nbase == 2)
1043  {
1044  int np0 = m_f->m_exp[0]->GetExp(i)->GetNumPoints(0);
1045  int np1 = m_f->m_exp[0]->GetExp(i)->GetNumPoints(1);
1046  int totPoints = m_f->m_exp[0]->GetTotPoints();
1047  int nPlanes = 1;
1048  int cnt2 = 0;
1049 
1050  if (m_f->m_exp[0]->GetExpType() == MultiRegions::e3DH1D)
1051  {
1052  nPlanes = m_f->m_exp[0]->GetZIDs().size();
1053 
1054  // default to 2D case for HalfMode when nPlanes = 1
1055  if (nPlanes > 1)
1056  {
1057  // If Fourier points, output extra plane to fill domain
1058  nPlanes += 1;
1059  totPoints = m_f->m_exp[0]->GetPlane(0)->GetTotPoints();
1060 
1061  Array<OneD, int> conn(8 * (np1 - 1) * (np0 - 1) *
1062  (nPlanes - 1));
1063 
1064  for (int n = 1; n < nPlanes; ++n)
1065  {
1066  for (j = 1; j < np1; ++j)
1067  {
1068  for (k = 1; k < np0; ++k)
1069  {
1070  conn[cnt2++] = cnt + (n - 1) * totPoints +
1071  (j - 1) * np0 + k - 1;
1072  conn[cnt2++] = cnt + (n - 1) * totPoints +
1073  (j - 1) * np0 + k;
1074  conn[cnt2++] =
1075  cnt + (n - 1) * totPoints + j * np0 + k;
1076  conn[cnt2++] =
1077  cnt + (n - 1) * totPoints + j * np0 + k - 1;
1078  conn[cnt2++] =
1079  cnt + n * totPoints + (j - 1) * np0 + k - 1;
1080  conn[cnt2++] =
1081  cnt + n * totPoints + (j - 1) * np0 + k;
1082  conn[cnt2++] =
1083  cnt + n * totPoints + j * np0 + k;
1084  conn[cnt2++] =
1085  cnt + n * totPoints + j * np0 + k - 1;
1086  }
1087  }
1088  }
1089  m_conn[i] = conn;
1090  }
1091  }
1092 
1093  if (nPlanes == 1)
1094  {
1095  Array<OneD, int> conn(4 * (np0 - 1) * (np1 - 1));
1096  for (j = 1; j < np1; ++j)
1097  {
1098  for (k = 1; k < np0; ++k)
1099  {
1100  conn[cnt2++] = cnt + (j - 1) * np0 + k - 1;
1101  conn[cnt2++] = cnt + (j - 1) * np0 + k;
1102  conn[cnt2++] = cnt + j * np0 + k;
1103  conn[cnt2++] = cnt + j * np0 + k - 1;
1104  }
1105  }
1106  m_conn[i] = conn;
1107  }
1108  }
1109  else if (nbase == 3)
1110  {
1111  int np0 = m_f->m_exp[0]->GetExp(i)->GetNumPoints(0);
1112  int np1 = m_f->m_exp[0]->GetExp(i)->GetNumPoints(1);
1113  int np2 = m_f->m_exp[0]->GetExp(i)->GetNumPoints(2);
1114  int cnt2 = 0;
1115 
1116  Array<OneD, int> conn(8 * (np0 - 1) * (np1 - 1) * (np2 - 1));
1117 
1118  for (j = 1; j < np2; ++j)
1119  {
1120  for (k = 1; k < np1; ++k)
1121  {
1122  for (l = 1; l < np0; ++l)
1123  {
1124  conn[cnt2++] =
1125  cnt + (j - 1) * np0 * np1 + (k - 1) * np0 + l - 1;
1126  conn[cnt2++] =
1127  cnt + (j - 1) * np0 * np1 + (k - 1) * np0 + l;
1128  conn[cnt2++] = cnt + (j - 1) * np0 * np1 + k * np0 + l;
1129  conn[cnt2++] =
1130  cnt + (j - 1) * np0 * np1 + k * np0 + l - 1;
1131  conn[cnt2++] =
1132  cnt + j * np0 * np1 + (k - 1) * np0 + l - 1;
1133  conn[cnt2++] = cnt + j * np0 * np1 + (k - 1) * np0 + l;
1134  conn[cnt2++] = cnt + j * np0 * np1 + k * np0 + l;
1135  conn[cnt2++] = cnt + j * np0 * np1 + k * np0 + l - 1;
1136  }
1137  }
1138  }
1139 
1140  m_conn[i] = conn;
1141  }
1142  else
1143  {
1144  ASSERTL0(false, "Not set up for this dimension");
1145  }
1146  }
1147 }
1148 } // namespace FieldUtils
1149 } // namespace Nektar
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:215
#define NEKERROR(type, msg)
Assert Level 0 – Fundamental assert which is used whether in FULLDEBUG, DEBUG or OPT compilation mode...
Definition: ErrorUtil.hpp:209
FieldSharedPtr m_f
Field object.
Definition: Module.h:234
std::map< std::string, ConfigOption > m_config
List of configuration values.
Definition: Module.h:263
Converter from fld to vtk.
fs::path GetFullOutName(std::string &filename, po::variables_map &vm)
fs::path GetPath(std::string &filename, po::variables_map &vm)
virtual void v_Process(po::variables_map &vm) override
Write fld to output file.
void WriteDoubleOrFloat(std::ofstream &outfile, Array< OneD, NekDouble > &data)
Write either double-precision or single-precision output of field data.
virtual void v_WriteTecplotConnectivity(std::ofstream &outfile) override
Write Tecplot connectivity information (ASCII)
virtual void v_WriteTecplotHeader(std::ofstream &outfile, std::vector< std::string > &var) override
Write Tecplot files header in binary format.
virtual void v_WriteTecplotZone(std::ofstream &outfile) override
virtual void v_WriteTecplotHeader(std::ofstream &outfile, std::vector< std::string > &var)
Write Tecplot files header.
virtual void v_Process(po::variables_map &vm) override
Write fld to output file.
virtual fs::path v_GetPath(std::string &filename, po::variables_map &vm) override
int m_totConn
Total number of connectivity entries.
virtual void v_OutputFromPts(po::variables_map &vm) override
Write from pts to output file.
std::vector< Array< OneD, int > > m_conn
Connectivty for each block: one per element.
Array< OneD, int > m_rankConnSizes
Each rank's connectivity sizes.
bool m_binary
True if writing binary field output.
Definition: OutputTecplot.h:98
bool m_oneOutputFile
True if writing a single output file.
void WriteTecplotZone(std::ofstream &outfile)
void CalculateConnectivity()
Calculate connectivity information for each expansion dimension.
void WriteTecplotConnectivity(std::ofstream &outfile)
virtual void v_OutputFromData(po::variables_map &vm) override
Write from data to output file.
bool m_writeHeader
True if writing header.
virtual void v_OutputFromExp(po::variables_map &vm) override
Write from m_exp to output file.
TecplotZoneType m_zoneType
Tecplot zone type of output.
Array< OneD, int > m_rankFieldSizes
Each rank's field sizes.
std::vector< int > m_numPoints
Number of points per block in Tecplot file.
void WriteTecplotHeader(std::ofstream &outfile, std::vector< std::string > &var)
void WriteTecplotFile(po::variables_map &vm)
virtual fs::path v_GetFullOutName(std::string &filename, po::variables_map &vm) override
int m_numBlocks
Number of blocks in Tecplot file.
int m_coordim
Coordinate dimension of output.
virtual void v_WriteTecplotConnectivity(std::ofstream &outfile)
Write Tecplot connectivity information (ASCII)
int GetNumTecplotBlocks()
Calculate number of Tecplot blocks.
virtual void v_WriteTecplotZone(std::ofstream &outfile)
Array< OneD, Array< OneD, NekDouble > > m_fields
Field data to output.
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:198
def copy(self)
Definition: pycml.py:2663
void WriteStream(std::ostream &outfile, T data)
Helper function to write binary data to stream.
std::shared_ptr< Field > FieldSharedPtr
Definition: Field.hpp:991
std::pair< ModuleType, std::string > ModuleKey
Definition: Module.h:317
std::string TecplotZoneTypeMap[]
ModuleFactory & GetModuleFactory()
Definition: Module.cpp:49
std::string PortablePath(const boost::filesystem::path &path)
create portable path on different platforms for boost::filesystem path
Definition: FileSystem.cpp:45
std::shared_ptr< PtsField > PtsFieldSharedPtr
Definition: PtsField.h:190
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:2
std::int32_t NekInt32
double NekDouble
T Vmin(int n, const T *x, const int incx)
Return the minimum element in x - called vmin to avoid conflict with min.
Definition: Vmath.cpp:1050
T Vsum(int n, const T *x, const int incx)
Subtract return sum(x)
Definition: Vmath.cpp:895
void Sadd(int n, const T alpha, const T *x, const int incx, T *y, const int incy)
Add scalar y = alpha + x.
Definition: Vmath.cpp:384
T Vmax(int n, const T *x, const int incx)
Return the maximum element in x – called vmax to avoid conflict with max.
Definition: Vmath.cpp:945
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition: Vmath.cpp:1255
Represents a command-line configuration option.
Definition: Module.h:131