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