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>
39 using namespace std;
40 
41 #include <boost/algorithm/string.hpp>
42 #include <boost/core/ignore_unused.hpp>
43 
44 #include "InputNek5000.h"
45 
46 namespace Nektar
47 {
48 namespace FieldUtils
49 {
50 
51 ModuleKey InputNek5000::m_className[1] = {
53  ModuleKey(eInputModule, "fld5000"), InputNek5000::create,
54  "Reads Nek5000 field file.")};
55 
56 /**
57  * @brief Set up InputNek5000 object.
58  *
59  */
60 InputNek5000::InputNek5000(FieldSharedPtr f) : InputModule(f)
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  */
83 void 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  {
111  swap_endian(test);
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
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