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