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