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