Nektar++
InputNek5000.cpp
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////////////
2//
3// File: InputNek5000.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: Reads a Nek5000 checkpoint file.
32//
33////////////////////////////////////////////////////////////////////////////////
34
35#include <fstream>
36#include <iostream>
37#include <string>
38#include <vector>
39using namespace std;
40
41#include <boost/algorithm/string.hpp>
42#include <boost/core/ignore_unused.hpp>
43
44#include "InputNek5000.h"
45
46namespace Nektar
47{
48namespace FieldUtils
49{
50
54 "Reads Nek5000 field file.")};
55
56/**
57 * @brief Set up InputNek5000 object.
58 *
59 */
61{
62 m_allowedFiles.insert("fld5000");
63}
64
65/**
66 *
67 */
69{
70}
71
72/**
73 * @brief Process Nek5000 input file.
74 *
75 * This routine reads a binary-format Nek5000 field file, loads the data into
76 * memory and populates the field definitions to match the data format. Nek5000
77 * is a classic nodal-Lagrangian spectral element code at a single polynomial
78 * order, meaning that the field data are set up according to this structure.
79 *
80 * This module is adapted from the VisIt visualisation software, which supports
81 * a number of Nek5000 inputs.
82 */
83void InputNek5000::v_Process(po::variables_map &vm)
84{
85 boost::ignore_unused(vm);
86
87 ifstream file(m_config["infile"].as<string>().c_str(), ios::binary);
88
89 // Header: 132 bytes for binary.
90 vector<char> data(132);
91 file.read(&data[0], 132);
92
93 // Check header: should be the four characters #std
94 string check(&data[0], 4);
95 string header(&data[4], 128);
96
97 ASSERTL0(check == "#std", "Unable to read file");
98
99 // Determine whether we need to byte-swap data: 4-byte float at byte 80
100 // should be 6.54321.
101 bool byteSwap = false;
102 float test;
103
104 file.read((char *)(&test), 4);
105 if (test > 6.5 && test < 6.6)
106 {
107 byteSwap = false;
108 }
109 else
110 {
112 ASSERTL0(test > 6.5 && test < 6.6,
113 "Unable to determine endian-ness of input file");
114 byteSwap = true;
115 }
116
117 stringstream ss;
118 ss.str(header);
119
120 int nBytes, nBlocksXYZ[3], nBlocks, nTotBlocks, dir, nDirs, nCycle, nDim;
121 NekDouble time;
122
123 // Read header information (this is written as ASCII)
124 string remain;
125 ss >> nBytes >> nBlocksXYZ[0] >> nBlocksXYZ[1] >> nBlocksXYZ[2] >>
126 nBlocks >> nTotBlocks >> time >> nCycle >> dir >> nDirs >> remain;
127 boost::trim(remain);
128
129 nDim = nBlocksXYZ[2] == 1 ? 2 : 3;
130
131 // Print some basic information for input if in verbose mode.
132 if (m_f->m_verbose)
133 {
134 cout << "Found header information:" << endl;
135 cout << " -- " << (byteSwap ? "" : "do not ") << "need to swap endian"
136 << endl;
137 cout << " -- Data byte size : " << nBytes << endl;
138 cout << " -- Number of xyz blocks : " << nBlocksXYZ[0] << "x"
139 << nBlocksXYZ[1] << "x" << nBlocksXYZ[2] << endl;
140 cout << " -- Blocks in file/total : " << nBlocks << "/" << nTotBlocks
141 << endl;
142 cout << " -- Simulation time : " << time << endl;
143 cout << " -- Number of cycles : " << nCycle << endl;
144 cout << " -- Number of dirs : " << dir << "/" << nDirs << endl;
145 cout << " -- Remaining header : " << remain << endl;
146 }
147
148 // Major limitation: we don't read out of multiple directories
149 ASSERTL0(nDirs == 1, "Number of directories must be one");
150
151 // We also don't read partial files.
152 ASSERTL0(nBlocks == nTotBlocks, "Partial field output not supported");
153
154 // We don't support non-double data
155 ASSERTL0(nBytes == 8, "Data file must contain double-precision data");
156
157 // Set up a field definition
160 fielddef->m_shapeType = LibUtilities::eHexahedron;
161 fielddef->m_numHomogeneousDir = 0;
162 fielddef->m_homoStrips = false;
163 fielddef->m_pointsDef = false;
164 fielddef->m_uniOrder = true;
165 fielddef->m_numPointsDef = false;
166
167 for (int i = 0; i < nDim; ++i)
168 {
169 fielddef->m_basis.push_back(LibUtilities::eGLL_Lagrange);
170 fielddef->m_numModes.push_back(nBlocksXYZ[i]);
171 }
172
173 // Read element IDs
174 NekUInt32 maxID = 0, minID = numeric_limits<NekUInt32>::max();
175 for (NekUInt32 i = 0; i < nBlocks; ++i)
176 {
177 NekUInt32 blockNum;
178 file.read((char *)&blockNum, 4);
179 if (byteSwap)
180 {
181 swap_endian(blockNum);
182 }
183 fielddef->m_elementIDs.push_back(blockNum - 1);
184
185 maxID = maxID > blockNum ? maxID : blockNum;
186 minID = minID < blockNum ? minID : blockNum;
187 }
188
189 // Determine how many fields we have to extract
190 size_t blockSize = nBlocksXYZ[0] * nBlocksXYZ[1] * nBlocksXYZ[2];
191 size_t dataSize = blockSize * nBlocks;
192
193 for (string::size_type i = 0; i < remain.size(); ++i)
194 {
195 switch (remain[i])
196 {
197 case 'U':
198 fielddef->m_fields.push_back("u");
199 fielddef->m_fields.push_back("v");
200 if (nDim == 3)
201 {
202 fielddef->m_fields.push_back("w");
203 }
204 break;
205 case 'P':
206 fielddef->m_fields.push_back("p");
207 break;
208 case 'T':
209 fielddef->m_fields.push_back("T");
210 break;
211 case '1':
212 case '2':
213 case '3':
214 fielddef->m_fields.push_back(string("scalar") + remain[i]);
215 break;
216 case ' ':
217 continue;
218 default:
219 cerr << "Field contains unknown variable: " << remain[i]
220 << endl;
221 abort();
222 }
223 }
224
225 m_f->m_data.resize(1);
226 m_f->m_data[0].resize(fielddef->m_fields.size() * dataSize);
227
228 // Now reprocess since different fields need different logic
229 for (size_t i = 0, cnt = 0; i < remain.size(); ++i)
230 {
231 switch (remain[i])
232 {
233 case 'U':
234 {
235 size_t cntVel[3] = {cnt, cnt + dataSize, cnt + 2 * dataSize};
236
237 for (size_t j = 0; j < nBlocks; ++j)
238 {
239 for (size_t k = 0; k < nDim; ++k)
240 {
241 file.read((char *)&m_f->m_data[0][cntVel[k]],
242 blockSize * sizeof(NekDouble));
243 cntVel[k] += blockSize;
244 }
245 }
246
247 cnt += nDim * dataSize;
248 break;
249 }
250 case 'P':
251 {
252 file.read((char *)&m_f->m_data[0][cnt],
253 dataSize * sizeof(NekDouble));
254 cnt += dataSize;
255 break;
256 }
257 case '1':
258 case '2':
259 case '3':
260 {
261 file.read((char *)&m_f->m_data[0][cnt],
262 dataSize * sizeof(NekDouble));
263 cnt += dataSize;
264 break;
265 }
266 case ' ':
267 continue;
268 }
269 }
270
271 m_f->m_fielddef.push_back(fielddef);
272
273 // save field names
274 m_f->m_variables = m_f->m_fielddef[0]->m_fields;
275}
276} // namespace FieldUtils
277} // namespace Nektar
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:215
Abstract base class for input modules.
Definition: Module.h:278
static ModuleSharedPtr create(FieldSharedPtr f)
Creates an instance of this class.
Definition: InputNek5000.h:55
InputNek5000(FieldSharedPtr f)
Set up InputNek5000 object.
static ModuleKey m_className[]
ModuleKey for class.
Definition: InputNek5000.h:60
virtual void v_Process(po::variables_map &vm) override
Process Nek5000 input file.
std::set< std::string > m_allowedFiles
List of allowed file formats.
Definition: Module.h:265
FieldSharedPtr m_f
Field object.
Definition: Module.h:234
std::map< std::string, ConfigOption > m_config
List of configuration values.
Definition: Module.h:263
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:198
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
std::shared_ptr< Field > FieldSharedPtr
Definition: Field.hpp:991
std::pair< ModuleType, std::string > ModuleKey
Definition: Module.h:317
void swap_endian(T &u)
Swap endian ordering of the input variable.
Definition: Module.h:100
ModuleFactory & GetModuleFactory()
Definition: Module.cpp:49
std::shared_ptr< FieldDefinitions > FieldDefinitionsSharedPtr
Definition: FieldIO.h:186
@ eGLL_Lagrange
Lagrange for SEM basis .
Definition: BasisType.h:58
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:2
std::uint32_t NekUInt32
double NekDouble