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