VirtualFluids 0.2.0
Parallel CFD LBM Solver
Loading...
Searching...
No Matches
TransientBCSetter.cpp
Go to the documentation of this file.
1//=======================================================================================
2// ____ ____ __ ______ __________ __ __ __ __
3// \ \ | | | | | _ \ |___ ___| | | | | / \ | |
4// \ \ | | | | | |_) | | | | | | | / \ | |
5// \ \ | | | | | _ / | | | | | | / /\ \ | |
6// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____
7// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______|
8// \ \ | | ________________________________________________________________
9// \ \ | | | ______________________________________________________________|
10// \ \| | | | __ __ __ __ ______ _______
11// \ | | |_____ | | | | | | | | | _ \ / _____)
12// \ | | _____| | | | | | | | | | | \ \ \_______
13// \ | | | | |_____ | \_/ | | | | |_/ / _____ |
14// \ _____| |__| |________| \_______/ |__| |______/ (_______/
15//
16// This file is part of VirtualFluids. VirtualFluids is free software: you can
17// redistribute it and/or modify it under the terms of the GNU General Public
18// License as published by the Free Software Foundation, either version 3 of
19// the License, or (at your option) any later version.
20//
21// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT
22// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
23// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24// for more details.
25//
26// SPDX-License-Identifier: GPL-3.0-or-later
27// SPDX-FileCopyrightText: Copyright © VirtualFluids Project contributors, see AUTHORS.md in root folder
28//
32#include "TransientBCSetter.h"
33
34#include <cmath>
35#include <sstream>
36#include <fstream>
37#include <iostream>
38#include <algorithm>
39#include <stdexcept>
40
42#include <logger/Logger.h>
43
45
46
47using namespace vf::basics::constant;
48
49namespace vf::gpu {
50
51SPtr<FileCollection> createFileCollection(const std::string& path, const std::string& prefix, TransientBCFileType type)
52{
53 switch(type)
54 {
56 return std::make_shared<VTKFileCollection>(path, prefix);
57 break;
58 default:
59 throw std::runtime_error("createFileCollection: Unknown file type");
60 }
61}
62
64{
65 switch(fileCollection->getFileType())
66 {
68 return std::make_shared<VTKReader>(std::static_pointer_cast<VTKFileCollection>(fileCollection), readLevel, cycleFiles);
69 break;
70 default:
71 throw std::runtime_error("createReaderForCollection: No reader availabel for this file t");
72 }
73}
74
75template<typename T>
76std::vector<T> readStringToVector(std::string s)
77{
78 std::vector<T> out;
79 std::stringstream input(s);
80 float num;
81 while(input >> num)
82 {
83 out.push_back(num);
84 }
85 return out;
86}
87std::string getTag(std::ifstream& input)
88{
89 //find beginning of tag
90 std::string tag;
91 char firstChar = input.get();
92 while(firstChar != '<')
93 firstChar = input.get();
94 tag += firstChar;
95 char nextChar = input.get();
96 while(nextChar != '>')
97 {
98 tag += nextChar;
99 nextChar = input.get();
100 }
101 tag += nextChar;
102 return tag;
103}
104
105std::string readElement(const std::string& line)
106{
107 const size_t elemStart = line.find('<')+1;
108 // size_t elemEnd = line.find("/>", elemStart);
109 const size_t nameLen = line.find(' ', elemStart)-elemStart;
110 return line.substr(elemStart, nameLen);
111}
112
113std::string readAttribute(const std::string& line, const std::string& attributeName)
114{
115 const size_t attributeStart = line.find(attributeName)+attributeName.size() + 2; // add 2 for '="'
116 const size_t attributeLen = line.find('\"', attributeStart)-attributeStart;
117 return line.substr(attributeStart, attributeLen);
118}
119
120void VTKFile::readHeader()
121{
122 //TODO make this more flexible
123 std::ifstream file(this->fileName);
124
125 std::string firstTag = getTag(file); // VTKFile
126 const std::string vtkLine = firstTag[1]=='?' ? getTag(file) : firstTag; // ignore first line if xml version
127
128 uint headerSize = 4;
129 if (readAttribute(vtkLine, "version")[0] >= 1 && readAttribute(vtkLine, "header_type") == "UInt64")
130 headerSize = 8;
131
132 const std::string imageData = getTag(file); // ImageData
133 std::vector<int> wholeExtent = readStringToVector<int>(readAttribute(imageData, "WholeExtent"));
134 std::vector<float> origin = readStringToVector<float>(readAttribute(imageData, "Origin"));
135 std::vector<float> spacing = readStringToVector<float>(readAttribute(imageData, "Spacing"));
136
137 const std::string piece = getTag(file); // Piece
138 std::vector<int> pieceExtent = readStringToVector<int>(readAttribute(piece, "Extent"));
139 getTag(file); // PointData
140
141 std::string dataArray = getTag(file);
142 while(strcmp(readElement(dataArray).c_str(), "DataArray")==0)
143 {
144 Quantity quant = Quantity();
145 quant.name = readAttribute(dataArray, "Name");
146 quant.offset = std::stoi(readAttribute(dataArray, "offset"));
147 this->quantities.push_back( quant );
148 dataArray = getTag(file);
149 }
150 getTag(file); // </Piece
151 getTag(file); // </ImageData
152 getTag(file); // AppendedData
153 while(file.get()!='_'){} // go until underscore
154 const int binaryDataStart = int(file.tellg()); // position right after underscore
155 file.close();
156
157 // Convert relative offsets (from XML) to absolute file positions.
158 // Each quantity's XML offset is relative to the underscore and already accounts
159 // for the headers of all preceding data blocks.
160 for(auto& quantity: this->quantities)
161 {
162 quantity.offset = binaryDataStart + quantity.offset + headerSize;
163 }
164
165 this->deltaX = spacing[0];
166 this->deltaY = spacing[1];
167 this->deltaZ = spacing[2];
168
169 this->nx = pieceExtent[1]-pieceExtent[0]+1;
170 this->ny = pieceExtent[3]-pieceExtent[2]+1;
171 this->nz = pieceExtent[5]-pieceExtent[4]+1;
172
173 this->minX = origin[0]+this->deltaX*pieceExtent[0]; this->maxX = (this->nx-1)*this->deltaX+this->minX;
174 this->minY = origin[1]+this->deltaY*pieceExtent[2]; this->maxY = (this->ny-1)*this->deltaY+this->minY;
175 this->minZ = origin[2]+this->deltaZ*pieceExtent[4]; this->maxZ = (this->nz-1)*this->deltaZ+this->minZ;
176 // printFileInfo();
177
178}
179
180bool VTKFile::markNANs(const std::vector<uint>& readIndices) const
181{
182 std::ifstream buf(fileName.c_str(), std::ios::in | std::ios::binary);
183
184 std::vector<double> tmp;
185 tmp.reserve(readIndices.size());
186 buf.seekg(this->quantities[0].offset);
187 buf.read((char*) tmp.data(), sizeof(double)*readIndices.size());
188 const auto firstNAN = std::find_if(tmp.begin(), tmp.end(), [](auto it){ return std::isnan(it); });
189
190 return firstNAN != tmp.end();
191}
192
194{
195 std::ifstream buf(this->fileName.c_str(), std::ios::in | std::ios::binary);
196 for(auto& quantity: this->quantities)
197 {
198 quantity.values.resize(getNumberOfPoints());
199 buf.seekg(quantity.offset);
200 buf.read(reinterpret_cast<char*>(quantity.values.data()), this->getNumberOfPoints()*sizeof(double));
201 }
202
203 buf.close();
204
205 this->loaded = true;
206}
207
209{
210 for(auto& quantity : this->quantities)
211 {
212 std::vector<double> replacement;
213 quantity.values.swap(replacement);
214 }
215 this->loaded = false;
216}
217
218void VTKFile::getData(real *data, uint numberOfNodes, const std::vector<uint> &readIndices,
219 const std::vector<uint> &writeIndices, uint offsetRead, uint offsetWrite)
220{
221 if(!this->loaded) loadFile();
222
223 const size_t nPoints = writeIndices.size();
224
225 for(size_t j=0; j<this->quantities.size(); j++)
226 {
227 real* quant = &data[j*numberOfNodes];
228 for(size_t i=0; i<nPoints; i++)
229 {
230 quant[offsetWrite+writeIndices[i]] = this->quantities[j].values[readIndices[i]+offsetRead];
231 }
232 }
233}
234
235void VTKFile::printFileInfo()
236{
237 VF_LOG_INFO("file {} with \n nx {} ny {} nz {]} \n origin {} {} {}\n spacing {} {} {} ",
238 fileName, nx, ny, nz, minX, minY, minZ, deltaX, deltaY, deltaZ);
239 for(const auto& quantity: this->quantities)
240 {
241 VF_LOG_INFO("\t quantity {} offset {}", quantity.name, quantity.offset);
242 }
243
244}
245
246
247void VTKFileCollection::findFiles()
248{
249 bool foundLastLevel = false;
250
251 while(!foundLastLevel)
252 {
253 bool foundLastID = false;
254 std::vector<std::vector<VTKFile>> filesOnThisLevel;
255 while(!foundLastID)
256 {
257 bool foundLastPart = false;
258 std::vector<VTKFile> filesWithThisId;
259 while (!foundLastPart)
260 {
261 const std::string fname = path + makeFileName((int)files.size(), (int)filesOnThisLevel.size(), (int)filesWithThisId.size());
262 const std::ifstream f(fname);
263 if(f.good())
264 filesWithThisId.emplace_back(fname);
265 else
266 foundLastPart = true;
267 }
268 if(!filesWithThisId.empty())
269 {
270 VF_LOG_INFO("VTKFileCollection found {} files with ID {} level {}", filesWithThisId.size(), filesOnThisLevel.size(), files.size() );
272 }
273 else foundLastID = true;
274 }
275
276
277 if(!filesOnThisLevel.empty())
278 files.push_back(filesOnThisLevel);
279 else
280 foundLastLevel = true;
281
282 }
283
284 if(files.empty())
285 throw std::runtime_error("VTKFileCollection found no files!");
286}
287
295
303
304
305void VTKReader::initializeIndexVectors()
306{
307 this->readIndices.resize(this->fileCollection->files.size());
308 this->writeIndices.resize(this->fileCollection->files.size());
309 this->nFile.resize(this->fileCollection->files.size());
310 for(size_t lev=0; lev<this->fileCollection->files.size(); lev++)
311 {
312 this->readIndices[lev].resize(this->fileCollection->files[lev].size());
313 this->writeIndices[lev].resize(this->fileCollection->files[lev].size());
314 this->nFile[lev].resize(this->fileCollection->files[lev].size());
315 }
316}
317
318void VTKReader::fillArrays(std::vector<real>& coordsY, std::vector<real>& coordsZ)
319{
320 this->nPoints = (uint)coordsY.size();
321 this->initializeIndexVectors();
322 const real max_diff = 1e-3; // maximum distance between point on grid and precursor plane to count as exact match
323 const real eps = 1e-7; // small number to avoid division by zero
324 bool perfect_match = true;
325
326 this->weights0PP.reserve(this->nPoints);
327 this->weights0PM.reserve(this->nPoints);
328 this->weights0MP.reserve(this->nPoints);
329 this->weights0MM.reserve(this->nPoints);
330
331 this->planeNeighbor0PP.reserve(this->nPoints);
332 this->planeNeighbor0PM.reserve(this->nPoints);
333 this->planeNeighbor0MP.reserve(this->nPoints);
334 this->planeNeighbor0MM.reserve(this->nPoints);
335
336 for(uint i=0; i<nPoints; i++)
337 {
338
339 const real posY = coordsY[i];
340 const real posZ = coordsZ[i];
341 bool found0PP = false, found0PM = false, found0MP = false, found0MM = false, foundAll = false;
342
343 const uint level = this->readLevel;
344
345 for(int fileId=0; fileId<(int)this->fileCollection->files[level].size(); fileId++)
346 {
347 VTKFile &file = this->fileCollection->files[level][fileId][0];
348 if(!file.inBoundingBox(posY, posZ, 0.0f)) continue;
349
350 // y in simulation is x in precursor/file, z in simulation is y in precursor/file
351 // simulation -> file: N -> E, S -> W, T -> N, B -> S
352 const int idx = file.findNeighborMMM(posY, posZ, c0o1);
353
354 if(idx!=-1)
355 {
356 // Filter for exact matches
357 if(std::abs(posY-file.getX(idx)) < max_diff && std::abs(posZ-file.getY(idx)) < max_diff)
358 {
359 this->weights0PP.emplace_back(1e6f);
360 this->weights0PM.emplace_back(c0o1);
361 this->weights0MP.emplace_back(c0o1);
362 this->weights0MM.emplace_back(c0o1);
363 const uint writeIdx = this->getWriteIndex(level, fileId, idx);
364 this->planeNeighbor0PP.push_back(writeIdx);
365 this->planeNeighbor0PM.push_back(writeIdx);
366 this->planeNeighbor0MP.push_back(writeIdx);
367 this->planeNeighbor0MM.push_back(writeIdx);
368 found0PP = true;
369 found0PM = true;
370 found0MM = true;
371 found0MP = true;
372 }
373 else
374 {
375 perfect_match = false;
376 }
377
378 if(!found0MM)
379 {
380 found0MM = true;
381 const real dy = file.getX(idx)-posY;
382 const real dz = file.getY(idx)-posZ;
383 this->weights0MM.emplace_back(1.f/(dy*dy+dz*dz+eps));
384 this->planeNeighbor0MM.emplace_back(getWriteIndex(level, fileId, idx));
385 }
386
387 }
388
389 if(!found0PP) //NT in simulation is EN in precursor
390 {
391 const int index = file.findNeighborPPM(posY, posZ, c0o1);
392 if(index!=-1)
393 {
394 found0PP = true;
395 const real dy = file.getX(index)-posY;
396 const real dz = file.getY(index)-posZ;
397 this->weights0PP.emplace_back(1.f/(dy*dy+dz*dz+eps));
398 this->planeNeighbor0PP.emplace_back(getWriteIndex(level, fileId, index));
399 }
400 }
401
402 if(!found0PM) //NB in simulation is ES in precursor
403 {
404 const int index = file.findNeighborPMM(posY, posZ, c0o1);
405 if(index!=-1)
406 {
407 found0PM = true;
408 const real dy = file.getX(index)-posY;
409 const real dz = file.getY(index)-posZ;
410 this->weights0PM.emplace_back(1.f/(dy*dy+dz*dz+eps));
411 this->planeNeighbor0PM.emplace_back(getWriteIndex(level, fileId, index));
412 }
413 }
414
415 if(!found0MP) //ST in simulation is WN in precursor
416 {
417 const int index = file.findNeighborMPM(posY, posZ, c0o1);
418 if(index!=-1)
419 {
420 found0MP = true;
421 const real dy = file.getX(index)-posY;
422 const real dz = file.getY(index)-posZ;
423 this->weights0MP.emplace_back(c1o1/(dy*dy+dz*dz+eps));
424 this->planeNeighbor0MP.emplace_back(getWriteIndex(level, fileId, index));
425 }
426 }
427
429
430 if(foundAll) break;
431 }
432
433 if(!foundAll)
434 {
435 VF_LOG_CRITICAL("Found no matching precursor neighbors for grid point at y={}, z={}", posY, posZ);
436 throw std::runtime_error("VTKReader::fillArrays(): Did not find neighbors in the FileCollection for all points");
437 }
438 }
439
440 if(perfect_match)
441 VF_LOG_INFO("Precursor was a perfect match");
442
443
444 for(size_t level=0; level<this->fileCollection->files.size(); level++){
445 for(size_t id=0; id<this->fileCollection->files[level].size(); id++){
446 if(this->fileCollection->files[level][id][0].markNANs(this->readIndices[level][id]))
447 throw std::runtime_error("Found a NAN in the precursor where a velocity is needed");
448 }}
449}
450
451uint VTKReader::getWriteIndex(int level, int id, int linearIndex)
452{
453 const auto it = std::find(this->writeIndices[level][id].begin(), this->writeIndices[level][id].end(), linearIndex);
454 const uint idx = it-this->writeIndices[level][id].begin();
455 if(it==this->writeIndices[level][id].end())
456 {
457 this->writeIndices[level][id].push_back(this->nPointsRead);
458 this->readIndices[level][id].push_back(linearIndex);
459 this->nPointsRead++;
460 }
461 return idx;
462}
463
464
465void VTKReader::getNextData(real* data, uint numberOfNodes, real time)
466{
467 const uint level = this->readLevel;
468 for(size_t id=0; id<this->fileCollection->files[level].size(); id++)
469 {
470 size_t numberOfFiles = this->nFile[level][id];
471
472 if(!this->fileCollection->files[level][id][numberOfFiles].inZBounds(time-startTime))
473 {
475
476 VF_LOG_INFO("PrecursorBC on level {}: switching to file no. {}", level, numberOfFiles);
477 if(numberOfFiles == this->fileCollection->files[level][id].size())
478 {
479 if(cycleFiles)
480 {
481 numberOfFiles = 0;
482 startTime = time;
483 }
484 else
485 throw std::runtime_error("Not enough Precursor Files to read");
486 }
487
488 if(numberOfFiles > 0)
489 this->fileCollection->files[level][id][numberOfFiles-1].unloadFile();
490 if(numberOfFiles+1<this->fileCollection->files[level][id].size())
491 {
492 VTKFile* nextFile = &this->fileCollection->files[level][id][numberOfFiles+1];
493 if(! nextFile->isLoaded())
494 {
495 read.wait();
496 read = std::async(std::launch::async, [](VTKFile* file){ file->loadFile(); }, &this->fileCollection->files[level][id][numberOfFiles+1]);
497 }
498 }
499 }
500
501 VTKFile* file = &this->fileCollection->files[level][id][numberOfFiles];
502
503 const int off = file->getClosestIdxZ(time-startTime)*file->getNumberOfPointsInXYPlane();
504 file->getData(data, numberOfNodes, this->readIndices[level][id], this->writeIndices[level][id], off, this->writingOffset);
505 this->nFile[level][id] = numberOfFiles;
506 }
507}
508
509}
510
#define VF_LOG_INFO(...)
Definition Logger.h:50
#define VF_LOG_CRITICAL(...)
Definition Logger.h:52
void getNeighbors(uint *neighbor0PP, uint *neighbor0PM, uint *neighbor0MP, uint *neighbor0MM)
void getWeights(real *_weights0PP, real *_weights0PM, real *_weights0MP, real *_weights0MM)
std::vector< std::vector< std::vector< VTKFile > > > files
int findNeighborPMM(real posX, real posY, real posZ) const
real getX(int linearIdx) const
int getClosestIdxZ(real posZ) const
bool inBoundingBox(real posX, real posY, real posZ) const
int getNumberOfPoints() const
int findNeighborMPM(real posX, real posY, real posZ) const
bool markNANs(const std::vector< uint > &readIndices) const
void getData(real *data, uint numberOfNodes, const std::vector< uint > &readIndices, const std::vector< uint > &writeIndices, uint offsetRead, uint offsetWrite)
real getY(int linearIdx) const
int getNumberOfPointsInXYPlane() const
int findNeighborPPM(real posX, real posY, real posZ) const
int findNeighborMMM(real posX, real posY, real posZ) const
void fillArrays(std::vector< real > &coordsY, std::vector< real > &coordsZ) override
void getNextData(real *data, uint numberOfNodes, real time) override
std::shared_ptr< T > SPtr
float real
Definition DataTypes.h:42
unsigned int uint
Definition DataTypes.h:47
std::string readAttribute(const std::string &line, const std::string &attributeName)
std::string getTag(std::ifstream &input)
SPtr< TransientBCInputFileReader > createReaderForCollection(SPtr< FileCollection > fileCollection, uint readLevel, bool cycleFiles)
std::vector< T > readStringToVector(std::string s)
std::string readElement(const std::string &line)
SPtr< FileCollection > createFileCollection(const std::string &path, const std::string &prefix, TransientBCFileType type)