diff --git a/CMakeLists.txt b/CMakeLists.txt index a0a46ed652ed3b586e56af163a749a86edf3c5be..03ed97b484e3cd3fc53d73d2ad0247f12503ea9c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ project(VirtualFluids CXX) set(CMAKE_BUILD_TYPE Release) -set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set_property(GLOBAL PROPERTY USE_FOLDERS ON) diff --git a/apps/gpu/DiluteGravityCurrents_Case1/DiluteGravityCurrents_Case1.cpp b/apps/gpu/DiluteGravityCurrents_Case1/DiluteGravityCurrents_Case1.cpp index 6473af944693e24440ce68137344d359f6c2e2df..838b2ccd5de9d89626ea8c61bf92592743a7ccba 100644 --- a/apps/gpu/DiluteGravityCurrents_Case1/DiluteGravityCurrents_Case1.cpp +++ b/apps/gpu/DiluteGravityCurrents_Case1/DiluteGravityCurrents_Case1.cpp @@ -100,9 +100,7 @@ int main(int argc, char *argv[]) // setup gridGenerator ////////////////////////////////////////////////////////////////////////// - auto gridFactory = GridFactory::make(); - gridFactory->setGridStrategy(Device::CPU); - auto gridBuilder = MultipleGridBuilder::makeShared(gridFactory); + auto gridBuilder = MultipleGridBuilder::makeShared(); ////////////////////////////////////////////////////////////////////////// // create grid diff --git a/apps/gpu/DiluteGravityCurrents_Case2/DiluteGravityCurrents_Case2.cpp b/apps/gpu/DiluteGravityCurrents_Case2/DiluteGravityCurrents_Case2.cpp index f0400a718ff17fe0fbb2f6edcea7997e9bf4f151..dcbb47c4b811434f10c6546e2c7b8ad2f829e6ae 100644 --- a/apps/gpu/DiluteGravityCurrents_Case2/DiluteGravityCurrents_Case2.cpp +++ b/apps/gpu/DiluteGravityCurrents_Case2/DiluteGravityCurrents_Case2.cpp @@ -100,9 +100,7 @@ int main(int argc, char *argv[]) // setup gridGenerator ////////////////////////////////////////////////////////////////////////// - auto gridFactory = GridFactory::make(); - gridFactory->setGridStrategy(Device::CPU); - auto gridBuilder = MultipleGridBuilder::makeShared(gridFactory); + auto gridBuilder = MultipleGridBuilder::makeShared(); ////////////////////////////////////////////////////////////////////////// // create grid diff --git a/apps/gpu/DiluteGravityCurrents_Case3/DiluteGravityCurrents_Case3.cpp b/apps/gpu/DiluteGravityCurrents_Case3/DiluteGravityCurrents_Case3.cpp index d452efdecabe07e730926d62efbd6af4f0bec555..e77d5f6ebc497bb8bd77a65cac6c6219c85ab5cc 100644 --- a/apps/gpu/DiluteGravityCurrents_Case3/DiluteGravityCurrents_Case3.cpp +++ b/apps/gpu/DiluteGravityCurrents_Case3/DiluteGravityCurrents_Case3.cpp @@ -100,9 +100,7 @@ int main(int argc, char *argv[]) // setup gridGenerator ////////////////////////////////////////////////////////////////////////// - auto gridFactory = GridFactory::make(); - gridFactory->setGridStrategy(Device::CPU); - auto gridBuilder = MultipleGridBuilder::makeShared(gridFactory); + auto gridBuilder = MultipleGridBuilder::makeShared(); ////////////////////////////////////////////////////////////////////////// // create grid diff --git a/apps/gpu/DiluteGravityCurrents_Case4/DiluteGravityCurrents_Case4.cpp b/apps/gpu/DiluteGravityCurrents_Case4/DiluteGravityCurrents_Case4.cpp index 96ea163ea10c201eeb7270bdc24f06317e29d129..7427aa9b7887e3645819a692f952f0e8320a81a1 100644 --- a/apps/gpu/DiluteGravityCurrents_Case4/DiluteGravityCurrents_Case4.cpp +++ b/apps/gpu/DiluteGravityCurrents_Case4/DiluteGravityCurrents_Case4.cpp @@ -100,9 +100,7 @@ int main(int argc, char *argv[]) // setup gridGenerator ////////////////////////////////////////////////////////////////////////// - auto gridFactory = GridFactory::make(); - gridFactory->setGridStrategy(Device::CPU); - auto gridBuilder = MultipleGridBuilder::makeShared(gridFactory); + auto gridBuilder = MultipleGridBuilder::makeShared(); ////////////////////////////////////////////////////////////////////////// // create grid diff --git a/apps/gpu/DiluteGravityCurrents_Case5/DiluteGravityCurrents_Case5.cpp b/apps/gpu/DiluteGravityCurrents_Case5/DiluteGravityCurrents_Case5.cpp index 849f1b35b3288c53f5c4925a2451dae083e0ef8d..9df9da2872112537b905fafc3f7275dfd6cb0430 100644 --- a/apps/gpu/DiluteGravityCurrents_Case5/DiluteGravityCurrents_Case5.cpp +++ b/apps/gpu/DiluteGravityCurrents_Case5/DiluteGravityCurrents_Case5.cpp @@ -100,9 +100,7 @@ int main(int argc, char *argv[]) // setup gridGenerator ////////////////////////////////////////////////////////////////////////// - auto gridFactory = GridFactory::make(); - gridFactory->setGridStrategy(Device::CPU); - auto gridBuilder = MultipleGridBuilder::makeShared(gridFactory); + auto gridBuilder = MultipleGridBuilder::makeShared(); ////////////////////////////////////////////////////////////////////////// // create grid diff --git a/apps/gpu/DiluteGravityCurrents_Case6/DiluteGravityCurrents_Case6.cpp b/apps/gpu/DiluteGravityCurrents_Case6/DiluteGravityCurrents_Case6.cpp index 751928fca4de3038e8532cc8c020a522492606ee..f1c8aa5c20d7bf987d0282c6e03b66a1ce3f89e2 100644 --- a/apps/gpu/DiluteGravityCurrents_Case6/DiluteGravityCurrents_Case6.cpp +++ b/apps/gpu/DiluteGravityCurrents_Case6/DiluteGravityCurrents_Case6.cpp @@ -100,9 +100,7 @@ int main(int argc, char *argv[]) // setup gridGenerator ////////////////////////////////////////////////////////////////////////// - auto gridFactory = GridFactory::make(); - gridFactory->setGridStrategy(Device::CPU); - auto gridBuilder = MultipleGridBuilder::makeShared(gridFactory); + auto gridBuilder = MultipleGridBuilder::makeShared(); ////////////////////////////////////////////////////////////////////////// // create grid diff --git a/apps/gpu/DiluteGravityCurrents_Case7/DiluteGravityCurrents_Case7.cpp b/apps/gpu/DiluteGravityCurrents_Case7/DiluteGravityCurrents_Case7.cpp index a6ac0ebb4a109889acbf6f7f4107a78c1e346c47..d6d4684369c03c90c63c02ae85ddfc2d5d88da89 100644 --- a/apps/gpu/DiluteGravityCurrents_Case7/DiluteGravityCurrents_Case7.cpp +++ b/apps/gpu/DiluteGravityCurrents_Case7/DiluteGravityCurrents_Case7.cpp @@ -100,9 +100,7 @@ int main(int argc, char *argv[]) // setup gridGenerator ////////////////////////////////////////////////////////////////////////// - auto gridFactory = GridFactory::make(); - gridFactory->setGridStrategy(Device::CPU); - auto gridBuilder = MultipleGridBuilder::makeShared(gridFactory); + auto gridBuilder = MultipleGridBuilder::makeShared(); ////////////////////////////////////////////////////////////////////////// // create grid diff --git a/apps/gpu/DiluteGravityCurrents_Case8/DiluteGravityCurrents_Case8.cpp b/apps/gpu/DiluteGravityCurrents_Case8/DiluteGravityCurrents_Case8.cpp index 94c0d76ef5ec2ffb0ac3c6cf2556913ed4b9db92..09459acd8ca78d37501c68ada334a98a6fc4a525 100644 --- a/apps/gpu/DiluteGravityCurrents_Case8/DiluteGravityCurrents_Case8.cpp +++ b/apps/gpu/DiluteGravityCurrents_Case8/DiluteGravityCurrents_Case8.cpp @@ -100,9 +100,7 @@ int main(int argc, char *argv[]) // setup gridGenerator ////////////////////////////////////////////////////////////////////////// - auto gridFactory = GridFactory::make(); - gridFactory->setGridStrategy(Device::CPU); - auto gridBuilder = MultipleGridBuilder::makeShared(gridFactory); + auto gridBuilder = MultipleGridBuilder::makeShared(); ////////////////////////////////////////////////////////////////////////// // create grid diff --git a/apps/gpu/LidDrivenCavityGPU/LidDrivenCavity.cpp b/apps/gpu/LidDrivenCavityGPU/LidDrivenCavity.cpp index 86b6f5f4a1176de85e689d6573a34667e0c74d47..a4fcec0f36e2c36b1fd90148b31a50fc998a8d26 100644 --- a/apps/gpu/LidDrivenCavityGPU/LidDrivenCavity.cpp +++ b/apps/gpu/LidDrivenCavityGPU/LidDrivenCavity.cpp @@ -94,7 +94,7 @@ int main(int argc, char *argv[]) ////////////////////////////////////////////////////////////////////////// // Simulation parameters ////////////////////////////////////////////////////////////////////////// - std::string path("./output"); + std::string path("D:/out/DrivenCavity"); std::string simulationName("LidDrivenCavity"); const real L = 1.0; @@ -123,9 +123,7 @@ int main(int argc, char *argv[]) // setup gridGenerator ////////////////////////////////////////////////////////////////////////// - auto gridFactory = GridFactory::make(); - gridFactory->setGridStrategy(Device::CPU); - auto gridBuilder = MultipleGridBuilder::makeShared(gridFactory); + auto gridBuilder = MultipleGridBuilder::makeShared(); ////////////////////////////////////////////////////////////////////////// // create grid diff --git a/src/basics/Core/ArrayTypes.h b/src/basics/Core/ArrayTypes.h index 7d5d70374b04d7ad29a6443fbcac0263fd8d0ad6..f899c92a7be4f29065b55b13fb1a1181da0eaf7e 100644 --- a/src/basics/Core/ArrayTypes.h +++ b/src/basics/Core/ArrayTypes.h @@ -1,3 +1,35 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file ArrayTypes.h +//! \ingroup Core +//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller +//======================================================================================= #ifndef ARRAYTYPES_H #define ARRAYTYPES_H diff --git a/src/basics/Core/DataTypes.h b/src/basics/Core/DataTypes.h index 49d269097b76cdf3ad350ed0cd65d72e6310d849..36fd33aaa0587382ce322c06b46bbb7cd0cdd8d0 100644 --- a/src/basics/Core/DataTypes.h +++ b/src/basics/Core/DataTypes.h @@ -1,3 +1,35 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file DataTypes.h +//! \ingroup Core +//! \author Soeren Peters +//======================================================================================= #ifndef DATATYPES_H #define DATATYPES_H diff --git a/src/basics/Core/Input/ConfigData/ConfigData.h b/src/basics/Core/Input/ConfigData/ConfigData.h deleted file mode 100644 index 44d50557608817bff889ba9aa4316861d8ce2bca..0000000000000000000000000000000000000000 --- a/src/basics/Core/Input/ConfigData/ConfigData.h +++ /dev/null @@ -1,185 +0,0 @@ -#ifndef CONFIGDATA_H -#define CONFIGDATA_H - -#include "../../DataTypes.h" - -#include <memory> -#include <vector> - -class ConfigData -{ -public: - virtual ~ConfigData() = default; - - virtual real getViscosity() = 0; - virtual uint getNumberOfDevices() = 0; - virtual std::vector<uint> getDevices() = 0; - virtual std::string getOutputPath() = 0; - virtual std::string getPrefix() = 0; - virtual std::string getGridPath() = 0; - virtual bool getPrintOutputFiles() = 0; - virtual bool getGeometryValues() = 0; - virtual bool getCalc2ndOrderMoments() = 0; - virtual bool getCalc3rdOrderMoments() = 0; - virtual bool getCalcHighOrderMoments() = 0; - virtual bool getReadGeo() = 0; - virtual bool getCalcMedian() = 0; - virtual bool getCalcDragLift() = 0; - virtual bool getCalcCp() = 0; - virtual bool getWriteVeloASCIIfiles() = 0; - virtual bool getCalcPlaneConc() = 0; - virtual bool getConcFile() = 0; - virtual bool getStreetVelocityFile() = 0; - virtual bool getUseMeasurePoints() = 0; - virtual bool getUseWale() = 0; - virtual bool getUseInitNeq() = 0; - virtual bool getSimulatePorousMedia() = 0; - virtual uint getD3Qxx() = 0; - virtual uint getTEnd() = 0; - virtual uint getTOut() = 0; - virtual uint getTStartOut() = 0; - virtual uint getTimeCalcMedStart() = 0; - virtual uint getTimeCalcMedEnd() = 0; - virtual uint getPressInID() = 0; - virtual uint getPressOutID() = 0; - virtual uint getPressInZ() = 0; - virtual uint getPressOutZ() = 0; - virtual bool getDiffOn() = 0; - virtual uint getDiffMod() = 0; - virtual real getDiffusivity() = 0; - virtual real getTemperatureInit() = 0; - virtual real getTemperatureBC() = 0; - virtual real getVelocity() = 0; - virtual real getViscosityRatio() = 0; - virtual real getVelocityRatio() = 0; - virtual real getDensityRatio() = 0; - virtual real getPressRatio() = 0; - virtual real getRealX() = 0; - virtual real getRealY() = 0; - virtual real getFactorPressBC() = 0; - virtual std::string getGeometryFileC() = 0; - virtual std::string getGeometryFileM() = 0; - virtual std::string getGeometryFileF() = 0; - virtual uint getClockCycleForMP() = 0; - virtual uint getTimestepForMP() = 0; - virtual real getForcingX() = 0; - virtual real getForcingY() = 0; - virtual real getForcingZ() = 0; - virtual real getQuadricLimiterP() = 0; - virtual real getQuadricLimiterM() = 0; - virtual real getQuadricLimiterD() = 0; - virtual bool getCalcParticles() = 0; - virtual int getParticleBasicLevel() = 0; - virtual int getParticleInitLevel() = 0; - virtual int getNumberOfParticles() = 0; - virtual real getStartXHotWall() = 0; - virtual real getEndXHotWall() = 0; - virtual std::vector<std::string> getPossNeighborFilesX() = 0; - virtual std::vector<std::string> getPossNeighborFilesY() = 0; - virtual std::vector<std::string> getPossNeighborFilesZ() = 0; - // virtual std::vector<std::string> getPossNeighborFilesX() = 0; - // virtual std::vector<std::string> getPossNeighborFilesY() = 0; - // virtual std::vector<std::string> getPossNeighborFilesZ() = 0; - virtual int getTimeDoCheckPoint() = 0; - virtual int getTimeDoRestart() = 0; - virtual bool getDoCheckPoint() = 0; - virtual bool getDoRestart() = 0; - virtual uint getMaxLevel() = 0; - virtual std::vector<int> getGridX() = 0; - virtual std::vector<int> getGridY() = 0; - virtual std::vector<int> getGridZ() = 0; - virtual std::vector<int> getDistX() = 0; - virtual std::vector<int> getDistY() = 0; - virtual std::vector<int> getDistZ() = 0; - virtual std::vector<bool> getNeedInterface() = 0; - virtual std::string getMainKernel() = 0; - virtual bool getMultiKernelOn() = 0; - virtual std::vector<int> getMultiKernelLevel() = 0; - virtual std::vector<std::string> getMultiKernelName() = 0; - - virtual bool isViscosityInConfigFile() = 0; - virtual bool isNumberOfDevicesInConfigFile() = 0; - virtual bool isDevicesInConfigFile() = 0; - virtual bool isOutputPathInConfigFile() = 0; - virtual bool isPrefixInConfigFile() = 0; - virtual bool isGridPathInConfigFile() = 0; - virtual bool isPrintOutputFilesInConfigFile() = 0; - virtual bool isGeometryValuesInConfigFile() = 0; - virtual bool isCalc2ndOrderMomentsInConfigFile() = 0; - virtual bool isCalc3rdOrderMomentsInConfigFile() = 0; - virtual bool isCalcHighOrderMomentsInConfigFile() = 0; - virtual bool isReadGeoInConfigFile() = 0; - virtual bool isCalcMedianInConfigFile() = 0; - virtual bool isCalcDragLiftInConfigFile() = 0; - virtual bool isCalcCpInConfigFile() = 0; - virtual bool isWriteVeloASCIIfilesInConfigFile() = 0; - virtual bool isCalcPlaneConcInConfigFile() = 0; - virtual bool isConcFileInConfigFile() = 0; - virtual bool isStreetVelocityFileInConfigFile() = 0; - virtual bool isUseMeasurePointsInConfigFile() = 0; - virtual bool isUseWaleInConfigFile() = 0; - virtual bool isUseInitNeqInConfigFile() = 0; - virtual bool isSimulatePorousMediaInConfigFile() = 0; - virtual bool isD3QxxInConfigFile() = 0; - virtual bool isTEndInConfigFile() = 0; - virtual bool isTOutInConfigFile() = 0; - virtual bool isTStartOutInConfigFile() = 0; - virtual bool isTimeCalcMedStartInConfigFile() = 0; - virtual bool isTimeCalcMedEndInConfigFile() = 0; - virtual bool isPressInIDInConfigFile() = 0; - virtual bool isPressOutIDInConfigFile() = 0; - virtual bool isPressInZInConfigFile() = 0; - virtual bool isPressOutZInConfigFile() = 0; - virtual bool isDiffOnInConfigFile() = 0; - virtual bool isDiffModInConfigFile() = 0; - virtual bool isDiffusivityInConfigFile() = 0; - virtual bool isTemperatureInitInConfigFile() = 0; - virtual bool isTemperatureBCInConfigFile() = 0; - // virtual bool isViscosityInConfigFile() = 0; - virtual bool isVelocityInConfigFile() = 0; - virtual bool isViscosityRatioInConfigFile() = 0; - virtual bool isVelocityRatioInConfigFile() = 0; - virtual bool isDensityRatioInConfigFile() = 0; - virtual bool isPressRatioInConfigFile() = 0; - virtual bool isRealXInConfigFile() = 0; - virtual bool isRealYInConfigFile() = 0; - virtual bool isFactorPressBCInConfigFile() = 0; - virtual bool isGeometryFileCInConfigFile() = 0; - virtual bool isGeometryFileMInConfigFile() = 0; - virtual bool isGeometryFileFInConfigFile() = 0; - virtual bool isClockCycleForMPInConfigFile() = 0; - virtual bool isTimestepForMPInConfigFile() = 0; - virtual bool isForcingXInConfigFile() = 0; - virtual bool isForcingYInConfigFile() = 0; - virtual bool isForcingZInConfigFile() = 0; - virtual bool isQuadricLimiterPInConfigFile() = 0; - virtual bool isQuadricLimiterMInConfigFile() = 0; - virtual bool isQuadricLimiterDInConfigFile() = 0; - virtual bool isCalcParticlesInConfigFile() = 0; - virtual bool isParticleBasicLevelInConfigFile() = 0; - virtual bool isParticleInitLevelInConfigFile() = 0; - virtual bool isNumberOfParticlesInConfigFile() = 0; - virtual bool isNeighborWSBInConfigFile() = 0; - virtual bool isStartXHotWallInConfigFile() = 0; - virtual bool isEndXHotWallInConfigFile() = 0; - virtual bool isPossNeighborFilesXInConfigFile() = 0; - virtual bool isPossNeighborFilesYInConfigFile() = 0; - virtual bool isPossNeighborFilesZInConfigFile() = 0; - virtual bool isTimeDoCheckPointInConfigFile() = 0; - virtual bool isTimeDoRestartInConfigFile() = 0; - virtual bool isDoCheckPointInConfigFile() = 0; - virtual bool isDoRestartInConfigFile() = 0; - virtual bool isMaxLevelInConfigFile() = 0; - virtual bool isGridXInConfigFile() = 0; - virtual bool isGridYInConfigFile() = 0; - virtual bool isGridZInConfigFile() = 0; - virtual bool isDistXInConfigFile() = 0; - virtual bool isDistYInConfigFile() = 0; - virtual bool isDistZInConfigFile() = 0; - virtual bool isNeedInterfaceInConfigFile() = 0; - virtual bool isMainKernelInConfigFile() = 0; - virtual bool isMultiKernelOnInConfigFile() = 0; - virtual bool isMultiKernelLevelInConfigFile() = 0; - virtual bool isMultiKernelNameInConfigFile() = 0; -}; -#endif diff --git a/src/basics/Core/Input/ConfigData/ConfigDataImp.cpp b/src/basics/Core/Input/ConfigData/ConfigDataImp.cpp deleted file mode 100644 index 0c53b32829eb989667b93fc7df156525267e930b..0000000000000000000000000000000000000000 --- a/src/basics/Core/Input/ConfigData/ConfigDataImp.cpp +++ /dev/null @@ -1,834 +0,0 @@ -#include "ConfigDataImp.h" - -std::shared_ptr<ConfigDataImp> ConfigDataImp::getNewInstance() -{ - return std::shared_ptr<ConfigDataImp>(new ConfigDataImp()); -} - -real ConfigDataImp::getViscosity() { return this->viscosity; } - -uint ConfigDataImp::getNumberOfDevices() { return this->numberOfDevices; } - -std::vector<uint> ConfigDataImp::getDevices() { return this->devices; } - -std::string ConfigDataImp::getOutputPath() { return this->outputPath; } - -std::string ConfigDataImp::getPrefix() { return this->prefix; } - -std::string ConfigDataImp::getGridPath() { return this->gridPath; } - -bool ConfigDataImp::getPrintOutputFiles() { return this->printOutputFiles; } - -bool ConfigDataImp::getGeometryValues() { return this->geometryValues; } - -bool ConfigDataImp::getCalc2ndOrderMoments() { return this->calc2ndOrderMoments; } - -bool ConfigDataImp::getCalc3rdOrderMoments() { return this->calc3rdOrderMoments; } - -bool ConfigDataImp::getCalcHighOrderMoments() { return this->calcHighOrderMoments; } - -bool ConfigDataImp::getReadGeo() { return this->readGeo; } - -bool ConfigDataImp::getCalcMedian() { return this->calcMedian; } - -bool ConfigDataImp::getCalcDragLift() { return this->calcDragLift; } - -bool ConfigDataImp::getCalcCp() { return this->calcCp; } - -bool ConfigDataImp::getWriteVeloASCIIfiles() { return this->writeVeloASCIIfiles; } - -bool ConfigDataImp::getCalcPlaneConc() { return this->calcPlaneConc; } - -bool ConfigDataImp::getConcFile() { return this->concFile; } - -bool ConfigDataImp::getStreetVelocityFile() { return this->streetVelocityFile; } - -bool ConfigDataImp::getUseMeasurePoints() { return this->useMeasurePoints; } - -bool ConfigDataImp::getUseWale() { return this->useWale; } - -bool ConfigDataImp::getUseInitNeq() { return this->useInitNeq; } - -bool ConfigDataImp::getSimulatePorousMedia() { return this->simulatePorousMedia; } - -uint ConfigDataImp::getD3Qxx() { return this->d3Qxx; } - -uint ConfigDataImp::getTEnd() { return this->tEnd; } - -uint ConfigDataImp::getTOut() { return this->tOut; } - -uint ConfigDataImp::getTStartOut() { return this->tStartOut; } - -uint ConfigDataImp::getTimeCalcMedStart() { return this->timeCalcMedStart; } - -uint ConfigDataImp::getTimeCalcMedEnd() { return this->timeCalcMedEnd; } - -uint ConfigDataImp::getPressInID() { return this->pressInID; } - -uint ConfigDataImp::getPressOutID() { return this->pressOutID; } - -uint ConfigDataImp::getPressInZ() { return this->pressInZ; } - -uint ConfigDataImp::getPressOutZ() { return this->pressOutZ; } - -bool ConfigDataImp::getDiffOn() { return this->diffOn; } - -uint ConfigDataImp::getDiffMod() { return this->diffMod; } - -real ConfigDataImp::getDiffusivity() { return this->diffusivity; } - -real ConfigDataImp::getTemperatureInit() { return this->temperatureInit; } - -real ConfigDataImp::getTemperatureBC() { return this->temperatureBC; } - -real ConfigDataImp::getVelocity() { return this->velocity; } - -real ConfigDataImp::getViscosityRatio() { return this->viscosityRatio; } - -real ConfigDataImp::getVelocityRatio() { return this->velocityRatio; } - -real ConfigDataImp::getDensityRatio() { return this->densityRatio; } - -real ConfigDataImp::getPressRatio() { return this->pressRatio; } - -real ConfigDataImp::getRealX() { return this->realX; } - -real ConfigDataImp::getRealY() { return this->realY; } - -real ConfigDataImp::getFactorPressBC() { return this->factorPressBC; } - -std::string ConfigDataImp::getGeometryFileC() { return this->geometryFileC; } - -std::string ConfigDataImp::getGeometryFileM() { return this->geometryFileM; } - -std::string ConfigDataImp::getGeometryFileF() { return this->geometryFileF; } - -uint ConfigDataImp::getClockCycleForMP() { return this->clockCycleForMP; } - -uint ConfigDataImp::getTimestepForMP() { return this->timestepForMP; } - -real ConfigDataImp::getForcingX() { return this->forcingX; } - -real ConfigDataImp::getForcingY() { return this->forcingY; } - -real ConfigDataImp::getForcingZ() { return this->forcingZ; } - -real ConfigDataImp::getQuadricLimiterP() { return this->quadricLimiterP; } - -real ConfigDataImp::getQuadricLimiterM() { return this->quadricLimiterM; } - -real ConfigDataImp::getQuadricLimiterD() { return this->quadricLimiterD; } - -bool ConfigDataImp::getCalcParticles() { return this->calcParticles; } - -int ConfigDataImp::getParticleBasicLevel() { return this->particleBasicLevel; } - -int ConfigDataImp::getParticleInitLevel() { return this->particleInitLevel; } - -int ConfigDataImp::getNumberOfParticles() { return this->numberOfParticles; } - -real ConfigDataImp::getStartXHotWall() { return this->startXHotWall; } - -real ConfigDataImp::getEndXHotWall() { return this->endXHotWall; } - -std::vector<std::string> ConfigDataImp::getPossNeighborFilesX() { return this->possNeighborFilesX; } - -std::vector<std::string> ConfigDataImp::getPossNeighborFilesY() { return this->possNeighborFilesY; } - -std::vector<std::string> ConfigDataImp::getPossNeighborFilesZ() { return this->possNeighborFilesZ; } - -int ConfigDataImp::getTimeDoCheckPoint() { return this->timeDoCheckPoint; } - -int ConfigDataImp::getTimeDoRestart() { return this->timeDoRestart; } - -bool ConfigDataImp::getDoCheckPoint() { return this->doCheckPoint; } - -bool ConfigDataImp::getDoRestart() { return this->doRestart; } - -uint ConfigDataImp::getMaxLevel() { return this->maxLevel; } - -std::vector<int> ConfigDataImp::getGridX() { return this->gridX; } - -std::vector<int> ConfigDataImp::getGridY() { return this->gridY; } - -std::vector<int> ConfigDataImp::getGridZ() { return this->gridZ; } - -std::vector<int> ConfigDataImp::getDistX() { return this->distX; } - -std::vector<int> ConfigDataImp::getDistY() { return this->distY; } - -std::vector<int> ConfigDataImp::getDistZ() { return this->distZ; } - -std::vector<bool> ConfigDataImp::getNeedInterface() { return this->needInterface; } - -std::string ConfigDataImp::getMainKernel() { return this->mainKernel; } - -bool ConfigDataImp::getMultiKernelOn() { return this->multiKernelOn; } - -std::vector<int> ConfigDataImp::getMultiKernelLevel() { return this->multiKernelLevel; } - -std::vector<std::string> ConfigDataImp::getMultiKernelName() { return this->multiKernelName; } - -void ConfigDataImp::setViscosity(real viscosity) -{ - this->viscosity = viscosity; - this->isViscosity = true; -} - -void ConfigDataImp::setNumberOfDevices(uint numberOfDevices) -{ - this->numberOfDevices = numberOfDevices; - this->isNumberOfDevices = true; -} - -void ConfigDataImp::setDevices(std::vector<uint> devices) -{ - this->devices = devices; - this->isDevices = true; -} - -void ConfigDataImp::setOutputPath(std::string outputPath) -{ - this->outputPath = outputPath; - this->isOutputPath = true; -} - -void ConfigDataImp::setPrefix(std::string prefix) -{ - this->prefix = prefix; - this->isPrefix = true; -} - -void ConfigDataImp::setGridPath(std::string gridPath) -{ - this->gridPath = gridPath; - this->isGridPath = true; -} - -void ConfigDataImp::setPrintOutputFiles(bool printOutputFiles) -{ - this->printOutputFiles = printOutputFiles; - this->isPrintOutputFiles = true; -} - -void ConfigDataImp::setGeometryValues(bool geometryValues) -{ - this->geometryValues = geometryValues; - this->isGeometryValues = true; -} - -void ConfigDataImp::setCalc2ndOrderMoments(bool calc2ndOrderMoments) -{ - this->calc2ndOrderMoments = calc2ndOrderMoments; - this->isCalc2ndOrderMoments = true; -} - -void ConfigDataImp::setCalc3rdOrderMoments(bool calc3rdOrderMoments) -{ - this->calc3rdOrderMoments = calc3rdOrderMoments; - this->isCalc3rdOrderMoments = true; -} - -void ConfigDataImp::setCalcHighOrderMoments(bool calcHighOrderMoments) -{ - this->calcHighOrderMoments = calcHighOrderMoments; - this->isCalcHighOrderMoments = true; -} - -void ConfigDataImp::setReadGeo(bool readGeo) -{ - this->readGeo = readGeo; - this->isReadGeo = true; -} - -void ConfigDataImp::setCalcMedian(bool calcMedian) -{ - this->calcMedian = calcMedian; - this->isCalcMedian = true; -} - -void ConfigDataImp::setCalcDragLift(bool calcDragLift) -{ - this->calcDragLift = calcDragLift; - this->isCalcDragLift = true; -} - -void ConfigDataImp::setCalcCp(bool calcCp) -{ - this->calcCp = calcCp; - this->isCalcCp = true; -} - -void ConfigDataImp::setWriteVeloASCIIfiles(bool writeVeloASCIIfiles) -{ - this->writeVeloASCIIfiles = writeVeloASCIIfiles; - this->isWriteVeloASCII = true; -} - -void ConfigDataImp::setCalcPlaneConc(bool calcPlaneConc) -{ - this->calcPlaneConc = calcPlaneConc; - this->isCalcPlaneConc = true; -} - -void ConfigDataImp::setConcFile(bool concFile) -{ - this->concFile = concFile; - this->isConcFile = true; -} - -void ConfigDataImp::setStreetVelocityFile(bool streetVelocityFile) -{ - this->streetVelocityFile = streetVelocityFile; - this->isStreetVelocityFile = true; -} - -void ConfigDataImp::setUseMeasurePoints(bool useMeasurePoints) -{ - this->useMeasurePoints = useMeasurePoints; - this->isUseMeasurePoints = true; -} - -void ConfigDataImp::setUseWale(bool useWale) -{ - this->useWale = useWale; - this->isUseWale = true; -} - -void ConfigDataImp::setUseInitNeq(bool useInitNeq) -{ - this->useInitNeq = useInitNeq; - this->isUseInitNeq = true; -} - -void ConfigDataImp::setSimulatePorousMedia(bool simulatePorousMedia) -{ - this->simulatePorousMedia = simulatePorousMedia; - this->isSimulatePorousMedia = true; -} - -void ConfigDataImp::setD3Qxx(uint d3Qxx) -{ - this->d3Qxx = d3Qxx; - this->isD3Qxx = true; -} - -void ConfigDataImp::setTEnd(uint tEnd) -{ - this->tEnd = tEnd; - this->isTEnd = true; -} - -void ConfigDataImp::setTOut(uint tOut) -{ - this->tOut = tOut; - this->isTOut = true; -} - -void ConfigDataImp::setTStartOut(uint tStartOut) -{ - this->tStartOut = tStartOut; - this->isTStartOut = true; -} - -void ConfigDataImp::setTimeCalcMedStart(uint timeCalcMedStart) -{ - this->timeCalcMedStart = timeCalcMedStart; - this->isTimeCalcMedStart = true; -} - -void ConfigDataImp::setTimeCalcMedEnd(uint timeCalcMedEnd) -{ - this->timeCalcMedEnd = timeCalcMedEnd; - this->isTimeCalcMedEnd = true; -} - -void ConfigDataImp::setPressInID(uint pressInID) -{ - this->pressInID = pressInID; - this->isPressInID = true; -} - -void ConfigDataImp::setPressOutID(uint pressOutID) -{ - this->pressOutID = pressOutID; - this->isPressOutID = true; -} - -void ConfigDataImp::setPressInZ(uint pressInZ) -{ - this->pressInZ = pressInZ; - this->isPressInZ = true; -} - -void ConfigDataImp::setPressOutZ(uint pressOutZ) -{ - this->pressOutZ = pressOutZ; - this->isPressOutZ = true; -} - -void ConfigDataImp::setDiffOn(bool diffOn) -{ - this->diffOn = diffOn; - this->isDiffOn = true; -} - -void ConfigDataImp::setDiffMod(uint diffMod) -{ - this->diffMod = diffMod; - this->isDiffMod = true; -} - -void ConfigDataImp::setDiffusivity(real diffusivity) -{ - this->diffusivity = diffusivity; - this->isDiffusivity = true; -} - -void ConfigDataImp::setTemperatureInit(real temperatureInit) -{ - this->temperatureInit = temperatureInit; - this->isTemperatureInit = true; -} - -void ConfigDataImp::setTemperatureBC(real temperatureBC) -{ - this->temperatureBC = temperatureBC; - this->isTemperatureBC = true; -} - -// void ConfigDataImp::setViscosity(real viscosity) -//{ -// this->viscosity = viscosity; -// this->isViscosity = true; -//} - -void ConfigDataImp::setVelocity(real velocity) -{ - this->velocity = velocity; - this->isVelocity = true; -} - -void ConfigDataImp::setViscosityRatio(real viscosityRatio) -{ - this->viscosityRatio = viscosityRatio; - this->isViscosityRatio = true; -} - -void ConfigDataImp::setVelocityRatio(real velocityRatio) -{ - this->velocityRatio = velocityRatio; - this->isVelocityRatio = true; -} - -void ConfigDataImp::setDensityRatio(real densityRatio) -{ - this->densityRatio = densityRatio; - this->isDensityRatio = true; -} - -void ConfigDataImp::setPressRatio(real pressRatio) -{ - this->pressRatio = pressRatio; - this->isPressRatio = true; -} - -void ConfigDataImp::setRealX(real realX) -{ - this->realX = realX; - this->isRealX = true; -} - -void ConfigDataImp::setRealY(real realY) -{ - this->realY = realY; - this->isRealY = true; -} - -void ConfigDataImp::setFactorPressBC(real factorPressBC) -{ - this->factorPressBC = factorPressBC; - this->isFactorPressBC = true; -} - -void ConfigDataImp::setGeometryFileC(std::string geometryFileC) -{ - this->geometryFileC = geometryFileC; - this->isGeometryFileC = true; -} - -void ConfigDataImp::setGeometryFileM(std::string geometryFileM) -{ - this->geometryFileM = geometryFileM; - this->isGeometryFileM = true; -} - -void ConfigDataImp::setGeometryFileF(std::string geometryFileF) -{ - this->geometryFileF = geometryFileF; - this->isGeometryFileF = true; -} - -void ConfigDataImp::setClockCycleForMP(uint clockCycleForMP) -{ - this->clockCycleForMP = clockCycleForMP; - this->isClockCycleForMP = true; -} - -void ConfigDataImp::setTimestepForMP(uint timestepForMP) -{ - this->timestepForMP = timestepForMP; - this->isTimestepForMP = true; -} - -void ConfigDataImp::setForcingX(real forcingX) -{ - this->forcingX = forcingX; - this->isForcingX = true; -} - -void ConfigDataImp::setForcingY(real forcingY) -{ - this->forcingY = forcingY; - this->isForcingY = true; -} - -void ConfigDataImp::setForcingZ(real forcingZ) -{ - this->forcingZ = forcingZ; - this->isForcingZ = true; -} - -void ConfigDataImp::setQuadricLimiterP(real quadricLimiterP) -{ - this->quadricLimiterP = quadricLimiterP; - this->isQuadricLimiterP = true; -} - -void ConfigDataImp::setQuadricLimiterM(real quadricLimiterM) -{ - this->quadricLimiterM = quadricLimiterM; - this->isQuadricLimiterM = true; -} - -void ConfigDataImp::setQuadricLimiterD(real quadricLimiterD) -{ - this->quadricLimiterD = quadricLimiterD; - this->isQuadricLimiterD = true; -} - -void ConfigDataImp::setCalcParticles(bool calcParticles) -{ - this->calcParticles = calcParticles; - this->isCalcParticles = true; -} - -void ConfigDataImp::setParticleBasicLevel(int particleBasicLevel) -{ - this->particleBasicLevel = particleBasicLevel; - this->isParticleBasicLevel = true; -} - -void ConfigDataImp::setParticleInitLevel(int particleInitLevel) -{ - this->particleInitLevel = particleInitLevel; - this->isParticleInitLevel = true; -} - -void ConfigDataImp::setNumberOfParticles(int numberOfParticles) -{ - this->numberOfParticles = numberOfParticles; - this->isNumberOfParticles = true; -} - -void ConfigDataImp::setStartXHotWall(real startXHotWall) -{ - this->startXHotWall = startXHotWall; - this->isStartXHotWall = true; -} - -void ConfigDataImp::setEndXHotWall(real endXHotWall) -{ - this->endXHotWall = endXHotWall; - this->isEndXHotWall = true; -} - -void ConfigDataImp::setPossNeighborFilesX(const std::vector<std::string> &possNeighborFilesX) -{ - this->possNeighborFilesX = possNeighborFilesX; - this->isPossNeighborFilesX = true; -} - -void ConfigDataImp::setPossNeighborFilesY(const std::vector<std::string> &possNeighborFilesY) -{ - this->possNeighborFilesY = possNeighborFilesY; - this->isPossNeighborFilesY = true; -} - -void ConfigDataImp::setPossNeighborFilesZ(const std::vector<std::string> &possNeighborFilesZ) -{ - this->possNeighborFilesZ = possNeighborFilesZ; - this->isPossNeighborFilesZ = true; -} - -void ConfigDataImp::setTimeDoCheckPoint(int timeDoCheckPoint) -{ - this->timeDoCheckPoint = timeDoCheckPoint; - this->isTimeDoCheckPoint = true; -} - -void ConfigDataImp::setTimeDoRestart(int timeDoRestart) -{ - this->timeDoRestart = timeDoRestart; - this->isTimeDoRestart = true; -} - -void ConfigDataImp::setDoCheckPoint(bool doCheckPoint) -{ - this->doCheckPoint = doCheckPoint; - this->isDoCheckPoint = true; -} - -void ConfigDataImp::setDoRestart(bool doRestart) -{ - this->doRestart = doRestart; - this->isDoRestart = true; -} - -void ConfigDataImp::setMaxLevel(uint maxLevel) -{ - this->maxLevel = maxLevel; - this->isMaxLevel = true; -} - -void ConfigDataImp::setGridX(const std::vector<int> &gridX) -{ - this->gridX = gridX; - this->isGridX = true; -} - -void ConfigDataImp::setGridY(const std::vector<int> &gridY) -{ - this->gridY = gridY; - this->isGridY = true; -} - -void ConfigDataImp::setGridZ(const std::vector<int> &gridZ) -{ - this->gridZ = gridZ; - this->isGridZ = true; -} - -void ConfigDataImp::setDistX(const std::vector<int> &distX) -{ - this->distX = distX; - this->isDistX = true; -} - -void ConfigDataImp::setDistY(const std::vector<int> &distY) -{ - this->distY = distY; - this->isDistY = true; -} - -void ConfigDataImp::setDistZ(const std::vector<int> &distZ) -{ - this->distZ = distZ; - this->isDistZ = true; -} - -void ConfigDataImp::setNeedInterface(const std::vector<bool> &needInterface) -{ - this->needInterface = needInterface; - this->isNeedInterface = true; -} - -void ConfigDataImp::setMainKernel(const std::string &mainKernel) -{ - this->mainKernel = mainKernel; - this->isMainKernel = true; -} - -void ConfigDataImp::setMultiKernelOn(bool multiKernelOn) -{ - this->multiKernelOn = multiKernelOn; - this->isMultiKernelOn = true; -} - -void ConfigDataImp::setMultiKernelLevel(const std::vector<int> &multiKernelLevel) -{ - this->multiKernelLevel = multiKernelLevel; - this->isMultiKernelLevel = true; -} - -void ConfigDataImp::setMultiKernelName(const std::vector<std::string> &multiKernelName) -{ - this->multiKernelName = multiKernelName; - this->isMultiKernelName = true; -} - -bool ConfigDataImp::isCalc2ndOrderMomentsInConfigFile() { return this->isCalc2ndOrderMoments; } - -bool ConfigDataImp::isCalc3rdOrderMomentsInConfigFile() { return this->isCalc2ndOrderMoments; } - -bool ConfigDataImp::isCalcHighOrderMomentsInConfigFile() { return this->isCalcHighOrderMoments; } - -bool ConfigDataImp::isReadGeoInConfigFile() { return this->isReadGeo; } - -bool ConfigDataImp::isCalcMedianInConfigFile() { return this->isCalcMedian; } - -bool ConfigDataImp::isCalcDragLiftInConfigFile() { return this->isCalcDragLift; } - -bool ConfigDataImp::isCalcCpInConfigFile() { return this->isCalcCp; } - -bool ConfigDataImp::isWriteVeloASCIIfilesInConfigFile() { return this->isWriteVeloASCII; } - -bool ConfigDataImp::isCalcPlaneConcInConfigFile() { return this->isCalcPlaneConc; } - -bool ConfigDataImp::isConcFileInConfigFile() { return this->isConcFile; } - -bool ConfigDataImp::isStreetVelocityFileInConfigFile() { return this->isStreetVelocityFile; } - -bool ConfigDataImp::isUseMeasurePointsInConfigFile() { return this->isUseMeasurePoints; } - -bool ConfigDataImp::isUseWaleInConfigFile() { return this->isUseWale; } - -bool ConfigDataImp::isUseInitNeqInConfigFile() { return this->isUseInitNeq; } - -bool ConfigDataImp::isSimulatePorousMediaInConfigFile() { return this->isSimulatePorousMedia; } - -bool ConfigDataImp::isD3QxxInConfigFile() { return this->isD3Qxx; } - -bool ConfigDataImp::isTEndInConfigFile() { return this->isTEnd; } - -bool ConfigDataImp::isTOutInConfigFile() { return this->isTOut; } - -bool ConfigDataImp::isTStartOutInConfigFile() { return this->isTStartOut; } - -bool ConfigDataImp::isTimeCalcMedStartInConfigFile() { return this->isTimeCalcMedStart; } - -bool ConfigDataImp::isTimeCalcMedEndInConfigFile() { return this->isTimeCalcMedEnd; } - -bool ConfigDataImp::isPressInIDInConfigFile() { return this->isPressInID; } - -bool ConfigDataImp::isPressOutIDInConfigFile() { return this->isPressOutID; } - -bool ConfigDataImp::isPressInZInConfigFile() { return this->isPressInZ; } - -bool ConfigDataImp::isPressOutZInConfigFile() { return this->isPressOutZ; } - -bool ConfigDataImp::isDiffOnInConfigFile() { return this->isDiffOn; } - -bool ConfigDataImp::isDiffModInConfigFile() { return this->isDiffMod; } - -bool ConfigDataImp::isDiffusivityInConfigFile() { return this->isDiffusivity; } - -bool ConfigDataImp::isTemperatureInitInConfigFile() { return this->isTemperatureInit; } - -bool ConfigDataImp::isTemperatureBCInConfigFile() { return this->isTemperatureBC; } - -bool ConfigDataImp::isViscosityInConfigFile() { return this->isViscosity; } - -bool ConfigDataImp::isNumberOfDevicesInConfigFile() { return this->isNumberOfDevices; } - -bool ConfigDataImp::isDevicesInConfigFile() { return this->isDevices; } - -bool ConfigDataImp::isOutputPathInConfigFile() { return this->isOutputPath; } - -bool ConfigDataImp::isPrefixInConfigFile() { return this->isPrefix; } - -bool ConfigDataImp::isGridPathInConfigFile() { return this->isGridPath; } - -bool ConfigDataImp::isPrintOutputFilesInConfigFile() { return this->isPrintOutputFiles; } - -bool ConfigDataImp::isGeometryValuesInConfigFile() { return this->isGeometryValues; } - -bool ConfigDataImp::isVelocityInConfigFile() { return this->isVelocity; } - -bool ConfigDataImp::isViscosityRatioInConfigFile() { return this->isViscosityRatio; } - -bool ConfigDataImp::isVelocityRatioInConfigFile() { return this->isVelocityRatio; } - -bool ConfigDataImp::isDensityRatioInConfigFile() { return this->isDensityRatio; } - -bool ConfigDataImp::isPressRatioInConfigFile() { return this->isPressRatio; } - -bool ConfigDataImp::isRealXInConfigFile() { return this->isRealX; } - -bool ConfigDataImp::isRealYInConfigFile() { return this->isRealY; } - -bool ConfigDataImp::isFactorPressBCInConfigFile() { return this->isFactorPressBC; } - -bool ConfigDataImp::isGeometryFileCInConfigFile() { return this->isGeometryFileC; } - -bool ConfigDataImp::isGeometryFileMInConfigFile() { return this->isGeometryFileM; } - -bool ConfigDataImp::isGeometryFileFInConfigFile() { return this->isGeometryFileF; } - -bool ConfigDataImp::isClockCycleForMPInConfigFile() { return this->isClockCycleForMP; } - -bool ConfigDataImp::isTimestepForMPInConfigFile() { return this->isTimestepForMP; } - -bool ConfigDataImp::isForcingXInConfigFile() { return this->isForcingX; } - -bool ConfigDataImp::isForcingYInConfigFile() { return this->isForcingY; } - -bool ConfigDataImp::isForcingZInConfigFile() { return this->isForcingZ; } - -bool ConfigDataImp::isQuadricLimiterPInConfigFile() { return this->isQuadricLimiterP; } - -bool ConfigDataImp::isQuadricLimiterMInConfigFile() { return this->isQuadricLimiterM; } - -bool ConfigDataImp::isQuadricLimiterDInConfigFile() { return this->isQuadricLimiterD; } - -bool ConfigDataImp::isCalcParticlesInConfigFile() { return this->isCalcParticles; } - -bool ConfigDataImp::isParticleBasicLevelInConfigFile() { return this->isParticleBasicLevel; } - -bool ConfigDataImp::isParticleInitLevelInConfigFile() { return this->isParticleInitLevel; } - -bool ConfigDataImp::isNumberOfParticlesInConfigFile() { return this->isNumberOfParticles; } - -bool ConfigDataImp::isNeighborWSBInConfigFile() { return this->isNeighborWSB; } - -bool ConfigDataImp::isStartXHotWallInConfigFile() { return this->isStartXHotWall; } - -bool ConfigDataImp::isEndXHotWallInConfigFile() { return this->isEndXHotWall; } - -bool ConfigDataImp::isPossNeighborFilesXInConfigFile() { return this->isPossNeighborFilesX; } - -bool ConfigDataImp::isPossNeighborFilesYInConfigFile() { return this->isPossNeighborFilesY; } - -bool ConfigDataImp::isPossNeighborFilesZInConfigFile() { return this->isPossNeighborFilesZ; } - -bool ConfigDataImp::isTimeDoCheckPointInConfigFile() { return this->isTimeDoCheckPoint; } - -bool ConfigDataImp::isTimeDoRestartInConfigFile() { return this->isTimeDoCheckPoint; } - -bool ConfigDataImp::isDoCheckPointInConfigFile() { return this->isDoCheckPoint; } - -bool ConfigDataImp::isDoRestartInConfigFile() { return this->isDoRestart; } - -bool ConfigDataImp::isMaxLevelInConfigFile() { return this->isMaxLevel; } - -bool ConfigDataImp::isGridXInConfigFile() { return this->isGridX; } - -bool ConfigDataImp::isGridYInConfigFile() { return this->isGridY; } - -bool ConfigDataImp::isGridZInConfigFile() { return this->isGridZ; } - -bool ConfigDataImp::isDistXInConfigFile() { return this->isDistX; } - -bool ConfigDataImp::isDistYInConfigFile() { return this->isDistY; } - -bool ConfigDataImp::isDistZInConfigFile() { return this->isDistZ; } - -bool ConfigDataImp::isNeedInterfaceInConfigFile() { return this->isNeedInterface; } - -bool ConfigDataImp::isMainKernelInConfigFile() { return this->isMainKernel; } - -bool ConfigDataImp::isMultiKernelOnInConfigFile() { return this->isMultiKernelOn; } - -bool ConfigDataImp::isMultiKernelLevelInConfigFile() { return this->isMultiKernelLevel; } - -bool ConfigDataImp::isMultiKernelNameInConfigFile() { return this->isMultiKernelName; } diff --git a/src/basics/Core/Input/ConfigData/ConfigDataImp.h b/src/basics/Core/Input/ConfigData/ConfigDataImp.h deleted file mode 100644 index 511ac4be166c7e43885209f144f0cdac6821c6f1..0000000000000000000000000000000000000000 --- a/src/basics/Core/Input/ConfigData/ConfigDataImp.h +++ /dev/null @@ -1,447 +0,0 @@ -#ifndef CONFIGDATAIMP_H -#define CONFIGDATAIMP_H - -#include "ConfigData.h" - -#include <memory> -#include <string> - -class ConfigDataImp : public ConfigData -{ -public: - static std::shared_ptr<ConfigDataImp> getNewInstance(); - - real getViscosity() override; - uint getNumberOfDevices() override; - std::vector<uint> getDevices() override; - std::string getOutputPath() override; - std::string getPrefix() override; - std::string getGridPath() override; - bool getPrintOutputFiles() override; - bool getGeometryValues() override; - bool getCalc2ndOrderMoments() override; - bool getCalc3rdOrderMoments() override; - bool getCalcHighOrderMoments() override; - bool getReadGeo() override; - bool getCalcMedian() override; - bool getCalcDragLift() override; - bool getCalcCp() override; - bool getWriteVeloASCIIfiles() override; - bool getCalcPlaneConc() override; - bool getConcFile() override; - bool getStreetVelocityFile() override; - bool getUseMeasurePoints() override; - bool getUseWale() override; - bool getUseInitNeq() override; - bool getSimulatePorousMedia() override; - uint getD3Qxx() override; - uint getTEnd() override; - uint getTOut() override; - uint getTStartOut() override; - uint getTimeCalcMedStart() override; - uint getTimeCalcMedEnd() override; - uint getPressInID() override; - uint getPressOutID() override; - uint getPressInZ() override; - uint getPressOutZ() override; - bool getDiffOn() override; - uint getDiffMod() override; - real getDiffusivity() override; - real getTemperatureInit() override; - real getTemperatureBC() override; - real getVelocity() override; - real getViscosityRatio() override; - real getVelocityRatio() override; - real getDensityRatio() override; - real getPressRatio() override; - real getRealX() override; - real getRealY() override; - real getFactorPressBC() override; - std::string getGeometryFileC() override; - std::string getGeometryFileM() override; - std::string getGeometryFileF() override; - uint getClockCycleForMP() override; - uint getTimestepForMP() override; - real getForcingX() override; - real getForcingY() override; - real getForcingZ() override; - real getQuadricLimiterP() override; - real getQuadricLimiterM() override; - real getQuadricLimiterD() override; - bool getCalcParticles() override; - int getParticleBasicLevel() override; - int getParticleInitLevel() override; - int getNumberOfParticles() override; - real getStartXHotWall() override; - real getEndXHotWall() override; - std::vector<std::string> getPossNeighborFilesX() override; - std::vector<std::string> getPossNeighborFilesY() override; - std::vector<std::string> getPossNeighborFilesZ() override; - // std::vector<std::string> getPossNeighborFilesX(); - // std::vector<std::string> getPossNeighborFilesY(); - // std::vector<std::string> getPossNeighborFilesZ(); - int getTimeDoCheckPoint() override; - int getTimeDoRestart() override; - bool getDoCheckPoint() override; - bool getDoRestart() override; - uint getMaxLevel() override; - std::vector<int> getGridX() override; - std::vector<int> getGridY() override; - std::vector<int> getGridZ() override; - std::vector<int> getDistX() override; - std::vector<int> getDistY() override; - std::vector<int> getDistZ() override; - std::vector<bool> getNeedInterface() override; - std::string getMainKernel() override; - bool getMultiKernelOn() override; - std::vector<int> getMultiKernelLevel() override; - std::vector<std::string> getMultiKernelName() override; - - void setViscosity(real viscosity); - void setNumberOfDevices(uint numberOfDevices); - void setDevices(std::vector<uint> devices); - void setOutputPath(std::string outputPath); - void setPrefix(std::string prefix); - void setGridPath(std::string gridPath); - void setPrintOutputFiles(bool printOutputFiles); - void setGeometryValues(bool geometryValues); - void setCalc2ndOrderMoments(bool calc2ndOrderMoments); - void setCalc3rdOrderMoments(bool calc3rdOrderMoments); - void setCalcHighOrderMoments(bool calcHighOrderMoment); - void setReadGeo(bool readGeo); - void setCalcMedian(bool calcMedian); - void setCalcDragLift(bool calcDragLift); - void setCalcCp(bool calcCp); - void setWriteVeloASCIIfiles(bool writeVeloASCIIfiles); - void setCalcPlaneConc(bool calcPlaneConc); - void setConcFile(bool concFile); - void setStreetVelocityFile(bool streetVelocityFile); - void setUseMeasurePoints(bool useMeasurePoints); - void setUseWale(bool useWale); - void setUseInitNeq(bool useInitNeq); - void setSimulatePorousMedia(bool simulatePorousMedia); - void setD3Qxx(uint d3Qxx); - void setTEnd(uint tEnd); - void setTOut(uint tOut); - void setTStartOut(uint tStartOut); - void setTimeCalcMedStart(uint timeCalcMedStart); - void setTimeCalcMedEnd(uint timeCalcMedEnd); - void setPressInID(uint pressInID); - void setPressOutID(uint pressOutID); - void setPressInZ(uint pressInZ); - void setPressOutZ(uint pressOutZ); - void setDiffOn(bool diffOn); - void setDiffMod(uint diffMod); - void setDiffusivity(real diffusivity); - void setTemperatureInit(real temperatureInit); - void setTemperatureBC(real temperatureBC); - // void setViscosity(real viscosity); - void setVelocity(real velocity); - void setViscosityRatio(real viscosityRatio); - void setVelocityRatio(real velocityRatio); - void setDensityRatio(real fensityRatio); - void setPressRatio(real pressRatio); - void setRealX(real realX); - void setRealY(real realY); - void setFactorPressBC(real factorPressBC); - void setGeometryFileC(std::string geometryFileC); - void setGeometryFileM(std::string geometryFileM); - void setGeometryFileF(std::string geometryFileF); - void setClockCycleForMP(uint clockCycleForMP); - void setTimestepForMP(uint timestepForMP); - void setForcingX(real forcingX); - void setForcingY(real forcingY); - void setForcingZ(real forcingZ); - void setQuadricLimiterP(real quadricLimiterP); - void setQuadricLimiterM(real quadricLimiterM); - void setQuadricLimiterD(real quadricLimiterD); - void setCalcParticles(bool calcParticles); - void setParticleBasicLevel(int particleBasicLevel); - void setParticleInitLevel(int particleInitLevel); - void setNumberOfParticles(int numberOfParticles); - void setStartXHotWall(real startXHotWall); - void setEndXHotWall(real endXHotWall); - void setPossNeighborFilesX(const std::vector<std::string> &possNeighborFilesX); - void setPossNeighborFilesY(const std::vector<std::string> &possNeighborFilesY); - void setPossNeighborFilesZ(const std::vector<std::string> &possNeighborFilesZ); - // void setPossNeighborFilesX(std::vector<std::string> possNeighborFilesX); - // void setPossNeighborFilesY(std::vector<std::string> possNeighborFilesY); - // void setPossNeighborFilesZ(std::vector<std::string> possNeighborFilesZ); - void setTimeDoCheckPoint(int timeDoCheckPoint); - void setTimeDoRestart(int timeDoRestart); - void setDoCheckPoint(bool doCheckPoint); - void setDoRestart(bool doRestart); - void setMaxLevel(uint maxLevel); - void setGridX(const std::vector<int> &gridX); - void setGridY(const std::vector<int> &gridY); - void setGridZ(const std::vector<int> &gridZ); - void setDistX(const std::vector<int> &distX); - void setDistY(const std::vector<int> &distY); - void setDistZ(const std::vector<int> &distZ); - void setNeedInterface(const std::vector<bool> &needInterface); - void setMainKernel(const std::string &mainKernel); - void setMultiKernelOn(bool multiKernelOn); - void setMultiKernelLevel(const std::vector<int> &multiKernelLevel); - void setMultiKernelName(const std::vector<std::string> &multiKernelName); - - bool isViscosityInConfigFile() override; - bool isNumberOfDevicesInConfigFile() override; - bool isDevicesInConfigFile() override; - bool isOutputPathInConfigFile() override; - bool isPrefixInConfigFile() override; - bool isGridPathInConfigFile() override; - bool isPrintOutputFilesInConfigFile() override; - bool isGeometryValuesInConfigFile() override; - bool isCalc2ndOrderMomentsInConfigFile() override; - bool isCalc3rdOrderMomentsInConfigFile() override; - bool isCalcHighOrderMomentsInConfigFile() override; - bool isReadGeoInConfigFile() override; - bool isCalcMedianInConfigFile() override; - bool isCalcDragLiftInConfigFile() override; - bool isCalcCpInConfigFile() override; - bool isWriteVeloASCIIfilesInConfigFile() override; - bool isCalcPlaneConcInConfigFile() override; - bool isConcFileInConfigFile() override; - bool isStreetVelocityFileInConfigFile() override; - bool isUseMeasurePointsInConfigFile() override; - bool isUseWaleInConfigFile() override; - bool isUseInitNeqInConfigFile() override; - bool isSimulatePorousMediaInConfigFile() override; - bool isD3QxxInConfigFile() override; - bool isTEndInConfigFile() override; - bool isTOutInConfigFile() override; - bool isTStartOutInConfigFile() override; - bool isTimeCalcMedStartInConfigFile() override; - bool isTimeCalcMedEndInConfigFile() override; - bool isPressInIDInConfigFile() override; - bool isPressOutIDInConfigFile() override; - bool isPressInZInConfigFile() override; - bool isPressOutZInConfigFile() override; - bool isDiffOnInConfigFile() override; - bool isDiffModInConfigFile() override; - bool isDiffusivityInConfigFile() override; - bool isTemperatureInitInConfigFile() override; - bool isTemperatureBCInConfigFile() override; - // bool isViscosityInConfigFile(); - bool isVelocityInConfigFile() override; - bool isViscosityRatioInConfigFile() override; - bool isVelocityRatioInConfigFile() override; - bool isDensityRatioInConfigFile() override; - bool isPressRatioInConfigFile() override; - bool isRealXInConfigFile() override; - bool isRealYInConfigFile() override; - bool isFactorPressBCInConfigFile() override; - bool isGeometryFileCInConfigFile() override; - bool isGeometryFileMInConfigFile() override; - bool isGeometryFileFInConfigFile() override; - bool isClockCycleForMPInConfigFile() override; - bool isTimestepForMPInConfigFile() override; - bool isForcingXInConfigFile() override; - bool isForcingYInConfigFile() override; - bool isForcingZInConfigFile() override; - bool isQuadricLimiterPInConfigFile() override; - bool isQuadricLimiterMInConfigFile() override; - bool isQuadricLimiterDInConfigFile() override; - bool isCalcParticlesInConfigFile() override; - bool isParticleBasicLevelInConfigFile() override; - bool isParticleInitLevelInConfigFile() override; - bool isNumberOfParticlesInConfigFile() override; - bool isNeighborWSBInConfigFile() override; - bool isStartXHotWallInConfigFile() override; - bool isEndXHotWallInConfigFile() override; - bool isPossNeighborFilesXInConfigFile() override; - bool isPossNeighborFilesYInConfigFile() override; - bool isPossNeighborFilesZInConfigFile() override; - bool isTimeDoCheckPointInConfigFile() override; - bool isTimeDoRestartInConfigFile() override; - bool isDoCheckPointInConfigFile() override; - bool isDoRestartInConfigFile() override; - bool isMaxLevelInConfigFile() override; - bool isGridXInConfigFile() override; - bool isGridYInConfigFile() override; - bool isGridZInConfigFile() override; - bool isDistXInConfigFile() override; - bool isDistYInConfigFile() override; - bool isDistZInConfigFile() override; - bool isNeedInterfaceInConfigFile() override; - bool isMainKernelInConfigFile() override; - bool isMultiKernelOnInConfigFile() override; - bool isMultiKernelLevelInConfigFile() override; - bool isMultiKernelNameInConfigFile() override; - -private: - ConfigDataImp() = default; - - real viscosity { 0. }; - uint numberOfDevices { 0 }; - std::vector<uint> devices; - std::string outputPath; - std::string prefix; - std::string gridPath; - bool printOutputFiles { false }; - bool geometryValues { false }; - bool calc2ndOrderMoments { false }; - bool calc3rdOrderMoments { false }; - bool calcHighOrderMoments { false }; - bool readGeo { false }; - bool calcMedian { false }; - bool calcDragLift { false }; - bool calcCp { false }; - bool writeVeloASCIIfiles { false }; - bool calcPlaneConc { false }; - bool concFile { false }; - bool streetVelocityFile { false }; - bool useMeasurePoints { false }; - bool useWale { false }; - bool useInitNeq { false }; - bool simulatePorousMedia { false }; - uint d3Qxx { 0 }; - uint tEnd { 0 }; - uint tOut { 0 }; - uint tStartOut { 0 }; - uint timeCalcMedStart { 0 }; - uint timeCalcMedEnd { 0 }; - uint pressInID { 0 }; - uint pressOutID { 0 }; - uint pressInZ { 0 }; - uint pressOutZ { 0 }; - bool diffOn { false }; - uint diffMod { 0 }; - real diffusivity { 0. }; - real temperatureInit { 0. }; - real temperatureBC { 0. }; - // real viscosity { 0 }; - real velocity { 0. }; - real viscosityRatio { 0. }; - real velocityRatio { 0. }; - real densityRatio { 0. }; - real pressRatio { 0. }; - real realX { 0. }; - real realY { 0. }; - real factorPressBC { 0. }; - std::string geometryFileC; - std::string geometryFileM; - std::string geometryFileF; - uint clockCycleForMP { 0 }; - uint timestepForMP { 0 }; - real forcingX { 0. }; - real forcingY { 0. }; - real forcingZ { 0. }; - real quadricLimiterP { 0. }; - real quadricLimiterM { 0. }; - real quadricLimiterD { 0. }; - bool calcParticles { false }; - int particleBasicLevel { 0 }; - int particleInitLevel { 0 }; - int numberOfParticles { 0 }; - real startXHotWall { 0. }; - real endXHotWall { 0. }; - std::vector<std::string> possNeighborFilesX; - std::vector<std::string> possNeighborFilesY; - std::vector<std::string> possNeighborFilesZ; - // std::vector<std::string> possNeighborFilesX; - // std::vector<std::string> possNeighborFilesY; - // std::vector<std::string> possNeighborFilesZ; - int timeDoCheckPoint { 0 }; - int timeDoRestart { 0 }; - bool doCheckPoint{ false }; - bool doRestart{ false }; - int maxLevel { 0 }; - std::vector<int> gridX; - std::vector<int> gridY; - std::vector<int> gridZ; - std::vector<int> distX; - std::vector<int> distY; - std::vector<int> distZ; - std::vector<bool> needInterface; - std::string mainKernel; - bool multiKernelOn{ false }; - std::vector<int> multiKernelLevel; - std::vector<std::string> multiKernelName; - - bool isViscosity { false }; - bool isNumberOfDevices {false}; - bool isDevices { false }; - bool isOutputPath { false }; - bool isPrefix { false }; - bool isGridPath { false }; - bool isPrintOutputFiles { false }; - bool isGeometryValues { false }; - bool isCalc2ndOrderMoments { false }; - bool isCalc3rdOrderMoments { false }; - bool isCalcHighOrderMoments { false }; - bool isReadGeo { false }; - bool isCalcMedian { false }; - bool isCalcDragLift { false }; - bool isCalcCp { false }; - bool isWriteVeloASCII { false }; - bool isCalcPlaneConc { false }; - bool isConcFile { false }; - bool isStreetVelocityFile { false }; - bool isUseMeasurePoints { false }; - bool isUseWale { false }; - bool isUseInitNeq { false }; - bool isSimulatePorousMedia { false }; - bool isD3Qxx { false }; - bool isTEnd { false }; - bool isTOut { false }; - bool isTStartOut { false }; - bool isTimeCalcMedStart { false }; - bool isTimeCalcMedEnd { false }; - bool isPressInID { false }; - bool isPressOutID { false }; - bool isPressInZ { false }; - bool isPressOutZ { false }; - bool isDiffOn { false }; - bool isDiffMod { false }; - bool isDiffusivity { false }; - bool isTemperatureInit { false }; - bool isTemperatureBC { false }; - // bool isViscosity { false }; - bool isVelocity { false }; - bool isViscosityRatio { false }; - bool isVelocityRatio { false }; - bool isDensityRatio { false }; - bool isPressRatio { false }; - bool isRealX { false }; - bool isRealY { false }; - bool isFactorPressBC { false }; - bool isGeometryFileC { false }; - bool isGeometryFileM { false }; - bool isGeometryFileF { false }; - bool isClockCycleForMP { false }; - bool isTimestepForMP { false }; - bool isForcingX { false }; - bool isForcingY { false }; - bool isForcingZ { false }; - bool isQuadricLimiterP { false }; - bool isQuadricLimiterM { false }; - bool isQuadricLimiterD { false }; - bool isCalcParticles { false }; - bool isParticleBasicLevel { false }; - bool isParticleInitLevel { false }; - bool isNumberOfParticles { false }; - bool isNeighborWSB { false }; - bool isStartXHotWall { false }; - bool isEndXHotWall { false }; - bool isPossNeighborFilesX { false }; - bool isPossNeighborFilesY { false }; - bool isPossNeighborFilesZ { false }; - bool isTimeDoCheckPoint { false }; - bool isTimeDoRestart { false }; - bool isDoCheckPoint { false }; - bool isDoRestart { false }; - bool isMaxLevel { false }; - bool isGridX { false }; - bool isGridY { false }; - bool isGridZ { false }; - bool isDistX { false }; - bool isDistY { false }; - bool isDistZ { false }; - bool isNeedInterface { false }; - bool isMainKernel { false }; - bool isMultiKernelOn { false }; - bool isMultiKernelLevel { false }; - bool isMultiKernelName { false }; -}; -#endif diff --git a/src/basics/Core/Input/ConfigFileReader/ConfigFileReader.cpp b/src/basics/Core/Input/ConfigFileReader/ConfigFileReader.cpp deleted file mode 100644 index 8fdb9fe1bc7f5dfe10dbfb522a87a4a3187dd60b..0000000000000000000000000000000000000000 --- a/src/basics/Core/Input/ConfigFileReader/ConfigFileReader.cpp +++ /dev/null @@ -1,262 +0,0 @@ -#include "ConfigFileReader.h" -#include "../../StringUtilities/StringUtil.h" -#include "../ConfigData/ConfigDataImp.h" -#include "../Input.h" - -#include <fstream> -#include <iostream> - -std::shared_ptr<ConfigFileReader> ConfigFileReader::getNewInstance() -{ - return std::shared_ptr<ConfigFileReader>(new ConfigFileReader()); -} - -std::shared_ptr<ConfigData> ConfigFileReader::readConfigFile(const char* filePath) const -{ - std::cout << filePath << std::endl; - std::shared_ptr<ConfigDataImp> data = ConfigDataImp::getNewInstance(); - std::ifstream stream; - stream.open(filePath, std::ios::in); - if (stream.fail()) - throw std::runtime_error("can not open config file!"); - std::unique_ptr<input::Input> input = input::Input::makeInput(stream, "config"); - - if (input->getValue("NumberOfDevices") != "") - data->setNumberOfDevices(StringUtil::toInt(input->getValue("NumberOfDevices"))); - - if (input->getValue("Devices") != "") - data->setDevices(StringUtil::toUintVector(input->getValue("Devices"))); - - if (input->getValue("Path") != "") - data->setOutputPath(input->getValue("Path")); - - if (input->getValue("Prefix") != "") - data->setPrefix(input->getValue("Prefix")); - - if (input->getValue("GridPath") != "") - data->setGridPath(input->getValue("GridPath")); - else { - std::cout << "GridPath has to be defined!" << std::endl; - exit(1); - } - - if (input->getValue("WriteGrid") != "") - data->setPrintOutputFiles(StringUtil::toBool(input->getValue("WriteGrid"))); - - if (input->getValue("GeometryValues") != "") - data->setGeometryValues(StringUtil::toBool(input->getValue("GeometryValues"))); - - if (input->getValue("calc2ndOrderMoments") != "") - data->setCalc2ndOrderMoments(StringUtil::toBool(input->getValue("calc2ndOrderMoments"))); - - if (input->getValue("calc3rdOrderMoments") != "") - data->setCalc3rdOrderMoments(StringUtil::toBool(input->getValue("calc3rdOrderMoments"))); - - if (input->getValue("calcHigherOrderMoments") != "") - data->setCalcHighOrderMoments(StringUtil::toBool(input->getValue("calcHigherOrderMoments"))); - - if (input->getValue("ReadGeometry") != "") - data->setReadGeo(StringUtil::toBool(input->getValue("ReadGeometry"))); - - if (input->getValue("calcMedian") != "") - data->setCalcMedian(StringUtil::toBool(input->getValue("calcMedian"))); - - if (input->getValue("UseConcFile") != "") - data->setConcFile(StringUtil::toBool(input->getValue("UseConcFile"))); - - if (input->getValue("UseStreetVelocityFile") != "") - data->setStreetVelocityFile(StringUtil::toBool(input->getValue("UseStreetVelocityFile"))); - - if (input->getValue("UseMeasurePoints") != "") - data->setUseMeasurePoints(StringUtil::toBool(input->getValue("UseMeasurePoints"))); - - if (input->getValue("UseWale") != "") - data->setUseWale(StringUtil::toBool(input->getValue("UseWale"))); - - if (input->getValue("UseInitNeq") != "") - data->setUseInitNeq(StringUtil::toBool(input->getValue("UseInitNeq"))); - - if (input->getValue("SimulatePorousMedia") != "") - data->setSimulatePorousMedia(StringUtil::toBool(input->getValue("SimulatePorousMedia"))); - - if (input->getValue("D3Qxx") != "") - data->setD3Qxx(StringUtil::toInt(input->getValue("D3Qxx"))); - - if (input->getValue("TimeEnd") != "") - data->setTEnd(StringUtil::toInt(input->getValue("TimeEnd"))); - - if (input->getValue("TimeOut") != "") - data->setTOut(StringUtil::toInt(input->getValue("TimeOut"))); - - if (input->getValue("TimeStartOut") != "") - data->setTStartOut(StringUtil::toInt(input->getValue("TimeStartOut"))); - - if (input->getValue("TimeStartCalcMedian") != "") - data->setTimeCalcMedStart(StringUtil::toInt(input->getValue("TimeStartCalcMedian"))); - - if (input->getValue("TimeEndCalcMedian") != "") - data->setTimeCalcMedEnd(StringUtil::toInt(input->getValue("TimeEndCalcMedian"))); - - if (input->getValue("PressInID") != "") - data->setPressInID(StringUtil::toInt(input->getValue("PressInID"))); - - if (input->getValue("PressOutID") != "") - data->setPressOutID(StringUtil::toInt(input->getValue("PressOutID"))); - - if (input->getValue("PressInZ") != "") - data->setPressInZ(StringUtil::toInt(input->getValue("PressInZ"))); - - if (input->getValue("PressOutZ") != "") - data->setPressOutZ(StringUtil::toInt(input->getValue("PressOutZ"))); - ////////////////////////////////////////////////////////////////////////// - if (input->getValue("DiffOn") != "") - data->setDiffOn(StringUtil::toBool(input->getValue("DiffOn"))); - - if (input->getValue("DiffMod") != "") - data->setDiffMod(StringUtil::toInt(input->getValue("DiffMod"))); - - if (input->getValue("Diffusivity") != "") - data->setDiffusivity(StringUtil::toFloat(input->getValue("Diffusivity"))); - - if (input->getValue("Temp") != "") - data->setTemperatureInit(StringUtil::toFloat(input->getValue("Temp"))); - - if (input->getValue("TempBC") != "") - data->setTemperatureBC(StringUtil::toFloat(input->getValue("TempBC"))); - ////////////////////////////////////////////////////////////////////////// - if (input->getValue("Viscosity_LB") != "") - data->setViscosity(StringUtil::toFloat(input->getValue("Viscosity_LB"))); - - if (input->getValue("Velocity_LB") != "") - data->setVelocity(StringUtil::toFloat(input->getValue("Velocity_LB"))); - - if (input->getValue("Viscosity_Ratio_World_to_LB") != "") - data->setViscosityRatio(StringUtil::toFloat(input->getValue("Viscosity_Ratio_World_to_LB"))); - - if (input->getValue("Velocity_Ratio_World_to_LB") != "") - data->setVelocityRatio(StringUtil::toFloat(input->getValue("Velocity_Ratio_World_to_LB"))); - - if (input->getValue("Density_Ratio_World_to_LB") != "") - data->setDensityRatio(StringUtil::toFloat(input->getValue("Density_Ratio_World_to_LB"))); - - if (input->getValue("Delta_Press") != "") - data->setPressRatio(StringUtil::toFloat(input->getValue("Delta_Press"))); - - if (input->getValue("SliceRealX") != "") - data->setRealX(StringUtil::toFloat(input->getValue("SliceRealX"))); - - if (input->getValue("SliceRealY") != "") - data->setRealY(StringUtil::toFloat(input->getValue("SliceRealY"))); - - if (input->getValue("FactorPressBC") != "") - data->setFactorPressBC(StringUtil::toFloat(input->getValue("FactorPressBC"))); - - if (input->getValue("GeometryC") != "") - data->setGeometryFileC(input->getValue("GeometryC")); - - if (input->getValue("GeometryM") != "") - data->setGeometryFileM(input->getValue("GeometryM")); - - if (input->getValue("GeometryF") != "") - data->setGeometryFileF(input->getValue("GeometryF")); - ////////////////////////////////////////////////////////////////////////// - if (input->getValue("measureClockCycle") != "") - data->setClockCycleForMP(StringUtil::toInt(input->getValue("measureClockCycle"))); - - if (input->getValue("measureTimestep") != "") - data->setTimestepForMP(StringUtil::toInt(input->getValue("measureTimestep"))); - ////////////////////////////////////////////////////////////////////////// - // Forcing - if (input->getValue("ForcingX") != "") - data->setForcingX(StringUtil::toFloat(input->getValue("ForcingX"))); - if (input->getValue("ForcingY") != "") - data->setForcingY(StringUtil::toFloat(input->getValue("ForcingY"))); - if (input->getValue("ForcingZ") != "") - data->setForcingZ(StringUtil::toFloat(input->getValue("ForcingZ"))); - ////////////////////////////////////////////////////////////////////////// - // Quadric Limiters - if (input->getValue("QuadricLimiterP") != "") - data->setQuadricLimiterP(StringUtil::toFloat(input->getValue("QuadricLimiterP"))); - if (input->getValue("QuadricLimiterM") != "") - data->setQuadricLimiterM(StringUtil::toFloat(input->getValue("QuadricLimiterM"))); - if (input->getValue("QuadricLimiterD") != "") - data->setQuadricLimiterD(StringUtil::toFloat(input->getValue("QuadricLimiterD"))); - ////////////////////////////////////////////////////////////////////////// - // Particles - if (input->getValue("calcParticles") != "") - data->setCalcParticles(StringUtil::toBool(input->getValue("calcParticles"))); - - if (input->getValue("baseLevel") != "") - data->setParticleBasicLevel(StringUtil::toInt(input->getValue("baseLevel"))); - - if (input->getValue("initLevel") != "") - data->setParticleInitLevel(StringUtil::toInt(input->getValue("initLevel"))); - - if (input->getValue("numberOfParticles") != "") - data->setNumberOfParticles(StringUtil::toInt(input->getValue("numberOfParticles"))); - - if (input->getValue("startXHotWall") != "") - data->setStartXHotWall(real(StringUtil::toDouble(input->getValue("startXHotWall")))); - - if (input->getValue("endXHotWall") != "") - data->setEndXHotWall(real(StringUtil::toDouble(input->getValue("endXHotWall")))); - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Restart - if (input->getValue("TimeDoCheckPoint") != "") - data->setTimeDoCheckPoint(StringUtil::toInt(input->getValue("TimeDoCheckPoint"))); - - if (input->getValue("TimeDoRestart") != "") - data->setTimeDoRestart(StringUtil::toInt(input->getValue("TimeDoRestart"))); - - if (input->getValue("DoCheckPoint") != "") - data->setDoCheckPoint(StringUtil::toBool(input->getValue("DoCheckPoint"))); - - if (input->getValue("DoRestart") != "") - data->setDoRestart(StringUtil::toBool(input->getValue("DoRestart"))); - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - if (input->getValue("NOGL") != "") - data->setMaxLevel(StringUtil::toInt(input->getValue("NOGL"))); - - if (input->getValue("GridX") != "") - data->setGridX(StringUtil::toIntVector(input->getValue("GridX"))); - - if (input->getValue("GridY") != "") - data->setGridY(StringUtil::toIntVector(input->getValue("GridY"))); - - if (input->getValue("GridZ") != "") - data->setGridZ(StringUtil::toIntVector(input->getValue("GridZ"))); - - if (input->getValue("DistX") != "") - data->setDistX(StringUtil::toIntVector(input->getValue("DistX"))); - - if (input->getValue("DistY") != "") - data->setDistY(StringUtil::toIntVector(input->getValue("DistY"))); - - if (input->getValue("DistZ") != "") - data->setDistZ(StringUtil::toIntVector(input->getValue("DistZ"))); - - if (input->getValue("NeedInterface") != "") - data->setNeedInterface(StringUtil::toBoolVector(input->getValue("NeedInterface"))); - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Kernel - if (input->getValue("MainKernelName") != "") - data->setMainKernel(input->getValue("MainKernelName")); - - if (input->getValue("MultiKernelOn") != "") - data->setMultiKernelOn(StringUtil::toBool(input->getValue("MultiKernelOn"))); - - if (input->getValue("MultiKernelLevel") != "") - data->setMultiKernelLevel(StringUtil::toIntVector(input->getValue("MultiKernelLevel"))); - - if (input->getValue("MultiKernelName") != "") - data->setMultiKernelName(StringUtil::toStringVector(input->getValue("MultiKernelName"))); - - if (StringUtil::toStringVector(input->getValue("MultiKernelName")).size() != - StringUtil::toIntVector(input->getValue("MultiKernelLevel")).size()) { - std::cout << "MultiKernelName and MultiKernelLevel has to be of same size!" << std::endl; - exit(1); - } - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - return data; -} diff --git a/src/basics/Core/Input/ConfigFileReader/ConfigFileReader.h b/src/basics/Core/Input/ConfigFileReader/ConfigFileReader.h deleted file mode 100644 index 77c93ebfa4ba8564188d8e4a5442963382cf91e3..0000000000000000000000000000000000000000 --- a/src/basics/Core/Input/ConfigFileReader/ConfigFileReader.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef CONFIGFILEREADER_H -#define CONFIGFILEREADER_H - - -#include <memory> -#include <string> - -#include "basics_export.h" - -class ConfigData; - -class ConfigFileReader -{ -public: - BASICS_EXPORT static std::shared_ptr<ConfigFileReader> getNewInstance(); - - BASICS_EXPORT std::shared_ptr<ConfigData> readConfigFile(const char* filePath) const; - -private: - ConfigFileReader() = default; -}; -#endif diff --git a/src/basics/Core/Input/ConfigInput/ConfigInput.cpp b/src/basics/Core/Input/ConfigInput/ConfigInput.cpp deleted file mode 100644 index 1fdff1e8794b5cb58f6b1a8a2e97a536531df829..0000000000000000000000000000000000000000 --- a/src/basics/Core/Input/ConfigInput/ConfigInput.cpp +++ /dev/null @@ -1,222 +0,0 @@ -#include "ConfigInput.h" -#include <algorithm> -#include <cerrno> -#include <iostream> -#include <sstream> -#include <string> - -#define COMMENT '#' - -namespace input -{ -// Trim the given characters from the beginning and end of a string. -// the default is to trim whitespace. If the string is empty or contains -// only the trim characters, an empty string is returned. -std::string trim(const std::string &instring, const std::string &trimstring = std::string(" \t\n")) -{ - if (trimstring.size() == 0) - return instring; - std::string temp = ""; - std::string::size_type begpos = instring.find_first_not_of(trimstring); - if (begpos == std::string::npos) { - return temp; - } else { - std::string::size_type endpos = instring.find_last_not_of(trimstring); - temp = instring.substr(begpos, endpos - begpos + 1); - } - return temp; -} - -ConfigInput::ConfigInput(std::istream &stream) : stream(stream) -{ - while (!stream.eof()) - this->setTokenValuePair(); -} - -ConfigInput::~ConfigInput() = default; - -bool ConfigInput::hasValue(const std::string &key) const -{ - bool valueFound = false; - std::string keyCopy = key; - this->makeLower(keyCopy); - if (configEntries.find(keyCopy.c_str()) != configEntries.end()) - valueFound = true; - - return valueFound; -} - -std::string ConfigInput::getValue(const std::string &key) -{ - std::string keyCopy = key; - this->makeLower(keyCopy); - if (configEntries.find(keyCopy.c_str()) != configEntries.end()) - return (*configEntries.find(keyCopy.c_str())).second; - return ""; -} - -////////////////////////////////////////////////////////////////////////// -// private methods // -////////////////////////////////////////////////////////////////////////// - -void ConfigInput::makeLower(std::string &value) const -{ - for (size_t i = 0; i < value.size(); i++) - value[i] = tolower(value[i]); -} - -void ConfigInput::setTokenValuePair() -{ - this->eatWhiteAndComments(true); - - std::string token; - if (!this->setToken(token)) - return; - - std::string value; - this->setValue(value); - - configEntries.insert(String_Pair(token, value)); -} - -bool ConfigInput::setToken(std::string &token) -{ - char tokenChar[1024]; - bool foundEqualSign = false; - int charIndex = 0; - - this->findToken(foundEqualSign, tokenChar, charIndex); - - if (!isToken(charIndex, foundEqualSign)) - return false; - - this->nullTerminate(tokenChar, charIndex); - token = tokenChar; - makeLower(token); - return true; -} - -void ConfigInput::findToken(bool &foundEqualSign, char *token, int &i) -{ - char ch; - while (!(stream.get(ch)).fail()) { - if ((ch != '\t')) { - if ((ch == '=') || (ch == ' ') || (ch == '\n') || (ch == '\r') || (ch == '\t')) { - foundEqualSign = true; - break; - } - token[i++] = ch; - } - } -} - -bool ConfigInput::isToken(int charIndex, bool foundEqualSign) -{ - if (charIndex == 0) { - configEntries.insert(String_Pair("", "")); - return false; - } - - if (!foundEqualSign && !advanceToEqualSignOnLine()) { - configEntries.insert(String_Pair("", "")); - return false; - } - return true; -} - -void ConfigInput::setValue(std::string &value) -{ - int charIndex = 0; - char valueChar[1024]; - this->findValue(charIndex, valueChar); - - if (charIndex == 0) - value = ""; - else { - this->nullTerminate(valueChar, charIndex); - value = valueChar; - value = trim(value); - this->stripLeadingAndTrailingQuotes(value); - } -} - -int ConfigInput::findValue(int &charIndex, char *value) -{ - char ch; - char c = eatWhiteAndComments(false); - if (c != '\n') { - charIndex = 0; - while (!(stream.get(ch)).fail()) { - if ((ch == '\t') || (ch == '\r') || (ch == '\n') || (ch == '#')) { - while (ch != '\n') { - if (stream.get(ch).fail()) - break; - } - break; - } else { - value[charIndex++] = ch; - } - } - } - return charIndex; -} - -void ConfigInput::stripLeadingAndTrailingQuotes(std::string &m_value) -{ - if (m_value[0] == '"') - m_value = m_value.substr(1); - if (m_value[m_value.length() - 1] == '"') - m_value = m_value.substr(0, m_value.length() - 1); -} - -void ConfigInput::nullTerminate(char *value, int &i) { value[i++] = '\0'; } - -bool ConfigInput::advanceToEqualSignOnLine() -{ - char ch; - bool foundEqual = false; - while (!(stream.get(ch)).fail()) { - if (isNewLine(ch) || isCarriageReturn(ch)) - break; - if (isEqualSign(ch)) { - foundEqual = true; - break; - } - } - return foundEqual; -} - -char ConfigInput::eatWhiteAndComments(bool traverseNewlines) -{ - char ch; - bool isComment = false; - - while (!(stream.get(ch)).fail()) { - if (isCommentSign(ch)) - isComment = true; - else if (isNewLine(ch)) { - isComment = false; - if (!traverseNewlines) - return (ch); - } else if (isRegularChar(isComment, ch)) { - stream.putback(ch); - return 0; - } - } - return 0; -} - -bool ConfigInput::isRegularChar(bool isComment, char ch) -{ - return (!isComment) && (ch != ' ') && (ch != '\t') && (ch != '\r'); -} - -bool ConfigInput::isCommentSign(char ch) { return ch == COMMENT; } - -bool ConfigInput::isEqualSign(char ch) { return ch == '='; } - -bool ConfigInput::isNewLine(char ch) { return ch == '\n'; } - -bool ConfigInput::isCarriageReturn(char ch) { return ch == '\r'; } - -} // namespace input diff --git a/src/basics/Core/Input/ConfigInput/ConfigInput.h b/src/basics/Core/Input/ConfigInput/ConfigInput.h deleted file mode 100644 index aee9242ca7cb63ac259fe27869c0d4f9d5036b05..0000000000000000000000000000000000000000 --- a/src/basics/Core/Input/ConfigInput/ConfigInput.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef ConfigInput_H -#define ConfigInput_H -#include <istream> -#include <list> -#include <map> -#include <memory> -#include <string> -#include <vector> - -#include "../Input.h" -#include "basics_export.h" - -namespace input -{ -class ConfigInput : public Input -{ -public: - BASICS_EXPORT ConfigInput(std::istream &stream); - BASICS_EXPORT ~ConfigInput() override; - - BASICS_EXPORT bool hasValue(const std::string &key) const override; - BASICS_EXPORT std::string getValue(const std::string &key) override; - -protected: - virtual void setTokenValuePair(); - void setValue(std::string &value); - bool setToken(std::string &token); - bool isToken(int charIndex, bool foundEqualSign); - int findValue(int &charIndex, char *value); - void stripLeadingAndTrailingQuotes(std::string &m_value); - void nullTerminate(char *token, int &i); - void findToken(bool &foundEqualSign, char *token, int &i); - char eatWhiteAndComments(bool traverse_newlines = true); - bool isRegularChar(bool isComment, char ch); - bool isNewLine(char ch); - bool isCommentSign(char ch); - bool advanceToEqualSignOnLine(); - bool isCarriageReturn(char ch); - bool isEqualSign(char ch); - void makeLower(std::string &instring) const; - -protected: - std::istream &stream; - using String_Pair = std::pair<std::string, std::string>; - std::map<std::string, std::string> configEntries; -}; -} // namespace input -#endif diff --git a/src/basics/Core/Input/Input.cpp b/src/basics/Core/Input/Input.cpp deleted file mode 100644 index f971dd2260d97c28c6e84f60d9b0415eb971ea16..0000000000000000000000000000000000000000 --- a/src/basics/Core/Input/Input.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "Input.h" - -#include <memory> - -#ifdef BUILD_JSONCPP -#include "JsonInput/JsonInput.h" -#endif - -#include "ConfigInput/ConfigInput.h" - -namespace input -{ - -std::unique_ptr<input::Input> Input::makeInput(std::istream &stream, const std::string & /*inputType*/) -{ -#ifdef BUILD_JSONCPP - if (inputType == "json") - return std::unique_ptr<Input>(new JsonInput(stream)); -#endif - - return std::make_unique<ConfigInput>(stream); -} - -} // namespace input diff --git a/src/basics/Core/Input/Input.h b/src/basics/Core/Input/Input.h deleted file mode 100644 index 3b07b8b32d99293c3216e1a14dc9df9fc9688bea..0000000000000000000000000000000000000000 --- a/src/basics/Core/Input/Input.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef Input_H -#define Input_H - -#include "basics_export.h" - -#include <istream> -#include <memory> -#include <string> - -namespace input -{ -class Input -{ -public: - static BASICS_EXPORT std::unique_ptr<Input> makeInput(std::istream &stream, const std::string &inputType); - - virtual ~Input() = default; - - virtual bool hasValue(const std::string &key) const = 0; - virtual std::string getValue(const std::string &key) = 0; -}; -} // namespace input - -#endif diff --git a/src/basics/Core/Input/JsonInput/JsonInput.cpp b/src/basics/Core/Input/JsonInput/JsonInput.cpp deleted file mode 100644 index 34a1d154a386d267c4d086e28b5f7e5f64c302cc..0000000000000000000000000000000000000000 --- a/src/basics/Core/Input/JsonInput/JsonInput.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#ifdef BUILD_JSONCPP - -#include "JsonInput.h" - -#include <fstream> -#include <iterator> -#include <sstream> -#include <string> -#include <vector> - -namespace input -{ -template <typename Out> -void split(const std::string &s, char delim, Out result) -{ - std::stringstream ss; - ss.str(s); - std::string item; - while (std::getline(ss, item, delim)) { - *(result++) = item; - } -} - -std::vector<std::string> split(const std::string &s, char delim) -{ - std::vector<std::string> elems; - split(s, delim, std::back_inserter(elems)); - return elems; -} - -JsonInput::JsonInput(std::istream &stream) -{ - Json::Reader reader; - reader.parse(stream, jsonValue); -} - -bool JsonInput::hasValue(const std::string &key) const -{ - auto keys = split(key, ' '); - - if (keys.size() == 1 && !jsonValue[keys[0]].isNull()) - return true; - else if (keys.size() == 2 && !jsonValue[keys[0]][keys[1]].isNull()) - return true; - else if (keys.size() == 3 && !jsonValue[keys[0]][keys[1]][keys[2]].isNull()) - return true; - else - return false; -} - -std::string JsonInput::getValue(const std::string &key) -{ - auto keys = split(key, ' '); - - if (keys.size() == 1) - return jsonValue[keys[0]].asString(); - else if (keys.size() == 2) - return jsonValue[keys[0]][keys[1]].asString(); - else if (keys.size() == 3) - return jsonValue[keys[0]][keys[1]][keys[2]].asString(); - else - return ""; -} - -} // namespace input - -#endif diff --git a/src/basics/Core/Input/JsonInput/JsonInput.h b/src/basics/Core/Input/JsonInput/JsonInput.h deleted file mode 100644 index 8a33e99bfe2904caff82349caaf2579049892b15..0000000000000000000000000000000000000000 --- a/src/basics/Core/Input/JsonInput/JsonInput.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifdef BUILD_JSONCPP - -#ifndef JsonInput_H -#define JsonInput_H - -#include <json/json.h> -#include <string> - -#include "basics_export.h" - -#include "../Input.h" - -namespace input -{ -class JsonInput : public Input -{ -public: - BASICS_EXPORT JsonInput(std::istream &stream); - - BASICS_EXPORT virtual bool hasValue(const std::string &key) const override; - BASICS_EXPORT virtual std::string getValue(const std::string &key) override; - -private: - Json::Value jsonValue; -}; -} // namespace input - -#endif - -#endif diff --git a/src/basics/Core/Logger/Logger.cpp b/src/basics/Core/Logger/Logger.cpp index 6ee96cba58ad6a4c95e25792963027b2e53a4df7..1a27ef6f2a33bf46b9f488a4cf8d17705c2a64e6 100644 --- a/src/basics/Core/Logger/Logger.cpp +++ b/src/basics/Core/Logger/Logger.cpp @@ -1,5 +1,36 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file Logger.cpp +//! \ingroup Logger +//! \author Stephan Lenz +//======================================================================================= #include "Logger.h" -//#include "mpi.h" #include <iostream> #include <memory> diff --git a/src/basics/Core/Logger/Logger.h b/src/basics/Core/Logger/Logger.h index d0cd91938868283ec7d13faa7439cf22d7c00729..53cb974b8e409a8ba6eb555abac41ca99eb2bbcf 100644 --- a/src/basics/Core/Logger/Logger.h +++ b/src/basics/Core/Logger/Logger.h @@ -1,3 +1,35 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file Logger.h +//! \ingroup Logger +//! \author Stephan Lenz +//======================================================================================= #ifndef Logger_H #define Logger_H diff --git a/src/basics/Core/Logger/implementations/LoggerImp.cpp b/src/basics/Core/Logger/implementations/LoggerImp.cpp index f002fdc59ee0a92bdc1be79a74aa347f0451600d..086c0e3aa5153f017905cd8476248ea7a7434335 100644 --- a/src/basics/Core/Logger/implementations/LoggerImp.cpp +++ b/src/basics/Core/Logger/implementations/LoggerImp.cpp @@ -1,3 +1,35 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file LoggerImp.cpp +//! \ingroup Logger +//! \author Stephan Lenz +//======================================================================================= #include "LoggerImp.h" #include <chrono> diff --git a/src/basics/Core/Logger/implementations/LoggerImp.h b/src/basics/Core/Logger/implementations/LoggerImp.h index 45b64b6dc2208991ca3c1ac67ad80af0b2ea6f22..070b06a23ee59a1d387f09fc86960dd3083c4e61 100644 --- a/src/basics/Core/Logger/implementations/LoggerImp.h +++ b/src/basics/Core/Logger/implementations/LoggerImp.h @@ -1,3 +1,35 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file LoggerImp.h +//! \ingroup Logger +//! \author Stephan Lenz +//======================================================================================= #ifndef LoggerImp_H #define LoggerImp_H diff --git a/src/basics/Core/NonCreatable.h b/src/basics/Core/NonCreatable.h index b25fc808bf0607a047b46643b412b23fb71037b0..c581a19ec92b666f45109f1e3c66b9e57fb54614 100644 --- a/src/basics/Core/NonCreatable.h +++ b/src/basics/Core/NonCreatable.h @@ -1,7 +1,35 @@ -/* - * Author: S. Peters - * mail: peters@irmb.tu-bs.de - */ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file NonCreatable.h +//! \ingroup Core +//! \author Soeren Peters +//======================================================================================= #ifndef NON_CREATABLE_H #define NON_CREATABLE_H diff --git a/src/basics/Core/RealConstants.h b/src/basics/Core/RealConstants.h index d353a341c9f75d58d11ede3048f3cb0521be40b3..697d628986bb417ab124c465526d0538b2734438 100644 --- a/src/basics/Core/RealConstants.h +++ b/src/basics/Core/RealConstants.h @@ -1,3 +1,35 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file RealConstants.h +//! \ingroup Core +//! \author Martin Schoenherr +//======================================================================================= #ifndef REAL_CONSTANT_H #define REAL_CONSTANT_H diff --git a/src/basics/Core/StringUtilities/StringUtil.cpp b/src/basics/Core/StringUtilities/StringUtil.cpp index 327a62346a91073834c8b710e90968a524ee2d28..d8bcae7a513d498418c62d2f39a8b7bdd450468d 100644 --- a/src/basics/Core/StringUtilities/StringUtil.cpp +++ b/src/basics/Core/StringUtilities/StringUtil.cpp @@ -1,3 +1,35 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file StringUtil.cpp +//! \ingroup StringUtilities +//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller +//======================================================================================= #include "StringUtil.h" #include <string.h> diff --git a/src/basics/Core/StringUtilities/StringUtil.h b/src/basics/Core/StringUtilities/StringUtil.h index 1927a69bc60bf2467fb09893463b3c9363191890..b1b777ad2a512ec78061f019df6e043bfb1cf37b 100644 --- a/src/basics/Core/StringUtilities/StringUtil.h +++ b/src/basics/Core/StringUtilities/StringUtil.h @@ -1,3 +1,35 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file StringUtil.h +//! \ingroup StringUtilities +//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller +//======================================================================================= #ifndef STRINGUTIL_H #define STRINGUTIL_H diff --git a/src/basics/Core/Timer/Timer.cpp b/src/basics/Core/Timer/Timer.cpp index 9ca58ed190a5ff68d9f57e8d27fda73f94958ef8..c8856f72adffe0c407ff29ee74246638ce5c8280 100644 --- a/src/basics/Core/Timer/Timer.cpp +++ b/src/basics/Core/Timer/Timer.cpp @@ -1,3 +1,35 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file Timer.cpp +//! \ingroup Timer +//! \author Stephan Lenz +//======================================================================================= #include "Timer.h" #include "TimerImp.h" diff --git a/src/basics/Core/Timer/Timer.h b/src/basics/Core/Timer/Timer.h index e8a97000fb8cc3967490e60edca1c564cc8431c7..6de04b2f3d5573ac6266bd2c35cf18cd232384dd 100644 --- a/src/basics/Core/Timer/Timer.h +++ b/src/basics/Core/Timer/Timer.h @@ -1,3 +1,35 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file Timer.h +//! \ingroup Timer +//! \author Stephan Lenz +//======================================================================================= #ifndef TIMER_H #define TIMER_H diff --git a/src/basics/Core/Timer/TimerImp.cpp b/src/basics/Core/Timer/TimerImp.cpp index 7aef3e999c0d5466fb69b08eafa32fa95370383b..76f9ac36793f2e2543abe9086f2780ee94b50eb7 100644 --- a/src/basics/Core/Timer/TimerImp.cpp +++ b/src/basics/Core/Timer/TimerImp.cpp @@ -1,3 +1,35 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file TimerImp.cpp +//! \ingroup Timer +//! \author Stephan Lenz +//======================================================================================= #include "TimerImp.h" void TimerImp::start() { this->startTime = std::chrono::high_resolution_clock::now(); } diff --git a/src/basics/Core/Timer/TimerImp.h b/src/basics/Core/Timer/TimerImp.h index bcc078db9a4f00eb23abe93a9a1e16509c948820..e180ae084cb19b939f6e7a82cae7a0db3cc1ea15 100644 --- a/src/basics/Core/Timer/TimerImp.h +++ b/src/basics/Core/Timer/TimerImp.h @@ -1,3 +1,35 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file TimerImp.h +//! \ingroup Timer +//! \author Stephan Lenz +//======================================================================================= #ifndef TIMER_IMP_H #define TIMER_IMP_H diff --git a/src/basics/Core/VectorTypes.cpp b/src/basics/Core/VectorTypes.cpp index dab2675093415ec103d1bf7ffd3666d57b0977f5..ecc986be836cb3c85d760f4db408707bfb1180b4 100644 --- a/src/basics/Core/VectorTypes.cpp +++ b/src/basics/Core/VectorTypes.cpp @@ -1,3 +1,35 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file VectorTypes.cpp +//! \ingroup Core +//! \author Soeren Peters +//======================================================================================= #include "VectorTypes.h" // Vec3 Vec3::operator+( Vec3& left, Vec3& right ){ diff --git a/src/basics/Core/VectorTypes.h b/src/basics/Core/VectorTypes.h index 3109112b299e5ac169d9f536a4d4e66b7970cff2..2ca45b359397c712b8b8695b9a99b4c5f8c324d1 100644 --- a/src/basics/Core/VectorTypes.h +++ b/src/basics/Core/VectorTypes.h @@ -1,3 +1,35 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file VectorTypes.h +//! \ingroup Core +//! \author Soeren Peters +//======================================================================================= #ifndef VECTORTYPES_H #define VECTORTYPES_H @@ -20,7 +52,7 @@ #include "RealConstants.h" struct BASICS_EXPORT Vec3 { - real x{ c0o1 }, y{ c0o1 }, z{ c0o1 }; + real x{ 0. }, y{ 0. }, z{ 0. }; __host__ __device__ Vec3(real x, real y, real z) : x(x), y(y), z(z) {} Vec3() = default; diff --git a/src/basics/Core/buildInfo.h b/src/basics/Core/buildInfo.h index a5499518c7a13ea52d470895b702ca0aab1294e0..598d5ee742fc329c01c66a24429cd20b2cebe89e 100644 --- a/src/basics/Core/buildInfo.h +++ b/src/basics/Core/buildInfo.h @@ -1,3 +1,35 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file buildInfo.h +//! \ingroup Core +//! \author Soeren Peters +//======================================================================================= #ifndef buildInfo_H #define buildInfo_H diff --git a/src/basics/basics/container/CbVectorPool.h b/src/basics/basics/container/CbVectorPool.h new file mode 100644 index 0000000000000000000000000000000000000000..f764dd9e53df7b3b0f07500a3cfa6577476819f7 --- /dev/null +++ b/src/basics/basics/container/CbVectorPool.h @@ -0,0 +1,500 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file CbVectorPool.h +//! \ingroup container +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#ifndef CBVECTORPOOL_H +#define CBVECTORPOOL_H + +#include <iostream> +#include <limits> +#include <map> +#include <sstream> +#include <typeinfo> +#include <vector> + +#include <basics/container/CbVector.h> +#include <basics/utilities/UbException.h> +#include <basics/utilities/UbLogger.h> +#include <basics/utilities/UbTuple.h> + +//#include "MPICommunicator.h" +// +//#include <execinfo.h> +//#include <stdio.h> +//#include <stdlib.h> +//#include <unistd.h> + +/*=========================================================================*/ +/* CbVectorPool */ +/* */ +/** +<BR><BR> +@author <A HREF="mailto:muffmolch@gmx.de">S. Freudiger</A> +@version 1.0 - 08.11.07 +@version 1.1 - 09.02.08 +*/ + +/* +Durch Verwendung eines CbVectors in Verbindung mit einem CbVectorAllocatorPool +wird der Datenvector nicht direkt im CbVector gehalten, sondern ist ein Teil +des Datenvectors des Uebergabe-CbVectorPools. +Die Methoden der von CbVectors funktionieren fehlerfrei +Es mss einem jedoch bewusst sein, dass die "resize"-Methoden l�nger ben�tigen, da +u.U. viele Elemente im Speicher verschoeben werden muessen. +Der Poolvector enthaelt KEINE gaps, so dass er z.B. gut zur �bertragung via MPI +geeignet ist... + +Verhaltensweise bei Zerstoeren des Pools: +wird der Pool zerst�rt bevor man die CbVectoren zerst�rt, so wird beim n�chsten +Datenzugriffsversuch eine entsprechende Exception geworfen, denn alle DatenElemente +des CbVEctors werden restet und der Pool dort zu NULL gesetzt. + +Verhaltensweise bei Zerstoeren eines CbVectors: +hier ganz normal der Datenspeicher wieder freigegen und der Poolvektor verk�rzt +*/ + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +template <typename T> +class CbVectorAllocatorPool; + +/*==================================================================*/ +template <typename T> +class CbVectorPool +{ +public: + using value_type = typename CbVector<T>::value_type; + using size_type = typename CbVector<T>::size_type; + using Pool = std::vector<value_type>; + + using CbVectorKey = std::string; + using CbVectorMap = std::map<CbVectorKey, CbVector<value_type> *>; + using CbVectorMapIter = typename CbVectorMap::iterator; + +public: + ////////////////////////////////////////////////////////////////////////// + CbVectorPool(const size_type &startPoolSize = 20000) // startPoolSize*sizeof(T)/1024/1024 [MB] + : poolStartAdress(NULL), nextCbVectorStartIndexInPool(0), nextCbVectorKey() + { + pool.reserve(startPoolSize); + } + /*==================================================================*/ + virtual ~CbVectorPool() + { + // hier werden lediglich ihre datenvektoren "resetet" + for (CbVectorMapIter it = cbVectorMap.begin(); it != cbVectorMap.end(); ++it) { + CbVector<value_type> &vec = *it->second; + CbVectorAllocatorPool<value_type> &allocator = + dynamic_cast<CbVectorAllocatorPool<value_type> &>(*vec.getAllocator()); + // FIXME: //if(allocator.ptrVectorPool != this) UB_THROW( UbException(UB_EXARGS,"CbVectorAllocator is part + // of different Pool") ); + + // allocator daten reseten + allocator.ptrVectorPool = NULL; + allocator.key = CbVectorKey(); + allocator.startIndexInPool = 0; + + // Datenzeiger/-groessen reseten + allocator.ptrDataOf(vec) = NULL; + allocator.dataSizeOf(vec) = 0; + } + } + /*==========================================================*/ + CbVectorKey getNextCbVectorKey() const { return this->nextCbVectorKey; } + /*==================================================================*/ + bool allocVectorData(CbVector<value_type> &vec, const size_type &dataSize, const value_type &value = value_type()) + { + // pool-allocator holen + CbVectorAllocatorPool<value_type> &allocator = + dynamic_cast<CbVectorAllocatorPool<value_type> &>(*vec.getAllocator()); + if (allocator.ptrVectorPool != this) + UB_THROW(UbException(UB_EXARGS, "CbVectorAllocator is part of different Pool")); + + // alloc nur wenn cbVector noch kein Element von Pool! + if (cbVectorMap.find(allocator.key) == cbVectorMap.end()) { + return this->allocData(allocator, vec, dataSize, value); + } + + UB_THROW(UbException(UB_EXARGS, "vector-key=" + UbSystem::toString(allocator.key) + " already taken! (e.g. SetConnectorBlockVisitor was called several times")); + } + /*==================================================================*/ + bool resizeVectorData(CbVector<value_type> &vec, const size_type &dataSize, const value_type &value = value_type()) + { + CbVectorAllocatorPool<value_type> &allocator = + dynamic_cast<CbVectorAllocatorPool<value_type> &>(*vec.getAllocator()); + if (allocator.ptrVectorPool != this) + UB_THROW(UbException(UB_EXARGS, "CbVectorAllocator is part of different Pool")); + + // cbVector noch nicht in map? + CbVectorMapIter pos = cbVectorMap.find(allocator.key); + + if (pos != cbVectorMap.end()) // cbVector vorhanden + { + // wenn bei alloc keine Laenge zugewiesen wurde, so erfolgt das nun + if (allocator.startIndexInPool == 0 && allocator.ptrDataOf(vec) == NULL) + return this->allocData(allocator, vec, dataSize, value); + else + return this->resizeData(allocator, vec, dataSize, value); + } + + UB_THROW(UbException(UB_EXARGS, + "vector gehoert laut allocator zum pool aber den key gibt s nicht... wie kann das sein?")); + } + /*==================================================================*/ + bool deallocVectorData(CbVector<value_type> &vec) + { + CbVectorAllocatorPool<value_type> &allocator = + dynamic_cast<CbVectorAllocatorPool<value_type> &>(*vec.getAllocator()); + if (allocator.ptrVectorPool != this) + UB_THROW(UbException(UB_EXARGS, "CbVectorAllocator is part of different Pool")); + + // nur wenn vector auch teil des + if (cbVectorMap.erase(allocator.key) > 0) { + if (this->resizeData(allocator, vec, 0, 0)) { + allocator.ptrVectorPool = NULL; + allocator.key = CbVectorKey(); + allocator.startIndexInPool = 0; + + // das Datenzeiger/-groessen reseten wird bereits in resize durchgefuehrt + return true; + } else + UB_THROW(UbException(UB_EXARGS, "unknown error")); + } + + // SPtr<Communicator> comm = MPICommunicator::getInstance(); + // int myid = comm->getProcessID(); + + // // Get the name of the processor + // char machinename[MPI_MAX_PROCESSOR_NAME]; + // int name_len; + // MPI_Get_processor_name(machinename, &name_len); + // UBLOG(logINFO, "PID = " << myid << " host name: " << machinename); + // + // int j, nptrs; + //#define SIZE 100 + // void *buffer[100]; + // char **strings; + // + // nptrs = backtrace(buffer, SIZE); + // printf("backtrace() returned %d addresses\n", nptrs); + // + // /* The call backtrace_symbols_fd(buffer, nptrs, STDOUT_FILENO) + // would produce similar output to the following: */ + // + // strings = backtrace_symbols(buffer, nptrs); + // if (strings == NULL) + // { + // perror("backtrace_symbols"); + // exit(EXIT_FAILURE); + // } + // + // for (j = 0; j < nptrs; j++) + // printf("%s\n", strings[j]); + // + // free(strings); + + UB_THROW(UbException(UB_EXARGS, + "vector gehoert laut allocator zum pool aber den key gibt s nicht... wie kann das sein?")); + } + /*==================================================================*/ + friend std::ostream &operator<<(std::ostream &os, const CbVectorPool &cbPool) + { + os << "map" << std::endl; + for (CbVectorMapIter pos = cbPool.cbVectorMap.begin(); pos != cbPool.cbVectorMap.end(); ++pos) { + CbVectorAllocatorPool<value_type> &tmpAllocator = + dynamic_cast<CbVectorAllocatorPool<value_type> &>(*pos->second->getAllocator()); + os << "vector-size=" << pos->second->size() << "vector-Adress=" << tmpAllocator->ptrDataOf(*pos->second) + << ", allocator(key=" << tmpAllocator.key << ", startIndex=" << tmpAllocator.startIndexInPool << ")" + << std::endl; + for (size_type i = 0; i < pos->second->size(); i++) + os << (*pos->second)[i] << ","; + os << std::endl; + } + os << "pool" << std::endl; + for (size_type i = 0; i < cbPool.pool.size(); i++) { + os << cbPool.pool[i] << ","; + os << std::endl; + } + + return os; + } + /*==================================================================*/ + typename CbVectorMap::size_type getNofStoredVectors() const { return this->cbVectorMap.size(); } + /*==================================================================*/ + typename Pool::size_type getPoolSize() const { return this->pool.size(); } + /*==================================================================*/ + // checks if all vectors have one to one pool-entries + bool consistencyCheck() + { + std::vector<int> pool2(pool.size(), 0); + for (CbVectorMapIter it = cbVectorMap.begin(); it != cbVectorMap.end(); ++it) { + CbVector<value_type> &tmpVec = *it->second; + CbVectorAllocatorPool<value_type> &tmpAllocator = + dynamic_cast<CbVectorAllocatorPool<value_type> &>(*tmpVec.getAllocator()); + for (size_type i = tmpAllocator.startIndexInPool; i < tmpAllocator.startIndexInPool + tmpVec.size(); ++i) { + pool2.at(i)++; + } + } + for (size_type i = 0; i < pool2.size(); ++i) { + if (pool2.at(i) > 1) { + UBLOG(logERROR, UB_FUNCTION << " - test failed typo 1"); + return false; + } + if (pool2.at(i) < 1) { + UBLOG(logERROR, UB_FUNCTION << " - test failed typo 2"); + return false; + } + } + return true; + } + +protected: + /*==================================================================*/ + inline bool allocData(CbVectorAllocatorPool<value_type> &allocator, CbVector<value_type> &vec, + const size_type &dataSize, const value_type &value) + { + // safety checks + if (allocator.startIndexInPool != 0 || allocator.ptrDataOf(vec) != NULL || allocator.dataSizeOf(vec) != 0) { + UB_THROW(UbException(UB_EXARGS, "zu allokierender vector ist nicht ganz sauber!!")); + } + + // poolVector vergroessern + if (dataSize > 0) { + pool.resize(pool.size() + dataSize, value); + + // Zeiger der vorhandenen CbVectoren neu setzen, wenn Pool im Speicher verschoben wurde + if (poolStartAdress != &pool.front()) { + poolStartAdress = &pool.front(); + for (CbVectorMapIter it = cbVectorMap.begin(); it != cbVectorMap.end(); ++it) { + CbVector<value_type> &tmpVec = *it->second; + CbVectorAllocatorPool<value_type> &tmpAllocator = + dynamic_cast<CbVectorAllocatorPool<value_type> &>(*tmpVec.getAllocator()); + + if (!tmpAllocator.ptrDataOf(tmpVec)) + continue; // Fall: CbVector hat noch keinen Datenbereich (data zeigt auf NULL) + tmpAllocator.ptrDataOf(tmpVec) = &pool[tmpAllocator.startIndexInPool]; + } + // std::cout<<"CbVectorPoolMpi::allocVectorData vector wurde im speicher verschoben - adressen + // angepasst!!!"<<std::endl; + } + + // aktuellem element adresse zuweisen (wurde evtl schon inder schleife zuvor gemacht) + allocator.ptrDataOf(vec) = &pool.at(nextCbVectorStartIndexInPool); + allocator.startIndexInPool = nextCbVectorStartIndexInPool; + + // neuen StartIndex fuer naechstes Element berechnen + nextCbVectorStartIndexInPool += dataSize; + if (nextCbVectorStartIndexInPool != pool.size()) + UB_THROW(UbException(UB_EXARGS, "index Problem... Annahme falsch?")); + } + + // vector zu map hinzuf�gen (speicher wird dann anschliessend zugwiesen) + cbVectorMap.insert( + std::make_pair(allocator.key, &vec)); // ist angeblich performanter als cbVectorMap[ allocator.key ] = + // cbVector; //aus Effective STL von Scott Meyer + allocator.dataSizeOf(vec) = dataSize; + + // dummDoof nextKey-Generung... + if (allocator.key >= this->nextCbVectorKey) + this->nextCbVectorKey = allocator.key + "1"; + + return true; + } + /*==========================================================*/ + bool resizeData(CbVectorAllocatorPool<value_type> &allocator, CbVector<value_type> &vec, const size_type &dataSize, + const value_type &value) + { + // datenvector verlaengern/-kuerzen + typename Pool::iterator startPos = + pool.begin() + allocator.startIndexInPool; // startPosition der cbVector-Daten im Pool + if (vec.size() > dataSize) + pool.erase(startPos + dataSize, startPos + vec.size()); + else + pool.insert(startPos + vec.size(), dataSize - vec.size(), value); + + ////////////////////////////////////////////////////////////////////////// + // adressen und laengen der einzelnen vectoren anpassen + if (!pool.empty()) { + bool poolMoved = (poolStartAdress != &pool.front()); + poolStartAdress = &pool.front(); + + for (CbVectorMapIter it = cbVectorMap.begin(); it != cbVectorMap.end(); ++it) { + CbVector<value_type> &tmpVec = *it->second; + + if (tmpVec.size() > 0) { + CbVectorAllocatorPool<value_type> &tmpAllocator = + dynamic_cast<CbVectorAllocatorPool<value_type> &>(*tmpVec.getAllocator()); + // liegt CbVector VOR ver�ndertem CbVector? + if (tmpAllocator.startIndexInPool <= + allocator.startIndexInPool) // ja: anpassung NUR wenn pool verschoben wurde! + { + if (poolMoved && tmpVec.size() > 0) + tmpAllocator.ptrDataOf(tmpVec) = &pool[tmpAllocator.startIndexInPool]; + } else // nein: -> Adresse + Index MUSS immer angepasst werden + { + tmpAllocator.startIndexInPool += dataSize - vec.size(); + tmpAllocator.ptrDataOf(tmpVec) = &pool[tmpAllocator.startIndexInPool]; + } + } + } + } else // Sonderfall: alle Elemente haben Laenge 0 -> kein pool -> alle Feld-Adressen auf NULL setzen! + { + poolStartAdress = NULL; + for (CbVectorMapIter it = cbVectorMap.begin(); it != cbVectorMap.end(); ++it) { + CbVector<value_type> &tmpVec = *it->second; + CbVectorAllocatorPool<value_type> &tmpAllocator = + dynamic_cast<CbVectorAllocatorPool<value_type> &>(*tmpVec.getAllocator()); + tmpAllocator.startIndexInPool = 0; + } + } + + // restliche Daten von cbVector + allocator aktualisieren + allocator.dataSizeOf(vec) = dataSize; + if (dataSize == 0) { + allocator.ptrDataOf(vec) = NULL; + allocator.startIndexInPool = 0; + } + + nextCbVectorStartIndexInPool = pool.size(); + + return true; + } + +protected: + /*==================================================================*/ + void getCbVectorData(const CbVector<value_type> &vec, CbVectorKey &vectorKey, size_type &startIndexInPool, + size_type &dataSize) + { + CbVectorAllocatorPool<value_type> &allocator = + dynamic_cast<CbVectorAllocatorPool<value_type> &>(*vec.getAllocator()); + + startIndexInPool = allocator.startIndexInPool; + vectorKey = allocator.key; + dataSize = vec.size(); + } + /*==================================================================*/ + void setCbVectorData(CbVector<value_type> &vec, const CbVectorKey &vectorKey, const size_type &startIndexInPool, + const size_type &dataSize) + { + CbVectorAllocatorPool<value_type> &allocator = + dynamic_cast<CbVectorAllocatorPool<value_type> &>(*vec.getAllocator()); + + allocator.startIndexInPool = startIndexInPool; + allocator.key = vectorKey; + allocator.dataSizeOf(vec) = dataSize; + allocator.ptrDataOf(vec) = &this->pool[startIndexInPool]; + } + /*==================================================================*/ + + CbVectorMap cbVectorMap; // informationsmap fuer MPIData und zugewiesener vector + + Pool pool; // globaler Datenvector + typename Pool::pointer poolStartAdress; // StartAdresse des aktuellen Datenvektors + typename Pool::size_type nextCbVectorStartIndexInPool; // StartIndex fuer den naechsten CbVector + + // key - erstmal dummdoof + CbVectorKey nextCbVectorKey; +}; + +////////////////////////////////////////////////////////////////////////// +// CbVectorAllocatorPool +////////////////////////////////////////////////////////////////////////// +template <typename T> +class CbVectorAllocatorPool : public CbVectorAllocator<T> +{ +public: + // typedefs wiederholen, da Basisklasse = template -> "Dependent-Base"-Problem + using value_type = typename CbVector<T>::value_type; + using size_type = typename CbVector<value_type>::size_type; + + friend class CbVectorPool<value_type>; + + CbVectorAllocatorPool(const CbVectorAllocatorPool &) = delete; + const CbVectorAllocatorPool &operator=(const CbVectorAllocatorPool &) = delete; + +public: + /*==========================================================*/ + CbVectorAllocatorPool(const typename CbVectorPool<value_type>::CbVectorKey &key, + CbVectorPool<value_type> *const &ptrVectorPool) + : CbVectorAllocator<value_type>(), key(key), startIndexInPool(0), ptrVectorPool(ptrVectorPool) + { + if (!ptrVectorPool) + UB_THROW(UbException(UB_EXARGS, "ptrVectorPool==NULL")); + } + /*==========================================================*/ + // hier wird der key automatisch erzeugt! + CbVectorAllocatorPool(CbVectorPool<value_type> *const &ptrVectorPool) + : CbVectorAllocator<value_type>(), startIndexInPool(0), ptrVectorPool(ptrVectorPool) + { + if (!ptrVectorPool) + UB_THROW(UbException(UB_EXARGS, "ptrVectorPool==NULL")); + key = ptrVectorPool->getNextCbVectorKey(); + } + /*==========================================================*/ + bool alloc(CbVector<value_type> &vec, const size_type &dataSize, const value_type &value = value_type()) override + { + if (!ptrVectorPool) + UB_THROW(UbException(UB_EXARGS, "vectorPool seems to be destroyed, ptrVectorPool==NULL")); + return ptrVectorPool->allocVectorData(vec, dataSize, value); + } + /*==========================================================*/ + bool resize(CbVector<value_type> &vec, const size_type &dataSize, const value_type &value = value_type()) override + { + if (!ptrVectorPool) + UB_THROW(UbException(UB_EXARGS, "vectorPool seems to be destroyed, ptrVectorPool==NULL")); + return ptrVectorPool->resizeVectorData(vec, dataSize, value); + } + /*==========================================================*/ + bool dealloc(CbVector<value_type> &vec) override + { + if (ptrVectorPool) + return this->ptrVectorPool->deallocVectorData(vec); + // wenn kein ptrVectorPool -> wurde bereits deallokiert + return true; + } + /*==========================================================*/ + const CbVectorPool<value_type> &getCbVectorPool() + { + if (!ptrVectorPool) + UB_THROW(UbException(UB_EXARGS, "vectorPool seems to be destroyed, ptrVectorPool==NULL")); + return *ptrVectorPool; + } + /*==========================================================*/ + +private: + typename CbVectorPool<value_type>::CbVectorKey key; + typename CbVectorPool<value_type>::Pool::size_type startIndexInPool; + + CbVectorPool<value_type> *ptrVectorPool; +}; + +#endif // CBVECTORPOOL_H diff --git a/src/basics/basics/memory/MbSmartPtr.h b/src/basics/basics/memory/MbSmartPtr.h new file mode 100644 index 0000000000000000000000000000000000000000..9c36cd97301c0fb3be3e98e612e4d05ab3fc899c --- /dev/null +++ b/src/basics/basics/memory/MbSmartPtr.h @@ -0,0 +1,134 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file MbSmartPtr.h +//! \ingroup memory +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#ifndef MBSMARTPTR_H +#define MBSMARTPTR_H + +#include <basics/memory/MbSmartPtrBase.h> + +#ifdef __clang__ +#pragma clang system_header +#endif + +//===================================================== +// Globale Funktion, um das Loeschen des referenzierten +// Objektes flexibler zu gestalten. +// +template <class ObjType> +void deleteRefPtr(ObjType *ptr) +{ + delete ptr; +} + +//====================================================== +// Die Reference-Pointer Klasse: +// +// Beim Referenzieren eines Objektes ueber einen SmartPointer wird ein Zaehler fuer die referezierte Objekt- +// adresse inkrementiert. Wird der Pointer wieder einem anderen Objekt zugewiesen, so wird der Zaehler fuer das +// urspruenglich referenzierte Objekt wieder dekremtiert, ebenfalls beim Destruktor des Reference-Pointers. +// Tatsaechlich geloescht wird das referenzierte Objekt erst, wenn der zugehoerige Zaehler auf 0 ist. Dies geschieht +// ueber die globale Template-Funktion deleteRefPtr(), die bei Bedarf ueberschrieben werden kann. +// Der Reference-Pointer verfuegt also sozusagen ueber eine automatische Garbage Collection + +template <class ObjType> +class MbSmartPtr : public MbSmartPtrBase +{ +public: + // Konstruktoren //bei explicit geht der implizite cast nicht mehr, aber um keinen stress zu verursachen + /*explicit*/ MbSmartPtr<ObjType>(const ObjType *pPtr = NULL) : MbSmartPtrBase(), mpPtr(NULL) { init(pPtr); } + template <class ParamType> + MbSmartPtr<ObjType>(const MbSmartPtr<ParamType> &ptr) : MbSmartPtrBase(), mpPtr(NULL) + { + init(ptr.get()); + } + // Destruktor + ~MbSmartPtr<ObjType>() override { init(NULL); } + //--------------------------------------------------- + // Kopierkonstruktor + MbSmartPtr<ObjType>(const MbSmartPtr<ObjType> &ptr) : MbSmartPtrBase(), mpPtr(NULL) { init(ptr.get()); } + //--------------------------------------------------- + // Zuweisungsoperatoren + template <class ParamType> + const MbSmartPtr<ObjType> &operator=(const MbSmartPtr<ParamType> &ptr) + { + init(ptr.get()); + return *this; + } + const MbSmartPtr<ObjType> &operator=(const MbSmartPtr<ObjType> &ptr) + { + init(ptr.get()); + return *this; + } + + const MbSmartPtr<ObjType> &operator=(const ObjType *pPtr) + { + init(pPtr); + return *this; + } + //--------------------------------------------------- + // Dereferenzierung-Operatoren + ObjType &operator*() const { return *mpPtr; } + ObjType *operator->() const { return mpPtr; } + bool operator!() const { return !mpPtr; } + operator ObjType *() const { return mpPtr; } + //--------------------------------------------------- + // Methoden + ObjType *get() const { return mpPtr; } + //--------------------------------------------------- + int ref_count() const { return MbSmartPtrBase::ref_count(mpPtr); } + //--------------------------------------------------- + bool release() const { return MbSmartPtrBase::removeFromGC(mpPtr); } + +private: + void init(const ObjType *pPtr) + { + // Nur was tun, wenn wirklich noetig + if (pPtr == mpPtr) + return; + + // Aktuell referenziertes Objekt freigeben, dabei ueberpruefen, ob letztes Release + if (mpPtr && releaseRef(mpPtr)) { + // referenziertes Objekt loeschen + deleteRefPtr(mpPtr); + } + + // Wenn pPtr ein neues Objekt ist, Zugriffszaehler auf neues Objekt erhoehen + mpPtr = const_cast<ObjType *>(pPtr); + if (mpPtr) + addRef(mpPtr); + } + +private: + ObjType *mpPtr; +}; + +#endif // MBSMARTPTR_H diff --git a/src/basics/basics/memory/MbSmartPtrBase.cpp b/src/basics/basics/memory/MbSmartPtrBase.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cebff4e4d5c99a6d05865d7cb9d6f936a064efe5 --- /dev/null +++ b/src/basics/basics/memory/MbSmartPtrBase.cpp @@ -0,0 +1,75 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file MbSmartPtrBase.cpp +//! \ingroup memory +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#include <basics/memory/MbSmartPtrBase.h> + +using namespace std; + +bool MbSmartPtrBase::addRef(void *ptr) +{ + MbSmartPtrBaseMap::getInstance()->getMap()[ptr]++; + return true; +} +//------------------------------------------------- +bool MbSmartPtrBase::releaseRef(void *ptr) +{ + map<void *, int> &ptrMap = MbSmartPtrBaseMap::getInstance()->getMap(); + map<void *, int>::iterator pos = ptrMap.find(ptr); + + if (pos != ptrMap.end()) { + pos->second--; + + if (pos->second == 0) { + ptrMap.erase(pos); + return true; + } + } + return false; +} +//------------------------------------------------- +bool MbSmartPtrBase::removeFromGC(void *ptr) const +{ + if (MbSmartPtrBaseMap::getInstance()->getMap().erase(ptr)) + return true; + return false; +} +//------------------------------------------------- +int MbSmartPtrBase::ref_count(void *ptr) const +{ + map<void *, int> &ptrMap = MbSmartPtrBaseMap::getInstance()->getMap(); + map<void *, int>::iterator pos = ptrMap.find(ptr); + + if (pos != ptrMap.end()) + return pos->second; + else + return 0; +} diff --git a/src/basics/basics/memory/MbSmartPtrBase.h b/src/basics/basics/memory/MbSmartPtrBase.h new file mode 100644 index 0000000000000000000000000000000000000000..697af8f3b01e183043dcc2f04bab670c3d42f78f --- /dev/null +++ b/src/basics/basics/memory/MbSmartPtrBase.h @@ -0,0 +1,82 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file MbSmartPtrBase.h +//! \ingroup memory +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#ifndef MBSMARTPTRBASE_H +#define MBSMARTPTRBASE_H + +#include <iostream> +#include <map> + +//============================================================ +// Klasse MbSmartPtrBase +// +// Basisklasse, speziell fuer MbSmartPtr, die das eigentliche +// Reference-Counting uebernimmt. +// +class MbSmartPtrBase +{ + // Ursprung: + // mpCntrMap ist ein Pointer, weil sichergestellt sein muss, dass die + // Map existiert, wenn das erste mal darauf zugegriffen wird. + // Ein Zugriff zwischen zwei statischen Objekten kann zum Fehler fuehren, da + // die Reihenfolge der Konstruktorenaufrufe dann vom Linker bestimmt wird. + + // Anpassung a la UbWriter mit SingletonMap + class MbSmartPtrBaseMap + { + private: + MbSmartPtrBaseMap() = default; + + std::map<void *, int> mpCntrMap; + + public: + MbSmartPtrBaseMap(const MbSmartPtrBaseMap &) = delete; + const MbSmartPtrBaseMap &operator=(const MbSmartPtrBaseMap &) = delete; + + static MbSmartPtrBaseMap *getInstance() + { + static MbSmartPtrBaseMap instance; + return &instance; + } + std::map<void *, int> &getMap() { return mpCntrMap; } + }; + +protected: + MbSmartPtrBase() = default; + virtual ~MbSmartPtrBase() = default; + bool addRef(void *p); + bool releaseRef(void *p); + bool removeFromGC(void *ptr) const; + int ref_count(void *ptr) const; +}; + +#endif // MBSMARTPTRBASE_H diff --git a/src/basics/basics/parallel/PbMpi.h b/src/basics/basics/parallel/PbMpi.h new file mode 100644 index 0000000000000000000000000000000000000000..7f73da85b4ee333a3f266ea8fc082fc5d88f1b40 --- /dev/null +++ b/src/basics/basics/parallel/PbMpi.h @@ -0,0 +1,503 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file PbMpi.h +//! \ingroup parallel +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#ifndef PbMpi_H +#define PbMpi_H + +#include <sstream> +#include <vector> + +#ifndef VF_MPI +#error VF_MPI has to be defined +#endif + +// As we doing a lot of const-cast here we define PbMpi.h to system_header to mute clang-tidy +#ifdef __clang__ +#pragma clang system_header +#endif + +//#undef SEEK_SET +//#undef SEEK_CUR +//#undef SEEK_END +#include <mpi.h> + +#include <basics/utilities/UbException.h> + +#ifdef USE_MPI_CXX_SYNTAX +#define PbMpi_COMM_WORLD MPI::COMM_WORLD +#define PbMpi_INT MPI::INT +#define PbMpi_CHAR MPI::CHAR +#define PbMpi_SHORT MPI::SHORT +#define PbMpi_FLOAT MPI::FLOAT +#define PbMpi_DOUBLE MPI::DOUBLE +#define PbMpi_COMM_NULL MPI::COMM_NULL + +namespace PbMpi +{ +typedef MPI::Intracomm Comm; +typedef MPI::Group Group; +typedef MPI::Request Request; +typedef MPI::Status Status; + +inline void Init() +{ + MPI::Init(); + MPI::COMM_WORLD.Set_errhandler(MPI::ERRORS_THROW_EXCEPTIONS); +} +inline void Init(int &argc, char **argv) +{ + MPI::Init(argc, argv); + MPI::COMM_WORLD.Set_errhandler(MPI::ERRORS_THROW_EXCEPTIONS); +} +inline void Finalize() { MPI::Finalize(); } + +inline int GetCommSize(const Comm &comm) { return comm.Get_size(); } +inline int GetCommRank(const Comm &comm) { return comm.Get_rank(); } +inline void Barrier(const Comm &comm) { comm.Barrier(); } + +inline double Wtime() { return MPI::Wtime(); } +inline double Wtick() { return MPI::Wtick(); } + +inline void Wait(Request &request, Status *outStatus = NULL) +{ + if (outStatus) + request.Wait(*outStatus); + else + request.Wait(); +} + +inline Group GetCommGroup(Comm &comm) { return comm.Get_group(); } +inline Group GetGroupIncl(Group &group, const int &n, int *ranks) { return group.Incl(n, ranks); } +inline Comm CommCreateComm(Comm &comm, Group &group) { return comm.Create(group); } + +inline void Alltoall(Comm &comm, void *sendBuffer, const int &sn, const MPI_Datatype &sdatatype, void *recvBuffer, + const int &rn, const MPI_Datatype &rdatatype) +{ + comm.Alltoall(sendBuffer, sn, sdatatype, recvBuffer, rn, rdatatype); +} +inline void Bcast(Comm &comm, void *data, const int &n, const MPI_Datatype &datatype, const int &srcRank) +{ + comm.Bcast(data, n, datatype, srcRank); +} +inline void Send(Comm &comm, const void *data, const int &length, const MPI_Datatype &dataType, const int &destRank, + const int &tag) +{ + try { + comm.Send(data, length, dataType, destRank, tag); + } catch (MPI::Exception &e) { + std::stringstream ss; + ss << "MPI::Exception error_string=" << e.Get_error_string() << std::endl; + throw UbException(UB_EXARGS, "MPI:Exception catched\n" + ss.str()); + } catch (...) { + throw UbException(UB_EXARGS, "unknown exception"); + } +} +inline void Recv(Comm &comm, const void *data, const int &length, const MPI_Datatype &dataType, const int &srcRank, + const int &tag) +{ + try { + comm.Recv(const_cast<void *>(data), length, dataType, srcRank, tag); + } catch (MPI::Exception &e) { + std::stringstream ss; + ss << "MPI::Exception error_string=" << e.Get_error_string() << std::endl; + throw UbException(UB_EXARGS, "MPI:Exception catched \n" + ss.str()); + } catch (...) { + throw UbException(UB_EXARGS, "unknown exception"); + } +} + +inline void Irecv(Comm comm, const void *data, const int &length, const MPI_Datatype &dataType, const int &srcRank, + const int &tag, Request &outRequest) +{ + outRequest = comm.Irecv(const_cast<void *>(data), length, dataType, srcRank, tag); +} +inline void Ssend(Comm &comm, const void *data, const int &length, const MPI_Datatype &dataType, const int &destRank, + const int &tag) +{ + try { + comm.Ssend(data, length, dataType, destRank, tag); + } catch (MPI::Exception &e) { + std::stringstream ss; + ss << "MPI::Exception error_string=" << e.Get_error_string() << std::endl; + throw UbException(UB_EXARGS, "MPI:Exception catched\n" + ss.str()); + } catch (...) { + throw UbException(UB_EXARGS, "unknown exception"); + } +} + +} // namespace PbMpi +#else ////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +// C-Syntax +////////////////////////////////////////////////////////////////////////// +namespace PbMpi +{ +using Comm = MPI_Comm; +using Group = MPI_Group; +using Request = MPI_Request; +using Status = MPI_Status; +} // namespace PbMpi + +#define PbMpi_COMM_WORLD ((PbMpi::Comm)MPI_COMM_WORLD) +#define PbMpi_INT MPI_INT +#define PbMpi_CHAR MPI_CHAR +#define PbMpi_SHORT MPI_SHORT +#define PbMpi_FLOAT MPI_FLOAT +#define PbMpi_DOUBLE MPI_DOUBLE +#define PbMpi_COMM_NULL MPI_COMM_NULL + +namespace PbMpi +{ +inline void Init() +{ + int argc = 1; + char **argv = new char *[1]; + argv[0] = new char[1]; + argv[0][0] = 'n'; + MPI_Init(&argc, &argv); +} +inline void Init(int &argc, char **argv) { MPI_Init(&argc, &argv); } +inline void Finalize() { MPI_Finalize(); } +inline int GetCommSize(Comm comm) +{ + int tmp; + MPI_Comm_size(comm, &tmp); + return tmp; +} +inline int GetCommRank(Comm comm) +{ + int tmp; + MPI_Comm_rank(comm, &tmp); + return tmp; +} +inline void Barrier(Comm comm) { MPI_Barrier(comm); } +inline double Wtime() { return MPI_Wtime(); } +inline double Wtick() { return MPI_Wtick(); } +inline void Wait(Request &request, Status *outStatus = NULL) { MPI_Wait(&request, outStatus); } + +inline Group GetCommGroup(Comm comm) +{ + Group out; + MPI_Comm_group(comm, &out); + return out; +} +inline Group GetGroupIncl(Group group, const int &n, int *ranks) +{ + Group out; + MPI_Group_incl(group, n, ranks, &out); + return out; +} +inline Comm CommCreateComm(Comm comm, Group &group) +{ + Comm out; + MPI_Comm_create(comm, group, &out); + return out; +} + +inline void Alltoall(Comm comm, void *sendBuffer, const int &sn, const MPI_Datatype &sdatatype, void *recvBuffer, + const int &rn, const MPI_Datatype &rdatatype) +{ + MPI_Alltoall(sendBuffer, sn, sdatatype, recvBuffer, rn, rdatatype, comm); +} +inline void Bcast(Comm comm, void *data, const int &n, const MPI_Datatype &datatype, const int &srcRank) +{ + MPI_Bcast(data, n, datatype, srcRank, comm); +} +inline void Send(Comm comm, const void *data, const int &length, const MPI_Datatype &dataType, const int &destRank, + const int &tag) +{ + MPI_Send(const_cast<void *>(data), length, dataType, destRank, tag, comm); +} +inline void Recv(Comm comm, const void *data, const int &length, const MPI_Datatype &dataType, const int &srcRank, + const int &tag) +{ + MPI_Recv(const_cast<void *>(data), length, dataType, srcRank, tag, comm, MPI_STATUS_IGNORE); +} +inline void Ssend(Comm comm, const void *data, const int &length, const MPI_Datatype &dataType, const int &destRank, + const int &tag) +{ + MPI_Ssend(const_cast<void *>(data), length, dataType, destRank, tag, comm); +} +inline void Irecv(Comm comm, const void *data, const int &length, const MPI_Datatype &dataType, const int &srcRank, + const int &tag, Request &outRequest) +{ + MPI_Irecv(const_cast<void *>(data), length, dataType, srcRank, tag, comm, &outRequest); +} + +} // namespace PbMpi +#endif + +namespace PbMpi +{ +/*======================================================================*/ +// send a single value "value" of MPI_Datatype +template <class T> +inline void sendSingleValue(const T &value, MPI_Datatype datatype, int dest, int tag, PbMpi::Comm comm); + +/*======================================================================*/ +// receives a single value "value" of MPI_Datatype +template <class T> +inline void receiveSingleValue(T &value, MPI_Datatype datatype, int source, int tag, PbMpi::Comm comm); + +/*======================================================================*/ +// receives and returns a single value of MPI_Datatype +// expample: int value = PbMpi::receiveSingleValue<int>(MPI::INT,0,10,comm); +template <class T> +inline T receiveSingleValue(MPI_Datatype datatype, int source, int tag, PbMpi::Comm comm); + +/*======================================================================*/ +// sends bool value (doesn't work with template, why ever... stupid MPI) +inline void sendBoolValue(const bool &value, int dest, int tag, PbMpi::Comm comm); + +/*======================================================================*/ +// receives bool value (doesn't work with template, why ever... stupid MPI) +inline bool receiveBoolValue(int source, int tag, PbMpi::Comm comm); + +/*======================================================================*/ +// sends bool value (doesn't work with template, why ever... stupid MPI) +inline void sendStringValue(const std::string &value, int dest, int tag, PbMpi::Comm comm); + +/*======================================================================*/ +// receives bool value (doesn't work with template, why ever... stupid MPI) +inline std::string receiveStringValue(int source, int tag, PbMpi::Comm comm); + +/*======================================================================*/ +// send a vector of MPI_Datatype +template <class T> +inline void sendVector(const std::vector<T> &v, MPI_Datatype datatype, int dest, int tag, PbMpi::Comm comm); + +/*======================================================================*/ +// receive a std::vector of MPI_Datatype +template <class T> +inline void receiveVector(std::vector<T> &v, MPI_Datatype datatype, int source, int tag, PbMpi::Comm comm); + +/*======================================================================*/ +// receive a vector of MPI_Datatype and adds this vector to existing vector +// ans returns number of received elements +template <class T> +inline int receiveVectorAndAddToVector(std::vector<T> &v, MPI_Datatype datatype, int source, int tag, PbMpi::Comm comm); + +/*======================================================================*/ +// send a std::vector of strings +inline void sendStringVector(const std::vector<std::string> &v, int dest, int tag, PbMpi::Comm comm); + +/*======================================================================*/ +// send a vector of strings +inline void receiveStringVector(std::vector<std::string> &v, int dest, int tag, PbMpi::Comm comm); +} // namespace PbMpi + +/*======================================================================*/ +// send a single value of MPI_Datatype +template <class T> +void PbMpi::sendSingleValue(const T &value, MPI_Datatype datatype, int dest, int tag, PbMpi::Comm comm) +{ + PbMpi::Send(comm, &value, 1, datatype, dest, tag); + // comm.Send(&value, 1, datatype, dest, tag); +} +/*======================================================================*/ +template <class T> +void PbMpi::receiveSingleValue(T &value, MPI_Datatype datatype, int source, int tag, PbMpi::Comm comm) +{ + PbMpi::Recv(comm, &value, 1, datatype, source, tag); + // comm.Recv(&value, 1, datatype, source, tag); +} +/*======================================================================*/ +template <class T> +T PbMpi::receiveSingleValue(MPI_Datatype datatype, int source, int tag, PbMpi::Comm comm) +{ + T value; + PbMpi::Recv(comm, &value, 1, datatype, source, tag); + // comm.Recv(&value, 1, datatype, source, tag); + + return value; +} +/*======================================================================*/ +// send a bool value (bool doesn't work with template, why ever) +void PbMpi::sendBoolValue(const bool &value, int dest, int tag, PbMpi::Comm comm) +{ + short dummy; + if (value) + dummy = 1; + else + dummy = 0; + + PbMpi::Send(comm, &dummy, 1, PbMpi_SHORT, dest, tag); + // comm.Send(&dummy, 1, MPI::SHORT, dest, tag); +} +/*======================================================================*/ +bool PbMpi::receiveBoolValue(int source, int tag, PbMpi::Comm comm) +{ + short dummy{ 0 }; + PbMpi::Recv(comm, &dummy, 1, PbMpi_SHORT, source, tag); + // comm.Recv(&dummy, 1, MPI::SHORT, source, tag); + + return (dummy == 1); +} +/*======================================================================*/ +// sends bool value (doesn't work with template, why ever... stupid MPI) +void PbMpi::sendStringValue(const std::string &value, int dest, int tag, PbMpi::Comm comm) +{ + std::vector<char> vec; + for (char i : value) + vec.push_back(i); + + PbMpi::sendVector(vec, PbMpi_CHAR, dest, tag, comm); +} + +/*======================================================================*/ +// receives bool value (doesn't work with template, why ever... stupid MPI) +std::string PbMpi::receiveStringValue(int source, int tag, PbMpi::Comm comm) +{ + std::vector<char> vec; + PbMpi::receiveVector(vec, PbMpi_CHAR, source, tag, comm); + + std::string str; + for (char i : vec) + str += i; + + return str; +} +/*======================================================================*/ +// send a vector of MPI_Datatype +template <class T> +void PbMpi::sendVector(const std::vector<T> &v, MPI_Datatype datatype, int dest, int tag, PbMpi::Comm comm) +{ + // send size + int size = (int)v.size(); + + PbMpi::Send(comm, &size, 1, PbMpi_INT, dest, tag); + // comm.Send(&size, 1, MPI::INT, dest, tag); + + if (size > 0) { + PbMpi::Send(comm, &v[0], size, datatype, dest, tag); + // comm.Send(&v[0], size, datatype, dest, tag); + } +} +/*======================================================================*/ +// receive a vector of MPI_Datatype +template <class T> +void PbMpi::receiveVector(std::vector<T> &v, MPI_Datatype datatype, int source, int tag, PbMpi::Comm comm) +{ + int size{ 0 }; + + PbMpi::Recv(comm, &size, 1, PbMpi_INT, source, tag); + // comm.Recv(&size, 1, MPI::INT, source, tag); + + v.resize(size); + + if (size > 0) { + PbMpi::Recv(comm, &v[0], size, datatype, source, tag); + // comm.Recv(&v[0], size, datatype, source, tag); + } +} +/*======================================================================*/ +// receive a vector of MPI_Datatype and adds this vector to existing vector +// return value is size of received elements +template <class T> +int PbMpi::receiveVectorAndAddToVector(std::vector<T> &v, MPI_Datatype datatype, int source, int tag, PbMpi::Comm comm) +{ + int incommingSize; + + PbMpi::Recv(comm, &incommingSize, 1, PbMpi_INT, source, tag); + // comm.Recv(&incommingSize, 1, MPI::INT, source, tag); + + int oldSize = (int)v.size(); + v.resize(oldSize + incommingSize); + + if (incommingSize > 0) { + PbMpi::Recv(comm, &v[oldSize], incommingSize, datatype, source, tag); + // comm.Recv(&v[oldSize], incommingSize, datatype, source, tag); + } + + return incommingSize; +} +/*======================================================================*/ +// send a vector of strings +void PbMpi::sendStringVector(const std::vector<std::string> &v, int dest, int tag, PbMpi::Comm comm) +{ + // send size + int stringVectorSize = (int)v.size(); + + PbMpi::Send(comm, &stringVectorSize, 1, PbMpi_INT, dest, tag); + // comm.Send(&stringVectorSize, 1, MPI::INT, dest, tag); + + if (stringVectorSize > 0) { + std::vector<int> singleStringSizes(stringVectorSize + 1); + int nofChars = 0; + for (int i = 0; i < stringVectorSize; i++) + nofChars += singleStringSizes[i] = (int)v[i].length(); + singleStringSizes[stringVectorSize] = nofChars; + + PbMpi::Send(comm, &singleStringSizes[0], stringVectorSize + 1, PbMpi_INT, dest, tag); + + std::vector<char> charVector(nofChars); + int pos = 0; + for (int i = 0; i < stringVectorSize; i++) + for (int j = 0; j < singleStringSizes[i]; j++) + charVector[pos++] = v[i][j]; + + PbMpi::Send(comm, &charVector[0], nofChars, PbMpi_CHAR, dest, tag); + // comm.Send(&charVector[0], nofChars, MPI::CHAR, dest, tag); + } +} +/*======================================================================*/ +// send a vector of strings +void PbMpi::receiveStringVector(std::vector<std::string> &v, int source, int tag, PbMpi::Comm comm) +{ + // send size + int stringVectorSize{ 0 }; + PbMpi::Recv(comm, &stringVectorSize, 1, PbMpi_INT, source, tag); + // comm.Recv(&stringVectorSize, 1, MPI::INT, source, tag); + + v.clear(); + v.resize(stringVectorSize); + + if (stringVectorSize > 0) { + std::vector<int> singleStringSizes(stringVectorSize + 1); + + PbMpi::Recv(comm, &singleStringSizes[0], stringVectorSize + 1, PbMpi_INT, source, tag); + // comm.Recv(&singleStringSizes[0], stringVectorSize+1, MPI::INT, source, tag); + + int nofChars = singleStringSizes[stringVectorSize]; + std::vector<char> charVector(nofChars); + + PbMpi::Recv(comm, &charVector[0], nofChars, PbMpi_CHAR, source, tag); + // comm.Recv(&charVector[0], nofChars, MPI::CHAR, source, tag); + + int pos = 0; + for (int i = 0; i < stringVectorSize; i++) + for (int j = 0; j < singleStringSizes[i]; j++) + v[i].push_back(charVector[pos++]); + } +} + +#endif // PbMpi_H diff --git a/src/basics/basics/transmitter/TbTransmitter.h b/src/basics/basics/transmitter/TbTransmitter.h new file mode 100644 index 0000000000000000000000000000000000000000..22fff52a1d1a9d2219b78e933d63e3e1c208897f --- /dev/null +++ b/src/basics/basics/transmitter/TbTransmitter.h @@ -0,0 +1,94 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file TbTransmitter.h +//! \ingroup transmitter +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#ifndef TBTRANSMITTER_H +#define TBTRANSMITTER_H + +#include <string> + +/*================================================================================*/ +/* TbTransmitter */ +/* */ +/** +This Class provides the base for sending and receiving of data. +<BR><BR> +@author <A HREF="mailto:muffmolch@gmx.de">S. Freudiger</A> +@version 1.0 - 08.11.07 +*/ + +/* +usage: ... +*/ + +////////////////////////////////////////////////////////////////////////// +// Transmitter +// macht nichts ausser daten senden und empfangen +template <typename T> +class TbTransmitter +{ +public: + using value_type = T; + +public: + TbTransmitter() = default; + virtual ~TbTransmitter() = default; + + virtual bool isLocalTransmitter() const = 0; + virtual bool isRemoteTransmitter() const = 0; + + // preprocess (e.g. synchronizing send-/receive-buffer) + virtual void sendDataSize() = 0; + virtual void receiveDataSize() = 0; + + // calculation + virtual void prepareForSend() {} + virtual void sendData() = 0; + virtual void prepareForReceive() {} + virtual value_type &receiveData() = 0; + + // data-access + inline value_type &getData() { return this->data; } + inline const value_type &getData() const { return this->data; } + + // info-section (usable for remote transmitter) + virtual int getSendToRank() const { return -1; } + virtual int getSendToTag() const { return -1; } + virtual int getRecvFromRank() const { return -1; } + virtual int getRecvFromTag() const { return -1; } + + virtual std::string toString() const = 0; + +protected: + value_type data; +}; + +#endif // TBTRANSMITTER_H diff --git a/src/basics/basics/transmitter/TbTransmitterLocal.h b/src/basics/basics/transmitter/TbTransmitterLocal.h new file mode 100644 index 0000000000000000000000000000000000000000..39a2592c19cbb23d56c880ef501a89b506b974d7 --- /dev/null +++ b/src/basics/basics/transmitter/TbTransmitterLocal.h @@ -0,0 +1,148 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file TbTransmitterLocal.h +//! \ingroup transmitter +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#ifndef TOTRANSMITTERLOCAL_H +#define TOTRANSMITTERLOCAL_H + +#include <PointerDefinitions.h> +#include <basics/transmitter/TbTransmitter.h> +#include <basics/utilities/UbException.h> + +/*================================================================================*/ +/* TbLocalTransmitter, TbVectorSenderLocal, TbVectorReceiverLocal */ +/* */ +/** +This Class provides the base for exception handling. +<BR><BR> +@author <A HREF="mailto:muffmolch@gmx.de">S. Freudiger</A> +@version 1.0 - 08.11.07 +*/ + +/* +usage: ... +*/ + +////////////////////////////////////////////////////////////////////////// +// LocalTransmitter lokalen Datenaustausch +// data = send- und zugleich receive-buffer +template <typename T> +class TbLocalTransmitter : public TbTransmitter<T> +{ +public: + using TbLocalTransmitterPtr = SPtr<TbLocalTransmitter<T>>; + + using value_type = T; + +public: + TbLocalTransmitter() : TbTransmitter<T>() {} + + bool isLocalTransmitter() const override { return true; } + bool isRemoteTransmitter() const override { return !this->isLocalTransmitter(); } + + // send buffer wird autom resized + void sendDataSize() override {} + // reiceive braucht nichts machen, da send==receive buffer ;-) + void receiveDataSize() override {} + + void sendData() override {} + value_type &receiveData() override { return this->data; } + + std::string toString() const override { return "TbLocalTransmitter" + (std::string) typeid(T).name(); } +}; + +////////////////////////////////////////////////////////////////////////// +// TbVectorSender/ReceiverLocal lokalen Datenaustausch ueber ZWEI vektoren +template <typename T> +class TbVectorReceiverLocal : public TbTransmitter<T> +{ +public: + using value_type = T; + +public: + TbVectorReceiverLocal() : TbTransmitter<value_type>() {} + // virtual ~TbVectorReceiverLocal() { std::cout<<typeid(*this).name()<<" tot"<<std::endl; } + + bool isLocalTransmitter() const { return true; } + bool isRemoteTransmitter() const { return !this->isLocalTransmitter(); } + + // send buffer wird autom resized + void sendDataSize() { UB_THROW(UbException(UB_EXARGS, "empfaengt nur")); } + // reiceive braucht nichts machen, das macht der sender :-) + void receiveDataSize() {} + + void sendData() { UB_THROW(UbException(UB_EXARGS, "empfaengt nur")); } + value_type &receiveData() { return this->data; } + + std::string toString() const { return "TbVectorReceiverLocal<" + (std::string) typeid(T).name() + ">"; } +}; + +template <typename T> +class TbVectorSenderLocal : public TbTransmitter<T> +{ +public: + using value_type = T; + +public: + TbVectorSenderLocal(SPtr<TbVectorReceiverLocal<value_type>> receiver) + : TbTransmitter<value_type>(), receiver(receiver) + { + } + // virtual ~TbVectorSenderLocal() { std::cout<<typeid(*this).name()<<" tot"<<std::endl; } + + bool isLocalTransmitter() const { return true; } + bool isRemoteTransmitter() const { return !this->isLocalTransmitter(); } + + // send buffer wird autom resized + void sendDataSize() + { + assert(receiver != NULL); + receiver->getData().resize(this->data.size()); + } + // reiceive braucht nichts machen, da send==receive buffer ;-) + void receiveDataSize() { UB_THROW(UbException(UB_EXARGS, "sendet nur")); } + + void sendData() + { + assert(this->data.size() == receiver->getData().size()); + receiver->getData() = this->data; + // for(int i=(int)this->data.size()-1; i>=0; --i) + // receiver->getData()[i]= this->data[i]; + } + value_type &receiveData() { UB_THROW(UbException(UB_EXARGS, "sendet nur")); } + + std::string toString() const { return "TbVectorSenderLocal<" + (std::string) typeid(T).name() + ">"; } + +protected: + SPtr<TbVectorReceiverLocal<value_type>> receiver; +}; + +#endif // TOTRANSMITTERLOCAL_H diff --git a/src/basics/basics/transmitter/TbTransmitterMpiPool.h b/src/basics/basics/transmitter/TbTransmitterMpiPool.h new file mode 100644 index 0000000000000000000000000000000000000000..83c0b1e396364840d4ec03a666f482791e098462 --- /dev/null +++ b/src/basics/basics/transmitter/TbTransmitterMpiPool.h @@ -0,0 +1,574 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file TbTransmitterMpiPool.h +//! \ingroup transmitter +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#ifndef TBTRANSMITTERMPIPOOL_H +#define TBTRANSMITTERMPIPOOL_H + +#ifdef VF_MPI + +#include <iomanip> +#include <iostream> +#include <map> +#include <sstream> +#include <vector> + +#include <mpi.h> + +#include <basics/container/CbVector.h> +#include <basics/container/CbVectorPool.h> +#include <basics/transmitter/TbTransmitter.h> + +#include <PointerDefinitions.h> +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +// TbCbVectorMpiPoolSender/Receiver +// diese verschicken immer einen VectorPool. Letztlich einen langen vector, +// der eigentlich aus vielen kleinen besteht +// jeder MpiPoolVector hat einen pointer auf die startadresse in diesem vector +// die informationen werden im TbMpiVectorPool verwaltet +// MpiPoolVector verhaelt sich nach aussen hin mit einschraenkungen wie ein std::vector +// und kann somit bei den vector connector verwendet werden +// man kann die klassen theoretisch verallgemeinern. + +template <typename T> +class TbCbVectorSenderMpiPool; +template <typename T> +class TbCbVectorReceiverMpiPool; + +/*==================================================================*/ +template <typename T> +class TbCbVectorMpiPool : public CbVectorPool<T> +{ +public: + using MpiPoolPtr = SPtr<TbCbVectorMpiPool<T>>; + + ////////////////////////////////////////////////////////////////////////// + using MpiPoolPtrMap = std::map<std::string, MpiPoolPtr>; + using MpiPoolPtrMapIter = typename MpiPoolPtrMap::iterator; + + // da BasisKlasse templateKlasse ist MUSS man hier die typedefs nochmal wiederholen! + using value_type = typename CbVector<T>::value_type; + using size_type = typename CbVector<T>::size_type; + using Pool = std::vector<value_type>; + + using CbVectorKey = std::string; + using CbVectorMap = std::map<CbVectorKey, CbVector<value_type> *>; + using CbVectorMapIter = typename CbVectorMap::iterator; + + ////////////////////////////////////////////////////////////////////////// + friend class TbCbVectorSenderMpiPool<T>; + friend class TbCbVectorReceiverMpiPool<T>; + +protected: + ////////////////////////////////////////////////////////////////////////// + static MpiPoolPtrMap poolMap; + +public: + ////////////////////////////////////////////////////////////////////////// + // STATIC MEMBERS + ////////////////////////////////////////////////////////////////////////// + // createTbCbVectorMpiPool: + // poolKey : Schluessel fuer eindeutige Indizierung in Map + // mpiRemoteRank: mpi-rank des Empfaengers/Senders + // mpiTag : mpi-tag mit dem empfangen/gesendet wird + static MpiPoolPtr createTbCbVectorMpiPool(CbVectorKey poolKey, int mpiRemoteRank, int mpiTag, MPI_Comm comm, + size_type startPoolSize = 20000) // startPoolSize*sizeof(T)/1024/1024 [MB] + + { + if (poolMap.find(poolKey) != poolMap.end()) { + throw UbException(UB_EXARGS, "es ist bereits ein Pool mit dem key vorhanden!!!"); + } + + // pool erstellen + MpiPoolPtr mpiPool(new TbCbVectorMpiPool<T>(poolKey, mpiRemoteRank, mpiTag, comm, startPoolSize)); + + // pool "speichern" + TbCbVectorMpiPool<value_type>::poolMap[poolKey] = mpiPool; + + return mpiPool; + } + static void deleteTbCbVectorMpiPool(CbVectorKey poolKey) + { + MpiPoolPtrMapIter it = TbCbVectorMpiPool<value_type>::poolMap.find(poolKey); + if (it == poolMap.end()) { + throw UbException(UB_EXARGS, "kein Pool mit dem key vorhanden"); + } + TbCbVectorMpiPool<value_type>::poolMap.erase(it); + } + /*==================================================================*/ + static MpiPoolPtr getTbCbVectorMpiPool(CbVectorKey poolKey) + { + MpiPoolPtrMapIter it; + if ((it = TbCbVectorMpiPool<T>::poolMap.find(poolKey)) != TbCbVectorMpiPool<T>::poolMap.end()) { + return it->second; + } + return MpiPoolPtr(); + } + /*==================================================================*/ + static std::string getInfoString() + { + std::stringstream out; + out << "TbCbVectorMpiPool<" << typeid(T).name() << ") - Info:" << std::endl; + for (MpiPoolPtrMapIter it = poolMap.begin(); it != poolMap.end(); ++it) + out << "pool with key(" << std::setw(15) << it->first << ") " + << "stores " << std::setw(12) << it->second->getNofStoredVectors() << " vectors " + << ", elements to transfer = " << std::setw(15) << it->second->getPoolSize() << " ( " + << it->second->getPoolSize() * sizeof(T) / (1024.0 * 1024.0) << " MB )" << std::endl; + return out.str(); + } + /*==================================================================*/ + // checks if all vectors have one to one pool-entries + static bool consistencyCheck() + { + for (MpiPoolPtrMapIter it = poolMap.begin(); it != poolMap.end(); ++it) { + if (!it->second->CbVectorPool<T>::consistencyCheck()) { + return false; + } + } + + return true; + } + ////////////////////////////////////////////////////////////////////////// + static void eraseMap() { poolMap.clear(); } + +protected: + ////////////////////////////////////////////////////////////////////////// + TbCbVectorMpiPool(CbVectorKey poolKey, int mpiRemoteRank, int mpiTag, MPI_Comm comm, size_type startPoolSize) + : CbVectorPool<value_type>(startPoolSize), poolKey(poolKey), + nofStoredVectors(0) //=Anzahl an Vectoren im Pool, wird bei send/receiveDataOrder gesetzt + , + counterPrepareReceiveDataOrder(0), counterSendDataOrder(0), counterReceiveDataOrder(0), + counterPrepareForReceive(0), counterReceive(0), counterPrepareForSend(0), counterSend(0), comm(comm), + receiveRequest(MPI_REQUEST_NULL) + //, sendRequest(MPI_REQUEST_NULL) + , + mpiRemoteRank(mpiRemoteRank), mpiTag(mpiTag) + { + if ((std::string) typeid(value_type).name() == (std::string) typeid(double).name()) + mpiDataType = MPI_DOUBLE; + else if ((std::string) typeid(value_type).name() == (std::string) typeid(float).name()) + mpiDataType = MPI_FLOAT; + else if ((std::string) typeid(value_type).name() == (std::string) typeid(int).name()) + mpiDataType = MPI_INT; + else + throw UbException(UB_EXARGS, "no MpiDataType for T" + (std::string) typeid(T).name()); + + for (int i = 0; i < 3; i++) { + sendRequest[i] = MPI_REQUEST_NULL; + } + } + +public: + /*==================================================================*/ + // returns key of Pool in MpiPoolMap + CbVectorKey getPoolKey() const { return this->poolKey; } + /*==================================================================*/ + // returns rank of process pool data will be send to/received from + int getRemoteRank() const { return this->mpiRemoteRank; } + /*==================================================================*/ + // returns tag of process pool data will be send to/received from + int getRemoteTag() const { return this->mpiTag; } + +protected: + /*==================================================================*/ + void sendDataOrder() + { + counterSendDataOrder++; + if (counterSendDataOrder == this->cbVectorMap.size()) { + // allg.: bei MPI muss man darauf achten, dass bei unblocked operationen die puffer (aus dem oder in den + // geschrieben wird auch noch vorhanden sind!!! wuerde man hier z.B. einen lokalen vector mit Isend() los- + // schicken, dann wurde der scope verlassen werden und der vector evtl geloescht werden, bevor mpi den + // vorgang abgeschlossen hat!!! -> tmpOrderVec ist class-member!!! + unsigned nofElements = (unsigned)this->cbVectorMap.size() * 3 + 1; + tmpSendOrderVec.resize(nofElements); // std::vector< unsigned > vec(nofElements); + unsigned index = 0; + tmpSendOrderVec[index++] = (unsigned)this->pool.size(); //= laenge des vectors + if (this->nextCbVectorStartIndexInPool != this->pool.size()) + throw UbException(UB_EXARGS, + "an dieser Stelle sollten nextStartIndex und pool.size() identisch sein!!!"); + for (CbVectorMapIter it = this->cbVectorMap.begin(); it != this->cbVectorMap.end(); ++it) { + CbVectorKey vectorKey; + size_type dataSize = 0, startIndexInPool = 0; + this->getCbVectorData(*it->second /*vec*/, vectorKey, startIndexInPool, dataSize); + if (it->first != vectorKey) + throw UbException(UB_EXARGS, "key mismatch!"); + + tmpSendOrderKeyVec += vectorKey; // vectorKey == allocator.getAllocatorKey() + tmpSendOrderVec[index++] = (unsigned)vectorKey.length(); + tmpSendOrderVec[index++] = (unsigned)startIndexInPool; // startIndex in poolVector + tmpSendOrderVec[index++] = (unsigned)dataSize; // dataSize + } + + MPI_Isend(&tmpSendOrderVec[0], (int)tmpSendOrderVec.size(), MPI_UNSIGNED, mpiRemoteRank, mpiTag, comm, + &sendRequest[0]); + + tmpSendOrderKeyVecLength = (unsigned)tmpSendOrderKeyVec.length(); + MPI_Isend(&tmpSendOrderKeyVecLength, 1, MPI_UNSIGNED, mpiRemoteRank, mpiTag, comm, &sendRequest[1]); + MPI_Isend((char *)tmpSendOrderKeyVec.c_str(), tmpSendOrderKeyVecLength, MPI_CHAR, mpiRemoteRank, mpiTag, + comm, &sendRequest[2]); + + counterSendDataOrder = 0; + + nofStoredVectors = this->cbVectorMap.size(); + + UBLOG(logDEBUG5, "TbCbVectorMpiPool::sendDataOrder()" + << " mpiRemoteRank=" << mpiRemoteRank << " mpiTag=" << mpiTag); + +#ifdef _DEBUG + orgPoolVectorStartPointer = &this->pool[0]; +#endif + } + } + /*==================================================================*/ + void receiveDataOrder() + { + counterReceiveDataOrder++; + if (counterReceiveDataOrder == this->cbVectorMap.size()) { + // receiveRequest.Wait(); + unsigned nofElements = + (unsigned)this->cbVectorMap.size() * 3 + + 1; // map MUSS auf beiden seiten gleich gross sein, sonst hat man ein grundsaetzliches problem ;-) + + UBLOG(logDEBUG5, "TbCbVectorMpiPool::receiveDataOrder()" + << " mpiRemoteRank=" << mpiRemoteRank << " mpiTag=" << mpiTag); + + std::vector<unsigned> tmpRecvOrderVec; + tmpRecvOrderVec.resize(nofElements); + + std::vector<char> tmpRecvOrderKeyVec; + + // MPI_Status status; + MPI_Recv(&tmpRecvOrderVec[0], nofElements, MPI_UNSIGNED, mpiRemoteRank, mpiTag, comm, MPI_STATUS_IGNORE); + + unsigned rcount; + MPI_Recv(&rcount, 1, MPI_UNSIGNED, mpiRemoteRank, mpiTag, comm, MPI_STATUS_IGNORE); + tmpRecvOrderKeyVec.resize(rcount); + MPI_Recv(&tmpRecvOrderKeyVec[0], rcount, MPI_CHAR, mpiRemoteRank, mpiTag, comm, MPI_STATUS_IGNORE); + + if (nofElements != (unsigned)tmpRecvOrderVec.size()) + throw UbException(UB_EXARGS, "error... vec size stimmt nicht"); + + unsigned index = 0; + size_type index2 = 0; + this->nextCbVectorStartIndexInPool = tmpRecvOrderVec[index++]; //= laenge des vectors + this->pool.resize(this->nextCbVectorStartIndexInPool); + CbVectorMapIter it = this->cbVectorMap.begin(); + for (/*index*/; index < nofElements; index += 3, ++it) { + size_type vectorKeyLength = (size_type)tmpRecvOrderVec.at(index); + size_type startIndexInPool = (size_type)tmpRecvOrderVec.at(index + 1); + size_type dataSize = (size_type)tmpRecvOrderVec.at(index + 2); + CbVectorKey vectorKey = CbVectorKey(&tmpRecvOrderKeyVec[index2], vectorKeyLength); + index2 += vectorKeyLength; + + // if(it==this->cbVectorMap.end() || it->first != vectorKey ) + // throw UbException(UB_EXARGS, "entweder hat map nicht die gleiche reihenfolge oder vectorKey = + // "+UbSystem::toString(vectorKey)+" nicht vorhanden"); + if (it == this->cbVectorMap.end()) + throw UbException(UB_EXARGS, "map ist leer"); + else if (it->first != vectorKey) + throw UbException(UB_EXARGS, "vectorKey = " + UbSystem::toString(vectorKey) + + " nicht vorhanden it->first =" + UbSystem::toString(it->first)); + + this->setCbVectorData(*it->second /*vec*/, vectorKey, startIndexInPool, dataSize); + } + if (it != this->cbVectorMap.end()) + throw UbException(UB_EXARGS, "error... in der map sind scheinbar noch weiter elemente vorhanden, die " + "es auf der send seite nicht gibt..."); + + counterReceiveDataOrder = 0; + nofStoredVectors = this->cbVectorMap.size(); + +#ifdef _DEBUG + orgPoolVectorStartPointer = &this->pool[0]; +#endif + } + } + /*==================================================================*/ + void prepareForSendData() + { + // da sendDataOrder einen request verwendet muss man hier immer abfragen + if (counterPrepareForSend == 0) { + UBLOG(logDEBUG5, "TbCbVectorMpiPool::prepareForSendData():start" + << " mpiRemoteRank=" << mpiRemoteRank << " mpiTag=" << mpiTag); + // if(sendRequest != MPI_REQUEST_NULL) MPI_Wait(&sendRequest, MPI_STATUS_IGNORE); + if (sendRequest[2] != MPI_REQUEST_NULL) + MPI_Waitall(3, sendRequest, MPI_STATUS_IGNORE); + UBLOG(logDEBUG5, "TbCbVectorMpiPool::prepareForSendData():end" + << " mpiRemoteRank=" << mpiRemoteRank << " mpiTag=" << mpiTag); + } + + counterPrepareForSend++; + + if (counterPrepareForSend == nofStoredVectors) { + counterPrepareForSend = 0; + } + + // A - non blocking + ////der ERSTE is entscheidend + ////Grund: wenn man + //// for(all trans) { trans->prepare(); trans->fillBuffer(); } + //// aufruft, dann wuerde u.U. der Buffer neu beschrieben werden obwohl noch nicht versendet wurde!!! + // counterPrepareForSend++; + // if(counterPrepareForSend==1) + //{ + // if(sendRequest != MPI::REQUEST_NULL) sendRequest.Wait(); + //} + // + // if(counterPrepareForSend==nofStoredVectors) + // counterPrepareForSend=0; + } + /*==================================================================*/ + void sendData() + { + // A - non blocking + // der LETZTE is entscheidend + // counterSend++; + // if(counterSend==nofStoredVectors) + //{ + // //std::cout<<"Isend von "<<(int)nextStartIndex<<"elementen von "<<mpiRemoteRank<<" mit + // tag="<<mpiTag<<std::endl; sendRequest = comm.Isend(&pool[0],(int)nextCbVectorStartIndexInPool, mpiDataType, + // mpiRemoteRank, mpiTag); counterSend=0; + //} + // B - blocking + // der LETZTE is entscheidend + counterSend++; + if (counterSend == nofStoredVectors) { + // std::cout<<"Isend von "<<(int)nextStartIndex<<"elementen von "<<mpiRemoteRank<<" mit + // tag="<<mpiTag<<std::endl; + UBLOG(logDEBUG5, "TbCbVectorMpiPool::sendData():start" + << " mpiRemoteRank=" << mpiRemoteRank << " mpiTag=" << mpiTag); + + // synchronous send + // comm.Ssend(&this->pool[0],(int)this->nextCbVectorStartIndexInPool, mpiDataType, mpiRemoteRank, mpiTag); +#ifdef _DEBUG + if (this->orgPoolVectorStartPointer != &this->pool[0]) + throw UbException(UB_EXARGS, "ups, pool array adress changed - unknown behavoir"); +#endif + + // standard send + MPI_Send(&this->pool[0], (int)this->nextCbVectorStartIndexInPool, mpiDataType, mpiRemoteRank, mpiTag, comm); + UBLOG(logDEBUG5, "TbCbVectorMpiPool::sendData():end" + << " mpiRemoteRank=" << mpiRemoteRank << " mpiTag=" << mpiTag); + //////////////////////////////////////////////////////////////////////////////////////////// + // DEBUG/////////////////////////////////////// + // int irank; + // MPI_Comm_rank(MPI_COMM_WORLD, &irank); + // std::cout << "MPI_Send: " << irank << " " << mpiRemoteRank << " " <<mpiTag<<std::endl; + /////////////////////////////////////////////////// + counterSend = 0; + } + } + /*==================================================================*/ + void prepareForReceiveData() + { + // A - non blocking + // sobald der Letzte kann man den den request holen. + // andernfalls kann nicht gewaehrleistet werden, dass evtl noch mit dem buffer gearbeitet wird!!! + counterPrepareForReceive++; + if (counterPrepareForReceive == this->nofStoredVectors) { + UBLOG(logDEBUG5, "TbCbVectorMpiPool::prepareForReceiveData():start" + << " mpiRemoteRank=" << mpiRemoteRank << " mpiTag=" << mpiTag); +#ifdef _DEBUG + if (this->orgPoolVectorStartPointer != &this->pool[0]) + throw UbException(UB_EXARGS, "ups, pool array adress changed - unknown behavoir"); +#endif + MPI_Irecv(&this->pool[0], (int)this->nextCbVectorStartIndexInPool, mpiDataType, mpiRemoteRank, mpiTag, comm, + &receiveRequest); + UBLOG(logDEBUG5, "TbCbVectorMpiPool::prepareForReceiveData():end" + << " mpiRemoteRank=" << mpiRemoteRank << " mpiTag=" << mpiTag); + counterPrepareForReceive = 0; + } + } + /*==================================================================*/ + void receiveData() + { + // A - non blocking + // sobald der ERSTE reinkommt muss man warten, bis received wurde!!! + // denn erst anschliessend stehen die empfangenen daten zur verfuegung + if (counterReceive == 0) { + UBLOG(logDEBUG5, "TbCbVectorMpiPool::receiveData():start" + << " mpiRemoteRank=" << mpiRemoteRank << " mpiTag=" << mpiTag); + MPI_Wait(&receiveRequest, MPI_STATUS_IGNORE); + UBLOG(logDEBUG5, "TbCbVectorMpiPool::receiveData():end" + << " mpiRemoteRank=" << mpiRemoteRank << " mpiTag=" << mpiTag); + } + counterReceive++; + if (counterReceive == this->nofStoredVectors) // alle receiver waren hier + { + counterReceive = 0; + } + + ////B - blocking + ////sobald der ERSTE reinkommt muss man warten, bis received wurde!!! + ////denn erst anschliessend stehen die empfangenen daten zur verfuegung + // if(counterReceive==0) + //{ + // comm.Recv(&this->pool[0],(int)this->nextCbVectorStartIndexInPool, mpiDataType, mpiRemoteRank, mpiTag); + //} + // counterReceive++; + // if(counterReceive==this->nofStoredVectors) //alle receiver waren hier + // counterReceive=0; + } + +protected: + CbVectorKey poolKey; // eindeutiger schluessel fuer pool + size_type nofStoredVectors; + + size_type counterPrepareReceiveDataOrder; + size_type counterSendDataOrder; + size_type counterReceiveDataOrder; + size_type counterPrepareForReceive; + size_type counterReceive; + size_type counterPrepareForSend; + size_type counterSend; + + std::vector<unsigned> tmpSendOrderVec; // wird zur temp speicherung der anordnung benoetigt + std::string tmpSendOrderKeyVec; + unsigned tmpSendOrderKeyVecLength; + + MPI_Comm comm; + MPI_Request receiveRequest; + // MPI_Request sendRequest; + MPI_Request sendRequest[3]; + // MPI_Status sendStatus; + // MPI_Status receiveStatus; + MPI_Datatype mpiDataType; + + int mpiRemoteRank, mpiTag; + +#ifdef _DEBUG + T *orgPoolVectorStartPointer; +#endif +}; + +template <typename T> +typename TbCbVectorMpiPool<T>::MpiPoolPtrMap TbCbVectorMpiPool<T>::poolMap; + +////////////////////////////////////////////////////////////////////////// +// TbSenderMpiPool +////////////////////////////////////////////////////////////////////////// +template <typename T> +class TbCbVectorSenderMpiPool : public TbTransmitter<CbVector<T>> +{ +public: + using value_type = CbVector<T>; + +public: + TbCbVectorSenderMpiPool(std::string cbVectorKey, TbCbVectorMpiPool<T> *mpiVectorPool) : mpiVectorPool(mpiVectorPool) + { + this->getData().setAllocator(new CbVectorAllocatorPool<T>(cbVectorKey, this->mpiVectorPool)); + } + ~TbCbVectorSenderMpiPool() override + { + if (this->mpiVectorPool->getNofStoredVectors() == 1) // last entry! + { + TbCbVectorMpiPool<T>::deleteTbCbVectorMpiPool(this->mpiVectorPool->getPoolKey()); + } + } + + bool isLocalTransmitter() const override { return false; } + bool isRemoteTransmitter() const override { return !this->isLocalTransmitter(); } + + void sendDataSize() override { this->mpiVectorPool->sendDataOrder(); } + void receiveDataSize() override { throw UbException(UB_EXARGS, "TbMpiPoolSender sends only"); } + CbVector<T> &receiveData() override { throw UbException(UB_EXARGS, "TbMpiPoolSender sends only"); } + void prepareForSend() override { this->mpiVectorPool->prepareForSendData(); } + void sendData() override { this->mpiVectorPool->sendData(); } + + // info-section (usable for remote transmitter) + int getSendTbRank() const { return this->mpiVectorPool->getRemoteRank(); } + int getSendTbTag() const { return this->mpiVectorPool->getRemoteTag(); } + int getRecvFromRank() const override { throw UbException(UB_EXARGS, "TbCbVectorSenderMpiPool sends only"); } + int getRecvFromTag() const override { throw UbException(UB_EXARGS, "TbCbVectorSenderMpiPool sends only"); } + + std::string toString() const override + { + return "TbCbVectorSenderMpiPool<" + (std::string) typeid(T).name() + " to rank (tag)" + + UbSystem::toString(getSendTbRank()) + "(" + UbSystem::toString(getSendTbTag()) + ")"; + } + +protected: + TbCbVectorMpiPool<T> *mpiVectorPool; +}; + +/*==================================================================*/ +template <typename T> +class TbCbVectorReceiverMpiPool : public TbTransmitter<CbVector<T>> +{ +public: + using value_type = CbVector<T>; + +public: + TbCbVectorReceiverMpiPool(std::string cbVectorKey, TbCbVectorMpiPool<T> *mpiVectorPool) + : mpiVectorPool(mpiVectorPool) + { + this->getData().setAllocator(new CbVectorAllocatorPool<T>(cbVectorKey, this->mpiVectorPool)); + } + ~TbCbVectorReceiverMpiPool() override + { + if (this->mpiVectorPool->getNofStoredVectors() == 1) // last entry! + { + TbCbVectorMpiPool<T>::deleteTbCbVectorMpiPool(this->mpiVectorPool->getPoolKey()); + } + } + bool isLocalTransmitter() const override { return false; } + bool isRemoteTransmitter() const override { return !this->isLocalTransmitter(); } + + void sendDataSize() override { throw UbException(UB_EXARGS, "TbCbVectorReceiverMpiPool receives only"); } + void receiveDataSize() override { this->mpiVectorPool->receiveDataOrder(); } + void sendData() override { throw UbException(UB_EXARGS, "TbCbVectorReceiverMpiPool receives only"); } + void prepareForReceive() override { this->mpiVectorPool->prepareForReceiveData(); } + CbVector<T> &receiveData() override + { + this->mpiVectorPool->receiveData(); + return this->getData(); + } + + // info-section (usable for remote transmitter) + int getSendTbRank() const { throw UbException(UB_EXARGS, "TbCbVectorReceiverMpiPool receives only"); } + int getSendTbTag() const { throw UbException(UB_EXARGS, "TbCbVectorReceiverMpiPool receives only"); } + int getRecvFromRank() const override { return this->mpiVectorPool->getRemoteRank(); } + int getRecvFromTag() const override { return this->mpiVectorPool->getRemoteTag(); } + + std::string toString() const override + { + return "TbCbVectorReceiverMpiPool<" + (std::string) typeid(T).name() + " to rank (tag)" + + UbSystem::toString(getRecvFromRank()) + "(" + UbSystem::toString(getRecvFromTag()) + ")"; + } + +protected: + TbCbVectorMpiPool<T> *mpiVectorPool; +}; + +#endif // VF_MPI + +#endif // TBTRANSMITTERMPIPOOL_H diff --git a/src/basics/basics/utilities/UbFileInput.h b/src/basics/basics/utilities/UbFileInput.h new file mode 100644 index 0000000000000000000000000000000000000000..d1eac796f437a17b5519d12b096dc8b5d4263de4 --- /dev/null +++ b/src/basics/basics/utilities/UbFileInput.h @@ -0,0 +1,122 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file UbFileInput.h +//! \ingroup utilities +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#ifndef UBFILEINPUT_H +#define UBFILEINPUT_H + +#include <fstream> +#include <iostream> +#include <string> + +#include <cstdlib> //atoi +#include <cstring> //strstr + +#include <basics/utilities/UbException.h> + +/*=========================================================================*/ +/* UbFileInput */ +/* */ +/** +... +<BR><BR> +@author <A HREF="mailto:muffmolch@gmx.de">S. Freudiger</A> +@version 1.0 - 23.11.04 +*/ + +/* +usage: ... +*/ + +class UbFileInput +{ +public: + enum FILETYPE { ASCII, BINARY }; + +public: + UbFileInput() : filename("") {} + virtual ~UbFileInput() = default; + + virtual bool operator!() { return !(infile); } + virtual bool isOpen() { return !(!(infile)); } + + virtual bool open(std::string filename) = 0; + virtual void close() { infile.close(); } + virtual int eof() { return infile.eof(); } + + virtual void skipLine() = 0; // Springt zur naechsten Zeile + virtual void readLine() = 0; + virtual std::string readStringLine() = 0; + virtual int readInteger() = 0; // Liest einen Int-Wert ein + virtual std::size_t readSize_t() = 0; + virtual double readDouble() = 0; // Liest einen double-Wert ein + virtual float readFloat() = 0; // Liest einen float-Wert ein + virtual bool readBool() = 0; // Liest einen bool-Wert ein + virtual char readChar() = 0; // Liest einen char-Wert ein + virtual std::string readString() = 0; // Liest ein Wort ein + virtual std::string readLineTill(char stop) = 0; // Liest gesamte Zeile ein bis zu einem bestimmten Zeichen + virtual std::string parseString() = 0; // Liest + + virtual void setCommentIndicator(char commentindicator) { this->commentindicator = commentindicator; } + + virtual bool containsString(const std::string &var) = 0; + virtual void setPosAfterLineWithString(const std::string &var) = 0; + virtual int readIntegerAfterString(const std::string &var) = 0; + virtual double readDoubleAfterString(const std::string &var) = 0; + virtual bool readBoolAfterString(const std::string &var) = 0; + virtual std::string readStringAfterString(const std::string &var) = 0; + + virtual std::string getFileName() { return this->filename; } + + // returns file extension: + // e.g. "./../test/ich.inp" -> "inp", "./../test/ich" -> "" + virtual std::string getFileExtension() + { + std::size_t pos1 = filename.rfind("/"); + if (pos1 == std::string::npos) + pos1 = 0; + std::size_t pos2 = filename.rfind("."); + if (pos2 != std::string::npos && pos2 > pos1) + return filename.substr(pos2 + 1); + + return ""; + } + + // returns "ASCII", "BINARY" + virtual FILETYPE getFileType() = 0; + +protected: + std::ifstream infile; + std::string filename; + char commentindicator{ 'C' }; +}; + +#endif // UBFILEINPUT_H diff --git a/src/basics/basics/utilities/UbFileInputASCII.cpp b/src/basics/basics/utilities/UbFileInputASCII.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2d73804f4d06df62e38b0180b9fb0a244eb13887 --- /dev/null +++ b/src/basics/basics/utilities/UbFileInputASCII.cpp @@ -0,0 +1,293 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file UbFileInputASCII.cpp +//! \ingroup utilities +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#include <algorithm> +#include <basics/utilities/UbFileInputASCII.h> +#include <cstring> + +using namespace std; + +UbFileInputASCII::UbFileInputASCII(string filename) +{ + this->filename = filename; + this->commentindicator = 'C'; + + infile.open(filename.c_str()); + + // if(!infile) UB_THROW( UbException((string)("UbFileInputASCII::UbFileInputASCII(string filename, int how) couldn't + // open file:\n "+filename)) ); +} +/*==========================================================*/ +bool UbFileInputASCII::open(string filename) +{ + infile.close(); + infile.clear(); // setzt flags zurueck + + this->filename = filename; + infile.open(this->filename.c_str()); + + return infile.is_open(); +} +/*==========================================================*/ +int UbFileInputASCII::readInteger() +{ + int dummy; + infile >> dummy; + return dummy; +} +/*==========================================================*/ +long long UbFileInputASCII::readLongLong() +{ + long long dummy; + infile >> dummy; + return dummy; +} +/*==========================================================*/ +string UbFileInputASCII::getFileName() { return this->filename; } + +/*==========================================================*/ +void UbFileInputASCII::skipLine() +{ + string dummy; + getline(infile, dummy); +} +/*==========================================================*/ +void UbFileInputASCII::readLine() +{ + string dummy; + getline(infile, dummy); +} +/*==========================================================*/ +string UbFileInputASCII::readStringLine() +{ + string dummy; + getline(infile, dummy); + return dummy; +} +/*==========================================================*/ +string UbFileInputASCII::readLineTill(char stop) +{ + string dummy; + getline(infile, dummy, stop); + return dummy; +} +/*==========================================================*/ +string UbFileInputASCII::parseString() +{ + string dummy; + getline(infile, dummy, ' '); + return dummy; +} +/*==========================================================*/ +double UbFileInputASCII::readDouble() +{ + double dummy; + infile >> dummy; + return dummy; +} +/*==========================================================*/ +float UbFileInputASCII::readFloat() +{ + float dummy; + infile >> dummy; + return dummy; +} +/*==========================================================*/ +string UbFileInputASCII::readString() +{ + string dummy; + infile >> dummy; + return dummy; +} +/*==========================================================*/ +char UbFileInputASCII::readChar() +{ + int dummy; + infile >> dummy; + return (char)dummy; +} +/*==========================================================*/ +std::size_t UbFileInputASCII::readSize_t() +{ + std::size_t dummy; + infile >> dummy; + return dummy; +} +/*==========================================================*/ +void UbFileInputASCII::setPosAfterLineWithString(const string &var) +{ + infile.seekg(0L, ios::beg); // Positionszeiger der Datei auf den Anfang setzen + char line[512]; + do { + infile.getline(line, 512); + if (infile.eof()) + UB_THROW(UbException(UB_EXARGS, "error at reading in file \"" + filename + "\" -> string " + var + + " wasn't found in " + this->filename)); + } while (strstr(line, var.c_str()) != line); // Ende Schleife, wenn varname ganz in zeile vorkommt +} +/*==========================================================*/ +bool UbFileInputASCII::containsString(const string &var) +{ + infile.clear(); // setzt den EOF-Status zurueck (wird durch infile.seekg() NICHT getan!!!) + + infile.seekg(0L, ios::beg); // Positionszeiger der Datei auf den Anfang setzen + char line[512]; + do { + infile.getline(line, 512); + if (infile.eof()) + return false; + } while (strstr(line, var.c_str()) != line); // Ende Schleife, wenn varname ganz in zeile vorkommt + + return true; +} +/*==========================================================*/ +int UbFileInputASCII::readIntegerAfterString(const string &var) +// last change [29.6.2021] at [13:52] +// suchts in einer Datei nach varname und gibt den dahinter stehenden int-Wert zurueck +// z.B. timesteps 9 +{ + infile.clear(); // setzt den EOF-Status zurueck (wird durch infile.seekg() NICHT getan!!!) + + infile.seekg(0L, ios::beg); // Positionszeiger der Datei auf den Anfang setzen + + char line[512]; + do { + infile.getline(line, 512); + + if (infile.eof()) + UB_THROW(UbException(UB_EXARGS, "error at reading in file \"" + filename + "\" -> " + var + + " wasn't found in " + this->filename)); + } while (strstr(line, var.c_str()) != line); // Ende Schleife, wenn varname ganz in zeile vorkommt + + std::string temp{ line }; + temp = temp.substr(var.size()); // zeile um "varname" kuerzen + + temp.erase(std::remove(temp.begin(), temp.end(), ' '), temp.end()); // remove whitespace + temp.erase(std::remove(temp.begin(), temp.end(), '\t'), temp.end()); // remove tabs + + return std::stoi(temp); +} +/*==========================================================*/ +// last change [29.6.2021] at [13:52] +// sucht in einer Datei nach varname und gibt den dahinter stehenden int-Wert zurueck +// z.B. nue 9.5 +double UbFileInputASCII::readDoubleAfterString(const string &var) +{ + infile.clear(); // setzt den EOF-Status zurueck (wird durch infile.seekg() NICHT getan!!!) + + infile.seekg(0L, ios::beg); // Positionszeiger der Datei auf den Anfang setzen + + char line[512]; + + do { + infile.getline(line, 512); + if (infile.eof()) + UB_THROW(UbException(UB_EXARGS, "error at reading in file \"" + filename + "\" -> " + var + + " wasn't found in " + this->filename)); + } while (/*!strncmp(varname,line,sizeof(varname))==0*/ strstr(line, var.c_str()) != + line); // Ende Schleife, wenn varname ganz in zeile vorkommt + + std::string temp{ line }; + temp = temp.substr(var.size()); // zeile um "varname" kuerzen + + temp.erase(std::remove(temp.begin(), temp.end(), ' '), temp.end()); // remove whitespace + temp.erase(std::remove(temp.begin(), temp.end(), '\t'), temp.end()); // remove tabs + + return std::stod(temp); +} +/*==========================================================*/ +// last change [29.6.2021] at [13:52] +// liefert string-Wert der hinter dem uebergebenen char feld in der datei infile steht +// zudem wird der wert in die uebergebene variable value uebertragen (falls man das ergebniss als char benoetig) +string UbFileInputASCII::readStringAfterString(const string &var) //,char *value) +{ + infile.clear(); // setzt den EOF-Status zurueck (wird durch infile.seekg() NICHT getan!!!) + + infile.seekg(0L, ios::beg); // Positionszeiger der Datei auf den Anfang setzen + + char line[512]; + // string line_copy[512]; + do { + infile.getline(line, 512); + if (infile.eof()) + UB_THROW(UbException(UB_EXARGS, "error at reading in file \"" + filename + "\" -> " + var + + " wasn't found in " + this->filename)); + } while (strstr(line, var.c_str()) != line); // Ende Schleife, wenn varname ganz in zeile vorkommt + + // std::string lineRead; + // while(getline(infile, lineRead)) + // { + // if(lineRead.find(toSearch, 0) < lineRead.length()) + // { + // occurenceNumber++; + // cout << counter << ":" << lineRead << endl; + + // } + // } + + std::string temp{ line }; + temp = temp.substr(var.size()); // zeile um "varname" kuerzen + + temp.erase(std::remove(temp.begin(), temp.end(), ' '), temp.end()); // remove whitespace + temp.erase(std::remove(temp.begin(), temp.end(), '\t'), temp.end()); // remove tabs + + return temp; +} +/*==========================================================*/ +// last change [10.3.2004] at [9:46] +// sucht in einer Datei nach varname und gibt den dahinter stehenden int-Wert zurueck +// z.B. nue 9.5 +bool UbFileInputASCII::readBoolAfterString(const string &var) +{ + if (this->readStringAfterString(var) == "true") + return true; + else if (this->readStringAfterString(var) == "false") + return false; + else + UB_THROW(UbException(UB_EXARGS, "error at reading in file \"" + filename + "\" -> expression after " + var + + " is not equal to 'true' or 'false' in " + this->filename)); +} +/*==========================================================*/ +// last change [10.3.2004] at [9:46] +// sucht in einer Datei nach varname und gibt den dahinter stehenden int-Wert zurueck +// z.B. nue 9.5 +bool UbFileInputASCII::readBool() +{ + string tmp = this->readString(); + if (tmp == "true") + return true; + else if (tmp == "false") + return false; + else + UB_THROW(UbException(UB_EXARGS, "error at reading in file \"" + filename + "\" -> expression=\"" + tmp + + "\" is not equal to 'true' or 'false' in " + this->filename)); +} diff --git a/src/basics/basics/utilities/UbFileInputASCII.h b/src/basics/basics/utilities/UbFileInputASCII.h new file mode 100644 index 0000000000000000000000000000000000000000..a86955bca511f194f5936a81dd9a542026f88f67 --- /dev/null +++ b/src/basics/basics/utilities/UbFileInputASCII.h @@ -0,0 +1,101 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file UbFileInputASCII.h +//! \ingroup utilities +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#ifndef UBFILEINPUTASCII_H +#define UBFILEINPUTASCII_H + +#include <fstream> +#include <iostream> +#include <string> + +#include "basics_export.h" + +#include <basics/utilities/UbException.h> +#include <basics/utilities/UbFileInput.h> + +/*=========================================================================*/ +/* UbFileInputASCII */ +/* */ +/** +... +<BR><BR> +@author <A HREF="mailto:muffmolch@gmx.de">S. Freudiger</A> +@version 1.0 - 23.11.04 +*/ + +/* +usage: ... +*/ + +class BASICS_EXPORT UbFileInputASCII : public UbFileInput +{ +public: + UbFileInputASCII() : UbFileInput() {} + UbFileInputASCII(std::string filename); + + bool open(std::string filename) override; + + std::string getFileName() override; + void skipLine() override; // Springt zur naechsten Zeile + + void readLine() override; + std::string readStringLine() override; + int readInteger() override; // Liest einen Int-Wert ein + long long readLongLong(); // Liest einen long-Wert ein + + std::size_t readSize_t() override; + double readDouble() override; // Liest einen double-Wert ein + float readFloat() override; // Liest einen float-Wert ein + bool readBool() override; // Liest einen bool-Wert ein + char readChar() override; // Liest einen char-Wert ein + std::string readString() override; // Liest ein Wort ein + std::string readLineTill(char stop) override; // Liest gesamte Zeile ein bis zu einem bestimmten Zeichen + std::string parseString() override; + + bool containsString(const std::string &var) override; + void setPosAfterLineWithString(const std::string &var) override; + int readIntegerAfterString(const std::string &var) override; + double readDoubleAfterString(const std::string &var) override; + bool readBoolAfterString(const std::string &var) override; + std::string readStringAfterString(const std::string &var) override; + + FILETYPE getFileType() override { return ASCII; } + + template <typename T> + friend inline UbFileInputASCII &operator>>(UbFileInputASCII &file, T &data) + { + file.infile >> data; + return file; + } +}; + +#endif // UBFILEINPUTASCII_H diff --git a/src/basics/basics/utilities/UbFileInputASCIITest.cfg b/src/basics/basics/utilities/UbFileInputASCIITest.cfg new file mode 100644 index 0000000000000000000000000000000000000000..294d58cd2eae2819366e4f9cb2e49195e4fd518a --- /dev/null +++ b/src/basics/basics/utilities/UbFileInputASCIITest.cfg @@ -0,0 +1 @@ +test = 1 diff --git a/src/basics/basics/utilities/UbFileInputASCIITest.cpp b/src/basics/basics/utilities/UbFileInputASCIITest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f22c385841d3b516d93650b505a0bf93c9ae85a6 --- /dev/null +++ b/src/basics/basics/utilities/UbFileInputASCIITest.cpp @@ -0,0 +1,18 @@ +#include <gmock/gmock.h> +#include <filesystem> + +#include <basics/utilities/UbFileInputASCII.h> + + +TEST(DISABLED_UbFileInputASCIITest, readIntegerAfterString) +{ + // assuming that the config files is stored parallel to this file. + std::filesystem::path filePath = __FILE__; + filePath.replace_filename("UbFileInputASCIITest.cfg"); + + UbFileInputASCII sut {filePath.string()}; + + const int actual = sut.readIntegerAfterString("test ="); + + EXPECT_THAT(actual, testing::Eq(1)); +} diff --git a/src/basics/basics/utilities/UbFileInputBinary.cpp b/src/basics/basics/utilities/UbFileInputBinary.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b77327f6d8c195f93ba34510a3b691e6cd6c52b2 --- /dev/null +++ b/src/basics/basics/utilities/UbFileInputBinary.cpp @@ -0,0 +1,182 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file UbFileInputBinary.cpp +//! \ingroup utilities +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#include <basics/utilities/UbFileInputBinary.h> +#include <cstring> + +using namespace std; + +/*==========================================================*/ +UbFileInputBinary::UbFileInputBinary(string filename) +{ + this->filename = filename; + infile.open(filename.c_str(), ios::in | ios::binary); +} +/*==========================================================*/ +bool UbFileInputBinary::open(string filename) +{ + infile.close(); + infile.clear(); // setzt flags zurueck + + this->filename = filename; + infile.open(this->filename.c_str(), ios::in | ios::binary); + + return infile.is_open(); +} +/*==========================================================*/ +int UbFileInputBinary::readInteger() +{ + int dummy; + infile.read((char *)&dummy, sizeof(int)); + return dummy; +} +/*==========================================================*/ +std::size_t UbFileInputBinary::readSize_t() +{ + std::size_t dummy; + infile.read((char *)&dummy, sizeof(std::size_t)); + return dummy; +} +/*==========================================================*/ +double UbFileInputBinary::readDouble() +{ + double dummy; + infile.read((char *)&dummy, sizeof(double)); + return dummy; +} +/*==========================================================*/ +float UbFileInputBinary::readFloat() +{ + float dummy; + infile.read((char *)&dummy, sizeof(float)); + return dummy; +} +/*==========================================================*/ +char UbFileInputBinary::readChar() +{ + char dummy; + infile.read((char *)&dummy, sizeof(char)); + return dummy; +} +/*==========================================================*/ +string UbFileInputBinary::readString() +{ + char c; + infile.read(&c, sizeof(char)); + while (c == ' ' || c == '\t') + infile.read(&c, sizeof(char)); + + string dummy; + dummy += c; + + infile.read(&c, sizeof(char)); + while (c != '\0' && c != ' ' && c != '\t' && c != '\n') { + dummy += c; + infile.read(&c, sizeof(char)); + } + return dummy; +} +/*==========================================================*/ +bool UbFileInputBinary::readBool() +{ + bool dummy; + infile.read((char *)&dummy, sizeof(bool)); + return dummy; +} +/*==========================================================*/ +void UbFileInputBinary::skipLine() +{ + char c; + do { + infile.read(&c, sizeof(char)); + } while (c != '\n'); +} +/*==========================================================*/ +void UbFileInputBinary::readLine() +{ + char c; + infile.read(&c, sizeof(char)); + while (c != '\n') + infile.read(&c, sizeof(char)); +} +/*==========================================================*/ +string UbFileInputBinary::readStringLine() +{ + char c; + string dummy; + infile.read(&c, sizeof(char)); + while (c != '\n') { + dummy += c; + infile.read(&c, sizeof(char)); + } + return dummy; +} +/*==========================================================*/ +string UbFileInputBinary::readLineTill(char /*stop*/) +{ + UB_THROW(UbException(UB_EXARGS, "method makes no sense for binary streams")); +} +/*==========================================================*/ +string UbFileInputBinary::parseString() +{ + UB_THROW(UbException(UB_EXARGS, "method makes no sense for binary streams")); +} +/*==========================================================*/ +bool UbFileInputBinary::containsString(const string & /*var*/) +{ + UB_THROW(UbException(UB_EXARGS, "method makes no sense for binary streams")); +} +/*==========================================================*/ +void UbFileInputBinary::setPosAfterLineWithString(const string & /*var*/) +{ + UB_THROW(UbException(UB_EXARGS, "method makes no sense for binary streams")); +} +/*==========================================================*/ +int UbFileInputBinary::readIntegerAfterString(const string & /*var*/) +{ + UB_THROW(UbException(UB_EXARGS, "method makes no sense for binary streams")); +} +/*==========================================================*/ +double UbFileInputBinary::readDoubleAfterString(const string & /*var*/) +{ + UB_THROW(UbException(UB_EXARGS, "method makes no sense for binary streams")); +} +/*==========================================================*/ +string UbFileInputBinary::readStringAfterString(const string & /*var*/) +{ + UB_THROW(UbException(UB_EXARGS, "method makes no sense for binary streams")); +} +/*==========================================================*/ +bool UbFileInputBinary::readBoolAfterString(const string & /*var*/) +{ + UB_THROW(UbException(UB_EXARGS, "method makes no sense for binary streams")); +} diff --git a/src/basics/basics/utilities/UbFileInputBinary.h b/src/basics/basics/utilities/UbFileInputBinary.h new file mode 100644 index 0000000000000000000000000000000000000000..9e477c3a24df2c78b5696688354d5dcba747d486 --- /dev/null +++ b/src/basics/basics/utilities/UbFileInputBinary.h @@ -0,0 +1,104 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file UbFileInputBinary.h +//! \ingroup utilities +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#ifndef UBFILEINPUTBINARY_H +#define UBFILEINPUTBINARY_H + +#include <fstream> +#include <iostream> +#include <string> + +#include <basics/utilities/UbException.h> +#include <basics/utilities/UbFileInput.h> + +/*=========================================================================*/ +/* UbFileInputBinary */ +/* */ +/** +... +<BR><BR> +@author <A HREF="mailto:muffmolch@gmx.de">S. Freudiger</A> +@version 1.0 - 23.11.04 +*/ + +/* +usage: ... +*/ + +class UbFileInputBinary : public UbFileInput +{ +public: + UbFileInputBinary() : UbFileInput() {} + UbFileInputBinary(std::string filename); + + bool open(std::string filename) override; + + void skipLine() override; // Springt zur naechsten Zeile + void readLine() override; + std::string readStringLine() override; + std::size_t readSize_t() override; + int readInteger() override; // Liest einen Int-Wert ein + double readDouble() override; // Liest einen double-Wert ein + float readFloat() override; // Liest einen float-Wert ein + bool readBool() override; // Liest einen bool-Wert ein + char readChar() override; // Liest einen char-Wert ein + std::string readString() override; // Liest ein Wort ein + std::string readLineTill(char stop) override; // Liest gesamte Zeile ein bis zu einem bestimmten Zeichen + std::string parseString() override; // Liest + + bool containsString(const std::string &var) override; + void setPosAfterLineWithString(const std::string &var) override; + int readIntegerAfterString(const std::string &var) override; + double readDoubleAfterString(const std::string &var) override; + bool readBoolAfterString(const std::string &var) override; + std::string readStringAfterString(const std::string &var) override; + + FILETYPE getFileType() override { return BINARY; } + + template <typename T> + friend inline UbFileInputBinary &operator>>(UbFileInputBinary &file, T &data) + { + file.infile.read((char *)&data, sizeof(T)); + return file; + } + + template <typename T> + void readVector(std::vector<T> &v) + { + size_t size = v.size(); + if (size > 0) { + infile.read((char *)&v[0], sizeof(T) * size); + } + } +}; + +#endif diff --git a/src/basics/basics/utilities/UbFileOutput.h b/src/basics/basics/utilities/UbFileOutput.h new file mode 100644 index 0000000000000000000000000000000000000000..877b96fc5c6a1d31ee7f6e724df134dd42373760 --- /dev/null +++ b/src/basics/basics/utilities/UbFileOutput.h @@ -0,0 +1,121 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file UbFileOutput.h +//! \ingroup utilities +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#ifndef UBFILEOUTPUT_H +#define UBFILEOUTPUT_H + +#include <fstream> +#include <iomanip> +#include <iostream> +#include <string> + +#include <basics/utilities/UbException.h> + +/*=========================================================================*/ +/* UbFileOutput */ +/* */ +/** +... +<BR><BR> +@author <A HREF="mailto:muffmolch@gmx.de">S. Freudiger</A> +@version 1.0 - 23.11.04 +*/ + +/* +usage: ... +*/ + +class UbFileOutput +{ +public: + enum CREATEOPTION { OUTFILE = 0, INANDOUTFILE = 1, APPENDFILE = 2 }; + enum FILETYPE { ASCII, BINARY }; + +public: + UbFileOutput() : filename("") {} + UbFileOutput(const std::string &filename) : filename(filename) {} + virtual ~UbFileOutput() { outfile.flush(); } + + virtual bool open(const std::string &filename, CREATEOPTION opt = OUTFILE) = 0; + + virtual bool operator!() { return !(outfile); } + virtual bool isOpen() { return !(!(outfile)); } + + virtual void flush() { outfile.flush(); } + virtual void close() { outfile.close(); } + + virtual void writeInteger(const int &value, const int &width = 0) = 0; + virtual void writeDouble(const double &value, const int &width = 0) = 0; + virtual void writeFloat(const float &value, const int &width = 0) = 0; + virtual void writeBool(const bool &value, const int &width = 0) = 0; + virtual void writeSize_t(const std::size_t &value, const int &width = 0) = 0; + virtual void writeChar(const char &value, const int &width = 0) = 0; + virtual void writeString(const std::string &value, const int &width = 0) = 0; + virtual void writeStringOnly(const std::string &value) = 0; + virtual void writeLine(const std::string &value, const int &width = 0) = 0; + virtual void writeLine() = 0; + + virtual void writeCommentLine(const std::string &line) = 0; + virtual void writeCommentLine(char indicator, const std::string &line) = 0; + virtual void writeCopyOfFile(const std::string &filename) = 0; + + virtual void setCommentIndicator(char commentindicator) { this->commentindicator = commentindicator; } + + virtual void setPrecision(const int &precision) = 0; + virtual int getPrecision() = 0; + + // returns "ASCII", "BINARY" + virtual FILETYPE getFileType() = 0; + + // returns file extension: + // e.g. "./../test/ich.inp" -> "inp", "./../test/ich" -> "" + virtual std::string getFileExtension() + { + std::size_t pos1 = filename.rfind("/"); + if (pos1 == std::string::npos) + pos1 = 0; + std::size_t pos2 = filename.rfind("."); + if (pos2 != std::string::npos && pos2 > pos1) + return filename.substr(pos2 + 1); + + return ""; + } + + virtual std::string getFileName() { return this->filename; } + +protected: + std::ofstream outfile; + std::string filename; + char commentindicator{ 'C' }; +}; + +#endif // UBFILEOUTPUT_H diff --git a/src/basics/basics/utilities/UbFileOutputASCII.cpp b/src/basics/basics/utilities/UbFileOutputASCII.cpp new file mode 100644 index 0000000000000000000000000000000000000000..56edaf919a9d3f058fff9f5d74e646679f5010f0 --- /dev/null +++ b/src/basics/basics/utilities/UbFileOutputASCII.cpp @@ -0,0 +1,203 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file UbFileOutputASCII.cpp +//! \ingroup utilities +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#include <basics/utilities/UbFileOutputASCII.h> +#include <basics/utilities/UbInfinity.h> +#include <basics/utilities/UbMath.h> +#include <basics/utilities/UbSystem.h> +#include <cstring> + +using namespace std; + +UbFileOutputASCII::UbFileOutputASCII(const string &filename, const bool &createPath, const int & /*precision*/) + : UbFileOutput(filename) +{ + this->commentindicator = 'C'; + this->setPrecision(20); + + outfile.open(filename.c_str(), ios::out); + + if (!outfile && createPath) { + outfile.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!! + string path = UbSystem::getPathFromString(filename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + outfile.open(filename.c_str(), ios::out); + } + } + + if (!outfile) + UB_THROW(UbException(UB_EXARGS, "couldn't open file:\n " + filename)); +} +/*==========================================================*/ +UbFileOutputASCII::UbFileOutputASCII(const std::string &filename, CREATEOPTION opt, const bool &createPath, + const int &precision) + : UbFileOutput(filename) +{ + this->commentindicator = 'C'; + this->setPrecision(precision); + + if (!this->open(filename, opt) && createPath) { + outfile.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!! + string path = UbSystem::getPathFromString(filename); + if (path.size() > 0) + UbSystem::makeDirectory(path); + + this->open(filename, opt); + } + + if (!outfile) + UB_THROW(UbException(UB_EXARGS, "couldn't open file:\n " + filename)); +} +/*==========================================================*/ +bool UbFileOutputASCII::open(const std::string &filename, CREATEOPTION opt) +{ + outfile.close(); + outfile.clear(); // setzt flags zurueck + this->filename = filename; + + if (opt == UbFileOutput::OUTFILE) + outfile.open(this->filename.c_str(), ios::out); + else if (opt == UbFileOutput::INANDOUTFILE) + outfile.open(this->filename.c_str(), ios::out | ios::in); + else if (opt == UbFileOutput::APPENDFILE) + outfile.open(this->filename.c_str(), ios::app); + else + UB_THROW(UbException(UB_EXARGS, "undefined CREATEOPTION")); + + return outfile.is_open(); +} +/*==========================================================*/ +void UbFileOutputASCII::writeBool(const bool &value, const int &width) +{ + outfile.width(width); + if (value) + outfile << "true "; + else + outfile << "false "; +} +/*==========================================================*/ +void UbFileOutputASCII::writeDouble(const double &value, const int &width) +{ + outfile.width(width); + // Problem: Ub::inf wird gerundet + // -> beim Einlesen ist der Wert evtl zu gross und es kommt murks raus + // -> max Laenge darstellen und gut ist + if (UbMath::equal(value, (double)Ub::inf)) { + ios_base::fmtflags flags = outfile.flags(); + outfile << setprecision(std::numeric_limits<double>::digits10 + 2); + outfile << value << " "; + outfile.flags(flags); + return; + } + outfile << value << " "; +} +/*==========================================================*/ +void UbFileOutputASCII::writeFloat(const float &value, const int &width) +{ + outfile.width(width); + // Problem: Ub::inf wird gerundet + // -> beim Einlesen ist der Wert evtl zu gross und es kommt murks raus + // -> max Laenge darstellen und gut ist + if (UbMath::equal(value, (float)Ub::inf)) { + ios_base::fmtflags flags = outfile.flags(); + outfile << setprecision(std::numeric_limits<float>::digits10 + 2); + outfile << value << " "; + outfile.flags(flags); + return; + } + outfile << value << " "; +} +/*==========================================================*/ +void UbFileOutputASCII::setPrecision(const int &precision) { outfile << setprecision(precision); } +/*==========================================================*/ +void UbFileOutputASCII::writeInteger(const int &value, const int &width) +{ + outfile.width(width); + outfile << value << " "; +} +/*==========================================================*/ +void UbFileOutputASCII::writeSize_t(const std::size_t &value, const int &width) +{ + outfile.width(width); + outfile << value << " "; +} +/*==========================================================*/ +void UbFileOutputASCII::writeChar(const char &value, const int &width) +{ + outfile.width(width); + outfile << (int)value << " "; +} +/*==========================================================*/ +void UbFileOutputASCII::writeString(const string &value, const int &width) +{ + outfile.width(width); + outfile << value.c_str() << " "; +} +/*==========================================================*/ +void UbFileOutputASCII::writeStringOnly(const string &value) { outfile << value.c_str(); } + +/*==========================================================*/ +void UbFileOutputASCII::writeLine(const string &value, const int &width) +{ + outfile.width(width); + outfile << value.c_str() << endl; +} +/*==========================================================*/ +void UbFileOutputASCII::writeLine() { outfile << endl; } +/*==========================================================*/ +void UbFileOutputASCII::writeCommentLine(const string &line) { this->writeCommentLine(this->commentindicator, line); } +/*==========================================================*/ +void UbFileOutputASCII::writeCommentLine(char indicator, const string &line) +{ + this->outfile << indicator << line << endl; +} +/*==========================================================*/ +void UbFileOutputASCII::writeCopyOfFile(const string &filename) +{ + ifstream infile(filename.c_str()); + if (!infile) + UB_THROW(UbException(UB_EXARGS, "couldn't open file:\n " + filename)); + + try { + char c; + while (infile.get(c)) { + outfile.put(c); //=out<<c; + } + outfile.flush(); + infile.close(); + } catch (std::exception &e) { + UB_THROW(UbException(UB_EXARGS, "catched std::exception, error: " + (std::string)e.what())); + } catch (...) { + UB_THROW(UbException(UB_EXARGS, "unknown error")); + } +} diff --git a/src/basics/basics/utilities/UbFileOutputASCII.h b/src/basics/basics/utilities/UbFileOutputASCII.h new file mode 100644 index 0000000000000000000000000000000000000000..24efd507a0b94266cd95e6b3113cef5bf498b076 --- /dev/null +++ b/src/basics/basics/utilities/UbFileOutputASCII.h @@ -0,0 +1,99 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file UbFileOutputASCII.h +//! \ingroup utilities +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#ifndef UBFILEOUTPUTASCII_H +#define UBFILEOUTPUTASCII_H + +#include <fstream> +#include <iomanip> +#include <iostream> + +#include "basics_export.h" + +#include <basics/utilities/UbException.h> +#include <basics/utilities/UbFileOutput.h> + +/*=========================================================================*/ +/* UbFileOutputASCII */ +/* */ +/** +... +<BR><BR> +@author <A HREF="mailto:muffmolch@gmx.de">S. Freudiger</A> +@version 1.0 - 23.11.04 +*/ + +/* +usage: ... +*/ + +class BASICS_EXPORT UbFileOutputASCII : public UbFileOutput +{ +public: + UbFileOutputASCII() : UbFileOutput() {} + UbFileOutputASCII(const std::string &filename, const bool &createPath = true, const int &precision = 15); + UbFileOutputASCII(const std::string &filename, CREATEOPTION opt, const bool &createPath = true, + const int &precision = 15); + + bool open(const std::string &filename, CREATEOPTION opt = OUTFILE) override; + + void writeBool(const bool &value, const int &width = 0) override; + void writeDouble(const double &value, const int &width = 0) override; + void writeFloat(const float &value, const int &width = 0) override; + void writeInteger(const int &value, const int &width = 0) override; + void writeSize_t(const std::size_t &value, const int &width = 0) override; + void writeChar(const char &value, const int &width = 0) override; + void writeString(const std::string &value, const int &width = 0) override; + void writeStringOnly(const std::string &value) override; + void writeLine(const std::string &value, const int &width = 0) override; + void writeLine() override; + + void setPrecision(const int &precision) override; + int getPrecision() override { return (int)outfile.precision(); } + + void setCommentIndicator(char commentindicator) override { this->commentindicator = commentindicator; } + + void writeCommentLine(const std::string &line) override; + void writeCommentLine(char indicator, const std::string &line) override; + void writeCopyOfFile(const std::string &filename) override; + + FILETYPE getFileType() override { return ASCII; } + + template <typename T> + friend inline UbFileOutputASCII &operator<<(UbFileOutputASCII &file, const T &data) + { + file.outfile << data; + return file; + } +}; + +#endif diff --git a/src/basics/basics/utilities/UbFileOutputBinary.cpp b/src/basics/basics/utilities/UbFileOutputBinary.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ce9fca58f7eddd8d0ec3cc4a7d0ecf48fb2f4691 --- /dev/null +++ b/src/basics/basics/utilities/UbFileOutputBinary.cpp @@ -0,0 +1,208 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file UbFileOutputBinary.cpp +//! \ingroup utilities +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#include <basics/utilities/UbFileOutputBinary.h> +#include <basics/utilities/UbSystem.h> +#include <cstring> + +using namespace std; + +/*==========================================================*/ +UbFileOutputBinary::UbFileOutputBinary(const string &filename, const bool &createPath) +{ + this->filename = filename; + this->commentindicator = 'C'; + + outfile.open(filename.c_str(), ios::out | ios::binary); + + if (!outfile && createPath) { + string path = UbSystem::getPathFromString(filename); + if (path.size() > 0) { + outfile.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!! + UbSystem::makeDirectory(path); + outfile.open(filename.c_str(), ios::out | ios::binary); + } + } + + if (!outfile) + UB_THROW(UbException(UB_EXARGS, "couldn't open file:\n " + filename)); +} +/*==========================================================*/ +UbFileOutputBinary::UbFileOutputBinary(const string &filename, UbFileOutput::CREATEOPTION opt, const bool &createPath) +{ + this->filename = filename; + this->commentindicator = 'C'; + + this->open(filename, opt); + + if (!this->open(filename, opt) && createPath) { + string path = UbSystem::getPathFromString(filename); + if (path.size() > 0) { + outfile.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!! + UbSystem::makeDirectory(path, 20); + + this->open(filename, opt); + } + } + + if (!outfile) + UB_THROW(UbException(UB_EXARGS, "couldn't open file:\n " + filename)); +} +/*==========================================================*/ +bool UbFileOutputBinary::open(const string &filename, UbFileOutput::CREATEOPTION opt) +{ + outfile.close(); + outfile.clear(); // setzt flags zurueck + + this->filename = filename; + + if (opt == UbFileOutput::OUTFILE) + outfile.open(this->filename.c_str(), ios::out | ios::binary); + else if (opt == UbFileOutput::APPENDFILE) + outfile.open(this->filename.c_str(), ios::app | ios::binary); + else if (opt == UbFileOutput::INANDOUTFILE) + UB_THROW(UbException(UB_EXARGS, "undefined CREATEOPTION - INANDOUTFILE not possible for BINARY files")); + else + UB_THROW(UbException(UB_EXARGS, "undefined CREATEOPTION")); + + return outfile.is_open(); +} +/*==========================================================*/ +void UbFileOutputBinary::writeBool(const bool &value, const int & /*width*/) +{ + outfile.write((char *)&value, sizeof(bool)); +} +/*==========================================================*/ +void UbFileOutputBinary::writeDouble(const double &value, const int & /*width*/) +{ + outfile.write((char *)&value, sizeof(double)); +} +/*==========================================================*/ +void UbFileOutputBinary::writeFloat(const float &value, const int & /*width*/) +{ + outfile.write((char *)&value, sizeof(float)); +} +/*==========================================================*/ +void UbFileOutputBinary::setPrecision(const int & /*precision*/) { UB_THROW(UbException(UB_EXARGS, "no way")); } +/*==========================================================*/ +int UbFileOutputBinary::getPrecision() { UB_THROW(UbException(UB_EXARGS, "no way")); } +/*==========================================================*/ +void UbFileOutputBinary::writeInteger(const int &value, const int & /*width*/) +{ + outfile.write((char *)&value, sizeof(value)); +} +/*==========================================================*/ +void UbFileOutputBinary::writeSize_t(const std::size_t &value, const int & /*width*/) +{ + outfile.write((char *)&value, sizeof(value)); +} +/*==========================================================*/ +void UbFileOutputBinary::writeChar(const char &value, const int & /*width*/) +{ + outfile.write((char *)&value, sizeof(value)); +} +/*==========================================================*/ +void UbFileOutputBinary::writeString(const string &value, const int & /*width*/) +{ + char c = '\0'; + unsigned int length = (unsigned)value.length(); + + unsigned pos; + // whitespaces und tabs am stringanfang uebergehen + for (pos = 0; pos < length; pos++) + if (value[pos] != ' ' && value[pos] != '\t') + break; + + while (pos < length) { + while (pos < length && value[pos] != ' ' && value[pos] != '\t' && value[pos] != '\0') { + outfile.write((char *)&(value[pos++]), sizeof(char)); + } + + outfile.write(&c, sizeof(char)); + pos++; + + while (pos < length && (value[pos] == ' ' || value[pos] == '\t' || value[pos] == '\0')) { + pos++; + } + } +} +/*==========================================================*/ +void UbFileOutputBinary::writeStringOnly(const string & /*value*/) +{ + throw UbException(UB_EXARGS, "no way... causes to many errors"); // TODO: WTF? +} +/*==========================================================*/ +void UbFileOutputBinary::writeLine(const std::string &value, const int & /*width*/) +{ + this->writeString(value); + char c = '\n'; + outfile.write(&c, sizeof(char)); +} +/*==========================================================*/ +void UbFileOutputBinary::writeLine() +{ + char c = '\n'; + outfile.write(&c, sizeof(char)); +} +/*==========================================================*/ +void UbFileOutputBinary::writeCommentLine(const string &line) +{ + try { + this->writeCommentLine(this->commentindicator, line); + } catch (...) { + UB_THROW(UbException(UB_EXARGS, "unknown error")); + } +} +/*==========================================================*/ +void UbFileOutputBinary::writeCommentLine(char indicator, const string &line) +{ + string dummy = indicator + line; + this->writeLine(dummy); +} +/*==========================================================*/ +void UbFileOutputBinary::writeCopyOfFile(const string &filename) +{ + ifstream infile(filename.c_str(), ios::in | ios::binary); + if (!infile) + UB_THROW(UbException(UB_EXARGS, "couldn't open file:\n " + filename)); + + try { + char c; + while (infile.get(c)) { + outfile.put(c); //=out<<c; + } + outfile.flush(); + infile.close(); + } catch (...) { + UB_THROW(UbException(UB_EXARGS, "unknown error")); + } +} diff --git a/src/basics/basics/utilities/UbFileOutputBinary.h b/src/basics/basics/utilities/UbFileOutputBinary.h new file mode 100644 index 0000000000000000000000000000000000000000..630df58b8a3ed47d9a3e8adc033db282ce5e80ef --- /dev/null +++ b/src/basics/basics/utilities/UbFileOutputBinary.h @@ -0,0 +1,102 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file UbFileOutputBinary.h +//! \ingroup utilities +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#ifndef UBFILEOUTPUTBINARY_H +#define UBFILEOUTPUTBINARY_H + +#include <fstream> +#include <iomanip> +#include <iostream> + +#include <basics/utilities/UbException.h> +#include <basics/utilities/UbFileOutput.h> + +/*=========================================================================*/ +/* UbFileOutputBinary */ +/* */ +/** +... +<BR><BR> +@author <A HREF="mailto:muffmolch@gmx.de">S. Freudiger</A> +@version 1.0 - 23.11.04 +*/ + +/* +usage: ... +*/ + +class UbFileOutputBinary : public UbFileOutput +{ +public: + UbFileOutputBinary() : UbFileOutput() {} + UbFileOutputBinary(const std::string &filename, const bool &createPath = true); + UbFileOutputBinary(const std::string &filename, UbFileOutput::CREATEOPTION opt, const bool &createPath); + + bool open(const std::string &filename, UbFileOutput::CREATEOPTION opt = OUTFILE) override; + + void writeInteger(const int &value, const int &width = 0) override; + void writeDouble(const double &value, const int &width = 0) override; + void writeFloat(const float &value, const int &width = 0) override; + void writeBool(const bool &value, const int &width = 0) override; + void writeChar(const char &value, const int &width = 0) override; + void writeSize_t(const std::size_t &value, const int &width = 0) override; + void writeString(const std::string &value, const int &width = 0) override; + void writeStringOnly(const std::string &value) override; + void writeLine(const std::string &value, const int &width = 0) override; + void writeLine() override; + void writeCommentLine(const std::string &line) override; + void writeCommentLine(char indicator, const std::string &line) override; + void writeCopyOfFile(const std::string &filename) override; + + void setPrecision(const int &precision) override; + int getPrecision() override; + + FILETYPE getFileType() override { return BINARY; } + + template <typename T> + friend inline UbFileOutputBinary &operator<<(UbFileOutputBinary &file, const T &data) + { + file.outfile.write((char *)&data, sizeof(T)); + return file; + } + + template <typename T> + void writeVector(std::vector<T> &v) + { + size_t size = v.size(); + if (size > 0) { + outfile.write((char *)&v[0], sizeof(T) * size); + } + } +}; + +#endif diff --git a/src/basics/basics/utilities/UbNupsTimer.h b/src/basics/basics/utilities/UbNupsTimer.h new file mode 100644 index 0000000000000000000000000000000000000000..1545b5b694a57d112b485cf766ce26e22f30d939 --- /dev/null +++ b/src/basics/basics/utilities/UbNupsTimer.h @@ -0,0 +1,125 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file UbNupsTimer.h +//! \ingroup utilities +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#ifndef UBNUPSTIMER_H +#define UBNUPSTIMER_H + +#include <basics/utilities/UbTiming.h> +#include <sstream> +#include <vector> + +/*=========================================================================*/ +/* UbNupsTimer */ +/* */ +/** +This Class provides the base for ... +<BR><BR> +@author <A HREF="mailto:muffmolch@gmx.de">S. Freudiger</A> +@version 1.0 - 01.11.04 +*/ +class UbNupsTimer : public UbTiming +{ +public: + UbNupsTimer() : UbTiming() + { + mTempNodes = 0.0; + mNofNodes.resize(0); + mDurations.resize(0); + } + /*==========================================================*/ + UbNupsTimer(std::string name) : UbTiming(name) + { + mNofNodes.resize(0); + mDurations.resize(0); + mTempNodes = 0.0; + } + /*==========================================================*/ + void initTiming() override + { + UbTiming::initTiming(); + mNofNodes.resize(0); + mDurations.resize(0); + mTempNodes = 0.0; + } + /*==========================================================*/ + void startNUPSTiming(double nofNodes) + { + mTempNodes = nofNodes; + UbTiming::startTiming(); + } + /*==========================================================*/ + void endTiming() override + { + UbTiming::endTiming(); + // save #node and time informations + mNofNodes.push_back(mTempNodes); + mDurations.push_back(UbTiming::getDuration()); + // reset internal timecounter + UbTiming::initTiming(); + } + /*==========================================================*/ + double getAverageNups() + { + double averageNups = 0.0; + for (int i = 0; i < (int)mNofNodes.size(); i++) + averageNups += mNofNodes.at(i) / mDurations.at(i); + + return averageNups / (double)mNofNodes.size(); + } + /*==========================================================*/ + double getSumOfDuration() + { + double duration = 0.0; + for (int i = 0; i < (int)mDurations.size(); i++) + duration += mDurations.at(i); + return duration; + } + /*==========================================================*/ + std::string getNupsString() + { + std::stringstream ss; + ss << "saved nups informations" << std::endl; + for (int i = 0; i < (int)mNofNodes.size(); i++) + ss << mNofNodes.at(i) << "nodes/" << mDurations.at(i) << "sec=" << mNofNodes.at(i) / mDurations.at(i) + << "nups\n"; + return ss.str(); + } + +protected: +private: + std::vector<double> mNofNodes; + std::vector<double> mDurations; + + double mTempNodes; +}; + +#endif diff --git a/src/basics/basics/utilities/UbRandom.h b/src/basics/basics/utilities/UbRandom.h new file mode 100644 index 0000000000000000000000000000000000000000..9026f600734f971923ec5b69f42ea7caddc1ddd2 --- /dev/null +++ b/src/basics/basics/utilities/UbRandom.h @@ -0,0 +1,86 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file UbRandom.h +//! \ingroup utilities +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#ifndef UBRANDOM_H +#define UBRANDOM_H + +#include <cassert> +#include <cmath> +#include <cstdlib> +#include <ctime> + +/*=========================================================================*/ +/* UbRandom */ +/* */ +/** +generates a random number +<BR><BR> +@author <A HREF="mailto:muffmolch@gmx.de">S. Freudiger</A> +@version 1.0 - 04.10.2007 +*/ +/* +usage: + int main() + { + char* hand[] = {"Schere", "Stein", "Papier"}; + for (unsigned u = 0; u < 20; u++) + { + cout << hand[UbRandom::rand(0, 2, 1)] << endl; + } + + return 0; + } +*/ + +class UbRandom +{ +private: + UbRandom() { std::srand(static_cast<int>(std::time(NULL))); } + +public: + // returns arbitrary int value element of [min ; max] + static inline int rand(const int &min, const int &max) + { + static UbRandom dummy; + assert(max - min < RAND_MAX); + return (min + std::rand() % (max - min + 1)); + } + // returns arbitrary float value element of "( (max - min) / gran ) * [min ; max]" + // with other words: val = min+n*(max-min)/gran, n=0..gran-1 + static inline double rand(const double &min, const double &max, const double &gran) + { + static UbRandom dummy; + return (min + std::floor(std::rand() / (1.0 + RAND_MAX) * gran) * (max - min) / gran); + } +}; + +#endif // UBRANDOM_H diff --git a/src/basics/basics/utilities/UbStringInputASCII.cpp b/src/basics/basics/utilities/UbStringInputASCII.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6a04f86aeb8d5b7be9e96ca39d1808b987c1f711 --- /dev/null +++ b/src/basics/basics/utilities/UbStringInputASCII.cpp @@ -0,0 +1,212 @@ +//#include <basics/utilities/UbStringInputASCII.h> +//#include <cstring> +// +// using namespace std; +// +// +// UbStringInputASCII::UbStringInputASCII(string inputString) : UbFileInputASCII("") +//{ +// instream.str(inputString); +// +// +//// this->filename = filename; +//// this->commentindicator = 'C'; +//// +//// infile.open(filename.c_str()); +// +//} +///*==========================================================*/ +// int UbStringInputASCII::readInteger() +//{ +// int dummy; +// instream>>dummy; +// return dummy; +//} +///*==========================================================*/ +// std::size_t UbStringInputASCII::readSize_t() +//{ +// std::size_t dummy; +// instream>>dummy; +// return dummy; +//} +///*==========================================================*/ +// string UbStringInputASCII::getFileName() +//{ +// return this->filename; +//} +// +///*==========================================================*/ +// void UbStringInputASCII::skipLine() +//{ +// string dummy; +// getline(instream, dummy); +//} +///*==========================================================*/ +// void UbStringInputASCII::readLine() +//{ +// string dummy; +// getline(instream, dummy); +//} +///*==========================================================*/ +// string UbStringInputASCII::readStringLine() +//{ +// string dummy; +// getline(instream, dummy); +// return dummy; +//} +///*==========================================================*/ +// string UbStringInputASCII::readLineTill(char stop) +//{ +// string dummy; +// getline(instream, dummy, stop); +// return dummy; +//} +///*==========================================================*/ +// string UbStringInputASCII::parseString() +//{ +// string dummy; +// getline(instream, dummy, ' '); +// return dummy; +//} +///*==========================================================*/ +// double UbStringInputASCII::readDouble() +//{ +// double dummy; +// instream>>dummy; +// return dummy; +//} +///*==========================================================*/ +// float UbStringInputASCII::readFloat() +//{ +// float dummy; +// instream>>dummy; +// return dummy; +//} +///*==========================================================*/ +// char UbStringInputASCII::readChar() +//{ +// char dummy; +// instream>>dummy; +// return dummy; +//} +///*==========================================================*/ +// string UbStringInputASCII::readString() +//{ +// string dummy; +// instream>>dummy; +// return dummy; +//} +///*==========================================================*/ +// bool UbStringInputASCII::containsString(string var) +//{ +// instream.seekg(0L, ios::beg); //Positionszeiger der Datei auf den Anfang setzen +// char line[512]; +// do +// { +// instream.getline(line,512); +// if(instream.eof()) return false; +// }while (strstr(line,var.c_str()) != line); // Ende Schleife, wenn varname ganz in zeile vorkommt +// +// return true; +//} +///*==========================================================*/ +// void UbStringInputASCII::setPosAfterLineWithString(string var) +//{ +// instream.seekg(0L, ios::beg); //Positionszeiger der Datei auf den Anfang setzen +// char line[512]; +// do +// { +// instream.getline(line,512); +// if(instream.eof()) UB_THROW( UbException(UB_EXARGS,var+" wasn't found in "+this->filename) ); +// }while (strstr(line,var.c_str()) != line); // Ende Schleife, wenn varname ganz in zeile vorkommt +//} +///*==========================================================*/ +// int UbStringInputASCII::readIntegerAfterString(string var) +//// last change [10.3.2004] at [9:46] +////suchts in einer Datei nach varname und gibt den dahinter stehenden int-Wert zurueck +////z.B. timesteps 9 +//{ +// instream.seekg(0L, ios::beg); //Positionszeiger der Datei auf den Anfang setzen +// +// char line[512]; +// +// do +// { +// instream.getline(line,512); +// if(instream.eof()) UB_THROW( UbException(UB_EXARGS,var+" wasn't found in "+this->filename) ); +// }while (strstr(line,var.c_str()) != line); // Ende Schleife, wenn varname ganz in zeile vorkommt +// +// strcpy (line, (line+strlen(var.c_str()))); // zeile um "varname" kuerzen +// while ((line[0] == ' ') || (line[0] == '\t')) strcpy (line, (line+1)); // Whitespaces entfernen +// +// return(atoi(line)); // Umwandlung in int +//} +///*==========================================================*/ +//// last change [10.3.2004] at [9:46] +////sucht in einer Datei nach varname und gibt den dahinter stehenden int-Wert zurueck +////z.B. nue 9.5 +// double UbStringInputASCII::readDoubleAfterString(string var) +//{ +// instream.seekg(0L, ios::beg); //Positionszeiger der Datei auf den Anfang setzen +// +// char line[512]; +// +// do +// { +// instream.getline(line,512); +// if(instream.eof()) UB_THROW( UbException(UB_EXARGS,var+" wasn't found in "+this->filename) ); +// }while (/*!strncmp(varname,line,sizeof(varname))==0*/strstr(line,var.c_str()) != line); // Ende Schleife, wenn +// varname ganz in zeile vorkommt +// +// +// strcpy (line, (line+strlen(var.c_str()))); // zeile um "varname" kuerzen +// while ((line[0] == ' ') || (line[0] == '\t')) strcpy (line, (line+1)); // Whitespaces entfernen +// +// return (atof(line)); // Umwandlung in double +//} +///*==========================================================*/ +//// [9.9.2002] +//// liefert sring-Wert der hinter dem uebergebenen char feld in der datei instream steht +//// zudem wird der wert in die uebergebene variable value uebertragen (falls man das ergebniss als char benoetig) +// string UbStringInputASCII::readStringAfterString(string var) +//{ +// instream.seekg(0L, ios::beg); //Positionszeiger der Datei auf den Anfang setzen +// +// char line[512]; +// //string line_copy[512]; +// +// do{ +// instream.getline(line,512); +// if(instream.eof()) UB_THROW( UbException(UB_EXARGS,var+" wasn't found in "+this->filename) ); +// }while (strstr(line,var.c_str()) != line); // Ende Schleife, wenn varname ganz in zeile vorkommt +// +// strcpy (line, (line+strlen(var.c_str()))); // zeile um "varname" kuerzen +// while ((line[0] == ' ') || (line[0] == '\t')) strcpy (line, (line+1)); // Whitespaces entfernen +// +// char *p; +// p=strtok(line," "); //schneidet alles "ab und inklusive space " nach namen ab +// p=strtok(line,"\t");//schneidet alles "ab und inklusive tab " nach namen ab +// +// return (string)p; // Umwandlung in string +//} +///*==========================================================*/ +//// last change [10.3.2004] at [9:46] +////sucht in einer Datei nach varname und gibt den dahinter stehenden int-Wert zurueck +////z.B. nue 9.5 +// bool UbStringInputASCII::readBoolAfterString(string var) +//{ +// if(this->readStringAfterString(var.c_str()) == "true" ) return true; +// else if(this->readStringAfterString(var.c_str()) == "false") return false; +// else UB_THROW( UbException(UB_EXARGS,var+" is not equal to 'true' or 'false' in "+this->filename) ); +//} +///*==========================================================*/ +//// last change [10.3.2004] at [9:46] +////sucht in einer Datei nach varname und gibt den dahinter stehenden int-Wert zurueck +////z.B. nue 9.5 +// bool UbStringInputASCII::readBool() +//{ +// string tmp = this->readString(); +// if( tmp == "true" ) return true; +// else if(tmp == "false") return false; +// else UB_THROW( UbException(UB_EXARGS,"expression is not equal to 'true' or 'false' in "+this->filename) ); +//} diff --git a/src/basics/basics/utilities/UbStringInputASCII.h b/src/basics/basics/utilities/UbStringInputASCII.h new file mode 100644 index 0000000000000000000000000000000000000000..d83adde4dee62f703a6a6070b7a2c0eb6c66360f --- /dev/null +++ b/src/basics/basics/utilities/UbStringInputASCII.h @@ -0,0 +1,55 @@ +//// _ ___ __ __________ _ __ +//// | | / (_)____/ /___ ______ _/ / ____/ /_ __(_)___/ /____ +//// | | / / / ___/ __/ / / / __ `/ / /_ / / / / / / __ / ___/ +//// | |/ / / / / /_/ /_/ / /_/ / / __/ / / /_/ / / /_/ (__ ) +//// |___/_/_/ \__/\__,_/\__,_/_/_/ /_/\__,_/_/\__,_/____/ +//// +//#ifndef UBSTRINGINPUTASCII_H +//#define UBSTRINGINPUTASCII_H +// +//#include <fstream> +//#include <iostream> +//#include <string> +// +//#include <basics/utilities/UbException.h> +//#include <basics/utilities/UbFileInput.h> +// +//#include <basics/utilities/UbFileInputASCII.h> +// +// class UbStringInputASCII : public UbFileInputASCII +//{ +// public: +// UbStringInputASCII(std::string inputString); +// +// std::string getFileName(); +// void skipLine(); // Springt zur naechsten Zeile +// +// void readLine(); +// std::string readStringLine(); +// std::size_t readSize_t(); +// int readInteger(); // Liest einen Int-Wert ein +// double readDouble(); // Liest einen double-Wert ein +// float readFloat(); // Liest einen float-Wert ein +// bool readBool(); // Liest einen bool-Wert ein +// char readChar(); // Liest einen char-Wert ein +// std::string readString(); // Liest ein Wort ein +// std::string readLineTill(char stop); // Liest gesamte Zeile ein bis zu einem bestimmten Zeichen +// std::string parseString(); +// +// bool containsString(std::string var); +// void setPosAfterLineWithString(std::string var); +// int readIntegerAfterString(std::string var); +// double readDoubleAfterString(std::string var); +// bool readBoolAfterString(std::string var); +// std::string readStringAfterString(std::string var); +// +// FILETYPE getFileType() { return ASCII; } +// +// private: +// std::istringstream instream; +//}; +// +// +//#endif +// +// diff --git a/src/basics/basics/utilities/Vector3D.cpp b/src/basics/basics/utilities/Vector3D.cpp index 6ff9dc8738f869d75e7fc9870bb5bb7468d83468..a97e8bfdcd64a717b556d7f02e4450ee56977ea0 100644 --- a/src/basics/basics/utilities/Vector3D.cpp +++ b/src/basics/basics/utilities/Vector3D.cpp @@ -26,7 +26,7 @@ // You should have received a copy of the GNU General Public License along // with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. // -//! \file UbVector3D.cpp +//! \file Vector3D.cpp //! \ingroup utilities //! \author Soeren Freudiger, Sebastian Geller //======================================================================================= diff --git a/src/basics/basics/utilities/Vector3D.h b/src/basics/basics/utilities/Vector3D.h index b278a80d732115a9b1183547e61ff1fe6e82d057..ab02dbeea18264a305564d995055744a15c1c7cb 100644 --- a/src/basics/basics/utilities/Vector3D.h +++ b/src/basics/basics/utilities/Vector3D.h @@ -26,7 +26,7 @@ // You should have received a copy of the GNU General Public License along // with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. // -//! \file UbVector3D.h +//! \file Vector3D.h //! \ingroup utilities //! \author Soeren Freudiger, Sebastian Geller //======================================================================================= diff --git a/src/basics/basics/utilities/Vector3DTest.cpp b/src/basics/basics/utilities/Vector3DTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0aaf474569b4baf58d8166a94ed37c394053eca4 --- /dev/null +++ b/src/basics/basics/utilities/Vector3DTest.cpp @@ -0,0 +1,157 @@ +#include "Vector3D.h" +#include "gmock/gmock.h" + +#include <cmath> + +using namespace testing; + +class Vector3DTest : public Test +{ +public: + Vector3D vec1; + Vector3D vec2; + + void SetUp() override + { + vec1[0] = vec1[1] = vec1[2] = 4.0f; + vec2[0] = 0.0f; + vec2[0] = 2.4f; + vec2[0] = -1.3f; + } +}; + +TEST_F(Vector3DTest, overloadMinusOperator) +{ + Vector3D vec3; + vec3[0] = vec2[0] - vec1[0]; + vec3[1] = vec2[1] - vec1[1]; + vec3[2] = vec2[2] - vec1[2]; + + Vector3D v4 = vec2 - vec1; + ASSERT_THAT((double)v4[0], DoubleEq(vec3[0])); + ASSERT_THAT((double)v4[1], DoubleEq(vec3[1])); + ASSERT_THAT((double)v4[2], DoubleEq(vec3[2])); +} + +TEST_F(Vector3DTest, overloadPlusOperator) +{ + Vector3D vec3; + vec3[0] = vec2[0] + vec1[0]; + vec3[1] = vec2[1] + vec1[1]; + vec3[2] = vec2[2] + vec1[2]; + + Vector3D v4 = vec2 + vec1; + ASSERT_THAT((double)v4[0], DoubleEq(vec3[0])); + ASSERT_THAT((double)v4[1], DoubleEq(vec3[1])); + ASSERT_THAT((double)v4[2], DoubleEq(vec3[2])); +} + +TEST_F(Vector3DTest, overloadTimesOperatorWithSkalarProduct) +{ + double skalar = vec1[0] * vec2[0] + vec1[1] * vec2[1] + vec1[2] * vec2[2]; + ASSERT_THAT(vec1.Dot(vec2), DoubleEq(skalar)); +} + +TEST_F(Vector3DTest, overloadTimesOperatorWithSkalarMultiplication) +{ + double skalar = 1.0f / 3.0f; + Vector3D vec3; + vec3[0] = skalar * vec1[0]; + vec3[1] = skalar * vec1[1]; + vec3[2] = skalar * vec1[2]; + + Vector3D v4 = vec1 * skalar; + + ASSERT_THAT((double)v4[0], DoubleEq(vec3[0])); + ASSERT_THAT((double)v4[1], DoubleEq(vec3[1])); + ASSERT_THAT((double)v4[2], DoubleEq(vec3[2])); +} + +TEST_F(Vector3DTest, getLengthFromVector) +{ + Vector3D v; + v[0] = 4.0; + v[1] = 3.0; + v[2] = -1.0; + + double expected = std::sqrt(16.0 + 9.0 + 1.0); + ASSERT_THAT(v.Length(), testing::DoubleEq(expected)); +} + +TEST_F(Vector3DTest, compareTwoVectors) +{ + Vector3D v; + v[0] = vec1[0]; + v[1] = vec1[1]; + v[2] = vec1[2]; + ASSERT_TRUE(v == vec1); +} +// +// TEST_F(Vector3DTest, checkEuclideanDistance) +//{ +// Vector3D v = Vector3D(3, 3, 3); +// +// ASSERT_FLOAT_EQ(v.getEuclideanDistanceTo(vec1), (float)sqrt(3)); +//} +// +// TEST_F(Vector3DTest, checkEuclideanDistanceWithNullVector_ExpectNull) +//{ +// Vector3D v1 = Vector3D(0.0, 0.0, 0.0); +// Vector3D v2 = Vector3D(0.0, 0.0, 0.0); +// +// ASSERT_THAT((double)v1.getEuclideanDistanceTo(v2), DoubleEq(0.0)); +//} +// +// TEST(Vector3DAngleTest, checkInnerAngleBetweenToVectors_ExpectRightAngle) +//{ +// Vector3D v1 = Vector3D(1.0, 4.0, -2.0); +// Vector3D v2 = Vector3D(-3.0, 3.0, 1); +// +// ASSERT_THAT((int)floor(v1.getInnerAngle(v2)), Eq(69)); +//} +// +// TEST(Vector3DAngleTest, checkInnerAngleBetweenSameVectors_ExpectNull) +//{ +// Vector3D v1 = Vector3D(1.0, 4.0, -2.0); +// Vector3D v2 = Vector3D(1.0, 4.0, -2.0); +// +// ASSERT_THAT((int)floor(v1.getInnerAngle(v2)), Eq(0.0)); +//} +// +// TEST(Vector3DAngleTest, checkInnerAngleBetweenNullVectors_ExpectNull) +//{ +// Vector3D v1 = Vector3D(0.0, 0.0, 0.0); +// Vector3D v2 = Vector3D(0.0, 0.0, 0.0); +// +// ASSERT_THAT((int)floor(v1.getInnerAngle(v2)), Eq(0.0)); +//} +// +// +// TEST(Vector3DAngleTest, checkInnerAngleBetweenSecondNullVectors_ExpectNull) +//{ +// Vector3D v1 = Vector3D(1.0, 0.0, 0.0); +// Vector3D v2 = Vector3D(0.0, 0.0, 0.0); +// +// ASSERT_THAT((int)floor(v1.getInnerAngle(v2)), Eq(0.0)); +//} +// +// TEST(Vector3DAngleTest, checkInnerAngleBetweenFirstNullVectors_ExpectNull) +//{ +// Vector3D v1 = Vector3D(0.0, 0.0, 0.0); +// Vector3D v2 = Vector3D(2.0, 0.0, 0.0); +// +// ASSERT_THAT((int)floor(v1.getInnerAngle(v2)), Eq(0.0)); +//} + +TEST_F(Vector3DTest, crossProductBetweenTwoVectors) +{ + Vector3D v1 = Vector3D(-5.0, -5.0, 0.0); + Vector3D v2 = Vector3D(5.0, 0.0, 10); + + Vector3D crossProd = Vector3D(-50.0, 50.0, 25.0); + Vector3D testCrossProduct = v1.Cross(v2); + + EXPECT_THAT(testCrossProduct[0], DoubleEq(crossProd[0])); + EXPECT_THAT(testCrossProduct[1], DoubleEq(crossProd[1])); + EXPECT_THAT(testCrossProduct[2], DoubleEq(crossProd[2])); +} diff --git a/src/basics/basics/writer/WbWriterAvsASCII.cpp b/src/basics/basics/writer/WbWriterAvsASCII.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3f17db89a1aa1893d156b9142991bf6ce15806c5 --- /dev/null +++ b/src/basics/basics/writer/WbWriterAvsASCII.cpp @@ -0,0 +1,1158 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file WbWriterAvsASCII.cpp +//! \ingroup writer +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#include <basics/utilities/UbLogger.h> +#include <basics/utilities/UbSystem.h> +#include <basics/writer/WbWriterAvsASCII.h> +#include <cstring> + +using namespace std; + +std::string WbWriterAvsASCII::writeQuads(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt4> &cells) +{ + string avsfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterAvsASCII::writeQuads to " << avsfilename << " - start"); + + ofstream out(avsfilename.c_str(), ios::out | ios::binary); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!! + string path = UbSystem::getPathFromString(avsfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(avsfilename.c_str(), ios::out | ios::binary); + } + if (!out) + throw UbException(UB_EXARGS, "couldn't open file " + avsfilename); + } + char magic = (char)7; + int idummy; + float fdummy; + + int nofNodes = (int)nodes.size(); + int nofCells = (int)cells.size(); + + int nofNodeData = 0; + int nofCellData = 0; + int nofModelData = 0; + int cellType = 3; //=quad + int nofNodesPerCell = 4; + + out.write((char *)&magic, sizeof(char)); + out.write((char *)&nofNodes, sizeof(int)); + out.write((char *)&nofCells, sizeof(int)); + out.write((char *)&nofNodeData, sizeof(int)); + out.write((char *)&nofCellData, sizeof(int)); + out.write((char *)&nofModelData, sizeof(int)); + + idummy = (int)nofCells * nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell) + for (int c = 0; c < nofCells; c++) { + idummy = c + 1; + out.write((char *)&idummy, sizeof(int)); // cell id + idummy = 1; + out.write((char *)&idummy, sizeof(int)); // mat + idummy = nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); // nodes per cell + idummy = cellType; + out.write((char *)&idummy, sizeof(int)); // cell type + } + // knotennummern der einzelnen zellen + for (int c = 0; c < nofCells; c++) { + idummy = val<1>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<2>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<3>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<4>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + } + + // coords + // x1-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<1>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x2-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<2>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x3-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<3>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // out<<"\n"; + + out.close(); + UBLOG(logDEBUG1, "WbWriterAvsASCII::writeQuads to " << avsfilename << " - end"); + + return avsfilename; +} +/*===============================================================================*/ +std::string WbWriterAvsASCII::writeOcts(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt8> &cells) +{ + string avsfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterAvsASCII::writeOcts to " << avsfilename << " - start"); + + ofstream out(avsfilename.c_str(), ios::out | ios::binary); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!! + string path = UbSystem::getPathFromString(avsfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(avsfilename.c_str(), ios::out | ios::binary); + } + if (!out) + throw UbException(UB_EXARGS, "file konnte nicht geschrieben werden " + avsfilename); + } + + char magic = (char)7; + int idummy; + float fdummy; + + int nofNodes = (int)nodes.size(); + int nofCells = (int)cells.size(); + + int nofNodeData = 0; + int nofCellData = 0; + int nofModelData = 0; + int cellType = 7; //=hex + int nofNodesPerCell = 8; + + out.write((char *)&magic, sizeof(char)); + out.write((char *)&nofNodes, sizeof(int)); + out.write((char *)&nofCells, sizeof(int)); + out.write((char *)&nofNodeData, sizeof(int)); + out.write((char *)&nofCellData, sizeof(int)); + out.write((char *)&nofModelData, sizeof(int)); + + idummy = (int)nofCells * nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell) + for (int c = 0; c < nofCells; c++) { + idummy = c + 1; + out.write((char *)&idummy, sizeof(int)); // cell id + idummy = 1; + out.write((char *)&idummy, sizeof(int)); // mat + idummy = nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); // nodes per cell + idummy = cellType; + out.write((char *)&idummy, sizeof(int)); // cell type + } + // knotennummern der einzelnen zellen + for (int c = 0; c < nofCells; c++) { + idummy = val<1>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<2>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<3>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<4>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<5>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<6>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<7>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<8>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + } + + // coords + // x1-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<1>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x2-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<2>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x3-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<3>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // out<<"\n"; + + out.close(); + UBLOG(logDEBUG1, "WbWriterAvsASCII::writeOcts to " << avsfilename << " - end"); + + return avsfilename; +} +/*===============================================================================*/ +std::string WbWriterAvsASCII::writeQuadsWithNodeData(const string &filename, vector<UbTupleFloat3> &nodes, + vector<UbTupleInt4> &cells, vector<string> &datanames, + vector<vector<double>> &nodedata) +{ + string avsfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterAvsASCII::writeQuadsWithNodeData to " << avsfilename << " - start"); + + ofstream out(avsfilename.c_str(), ios::out | ios::binary); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!! + string path = UbSystem::getPathFromString(avsfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(avsfilename.c_str(), ios::out | ios::binary); + } + if (!out) + throw UbException(UB_EXARGS, "write UCD File " + avsfilename + " konnte nicht geschrieben werden"); + } + char magic = (char)7; + int idummy; + float fdummy; + + int nofNodes = (int)nodes.size(); + int nofCells = (int)cells.size(); + + int nofNodeData = (int)datanames.size(); + int nofCellData = 0; + int nofModelData = 0; + int cellType = 3; //=quad + int nofNodesPerCell = 4; + + out.write((char *)&magic, sizeof(char)); + out.write((char *)&nofNodes, sizeof(int)); + out.write((char *)&nofCells, sizeof(int)); + out.write((char *)&nofNodeData, sizeof(int)); + out.write((char *)&nofCellData, sizeof(int)); + out.write((char *)&nofModelData, sizeof(int)); + + idummy = (int)nofCells * nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell) + for (int c = 0; c < nofCells; c++) { + idummy = c + 1; + out.write((char *)&idummy, sizeof(int)); // cell id + idummy = 1; + out.write((char *)&idummy, sizeof(int)); // mat + idummy = nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); // nodes per cell + idummy = cellType; + out.write((char *)&idummy, sizeof(int)); // cell type + } + // knotennummern der einzelnen zellen + for (int c = 0; c < nofCells; c++) { + idummy = val<1>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<2>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<3>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<4>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + } + + // coords + // x1-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<1>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x2-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<2>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x3-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<3>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // out<<"\n"; + + // NODE DATA + char labels[1024]; + char units[1024]; + strcpy(labels, ""); + strcpy(units, ""); + + for (int d = 0; d < nofNodeData - 1; ++d) { + strcat(labels, datanames[d].c_str()); + strcat(labels, "."); + } + strcat(labels, datanames[nofNodeData - 1].c_str()); + + for (int i = 0; i < (nofNodeData - 1); i++) + strcat(units, "no_unit."); + strcat(units, "no_unit"); + + out.write((char *)&labels, sizeof(labels)); + out.write((char *)&units, sizeof(units)); + + // nof and type of data + idummy = nofNodeData; + out.write((char *)&idummy, sizeof(int)); // Datentypen pro knoten (hier = nof_node_data, da NUR skalare) + + idummy = 1; + for (int i = 0; i < nofNodeData; i++) + out.write((char *)&idummy, sizeof(int)); // jeder Datentyp ist ein skalarer Wert + + // min and max of data + fdummy = 0.0; + for (int i = 0; i < nofNodeData; i++) + out.write((char *)&fdummy, sizeof(float)); // min Wert pro Datentyp + fdummy = 1.0; + for (int i = 0; i < nofNodeData; i++) + out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp + + // daten ins file schreiben + for (int d = 0; d < nofNodeData; ++d) + for (int n = 0; n < (int)nodedata[d].size(); n++) { + fdummy = (float)nodedata[d][n]; + out.write((char *)&fdummy, sizeof(float)); + } + + fdummy = 1.; + for (int i = 0; i < nofNodeData; i++) + out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp + + out.close(); + UBLOG(logDEBUG1, "WbWriterAvsASCII::writeQuadsWithNodeData to " << avsfilename << " - end"); + + return avsfilename; +} +/*===============================================================================*/ +std::string WbWriterAvsASCII::writeQuadsWithCellData(const string &filename, vector<UbTupleFloat3> &nodes, + vector<UbTupleInt4> &cells, vector<string> &datanames, + vector<vector<double>> &celldata) +{ + string avsfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterAvsASCII::writeQuadsWithCellData to " << avsfilename << " - start"); + + ofstream out(avsfilename.c_str(), ios::out | ios::binary); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!! + string path = UbSystem::getPathFromString(avsfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(avsfilename.c_str(), ios::out | ios::binary); + } + if (!out) + throw UbException(UB_EXARGS, + "write_OutputFile-UCD File " + avsfilename + " konnte nicht geschrieben werden"); + } + + char magic = (char)7; + int idummy; + float fdummy; + + int nofNodes = (int)nodes.size(); + int nofCells = (int)cells.size(); + + int nofNodeData = 0; + int nofCellData = (int)datanames.size(); + int nofModelData = 0; + int cellType = 3; //=quad + int nofNodesPerCell = 4; + + out.write((char *)&magic, sizeof(char)); + out.write((char *)&nofNodes, sizeof(int)); + out.write((char *)&nofCells, sizeof(int)); + out.write((char *)&nofNodeData, sizeof(int)); + out.write((char *)&nofCellData, sizeof(int)); + out.write((char *)&nofModelData, sizeof(int)); + + idummy = (int)nofCells * nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell) + for (int c = 0; c < nofCells; c++) { + idummy = c + 1; + out.write((char *)&idummy, sizeof(int)); // cell id + idummy = 1; + out.write((char *)&idummy, sizeof(int)); // mat + idummy = nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); // nodes per cell + idummy = cellType; + out.write((char *)&idummy, sizeof(int)); // cell type + } + // knotennummern der einzelnen zellen + for (int c = 0; c < nofCells; c++) { + idummy = val<1>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<2>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<3>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<4>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + } + + // coords + // x1-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<1>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x2-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<2>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x3-coords + fdummy = 0.0; + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<3>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // out<<"\n"; + + // CELL DATA + char labels[1024]; + char units[1024]; + strcpy(labels, ""); + strcpy(units, ""); + + for (int d = 0; d < nofCellData - 1; ++d) { + strcat(labels, datanames[d].c_str()); + strcat(labels, "."); + } + strcat(labels, datanames[nofCellData - 1].c_str()); + + for (int d = 0; d < nofCellData - 1; ++d) + strcat(units, "no_unit."); + strcat(units, "no_unit"); + + out.write((char *)&labels, sizeof(labels)); + out.write((char *)&units, sizeof(units)); + + // nof and type of data + idummy = nofCellData; + out.write((char *)&idummy, sizeof(int)); // Datentypen pro knoten (hier = nof_node_data, da NUR skalare) + + idummy = 1; + for (int i = 0; i < nofCellData; i++) + out.write((char *)&idummy, sizeof(int)); // jeder Datentyp ist ein skalarer Wert + + // min and max of data + fdummy = 0.0; + for (int i = 0; i < nofCellData; i++) + out.write((char *)&fdummy, sizeof(float)); // min Wert pro Datentyp + fdummy = 1.0; + for (int i = 0; i < nofCellData; i++) + out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp + + // daten ins file schreiben + for (int d = 0; d < nofCellData; ++d) + for (int n = 0; n < (int)celldata[d].size(); n++) { + fdummy = (float)celldata[d][n]; + out.write((char *)&fdummy, sizeof(float)); + } + + fdummy = 1.; + for (int i = 0; i < nofCellData; i++) + out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp + + out.close(); + UBLOG(logDEBUG1, "WbWriterAvsASCII::writeQuadsWithCellData to " << avsfilename << " - end"); + + return avsfilename; +} +/*===============================================================================*/ +std::string WbWriterAvsASCII::writeQuadsWithNodeAndCellData(const string &filename, vector<UbTupleFloat3> &nodes, + vector<UbTupleInt4> &cells, vector<string> &nodedatanames, + vector<vector<double>> &nodedata, + vector<string> &celldatanames, + vector<vector<double>> &celldata) +{ + string avsfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterAvsASCII::writeQuadsWithNodeAndCellData to " << avsfilename << " - start"); + + ofstream out(avsfilename.c_str(), ios::out | ios::binary); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!! + string path = UbSystem::getPathFromString(avsfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(avsfilename.c_str(), ios::out | ios::binary); + } + if (!out) + throw UbException(UB_EXARGS, + "write_OutputFile-UCD File " + avsfilename + " konnte nicht geschrieben werden"); + } + + char magic = (char)7; + int idummy; + float fdummy; + + int nofNodes = (int)nodes.size(); + int nofCells = (int)cells.size(); + + int nofNodeData = (int)nodedatanames.size(); + int nofCellData = (int)celldatanames.size(); + int nofModelData = 0; + int cellType = 3; //=quad + int nofNodesPerCell = 4; + + out.write((char *)&magic, sizeof(char)); + out.write((char *)&nofNodes, sizeof(int)); + out.write((char *)&nofCells, sizeof(int)); + out.write((char *)&nofNodeData, sizeof(int)); + out.write((char *)&nofCellData, sizeof(int)); + out.write((char *)&nofModelData, sizeof(int)); + + idummy = (int)nofCells * nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell) + for (int c = 0; c < nofCells; c++) { + idummy = c + 1; + out.write((char *)&idummy, sizeof(int)); // cell id + idummy = 1; + out.write((char *)&idummy, sizeof(int)); // mat + idummy = nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); // nodes per cell + idummy = cellType; + out.write((char *)&idummy, sizeof(int)); // cell type + } + // knotennummern der einzelnen zellen + for (int c = 0; c < nofCells; c++) { + idummy = val<1>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<2>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<3>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<4>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + } + + // coords + // x1-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<1>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x2-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<2>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x3-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<3>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // out<<"\n"; + + // NODE DATA + char nodelabels[1024]; + char nodeunits[1024]; + strcpy(nodelabels, ""); + strcpy(nodeunits, ""); + + for (int d = 0; d < nofNodeData - 1; ++d) { + strcat(nodelabels, nodedatanames[d].c_str()); + strcat(nodelabels, "."); + } + strcat(nodelabels, nodedatanames[nofNodeData - 1].c_str()); + + for (int i = 0; i < (nofNodeData - 1); i++) + strcat(nodeunits, "no_unit."); + strcat(nodeunits, "no_unit"); + + out.write((char *)&nodelabels, sizeof(nodelabels)); + out.write((char *)&nodeunits, sizeof(nodeunits)); + + // nof and type of data + idummy = nofNodeData; + out.write((char *)&idummy, sizeof(int)); // Datentypen pro knoten (hier = nof_node_data, da NUR skalare) + + idummy = 1; + for (int i = 0; i < nofNodeData; i++) + out.write((char *)&idummy, sizeof(int)); // jeder Datentyp ist ein skalarer Wert + + // min and max of data + fdummy = 0.0; + for (int i = 0; i < nofNodeData; i++) + out.write((char *)&fdummy, sizeof(float)); // min Wert pro Datentyp + fdummy = 1.0; + for (int i = 0; i < nofNodeData; i++) + out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp + + // daten ins file schreiben + for (int d = 0; d < nofNodeData; ++d) + for (int n = 0; n < (int)nodedata[d].size(); n++) { + fdummy = (float)nodedata[d][n]; + out.write((char *)&fdummy, sizeof(float)); + } + + fdummy = 1.; + for (int i = 0; i < nofNodeData; i++) + out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp + + // CELL DATA + char celllabels[1024]; + char cellunits[1024]; + strcpy(celllabels, ""); + strcpy(cellunits, ""); + + for (int d = 0; d < nofCellData - 1; ++d) { + strcat(celllabels, celldatanames[d].c_str()); + strcat(celllabels, "."); + } + strcat(celllabels, celldatanames[nofCellData - 1].c_str()); + + for (int d = 0; d < nofCellData - 1; ++d) + strcat(cellunits, "no_unit."); + strcat(cellunits, "no_unit"); + + out.write((char *)&celllabels, sizeof(celllabels)); + out.write((char *)&cellunits, sizeof(cellunits)); + + // nof and type of data + idummy = nofCellData; + out.write((char *)&idummy, sizeof(int)); // Datentypen pro knoten (hier = nof_node_data, da NUR skalare) + + idummy = 1; + for (int i = 0; i < nofCellData; i++) + out.write((char *)&idummy, sizeof(int)); // jeder Datentyp ist ein skalarer Wert + + // min and max of data + fdummy = 0.0; + for (int i = 0; i < nofCellData; i++) + out.write((char *)&fdummy, sizeof(float)); // min Wert pro Datentyp + fdummy = 1.0; + for (int i = 0; i < nofCellData; i++) + out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp + + // daten ins file schreiben + for (int d = 0; d < nofCellData; ++d) + for (int n = 0; n < (int)celldata[d].size(); n++) { + fdummy = (float)celldata[d][n]; + out.write((char *)&fdummy, sizeof(float)); + } + + fdummy = 1.; + for (int i = 0; i < nofCellData; i++) + out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp + + out.close(); + UBLOG(logDEBUG1, "WbWriterAvsASCII::writeQuadsWithNodeAndCellData to " << avsfilename << " - end"); + + return avsfilename; +} +/*===============================================================================*/ +std::string WbWriterAvsASCII::writeLines(const string &filename, vector<UbTupleFloat3> &nodes, + vector<UbTupleInt2> &lines) +{ + string avsfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterAvsASCII::writeLines to " << avsfilename << " - start"); + + ofstream out(avsfilename.c_str(), ios::out); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!! + string path = UbSystem::getPathFromString(avsfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(avsfilename.c_str(), ios::out); + } + if (!out) + throw UbException(UB_EXARGS, avsfilename + " konnte nicht geschrieben werden"); + } + + int nofNodes = (int)nodes.size(); + int nofLines = (int)lines.size(); + + out << "# UCD-File created by WbWriterAvsASCII\n"; + out << nofNodes << " " << nofLines << " 0 0 0 " << endl; + + for (int n = 0; n < nofNodes; n++) + out << n + 1 << " " << val<1>(nodes[n]) << " " << val<2>(nodes[n]) << " " << val<3>(nodes[n]) << " \n"; + + for (int l = 0; l < nofLines; l++) + out << l + 1 << " 2 line " << val<1>(lines[l]) + 1 << " " << val<2>(lines[l]) + 1 << " " << endl; + + out.close(); + UBLOG(logDEBUG1, "WbWriterAvsASCII::writeLines to " << avsfilename << " - end"); + + return avsfilename; +} +/*===============================================================================*/ +std::string WbWriterAvsASCII::writeTriangles(const string &filename, vector<UbTupleFloat3> &nodes, + vector<UbTupleInt3> &triangles) +{ + string avsfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterAvsASCII::writeTriangles to " << avsfilename << " - start"); + + ofstream out(avsfilename.c_str(), ios::out); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!! + string path = UbSystem::getPathFromString(avsfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(avsfilename.c_str(), ios::out); + } + if (!out) + throw UbException(UB_EXARGS, "file konnte nicht geschrieben werden " + avsfilename); + } + + int nofNodes = (int)nodes.size(); + int nofTrian = (int)triangles.size(); + + out << "# UCD-File created by WbWriterAvsASCII\n"; + out << nofNodes << " " << nofTrian << " 0 0 0 " << endl; + + for (int n = 0; n < nofNodes; n++) + out << n + 1 << " " << val<1>(nodes[n]) << " " << val<2>(nodes[n]) << " " << val<3>(nodes[n]) << " \n"; + + for (int l = 0; l < nofTrian; l++) + out << l + 1 << " 2 tri " << val<1>(triangles[l]) + 1 << " " << val<2>(triangles[l]) + 1 << " " + << val<3>(triangles[l]) + 1 << " " << endl; + + out.close(); + UBLOG(logDEBUG1, "WbWriterAvsASCII::writeTriangles to " << avsfilename << " - end"); + + return avsfilename; +} +/*===============================================================================*/ +std::string WbWriterAvsASCII::writeTrianglesWithNodeData(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt3> &cells, + std::vector<std::string> &datanames, + std::vector<std::vector<double>> &nodedata) +{ + string avsfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterAvsASCII::writeTrianglesWithNodeData to " << avsfilename << " - end"); + + ofstream out(avsfilename.c_str(), ios::out | ios::binary); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!! + string path = UbSystem::getPathFromString(avsfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(avsfilename.c_str(), ios::out | ios::binary); + } + if (!out) + throw UbException(UB_EXARGS, + "write_OutputFile-UCD File " + avsfilename + " konnte nicht geschrieben werden"); + } + char magic = (char)7; + int idummy; + float fdummy; + + int nofNodes = (int)nodes.size(); + int nofCells = (int)cells.size(); + + int nofNodeData = (int)datanames.size(); + int nofCellData = 0; + int nofModelData = 0; + int cellType = 2; // triangle + int nofNodesPerCell = 3; + + out.write((char *)&magic, sizeof(char)); + out.write((char *)&nofNodes, sizeof(int)); + out.write((char *)&nofCells, sizeof(int)); + out.write((char *)&nofNodeData, sizeof(int)); + out.write((char *)&nofCellData, sizeof(int)); + out.write((char *)&nofModelData, sizeof(int)); + + idummy = (int)nofCells * nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell) + for (int c = 0; c < nofCells; c++) { + idummy = c + 1; + out.write((char *)&idummy, sizeof(int)); // cell id + idummy = 1; + out.write((char *)&idummy, sizeof(int)); // mat + idummy = nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); // nodes per cell + idummy = cellType; + out.write((char *)&idummy, sizeof(int)); // cell type + } + // knotennummern der einzelnen zellen + for (int c = 0; c < nofCells; c++) { + idummy = val<1>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<2>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<3>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + } + + // coords + // x1-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<1>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x2-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<2>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x3-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<3>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // out<<"\n"; + + // NODE DATA + char labels[1024]; + char units[1024]; + strcpy(labels, ""); + strcpy(units, ""); + + for (int d = 0; d < nofNodeData - 1; ++d) { + strcat(labels, datanames[d].c_str()); + strcat(labels, "."); + } + strcat(labels, datanames[nofNodeData - 1].c_str()); + + for (int i = 0; i < (nofNodeData - 1); i++) + strcat(units, "no_unit."); + strcat(units, "no_unit"); + + out.write((char *)&labels, sizeof(labels)); + out.write((char *)&units, sizeof(units)); + + // nof and type of data + idummy = nofNodeData; + out.write((char *)&idummy, sizeof(int)); // Datentypen pro knoten (hier = nof_node_data, da NUR skalare) + + idummy = 1; + for (int i = 0; i < nofNodeData; i++) + out.write((char *)&idummy, sizeof(int)); // jeder Datentyp ist ein skalarer Wert + + // min and max of data + fdummy = 0.0; + for (int i = 0; i < nofNodeData; i++) + out.write((char *)&fdummy, sizeof(float)); // min Wert pro Datentyp + fdummy = 1.0; + for (int i = 0; i < nofNodeData; i++) + out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp + + // daten ins file schreiben + for (int d = 0; d < nofNodeData; ++d) { + for (int n = 0; n < (int)nodedata[d].size(); n++) { + fdummy = (float)nodedata[d][n]; + out.write((char *)&fdummy, sizeof(float)); + } + } + + fdummy = 1.; + for (int i = 0; i < nofNodeData; i++) + out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp + + out.close(); + UBLOG(logDEBUG1, "WbWriterAvsASCII::writeTrianglesWithNodeData to " << avsfilename << " - end"); + + return avsfilename; +} +/*===============================================================================*/ +std::string WbWriterAvsASCII::writeOctsWithCellData(const string &filename, vector<UbTupleFloat3> &nodes, + vector<UbTupleInt8> &cells, vector<string> &datanames, + vector<vector<double>> &celldata) +{ + string avsfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterAvsASCII::writeOctsWithCellData to " << avsfilename << " - start"); + + ofstream out(avsfilename.c_str(), ios::out | ios::binary); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!! + string path = UbSystem::getPathFromString(avsfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(avsfilename.c_str(), ios::out | ios::binary); + } + if (!out) + throw UbException(UB_EXARGS, "file konnte nicht geschrieben werden " + avsfilename); + } + + char magic = (char)7; + int idummy; + float fdummy; + + int nofNodes = (int)nodes.size(); + int nofCells = (int)cells.size(); + + int nofNodeData = 0; + int nofCellData = (int)datanames.size(); + int nofModelData = 0; + int cellType = 7; //=hex + int nofNodesPerCell = 8; + + out.write((char *)&magic, sizeof(char)); + out.write((char *)&nofNodes, sizeof(int)); + out.write((char *)&nofCells, sizeof(int)); + out.write((char *)&nofNodeData, sizeof(int)); + out.write((char *)&nofCellData, sizeof(int)); + out.write((char *)&nofModelData, sizeof(int)); + + idummy = (int)nofCells * nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell) + for (int c = 0; c < nofCells; c++) { + idummy = c + 1; + out.write((char *)&idummy, sizeof(int)); // cell id + idummy = 1; + out.write((char *)&idummy, sizeof(int)); // mat + idummy = nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); // nodes per cell + idummy = cellType; + out.write((char *)&idummy, sizeof(int)); // cell type + } + // knotennummern der einzelnen zellen + for (int c = 0; c < nofCells; c++) { + idummy = val<1>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<2>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<3>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<4>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<5>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<6>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<7>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<8>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + } + + // coords + // x1-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<1>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x2-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<2>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x3-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<3>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // out<<"\n"; + + // CELL DATA + char labels[1024]; + char units[1024]; + strcpy(labels, ""); + strcpy(units, ""); + + for (int d = 0; d < nofCellData - 1; ++d) { + strcat(labels, datanames[d].c_str()); + strcat(labels, "."); + } + strcat(labels, datanames[nofCellData - 1].c_str()); + + for (int d = 0; d < nofCellData - 1; ++d) + strcat(units, "no_unit."); + strcat(units, "no_unit"); + + out.write((char *)&labels, sizeof(labels)); + out.write((char *)&units, sizeof(units)); + + // nof and type of data + idummy = nofCellData; + out.write((char *)&idummy, sizeof(int)); // Datentypen pro knoten (hier = nof_node_data, da NUR skalare) + + idummy = 1; + for (int i = 0; i < nofCellData; i++) + out.write((char *)&idummy, sizeof(int)); // jeder Datentyp ist ein skalarer Wert + + // min and max of data + fdummy = 0.0; + for (int i = 0; i < nofCellData; i++) + out.write((char *)&fdummy, sizeof(float)); // min Wert pro Datentyp + fdummy = 1.0; + for (int i = 0; i < nofCellData; i++) + out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp + + // daten ins file schreiben + for (int d = 0; d < nofCellData; ++d) + for (int n = 0; n < (int)celldata[d].size(); n++) { + fdummy = (float)celldata[d][n]; + out.write((char *)&fdummy, sizeof(float)); + } + + fdummy = 1.; + for (int i = 0; i < nofCellData; i++) + out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp + + out.close(); + UBLOG(logDEBUG1, "WbWriterAvsASCII::writeOctsWithCellData to " << avsfilename << " - end"); + + return avsfilename; +} +/*===============================================================================*/ +std::string WbWriterAvsASCII::writeOctsWithNodeData(const string &filename, vector<UbTupleFloat3> &nodes, + vector<UbTupleUInt8> &cells, vector<string> &datanames, + vector<vector<double>> &nodedata) +{ + string avsfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterAvsASCII::writeOctsWithNodeData to " << avsfilename << " - start"); + + ofstream out(avsfilename.c_str(), ios::out | ios::binary); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!! + string path = UbSystem::getPathFromString(avsfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(avsfilename.c_str(), ios::out | ios::binary); + } + if (!out) + throw UbException(UB_EXARGS, "file konnte nicht geschrieben werden " + avsfilename); + } + + if ((int)nodedata.size() == 0) + throw UbException(UB_EXARGS, "no nodedata!!!"); + if (nodes.size() != nodedata[0].size()) + throw UbException(UB_EXARGS, "nodedata != nofNodes!!!"); + + char magic = (char)7; + int idummy; + float fdummy; + + int nofNodes = (int)nodes.size(); + int nofCells = (int)cells.size(); + + int nofNodeData = (int)datanames.size(); + int nofCellData = 0; + int nofModelData = 0; + int cellType = 7; //=hex + int nofNodesPerCell = 8; + + out.write((char *)&magic, sizeof(char)); + out.write((char *)&nofNodes, sizeof(int)); + out.write((char *)&nofCells, sizeof(int)); + out.write((char *)&nofNodeData, sizeof(int)); + out.write((char *)&nofCellData, sizeof(int)); + out.write((char *)&nofModelData, sizeof(int)); + + idummy = (int)nofCells * nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell) + for (int c = 0; c < nofCells; c++) { + idummy = c + 1; + out.write((char *)&idummy, sizeof(int)); // cell id + idummy = 1; + out.write((char *)&idummy, sizeof(int)); // mat + idummy = nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); // nodes per cell + idummy = cellType; + out.write((char *)&idummy, sizeof(int)); // cell type + } + // knotennummern der einzelnen zellen + for (int c = 0; c < nofCells; c++) { + idummy = val<1>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<2>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<3>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<4>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<5>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<6>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<7>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<8>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + } + + // coords + // x1-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<1>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x2-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<2>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x3-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<3>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + + // NODE DATA + char labels[1024]; + char units[1024]; + strcpy(labels, ""); + strcpy(units, ""); + + for (int d = 0; d < nofNodeData - 1; ++d) { + strcat(labels, datanames[d].c_str()); + strcat(labels, "."); + } + strcat(labels, datanames[nofNodeData - 1].c_str()); + + for (int i = 0; i < (nofNodeData - 1); i++) + strcat(units, "no_unit."); + strcat(units, "no_unit"); + + out.write((char *)&labels, sizeof(labels)); + out.write((char *)&units, sizeof(units)); + + // nof and type of data + idummy = nofNodeData; + out.write((char *)&idummy, sizeof(int)); // Datentypen pro knoten (hier = nof_node_data, da NUR skalare) + + idummy = 1; + for (int i = 0; i < nofNodeData; i++) + out.write((char *)&idummy, sizeof(int)); // jeder Datentyp ist ein skalarer Wert + + // min and max of data + fdummy = 0.0; + for (int i = 0; i < nofNodeData; i++) + out.write((char *)&fdummy, sizeof(float)); // min Wert pro Datentyp + fdummy = 1.0; + for (int i = 0; i < nofNodeData; i++) + out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp + + // daten ins file schreiben + for (int d = 0; d < nofNodeData; ++d) + for (int n = 0; n < (int)nodedata[d].size(); n++) { + fdummy = (float)nodedata[d][n]; + out.write((char *)&fdummy, sizeof(float)); + } + + fdummy = 1.; + for (int i = 0; i < nofNodeData; i++) + out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp + + out.close(); + UBLOG(logDEBUG1, "WbWriterAvsASCII::writeOctsWithNodeData to " << avsfilename << " - end"); + + return avsfilename; +} diff --git a/src/basics/basics/writer/WbWriterAvsASCII.h b/src/basics/basics/writer/WbWriterAvsASCII.h new file mode 100644 index 0000000000000000000000000000000000000000..f5a462c70f11ddd7b1e4b76ab935b9ad1f988523 --- /dev/null +++ b/src/basics/basics/writer/WbWriterAvsASCII.h @@ -0,0 +1,118 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file WbWriterAvsASCII.h +//! \ingroup writer +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#ifndef WBWRITERAVSASCII_H +#define WBWRITERAVSASCII_H + +#include <basics/writer/WbWriter.h> + +class WbWriterAvsASCII : public WbWriter +{ +public: + static WbWriterAvsASCII *getInstance() + { + static WbWriterAvsASCII instance; + return &instance; + } + + WbWriterAvsASCII(const WbWriterAvsASCII &) = delete; + const WbWriterAvsASCII &operator=(const WbWriterAvsASCII &) = delete; + +private: + WbWriterAvsASCII() = default; + +public: + std::string getFileExtension() override { return ".ascii.inp"; } + + ///////////////////virtual std::string writeOcts(const std::string& filename,std::vector< UbTupleFloat3 >& nodes, + ///std::vector< UbTupleInt8 >& cells) = 0; + /////////////////////////////////////////////////////// + // lines + // 0 ---- 1 + // nodenumbering must start with 0! + std::string writeLines(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt2> &lines) override; + + ////////////////////////////////////////////////////////////////////////// + // triangles + // cell numbering: + // 2 + // + // 0---1 + // nodenumbering must start with 0! + std::string writeTriangles(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTuple<int, int, int>> &triangles) override; + std::string writeTrianglesWithNodeData(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt3> &cells, std::vector<std::string> &datanames, + std::vector<std::vector<double>> &nodedata) override; + + ////////////////////////////////////////////////////////////////////////// + // quads + // cell numbering: + // 3---2 + // | | + // 0---1 + // nodenumbering must start with 0! + std::string writeQuads(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt4> &cells) override; + std::string writeQuadsWithNodeData(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt4> &cells, std::vector<std::string> &datanames, + std::vector<std::vector<double>> &nodedata) override; + std::string writeQuadsWithCellData(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt4> &cells, std::vector<std::string> &datanames, + std::vector<std::vector<double>> &celldata) override; + std::string writeQuadsWithNodeAndCellData(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt4> &cells, std::vector<std::string> &nodedatanames, + std::vector<std::vector<double>> &nodedata, + std::vector<std::string> &celldatanames, + std::vector<std::vector<double>> &celldata) override; + + ////////////////////////////////////////////////////////////////////////// + // octs + // 7 ---- 6 + // /| /| + // 4 +--- 5 | + // | | | | + // | 3 ---+ 2 + // |/ |/ + // 0 ---- 1 + std::string writeOcts(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt8> &cells) override; + std::string writeOctsWithCellData(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt8> &cells, std::vector<std::string> &datanames, + std::vector<std::vector<double>> &celldata) override; + std::string writeOctsWithNodeData(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleUInt8> &cells, std::vector<std::string> &datanames, + std::vector<std::vector<double>> &nodedata) override; +}; + +#endif // WBWRITERAVSASCII_H diff --git a/src/basics/basics/writer/WbWriterAvsBinary.cpp b/src/basics/basics/writer/WbWriterAvsBinary.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8ce19629448cff4ebbb33a61eaead0bca119a998 --- /dev/null +++ b/src/basics/basics/writer/WbWriterAvsBinary.cpp @@ -0,0 +1,1254 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file WbWriterAvsBinary.cpp +//! \ingroup writer +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#include <basics/utilities/UbLogger.h> +#include <basics/utilities/UbSystem.h> +#include <basics/writer/WbWriterAvsASCII.h> +#include <basics/writer/WbWriterAvsBinary.h> + +#include <cstring> + +using namespace std; + +std::string WbWriterAvsBinary::writeLines(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt2> &lines) +{ + string avsfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterAvsBinary::writeLines to " << avsfilename << " - start"); + + ofstream out(avsfilename.c_str(), ios::out | ios::binary); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!! + string path = UbSystem::getPathFromString(avsfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(avsfilename.c_str(), ios::out | ios::binary); + } + if (!out) + throw UbException(UB_EXARGS, avsfilename + " konnte nicht geschrieben werden"); + } + + char magic = (char)7; + int idummy; + float fdummy; + + int nofNodes = (int)nodes.size(); + int nofCells = (int)lines.size(); + + int nofNodeData = 0; + int nofCellData = 0; + int nofModelData = 0; + int cellType = 1; // line + int nofNodesPerCell = 2; + + out.write((char *)&magic, sizeof(char)); + out.write((char *)&nofNodes, sizeof(int)); + out.write((char *)&nofCells, sizeof(int)); + out.write((char *)&nofNodeData, sizeof(int)); + out.write((char *)&nofCellData, sizeof(int)); + out.write((char *)&nofModelData, sizeof(int)); + + idummy = (int)nofCells * nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell) + for (int c = 0; c < nofCells; c++) { + idummy = c + 1; + out.write((char *)&idummy, sizeof(int)); // cell id + idummy = 1; + out.write((char *)&idummy, sizeof(int)); // mat + idummy = nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); // nodes per cell + idummy = cellType; + out.write((char *)&idummy, sizeof(int)); // cell type + } + // knotennummern der einzelnen zellen + for (int c = 0; c < nofCells; c++) { + idummy = val<1>(lines[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<2>(lines[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + } + + // coords + // x1-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<1>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x2-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<2>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x3-coords + fdummy = 0.0; + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<3>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // out<<"\n"; + + out.close(); + UBLOG(logDEBUG1, "WbWriterAvsBinary::writeLines to " << avsfilename << " - end"); + + return avsfilename; +} +/*===============================================================================*/ +std::string WbWriterAvsBinary::writeTriangles(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTuple<int, int, int>> &triangles) +{ + string avsfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterAvsBinary::writeTriangles to " << avsfilename << " - start"); + + ofstream out(avsfilename.c_str(), ios::out | ios::binary); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!! + string path = UbSystem::getPathFromString(avsfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(avsfilename.c_str(), ios::out | ios::binary); + } + if (!out) + throw UbException(UB_EXARGS, avsfilename + " konnte nicht geschrieben werden"); + } + + char magic = (char)7; + int idummy; + float fdummy; + + int nofNodes = (int)nodes.size(); + int nofCells = (int)triangles.size(); + + int nofNodeData = 0; + int nofCellData = 0; + int nofModelData = 0; + int cellType = 2; // triangle + int nofNodesPerCell = 3; + + out.write((char *)&magic, sizeof(char)); + out.write((char *)&nofNodes, sizeof(int)); + out.write((char *)&nofCells, sizeof(int)); + out.write((char *)&nofNodeData, sizeof(int)); + out.write((char *)&nofCellData, sizeof(int)); + out.write((char *)&nofModelData, sizeof(int)); + + idummy = (int)nofCells * nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell) + for (int c = 0; c < nofCells; c++) { + idummy = c + 1; + out.write((char *)&idummy, sizeof(int)); // cell id + idummy = 1; + out.write((char *)&idummy, sizeof(int)); // mat + idummy = nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); // nodes per cell + idummy = cellType; + out.write((char *)&idummy, sizeof(int)); // cell type + } + // knotennummern der einzelnen zellen + for (int c = 0; c < nofCells; c++) { + idummy = val<1>(triangles[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<2>(triangles[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<3>(triangles[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + } + + // coords + // x1-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<1>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x2-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<2>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x3-coords + fdummy = 0.0; + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<3>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // out<<"\n"; + + out.close(); + UBLOG(logDEBUG1, "WbWriterAvsBinary::writeTriangles to " << avsfilename << " - end"); + + return avsfilename; +} +/*===============================================================================*/ +std::string WbWriterAvsBinary::writeQuads(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt4> &cells) +{ + string avsfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterAvsBinary::writeQuads to " << avsfilename << " - start"); + + ofstream out(avsfilename.c_str(), ios::out | ios::binary); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!! + string path = UbSystem::getPathFromString(avsfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(avsfilename.c_str(), ios::out | ios::binary); + } + if (!out) + throw UbException(UB_EXARGS, avsfilename + " konnte nicht geschrieben werden"); + } + char magic = (char)7; + int idummy; + float fdummy; + + int nofNodes = (int)nodes.size(); + int nofCells = (int)cells.size(); + + int nofNodeData = 0; + int nofCellData = 0; + int nofModelData = 0; + int cellType = 3; //=quad + int nofNodesPerCell = 4; + + out.write((char *)&magic, sizeof(char)); + out.write((char *)&nofNodes, sizeof(int)); + out.write((char *)&nofCells, sizeof(int)); + out.write((char *)&nofNodeData, sizeof(int)); + out.write((char *)&nofCellData, sizeof(int)); + out.write((char *)&nofModelData, sizeof(int)); + + idummy = (int)nofCells * nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell) + for (int c = 0; c < nofCells; c++) { + idummy = c + 1; + out.write((char *)&idummy, sizeof(int)); // cell id + idummy = 1; + out.write((char *)&idummy, sizeof(int)); // mat + idummy = nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); // nodes per cell + idummy = cellType; + out.write((char *)&idummy, sizeof(int)); // cell type + } + // knotennummern der einzelnen zellen + for (int c = 0; c < nofCells; c++) { + idummy = val<1>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<2>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<3>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<4>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + } + + // coords + // x1-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<1>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x2-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<2>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x3-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<3>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // out<<"\n"; + + out.close(); + UBLOG(logDEBUG1, "WbWriterAvsBinary::writeQuads to " << avsfilename << " - end"); + + return avsfilename; +} +/*===============================================================================*/ +std::string WbWriterAvsBinary::writeOcts(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt8> &cells) +{ + string avsfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterAvsBinary::writeOcts to " << avsfilename << " - start"); + + ofstream out(avsfilename.c_str(), ios::out | ios::binary); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!! + string path = UbSystem::getPathFromString(avsfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(avsfilename.c_str(), ios::out | ios::binary); + } + if (!out) + throw UbException(UB_EXARGS, "file konnte nicht geschrieben werden"); + } + + char magic = (char)7; + int idummy; + float fdummy; + + int nofNodes = (int)nodes.size(); + int nofCells = (int)cells.size(); + + int nofNodeData = 0; + int nofCellData = 0; + int nofModelData = 0; + int cellType = 7; //=hex + int nofNodesPerCell = 8; + + out.write((char *)&magic, sizeof(char)); + out.write((char *)&nofNodes, sizeof(int)); + out.write((char *)&nofCells, sizeof(int)); + out.write((char *)&nofNodeData, sizeof(int)); + out.write((char *)&nofCellData, sizeof(int)); + out.write((char *)&nofModelData, sizeof(int)); + + idummy = (int)nofCells * nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell) + for (int c = 0; c < nofCells; c++) { + idummy = c + 1; + out.write((char *)&idummy, sizeof(int)); // cell id + idummy = 1; + out.write((char *)&idummy, sizeof(int)); // mat + idummy = nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); // nodes per cell + idummy = cellType; + out.write((char *)&idummy, sizeof(int)); // cell type + } + // knotennummern der einzelnen zellen + for (int c = 0; c < nofCells; c++) { + idummy = val<1>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<2>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<3>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<4>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<5>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<6>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<7>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<8>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + } + + // coords + // x1-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<1>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x2-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<2>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x3-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<3>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // out<<"\n"; + + out.close(); + UBLOG(logDEBUG1, "WbWriterAvsBinary::writeOcts to " << avsfilename << " - end"); + + return avsfilename; +} +/*===============================================================================*/ +std::string WbWriterAvsBinary::writeTrianglesWithNodeData(const std::string &filename, + std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt3> &cells, + std::vector<std::string> &datanames, + std::vector<std::vector<double>> &nodedata) +{ + string avsfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterAvsBinary::writeTrianglesWithNodeData to " << avsfilename << " - start"); + + ofstream out(avsfilename.c_str(), ios::out | ios::binary); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!! + string path = UbSystem::getPathFromString(avsfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(avsfilename.c_str(), ios::out | ios::binary); + } + if (!out) + throw UbException(UB_EXARGS, + "write_OutputFile-UCD File " + avsfilename + " konnte nicht geschrieben werden"); + } + char magic = (char)7; + int idummy; + float fdummy; + + int nofNodes = (int)nodes.size(); + int nofCells = (int)cells.size(); + + int nofNodeData = (int)datanames.size(); + int nofCellData = 0; + int nofModelData = 0; + int cellType = 2; // triangle + int nofNodesPerCell = 3; + + out.write((char *)&magic, sizeof(char)); + out.write((char *)&nofNodes, sizeof(int)); + out.write((char *)&nofCells, sizeof(int)); + out.write((char *)&nofNodeData, sizeof(int)); + out.write((char *)&nofCellData, sizeof(int)); + out.write((char *)&nofModelData, sizeof(int)); + + idummy = (int)nofCells * nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell) + for (int c = 0; c < nofCells; c++) { + idummy = c + 1; + out.write((char *)&idummy, sizeof(int)); // cell id + idummy = 1; + out.write((char *)&idummy, sizeof(int)); // mat + idummy = nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); // nodes per cell + idummy = cellType; + out.write((char *)&idummy, sizeof(int)); // cell type + } + // knotennummern der einzelnen zellen + for (int c = 0; c < nofCells; c++) { + idummy = val<1>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<2>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<3>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + } + + // coords + // x1-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<1>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x2-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<2>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x3-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<3>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // out<<"\n"; + + // NODE DATA + char labels[1024]; + char units[1024]; + strcpy(labels, ""); + strcpy(units, ""); + + for (int d = 0; d < nofNodeData - 1; ++d) { + strcat(labels, datanames[d].c_str()); + strcat(labels, "."); + } + strcat(labels, datanames[nofNodeData - 1].c_str()); + + for (int i = 0; i < (nofNodeData - 1); i++) + strcat(units, "no_unit."); + strcat(units, "no_unit"); + + out.write((char *)&labels, sizeof(labels)); + out.write((char *)&units, sizeof(units)); + + // nof and type of data + idummy = nofNodeData; + out.write((char *)&idummy, sizeof(int)); // Datentypen pro knoten (hier = nof_node_data, da NUR skalare) + + idummy = 1; + for (int i = 0; i < nofNodeData; i++) + out.write((char *)&idummy, sizeof(int)); // jeder Datentyp ist ein skalarer Wert + + // min and max of data + fdummy = 0.0; + for (int i = 0; i < nofNodeData; i++) + out.write((char *)&fdummy, sizeof(float)); // min Wert pro Datentyp + fdummy = 1.0; + for (int i = 0; i < nofNodeData; i++) + out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp + + // daten ins file schreiben + for (int d = 0; d < nofNodeData; ++d) + for (int n = 0; n < (int)nodedata[d].size(); n++) { + fdummy = (float)nodedata[d][n]; + out.write((char *)&fdummy, sizeof(float)); + } + + fdummy = 1.; + for (int i = 0; i < nofNodeData; i++) + out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp + + out.close(); + UBLOG(logDEBUG1, "WbWriterAvsBinary::writeTrianglesWithNodeData to " << avsfilename << " - end"); + + return avsfilename; +} +/*===============================================================================*/ +std::string WbWriterAvsBinary::writeQuadsWithNodeData(const string &filename, vector<UbTupleFloat3> &nodes, + vector<UbTupleInt4> &cells, vector<string> &datanames, + vector<vector<double>> &nodedata) +{ + string avsfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterAvsBinary::writeQuadsWithNodeData to " << avsfilename << " - start"); + + ofstream out(avsfilename.c_str(), ios::out | ios::binary); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!! + string path = UbSystem::getPathFromString(avsfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(avsfilename.c_str(), ios::out | ios::binary); + } + if (!out) + throw UbException(UB_EXARGS, + "write_OutputFile-UCD File " + avsfilename + " konnte nicht geschrieben werden"); + } + char magic = (char)7; + int idummy; + float fdummy; + + int nofNodes = (int)nodes.size(); + int nofCells = (int)cells.size(); + + int nofNodeData = (int)datanames.size(); + int nofCellData = 0; + int nofModelData = 0; + int cellType = 3; //=quad + int nofNodesPerCell = 4; + + out.write((char *)&magic, sizeof(char)); + out.write((char *)&nofNodes, sizeof(int)); + out.write((char *)&nofCells, sizeof(int)); + out.write((char *)&nofNodeData, sizeof(int)); + out.write((char *)&nofCellData, sizeof(int)); + out.write((char *)&nofModelData, sizeof(int)); + + idummy = (int)nofCells * nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell) + for (int c = 0; c < nofCells; c++) { + idummy = c + 1; + out.write((char *)&idummy, sizeof(int)); // cell id + idummy = 1; + out.write((char *)&idummy, sizeof(int)); // mat + idummy = nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); // nodes per cell + idummy = cellType; + out.write((char *)&idummy, sizeof(int)); // cell type + } + // knotennummern der einzelnen zellen + for (int c = 0; c < nofCells; c++) { + idummy = val<1>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<2>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<3>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<4>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + } + + // coords + // x1-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<1>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x2-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<2>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x3-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<3>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // out<<"\n"; + + // NODE DATA + char labels[1024]; + char units[1024]; + strcpy(labels, ""); + strcpy(units, ""); + + for (int d = 0; d < nofNodeData - 1; ++d) { + strcat(labels, datanames[d].c_str()); + strcat(labels, "."); + } + strcat(labels, datanames[nofNodeData - 1].c_str()); + + for (int i = 0; i < (nofNodeData - 1); i++) + strcat(units, "no_unit."); + strcat(units, "no_unit"); + + out.write((char *)&labels, sizeof(labels)); + out.write((char *)&units, sizeof(units)); + + // nof and type of data + idummy = nofNodeData; + out.write((char *)&idummy, sizeof(int)); // Datentypen pro knoten (hier = nof_node_data, da NUR skalare) + + idummy = 1; + for (int i = 0; i < nofNodeData; i++) + out.write((char *)&idummy, sizeof(int)); // jeder Datentyp ist ein skalarer Wert + + // min and max of data + fdummy = 0.0; + for (int i = 0; i < nofNodeData; i++) + out.write((char *)&fdummy, sizeof(float)); // min Wert pro Datentyp + fdummy = 1.0; + for (int i = 0; i < nofNodeData; i++) + out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp + + // daten ins file schreiben + for (int d = 0; d < nofNodeData; ++d) + for (int n = 0; n < (int)nodedata[d].size(); n++) { + fdummy = (float)nodedata[d][n]; + out.write((char *)&fdummy, sizeof(float)); + } + + fdummy = 1.; + for (int i = 0; i < nofNodeData; i++) + out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp + + out.close(); + UBLOG(logDEBUG1, "WbWriterAvsBinary::writeQuadsWithNodeData to " << avsfilename << " - end"); + + return avsfilename; +} +/*===============================================================================*/ +std::string WbWriterAvsBinary::writeQuadsWithCellData(const string &filename, vector<UbTupleFloat3> &nodes, + vector<UbTupleInt4> &cells, vector<string> &datanames, + vector<vector<double>> &celldata) +{ + string avsfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterAvsBinary::writeQuadsWithCellData to " << avsfilename << " - start"); + + ofstream out(avsfilename.c_str(), ios::out | ios::binary); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!! + string path = UbSystem::getPathFromString(avsfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(avsfilename.c_str(), ios::out | ios::binary); + } + if (!out) + throw UbException(UB_EXARGS, avsfilename + " konnte nicht geschrieben werden"); + } + + char magic = (char)7; + int idummy; + float fdummy; + + int nofNodes = (int)nodes.size(); + int nofCells = (int)cells.size(); + + int nofNodeData = 0; + int nofCellData = (int)datanames.size(); + int nofModelData = 0; + int cellType = 3; //=quad + int nofNodesPerCell = 4; + + out.write((char *)&magic, sizeof(char)); + out.write((char *)&nofNodes, sizeof(int)); + out.write((char *)&nofCells, sizeof(int)); + out.write((char *)&nofNodeData, sizeof(int)); + out.write((char *)&nofCellData, sizeof(int)); + out.write((char *)&nofModelData, sizeof(int)); + + idummy = (int)nofCells * nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell) + for (int c = 0; c < nofCells; c++) { + idummy = c + 1; + out.write((char *)&idummy, sizeof(int)); // cell id + idummy = 1; + out.write((char *)&idummy, sizeof(int)); // mat + idummy = nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); // nodes per cell + idummy = cellType; + out.write((char *)&idummy, sizeof(int)); // cell type + } + // knotennummern der einzelnen zellen + for (int c = 0; c < nofCells; c++) { + idummy = val<1>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<2>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<3>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<4>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + } + + // coords + // x1-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<1>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x2-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<2>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x3-coords + fdummy = 0.0; + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<3>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // out<<"\n"; + + // CELL DATA + char labels[1024]; + char units[1024]; + strcpy(labels, ""); + strcpy(units, ""); + + for (int d = 0; d < nofCellData - 1; ++d) { + strcat(labels, datanames[d].c_str()); + strcat(labels, "."); + } + strcat(labels, datanames[nofCellData - 1].c_str()); + + for (int d = 0; d < nofCellData - 1; ++d) + strcat(units, "no_unit."); + strcat(units, "no_unit"); + + out.write((char *)&labels, sizeof(labels)); + out.write((char *)&units, sizeof(units)); + + // nof and type of data + idummy = nofCellData; + out.write((char *)&idummy, sizeof(int)); // Datentypen pro knoten (hier = nof_node_data, da NUR skalare) + + idummy = 1; + for (int i = 0; i < nofCellData; i++) + out.write((char *)&idummy, sizeof(int)); // jeder Datentyp ist ein skalarer Wert + + // min and max of data + fdummy = 0.0; + for (int i = 0; i < nofCellData; i++) + out.write((char *)&fdummy, sizeof(float)); // min Wert pro Datentyp + fdummy = 1.0; + for (int i = 0; i < nofCellData; i++) + out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp + + // daten ins file schreiben + for (int d = 0; d < nofCellData; ++d) + for (int n = 0; n < (int)celldata[d].size(); n++) { + fdummy = (float)celldata[d][n]; + out.write((char *)&fdummy, sizeof(float)); + } + + fdummy = 1.; + for (int i = 0; i < nofCellData; i++) + out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp + + out.close(); + UBLOG(logDEBUG1, "WbWriterAvsBinary::writeQuadsWithCellData to " << avsfilename << " - end"); + + return avsfilename; +} +/*===============================================================================*/ +std::string WbWriterAvsBinary::writeQuadsWithNodeAndCellData(const string &filename, vector<UbTupleFloat3> &nodes, + vector<UbTupleInt4> &cells, vector<string> &nodedatanames, + vector<vector<double>> &nodedata, + vector<string> &celldatanames, + vector<vector<double>> &celldata) +{ + string avsfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterAvsBinary::writeQuadsWithNodeAndCellData to " << avsfilename << " - start"); + + ofstream out(avsfilename.c_str(), ios::out | ios::binary); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!! + string path = UbSystem::getPathFromString(avsfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(avsfilename.c_str(), ios::out | ios::binary); + } + if (!out) + throw UbException(UB_EXARGS, avsfilename + " konnte nicht geschrieben werden"); + } + + char magic = (char)7; + int idummy; + float fdummy; + + int nofNodes = (int)nodes.size(); + int nofCells = (int)cells.size(); + + int nofNodeData = (int)nodedatanames.size(); + int nofCellData = (int)celldatanames.size(); + int nofModelData = 0; + int cellType = 3; //=quad + int nofNodesPerCell = 4; + + out.write((char *)&magic, sizeof(char)); + out.write((char *)&nofNodes, sizeof(int)); + out.write((char *)&nofCells, sizeof(int)); + out.write((char *)&nofNodeData, sizeof(int)); + out.write((char *)&nofCellData, sizeof(int)); + out.write((char *)&nofModelData, sizeof(int)); + + idummy = (int)nofCells * nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell) + for (int c = 0; c < nofCells; c++) { + idummy = c + 1; + out.write((char *)&idummy, sizeof(int)); // cell id + idummy = 1; + out.write((char *)&idummy, sizeof(int)); // mat + idummy = nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); // nodes per cell + idummy = cellType; + out.write((char *)&idummy, sizeof(int)); // cell type + } + // knotennummern der einzelnen zellen + for (int c = 0; c < nofCells; c++) { + idummy = val<1>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<2>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<3>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<4>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + } + + // coords + // x1-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<1>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x2-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<2>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x3-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<3>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // out<<"\n"; + + // NODE DATA + char nodelabels[1024]; + char nodeunits[1024]; + strcpy(nodelabels, ""); + strcpy(nodeunits, ""); + + for (int d = 0; d < nofNodeData - 1; ++d) { + strcat(nodelabels, nodedatanames[d].c_str()); + strcat(nodelabels, "."); + } + strcat(nodelabels, nodedatanames[nofNodeData - 1].c_str()); + + for (int i = 0; i < (nofNodeData - 1); i++) + strcat(nodeunits, "no_unit."); + strcat(nodeunits, "no_unit"); + + out.write((char *)&nodelabels, sizeof(nodelabels)); + out.write((char *)&nodeunits, sizeof(nodeunits)); + + // nof and type of data + idummy = nofNodeData; + out.write((char *)&idummy, sizeof(int)); // Datentypen pro knoten (hier = nof_node_data, da NUR skalare) + + idummy = 1; + for (int i = 0; i < nofNodeData; i++) + out.write((char *)&idummy, sizeof(int)); // jeder Datentyp ist ein skalarer Wert + + // min and max of data + fdummy = 0.0; + for (int i = 0; i < nofNodeData; i++) + out.write((char *)&fdummy, sizeof(float)); // min Wert pro Datentyp + fdummy = 1.0; + for (int i = 0; i < nofNodeData; i++) + out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp + + // daten ins file schreiben + for (int d = 0; d < nofNodeData; ++d) + for (int n = 0; n < (int)nodedata[d].size(); n++) { + fdummy = (float)nodedata[d][n]; + out.write((char *)&fdummy, sizeof(float)); + } + + fdummy = 1.; + for (int i = 0; i < nofNodeData; i++) + out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp + + // CELL DATA + char celllabels[1024]; + char cellunits[1024]; + strcpy(celllabels, ""); + strcpy(cellunits, ""); + + for (int d = 0; d < nofCellData - 1; ++d) { + strcat(celllabels, celldatanames[d].c_str()); + strcat(celllabels, "."); + } + strcat(celllabels, celldatanames[nofCellData - 1].c_str()); + + for (int d = 0; d < nofCellData - 1; ++d) + strcat(cellunits, "no_unit."); + strcat(cellunits, "no_unit"); + + out.write((char *)&celllabels, sizeof(celllabels)); + out.write((char *)&cellunits, sizeof(cellunits)); + + // nof and type of data + idummy = nofCellData; + out.write((char *)&idummy, sizeof(int)); // Datentypen pro knoten (hier = nof_node_data, da NUR skalare) + + idummy = 1; + for (int i = 0; i < nofCellData; i++) + out.write((char *)&idummy, sizeof(int)); // jeder Datentyp ist ein skalarer Wert + + // min and max of data + fdummy = 0.0; + for (int i = 0; i < nofCellData; i++) + out.write((char *)&fdummy, sizeof(float)); // min Wert pro Datentyp + fdummy = 1.0; + for (int i = 0; i < nofCellData; i++) + out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp + + // daten ins file schreiben + for (int d = 0; d < nofCellData; ++d) + for (int n = 0; n < (int)celldata[d].size(); n++) { + fdummy = (float)celldata[d][n]; + out.write((char *)&fdummy, sizeof(float)); + } + + fdummy = 1.; + for (int i = 0; i < nofCellData; i++) + out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp + + out.close(); + UBLOG(logDEBUG1, "WbWriterAvsBinary::writeQuadsWithNodeAndCellData to " << avsfilename << " - end"); + + return avsfilename; +} +/*===============================================================================*/ +std::string WbWriterAvsBinary::writeOctsWithCellData(const string &filename, vector<UbTupleFloat3> &nodes, + vector<UbTupleInt8> &cells, vector<string> &datanames, + vector<vector<double>> &celldata) +{ + string avsfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterAvsBinary::writeOctsWithCellData to " << avsfilename << " - start"); + + ofstream out(avsfilename.c_str(), ios::out | ios::binary); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!! + string path = UbSystem::getPathFromString(avsfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(avsfilename.c_str(), ios::out | ios::binary); + } + if (!out) + throw UbException(UB_EXARGS, "file konnte nicht geschrieben werden"); + } + + char magic = (char)7; + int idummy; + float fdummy; + + int nofNodes = (int)nodes.size(); + int nofCells = (int)cells.size(); + + int nofNodeData = 0; + int nofCellData = (int)datanames.size(); + int nofModelData = 0; + int cellType = 7; //=hex + int nofNodesPerCell = 8; + + out.write((char *)&magic, sizeof(char)); + out.write((char *)&nofNodes, sizeof(int)); + out.write((char *)&nofCells, sizeof(int)); + out.write((char *)&nofNodeData, sizeof(int)); + out.write((char *)&nofCellData, sizeof(int)); + out.write((char *)&nofModelData, sizeof(int)); + + idummy = (int)nofCells * nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell) + for (int c = 0; c < nofCells; c++) { + idummy = c + 1; + out.write((char *)&idummy, sizeof(int)); // cell id + idummy = 1; + out.write((char *)&idummy, sizeof(int)); // mat + idummy = nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); // nodes per cell + idummy = cellType; + out.write((char *)&idummy, sizeof(int)); // cell type + } + // knotennummern der einzelnen zellen + for (int c = 0; c < nofCells; c++) { + idummy = val<1>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<2>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<3>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<4>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<5>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<6>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<7>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<8>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + } + + // coords + // x1-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<1>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x2-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<2>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x3-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<3>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // out<<"\n"; + + // CELL DATA + char labels[1024]; + char units[1024]; + strcpy(labels, ""); + strcpy(units, ""); + + for (int d = 0; d < nofCellData - 1; ++d) { + strcat(labels, datanames[d].c_str()); + strcat(labels, "."); + } + strcat(labels, datanames[nofCellData - 1].c_str()); + + for (int d = 0; d < nofCellData - 1; ++d) + strcat(units, "no_unit."); + strcat(units, "no_unit"); + + out.write((char *)&labels, sizeof(labels)); + out.write((char *)&units, sizeof(units)); + + // nof and type of data + idummy = nofCellData; + out.write((char *)&idummy, sizeof(int)); // Datentypen pro knoten (hier = nof_node_data, da NUR skalare) + + idummy = 1; + for (int i = 0; i < nofCellData; i++) + out.write((char *)&idummy, sizeof(int)); // jeder Datentyp ist ein skalarer Wert + + // min and max of data + fdummy = 0.0; + for (int i = 0; i < nofCellData; i++) + out.write((char *)&fdummy, sizeof(float)); // min Wert pro Datentyp + fdummy = 1.0; + for (int i = 0; i < nofCellData; i++) + out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp + + // daten ins file schreiben + for (int d = 0; d < nofCellData; ++d) + for (int n = 0; n < (int)celldata[d].size(); n++) { + fdummy = (float)celldata[d][n]; + out.write((char *)&fdummy, sizeof(float)); + } + + fdummy = 1.; + for (int i = 0; i < nofCellData; i++) + out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp + + out.close(); + UBLOG(logDEBUG1, "WbWriterAvsBinary::writeOctsWithCellData to " << avsfilename << " - end"); + + return avsfilename; +} +/*===============================================================================*/ +std::string WbWriterAvsBinary::writeOctsWithNodeData(const string &filename, vector<UbTupleFloat3> &nodes, + vector<UbTupleUInt8> &cells, vector<string> &datanames, + vector<vector<double>> &nodedata) +{ + string avsfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterAvsBinary::writeOctsWithNodeData to " << avsfilename << " - start"); + + ofstream out(avsfilename.c_str(), ios::out | ios::binary); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!! + string path = UbSystem::getPathFromString(avsfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(avsfilename.c_str(), ios::out | ios::binary); + } + if (!out) + throw UbException(UB_EXARGS, "file konnte nicht geschrieben werden"); + } + + if ((int)nodedata.size() == 0) + throw UbException(UB_EXARGS, "no nodedata!!!"); + if (nodes.size() != nodedata[0].size()) + throw UbException(UB_EXARGS, "nodedata != nofNodes!!!"); + + char magic = (char)7; + int idummy; + float fdummy; + + int nofNodes = (int)nodes.size(); + int nofCells = (int)cells.size(); + + int nofNodeData = (int)datanames.size(); + int nofCellData = 0; + int nofModelData = 0; + int cellType = 7; //=hex + int nofNodesPerCell = 8; + + out.write((char *)&magic, sizeof(char)); + out.write((char *)&nofNodes, sizeof(int)); + out.write((char *)&nofCells, sizeof(int)); + out.write((char *)&nofNodeData, sizeof(int)); + out.write((char *)&nofCellData, sizeof(int)); + out.write((char *)&nofModelData, sizeof(int)); + + idummy = (int)nofCells * nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell) + for (int c = 0; c < nofCells; c++) { + idummy = c + 1; + out.write((char *)&idummy, sizeof(int)); // cell id + idummy = 1; + out.write((char *)&idummy, sizeof(int)); // mat + idummy = nofNodesPerCell; + out.write((char *)&idummy, sizeof(int)); // nodes per cell + idummy = cellType; + out.write((char *)&idummy, sizeof(int)); // cell type + } + // knotennummern der einzelnen zellen + for (int c = 0; c < nofCells; c++) { + idummy = val<1>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<2>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<3>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<4>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<5>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<6>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<7>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + idummy = val<8>(cells[c]) + 1; + out.write((char *)&idummy, sizeof(int)); + } + + // coords + // x1-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<1>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x2-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<2>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + // x3-coords + for (int n = 0; n < nofNodes; n++) { + fdummy = (float)(val<3>(nodes[n])); + out.write((char *)&fdummy, sizeof(float)); + } + + // NODE DATA + char labels[1024]; + char units[1024]; + strcpy(labels, ""); + strcpy(units, ""); + + for (int d = 0; d < nofNodeData - 1; ++d) { + strcat(labels, datanames[d].c_str()); + strcat(labels, "."); + } + strcat(labels, datanames[nofNodeData - 1].c_str()); + + for (int i = 0; i < (nofNodeData - 1); i++) + strcat(units, "no_unit."); + strcat(units, "no_unit"); + + out.write((char *)&labels, sizeof(labels)); + out.write((char *)&units, sizeof(units)); + + // nof and type of data + idummy = nofNodeData; + out.write((char *)&idummy, sizeof(int)); // Datentypen pro knoten (hier = nof_node_data, da NUR skalare) + + idummy = 1; + for (int i = 0; i < nofNodeData; i++) + out.write((char *)&idummy, sizeof(int)); // jeder Datentyp ist ein skalarer Wert + + // min and max of data + fdummy = 0.0; + for (int i = 0; i < nofNodeData; i++) + out.write((char *)&fdummy, sizeof(float)); // min Wert pro Datentyp + fdummy = 1.0; + for (int i = 0; i < nofNodeData; i++) + out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp + + // daten ins file schreiben + for (int d = 0; d < nofNodeData; ++d) + for (int n = 0; n < (int)nodedata[d].size(); n++) { + fdummy = (float)nodedata[d][n]; + out.write((char *)&fdummy, sizeof(float)); + } + + fdummy = 1.; + for (int i = 0; i < nofNodeData; i++) + out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp + + out.close(); + UBLOG(logDEBUG1, "WbWriterAvsBinary::writeOctsWithNodeData to " << avsfilename << " - end"); + + return avsfilename; +} diff --git a/src/basics/basics/writer/WbWriterAvsBinary.h b/src/basics/basics/writer/WbWriterAvsBinary.h new file mode 100644 index 0000000000000000000000000000000000000000..ef6c73cacbfdac1d8ad500022ec2e3cafe0d373e --- /dev/null +++ b/src/basics/basics/writer/WbWriterAvsBinary.h @@ -0,0 +1,116 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file WbWriterAvsBinary.h +//! \ingroup writer +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#ifndef WBWRITERAVSBINARY_H +#define WBWRITERAVSBINARY_H + +#include <basics/writer/WbWriter.h> + +class WbWriterAvsBinary : public WbWriter +{ +public: + static WbWriterAvsBinary *getInstance() + { + static WbWriterAvsBinary instance; + return &instance; + } + + WbWriterAvsBinary(const WbWriterAvsBinary &) = delete; + const WbWriterAvsBinary &operator=(const WbWriterAvsBinary &) = delete; + +private: + WbWriterAvsBinary() = default; + +public: + std::string getFileExtension() override { return ".bin.inp"; } + + ////////////////////////////////////////////////////////////////////////// + // lines + // 0 ---- 1 + // nodenumbering must start with 0! + std::string writeLines(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt2> &lines) override; + + ////////////////////////////////////////////////////////////////////////// + // triangles + // cell numbering: + // 2 + // + // 0---1 + // nodenumbering must start with 0! + std::string writeTriangles(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTuple<int, int, int>> &triangles) override; + std::string writeTrianglesWithNodeData(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt3> &cells, std::vector<std::string> &datanames, + std::vector<std::vector<double>> &nodedata) override; + + ////////////////////////////////////////////////////////////////////////// + // quads + // cell numbering: + // 3---2 + // | | + // 0---1 + // nodenumbering must start with 0! + std::string writeQuads(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt4> &cells) override; + std::string writeQuadsWithNodeData(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt4> &cells, std::vector<std::string> &datanames, + std::vector<std::vector<double>> &nodedata) override; + std::string writeQuadsWithCellData(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt4> &cells, std::vector<std::string> &datanames, + std::vector<std::vector<double>> &celldata) override; + std::string writeQuadsWithNodeAndCellData(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt4> &cells, std::vector<std::string> &nodedatanames, + std::vector<std::vector<double>> &nodedata, + std::vector<std::string> &celldatanames, + std::vector<std::vector<double>> &celldata) override; + + ////////////////////////////////////////////////////////////////////////// + // octs + // 7 ---- 6 + // /| /| + // 4 +--- 5 | + // | | | | + // | 3 ---+ 2 + // |/ |/ + // 0 ---- 1 + std::string writeOcts(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt8> &cells) override; + std::string writeOctsWithCellData(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt8> &cells, std::vector<std::string> &datanames, + std::vector<std::vector<double>> &celldata) override; + std::string writeOctsWithNodeData(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleUInt8> &cells, std::vector<std::string> &datanames, + std::vector<std::vector<double>> &nodedata) override; +}; + +#endif // WBWRITERAVSBINARY_H diff --git a/src/basics/basics/writer/WbWriterBOBJ.cpp b/src/basics/basics/writer/WbWriterBOBJ.cpp new file mode 100644 index 0000000000000000000000000000000000000000..59ea865efc1a21f017a0804b40c8e6cb0089ff32 --- /dev/null +++ b/src/basics/basics/writer/WbWriterBOBJ.cpp @@ -0,0 +1,113 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file WbWriterBOBJ.cpp +//! \ingroup writer +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#ifdef CAB_ZLIB +#include <basics/utilities/UbLogger.h> +#include <basics/writer/WbWriterBOBJ.h> +#include <cstring> + +#include <zlib.h> + +using namespace std; +/*===============================================================================*/ +std::string WbWriterBOBJ::writeTriangles(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt3> &triangles) +{ + string bobjFilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterBOBJ::writeTriangles to " << bobjFilename << " - start"); + + gzFile gzf = gzopen(bobjFilename.c_str(), "wb1"); + + size_t nofNodes = nodes.size(); + size_t nofTriangles = triangles.size(); + + // write to file + size_t numVerts; + // double v[3]; + if (sizeof(numVerts) != 4) { + throw UbException(UB_EXARGS, "danger..."); + } + numVerts = nofNodes; + gzwrite(gzf, &numVerts, sizeof(numVerts)); + + for (size_t k = 0; k < nofNodes; k++) { + float vertp = val<1>(nodes[k]); + gzwrite(gzf, &vertp, sizeof(vertp)); + vertp = val<2>(nodes[k]); + gzwrite(gzf, &vertp, sizeof(vertp)); + vertp = val<3>(nodes[k]); + gzwrite(gzf, &vertp, sizeof(vertp)); + } + + // NORMAL VECTOR + // double n[3]; + gzwrite(gzf, &numVerts, sizeof(numVerts)); + for (size_t k = 0; k < nofNodes; k++) { + // poly->GetPointData()->GetNormals()->GetTuple(k, n); + float normp = 0.0; // n[0]; + gzwrite(gzf, &normp, sizeof(normp)); + normp = 0.0; // n[1]; + gzwrite(gzf, &normp, sizeof(normp)); + normp = 0.0; // n[2]; + gzwrite(gzf, &normp, sizeof(normp)); + } + + // vtkIdType npts = 3; + // vtkIdType* pts; + size_t numTris = nofTriangles; + gzwrite(gzf, &numTris, sizeof(numTris)); + for (size_t k = 0; k < nofTriangles /*(size_t)poly->GetNumberOfPolys()*/; k++) { + // poly->GetPolys()->GetNextCell(npts, pts); + // int triIndex = *pts; + // gzwrite(gzf, &triIndex, sizeof(triIndex)); + // triIndex = *(pts+1); + // gzwrite(gzf, &triIndex, sizeof(triIndex)); + // triIndex = *(pts+2); + // gzwrite(gzf, &triIndex, sizeof(triIndex)); + // poly->GetPolys()->GetNextCell(npts, pts); + int triIndex = val<1>(triangles[k]); //*pts; + gzwrite(gzf, &triIndex, sizeof(triIndex)); + triIndex = val<2>(triangles[k]); //*(pts+1); + gzwrite(gzf, &triIndex, sizeof(triIndex)); + triIndex = val<3>(triangles[k]); //*(pts+2); + gzwrite(gzf, &triIndex, sizeof(triIndex)); + } + + gzclose(gzf); + + UBLOG(logDEBUG1, "WbWriterBOBJ::writeTriangles to " << bobjFilename << " - end"); + + return bobjFilename; +} +/*===============================================================================*/ + +#endif // CAB_ZLIB diff --git a/src/basics/basics/writer/WbWriterBOBJ.h b/src/basics/basics/writer/WbWriterBOBJ.h new file mode 100644 index 0000000000000000000000000000000000000000..591357ac6f861b39af617b3d4c8380de6be7dff6 --- /dev/null +++ b/src/basics/basics/writer/WbWriterBOBJ.h @@ -0,0 +1,79 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file WbWriterBOBJ.h +//! \ingroup writer +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#ifdef CAB_ZLIB +#ifndef WBWRITERBOBJ_H +#define WBWRITERBOBJ_H + +#include <basics/writer/WbWriter.h> +#include <string> + +class WbWriterBOBJ : public WbWriter +{ +public: + OBCREATOR_EXT(WbWriterBOBJ) + + static WbWriterBOBJ *getInstance() + { + static WbWriterBOBJ instance; + return &instance; + } + +private: + WbWriterBOBJ() : WbWriter() + { + if (sizeof(unsigned char) != 1) + throw UbException(UB_EXARGS, "error char type mismatch"); + if (sizeof(int) != 4) + throw UbException(UB_EXARGS, "error int type mismatch"); + if (sizeof(float) != 4) + throw UbException(UB_EXARGS, "error float type mismatch"); + } + WbWriterBOBJ(const WbWriterBOBJ &); // no copy allowed + const WbWriterBOBJ &operator=(const WbWriterBOBJ &); // no copy allowed + + static std::string pvdEndTag; + +public: + std::string getFileExtension() { return "BOBJ.gz"; } + + std::string writeTriangles(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt3> &triangles); +}; + +UB_AUTO_RUN_NAMED( + ObFactory<WbWriter>::getInstance()->addObCreator(ObSingletonCreatorImpl<WbWriterBOBJ, WbWriter>::getInstance()), + CAB_WbWriterVtkXmlASCII); + +#endif // WBWRITERBOBJ_H + +#endif // CAB_ZLIB diff --git a/src/basics/basics/writer/WbWriterSunflow.cpp b/src/basics/basics/writer/WbWriterSunflow.cpp new file mode 100644 index 0000000000000000000000000000000000000000..61ecc8e567aa546b6c92c0a0f662714bee0a1746 --- /dev/null +++ b/src/basics/basics/writer/WbWriterSunflow.cpp @@ -0,0 +1,147 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file WbWriterSunflow.cpp +//! \ingroup writer +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#include <basics/utilities/UbLogger.h> +#include <basics/writer/WbWriterSunflow.h> +#include <cstring> + +using namespace std; + +/*===============================================================================*/ +std::string WbWriterSunflow::writeTriangles(const string &filename, vector<UbTupleFloat3> &nodes, + vector<UbTupleInt3> &triangles) +{ + string sunflowFilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterSunflow::writeTriangles to " << sunflowFilename << " - start"); + + std::ofstream out(sunflowFilename.c_str()); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!! + string path = UbSystem::getPathFromString(sunflowFilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(sunflowFilename.c_str()); + } + if (!out) + throw UbException(UB_EXARGS, "couldn't open file " + sunflowFilename); + } + + // General part + + // Image details + out << "image {" << endl; + out << " resolution 640 480" << endl; + out << " aa 0 1" << endl; + out << " filter mitchell" << endl; + out << "}" << endl << endl; + + // Camera position + out << "camera {" << endl; + out << " type pinhole" << endl; + out << " eye -0.25 -0.3 0.13" << endl; + out << " target -0.1 0.1 0.13" << endl; + out << " up 0 0 1" << endl; + out << " fov 60" << endl; + out << " aspect 1.333333" << endl; + out << "}" << endl << endl; + + // Light + out << "light {" << endl; + out << " type ibl" << endl; + out << " image sky_small.hdr" << endl; + out << " center 0 -1 0" << endl; + out << " up 0 0 1" << endl; + out << " lock true" << endl; + out << " samples 200" << endl; + out << "}" << endl << endl; + + // Shaders + out << "shader {" << endl; + out << " name default-shader" << endl; + out << " type diffuse" << endl; + out << " diff 0.25 0.25 0.25" << endl; + out << "}" << endl << endl; + + out << "shader {" << endl; + out << " name Glass" << endl; + out << " type glass" << endl; + out << " eta 1.333" << endl; + out << " color 0.1 0.3 0.8" << endl; + out << "}" << endl << endl; + + out << "shader {" << endl; + out << " name Mirror" << endl; + out << " type mirror" << endl; + out << " refl 0.7 0.7 0.7" << endl; + out << "}" << endl << endl; + + // Objects + // a) Ground plane + out << "object {" << endl; + out << " shader default-shader" << endl; + out << " type plane" << endl; + out << " p 0 0 0" << endl; + out << " n 0 0 1" << endl; + out << "}" << endl << endl; + + // b) Mesh + out << "object {" << endl; + out << " shader Glass" << endl; + out << " transform {" << endl; + out << " rotatey 270.0" << endl; + out << " }" << endl; + out << " type generic-mesh" << endl; + out << " name polySurfac" << endl << endl; + + // POINTS SECTION + int nofNodes = (int)nodes.size(); + out << " points " << nofNodes << endl; + for (int n = 0; n < nofNodes; n++) + out << " " << val<1>(nodes[n]) << " " << val<2>(nodes[n]) << " " << val<3>(nodes[n]) << endl; + + // TRIANGLES SECTION + int nofTriangles = (int)triangles.size(); + out << " triangles " << nofTriangles << endl; + for (int c = 0; c < nofTriangles; c++) + out << " " << val<1>(triangles[c]) << " " << val<2>(triangles[c]) << " " << val<3>(triangles[c]) << endl; + + // FOOTER + out << " normals none" << endl; + out << " uvs none" << endl; + out << "}" << endl; + + out.close(); + UBLOG(logDEBUG1, "WbWriterSunflow::writeTriangles to " << sunflowFilename << " - end"); + + return sunflowFilename; +} +/*===============================================================================*/ diff --git a/src/basics/basics/writer/WbWriterSunflow.h b/src/basics/basics/writer/WbWriterSunflow.h new file mode 100644 index 0000000000000000000000000000000000000000..519a932f9088b535fb49e77770accd8364226096 --- /dev/null +++ b/src/basics/basics/writer/WbWriterSunflow.h @@ -0,0 +1,72 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file WbWriterSunflow.h +//! \ingroup writer +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#ifndef WbWriterSunflow_H +#define WbWriterSunflow_H + +#include <string> + +#include <basics/writer/WbWriter.h> + +class WbWriterSunflow : public WbWriter +{ +public: + static WbWriterSunflow *getInstance() + { + static WbWriterSunflow instance; + return &instance; + } + + WbWriterSunflow(const WbWriterSunflow &) = delete; + const WbWriterSunflow &operator=(const WbWriterSunflow &) = delete; + +private: + WbWriterSunflow() : WbWriter() + { + if (sizeof(unsigned char) != 1) + throw UbException(UB_EXARGS, "error char type mismatch"); + if (sizeof(int) != 4) + throw UbException(UB_EXARGS, "error int type mismatch"); + if (sizeof(float) != 4) + throw UbException(UB_EXARGS, "error float type mismatch"); + } + + static std::string pvdEndTag; + +public: + std::string getFileExtension() override { return "ascii.sunflow"; } + + std::string writeTriangles(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt3> &triangles) override; +}; + +#endif // WbWriterSunflow_H diff --git a/src/basics/basics/writer/WbWriterTecPlotASCII.cpp b/src/basics/basics/writer/WbWriterTecPlotASCII.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ec7748d35ecea52b645a6cc654d52a6bb93fc874 --- /dev/null +++ b/src/basics/basics/writer/WbWriterTecPlotASCII.cpp @@ -0,0 +1,96 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file WbWriterTechPlotASCII.cpp +//! \ingroup writer +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#include <basics/utilities/UbLogger.h> +#include <basics/writer/WbWriterTecPlotASCII.h> + +using namespace std; + +/*===============================================================================*/ +string WbWriterTecPlotASCII::writeOctsWithNodeData(const string &filename, vector<UbTupleFloat3> &nodes, + vector<UbTupleUInt8> &cells, vector<string> &datanames, + vector<vector<double>> &nodedata) +{ + string tecplotfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterTecPlotASCII::writeOctsWithNodeData to " << tecplotfilename << " - start"); + + ofstream out(tecplotfilename.c_str()); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!! + string path = UbSystem::getPathFromString(tecplotfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(tecplotfilename.c_str()); + } + if (!out) + throw UbException(UB_EXARGS, "couldn't open file " + tecplotfilename); + } + + int nofNodes = (int)nodes.size(); + int nofCells = (int)cells.size(); + + out << "TITLE = VirtualFluids OctGrid from " << UbSystem::getTimeStamp() << endl; + + out << "VARIABLES = \"X\", \"Y\", \"Z\""; + for (size_t d = 0; d < datanames.size(); d++) + out << ", \"" << datanames[d] << "\""; + out << endl; + + out << "ZONE NODES=" << nofNodes << ", ELEMENTS=" << nofCells << ", DATAPACKING=POINT, ZONETYPE=FEBRICK" << endl; + for (size_t n = 0; n < nodes.size(); n++) { + UbTupleFloat3 &coords = nodes[n]; + out << val<1>(coords) << " " << val<2>(coords) << " " << val<3>(coords); + for (size_t d = 0; d < datanames.size(); d++) + out << " " << nodedata[d][n]; + out << endl; + } + + for (size_t c = 0; c < cells.size(); c++) { + UbTupleUInt8 &cell = cells[c]; + out << val<1>(cell) << " " << val<2>(cell) << " " << val<3>(cell) << " " << val<4>(cell) << " " << val<5>(cell) + << " " << val<6>(cell) << " " << val<7>(cell) << " " << val<8>(cell) << endl; + } + + out.close(); + UBLOG(logDEBUG1, "WbWriterTecPlotASCII::writeOctsWithNodeData to " << tecplotfilename << " - end"); + + return tecplotfilename; +} +/*===============================================================================*/ +string WbWriterTecPlotASCII::writeOctsU(const string &filename, vector<UbTupleFloat3> &nodes, + vector<UbTupleUInt8> &cells) +{ + vector<string> datanames; + vector<vector<double>> nodedata; + return writeOctsWithNodeData(filename, nodes, cells, datanames, nodedata); +} +/*===============================================================================*/ diff --git a/src/basics/basics/writer/WbWriterTecPlotASCII.h b/src/basics/basics/writer/WbWriterTecPlotASCII.h new file mode 100644 index 0000000000000000000000000000000000000000..31cac3cc49b60d66f932530eb4f36c1b8029304d --- /dev/null +++ b/src/basics/basics/writer/WbWriterTecPlotASCII.h @@ -0,0 +1,139 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file WbWriterTechPlotASCII.h +//! \ingroup writer +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#ifndef WBWRITERTECPLOTASCII_H +#define WBWRITERTECPLOTASCII_H + +#include <string> + +#include <basics/writer/WbWriter.h> + +class WbWriterTecPlotASCII : public WbWriter +{ +public: + static WbWriterTecPlotASCII *getInstance() + { + static WbWriterTecPlotASCII instance; + return &instance; + } + + WbWriterTecPlotASCII(const WbWriterTecPlotASCII &) = delete; + const WbWriterTecPlotASCII &operator=(const WbWriterTecPlotASCII &) = delete; + +private: + WbWriterTecPlotASCII() : WbWriter() + { + if (sizeof(unsigned char) != 1) + throw UbException(UB_EXARGS, "machine error char type mismatch"); + if (sizeof(int) != 4) + throw UbException(UB_EXARGS, "machine error int type mismatch"); + if (sizeof(float) != 4) + throw UbException(UB_EXARGS, "machine error float type mismatch"); + } + + static std::string pvdEndTag; + +public: + std::string getFileExtension() override { return ".ascii.dat"; } + + // write a metafile + // std::string writeCollection(const std::string& filename, const std::vector<std::string>& filenames, const + // double& timestep, const bool& sepGroups); std::string addFilesToCollection(const std::string& filename, const + // std::vector<std::string>& filenames, const double& timestep, const bool& sepGroups); std::string + // writeParallelFile(const std::string& filename,std::vector<std::string>& pieceSources, + // std::vector<std::string>& pointDataNames, std::vector<std::string>& cellDataNames); + + ////////////////////////////////////////////////////////////////////////// + // nodes + // std::string writeNodes(const std::string& filename,std::vector< UbTupleFloat3 >& nodes); + // std::string writeNodesWithNodeData(const std::string& filename,std::vector< UbTupleFloat3 >& nodes, + // std::vector<std::string >& datanames, std::vector<std::vector<double > >& nodedata); + + ////////////////////////////////////////////////////////////////////////// + // lines + // 0 ---- 1 + // nodenumbering must start with 0! + // std::string writeLines(const std::string& filename,std::vector<UbTupleFloat3 >& nodes, std::vector<UbTupleInt2 + // >& lines); std::string writeLinesWithNodeData(const std::string& filename,std::vector<UbTupleFloat3 >& nodes, + // std::vector<UbTupleInt2 >& lines, std::vector< std::string >& datanames, std::vector< std::vector< double > >& + // nodedata); + // + ////////////////////////////////////////////////////////////////////////// + // triangles + // 2 + // + // 0---1 + // nodenumbering must start with 0! + // std::string writeTriangles(const std::string& filename,std::vector<UbTupleFloat3 >& nodes, + // std::vector<UbTupleInt3 >& triangles); std::string writeTrianglesWithNodeData(const std::string& + // filename,std::vector< UbTupleFloat3 >& nodes, std::vector< UbTupleInt3 >& cells, std::vector<std::string >& + // datanames, std::vector<std::vector<double > >& nodedata); + + ////////////////////////////////////////////////////////////////////////// + // 2D + // cell numbering: + // 3---2 + // | | + // 0---1 + // nodenumbering must start with 0! + + // std::string writeQuads(const std::string& filename,std::vector< UbTupleFloat3 >& nodes, std::vector< + // UbTupleInt4 >& cells); std::string writeQuadsWithNodeData(const std::string& filename,std::vector< + // UbTupleFloat3 >& nodes, std::vector< UbTupleInt4 >& cells, std::vector< std::string >& datanames, std::vector< + // std::vector< double > >& nodedata); std::string writeQuadsWithCellData(const std::string& + // filename,std::vector< UbTupleFloat3 >& nodes, std::vector< UbTupleInt4 >& cells, std::vector< std::string >& + // datanames, std::vector< std::vector< double > >& celldata); std::string writeQuadsWithNodeAndCellData(const + // std::string& filename,std::vector< UbTupleFloat3 >& nodes, std::vector< UbTupleInt4 >& cells, + // std::vector< std::string >& nodedatanames, std::vector< std::vector< + // double > >& nodedata, std::vector< std::string >& celldatanames, + // std::vector< std::vector< double > >& celldata ); + + ////////////////////////////////////////////////////////////////////////// + // octs + // 7 ---- 6 + // /| /| + // 4 +--- 5 | + // | | | | + // | 3 ---+ 2 + // |/ |/ + // 0 ---- 1 + std::string writeOctsU(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleUInt8> &cells); + // std::string writeOctsWithCellData(const std::string& filename,std::vector<UbTupleFloat3 >& nodes, + // std::vector<UbTupleInt8 >& cells, std::vector<std::string >& datanames, std::vector<std::vector<double > >& + // celldata); + std::string writeOctsWithNodeData(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleUInt8> &cells, std::vector<std::string> &datanames, + std::vector<std::vector<double>> &nodedata) override; +}; + +#endif // WBWRITERTECPLOTASCII_H diff --git a/src/basics/basics/writer/WbWriterVtkASCII.cpp b/src/basics/basics/writer/WbWriterVtkASCII.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dcd94f8203b1388e974fdcc3638dc3abff10cb67 --- /dev/null +++ b/src/basics/basics/writer/WbWriterVtkASCII.cpp @@ -0,0 +1,699 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file WbWriterVtkASCII.cpp +//! \ingroup writer +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#include <basics/utilities/UbLogger.h> +#include <basics/writer/WbWriterVtkASCII.h> +#include <cstring> + +using namespace std; + +std::string WbWriterVtkASCII::writeQuads(const string &filename, vector<UbTupleFloat3> &nodes, + vector<UbTupleInt4> &cells) +{ + string vtkfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterVtkASCII::writeQuads to " << vtkfilename << " - start"); + + std::ofstream out(vtkfilename.c_str()); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!! + string path = UbSystem::getPathFromString(vtkfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(vtkfilename.c_str()); + } + if (!out) + throw UbException(UB_EXARGS, "couldn't open file " + vtkfilename); + } + + int nofNodes = (int)nodes.size(); + int nofCells = (int)cells.size(); + + // VtkASCII FILE + out << "# vtk DataFile Version 4.0" + << "\n"; + out << "GeoFile" + << "\n"; + out << "ASCII" + << "\n"; + + // POINTS SECTION + out << "DATASET UNSTRUCTURED_GRID" + << "\n"; + out << "POINTS " << nofNodes << " float" + << "\n"; + for (int n = 0; n < nofNodes; n++) + out << val<1>(nodes[n]) << " " << val<2>(nodes[n]) << " " << val<3>(nodes[n]) << " \n"; + + out << "\n"; + + // CELLS SECTION + out << "CELLS " << nofCells << " " << 5 * nofCells << "\n"; + for (int c = 0; c < (int)cells.size(); c++) + out << "4 " << val<1>(cells[c]) << " " << val<2>(cells[c]) << " " << val<4>(cells[c]) << " " << val<3>(cells[c]) + << " \n"; + out << "\n"; + + out << "CELL_TYPES " << nofCells << "\n"; + for (int i = 0; i < nofCells; i++) + out << "8" << endl; + out << endl; + + out.close(); + + UBLOG(logDEBUG1, "WbWriterVtkASCII::writeQuads to " << vtkfilename << " - end"); + + return vtkfilename; +} +/*===============================================================================*/ +std::string WbWriterVtkASCII::writeQuadsWithNodeData(const string &filename, vector<UbTupleFloat3> &nodes, + vector<UbTupleInt4> &cells, vector<string> &datanames, + vector<vector<double>> &nodedata) +{ + string vtkfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterVtkASCII::writeQuadsWithNodeData to " << vtkfilename << " - start"); + + std::ofstream out(vtkfilename.c_str()); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!! + string path = UbSystem::getPathFromString(vtkfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(vtkfilename.c_str()); + } + if (!out) + throw UbException(UB_EXARGS, "couldn't open file " + vtkfilename); + } + + // write geo + int nofNodes = (int)nodes.size(); + int nofCells = (int)cells.size(); + + // VtkASCII FILE + out << "# vtk DataFile Version 4.0" + << "\n"; + out << "GeoFile" + << "\n"; + out << "ASCII" + << "\n"; + + // POINTS SECTION + out << "DATASET UNSTRUCTURED_GRID" + << "\n"; + out << "POINTS " << nofNodes << " float" + << "\n"; + for (int n = 0; n < nofNodes; n++) + out << val<1>(nodes[n]) << " " << val<2>(nodes[n]) << " " << val<3>(nodes[n]) << " \n"; + + out << "\n"; + + // CELLS SECTION + out << "CELLS " << nofCells << " " << 5 * nofCells << "\n"; + for (int c = 0; c < (int)cells.size(); c++) + out << "4 " << val<1>(cells[c]) << " " << val<2>(cells[c]) << " " << val<4>(cells[c]) << " " << val<3>(cells[c]) + << " \n"; + out << "\n"; + + out << "CELL_TYPES " << nofCells << "\n"; + for (int i = 0; i < nofCells; i++) + out << "8" << endl; + out << endl; + + // write data section + out << "POINT_DATA " << nofNodes << "\n"; + for (int s = 0; s < (int)datanames.size(); ++s) { + out << "SCALARS " << datanames[s] << " float 1 \n LOOKUP_TABLE default \n"; + for (int d = 0; d < (int)nodedata[s].size(); d++) + out << nodedata[s][d] << "\n"; + + out << endl; + } + + out.close(); + UBLOG(logDEBUG1, "WbWriterVtkASCII::writeQuadsWithNodeData to " << vtkfilename << " - end"); + return vtkfilename; +} +/*===============================================================================*/ +std::string WbWriterVtkASCII::writeQuadsWithCellData(const string &filename, vector<UbTupleFloat3> &nodes, + vector<UbTupleInt4> &cells, vector<string> &datanames, + vector<vector<double>> &celldata) +{ + string vtkfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterVtkASCII::writeQuadsWithCellData to " << vtkfilename << " - start"); + + std::ofstream out(vtkfilename.c_str()); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!! + string path = UbSystem::getPathFromString(vtkfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(vtkfilename.c_str()); + } + if (!out) + throw UbException(UB_EXARGS, "couldn't open file " + vtkfilename); + } + + // write geo + int nofNodes = (int)nodes.size(); + int nofCells = (int)cells.size(); + + // VtkASCII FILE + out << "# vtk DataFile Version 4.0" + << "\n"; + out << "GeoFile" + << "\n"; + out << "ASCII" + << "\n"; + + // POINTS SECTION + out << "DATASET UNSTRUCTURED_GRID" + << "\n"; + out << "POINTS " << nofNodes << " float" + << "\n"; + for (int n = 0; n < nofNodes; n++) + out << val<1>(nodes[n]) << " " << val<2>(nodes[n]) << " " << val<3>(nodes[n]) << " \n"; + + out << "\n"; + + // CELLS SECTION + out << "CELLS " << nofCells << " " << 5 * nofCells << "\n"; + for (int c = 0; c < (int)cells.size(); c++) + out << "4 " << val<1>(cells[c]) << " " << val<2>(cells[c]) << " " << val<4>(cells[c]) << " " << val<3>(cells[c]) + << " \n"; + out << "\n"; + + out << "CELL_TYPES " << nofCells << "\n"; + for (int i = 0; i < nofCells; i++) + out << "8" << endl; + out << endl; + + // write data section + out << "CELL_DATA " << nofCells << "\n"; + for (int s = 0; s < (int)datanames.size(); ++s) { + out << "SCALARS " << datanames[s] << " float 1 \n LOOKUP_TABLE default \n"; + for (int d = 0; d < (int)celldata[s].size(); d++) + out << celldata[s][d] << "\n"; + + out << endl; + } + + out.close(); + UBLOG(logDEBUG1, "WbWriterVtkASCII::writeQuadsWithCellData to " << vtkfilename << " - end"); + return vtkfilename; +} +/*===============================================================================*/ +std::string WbWriterVtkASCII::writeQuadsWithNodeAndCellData(const string &filename, vector<UbTupleFloat3> &nodes, + vector<UbTupleInt4> &cells, vector<string> &nodedatanames, + vector<vector<double>> &nodedata, + vector<string> &celldatanames, + vector<vector<double>> &celldata) +{ + string vtkfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterVtkASCII::writeQuadsWithNodeAndCellData to " << vtkfilename << " - start"); + + std::ofstream out(vtkfilename.c_str()); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!! + string path = UbSystem::getPathFromString(vtkfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(vtkfilename.c_str()); + } + if (!out) + throw UbException(UB_EXARGS, "couldn't open file " + vtkfilename); + } + + // write geo + int nofNodes = (int)nodes.size(); + int nofCells = (int)cells.size(); + + // VtkASCII FILE + out << "# vtk DataFile Version 4.0" + << "\n"; + out << "GeoFile" + << "\n"; + out << "ASCII" + << "\n"; + + // POINTS SECTION + out << "DATASET UNSTRUCTURED_GRID" + << "\n"; + out << "POINTS " << nofNodes << " float" + << "\n"; + for (int n = 0; n < nofNodes; n++) + out << val<1>(nodes[n]) << " " << val<2>(nodes[n]) << " " << val<3>(nodes[n]) << " \n"; + + out << "\n"; + + // CELLS SECTION + out << "CELLS " << nofCells << " " << 5 * nofCells << "\n"; + for (int c = 0; c < (int)cells.size(); c++) + out << "4 " << val<1>(cells[c]) << " " << val<2>(cells[c]) << " " << val<4>(cells[c]) << " " << val<3>(cells[c]) + << " \n"; + out << "\n"; + + out << "CELL_TYPES " << nofCells << "\n"; + for (int i = 0; i < nofCells; i++) + out << "8" << endl; + out << endl; + + // write node data section + out << "POINT_DATA " << nofNodes << "\n"; + for (int s = 0; s < (int)nodedatanames.size(); ++s) { + out << "SCALARS " << nodedatanames[s] << " float 1 \n LOOKUP_TABLE default \n"; + for (int d = 0; d < (int)nodedata[s].size(); d++) + out << nodedata[s][d] << "\n"; + + out << endl; + } + + // write cell data section + out << "CELL_DATA " << nofCells << "\n"; + for (int s = 0; s < (int)celldatanames.size(); ++s) { + out << "SCALARS " << celldatanames[s] << " float 1 \n LOOKUP_TABLE default \n"; + for (int d = 0; d < (int)celldata[s].size(); d++) + out << celldata[s][d] << "\n"; + + out << endl; + } + + out.close(); + UBLOG(logDEBUG1, "WbWriterVtkASCII::writeQuadsWithNodeAndCellData to " << vtkfilename << " - end"); + return vtkfilename; +} +/*===============================================================================*/ +std::string WbWriterVtkASCII::writeLines(const string &filename, vector<UbTupleFloat3> &nodes, + vector<UbTupleInt2> &lines) +{ + string vtkfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterVtkASCII::writeLines to " << vtkfilename << " - start"); + + std::ofstream out(vtkfilename.c_str()); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!! + string path = UbSystem::getPathFromString(vtkfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(vtkfilename.c_str()); + } + if (!out) + throw UbException(UB_EXARGS, "couldn't open file " + vtkfilename); + } + + int nofNodes = (int)nodes.size(); + int nofLines = (int)lines.size(); + + // VtkASCII FILE + out << "# vtk DataFile Version 4.0" + << "\n"; + out << "GeoFile" + << "\n"; + out << "ASCII" + << "\n"; + + // POINTS SECTION + out << "DATASET UNSTRUCTURED_GRID" + << "\n"; + out << "POINTS " << nofNodes << " float" + << "\n"; + for (int n = 0; n < nofNodes; n++) { + out << val<1>(nodes[n]) << " " << val<2>(nodes[n]) << " " << val<3>(nodes[n]) << " \n"; + } + out << "\n"; + + // CELLS SECTION + out << "CELLS " << nofLines << " " << 3 * nofLines << "\n"; + int nr = 0; + for (int l = 0; l < nofLines; l++) { + int el = nr + 1; + out << "2 " << val<1>(lines[l]) << " " << val<2>(lines[l]) << " " << endl; + nr = el + 1; + } + out << "\n"; + + out << "CELL_TYPES " << nofLines << "\n"; + for (int l = 0; l < nofLines; l++) + out << "3" << endl; + out << endl; + + out.close(); + + UBLOG(logDEBUG1, "WbWriterVtkASCII::writeLines to " << vtkfilename << " - end"); + return vtkfilename; +} +/*===============================================================================*/ +std::string WbWriterVtkASCII::writeTriangles(const string &filename, vector<UbTupleFloat3> &nodes, + vector<UbTupleInt3> &triangles) +{ + string vtkfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterVtkASCII::writeTriangles to " << vtkfilename << " - start"); + + std::ofstream out(vtkfilename.c_str()); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!! + string path = UbSystem::getPathFromString(vtkfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(vtkfilename.c_str()); + } + if (!out) + throw UbException(UB_EXARGS, "couldn't open file " + vtkfilename); + } + + int nofNodes = (int)nodes.size(); + int nofTriangles = (int)triangles.size(); + + // VtkASCII FILE + out << "# vtk DataFile Version 4.0" + << "\n"; + out << "GeoFile" + << "\n"; + out << "ASCII" + << "\n"; + + // POINTS SECTION + out << "DATASET UNSTRUCTURED_GRID" + << "\n"; + out << "POINTS " << nofNodes << " float" + << "\n"; + for (int n = 0; n < nofNodes; n++) { + out << val<1>(nodes[n]) << " " << val<2>(nodes[n]) << " " << val<3>(nodes[n]) << " \n"; + } + out << "\n"; + + // CELLS SECTION + out << "CELLS " << nofTriangles << " " << 4 * nofTriangles << "\n"; + int nr = 0; + for (int t = 0; t < nofTriangles; t++) { + int el = nr + 1; + out << "3 " << val<1>(triangles[t]) << " " << val<2>(triangles[t]) << " " << val<3>(triangles[t]) << " " + << endl; + nr = el + 1; + } + out << "\n"; + + out << "CELL_TYPES " << nofTriangles << "\n"; + for (int l = 0; l < nofTriangles; l++) + out << "5" << endl; + out << endl; + + out.close(); + + UBLOG(logDEBUG1, "WbWriterVtkASCII::writeTriangles to " << vtkfilename << " - end"); + return vtkfilename; +} +/*===============================================================================*/ +std::string WbWriterVtkASCII::writeTrianglesWithNodeData(const string &filename, vector<UbTupleFloat3> &nodes, + vector<UbTupleInt3> &cells, vector<string> &datanames, + vector<vector<double>> &nodedata) +{ + string vtkfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterVtkASCII::writeTrianglesWithNodeData to " << vtkfilename << " - start"); + + std::ofstream out(vtkfilename.c_str()); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!! + string path = UbSystem::getPathFromString(vtkfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(vtkfilename.c_str()); + } + if (!out) + throw UbException(UB_EXARGS, "couldn't open file " + vtkfilename); + } + + // write geo + int nofNodes = (int)nodes.size(); + int nofCells = (int)cells.size(); + + // VtkASCII FILE + out << "# vtk DataFile Version 4.0" + << "\n"; + out << "GeoFile" + << "\n"; + out << "ASCII" + << "\n"; + + // POINTS SECTION + out << "DATASET UNSTRUCTURED_GRID" + << "\n"; + out << "POINTS " << nofNodes << " float" + << "\n"; + for (int n = 0; n < nofNodes; n++) + out << val<1>(nodes[n]) << " " << val<2>(nodes[n]) << " " << val<3>(nodes[n]) << " \n"; + + out << "\n"; + + // CELLS SECTION + out << "CELLS " << nofCells << " " << 4 * nofCells << "\n"; + for (int c = 0; c < (int)cells.size(); c++) + out << "3 " << val<1>(cells[c]) << " " << val<2>(cells[c]) << " " << val<3>(cells[c]) << " \n"; + out << "\n"; + + out << "CELL_TYPES " << nofCells << "\n"; + for (int i = 0; i < nofCells; i++) + out << "5" << endl; + out << endl; + + // write data section + out << "POINT_DATA " << nofNodes << "\n"; + for (int s = 0; s < (int)datanames.size(); ++s) { + out << "SCALARS " << datanames[s] << " float 1 \n LOOKUP_TABLE default \n"; + for (int d = 0; d < (int)nodedata[s].size(); d++) + out << nodedata[s][d] << "\n"; + + out << endl; + } + + out.close(); + UBLOG(logDEBUG1, "WbWriterVtkASCII::writeTrianglesWithNodeData to " << vtkfilename << " - end"); + return vtkfilename; +} +/*===============================================================================*/ +std::string WbWriterVtkASCII::writeOctsWithCellData(const string &filename, vector<UbTupleFloat3> &nodes, + vector<UbTupleInt8> &cells, vector<string> &datanames, + vector<vector<double>> &celldata) +{ + string vtkfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterVtkASCII::writeOctsWithCellData to " << vtkfilename << " - start"); + + std::ofstream out(vtkfilename.c_str()); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!! + string path = UbSystem::getPathFromString(vtkfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(vtkfilename.c_str()); + } + if (!out) + throw UbException(UB_EXARGS, "couldn't open file " + vtkfilename); + } + + // write geo + int nofNodes = (int)nodes.size(); + int nofCells = (int)cells.size(); + + // VtkASCII FILE + out << "# vtk DataFile Version 4.0" + << "\n"; + out << "GeoFile" + << "\n"; + out << "ASCII" + << "\n"; + + // POINTS SECTION + out << "DATASET UNSTRUCTURED_GRID" + << "\n"; + out << "POINTS " << nofNodes << " float" + << "\n"; + for (int n = 0; n < nofNodes; n++) + out << val<1>(nodes[n]) << " " << val<2>(nodes[n]) << " " << val<3>(nodes[n]) << " \n"; + + out << "\n"; + + // CELLS SECTION + out << "CELLS " << nofCells << " " << 9 * nofCells << "\n"; + for (int c = 0; c < (int)cells.size(); c++) { + out << "8 " << val<1>(cells[c]) << " " << val<2>(cells[c]) << " " << val<4>(cells[c]) << " " << val<3>(cells[c]) + << " " << val<5>(cells[c]) << " " << val<6>(cells[c]) << " " << val<8>(cells[c]) << " " << val<7>(cells[c]) + << " \n"; + } + + out << "\n"; + + out << "CELL_TYPES " << nofCells << "\n"; + for (int i = 0; i < nofCells; i++) + out << "11 " << endl; + out << endl; + + // write data section + out << "CELL_DATA " << nofCells << "\n"; + for (int s = 0; s < (int)datanames.size(); ++s) { + out << "SCALARS " << datanames[s] << " float 1 \n LOOKUP_TABLE default \n"; + for (int d = 0; d < (int)celldata[s].size(); d++) + out << celldata[s][d] << "\n"; + + out << endl; + } + + out.close(); + UBLOG(logDEBUG1, "WbWriterVtkASCII::writeOctsWithCellData to " << vtkfilename << " - end"); + + return vtkfilename; +} +/*===============================================================================*/ +std::string WbWriterVtkASCII::writeOctsWithNodeData(const string &filename, vector<UbTupleFloat3> &nodes, + vector<UbTupleUInt8> &cells, vector<string> &datanames, + vector<vector<double>> &nodedata) +{ + string vtkfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterVtkASCII::writeOctsWithNodeData to " << vtkfilename << " - start"); + + std::ofstream out(vtkfilename.c_str()); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!! + string path = UbSystem::getPathFromString(vtkfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(vtkfilename.c_str()); + } + if (!out) + throw UbException(UB_EXARGS, "couldn't open file " + vtkfilename); + } + + // write geo + int nofNodes = (int)nodes.size(); + int nofCells = (int)cells.size(); + + // VtkASCII FILE + out << "# vtk DataFile Version 4.0" + << "\n"; + out << "GeoFile" + << "\n"; + out << "ASCII" + << "\n"; + + // POINTS SECTION + out << "DATASET UNSTRUCTURED_GRID" + << "\n"; + out << "POINTS " << nofNodes << " float" + << "\n"; + for (int n = 0; n < nofNodes; n++) + out << val<1>(nodes[n]) << " " << val<2>(nodes[n]) << " " << val<3>(nodes[n]) << " \n"; + + out << "\n"; + + // CELLS SECTION + out << "CELLS " << nofCells << " " << 9 * nofCells << "\n"; + for (int c = 0; c < (int)cells.size(); c++) { + out << "8 " << val<1>(cells[c]) << " " << val<2>(cells[c]) << " " << val<4>(cells[c]) << " " << val<3>(cells[c]) + << " " << val<5>(cells[c]) << " " << val<6>(cells[c]) << " " << val<8>(cells[c]) << " " << val<7>(cells[c]) + << " \n"; + } + out << "\n"; + + out << "CELL_TYPES " << nofCells << "\n"; + for (int i = 0; i < nofCells; i++) + out << "11" << endl; + out << endl; + + // write data section + out << "POINT_DATA " << nofNodes << "\n"; + for (int s = 0; s < (int)datanames.size(); ++s) { + out << "SCALARS " << datanames[s] << " float 1 \n LOOKUP_TABLE default \n"; + for (int d = 0; d < (int)nodedata[s].size(); d++) + out << nodedata[s][d] << "\n"; + + out << endl; + } + + out.close(); + UBLOG(logDEBUG1, "WbWriterVtkASCII::writeOctsWithNodeData to " << vtkfilename << " - end"); + return vtkfilename; +} +/*===============================================================================*/ +std::string WbWriterVtkASCII::writeOcts(const string &filename, vector<UbTupleFloat3> &nodes, + vector<UbTupleInt8> &cells) +{ + string vtkfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterVtkASCII::writeOcts to " << vtkfilename << " - start"); + + std::ofstream out(vtkfilename.c_str()); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!! + string path = UbSystem::getPathFromString(vtkfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(vtkfilename.c_str()); + } + if (!out) + throw UbException(UB_EXARGS, "couldn't open file " + vtkfilename); + } + + int nofNodes = (int)nodes.size(); + int nofCells = (int)cells.size(); + + // VtkASCII FILE + out << "# vtk DataFile Version 4.0" + << "\n"; + out << "GeoFile" + << "\n"; + out << "ASCII" + << "\n"; + + // POINTS SECTION + out << "DATASET UNSTRUCTURED_GRID" + << "\n"; + out << "POINTS " << nofNodes << " float" + << "\n"; + for (int n = 0; n < nofNodes; n++) + out << val<1>(nodes[n]) << " " << val<2>(nodes[n]) << " " << val<3>(nodes[n]) << " \n"; + + out << "\n"; + + // CELLS SECTION + out << "CELLS " << nofCells << " " << 9 * nofCells << "\n"; + for (int c = 0; c < (int)cells.size(); c++) + out << "8 " << val<1>(cells[c]) << " " << val<2>(cells[c]) << " " << val<4>(cells[c]) << " " << val<3>(cells[c]) + << " " << val<5>(cells[c]) << " " << val<6>(cells[c]) << " " << val<8>(cells[c]) << " " << val<7>(cells[c]) + << " \n"; + out << "\n"; + + out << "CELL_TYPES " << nofCells << "\n"; + for (int i = 0; i < nofCells; i++) + out << "11" << endl; + out << endl; + + out.close(); + + UBLOG(logDEBUG1, "WbWriterVtkASCII::writeOcts to " << vtkfilename << " - end"); + return vtkfilename; +} diff --git a/src/basics/basics/writer/WbWriterVtkASCII.h b/src/basics/basics/writer/WbWriterVtkASCII.h new file mode 100644 index 0000000000000000000000000000000000000000..f041a45eba07e32af59b490b11ca2c041a822339 --- /dev/null +++ b/src/basics/basics/writer/WbWriterVtkASCII.h @@ -0,0 +1,117 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file WbWriterVtkASCII.h +//! \ingroup writer +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#ifndef WBWRITERVTKASCII_H +#define WBWRITERVTKASCII_H + +#include <basics/writer/WbWriter.h> + +class WbWriterVtkASCII : public WbWriter +{ +public: + static WbWriterVtkASCII *getInstance() + { + static WbWriterVtkASCII instance; + return &instance; + } + +private: + WbWriterVtkASCII() : WbWriter() {} + WbWriterVtkASCII(const WbWriterVtkASCII &); // no copy allowed + const WbWriterVtkASCII &operator=(const WbWriterVtkASCII &); // no copy allowed + +public: + std::string getFileExtension() override { return ".ascii.vtk"; } + + ////////////////////////////////////////////////////////////////////////// + // lines + // 0 ---- 1 + // nodenumbering must start with 0! + std::string writeLines(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt2> &lines) override; + + ////////////////////////////////////////////////////////////////////////// + // triangles + // cell numbering: + // 2 + // + // 0---1 + // nodenumbering must start with 0! + std::string writeTriangles(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt3> &cells) override; + std::string writeTrianglesWithNodeData(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt3> &cells, std::vector<std::string> &datanames, + std::vector<std::vector<double>> &nodedata) override; + + ////////////////////////////////////////////////////////////////////////// + // 2D + // cell numbering: + // 3---2 + // | | + // 0---1 + // nodenumbering must start with 0! + std::string writeQuads(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt4> &cells) override; + std::string writeQuadsWithNodeData(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt4> &cells, std::vector<std::string> &datanames, + std::vector<std::vector<double>> &nodedata) override; + std::string writeQuadsWithCellData(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt4> &cells, std::vector<std::string> &datanames, + std::vector<std::vector<double>> &celldata) override; + std::string writeQuadsWithNodeAndCellData(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt4> &cells, std::vector<std::string> &nodedatanames, + std::vector<std::vector<double>> &nodedata, + std::vector<std::string> &celldatanames, + std::vector<std::vector<double>> &celldata) override; + + ////////////////////////////////////////////////////////////////////////// + // octs + // 7 ---- 6 + // /| /| + // 4 +--- 5 | + // | | | | + // | 3 ---+ 2 + // |/ |/ + // 0 ---- 1 + std::string writeOcts(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt8> &cells) override; + std::string writeOctsBinary(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt8> &cells); + std::string writeOctsWithCellData(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt8> &cells, std::vector<std::string> &datanames, + std::vector<std::vector<double>> &celldata) override; + std::string writeOctsWithNodeData(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleUInt8> &cells, std::vector<std::string> &datanames, + std::vector<std::vector<double>> &nodedata) override; +}; + +#endif // WBWRITERVTKASCII_H diff --git a/src/basics/basics/writer/WbWriterVtkBinary.cpp b/src/basics/basics/writer/WbWriterVtkBinary.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0b1507e7a5f2c9cb22128c06dd9112541c642504 --- /dev/null +++ b/src/basics/basics/writer/WbWriterVtkBinary.cpp @@ -0,0 +1,850 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file WbWriterVtkBinary.cpp +//! \ingroup writer +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#include <basics/utilities/UbLogger.h> +#include <basics/writer/WbWriterVtkASCII.h> +#include <basics/writer/WbWriterVtkBinary.h> +#include <cstring> + +using namespace std; + +std::string WbWriterVtkBinary::writeLines(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt2> &lines) +{ + return WbWriterVtkASCII::getInstance()->writeLines(filename, nodes, lines); +} +/*===============================================================================*/ +std::string WbWriterVtkBinary::writeTriangles(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt3> &cells) +{ + return WbWriterVtkASCII::getInstance()->writeTriangles(filename, nodes, cells); +} +/*===============================================================================*/ +std::string WbWriterVtkBinary::writeTrianglesWithNodeData(const std::string &filename, + std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt3> &cells, + std::vector<std::string> &datanames, + std::vector<std::vector<double>> &nodedata) +{ + return WbWriterVtkASCII::getInstance()->writeTrianglesWithNodeData(filename, nodes, cells, datanames, nodedata); +} +/*===============================================================================*/ +std::string WbWriterVtkBinary::writeQuads(const string &filename, vector<UbTupleFloat3> &nodes, + vector<UbTupleInt4> &cells) +{ + string vtkfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterVtkBinary::writeQuads to " << vtkfilename << " - start"); + + ofstream out(vtkfilename.c_str(), ofstream::out | ofstream::binary); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!! + string path = UbSystem::getPathFromString(vtkfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(vtkfilename.c_str(), ios::out | ios::binary); + } + if (!out) + throw UbException(UB_EXARGS, "couldn't open file " + vtkfilename); + } + + // HEADER-SECTION + // WRITE BIGENDIAN VtkBinary FILE + bool swapByte = UbSystem::isLittleEndian(); + int nofNodes = (int)nodes.size(); + int nofCells = (int)cells.size(); + + out << "# vtk DataFile Version 4.0" + << "\n"; + out << "D3Q19MasterNodeGrid" + << "\n"; + out << "" + << "\n"; + + // POINTS SECTION + out << "DATASET UNSTRUCTURED_GRID" + << "\n"; + out << "POINTS " << nofNodes << " float" + << "\n"; + for (int n = 0; n < nofNodes; n++) { + float x1 = (float)val<1>(nodes[n]); + float x2 = (float)val<2>(nodes[n]); + float x3 = (float)val<3>(nodes[n]); + + if (swapByte) { + UbSystem::swapByteOrder((unsigned char *)&x1, sizeof(float)); + UbSystem::swapByteOrder((unsigned char *)&x2, sizeof(float)); + UbSystem::swapByteOrder((unsigned char *)&x3, sizeof(float)); + } + + out.write((char *)&x1, sizeof(float)); + out.write((char *)&x2, sizeof(float)); + out.write((char *)&x3, sizeof(float)); + } + out << "\n"; + + // CELLS SECTION + out << "CELLS " << nofCells << " " << nofCells * 5 << "\n"; + + int nodesPerCellDummy = 4; // nofNodesPerCell + if (swapByte) + UbSystem::swapByteOrder((unsigned char *)&nodesPerCellDummy, sizeof(int)); + for (int c = 0; c < (int)cells.size(); c++) { + int SW = val<1>(cells[c]); + int SE = val<2>(cells[c]); + int NE = val<3>(cells[c]); + int NW = val<4>(cells[c]); + if (swapByte) { + UbSystem::swapByteOrder((unsigned char *)&SW, sizeof(int)); + UbSystem::swapByteOrder((unsigned char *)&SE, sizeof(int)); + UbSystem::swapByteOrder((unsigned char *)&NW, sizeof(int)); + UbSystem::swapByteOrder((unsigned char *)&NE, sizeof(int)); + } + + out.write((char *)&nodesPerCellDummy, sizeof(int)); + out.write((char *)&SW, sizeof(int)); + out.write((char *)&SE, sizeof(int)); + out.write((char *)&NW, sizeof(int)); + out.write((char *)&NE, sizeof(int)); + } + out << "\n"; + + out << "CELL_TYPES " << (int)cells.size() << "\n"; + int celltype = 8; + if (swapByte) + UbSystem::swapByteOrder((unsigned char *)&celltype, sizeof(int)); + for (int c = 0; c < nofCells; c++) + out.write((char *)&celltype, sizeof(int)); + + out << endl; + out.close(); + + UBLOG(logDEBUG1, "WbWriterVtkBinary::writeQuads to " << vtkfilename << " - end"); + return vtkfilename; +} +/*===============================================================================*/ +std::string WbWriterVtkBinary::writeQuadsWithNodeData(const string &filename, vector<UbTupleFloat3> &nodes, + vector<UbTupleInt4> &cells, vector<string> &datanames, + vector<vector<double>> &nodedata) +{ + string vtkfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterVtkBinary::writeQuadsWithNodeData to " << vtkfilename << " - start"); + + ofstream out(vtkfilename.c_str(), ofstream::out | ofstream::binary); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!! + string path = UbSystem::getPathFromString(vtkfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(vtkfilename.c_str(), ios::out | ios::binary); + } + if (!out) + throw UbException(UB_EXARGS, "couldn't open file " + vtkfilename); + } + + // WRITE BIGENDIAN VtkBinary FILE + bool swapByte = UbSystem::isLittleEndian(); + int nofNodes = (int)nodes.size(); + int nofCells = (int)cells.size(); + + out << "# vtk DataFile Version 4.0" + << "\n"; + out << "D3Q19MasterNodeGrid" + << "\n"; + out << "" + << "\n"; + + // POINTS SECTION + out << "DATASET UNSTRUCTURED_GRID" + << "\n"; + out << "POINTS " << nofNodes << " float" + << "\n"; + for (int n = 0; n < nofNodes; n++) { + float x1 = (float)val<1>(nodes[n]); + float x2 = (float)val<2>(nodes[n]); + float x3 = (float)val<3>(nodes[n]); + + if (swapByte) { + UbSystem::swapByteOrder((unsigned char *)&x1, sizeof(float)); + UbSystem::swapByteOrder((unsigned char *)&x2, sizeof(float)); + UbSystem::swapByteOrder((unsigned char *)&x3, sizeof(float)); + } + + out.write((char *)&x1, sizeof(float)); + out.write((char *)&x2, sizeof(float)); + out.write((char *)&x3, sizeof(float)); + } + out << "\n"; + + // CELLS SECTION + out << "CELLS " << nofCells << " " << nofCells * 5 << "\n"; + + int nodesPerCellDummy = 4; // nofNodesPerCell + if (swapByte) + UbSystem::swapByteOrder((unsigned char *)&nodesPerCellDummy, sizeof(int)); + for (int c = 0; c < (int)cells.size(); c++) { + int SW = val<1>(cells[c]); + int SE = val<2>(cells[c]); + int NE = val<3>(cells[c]); + int NW = val<4>(cells[c]); + if (swapByte) { + UbSystem::swapByteOrder((unsigned char *)&SW, sizeof(int)); + UbSystem::swapByteOrder((unsigned char *)&SE, sizeof(int)); + UbSystem::swapByteOrder((unsigned char *)&NW, sizeof(int)); + UbSystem::swapByteOrder((unsigned char *)&NE, sizeof(int)); + } + + out.write((char *)&nodesPerCellDummy, sizeof(int)); + out.write((char *)&SW, sizeof(int)); + out.write((char *)&SE, sizeof(int)); + out.write((char *)&NW, sizeof(int)); + out.write((char *)&NE, sizeof(int)); + } + out << "\n"; + + out << "CELL_TYPES " << (int)cells.size() << "\n"; + int celltype = 8; + if (swapByte) + UbSystem::swapByteOrder((unsigned char *)&celltype, sizeof(int)); + for (int c = 0; c < nofCells; c++) + out.write((char *)&celltype, sizeof(int)); + + out << endl; + + // DATA SECTION + // write data section + out << "POINT_DATA " << nofNodes << "\n"; + for (int s = 0; s < (int)datanames.size(); ++s) { + if ((int)nodedata[s].size() != nofNodes) + throw UbException(UB_EXARGS, "datasetsize must be equal to nofNodes"); + out << "SCALARS " << datanames[s] << " float 1 \n LOOKUP_TABLE default \n"; + for (int d = 0; d < (int)nodedata[s].size(); d++) { + float dummy = (float)nodedata[s][d]; + if (swapByte) + UbSystem::swapByteOrder((unsigned char *)&dummy, sizeof(float)); + out.write((const char *)&dummy, sizeof(float)); + } + out << endl; + } + out.close(); + + UBLOG(logDEBUG1, "WbWriterVtkBinary::writeQuadsWithNodeData to " << vtkfilename << " - end"); + return vtkfilename; +} +/*===============================================================================*/ +std::string WbWriterVtkBinary::writeQuadsWithCellData(const string &filename, vector<UbTupleFloat3> &nodes, + vector<UbTupleInt4> &cells, vector<string> &datanames, + vector<vector<double>> &celldata) +{ + // HEADER-SECTION + string vtkfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterVtkBinary::writeQuadsWithCellData to " << vtkfilename << " - start"); + + ofstream out(vtkfilename.c_str(), ofstream::out | ofstream::binary); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!! + string path = UbSystem::getPathFromString(vtkfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(vtkfilename.c_str(), ios::out | ios::binary); + } + if (!out) + throw UbException(UB_EXARGS, "couldn't open file " + vtkfilename); + } + + // WRITE BIGENDIAN VtkBinary FILE + bool swapByte = UbSystem::isLittleEndian(); + int nofNodes = (int)nodes.size(); + int nofCells = (int)cells.size(); + + out << "# vtk DataFile Version 4.0" + << "\n"; + out << "D3Q19MasterNodeGrid" + << "\n"; + out << "" + << "\n"; + + // POINTS SECTION + out << "DATASET UNSTRUCTURED_GRID" + << "\n"; + out << "POINTS " << nofNodes << " float" + << "\n"; + for (int n = 0; n < nofNodes; n++) { + float x1 = (float)val<1>(nodes[n]); + float x2 = (float)val<2>(nodes[n]); + float x3 = (float)val<3>(nodes[n]); + + if (swapByte) { + UbSystem::swapByteOrder((unsigned char *)&x1, sizeof(float)); + UbSystem::swapByteOrder((unsigned char *)&x2, sizeof(float)); + UbSystem::swapByteOrder((unsigned char *)&x3, sizeof(float)); + } + + out.write((char *)&x1, sizeof(float)); + out.write((char *)&x2, sizeof(float)); + out.write((char *)&x3, sizeof(float)); + } + out << "\n"; + + // CELLS SECTION + out << "CELLS " << nofCells << " " << nofCells * 5 << "\n"; + + int nodesPerCellDummy = 4; // nofNodesPerCell + if (swapByte) + UbSystem::swapByteOrder((unsigned char *)&nodesPerCellDummy, sizeof(int)); + for (int c = 0; c < (int)cells.size(); c++) { + int SW = val<1>(cells[c]); + int SE = val<2>(cells[c]); + int NE = val<3>(cells[c]); + int NW = val<4>(cells[c]); + if (swapByte) { + UbSystem::swapByteOrder((unsigned char *)&SW, sizeof(int)); + UbSystem::swapByteOrder((unsigned char *)&SE, sizeof(int)); + UbSystem::swapByteOrder((unsigned char *)&NW, sizeof(int)); + UbSystem::swapByteOrder((unsigned char *)&NE, sizeof(int)); + } + + out.write((char *)&nodesPerCellDummy, sizeof(int)); + out.write((char *)&SW, sizeof(int)); + out.write((char *)&SE, sizeof(int)); + out.write((char *)&NW, sizeof(int)); + out.write((char *)&NE, sizeof(int)); + } + out << "\n"; + + out << "CELL_TYPES " << (int)cells.size() << "\n"; + int celltype = 8; + if (swapByte) + UbSystem::swapByteOrder((unsigned char *)&celltype, sizeof(int)); + for (int c = 0; c < nofCells; c++) + out.write((char *)&celltype, sizeof(int)); + + out << endl; + + // DATA SECTION + // write data section + out << "CELL_DATA " << nofCells << "\n"; + for (int s = 0; s < (int)datanames.size(); ++s) { + if ((int)celldata[s].size() != nofCells) + throw UbException(UB_EXARGS, "datasetsize must be equal to nofNodes"); + out << "SCALARS " << datanames[s] << " float 1 \n LOOKUP_TABLE default \n"; + for (int d = 0; d < (int)celldata[s].size(); d++) { + float dummy = (float)celldata[s][d]; + if (swapByte) + UbSystem::swapByteOrder((unsigned char *)&dummy, sizeof(float)); + out.write((const char *)&dummy, sizeof(float)); + } + out << endl; + } + out.close(); + + UBLOG(logDEBUG1, "WbWriterVtkBinary::writeQuadsWithCellData to " << vtkfilename << " - end"); + return vtkfilename; +} +/*===============================================================================*/ +std::string WbWriterVtkBinary::writeQuadsWithNodeAndCellData(const string &filename, vector<UbTupleFloat3> &nodes, + vector<UbTupleInt4> &cells, vector<string> &nodedatanames, + vector<vector<double>> &nodedata, + vector<string> &celldatanames, + vector<vector<double>> &celldata) +{ + string vtkfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterVtkBinary::writeQuadsWithNodeAndCellData to " << vtkfilename << " - start"); + + ofstream out(vtkfilename.c_str(), ofstream::out | ofstream::binary); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!! + string path = UbSystem::getPathFromString(vtkfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(vtkfilename.c_str(), ios::out | ios::binary); + } + if (!out) + throw UbException(UB_EXARGS, "couldn't open file " + vtkfilename); + } + + // HEADER-SECTION + // WRITE BIGENDIAN VtkBinary FILE + bool swapByte = UbSystem::isLittleEndian(); + int nofNodes = (int)nodes.size(); + int nofCells = (int)cells.size(); + + out << "# vtk DataFile Version 4.0" + << "\n"; + out << "D3Q19MasterNodeGrid" + << "\n"; + out << "" + << "\n"; + + // POINTS SECTION + out << "DATASET UNSTRUCTURED_GRID" + << "\n"; + out << "POINTS " << nofNodes << " float" + << "\n"; + for (int n = 0; n < nofNodes; n++) { + float x1 = (float)val<1>(nodes[n]); + float x2 = (float)val<2>(nodes[n]); + float x3 = (float)val<3>(nodes[n]); + + if (swapByte) { + UbSystem::swapByteOrder((unsigned char *)&x1, sizeof(float)); + UbSystem::swapByteOrder((unsigned char *)&x2, sizeof(float)); + UbSystem::swapByteOrder((unsigned char *)&x3, sizeof(float)); + } + + out.write((char *)&x1, sizeof(float)); + out.write((char *)&x2, sizeof(float)); + out.write((char *)&x3, sizeof(float)); + } + out << "\n"; + + // CELLS SECTION + out << "CELLS " << nofCells << " " << nofCells * 5 << "\n"; + + int nodesPerCellDummy = 4; // nofNodesPerCell + if (swapByte) + UbSystem::swapByteOrder((unsigned char *)&nodesPerCellDummy, sizeof(int)); + for (int c = 0; c < (int)cells.size(); c++) { + int SW = val<1>(cells[c]); + int SE = val<2>(cells[c]); + int NE = val<3>(cells[c]); + int NW = val<4>(cells[c]); + if (swapByte) { + UbSystem::swapByteOrder((unsigned char *)&SW, sizeof(int)); + UbSystem::swapByteOrder((unsigned char *)&SE, sizeof(int)); + UbSystem::swapByteOrder((unsigned char *)&NW, sizeof(int)); + UbSystem::swapByteOrder((unsigned char *)&NE, sizeof(int)); + } + + out.write((char *)&nodesPerCellDummy, sizeof(int)); + out.write((char *)&SW, sizeof(int)); + out.write((char *)&SE, sizeof(int)); + out.write((char *)&NW, sizeof(int)); + out.write((char *)&NE, sizeof(int)); + } + out << "\n"; + + out << "CELL_TYPES " << (int)cells.size() << "\n"; + int celltype = 8; + if (swapByte) + UbSystem::swapByteOrder((unsigned char *)&celltype, sizeof(int)); + for (int c = 0; c < nofCells; c++) + out.write((char *)&celltype, sizeof(int)); + + out << endl; + + // NODE DATA SECTION + // write data section + out << "POINT_DATA " << nofNodes << "\n"; + for (int s = 0; s < (int)nodedatanames.size(); ++s) { + if ((int)nodedata[s].size() != nofNodes) + throw UbException(UB_EXARGS, "datasetsize must be equal to nofNodes"); + out << "SCALARS " << nodedatanames[s] << " float 1 \n LOOKUP_TABLE default \n"; + for (int d = 0; d < (int)nodedata[s].size(); d++) { + float dummy = (float)nodedata[s][d]; + if (swapByte) + UbSystem::swapByteOrder((unsigned char *)&dummy, sizeof(float)); + out.write((const char *)&dummy, sizeof(float)); + } + out << endl; + } + + // CELL DATA SECTION + // write data section + out << "CELL_DATA " << nofCells << "\n"; + for (int s = 0; s < (int)celldatanames.size(); ++s) { + if ((int)celldata[s].size() != nofCells) + throw UbException(UB_EXARGS, "datasetsize must be equal to nofNodes"); + out << "SCALARS " << celldatanames[s] << " float 1 \n LOOKUP_TABLE default \n"; + for (int d = 0; d < (int)celldata[s].size(); d++) { + float dummy = (float)celldata[s][d]; + if (swapByte) + UbSystem::swapByteOrder((unsigned char *)&dummy, sizeof(float)); + out.write((const char *)&dummy, sizeof(float)); + } + out << endl; + } + + out.close(); + + UBLOG(logDEBUG1, "WbWriterVtkBinary::writeQuadsWithNodeAndCellData to " << vtkfilename << " - end"); + return vtkfilename; +} +/*===============================================================================*/ +std::string WbWriterVtkBinary::writeOctsWithCellData(const string &filename, vector<UbTupleFloat3> &nodes, + vector<UbTupleInt8> &cells, vector<string> &datanames, + vector<vector<double>> &celldata) +{ + string vtkfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterVtkBinary::writeOctsWithCellData to " << vtkfilename << " - start"); + + ofstream out(vtkfilename.c_str(), ofstream::out | ofstream::binary); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!! + string path = UbSystem::getPathFromString(vtkfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(vtkfilename.c_str(), ios::out | ios::binary); + } + if (!out) + throw UbException(UB_EXARGS, "couldn't open file " + vtkfilename); + } + + // HEADER-SECTION + // WRITE BIGENDIAN VtkBinary FILE + bool swapByte = UbSystem::isLittleEndian(); + int nofNodes = (int)nodes.size(); + int nofCells = (int)cells.size(); + + out << "# vtk DataFile Version 4.0" + << "\n"; + out << "D3Q19MasterNodeGrid" + << "\n"; + out << "" + << "\n"; + + // POINTS SECTION + out << "DATASET UNSTRUCTURED_GRID" + << "\n"; + out << "POINTS " << nofNodes << " float" + << "\n"; + for (int n = 0; n < nofNodes; n++) { + float x1 = (float)val<1>(nodes[n]); + float x2 = (float)val<2>(nodes[n]); + float x3 = (float)val<3>(nodes[n]); + + if (swapByte) { + UbSystem::swapByteOrder((unsigned char *)&x1, sizeof(float)); + UbSystem::swapByteOrder((unsigned char *)&x2, sizeof(float)); + UbSystem::swapByteOrder((unsigned char *)&x3, sizeof(float)); + } + + out.write((char *)&x1, sizeof(float)); + out.write((char *)&x2, sizeof(float)); + out.write((char *)&x3, sizeof(float)); + } + out << "\n"; + + // CELLS SECTION + out << "CELLS " << nofCells << " " << nofCells * 9 << "\n"; + + int nodesPerCellDummy = 8; // nofNodesPerCell + if (swapByte) + UbSystem::swapByteOrder((unsigned char *)&nodesPerCellDummy, sizeof(int)); + for (int c = 0; c < (int)cells.size(); c++) { + int BSW = val<1>(cells[c]); + int TSW = val<5>(cells[c]); + int BSE = val<2>(cells[c]); + int TSE = val<6>(cells[c]); + int BNW = val<3>(cells[c]); + int TNW = val<7>(cells[c]); + int BNE = val<4>(cells[c]); + int TNE = val<8>(cells[c]); + if (swapByte) { + UbSystem::swapByteOrder((unsigned char *)&BSW, sizeof(int)); + UbSystem::swapByteOrder((unsigned char *)&BSE, sizeof(int)); + UbSystem::swapByteOrder((unsigned char *)&BNW, sizeof(int)); + UbSystem::swapByteOrder((unsigned char *)&BNE, sizeof(int)); + UbSystem::swapByteOrder((unsigned char *)&TSW, sizeof(int)); + UbSystem::swapByteOrder((unsigned char *)&TSE, sizeof(int)); + UbSystem::swapByteOrder((unsigned char *)&TNW, sizeof(int)); + UbSystem::swapByteOrder((unsigned char *)&TNE, sizeof(int)); + } + + out.write((char *)&nodesPerCellDummy, sizeof(int)); + out.write((char *)&BSW, sizeof(int)); + out.write((char *)&BSE, sizeof(int)); + out.write((char *)&BNE, sizeof(int)); + out.write((char *)&BNW, sizeof(int)); + out.write((char *)&TSW, sizeof(int)); + out.write((char *)&TSE, sizeof(int)); + out.write((char *)&TNE, sizeof(int)); + out.write((char *)&TNW, sizeof(int)); + } + out << "\n"; + + out << "CELL_TYPES " << (int)cells.size() << "\n"; + int celltype = 11; + if (swapByte) + UbSystem::swapByteOrder((unsigned char *)&celltype, sizeof(int)); + for (int c = 0; c < nofCells; c++) + out.write((char *)&celltype, sizeof(int)); + + out << endl; + + // CELL DATA SECTION + // write data section + out << "CELL_DATA " << nofCells << "\n"; + for (int s = 0; s < (int)datanames.size(); ++s) { + if ((int)celldata[s].size() != nofCells) + throw UbException(UB_EXARGS, "datasetsize must be equal to nofNodes"); + out << "SCALARS " << datanames[s] << " float 1 \n LOOKUP_TABLE default \n"; + for (int d = 0; d < (int)celldata[s].size(); d++) { + float dummy = (float)celldata[s][d]; + if (swapByte) + UbSystem::swapByteOrder((unsigned char *)&dummy, sizeof(float)); + out.write((const char *)&dummy, sizeof(float)); + } + out << endl; + } + out.close(); + + UBLOG(logDEBUG1, "WbWriterVtkBinary::writeOctsWithCellData to " << vtkfilename << " - end"); + return vtkfilename; +} +/*===============================================================================*/ +std::string WbWriterVtkBinary::writeOctsWithNodeData(const string &filename, vector<UbTupleFloat3> &nodes, + vector<UbTupleUInt8> &cells, vector<string> &datanames, + vector<vector<double>> &nodedata) +{ + // HEADER-SECTION + string vtkfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterVtkBinary::writeOctsWithNodeData to " << vtkfilename << " - start"); + + ofstream out(vtkfilename.c_str(), ofstream::out | ofstream::binary); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!! + string path = UbSystem::getPathFromString(vtkfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(vtkfilename.c_str(), ios::out | ios::binary); + } + if (!out) + throw UbException(UB_EXARGS, "couldn't open file " + vtkfilename); + } + + // WRITE BIGENDIAN VtkBinary FILE + bool swapByte = UbSystem::isLittleEndian(); + int nofNodes = (int)nodes.size(); + int nofCells = (int)cells.size(); + + out << "# vtk DataFile Version 4.0" + << "\n"; + out << "D3Q19MasterNodeGrid" + << "\n"; + out << "" + << "\n"; + + // POINTS SECTION + out << "DATASET UNSTRUCTURED_GRID" + << "\n"; + out << "POINTS " << nofNodes << " float" + << "\n"; + for (int n = 0; n < nofNodes; n++) { + float x1 = val<1>(nodes[n]); + float x2 = val<2>(nodes[n]); + float x3 = val<3>(nodes[n]); + + if (swapByte) { + UbSystem::swapByteOrder((unsigned char *)&x1, sizeof(float)); + UbSystem::swapByteOrder((unsigned char *)&x2, sizeof(float)); + UbSystem::swapByteOrder((unsigned char *)&x3, sizeof(float)); + } + + out.write((char *)&x1, sizeof(float)); + out.write((char *)&x2, sizeof(float)); + out.write((char *)&x3, sizeof(float)); + } + out << "\n"; + + // CELLS SECTION + out << "CELLS " << nofCells << " " << nofCells * 9 << "\n"; + + int nodesPerCellDummy = 8; // nofNodesPerCell + if (swapByte) + UbSystem::swapByteOrder((unsigned char *)&nodesPerCellDummy, sizeof(int)); + for (int c = 0; c < (int)cells.size(); c++) { + int BSW = val<1>(cells[c]); + int TSW = val<5>(cells[c]); + int BSE = val<2>(cells[c]); + int TSE = val<6>(cells[c]); + int BNW = val<3>(cells[c]); + int TNW = val<7>(cells[c]); + int BNE = val<4>(cells[c]); + int TNE = val<8>(cells[c]); + if (swapByte) { + UbSystem::swapByteOrder((unsigned char *)&BSW, sizeof(int)); + UbSystem::swapByteOrder((unsigned char *)&BSE, sizeof(int)); + UbSystem::swapByteOrder((unsigned char *)&BNW, sizeof(int)); + UbSystem::swapByteOrder((unsigned char *)&BNE, sizeof(int)); + UbSystem::swapByteOrder((unsigned char *)&TSW, sizeof(int)); + UbSystem::swapByteOrder((unsigned char *)&TSE, sizeof(int)); + UbSystem::swapByteOrder((unsigned char *)&TNW, sizeof(int)); + UbSystem::swapByteOrder((unsigned char *)&TNE, sizeof(int)); + } + + out.write((char *)&nodesPerCellDummy, sizeof(int)); + out.write((char *)&BSW, sizeof(int)); + out.write((char *)&BSE, sizeof(int)); + out.write((char *)&BNE, sizeof(int)); + out.write((char *)&BNW, sizeof(int)); + out.write((char *)&TSW, sizeof(int)); + out.write((char *)&TSE, sizeof(int)); + out.write((char *)&TNE, sizeof(int)); + out.write((char *)&TNW, sizeof(int)); + } + out << "\n"; + + out << "CELL_TYPES " << (int)cells.size() << "\n"; + int celltype = 11; + if (swapByte) + UbSystem::swapByteOrder((unsigned char *)&celltype, sizeof(int)); + for (int c = 0; c < nofCells; c++) + out.write((char *)&celltype, sizeof(int)); + + out << endl; + + // NODE DATA SECTION + // write data section + out << "POINT_DATA " << nofNodes << "\n"; + for (int s = 0; s < (int)datanames.size(); ++s) { + if ((int)nodedata[s].size() != nofNodes) + throw UbException(UB_EXARGS, "datasetsize must be equal to nofNodes"); + out << "SCALARS " << datanames[s] << " float 1 \n LOOKUP_TABLE default \n"; + for (int d = 0; d < (int)nodedata[s].size(); d++) { + float dummy = (float)nodedata[s][d]; + if (swapByte) + UbSystem::swapByteOrder((unsigned char *)&dummy, sizeof(float)); + out.write((const char *)&dummy, sizeof(float)); + } + out << endl; + } + + out.close(); + + UBLOG(logDEBUG1, "WbWriterVtkBinary::writeOctsWithNodeData to " << vtkfilename << " - end"); + return vtkfilename; +} +/*===============================================================================*/ +std::string WbWriterVtkBinary::writeOcts(const string &filename, vector<UbTupleFloat3> &nodes, + vector<UbTupleInt8> &cells) +{ + string vtkfilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterVtkBinary::writeOcts to " << vtkfilename << " - start"); + + ofstream out(vtkfilename.c_str(), ofstream::out | ofstream::binary); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!! + string path = UbSystem::getPathFromString(vtkfilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(vtkfilename.c_str(), ios::out | ios::binary); + } + if (!out) + throw UbException(UB_EXARGS, "couldn't open file " + vtkfilename); + } + + // HEADER-SECTION + // WRITE BIGENDIAN VtkBinary FILE + bool swapByte = UbSystem::isLittleEndian(); + int nofNodes = (int)nodes.size(); + int nofCells = (int)cells.size(); + + out << "# vtk DataFile Version 4.0" + << "\n"; + out << "D3Q19MasterNodeGrid" + << "\n"; + out << "" + << "\n"; + + // POINTS SECTION + out << "DATASET UNSTRUCTURED_GRID" + << "\n"; + out << "POINTS " << nofNodes << " float" + << "\n"; + for (int n = 0; n < nofNodes; n++) { + float x1 = val<1>(nodes[n]); + float x2 = val<2>(nodes[n]); + float x3 = val<3>(nodes[n]); + + if (swapByte) { + UbSystem::swapByteOrder((unsigned char *)&x1, sizeof(float)); + UbSystem::swapByteOrder((unsigned char *)&x2, sizeof(float)); + UbSystem::swapByteOrder((unsigned char *)&x3, sizeof(float)); + } + + out.write((char *)&x1, sizeof(float)); + out.write((char *)&x2, sizeof(float)); + out.write((char *)&x3, sizeof(float)); + } + out << "\n"; + + // CELLS SECTION + out << "CELLS " << nofCells << " " << nofCells * 9 << "\n"; + + int nodesPerCellDummy = 8; // nofNodesPerCell + if (swapByte) + UbSystem::swapByteOrder((unsigned char *)&nodesPerCellDummy, sizeof(int)); + for (int c = 0; c < (int)cells.size(); c++) { + int BSW = val<1>(cells[c]); + int TSW = val<5>(cells[c]); + int BSE = val<2>(cells[c]); + int TSE = val<6>(cells[c]); + int BNW = val<3>(cells[c]); + int TNW = val<7>(cells[c]); + int BNE = val<4>(cells[c]); + int TNE = val<8>(cells[c]); + if (swapByte) { + UbSystem::swapByteOrder((unsigned char *)&BSW, sizeof(int)); + UbSystem::swapByteOrder((unsigned char *)&BSE, sizeof(int)); + UbSystem::swapByteOrder((unsigned char *)&BNW, sizeof(int)); + UbSystem::swapByteOrder((unsigned char *)&BNE, sizeof(int)); + UbSystem::swapByteOrder((unsigned char *)&TSW, sizeof(int)); + UbSystem::swapByteOrder((unsigned char *)&TSE, sizeof(int)); + UbSystem::swapByteOrder((unsigned char *)&TNW, sizeof(int)); + UbSystem::swapByteOrder((unsigned char *)&TNE, sizeof(int)); + } + + out.write((char *)&nodesPerCellDummy, sizeof(int)); + out.write((char *)&BSW, sizeof(int)); + out.write((char *)&BSE, sizeof(int)); + out.write((char *)&BNE, sizeof(int)); + out.write((char *)&BNW, sizeof(int)); + out.write((char *)&TSW, sizeof(int)); + out.write((char *)&TSE, sizeof(int)); + out.write((char *)&TNE, sizeof(int)); + out.write((char *)&TNW, sizeof(int)); + } + out << "\n"; + + out << "CELL_TYPES " << (int)cells.size() << "\n"; + int celltype = 11; + if (swapByte) + UbSystem::swapByteOrder((unsigned char *)&celltype, sizeof(int)); + for (int c = 0; c < nofCells; c++) + out.write((char *)&celltype, sizeof(int)); + + out << endl; + out.close(); + + UBLOG(logDEBUG1, "WbWriterVtkBinary::writeOcts to " << vtkfilename << " - end"); + return vtkfilename; +} diff --git a/src/basics/basics/writer/WbWriterVtkBinary.h b/src/basics/basics/writer/WbWriterVtkBinary.h new file mode 100644 index 0000000000000000000000000000000000000000..8d5485a58db22c60124b931a878e12acce16bd09 --- /dev/null +++ b/src/basics/basics/writer/WbWriterVtkBinary.h @@ -0,0 +1,116 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file WbWriterVtkBinary.h +//! \ingroup writer +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#ifndef WBWRITERVTKBINARY_H +#define WBWRITERVTKBINARY_H + +#include <basics/writer/WbWriter.h> + +class WbWriterVtkBinary : public WbWriter +{ +public: + static WbWriterVtkBinary *getInstance() + { + static WbWriterVtkBinary instance; + return &instance; + } + + WbWriterVtkBinary(const WbWriterVtkBinary &) = delete; + const WbWriterVtkBinary &operator=(const WbWriterVtkBinary &) = delete; + +private: + WbWriterVtkBinary() = default; + +public: + std::string getFileExtension() override { return ".bin.vtk"; } + + ////////////////////////////////////////////////////////////////////////// + // lines + // 0 ---- 1 + // nodenumbering must start with 0! + std::string writeLines(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt2> &lines) override; + + ////////////////////////////////////////////////////////////////////////// + // triangles + // cell numbering: + // 2 + // + // 0---1 + // nodenumbering must start with 0! + std::string writeTriangles(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt3> &cells) override; + std::string writeTrianglesWithNodeData(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt3> &cells, std::vector<std::string> &datanames, + std::vector<std::vector<double>> &nodedata) override; + + ////////////////////////////////////////////////////////////////////////// + // 2D + // cell numbering: + // 3---2 + // | | + // 0---1 + // nodenumbering must start with 0! + std::string writeQuads(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt4> &cells) override; + std::string writeQuadsWithNodeData(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt4> &cells, std::vector<std::string> &datanames, + std::vector<std::vector<double>> &nodedata) override; + std::string writeQuadsWithCellData(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt4> &cells, std::vector<std::string> &datanames, + std::vector<std::vector<double>> &celldata) override; + std::string writeQuadsWithNodeAndCellData(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt4> &cells, std::vector<std::string> &nodedatanames, + std::vector<std::vector<double>> &nodedata, + std::vector<std::string> &celldatanames, + std::vector<std::vector<double>> &celldata) override; + + ////////////////////////////////////////////////////////////////////////// + // octs + // 7 ---- 6 + // /| /| + // 4 +--- 5 | + // | | | | + // | 3 ---+ 2 + // |/ |/ + // 0 ---- 1 + std::string writeOcts(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt8> &cells) override; + std::string writeOctsWithCellData(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt8> &cells, std::vector<std::string> &datanames, + std::vector<std::vector<double>> &celldata) override; + std::string writeOctsWithNodeData(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleUInt8> &cells, std::vector<std::string> &datanames, + std::vector<std::vector<double>> &nodedata) override; +}; + +#endif // WBWRITERVTKBINARY_H diff --git a/src/basics/basics/writer/WbWriterX3D.cpp b/src/basics/basics/writer/WbWriterX3D.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fd8ab6174b0b948718b0d7fbc8ca74d4054b2d2b --- /dev/null +++ b/src/basics/basics/writer/WbWriterX3D.cpp @@ -0,0 +1,191 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file WbWriterX3D.cpp +//! \ingroup writer +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#include <basics/utilities/UbLogger.h> +#include <basics/writer/WbWriterX3D.h> + +using namespace std; + +/*===============================================================================*/ +std::string WbWriterX3D::writeTriangles(const string &filename, vector<UbTupleFloat3> &nodes, + vector<UbTupleInt3> &triangles) +{ + string X3DFilename = filename + getFileExtension(); + UBLOG(logDEBUG1, "WbWriterX3D::writeTriangles to " << X3DFilename << " - start"); + + std::ofstream out(X3DFilename.c_str()); + if (!out) { + out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!! + string path = UbSystem::getPathFromString(X3DFilename); + if (path.size() > 0) { + UbSystem::makeDirectory(path); + out.open(X3DFilename.c_str()); + } + if (!out) + throw UbException(UB_EXARGS, "couldn't open file " + X3DFilename); + } + + // General part + + // Root Element + out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl; + out << "<!DOCTYPE X3D PUBLIC \"ISO//Web3D//DTD X3D 3.1//EN\" \"http://www.web3d.org/specifications/x3d-3.1.dtd\">" + << endl; + out << "<X3D profile='Interchange' version='3.1' xmlns:xsd='http://www.w3.org/2001/XMLSchema-instance' " + "xsd:noNamespaceSchemaLocation=' http://www.web3d.org/specifications/x3d-3.1.xsd '>" + << endl + << endl; + + // Head + out << "<head>" << endl; + out << "<meta content='Simple X3D Writer for blender'/>" << endl; + out << "</head>" << endl << endl; + + // Scene, Shape beginn + out << "<Scene>" << endl; + out << "<Shape>" << endl; + + // IndexedFaceSet => Polylinien der Dreiecke + out << "<IndexedFaceSet coordIndex=\"" << endl; + + // TRIANGLES Ponits SECTION + int nofTriangles = (int)triangles.size(); + // out<<" triangles "<<nofTriangles<<endl; + for (int c = 0; c < nofTriangles; c++) + out << " " << val<1>(triangles[c]) << " " << val<2>(triangles[c]) << " " << val<3>(triangles[c]) << " -1" + << endl; + out << "\">" << endl; + + // Coordinates + out << "<Coordinate point=\"" << endl; + + // Coordinates SECTION + int nofNodes = (int)nodes.size(); + // out<<" points "<<nofNodes<<endl; + for (int n = 0; n < nofNodes; n++) + out << " " << val<1>(nodes[n]) << ", " << val<2>(nodes[n]) << ", " << val<3>(nodes[n]) << ", " << endl; + out << "\"/>" << endl; + + // Footer + out << "</IndexedFaceSet>" << endl; + out << "</Shape>" << endl; + out << "</Scene>" << endl; + out << "</X3D>" << endl; + + //// Image details + // out<<"image {" <<endl; + // out<<" resolution 640 480"<<endl; + // out<<" aa 0 1" <<endl; + // out<<" filter mitchell" <<endl; + // out<<"}" <<endl<<endl; + + //// Camera position + // out<<"camera {" <<endl; + // out<<" type pinhole" <<endl; + // out<<" eye -0.25 -0.3 0.13"<<endl; + // out<<" target -0.1 0.1 0.13" <<endl; + // out<<" up 0 0 1" <<endl; + // out<<" fov 60" <<endl; + // out<<" aspect 1.333333" <<endl; + // out<<"}" <<endl<<endl; + + //// Light + // out<<"light {" <<endl; + // out<<" type ibl" <<endl; + // out<<" image sky_small.hdr" <<endl; + // out<<" center 0 -1 0" <<endl; + // out<<" up 0 0 1" <<endl; + // out<<" lock true" <<endl; + // out<<" samples 200" <<endl; + // out<<"}" <<endl<<endl; + + //// Shaders + // out<<"shader {" <<endl; + // out<<" name default-shader" <<endl; + // out<<" type diffuse" <<endl; + // out<<" diff 0.25 0.25 0.25" <<endl; + // out<<"}" <<endl<<endl; + + // out<<"shader {" <<endl; + // out<<" name Glass" <<endl; + // out<<" type glass" <<endl; + // out<<" eta 1.333" <<endl; + // out<<" color 0.1 0.3 0.8" <<endl; + // out<<"}" <<endl<<endl; + // + // out<<"shader {" <<endl; + // out<<" name Mirror" <<endl; + // out<<" type mirror" <<endl; + // out<<" refl 0.7 0.7 0.7" <<endl; + // out<<"}" <<endl<<endl; + + //// Objects + //// a) Ground plane + // out<<"object {" <<endl; + // out<<" shader default-shader" <<endl; + // out<<" type plane" <<endl; + // out<<" p 0 0 0" <<endl; + // out<<" n 0 0 1" <<endl; + // out<<"}" <<endl<<endl; + + //// b) Mesh + // out<<"object {" <<endl; + // out<<" shader Glass" <<endl; + // out<<" transform {" <<endl; + // out<<" rotatey 270.0" <<endl; + // out<<" }" <<endl; + // out<<" type generic-mesh" <<endl; + // out<<" name polySurfac" <<endl<<endl; + + //// POINTS SECTION + // int nofNodes = (int)nodes.size(); + // out<<" points "<<nofNodes<<endl; + // for(int n=0; n<nofNodes; n++) + // out<<" "<< val<1>(nodes[n]) <<" "<< val<2>(nodes[n]) <<" "<< val<3>(nodes[n]) <<endl; + + //// TRIANGLES SECTION + // int nofTriangles= (int)triangles.size(); + // out<<" triangles "<<nofTriangles<<endl; + // for(int c=0; c<nofTriangles; c++) + // out<<" "<<val<1>(triangles[c]) <<" "<< val<2>(triangles[c])<<" "<< val<3>(triangles[c])<<endl; + + //// FOOTER + // out<<" normals none" << endl; + // out<<" uvs none" << endl; + // out<<"}" << endl; + + out.close(); + UBLOG(logDEBUG1, "WbWriterX3D::writeTriangles to " << X3DFilename << " - end"); + + return X3DFilename; +} +/*===============================================================================*/ diff --git a/src/basics/basics/writer/WbWriterX3D.h b/src/basics/basics/writer/WbWriterX3D.h new file mode 100644 index 0000000000000000000000000000000000000000..4884d828c8f17a4c0ec270fbbe6fa42e69adb69e --- /dev/null +++ b/src/basics/basics/writer/WbWriterX3D.h @@ -0,0 +1,72 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file WbWriterX3D.h +//! \ingroup writer +//! \author Soeren Freudiger, Sebastian Geller +//======================================================================================= +#ifndef WBWRITERX3D_H +#define WBWRITERX3D_H + +#include <string> + +#include <basics/writer/WbWriter.h> + +class WbWriterX3D : public WbWriter +{ +public: + static WbWriterX3D *getInstance() + { + static WbWriterX3D instance; + return &instance; + } + + WbWriterX3D(const WbWriterX3D &) = delete; + const WbWriterX3D &operator=(const WbWriterX3D &) = delete; + +private: + WbWriterX3D() : WbWriter() + { + if (sizeof(unsigned char) != 1) + throw UbException(UB_EXARGS, "error char type mismatch"); + if (sizeof(int) != 4) + throw UbException(UB_EXARGS, "error int type mismatch"); + if (sizeof(float) != 4) + throw UbException(UB_EXARGS, "error float type mismatch"); + } + + static std::string pvdEndTag; + +public: + std::string getFileExtension() override { return "ascii.X3D"; } + + std::string writeTriangles(const std::string &filename, std::vector<UbTupleFloat3> &nodes, + std::vector<UbTupleInt3> &triangles) override; +}; + +#endif // WBWRITERX3D_H diff --git a/src/basics/config/ConfigurationFile.cpp b/src/basics/config/ConfigurationFile.cpp new file mode 100644 index 0000000000000000000000000000000000000000..026d13e15486c46a7056e061ea075a03c9c06f9f --- /dev/null +++ b/src/basics/config/ConfigurationFile.cpp @@ -0,0 +1,133 @@ +#include "ConfigurationFile.h" + + +#include <map> +#include <vector> +#include <sstream> +#include <string> +#include <fstream> +#include <iostream> +#include <stdlib.h> + +#include <basics/basics/utilities/UbException.h> + + +namespace vf::basics +{ + +void ConfigurationFile::clear() +{ + data.clear(); +} +////////////////////////////////////////////////////////////////////////// +bool ConfigurationFile::load(const std::string& file) +{ + std::ifstream inFile(file.c_str()); + + if (!inFile.good()) + { + UB_THROW(UbException(UB_EXARGS, "Cannot read configuration file "+file+"!")); + } + + while (inFile.good() && ! inFile.eof()) + { + std::string line; + getline(inFile, line); + + // filter out comments + if (!line.empty()) + { + size_t pos = line.find('#'); + + if (pos != std::string::npos) + { + line = line.substr(0, pos); + } + } + + // split line into key and value + if (!line.empty()) + { + size_t pos = line.find('='); + + if (pos != std::string::npos) + { + std::string key = trim(line.substr(0, pos)); + std::string value = trim(line.substr(pos + 1)); + + if (!key.empty() && !value.empty()) + { + data[key] = value; + } + } + } + } + + return true; +} + +////////////////////////////////////////////////////////////////////////// +template<> +bool ConfigurationFile::fromString<bool>(const std::string& str) const +{ + return str == "true"; +} + +////////////////////////////////////////////////////////////////////////// +bool ConfigurationFile::contains(const std::string& key) const +{ + return data.find(key) != data.end(); +} +////////////////////////////////////////////////////////////////////////// +std::string ConfigurationFile::getString(const std::string& key) const +{ + std::map<std::string, std::string>::const_iterator iter = data.find(key); + + if (iter != data.end()) + { + std::string value = iter->second; + return value; + } + else + { + UB_THROW(UbException(UB_EXARGS, "The parameter \"" + key + "\" is missing!")); + } +} +////////////////////////////////////////////////////////////////////////// +std::string ConfigurationFile::trim(const std::string& str) +{ + size_t first = str.find_first_not_of(" \t\n\r"); + + if (first != std::string::npos) + { + size_t last = str.find_last_not_of(" \t\n\r"); + + return str.substr(first, last - first + 1); + } + else + { + return ""; + } +} +////////////////////////////////////////////////////////////////////////// +void ConfigurationFile::split(std::vector<std::string>& lst, const std::string& input, const std::string& separators, bool remove_empty) const +{ + std::ostringstream word; + for (size_t n = 0; n < input.size(); ++n) + { + if (std::string::npos == separators.find(input[n])) + word << input[n]; + else + { + if (!word.str().empty() || !remove_empty) + lst.push_back(word.str()); + word.str(""); + } + } + if (!word.str().empty() || !remove_empty) + lst.push_back(word.str()); +} +////////////////////////////////////////////////////////////////////////// + + +} diff --git a/src/basics/config/ConfigurationFile.h b/src/basics/config/ConfigurationFile.h new file mode 100644 index 0000000000000000000000000000000000000000..ef7e7c9f06f94cabb3ba9cbefe95c8ee75736958 --- /dev/null +++ b/src/basics/config/ConfigurationFile.h @@ -0,0 +1,143 @@ +#ifndef BASICS_CONFIGURATIONFILE_H +#define BASICS_CONFIGURATIONFILE_H + +#include <map> +#include <vector> +#include <sstream> +#include <string> +#include <fstream> +#include <iostream> +#include <stdlib.h> + +#include <basics/basics/utilities/UbException.h> + +//! \brief Simple configuration file +//! \details The Configuration class presented here can read and keep values of any configuration file written in a format like this: +//!# +//!# Simulation parameters +//!# +//! +//!nbDimensions = 2 +//!temperature = 25.001 +//!epsilon = 1.013e-14 +//!writeLogFile = false # NOTE: Set to "true" in debug mode only. +//! # Logging slows down the program. +//!errorMessage = the simulation failed +//!origin = 0.0 0.0 0.0 # x, y, z of origin +//! +//!Example how to use it: +//! +//!ConfigurationFile config; +//!config.load(configname); +//! +//!int nbDimensions = config.getValue<int>("nbDimensions"); +//!float temperature = config.getValue<float>("temperature"); +//!double epsilon = config.getValue<double>("epsilon"); +//!bool writeLogFile = config.getValue<bool>("writeLogFile"); +//!string errorMessage = config.getValue<string>("errorMessage"); +//!vector<double> origin = config.getVector<double>("origin"); +//! +//! \author Konstantin Kutscher + + +namespace vf::basics +{ + + +class ConfigurationFile +{ +public: + //! clear all values + void clear(); + + //! load a configuration file + bool load(const std::string& File); + + //! check if value associated with given key exists + bool contains(const std::string& key) const; + + //! get vector with key + template<class T> + std::vector<T> getVector(const std::string& key) const; + + //! get value with key + template<class T> + T getValue(const std::string& key) const; + +private: + //! the container + std::map<std::string, std::string> data; + + //! get string with key + std::string getString(const std::string& key) const; + + //! remove leading and trailing tabs and spaces + static std::string trim(const std::string& str); + + //! convert string to data type T + template<class T> + T fromString(const std::string& str) const; + + void split(std::vector<std::string>& lst, const std::string& input, const std::string& separators, bool remove_empty = true) const; +}; + + +////////////////////////////////////////////////////////////////////////// +template<class T> +std::vector<T> ConfigurationFile::getVector(const std::string& key) const +{ + std::string str = getString(key); + std::vector<T> v; + std::vector<std::string> strings; + split(strings, str, "\t\n\r;, "); + for (std::vector<std::string>::iterator it = strings.begin(); it != strings.end(); ++it) + { + if (*it != "") + { + v.push_back(fromString<T>(*it)); + } + } + return v; +} +////////////////////////////////////////////////////////////////////////// +template<class T> +T ConfigurationFile::fromString(const std::string& str) const +{ + std::istringstream stream(str); + T t; + stream >> t; + return t; +} + +template<> +bool ConfigurationFile::fromString<bool>(const std::string& str) const; + +////////////////////////////////////////////////////////////////////////// +template<class T> +T ConfigurationFile::getValue(const std::string& key) const +{ + std::string str = getString(key); + bool bFlag = false; + if ((std::string)typeid(T).name() == (std::string)typeid(bool).name()) + { + bFlag = true; + } + + std::istringstream iss(str); + T x; + iss >> x; + if (!iss && !bFlag) + UB_THROW(UbException(UB_EXARGS, " cannot convert \"" + str + "\" to type <" + static_cast<std::string>(typeid(x).name()) + ">")); + + if (bFlag) + { + bool value = (str == "true"); + x = value; + } + + return x; +} + +} + +#endif diff --git a/src/basics/geometry3d/GbCylinder3D.cpp b/src/basics/geometry3d/GbCylinder3D.cpp new file mode 100644 index 0000000000000000000000000000000000000000..562eb70c85acd87b405cf0c05f646ce22a40b3de --- /dev/null +++ b/src/basics/geometry3d/GbCylinder3D.cpp @@ -0,0 +1,1344 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file GbCylinder3D.cpp +//! \ingroup geometry3D +//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller +//======================================================================================= +#include <basics/utilities/UbInfinity.h> +#include <geometry3d/GbCylinder3D.h> +#include <geometry3d/GbPoint3D.h> +#include <geometry3d/GbSystem3D.h> +#include <geometry3d/GbTriangle3D.h> + +using namespace std; + +// Konstruktor +/*==========================================================*/ +GbCylinder3D::GbCylinder3D() + +{ + this->setName("cylinder"); + GbPoint3D *p1 = new GbPoint3D(); + GbPoint3D *p2 = new GbPoint3D(); + mLine = new GbLine3D(p1, p2); + this->mLine->addObserver(this); + mRad = 0.0; + cylinderType = GbCylinder3D::NOTPARALLELTOAXIS; + this->mLine->addObserver(this); + this->calculateValues(); +} +/*=======================================================*/ +GbCylinder3D::GbCylinder3D(GbCylinder3D *cylinder) +{ + this->setName("cylinder"); + mRad = cylinder->getRadius(); + cylinderType = cylinder->cylinderType; + mLine = cylinder->getLine()->clone(); + + this->mLine->addObserver(this); + this->calculateValues(); +} +/*==========================================================*/ +GbCylinder3D::GbCylinder3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b, + const double &x2b, const double &x3b, const double &rad) +{ + this->setName("cylinder"); + mLine = new GbLine3D; + // Min/Max, damit gewaehrleistet ist, dass Startpunkt immer der "Achs-Minimale" ist + // Anm.: bin nich tsicher ob weiter unten irgendwelche Algos drauf beruhen... + // geht nat nur solange, zylinder achs-parallel, aber das ist erzeit so!!! + mLine->setPoints(new GbPoint3D(min(x1a, x1b), min(x2a, x2b), min(x3a, x3b)), + new GbPoint3D(max(x1a, x1b), max(x2a, x2b), max(x3a, x3b))); + // mLine->setPoints( new GbPoint3D(x1a,x2a,x3a),new GbPoint3D(x1b, x2b ,x3b )); + this->mLine->addObserver(this); + mRad = fabs(rad); + + this->calculateValues(); +} +/*==========================================================*/ +GbCylinder3D::GbCylinder3D(GbPoint3D *p1, GbPoint3D *p2, const double &rad) +{ + this->setName("cylinder"); + mRad = rad; + + mLine = new GbLine3D(p1, p2); + this->mLine->addObserver(this); + this->calculateValues(); +} +/*==========================================================*/ +GbCylinder3D::GbCylinder3D(GbLine3D *line, const double &rad) +{ + this->setName("cylinder"); + mRad = rad; + + this->mLine = line; + this->mLine->addObserver(this); + + this->calculateValues(); +} +/*==========================================================*/ +// Destruktor +GbCylinder3D::~GbCylinder3D() +{ + if (mLine) + this->mLine->removeObserver(this); + mLine = NULL; +} +/*=======================================================*/ +void GbCylinder3D::calculateValues() +{ + double x1a = mLine->getPoint1()->x1; + double x1b = mLine->getPoint2()->x1; + double x2a = mLine->getPoint1()->x2; + double x2b = mLine->getPoint2()->x2; + double x3a = mLine->getPoint1()->x3; + double x3b = mLine->getPoint2()->x3; + + if (x1a != x1b && x2a == x2b && x3a == x3b) + this->cylinderType = X1PARALLEL; + else if (x2a != x2b && x1a == x1b && x3a == x3b) + this->cylinderType = X2PARALLEL; + else if (x3a != x3b && x1a == x1b && x2a == x2b) + this->cylinderType = X3PARALLEL; + // nach dem serialisieren ruft er den Standardkonstruktor auf wo alles 0 ist und bricht sonst hier ab + else if (x3a == x3b && x1a == x1b && x2a == x2b) + this->cylinderType = X1PARALLEL; + else + this->cylinderType = NOTPARALLELTOAXIS; + + if ((this->cylinderType & NOTPARALLELTOAXIS) == NOTPARALLELTOAXIS) + throw UbException(UB_EXARGS, + "derzeit nur zu Achsen orthogonale Zylinder erlaubt... isPointInObject3D funzt sonst ned"); + + if (this->isParallelToX1Axis()) { + minX1 = mLine->getX1Minimum(); + maxX1 = mLine->getX1Maximum(); + minX2 = mLine->getX2Centroid() - mRad; + maxX2 = mLine->getX2Centroid() + mRad; + minX3 = mLine->getX3Centroid() - mRad; + maxX3 = mLine->getX3Centroid() + mRad; + } else if (this->isParallelToX2Axis()) { + minX1 = mLine->getX1Centroid() - mRad; + maxX1 = mLine->getX1Centroid() + mRad; + minX2 = mLine->getX2Minimum(); + maxX2 = mLine->getX2Maximum(); + minX3 = mLine->getX3Centroid() - mRad; + maxX3 = mLine->getX3Centroid() + mRad; + } else if (this->isParallelToX3Axis()) { + minX1 = mLine->getX1Centroid() - mRad; + maxX1 = mLine->getX1Centroid() + mRad; + minX2 = mLine->getX2Centroid() - mRad; + maxX2 = mLine->getX2Centroid() + mRad; + minX3 = mLine->getX3Minimum(); + maxX3 = mLine->getX3Maximum(); + } + + centerX1 = mLine->getX1Centroid(); + centerX2 = mLine->getX2Centroid(); + centerX3 = mLine->getX3Centroid(); +} + +/*=======================================================*/ +void GbCylinder3D::finalize() +{ + if (this->mLine) { + mLine->finalize(); + delete mLine; + mLine = NULL; + } +} +/*=======================================================*/ +double GbCylinder3D::getHeight() +{ + if (mLine) + return mLine->getLength(); + + return 0.0; +} +/*=======================================================*/ +GbPoint3D *GbCylinder3D::getPoint1() +{ + if (this->mLine) + return this->mLine->getPoint1(); + return NULL; +} +/*=======================================================*/ +GbPoint3D *GbCylinder3D::getPoint2() +{ + if (this->mLine) + return this->mLine->getPoint2(); + return NULL; +} +/*=======================================================*/ +void GbCylinder3D::setRadius(const double &radius) +{ + this->mRad = std::fabs(radius); + this->notifyObserversObjectChanged(); +} +/*=======================================================*/ +void GbCylinder3D::setLine(GbLine3D *line) +{ + if (this->mLine) + this->mLine->removeObserver(this); + this->mLine = line; + this->mLine->addObserver(this); + this->calculateValues(); + + this->notifyObserversObjectChanged(); +} +/*=======================================================*/ +void GbCylinder3D::setPoint1(const double &x1, const double &x2, const double &x3) +{ + if (!mLine->getPoint1()) + throw UbException(UB_EXARGS, "line has no point1"); + mLine->getPoint1()->setCoordinates(x1, x2, x3); + this->calculateValues(); + + // this->notifyObserversObjectChanged(); //wird automatisch aufgerufen, da der point (this) benachrichtigt... +} +/*=======================================================*/ +void GbCylinder3D::setPoint2(const double &x1, const double &x2, const double &x3) +{ + if (!mLine->getPoint2()) + throw UbException(UB_EXARGS, "line has no point2"); + mLine->getPoint2()->setCoordinates(x1, x2, x3); + this->calculateValues(); + + // this->notifyObserversObjectChanged(); //wird automatisch aufgerufen, da der point (this) benachrichtigt... +} +/*==========================================================*/ +bool GbCylinder3D::isPointInGbObject3D(const double &x1p, const double &x2p, const double &x3p) +{ + // true, wenn 'in Object' oder 'auf Boundary'! + if (this->isParallelToX1Axis() && (UbMath::less(x1p, minX1) || UbMath::greater(x1p, maxX1))) + return false; + else if (this->isParallelToX2Axis() && (UbMath::less(x2p, minX2) || UbMath::greater(x2p, maxX2))) + return false; + else if (this->isParallelToX3Axis() && (UbMath::less(x3p, minX3) || UbMath::greater(x3p, maxX3))) + return false; + else if (this->isNotParallelToAxis()) + throw UbException(UB_EXARGS, + "derzeit nur zu Achsen orthogonale Zylinder erlaubt... isPointInObject3D funzt sonst ned"); + + return UbMath::lessEqual(fabs(mLine->getDistance(x1p, x2p, x3p)), fabs(mRad)); +} +/*==========================================================*/ +bool GbCylinder3D::isPointInGbObject3D(const double &x1p, const double &x2p, const double &x3p, bool &pointIsOnBoundary) +{ + // funzt derzeit nur bei achsparallelen cylindern + pointIsOnBoundary = false; + + if (this->isParallelToX1Axis() && (UbMath::less(x1p, minX1) || UbMath::greater(x1p, maxX1))) + return false; + else if (this->isParallelToX2Axis() && (UbMath::less(x2p, minX2) || UbMath::greater(x2p, maxX2))) + return false; + else if (this->isParallelToX3Axis() && (UbMath::less(x3p, minX3) || UbMath::greater(x3p, maxX3))) + return false; + else if (this->isNotParallelToAxis()) + throw UbException(UB_EXARGS, + "derzeit nur zu Achsen orthogonale Zylinder erlaubt... isPointInObject3D funzt sonst ned"); + + // true, wenn 'in Object' oder 'auf Boundary'! + + double dis = mLine->getDistance(x1p, x2p, x3p); + + if (UbMath::equal(dis, mRad)) + pointIsOnBoundary = true; + + if (this->isParallelToX1Axis() && (UbMath::equal(x1p, minX1) || UbMath::equal(x1p, maxX1))) + pointIsOnBoundary = true; + else if (this->isParallelToX2Axis() && (UbMath::equal(x2p, minX2) || UbMath::equal(x2p, maxX2))) + pointIsOnBoundary = true; + else if (this->isParallelToX3Axis() && (UbMath::equal(x3p, minX3) || UbMath::equal(x3p, maxX3))) + pointIsOnBoundary = true; + + return UbMath::lessEqual(dis, mRad); +} +/*==========================================================*/ +string GbCylinder3D::toString() +{ + stringstream ss; + ss << "GbCylinder3D["; + ss << "line=" << this->mLine->toString(); + ss << ", r=" << this->mRad; + ss << "]"; + return (ss.str()); +} +/*=======================================================*/ +bool GbCylinder3D::isCellInsideGbObject3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b, + const double &x2b, const double &x3b) +{ + if (this->isPointInGbObject3D(x1a, x2a, x3a) && this->isPointInGbObject3D(x1b, x2a, x3a) && + this->isPointInGbObject3D(x1b, x2b, x3a) && this->isPointInGbObject3D(x1a, x2b, x3a) && + this->isPointInGbObject3D(x1a, x2a, x3b) && this->isPointInGbObject3D(x1b, x2a, x3b) && + this->isPointInGbObject3D(x1b, x2b, x3b) && this->isPointInGbObject3D(x1a, x2b, x3b)) { + return true; + } + return false; +} +/*==========================================================*/ +bool GbCylinder3D::isCellCuttingGbObject3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b, + const double &x2b, const double &x3b) +// Merksatz: cell oder deren Volumen schneidet oder beinhaltet komplette oder Teile der CuboidUmrandung +// returns true: +// - cell cuts cylinder3D +// - cell boxes cylinder3D +// returns false: +// - cell completely inside cylinder3D ( = cylinder3D boxes cell) +// - cell und cylinder3D haben kein gemeinsames Volumen +{ + // erstmal wieder die dumm Loesung + if (this->isCellInsideOrCuttingGbObject3D(x1a, x2a, x3a, x1b, x2b, x3b) && + !this->isCellInsideGbObject3D(x1a, x2a, x3a, x1b, x2b, x3b)) { + return true; + } + + return false; +} +/*==========================================================*/ +bool GbCylinder3D::isCellInsideOrCuttingGbObject3D(const double &x1a, const double &x2a, const double &x3a, + const double &x1b, const double &x2b, const double &x3b) +// returns true: +// - cell completely inside cylinder3D ( = cylinder3D boxes cell) +// - cell cuts cylinder3D +// - cell boxes cylinder3D +// returns false: +// - cell und cylinder3D haben kein gemeinsames Volumen +{ + double dmin = 0.0; + + if (this->isParallelToX1Axis()) { + // check liegt Cell komplett !x1-ausserhalb"? + if (UbMath::less(x1a, minX1) && UbMath::less(x1b, minX1)) + return false; + if (UbMath::greater(x1a, maxX1) && UbMath::greater(x1b, maxX1)) + return false; + + // mittelpunkt kreis-querschnitt + double &midX2 = mLine->getPoint1()->x2; + double &midX3 = mLine->getPoint1()->x3; + if (UbMath::less(midX2, x2a)) + dmin += std::pow(midX2 - x2a, 2.0); + else if (UbMath::greater(midX2, x2b)) + dmin += std::pow(midX2 - x2b, 2.0); + if (UbMath::less(midX3, x3a)) + dmin += std::pow(midX3 - x3a, 2.0); + else if (UbMath::greater(midX3, x3b)) + dmin += std::pow(midX3 - x3b, 2.0); + if (UbMath::lessEqual(dmin, mRad * mRad)) + return true; + + return false; + } else if (this->isParallelToX2Axis()) { + // check liegt Cell komplett !x2-ausserhalb"? + if (UbMath::less(x2a, minX2) && UbMath::less(x2b, minX2)) + return false; + if (UbMath::greater(x2a, maxX2) && UbMath::greater(x2b, maxX2)) + return false; + + // mittelpunkt kreis-querschnitt + double &midX1 = mLine->getPoint1()->x1; + double &midX3 = mLine->getPoint1()->x3; + if (UbMath::less(midX1, x1a)) + dmin += std::pow(midX1 - x1a, 2.0); + else if (UbMath::greater(midX1, x1b)) + dmin += std::pow(midX1 - x1b, 2.0); + if (UbMath::less(midX3, x3a)) + dmin += std::pow(midX3 - x3a, 2.0); + else if (UbMath::greater(midX3, x3b)) + dmin += std::pow(midX3 - x3b, 2.0); + if (UbMath::lessEqual(dmin, mRad * mRad)) + return true; + + } else if (this->isParallelToX3Axis()) { + // check liegt Cell komplett !x3-ausserhalb"? + if (UbMath::less(x3a, minX3) && UbMath::less(x3b, minX3)) + return false; + if (UbMath::greater(x3a, maxX3) && UbMath::greater(x3b, maxX3)) + return false; + + // mittelpunkt kreis-querschnitt + double &midX1 = mLine->getPoint1()->x1; + double &midX2 = mLine->getPoint1()->x2; + if (UbMath::less(midX1, x1a)) + dmin += std::pow(midX1 - x1a, 2.0); + else if (UbMath::greater(midX1, x1b)) + dmin += std::pow(midX1 - x1b, 2.0); + if (UbMath::less(midX2, x2a)) + dmin += std::pow(midX2 - x2a, 2.0); + else if (UbMath::greater(midX2, x2b)) + dmin += std::pow(midX2 - x2b, 2.0); + if (UbMath::lessEqual(dmin, mRad * mRad)) + return true; + } + + return false; +} +/*==========================================================*/ +GbLine3D *GbCylinder3D::createClippedLine3D(GbPoint3D &point1, GbPoint3D &point2) +{ + // liefert immer "innere" linie, also der teil, der vom Zylinder "abgeschnitten" wurde! + // funktioniert derzeit nur mit achsenparallelen Zylindern! + vector<GbPoint3D *> schnittpunkte; + + double xa, ya, za, xb, yb, zb, xm, ym, zStart, zEnd, t1, t2; + + if (this->isParallelToX1Axis()) { + xa = point1.getX2Coordinate(); + ya = point1.getX3Coordinate(); + za = point1.getX1Coordinate(); + xb = point2.getX2Coordinate(); + yb = point2.getX3Coordinate(); + zb = point2.getX1Coordinate(); + xm = mLine->getPoint1()->getX2Coordinate(); + ym = mLine->getPoint1()->getX3Coordinate(); + zStart = mLine->getPoint1()->getX1Coordinate(); + zEnd = mLine->getPoint2()->getX1Coordinate(); + } else if (this->isParallelToX2Axis()) { + xa = point1.getX1Coordinate(); + ya = point1.getX3Coordinate(); + za = point1.getX2Coordinate(); + xb = point2.getX1Coordinate(); + yb = point2.getX3Coordinate(); + zb = point2.getX2Coordinate(); + xm = mLine->getPoint1()->getX1Coordinate(); + ym = mLine->getPoint1()->getX3Coordinate(); + zStart = mLine->getPoint1()->getX2Coordinate(); + zEnd = mLine->getPoint2()->getX2Coordinate(); + } else if (this->isParallelToX3Axis()) { + xa = point1.getX1Coordinate(); + ya = point1.getX2Coordinate(); + za = point1.getX3Coordinate(); + xb = point2.getX1Coordinate(); + yb = point2.getX2Coordinate(); + zb = point2.getX3Coordinate(); + xm = mLine->getPoint1()->getX1Coordinate(); + ym = mLine->getPoint1()->getX2Coordinate(); + zStart = mLine->getPoint1()->getX3Coordinate(); + zEnd = mLine->getPoint2()->getX3Coordinate(); + } else + throw UbException(UB_EXARGS, "funktioniert derzeit nur mit achsenparallelen Zylindern"); + + // Bestimmung des Schnittpunktes mit unendlich ausgedehntem Zylinder + double r = mRad; + double r2 = r * r; + double xa2 = xa * xa; + double xb2 = xb * xb; + double ya2 = ya * ya; + double yb2 = yb * yb; + double xm2 = xm * xm; + double ym2 = ym * ym; + + double wurzel = 2.0 * xa * xm * yb2 + 2.0 * ya * ym * xb2 - 2.0 * xa * xb * r2 + 2.0 * xa * xb * ym2 - + 2.0 * ya * yb * r2 + 2.0 * xa2 * yb * ym + 2.0 * xa * xm * ya * ym - 2.0 * xa * xm * yb * ym - + 2.0 * ya * ym * xb * xm + 2.0 * xb * xm * yb * ym + 2.0 * ya * yb * xa * xb - + 2.0 * ya * yb * xa * xm - 2.0 * ya * yb * xb * xm - 2.0 * xa * xb * ya * ym - + 2.0 * xa * xb * yb * ym + 2.0 * xb * xm * ya2 + 2.0 * ya * yb * xm2 - xa2 * yb2 - xb2 * ya2 + + xa2 * r2 - xa2 * ym2 + xb2 * r2 - xb2 * ym2 + ya2 * r2 - ya2 * xm2 + yb2 * r2 - yb2 * xm2; + double nenner = -2.0 * (ya * yb + xa * xb) + xa2 + xb2 + ya2 + yb2; + double zaehler = 2.0 * (-xa * xm + xb * xm - ya * ym + yb * ym) + xa2 - xb2 + ya2 - yb2; + + if (UbMath::greaterEqual(wurzel, 0.0) && !UbMath::zero(nenner)) // fabs(nenner)>1.E-13) + { + t1 = (zaehler + 2.0 * sqrt(wurzel)) / nenner; + t2 = (zaehler - 2.0 * sqrt(wurzel)) / nenner; + + if (UbMath::inClosedInterval(t1, -1.0, 1.0)) // Schnittpunkt innerhalb der Strecke + { + double x = xa * (0.5 - 0.5 * t1) + xb * (0.5 + 0.5 * t1); + double y = ya * (0.5 - 0.5 * t1) + yb * (0.5 + 0.5 * t1); + double z = za * (0.5 - 0.5 * t1) + zb * (0.5 + 0.5 * t1); + + if (UbMath::inClosedInterval(z, zStart, zEnd)) // zWert muss sich innerhal der cylinderlaenge befinden + { + if (this->isParallelToX1Axis()) + schnittpunkte.push_back(new GbPoint3D(z, x, y)); + else if (this->isParallelToX2Axis()) + schnittpunkte.push_back(new GbPoint3D(x, z, y)); + else if (this->isParallelToX3Axis()) + schnittpunkte.push_back(new GbPoint3D(x, y, z)); + } + } + if (fabs(t2 - t1) > 1.E-13 && UbMath::inClosedInterval(t2, -1.0, 1.0)) // Schnittpunkt innerhalb der Strecke + { + double x = xa * (0.5 - 0.5 * t2) + xb * (0.5 + 0.5 * t2); + double y = ya * (0.5 - 0.5 * t2) + yb * (0.5 + 0.5 * t2); + double z = za * (0.5 - 0.5 * t2) + zb * (0.5 + 0.5 * t2); + + if (UbMath::inClosedInterval(z, zStart, zEnd)) // zWert muss sich innerhal der cylinderlaenge befinden + { + if (this->isParallelToX1Axis()) + schnittpunkte.push_back(new GbPoint3D(z, x, y)); + else if (this->isParallelToX2Axis()) + schnittpunkte.push_back(new GbPoint3D(x, z, y)); + else if (this->isParallelToX3Axis()) + schnittpunkte.push_back(new GbPoint3D(x, y, z)); + } + } + } + // wenn nenner==0 -> Strecke parallel zu Zylinder! Es muss noch auf Schnittpunkt mit "Deckeln" geprueft werden + + // Schnittpunkt mit Seitenflaechen bestimmen + // hierzu wird der schnittpunkt der gegebnen strecke mit den seitenflaechenberechnet + // als erstes "schaut man seitlich auf den Zylinder" --> kreisflaechen wird als strecke darsgestellt + // mit diesen "strecken" berechnet man Schnittpunkte. + // anschliessend wird geprueft, ob der berechnete Schnittpunkt ueberhaupt im kreis liegt + // falls ja --> Schnittpunkt vorhanden + + double x1a, y1a, z1a, x1b, y1b, z1b, // uebergebene Strecke + x2a, y2a, x2b, y2b, // erste "Kreisstrecke" + x3a, y3a, x3b, y3b, // zweite "Kreisstrecke" + y2m, /*z2m,*/ y3m, z3m; + double nenner1ab; + + if (this->isParallelToX1Axis()) { + x1a = point1.getX1Coordinate(); + y1a = point1.getX2Coordinate(); + z1a = point1.getX3Coordinate(); + x1b = point2.getX1Coordinate(); + y1b = point2.getX2Coordinate(); + z1b = point2.getX3Coordinate(); + + x2a = mLine->getPoint1()->getX1Coordinate(); + y2m = mLine->getPoint1()->getX2Coordinate(); + // z2m=mLine->getPoint1()->getX3Coordinate(); + y2a = y2m + mRad; + x2b = mLine->getPoint1()->getX1Coordinate(); + y2b = y2m - mRad; + + x3a = mLine->getPoint2()->getX1Coordinate(); // + y3m = mLine->getPoint2()->getX2Coordinate(); + z3m = mLine->getPoint2()->getX3Coordinate(); + y3a = y3m + mRad; + x3b = mLine->getPoint2()->getX1Coordinate(); + y3b = y3m - mRad; + } else if (this->isParallelToX2Axis()) { + x1a = point1.getX2Coordinate(); + y1a = point1.getX3Coordinate(); + z1a = point1.getX1Coordinate(); + x1b = point2.getX2Coordinate(); + y1b = point2.getX3Coordinate(); + z1b = point2.getX1Coordinate(); + + x2a = mLine->getPoint1()->getX2Coordinate(); + y2m = mLine->getPoint1()->getX3Coordinate(); + // z2m=mLine->getPoint1()->getX1Coordinate(); + y2a = y2m + mRad; + x2b = mLine->getPoint1()->getX2Coordinate(); + y2b = y2m - mRad; + + x3a = mLine->getPoint2()->getX2Coordinate(); // + y3m = mLine->getPoint2()->getX3Coordinate(); + z3m = mLine->getPoint2()->getX1Coordinate(); + y3a = y3m + mRad; + x3b = mLine->getPoint2()->getX2Coordinate(); + y3b = y3m - mRad; + } else if (this->isParallelToX3Axis()) { + x1a = point1.getX3Coordinate(); + y1a = point1.getX2Coordinate(); + z1a = point1.getX1Coordinate(); + x1b = point2.getX3Coordinate(); + y1b = point2.getX2Coordinate(); + z1b = point2.getX1Coordinate(); + + x2a = mLine->getPoint1()->getX3Coordinate(); + y2m = mLine->getPoint1()->getX2Coordinate(); + // z2m=mLine->getPoint1()->getX1Coordinate(); + y2a = y2m + mRad; + x2b = mLine->getPoint1()->getX3Coordinate(); + y2b = y2m - mRad; + + x3a = mLine->getPoint2()->getX3Coordinate(); // + y3m = mLine->getPoint2()->getX2Coordinate(); + z3m = mLine->getPoint2()->getX1Coordinate(); + y3a = y3m + mRad; + x3b = mLine->getPoint2()->getX3Coordinate(); + y3b = y3m - mRad; + } else + throw UbException(UB_EXARGS, "funktioniert derzeit nur mit achsenparallelen Zylindern"); + + nenner1ab = -y1a * x2a + y1a * x2b + y1b * x2a - y1b * x2b + x1a * y2a - x1a * y2b - x1b * y2a + x1b * y2b; + // double nenner2 = x1a*y2a-x1a*y2b-x1b*y2a+x1b*y2b-y1a*x2a+y1a*x2b+y1b*x2a-y1b*x2b; + if (fabs(nenner1ab) > 1.E-13) // andernfalls sind die beiden Strecken parallel + { + // tStrecke ist fuer gegebene Strecke! + double t1ab = (-y1a * x2a + y1a * x2b - 2.0 * y2a * x2b + x1a * y2a - x1a * y2b - x1b * y2b + 2.0 * y2b * x2a + + x1b * y2a - y1b * x2a + y1b * x2b) / + nenner1ab; + // double tStrecke = + // -(-x1a*y2a+x1a*y2b+2.0*y2a*x2b+y1a*x2a-2.0*x2a*y2b-y1a*x2b+y1b*x2a-y1b*x2b-x1b*y2a+x1b*y2b)/nenner2; wenn -1 + // <= t2 <= +1 -> SP mit strecke + if (UbMath::inClosedInterval(t1ab, -1.0, 1.0)) // Schnittpunkt innerhalb der Strecke + { + double x, y, z, abstand_ist; + if (this->isParallelToX1Axis()) { + x = x1a * (0.5 - 0.5 * t1ab) + x1b * (0.5 + 0.5 * t1ab); + y = y1a * (0.5 - 0.5 * t1ab) + y1b * (0.5 + 0.5 * t1ab); + z = z1a * (0.5 - 0.5 * t1ab) + z1b * (0.5 + 0.5 * t1ab); + abstand_ist = sqrt((y3m - y) * (y3m - y) + (z3m - z) * (z3m - z)); + } else if (this->isParallelToX2Axis()) { + y = x1a * (0.5 - 0.5 * t1ab) + x1b * (0.5 + 0.5 * t1ab); + z = y1a * (0.5 - 0.5 * t1ab) + y1b * (0.5 + 0.5 * t1ab); + x = z1a * (0.5 - 0.5 * t1ab) + z1b * (0.5 + 0.5 * t1ab); + abstand_ist = sqrt((y3m - z) * (y3m - z) + (z3m - x) * (z3m - x)); + } else if (this->isParallelToX3Axis()) { + z = x1a * (0.5 - 0.5 * t1ab) + x1b * (0.5 + 0.5 * t1ab); + y = y1a * (0.5 - 0.5 * t1ab) + y1b * (0.5 + 0.5 * t1ab); + x = z1a * (0.5 - 0.5 * t1ab) + z1b * (0.5 + 0.5 * t1ab); + abstand_ist = sqrt((y3m - y) * (y3m - y) + (z3m - x) * (z3m - x)); + } else + throw UbException(UB_EXARGS, "funktioniert derzeit nur mit achsenparallelen Zylindern"); + + // pruefen, ob Punkt Element von Kreisflaeche + // double abstand_ist=sqrt((y2m-y)*(y2m-y)+(z2m-z)*(z2m-z)); + if (UbMath::lessEqual(abstand_ist, mRad)) // Punkt ist Schnittpunkt + { + bool exists = false; + for (int pos = 0; pos < (int)schnittpunkte.size(); ++pos) { + if (fabs(schnittpunkte[pos]->getX1Coordinate() - x) < 1.E-13 && + fabs(schnittpunkte[pos]->getX2Coordinate() - y) < 1.E-13 && + fabs(schnittpunkte[pos]->getX3Coordinate() - z) < 1.E-13) + exists = true; + } + + if (!exists) + schnittpunkte.push_back(new GbPoint3D(x, y, z)); + } + } + } + + nenner1ab = -y1a * x3a + y1a * x3b + y1b * x3a - y1b * x3b + x1a * y3a - x1a * y3b - x1b * y3a + x1b * y3b; + + if (fabs(nenner1ab) > 1.E-13) // andernfalls sind die beiden Strecken parallel + { + // tStrecke ist fuer gegebene Strecke! + double t1ab = (-y1a * x3a + y1a * x3b - x1b * y3b - 2.0 * y3a * x3b - x1a * y3b + 2.0 * y3b * x3a + x1a * y3a + + x1b * y3a - y1b * x3a + y1b * x3b) / + nenner1ab; + + if (UbMath::inClosedInterval(t1ab, -1.0, 1.0)) // Schnittpunkt innerhalb der Strecke + { + double x, y, z, abstand_ist; + if (this->isParallelToX1Axis()) { + x = x1a * (0.5 - 0.5 * t1ab) + x1b * (0.5 + 0.5 * t1ab); + y = y1a * (0.5 - 0.5 * t1ab) + y1b * (0.5 + 0.5 * t1ab); + z = z1a * (0.5 - 0.5 * t1ab) + z1b * (0.5 + 0.5 * t1ab); + abstand_ist = sqrt((y3m - y) * (y3m - y) + (z3m - z) * (z3m - z)); + } else if (this->isParallelToX2Axis()) { + y = x1a * (0.5 - 0.5 * t1ab) + x1b * (0.5 + 0.5 * t1ab); + z = y1a * (0.5 - 0.5 * t1ab) + y1b * (0.5 + 0.5 * t1ab); + x = z1a * (0.5 - 0.5 * t1ab) + z1b * (0.5 + 0.5 * t1ab); + abstand_ist = sqrt((y3m - z) * (y3m - z) + (z3m - x) * (z3m - x)); + } else if (this->isParallelToX3Axis()) { + z = x1a * (0.5 - 0.5 * t1ab) + x1b * (0.5 + 0.5 * t1ab); + y = y1a * (0.5 - 0.5 * t1ab) + y1b * (0.5 + 0.5 * t1ab); + x = z1a * (0.5 - 0.5 * t1ab) + z1b * (0.5 + 0.5 * t1ab); + abstand_ist = sqrt((y3m - y) * (y3m - y) + (z3m - x) * (z3m - x)); + } else + throw UbException(UB_EXARGS, "cylinder must be parallel to one axis"); + + // pruefen, ob Punkt Element von Kreisflaeche + // double abstand_ist=sqrt((y2m-y)*(y2m-y)+(z2m-z)*(z2m-z)); + + if (UbMath::lessEqual(abstand_ist, mRad)) // Punkt ist Schnittpunkt + { + bool exists = false; + for (int pos = 0; pos < (int)schnittpunkte.size(); ++pos) { + if (fabs(schnittpunkte[pos]->getX1Coordinate() - x) < 1.E-13 && + fabs(schnittpunkte[pos]->getX2Coordinate() - y) < 1.E-13 && + fabs(schnittpunkte[pos]->getX3Coordinate() - z) < 1.E-13) + exists = true; + } + + if (!exists) + schnittpunkte.push_back(new GbPoint3D(x, y, z)); + } + } + } + + int nofSchnittpunkte = (int)schnittpunkte.size(); + if (nofSchnittpunkte == 0) + return NULL; + else if (nofSchnittpunkte > 2) + throw UbException(UB_EXARGS, "more than three intersection points - not possible"); + else if (nofSchnittpunkte == 2) + return new GbLine3D(schnittpunkte[0], schnittpunkte[1]); + else if (nofSchnittpunkte == 1) { + if (this->isPointInGbObject3D(&point1)) + return new GbLine3D(schnittpunkte[0], new GbPoint3D(point1)); + else if (this->isPointInGbObject3D(&point2)) + return new GbLine3D(schnittpunkte[0], new GbPoint3D(point2)); + else + return new GbLine3D( + schnittpunkte[0], + new GbPoint3D(*(schnittpunkte[0]))); // strecke beruehrt clippedLine reduziert sich auf einen Punkt!!! + } + + return NULL; +} +/*==========================================================*/ +vector<GbTriangle3D *> GbCylinder3D::getSurfaceTriangleSet() +{ + double x1ma, x1mb, x2m, x3m; + if (this->isParallelToX1Axis()) { + x1ma = this->getX1Minimum(); + x1mb = this->getX1Maximum(); + x2m = this->getX2Centroid(); + x3m = this->getX3Centroid(); + } else if (this->isParallelToX2Axis()) { + x1ma = this->getX2Minimum(); + x1mb = this->getX2Maximum(); + x2m = this->getX1Centroid(); + x3m = this->getX3Centroid(); + } else if (this->isParallelToX3Axis()) { + x1ma = this->getX3Minimum(); + x1mb = this->getX3Maximum(); + x2m = this->getX2Centroid(); + x3m = this->getX1Centroid(); + } else + throw UbException(UB_EXARGS, "cylinder not axis prallel"); + + vector<GbTriangle3D *> triangles; + + int segmentsCircle = 20; + double deltaPhi = UbMath::PI / (double)segmentsCircle; + + double phiX1a, phiX1b; + double x1a, x2a, x3a, x1b, x2b, x3b, x1c, x2c, x3c, x1d, x2d, x3d; + + double dXCylinder = fabs((x1mb - x1ma)) / (double)segmentsCircle; + int segmentsCylinder = (int)(fabs(x1mb - x1ma) / dXCylinder); + for (int segCyl = 0; segCyl < segmentsCylinder; segCyl++) { + x1a = x1d = x1ma + segCyl * dXCylinder; + x1b = x1c = x1a + dXCylinder; + + for (phiX1a = 2.0 * UbMath::PI; phiX1a > 0; phiX1a -= deltaPhi) { + phiX1b = phiX1a + deltaPhi; + + x2a = x2m + mRad * std::sin(phiX1a); + x3a = x3m + mRad * std::cos(phiX1a); + x2b = x2m + mRad * std::sin(phiX1b); + x3b = x3m + mRad * std::cos(phiX1b); + + if (this->isParallelToX1Axis()) { + triangles.push_back(new GbTriangle3D(new GbPoint3D(x1b, x2b, x3b), new GbPoint3D(x1b, x2a, x3a), + new GbPoint3D(x1a, x2a, x3a))); + triangles.push_back(new GbTriangle3D(new GbPoint3D(x1a, x2a, x3a), new GbPoint3D(x1a, x2b, x3b), + new GbPoint3D(x1b, x2b, x3b))); + } else if (this->isParallelToX2Axis()) { + triangles.push_back(new GbTriangle3D(new GbPoint3D(x2b, x1b, x3b), new GbPoint3D(x2a, x1b, x3a), + new GbPoint3D(x2a, x1a, x3a))); + triangles.push_back(new GbTriangle3D(new GbPoint3D(x2a, x1a, x3a), new GbPoint3D(x2b, x1a, x3b), + new GbPoint3D(x2b, x1b, x3b))); + } else if (this->isParallelToX3Axis()) { + triangles.push_back(new GbTriangle3D(new GbPoint3D(x3b, x2b, x1b), new GbPoint3D(x3a, x2a, x1b), + new GbPoint3D(x3a, x2a, x1a))); + triangles.push_back(new GbTriangle3D(new GbPoint3D(x3a, x2a, x1a), new GbPoint3D(x3b, x2b, x1a), + new GbPoint3D(x3b, x2b, x1b))); + } + } + } + + int segmentsSide = (int)(mRad / dXCylinder); + double radius0, radius1; + for (int segCyl = 0; segCyl < segmentsSide; segCyl++) { + radius0 = segCyl * dXCylinder; + radius1 = radius0 + dXCylinder; + if (segCyl == segmentsSide - 1) + radius1 = mRad; + + for (phiX1a = 2.0 * UbMath::PI; phiX1a > 0; phiX1a -= deltaPhi) { + phiX1b = phiX1a + deltaPhi; + + x2a = x2m + radius0 * std::sin(phiX1a); + x3a = x3m + radius0 * std::cos(phiX1a); + x2b = x2m + radius0 * std::sin(phiX1b); + x3b = x3m + radius0 * std::cos(phiX1b); + x2c = x2m + radius1 * std::sin(phiX1b); + x3c = x3m + radius1 * std::cos(phiX1b); + x2d = x2m + radius1 * std::sin(phiX1a); + x3d = x3m + radius1 * std::cos(phiX1a); + + if (this->isParallelToX1Axis()) { + triangles.push_back(new GbTriangle3D(new GbPoint3D(x1ma, x2a, x3a), new GbPoint3D(x1ma, x2b, x3b), + new GbPoint3D(x1ma, x2c, x3c))); + triangles.push_back(new GbTriangle3D(new GbPoint3D(x1ma, x2c, x3c), new GbPoint3D(x1ma, x2d, x3d), + new GbPoint3D(x1ma, x2a, x3a))); + triangles.push_back(new GbTriangle3D(new GbPoint3D(x1mb, x2c, x3c), new GbPoint3D(x1mb, x2b, x3b), + new GbPoint3D(x1mb, x2a, x3a))); + triangles.push_back(new GbTriangle3D(new GbPoint3D(x1mb, x2a, x3a), new GbPoint3D(x1mb, x2d, x3d), + new GbPoint3D(x1mb, x2c, x3c))); + } else if (this->isParallelToX2Axis()) { + triangles.push_back(new GbTriangle3D(new GbPoint3D(x2a, x1ma, x3a), new GbPoint3D(x2b, x1ma, x3b), + new GbPoint3D(x2c, x1ma, x3c))); + triangles.push_back(new GbTriangle3D(new GbPoint3D(x2c, x1ma, x3c), new GbPoint3D(x2d, x1ma, x3d), + new GbPoint3D(x2a, x1ma, x3a))); + triangles.push_back(new GbTriangle3D(new GbPoint3D(x2c, x1mb, x3c), new GbPoint3D(x2b, x1mb, x3b), + new GbPoint3D(x2a, x1mb, x3a))); + triangles.push_back(new GbTriangle3D(new GbPoint3D(x2a, x1mb, x3a), new GbPoint3D(x2d, x1mb, x3d), + new GbPoint3D(x2c, x1mb, x3c))); + } else if (this->isParallelToX3Axis()) { + triangles.push_back(new GbTriangle3D(new GbPoint3D(x3a, x2a, x1ma), new GbPoint3D(x3b, x2b, x1ma), + new GbPoint3D(x3c, x2c, x1ma))); + triangles.push_back(new GbTriangle3D(new GbPoint3D(x3c, x2c, x1ma), new GbPoint3D(x3d, x2d, x1ma), + new GbPoint3D(x3a, x2a, x1ma))); + triangles.push_back(new GbTriangle3D(new GbPoint3D(x3c, x2c, x1mb), new GbPoint3D(x3b, x2b, x1mb), + new GbPoint3D(x3a, x2a, x1mb))); + triangles.push_back(new GbTriangle3D(new GbPoint3D(x3a, x2a, x1mb), new GbPoint3D(x3d, x2d, x1mb), + new GbPoint3D(x3c, x2c, x1mb))); + } + } + } + + return triangles; +} +/*==========================================================*/ +void GbCylinder3D::addSurfaceTriangleSet(vector<UbTupleFloat3> &nodes, vector<UbTupleInt3> &triangles) +{ + float x1ma, x1mb, x2m, x3m; + if (this->isParallelToX1Axis()) { + x1ma = (float)this->getX1Minimum(); + x1mb = (float)this->getX1Maximum(); + x2m = (float)this->getX2Centroid(); + x3m = (float)this->getX3Centroid(); + } else if (this->isParallelToX2Axis()) { + x1ma = (float)this->getX2Minimum(); + x1mb = (float)this->getX2Maximum(); + x2m = (float)this->getX1Centroid(); + x3m = (float)this->getX3Centroid(); + } else if (this->isParallelToX3Axis()) { + x1ma = (float)this->getX3Minimum(); + x1mb = (float)this->getX3Maximum(); + x2m = (float)this->getX2Centroid(); + x3m = (float)this->getX1Centroid(); + } else + throw UbException(UB_EXARGS, "cylinder not axis prallel"); + + int segmentsCircle = 20; + double deltaPhi = UbMath::PI / (double)segmentsCircle; + + double phiX1a, phiX1b; + float x1a, x2a, x3a, x1b, x2b, x3b, x1c, x2c, x3c, x1d, x2d, x3d; + + double dXCylinder = fabs((x1mb - x1ma)) / (double)segmentsCircle; + int segmentsCylinder = (int)(fabs(x1mb - x1ma) / dXCylinder); + int nodenr = 0; + for (int segCyl = 0; segCyl < segmentsCylinder; segCyl++) { + x1a = x1d = (float)(x1ma + segCyl * dXCylinder); + x1b = x1c = (float)(x1a + dXCylinder); + + for (phiX1a = 2.0 * UbMath::PI; phiX1a > 0; phiX1a -= deltaPhi) { + phiX1b = phiX1a + deltaPhi; + + x2a = (float)(x2m + mRad * std::sin(phiX1a)); + x3a = (float)(x3m + mRad * std::cos(phiX1a)); + x2b = (float)(x2m + mRad * std::sin(phiX1b)); + x3b = (float)(x3m + mRad * std::cos(phiX1b)); + + if (this->isParallelToX1Axis()) { + nodes.push_back(makeUbTuple(x1b, x2b, x3b)); + nodes.push_back(makeUbTuple(x1b, x2a, x3a)); + nodes.push_back(makeUbTuple(x1a, x2a, x3a)); + nodes.push_back(makeUbTuple(x1a, x2a, x3a)); + nodes.push_back(makeUbTuple(x1a, x2b, x3b)); + nodes.push_back(makeUbTuple(x1b, x2b, x3b)); + } else if (this->isParallelToX2Axis()) { + nodes.push_back(makeUbTuple(x2b, x1b, x3b)); + nodes.push_back(makeUbTuple(x2a, x1b, x3a)); + nodes.push_back(makeUbTuple(x2a, x1a, x3a)); + nodes.push_back(makeUbTuple(x2a, x1a, x3a)); + nodes.push_back(makeUbTuple(x2b, x1a, x3b)); + nodes.push_back(makeUbTuple(x2b, x1b, x3b)); + } else if (this->isParallelToX3Axis()) { + nodes.push_back(makeUbTuple(x3b, x2b, x1b)); + nodes.push_back(makeUbTuple(x3a, x2a, x1b)); + nodes.push_back(makeUbTuple(x3a, x2a, x1a)); + nodes.push_back(makeUbTuple(x3a, x2a, x1a)); + nodes.push_back(makeUbTuple(x3b, x2b, x1a)); + nodes.push_back(makeUbTuple(x3b, x2b, x1b)); + } + triangles.push_back(makeUbTuple(nodenr, nodenr + 1, nodenr + 2)); + nodenr += 3; + triangles.push_back(makeUbTuple(nodenr, nodenr + 1, nodenr + 2)); + nodenr += 3; + } + } + + int segmentsSide = (int)(mRad / dXCylinder); + double radius0, radius1; + for (int segCyl = 0; segCyl < segmentsSide; segCyl++) { + radius0 = segCyl * dXCylinder; + radius1 = radius0 + dXCylinder; + if (segCyl == segmentsSide - 1) + radius1 = mRad; + + for (phiX1a = 2.0 * UbMath::PI; phiX1a > 0; phiX1a -= deltaPhi) { + phiX1b = phiX1a + deltaPhi; + + x2a = x2m + (float)(radius0 * std::sin(phiX1a)); + x3a = x3m + (float)(radius0 * std::cos(phiX1a)); + x2b = x2m + (float)(radius0 * std::sin(phiX1b)); + x3b = x3m + (float)(radius0 * std::cos(phiX1b)); + x2c = x2m + (float)(radius1 * std::sin(phiX1b)); + x3c = x3m + (float)(radius1 * std::cos(phiX1b)); + x2d = x2m + (float)(radius1 * std::sin(phiX1a)); + x3d = x3m + (float)(radius1 * std::cos(phiX1a)); + + if (this->isParallelToX1Axis()) { + nodes.push_back(makeUbTuple(x1ma, x2a, x3a)); + nodes.push_back(makeUbTuple(x1ma, x2b, x3b)); + nodes.push_back(makeUbTuple(x1ma, x2c, x3c)); + nodes.push_back(makeUbTuple(x1ma, x2c, x3c)); + nodes.push_back(makeUbTuple(x1ma, x2d, x3d)); + nodes.push_back(makeUbTuple(x1ma, x2a, x3a)); + nodes.push_back(makeUbTuple(x1mb, x2c, x3c)); + nodes.push_back(makeUbTuple(x1mb, x2b, x3b)); + nodes.push_back(makeUbTuple(x1mb, x2a, x3a)); + nodes.push_back(makeUbTuple(x1mb, x2a, x3a)); + nodes.push_back(makeUbTuple(x1mb, x2d, x3d)); + nodes.push_back(makeUbTuple(x1mb, x2c, x3c)); + } else if (this->isParallelToX2Axis()) { + nodes.push_back(makeUbTuple(x2a, x1ma, x3a)); + nodes.push_back(makeUbTuple(x2b, x1ma, x3b)); + nodes.push_back(makeUbTuple(x2c, x1ma, x3c)); + nodes.push_back(makeUbTuple(x2c, x1ma, x3c)); + nodes.push_back(makeUbTuple(x2d, x1ma, x3d)); + nodes.push_back(makeUbTuple(x2a, x1ma, x3a)); + nodes.push_back(makeUbTuple(x2c, x1mb, x3c)); + nodes.push_back(makeUbTuple(x2b, x1mb, x3b)); + nodes.push_back(makeUbTuple(x2a, x1mb, x3a)); + nodes.push_back(makeUbTuple(x2a, x1mb, x3a)); + nodes.push_back(makeUbTuple(x2d, x1mb, x3d)); + nodes.push_back(makeUbTuple(x2c, x1mb, x3c)); + } else if (this->isParallelToX3Axis()) { + nodes.push_back(makeUbTuple(x3a, x2a, x1ma)); + nodes.push_back(makeUbTuple(x3b, x2b, x1ma)); + nodes.push_back(makeUbTuple(x3c, x2c, x1ma)); + nodes.push_back(makeUbTuple(x3c, x2c, x1ma)); + nodes.push_back(makeUbTuple(x3d, x2d, x1ma)); + nodes.push_back(makeUbTuple(x3a, x2a, x1ma)); + nodes.push_back(makeUbTuple(x3c, x2c, x1mb)); + nodes.push_back(makeUbTuple(x3b, x2b, x1mb)); + nodes.push_back(makeUbTuple(x3a, x2a, x1mb)); + nodes.push_back(makeUbTuple(x3a, x2a, x1mb)); + nodes.push_back(makeUbTuple(x3d, x2d, x1mb)); + nodes.push_back(makeUbTuple(x3c, x2c, x1mb)); + } + + triangles.push_back(makeUbTuple(nodenr, nodenr + 1, nodenr + 2)); + nodenr += 3; + triangles.push_back(makeUbTuple(nodenr, nodenr + 1, nodenr + 2)); + nodenr += 3; + triangles.push_back(makeUbTuple(nodenr, nodenr + 1, nodenr + 2)); + nodenr += 3; + triangles.push_back(makeUbTuple(nodenr, nodenr + 1, nodenr + 2)); + nodenr += 3; + } + } +} +/*==========================================================*/ +void GbCylinder3D::addSurfaceTriangleSetSegments(vector<UbTupleFloat3> &nodes, vector<UbTupleInt3> &triangles, + int segmentsRound, int segmentsHeight) +{ + float x1ma, x1mb, x2m, x3m; + if (this->isParallelToX1Axis()) { + x1ma = (float)this->getX1Minimum(); + x1mb = (float)this->getX1Maximum(); + x2m = (float)this->getX2Centroid(); + x3m = (float)this->getX3Centroid(); + } else if (this->isParallelToX2Axis()) { + x1ma = (float)this->getX2Minimum(); + x1mb = (float)this->getX2Maximum(); + x2m = (float)this->getX1Centroid(); + x3m = (float)this->getX3Centroid(); + } else if (this->isParallelToX3Axis()) { + x1ma = (float)this->getX3Minimum(); + x1mb = (float)this->getX3Maximum(); + x2m = (float)this->getX2Centroid(); + x3m = (float)this->getX1Centroid(); + } else + throw UbException(UB_EXARGS, "cylinder not axis prallel"); + + int segmentsCircle = segmentsRound; + double deltaPhi = UbMath::PI / (double)segmentsCircle; + + double phiX1a, phiX1b; + float x1a, x2a, x3a, x1b, x2b, x3b, x1c, x2c, x3c, x1d, x2d, x3d; + + double dXCylinder = fabs((x1mb - x1ma)) / (double)segmentsHeight; // hier evtl. segmentsheight + int segmentsCylinder = (int)(fabs(x1mb - x1ma) / dXCylinder); + int nodenr = 0; + for (int segCyl = 0; segCyl < segmentsCylinder; segCyl++) { + x1a = x1d = (float)(x1ma + segCyl * dXCylinder); + x1b = x1c = (float)(x1a + dXCylinder); + + // for(phiX1a=2.0*UbMath::PI; phiX1a>0.0; phiX1a-=deltaPhi) + for (phiX1a = 0.0; phiX1a < 2.0 * UbMath::PI - 0.5 * deltaPhi; phiX1a += deltaPhi) { + phiX1b = phiX1a + deltaPhi; + + x2a = (float)(x2m + mRad * std::sin(phiX1a)); + x3a = (float)(x3m + mRad * std::cos(phiX1a)); + x2b = (float)(x2m + mRad * std::sin(phiX1b)); + x3b = (float)(x3m + mRad * std::cos(phiX1b)); + + if (this->isParallelToX1Axis()) { + nodes.push_back(makeUbTuple(x1b, x2b, x3b)); + nodes.push_back(makeUbTuple(x1b, x2a, x3a)); + nodes.push_back(makeUbTuple(x1a, x2a, x3a)); + nodes.push_back(makeUbTuple(x1a, x2a, x3a)); + nodes.push_back(makeUbTuple(x1a, x2b, x3b)); + nodes.push_back(makeUbTuple(x1b, x2b, x3b)); + } else if (this->isParallelToX2Axis()) { + nodes.push_back(makeUbTuple(x2b, x1b, x3b)); + nodes.push_back(makeUbTuple(x2a, x1b, x3a)); + nodes.push_back(makeUbTuple(x2a, x1a, x3a)); + nodes.push_back(makeUbTuple(x2a, x1a, x3a)); + nodes.push_back(makeUbTuple(x2b, x1a, x3b)); + nodes.push_back(makeUbTuple(x2b, x1b, x3b)); + } else if (this->isParallelToX3Axis()) { + nodes.push_back(makeUbTuple(x3b, x2b, x1b)); + nodes.push_back(makeUbTuple(x3a, x2a, x1b)); + nodes.push_back(makeUbTuple(x3a, x2a, x1a)); + nodes.push_back(makeUbTuple(x3a, x2a, x1a)); + nodes.push_back(makeUbTuple(x3b, x2b, x1a)); + nodes.push_back(makeUbTuple(x3b, x2b, x1b)); + } + triangles.push_back(makeUbTuple(nodenr, nodenr + 1, nodenr + 2)); + nodenr += 3; + triangles.push_back(makeUbTuple(nodenr, nodenr + 1, nodenr + 2)); + nodenr += 3; + } + } + + int segmentsSide = (int)(mRad / dXCylinder); + double radius0, radius1; + for (int segCyl = 0; segCyl < segmentsSide; segCyl++) { + radius0 = segCyl * dXCylinder; + radius1 = radius0 + dXCylinder; + if (segCyl == segmentsSide - 1) + radius1 = mRad; + + // for(phiX1a=2.0*UbMath::PI; phiX1a>0.0; phiX1a-=deltaPhi) + for (phiX1a = 0.0; phiX1a < 2.0 * UbMath::PI - 0.5 * deltaPhi; phiX1a += deltaPhi) { + phiX1b = phiX1a + deltaPhi; + + x2a = x2m + (float)(radius0 * std::sin(phiX1a)); + x3a = x3m + (float)(radius0 * std::cos(phiX1a)); + x2b = x2m + (float)(radius0 * std::sin(phiX1b)); + x3b = x3m + (float)(radius0 * std::cos(phiX1b)); + x2c = x2m + (float)(radius1 * std::sin(phiX1b)); + x3c = x3m + (float)(radius1 * std::cos(phiX1b)); + x2d = x2m + (float)(radius1 * std::sin(phiX1a)); + x3d = x3m + (float)(radius1 * std::cos(phiX1a)); + + if (this->isParallelToX1Axis()) { + nodes.push_back(makeUbTuple(x1ma, x2a, x3a)); + nodes.push_back(makeUbTuple(x1ma, x2b, x3b)); + nodes.push_back(makeUbTuple(x1ma, x2c, x3c)); + nodes.push_back(makeUbTuple(x1ma, x2c, x3c)); + nodes.push_back(makeUbTuple(x1ma, x2d, x3d)); + nodes.push_back(makeUbTuple(x1ma, x2a, x3a)); + nodes.push_back(makeUbTuple(x1mb, x2c, x3c)); + nodes.push_back(makeUbTuple(x1mb, x2b, x3b)); + nodes.push_back(makeUbTuple(x1mb, x2a, x3a)); + nodes.push_back(makeUbTuple(x1mb, x2a, x3a)); + nodes.push_back(makeUbTuple(x1mb, x2d, x3d)); + nodes.push_back(makeUbTuple(x1mb, x2c, x3c)); + } else if (this->isParallelToX2Axis()) { + nodes.push_back(makeUbTuple(x2a, x1ma, x3a)); + nodes.push_back(makeUbTuple(x2b, x1ma, x3b)); + nodes.push_back(makeUbTuple(x2c, x1ma, x3c)); + nodes.push_back(makeUbTuple(x2c, x1ma, x3c)); + nodes.push_back(makeUbTuple(x2d, x1ma, x3d)); + nodes.push_back(makeUbTuple(x2a, x1ma, x3a)); + nodes.push_back(makeUbTuple(x2c, x1mb, x3c)); + nodes.push_back(makeUbTuple(x2b, x1mb, x3b)); + nodes.push_back(makeUbTuple(x2a, x1mb, x3a)); + nodes.push_back(makeUbTuple(x2a, x1mb, x3a)); + nodes.push_back(makeUbTuple(x2d, x1mb, x3d)); + nodes.push_back(makeUbTuple(x2c, x1mb, x3c)); + } else if (this->isParallelToX3Axis()) { + nodes.push_back(makeUbTuple(x3a, x2a, x1ma)); + nodes.push_back(makeUbTuple(x3b, x2b, x1ma)); + nodes.push_back(makeUbTuple(x3c, x2c, x1ma)); + nodes.push_back(makeUbTuple(x3c, x2c, x1ma)); + nodes.push_back(makeUbTuple(x3d, x2d, x1ma)); + nodes.push_back(makeUbTuple(x3a, x2a, x1ma)); + nodes.push_back(makeUbTuple(x3c, x2c, x1mb)); + nodes.push_back(makeUbTuple(x3b, x2b, x1mb)); + nodes.push_back(makeUbTuple(x3a, x2a, x1mb)); + nodes.push_back(makeUbTuple(x3a, x2a, x1mb)); + nodes.push_back(makeUbTuple(x3d, x2d, x1mb)); + nodes.push_back(makeUbTuple(x3c, x2c, x1mb)); + } + + triangles.push_back(makeUbTuple(nodenr, nodenr + 1, nodenr + 2)); + nodenr += 3; + triangles.push_back(makeUbTuple(nodenr, nodenr + 1, nodenr + 2)); + nodenr += 3; + triangles.push_back(makeUbTuple(nodenr, nodenr + 1, nodenr + 2)); + nodenr += 3; + triangles.push_back(makeUbTuple(nodenr, nodenr + 1, nodenr + 2)); + nodenr += 3; + } + } +} + +/*==========================================================*/ +void GbCylinder3D::objectChanged(UbObservable *changedObject) +{ + GbLine3D *line = dynamic_cast<GbLine3D *>(changedObject); + if (!line || this->mLine != line) + return; + + this->notifyObserversObjectChanged(); +} +/*==========================================================*/ +void GbCylinder3D::objectWillBeDeleted(UbObservable *objectForDeletion) +{ + if (this->mLine) { + UbObservable *observedObj = dynamic_cast<UbObservable *>(this->mLine); + if (objectForDeletion == observedObj) { + this->mLine = NULL; + } + } +} +/*=======================================================*/ +void GbCylinder3D::scale(const double &sx1, const double &sx2, const double &sx3) +{ + if (this->isParallelToX1Axis()) { + if (!UbMath::equal(sx2, sx3)) + throw UbException(UB_EXARGS, "|| to x1 -> different scaling sx2 and sx3 not possible"); + this->mRad *= sx2; + } else if (this->isParallelToX2Axis()) { + if (!UbMath::equal(sx1, sx3)) + throw UbException(UB_EXARGS, "|| to x2 -> different scaling sx1 and sx3 not possible"); + this->mRad *= sx1; + } else if (this->isParallelToX3Axis()) { + if (!UbMath::equal(sx1, sx2)) + throw UbException(UB_EXARGS, "|| to x3 -> different scaling sx1 and sx2 not possible"); + this->mRad *= sx1; + } else + throw UbException(UB_EXARGS, "unknown direction"); + + this->mLine->scale(sx1, sx2, sx3); + // notify observer wird automatisch aufgerufen +} + +/*==========================================================*/ +double GbCylinder3D::getIntersectionRaytraceFactor(const double &x1, const double &x2, const double &x3, + const double &rx1, const double &rx2, const double &rx3) +{ + /* + Distance D of the intersection between a Ray((ox1,ox2,ox3),(dx1,dx2,dx3)) and a Plane P: ax+by+cz+d=0 + dc = a*dx1 + b*dx2 + c*dx3 + dw = a*ox1 + b*ox2 + c*ox3 + d + D = - dw / dc + */ + double px1, px2, px3; + double d = Ub::inf; // Distance to Min or Max Plane of the Zylinder + // final distance should be less that d + + if (this->isParallelToX1Axis()) { + if (UbMath::equal(x1, minX1) && UbMath::negative(rx1)) + return -1.0; + else if (UbMath::equal(x1, maxX1) && UbMath::positive(rx1)) + return -1.0; + + // falls die Linie nicht parallel zu den Seitenflaechen ist + if (x1 < minX1 || x1 > maxX1) // nur fuer punkte links und rechts des cylinders + { + px1 = (x1 < minX1 ? minX1 : maxX1); + // falls die Linie nicht parallel zu den Seitenflaechen ist + if (!UbMath::zero(rx1)) { + // Plane a= 0, b= 1, c=0 d= -1*px2 + d = -1.0 * (x1 - px1) / rx1; + px2 = x2 + d * rx2; + px3 = x3 + d * rx3; + + if (UbMath::greater(mLine->getDistance(px1, px2, px3), mRad)) { + if (x1 < minX1 && rx1 > 0.0) + d = Ub::inf; // punkt liegt "links" vom cylinder und strahl hat evtl weiteren SP auf oberflaeche + else if (x1 > maxX1 && rx1 < 0.0) + d = Ub::inf; + else + return -1.0; + } else + return d; + } else + return -1.0; + } else { + if (UbMath::negative(rx1)) + d = -1.0 * (x1 - minX1) / rx1; + else if (UbMath::positive(rx1)) + d = -1.0 * (x1 - maxX1) / rx1; + } + } else if (this->isParallelToX2Axis()) { + if (UbMath::equal(x2, minX2) && UbMath::negative(rx2)) + return -1; + else if (UbMath::equal(x2, maxX2) && UbMath::positive(rx2)) + return -1; + + if (minX2 > x2 || x2 > maxX2) { + px2 = (x2 < minX2 ? minX2 : maxX2); + // falls die Linie nicht parallel zu den Seitenflaechen ist + if (!UbMath::zero(rx2)) { + // Plane a= 0, b= 1, c=0 d= -1*px2 + d = -1 * (x2 - px2) / rx2; + px1 = x1 + d * rx1; + px3 = x3 + d * rx3; + + if (UbMath::greater(mLine->getDistance(px1, px2, px3), mRad)) { + if (x2 < minX2 && rx2 > 0.0) + d = Ub::inf; // punkt liegt "links oberhalb" vom cylinder und strahl mit pos x1 hat evtl + // weiteren SP auf oberflaeche + else if (x2 > maxX2 && rx2 < 0.0) + d = Ub::inf; + else + return -1.0; + } else + return d; + } else + return -1.0; + } else { + if (UbMath::negative(rx2)) + d = -1.0 * (x2 - minX2) / rx2; + else if (UbMath::positive(rx2)) + d = -1.0 * (x2 - maxX2) / rx2; + } + } else if (this->isParallelToX3Axis()) { + if (UbMath::equal(x3, minX3) && UbMath::negative(rx3)) + return -1.0; + else if (UbMath::equal(x3, maxX3) && UbMath::positive(rx3)) + return -1.0; + + if (minX3 > x3 || x3 > maxX3) { + px3 = (x3 < minX3 ? minX3 : maxX3); + // falls die Linie nicht parallel zu den Seitenflaechen ist + if (!UbMath::zero(rx3)) { + // Plane a= 0, b= 0, c=1 d= -1*px3 + d = -1.0 * (x3 - px3) / rx3; + px2 = x2 + d * rx2; + px1 = x1 + d * rx1; + if (UbMath::greater(mLine->getDistance(px1, px2, px3), mRad)) { + if (x3 < minX3 && rx3 > 0.0) + d = Ub::inf; + else if (x3 > maxX3 && rx3 < 0.0) + d = Ub::inf; + else + return -1.0; + } else + return d; + } else + return -1.0; + } else { + if (UbMath::negative(rx3)) + d = -1.0 * (x3 - minX3) / rx3; + else if (UbMath::positive(rx3)) + d = -1.0 * (x3 - maxX3) / rx3; + } + } else + throw UbException(UB_EXARGS, "funzt nur bei achsen parallelem cylinder"); + ////////////////////////////////////////////////////////////////////////// + // Q berechnen fuer Infinity Zylinder + double axisX1 = mLine->getPoint2()->x1 - mLine->getPoint1()->x1; /* Axis of the cylinder */ + double axisX2 = mLine->getPoint2()->x2 - mLine->getPoint1()->x2; /* mit p1 als base of cylinder */ + double axisX3 = mLine->getPoint2()->x3 - mLine->getPoint1()->x3; + + // double dirlen = mLine->getLength(); + // double abs, t, s; + + double RCx1 = x1 - mLine->getPoint1()->x1; + double RCx2 = x2 - mLine->getPoint1()->x2; + double RCx3 = x3 - mLine->getPoint1()->x3; + + // n = ray x axis + double nx1 = rx2 * axisX3 - rx3 * axisX2; + double nx2 = rx3 * axisX1 - rx1 * axisX3; + double nx3 = rx1 * axisX2 - rx2 * axisX1; + double nLength = nx1 * nx1 + nx2 * nx2 + nx3 * nx3; + + double abs; + if (UbMath::zero(nLength)) { /* ray parallel to cyl */ + // abs = RC dot axis + double tmpabs = RCx1 * axisX1 + RCx2 * axisX2 + RCx3 * axisX3; + double dx1 = RCx1 - tmpabs * axisX1; + double dx2 = RCx2 - tmpabs * axisX2; + double dx3 = RCx3 - tmpabs * axisX3; + if (UbMath::greater(dx1 * dx1 + dx2 * dx2 + dx3 * dx3, mRad * mRad)) + return -1.0; + } + + // normalize "n" + nLength = std::sqrt(nLength); + double invnLength = 1.0 / nLength; + nx1 *= invnLength; + nx2 *= invnLength; + nx3 *= invnLength; + + // shortest distance = fabs( RC dot n ) + abs = std::fabs(RCx1 * nx1 + RCx2 * nx2 + RCx3 * nx3); + + if (UbMath::lessEqual(abs, mRad)) { /* if ray hits cylinder */ + // Ox1 = RC x axis + double Ox1 = RCx2 * axisX3 - RCx3 * axisX2; + double Ox2 = RCx3 * axisX1 - RCx1 * axisX3; + double Ox3 = RCx1 * axisX2 - RCx2 * axisX1; + // t = - O dot n / nLength; + double t = -(Ox1 * nx1 + Ox2 * nx2 + Ox3 * nx3) / nLength; + + // O = n x axis; + Ox1 = nx2 * axisX3 - nx3 * axisX2; + Ox2 = nx3 * axisX1 - nx1 * axisX3; + Ox3 = nx1 * axisX2 - nx2 * axisX1; + + // normalize O + invnLength = 1.0 / std::sqrt(Ox1 * Ox1 + Ox2 * Ox2 + Ox3 * Ox3); + Ox1 *= invnLength; + Ox2 *= invnLength; + Ox3 *= invnLength; + + double s = std::fabs(sqrt(mRad * mRad - abs * abs) / (rx1 * Ox1 + rx2 * Ox2 + rx3 * Ox3)); + + // Wert a) t-s: entering distance + // b) t+s: exiting distance + // + // -> we only consider factors in ray-dir -> means positive values! + // (s is always positive) + + if (t > s) { + return UbMath::min(t - s, d); + } else if ((t + s) > 0) { + return UbMath::min(t + s, d); + } + } + + return -1.0; +} +/*==========================================================*/ diff --git a/src/basics/geometry3d/GbCylinder3D.h b/src/basics/geometry3d/GbCylinder3D.h new file mode 100644 index 0000000000000000000000000000000000000000..5bb25a8650379540679fba693a396bc1a50434b5 --- /dev/null +++ b/src/basics/geometry3d/GbCylinder3D.h @@ -0,0 +1,156 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file GbCylinder3D.h +//! \ingroup geometry3D +//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller +//======================================================================================= +#ifndef GBCYLINDER3D_H +#define GBCYLINDER3D_H + +#include <cmath> +#include <vector> + +#include <basics/utilities/UbObserver.h> +#include <geometry3d/GbLine3D.h> +#include <geometry3d/GbObject3D.h> + +class GbPoint3D; +class GbLine3D; +class GbTriangle3D; + +class GbObject3DCreator; + +#include <PointerDefinitions.h> +class GbCylinder3D; +using GbCylinder3DPtr = SPtr<GbCylinder3D>; + +class GbCylinder3D : public GbObject3D, public UbObserver +{ +public: + GbCylinder3D(); + GbCylinder3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b, const double &x2b, + const double &x3b, const double &radius); + GbCylinder3D(GbPoint3D *p1, GbPoint3D *p2, const double &radius); + GbCylinder3D(GbLine3D *line, const double &rad); + GbCylinder3D(GbCylinder3D *cylinder); + ~GbCylinder3D() override; + + GbCylinder3D *clone() override { return new GbCylinder3D(this); } + void finalize() override; + + double getRadius() { return this->mRad; }; + GbLine3D *getLine() { return mLine; } + GbPoint3D *getPoint1(); + GbPoint3D *getPoint2(); + + void setRadius(const double &radius); + void setLine(GbLine3D *line); + void setPoint1(const double &x1, const double &x2, const double &x3); + void setPoint2(const double &x1, const double &x2, const double &x3); + + bool isParallelToX1Axis() { return ((this->cylinderType & X1PARALLEL) == X1PARALLEL); } + bool isParallelToX2Axis() { return ((this->cylinderType & X2PARALLEL) == X2PARALLEL); } + bool isParallelToX3Axis() { return ((this->cylinderType & X3PARALLEL) == X3PARALLEL); } + bool isNotParallelToAxis() { return ((this->cylinderType & NOTPARALLELTOAXIS) == NOTPARALLELTOAXIS); } + + double getHeight(); + + void scale(const double &sx1, const double &sx2, const double &sx3) override; + + void translate(const double &x1, const double &x2, const double &x3) override + { + this->mLine->translate(x1, x2, x3); + this->calculateValues(); + // this->notifyObserversObjectChanged(); + } + + double getX1Centroid() override { return centerX1; } + double getX1Minimum() override { return minX1; } + double getX1Maximum() override { return maxX1; } + double getX2Centroid() override { return centerX2; } + double getX2Minimum() override { return minX2; } + double getX2Maximum() override { return maxX2; } + double getX3Centroid() override { return centerX3; } + double getX3Minimum() override { return minX3; } + double getX3Maximum() override { return maxX3; } + + bool isPointInGbObject3D(const double &x1p, const double &x2p, const double &x3p) override; + bool isPointInGbObject3D(const double &x1p, const double &x2p, const double &x3p, bool &pointIsOnBoundary) override; + bool isCellInsideGbObject3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b, + const double &x2b, const double &x3b) override; + bool isCellCuttingGbObject3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b, + const double &x2b, const double &x3b) override; + bool isCellInsideOrCuttingGbObject3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b, + const double &x2b, const double &x3b) override; + + GbLine3D *createClippedLine3D(GbPoint3D &point1, GbPoint3D &point2) override; + + // SG ausdokumentieren, da der nur unendlcihe Zylinder macht ... + // bool hasRaytracing() { return true; } + bool hasRaytracing() override { return false; } + bool raytracingSupportsPointsInside() override { return true; } + + /*|r| must be 1! einheitsvector!!*/ + double getIntersectionRaytraceFactor(const double &x1, const double &x2, const double &x3, const double &rx1, + const double &rx2, const double &rx3) override; + + std::vector<GbTriangle3D *> getSurfaceTriangleSet() override; + void addSurfaceTriangleSet(std::vector<UbTupleFloat3> &nodes, std::vector<UbTupleInt3> &triangles) override; + void addSurfaceTriangleSetSegments(std::vector<UbTupleFloat3> &nodes, std::vector<UbTupleInt3> &triangles, + int segmentsRound, int segmentsHeight); + + std::string toString() override; + + // virtuelle Methoden von UbObserver + void objectChanged(UbObservable *changedObject) override; + void objectWillBeDeleted(UbObservable *objectForDeletion) override; + + using GbObject3D::isPointInGbObject3D; // Grund: dadurch muss man hier isPointInGbObject3D(GbPoint3D*) nicht + // ausprogrammieren, welche sonst hier "ueberdeckt" waere + +protected: + void calculateValues(); + + GbLine3D *mLine; + double mRad; + + double minX1{ 0.0 }, minX2{ 0.0 }, minX3{ 0.0 }; + double maxX1{ 0.0 }, maxX2{ 0.0 }, maxX3{ 0.0 }; + double centerX1{ 0.0 }, centerX2{ 0.0 }, centerX3{ 0.0 }; + + int cylinderType; + + // void berechneQuerschnittsWerte(); + static const int NOTPARALLELTOAXIS = (1 << 0); // 1 + static const int X1PARALLEL = (1 << 1); // 2 + static const int X2PARALLEL = (1 << 2); // 4 + static const int X3PARALLEL = (1 << 3); // 8 +}; + +#endif diff --git a/src/basics/geometry3d/GbHalfSpace3D.cpp b/src/basics/geometry3d/GbHalfSpace3D.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9e72e281e0bc456d32e46780d66de787547b3806 --- /dev/null +++ b/src/basics/geometry3d/GbHalfSpace3D.cpp @@ -0,0 +1,131 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file GbHalfSpace3D.cpp +//! \ingroup geometry3D +//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller +//======================================================================================= +#include <geometry3d/GbHalfSpace3D.h> + +using namespace std; + +/*==========================================================*/ +GbHalfSpace3D::GbHalfSpace3D(GbTriangle3D *triangle) +{ + GbPoint3D *PointA = triangle->getPoint1(); + GbPoint3D *PointB = triangle->getPoint2(); + GbPoint3D *PointC = triangle->getPoint3(); + + GbVector3D A(PointA->x1, PointA->x2, PointA->x3); + GbVector3D BA(PointB->x1 - PointA->x1, PointB->x2 - PointA->x2, PointB->x3 - PointA->x3); + GbVector3D CA(PointC->x1 - PointA->x1, PointC->x2 - PointA->x2, PointC->x3 - PointA->x3); + GbVector3D BACA = BA.Cross(CA); + // this->Normal = PointB->subtract(PointA)->cross(PointC->subtract(PointA))->normalize(); + BACA.Normalize(); + // this->Normal = BACA; + normalX = BACA[0]; + normalY = BACA[1]; + normalZ = BACA[2]; + // this->d = this->Normal.Dot(A); + this->d = normalX * A[0] + normalY * A[1] + normalZ * A[2]; +} +/*==========================================================*/ +GbHalfSpace3D::GbHalfSpace3D(GbPoint3D *PointA, GbPoint3D *PointB, GbPoint3D *PointC) +{ + GbVector3D A(PointA->x1, PointA->x2, PointA->x3); + GbVector3D BA(PointB->x1 - PointA->x1, PointB->x2 - PointA->x2, PointB->x3 - PointA->x3); + GbVector3D CA(PointC->x1 - PointA->x1, PointC->x2 - PointA->x2, PointC->x3 - PointA->x3); + GbVector3D BACA = BA.Cross(CA); + // this->Normal = PointB->subtract(PointA)->cross(PointC->subtract(PointA))->normalize(); + BACA.Normalize(); + // this->Normal = BACA; + normalX = BACA[0]; + normalY = BACA[1]; + normalZ = BACA[2]; + // this->d = this->Normal.Dot(A); + this->d = normalX * A[0] + normalY * A[1] + normalZ * A[2]; +} +/*==========================================================*/ +GbHalfSpace3D::GbHalfSpace3D(GbPoint3D *PointA, GbPoint3D *PointB) +{ + GbVector3D A(PointA->x1, PointA->x2, PointA->x3); + GbVector3D B(PointB->x1, PointB->x2, PointB->x3); + GbVector3D K(0.0, 0.0, 0.99); // the vector from PointA - third point + + GbVector3D PointBA = B - A; + GbVector3D PointBAK = PointBA.Cross(K); + PointBAK.Normalize(); + + // this->Normal = PointBAK; + normalX = PointBAK[0]; + normalY = PointBAK[1]; + normalZ = PointBAK[2]; + + // this->d = this->Normal.Dot(A); + this->d = normalX * PointA->x1 + normalY * PointA->x2 + normalZ * PointA->x3; +} +/*==========================================================*/ +GbHalfSpace3D::GbHalfSpace3D(const double &p1x, const double &p1y, const double &p1z, const double &p2x, + const double &p2y, const double &p2z, const double &p3x, const double &p3y, + const double &p3z) +{ + double p2minusP1x = p2x - p1x; + double p2minusP1y = p2y - p1y; + double p2minusP1z = p2z - p1z; + + double P3minusP1x = p3x - p1x; + double P3minusP1y = p3y - p1y; + double P3minusP1z = p3z - p1z; + + // normal = BA x CA + normalX = p2minusP1y * P3minusP1z - p2minusP1z * P3minusP1y; + normalY = p2minusP1z * P3minusP1x - p2minusP1x * P3minusP1z; + normalZ = p2minusP1x * P3minusP1y - p2minusP1y * P3minusP1x; + + // normalize BACA + double oneOverNormalLength = 1.0 / (std::sqrt(normalX * normalX + normalY * normalY + normalZ * normalZ)); + normalX *= oneOverNormalLength; + normalY *= oneOverNormalLength; + normalZ *= oneOverNormalLength; + + // d = normal * p1 + this->d = normalX * p1x + normalY * p1y + normalZ * p1z; +} +/*==========================================================*/ +GbHalfSpace3D::GbHalfSpace3D(const double &p1x, const double &p1y, const double &p1z, const double &nx, + const double &ny, const double &nz) +{ + // normal = BA x CA + normalX = nx; + normalY = ny; + normalZ = nz; + + // d = normal * p1 + this->d = nx * p1x + ny * p1y + nz * p1z; +} +/*==========================================================*/ diff --git a/src/basics/geometry3d/GbHalfSpace3D.h b/src/basics/geometry3d/GbHalfSpace3D.h new file mode 100644 index 0000000000000000000000000000000000000000..b4ac549fbf21d136c3916980d6336fa92b0b4f44 --- /dev/null +++ b/src/basics/geometry3d/GbHalfSpace3D.h @@ -0,0 +1,108 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file GbHalfSpace3D.h +//! \ingroup geometry3D +//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller +//======================================================================================= +#ifndef GBHALFSPACE3D_H +#define GBHALFSPACE3D_H + +#include <iostream> +#include <sstream> + +#include <basics/utilities/UbMath.h> + +#include <geometry3d/GbPoint3D.h> +#include <geometry3d/GbTriangle3D.h> +#include <geometry3d/GbVector3D.h> + +#include <PointerDefinitions.h> + +/*=========================================================================*/ +/* GbHalfSpace3D */ +/* */ +/** + * This Class helps in performing some operations on a halfspace defined by 2 or 3 points + */ + +class GbHalfSpace3D +{ +public: + GbHalfSpace3D(GbTriangle3D *triangle); + + GbHalfSpace3D(GbPoint3D *PointA, GbPoint3D *PointB, GbPoint3D *PointC); + + GbHalfSpace3D(GbPoint3D *PointA, GbPoint3D *PointB); + + GbHalfSpace3D(const double &p1x, const double &p1y, const double &p1z, const double &p2x, const double &p2y, + const double &p2z, const double &p3x, const double &p3y, const double &p3z); + GbHalfSpace3D(const double &p1x, const double &p1y, const double &p1z, const double &nx, const double &ny, + const double &nz); + + /*=======================================================*/ + std::string getTypeID() { return "GbHalfSpace3D"; } + /*=============================================*/ + bool ptInside(const double &x, const double &y, const double &z) + { + return UbMath::greaterEqual(normalX * x + normalY * y + normalZ * z, this->d); + } + /*=============================================*/ + bool ptInside(GbPoint3D *pointX) + { + // GbVector3D X(PointX->x1, PointX->x2, PointX->x3 ); + // return UbMath::greaterEqual(this->Normal.Dot(X), this->d); + return UbMath::greaterEqual(normalX * pointX->x1 + normalY * pointX->x2 + normalZ * pointX->x3, this->d); + } + /*=============================================*/ + bool ptInside(GbVector3D &x) + { + // return UbMath::greaterEqual(this->Normal.Dot(X), this->d); + return UbMath::greaterEqual(normalX * x[0] + normalY * x[1] + normalZ * x[2], this->d); + } + /*=============================================*/ + double getDistance(const double &x1p, const double &x2p, const double &x3p) + { + return (normalX * x1p + normalY * x2p + normalZ * x3p) - this->d; + } + + const double &getNormalX() { return this->normalX; } + const double &getNormalY() { return this->normalY; } + const double &getNormalZ() { return this->normalZ; } + const double &getD() { return this->d; } + +private: + // GbVector3D Normal; + double normalX; + double normalY; + double normalZ; + double d; +}; +/*=========================================================================*/ + +#endif // GBHALFSPACE3D_H diff --git a/src/basics/geometry3d/GbHalfSpaceKrischan3D.cpp b/src/basics/geometry3d/GbHalfSpaceKrischan3D.cpp new file mode 100644 index 0000000000000000000000000000000000000000..929868f764bdcdc4c420efcfb2d6b829ddcdd112 --- /dev/null +++ b/src/basics/geometry3d/GbHalfSpaceKrischan3D.cpp @@ -0,0 +1,303 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file GbHalfSpaceKrischan3D.cpp +//! \ingroup geometry3D +//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller +//======================================================================================= +#include <geometry3d/GbHalfSpaceKrischan3D.h> + +using namespace std; + +/*==========================================================*/ +GbHalfSpaceKrischan3D::GbHalfSpaceKrischan3D(GbTriangle3D *triangle) +{ + GbPoint3D *PointA = triangle->getPoint1(); + GbPoint3D *PointB = triangle->getPoint2(); + GbPoint3D *PointC = triangle->getPoint3(); + + GbVector3D A(PointA->x1, PointA->x2, PointA->x3); + GbVector3D BA(PointB->x1 - PointA->x1, PointB->x2 - PointA->x2, PointB->x3 - PointA->x3); + GbVector3D CA(PointC->x1 - PointA->x1, PointC->x2 - PointA->x2, PointC->x3 - PointA->x3); + GbVector3D BACA = BA.Cross(CA); + // this->Normal = PointB->subtract(PointA)->cross(PointC->subtract(PointA))->normalize(); + BACA.Normalize(); + this->Normal = BACA; + this->d = this->Normal.Dot(A); +} +/*==========================================================*/ +GbHalfSpaceKrischan3D::GbHalfSpaceKrischan3D(GbPoint3D *PointA, GbPoint3D *PointB, GbPoint3D *PointC) +{ + GbVector3D A(PointA->x1, PointA->x2, PointA->x3); + GbVector3D BA(PointB->x1 - PointA->x1, PointB->x2 - PointA->x2, PointB->x3 - PointA->x3); + GbVector3D CA(PointC->x1 - PointA->x1, PointC->x2 - PointA->x2, PointC->x3 - PointA->x3); + GbVector3D BACA = BA.Cross(CA); + // this->Normal = PointB->subtract(PointA)->cross(PointC->subtract(PointA))->normalize(); + BACA.Normalize(); + this->Normal = BACA; + this->d = this->Normal.Dot(A); +} +/*==========================================================*/ +GbHalfSpaceKrischan3D::GbHalfSpaceKrischan3D(GbPoint3D *PointA, GbPoint3D *PointB) +{ + GbVector3D A(PointA->x1, PointA->x2, PointA->x3); + GbVector3D B(PointB->x1, PointB->x2, PointB->x3); + GbVector3D K(0.0, 0.0, 0.99); // the vector from PointA - third point + + GbVector3D PointBA = B - A; + GbVector3D PointBAK = PointBA.Cross(K); + PointBAK.Normalize(); + this->Normal = PointBAK; + this->d = this->Normal.Dot(A); +} +/*==========================================================*/ +GbHalfSpaceKrischan3D::GbHalfSpaceKrischan3D(const double &p1x, const double &p1y, const double &p1z, const double &p2x, + const double &p2y, const double &p2z, const double &p3x, const double &p3y, + const double &p3z) +{ + GbVector3D A(p1x, p1y, p1z); + GbVector3D BA(p2x - p1x, p2y - p1y, p2z - p1z); + GbVector3D CA(p3x - p1x, p3y - p1y, p3z - p1z); + GbVector3D BACA = BA.Cross(CA); + + BACA.Normalize(); + this->Normal = BACA; + this->d = this->Normal.Dot(A); +} +/*==========================================================*/ +GbHalfSpaceKrischan3D::GbHalfSpaceKrischan3D(double nx, double ny, double nz, double dist) +{ + this->Normal = GbVector3D(nx, ny, nz); + this->Normal.Normalize(); + this->d = dist; +} +/*==========================================================*/ +double GbHalfSpaceKrischan3D::getCellVolumeInsideGbObject3D(const double &x1a, const double &x2a, const double &x3a, + const double &x1b, const double &x2b, const double &x3b) +{ + + double x1 = x1b - x1a; + double x2 = x2b - x2a; + double x3 = x3b - x3a; + + if (this->isCellInsideGbObject3D(x1a, x2a, x3a, x1b, x2b, x3b)) + return 1.0 * x1 * x2 * x3; + if (!(this->isCellCuttingGbObject3D(x1a, x2a, x3a, x1b, x2b, x3b))) + return 0.0; + + double alpha = 0.0; + double internX1, internX2, internX3; + + for (int x1vers = 0; x1vers < 2; x1vers++) { + for (int x2vers = 0; x2vers < 2; x2vers++) { + for (int x3vers = 0; x3vers < 2; x3vers++) { + internX1 = x1a + (x1b - x1a) * x1vers; + internX2 = x2a + (x2b - x2a) * x2vers; + internX3 = x3a + (x3b - x3a) * x3vers; + + // if point is INSIDE the halfspace, distance is smaller than zero + // --> loop determines the minimum alpha...i.e. the alpha with maximum absolute value for all points + // INSIDE the halfspace + if (UbMath::lessEqual(this->getDistance(internX1, internX2, internX3), alpha)) + alpha = this->getDistance(internX1, internX2, internX3); + // cout<<zelltyp<<" "<<kugel->getDistance(internX1,internX2,internX3)<<" "<<alpha<<endl; + } // end first for + } // end second for + } // end third for + + // PLIC needs alphas > 0.0 + alpha = (-1) * alpha; + + double n[3]; + n[0] = this->Normal[0]; + n[1] = this->Normal[1]; + n[2] = this->Normal[2]; + + // cout << "Koordinaten: "<<x1<<" "<<x2<<" "<<x3<<endl; + // cout << "Deltas: "<<deltaX1<<" "<<deltaX2<<" "<<deltaX3<<endl; + // cout << "Halbe Zelle: "<<halfcelldelta<<endl; + + // cout<<"Centroid: "<<kugel->getX1Centroid()<<" "<<kugel->getX2Centroid()<<" "<<kugel->getX3Centroid()<<endl; + + // cout<<"Normals: "<<n[0]<<" "<<n[1]<<" "<<n[2]<<endl; + + double normLength; + normLength = sqrt(n[0] * n[0] + n[1] * n[1] + n[2] * n[2]); + n[0] /= normLength; + n[1] /= normLength; + n[2] /= normLength; + + if (UbMath::less(n[0], 0.0)) + n[0] = -n[0]; + if (UbMath::less(n[1], 0.0)) + n[1] = -n[1]; + if (UbMath::less(n[2], 0.0)) + n[2] = -n[2]; + + // cout<<"Normals: "<<n[0]<<" "<<n[1]<<" "<<n[2]<<endl; + + double dummy; + if (UbMath::greater(n[0], n[1])) { + dummy = n[1]; + n[1] = n[0]; + n[0] = dummy; + } + if (UbMath::greater(n[1], n[2])) { + dummy = n[2]; + n[2] = n[1]; + n[1] = dummy; + } + if (UbMath::greater(n[0], n[1])) { + dummy = n[1]; + n[1] = n[0]; + n[0] = dummy; + } + + // cout<<"Normals: "<<n[0]<<" "<<n[1]<<" "<<n[2]<<endl; + + double n1, n2, n3; + n1 = n[0]; + n2 = n[1]; + n3 = n[2]; + + double preresult = 0.0, result = 0.0; + + // 1D Check + if (UbMath::lessEqual(n1, 0.00001) && UbMath::lessEqual(n2, 0.00001)) { + result = alpha * x1 * x2; + } + // 2D Check + else if (UbMath::lessEqual(n1, 0.00001)) { + preresult = (2 * n2 * n3); + result = (alpha * alpha) / preresult; + + if (UbMath::greater(alpha, n2 * x2)) { + result += -(alpha - n2 * x2) * (alpha - n2 * x2) / preresult; + } + if (UbMath::greater(alpha, n3 * x3)) { + result += -(alpha - n3 * x3) * (alpha - n3 * x3) / preresult; + } + if (UbMath::greater(alpha, n2 * x2 + n3 * x3)) { + result += (alpha - n2 * x2 - n3 * x3) * (alpha - n2 * x2 - n3 * x3) / preresult; + } + + // tiefenrichtung mit einmultiplizieren... + result *= x1; + } + // 3D Check + else { + preresult = 6 * n1 * n2 * n3; + + result = alpha * alpha * alpha / preresult; + + if (UbMath::greater(alpha, n1 * x1)) { + result += -((alpha - n1 * x1) * (alpha - n1 * x1) * (alpha - n1 * x1)) / preresult; + } + if (UbMath::greater(alpha, n2 * x2)) { + result += -((alpha - n2 * x2) * (alpha - n2 * x2) * (alpha - n2 * x2)) / preresult; + } + if (UbMath::greater(alpha, n3 * x3)) { + result += -((alpha - n3 * x3) * (alpha - n3 * x3) * (alpha - n3 * x3)) / preresult; + } + if (UbMath::greater(alpha, (n1 * x1 + n2 * x2))) { + result += ((alpha - (n1 * x1 + n2 * x2)) * (alpha - (n1 * x1 + n2 * x2)) * (alpha - (n1 * x1 + n2 * x2))) / + preresult; + } + if (UbMath::greater(alpha, (n1 * x1 + n3 * x3))) { + result += ((alpha - (n1 * x1 + n3 * x3)) * (alpha - (n1 * x1 + n3 * x3)) * (alpha - (n1 * x1 + n3 * x3))) / + preresult; + } + if (UbMath::greater(alpha, (n2 * x2 + n3 * x3))) { + result += ((alpha - (n2 * x2 + n3 * x3)) * (alpha - (n2 * x2 + n3 * x3)) * (alpha - (n2 * x2 + n3 * x3))) / + preresult; + } + + // NEW + if (UbMath::greater(alpha, (n1 * x1 + n2 * x2 + n3 * x3))) { + result += -((alpha - (n1 * x1 + n2 * x2 + n3 * x3)) * (alpha - (n1 * x1 + n2 * x2 + n3 * x3)) * + (alpha - (n1 * x1 + n2 * x2 + n3 * x3))) / + preresult; + } + } + + if (!UbMath::inClosedInterval(result / (x1 * x2 * x3), -0.01, 1.01)) { + stringstream errMsg; + + errMsg << "Danger...Fuellstand " << result << " nicht im Interfall [0.0..1.0]" << endl; + errMsg << "NormVec: " << n1 << " " << n2 << " " << n3 << endl; + errMsg << "Cell: " << x1 << " " << x2 << " " << x3 << endl; + errMsg << "Alpha: " << alpha << endl; + + throw UbException(UB_EXARGS, errMsg.str()); + } + + return result; + + // double eps=0.0; + // if( UbMath::equal(n1,0.0) && UbMath::equal(n2,0.0) ) + //{ + // eps = alpha/n3; + //} + // else if( UbMath::equal(n1,0.0) ) + //{ + // double dim1,dim2; + // dim1 = alpha/n2; + // dim2 = alpha/n3; + + // eps = 0.5*dim1*dim2; + // if( UbMath::greater(dim1,1.0) ) eps -= 0.5*(dim1-1.0)*dim2/dim1*(dim1-1.0); + // if( UbMath::greater(dim2,1.0) ) eps -= 0.5*(dim2-1.0)*dim1/dim2*(dim2-1.0); + //} + // else + //{ + // eps = alpha*alpha*alpha; + // if( UbMath::greater(alpha,n1) ) + // eps -= (alpha-n1)*(alpha-n1)*(alpha-n1); + // if( UbMath::greater(alpha,n2) ) + // eps -= (alpha-n2)*(alpha-n2)*(alpha-n2); + // if( UbMath::greater(alpha,n3) ) + // eps -= (alpha-n3)*(alpha-n3)*(alpha-n3); + + // if( UbMath::greater(alpha,n1+n2) ) + // eps += (alpha-n1-n2)*(alpha-n1-n2)*(alpha-n1-n2); + // if( UbMath::greater(alpha,n1+n3) ) + // eps += (alpha-n1-n3)*(alpha-n1-n3)*(alpha-n1-n3); + // if( UbMath::greater(alpha,n2+n3) ) + // eps += (alpha-n2-n3)*(alpha-n2-n3)*(alpha-n2-n3); + + // //attention: use without delta_i + // eps = eps / (6*n[0]*n[1]*n[2]); + + // eps = eps / (deltaX1*deltaX2*deltaX3); + //} + + // return(eps) ; + // cout << "alpha ist " << alpha << endl; + // cout << "fillLevel ist " << eps << endl; +} +/*==========================================================*/ diff --git a/src/basics/geometry3d/GbHalfSpaceKrischan3D.h b/src/basics/geometry3d/GbHalfSpaceKrischan3D.h new file mode 100644 index 0000000000000000000000000000000000000000..d62046d4a63d17e3c272c177bdb50823ce1954bb --- /dev/null +++ b/src/basics/geometry3d/GbHalfSpaceKrischan3D.h @@ -0,0 +1,226 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file GbHalfSpaceKrischan3D.h +//! \ingroup geometry3D +//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller +//======================================================================================= +#ifndef GbHalfSpaceKrischan3D_H +#define GbHalfSpaceKrischan3D_H + +#include <iostream> +#include <sstream> + +#include <basics/utilities/UbMath.h> + +#include <geometry3d/GbLine3D.h> +#include <geometry3d/GbPoint3D.h> +#include <geometry3d/GbTriangle3D.h> +#include <geometry3d/GbVector3D.h> + +/*=========================================================================*/ +/* GbHalfSpaceKrischan3D */ +/* */ +/** + * This Class helps in performing some operations on a halfspace defined by 2 or 3 points + */ + +class GbHalfSpaceKrischan3D : public GbObject3D, public UbObserver +{ +public: + GbHalfSpaceKrischan3D(GbTriangle3D *triangle); + + GbHalfSpaceKrischan3D(GbPoint3D *PointA, GbPoint3D *PointB, GbPoint3D *PointC); + + GbHalfSpaceKrischan3D(double nx, double ny, double nz, double dist); + + GbHalfSpaceKrischan3D(GbPoint3D *PointA, GbPoint3D *PointB); + + GbHalfSpaceKrischan3D(const double &p1x, const double &p1y, const double &p1z, const double &p2x, const double &p2y, + const double &p2z, const double &p3x, const double &p3y, const double &p3z); + + /*=======================================================*/ + ~GbHalfSpaceKrischan3D() override = default; + /*=======================================================*/ + std::string getTypeID() { return "GbHalfSpaceKrischan3D"; } + /*=============================================*/ + bool ptInside(const double &x, const double &y, const double &z) + { + return UbMath::lessEqual(Normal[0] * x + Normal[1] * y + Normal[2] * z, this->d); + } + /*=============================================*/ + bool ptInside(GbPoint3D *PointX) + { + GbVector3D X(PointX->x1, PointX->x2, PointX->x3); + return UbMath::lessEqual(this->Normal.Dot(X), this->d); + } + /*=============================================*/ + bool ptInside(GbVector3D &X) { return UbMath::lessEqual(this->Normal.Dot(X), this->d); } + + /*=====================================================*/ + // true, wenn 'in Object' oder 'auf Boundary'! + bool isPointInGbObject3D(const double &x1p, const double &x2p, const double &x3p) override + { + return (ptInside(x1p, x2p, x3p)); + } + /*=====================================================*/ + // true, wenn 'in Object' oder 'auf Boundary'! + bool isPointInGbObject3D(const double &x1p, const double &x2p, const double &x3p, + bool & /*pointIsOnBoundary*/) override + { + return (ptInside(x1p, x2p, x3p)); + } + + void finalize() override {} + + double getX1Centroid() override { return 0.0; } + double getX1Minimum() override { return -99999.0; } + double getX1Maximum() override { return 99999.0; } + double getX2Centroid() override { return 0.0; } + double getX2Minimum() override { return -99999.0; } + double getX2Maximum() override { return 99999.0; } + double getX3Centroid() override { return 0.0; } + double getX3Minimum() override { return -99999.0; } + double getX3Maximum() override { return 99999.0; } + + GbLine3D *createClippedLine3D(GbPoint3D &point1, GbPoint3D &point2) override + { + GbPoint3D *p1 = new GbPoint3D(point1); + GbPoint3D *p2 = new GbPoint3D(point2); + + GbVector3D p1p2(p2->x1 - p1->x1, p2->x2 - p1->x2, p2->x3 - p1->x3); + + double dist1 = getDistance(p1->x1, p1->x2, p1->x3); + double dist2 = getDistance(p2->x1, p2->x2, p2->x3); + + double totalDist = std::abs(dist1) + std::abs(dist2); + + // Falls erster Punkt nicht drinliegt + if (!ptInside(p1)) { + if (!ptInside(p2)) + return NULL; + + // distance ausrechnen (groesser null) + if (UbMath::less(dist1, 0.0)) + throw UbException(UB_EXARGS, "Punkt ausserhalb, aber Distanz kleiner null???"); + + p1->x1 = p1->x1 + dist1 / totalDist * p1p2[0]; + p1->x2 = p1->x2 + dist1 / totalDist * p1p2[1]; + p1->x3 = p1->x3 + dist1 / totalDist * p1p2[2]; + } + // Falls zweiter Punkt nicht drinliegt + if (!ptInside(p2)) { + if (!ptInside(p1)) + return NULL; + + // distance ausrechnen (groesser null) + if (UbMath::less(dist2, 0.0)) + throw UbException(UB_EXARGS, "Punkt ausserhalb, aber Distanz kleiner null???"); + + p2->x1 = p2->x1 - dist2 / totalDist * p1p2[0]; + p2->x2 = p2->x2 - dist2 / totalDist * p1p2[1]; + p2->x3 = p2->x3 - dist2 / totalDist * p1p2[2]; + } + + return new GbLine3D(p1, p2); + } + + double getCellVolumeInsideGbObject3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b, + const double &x2b, const double &x3b) override; + + double getDistance(const double &x1p, const double &x2p, const double &x3p) + { + return (Normal[0] * x1p + Normal[1] * x2p + Normal[2] * x3p) - this->d; + } + + void getNormal(double &n1, double &n2, double &n3) + { + n1 = this->Normal[0]; + n2 = this->Normal[1]; + n3 = this->Normal[2]; + } + + void addSurfaceTriangleSet(std::vector<UbTupleFloat3> & /*nodes*/, + std::vector<UbTupleInt3> & /*triangles*/) override + { + std::cout << " addSurfaceTriangleSet(): TO BE DONE AND CHECKED ... " << std::endl; + } + + std::vector<GbTriangle3D *> getSurfaceTriangleSet() override + { + std::vector<GbTriangle3D *> triangles; + GbPoint3D p1(0.0, 0.0, 0.0); + GbPoint3D p2(1.0, 0.0, 0.0); + GbPoint3D p3(0.0, 1.0, 0.0); + + triangles.push_back(new GbTriangle3D(new GbPoint3D(p1), new GbPoint3D(p2), new GbPoint3D(p3))); + + return triangles; + } + + void objectChanged(UbObservable * /*changedObject*/) override + { + return; + + // GbLine3D* line = dynamic_cast<GbLine3D*>(changedObject); + // if(!line || this->mLine!=line) return; + // this->notifyObserversObjectChanged(); + } + /*==========================================================*/ + void objectWillBeDeleted(UbObservable * /*objectForDeletion*/) override + { + return; + // if(this->mLine) + //{ + // UbObservable* observedObj = dynamic_cast<UbObservable*>(this->mLine); + // if(objectForDeletion == observedObj) { this->mLine = NULL; } + //} + } + + ObObject *clone() override { return NULL; }; + + std::string toString() override + { + std::stringstream temp; + + temp << "GbHalfSpaceKrischan3D: "; + temp << " Distance " << this->d; + temp << " Norm vec " << this->Normal[0]; + temp << " " << this->Normal[1]; + temp << " " << this->Normal[2]; + + return temp.str(); + }; + +private: + GbVector3D Normal; + double d; +}; +/*=========================================================================*/ + +#endif // GbHalfSpaceKrischan3D_H diff --git a/src/basics/geometry3d/GbMeshTools3D.h b/src/basics/geometry3d/GbMeshTools3D.h new file mode 100644 index 0000000000000000000000000000000000000000..2464bcc34788dadfd99e64b9a94878d22df4a54b --- /dev/null +++ b/src/basics/geometry3d/GbMeshTools3D.h @@ -0,0 +1,496 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file GbMeshTools3D.h +//! \ingroup geometry3D +//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller +//======================================================================================= +#ifndef GBMESHTOOLS3D_H +#define GBMESHTOOLS3D_H + +#include <iostream> +#include <sstream> +#include <vector> + +#include <basics/utilities/UbMath.h> + +namespace GbMeshTools3D +{ +inline int planeBoxOverlap(float normal[3], float vert[3], float maxbox[3]) // -NJMP- +{ + int q; + float vmin[3], vmax[3], v; + + for (q = 0; q <= 2; q++) { + v = vert[q]; // -NJMP- + if (normal[q] > 0.0f) { + vmin[q] = -maxbox[q] - v; // -NJMP- + vmax[q] = maxbox[q] - v; // -NJMP- + } else { + vmin[q] = maxbox[q] - v; // -NJMP- + vmax[q] = -maxbox[q] - v; // -NJMP- + } + } + if ((normal[0] * vmin[0] + normal[1] * vmin[1] + normal[2] * vmin[2]) > 0.0f) + return 0; // -NJMP- + if ((normal[0] * vmax[0] + normal[1] * vmax[1] + normal[2] * vmax[2]) >= 0.0f) + return 1; // -NJMP- + return 0; +} + +// Testet auf schnittpunkt Box <-> Dreieck +// boxcenter = Mittelpunkt der Box +// boxhalfsize = Halbe Laenge/Hoehe/Breite der Box +// triverts = Koordinaten der Deickspunkte +inline int triBoxOverlap(float boxcenter[3], float boxhalfsize[3], float triverts[3][3]) +{ + /* use separating axis theorem to test overlap between triangle and box */ + /* need to test for overlap in these directions: */ + /* 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle */ + /* we do not even need to test these) */ + /* 2) normal of the triangle */ + /* 3) crossproduct(edge from tri, {x,y,z}-directin) */ + /* this gives 3x3=9 more tests */ + + float v0[3], v1[3], v2[3]; + + // float axis[3]; + + float min, max, p0, p1, p2, rad, fex, fey, fez; // -NJMP- "d" local variable removed + float normal[3], e0[3], e1[3], e2[3]; + + /* This is the fastest branch on Sun */ + /* move everything so that the boxcenter is in (0,0,0) */ + // SUB(v0,triverts[0],boxcenter); + //#define SUB(dest,v1,v2) + v0[0] = triverts[0][0] - boxcenter[0]; + v0[1] = triverts[0][1] - boxcenter[1]; + v0[2] = triverts[0][2] - boxcenter[2]; + + // SUB(v1,triverts[1],boxcenter); + //#define SUB(dest,v1,v2) + v1[0] = triverts[1][0] - boxcenter[0]; + v1[1] = triverts[1][1] - boxcenter[1]; + v1[2] = triverts[1][2] - boxcenter[2]; + + // SUB(v2,triverts[2],boxcenter); + //#define SUB(dest,v1,v2) + v2[0] = triverts[2][0] - boxcenter[0]; + v2[1] = triverts[2][1] - boxcenter[1]; + v2[2] = triverts[2][2] - boxcenter[2]; + + /* compute triangle edges */ + // SUB(e0,v1,v0); /* tri edge 0 */ + //#define SUB(dest,v1,v2) + e0[0] = v1[0] - v0[0]; + e0[1] = v1[1] - v0[1]; + e0[2] = v1[2] - v0[2]; + + // SUB(e1,v2,v1); /* tri edge 1 */ + //#define SUB(dest,v1,v2) + e1[0] = v2[0] - v1[0]; + e1[1] = v2[1] - v1[1]; + e1[2] = v2[2] - v1[2]; + + // SUB(e2,v0,v2); /* tri edge 2 */ + //#define SUB(dest,v1,v2) + e2[0] = v0[0] - v2[0]; + e2[1] = v0[1] - v2[1]; + e2[2] = v0[2] - v2[2]; + + /* Bullet 3: */ + /* test the 9 tests first (this was faster) */ + fex = fabsf(e0[0]); + fey = fabsf(e0[1]); + fez = fabsf(e0[2]); + + // AXISTEST_X01(e0[2], e0[1], fez, fey); + //#define AXISTEST_X01(a, b, fa, fb) + p0 = e0[2] * v0[1] - e0[1] * v0[2]; + p2 = e0[2] * v2[1] - e0[1] * v2[2]; + if (p0 < p2) { + min = p0; + max = p2; + } else { + min = p2; + max = p0; + } + rad = fez * boxhalfsize[1] + fey * boxhalfsize[2]; + if (min > rad || max < -rad) + return 0; + + // AXISTEST_Y02(e0[2], e0[0], fez, fex); + //#define AXISTEST_Y02(a, b, fa, fb) + p0 = -e0[2] * v0[0] + e0[0] * v0[2]; + p2 = -e0[2] * v2[0] + e0[0] * v2[2]; + if (p0 < p2) { + min = p0; + max = p2; + } else { + min = p2; + max = p0; + } + rad = fez * boxhalfsize[0] + fex * boxhalfsize[2]; + if (min > rad || max < -rad) + return 0; + + // AXISTEST_Z12(e0[1], e0[0], fey, fex); + //#define AXISTEST_Z12(a, b, fa, fb) + p1 = e0[1] * v1[0] - e0[0] * v1[1]; + p2 = e0[1] * v2[0] - e0[0] * v2[1]; + if (p2 < p1) { + min = p2; + max = p1; + } else { + min = p1; + max = p2; + } + rad = fey * boxhalfsize[0] + fex * boxhalfsize[1]; + if (min > rad || max < -rad) + return 0; + + fex = fabsf(e1[0]); + fey = fabsf(e1[1]); + fez = fabsf(e1[2]); + + // AXISTEST_X01(e1[2], e1[1], fez, fey); + //#define AXISTEST_X01(a, b, fa, fb) + p0 = e1[2] * v0[1] - e1[1] * v0[2]; + p2 = e1[2] * v2[1] - e1[1] * v2[2]; + if (p0 < p2) { + min = p0; + max = p2; + } else { + min = p2; + max = p0; + } + rad = fez * boxhalfsize[1] + fey * boxhalfsize[2]; + if (min > rad || max < -rad) + return 0; + + // AXISTEST_Y02(e1[2], e1[0], fez, fex); + //#define AXISTEST_Y02(a, b, fa, fb) + p0 = -e1[2] * v0[0] + e1[0] * v0[2]; + p2 = -e1[2] * v2[0] + e1[0] * v2[2]; + if (p0 < p2) { + min = p0; + max = p2; + } else { + min = p2; + max = p0; + } + rad = fez * boxhalfsize[0] + fex * boxhalfsize[2]; + if (min > rad || max < -rad) + return 0; + + // AXISTEST_Z0(e1[1], e1[0], fey, fex); + //#define AXISTEST_Z0(a, b, fa, fb) + p0 = e1[1] * v0[0] - e1[0] * v0[1]; + p1 = e1[1] * v1[0] - e1[0] * v1[1]; + if (p0 < p1) { + min = p0; + max = p1; + } else { + min = p1; + max = p0; + } + rad = fey * boxhalfsize[0] + fex * boxhalfsize[2]; + if (min > rad || max < -rad) + return 0; + + fex = fabsf(e2[0]); + fey = fabsf(e2[1]); + fez = fabsf(e2[2]); + // AXISTEST_X2(e2[2], e2[1], fez, fey); + //#define AXISTEST_X2(a, b, fa, fb) + p0 = e2[2] * v0[1] - e2[1] * v0[2]; + p1 = e2[2] * v1[1] - e2[1] * v1[2]; + if (p0 < p1) { + min = p0; + max = p1; + } else { + min = p1; + max = p0; + } + rad = fez * boxhalfsize[1] + fey * boxhalfsize[2]; + if (min > rad || max < -rad) + return 0; + + // AXISTEST_Y1(e2[2], e2[0], fez, fex); + //#define AXISTEST_Y1(a, b, fa, fb) + p0 = -e2[2] * v0[0] + e2[0] * v0[2]; + p1 = -e2[2] * v1[0] + e2[0] * v1[2]; + if (p0 < p1) { + min = p0; + max = p1; + } else { + min = p1; + max = p0; + } + rad = fez * boxhalfsize[0] + fex * boxhalfsize[2]; + if (min > rad || max < -rad) + return 0; + + // AXISTEST_Z12(e2[1], e2[0], fey, fex); + //#define AXISTEST_Z12(a, b, fa, fb) + p1 = e2[1] * v1[0] - e2[0] * v1[1]; + p2 = e2[1] * v2[0] - e2[0] * v2[1]; + if (p2 < p1) { + min = p2; + max = p1; + } else { + min = p1; + max = p2; + } + rad = fey * boxhalfsize[0] + fex * boxhalfsize[1]; + if (min > rad || max < -rad) + return 0; + + /* Bullet 1: */ + /* first test overlap in the {x,y,z}-directions */ + /* find min, max of the triangle each direction, and test for overlap in */ + /* that direction -- this is equivalent to testing a minimal AABB around */ + /* the triangle against the AABB */ + /* test in X-direction */ + // FINDMINMAX(v0[0],v1[0],v2[0],min,max); + min = (float)UbMath::min(v0[0], v1[0], v2[0]); + max = (float)UbMath::max(v0[0], v1[0], v2[0]); + if (min > boxhalfsize[0] || max < -boxhalfsize[0]) + return 0; + + /* test in Y-direction */ + // FINDMINMAX(v0[1],v1[1],v2[1],min,max); + min = (float)UbMath::min(v0[1], v1[1], v2[1]); + max = (float)UbMath::max(v0[1], v1[1], v2[1]); + if (min > boxhalfsize[1] || max < -boxhalfsize[1]) + return 0; + + /* test in Z-direction */ + // FINDMINMAX(v0[2],v1[2],v2[2],min,max); + min = (float)UbMath::min(v0[2], v1[2], v2[2]); + max = (float)UbMath::max(v0[2], v1[2], v2[2]); + + if (min > boxhalfsize[2] || max < -boxhalfsize[2]) + return 0; + + /* Bullet 2: */ + /* test if the box intersects the plane of the triangle */ + /* compute plane equation of triangle: normal*x+d=0 */ + // CROSS(normal,e0,e1); + //#define CROSS(dest,v1,v2) + normal[0] = e0[1] * e1[2] - e0[2] * e1[1]; + normal[1] = e0[2] * e1[0] - e0[0] * e1[2]; + normal[2] = e0[0] * e1[1] - e0[1] * e1[0]; + + // -NJMP- (line removed here) + if (!planeBoxOverlap(normal, v0, boxhalfsize)) + return 0; // -NJMP- + return 1; /* box and triangle overlaps */ +} + +} // namespace GbMeshTools3D + +#endif + +// original - NICHT LOESCHEN - von kroete lynn + +//#define X 0 +//#define Y 1 +//#define Z 2 +// +//#define CROSS(dest,v1,v2) +// dest[0]=v1[1]*v2[2]-v1[2]*v2[1]; +// dest[1]=v1[2]*v2[0]-v1[0]*v2[2]; +// dest[2]=v1[0]*v2[1]-v1[1]*v2[0]; +// +//#define DOT(v1,v2) (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]) +// +//#define SUB(dest,v1,v2) +// dest[0]=v1[0]-v2[0]; +// dest[1]=v1[1]-v2[1]; +// dest[2]=v1[2]-v2[2]; +// +//#define FINDMINMAX(x0,x1,x2,min,max) +// min = max = x0; +// if(x1<min) min=x1; +// if(x1>max) max=x1; +// if(x2<min) min=x2; +// if(x2>max) max=x2; +// +// int planeBoxOverlap(float normal[3], float vert[3], float maxbox[3]) // -NJMP- +//{ +// int q; +// float vmin[3],vmax[3],v; +// +// for(q=X;q<=Z;q++) +// { +// v=vert[q]; // -NJMP- +// if(normal[q]>0.0f) +// { +// vmin[q]=-maxbox[q] - v; // -NJMP- +// vmax[q]= maxbox[q] - v; // -NJMP- +// } +// else +// { +// vmin[q]= maxbox[q] - v; // -NJMP- +// vmax[q]=-maxbox[q] - v; // -NJMP- +// } +// } +// if(DOT(normal,vmin)>0.0f) return 0; // -NJMP- +// if(DOT(normal,vmax)>=0.0f) return 1; // -NJMP- +// return 0; +//} +// +///*======================== X-tests ======================== +// +//#define AXISTEST_X01(a, b, fa, fb) +// p0 = a*v0[Y] - b*v0[Z]; +// p2 = a*v2[Y] - b*v2[Z]; +// if(p0<p2) {min=p0; max=p2;} else {min=p2; max=p0;} +// rad = fa * boxhalfsize[Y] + fb * boxhalfsize[Z]; +// if(min>rad || max<-rad) return 0; +// +//#define AXISTEST_X2(a, b, fa, fb) +// p0 = a*v0[Y] - b*v0[Z]; +// p1 = a*v1[Y] - b*v1[Z]; +// if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} +// rad = fa * boxhalfsize[Y] + fb * boxhalfsize[Z]; +// if(min>rad || max<-rad) return 0; +// +// +// +///*======================== Y-tests ======================== +// +//#define AXISTEST_Y02(a, b, fa, fb) +// p0 = -a*v0[X] + b*v0[Z]; +// p2 = -a*v2[X] + b*v2[Z]; +// if(p0<p2) {min=p0; max=p2;} else {min=p2; max=p0;} +// rad = fa * boxhalfsize[X] + fb * boxhalfsize[Z]; +// if(min>rad || max<-rad) return 0; +// +//#define AXISTEST_Y1(a, b, fa, fb) +// p0 = -a*v0[X] + b*v0[Z]; +// p1 = -a*v1[X] + b*v1[Z]; +// if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} +// rad = fa * boxhalfsize[X] + fb * boxhalfsize[Z]; +// if(min>rad || max<-rad) return 0; +// +//======================== Z-tests ======================== +// +//#define AXISTEST_Z12(a, b, fa, fb) +// p1 = a*v1[X] - b*v1[Y]; +// p2 = a*v2[X] - b*v2[Y]; +// if(p2<p1) {min=p2; max=p1;} else {min=p1; max=p2;} +// rad = fa * boxhalfsize[X] + fb * boxhalfsize[Y]; +// if(min>rad || max<-rad) return 0; +// +//#define AXISTEST_Z0(a, b, fa, fb) +// p0 = a*v0[X] - b*v0[Y]; +// p1 = a*v1[X] - b*v1[Y]; +// if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} +// rad = fa * boxhalfsize[X] + fb * boxhalfsize[Y]; +// if(min>rad || max<-rad) return 0; +// +// int triBoxOverlap(float boxcenter[3],float boxhalfsize[3],float triverts[3][3]) +//{ +// //use separating axis theorem to test overlap between triangle and box +// //need to test for overlap in these directions: +// //1) the {x,y,z}-directions (actually, since we use the AABB of the triangle +// // we do not even need to test these) +// //2) normal of the triangle +// //3) crossproduct(edge from tri, {x,y,z}-directin) +// // this gives 3x3=9 more tests +// +// float v0[3],v1[3],v2[3]; +// +// // float axis[3]; +// +// float min,max,p0,p1,p2,rad,fex,fey,fez; // -NJMP- "d" local variable removed +// float normal[3],e0[3],e1[3],e2[3]; +// +// /* This is the fastest branch on Sun */ +// /* move everything so that the boxcenter is in (0,0,0) */ +// SUB(v0,triverts[0],boxcenter); +// SUB(v1,triverts[1],boxcenter); +// SUB(v2,triverts[2],boxcenter); +// +// /* compute triangle edges */ +// SUB(e0,v1,v0); /* tri edge 0 */ +// SUB(e1,v2,v1); /* tri edge 1 */ +// SUB(e2,v0,v2); /* tri edge 2 */ +// +// /* Bullet 3: */ +// /* test the 9 tests first (this was faster) */ +// fex = fabsf(e0[X]); +// fey = fabsf(e0[Y]); +// fez = fabsf(e0[Z]); +// +// AXISTEST_X01(e0[Z], e0[Y], fez, fey); +// AXISTEST_Y02(e0[Z], e0[X], fez, fex); +// AXISTEST_Z12(e0[Y], e0[X], fey, fex); +// fex = fabsf(e1[X]); +// fey = fabsf(e1[Y]); +// fez = fabsf(e1[Z]); +// +// AXISTEST_X01(e1[Z], e1[Y], fez, fey); +// AXISTEST_Y02(e1[Z], e1[X], fez, fex); +// AXISTEST_Z0(e1[Y], e1[X], fey, fex); +// +// fex = fabsf(e2[X]); +// fey = fabsf(e2[Y]); +// fez = fabsf(e2[Z]); +// AXISTEST_X2(e2[Z], e2[Y], fez, fey); +// AXISTEST_Y1(e2[Z], e2[X], fez, fex); +// AXISTEST_Z12(e2[Y], e2[X], fey, fex); +// +// /* Bullet 1: */ +// /* first test overlap in the {x,y,z}-directions */ +// /* find min, max of the triangle each direction, and test for overlap in */ +// /* that direction -- this is equivalent to testing a minimal AABB around */ +// /* the triangle against the AABB */ +// /* test in X-direction */ +// FINDMINMAX(v0[X],v1[X],v2[X],min,max); +// if(min>boxhalfsize[X] || max<-boxhalfsize[X]) return 0; +// +// /* test in Y-direction */ +// FINDMINMAX(v0[Y],v1[Y],v2[Y],min,max); +// if(min>boxhalfsize[Y] || max<-boxhalfsize[Y]) return 0; +// +// /* test in Z-direction */ +// FINDMINMAX(v0[Z],v1[Z],v2[Z],min,max); +// if(min>boxhalfsize[Z] || max<-boxhalfsize[Z]) return 0; +// +// /* Bullet 2: */ +// /* test if the box intersects the plane of the triangle */ +// /* compute plane equation of triangle: normal*x+d=0 */ +// CROSS(normal,e0,e1); +// +// // -NJMP- (line removed here) +// if(!planeBoxOverlap(normal,v0,boxhalfsize)) return 0; // -NJMP- +// return 1; /* box and triangle overlaps */ +//} diff --git a/src/basics/geometry3d/GbObjectGroup3D.cpp b/src/basics/geometry3d/GbObjectGroup3D.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a3a964b1dc95a9f13a122f985375873baa830f7d --- /dev/null +++ b/src/basics/geometry3d/GbObjectGroup3D.cpp @@ -0,0 +1,148 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file GbObjectGroup3D.cpp +//! \ingroup geometry3D +//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller +//======================================================================================= +#include <geometry3d/GbLine3D.h> +#include <geometry3d/GbObjectGroup3D.h> +#include <geometry3d/GbPoint3D.h> +#include <geometry3d/GbSystem3D.h> +#include <geometry3d/GbTriangle3D.h> + +using namespace std; + +/*=====================================================*/ +GbObjectGroup3D::GbObjectGroup3D() { this->setName("ObjectGroup"); } +/*=====================================================*/ +GbObjectGroup3D::~GbObjectGroup3D() = default; +/*=====================================================*/ +void GbObjectGroup3D::finalize() { throw UbException(UB_EXARGS, "not implemented."); } +/*=======================================================*/ +void GbObjectGroup3D::setCenterCoordinates(const double & /*x1*/, const double & /*x2*/, const double & /*x3*/) +{ + throw UbException(UB_EXARGS, "not implemented."); +} +/*=====================================================*/ +double GbObjectGroup3D::getDistance(GbPoint3D * /*p*/) { throw UbException(UB_EXARGS, "not implemented."); } +/*=====================================================*/ + +void GbObjectGroup3D::setCenterX1Coordinate(const double & /*value*/) +{ + throw UbException(UB_EXARGS, "not implemented."); +} +/*=====================================================*/ +void GbObjectGroup3D::setCenterX2Coordinate(const double & /*value*/) +{ + throw UbException(UB_EXARGS, "not implemented."); +} +/*=====================================================*/ +void GbObjectGroup3D::setCenterX3Coordinate(const double & /*value*/) +{ + throw UbException(UB_EXARGS, "not implemented."); +} +/*=====================================================*/ +void GbObjectGroup3D::setRadius(const double & /*radius*/) { throw UbException(UB_EXARGS, "not implemented."); } +/*=====================================================*/ +double GbObjectGroup3D::getDistance(const double & /*x1p*/, const double & /*x2p*/, const double & /*x3p*/) +{ + throw UbException(UB_EXARGS, "not implemented."); +} +/*=====================================================*/ +// true, wenn 'in Object' oder 'auf Boundary'! +bool GbObjectGroup3D::isPointInGbObject3D(const double & /*x1p*/, const double & /*x2p*/, const double & /*x3p*/) +{ + return false; +} +/*=====================================================*/ +// true, wenn 'in Object' oder 'auf Boundary'! +bool GbObjectGroup3D::isPointInGbObject3D(const double & /*x1p*/, const double & /*x2p*/, const double & /*x3p*/, + bool & /*pointIsOnBoundary*/) +{ + return false; +} +/*=====================================================*/ +string GbObjectGroup3D::toString() +{ + stringstream ss; + ss << "GbObjectGroup3D["; + ss << "mid=" << midPoint->toString() << ", r=" << radius << "]"; + return ss.str(); +} +/*=====================================================*/ +GbLine3D *GbObjectGroup3D::createClippedLine3D(GbPoint3D & /*point1*/, GbPoint3D & /*point2*/) { return NULL; } +/*=========================================================================*/ +vector<GbTriangle3D *> GbObjectGroup3D::getSurfaceTriangleSet() +{ + vector<GbTriangle3D *> allTriangles; + + // loop ueber alle objekte in der group + for (std::list<GbObject3D *>::iterator iter = this->geoobjects.begin(); iter != this->geoobjects.end(); iter++) { + vector<GbTriangle3D *> triangles; + triangles = (*iter)->getSurfaceTriangleSet(); + + for (size_t i = 0; i < triangles.size(); i++) { + // kopieren... + allTriangles.push_back(triangles[i]); + } + } + return allTriangles; +} +/*=======================================================*/ +void GbObjectGroup3D::addSurfaceTriangleSet(vector<UbTupleFloat3> &/*nodes*/, vector<UbTupleInt3> &/*triangles*/) {} +/*=======================================================*/ +bool GbObjectGroup3D::hasIntersectionWithDirectedLine(GbPoint3D /*origin*/, GbPoint3D /*direction*/) { return false; } +/*=======================================================*/ +bool GbObjectGroup3D::isCellCuttingGbObject3D(const double & /*x1a*/, const double & /*x2a*/, const double & /*x3a*/, + const double & /*x1b*/, const double & /*x2b*/, const double & /*x3b*/) +{ + return false; +} +/*=======================================================*/ +bool GbObjectGroup3D::isCellInsideOrCuttingGbObject3D(const double & /*x1a*/, const double & /*x2a*/, + const double & /*x3a*/, const double & /*x1b*/, + const double & /*x2b*/, const double & /*x3b*/) +{ + return false; +} +/*==========================================================*/ +double GbObjectGroup3D::getCellVolumeInsideGbObject3D(const double & /*x1a*/, const double & /*x2a*/, + const double & /*x3a*/, const double & /*x1b*/, + const double & /*x2b*/, const double & /*x3b*/) +{ + return 0.0; +} +/*==========================================================*/ +double GbObjectGroup3D::getIntersectionRaytraceFactor(const double & /*x1*/, const double & /*x2*/, + const double & /*x3*/, const double & /*rx1*/, + const double & /*rx2*/, const double & /*rx3*/) +{ + return 0.0; +} +/*=======================================================*/ diff --git a/src/basics/geometry3d/GbObjectGroup3D.h b/src/basics/geometry3d/GbObjectGroup3D.h new file mode 100644 index 0000000000000000000000000000000000000000..6c748a12a403594e7604f580fdc30245c1c6d28c --- /dev/null +++ b/src/basics/geometry3d/GbObjectGroup3D.h @@ -0,0 +1,163 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file GbObjectGroup3D.h +//! \ingroup geometry3D +//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller +//======================================================================================= +#ifndef GBOBJECTGROUP3D_H +#define GBOBJECTGROUP3D_H + +#ifdef CAB_CTL +#include <ctl.h> +#endif // CAB_CTL + +#include <cmath> +#include <vector> + +#include <basics/utilities/UbObserver.h> +#include <geometry3d/GbObject3D.h> +#include <geometry3d/GbPoint3D.h> + +#include <PointerDefinitions.h> + +class GbLine3D; +class GbTriangle3D; +class GbObject3DCreator; + +class GbObjectGroup3D : public GbObject3D, public UbObserver +{ +public: + enum TRIANGULATIONMODE { CUBOIDPROJECTION, RAYPROJECTION }; + + ////////////////////////////////////////////////////////////////////////// + // Konstruktoren + GbObjectGroup3D(); + GbObjectGroup3D(GbObjectGroup3D * /*group*/){}; + ~GbObjectGroup3D() override; + + GbObjectGroup3D *clone() override { return new GbObjectGroup3D(this); } + void finalize() override; + + void addGbObject(GbObject3D *object) { this->geoobjects.push_back(object); } + + double getRadius() const { return this->radius; } + + double getX1Centroid() override { return midPoint->getX1Coordinate(); } + double getX1Minimum() override { return midPoint->getX1Coordinate() - radius; } + double getX1Maximum() override { return midPoint->getX1Coordinate() + radius; } + double getX2Centroid() override { return midPoint->getX2Coordinate(); } + double getX2Minimum() override { return midPoint->getX2Coordinate() - radius; } + double getX2Maximum() override { return midPoint->getX2Coordinate() + radius; } + double getX3Centroid() override { return midPoint->getX3Coordinate(); } + double getX3Minimum() override { return midPoint->getX3Coordinate() - radius; } + double getX3Maximum() override { return midPoint->getX3Coordinate() + radius; } + + void setCenterX1Coordinate(const double &value) override; + void setCenterX2Coordinate(const double &value) override; + void setCenterX3Coordinate(const double &value) override; + void setCenterCoordinates(const double &x1, const double &x2, const double &x3) override; + void setRadius(const double &radius); + + GbLine3D *createClippedLine3D(GbPoint3D &point1, GbPoint3D &point2) override; + double getDistance(GbPoint3D *p); + double getDistance(const double &x1p, const double &x2p, const double &x3p); + + bool isPointInGbObject3D(const double &x1, const double &x2, const double &x3) override; + bool isPointInGbObject3D(const double &x1p, const double &x2p, const double &x3p, bool &pointIsOnBoundary) override; + + bool isCellCuttingGbObject3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b, + const double &x2b, const double &x3b) override; + bool isCellInsideOrCuttingGbObject3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b, + const double &x2b, const double &x3b) override; + double getCellVolumeInsideGbObject3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b, + const double &x2b, const double &x3b) override; + + std::vector<GbTriangle3D *> getSurfaceTriangleSet() override; + void addSurfaceTriangleSet(std::vector<UbTupleFloat3> &nodes, std::vector<UbTupleInt3> &triangles) override; + + bool hasRaytracing() override { return true; } + /*|r| must be 1! einheitsvector!!*/ + double getIntersectionRaytraceFactor(const double &x1, const double &x2, const double &x3, const double &rx1, + const double &rx2, const double &rx3) override; + + bool hasIntersectionWithDirectedLine(GbPoint3D origin, GbPoint3D direction); + + std::string toString() override; + + void translate(const double &x1, const double &x2, const double &x3) override + { + this->midPoint->translate(x1, x2, x3); + this->notifyObserversObjectChanged(); + } + void rotate(const double &/*rx1*/, const double &/*rx2*/, const double &/*rx3*/) override + { /* rotation makes no sense*/ + } + void scale(const double &sx1, const double & /*sx2*/, const double & /*sx3*/) override { this->radius *= sx1; } + + TRIANGULATIONMODE getTriangulationMode() { return triangulationMode; } + void setTriangulationMode(TRIANGULATIONMODE mode) { this->triangulationMode = mode; } + + // virtuelle Methoden von UbObserver + void objectChanged(UbObservable * /*changedObject*/) override + { + this->notifyObserversObjectChanged(); + // std::cout<<"GbSphere:objectChanged() - toDo-);"; + } + void objectWillBeDeleted(UbObservable * /*objectForDeletion*/) override + { + std::cout << "throw UbException(-GbObjectGroup3D::finalize() - toDo-);"; + } + + using GbObject3D::isPointInGbObject3D; // Grund: dadurch muss man hier isPointInGbObject3D(GbPoint3D*) nicht + // ausprogrammieren, welche sonst hier "ueberdeckt" waere, weil man eine + + std::list<GbObject3D *> getGbObject3DList() { return this->geoobjects; } + +#ifdef CAB_CTL + ctl::oStream &write(ctl::oStream &os) const + { + midPoint->write(os); + return os << radius; + } + ctl::iStream &read(ctl::iStream &is) + { + midPoint->read(is); + return is >> radius; + } +#endif // CAB_CTL + +private: + GbPoint3D *midPoint; + double radius; // Radius des Kreises + TRIANGULATIONMODE triangulationMode; + + std::list<GbObject3D *> geoobjects; +}; + +#endif // GbObjectGroup3D_H diff --git a/src/basics/geometry3d/GbQuadFaceMesh3D.cpp b/src/basics/geometry3d/GbQuadFaceMesh3D.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1b2c2aeaabf1eacd78577cc67b678be895747e05 --- /dev/null +++ b/src/basics/geometry3d/GbQuadFaceMesh3D.cpp @@ -0,0 +1,342 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file GbQuadFaceMesh3D.cpp +//! \ingroup geometry3D +//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller +//======================================================================================= +#include <geometry3d/GbQuadFaceMesh3D.h> + +#include <geometry3d/GbCuboid3D.h> +#include <geometry3d/GbHalfSpace3D.h> + +using namespace std; + +GbQuadFaceMesh3D::GbQuadFaceMesh3D() : GbObject3D() +{ + this->name = "new GbMesh"; + this->nodes = new vector<Vertex>; + this->quads = new vector<QuadFace>; + this->consistent = false; +} + +GbQuadFaceMesh3D::GbQuadFaceMesh3D(string name, vector<Vertex> *nodes, vector<QuadFace> *quads) : GbObject3D() +{ + if (name.size() == 0) + throw UbException(UB_EXARGS, "no name specified"); + if (!nodes) + throw UbException(UB_EXARGS, "no nodes specified"); + if (!quads) + throw UbException(UB_EXARGS, "no quads specified"); + + this->name = name; + this->nodes = nodes; + this->quads = quads; + this->consistent = false; +} +/*=============================================================================================*/ + +GbQuadFaceMesh3D::~GbQuadFaceMesh3D() +{ + if (nodes) { + // for(unsigned u=0; u<nodes->size(); u++) delete (*nodes)[u]; + delete nodes; + } + if (quads) { + delete quads; + } +} +/*======================================================================*/ + +void GbQuadFaceMesh3D::init() +{ + nodes = NULL; + quads = NULL; + x1min = 0.0; + x1max = 0.0; + x2min = 0.0; + x2max = 0.0; + x3min = 0.0; + x3max = 0.0; + consistent = false; +} +/** + * Returns a string representation of this triangular mesh. + * @return a string representation of this triangular mesh + */ +string GbQuadFaceMesh3D::toString() +{ + stringstream ss; + ss << "GbQuadFaceMesh3D["; + ss << (int)this->quads->size() << "-Quadangles, " << (int)this->nodes->size() << "-Nodes, " << endl; + // ss<<"\""<<this->name<<", Area=sollt mal berechnet werden ;-)"<<"\""; + // ss<<", x1min="<<this->x1min; + // ss<<", x1max="<<this->x1max; + // ss<<", x2min="<<this->x2min; + // ss<<", x2max="<<this->x2max; + // ss<<", x3min="<<this->x3min; + // ss<<", x3max="<<this->x3max; + ss << "]"; + return (ss.str()); +} +/** + * Returns the name of this triangular mesh. + * @return the name of this triangular mesh + */ +string GbQuadFaceMesh3D::getName() { return (this->name); } + +/** + * Returns the nodes of this triangular mesh. + * @return the nodes of this triangular mesh + */ +vector<GbQuadFaceMesh3D::Vertex> *GbQuadFaceMesh3D::getNodes() { return (this->nodes); } +/** + * Returns the quads of this triangular mesh. + * @return the quads of this triangular mesh + */ +vector<GbQuadFaceMesh3D::QuadFace> *GbQuadFaceMesh3D::getQuads() { return (this->quads); } +/** + * Returns the center x1 coordinate of this triangular mesh. + * @return the center x1 coordinate of this triangular mesh + */ +double GbQuadFaceMesh3D::getX1Centroid() +{ + if (!this->consistent) + this->calculateValues(); + return (0.5 * (this->x1min + this->x1max)); +} +/** + * Returns the center x2 coordinate of this triangular mesh. + * @return the center x2 coordinate of this triangular mesh + */ +double GbQuadFaceMesh3D::getX2Centroid() +{ + if (!this->consistent) + this->calculateValues(); + return (0.5 * (this->x2min + this->x2max)); +} +/** + * Returns the center x3 coordinate of this triangular mesh. + * @return the center x3 coordinate of this triangular mesh + */ +double GbQuadFaceMesh3D::getX3Centroid() +{ + if (!this->consistent) + this->calculateValues(); + return (0.5 * (this->x3min + this->x3max)); +} + +/** + * Returns the minimum x1 coordinate of this triangular mesh. + * @return the minimum x1 coordinate of this triangular mesh + */ +double GbQuadFaceMesh3D::getX1Minimum() +{ + if (!this->consistent) + this->calculateValues(); + return (this->x1min); +} +/** + * Returns the maximum x1 coordinate of this triangular mesh. + * @return the maximum x1 coordinate of this triangular mesh + */ +double GbQuadFaceMesh3D::getX1Maximum() +{ + if (!this->consistent) + this->calculateValues(); + return (this->x1max); +} +/** + * Returns the minimum x2 coordinate of this triangular mesh. + * @return the minimum x2 coordinate of this triangular mesh + */ +double GbQuadFaceMesh3D::getX2Minimum() +{ + if (!this->consistent) + this->calculateValues(); + return (this->x2min); +} +/** + * Returns the maximum x2 coordinate of this triangular mesh. + * @return the maximum x2 coordinate of this triangular mesh + */ +double GbQuadFaceMesh3D::getX2Maximum() +{ + if (!this->consistent) + this->calculateValues(); + return (this->x2max); +} +/** + * Returns the minimum x3 coordinate of this triangular mesh. + * @return the minimum x3 coordinate of this triangular mesh + */ +double GbQuadFaceMesh3D::getX3Minimum() +{ + if (!this->consistent) + this->calculateValues(); + return (this->x3min); +} +/** + * Returns the maximum x3 coordinate of this triangular mesh. + * @return the maximum x3 coordinate of this triangular mesh + */ +double GbQuadFaceMesh3D::getX3Maximum() +{ + if (!this->consistent) + this->calculateValues(); + return (this->x3max); +} + +void GbQuadFaceMesh3D::calculateValues() +{ + double x1, x2, x3; + + this->x1min = (*this->nodes)[0].x; + this->x1max = (*this->nodes)[0].x; + this->x2min = (*this->nodes)[0].y; + this->x2max = (*this->nodes)[0].y; + this->x3min = (*this->nodes)[0].z; + this->x3max = (*this->nodes)[0].z; + + for (int i = 1; i < (int)this->nodes->size(); i++) { + x1 = (*this->nodes)[i].x; + x2 = (*this->nodes)[i].y; + x3 = (*this->nodes)[i].z; + if (x1 < this->x1min) + this->x1min = x1; + if (x1 > this->x1max) + this->x1max = x1; + if (x2 < this->x2min) + this->x2min = x2; + if (x2 > this->x2max) + this->x2max = x2; + if (x3 < this->x3min) + this->x3min = x3; + if (x3 > this->x3max) + this->x3max = x3; + } + this->consistent = true; +} + +/*======================================================================*/ +vector<GbTriangle3D *> GbQuadFaceMesh3D::getSurfaceTriangleSet() +{ + vector<GbTriangle3D *> triangles(0); + return triangles; + // throw UbException(__FILE__, __LINE__, "GbQuadFaceMesh3D::getSurfaceTriangelSet - not implemented"); +} +// vector<GbQuad3D*> GbQuadFaceMesh3D::getSurfaceQuadSet() +//{ +// throw UbException(__FILE__, __LINE__, "GbQuadFaceMesh3D::getSurfaceQuadSet - not implemented"); +// //vector<GbQuadangle3D*> tris; +// //GbQuadangle3D* quad; +// //GbPoint3D* p1; +// //GbPoint3D* p2; +// //GbPoint3D* p3; +// //int size = (int)this->quads->size(); +// //for(int u=0; u<size;u++) +// //{ +// // quad = (*this->quads)[u]; +// // p1 = new GbPoint3D(quad->getPoint1()); +// // p2 = new GbPoint3D(quad->getPoint2()); +// // p3 = new GbPoint3D(quad->getPoint3()); +// // tris.push_back(new GbQuadangle3D(p1, p2, p3)); +// //} +// //return tris; +//} +/*======================================================================*/ +/* + * Function to determine if the point is inside the polyhedron defined as a 3D object + * using the Halfspace algorithm + * @param xp the x-coordinate of the point + * @param yp the y-coordinate of the point + * @param zp the z-coordinate of the point + * @return true if point is inside else return false + */ +bool GbQuadFaceMesh3D::isPointInObject3DHalfSpace(const double & /*xp*/, const double & /*yp*/, const double & /*zp*/) +{ + throw UbException(UB_EXARGS, "not implemented"); + // vector<GbQuadangle3D*> *Quadangles = this->quads; + // int Quadanglesize = (int)Quadangles->size(); + // GbPoint3D Point(xp,yp,zp); + // for (int i=0; i<Quadanglesize; i++) + //{ + // GbPoint3D* point1 = (*Quadangles)[i]->getPoint1(); + // GbPoint3D* point2 = (*Quadangles)[i]->getPoint2(); + // GbPoint3D* point3 = (*Quadangles)[i]->getPoint3(); + + // GbHalfSpace3D halfspace(point1, point2, point3); + // if (halfspace.ptInside(&Point)) return false; + //} + // return true; +} +/*======================================================================*/ +/*======================================================================*/ +bool GbQuadFaceMesh3D::isPointInGbObject3D(const double &x1, const double &x2, const double &x3) +{ + + double xmin = this->getX1Minimum(); + double xmax = this->getX1Maximum(); + double ymin = this->getX2Minimum(); + double ymax = this->getX2Maximum(); + double zmin = this->getX3Minimum(); + double zmax = this->getX3Maximum(); + double dX = (xmax - xmin) / 100.; + double dY = (ymax - ymin) / 100.; + double dZ = (zmax - zmin) / 100.; + GbCuboid3D boundingCube(xmin - dX, ymin - dY, zmin - dZ, xmax + dX, ymax + dY, zmax + dZ); + if (!boundingCube.isPointInGbObject3D(x1, x2, x3)) { + boundingCube.finalize(); + return false; + } + boundingCube.finalize(); + + // Halfspace algorithm, Area of spherical polygons algorithm or Ray crossing algorithm + GbVector3D bMin(boundingCube.getPoint1()); + GbVector3D bMax(boundingCube.getPoint2()); + bMin = bMax.Subtract(bMin); + // int radius = (int)bMin.Length(); + + // if(((GbQuadFaceMesh3D*)this->geoObject3D)->isPointInObject3DHalfSpace(x1,x2,x3) ) + // if(((GbQuadFaceMesh3D*)this->geoObject3D)->isPointInObject3Darea(x11,x12,x13,numQuadangles)) + // if(this->isPointInObject3DRayCrossing(x1,x2,x3,radius,(int)this->nodes->size(),(int)this->quads->size())) + // return true; + // else + return false; +} +/*======================================================================*/ +bool GbQuadFaceMesh3D::isPointInGbObject3D(const double & /*x1*/, const double & /*x2*/, const double & /*x3*/, + bool & /*pointIsOnBoundary*/) +{ + throw UbException(UB_EXARGS, "not implemented"); +} +/*======================================================================*/ +GbLine3D *GbQuadFaceMesh3D::createClippedLine3D(GbPoint3D & /*point1*/, GbPoint3D & /*point2*/) +{ + throw UbException(UB_EXARGS, "not implemented"); +} diff --git a/src/basics/geometry3d/GbQuadFaceMesh3D.h b/src/basics/geometry3d/GbQuadFaceMesh3D.h new file mode 100644 index 0000000000000000000000000000000000000000..2671488303695158dcaa618a4ffa9c101bb5e1c3 --- /dev/null +++ b/src/basics/geometry3d/GbQuadFaceMesh3D.h @@ -0,0 +1,150 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file GbQuadFaceMesh3D.h +//! \ingroup geometry3D +//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller +//======================================================================================= +#ifndef GBQUADFACEMESH3D_H +#define GBQUADFACEMESH3D_H + +#include <iostream> +#include <sstream> + +#include <basics/utilities/UbException.h> +#include <geometry3d/GbObject3D.h> + +#include <PointerDefinitions.h> + +class UbFileOutput; +class UbFileInput; +/*=========================================================================*/ +/* GbQuadFaceMesh3D */ +/* */ +/** + * This Class provides the triangular meshes. + * Note, that up to now no methods for checking consistency are included. + * in this context this class describes facettes from an 3D-object !!! + */ +class GbQuadFaceMesh3D : public GbObject3D +{ +public: + // nested class start + class Vertex + { + public: + Vertex() = default; + Vertex(float x, float y, float z) + { + this->x = x; + this->y = y; + this->z = z; + } + float x, y, z; + }; + + class QuadFace + { + public: + QuadFace() = default; + QuadFace(int v1, int v2, int v3, int v4) + { + this->vertex1 = v1; + this->vertex2 = v2; + this->vertex3 = v3; + this->vertex4 = v4; + } + + int vertex1, vertex2, vertex3, vertex4; + }; + // nested class end + +public: + GbQuadFaceMesh3D(); + GbQuadFaceMesh3D(std::string name, std::vector<Vertex> *nodes, std::vector<QuadFace> *quads); + ~GbQuadFaceMesh3D() override; + GbQuadFaceMesh3D *clone() override { throw UbException(UB_EXARGS, "clone() - not implemented"); } + void finalize() override { throw UbException(UB_EXARGS, "finalize() - not implemented"); } + + std::string toString() override; + std::string getName() override; + std::vector<Vertex> *getNodes(); + std::vector<QuadFace> *getQuads(); + double getX1Centroid() override; + double getX2Centroid() override; + double getX3Centroid() override; + double getX1Minimum() override; + double getX1Maximum() override; + double getX2Minimum() override; + double getX2Maximum() override; + double getX3Minimum() override; + double getX3Maximum() override; + void calculateValues(); + + bool isPointInGbObject3D(const double &x1, const double &x2, const double &x3) override; + bool isPointInGbObject3D(const double &x1, const double &x2, const double &x3, bool &pointIsOnBoundary) override; + + bool isPointInObject3DHalfSpace(const double &xp, const double &yp, + const double &zp); // based on Halfspace algorithm + // bool isPointInObject3DSpherical(const double& xp, const double& yp, const double& zp, int numQuads); //based + // on Spherical polygon area method bool isPointInObject3DRayCrossing(const double& xp, const double& yp, const + // double& zp, int radius, int numVertices, int numQuads); //based on Ray tracing algorithm + + // char SegPlaneInt(GbQuad3D *quad, GbVector3D &PointQ, GbVector3D &PointR, GbVector3D &Point, int *m); + // char SegQuadCross(GbQuad3D *quad, GbVector3D &PointQ, GbVector3D &PointR); + // till here !!! + + GbLine3D *createClippedLine3D(GbPoint3D &point1, GbPoint3D &point2) override; + // virtual std::vector<GbQuad3D*> getSurfaceQuadSet(); + std::vector<GbTriangle3D *> getSurfaceTriangleSet() override; + + virtual void write(UbFileOutput * /*out*/) { std::cout << "GbQuadFaceMesh3D::write - sorry not implemented\n"; } + virtual void read(UbFileInput * /*in*/) { std::cout << "GbQuadFaceMesh3D::read - sorry not implemented\n"; } + + void writeAVSMesh(UbFileOutput *out, bool normals = false); + + /*======================================================================*/ + using GbObject3D::isPointInGbObject3D; // Grund: dadurch muss man hier isPointInGbObject3D(GbPoint3D*) nicht + // ausprogrammieren, welche sonst hier "ueberdeckt" waere +private: + void init(); + /*======================================================================*/ + std::string name; + std::vector<Vertex> *nodes; + std::vector<QuadFace> *quads; + double x1min; + double x1max; + double x2min; + double x2max; + double x3min; + double x3max; + bool consistent; +}; +/*=========================================================================*/ + +#endif diff --git a/src/basics/geometry3d/GbSphere3D.cpp b/src/basics/geometry3d/GbSphere3D.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2cb94c462c6e2c1b95e820fab06fe2d37325ecb1 --- /dev/null +++ b/src/basics/geometry3d/GbSphere3D.cpp @@ -0,0 +1,957 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file GbSphere3D.cpp +//! \ingroup geometry3D +//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller +//======================================================================================= +#include <geometry3d/GbLine3D.h> +#include <geometry3d/GbPoint3D.h> +#include <geometry3d/GbSphere3D.h> +#include <geometry3d/GbSystem3D.h> +#include <geometry3d/GbTriangle3D.h> + +using namespace std; + +/*=====================================================*/ +GbSphere3D::GbSphere3D() : GbObject3D(), UbObserver() +{ + this->setName("sphere"); + radius = 0; + midPoint = new GbPoint3D(0, 0, 0); +} +/*=====================================================*/ +GbSphere3D::GbSphere3D(const double &x1, const double &x2, const double &x3, const double &radius) + : GbObject3D(), UbObserver() +{ + this->setName("sphere"); + midPoint = new GbPoint3D(x1, x2, x3); + midPoint->addObserver(this); + + this->radius = radius; + triangulationMode = RAYPROJECTION; + // triangulationMode = CUBOIDPROJECTION; +} +/*=====================================================*/ +GbSphere3D::GbSphere3D(const GbSphere3D &sphere) : GbObject3D(sphere), UbObserver() +{ + this->setName("sphere"); + + this->midPoint = sphere.midPoint->clone(); + this->radius = sphere.radius; + triangulationMode = RAYPROJECTION; + + this->midPoint->addObserver(this); +} +/*=====================================================*/ +GbSphere3D::GbSphere3D(GbSphere3D *sphere) : GbObject3D(), UbObserver() +{ + this->setName(sphere->getName()); + midPoint = sphere->midPoint->clone(); + midPoint->addObserver(this); + + this->radius = sphere->getRadius(); + triangulationMode = RAYPROJECTION; +} +/*=====================================================*/ +GbSphere3D::~GbSphere3D() +{ + if (this->midPoint) + this->midPoint->removeObserver(this); +} +/*=====================================================*/ +void GbSphere3D::finalize() +{ + if (this->midPoint) { + this->midPoint->removeObserver(this); + this->midPoint->finalize(); + delete this->midPoint; + this->midPoint = NULL; + } + + if (this->midPoint) + this->midPoint->removeObserver(this); +} +/*=====================================================*/ +bool GbSphere3D::intersects(SPtr<GbSphere3D> sphere) +{ + return this->getDistance(sphere->midPoint) < radius + sphere->radius; +} +/*=======================================================*/ +void GbSphere3D::setCenterCoordinates(const double &x1, const double &x2, const double &x3) +{ + this->translate(x1 - getX1Centroid(), x2 - getX2Centroid(), x3 - getX3Centroid()); +} + +void GbSphere3D::setCenterCoordinates(const UbTupleDouble3 &position) +{ + this->setCenterCoordinates(val<1>(position), val<2>(position), val<3>(position)); +} + +/*=====================================================*/ +double GbSphere3D::getDistance(GbPoint3D *p) +{ + return this->getDistance(p->getX1Centroid(), p->getX2Coordinate(), p->getX3Coordinate()); +} +/*=====================================================*/ +void GbSphere3D::setCenterX1Coordinate(const double &value) +{ + if (this->midPoint) + this->midPoint->setX1(value); + else + throw UbException(UB_EXARGS, "Sphere has no midPoint"); + // kein notifyObserver(), da der knoten notifyObserver() ausfuehrt und die GbSphere dieses event + // abfaengt und dann selbst notifyObservers ausfuehrt ;-) +} +/*=====================================================*/ +void GbSphere3D::setCenterX2Coordinate(const double &value) +{ + if (this->midPoint) + this->midPoint->setX2(value); + else + throw UbException(UB_EXARGS, "Sphere has no midPoint"); + // kein notifyObserver(), da der knoten notifyObserver() ausfuehrt und die GbSphere dieses event + // abfaengt und dann selbst notifyObservers ausfuehrt ;-) +} +/*=====================================================*/ +void GbSphere3D::setCenterX3Coordinate(const double &value) +{ + if (this->midPoint) + this->midPoint->setX3(value); + else + throw UbException(UB_EXARGS, "sphere has no midPoint"); + // kein notifyObserver(), da der knoten notifyObserver() ausfuehrt und die GbSphere dieses event + // abfaengt und dann selbst notifyObservers ausfuehrt ;-) +} +/*=====================================================*/ +void GbSphere3D::setRadius(const double &radius) +{ + if (radius != this->radius) { + this->radius = radius; + this->notifyObserversObjectChanged(); + } +} +/*=====================================================*/ +double GbSphere3D::getDistance(const double &x1p, const double &x2p, const double &x3p) +{ + double deltaX1 = x1p - midPoint->getX1Coordinate(); + double deltaX2 = x2p - midPoint->getX2Coordinate(); + double deltaX3 = x3p - midPoint->getX3Coordinate(); + return sqrt(deltaX1 * deltaX1 + deltaX2 * deltaX2 + deltaX3 * deltaX3) - this->radius; +} +/*=====================================================*/ +// true, wenn 'in Object' oder 'auf Boundary'! +bool GbSphere3D::isPointInGbObject3D(const double &x1p, const double &x2p, const double &x3p) +{ + double deltaX1 = x1p - midPoint->getX1Coordinate(); + double deltaX2 = x2p - midPoint->getX2Coordinate(); + double deltaX3 = x3p - midPoint->getX3Coordinate(); + + return UbMath::lessEqual(deltaX1 * deltaX1 + deltaX2 * deltaX2 + deltaX3 * deltaX3, this->radius * this->radius); +} +/*=====================================================*/ +// true, wenn 'in Object' oder 'auf Boundary'! +bool GbSphere3D::isPointInGbObject3D(const double &x1p, const double &x2p, const double &x3p, bool &pointIsOnBoundary) +{ + double deltaX1 = x1p - midPoint->getX1Coordinate(); + double deltaX2 = x2p - midPoint->getX2Coordinate(); + double deltaX3 = x3p - midPoint->getX3Coordinate(); + + double distanceSquare = deltaX1 * deltaX1 + deltaX2 * deltaX2 + deltaX3 * deltaX3; + double radiusSquare = this->radius * this->radius; + + pointIsOnBoundary = UbMath::equal(distanceSquare, radiusSquare); + + return UbMath::lessEqual(distanceSquare, radiusSquare); +} +/*=====================================================*/ +// bool GbSphere3D::crossCellCrossSection(double x11,double x21,double x12,double x22, double ra) +//{ +// if(this->isPointInCrossection(x11, x12) || this->isPointInCrossection(x21, x22) || this->isPointInCrossection(x11, +// x22) || this->isPointInCrossection(x21, x12)) +// { +// if(!this->isPointInCrossection(x11, x12) || !this->isPointInCrossection(x21, x22) || +//!this->isPointInCrossection(x11, x22) || !this->isPointInCrossection(x21, x12)) return true; +// } +// return false; +//} +// +///*=====================================================*/ +// bool GbSphere3D::cellCrossAndInsideCrossSection(double x11,double x21,double x12,double x22, double ra) +//{ +// if(this->isPointInCrossection(x11, x12) || this->isPointInCrossection(x21, x22) || this->isPointInCrossection(x11, +// x22) || this->isPointInCrossection(x21, x12)) return true; return false; +//} +/*=====================================================*/ +string GbSphere3D::toString() +{ + stringstream ss; + ss << "GbSphere3D["; + ss << "mid=" << midPoint->toString() << ", r=" << radius << "]"; + return ss.str(); +} +/*=====================================================*/ +GbLine3D *GbSphere3D::createClippedLine3D(GbPoint3D &point1, GbPoint3D &point2) +{ + double factor = 100.0; // um rundungsfehler beim wurzelterm zu minimieren + double xa = factor * point1.getX1Coordinate(); + double ya = factor * point1.getX2Coordinate(); + double za = factor * point1.getX3Coordinate(); + double xb = factor * point2.getX1Coordinate(); + double yb = factor * point2.getX2Coordinate(); + double zb = factor * point2.getX3Coordinate(); + double xm = factor * this->midPoint->getX1Coordinate(); + double ym = factor * this->midPoint->getX2Coordinate(); + double zm = factor * this->midPoint->getX3Coordinate(); + double r = factor * this->radius; + + double xa2 = xa * xa; + double ya2 = ya * ya; + double za2 = za * za; + double xb2 = xb * xb; + double yb2 = yb * yb; + double zb2 = zb * zb; + double xm2 = xm * xm; + double ym2 = ym * ym; + double zm2 = zm * zm; + double r2 = r * r; + + double wurzel = + 2.0 * xa * xb * ym2 - 2.0 * ya * yb * r2 + 2.0 * ya * ym * xb2 + 2.0 * yb * ym * za2 + 2.0 * ya * ym * zb2 + + 2.0 * xb * xm * za2 + 2.0 * za * zb * ym2 + 2.0 * xb * xm * ya2 + 2.0 * xa * xm * yb2 + 2.0 * yb * ym * xa2 + + 2.0 * zb * zm * ya2 + 2.0 * xa * xm * zb2 + 2.0 * za * zm * xb2 + 2.0 * za * zm * yb2 + 2.0 * xa * xb * zm2 - + 2.0 * xa * xb * r2 - 2.0 * za * zb * r2 + 2.0 * za * zb * xm2 - 2.0 * ya * yb * xa * xm + + 2.0 * ya * yb * xa * xb + 2.0 * zb * zm * xa2 - 2.0 * ya * yb * xb * xm + 2.0 * ya * yb * xm2 - + 2.0 * ya * yb * zb * zm + 2.0 * ya * yb * zm2 + 2.0 * zb * zm * yb * ym - 2.0 * zb * zm * ya * ym + + 2.0 * zb * zm * xb * xm - 2.0 * xa * xm * yb * ym + 2.0 * xa * xm * za * zm + 2.0 * xa * xm * ya * ym - + 2.0 * yb * ym * za * zm + 2.0 * yb * ym * xb * xm + 2.0 * za * zm * ya * ym - 2.0 * za * zm * xb * xm - + 2.0 * ya * ym * xb * xm + 2.0 * za * zb * xa * xb - 2.0 * za * zb * xa * xm - 2.0 * za * zb * xb * xm + + 2.0 * za * zb * ya * yb - 2.0 * za * zb * ya * ym - 2.0 * za * zb * yb * ym - 2.0 * ya * yb * za * zm - + xa2 * zb2 - xa2 * yb2 - zb2 * ya2 - za2 * xb2 - za2 * yb2 - xb2 * ya2 - 2.0 * zb * zm * xa * xm - + 2.0 * xa * xb * za * zm - 2.0 * xa * xb * zb * zm - 2.0 * xa * xb * ya * ym - 2.0 * xa * xb * yb * ym + + za2 * r2 - za2 * xm2 - za2 * ym2 + zb2 * r2 - zb2 * xm2 - zb2 * ym2 + xa2 * r2 - xa2 * zm2 - xa2 * ym2 + + xb2 * r2 - xb2 * zm2 - xb2 * ym2 + ya2 * r2 - ya2 * zm2 - ya2 * xm2 + yb2 * r2 - yb2 * zm2 - yb2 * xm2; + double nenner = -2.0 * za * zb - 2.0 * ya * yb - 2.0 * xa * xb + za2 + zb2 + xa2 + xb2 + ya2 + yb2; + double zaehler = 2.0 * zb * zm - 2.0 * xa * xm + 2.0 * yb * ym - 2.0 * za * zm + xa2 - 2.0 * ya * ym + + 2.0 * xb * xm - zb2 + za2 - xb2 + ya2 - yb2; + + vector<GbPoint3D *> schnittpunkte; + + if (fabs(nenner) > 1.E-13 && UbMath::greaterEqual(wurzel, 0.0)) { + double t1 = (zaehler + 2.0 * sqrt(wurzel)) / nenner; + double t2 = (zaehler - 2.0 * sqrt(wurzel)) / nenner; + + if (UbMath::inClosedInterval(t1, -1.0, 1.0)) { + double x = (xa * (0.5 - 0.5 * t1) + xb * (0.5 + 0.5 * t1)) / factor; + double y = (ya * (0.5 - 0.5 * t1) + yb * (0.5 + 0.5 * t1)) / factor; + double z = (za * (0.5 - 0.5 * t1) + zb * (0.5 + 0.5 * t1)) / factor; + + schnittpunkte.push_back(new GbPoint3D(x, y, z)); + } + if (fabs(t2 - t1) > 1.E-13 && UbMath::inClosedInterval(t2, -1.0, 1.0)) { + double x = (xa * (0.5 - 0.5 * t2) + xb * (0.5 + 0.5 * t2)) / factor; + double y = (ya * (0.5 - 0.5 * t2) + yb * (0.5 + 0.5 * t2)) / factor; + double z = (za * (0.5 - 0.5 * t2) + zb * (0.5 + 0.5 * t2)) / factor; + + schnittpunkte.push_back(new GbPoint3D(x, y, z)); + } + } + + int nofSchnittpunkte = (int)schnittpunkte.size(); + if (nofSchnittpunkte == 1) { + if (this->isPointInGbObject3D(&point1)) + return new GbLine3D(schnittpunkte[0], new GbPoint3D(point1)); + else if (this->isPointInGbObject3D(&point2)) + return new GbLine3D(schnittpunkte[0], new GbPoint3D(point2)); + else // line beruehrt kugel! -> clippedLine reduziert sich zu einem Punkt! + { + if (std::fabs(this->getDistance(schnittpunkte[0]) - this->radius) < 1.E-13) + throw UbException(UB_EXARGS, "Beide LinenPunkte ausserhalb des Kreises, der berechnete Punkt ist " + "jedoch KEIN Beruhrungspunkt der Sphere..."); + return new GbLine3D(schnittpunkte[0], new GbPoint3D(*(schnittpunkte[0]))); + } + } else if (nofSchnittpunkte == 2) + return new GbLine3D(schnittpunkte[0], schnittpunkte[1]); + + return NULL; +} +/*=========================================================================*/ +vector<GbTriangle3D *> GbSphere3D::getSurfaceTriangleSet() +{ + if (triangulationMode == RAYPROJECTION) { + double x1m = midPoint->getX1Coordinate(); + double x2m = midPoint->getX2Coordinate(); + double x3m = midPoint->getX3Coordinate(); + + vector<GbTriangle3D *> triangles; + + int segments = 30; + double deltaPhi = UbMath::PI / (double)segments; + double phiX1a, phiX1b, phiX3a, phiX3b; + double x1a, x2a, x3a, x1b, x2b, x3b, x1c, x2c, x3c, x1d, x2d, x3d; + + for (phiX3a = 0.5 * UbMath::PI; phiX3a > -1.5 * UbMath::PI; phiX3a -= deltaPhi) { + for (phiX1a = 0.0; phiX1a < UbMath::PI; phiX1a += deltaPhi) { + phiX1b = phiX1a + deltaPhi; + phiX3b = phiX3a + deltaPhi; + + x1a = x1m + radius * cos(phiX3a) * std::cos(phiX1a); + x2a = x2m + radius * cos(phiX3a) * std::sin(phiX1a); + x3a = x3m + radius * sin(phiX3a); + x1b = x1m + radius * cos(phiX3a) * std::cos(phiX1b); + x2b = x2m + radius * cos(phiX3a) * std::sin(phiX1b); + x3b = x3m + radius * sin(phiX3a); + x1c = x1m + radius * cos(phiX3b) * std::cos(phiX1b); + x2c = x2m + radius * cos(phiX3b) * std::sin(phiX1b); + x3c = x3m + radius * sin(phiX3b); + x1d = x1m + radius * cos(phiX3b) * std::cos(phiX1a); + x2d = x2m + radius * cos(phiX3b) * std::sin(phiX1a); + x3d = x3m + radius * sin(phiX3b); + + if (UbMath::greater(phiX3b, -0.5 * UbMath::PI) && UbMath::less(phiX3a, 0.5 * UbMath::PI)) { + triangles.push_back(new GbTriangle3D(new GbPoint3D(x1a, x2a, x3a), new GbPoint3D(x1b, x2b, x3b), + new GbPoint3D(x1c, x2c, x3c))); + triangles.push_back(new GbTriangle3D(new GbPoint3D(x1a, x2a, x3a), new GbPoint3D(x1c, x2c, x3c), + new GbPoint3D(x1d, x2d, x3d))); + } else { + triangles.push_back(new GbTriangle3D(new GbPoint3D(x1d, x2d, x3d), new GbPoint3D(x1c, x2c, x3c), + new GbPoint3D(x1a, x2a, x3a))); + triangles.push_back(new GbTriangle3D(new GbPoint3D(x1c, x2c, x3c), new GbPoint3D(x1b, x2b, x3b), + new GbPoint3D(x1a, x2a, x3a))); + } + } + } + return triangles; + } else if (triangulationMode == CUBOIDPROJECTION) { + vector<GbTriangle3D *> triangles; + vector<GbPoint3D *> points; + double x1min = this->getX1Minimum(); + double x2min = this->getX2Minimum(); + double x3min = this->getX3Minimum(); + double x1max = this->getX1Maximum(); + double x2max = this->getX2Maximum(); + double x3max = this->getX3Maximum(); + double ax1 = x1min; + double bx2 = x2min; + double cx1 = x1min; + double ax2 = x2min; + double bx3 = x3min; + double cx3 = x3min; + + int anzahl = 20; + double dx1 = (x1max - x1min) / (double)(anzahl - 1); + double dx2 = (x2max - x2min) / (double)(anzahl - 1); + double dx3 = (x3max - x3min) / (double)(anzahl - 1); + + for (int u = 0; u < anzahl; u++) { + ax2 = x2min; + bx2 = x2min; + cx3 = x3min; + for (int v = 0; v < anzahl; v++) { + GbPoint3D p1 = GbPoint3D(ax1, ax2, x3max); + GbPoint3D p2 = GbPoint3D(ax1, ax2, x3min); + GbPoint3D p3 = GbPoint3D(cx1, x2min, cx3); + GbPoint3D p4 = GbPoint3D(cx1, x2max, cx3); + GbPoint3D p5 = GbPoint3D(x1min, bx2, bx3); + GbPoint3D p6 = GbPoint3D(x1max, bx2, bx3); + + GbLine3D *clippedline1 = this->createClippedLine3D(*this->midPoint, p1); + GbLine3D *clippedline2 = this->createClippedLine3D(*this->midPoint, p2); + GbLine3D *clippedline3 = this->createClippedLine3D(*this->midPoint, p3); + GbLine3D *clippedline4 = this->createClippedLine3D(*this->midPoint, p4); + GbLine3D *clippedline5 = this->createClippedLine3D(*this->midPoint, p5); + GbLine3D *clippedline6 = this->createClippedLine3D(*this->midPoint, p6); + points.push_back(new GbPoint3D(clippedline1->getPoint1())); + points.push_back(new GbPoint3D(clippedline2->getPoint1())); + points.push_back(new GbPoint3D(clippedline3->getPoint1())); + points.push_back(new GbPoint3D(clippedline4->getPoint1())); + points.push_back(new GbPoint3D(clippedline5->getPoint1())); + points.push_back(new GbPoint3D(clippedline6->getPoint1())); + clippedline1->deletePoints(); + delete clippedline1; + clippedline2->deletePoints(); + delete clippedline2; + clippedline3->deletePoints(); + delete clippedline3; + clippedline4->deletePoints(); + delete clippedline4; + clippedline5->deletePoints(); + delete clippedline5; + clippedline6->deletePoints(); + delete clippedline6; + ax2 += dx2; + cx3 += dx3; + bx2 += dx2; + } + ax1 += dx1; + cx1 += dx1; + bx3 += dx3; + } + + int anz = anzahl * anzahl * 6; + GbPoint3D *point1 = NULL; + GbPoint3D *point2 = NULL; + GbPoint3D *point3 = NULL; + int anzahl2 = anzahl * 6; + int anzahl3 = anzahl2 + 6; + for (int u = 0; u < anz - anzahl3; u++) { + point1 = new GbPoint3D(points[u + 6]); + point2 = new GbPoint3D(points[u]); + point3 = new GbPoint3D(points[u + anzahl2]); + if (u % 2 == 0) + triangles.push_back(new GbTriangle3D(point1, point2, point3)); + else + triangles.push_back(new GbTriangle3D(point2, point1, point3)); + + point1 = new GbPoint3D(points[u + 6]); + point2 = new GbPoint3D(points[u + anzahl2]); + point3 = new GbPoint3D(points[u + anzahl3]); + if (u % 2 == 0) + triangles.push_back(new GbTriangle3D(point1, point2, point3)); + else + triangles.push_back(new GbTriangle3D(point2, point1, point3)); + } + for (int u = 0; u < anz; u++) + delete points[u]; + + return triangles; + } else + throw UbException(UB_EXARGS, "undefined triangulationmode"); +} +/*=======================================================*/ +void GbSphere3D::addSurfaceTriangleSet(vector<UbTupleFloat3> &nodes, vector<UbTupleInt3> &triangles) +{ + // wenn ich viele Kugeln bei der PE rausschreibe sollten die vektoren nicht geresized werden + // nodes.resize(0); + // triangles.resize(0); + + if (triangulationMode == RAYPROJECTION) { + float x1m = (float)midPoint->getX1Coordinate(); + float x2m = (float)midPoint->getX2Coordinate(); + float x3m = (float)midPoint->getX3Coordinate(); + + int segments = 30; + float deltaPhi = (float)UbMath::PI / (float)segments; + float phiX1a, phiX1b, phiX3a, phiX3b; + float x1a, x2a, x3a, x1b, x2b, x3b, x1c, x2c, x3c, x1d, x2d, x3d; + int nodeNr = int(nodes.size()); + for (phiX3a = (float)(0.5 * UbMath::PI); phiX3a > (float)(-1.5 * UbMath::PI); phiX3a -= deltaPhi) { + for (phiX1a = 0.0; phiX1a < UbMath::PI; phiX1a += deltaPhi) { + phiX1b = phiX1a + deltaPhi; + phiX3b = phiX3a + deltaPhi; + + x1a = x1m + (float)(radius * cos(phiX3a) * std::cos(phiX1a)); + x2a = x2m + (float)(radius * cos(phiX3a) * std::sin(phiX1a)); + x3a = x3m + (float)(radius * sin(phiX3a)); + x1b = x1m + (float)(radius * cos(phiX3a) * std::cos(phiX1b)); + x2b = x2m + (float)(radius * cos(phiX3a) * std::sin(phiX1b)); + x3b = x3m + (float)(radius * sin(phiX3a)); + x1c = x1m + (float)(radius * cos(phiX3b) * std::cos(phiX1b)); + x2c = x2m + (float)(radius * cos(phiX3b) * std::sin(phiX1b)); + x3c = x3m + (float)(radius * sin(phiX3b)); + x1d = x1m + (float)(radius * cos(phiX3b) * std::cos(phiX1a)); + x2d = x2m + (float)(radius * cos(phiX3b) * std::sin(phiX1a)); + x3d = x3m + (float)(radius * sin(phiX3b)); + + if (UbMath::greater(phiX3b, -0.5 * UbMath::PI) && UbMath::less(phiX3a, 0.5 * UbMath::PI)) { + nodes.push_back(makeUbTuple(x1a, x2a, x3a)); + nodes.push_back(makeUbTuple(x1b, x2b, x3b)); + nodes.push_back(makeUbTuple(x1c, x2c, x3c)); + + nodes.push_back(makeUbTuple(x1a, x2a, x3a)); + nodes.push_back(makeUbTuple(x1c, x2c, x3c)); + nodes.push_back(makeUbTuple(x1d, x2d, x3d)); + } else { + nodes.push_back(makeUbTuple(x1d, x2d, x3d)); + nodes.push_back(makeUbTuple(x1c, x2c, x3c)); + nodes.push_back(makeUbTuple(x1a, x2a, x3a)); + + nodes.push_back(makeUbTuple(x1c, x2c, x3c)); + nodes.push_back(makeUbTuple(x1b, x2b, x3b)); + nodes.push_back(makeUbTuple(x1a, x2a, x3a)); + } + triangles.push_back(makeUbTuple(nodeNr, nodeNr + 1, nodeNr + 2)); + triangles.push_back(makeUbTuple(nodeNr + 3, nodeNr + 4, nodeNr + 5)); + nodeNr += 6; + } + } + } else if (triangulationMode == CUBOIDPROJECTION) { + vector<GbPoint3D *> points; + double x1min = this->getX1Minimum(); + double x2min = this->getX2Minimum(); + double x3min = this->getX3Minimum(); + double x1max = this->getX1Maximum(); + double x2max = this->getX2Maximum(); + double x3max = this->getX3Maximum(); + double ax1 = x1min; + double bx2 = x2min; + double cx1 = x1min; + double ax2 = x2min; + double bx3 = x3min; + double cx3 = x3min; + + int anzahl = 20; + double dx1 = (x1max - x1min) / (double)(anzahl - 1); + double dx2 = (x2max - x2min) / (double)(anzahl - 1); + double dx3 = (x3max - x3min) / (double)(anzahl - 1); + + for (int u = 0; u < anzahl; u++) { + ax2 = x2min; + bx2 = x2min; + cx3 = x3min; + for (int v = 0; v < anzahl; v++) { + GbPoint3D p1 = GbPoint3D(ax1, ax2, x3max); + GbPoint3D p2 = GbPoint3D(ax1, ax2, x3min); + GbPoint3D p3 = GbPoint3D(cx1, x2min, cx3); + GbPoint3D p4 = GbPoint3D(cx1, x2max, cx3); + GbPoint3D p5 = GbPoint3D(x1min, bx2, bx3); + GbPoint3D p6 = GbPoint3D(x1max, bx2, bx3); + + GbLine3D *clippedline1 = this->createClippedLine3D(*this->midPoint, p1); + GbLine3D *clippedline2 = this->createClippedLine3D(*this->midPoint, p2); + GbLine3D *clippedline3 = this->createClippedLine3D(*this->midPoint, p3); + GbLine3D *clippedline4 = this->createClippedLine3D(*this->midPoint, p4); + GbLine3D *clippedline5 = this->createClippedLine3D(*this->midPoint, p5); + GbLine3D *clippedline6 = this->createClippedLine3D(*this->midPoint, p6); + points.push_back(new GbPoint3D(clippedline1->getPoint1())); + points.push_back(new GbPoint3D(clippedline2->getPoint1())); + points.push_back(new GbPoint3D(clippedline3->getPoint1())); + points.push_back(new GbPoint3D(clippedline4->getPoint1())); + points.push_back(new GbPoint3D(clippedline5->getPoint1())); + points.push_back(new GbPoint3D(clippedline6->getPoint1())); + clippedline1->deletePoints(); + delete clippedline1; + clippedline2->deletePoints(); + delete clippedline2; + clippedline3->deletePoints(); + delete clippedline3; + clippedline4->deletePoints(); + delete clippedline4; + clippedline5->deletePoints(); + delete clippedline5; + clippedline6->deletePoints(); + delete clippedline6; + ax2 += dx2; + cx3 += dx3; + bx2 += dx2; + } + ax1 += dx1; + cx1 += dx1; + bx3 += dx3; + } + + int anz = anzahl * anzahl * 6; + int anzahl2 = anzahl * 6; + int anzahl3 = anzahl2 + 6; + int nodeNr = 0; + for (int u = 0; u < anz - anzahl3; u++) { + nodes.push_back(makeUbTuple((float)points[u + 6]->x1, (float)points[u + 6]->x2, (float)points[u + 6]->x3)); + nodes.push_back(makeUbTuple((float)points[u]->x1, (float)points[u]->x2, (float)points[u]->x3)); + nodes.push_back(makeUbTuple((float)points[u + anzahl2]->x1, (float)points[u + anzahl2]->x2, + (float)points[u + anzahl2]->x3)); + + if (u % 2 == 0) + triangles.push_back(makeUbTuple(nodeNr, nodeNr + 1, nodeNr + 2)); + else + triangles.push_back(makeUbTuple(nodeNr, nodeNr + 1, nodeNr + 2)); + + nodes.push_back(makeUbTuple((float)points[u + 6]->x1, (float)points[u + 6]->x2, (float)points[u + 6]->x3)); + nodes.push_back(makeUbTuple((float)points[u + anzahl2]->x1, (float)points[u + anzahl2]->x2, + (float)points[u + anzahl2]->x3)); + nodes.push_back(makeUbTuple((float)points[u + anzahl3]->x1, (float)points[u + anzahl3]->x2, + (float)points[u + anzahl3]->x3)); + if (u % 2 == 0) + triangles.push_back(makeUbTuple(nodeNr + 3, nodeNr + 4, nodeNr + 5)); + else + triangles.push_back(makeUbTuple(nodeNr + 3, nodeNr + 4, nodeNr + 5)); + + nodeNr += 6; + } + for (int u = 0; u < anz; u++) + delete points[u]; + } else + throw UbException(UB_EXARGS, "undefined triangulationmode"); +} +/*=======================================================*/ +void GbSphere3D::transform(const double matrix[4][4]) +{ + midPoint->transform(matrix); + this->setRadius(this->getRadius() * matrix[0][0]); + this->notifyObserversObjectChanged(); +} +/*=======================================================*/ +bool GbSphere3D::hasIntersectionWithDirectedLine(GbPoint3D origin, GbPoint3D direction) +{ + GbVector3D vecOrigin(origin.getX1Coordinate(), origin.getX2Coordinate(), origin.getX3Coordinate()); + GbVector3D vecDirection(direction.getX1Coordinate(), direction.getX2Coordinate(), direction.getX3Coordinate()); + GbVector3D vecSfereCenter(getX1Centroid(), getX2Centroid(), getX3Centroid()); + GbVector3D diff = vecOrigin - vecSfereCenter; + float a = (float)(vecDirection.Dot(vecDirection)); + float b = (float)(2.0 * vecDirection.Dot(diff)); + float c = (float)(diff.Dot(diff) - this->getRadius() * this->getRadius()); + + // use 'abc'-formula for finding root t_1,2 = (-b +/- sqrt(b^2-4ac))/(2a) + float inRoot = (float)(b * b - 4.0 * a * c); + if (inRoot < 0) + return false; + float root = sqrt(inRoot); + + float dist = (float)((-b - root) / (2.0 * a)); + + double infinity = DBL_MAX; + double eps = 1E-4; + + if (dist > infinity) + return false; + + if (dist < eps) { + dist = (float)((-b + root) / (2.0 * a)); + if (dist < eps || dist > infinity) + return false; + } + return true; +} +/*=======================================================*/ +bool GbSphere3D::isCellCuttingGbObject3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b, + const double &x2b, const double &x3b) +// Merksatz: cell oder deren Volumen schneidet oder beinhaltet komplette oder Teile der SphereUmrandung +// returns true: +// - cell cuts sphere3D +// - cell boxes sphere3D +// returns false: +// - cell completely inside sphere3D ( = sphere3D boxes cell) +// - cell und sphere3D haben kein gemeinsames Volumen +{ + double midX[] = { this->getX1Centroid(), this->getX2Centroid(), this->getX3Centroid() }; + + double Bmin[] = { UbMath::min(x1a, x1b), UbMath::min(x2a, x2b), UbMath::min(x3a, x3b) }; + + double Bmax[] = { UbMath::max(x1a, x1b), UbMath::max(x2a, x2b), UbMath::max(x3a, x3b) }; + + /* Solid Box - Hollow Sphere */ + double dmin = 0.0; + double dmax = 0.0; + double r2 = radius * radius; + + for (int i = 0; i < 3; i++) { + double a = pow(midX[i] - Bmin[i], 2.0); + double b = pow(midX[i] - Bmax[i], 2.0); + dmax += UbMath::max(a, b); + if (UbMath::less(midX[i], Bmin[i])) + dmin += a; + else if (UbMath::greater(midX[i], Bmax[i])) + dmin += b; + } + if (UbMath::lessEqual(dmin, r2) && UbMath::lessEqual(r2, dmax)) { + return true; + } + return false; +} +/*=======================================================*/ +bool GbSphere3D::isCellInsideOrCuttingGbObject3D(const double &x1a, const double &x2a, const double &x3a, + const double &x1b, const double &x2b, const double &x3b) +// returns true: +// - cell completely inside sphere3D ( = sphere3D boxes cell) +// - cell cuts sphere3D +// - cell boxes sphere3D +// returns false: +// - cell und sphere3D haben kein gemeinsames Volumen +{ + // URL: http://tog.acm.org/GraphicsGems/gems/BoxSphere.c (mode=4, beides solids!!!) + // solid - solid + // this routine tests for intersection between an 3-dimensional + // axis-aligned box and an 3-dimensional sphere. + + // true: + // - wenn Schnitt + // - Cell komplett innerhalb GbSphere3D + // - Cell umhuellt GbSphere3D + + double midX1 = this->getX1Centroid(); + double midX2 = this->getX2Centroid(); + double midX3 = this->getX3Centroid(); + + double dmin = 0.0; + + if (UbMath::less(midX1, x1a)) + dmin += std::pow(midX1 - x1a, 2.0); + else if (UbMath::greater(midX1, x1b)) + dmin += std::pow(midX1 - x1b, 2.0); + + if (UbMath::less(midX2, x2a)) + dmin += std::pow(midX2 - x2a, 2.0); + else if (UbMath::greater(midX2, x2b)) + dmin += std::pow(midX2 - x2b, 2.0); + + if (UbMath::less(midX3, x3a)) + dmin += std::pow(midX3 - x3a, 2.0); + else if (UbMath::greater(midX3, x3b)) + dmin += std::pow(midX3 - x3b, 2.0); + + if (UbMath::lessEqual(dmin, radius * radius)) { + return true; + } + + return false; +} +/*==========================================================*/ +double GbSphere3D::getCellVolumeInsideGbObject3D(const double &x1a, const double &x2a, const double &x3a, + const double &x1b, const double &x2b, const double &x3b) +{ + double deltaX1 = (x1b - x1a); + double deltaX2 = (x2b - x2a); + double deltaX3 = (x3b - x3a); + + if (this->isCellInsideGbObject3D(x1a, x2a, x3a, x1b, x2b, x3b)) + return 1.0 * deltaX1 * deltaX2 * deltaX3; + if (!(this->isCellCuttingGbObject3D(x1a, x2a, x3a, x1b, x2b, x3b))) + return 0.0; + + double tempResult = 0.0; + + int iMax = 10; + int jMax = 10; + int kMax = 10; + + for (int i = 0; i < iMax; i++) { + for (int j = 0; j < jMax; j++) { + for (int k = 0; k < kMax; k++) { + + tempResult += getCellVolumeInsideGbObject3DHelperFunction( + x1a + ((double)i) * deltaX1 / ((double)iMax), x2a + ((double)j) * deltaX2 / ((double)jMax), + x3a + ((double)k) * deltaX3 / ((double)kMax), x1a + ((double)(i + 1)) * deltaX1 / ((double)iMax), + x2a + ((double)(j + 1)) * deltaX2 / ((double)jMax), + x3a + ((double)(k + 1)) * deltaX3 / ((double)kMax)); + } + } + } + + // double resultWithOneCell = getCellVolumeInsideGbObject3DHelperFunction( x1a, x2a, x3a, x1b, x2b, x3b ); + // cout << tempResult << " vs. " << resultWithOneCell << endl; + + return tempResult; +} +/*==========================================================*/ +double GbSphere3D::getCellVolumeInsideGbObject3DHelperFunction(const double &x1a, const double &x2a, const double &x3a, + const double &x1b, const double &x2b, const double &x3b) +{ + + double deltaX1 = x1b - x1a; + double deltaX2 = x2b - x2a; + double deltaX3 = x3b - x3a; + + if (this->isCellInsideGbObject3D(x1a, x2a, x3a, x1b, x2b, x3b)) + return 1.0 * deltaX1 * deltaX2 * deltaX3; + if (!(this->isCellCuttingGbObject3D(x1a, x2a, x3a, x1b, x2b, x3b))) + return 0.0; + + double alpha = 0.0; + double internX1, internX2, internX3; + + for (int x1vers = 0; x1vers < 2; x1vers++) { + for (int x2vers = 0; x2vers < 2; x2vers++) { + for (int x3vers = 0; x3vers < 2; x3vers++) { + internX1 = x1a + (x1b - x1a) * x1vers; + internX2 = x2a + (x2b - x2a) * x2vers; + internX3 = x3a + (x3b - x3a) * x3vers; + + if (UbMath::lessEqual(this->getDistance(internX1, internX2, internX3), alpha)) + alpha = this->getDistance(internX1, internX2, internX3); + // cout<<zelltyp<<" "<<kugel->getDistance(internX1,internX2,internX3)<<" "<<alpha<<endl; + } // end first for + } // end second for + } // end third for + + alpha = (-1) * alpha; + + double n[3]; + n[0] = 0.5 * (x1b + x1a) - this->getX1Centroid(); + n[1] = 0.5 * (x2b + x2a) - this->getX2Centroid(); + n[2] = 0.5 * (x3b + x3a) - this->getX3Centroid(); + + // cout << "Koordinaten: "<<x1<<" "<<x2<<" "<<x3<<endl; + // cout << "Deltas: "<<deltaX1<<" "<<deltaX2<<" "<<deltaX3<<endl; + // cout << "Halbe Zelle: "<<halfcelldelta<<endl; + + // cout<<"Centroid: "<<kugel->getX1Centroid()<<" "<<kugel->getX2Centroid()<<" "<<kugel->getX3Centroid()<<endl; + + // cout<<"Normals: "<<n[0]<<" "<<n[1]<<" "<<n[2]<<endl; + + double normLength; + normLength = sqrt(n[0] * n[0] + n[1] * n[1] + n[2] * n[2]); + n[0] /= normLength; + n[1] /= normLength; + n[2] /= normLength; + + if (UbMath::less(n[0], 0.0)) + n[0] = -n[0]; + if (UbMath::less(n[1], 0.0)) + n[1] = -n[1]; + if (UbMath::less(n[2], 0.0)) + n[2] = -n[2]; + + // cout<<"Normals: "<<n[0]<<" "<<n[1]<<" "<<n[2]<<endl; + + double dummy; + if (UbMath::greater(n[0], n[1])) { + dummy = n[1]; + n[1] = n[0]; + n[0] = dummy; + } + if (UbMath::greater(n[1], n[2])) { + dummy = n[2]; + n[2] = n[1]; + n[1] = dummy; + } + if (UbMath::greater(n[0], n[1])) { + dummy = n[1]; + n[1] = n[0]; + n[0] = dummy; + } + + // cout<<"Normals: "<<n[0]<<" "<<n[1]<<" "<<n[2]<<endl; + + double n1, n2, n3; + n1 = n[0]; + n2 = n[1]; + n3 = n[2]; + + double maxVol = deltaX1 * deltaX2 * deltaX3; + + double result = 0.0, preresult = 0.0; + + if (UbMath::lessEqual(maxVol, 0.000001)) + return 0.0; + + // 1D Check + if (UbMath::lessEqual(n1, 0.001) && UbMath::lessEqual(n2, 0.001)) { + result = alpha * deltaX1 * deltaX2; + } + // 2D Check + else if (UbMath::lessEqual(n1, 0.001)) { + preresult = (2 * n2 * n3); + result = (alpha * alpha) / preresult; + + if (UbMath::greater(alpha, n2 * deltaX2)) { + result += -(alpha - n2 * deltaX2) * (alpha - n2 * deltaX2) / preresult; + } + if (UbMath::greater(alpha, n3 * deltaX3)) { + result += -(alpha - n3 * deltaX3) * (alpha - n3 * deltaX3) / preresult; + } + if (UbMath::greater(alpha, n2 * deltaX2 + n3 * deltaX3)) { + result += (alpha - n2 * deltaX2 - n3 * deltaX3) * (alpha - n2 * deltaX2 - n3 * deltaX3) / preresult; + } + + // tiefenrichtung mit einmultiplizieren... + result *= deltaX1; + } + // 3D Check + else { + preresult = 6 * n1 * n2 * n3; + + result = alpha * alpha * alpha; + + if (UbMath::greaterEqual(alpha, n1 * deltaX1)) { + result += -((alpha - n1 * deltaX1) * (alpha - n1 * deltaX1) * (alpha - n1 * deltaX1)); + } + if (UbMath::greaterEqual(alpha, n2 * deltaX2)) { + result += -((alpha - n2 * deltaX2) * (alpha - n2 * deltaX2) * (alpha - n2 * deltaX2)); + } + if (UbMath::greaterEqual(alpha, n3 * deltaX3)) { + result += -((alpha - n3 * deltaX3) * (alpha - n3 * deltaX3) * (alpha - n3 * deltaX3)); + } + if (UbMath::greaterEqual(alpha, (n1 * deltaX1 + n2 * deltaX2))) { + result += ((alpha - (n1 * deltaX1 + n2 * deltaX2)) * (alpha - (n1 * deltaX1 + n2 * deltaX2)) * + (alpha - (n1 * deltaX1 + n2 * deltaX2))); + } + if (UbMath::greaterEqual(alpha, (n1 * deltaX1 + n3 * deltaX3))) { + result += ((alpha - (n1 * deltaX1 + n3 * deltaX3)) * (alpha - (n1 * deltaX1 + n3 * deltaX3)) * + (alpha - (n1 * deltaX1 + n3 * deltaX3))); + } + if (UbMath::greaterEqual(alpha, (n2 * deltaX2 + n3 * deltaX3))) { + result += ((alpha - (n2 * deltaX2 + n3 * deltaX3)) * (alpha - (n2 * deltaX2 + n3 * deltaX3)) * + (alpha - (n2 * deltaX2 + n3 * deltaX3))); + } + + // NEW + if (UbMath::greaterEqual(alpha, (n1 * deltaX1 + n2 * deltaX2 + n3 * deltaX3))) { + result += -((alpha - (n1 * deltaX1 + n2 * deltaX2 + n3 * deltaX3)) * + (alpha - (n1 * deltaX1 + n2 * deltaX2 + n3 * deltaX3)) * + (alpha - (n1 * deltaX1 + n2 * deltaX2 + n3 * deltaX3))); + } + + result = result / preresult; + } + return (result); + + // cout << "alpha ist " << alpha << endl; + // cout << "fillLevel ist " << eps << endl; +} +/*==========================================================*/ +double GbSphere3D::getIntersectionRaytraceFactor(const double &x1, const double &x2, const double &x3, + const double &rx1, const double &rx2, const double &rx3) +{ + double lx1 = midPoint->x1 - x1; + double lx2 = midPoint->x2 - x2; + double lx3 = midPoint->x3 - x3; + double l_sq = lx1 * lx1 + lx2 * lx2 + lx3 * lx3; // l = abstand Punkt(x1,x2,x3)<->kreismittelpunkt + + double s = lx1 * rx1 + lx2 * rx2 + lx3 * rx3; // s= l*ray_dir) + double r_sq = this->radius * this->radius; // r� =r*r + // if (d<0 (fuer die Richtung falls sie gegen das Kreis dann haben wir ein negativer Zahl) + // && l� > r� (point outside )) + // wenn s<0->Punkt liegt rechts vom mittelpunkt, wenn nun punkt ausserhalb des kreises liegt, kann es keinen SP mehr + // geben + if (s < -1.E-10 && l_sq > r_sq + 1.E-10) + return -1.0; + // Pythagor on Triangle Rectangle (point, center of the cercle, intersection of the direction on point and m) + // l� = m� + d� + double m_sq = l_sq - s * s; + // if (m� > r� (dann gibt es kein schnittpunt zwischen direction und circle)) + if (m_sq > r_sq + 1.E-10) + return -1.0; + // Pythagoras on Triangle Rectangle in cercle (direction , m, r) + // r� = m� + h� + + // patch: rundungsfehler bei kleinen delta!!! + //-> wenn wurzel minimal null-> + double wurzelTerm = r_sq - m_sq; + if (wurzelTerm < 0.0) { + if (wurzelTerm < -1E-10) + return -1.0; // definitiv kein SP + else + return s; // im rundungsfehler-bereich. SP liegt dierkt auf sphere umrandung + } + + // if point outside of the circle + if (l_sq > r_sq) + return s - sqrt(wurzelTerm); + + return s + sqrt(wurzelTerm); +} +/*=======================================================*/ diff --git a/src/basics/geometry3d/GbSphere3D.h b/src/basics/geometry3d/GbSphere3D.h new file mode 100644 index 0000000000000000000000000000000000000000..2ffef25dbfa7e0732ddd3e24b158d7046a7b11b6 --- /dev/null +++ b/src/basics/geometry3d/GbSphere3D.h @@ -0,0 +1,172 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file GbSphere3D.h +//! \ingroup geometry3D +//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller +//======================================================================================= +#ifndef GBSPHERE3D_H +#define GBSPHERE3D_H + +#ifdef CAB_CTL +#include <ctl.h> +#endif // CAB_CTL + +#include <cmath> +#include <vector> + +#include <basics/utilities/UbObserver.h> + +#include <geometry3d/GbObject3D.h> +#include <geometry3d/GbPoint3D.h> + +#include <PointerDefinitions.h> + +class GbLine3D; +class GbTriangle3D; +class GbObject3DCreator; + +class GbSphere3D : public GbObject3D, public UbObserver +{ +public: + enum TRIANGULATIONMODE { CUBOIDPROJECTION, RAYPROJECTION }; + + ////////////////////////////////////////////////////////////////////////// + // Konstruktoren + GbSphere3D(); + GbSphere3D(const double &x1, const double &x2, const double &x3, const double &radius); + GbSphere3D(const GbSphere3D &sphere); + GbSphere3D(GbSphere3D *sphere); //<-unschoen! + + ~GbSphere3D() override; + + GbSphere3D *clone() override { return new GbSphere3D(*this); } + void finalize() override; + + bool intersects(SPtr<GbSphere3D> sphere); + + double getRadius() const { return this->radius; } + + double getX1Centroid() override { return midPoint->getX1Coordinate(); } + double getX1Minimum() override { return midPoint->getX1Coordinate() - radius; } + double getX1Maximum() override { return midPoint->getX1Coordinate() + radius; } + double getX2Centroid() override { return midPoint->getX2Coordinate(); } + double getX2Minimum() override { return midPoint->getX2Coordinate() - radius; } + double getX2Maximum() override { return midPoint->getX2Coordinate() + radius; } + double getX3Centroid() override { return midPoint->getX3Coordinate(); } + double getX3Minimum() override { return midPoint->getX3Coordinate() - radius; } + double getX3Maximum() override { return midPoint->getX3Coordinate() + radius; } + + void setCenterX1Coordinate(const double &value) override; + void setCenterX2Coordinate(const double &value) override; + void setCenterX3Coordinate(const double &value) override; + void setCenterCoordinates(const double &x1, const double &x2, const double &x3) override; + void setCenterCoordinates(const UbTupleDouble3 &position) override; + void setRadius(const double &radius); + + GbLine3D *createClippedLine3D(GbPoint3D &point1, GbPoint3D &point2) override; + double getDistance(GbPoint3D *p); + double getDistance(const double &x1p, const double &x2p, const double &x3p); + + bool isPointInGbObject3D(const double &x1, const double &x2, const double &x3) override; + bool isPointInGbObject3D(const double &x1p, const double &x2p, const double &x3p, bool &pointIsOnBoundary) override; + + bool isCellCuttingGbObject3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b, + const double &x2b, const double &x3b) override; + bool isCellInsideOrCuttingGbObject3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b, + const double &x2b, const double &x3b) override; + double getCellVolumeInsideGbObject3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b, + const double &x2b, const double &x3b) override; + double getCellVolumeInsideGbObject3DHelperFunction(const double &x1a, const double &x2a, const double &x3a, + const double &x1b, const double &x2b, const double &x3b); + + std::vector<GbTriangle3D *> getSurfaceTriangleSet() override; + void addSurfaceTriangleSet(std::vector<UbTupleFloat3> &nodes, std::vector<UbTupleInt3> &triangles) override; + + bool hasRaytracing() override { return true; } + /*|r| must be 1! einheitsvector!!*/ + double getIntersectionRaytraceFactor(const double &x1, const double &x2, const double &x3, const double &rx1, + const double &rx2, const double &rx3) override; + + bool hasIntersectionWithDirectedLine(GbPoint3D origin, GbPoint3D direction); + + std::string toString() override; + + void translate(const double &x1, const double &x2, const double &x3) override + { + this->midPoint->translate(x1, x2, x3); + this->notifyObserversObjectChanged(); + } + void rotate(const double &rx1, const double &rx2, const double &rx3) override + { /* rotation makes no sense*/ + } + void scale(const double &sx1, const double & /*sx2*/, const double & /*sx3*/) override + { + this->radius *= sx1; + this->notifyObserversObjectChanged(); + } + + void transform(const double matrix[4][4]); + + TRIANGULATIONMODE getTriangulationMode() { return triangulationMode; } + void setTriangulationMode(TRIANGULATIONMODE mode) { this->triangulationMode = mode; } + + // virtuelle Methoden von UbObserver + void objectChanged(UbObservable * /*changedObject*/) override + { + this->notifyObserversObjectChanged(); + // std::cout<<"GbSphere:objectChanged() - toDo-);"; + } + void objectWillBeDeleted(UbObservable * /*objectForDeletion*/) override + { + throw UbException(UB_EXARGS, "not implemented"); + } + + using GbObject3D::isPointInGbObject3D; // Grund: dadurch muss man hier isPointInGbObject3D(GbPoint3D*) nicht + // ausprogrammieren, welche sonst hier "ueberdeckt" waere, weil man eine + +#ifdef CAB_CTL + ctl::oStream &write(ctl::oStream &os) const + { + midPoint->write(os); + return os << radius; + } + ctl::iStream &read(ctl::iStream &is) + { + midPoint->read(is); + return is >> radius; + } +#endif // CAB_CTL + +private: + GbPoint3D *midPoint; + double radius; // Radius des Kreises + TRIANGULATIONMODE triangulationMode; +}; + +#endif // GBSPHERE3D_H diff --git a/src/basics/geometry3d/GbTriFaceMesh3D.cpp b/src/basics/geometry3d/GbTriFaceMesh3D.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7da89fc9bf0565ec7862939ffa652b3ff1880a4f --- /dev/null +++ b/src/basics/geometry3d/GbTriFaceMesh3D.cpp @@ -0,0 +1,1170 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file GbTriFaceMesh3D.cpp +//! \ingroup geometry3D +//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller +//======================================================================================= +#include <geometry3d/GbTriFaceMesh3D.h> + +#include <basics/utilities/UbFileInputASCII.h> +#include <basics/utilities/UbLogger.h> +#include <basics/utilities/UbRandom.h> +#include <basics/utilities/UbTiming.h> +#include <basics/writer/WbWriter.h> +#include <geometry3d/CoordinateTransformation3D.h> +#include <geometry3d/GbCuboid3D.h> +#include <geometry3d/GbHalfSpace3D.h> + +#include <geometry3d/KdTree/KdTree.h> +#include <geometry3d/KdTree/intersectionhandler/KdCountLineIntersectionHandler.h> +#include <geometry3d/KdTree/intersectionhandler/KdCountRayIntersectionHandler.h> +#include <geometry3d/KdTree/splitalgorithms/KdSAHSplit.h> +#include <geometry3d/KdTree/splitalgorithms/KdSpatiallMedianSplit.h> + +#define MAX_ITER 10 + +using namespace std; + +GbTriFaceMesh3D::GbTriFaceMesh3D() : GbObject3D() +{ + this->setName("CAB_GbTriFaceMesh3D"); + this->nodes = new vector<Vertex>; + this->triangles = new vector<TriFace>; + this->consistent = false; + this->kdtreeSplitAlg = KDTREE_SAHPLIT; +} +/*=======================================================================*/ +GbTriFaceMesh3D::GbTriFaceMesh3D(string name, vector<Vertex> *nodes, vector<TriFace> *triangles, + KDTREE_SPLITAGORITHM splitAlg, bool removeRedundantNodes) + : GbObject3D(), nodes(nodes), triangles(triangles), kdtreeSplitAlg(splitAlg) +{ + if (name.empty()) + throw UbException(UB_EXARGS, "no name specified"); + if (!nodes) + throw UbException(UB_EXARGS, "no nodes specified"); + if (!triangles) + throw UbException(UB_EXARGS, "no triangles specified"); + + this->setName(name); + + if (removeRedundantNodes) { + this->deleteRedundantNodes(); // dort wird autoamtisch calculateValues() aufgerufen + } else { + this->calculateValues(); + } +} +/*=======================================================================*/ +GbTriFaceMesh3D::~GbTriFaceMesh3D() +{ + if (nodes) { + delete nodes; + nodes = NULL; + } + if (triangles) { + delete triangles; + triangles = NULL; + } + if (kdTree) { + delete kdTree; + kdTree = NULL; + } +} +/*======================================================================*/ +void GbTriFaceMesh3D::init() +{ + //nodes = NULL; + //triangles = NULL; + x1min = 0.0; + x1max = 0.0; + x1center = 0.0; + x2min = 0.0; + x2max = 0.0; + x2center = 0.0; + x3min = 0.0; + x3max = 0.0; + x3center = 0.0; + consistent = false; +} +/*======================================================================*/ +GbTriFaceMesh3D *GbTriFaceMesh3D::clone() +{ + vector<GbTriFaceMesh3D::Vertex> *newNodes = new vector<GbTriFaceMesh3D::Vertex>; + vector<GbTriFaceMesh3D::TriFace> *newTriangles = new vector<GbTriFaceMesh3D::TriFace>; + + int numberNodes = (int)this->nodes->size(); + + double x, y, z; + for (int u = 0; u < numberNodes; u++) { + x = (*nodes)[u].x; + y = (*nodes)[u].y; + z = (*nodes)[u].z; + newNodes->push_back(GbTriFaceMesh3D::Vertex((float)x, (float)y, (float)z)); + } + int numberTris = (int)this->triangles->size(); + UBLOG(logDEBUG1, "numberTris:" << numberTris); + + int id1, id2, id3; + for (int u = 0; u < numberTris; u++) { + id1 = (*this->triangles)[u].v1; + id2 = (*this->triangles)[u].v2; + id3 = (*this->triangles)[u].v3; + newTriangles->push_back(GbTriFaceMesh3D::TriFace(id1, id2, id3)); + // cout<<u<<" - id1,id2,id3:"<<id1<<","<<id2<<","<<id3<<endl; + } + UBLOG(logDEBUG1, "Tris gelesen"); + + GbTriFaceMesh3D *mesh = new GbTriFaceMesh3D("no name", newNodes, newTriangles); + UBLOG(logDEBUG1, "mesh cloned ..."); + + return mesh; +} + +/*======================================================================*/ +// checks for doppelt nodes und fixed Dreicke die zweimal denselben Knoten haben +void GbTriFaceMesh3D::deleteRedundantNodes() +{ + UBLOG(logDEBUG1, + "GbTriFaceMesh3D::deleteRedundantNodes - Nodes before deleting redundant: " << this->nodes->size()); + + map<Vertex, size_t /*new vecIndex*/> vertexMap; + map<Vertex, size_t /*new vecIndex*/>::iterator pos; + map<Vertex, size_t /*new vecIndex*/>::iterator it; + + vector<TriFace> &tris = *this->triangles; + vector<Vertex> &oldNodes = *this->nodes; + vector<Vertex> newNodes; + + for (size_t t = 0; t < tris.size(); t++) { + if (t % 100 == 0) { + UBLOG(logDEBUG5, "GbTriFaceMesh3D::deleteRedundantNodes - tri: " << (t) << " von " << tris.size()); + } + TriFace &tri = tris[t]; + // Knoten bereits in neuem node vector? + for (int v = 0; v <= 2; v++) { + Vertex &vert = tri.getNode(v, oldNodes); + // pos=vertexMap.find( vert ); + // if( pos==vertexMap.end() ) + { + for (pos = vertexMap.begin(); pos != vertexMap.end(); pos++) { + Vertex rhs = pos->first; + // if(UbMath::inClosedInterval(vert.z,0.01999, 0.02001)) + if (fabs(vert.x - rhs.x) < 1.E-5 && fabs(vert.y - rhs.y) < 1.E-5 && fabs(vert.z - rhs.z) < 1.E-5) { + break; + } + } + } + if (pos != vertexMap.end()) + tri.setNode(v, (int)pos->second); + else { + newNodes.push_back(vert); + int index = (int)newNodes.size() - 1; + vertexMap[vert] = index; + tri.setNode(v, index); + } + } + } + + std::swap(*nodes, newNodes); + + UBLOG(logDEBUG1, "GbTriFaceMesh3D::deleteRedundantNodes - Nodes after deleting redundant:" << this->nodes->size()); + // + // Das geht irgendwie nicht ... + // + // UBLOG(logDEBUG1,"GbTriFaceMesh3D::deleteRedundantNodes - checking for double triangles !!!"); + // UBLOG(logDEBUG1,"GbTriFaceMesh3D::deleteRedundantNodes - Triangles before deleting redundant: + // "<<this->triangles->size()); vector<TriFace> newSingleTris; newSingleTris.reserve( this->triangles->size() ); + // for(size_t t=0; t<tris.size(); t++) + //{ + // Vertex& v1 = tris[t].getNode(0,*nodes); + // Vertex& v2 = tris[t].getNode(1,*nodes); + // Vertex& v3 = tris[t].getNode(2,*nodes); + + // if(UbMath::greater(std::fabs(v1.x), 0.0634) && UbMath::inClosedInterval(v1.z, 0.01999, 0.02001)) + // { + // UBLOG2(logINFO,std::cout, "V1:"<<v1.x<<" "<<v1.y<<" "<<v1.z); + // } + // if(UbMath::greater(std::fabs(v2.x), 0.0634) && UbMath::inClosedInterval(v2.z, 0.01999, 0.02001)) + // { + // UBLOG2(logINFO,std::cout, "V2:"<<v2.x<<" "<<v2.y<<" "<<v2.z); + // } + // if(UbMath::greater(std::fabs(v3.x), 0.0634) && UbMath::inClosedInterval(v3.z, 0.01999, 0.02001)) + // { + // UBLOG2(logINFO,std::cout, "V3:"<<v3.x<<" "<<v3.y<<" "<<v3.z); + // } + + // bool inList = false; + // for(size_t u=0; u<newSingleTris.size(); u++) + // { + // Vertex& vn1 = newSingleTris[t].getNode(0,*nodes); + // Vertex& vn2 = newSingleTris[t].getNode(1,*nodes); + // Vertex& vn3 = newSingleTris[t].getNode(2,*nodes); + + // if(v1==vn1 && v2==vn2 && v3==vn3) inList = true; + // else if(v1==vn1 && v2==vn3 && v3==vn2) inList = true; + // else if(v1==vn2 && v2==vn3 && v3==vn1) inList = true; + // else if(v1==vn2 && v2==vn1 && v3==vn3) inList = true; + // else if(v1==vn3 && v2==vn1 && v3==vn2) inList = true; + // else if(v1==vn3 && v2==vn2 && v3==vn1) inList = true; + // } + // if(!inList) newSingleTris.push_back(tris[t]); + // else + // UBLOG(logDEBUG1,"GbTriFaceMesh3D::deleteRedundantNodes - inList !!!!"); + + //} + // swap(tris,newSingleTris); + + // UBLOG(logDEBUG1,"GbTriFaceMesh3D::deleteRedundantNodes - Triangles after deleting + // redundant:"<<this->triangles->size()); + UBLOG(logDEBUG1, "GbTriFaceMesh3D::deleteRedundantNodes - checking for triangles that have same node several times " + "or are lines!!!"); + int counter1 = 0; + int counter2 = 0; + vector<TriFace> newTris; + newTris.reserve(this->triangles->size()); + for (size_t t = 0; t < tris.size(); t++) { + Vertex &v1 = tris[t].getNode(0, *nodes); + Vertex &v2 = tris[t].getNode(1, *nodes); + Vertex &v3 = tris[t].getNode(2, *nodes); + if (v1 == v2 || v1 == v3 || v2 == v3) { + counter1++; + } else if (tris[t].getArea(*nodes) < 1.0E-8) { + counter2++; + } else + newTris.push_back(tris[t]); + } + if (counter1) { + UBLOG(logDEBUG1, "GbTriFaceMesh3D::deleteRedundantNodes - ### Warning ###: found and removed " + << counter1 << " triangle with double nodes!"); + } + if (counter2) { + UBLOG(logDEBUG1, "GbTriFaceMesh3D::deleteRedundantNodes - ### Warning ###: found and removed " + << counter2 << " triangle that are lines!"); + } + if (!counter1 && !counter2) { + UBLOG(logDEBUG1, "GbTriFaceMesh3D::deleteRedundantNodes - alles gut... nix doppelt"); + } else + swap(tris, newTris); + + UBLOG(logDEBUG1, "GbTriFaceMesh3D::deleteRedundantNodes - done"); + this->calculateValues(); +} +/*======================================================================*/ +void GbTriFaceMesh3D::setKdTreeSplitAlgorithm(KDTREE_SPLITAGORITHM mode) +{ + if (kdTree && mode != this->kdtreeSplitAlg) { + delete kdTree; + kdTree = NULL; + } + this->kdtreeSplitAlg = mode; +} +/*======================================================================*/ +/** + * Returns a string representation of this triangular mesh. + * @return a string representation of this triangular mesh + */ +string GbTriFaceMesh3D::toString() +{ + stringstream ss; + ss << "GbTriFaceMesh3D["; + ss << (int)this->triangles->size() << "-Triangles, " << (int)this->nodes->size() << "-Nodes, " << endl; + ss << "]"; + return (ss.str()); +} +/** + * Returns the nodes of this triangular mesh. + * @return the nodes of this triangular mesh + */ +vector<GbTriFaceMesh3D::Vertex> *GbTriFaceMesh3D::getNodes() { return this->nodes; } +/** + * Returns the triangles of this triangular mesh. + * @return the triangles of this triangular mesh + */ +vector<GbTriFaceMesh3D::TriFace> *GbTriFaceMesh3D::getTriangles() { return this->triangles; } +/** + * Returns the center x1 coordinate of this triangular mesh. + * @return the center x1 coordinate of this triangular mesh + */ +double GbTriFaceMesh3D::getVolume() +{ + vector<Vertex> &vertices = *nodes; + vector<TriFace> &tris = *triangles; + + double x1, x2, x3, y1, y2, y3, z1, z2, z3, G3i; + // double rSP1 = 0.0;double rSP2 = 0.0;double rSP3 = 0.0; + double volume = 0.0; + for (size_t t = 0; t < tris.size(); t++) { + TriFace &triangle = tris[t]; + x1 = triangle.getV1x(vertices); + y1 = triangle.getV1y(vertices); + z1 = triangle.getV1z(vertices); + x2 = triangle.getV2x(vertices); + y2 = triangle.getV2y(vertices); + z2 = triangle.getV2z(vertices); + x3 = triangle.getV3x(vertices); + y3 = triangle.getV3y(vertices); + z3 = triangle.getV3z(vertices); + G3i = x1 * (y2 * z3 - z2 * y3) + y1 * (z2 * x3 - x2 * z3) + z1 * (x2 * y3 - y2 * x3); + volume = volume + G3i / 6.0; + } + return volume; +} +/*===============================================*/ +UbTupleDouble3 GbTriFaceMesh3D::calculateCenterOfGravity() +{ + vector<Vertex> &vertices = *nodes; + vector<TriFace> &tris = *triangles; + + double x1, x2, x3, y1, y2, y3, z1, z2, z3; + double G3i; + double rSP1 = 0.0, rSP2 = 0.0, rSP3 = 0.0, volume = 0.0; + + for (size_t t = 0; t < tris.size(); t++) { + TriFace &triangle = tris[t]; + x1 = triangle.getV1x(vertices); + y1 = triangle.getV1y(vertices); + z1 = triangle.getV1z(vertices); + x2 = triangle.getV2x(vertices); + y2 = triangle.getV2y(vertices); + z2 = triangle.getV2z(vertices); + x3 = triangle.getV3x(vertices); + y3 = triangle.getV3y(vertices); + z3 = triangle.getV3z(vertices); + G3i = x1 * (y2 * z3 - z2 * y3) + y1 * (z2 * x3 - x2 * z3) + z1 * (x2 * y3 - y2 * x3); + volume = volume + G3i / 6.0; + rSP1 = rSP1 + G3i * (x1 + x2 + x3); + rSP2 = rSP2 + G3i * (y1 + y2 + y3); + rSP3 = rSP3 + G3i * (z1 + z2 + z3); + } + rSP1 = rSP1 / (24.0 * volume); + rSP2 = rSP2 / (24.0 * volume); + rSP3 = rSP3 / (24.0 * volume); + + return { rSP1, rSP2, rSP3 }; +} +/*===============================================*/ +UbTupleDouble6 GbTriFaceMesh3D::calculateMomentOfInertia(double rhoP) +{ + vector<Vertex> &vertices = *nodes; + + double x1, x2, x3, y1, y2, y3, z1, z2, z3; + double G3i; + double xx, yy, zz, xy, yz, zx; + double rSP1 = 0.0; + double rSP2 = 0.0; + double rSP3 = 0.0; + double volume = 0.0; + double top11 = 0.0; + double top22 = 0.0; + double top33 = 0.0; + double top12 = 0.0; + double top23 = 0.0; + double top13 = 0.0; + int size = (int)this->triangles->size(); + for (int u = 0; u < size; u++) { + TriFace &triangle = (*this->triangles)[u]; + x1 = triangle.getV1x(vertices); + y1 = triangle.getV1y(vertices); + z1 = triangle.getV1z(vertices); + x2 = triangle.getV2x(vertices); + y2 = triangle.getV2y(vertices); + z2 = triangle.getV2z(vertices); + x3 = triangle.getV3x(vertices); + y3 = triangle.getV3y(vertices); + z3 = triangle.getV3z(vertices); + G3i = x1 * (y2 * z3 - z2 * y3) + y1 * (z2 * x3 - x2 * z3) + z1 * (x2 * y3 - y2 * x3); + volume = volume + G3i / 6.0; + rSP1 = rSP1 + G3i * (x1 + x2 + x3); + rSP2 = rSP2 + G3i * (y1 + y2 + y3); + rSP3 = rSP3 + G3i * (z1 + z2 + z3); + } + rSP1 = rSP1 / (24.0 * volume); + rSP2 = rSP2 / (24.0 * volume); + rSP3 = rSP3 / (24.0 * volume); + + double x1s = 0.0; // rSP1;//0.0;// + double x2s = 0.0; // rSP2;//0.0;// + double x3s = 0.0; // rSP3;//0.0;// + + for (int u = 0; u < size; u++) { + TriFace &triangle = (*this->triangles)[u]; + x1 = triangle.getV1x(vertices) - x1s; + y1 = triangle.getV1y(vertices) - x2s; + z1 = triangle.getV1z(vertices) - x3s; + x2 = triangle.getV2x(vertices) - x1s; + y2 = triangle.getV2y(vertices) - x2s; + z2 = triangle.getV2z(vertices) - x3s; + x3 = triangle.getV3x(vertices) - x1s; + y3 = triangle.getV3y(vertices) - x2s; + z3 = triangle.getV3z(vertices) - x3s; + G3i = x1 * (y2 * z3 - z2 * y3) + y1 * (z2 * x3 - x2 * z3) + z1 * (x2 * y3 - y2 * x3); + // rSP1 = rSP1+G3i*(x1+x2+x3)/(24.0*volume); + // rSP2 = rSP2+G3i*(y1+y2+y3)/(24.0*volume); + // rSP3 = rSP3+G3i*(z1+z2+z3)/(24.0*volume); + xx = x1 * x1 + x2 * x2 + x3 * x3 + x1 * x2 + x2 * x3 + x3 * x1; + yy = y1 * y1 + y2 * y2 + y3 * y3 + y1 * y2 + y2 * y3 + y3 * y1; + zz = z1 * z1 + z2 * z2 + z3 * z3 + z1 * z2 + z2 * z3 + z3 * z1; + top11 = top11 + (yy + zz) * rhoP * G3i / 60.; + top22 = top22 + (xx + zz) * rhoP * G3i / 60.; + top33 = top33 + (yy + xx) * rhoP * G3i / 60.; + xy = 2.0 * (x1 * y1 + x2 * y2 + x3 * y3) + x2 * y3 + x3 * y1 + x1 * y2 + x3 * y2 + x1 * y3 + x2 * y1; + yz = 2.0 * (y1 * z1 + y2 * z2 + y3 * z3) + y2 * z3 + y3 * z1 + y1 * z2 + y3 * z2 + y1 * z3 + y2 * z1; + zx = 2.0 * (z1 * x1 + z2 * x2 + z3 * x3) + z2 * x3 + z3 * x1 + z1 * x2 + z3 * x2 + z1 * x3 + z2 * x1; + top12 = top12 - xy * rhoP * G3i / 120.; + top23 = top23 - yz * rhoP * G3i / 120.; + top13 = top13 - zx * rhoP * G3i / 120.; + } + // Satz von Steiner ... + top11 = top11 - rhoP * volume * (rSP2 * rSP2 + rSP3 + rSP3); + top22 = top22 - rhoP * volume * (rSP3 * rSP3 + rSP1 * rSP1); + top33 = top33 - rhoP * volume * (rSP1 * rSP1 + rSP2 * rSP2); + top12 = top12 + rhoP * volume * rSP1 * rSP2; + top23 = top23 + rhoP * volume * rSP2 * rSP3; + top13 = top13 + rhoP * volume * rSP3 * rSP1; + + cout << "Volume:" << volume << "\n Traegheitsmomente:\n"; + cout << " top11:" << top11 << " top22:" << top22 << " top33:" << top33 << endl; + cout << " top12:" << top12 << " top23:" << top23 << " top13:" << top13 << endl; + + return { top11, top22, top33, top12, top23, top13 }; +} +/*==============================================================*/ +void GbTriFaceMesh3D::calculateValues() +{ + relationVertTris.clear(); + + if (nodes->empty()) { + x1min = x1max = x2min = x2max = x3min = x3max = 0.0; + } else { + Vertex &v = (*nodes)[0]; + x1min = x1max = v.x; + x2min = x2max = v.y; + x3min = x3max = v.z; + + for (size_t i = 1; i < this->nodes->size(); i++) { + Vertex &v1 = (*nodes)[i]; + + x1min = UbMath::min<double>(x1min, v1.x); + x2min = UbMath::min<double>(x2min, v1.y); + x3min = UbMath::min<double>(x3min, v1.z); + + x1max = UbMath::max<double>(x1max, v1.x); + x2max = UbMath::max<double>(x2max, v1.y); + x3max = UbMath::max<double>(x3max, v1.z); + } + x1center = 0.5 * (x1min + x1max); + x2center = 0.5 * (x2min + x2max); + x3center = 0.5 * (x3min + x3max); + + vector<TriFace> &tris = *this->triangles; + vector<Vertex> &verts = *this->nodes; + for (size_t i = 0; i < this->triangles->size(); i++) { + tris[i].calculateNormal(verts); + } + // relation Vertex <-> Triangle ermitteln + if (buildVertTriRelationMap) { + for (size_t t = 0; t < tris.size(); t++) { + TriFace &tri = tris[t]; + relationVertTris.insert(make_pair(&verts[tri.v1], &tri)); + relationVertTris.insert(make_pair(&verts[tri.v2], &tri)); + relationVertTris.insert(make_pair(&verts[tri.v3], &tri)); + } + } + } + if (kdTree) { + delete kdTree; + kdTree = NULL; + } + + this->consistent = true; +} +/*=========================================================================*/ +std::vector<GbTriFaceMesh3D::TriFace *> GbTriFaceMesh3D::getTrianglesForVertex(Vertex *vertex) +{ + if (!buildVertTriRelationMap) { + buildVertTriRelationMap = true; + consistent = false; + } + if (!consistent) + this->calculateValues(); + + typedef std::multimap<Vertex *, TriFace *>::iterator Iterator; + pair<Iterator, Iterator> objRange = relationVertTris.equal_range(vertex); + + std::vector<TriFace *> tmpTris; + for (Iterator pos = objRange.first; pos != objRange.second; ++pos) + tmpTris.push_back(pos->second); + + return tmpTris; +} +/*=======================================================*/ +void GbTriFaceMesh3D::setCenterCoordinates(const double &x1, const double &x2, const double &x3) +{ + this->translate(x1 - getX1Centroid(), x2 - getX2Centroid(), x3 - getX3Centroid()); +} + +/*======================================================================*/ +void GbTriFaceMesh3D::setCenterCoordinates(const UbTupleDouble3 & /*position*/) +{ + throw UbException(UB_EXARGS, "not implemented for " + (std::string) typeid(*this).name()); +} + +/*======================================================================*/ +void GbTriFaceMesh3D::scale(const double &sx1, const double &sx2, const double &sx3) +{ + CoordinateTransformation3D trafoForw(this->getX1Centroid(), this->getX2Centroid(), this->getX3Centroid(), 1.0, 1.0, + 1.0, 0.0, 0.0, 0.0); + CoordinateTransformation3D trafoBack(this->getX1Centroid(), this->getX2Centroid(), this->getX3Centroid(), sx1, sx2, + sx3, 0, 0, 0); + + vector<Vertex> &vertices = *nodes; + for (size_t i = 0; i < vertices.size(); i++) { + Vertex &v = vertices[i]; + double p1x1 = trafoForw.transformForwardToX1Coordinate(v.x, v.y, v.z); + double p1x2 = trafoForw.transformForwardToX2Coordinate(v.x, v.y, v.z); + double p1x3 = trafoForw.transformForwardToX3Coordinate(v.x, v.y, v.z); + v.x = (float)trafoBack.transformBackwardToX1Coordinate(p1x1, p1x2, p1x3); + v.y = (float)trafoBack.transformBackwardToX2Coordinate(p1x1, p1x2, p1x3); + v.z = (float)trafoBack.transformBackwardToX3Coordinate(p1x1, p1x2, p1x3); + } + this->calculateValues(); +} +/*======================================================================*/ +void GbTriFaceMesh3D::rotate(const double &alpha, const double &beta, const double &gamma) +{ + CoordinateTransformation3D trafoForw(this->getX1Centroid(), this->getX2Centroid(), this->getX3Centroid(), 1.0, 1.0, + 1.0, 0.0, 0.0, 0.0); + CoordinateTransformation3D trafoBack(this->getX1Centroid(), this->getX2Centroid(), this->getX3Centroid(), 1.0, 1.0, + 1.0, alpha, beta, gamma); + + vector<Vertex> &vertices = *nodes; + for (size_t i = 0; i < vertices.size(); i++) { + Vertex &v = vertices[i]; + double p1x1 = trafoForw.transformForwardToX1Coordinate(v.x, v.y, v.z); + double p1x2 = trafoForw.transformForwardToX2Coordinate(v.x, v.y, v.z); + double p1x3 = trafoForw.transformForwardToX3Coordinate(v.x, v.y, v.z); + v.x = (float)trafoBack.transformBackwardToX1Coordinate(p1x1, p1x2, p1x3); + v.y = (float)trafoBack.transformBackwardToX2Coordinate(p1x1, p1x2, p1x3); + v.z = (float)trafoBack.transformBackwardToX3Coordinate(p1x1, p1x2, p1x3); + } + this->calculateValues(); +} +/*======================================================================*/ +void GbTriFaceMesh3D::rotateAroundPoint(const double &px1, const double &px2, const double &px3, const double &alpha, + const double &beta, const double &gamma) +{ + CoordinateTransformation3D trafoForw(px1, px2, px3, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0); + CoordinateTransformation3D trafoBack(px1, px2, px3, 1.0, 1.0, 1.0, alpha, beta, gamma); + + vector<Vertex> &vertices = *nodes; + for (size_t i = 0; i < vertices.size(); i++) { + Vertex &v = vertices[i]; + double p1x1 = trafoForw.transformForwardToX1Coordinate(v.x, v.y, v.z); + double p1x2 = trafoForw.transformForwardToX2Coordinate(v.x, v.y, v.z); + double p1x3 = trafoForw.transformForwardToX3Coordinate(v.x, v.y, v.z); + v.x = (float)trafoBack.transformBackwardToX1Coordinate(p1x1, p1x2, p1x3); + v.y = (float)trafoBack.transformBackwardToX2Coordinate(p1x1, p1x2, p1x3); + v.z = (float)trafoBack.transformBackwardToX3Coordinate(p1x1, p1x2, p1x3); + } + this->calculateValues(); +} + +/*======================================================================*/ +void GbTriFaceMesh3D::translate(const double &x1, const double &x2, const double &x3) +{ + vector<Vertex> &vertices = *nodes; + for (size_t i = 0; i < vertices.size(); i++) { + Vertex &v = vertices[i]; + v.x += static_cast<float>(x1); + v.y += static_cast<float>(x2); + v.z += static_cast<float>(x3); + } + this->calculateValues(); +} +/*======================================================================*/ +vector<GbTriangle3D *> GbTriFaceMesh3D::getSurfaceTriangleSet() +{ + // SirAnn: eine miese Speicherlochmethode + // hier werden dynmamische Objekte angelegt + // mit sowas rechnet von aussen kein Mensch!!! + vector<GbTriangle3D *> tris(triangles->size()); + + for (size_t i = 0; i < this->triangles->size(); i++) { + Vertex &v1 = (*nodes)[(*triangles)[i].v1]; + Vertex &v2 = (*nodes)[(*triangles)[i].v2]; + Vertex &v3 = (*nodes)[(*triangles)[i].v3]; + + tris[i] = new GbTriangle3D(new GbPoint3D(v1.x, v1.y, v1.z), new GbPoint3D(v2.x, v2.y, v2.z), + new GbPoint3D(v3.x, v3.y, v3.z)); + } + return tris; +} +/*=======================================================*/ +void GbTriFaceMesh3D::addSurfaceTriangleSet(vector<UbTupleFloat3> &pts, vector<UbTupleInt3> &tris) +{ + int nodeNr = int(pts.size()); + for (int i = 0; i < (int)this->triangles->size(); i++) { + Vertex &v1 = (*nodes)[(*triangles)[i].v1]; + Vertex &v2 = (*nodes)[(*triangles)[i].v2]; + Vertex &v3 = (*nodes)[(*triangles)[i].v3]; + pts.push_back(makeUbTuple(v1.x, v1.y, v1.z)); + pts.push_back(makeUbTuple(v2.x, v2.y, v2.z)); + pts.push_back(makeUbTuple(v3.x, v3.y, v3.z)); + + tris.push_back(makeUbTuple(nodeNr, nodeNr + 1, nodeNr + 2)); + nodeNr += 3; + } +} +/*======================================================================*/ +// bool GbTriFaceMesh3D::isPointInGbObject3D(const double& x1, const double& x2, const double& x3, int counter) +//{ +// +// +// if( !nodes->empty() ) +// { +// //Baum erstellen, wen noch keiner vorhanden +// if( !kdTree) +// { +// UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - build KdTree start"); +// UbTimer timer; timer.start(); +// if(kdtreeSplitAlg == KDTREE_SAHPLIT ) +// { +// UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - build KdTree with SAHSplit"); +// this->kdTree = new Kd::Tree<double>( *this, Kd::SAHSplit<double>() ); +// } +// else if(kdtreeSplitAlg == KDTREE_SPATIALSPLIT) +// { +// UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - build KdTree with SpatialMedianSplit"); +// this->kdTree = new Kd::Tree<double>( *this, Kd::SpatialMedianSplit<double>() ); +// } +// else throw UbException(UB_EXARGS, "unknown kdtree split option)" ); +// UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - built kdTree in "<<timer.stop()<<"seconds"); +// } +// +// //eigentlicher PIO-Test +// //int iSec; +// //for(int i=0; i<100; i++) +// //{ +// // Kd::Ray<double> ray( x1, x2, x3 //, 1, 0 ,0 ); +// // , ( x1 < x1center ? UbRandom::rand(-1.0,-0.001, 10) : UbRandom::rand(0.001, 1.0, 10) ) +// // , ( x2 < x2center ? UbRandom::rand(-1.0,-0.001, 10) : UbRandom::rand(0.001, 1.0, 10) ) +// // , ( x3 < x3center ? UbRandom::rand(-1.0,-0.001, 10) : UbRandom::rand(0.001, 1.0, 10) ) +// ); +// // +// // iSec = kdTree->intersectRay( ray, Kd::CountRayIntersectionHandler<double>() ); +// // +// // if( iSec != Kd::Intersection::INTERSECT_EDGE ) //KEINE Kante getroffen +// // { +// // if(iSec == Kd::Intersection::ON_BOUNDARY ) +// // { +// // return true; +// // } +// // return (iSec&1); //ungerade anzahl an schnitten --> drinnen +// // } +// // UBLOG(logDEBUG3, "GbTriFaceMesh3D.isPointInGbObject3D.if - an edge was hit "); +// //} +// //throw UbException(UB_EXARGS, "ups, nach 100 Strahlen immer noch kein Ergebnis"); +// int iSec1,iSec2; +// +// Kd::Ray<double> ray1( x1, x2, x3, 1.0, 0.0 ,0.0 ); +// iSec1 = kdTree->intersectRay( ray1, Kd::CountRayIntersectionHandler<double>() ); +// Kd::Ray<double> ray2( x1, x2, x3, -1.0, 0.0 ,0.0 ); +// iSec2 = kdTree->intersectRay( ray2, Kd::CountRayIntersectionHandler<double>() ); +// +// if(iSec1 == Kd::Intersection::ON_BOUNDARY || iSec2 == Kd::Intersection::ON_BOUNDARY) +// { +// return true; +// } +// if( iSec1 == Kd::Intersection::INTERSECT_EDGE && iSec2 == Kd::Intersection::INTERSECT_EDGE) +// { +// UBLOG(logINFO, "GbTriFaceMesh3D.isPointInGbObject3D.INTERSECT_EDGE"); +// double eps = UbMath::getEqualityEpsilon<float>()*1000.0; +// if (counter>100) {return(iSec1&1); UBLOG(logINFO, "NACH 100 Iterationen Eps umsetzen aufgegeben!");} +// return this->isPointInGbObject3D(x1+eps, x2+eps, x3+eps,(counter+1)); +// } +// else if( iSec1 == Kd::Intersection::INTERSECT_EDGE) +// { +// return (iSec2&1); +// } +// else if( iSec2 == Kd::Intersection::INTERSECT_EDGE) +// { +// return (iSec1&1); +// } +// else +// { +// if((iSec1&1) != (iSec2&1)) +// { +// UBLOG(logINFO, "GbTriFaceMesh3D.isPointInGbObject3D.iSec1&1 != iSec2&1"); +// double eps = UbMath::getEqualityEpsilon<float>()*1000.0; +// if (counter>100) {return(iSec1&1); UBLOG(logINFO, "NACH 100 Iterationen Eps umsetzen aufgegeben!");} +// return this->isPointInGbObject3D(x1+eps, x2+eps, x3+eps,(counter+1)); +// } +// return iSec1&1; +// } +// //throw UbException(UB_EXARGS, "ups, nach 100 Strahlen immer noch kein Ergebnis"); +// +// } +// return false; +//} +bool GbTriFaceMesh3D::isPointInGbObject3D(const double &x1, const double &x2, const double &x3, int counter) +{ + + if (!nodes->empty()) { + // Baum erstellen, wen noch keiner vorhanden + if (!kdTree) { + UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - build KdTree start"); + UbTimer timer; + timer.start(); + if (kdtreeSplitAlg == KDTREE_SAHPLIT) { + UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - build KdTree with SAHSplit"); + this->kdTree = new Kd::Tree<double>(*this, Kd::SAHSplit<double>()); + } else if (kdtreeSplitAlg == KDTREE_SPATIALSPLIT) { + UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - build KdTree with SpatialMedianSplit"); + this->kdTree = new Kd::Tree<double>(*this, Kd::SpatialMedianSplit<double>()); + } else + throw UbException(UB_EXARGS, "unknown kdtree split option)"); + UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - built kdTree in " << timer.stop() << "seconds"); + } + + // eigentlicher PIO-Test + // int iSec; + // for(int i=0; i<100; i++) + //{ + // Kd::Ray<double> ray( x1, x2, x3 //, 1, 0 ,0 ); + // , ( x1 < x1center ? UbRandom::rand(-1.0,-0.001, 10) : UbRandom::rand(0.001, 1.0, 10) ) + // , ( x2 < x2center ? UbRandom::rand(-1.0,-0.001, 10) : UbRandom::rand(0.001, 1.0, 10) ) + // , ( x3 < x3center ? UbRandom::rand(-1.0,-0.001, 10) : UbRandom::rand(0.001, 1.0, 10) ) + // ); + // + // iSec = kdTree->intersectRay( ray, Kd::CountRayIntersectionHandler<double>() ); + // + // if( iSec != Kd::Intersection::INTERSECT_EDGE ) //KEINE Kante getroffen + // { + // if(iSec == Kd::Intersection::ON_BOUNDARY ) + // { + // return true; + // } + // return (iSec&1); //ungerade anzahl an schnitten --> drinnen + // } + // UBLOG(logDEBUG3, "GbTriFaceMesh3D.isPointInGbObject3D.if - an edge was hit "); + //} + // throw UbException(UB_EXARGS, "ups, nach 100 Strahlen immer noch kein Ergebnis"); + int iSec1, iSec2; + double eps = 0.05; + Kd::Ray<double> ray1(x1, x2, x3, 1.0 + eps * ((double)counter), eps * ((double)counter), + eps * ((double)counter)); + iSec1 = kdTree->intersectRay(ray1, Kd::CountRayIntersectionHandler<double>()); + Kd::Ray<double> ray2(x1, x2, x3, -1.0 - eps * ((double)counter), -eps * ((double)counter), + -eps * ((double)counter)); + + iSec2 = kdTree->intersectRay(ray2, Kd::CountRayIntersectionHandler<double>()); + + if (iSec1 == Kd::Intersection::ON_BOUNDARY || iSec2 == Kd::Intersection::ON_BOUNDARY) { + return true; + } + if (iSec1 == Kd::Intersection::INTERSECT_EDGE && iSec2 == Kd::Intersection::INTERSECT_EDGE) { + // UBLOG(logINFO, "GbTriFaceMesh3D.isPointInGbObject3D.INTERSECT_EDGE"); + + if (counter > 20) { + return (iSec1 & 1); /*UBLOG(logINFO, "NACH 100 Iterationen Eps umsetzen aufgegeben!");*/ + } + return this->isPointInGbObject3D(x1, x2, x3, (counter + 1)); + } else if (iSec1 == Kd::Intersection::INTERSECT_EDGE) { + return (iSec2 & 1); + } else if (iSec2 == Kd::Intersection::INTERSECT_EDGE) { + return (iSec1 & 1); + } else { + if ((iSec1 & 1) != (iSec2 & 1)) { + // UBLOG(logINFO, "GbTriFaceMesh3D.isPointInGbObject3D.iSec1&1 != iSec2&1"); + + if (counter > 20) { + return (iSec1 & 1); /* UBLOG(logINFO, "NACH 100 Iterationen Eps umsetzen aufgegeben!");*/ + } + return this->isPointInGbObject3D(x1, x2, x3, (counter + 1)); + } + return iSec1 & 1; + } + // throw UbException(UB_EXARGS, "ups, nach 100 Strahlen immer noch kein Ergebnis"); + } + return false; +} +/*======================================================================*/ +bool GbTriFaceMesh3D::isPointInGbObject3D(const double &x1, const double &x2, const double &x3) +{ + if (!nodes->empty()) { + // Baum erstellen, wen noch keiner vorhanden + if (!kdTree) { + UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - build KdTree start"); + UbTimer timer; + timer.start(); + if (kdtreeSplitAlg == KDTREE_SAHPLIT) { + UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - build KdTree with SAHSplit"); + //cout << "GbTriFaceMesh3D::calculateValues - build KdTree with SAHSplit" << std::endl; + this->kdTree = new Kd::Tree<double>(*this, Kd::SAHSplit<double>()); + } else if (kdtreeSplitAlg == KDTREE_SPATIALSPLIT) { + UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - build KdTree with SpatialMedianSplit"); + this->kdTree = new Kd::Tree<double>(*this, Kd::SpatialMedianSplit<double>()); + } else + throw UbException(UB_EXARGS, "unknown kdtree split option)"); + UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - built kdTree in " << timer.stop() << "seconds"); + //cout << "GbTriFaceMesh3D::calculateValues - built kdTree in " << timer.stop() << "seconds" << std::endl; + } + + // eigentlicher PIO-Test + int iSec; + for (int i = 0; i < MAX_ITER; i++) { + Kd::Ray<double> ray(x1, x2, x3 //, 1, 0 ,0 ); + , + (x1 < x1center ? UbRandom::rand(-1.0, -0.001, 10) : UbRandom::rand(0.001, 1.0, 10)), + (x2 < x2center ? UbRandom::rand(-1.0, -0.001, 10) : UbRandom::rand(0.001, 1.0, 10)), + (x3 < x3center ? UbRandom::rand(-1.0, -0.001, 10) : UbRandom::rand(0.001, 1.0, 10))); + + iSec = kdTree->intersectRay(ray, Kd::CountRayIntersectionHandler<double>()); + + if (iSec != Kd::Intersection::INTERSECT_EDGE) // KEINE Kante getroffen + { + if (iSec == Kd::Intersection::ON_BOUNDARY) { + return true; + } + return (iSec & 1); // ungerade anzahl an schnitten --> drinnen + } + UBLOG(logDEBUG3, "GbTriFaceMesh3D.isPointInGbObject3D.if - an edge was hit "); + } + throw UbException(UB_EXARGS, "ups, nach 100 Strahlen immer noch kein Ergebnis"); + + // int iSec1,iSec2; + // + // Kd::Ray<double> ray1( x1, x2, x3, 1.0, 0.0 ,0.0 ); + // iSec1 = kdTree->intersectRay( ray1, Kd::CountRayIntersectionHandler<double>() ); + // Kd::Ray<double> ray2( x1, x2, x3, -1.0, 0.0 ,0.0 ); + // iSec2 = kdTree->intersectRay( ray2, Kd::CountRayIntersectionHandler<double>() ); + + // if(iSec1 == Kd::Intersection::ON_BOUNDARY || iSec2 == Kd::Intersection::ON_BOUNDARY) + // { + // return true; + // } + // if( iSec1 == Kd::Intersection::INTERSECT_EDGE && iSec2 == Kd::Intersection::INTERSECT_EDGE) + // { + // //UBLOG(logINFO, "GbTriFaceMesh3D.isPointInGbObject3D.INTERSECT_EDGE"); + // double eps = UbMath::getEqualityEpsilon<double>(); + // if (counter>100) {return(iSec1&1); UBLOG(logINFO, "NACH 100 Iterationen Eps umsetzen aufgegeben!");} + // return this->isPointInGbObject3D(x1+eps, x2+eps, x3+eps,(counter+1)); + // } + // else if( iSec1 == Kd::Intersection::INTERSECT_EDGE) + // { + // return (iSec2&1); + // } + // else if( iSec2 == Kd::Intersection::INTERSECT_EDGE) + // { + // return (iSec1&1); + // } + // else + // { + // if((iSec1&1) != (iSec2&1)) + // { + // UBLOG(logINFO, "GbTriFaceMesh3D.isPointInGbObject3D.iSec1&1 != iSec2&1"); + // double eps = UbMath::getEqualityEpsilon<double>(); + // if (counter>100) {return(iSec1&1); UBLOG(logINFO, "NACH 100 Iterationen Eps umsetzen aufgegeben!");} + // return this->isPointInGbObject3D(x1+eps, x2+eps, x3+eps,(counter+1)); + // } + // return iSec1&1; + // } + // //throw UbException(UB_EXARGS, "ups, nach 100 Strahlen immer noch kein Ergebnis"); + } + return false; +} +/*======================================================================*/ +bool GbTriFaceMesh3D::isPointInGbObject3D(const double &x1, const double &x2, const double &x3, bool &pointIsOnBoundary) +{ + if (!nodes->empty()) { + // Baum erstellen, wen noch keiner vorhanden + if (!kdTree) { + UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - build KdTree start"); + UbTimer timer; + timer.start(); + if (kdtreeSplitAlg == KDTREE_SAHPLIT) { + UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - build KdTree with SAHSplit"); + this->kdTree = new Kd::Tree<double>(*this, Kd::SAHSplit<double>()); + } else if (kdtreeSplitAlg == KDTREE_SPATIALSPLIT) { + UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - build KdTree with SpatialMedianSplit"); + this->kdTree = new Kd::Tree<double>(*this, Kd::SpatialMedianSplit<double>()); + } else + throw UbException(UB_EXARGS, "unknown kdtree split option)"); + UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - built kdTree in " << timer.stop() << "seconds"); + } + + // eigentlicher PIO-Test + int iSec; + for (int i = 0; i < MAX_ITER; i++) { + Kd::Ray<double> ray( + x1, x2, x3, float((x1 < x1center ? UbRandom::rand(-1.0, -0.001, 10) : UbRandom::rand(0.001, 1.0, 10))), + float((x2 < x2center ? UbRandom::rand(-1.0, -0.001, 10) : UbRandom::rand(0.001, 1.0, 10))), + float((x3 < x3center ? UbRandom::rand(-1.0, -0.001, 10) : UbRandom::rand(0.001, 1.0, 10)))); + + iSec = kdTree->intersectRay(ray, Kd::CountRayIntersectionHandler<double>()); + + if (iSec != Kd::Intersection::INTERSECT_EDGE) // KEINE Kante getroffen + { + if (iSec == Kd::Intersection::ON_BOUNDARY) { + pointIsOnBoundary = true; + return true; + } + pointIsOnBoundary = false; + return (iSec & 1); // ungerade anzahl an schnitten --> drinnen + } + } + + throw UbException(UB_EXARGS, "ups, nach 100 Strahlen immer noch kein Ergebnis"); + } + + return false; +} +/*======================================================================*/ +bool GbTriFaceMesh3D::intersectLine(const double &p1_x1, const double &p1_x2, const double &p1_x3, const double &p2_x1, + const double &p2_x2, const double &p2_x3) +{ + // Baum erstellen, wen noch keiner vorhanden + if (!kdTree) { + UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - build KdTree start"); + UbTimer timer; + timer.start(); + if (kdtreeSplitAlg == KDTREE_SAHPLIT) { + UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - build KdTree with SAHSplit"); + this->kdTree = new Kd::Tree<double>(*this, Kd::SAHSplit<double>()); + } else if (kdtreeSplitAlg == KDTREE_SPATIALSPLIT) { + UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - build KdTree with SpatialMedianSplit"); + this->kdTree = new Kd::Tree<double>(*this, Kd::SpatialMedianSplit<double>()); + } else + throw UbException(UB_EXARGS, "unknown kdtree split option)"); + UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - built kdTree in " << timer.stop() << "seconds"); + } + + int iSec = kdTree->intersectLine(UbTupleDouble3(p1_x1, p1_x2, p1_x3), UbTupleDouble3(p2_x1, p2_x2, p2_x3), + Kd::CountLineIntersectionHandler<double>()); + + return (iSec != Kd::Intersection::NO_INTERSECTION); +} +/*======================================================================*/ +GbLine3D *GbTriFaceMesh3D::createClippedLine3D(GbPoint3D & /*point1*/, GbPoint3D & /*point2*/) +{ + throw UbException(UB_EXARGS, "not implemented"); +} + +/*======================================================================*/ +UbTuple<string, string> GbTriFaceMesh3D::writeMesh(string filename, WbWriter *writer, bool writeNormals, + vector<string> *datanames, + std::vector<std::vector<double>> *nodedata) +{ + UBLOG(logINFO, "GbTriFaceMesh3D::writeMesh "); + + vector<UbTupleFloat3> triNodes(nodes->size()); + vector<UbTupleInt3> tris(triangles->size()); + + for (size_t i = 0; i < nodes->size(); i++) + triNodes[i] = makeUbTuple((*nodes)[i].x, (*nodes)[i].y, (*nodes)[i].z); + + for (size_t i = 0; i < triangles->size(); i++) + tris[i] = makeUbTuple((*triangles)[i].v1, (*triangles)[i].v2, (*triangles)[i].v3); + + UbTuple<string, string> filenames("", ""); + + if (!datanames || datanames->empty() || !nodedata) { + val<1>(filenames) = writer->writeTriangles(filename, triNodes, tris); + } else { + val<1>(filenames) = writer->writeTrianglesWithNodeData(filename, triNodes, tris, *datanames, *nodedata); + } + + if (writeNormals) { + vector<UbTupleFloat3> lineNodes(triangles->size() * 2); + vector<UbTupleInt2> lines(triangles->size()); + for (size_t i = 0; i < triangles->size(); i++) { + TriFace &triangle = (*triangles)[i]; + lineNodes[i * 2] = makeUbTuple(triangle.getX1Centroid(*nodes), triangle.getX2Centroid(*nodes), + triangle.getX3Centroid(*nodes)); + + lineNodes[i * 2 + 1] = makeUbTuple((float)(triangle.getX1Centroid(*nodes) + 1.0 * triangle.nx), + (float)(triangle.getX2Centroid(*nodes) + 1.0 * triangle.ny), + (float)(triangle.getX3Centroid(*nodes) + 1.0 * triangle.nz)); + + lines[i] = makeUbTuple((int)i * 2, (int)i * 2 + 1); + } + val<2>(filenames) = writer->writeLines(filename + "_normals", lineNodes, lines); + } + + return filenames; +} +/*======================================================================*/ +void GbTriFaceMesh3D::writeMeshPly(const std::string &filename) +{ + ofstream out(filename.c_str()); + if (!out) + throw UbException(UB_EXARGS, "couldn't open " + filename); + + out << "ply" << endl; + out << "format ascii 1.0" << endl; + out << "element vertex " << (int)nodes->size() << endl; + out << "property float x" << endl; + out << "property float y" << endl; + out << "property float z" << endl; + out << "element face " << (int)triangles->size() << endl; + out << "property list uchar int vertex_indices" << endl; + out << "end_header" << endl; + + for (size_t i = 0; i < nodes->size(); i++) + out << (*nodes)[i].x << " " << (*nodes)[i].y << " " << (*nodes)[i].z << endl; + + for (size_t i = 0; i < triangles->size(); i++) + out << "3 " << (*triangles)[i].v1 << " " << (*triangles)[i].v2 << " " << (*triangles)[i].v3 << endl; +} +/*======================================================================*/ +void GbTriFaceMesh3D::readMeshFromSTLFileASCII(string filename, bool removeRedundantNodes) +{ + UBLOG(logDEBUG1, "GbTriFaceMesh3DCreator::readMeshFromSTLFile !!! Dieses Format hat leider redundante Knoten ..."); + + int nr = 0; + + ifstream in(filename.c_str()); + if (!in.good()) { + (*nodes).clear(); + (*triangles).clear(); + UB_THROW(UbException(UB_EXARGS, "Can not open STL file: " + filename)); + } + char title[80]; + std::string s0, s1; + float n0, n1, n2, f0, f1, f2, f3, f4, f5, f6, f7, f8; + in.read(title, 80); + while (!in.eof()) { + in >> s0; // facet || endsolid + if (s0 == "facet") { + in >> s1 >> n0 >> n1 >> n2; // normal x y z + in >> s0 >> s1; // outer loop + in >> s0 >> f0 >> f1 >> f2; // vertex x y z + in >> s0 >> f3 >> f4 >> f5; // vertex x y z + in >> s0 >> f6 >> f7 >> f8; // vertex x y z + in >> s0; // endloop + in >> s0; // endfacet + // Generate a new Triangle without Normal as 3 Vertices + nodes->push_back(GbTriFaceMesh3D::Vertex(f0, f1, f2)); + nodes->push_back(GbTriFaceMesh3D::Vertex(f3, f4, f5)); + nodes->push_back(GbTriFaceMesh3D::Vertex(f6, f7, f8)); + triangles->push_back(GbTriFaceMesh3D::TriFace(nr, nr + 1, nr + 2)); + nr += 3; + } else if (s0 == "endsolid") { + break; + } + } + in.close(); + + if (removeRedundantNodes) { + this->deleteRedundantNodes(); // dort wird autoamtisch calculateValues() aufgerufen + } else { + this->calculateValues(); + } + //UBLOG(logDEBUG1, "GbTriFaceMesh3DCreator::readMeshFromSTLFile !!! Dieses Format hat leider redundante Knoten ..."); + + //string dummy; + + //double x, y, z; + //int nr = 0; + + //UbFileInputASCII in(filename); + //in.readLine(); + //while (dummy != "endsolid") { + // in.readLine(); + // in.readLine(); + // dummy = in.readString(); + // if (dummy != "vertex") + // throw UbException(UB_EXARGS, "no vertex format"); + // x = in.readDouble(); + // y = in.readDouble(); + // z = in.readDouble(); + // nodes->push_back(GbTriFaceMesh3D::Vertex((float)x, (float)y, (float)z)); + // in.readLine(); + // in.readString(); + // x = in.readDouble(); + // y = in.readDouble(); + // z = in.readDouble(); + // nodes->push_back(GbTriFaceMesh3D::Vertex((float)x, (float)y, (float)z)); + // in.readLine(); + // in.readString(); + // x = in.readDouble(); + // y = in.readDouble(); + // z = in.readDouble(); + // nodes->push_back(GbTriFaceMesh3D::Vertex((float)x, (float)y, (float)z)); + // triangles->push_back(GbTriFaceMesh3D::TriFace(nr, nr + 1, nr + 2)); + // in.readLine(); + // in.readLine(); + // in.readLine(); + // dummy = in.readString(); + // nr += 3; + // // std::cout<<"read mesh "<< nr <<" \n"; + //} + + //if (removeRedundantNodes) { + // this->deleteRedundantNodes(); // dort wird autoamtisch calculateValues() aufgerufen + //} else { + // this->calculateValues(); + //} +} +/*======================================================================*/ +void GbTriFaceMesh3D::readMeshFromSTLFileBinary(string filename, bool removeRedundantNodes) +{ + int nr = 0; + FILE *f = fopen(filename.c_str(), "rb"); + if (!f) { + (*nodes).clear(); + (*triangles).clear(); + UB_THROW(UbException(UB_EXARGS, "Can not open STL file: " + filename)); + } + char title[80]; + int nFaces; + size_t sizef = fread(title, 80, 1, f); + sizef = fread((void *)&nFaces, 4, 1, f); + float v[12]; // normal=3, vertices=3*3 = 12 + unsigned short uint16; + // Every Face is 50 Bytes: Normal(3*float), Vertices(9*float), 2 Bytes Spacer + for (int i = 0; i < nFaces; ++i) { + for (size_t j = 0; j < 12; ++j) { + sizef = fread((void *)&v[j], sizeof(float), 1, f); + } + sizef = fread((void *)&uint16, sizeof(unsigned short), 1, f); // spacer between successive faces + nodes->push_back(GbTriFaceMesh3D::Vertex(v[3], v[4], v[5])); + nodes->push_back(GbTriFaceMesh3D::Vertex(v[6], v[7], v[8])); + nodes->push_back(GbTriFaceMesh3D::Vertex(v[9], v[10], v[11])); + triangles->push_back(GbTriFaceMesh3D::TriFace(nr, nr + 1, nr + 2)); + nr += 3; + } + (void)sizef; + fclose(f); + + if (removeRedundantNodes) { + this->deleteRedundantNodes(); // dort wird autoamtisch calculateValues() aufgerufen + } else { + this->calculateValues(); + } +} diff --git a/src/basics/geometry3d/GbTriFaceMesh3D.h b/src/basics/geometry3d/GbTriFaceMesh3D.h new file mode 100644 index 0000000000000000000000000000000000000000..33ddbe2fdd82fb1cfd8fe96fd8b98843a6e82879 --- /dev/null +++ b/src/basics/geometry3d/GbTriFaceMesh3D.h @@ -0,0 +1,436 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file GbTriFaceMesh3D.h +//! \ingroup geometry3D +//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller +//======================================================================================= +#ifndef GBTRIFACEMESH3D_H +#define GBTRIFACEMESH3D_H + +#include <iostream> +#include <map> +#include <sstream> +#include <vector> + +#include <basics/utilities/UbException.h> +#include <basics/utilities/UbMath.h> +#include <basics/utilities/Vector3D.h> + +#include <geometry3d/GbPoint3D.h> + +#include <PointerDefinitions.h> + +#include <basics_export.h> + +namespace Kd +{ +template <typename T> +class Tree; +template <typename T> +class SplitAlgorithm; +template <typename T> +class RayIntersectionHandler; +} // namespace Kd + +class WbWriter; + +/*=========================================================================*/ +/* GbTriFaceMesh3D */ +/* */ +/** + * This Class provides the triangular meshes. + * Note, that up to now no methods for checking consistency are included. + * in this context this class describes facettes from an 3D-object !!! + */ +class BASICS_EXPORT GbTriFaceMesh3D : public GbObject3D +{ +public: + // nested class start + class Vertex + { + public: + Vertex() = default; + Vertex(const float &x, const float &y, const float &z) : x(x), y(y), z(z) {} + Vertex(Vertex *vert) + { + this->x = vert->x; + this->y = vert->y; + this->z = vert->z; + } + float operator[](const int &i) const + { + if (i == 0) + return x; + else if (i == 1) + return y; + else if (i == 2) + return z; + + throw UbException(UB_EXARGS, "i not in [0;2]"); + } + float &operator[](const int &i) + { + if (i == 0) + return x; + else if (i == 1) + return y; + else if (i == 2) + return z; + + throw UbException(UB_EXARGS, "not in [0;2]"); + } + bool operator==(const Vertex &rhs) + { + return (fabs(x - rhs.x) < 1.E-8 && fabs(y - rhs.y) < 1.E-8 && fabs(z - rhs.z) < 1.E-8); + } + friend inline bool operator<(const Vertex &lhsVert, const Vertex &rhsVert) + { + if (lhsVert.x < rhsVert.x) + return true; + if (lhsVert.x > rhsVert.x) + return false; + if (lhsVert.y < rhsVert.y) + return true; + if (lhsVert.y > rhsVert.y) + return false; + if (lhsVert.z < rhsVert.z) + return true; + + return false; + } + friend std::ostream &operator<<(std::ostream &os, const Vertex &node) + { + return os << node.x << "," << node.y << "," << node.z; + } + Vertex *clone() { return (new Vertex(this)); } + + public: + float x{ 0.0 }, y{ 0.0 }, z{ 0.0 }; + }; + ////////////////////////////////////////////////////////////////////////// + class TriFace + { + public: + TriFace() + + = default; + TriFace(const int &v1, const int &v2, const int &v3) : v1(v1), v2(v2), v3(v3) {} + + const int &getIndexVertex1() const { return v1; } + const int &getIndexVertex2() const { return v2; } + const int &getIndexVertex3() const { return v3; } + + Vertex &getNode(const int &i, std::vector<Vertex> &nodes) + { + if (i == 0) + return nodes[v1]; + if (i == 1) + return nodes[v2]; + if (i == 2) + return nodes[v3]; + throw UbException(UB_EXARGS, "invalid i - not in range [0;2]"); + } + void setNode(const int &i, const int &index) + { + if (i == 0) + v1 = index; + else if (i == 1) + v2 = index; + else if (i == 2) + v3 = index; + else + throw UbException(UB_EXARGS, "invalid i - not in range [0;2]"); + } + + int operator[](int index) + { + if (index == 0) + return v1; + if (index == 1) + return v2; + if (index == 2) + return v3; + throw UbException(UB_EXARGS, "invalid i - not in range [0;2]"); + } + + float &getV1x(std::vector<Vertex> &nodes) { return nodes[v1].x; } + float &getV1y(std::vector<Vertex> &nodes) { return nodes[v1].y; } + float &getV1z(std::vector<Vertex> &nodes) { return nodes[v1].z; } + + float &getV2x(std::vector<Vertex> &nodes) { return nodes[v2].x; } + float &getV2y(std::vector<Vertex> &nodes) { return nodes[v2].y; } + float &getV2z(std::vector<Vertex> &nodes) { return nodes[v2].z; } + + float &getV3x(std::vector<Vertex> &nodes) { return nodes[v3].x; } + float &getV3y(std::vector<Vertex> &nodes) { return nodes[v3].y; } + float &getV3z(std::vector<Vertex> &nodes) { return nodes[v3].z; } + + float getMinX(std::vector<Vertex> &nodes) { return (float)UbMath::min(nodes[v1].x, nodes[v2].x, nodes[v3].x); } + float getMinY(std::vector<Vertex> &nodes) { return (float)UbMath::min(nodes[v1].y, nodes[v2].y, nodes[v3].y); } + float getMinZ(std::vector<Vertex> &nodes) { return (float)UbMath::min(nodes[v1].z, nodes[v2].z, nodes[v3].z); } + + float getMaxX(std::vector<Vertex> &nodes) { return (float)UbMath::max(nodes[v1].x, nodes[v2].x, nodes[v3].x); } + float getMaxY(std::vector<Vertex> &nodes) { return (float)UbMath::max(nodes[v1].y, nodes[v2].y, nodes[v3].y); } + float getMaxZ(std::vector<Vertex> &nodes) { return (float)UbMath::max(nodes[v1].z, nodes[v2].z, nodes[v3].z); } + + float getX1Centroid(std::vector<Vertex> &nodes) + { + return (float)UbMath::c1o3 * (getV1x(nodes) + getV2x(nodes) + getV3x(nodes)); + } + float getX2Centroid(std::vector<Vertex> &nodes) + { + return (float)UbMath::c1o3 * (getV1y(nodes) + getV2y(nodes) + getV3y(nodes)); + } + float getX3Centroid(std::vector<Vertex> &nodes) + { + return (float)UbMath::c1o3 * (getV1z(nodes) + getV2z(nodes) + getV3z(nodes)); + } + + double calculateDistanceToPoint3D(const double &x1, const double &x2, const double &x3, + std::vector<Vertex> &nodes); + + double getArea(std::vector<Vertex> &nodes) + { + // GbVector3D A(nodes[v1].x, nodes[v1].y, nodes[v1].z); + // GbVector3D B(nodes[v2].x, nodes[v2].y, nodes[v2].z); + // GbVector3D C(nodes[v3].x, nodes[v3].y, nodes[v3].z); + // GbVector3D AB = B-A; + // GbVector3D AC = C-A; + // GbVector3D N = AB.Cross(AC); + // return 0.5*N.Length(); + Vector3D A(nodes[v1].x, nodes[v1].y, nodes[v1].z); + Vector3D B(nodes[v2].x, nodes[v2].y, nodes[v2].z); + Vector3D C(nodes[v3].x, nodes[v3].y, nodes[v3].z); + Vector3D AB = B - A; + Vector3D AC = C - A; + Vector3D N = AB.Cross(AC); + return 0.5 * N.Length(); + } + void calculateNormal(std::vector<Vertex> &nodes) + { + const float &v1x = nodes[v1].x; + const float &v1y = nodes[v1].y; + const float &v1z = nodes[v1].z; + const float &v2x = nodes[v2].x; + const float &v2y = nodes[v2].y; + const float &v2z = nodes[v2].z; + const float &v3x = nodes[v3].x; + const float &v3y = nodes[v3].y; + const float &v3z = nodes[v3].z; + + nx = (v3z - v1z) * (v2y - v1y) - (v2z - v1z) * (v3y - v1y); + ny = (v2z - v1z) * (v3x - v1x) - (v2x - v1x) * (v3z - v1z); + nz = (v2x - v1x) * (v3y - v1y) - (v2y - v1y) * (v3x - v1x); + + float length = std::sqrt(nx * nx + ny * ny + nz * nz); + if (length > 1.E-10) { + length = 1.0f / length; + nx *= length; + ny *= length; + nz *= length; + } else { + std::cerr << "GbTriFaceMesh3D::TriFace - calculateNormal: nx=ny=nz=0 -> kann nich sein " + << "(dreieck hat evtl knoten doppelt oder ist ne Linie)" + << "->removeRedunantNodes" << std::endl; + } + } + + public: + int v1{ -1 }, v2{ -1 }, v3{ -1 }; + float nx{ 0.0 }, ny{ 0.0 }, nz{ 0.0 }; + }; + +public: + enum KDTREE_SPLITAGORITHM { KDTREE_SAHPLIT, KDTREE_SPATIALSPLIT }; + +public: + GbTriFaceMesh3D(); + GbTriFaceMesh3D(std::string name, std::vector<Vertex> *nodes, std::vector<TriFace> *triangles, + KDTREE_SPLITAGORITHM splitAlg = KDTREE_SAHPLIT, bool removeRedundantNodes = true); + ~GbTriFaceMesh3D() override; + + GbTriFaceMesh3D *clone() override; // { throw UbException(UB_EXARGS,"not implemented"); } + void finalize() override {} + + // void setRegardPointInPolyhedronTest(bool value) { this->regardPiO=value; } + + std::string toString() override; + + // std::string getName(); + std::vector<Vertex> *getNodes(); + std::vector<TriFace> *getTriangles(); + + void setTransferViaFilename(bool transferViaFilename, std::string filename, double transX1, double transX2, + double transX3) + { + this->filename = filename; + this->transferViaFilename = transferViaFilename; + this->transX1 = transX1; + this->transX2 = transX2; + this->transX3 = transX3; + } + void readMeshFromSTLFileASCII(std::string filename, bool removeRedundantNodes); + void readMeshFromSTLFileBinary(std::string filename, bool removeRedundantNodes); + + double getX1Minimum() override + { + if (!this->consistent) + this->calculateValues(); + return this->x1min; + } + double getX1Maximum() override + { + if (!this->consistent) + this->calculateValues(); + return this->x1max; + } + double getX1Centroid() override + { + if (!this->consistent) + this->calculateValues(); + return this->x1center; + } + + double getX2Minimum() override + { + if (!this->consistent) + this->calculateValues(); + return this->x2min; + } + double getX2Maximum() override + { + if (!this->consistent) + this->calculateValues(); + return this->x2max; + } + double getX2Centroid() override + { + if (!this->consistent) + this->calculateValues(); + return this->x2center; + } + + double getX3Minimum() override + { + if (!this->consistent) + this->calculateValues(); + return this->x3min; + } + double getX3Centroid() override + { + if (!this->consistent) + this->calculateValues(); + return this->x3center; + } + double getX3Maximum() override + { + if (!this->consistent) + this->calculateValues(); + return this->x3max; + } + + void calculateValues(); + + double getVolume(); + void deleteRedundantNodes(); + + UbTupleDouble6 calculateMomentOfInertia(double rhoP); + UbTupleDouble3 calculateCenterOfGravity(); + + void setCenterCoordinates(const double &x1, const double &x2, const double &x3) override; + + void setCenterCoordinates(const UbTupleDouble3 & /*position*/) override; + + void scale(const double &sx1, const double &sx2, const double &sx3) override; + void rotate(const double &alpha, const double &beta, const double &gamma) override; + void rotateAroundPoint(const double &px1, const double &px2, const double &px3, const double &alpha, + const double &beta, const double &gamma); + void translate(const double &x1, const double &x2, const double &x3) override; + //void reflectAcrossXYLine(const double &alpha); + + bool isPointInGbObject3D(const double &x1, const double &x2, const double &x3) override; + bool isPointInGbObject3D(const double &x1, const double &x2, const double &x3, int counter); + bool isPointInGbObject3D(const double &x1, const double &x2, const double &x3, bool &pointIsOnBoundary) override; + + GbLine3D *createClippedLine3D(GbPoint3D &point1, GbPoint3D &point2) override; + + std::vector<GbTriangle3D *> getSurfaceTriangleSet() override; + void addSurfaceTriangleSet(std::vector<UbTupleFloat3> &nodes, std::vector<UbTupleInt3> &triangles) override; + + std::vector<GbTriFaceMesh3D::TriFace *> getTrianglesForVertex(Vertex *vertex); + + void setKdTreeSplitAlgorithm(KDTREE_SPLITAGORITHM mode); + KDTREE_SPLITAGORITHM getKdTreeSplitAlgorithm() { return this->kdtreeSplitAlg; } + Kd::Tree<double> *getKdTree() { return this->kdTree; } + + virtual UbTuple<std::string, std::string> writeMesh(std::string filename, WbWriter *writer, + bool writeNormals = false, + std::vector<std::string> *datanames = NULL, + std::vector<std::vector<double>> *nodedata = NULL); + void writeMeshPly(const std::string &filename); + + /*======================================================================*/ + using GbObject3D::isPointInGbObject3D; // Grund: dadurch muss man hier isPointInGbObject3D(GbPoint3D*) nicht + // ausprogrammieren, welche sonst hier "ueberdeckt" waere + + bool intersectLine(const double &p1_x1, const double &p1_x2, const double &p1_x3, const double &p2_x1, + const double &p2_x2, const double &p2_x3); + +protected: + KDTREE_SPLITAGORITHM kdtreeSplitAlg; + void init(); + + std::vector<Vertex> * nodes; + std::vector<TriFace> * triangles; + // for transfer + std::string filename; + bool transferViaFilename{ false }; + double transX1{ 0.0 }; + double transX2{ 0.0 }; + double transX3{ 0.0 }; + + double x1min; + double x1max; + double x2min; + double x2max; + double x3min; + double x3max; + double x1center; + double x2center; + double x3center; + + bool consistent{ false }; + + bool buildVertTriRelationMap{ false }; + std::multimap<Vertex *, TriFace *> relationVertTris; + + Kd::Tree<double> *kdTree = nullptr; +}; + +#endif // GBTRIFACEMESH3D_H diff --git a/src/basics/geometry3d/GbTriangularMesh3D.cpp b/src/basics/geometry3d/GbTriangularMesh3D.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3fc0495fad3a1426a9749b43bca7348be4aa6186 --- /dev/null +++ b/src/basics/geometry3d/GbTriangularMesh3D.cpp @@ -0,0 +1,1531 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file GbTriangularMesh3D.cpp +//! \ingroup geometry3D +//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller +//======================================================================================= +#include <geometry3d/GbTriangularMesh3D.h> + +#include <map> + +#include <basics/utilities/UbMath.h> + +#include <geometry3d/CoordinateTransformation3D.h> +#include <geometry3d/GbCuboid3D.h> +#include <geometry3d/GbHalfSpace3D.h> + +using namespace std; + +GbTriangularMesh3D::GbTriangularMesh3D() : GbObject3D() +{ + this->setName("new GbMesh"); + this->nodes = new vector<GbPoint3D *>; + this->triangles = new vector<GbTriangle3D *>; + this->edges = new vector<GbLine3D *>; + + this->pointinobjecttest = RAYCROSSING; + + this->consistent = false; + x1min = x1max = x2min = x2max = x3min = x3max = 0.0; +} +/*=============================================================================================*/ +GbTriangularMesh3D::GbTriangularMesh3D(string name, vector<GbPoint3D *> *nodes, vector<GbTriangle3D *> *triangles) + : GbObject3D() +{ + if (name.size() == 0) + throw UbException(UB_EXARGS, "no name specified"); + if (!nodes) + throw UbException(UB_EXARGS, "no nodes specified"); + if (!triangles) + throw UbException(UB_EXARGS, "no triangles specified"); + + this->setName(name); + this->nodes = nodes; + this->triangles = triangles; + this->edges = new vector<GbLine3D *>; + this->pointinobjecttest = RAYCROSSING; + + this->consistent = false; + x1min = x1max = x2min = x2max = x3min = x3max = 0.0; +} +/*=============================================================================================*/ +GbTriangularMesh3D::GbTriangularMesh3D(string name, vector<GbTriangle3D *> *tris) : GbObject3D() +{ + cout << "Das Teil erzeugt seinen KnotenVector aus den Dreiecken ...\n Es sollte deleteRedundantNodes() aufgerufen " + "werden \n"; + if (name.size() == 0) + throw UbException(UB_EXARGS, "no name specified"); + if (!tris) + throw UbException(UB_EXARGS, "no triangles specified"); + + vector<GbPoint3D *> *points = new vector<GbPoint3D *>; + this->triangles = new vector<GbTriangle3D *>; + GbPoint3D *p1 = NULL; + GbPoint3D *p2 = NULL; + GbPoint3D *p3 = NULL; + for (int u = 0; u < (int)tris->size(); u++) { + if (UbMath::zero((*tris)[u]->getArea())) { + (*tris)[u]->finalize(); + delete (*tris)[u]; + (*tris)[u] = NULL; + continue; + } + this->triangles->push_back((*tris)[u]); + p1 = (*tris)[u]->getPoint1(); + p2 = (*tris)[u]->getPoint2(); + p3 = (*tris)[u]->getPoint3(); + points->push_back(p1); + points->push_back(p2); + points->push_back(p3); + } + + this->setName(name); + this->nodes = points; + // this->triangles = triangles; + this->edges = new vector<GbLine3D *>; + this->edges->resize(0, NULL); + this->pointinobjecttest = RAYCROSSING; + + this->consistent = false; + x1min = x1max = x2min = x2max = x3min = x3max = 0.0; +} +/*=============================================================================================*/ +GbTriangularMesh3D::GbTriangularMesh3D(string name, vector<GbPoint3D *> *nodes, vector<GbLine3D *> *edges, + vector<GbTriangle3D *> *triangles) + : GbObject3D() +{ + if (name.size() == 0) + throw UbException(UB_EXARGS, "no name specified"); + if (!nodes) + throw UbException(UB_EXARGS, "no nodes specified"); + if (!triangles) + throw UbException(UB_EXARGS, "no triangles specified"); + if (!edges) + throw UbException(UB_EXARGS, "no edges specified"); + + this->setName(name); + this->nodes = nodes; + this->edges = edges; + this->triangles = triangles; + this->pointinobjecttest = RAYCROSSING; + + this->consistent = false; + x1min = x1max = x2min = x2max = x3min = x3max = 0.0; +} +/*=============================================================================================*/ +GbTriangularMesh3D::~GbTriangularMesh3D() +{ + if (this->nodes) { + for (unsigned u = 0; u < nodes->size(); u++) + delete (*nodes)[u]; + delete nodes; + } + if (triangles) { + for (unsigned u = 0; u < triangles->size(); u++) + delete (*triangles)[u]; + delete triangles; + } +} +/*======================================================================*/ +void GbTriangularMesh3D::deleteRedundantNodes() +{ + std::map<GbPoint3D *, GbTriangle3D *> pointTriMap; + GbPoint3D *p1 = NULL; + GbPoint3D *p2 = NULL; + GbPoint3D *p3 = NULL; + GbTriangle3D *tri = NULL; + + for (int u = 0; u < (int)this->triangles->size(); u++) { + tri = (*this->triangles)[u]; + p1 = tri->getPoint1(); + p2 = tri->getPoint2(); + p3 = tri->getPoint3(); + pointTriMap.insert(pair<GbPoint3D *, GbTriangle3D *>(p1, tri)); + pointTriMap.insert(pair<GbPoint3D *, GbTriangle3D *>(p2, tri)); + pointTriMap.insert(pair<GbPoint3D *, GbTriangle3D *>(p3, tri)); + } + + cout << "Nodes before deleting redundant:" << this->nodes->size() << endl; + GbPoint3D *pA = NULL; + GbPoint3D *pB = NULL; + std::map<GbPoint3D *, GbTriangle3D *>::iterator mapIterator; + for (int u = 0; u < (int)this->nodes->size(); u++) { + // cout<<u<<" von "<<this->nodes->size()<<endl; + pA = (*this->nodes)[u]; + if (pA == NULL) + continue; + for (int w = u + 1; w < (int)this->nodes->size(); w++) { + // cout<<w<<" Wvon "<<this->nodes->size()<<endl; + pB = (*this->nodes)[w]; + if (pB == NULL) + continue; + if (pA->equals(pB)) { + // doppelter Knoten ... + mapIterator = pointTriMap.find(pB); + tri = dynamic_cast<GbTriangle3D *>(mapIterator->second); + if (!tri) + throw UbException(UB_EXARGS, "triangle not found"); + p1 = tri->getPoint1(); + p2 = tri->getPoint2(); + p3 = tri->getPoint3(); + if (pB == p1) + tri->setPoint(pA, 0); + else if (pB == p2) + tri->setPoint(pA, 1); + else if (pB == p3) + tri->setPoint(pA, 2); + else + throw UbException(UB_EXARGS, "node should be there"); + delete pB; + (*this->nodes)[w] = NULL; + } + } + } + vector<GbPoint3D *> *points = new vector<GbPoint3D *>; + for (int u = 0; u < (int)this->nodes->size(); u++) { + pA = (*this->nodes)[u]; + if (pA != NULL) + points->push_back(pA); + } + delete this->nodes; + this->nodes = points; + cout << "Nodes after deleting redundant:" << this->nodes->size() << endl; + + // nochmal kontrolle ... + pointTriMap.clear(); + for (int u = 0; u < (int)this->triangles->size(); u++) { + tri = (*this->triangles)[u]; + p1 = tri->getPoint1(); + p2 = tri->getPoint2(); + p3 = tri->getPoint3(); + pointTriMap.insert(pair<GbPoint3D *, GbTriangle3D *>(p1, tri)); + pointTriMap.insert(pair<GbPoint3D *, GbTriangle3D *>(p2, tri)); + pointTriMap.insert(pair<GbPoint3D *, GbTriangle3D *>(p3, tri)); + } + for (int u = 0; u < (int)this->nodes->size(); u++) { + pA = (*this->nodes)[u]; + if (pA == NULL) + throw UbException(UB_EXARGS, "sollte kein NULL pointer sein ..."); + mapIterator = pointTriMap.find(pA); + tri = dynamic_cast<GbTriangle3D *>(mapIterator->second); + if (!tri) + throw UbException(UB_EXARGS, "triangle not found"); + } +} +/*======================================================================*/ +void GbTriangularMesh3D::translate(const double &x1, const double &x2, const double &x3) +{ + GbPoint3D *pt; + for (int u = 0; u < (int)this->nodes->size(); u++) { + pt = (*nodes)[u]; + pt->setX1(pt->getX1Coordinate() + x1); + pt->setX2(pt->getX2Coordinate() + x2); + pt->setX3(pt->getX3Coordinate() + x3); + } + this->consistent = false; +} +/*======================================================================*/ +void GbTriangularMesh3D::rotate(const double &alpha, const double &beta, const double &gamma) +{ + if (!this->consistent) + this->calculateValues(); + double a1 = this->getX1Centroid(); + double a2 = this->getX2Centroid(); + double a3 = this->getX3Centroid(); + CoordinateTransformation3D trafoFor(a1, a2, a3, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0); + CoordinateTransformation3D trafoBack(a1, a2, a3, 1.0, 1.0, 1.0, alpha, beta, gamma); + + vector<GbPoint3D *> points; + GbPoint3D *p1 = NULL; + GbPoint3D *p2 = NULL; + GbPoint3D *p3 = NULL; + for (int u = 0; u < (int)this->triangles->size(); u++) { + p1 = (*triangles)[u]->getPoint1(); + p2 = (*triangles)[u]->getPoint2(); + p3 = (*triangles)[u]->getPoint3(); + double p1x1 = trafoFor.transformForwardToX1Coordinate(p1->x1, p1->x2, p1->x3); + double p1x2 = trafoFor.transformForwardToX2Coordinate(p1->x1, p1->x2, p1->x3); + double p1x3 = trafoFor.transformForwardToX3Coordinate(p1->x1, p1->x2, p1->x3); + double p2x1 = trafoFor.transformForwardToX1Coordinate(p2->x1, p2->x2, p2->x3); + double p2x2 = trafoFor.transformForwardToX2Coordinate(p2->x1, p2->x2, p2->x3); + double p2x3 = trafoFor.transformForwardToX3Coordinate(p2->x1, p2->x2, p2->x3); + double p3x1 = trafoFor.transformForwardToX1Coordinate(p3->x1, p3->x2, p3->x3); + double p3x2 = trafoFor.transformForwardToX2Coordinate(p3->x1, p3->x2, p3->x3); + double p3x3 = trafoFor.transformForwardToX3Coordinate(p3->x1, p3->x2, p3->x3); + p1->x1 = trafoBack.transformBackwardToX1Coordinate(p1x1, p1x2, p1x3); + p1->x2 = trafoBack.transformBackwardToX2Coordinate(p1x1, p1x2, p1x3); + p1->x3 = trafoBack.transformBackwardToX3Coordinate(p1x1, p1x2, p1x3); + p2->x1 = trafoBack.transformBackwardToX1Coordinate(p2x1, p2x2, p2x3); + p2->x2 = trafoBack.transformBackwardToX2Coordinate(p2x1, p2x2, p2x3); + p2->x3 = trafoBack.transformBackwardToX3Coordinate(p2x1, p2x2, p2x3); + p3->x1 = trafoBack.transformBackwardToX1Coordinate(p3x1, p3x2, p3x3); + p3->x2 = trafoBack.transformBackwardToX2Coordinate(p3x1, p3x2, p3x3); + p3->x3 = trafoBack.transformBackwardToX3Coordinate(p3x1, p3x2, p3x3); + } + this->calculateValues(); +} +/*======================================================================*/ +/** + * Returns a string representation of this triangular mesh. + * @return a string representation of this triangular mesh + */ +string GbTriangularMesh3D::toString() +{ + stringstream ss; + ss << "GbTriangularMesh3D["; + ss << (int)this->triangles->size() << "-Triangles, " << (int)this->nodes->size() << "-Nodes, " + << (int)this->edges->size() << "-Edges" << endl; + // ss<<"\""<<this->name<<", Area=sollt mal berechnet werden ;-)"<<"\""; + // ss<<", x1min="<<this->x1min; + // ss<<", x1max="<<this->x1max; + // ss<<", x2min="<<this->x2min; + // ss<<", x2max="<<this->x2max; + // ss<<", x3min="<<this->x3min; + // ss<<", x3max="<<this->x3max; + ss << "]"; + return (ss.str()); +} +/** + * Returns the name of this triangular mesh. + * @return the name of this triangular mesh + */ +// string GbTriangularMesh3D::getName(){ return(this->name); } + +/** + * Returns the nodes of this triangular mesh. + * @return the nodes of this triangular mesh + */ +vector<GbPoint3D *> *GbTriangularMesh3D::getNodes() { return (this->nodes); } +/** + * Returns the triangles of this triangular mesh. + * @return the triangles of this triangular mesh + */ +vector<GbTriangle3D *> *GbTriangularMesh3D::getTriangles() { return (this->triangles); } +/** + * Returns the center x1 coordinate of this triangular mesh. + * @return the center x1 coordinate of this triangular mesh + */ +double GbTriangularMesh3D::getX1Centroid() +{ + if (!this->consistent) + this->calculateValues(); + return (0.5 * (this->x1min + this->x1max)); +} +/** + * Returns the center x2 coordinate of this triangular mesh. + * @return the center x2 coordinate of this triangular mesh + */ +double GbTriangularMesh3D::getX2Centroid() +{ + if (!this->consistent) + this->calculateValues(); + return (0.5 * (this->x2min + this->x2max)); +} +/** + * Returns the center x3 coordinate of this triangular mesh. + * @return the center x3 coordinate of this triangular mesh + */ +double GbTriangularMesh3D::getX3Centroid() +{ + if (!this->consistent) + this->calculateValues(); + return (0.5 * (this->x3min + this->x3max)); +} + +/** + * Returns the minimum x1 coordinate of this triangular mesh. + * @return the minimum x1 coordinate of this triangular mesh + */ +double GbTriangularMesh3D::getX1Minimum() +{ + if (!this->consistent) + this->calculateValues(); + return (this->x1min); +} +/** + * Returns the maximum x1 coordinate of this triangular mesh. + * @return the maximum x1 coordinate of this triangular mesh + */ +double GbTriangularMesh3D::getX1Maximum() +{ + if (!this->consistent) + this->calculateValues(); + return (this->x1max); +} +/** + * Returns the minimum x2 coordinate of this triangular mesh. + * @return the minimum x2 coordinate of this triangular mesh + */ +double GbTriangularMesh3D::getX2Minimum() +{ + if (!this->consistent) + this->calculateValues(); + return (this->x2min); +} +/** + * Returns the maximum x2 coordinate of this triangular mesh. + * @return the maximum x2 coordinate of this triangular mesh + */ +double GbTriangularMesh3D::getX2Maximum() +{ + if (!this->consistent) + this->calculateValues(); + return (this->x2max); +} +/** + * Returns the minimum x3 coordinate of this triangular mesh. + * @return the minimum x3 coordinate of this triangular mesh + */ +double GbTriangularMesh3D::getX3Minimum() +{ + if (!this->consistent) + this->calculateValues(); + return (this->x3min); +} +/** + * Returns the maximum x3 coordinate of this triangular mesh. + * @return the maximum x3 coordinate of this triangular mesh + */ +double GbTriangularMesh3D::getX3Maximum() +{ + if (!this->consistent) + this->calculateValues(); + return (this->x3max); +} + +void GbTriangularMesh3D::calculateValues() +{ + double x1, x2, x3; + + this->x1min = (*this->nodes)[0]->getX1Coordinate(); + this->x1max = (*this->nodes)[0]->getX1Coordinate(); + this->x2min = (*this->nodes)[0]->getX2Coordinate(); + this->x2max = (*this->nodes)[0]->getX2Coordinate(); + this->x3min = (*this->nodes)[0]->getX3Coordinate(); + this->x3max = (*this->nodes)[0]->getX3Coordinate(); + + for (int i = 1; i < (int)this->nodes->size(); i++) { + x1 = (*this->nodes)[i]->getX1Coordinate(); + x2 = (*this->nodes)[i]->getX2Coordinate(); + x3 = (*this->nodes)[i]->getX3Coordinate(); + if (x1 < this->x1min) + this->x1min = x1; + if (x1 > this->x1max) + this->x1max = x1; + if (x2 < this->x2min) + this->x2min = x2; + if (x2 > this->x2max) + this->x2max = x2; + if (x3 < this->x3min) + this->x3min = x3; + if (x3 > this->x3max) + this->x3max = x3; + } + this->consistent = true; +} + +/** + * Returns the total area of this triangular mesh. + * @return the total area of this triangular mesh + */ +double GbTriangularMesh3D::getArea() +{ + double area = 0.0; + for (int i = 0; i < (int)this->triangles->size(); i++) + area += (*this->triangles)[i]->getArea(); + return (area); +} +/** + * Returns the total volume of this triangular mesh. + * @return the total volume of this triangular mesh + */ +double GbTriangularMesh3D::getVolume() +{ + GbTriangle3D *triangle; + GbPoint3D *p1; + GbPoint3D *p2; + GbPoint3D *p3; + + double x1, x2, x3, y1, y2, y3, z1, z2, z3; + double G3i; + double volume = 0.0; + int size = (int)this->triangles->size(); + for (int u = 0; u < size; u++) { + triangle = (*this->triangles)[u]; + p1 = triangle->getPoint1(); + p2 = triangle->getPoint2(); + p3 = triangle->getPoint3(); + x1 = p1->getX1Coordinate(); + y1 = p1->getX2Coordinate(); + z1 = p1->getX3Coordinate(); + x2 = p2->getX1Coordinate(); + y2 = p2->getX2Coordinate(); + z2 = p2->getX3Coordinate(); + x3 = p3->getX1Coordinate(); + y3 = p3->getX2Coordinate(); + z3 = p3->getX3Coordinate(); + G3i = x1 * (y2 * z3 - z2 * y3) + y1 * (z2 * x3 - x2 * z3) + z1 * (x2 * y3 - y2 * x3); + volume = volume + G3i / 6.0; + } + return volume; +} +/*===============================================*/ +UbTupleDouble3 GbTriangularMesh3D::calculateCenterOfGravity() +{ + GbTriangle3D *triangle; + GbPoint3D *p1; + GbPoint3D *p2; + GbPoint3D *p3; + + double x1, x2, x3, y1, y2, y3, z1, z2, z3; + double G3i; + double rSP1 = 0.0; + double rSP2 = 0.0; + double rSP3 = 0.0; + double volume = 0.0; + int size = (int)this->triangles->size(); + for (int u = 0; u < size; u++) { + triangle = (*this->triangles)[u]; + p1 = triangle->getPoint1(); + p2 = triangle->getPoint2(); + p3 = triangle->getPoint3(); + x1 = p1->getX1Coordinate(); + y1 = p1->getX2Coordinate(); + z1 = p1->getX3Coordinate(); + x2 = p2->getX1Coordinate(); + y2 = p2->getX2Coordinate(); + z2 = p2->getX3Coordinate(); + x3 = p3->getX1Coordinate(); + y3 = p3->getX2Coordinate(); + z3 = p3->getX3Coordinate(); + G3i = x1 * (y2 * z3 - z2 * y3) + y1 * (z2 * x3 - x2 * z3) + z1 * (x2 * y3 - y2 * x3); + volume = volume + G3i / 6.0; + rSP1 = rSP1 + G3i * (x1 + x2 + x3); + rSP2 = rSP2 + G3i * (y1 + y2 + y3); + rSP3 = rSP3 + G3i * (z1 + z2 + z3); + } + rSP1 = rSP1 / (24.0 * volume); + rSP2 = rSP2 / (24.0 * volume); + rSP3 = rSP3 / (24.0 * volume); + + return { rSP1, rSP2, rSP3 }; +} +/*===============================================*/ +UbTupleDouble6 GbTriangularMesh3D::calculateMomentOfInertia(double rhoP) +{ + GbTriangle3D *triangle; + GbPoint3D *p1; + GbPoint3D *p2; + GbPoint3D *p3; + + double x1, x2, x3, y1, y2, y3, z1, z2, z3; + double G3i; + double xx, yy, zz, xy, yz, zx; + double rSP1 = 0.0; + double rSP2 = 0.0; + double rSP3 = 0.0; + double volume = 0.0; + double top11 = 0.0; + double top22 = 0.0; + double top33 = 0.0; + double top12 = 0.0; + double top23 = 0.0; + double top13 = 0.0; + int size = (int)this->triangles->size(); + for (int u = 0; u < size; u++) { + triangle = (*this->triangles)[u]; + p1 = triangle->getPoint1(); + p2 = triangle->getPoint2(); + p3 = triangle->getPoint3(); + x1 = p1->getX1Coordinate(); + y1 = p1->getX2Coordinate(); + z1 = p1->getX3Coordinate(); + x2 = p2->getX1Coordinate(); + y2 = p2->getX2Coordinate(); + z2 = p2->getX3Coordinate(); + x3 = p3->getX1Coordinate(); + y3 = p3->getX2Coordinate(); + z3 = p3->getX3Coordinate(); + G3i = x1 * (y2 * z3 - z2 * y3) + y1 * (z2 * x3 - x2 * z3) + z1 * (x2 * y3 - y2 * x3); + volume = volume + G3i / 6.0; + rSP1 = rSP1 + G3i * (x1 + x2 + x3); + rSP2 = rSP2 + G3i * (y1 + y2 + y3); + rSP3 = rSP3 + G3i * (z1 + z2 + z3); + } + rSP1 = rSP1 / (24.0 * volume); + rSP2 = rSP2 / (24.0 * volume); + rSP3 = rSP3 / (24.0 * volume); + + double x1s = 0.0; // rSP1;//0.0;// + double x2s = 0.0; // rSP2;//0.0;// + double x3s = 0.0; // rSP3;//0.0;// + + for (int u = 0; u < size; u++) { + triangle = (*this->triangles)[u]; + p1 = triangle->getPoint1(); + p2 = triangle->getPoint2(); + p3 = triangle->getPoint3(); + x1 = p1->getX1Coordinate() - x1s; + y1 = p1->getX2Coordinate() - x2s; + z1 = p1->getX3Coordinate() - x3s; + x2 = p2->getX1Coordinate() - x1s; + y2 = p2->getX2Coordinate() - x2s; + z2 = p2->getX3Coordinate() - x3s; + x3 = p3->getX1Coordinate() - x1s; + y3 = p3->getX2Coordinate() - x2s; + z3 = p3->getX3Coordinate() - x3s; + G3i = x1 * (y2 * z3 - z2 * y3) + y1 * (z2 * x3 - x2 * z3) + z1 * (x2 * y3 - y2 * x3); + // rSP1 = rSP1+G3i*(x1+x2+x3)/(24.0*volume); + // rSP2 = rSP2+G3i*(y1+y2+y3)/(24.0*volume); + // rSP3 = rSP3+G3i*(z1+z2+z3)/(24.0*volume); + xx = x1 * x1 + x2 * x2 + x3 * x3 + x1 * x2 + x2 * x3 + x3 * x1; + yy = y1 * y1 + y2 * y2 + y3 * y3 + y1 * y2 + y2 * y3 + y3 * y1; + zz = z1 * z1 + z2 * z2 + z3 * z3 + z1 * z2 + z2 * z3 + z3 * z1; + top11 = top11 + (yy + zz) * rhoP * G3i / 60.; + top22 = top22 + (xx + zz) * rhoP * G3i / 60.; + top33 = top33 + (yy + xx) * rhoP * G3i / 60.; + xy = 2.0 * (x1 * y1 + x2 * y2 + x3 * y3) + x2 * y3 + x3 * y1 + x1 * y2 + x3 * y2 + x1 * y3 + x2 * y1; + yz = 2.0 * (y1 * z1 + y2 * z2 + y3 * z3) + y2 * z3 + y3 * z1 + y1 * z2 + y3 * z2 + y1 * z3 + y2 * z1; + zx = 2.0 * (z1 * x1 + z2 * x2 + z3 * x3) + z2 * x3 + z3 * x1 + z1 * x2 + z3 * x2 + z1 * x3 + z2 * x1; + top12 = top12 - xy * rhoP * G3i / 120.; + top23 = top23 - yz * rhoP * G3i / 120.; + top13 = top13 - zx * rhoP * G3i / 120.; + } + // Satz von Steiner ... + top11 = top11 - rhoP * volume * (rSP2 * rSP2 + rSP3 + rSP3); + top22 = top22 - rhoP * volume * (rSP3 * rSP3 + rSP1 * rSP1); + top33 = top33 - rhoP * volume * (rSP1 * rSP1 + rSP2 * rSP2); + top12 = top12 + rhoP * volume * rSP1 * rSP2; + top23 = top23 + rhoP * volume * rSP2 * rSP3; + top13 = top13 + rhoP * volume * rSP3 * rSP1; + + cout << "Volume:" << volume << "\n Traegheitsmomente:\n"; + cout << " top11:" << top11 << " top22:" << top22 << " top33:" << top33 << endl; + cout << " top12:" << top12 << " top23:" << top23 << " top13:" << top13 << endl; + + return { top11, top22, top33, top12, top23, top13 }; +} + +/** + * Returns the volume of this triangular mesh within the specified rectangle. + * @param p1x1 the 1st x1 coordinate of the rectangle + * @param p1x2 the 1st x2 coordinate of the rectangle + * @param p2x1 the 2nd x1 coordinate of the rectangle + * @param p2x2 the 2nd x2 coordinate of the rectangle + * @return the volume of this triangular mesh within the specified rectangle + * @exception NullPointerException if no triangles are found within the specified rectangle + */ +double GbTriangularMesh3D::getVolumeForRectangle(const double & /*p1x1*/, const double & /*p1x2*/, + const double & /*p2x1*/, const double & /*p2x2*/) +{ + throw UbException(UB_EXARGS, "not yet implemented"); + // GbPolygon2D polygon; + // double volume = 0.0; + // double area1 = Math.abs((p1x1-p2x1)*(p1x2-p2x2)); + // double area2 = 0.0; + // double t1min, t1max, t2min, t2max; + // double x1, x2; + // boolean f = false; + + // for(int i=0; i<this.triangles.length; i++) + // { + // t1min = this.triangles[i].getX1Minimum(); + // t1max = this.triangles[i].getX1Maximum(); + // if(GbSystem.less2(t1min, t1max, p1x1, p2x1)) continue; + // if(GbSystem.greater2(t1min, t1max, p1x1, p2x1)) continue; + + // t2min = this.triangles[i].getX2Minimum(); + // t2max = this.triangles[i].getX2Maximum(); + // if(GbSystem.less2(t2min, t2max, p1x2, p2x2)) continue; + // if(GbSystem.greater2(t2min, t2max, p1x2, p2x2)) continue; + + // if(GbSystem.inOpenInterval(t1min, p1x1, p2x1) && GbSystem.inOpenInterval(t1max, p1x1, p2x1) && + // GbSystem.inOpenInterval(t2min, p1x2, p2x2) && GbSystem.inOpenInterval(t2max, p1x2, p2x2)) + // { + // volume += this.triangles[i].getVolume(); + // area2 += this.triangles[i].getArea(); + // f = true; + // } + // else + // { + // polygon = this.triangles[i].createClippedPolygon3D(p1x1, p1x2, p2x1, p2x2); + + // if(polygon != null && polygon.size() > 2) + // { + // try + // { + // x1 = polygon.getX1Centroid(); + // x2 = polygon.getX2Centroid(); + // volume += this.triangles[i].getX3Coordinate(x1, x2) * Math.abs(polygon.getArea()); + // area2 += Math.abs(polygon.getArea()); + // f = true; + // } + // catch(Exception e){} + // } + // } + // if(GbSystem.greaterEqual(area2, area1)) break; + //} + // if(f) return(volume); + // else throw new NullPointerException(); +} + +/** + * Returns the triangles of this triangular mesh located within the specified rectangle (may be an empty array). + * @param p1x1 the 1st x1 coordinate of the rectangle + * @param p1x2 the 1st x2 coordinate of the rectangle + * @param p2x1 the 2nd x1 coordinate of the rectangle + * @param p2x2 the 2nd x2 coordinate of the rectangle + * @return the triangles of this triangular mesh located within the specified rectangle + */ +vector<GbTriangle3D *> *GbTriangularMesh3D::getTrianglesForRectangle(const double & /*p1x1*/, const double & /*p1x2*/, + const double & /*p2x1*/, const double & /*p2x2*/) +{ + throw UbException(UB_EXARGS, "not yet implemented"); + // QbList triangleList = new QbList(GbTriangle3D.class); + // GbPolygon2D polygon; + // double t1min, t1max, t2min, t2max; + // double area1 = Math.abs((p1x1-p2x1)*(p1x2-p2x2)); + // double area2 = 0.0; + + // for(int i=0; i<this.triangles.length; i++) + // { + // t1min = this.triangles[i].getX1Minimum(); + // t1max = this.triangles[i].getX1Maximum(); + // if(GbSystem.less2(t1min, t1max, p1x1, p2x1)) continue; + // if(GbSystem.greater2(t1min, t1max, p1x1, p2x1)) continue; + + // t2min = this.triangles[i].getX2Minimum(); + // t2max = this.triangles[i].getX2Maximum(); + // if(GbSystem.less2(t2min, t2max, p1x2, p2x2)) continue; + // if(GbSystem.greater2(t2min, t2max, p1x2, p2x2)) continue; + + // if(GbSystem.inOpenInterval(t1min, p1x1, p2x1) && GbSystem.inOpenInterval(t1max, p1x1, p2x1) && + // GbSystem.inOpenInterval(t2min, p1x2, p2x2) && GbSystem.inOpenInterval(t2max, p1x2, p2x2)) + // { + // try { triangleList.append(this.triangles[i]); } catch(Exception e){} + // area2 += this.triangles[i].getArea(); + // } + // else + // { + // polygon = this.triangles[i].createClippedPolygon3D(p1x1, p1x2, p2x1, p2x2); + // if(polygon != null && polygon.size() > 2) + // { + // try { triangleList.append(this.triangles[i]); } catch(Exception e){} + // area2 += Math.abs(polygon.getArea()); + // } + // } + // if(GbSystem.greaterEqual(area2, area1)) break; + //} + // return((GbTriangle3D[])triangleList.getObjectArray()); +} +/** + * Returns the nodes of this triangular mesh located within the specified rectangle (may be an empty array). + * @param p1x1 the 1st x1 coordinate of the rectangle + * @param p1x2 the 1st x2 coordinate of the rectangle + * @param p2x1 the 2nd x1 coordinate of the rectangle + * @param p2x2 the 2nd x2 coordinate of the rectangle + * @return the nodes of this triangular mesh located within the specified rectangle + */ +vector<GbPoint3D *> *GbTriangularMesh3D::getNodesForRectangle(const double & /*p1x1*/, const double & /*p1x2*/, + const double & /*p2x1*/, const double & /*p2x2*/) +{ + throw UbException(UB_EXARGS, "not implemented"); + // QbList nodeList = new QbList(GbPoint3D.class); + + // for(int i=0; i<this.edges.length; i++) + // { + // if(GbSystem.inClosedInterval(this.nodes[i].getX1Coordinate(), p1x1, p2x1) && + // GbSystem.inClosedInterval(this.nodes[i].getX2Coordinate(), p1x2, p2x2)) + //{ + // try { nodeList.append(this.nodes[i]); } catch(Exception e){} + //} + // } + // return((GbPoint3D[])nodeList.getObjectArray()); +} + +/** + * Returns the difference of maximum and minimum x3 coordinates + * of this triangular mesh within the specified rectangle. + * @param p1x1 the 1st x1 coordinate of the rectangle + * @param p1x2 the 1st x2 coordinate of the rectangle + * @param p2x1 the 2nd x1 coordinate of the rectangle + * @param p2x2 the 2nd x2 coordinate of the rectangle + * @return the difference of maximum and minimum x3 coordinates of this triangular mesh within the specified rectangle + * @exception NullPointerException if no triangles are found within the specified rectangle + */ +double GbTriangularMesh3D::getX3RangeForRectangle(const double & /*p1x1*/, const double & /*p1x2*/, + const double & /*p2x1*/, const double & /*p2x2*/) +{ + throw UbException(UB_EXARGS, "not implemented"); + // GbPolygon3D polygon; + // boolean f = false; + // double x3min = 0.0; + // double x3max = 0.0; + // double t1min, t1max, t2min, t2max; + // double area1 = Math.abs((p1x1-p2x1)*(p1x2-p2x2)); + // double area2 = 0.0; + + // for(int i=0; i<this.triangles.length; i++) + // { + // t1min = this.triangles[i].getX1Minimum(); + // t1max = this.triangles[i].getX1Maximum(); + // if(GbSystem.less2(t1min, t1max, p1x1, p2x1)) continue; + // if(GbSystem.greater2(t1min, t1max, p1x1, p2x1)) continue; + + // t2min = this.triangles[i].getX2Minimum(); + // t2max = this.triangles[i].getX2Maximum(); + // if(GbSystem.less2(t2min, t2max, p1x2, p2x2)) continue; + // if(GbSystem.greater2(t2min, t2max, p1x2, p2x2)) continue; + + // if(GbSystem.inOpenInterval(t1min, p1x1, p2x1) && GbSystem.inOpenInterval(t1max, p1x1, p2x1) && + // GbSystem.inOpenInterval(t2min, p1x2, p2x2) && GbSystem.inOpenInterval(t2max, p1x2, p2x2)) + // { + // if(f) + // { + // if(this.triangles[i].getX3Minimum() < x3min) x3min = this.triangles[i].getX3Minimum(); + // if(this.triangles[i].getX3Maximum() > x3max) x3max = this.triangles[i].getX3Maximum(); + // } + // else + // { + // x3min = this.triangles[i].getX3Minimum(); + // x3max = this.triangles[i].getX3Maximum(); + // f = true; + // } + // area2 += this.triangles[i].getArea(); + //} + // else + // { + // polygon = this.triangles[i].createClippedPolygon3D(p1x1, p1x2, p2x1, p2x2); + + // if(polygon != null && polygon.size() > 2) + // { + // if(f) + // { + // if(polygon.getX3Minimum() < x3min) x3min = polygon.getX3Minimum(); + // if(polygon.getX3Maximum() > x3max) x3max = polygon.getX3Maximum(); + // } + // else + // { + // x3min = polygon.getX3Minimum(); + // x3max = polygon.getX3Maximum(); + // f = true; + // } + // area2 += Math.abs(polygon.getArea()); + // } + // } + // if(GbSystem.greaterEqual(area2, area1)) break; + // } + // if(f) return(x3max-x3min); + // else throw new NullPointerException(); +} +/** + * Returns the minimum x3 coordinates of this triangular mesh within the specified rectangle. + * @param p1x1 the 1st x1 coordinate of the rectangle + * @param p1x2 the 1st x2 coordinate of the rectangle + * @param p2x1 the 2nd x1 coordinate of the rectangle + * @param p2x2 the 2nd x2 coordinate of the rectangle + * @return the minimum x3 coordinates of this triangular mesh within the specified rectangle + * @exception NullPointerException if no triangles are found within the specified rectangle + */ +double GbTriangularMesh3D::getX3MinimumForRectangle(const double & /*p1x1*/, const double & /*p1x2*/, + const double & /*p2x1*/, const double & /*p2x2*/) +{ + throw UbException(UB_EXARGS, "not implemented"); + // GbPolygon3D polygon; + // boolean f = false; + // double x3min = 0.0; + // double t1min, t1max, t2min, t2max; + // double area1 = Math.abs((p1x1-p2x1)*(p1x2-p2x2)); + // double area2 = 0.0; + + // for(int i=0; i<this.triangles.length; i++) + // { + // t1min = this.triangles[i].getX1Minimum(); + // t1max = this.triangles[i].getX1Maximum(); + // if(GbSystem.less2(t1min, t1max, p1x1, p2x1)) continue; + // if(GbSystem.greater2(t1min, t1max, p1x1, p2x1)) continue; + + // t2min = this.triangles[i].getX2Minimum(); + // t2max = this.triangles[i].getX2Maximum(); + // if(GbSystem.less2(t2min, t2max, p1x2, p2x2)) continue; + // if(GbSystem.greater2(t2min, t2max, p1x2, p2x2)) continue; + + // if(GbSystem.inOpenInterval(t1min, p1x1, p2x1) && GbSystem.inOpenInterval(t1max, p1x1, p2x1) && + // GbSystem.inOpenInterval(t2min, p1x2, p2x2) && GbSystem.inOpenInterval(t2max, p1x2, p2x2)) + //{ + // if(f) + // { + // if(this.triangles[i].getX3Minimum() < x3min) x3min = this.triangles[i].getX3Minimum(); + // } + // else + // { + // x3min = this.triangles[i].getX3Minimum(); + // f = true; + // } + // area2 += this.triangles[i].getArea(); + //} + // else + //{ + // polygon = this.triangles[i].createClippedPolygon3D(p1x1, p1x2, p2x1, p2x2); + + // if(polygon != null && polygon.size() > 2) + // { + // if(f) + // { + // if(polygon.getX3Minimum() < x3min) x3min = polygon.getX3Minimum(); + // } + // else + // { + // x3min = polygon.getX3Minimum(); + // f = true; + // } + // area2 += Math.abs(polygon.getArea()); + // } + //} + // if(GbSystem.greaterEqual(area2, area1)) break; + // } + // if(f) return(x3min); + // else throw new NullPointerException(); +} +/** + * Returns the maximum x3 coordinates of this triangular mesh within the specified rectangle. + * @param p1x1 the 1st x1 coordinate of the rectangle + * @param p1x2 the 1st x2 coordinate of the rectangle + * @param p2x1 the 2nd x1 coordinate of the rectangle + * @param p2x2 the 2nd x2 coordinate of the rectangle + * @return the maximum x3 coordinates of this triangular mesh within the specified rectangle + * @exception NullPointerException if no triangles are found within the specified rectangle + */ +double GbTriangularMesh3D::getX3MaximumForRectangle(const double & /*p1x1*/, const double & /*p1x2*/, + const double & /*p2x1*/, const double & /*p2x2*/) +{ + throw UbException(UB_EXARGS, "not implemented"); + // GbPolygon3D polygon; + // boolean f = false; + // double x3max = 0.0; + // double t1min, t1max, t2min, t2max; + // double area1 = Math.abs((p1x1-p2x1)*(p1x2-p2x2)); + // double area2 = 0.0; + + // for(int i=0; i<this.triangles.length; i++) + // { + // t1min = this.triangles[i].getX1Minimum(); + // t1max = this.triangles[i].getX1Maximum(); + // if(GbSystem.less2(t1min, t1max, p1x1, p2x1)) continue; + // if(GbSystem.greater2(t1min, t1max, p1x1, p2x1)) continue; + + // t2min = this.triangles[i].getX2Minimum(); + // t2max = this.triangles[i].getX2Maximum(); + // if(GbSystem.less2(t2min, t2max, p1x2, p2x2)) continue; + // if(GbSystem.greater2(t2min, t2max, p1x2, p2x2)) continue; + + // if(GbSystem.inOpenInterval(t1min, p1x1, p2x1) && GbSystem.inOpenInterval(t1max, p1x1, p2x1) && + // GbSystem.inOpenInterval(t2min, p1x2, p2x2) && GbSystem.inOpenInterval(t2max, p1x2, p2x2)) + //{ + // if(f) + // { + // if(this.triangles[i].getX3Maximum() < x3max) x3max = this.triangles[i].getX3Maximum(); + // } + // else + // { + // x3max = this.triangles[i].getX3Maximum(); + // f = true; + // } + // area2 += this.triangles[i].getArea(); + //} + // else + //{ + // polygon = this.triangles[i].createClippedPolygon3D(p1x1, p1x2, p2x1, p2x2); + + // if(polygon != null && polygon.size() > 2) + // { + // if(f) + // { + // if(polygon.getX3Maximum() < x3max) x3max = polygon.getX3Maximum(); + // } + // else + // { + // x3max = polygon.getX3Maximum(); + // f = true; + // } + // area2 += Math.abs(polygon.getArea()); + // } + //} + // if(GbSystem.greaterEqual(area2, area1)) break; + // } + // if(f) return(x3max); + // else throw new NullPointerException(); +} +/*======================================================================*/ +vector<GbTriangle3D *> GbTriangularMesh3D::getSurfaceTriangleSet() +{ + vector<GbTriangle3D *> tris; + GbTriangle3D *triangle; + GbPoint3D *p1; + GbPoint3D *p2; + GbPoint3D *p3; + int size = (int)this->triangles->size(); + for (int u = 0; u < size; u++) { + triangle = (*this->triangles)[u]; + p1 = new GbPoint3D(triangle->getPoint1()); + p2 = new GbPoint3D(triangle->getPoint2()); + p3 = new GbPoint3D(triangle->getPoint3()); + tris.push_back(new GbTriangle3D(p1, p2, p3)); + } + return tris; +} +/*======================================================================*/ +/* + * Function to determine if the point is inside the polyhedron defined as a 3D object + * using the Halfspace algorithm + * @param xp the x-coordinate of the point + * @param yp the y-coordinate of the point + * @param zp the z-coordinate of the point + * @return true if point is inside else return false + */ +bool GbTriangularMesh3D::isPointInObject3DHalfSpace(const double &xp, const double &yp, const double &zp) +{ + vector<GbTriangle3D *> *Triangles = this->triangles; + int Trianglesize = (int)Triangles->size(); + // GbPoint3D Point(xp,yp,zp); + for (int i = 0; i < Trianglesize; i++) { + // GbPoint3D* point1 = (*Triangles)[i]->getPoint1(); + // GbPoint3D* point2 = (*Triangles)[i]->getPoint2(); + // GbPoint3D* point3 = (*Triangles)[i]->getPoint3(); + + // GbHalfSpace3D halfspace(point1, point2, point3); + GbHalfSpace3D halfspace((*Triangles)[i]); + if (halfspace.ptInside(xp, yp, zp)) + return false; + } + return true; +} +/*======================================================================*/ +bool GbTriangularMesh3D::isPointInObject3DRayCrossing(const double &xp, const double &yp, const double &zp, int radius, + int /*numVertices*/, int numTriangles) +{ + GbVector3D point(xp, yp, zp); + + if (this->InPolyhedron(numTriangles, point, radius)) + return true; + else + return false; +} +/*======================================================================*/ +bool GbTriangularMesh3D::isPointInGbObject3D(const double &x1, const double &x2, const double &x3) +{ + double xmin = this->getX1Minimum(); + double xmax = this->getX1Maximum(); + double ymin = this->getX2Minimum(); + double ymax = this->getX2Maximum(); + double zmin = this->getX3Minimum(); + double zmax = this->getX3Maximum(); + double dX = (xmax - xmin) / 100.; + double dY = (ymax - ymin) / 100.; + double dZ = (zmax - zmin) / 100.; + GbCuboid3D boundingCube(xmin - dX, ymin - dY, zmin - dZ, xmax + dX, ymax + dY, zmax + dZ); + if (!boundingCube.isPointInGbObject3D(x1, x2, x3)) { + boundingCube.finalize(); + return false; + } + + // Halfspace algorithm, Area of spherical polygons algorithm or Ray crossing algorithm + GbVector3D bMin(boundingCube.getPoint1()); + GbVector3D bMax(boundingCube.getPoint2()); + + boundingCube.finalize(); + + bMin = bMax.Subtract(bMin); + int radius = (int)(bMin.Length() + 1) + 1; + + if (this->pointinobjecttest == HALFSPACE) + return this->isPointInObject3DHalfSpace(x1, x2, x3); + else if (this->pointinobjecttest == RAYCROSSING) + return this->isPointInObject3DRayCrossing(x1, x2, x3, radius, (int)this->nodes->size(), + (int)this->triangles->size()); + else + throw UbException(UB_EXARGS, "no ptInObjTest"); +} +/*======================================================================*/ +bool GbTriangularMesh3D::isPointInGbObject3D(const double & /*x1*/, const double & /*x2*/, const double & /*x3*/, + bool & /*pointIsOnBoundary*/) +{ + throw UbException(UB_EXARGS, "not implemented"); +} +/*======================================================================*/ +GbLine3D *GbTriangularMesh3D::createClippedLine3D(GbPoint3D & /*point1*/, GbPoint3D & /*point2*/) +{ + throw UbException(UB_EXARGS, "not implemented"); +} +/*======================================================================*/ +void GbTriangularMesh3D::writeMesh(string filename, WbWriter *writer, bool writeNormals) +{ + vector<UbTupleFloat3> nodes(triangles->size() * 3); + vector<UbTupleInt3> tris(triangles->size()); + + for (size_t i = 0; i < triangles->size(); i++) { + GbTriangle3D &tri = *((*triangles)[i]); + GbPoint3D &node1 = *tri.getPoint(0); + GbPoint3D &node2 = *tri.getPoint(1); + GbPoint3D &node3 = *tri.getPoint(2); + + nodes[i * 3] = + makeUbTuple((float)node1.getX1Coordinate(), (float)node1.getX2Coordinate(), (float)node1.getX3Coordinate()); + nodes[i * 3 + 1] = + makeUbTuple((float)node2.getX1Coordinate(), (float)node2.getX2Coordinate(), (float)node2.getX3Coordinate()); + nodes[i * 3 + 2] = + makeUbTuple((float)node3.getX1Coordinate(), (float)node3.getX2Coordinate(), (float)node3.getX3Coordinate()); + + tris[i] = makeUbTuple((int)i * 3, (int)i * 3 + 1, (int)i * 3 + 2); + } + writer->writeTriangles(filename, nodes, tris); + + if (writeNormals) { + vector<UbTupleFloat3> lineNodes(triangles->size() * 2); + vector<UbTupleInt2> lines(triangles->size()); + for (size_t i = 0; i < triangles->size(); i++) { + GbVector3D vec = (*triangles)[i]->getNormal(); + lineNodes[i * 2] = + makeUbTuple((float)(*triangles)[i]->getX1Centroid(), (float)(*triangles)[i]->getX2Centroid(), + (float)(*triangles)[i]->getX3Centroid()); + lineNodes[i * 2 + 1] = makeUbTuple((float)((*triangles)[i]->getX1Centroid() + vec.X1()), + (float)((*triangles)[i]->getX2Centroid() + vec.X2()), + (float)((*triangles)[i]->getX3Centroid() + vec.X3())); + + lines[i] = makeUbTuple((int)i * 2, (int)i * 2 + 1); + } + writer->writeLines(filename + "_normals", lineNodes, lines); + } +} + +/*======================================================================*/ +/* +This function returns a char: +'V': the query point a coincides with a Vertex of polyhedron P. +'E': the query point a is in the relative interior of an Edge of polyhedron P. +'F': the query point a is in the relative interior of a Face of polyhedron P. +'i': the query point a is strictly interior to polyhedron P. +'o': the query point a is strictly exterior to( or outside of) polyhedron P. +*/ +bool GbTriangularMesh3D::InPolyhedron(int F, GbVector3D &q, int radius) +{ + GbVector3D r; /* Ray endpoint. */ + GbVector3D p; /* Intersection point; not used. */ + int f, k = 0, crossings = 0; + char code = '?'; + + while (k++ < F) { + crossings = 0; + + RandomRay(r, radius); + r = q.Add(r); + // printf("Ray endpoint: (%d,%d,%d)\n", r[0],r[1],r[2] ); + + for (f = 0; f < F; f++) /* Begin check each face */ + { + if (BoxTest((*this->triangles)[f], q, r) == false) + code = '0'; // printf("BoxTest = 0!\n"); + else + code = SegTriInt((*this->triangles)[f], q, r, + p); // printf( "Face = %d: BoxTest/SegTriInt returns %c\n\n", f, code ); + + /* If ray is degenerate, then goto outer while to generate another. */ + if (code == 'p' || code == 'v' || code == 'e') + break; // goto LOOP; //printf("Degenerate ray\n"); + /* If ray hits face at interior point, increment crossings. */ + else if (code == 'f') + crossings++; // printf( "crossings = %d\n", crossings ); + /* If query endpoint q sits on a V/E/F, return that code. */ + else if (code == 'V' || code == 'E' || code == 'F') + return true; + /* If ray misses triangle, do nothing. */ + else if (code == '0') { /*nothing to do*/ + } else + throw UbException(UB_EXARGS, "Error"); + } /* End check each face */ + + /* No degeneracies encountered: ray is generic, so finished. */ + if (f >= F) + break; + } /* End while loop */ + + // printf( "Crossings = %d\n", crossings ); + /* q strictly interior to polyhedron iff an odd number of crossings. */ + if ((crossings % 2) == 1) + return true; + + return false; +} + +/* Return a random ray endpoint */ +void GbTriangularMesh3D::RandomRay(GbVector3D &ray, int radius) +{ + double x, y, z, w, t; + + double MAX_INT = 2147483647; + /* Generate a random point on a sphere of radius 1. */ + /* the sphere is sliced at z, and a random point at angle t + generated on the circle of intersection. */ + z = 2.0 * (double)rand() / MAX_INT - 1.0; + t = 2.0 * UbMath::PI * (double)rand() / MAX_INT; + w = sqrt(1 - z * z); + x = w * cos(t); + y = w * sin(t); + + ray[0] = radius * x; + ray[1] = radius * y; + ray[2] = radius * z; + + /*printf( "RandomRay returns %6d %6d %6d\n", ray[X], ray[Y], ray[Z] );*/ +} + +/*--------------------------------------------------------------------- +'p': The segment lies wholly within the plane. +'q': The q endpoint is on the plane (but not 'p'). +'r': The r endpoint is on the plane (but not 'p'). +'0': The segment lies strictly to one side or the other of the plane. +'1': The segement intersects the plane, and 'p' does not hold. +---------------------------------------------------------------------*/ +char GbTriangularMesh3D::SegPlaneInt(GbTriangle3D *T, GbVector3D &q, GbVector3D &r, GbVector3D &p, int *m) +{ + // cout<<"SegPlaneInt..\n"; + GbVector3D N; + double D; + GbVector3D rq; + double num, denom, t; + int i; + + *m = PlaneCoeff(T, N, &D); + /*printf("m=%d; plane=(%lf,%lf,%lf,%lf)\n", m, N[X],N[Y],N[Z],D);*/ + num = D - q.Dot(N); + rq = r.Subtract(q); + denom = rq.Dot(N); + /*printf("SegPlaneInt: num=%lf, denom=%lf\n", num, denom );*/ + + if (denom == 0.0) { /* Segment is parallel to plane. */ + if (num == 0.0) /* q is on plane. */ + // if (UbMath::zero(denom)) { /* Segment is parallel to plane. */ + // if ( UbMath::zero(num)) /* q is on plane. */ + return 'p'; + else + return '0'; + } else + t = num / denom; + /*printf("SegPlaneInt: t=%lf \n", t );*/ + + for (i = 0; i < 3; i++) + p[i] = q[i] + t * (r[i] - q[i]); + + if ((0.0 < t) && (t < 1.0)) + return '1'; + else if (num == 0.0) /* t == 0 */ + return 'q'; + else if (num == denom) /* t == 1 */ + return 'r'; + else + return '0'; + + // if ( (0.0 < t) && (t < 1.0) ) + // return '1'; + // else if ( UbMath::zero(num)) /* t == 0 */ + // return 'q'; + // else if ( UbMath::equal(num , denom) ) /* t == 1 */ + // return 'r'; + // else return '0'; +} +/*--------------------------------------------------------------------- +Computes N & D and returns index m of largest component. +---------------------------------------------------------------------*/ +int GbTriangularMesh3D::PlaneCoeff(GbTriangle3D *T, GbVector3D &N, double *D) +{ + int i; + double t; /* Temp storage */ + double biggest = 0.0; /* Largest component of normal vector. */ + int m = 0; /* Index of largest component. */ + + N = T->getNormal(); + /*printf("PlaneCoeff: N=(%lf,%lf,%lf)\n", N[X],N[Y],N[Z]);*/ + GbVector3D a(T->getPoint1()); + + *D = a.Dot(N); + + /* Find the largest component of N. */ + for (i = 0; i < 3; i++) { + t = std::fabs(N[i]); + if (t > biggest) { + biggest = t; + m = i; + } + } + return m; +} + +/* Assumption: p lies in the plane containing T. +Returns a char: +'V': the query point p coincides with a Vertex of triangle T. +'E': the query point p is in the relative interior of an Edge of triangle T. +'F': the query point p is in the relative interior of a Face of triangle T. +'0': the query point p does not intersect (misses) triangle T. +*/ + +char GbTriangularMesh3D::InTri3D(GbTriangle3D *T, int m, GbVector3D & /*p*/) +{ + // int i; /* Index for X,Y,Z */ + int j; /* Index for X,Y */ + // int k; /* Index for triangle vertex */ + GbVector3D pp; /* projected p */ + GbVector3D Tp[3]; /* projected T: three new vertices */ + + /* Project out coordinate m in both p and the triangular face */ + // j = 0; + // for ( i = 0; i < 3; i++ ) { + // if ( i != m ) { /* skip largest coordinate */ + // pp[j] = p[i]; + // //for ( k = 0; k < 3; k++ ) + // std::cout<<"aachtung###############################################"; + // // Tp[k][j] = Vertices[T[k]][i]; + // j++; + // } + //} + j = 0; + if (m != 0) { + Tp[0][j] = T->getPoint1()->getX1Coordinate(); + Tp[1][j] = T->getPoint2()->getX1Coordinate(); + Tp[2][j] = T->getPoint3()->getX1Coordinate(); + j++; + } + if (m != 1) { + Tp[0][j] = T->getPoint1()->getX2Coordinate(); + Tp[1][j] = T->getPoint2()->getX2Coordinate(); + Tp[2][j] = T->getPoint3()->getX2Coordinate(); + j++; + } + if (m != 2) { + Tp[0][j] = T->getPoint1()->getX3Coordinate(); + Tp[1][j] = T->getPoint2()->getX3Coordinate(); + Tp[2][j] = T->getPoint3()->getX3Coordinate(); + j++; + } + + return (InTri2D(Tp, pp)); +} + +char GbTriangularMesh3D::InTri2D(GbVector3D Tp[3], GbVector3D &pp) +{ + double area0, area1, area2; + + /* compute three AreaSign() values for pp w.r.t. each edge of the face in 2D */ + area0 = AreaSign(pp, Tp[0], Tp[1]); + area1 = AreaSign(pp, Tp[1], Tp[2]); + area2 = AreaSign(pp, Tp[2], Tp[0]); + // printf("area0=%f area1=%f area2=%f\n",area0,area1,area2); + + if (((area0 == 0.) && (area1 > 0.) && (area2 > 0.)) || ((area1 == 0.) && (area0 > 0.) && (area2 > 0.)) || + ((area2 == 0.) && (area0 > 0.) && (area1 > 0.))) + return 'E'; + + if (((area0 == 0.) && (area1 < 0.) && (area2 < 0.)) || ((area1 == 0.) && (area0 < 0.) && (area2 < 0.)) || + ((area2 == 0.) && (area0 < 0.) && (area1 < 0.))) + return 'E'; + + if (((area0 > 0.) && (area1 > 0.) && (area2 > 0.)) || ((area0 < 0.) && (area1 < 0.) && (area2 < 0.))) + return 'F'; + + if ((area0 == 0.0) && (area1 == 0.0) && (area2 == 0.0)) + fprintf(stderr, "Error in InTriD\n"), exit(EXIT_FAILURE); + + if (((area0 == 0.) && (area1 == 0.)) || ((area0 == 0.) && (area2 == 0.)) || ((area1 == 0.) && (area2 == 0.))) + return 'V'; + + else + return '0'; +} + +double GbTriangularMesh3D::AreaSign(GbVector3D &a, GbVector3D &b, GbVector3D &c) +{ + double area2; + + area2 = (b[0] - a[0]) * (c[1] - a[1]) - (c[0] - a[0]) * (b[1] - a[1]); + + return area2; + /* The area should be an integer. */ + // FIXME: unrechable code + // if ( area2 > 0.5 ) return 1; + // else if ( area2 < -0.5 ) return -1; + // else return 0; +} + +char GbTriangularMesh3D::SegTriInt(GbTriangle3D *T, GbVector3D &q, GbVector3D &r, GbVector3D &p) +{ + int code = '?'; + int m = -1; + + code = (unsigned char)SegPlaneInt(T, q, r, p, &m); + // printf("SegPlaneInt code=%c, m=%d; p=(%lf,%lf,%lf)\n", code,m,p[0],p[1],p[2]); + + if (code == '0') + return '0'; + else if (code == 'q') + return InTri3D(T, m, q); + else if (code == 'r') + return InTri3D(T, m, r); + else if (code == 'p') + return InPlane(T, m, q, r, p); + else if (code == '1') + return SegTriCross(T, q, r); + else /* Error */ + return code; +} + +char GbTriangularMesh3D::InPlane(GbTriangle3D * /*T*/, int /*m*/, GbVector3D & /*q*/, GbVector3D & /*r*/, + GbVector3D & /*p*/) +{ + // cout<<"inplane\n"; + /* NOT IMPLEMENTED */ + return 'p'; +} + +/*--------------------------------------------------------------------- +The signed volumes of three tetrahedra are computed, determined +by the segment qr, and each edge of the triangle. +Returns a char: +'v': the open segment includes a vertex of T. +'e': the open segment includes a point in the relative interior of an edge +of T. +'f': the open segment includes a point in the relative interior of a face +of T. +'0': the open segment does not intersect triangle T. +---------------------------------------------------------------------*/ + +char GbTriangularMesh3D::SegTriCross(GbTriangle3D *T, GbVector3D &q, GbVector3D &r) +{ + // cout<<"SegTriCross\n"; + double vol0, vol1, vol2; + GbVector3D vert0(T->getPoint1()); + GbVector3D vert1(T->getPoint2()); + GbVector3D vert2(T->getPoint3()); + + vol0 = VolumeSign(q, vert0, vert1, r); + vol1 = VolumeSign(q, vert1, vert2, r); + vol2 = VolumeSign(q, vert2, vert0, r); + + // printf( "SegTriCross: vol0 = %d; vol1 = %d; vol2 = %d\n", vol0, vol1, vol2 ); + + /* Same sign: segment intersects interior of triangle. */ + if (((vol0 > 0.) && (vol1 > 0.) && (vol2 > 0.)) || ((vol0 < 0.) && (vol1 < 0.) && (vol2 < 0.))) + // if ( ( UbMath::greater(vol0, 0. ) && UbMath::greater(vol1 , 0. ) && UbMath::greater(vol2 , 0. ) ) || + // ( UbMath::less(vol0, 0. ) && UbMath::less(vol1, 0. ) && UbMath::less(vol2, 0. ) ) ) + { + return 'f'; + } + + /* Opposite sign: no intersection between segment and triangle */ + if (((vol0 > 0.) || (vol1 > 0.) || (vol2 > 0.)) && ((vol0 < 0.) || (vol1 < 0.) || (vol2 < 0.))) { + return '0'; + } else if ((vol0 == 0.0) && (vol1 == 0.0) && (vol2 == 0.0)) { + std::cout << vol0 << " " << vol1 << " " << vol2 << std::endl; + fprintf(stderr, "Error 1 in SegTriCross\n"), exit(EXIT_FAILURE); + } + + /* Two zeros: segment intersects vertex. */ + else if (((vol0 == 0.) && (vol1 == 0.)) || ((vol0 == 0.) && (vol2 == 0.)) || ((vol1 == 0.) && (vol2 == 0.))) { + return 'v'; + } + + /* One zero: segment intersects edge. */ + else if ((vol0 == 0.) || (vol1 == 0.) || (vol2 == 0.)) { + return 'e'; + } + + throw UbException(UB_EXARGS, "fprintf( stderr, Error 2 in SegTriCross\n ), exit(EXIT_FAILURE);"); +} + +double GbTriangularMesh3D::VolumeSign(GbVector3D &a, GbVector3D &b, GbVector3D &c, GbVector3D &d) +{ + double vol; + double ax, ay, az, bx, by, bz, cx, cy, cz, dx, dy, dz; + double bxdx, bydy, bzdz, cxdx, cydy, czdz; + + ax = a[0]; + ay = a[1]; + az = a[2]; + bx = b[0]; + by = b[1]; + bz = b[2]; + cx = c[0]; + cy = c[1]; + cz = c[2]; + dx = d[0]; + dy = d[1]; + dz = d[2]; + + bxdx = bx - dx; + bydy = by - dy; + bzdz = bz - dz; + cxdx = cx - dx; + cydy = cy - dy; + czdz = cz - dz; + vol = (az - dz) * (bxdx * cydy - bydy * cxdx) + (ay - dy) * (bzdz * cxdx - bxdx * czdz) + + (ax - dx) * (bydy * czdz - bzdz * cydy); + + // std::cout<< vol<<std::endl; + return vol; + + /* The volume should be an integer. */ + // FIXME: unreachable code + // if ( vol > 0.5 ) return 1; + // else if ( vol < -0.5 ) return -1; + // else return 0; +} + +bool GbTriangularMesh3D::BoxTest(GbTriangle3D *triangle, GbVector3D &PointQ, GbVector3D &PointR) +{ + double minX1 = triangle->getX1Minimum(); + double minX2 = triangle->getX2Minimum(); + double minX3 = triangle->getX3Minimum(); + + double maxX1 = triangle->getX1Maximum(); + double maxX2 = triangle->getX2Maximum(); + double maxX3 = triangle->getX3Maximum(); + + if ((PointQ.X1() < minX1) && (PointR.X1() < minX1)) + return false; + if ((PointQ.X2() < minX2) && (PointR.X2() < minX2)) + return false; + if ((PointQ.X3() < minX3) && (PointR.X3() < minX3)) + return false; + if ((PointQ.X1() > maxX1) && (PointR.X1() > maxX1)) + return false; + if ((PointQ.X2() > maxX2) && (PointR.X2() > maxX2)) + return false; + if ((PointQ.X3() > maxX3) && (PointR.X3() > maxX3)) + return false; + + return true; +} diff --git a/src/basics/geometry3d/GbTriangularMesh3D.h b/src/basics/geometry3d/GbTriangularMesh3D.h new file mode 100644 index 0000000000000000000000000000000000000000..61f8a4f4b7a0b9b1122bf78b74129ec5da437f86 --- /dev/null +++ b/src/basics/geometry3d/GbTriangularMesh3D.h @@ -0,0 +1,199 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file GbTriangularMesh3D.h +//! \ingroup geometry3D +//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller +//======================================================================================= +#ifndef GBTRIANGULARMESH_H +#define GBTRIANGULARMESH_H + +#include <iostream> +#include <sstream> + +#include <geometry3d/GbLine3D.h> +#include <geometry3d/GbPoint3D.h> +#include <geometry3d/GbTriangle3D.h> +#include <geometry3d/GbVector3D.h> + +#include <basics/writer/WbWriter.h> + +#ifdef CAB_RCF +#include <3rdParty/rcf/RcfSerializationIncludes.h> +#endif // CAB_RCF + +#include <PointerDefinitions.h> + +/*=========================================================================*/ +/* GbTriangularMesh3D */ +/* */ +/** + * This Class provides the triangular meshes. + * Note, that up to now no methods for checking consistency are included. + * in this context this class describes facettes from an 3D-object !!! + */ +class GbTriangularMesh3D : public GbObject3D +{ +public: + enum POINTINOBJECTTEST { RAYCROSSING, HALFSPACE }; + + GbTriangularMesh3D(); + GbTriangularMesh3D(std::string name, std::vector<GbPoint3D *> *nodes, std::vector<GbTriangle3D *> *triangles); + GbTriangularMesh3D(std::string name, std::vector<GbTriangle3D *> *triangles); + GbTriangularMesh3D(std::string name, std::vector<GbPoint3D *> *nodes, std::vector<GbLine3D *> *edges, + std::vector<GbTriangle3D *> *triangles); + ~GbTriangularMesh3D() override; + GbTriangularMesh3D *clone() override { throw UbException(UB_EXARGS, "not implemented"); } + void finalize() override { throw UbException("GbTriangularMesh3D::finalize() - toDo"); } + void setPointInObjectTest(POINTINOBJECTTEST mode) { this->pointinobjecttest = mode; } + + std::string getClassName() { return "GbTriangularMesh3D"; } + + std::string toString() override; + // std::string getName(); + std::vector<GbPoint3D *> *getNodes(); + std::vector<GbTriangle3D *> *getTriangles(); + double getX1Centroid() override; + double getX2Centroid() override; + double getX3Centroid() override; + double getX1Minimum() override; + double getX1Maximum() override; + double getX2Minimum() override; + double getX2Maximum() override; + double getX3Minimum() override; + double getX3Maximum() override; + + void rotate(const double &alpha, const double &beta, const double &gamma) override; + void translate(const double &x1, const double &x2, const double &x3) override; + + void calculateValues(); + void deleteRedundantNodes(); + + UbTupleDouble6 calculateMomentOfInertia(double rhoP); + UbTupleDouble3 calculateCenterOfGravity(); + + double getArea(); + double getVolume(); + double getVolumeForRectangle(const double &p1x1, const double &p1x2, const double &p2x1, const double &p2x2); + std::vector<GbTriangle3D *> *getTrianglesForRectangle(const double &p1x1, const double &p1x2, const double &p2x1, + const double &p2x2); + std::vector<GbPoint3D *> *getNodesForRectangle(const double &p1x1, const double &p1x2, const double &p2x1, + const double &p2x2); + double getX3RangeForRectangle(const double &p1x1, const double &p1x2, const double &p2x1, const double &p2x2); + double getX3MinimumForRectangle(const double &p1x1, const double &p1x2, const double &p2x1, const double &p2x2); + double getX3MaximumForRectangle(const double &p1x1, const double &p1x2, const double &p2x1, const double &p2x2); + + bool isPointInGbObject3D(const double &x1, const double &x2, const double &x3) override; + + bool isPointInGbObject3D(const double &x1, const double &x2, const double &x3, bool &pointIsOnBoundary) override; + + bool isPointInObject3DHalfSpace(const double &xp, const double &yp, + const double &zp); // based on Halfspace algorithm + bool isPointInObject3DSpherical(const double &xp, const double &yp, const double &zp, + int numTriangles); // based on Spherical polygon area method + + // should be checked !!! + bool isPointInObject3DRayCrossing(const double &xp, const double &yp, const double &zp, int radius, int numVertices, + int numTriangles); // based on Ray tracing algorithm + + bool InPolyhedron(int F, GbVector3D &q, int radius); + void RandomRay(GbVector3D &ray, int radius); + char SegPlaneInt(GbTriangle3D *Tri, GbVector3D &q, GbVector3D &r, GbVector3D &p, int *m); + int PlaneCoeff(GbTriangle3D *Tri, GbVector3D &Normal, double *D); + char InTri3D(GbTriangle3D *T, int m, GbVector3D &p); + char InTri2D(GbVector3D Tp[3], GbVector3D &pp); + double AreaSign(GbVector3D &a, GbVector3D &b, GbVector3D &c); + char SegTriInt(GbTriangle3D *Tri, GbVector3D &q, GbVector3D &r, GbVector3D &p); + char InPlane(GbTriangle3D *T, int m, GbVector3D &q, GbVector3D &r, GbVector3D &p); + char SegTriCross(GbTriangle3D *T, GbVector3D &q, GbVector3D &r); + double VolumeSign(GbVector3D &a, GbVector3D &b, GbVector3D &c, GbVector3D &d); + bool BoxTest(GbTriangle3D *triangle, GbVector3D &PointQ, GbVector3D &PointR); + // till here !!! + + GbLine3D *createClippedLine3D(GbPoint3D &point1, GbPoint3D &point2) override; + std::vector<GbTriangle3D *> getSurfaceTriangleSet() override; + + void writeMesh(std::string filename, WbWriter *writer, bool writeNormals = false); + /*======================================================================*/ + using GbObject3D::isPointInGbObject3D; // Grund: dadurch muss man hier isPointInGbObject3D(GbPoint3D*) nicht + // ausprogrammieren, welche sonst hier "ueberdeckt" waere + +#ifdef CAB_RCF + template <class Archive> + void SF_SERIALIZE(Archive &ar) + { + SF_SERIALIZE_PARENT<GbObject3D>(ar, *this); + ar &triangles; + if (ArchiveTools::isWriting(ar)) { + for (std::size_t t = 0; t < triangles->size(); t++) { + nodes->push_back((*triangles)[t]->getPoint(0)); + nodes->push_back((*triangles)[t]->getPoint(1)); + nodes->push_back((*triangles)[t]->getPoint(2)); + } + } + // ar & nodes; //<- problem redundanz + // ar & edges; + ar &pointinobjecttest; + ar &x1min; + ar &x1max; + ar &x2min; + ar &x2max; + ar &x3min; + ar &x3max; + ar &consistent; + } +#endif // CAB_RCF + +protected: + std::vector<GbPoint3D *> *nodes; + std::vector<GbLine3D *> *edges; + std::vector<GbTriangle3D *> *triangles; + +private: + POINTINOBJECTTEST pointinobjecttest; + void init(); + /*======================================================================*/ + double x1min; + double x1max; + double x2min; + double x2max; + double x3min; + double x3max; + bool consistent; +}; +/*=========================================================================*/ + +#if defined(RCF_USE_SF_SERIALIZATION) && !defined(SWIG) +#if CAB_RCF <= 903 +SF_SERIALIZE_ENUM(GbTriangularMesh3D::POINTINOBJECTTEST) // bei klassen ausserhalb der klasse;-) +#endif +UB_AUTO_RUN_NAMED(SF::registerType<GbTriangularMesh3D>("GbTriangularMesh3D "), SF_GbTriangularMesh3D); +UB_AUTO_RUN_NAMED((SF::registerBaseAndDerived<GbObject3D, GbTriangularMesh3D>()), SF_GbTriangularMesh3D_BD1); +#endif // RCF_USE_SF_SERIALIZATION + +#endif diff --git a/src/basics/geometry3d/GbVoxelMatrix3D.cpp b/src/basics/geometry3d/GbVoxelMatrix3D.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c88f1d13104a5312efd161143d40e835f5654571 --- /dev/null +++ b/src/basics/geometry3d/GbVoxelMatrix3D.cpp @@ -0,0 +1,996 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file GbVoxelMatrix3D.cpp +//! \ingroup geometry3D +//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller +//======================================================================================= +#include <geometry3d/GbVoxelMatrix3D.h> + +#include <basics/utilities/UbFileInputASCII.h> +#include <basics/utilities/UbFileOutputASCII.h> +#include <basics/utilities/UbMath.h> +#include <geometry3d/CoordinateTransformation3D.h> +#include <geometry3d/GbTriangle3D.h> + +#include <basics/utilities/UbSystem.h> + +#ifdef MC_CUBES +#include <MarchingCubes/MarchingCubes.h> +#endif // MC_CUBES + +using namespace std; + +const float GbVoxelMatrix3D::SOLID = 1.0f; +const float GbVoxelMatrix3D::FLUID = 0.0f; + +/*=======================================================*/ +// Konstruktor +GbVoxelMatrix3D::GbVoxelMatrix3D(int nx1, int nx2, int nx3, float initVal, double lowerThreshold, double upperThreshold) + : GbObject3D(), lowerThreshold(lowerThreshold), upperThreshold(upperThreshold), nodesX1(nx1), nodesX2(nx2), + nodesX3(nx3), voxelMatrix(Matrix3D(nx1, nx2, nx3, initVal)) +{ + this->setName("VoxelMatrix3D"); +} +/*=======================================================*/ +GbVoxelMatrix3D::GbVoxelMatrix3D() : GbObject3D() { this->setName("VoxelMatrix3D"); } +/*=======================================================*/ +GbVoxelMatrix3D::GbVoxelMatrix3D(const Matrix3D &voxelMatrix, double lowerThreshold, double upperThreshold) + : GbObject3D(), nodesX1((int)voxelMatrix.getNX1()), nodesX2((int)voxelMatrix.getNX2()), + nodesX3((int)voxelMatrix.getNX3()), lowerThreshold(lowerThreshold), upperThreshold(upperThreshold), + voxelMatrix(voxelMatrix) +{ + this->setName("VoxelMatrix3D"); +} +/*=======================================================*/ +GbVoxelMatrix3D *GbVoxelMatrix3D::clone() +{ + GbVoxelMatrix3D *vm = new GbVoxelMatrix3D(voxelMatrix, lowerThreshold, upperThreshold); + vm->setVoxelMatrixMininum(minX1, minX2, minX3); + vm->setVoxelMatrixDelta(deltaX1, deltaX2, deltaX3); + return vm; +} +/*=======================================================*/ +void GbVoxelMatrix3D::setCenterCoordinates(const double &x1, const double &x2, const double &x3) +{ + this->translate(x1 - getX1Centroid(), x2 - getX2Centroid(), x3 - getX3Centroid()); +} +/*=======================================================*/ +void GbVoxelMatrix3D::translate(const double &tx1, const double &tx2, const double &tx3) +{ + this->minX1 += tx1; + this->minX2 += tx2; + this->minX3 += tx3; + this->notifyObserversObjectChanged(); +} +/*=======================================================*/ +void GbVoxelMatrix3D::setClosedVoidSpaceToSolid() +{ + voxelMatrixTemp = Matrix3D(nodesX1, nodesX2, nodesX3, SOLID); + flagMatrix = CbArray3D<char>(nodesX1, nodesX2, nodesX3, 0); + + for (int x3 = 0; x3 < nodesX3; x3++) { + for (int x2 = 0; x2 < nodesX2; x2++) { + for (int x1 = 0; x1 < nodesX1; x1++) { + if (voxelMatrix(x1, x2, x3) == FLUID) { + UBLOG(logINFO, "setClosedVoidSpaceToSolid:start"); + x1Nbr.push_back(x1); + x2Nbr.push_back(x2); + x3Nbr.push_back(x3); + int size = (int)x1Nbr.size(); + while (size > 0) { + for (int i = 0; i < size; i++) { + findFluidNeighbor(x1Nbr[i], x2Nbr[i], x3Nbr[i]); + } + + swap(x1Nbr, x1NbrTemp); + swap(x2Nbr, x2NbrTemp); + swap(x3Nbr, x3NbrTemp); + + x1NbrTemp.clear(); + x2NbrTemp.clear(); + x3NbrTemp.clear(); + size = (int)x1Nbr.size(); + } + UBLOG(logINFO, "setClosedVoidSpaceToSolid:end"); + voxelMatrix = voxelMatrixTemp; + return; + } + } + } + } +} +/*=======================================================*/ +void GbVoxelMatrix3D::findFluidNeighbor(int x1, int x2, int x3) +{ + for (int k3 = -1; k3 <= 1; k3++) { + for (int k2 = -1; k2 <= 1; k2++) { + for (int k1 = -1; k1 <= 1; k1++) { + int j1 = x1 + k1; + int j2 = x2 + k2; + int j3 = x3 + k3; + if (j1 >= 0 && j1 < nodesX1 && j2 >= 0 && j2 < nodesX2 && j3 >= 0 && j3 < nodesX3) { + if (voxelMatrix(j1, j2, j3) == FLUID) { + if (flagMatrix(j1, j2, j3) == 0) { + voxelMatrixTemp(j1, j2, j3) = FLUID; + flagMatrix(j1, j2, j3) = 1; + x1NbrTemp.push_back(j1); + x2NbrTemp.push_back(j2); + x3NbrTemp.push_back(j3); + } + } + } + } + } + } +} +/*=======================================================*/ +void GbVoxelMatrix3D::calculateNumberOfSolidAndFluid() +{ + numberOfSolid = 0; + + for (int x3 = 0; x3 < nodesX3; x3++) + for (int x2 = 0; x2 < nodesX2; x2++) + for (int x1 = 0; x1 < nodesX1; x1++) { + if (voxelMatrix(x1, x2, x3) == GbVoxelMatrix3D::SOLID) { + numberOfSolid++; + } + } + + numberOfFluid = (long)nodesX1 * (long)nodesX2 * (long)nodesX3 - numberOfSolid; +} +/*=======================================================*/ +long GbVoxelMatrix3D::getNumberOfSolid() { return numberOfSolid; } +/*=======================================================*/ +long GbVoxelMatrix3D::getNumberOfFluid() { return numberOfFluid; } +/*=======================================================*/ +double GbVoxelMatrix3D::getIntersectionRaytraceFactor(const double &x1, const double &x2, const double &x3, + const double &rx1, const double &rx2, const double &rx3) +{ + if (!((UbMath::equal(rx1, 0.0) || UbMath::equal(fabs(rx1), 1.0) || + UbMath::equal(fabs(rx1), UbMath::one_over_sqrt2) || UbMath::equal(fabs(rx1), UbMath::one_over_sqrt3)) && + (UbMath::equal(rx2, 0.0) || UbMath::equal(fabs(rx2), 1.0) || + UbMath::equal(fabs(rx2), UbMath::one_over_sqrt2) || UbMath::equal(fabs(rx2), UbMath::one_over_sqrt3)) && + (UbMath::equal(rx3, 0.0) || UbMath::equal(fabs(rx3), 1.0) || + UbMath::equal(fabs(rx3), UbMath::one_over_sqrt2) || UbMath::equal(fabs(rx3), UbMath::one_over_sqrt3)))) { + throw UbException(UB_EXARGS, "nur fuer diskrete Boltzmannrichungen implementiert!!!"); + } + + // nachbarindex ermitteln + int ndx1 = 0, ndx2 = 0, ndx3 = 0; + if (UbMath::greater(rx1, 0.0)) + ndx1 = 1; + else if (UbMath::less(rx1, 0.0)) + ndx1 = -1; + if (UbMath::greater(rx2, 0.0)) + ndx2 = 1; + else if (UbMath::less(rx2, 0.0)) + ndx2 = -1; + if (UbMath::greater(rx3, 0.0)) + ndx3 = 1; + else if (UbMath::less(rx3, 0.0)) + ndx3 = -1; + + int nix1 = UbMath::integerRounding((x1 - minX1) / deltaX1) + ndx1; + int nix2 = UbMath::integerRounding((x2 - minX2) / deltaX2) + ndx2; + int nix3 = UbMath::integerRounding((x3 - minX3) / deltaX3) + ndx3; + + // test ob nachbar solid + if (nix1 >= 0 && nix2 >= 0 && nix3 >= 0 && nix1 < (int)voxelMatrix.getNX1() && nix2 < (int)voxelMatrix.getNX2() && + nix3 < (int)voxelMatrix.getNX3()) { + if (UbMath::equal(voxelMatrix(nix1, nix2, nix3), SOLID)) { + // return halber abstand der beiden knoten + return 0.5 * sqrt((ndx1 * deltaX1) * (ndx1 * deltaX1) + (ndx2 * deltaX2) * (ndx2 * deltaX2) + + (ndx3 * deltaX3) * (ndx3 * deltaX3)); + } + } + + return 0.0; +} +/*=======================================================*/ +bool GbVoxelMatrix3D::isPointInGbObject3D(const double &x1p, const double &x2p, const double &x3p) +{ + int ix1 = UbMath::integerRounding((x1p - minX1) / deltaX1); + int ix2 = UbMath::integerRounding((x2p - minX2) / deltaX2); + int ix3 = UbMath::integerRounding((x3p - minX3) / deltaX3); + + if (ix1 >= 0 && ix2 >= 0 && ix3 >= 0 && ix1 < (int)voxelMatrix.getNX1() && ix2 < (int)voxelMatrix.getNX2() && + ix3 < (int)voxelMatrix.getNX3()) { + if (UbMath::equal(voxelMatrix(ix1, ix2, ix3), SOLID)) + return true; + } + return false; +} +/*=======================================================*/ +bool GbVoxelMatrix3D::isPointInGbObject3D(const double &x1p, const double &x2p, const double &x3p, + bool &pointIsOnBoundary) +{ + pointIsOnBoundary = false; + + return isPointInGbObject3D(x1p, x2p, x3p); +} +/*=======================================================*/ +bool GbVoxelMatrix3D::isCellInsideGbObject3D(const double & /*x1p1*/, const double & /*x2p1*/, const double & /*x3p1*/, + const double & /*x1p2*/, const double & /*x2p2*/, const double & /*x3p2*/) +{ + return false; + // FIXME: unreachable cide + ////dass haengt von der Konfigration ab, aber meist ist der Block groesser wie etliche Poren ... + + // //indizes ermitteln + // int startix1 = (int)std::floor((x1p1-minX1)/deltaX1+1E-13); + // int startix2 = (int)std::floor((x2p1-minX2)/deltaX2+1E-13); + // int startix3 = (int)std::floor((x3p1-minX3)/deltaX3+1E-13); + + // if (startix1<0) return false; + // if (startix2<0) return false; + // if (startix3<0) return false; + + // int maxiX1 = (int)voxelMatrix.getNX1()-1; + // int maxiX2 = (int)voxelMatrix.getNX2()-1; + // int maxiX3 = (int)voxelMatrix.getNX3()-1; + + // int endix1 = (int)std::ceil((x1p2-minX1)/deltaX1-1E-13); + // int endix2 = (int)std::ceil((x2p2-minX2)/deltaX2-1E-13); + // int endix3 = (int)std::ceil((x3p2-minX3)/deltaX3-1E-13); + + // if (endix1>maxiX1) return false; + // if (endix2>maxiX2) return false; + // if (endix3>maxiX3) return false; + + // for (int ix3 = startix3; ix3<=endix3; ix3++) + // for (int ix2 = startix2; ix2<=endix2; ix2++) + // for (int ix1 = startix1; ix1<=endix1; ix1++) + // if (UbMath::equal(voxelMatrix(ix1, ix2, ix3), FLUID)) + // return false; + // return true; +} +/*=======================================================*/ +bool GbVoxelMatrix3D::isCellCuttingGbObject3D(const double &x1a, const double &x2a, const double &x3a, + const double &x1b, const double &x2b, const double &x3b) +// Merksatz: cell oder deren Volumen schneidet oder beinhaltet komplette oder Teile der CuboidUmrandung +// returns true: +// - cell cuts GbVoxelMatrix3D +// - cell boxes GbVoxelMatrix3D +// returns false: +// - cell completely inside GbVoxelMatrix3D +// - cell und cuboid3D haben kein gemeinsames Volumen +{ + // erstmal die dumm Loesung + if (!(this->isCellInsideGbObject3D(x1a, x2a, x3a, x1b, x2b, x3b)) && + this->isCellInsideOrCuttingGbObject3D(x1a, x2a, x3a, x1b, x2b, x3b)) { + return true; + } + + return false; +} +/*=======================================================*/ +bool GbVoxelMatrix3D::isCellInsideOrCuttingGbObject3D(const double &x1a, const double &x2a, const double &x3a, + const double &x1b, const double &x2b, const double &x3b) +// returns true: +// - cell completely inside cuboid3D ( = cuboid3D boxes cell) +// - cell cuts cuboid3D +// - cell boxes cuboid3D +// returns false: +// - cell und cuboid3D haben kein gemeinsames Volumen +{ + // simpler check, da unser GbCuboid3D ein AABB is: + // anfA midA endA anfB midB endB + // | x<-- dxA -->| |<-dxB->x | + // |<----------------- T --------------->| + // ist |T| <= dxA + dxB -> overlap! + + if (UbMath::lessEqual(std::fabs(this->getX1Centroid() - 0.5 * (x1b + x1a) /*Tx1*/), + 0.5 * (this->getLengthX1() + std::fabs(x1b - x1a) /*dx1A+dx1B*/)) + + && UbMath::lessEqual(std::fabs(this->getX2Centroid() - 0.5 * (x2b + x2a) /*Tx2*/), + 0.5 * (this->getLengthX2() + std::fabs(x2b - x2a) /*dx2A+dx2B*/)) + + && UbMath::lessEqual(std::fabs(this->getX3Centroid() - 0.5 * (x3b + x3a) /*Tx3*/), + 0.5 * (this->getLengthX3() + std::fabs(x3b - x3a) /*dx3A+dx3B*/))) { + return true; + } + + return false; +} +/*=======================================================*/ +vector<GbTriangle3D *> GbVoxelMatrix3D::getSurfaceTriangleSet() +{ + vector<GbTriangle3D *> triangles; + +#ifdef MC_CUBES + // MC + typedef McCubes::Matrix3DWrapper<Matrix3D> McMatrixWrapper; + typedef McCubes::MarchingCubes<McMatrixWrapper> McMarchingCubesGenerator; + typedef McMarchingCubesGenerator::Vertex McVertex; + typedef McMarchingCubesGenerator::Triangle McTriangle; + + McMatrixWrapper wrapper( + &voxelMatrix); //,0,0,0,voxelMatrix.getNX1()-1,voxelMatrix.getNX2()-1,voxelMatrix.getNX3()-1); + McMarchingCubesGenerator mc(wrapper); + + mc.init_all(); + mc.run(0.5); + + // const int nofVertices = mc.nverts(); + const int nofTriangles = mc.ntrigs(); + + McVertex *mcvertices = mc.vertices(); + McTriangle *mctriangles = mc.triangles(); + + for (int t = 0; t < nofTriangles; t++) { + triangles.push_back( + new GbTriangle3D(new GbPoint3D(minX1 + deltaX1 * (mcvertices[mctriangles[t].v1].x /*-1*/), + minX2 + deltaX2 * (mcvertices[mctriangles[t].v1].y /*-1*/), + minX3 + deltaX3 * (mcvertices[mctriangles[t].v1].z /*-1*/)), + new GbPoint3D(minX1 + deltaX1 * (mcvertices[mctriangles[t].v2].x /*-1*/), + minX2 + deltaX2 * (mcvertices[mctriangles[t].v2].y /*-1*/), + minX3 + deltaX3 * (mcvertices[mctriangles[t].v2].z /*-1*/)), + new GbPoint3D(minX1 + deltaX1 * (mcvertices[mctriangles[t].v3].x /*-1*/), + minX2 + deltaX2 * (mcvertices[mctriangles[t].v3].y /*-1*/), + minX3 + deltaX3 * (mcvertices[mctriangles[t].v3].z /*-1*/)))); + } +#else + cerr + << "vector<GbTriangle3D*> GbVoxelMatrix3D::getSurfaceTriangleSet() - benoetigt MARCHING_CUBE paket aus 3rdParty" + << endl; +#endif // MC_CUBES + + return triangles; +} +/*=======================================================*/ +void GbVoxelMatrix3D::addSurfaceTriangleSet(vector<UbTupleFloat3> & /*nodes*/, vector<UbTupleInt3> & /*triangles*/) +{ + UBLOG(logINFO, " GbVoxelMatrix3D addSurfaceTriangleSet start") + if (!this->addSurfaceTriangleSetFlag) { + UBLOG(logINFO, " GbVoxelMatrix3D addSurfaceTriangleSet end without TriangleSetCreation") + return; + } +#ifdef MC_CUBES + UBLOG(logDEBUG1, " GbVoxelMatrix3D addSurfaceTriangleSet MC defined") + + typedef McCubes::Matrix3DWrapper<Matrix3D> McMatrixWrapper; + typedef McCubes::MarchingCubes<McMatrixWrapper> McMarchingCubesGenerator; + typedef McMarchingCubesGenerator::Vertex McVertex; + typedef McMarchingCubesGenerator::Triangle McTriangle; + + // MC + { // standard( fuer voxelmatrix) + McMatrixWrapper wrapper(&voxelMatrix); + McMarchingCubesGenerator mc(wrapper); + + UBLOG(logDEBUG1, " GbVoxelMatrix3D addSurfaceTriangleSet McMarchingCubesGenerator") + + UBLOG(logDEBUG1, " GbVoxelMatrix3D addSurfaceTriangleSet mc.init") + mc.init_all(); + UBLOG(logDEBUG1, " GbVoxelMatrix3D addSurfaceTriangleSet mc.run") + mc.run(0.5); + UBLOG(logDEBUG1, " GbVoxelMatrix3D addSurfaceTriangleSet mc.run done") + + const int nofVertices = mc.nverts(); + const int nofTriangles = mc.ntrigs(); + + McVertex *mcvertices = mc.vertices(); + McTriangle *mctriangles = mc.triangles(); + + UBLOG(logDEBUG1, " GbVoxelMatrix3D node tuple") + for (int n = 0; n < nofVertices; n++) + nodes.push_back(makeUbTuple( + (float)(minX1 + deltaX1 * (mcvertices[n].x /*-1*/)), // Anm: kein -1, da man durch manipulation der + // indices die dreiecke um eins versetzt bekommt + (float)(minX2 + deltaX2 * (mcvertices[n].y /*-1*/)), + (float)(minX3 + deltaX3 * (mcvertices[n].z /*-1*/)))); + UBLOG(logDEBUG1, " GbVoxelMatrix3D triangles tuple") + for (int t = 0; t < nofTriangles; t++) + triangles.push_back(makeUbTuple(mctriangles[t].v1, mctriangles[t].v2, mctriangles[t].v3)); + UBLOG(logDEBUG1, " GbVoxelMatrix3D triangles tuple done") + } + + // false - das scheint probleme bei der asphaltprobe zu machen 1500x600x100 + // da lief es bis C - evtl. memory voll + if (false) // extension... um die raender koerrekt abzubilden muesste man eine dummy FLUID reihe um + { // die matrix legen( lsg1: temp matrix mit 2 reihen pro richtung mehr -> zuviel speicher, 500^3 = 500MB + // lsg2: fuer jede flaeche eine dummy matrix -> wie folgt: + int nx1 = (int)voxelMatrix.getNX1(); + int nx2 = (int)voxelMatrix.getNX2(); + int nx3 = (int)voxelMatrix.getNX3(); + UBLOG(logINFO, " A ") + Matrix3D tmpX1Min(2, nx2 + 2, nx3 + 2, FLUID); + Matrix3D tmpX1Max(2, nx2 + 2, nx3 + 2, FLUID); + for (int x3 = 0; x3 < nx3; x3++) + for (int x2 = 0; x2 < nx2; x2++) { + tmpX1Min(1, x2 + 1, x3 + 1) = voxelMatrix(0, x2, x3); + tmpX1Max(0, x2 + 1, x3 + 1) = voxelMatrix(nx1 - 1, x2, x3); + } + UBLOG(logINFO, " B") + Matrix3D tmpX2Min(nx1 + 2, 2, nx3 + 2, FLUID); + Matrix3D tmpX2Max(nx1 + 2, 2, nx3 + 2, FLUID); + for (int x3 = 0; x3 < nx3; x3++) + for (int x1 = 0; x1 < nx1; x1++) { + tmpX2Min(x1 + 1, 1, x3 + 1) = voxelMatrix(x1, 0, x3); + tmpX2Max(x1 + 1, 0, x3 + 1) = voxelMatrix(x1, nx2 - 1, x3); + } + UBLOG(logINFO, " C ") + Matrix3D tmpX3Min(nx1 + 2, nx3 + 2, 2, FLUID); + Matrix3D tmpX3Max(nx1 + 2, nx3 + 2, 2, FLUID); + for (int x2 = 0; x2 < nx2; x2++) + for (int x1 = 0; x1 < nx1; x1++) { + tmpX3Min(x1 + 1, x2 + 1, 1) = voxelMatrix(x1, x2, 0); + tmpX3Max(x1 + 1, x2 + 1, 0) = voxelMatrix(x1, x2, nx3 - 1); + } + UBLOG(logINFO, " D") + Matrix3D *matrices[] = { &tmpX1Min, &tmpX1Max, &tmpX2Min, &tmpX2Max, &tmpX3Min, &tmpX3Max }; + int dx1[] = { -1, nx1 - 1, -1, -1, -1, -1 }; + int dx2[] = { -1, -1, -1, nx2 - 1, -1, -1 }; + int dx3[] = { -1, -1, -1, -1, -1, nx3 - 1 }; + UBLOG(logINFO, " E") + for (int i = 0; i < 6; i++) { + McMatrixWrapper wrapper(matrices[i]); + McMarchingCubesGenerator mc(wrapper); + + mc.init_all(); + mc.run(0.5); + + McVertex *mcvertices = mc.vertices(); + McTriangle *mctriangles = mc.triangles(); + + int deltaNodeNr = (int)nodes.size(); + UBLOG(logINFO, " GbVoxelMatrix3D node tuple") + for (int n = 0; n < mc.nverts(); n++) + nodes.push_back( + makeUbTuple((float)(minX1 + deltaX1 * (mcvertices[n].x + + dx1[i])), // Anm: kein -1, da man durch manipulation der + // indices die dreiecke um eins versetzt bekommt + (float)(minX2 + deltaX2 * (mcvertices[n].y + dx2[i])), + (float)(minX3 + deltaX3 * (mcvertices[n].z + dx3[i])))); + for (int t = 0; t < mc.ntrigs(); t++) + triangles.push_back(makeUbTuple(deltaNodeNr + mctriangles[t].v1, deltaNodeNr + mctriangles[t].v2, + deltaNodeNr + mctriangles[t].v3)); + } + } +#else + cerr << "void GbVoxelMatrix3D.addSurfaceTriangleSet - benoetigt MARCHING_CUBE paket aus 3rdParty" << endl; +#endif // MC_CUBES + + UBLOG(logINFO, " GbVoxelMatrix3D addSurfaceTriangleSet end") +} +/*=======================================================*/ +string GbVoxelMatrix3D::toString() { return "GbVoxelMatrix3D"; } +/*=======================================================*/ +void GbVoxelMatrix3D::readMatrixFromVtiASCIIFile(std::string filename) + +{ + // UBLOG(logINFO," - create GbVoxelMatrix3D"); + UbFileInputASCII in(filename); + // ifstream in(filename.c_str(), ios::binary); + if (!in) + throw UbException(UB_EXARGS, "could not open file " + filename); + in.readLine(); + in.readLine(); + in.readLine(); + in.readLine(); + in.readLine(); + + voxelMatrix = Matrix3D(nodesX1, nodesX2, nodesX3, GbVoxelMatrix3D::FLUID); + + // UBLOG(logINFO," - init values"); + int val; + for (int x3 = 0; x3 < nodesX3; x3++) + for (int x2 = 0; x2 < nodesX2; x2++) + for (int x1 = 0; x1 < nodesX1; x1++) { + val = in.readInteger(); + // if( !UbMath::equal(val, 0.0f) ) + // if( UbMath::greater(val, threshold) ) + if ((double)val >= lowerThreshold && (double)val <= upperThreshold) { + (voxelMatrix)(x1, x2, x3) = GbVoxelMatrix3D::SOLID; + } + } + // UBLOG(logINFO," - create GbVoxelMatrix3D done"); +} + +////////////////////////////////////////////////////////////////////////// +void GbVoxelMatrix3D::rotate90aroundX(double /*cX1*/, double cX2, double cX3) +{ + // double tempMinPunktX1 = minX1-cX1; + double tempMinPunktX2 = minX2 - cX2; + double tempMinPunktX3 = getX3Maximum() - cX3; + + // double tempMinPunktX1tf = tempMinPunktX1; + double tempMinPunktX2tf = -tempMinPunktX3; + double tempMinPunktX3tf = tempMinPunktX2; + + // double minX1_temp = tempMinPunktX1tf+cX1; + double minX2_temp = tempMinPunktX2tf + cX2; + double minX3_temp = tempMinPunktX3tf + cX3; + + minX2 = minX2_temp; + minX3 = minX3_temp; + + int nx1 = (int)voxelMatrix.getNX1(); + int nx2 = (int)voxelMatrix.getNX2(); + int nx3 = (int)voxelMatrix.getNX3(); + + int nx1_new = nx1; + int nx2_new = nx3; + int nx3_new = nx2; + + double delta_temp = deltaX2; + deltaX2 = deltaX3; + deltaX3 = delta_temp; + + GbVoxelMatrix3D::Matrix3D voxelMatrix_temp(nx1_new, nx2_new, nx3_new); + + for (int x3 = 0; x3 < nx3; x3++) { + for (int x2 = 0; x2 < nx2; x2++) { + for (int x1 = 0; x1 < nx1; x1++) { + voxelMatrix_temp(x1, nx3 - x3 - 1, x2) = this->voxelMatrix(x1, x2, x3); + } + } + } + std::swap(this->voxelMatrix, voxelMatrix_temp); +} +////////////////////////////////////////////////////////////////////////// +void GbVoxelMatrix3D::rotate90aroundX() +{ + double cX1 = this->getX1Centroid(); + double cX2 = this->getX2Centroid(); + double cX3 = this->getX3Centroid(); + + rotate90aroundX(cX1, cX2, cX3); +} +////////////////////////////////////////////////////////////////////////// +void GbVoxelMatrix3D::rotate90aroundY(double cX1, double /*cX2*/, double cX3) +{ + double tempMinPunktX1 = getX1Maximum() - cX1; + // double tempMinPunktX2 = minX2-cX2; + double tempMinPunktX3 = minX3 - cX3; + + double tempMinPunktX1tf = tempMinPunktX3; + // double tempMinPunktX2tf = tempMinPunktX2; + double tempMinPunktX3tf = -tempMinPunktX1; + + double minX1_temp = tempMinPunktX1tf + cX1; + // double minX2_temp = tempMinPunktX2tf+cX2; + double minX3_temp = tempMinPunktX3tf + cX3; + + minX1 = minX1_temp; + minX3 = minX3_temp; + + int nx1 = (int)voxelMatrix.getNX1(); + int nx2 = (int)voxelMatrix.getNX2(); + int nx3 = (int)voxelMatrix.getNX3(); + + int nx1_new = nx3; + int nx2_new = nx2; + int nx3_new = nx1; + + double delta_temp = deltaX1; + deltaX1 = deltaX3; + deltaX3 = delta_temp; + + GbVoxelMatrix3D::Matrix3D voxelMatrix_temp(nx1_new, nx2_new, nx3_new); + + for (int x3 = 0; x3 < nx3; x3++) { + for (int x2 = 0; x2 < nx2; x2++) { + for (int x1 = 0; x1 < nx1; x1++) { + voxelMatrix_temp(x3, x2, nx1 - x1 - 1) = this->voxelMatrix(x1, x2, x3); + } + } + } + std::swap(this->voxelMatrix, voxelMatrix_temp); +} +////////////////////////////////////////////////////////////////////////// +void GbVoxelMatrix3D::rotate90aroundY() +{ + double cX1 = this->getX1Centroid(); + double cX2 = this->getX2Centroid(); + double cX3 = this->getX3Centroid(); + + rotate90aroundY(cX1, cX2, cX3); +} +////////////////////////////////////////////////////////////////////////// +void GbVoxelMatrix3D::rotate90aroundZ(double cX1, double cX2, double /*cX3*/) +{ + double tempMinPunktX1 = minX1 - cX1; + double tempMinPunktX2 = getX2Maximum() - cX2; + // double tempMinPunktX3 = minX3-cX3; + + double tempMinPunktX1tf = -tempMinPunktX2; + double tempMinPunktX2tf = tempMinPunktX1; + // double tempMinPunktX3tf = tempMinPunktX3; + + double minX1_temp = tempMinPunktX1tf + cX1; + double minX2_temp = tempMinPunktX2tf + cX2; + // double minX3_temp = tempMinPunktX3tf+cX3; + + minX1 = minX1_temp; + minX2 = minX2_temp; + + int nx1 = (int)voxelMatrix.getNX1(); + int nx2 = (int)voxelMatrix.getNX2(); + int nx3 = (int)voxelMatrix.getNX3(); + + int nx1_new = nx2; + int nx2_new = nx1; + int nx3_new = nx3; + + double delta_temp = deltaX1; + deltaX1 = deltaX2; + deltaX2 = delta_temp; + + GbVoxelMatrix3D::Matrix3D voxelMatrix_temp(nx1_new, nx2_new, nx3_new); + + for (int x3 = 0; x3 < nx3; x3++) { + for (int x2 = 0; x2 < nx2; x2++) { + for (int x1 = 0; x1 < nx1; x1++) { + voxelMatrix_temp(nx2 - x2 - 1, x1, x3) = this->voxelMatrix(x1, x2, x3); + } + } + } + std::swap(this->voxelMatrix, voxelMatrix_temp); +} +////////////////////////////////////////////////////////////////////////// +void GbVoxelMatrix3D::rotate90aroundZ() +{ + double cX1 = this->getX1Centroid(); + double cX2 = this->getX2Centroid(); + double cX3 = this->getX3Centroid(); + + rotate90aroundZ(cX1, cX2, cX3); +} +////////////////////////////////////////////////////////////////////////// +void GbVoxelMatrix3D::mirrorX() +{ + int nx1 = (int)voxelMatrix.getNX1(); + int nx2 = (int)voxelMatrix.getNX2(); + int nx3 = (int)voxelMatrix.getNX3(); + + GbVoxelMatrix3D::Matrix3D voxelMatrix_temp(nx1, nx2, nx3); + + for (int x3 = 0; x3 < nx3; x3++) { + for (int x2 = 0; x2 < nx2; x2++) { + for (int x1 = 0; x1 < nx1; x1++) { + voxelMatrix_temp(nx1 - x1 - 1, x2, x3) = this->voxelMatrix(x1, x2, x3); + } + } + } + std::swap(this->voxelMatrix, voxelMatrix_temp); +} +////////////////////////////////////////////////////////////////////////// +void GbVoxelMatrix3D::mirrorY() +{ + int nx1 = (int)voxelMatrix.getNX1(); + int nx2 = (int)voxelMatrix.getNX2(); + int nx3 = (int)voxelMatrix.getNX3(); + + GbVoxelMatrix3D::Matrix3D voxelMatrix_temp(nx1, nx2, nx3); + + for (int x3 = 0; x3 < nx3; x3++) { + for (int x2 = 0; x2 < nx2; x2++) { + for (int x1 = 0; x1 < nx1; x1++) { + voxelMatrix_temp(x1, nx2 - x2 - 1, x3) = this->voxelMatrix(x1, x2, x3); + } + } + } + std::swap(this->voxelMatrix, voxelMatrix_temp); +} +////////////////////////////////////////////////////////////////////////// +void GbVoxelMatrix3D::mirrorZ() +{ + int nx1 = (int)voxelMatrix.getNX1(); + int nx2 = (int)voxelMatrix.getNX2(); + int nx3 = (int)voxelMatrix.getNX3(); + + GbVoxelMatrix3D::Matrix3D voxelMatrix_temp(nx1, nx2, nx3); + + for (int x3 = 0; x3 < nx3; x3++) { + for (int x2 = 0; x2 < nx2; x2++) { + for (int x1 = 0; x1 < nx1; x1++) { + voxelMatrix_temp(x1, x2, nx3 - x3 - 1) = this->voxelMatrix(x1, x2, x3); + } + } + } + std::swap(this->voxelMatrix, voxelMatrix_temp); +} +////////////////////////////////////////////////////////////////////////// +void GbVoxelMatrix3D::rotateAroundY(double theta) +{ + int nx1 = (int)voxelMatrix.getNX1(); + int nx2 = (int)voxelMatrix.getNX2(); + int nx3 = (int)voxelMatrix.getNX3(); + + GbVoxelMatrix3D::Matrix3D voxelMatrix_temp(nx1, nx2, nx3, FLUID); + + for (int x3 = 0; x3 < nx3; x3++) { + for (int x2 = 0; x2 < nx2; x2++) { + for (int x1 = 0; x1 < nx1; x1++) { + if (voxelMatrix(x1, x2, x3) == SOLID) { + double rcX1 = minX1 + deltaX1 * x1; + double rcX3 = minX3 + deltaX3 * x3; + + double nrcX1 = cos(theta) * rcX1 + sin(theta) * rcX3; + double nrcX3 = -sin(theta) * rcX1 + cos(theta) * rcX3; + + int newX1 = UbMath::integerRounding((nrcX1 - minX1) / deltaX1); + int newX2 = x2; + int newX3 = UbMath::integerRounding((nrcX3 - minX3) / deltaX3); + + if (newX1 > 0 && newX3 > 0 && newX1 < nx1 && newX3 < nx3) { + voxelMatrix_temp(newX1, newX2, newX3) = voxelMatrix(x1, x2, x3); + } + + // int ix1, ix2, ix3; + // double ixx1 = (abs(nrcX1-minX1)/deltaX1); + // ix2 = x2; + // double ixx3 = (abs(nrcX3-minX3)/deltaX3); + // if (ixx1-(int)ixx1>.9999999999) ix1 = (int)ixx1+1; else ix1 = (int)ixx1; + ////if (ixx2-(int)ixx2>.9999999999) ix2 = (int)ixx2+1; else ix2 = (int)ixx2; + // if (ixx3-(int)ixx3>.9999999999) ix3 = (int)ixx3+1; else ix3 = (int)ixx3; + + // if (ix1>=0 && ix3>=0 && ix1<nx1 && ix3<nx3) + //{ + // voxelMatrix_temp(ix1, ix2, ix3) = voxelMatrix(x1, x2, x3); + //} + } + } + } + } + std::swap(voxelMatrix, voxelMatrix_temp); + + for (int x3 = 0; x3 < nx3; x3++) + for (int x2 = 0; x2 < nx2; x2++) + for (int x1 = 0; x1 < nx1; x1++) { + int count = 0; + for (int k3 = -1; k3 <= 1; k3++) + for (int k1 = -1; k1 <= 1; k1++) { + int j1 = x1 + k1; + int j3 = x3 + k3; + if (j1 >= 0 && j3 >= 0 && j1 < nx1 && j3 < nx3) { + if (voxelMatrix(j1, x2, j3) == SOLID) { + count++; + } + } + } + if (count == 8) { + voxelMatrix(x1, x2, x3) = SOLID; + } + } +} +////////////////////////////////////////////////////////////////////////// +void GbVoxelMatrix3D::writeToLegacyVTKASCII(const std::string &fileName) +{ + string fn = fileName + ".ascii.vtk"; + + FILE *file; + file = fopen(fn.c_str(), "w"); + + if (file == NULL) { + std::string pathf = UbSystem::getPathFromString(fn); + if (fn.size() > 0) { + UbSystem::makeDirectory(pathf); + file = fopen(fn.c_str(), "w"); + } + if (file == NULL) + throw UbException(UB_EXARGS, "can not open " + fn); + } + + if (file == NULL) + throw UbException(UB_EXARGS, "can not open " + fn); + + int nx1 = (int)voxelMatrix.getNX1(); + int nx2 = (int)voxelMatrix.getNX2(); + int nx3 = (int)voxelMatrix.getNX3(); + + int nn = nx1 * nx2 * nx3; + + fprintf(file, "# vtk DataFile Version 2.0\n"); + fprintf(file, "vtk output\n"); + fprintf(file, "ASCII\n"); + fprintf(file, "DATASET STRUCTURED_POINTS\n"); + fprintf(file, "DIMENSIONS %d %d %d\n", nx1, nx2, nx3); + fprintf(file, "ORIGIN %g %g %g\n", minX1, minX2, minX3); + fprintf(file, "SPACING %g %g %g\n", deltaX1, deltaX2, deltaX3); + fprintf(file, "POINT_DATA %d\n", nn); + fprintf(file, "SCALARS Geo float\n"); + fprintf(file, "LOOKUP_TABLE default\n"); + + for (int k = 0; k < nx3; k++) { + for (int j = 0; j < nx2; j++) { + for (int i = 0; i < nx1; i++) { + fprintf(file, "%g ", voxelMatrix(i, j, k)); + } + } + } + + fprintf(file, "\n"); + + fclose(file); +} +////////////////////////////////////////////////////////////////////////// +void GbVoxelMatrix3D::writeToLegacyVTKBinary(const std::string &fileName) +{ + string fn = fileName + ".binary.vtk"; + + FILE *file; + file = fopen(fn.c_str(), "w"); + + if (file == NULL) { + std::string pathf = UbSystem::getPathFromString(fn); + if (fn.size() > 0) { + UbSystem::makeDirectory(pathf); + file = fopen(fn.c_str(), "w"); + } + if (file == NULL) + throw UbException(UB_EXARGS, "can not open " + fn); + } + + int nx1 = (int)voxelMatrix.getNX1(); + int nx2 = (int)voxelMatrix.getNX2(); + int nx3 = (int)voxelMatrix.getNX3(); + + int nn = nx1 * nx2 * nx3; + + char LF = 0x0A; + + fprintf(file, "# vtk DataFile Version 3.0\n"); + fprintf(file, "vtk output\n"); + fprintf(file, "BINARY\n"); + fprintf(file, "DATASET STRUCTURED_POINTS\n"); + fprintf(file, "DIMENSIONS %d %d %d\n", nx1, nx2, nx3); + fprintf(file, "ORIGIN %g %g %g\n", minX1, minX2, minX3); + fprintf(file, "SPACING %g %g %g\n", deltaX1, deltaX2, deltaX3); + fprintf(file, "POINT_DATA %d\n", nn); + fprintf(file, "SCALARS Geo float\n"); + fprintf(file, "LOOKUP_TABLE default"); + fclose(file); + + GbVoxelMatrix3D::Matrix3D voxelMatrix_temp(nx1, nx2, nx3); + + if (UbSystem::isLittleEndian()) { + for (int x3 = 0; x3 < nx3; x3++) { + for (int x2 = 0; x2 < nx2; x2++) { + for (int x1 = 0; x1 < nx1; x1++) { + float tmp = this->voxelMatrix(x1, x2, x3); + UbSystem::swapByteOrder((unsigned char *)(&(tmp)), sizeof(float)); + voxelMatrix_temp(x1, x2, x3) = tmp; + } + } + } + } + + file = fopen(fn.c_str(), "ab"); + + fwrite(&LF, sizeof(char), 1, file); + fwrite(voxelMatrix_temp.getStartAdressOfSortedArray(0, 0, 0), sizeof(float), + voxelMatrix_temp.getDataVector().size(), file); + fwrite(&LF, sizeof(char), 1, file); + fclose(file); +} +////////////////////////////////////////////////////////////////////////// +void GbVoxelMatrix3D::writeToVTKImageDataASCII(const std::string &fileName) +{ + int nx1 = (int)voxelMatrix.getNX1(); + int nx2 = (int)voxelMatrix.getNX2(); + int nx3 = (int)voxelMatrix.getNX3(); + + string fn = fileName + ".ascii.vti"; + + FILE *file; + file = fopen(fn.c_str(), "w"); + + if (file == NULL) { + std::string pathf = UbSystem::getPathFromString(fn); + if (fn.size() > 0) { + UbSystem::makeDirectory(pathf); + file = fopen(fn.c_str(), "w"); + } + if (file == NULL) + throw UbException(UB_EXARGS, "can not open " + fn); + } + + fprintf(file, + "<VTKFile type=\"ImageData\" version=\"1.0\" byte_order=\"LittleEndian\" header_type=\"UInt64\">\n"); // paraview + // 4.1 + // fprintf(file,"<VTKFile type=\"ImageData\" version=\"0.1\" byte_order=\"LittleEndian\">\n"); //paraview 3.1 + fprintf(file, " <ImageData WholeExtent=\"%d %d %d %d %d %d\" Origin=\"%g %g %g\" Spacing=\"%g %g %g\">\n", 0, + nx1 - 1, 0, nx2 - 1, 0, nx3 - 1, minX1, minX2, minX3, deltaX1, deltaX2, deltaX3); + fprintf(file, " <Piece Extent=\"%d %d %d %d %d %d\">\n", 0, nx1 - 1, 0, nx2 - 1, 0, nx3 - 1); + fprintf(file, " <PointData Scalars=\"VoxelMatrix\">\n"); + fprintf(file, " <DataArray type=\"Float32\" Name=\"VoxelMatrix\" format=\"ascii\" RangeMin=\"0\" " + "RangeMax=\"1\">\n "); + + for (int k = 0; k < nx3; k++) { + for (int j = 0; j < nx2; j++) { + for (int i = 0; i < nx1; i++) { + fprintf(file, "%g ", voxelMatrix(i, j, k)); + } + } + } + + fprintf(file, "\n </DataArray>\n"); + fprintf(file, " </PointData>\n"); + fprintf(file, " <CellData>\n"); + fprintf(file, " </CellData>\n"); + fprintf(file, " </Piece>\n"); + fprintf(file, " </ImageData>\n"); + fprintf(file, "</VTKFile>\n"); + + fclose(file); +} +////////////////////////////////////////////////////////////////////////// +void GbVoxelMatrix3D::writeToVTKImageDataAppended(const std::string &fileName) +{ + int nx1 = (int)voxelMatrix.getNX1(); + int nx2 = (int)voxelMatrix.getNX2(); + int nx3 = (int)voxelMatrix.getNX3(); + + string fn = fileName + ".appended.vti"; + + FILE *file; + file = fopen(fn.c_str(), "w"); + + if (file == NULL) { + std::string pathf = UbSystem::getPathFromString(fn); + if (fn.size() > 0) { + UbSystem::makeDirectory(pathf); + file = fopen(fn.c_str(), "w"); + } + if (file == NULL) + throw UbException(UB_EXARGS, "can not open " + fn); + } + + fprintf(file, + "<VTKFile type=\"ImageData\" version=\"1.0\" byte_order=\"LittleEndian\" header_type=\"UInt64\">\n"); // paraview + // 4.1 + fprintf(file, " <ImageData WholeExtent=\"%d %d %d %d %d %d\" Origin=\"%g %g %g\" Spacing=\"%g %g %g\">\n", 0, + nx1 - 1, 0, nx2 - 1, 0, nx3 - 1, minX1, minX2, minX3, deltaX1, deltaX2, deltaX3); + fprintf(file, " <Piece Extent=\"%d %d %d %d %d %d\">\n", 0, nx1 - 1, 0, nx2 - 1, 0, nx3 - 1); + fprintf(file, " <PointData Scalars=\"VoxelMatrix\">\n"); + fprintf(file, " <DataArray type=\"Float32\" Name=\"VoxelMatrix\" format=\"appended\" RangeMin=\"0\" " + "RangeMax=\"1\" offset=\"0\" />\n"); + fprintf(file, " </PointData>\n"); + fprintf(file, " <CellData>\n"); + fprintf(file, " </CellData>\n"); + fprintf(file, " </Piece>\n"); + fprintf(file, " </ImageData>\n"); + fprintf(file, " <AppendedData encoding=\"raw\">\n"); + fprintf(file, " _"); + fclose(file); + + file = fopen(fn.c_str(), "ab"); + unsigned long long size = (unsigned long long)voxelMatrix.getDataVector().size() * sizeof(float); + fwrite(&size, sizeof(unsigned long long), 1, file); + fwrite(voxelMatrix.getStartAdressOfSortedArray(0, 0, 0), sizeof(float), voxelMatrix.getDataVector().size(), file); + fclose(file); + + file = fopen(fn.c_str(), "a"); + fprintf(file, "\n"); + fprintf(file, " </AppendedData>\n"); + fprintf(file, "</VTKFile>\n"); + fclose(file); +} diff --git a/src/basics/geometry3d/GbVoxelMatrix3D.h b/src/basics/geometry3d/GbVoxelMatrix3D.h new file mode 100644 index 0000000000000000000000000000000000000000..c71646e206777533fa0423ce5916c974a7124929 --- /dev/null +++ b/src/basics/geometry3d/GbVoxelMatrix3D.h @@ -0,0 +1,350 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file GbVoxelMatrix3D.h +//! \ingroup geometry3D +//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller +//======================================================================================= +#ifndef GBVOXELMATRIX3D_H +#define GBVOXELMATRIX3D_H + +#include <cmath> +#include <vector> + +#include <basics/container/CbArray3D.h> +#include <basics/utilities/UbObserver.h> +#include <geometry3d/GbObject3D.h> + +#include <PointerDefinitions.h> + +class GbLine3D; +class GbTriangle3D; +class GbObject3DCreator; + +class GbVoxelMatrix3D : public GbObject3D, public UbObserver +{ +public: + using Matrix3D = CbArray3D<float>; + static const float SOLID; + static const float FLUID; + enum Endian { BigEndian, LittleEndian }; + + GbVoxelMatrix3D(); + GbVoxelMatrix3D(int nx1, int nx2, int nx3, float initVal, double lowerThreshold = 0, double upperThreshold = 0); + GbVoxelMatrix3D(const Matrix3D &voxelMatrix, double lowerThreshold = 0, double upperThreshold = 0); + ~GbVoxelMatrix3D() override = default; + + void finalize() override{}; + GbVoxelMatrix3D *clone() override; + + /*=======================================================================*/ + Matrix3D::reference operator()(const Matrix3D::size_type &x1, const Matrix3D::size_type &x2, + const Matrix3D::size_type &x3) + { + return voxelMatrix(x1, x2, x3); + } + /*=======================================================================*/ + Matrix3D::const_reference operator()(const Matrix3D::size_type &x1, const Matrix3D::size_type &x2, + const Matrix3D::size_type &x3) const + { + return voxelMatrix(x1, x2, x3); + } + /*=======================================================================*/ + void setTransferViaFilename(bool transferViaFilename, std::string filename) + { + this->filename = filename; + this->transferViaFilename = transferViaFilename; + } + void setThreshold(double lowerThreshold, double upperThreshold) + { + this->lowerThreshold = lowerThreshold; + this->upperThreshold = upperThreshold; + } + void setAddSurfaceTriangleSetFlag(bool flag) { this->addSurfaceTriangleSetFlag = flag; } + + /*=======================================================================*/ + void setVoxelMatrixMininum(double minX1, double minX2, double minX3) + { + this->minX1 = minX1; + this->minX2 = minX2; + this->minX3 = minX3; + } + void setVoxelMatrixMinX1(double minX1) { this->minX1 = minX1; } + void setVoxelMatrixMinX2(double minX2) { this->minX2 = minX2; } + void setVoxelMatrixMinX3(double minX3) { this->minX3 = minX3; } + + /*=======================================================================*/ + void setVoxelMatrixDelta(double deltaX1, double deltaX2, double deltaX3) + { + this->deltaX1 = deltaX1; + this->deltaX2 = deltaX2; + this->deltaX3 = deltaX3; + } + void setVoxelMatrixDeltaX1(double deltaX1) { this->deltaX1 = deltaX1; } + void setVoxelMatrixDeltaX2(double deltaX2) { this->deltaX2 = deltaX2; } + void setVoxelMatrixDeltaX3(double deltaX3) { this->deltaX3 = deltaX3; } + + /*=======================================================================*/ + double getX1Centroid() override { return 0.5 * (minX1 + this->getX1Maximum()); } + double getX1Minimum() override { return minX1; } + double getX1Maximum() override { return minX1 + deltaX1 * voxelMatrix.getNX1(); } + + double getX2Centroid() override { return 0.5 * (minX2 + this->getX2Maximum()); } + double getX2Minimum() override { return minX2; } + double getX2Maximum() override { return minX2 + deltaX2 * voxelMatrix.getNX2(); } + + double getX3Centroid() override { return 0.5 * (this->getX3Minimum() + this->getX3Maximum()); } + double getX3Minimum() override { return minX3; } + double getX3Maximum() override { return minX3 + deltaX3 * voxelMatrix.getNX3(); } + + double getLengthX1() { return this->getX1Maximum() - minX1; } + double getLengthX2() { return this->getX2Maximum() - minX2; } + double getLengthX3() { return this->getX3Maximum() - minX3; } + + void setCenterCoordinates(const double &x1, const double &x2, const double &x3) override; + void translate(const double &tx1, const double &tx2, const double &tx3) override; + + bool isPointInGbObject3D(const double &x1p, const double &x2p, const double &x3p, bool &pointIsOnBoundary) override; + bool isPointInGbObject3D(const double &x1p, const double &x2p, const double &x3p) override; + bool isCellInsideGbObject3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b, + const double &x2b, const double &x3b) override; + bool isCellCuttingGbObject3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b, + const double &x2b, const double &x3b) override; + bool isCellInsideOrCuttingGbObject3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b, + const double &x2b, const double &x3b) override; + // double getCellVolumeInsideGbObject3D(const double& x1a,const double& x2a,const double& x3a,const double& + // x1b,const double& x2b,const double& x3b); + + GbPoint3D *calculateInterSectionPoint3D(GbPoint3D & /*point1*/, GbPoint3D & /*point2*/) + { + throw UbException(__FILE__, __LINE__, UB_FUNCTION, "not implemented"); + } + GbLine3D *createClippedLine3D(GbPoint3D & /*point1*/, GbPoint3D & /*point2*/) override + { + throw UbException(__FILE__, __LINE__, UB_FUNCTION, "not implemented"); + } + + std::vector<GbTriangle3D *> getSurfaceTriangleSet() override; + void addSurfaceTriangleSet(std::vector<UbTupleFloat3> &nodes, std::vector<UbTupleInt3> &triangles) override; + + bool hasRaytracing() override { return true; } + /*|r| must be 1! einheitsvector!!*/ + double getIntersectionRaytraceFactor(const double &x1, const double &x2, const double &x3, const double &rx1, + const double &rx2, const double &rx3) override; + + std::string toString() override; + + // virtuelle Methoden von UbObserver + void objectChanged(UbObservable *changedObject) override {} + void objectWillBeDeleted(UbObservable *objectForDeletion) override {} + + template <class T> + void readMatrixFromRawFile(std::string filename, GbVoxelMatrix3D::Endian endian); + template <class T> + void readBufferedMatrixFromRawFile(std::string filename, GbVoxelMatrix3D::Endian endian); + void readMatrixFromVtiASCIIFile(std::string filename); + + void rotate90aroundX(); + void rotate90aroundY(); + void rotate90aroundZ(); + void rotate90aroundX(double cX1, double cX2, double cX3); + void rotate90aroundY(double cX1, double cX2, double cX3); + void rotate90aroundZ(double cX1, double cX2, double cX3); + void mirrorX(); + void mirrorY(); + void mirrorZ(); + + void rotateAroundY(double theta); + + void writeToLegacyVTKASCII(const std::string &fileName); + void writeToLegacyVTKBinary(const std::string &fileName); + void writeToVTKImageDataASCII(const std::string &fileName); + void writeToVTKImageDataAppended(const std::string &fileName); + + void setClosedVoidSpaceToSolid(); + + void calculateNumberOfSolidAndFluid(); + long getNumberOfSolid(); + long getNumberOfFluid(); + +protected: + void findFluidNeighbor(int cx1, int cx2, int cx3); + Matrix3D voxelMatrixTemp; + CbArray3D<char> flagMatrix; + + std::vector<int> x1Nbr; + std::vector<int> x2Nbr; + std::vector<int> x3Nbr; + + std::vector<int> x1NbrTemp; + std::vector<int> x2NbrTemp; + std::vector<int> x3NbrTemp; + + using GbObject3D::isPointInGbObject3D; // Grund: dadurch muss man hier isPointInGbObject3D(GbPoint3D*) nicht + // ausprogrammieren, welche sonst hier "ueberdeckt" waere + +protected: + // for transfer + std::string filename; + bool transferViaFilename{ false }; + + bool addSurfaceTriangleSetFlag{ true }; + + int nodesX1{ 0 }; + int nodesX2{ 0 }; + int nodesX3{ 0 }; + double lowerThreshold{ 0.0 }, upperThreshold{ 0.0 }; + + double minX1{ 0.0 }; + double minX2{ 0.0 }; + double minX3{ 0.0 }; + double deltaX1{ 1.0 }; + double deltaX2{ 1.0 }; + double deltaX3{ 1.0 }; + + Matrix3D voxelMatrix; + + long numberOfSolid; + long numberOfFluid; +}; + +////////////////////////////////////////////////////////////////////////// +template <class T> +void GbVoxelMatrix3D::readMatrixFromRawFile(std::string filename, GbVoxelMatrix3D::Endian endian) +{ + using namespace std; + // UBLOG(logINFO,"GbVoxelMatrix3D::readMatrixFromFile \""<<filename<<"\" + // nodes("<<nodesX1<<"/"<<nodesX2<<"/"<<nodesX3<<") - start"); + ifstream in(filename.c_str(), ios::binary); + if (!in) + throw UbException(UB_EXARGS, "could not open file " + filename); + + in.seekg(0, ios::end); // Ende springen + fstream::off_type length = in.tellg(); // Position abfragen + in.seekg(0, ios::beg); // An den Anfang springen + + // UBLOG(logINFO,"number of nodes = "<<nodesX1*nodesX2*nodesX3*sizeof(T)<<" file size = "<<(long)length); + // if( (nodesX1*nodesX2*nodesX3)*sizeof(float) != (long)length ) + unsigned long long nofn = (unsigned long long)nodesX1 * (unsigned long long)nodesX2 * (unsigned long long)nodesX3 * + (unsigned long long)sizeof(T); + if (nofn != (unsigned long long)length) { + throw UbException(UB_EXARGS, "number of nodes(" + UbSystem::toString(nofn) + ") doesn't match file size(" + + UbSystem::toString((long)length) + ")"); + } + + // UBLOG(logINFO," - create GbVoxelMatrix3D"); + // GbVoxelMatrix3D* voxelGeo = new GbVoxelMatrix3D(nodesX1,nodesX2,nodesX3,GbVoxelMatrix3D::FLUID); + voxelMatrix = Matrix3D(nodesX1, nodesX2, nodesX3, GbVoxelMatrix3D::FLUID); + + // UBLOG(logINFO," - init values"); + // float val; + T val; + for (int x3 = 0; x3 < nodesX3; x3++) + for (int x2 = 0; x2 < nodesX2; x2++) + for (int x1 = 0; x1 < nodesX1; x1++) { + // in.read((char*)&val,sizeof(float)); + in.read((char *)&val, sizeof(T)); + if (endian == BigEndian) + UbSystem::swapByteOrder((unsigned char *)(&(val)), sizeof(T)); + // if( UbMath::equal((double)val, threshold) ) + // if( UbMath::greater((double)val, threshold) ) + if ((double)val >= lowerThreshold && (double)val <= upperThreshold) { + (voxelMatrix)(x1, x2, x3) = GbVoxelMatrix3D::SOLID; + } + //(voxelMatrix)(x1, x2, x3) = (float)val; + } + + // UBLOG(logINFO,"GbVoxelMatrix3D::readMatrixFromFile \""<<filename<<"\" + // nodes("<<nodesX1<<"/"<<nodesX2<<"/"<<nodesX3<<") - end"); +} + +////////////////////////////////////////////////////////////////////////// +template <class T> +void GbVoxelMatrix3D::readBufferedMatrixFromRawFile(std::string filename, GbVoxelMatrix3D::Endian endian) +{ + using namespace std; + UBLOG(logINFO, "GbVoxelMatrix3D::readMatrixFromRawFile \"" << filename << "\" nodes(" << nodesX1 << "/" << nodesX2 + << "/" << nodesX3 << ") - start"); + + FILE *file; + file = fopen(filename.c_str(), "rb"); + if (file == NULL) { + throw UbException(UB_EXARGS, "Could not open file " + filename); + } + + // obtain file size: + fseek(file, 0, SEEK_END); + unsigned long int length = ftell(file); + rewind(file); + + UBLOG(logINFO, "number of nodes = " << (long)nodesX1 * (long)nodesX2 * (long)nodesX3 << " file size = " << length); + + unsigned long int nofn = (long)nodesX1 * (long)nodesX2 * (long)nodesX3 * (long)sizeof(T); + if (nofn != length) { + // throw UbException(UB_EXARGS, "number of nodes("+UbSystem::toString(nofn)+") doesn't match file + // size("+UbSystem::toString(length)+")"); + } + + UBLOG(logINFO, " - create GbVoxelMatrix3D"); + voxelMatrix = Matrix3D(nodesX1, nodesX2, nodesX3, GbVoxelMatrix3D::FLUID); + + CbArray3D<T> readMatrix(nodesX1, nodesX2, nodesX3); + + UBLOG(logINFO, " - read file to matrix"); + fread(readMatrix.getStartAdressOfSortedArray(0, 0, 0), sizeof(T), readMatrix.getDataVector().size(), file); + fclose(file); + + UBLOG(logINFO, " - init values"); + + numberOfSolid = 0; + T val; + for (int x3 = 0; x3 < nodesX3; x3++) + for (int x2 = 0; x2 < nodesX2; x2++) + for (int x1 = 0; x1 < nodesX1; x1++) { + val = readMatrix(x1, x2, x3); + + if (endian == BigEndian) { + UbSystem::swapByteOrder((unsigned char *)(&(val)), sizeof(T)); + } + + if ((double)val >= lowerThreshold && (double)val <= upperThreshold) { + voxelMatrix(x1, x2, x3) = GbVoxelMatrix3D::SOLID; + } + } + + UBLOG(logINFO, "GbVoxelMatrix3D::readMatrixFromRawFile \"" << filename << "\" nodes(" << nodesX1 << "/" << nodesX2 + << "/" << nodesX3 << ") - end"); +} + +//#if defined(RCF_USE_SF_SERIALIZATION) && !defined(SWIG) +// UB_AUTO_RUN_NAMED(SF::registerType<GbVoxelMatrix3D>("GbVoxelMatrix3D"), SF_GbVoxelMatrix3D); +// UB_AUTO_RUN_NAMED((SF::registerBaseAndDerived< GbObject3D, GbVoxelMatrix3D >()), SF_GbVoxelMatrix3D_BD1); +// UB_AUTO_RUN_NAMED((SF::registerBaseAndDerived< UbObserver, GbVoxelMatrix3D>()), SF_GbVoxelMatrix3D_BD2); +//#endif //RCF_USE_SF_SERIALIZATION + +#endif diff --git a/src/basics/geometry3d/KdTree/KdNode.h b/src/basics/geometry3d/KdTree/KdNode.h new file mode 100644 index 0000000000000000000000000000000000000000..f60de664934a79a01f1ebcdabb83a862c55ab6b2 --- /dev/null +++ b/src/basics/geometry3d/KdTree/KdNode.h @@ -0,0 +1,315 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file KdNode.h +//! \ingroup KdTree +//! \author Soeren Textor, Sebastian Bindick +//======================================================================================= +#ifndef KDNODE_H +#define KDNODE_H + +#include <basics/memory/MbSmartPtr.h> + +#include <basics/utilities/UbException.h> +#include <basics/utilities/UbKeys.h> +#include <basics/utilities/UbMath.h> +#include <basics/utilities/UbTuple.h> + +#include <geometry3d/GbTriFaceMesh3D.h> +#include <geometry3d/KdTree/KdRay.h> +#include <geometry3d/KdTree/KdSplitCandidate.h> +#include <geometry3d/KdTree/KdUtilities.h> +#include <geometry3d/KdTree/intersectionhandler/KdLineIntersectionHandler.h> +#include <geometry3d/KdTree/intersectionhandler/KdRayIntersectionHandler.h> +#include <geometry3d/KdTree/splitalgorithms/KdSplitAlgorithm.h> + +#include <string> +#include <vector> + +namespace Kd +{ +template <typename T> +class Node +{ +public: + Node(const T &x1, const T &y1, const T &z1, const T &x2, const T &y2, const T &z2, + const MbSmartPtr<std::vector<GbTriFaceMesh3D::TriFace>> triFaces, + std::vector<GbTriFaceMesh3D::Vertex> *ptrNodes) + : child1(NULL), child2(NULL), triFaces(triFaces), ptrNodes(ptrNodes) + { + if (x1 < x2) { + this->x[0] = x1; + this->x[1] = x2; + } else { + this->x[0] = x2; + this->x[1] = x1; + } + + if (y1 < y2) { + this->y[0] = y1; + this->y[1] = y2; + } else { + this->y[0] = y2; + this->y[1] = y1; + } + + if (z1 < z2) { + this->z[0] = z1; + this->z[1] = z2; + } else { + this->z[0] = z2; + this->z[1] = z1; + } + } + /* ======================================================================================= */ + ~Node() + { + if (child1) { + delete child1; + child1 = NULL; + } + if (child2) { + delete child2; + child2 = NULL; + } + } + /* ======================================================================================= */ + bool isLeaf() { return child1 == NULL && child2 == NULL; } + /* ======================================================================================= */ + void deleteTriFaces() { triFaces = MbSmartPtr<std::vector<GbTriFaceMesh3D::TriFace>>(); } + /* ======================================================================================= */ + const MbSmartPtr<std::vector<GbTriFaceMesh3D::TriFace>> &getTriFaces() { return triFaces; } + /* ======================================================================================= */ + std::vector<GbTriFaceMesh3D::Vertex> &getNodes() + { + if (!ptrNodes) + throw UbException(UB_EXARGS, "ups,no nodes"); + return *ptrNodes; + } + + /* ======================================================================================= */ + void buildTree(const int &level, const int &maxLevel, const SplitAlgorithm<T> &splitAlg) + { + SplitCandidate<T> splitCandidate = splitAlg.findBestSplitCandidate(level, maxLevel, *this); + + if (splitCandidate.isValid) { + + MbSmartPtr<std::vector<GbTriFaceMesh3D::TriFace>> triFacesForChild1( + new std::vector<GbTriFaceMesh3D::TriFace>); + MbSmartPtr<std::vector<GbTriFaceMesh3D::TriFace>> triFacesForChild2( + new std::vector<GbTriFaceMesh3D::TriFace>); + + splitAlg.distributeTriFaces(splitCandidate, *triFacesForChild1, *triFacesForChild2, *this); + + ////////////////////////////////////////////////////////////////////////// + // calculate center points and edges of new child nodes + T x1_l = x[0], y1_l = y[0], z1_l = z[0]; + T x2_l = x[1], y2_l = y[1], z2_l = z[1]; + T x1_r = x[0], y1_r = y[0], z1_r = z[0]; + T x2_r = x[1], y2_r = y[1], z2_r = z[1]; + + if (splitCandidate.axis == Axis::X) { + x2_l = splitCandidate.position; + x1_r = splitCandidate.position; + } else if (splitCandidate.axis == Axis::Y) { + y2_l = splitCandidate.position; + y1_r = splitCandidate.position; + } else { + z2_l = splitCandidate.position; + z1_r = splitCandidate.position; + } + // ---------------------------------------------------------------------- + // ---------------------------------------------------------------------- + + if (triFacesForChild1->size() > 0) { + if (this->child1) + delete this->child1; + this->child1 = new Node(x1_l, y1_l, z1_l, x2_l, y2_l, z2_l, triFacesForChild1, ptrNodes); + this->child1->buildTree(level + 1, maxLevel, splitAlg); + } + + if (triFacesForChild2->size() > 0) { + if (this->child2) + delete this->child2; + this->child2 = new Node(x1_r, y1_r, z1_r, x2_r, y2_r, z2_r, triFacesForChild2, ptrNodes); + this->child2->buildTree(level + 1, maxLevel, splitAlg); + } + } + } + /* ======================================================================================= */ + int intersectLineBoundingBox(const UbTuple<T, T, T> &n1, const UbTuple<T, T, T> &n2) + { + const T &n1X = val<1>(n1); + const T &n1Y = val<2>(n1); + const T &n1Z = val<3>(n1); + + const T &n2X = val<1>(n2); + const T &n2Y = val<2>(n2); + const T &n2Z = val<3>(n2); + + if (UbMath::greater(UbMath::max(((n1X <= n2X ? x[0] : x[1]) - n1X) / (n2X - n1X), + ((n1Y <= n2Y ? y[0] : y[1]) - n1Y) / (n2Y - n1Y), + ((n1Z <= n2Z ? z[0] : z[1]) - n1Z) / (n2Z - n1Z)), + UbMath::min(((n1X > n2X ? x[0] : x[1]) - n1X) / (n2X - n1X), + ((n1Y > n2Y ? y[0] : y[1]) - n1Y) / (n2Y - n1Y), + ((n1Z > n2Z ? z[0] : z[1]) - n1Z) / (n2Z - n1Z)))) { + return Intersection::NO_INTERSECTION; + } else { + return Intersection::INTERSECTION; + } + } + /* ======================================================================================= */ + int intersectRayBoundingBox(const Ray<T> &ray) + { + T tmin = (x[ray.signX] - ray.originX) * ray.inv_directionX; + T tmax = (x[1 - ray.signX] - ray.originX) * ray.inv_directionX; + + T tymin = (y[ray.signY] - ray.originY) * ray.inv_directionY; + T tymax = (y[1 - ray.signY] - ray.originY) * ray.inv_directionY; + + if ((tmin > tymax) || (tymin > tmax)) { + return false; + } + if (tymin > tmin) + tmin = tymin; + if (tymax < tmax) + tmax = tymax; + + T tzmin = (z[ray.signZ] - ray.originZ) * ray.inv_directionZ; + T tzmax = (z[1 - ray.signZ] - ray.originZ) * ray.inv_directionZ; + + // if( (UbMath::greater( tmin, tzmax) ) || ( UbMath::greater( tzmin, tmax) ) ) + if ((tmin > tzmax) || (tzmin > tmax)) { + return false; + } + // if(tzmin > tmin) tmin = tzmin; + if (tzmax < tmax) + tmax = tzmax; + + // return ( (tmin =< t1) && (tmax >= t0) ); + if (UbMath::greaterEqual(tmax, T(0.0))) { + return Intersection::INTERSECTION; + } else { + return Intersection::NO_INTERSECTION; + } + } + /* ======================================================================================= */ + bool intersectLine(const UbTuple<T, T, T> &n1, const UbTuple<T, T, T> &n2, + const LineIntersectionHandler<T> &iHandler) + { + return iHandler.intersectLine(n1, n2, *this, child1, child2); + } + /* ======================================================================================= */ + int intersectRay(const Ray<T> &ray, const RayIntersectionHandler<T> &iHandler, std::set<UbKeys::Key3<int>> &mailbox) + { + return iHandler.intersectRay(ray, *this, child1, child2, mailbox); + } + /* ======================================================================================= */ + int getNumOfTriFaces() + { + if (!child1 && !child2) { + if (triFaces) + return (int)triFaces->size(); + else + return 0; + } else { + int sum = 0; + + if (child1) + sum += child1->getNumOfTriFaces(); + if (child2) + sum += child2->getNumOfTriFaces(); + + return sum; + } + } + /* ======================================================================================= */ + int getNumOfNodes() + { + if (!child1 && !child2) { + return 1; + } else { + int sum = 0; + if (child1) + sum += child1->getNumOfNodes(); + if (child2) + sum += child2->getNumOfNodes(); + + return 1 + sum; + } + } + /* ======================================================================================= */ + std::string toString() + { + return ""; //"[" + x1 + "," + y1 + "," + z1 + "] -" + " [" + x2 + "," + y2 + "," + z2 + "]"; + } + /* ======================================================================================= */ + void addCubeInfo(std::vector<UbTupleFloat3> &nodes, std::vector<UbTupleInt8> &cells, + std::vector<std::string> &datanames, std::vector<std::vector<double>> &celldata) + { + nodes.push_back(makeUbTuple(float(x[0]), float(y[0]), float(z[0]))); + nodes.push_back(makeUbTuple(float(x[1]), float(y[0]), float(z[0]))); + nodes.push_back(makeUbTuple(float(x[1]), float(y[1]), float(z[0]))); + nodes.push_back(makeUbTuple(float(x[0]), float(y[1]), float(z[0]))); + + nodes.push_back(makeUbTuple(float(x[0]), float(y[0]), float(z[1]))); + nodes.push_back(makeUbTuple(float(x[1]), float(y[0]), float(z[1]))); + nodes.push_back(makeUbTuple(float(x[1]), float(y[1]), float(z[1]))); + nodes.push_back(makeUbTuple(float(x[0]), float(y[1]), float(z[1]))); + + cells.push_back(makeUbTuple(int(nodes.size() - 8), int(nodes.size() - 7), int(nodes.size() - 6), + int(nodes.size() - 5), int(nodes.size() - 4), int(nodes.size() - 3), + int(nodes.size() - 2), int(nodes.size() - 1))); + datanames.resize(1); + datanames[0] = "childs"; + celldata.resize(datanames.size()); + if (child1 && child2) + celldata[0].push_back(2); + else if (child1 || child2) + celldata[0].push_back(1); + else + celldata[0].push_back(0); + + if (child1) + child1->addCubeInfo(nodes, cells, datanames, celldata); + if (child2) + child2->addCubeInfo(nodes, cells, datanames, celldata); + } + +public: + T x[2], y[2], z[2]; + +private: + Node *child1; + Node *child2; + + MbSmartPtr<std::vector<GbTriFaceMesh3D::TriFace>> triFaces; + std::vector<GbTriFaceMesh3D::Vertex> *ptrNodes; // lediglich f�r Zugriff auf die Knoten!!! +}; +} // namespace Kd +#endif // KDNODE_H diff --git a/src/basics/geometry3d/KdTree/KdRay.h b/src/basics/geometry3d/KdTree/KdRay.h new file mode 100644 index 0000000000000000000000000000000000000000..43bbcd4500c98a5aa8fc4ba52993f8b62d6d1021 --- /dev/null +++ b/src/basics/geometry3d/KdTree/KdRay.h @@ -0,0 +1,105 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file KdRay.h +//! \ingroup KdTree +//! \author Soeren Textor, Sebastian Bindick +//======================================================================================= +#ifndef KDRAY_H +#define KDRAY_H + +#include <basics/utilities/UbException.h> +#include <basics/utilities/UbMath.h> + +namespace Kd +{ +/* + * Ray class, for use with the optimized ray-box intersection test + * described in: + * + * Amy Williams, Steve Barrus, R. Keith Morley, and Peter Shirley + * "An Efficient and Robust Ray-Box Intersection Algorithm" + * Journal of graphics tools, 10(1):49-54, 2005 + * + */ +template <typename T> +class Ray +{ +public: + Ray(const T &originX, const T &originY, const T &originZ, const T &directionX, const T &directionY, + const T &directionZ) + { + this->originX = originX; + this->originY = originY; + this->originZ = originZ; + + // normierung (fuer ray-triangle-intersection) + T oneOverLength = + T(1.0 / std::sqrt(directionX * directionX + directionY * directionY + directionZ * directionZ)); + + this->directionX = directionX * oneOverLength; + this->directionY = directionY * oneOverLength; + this->directionZ = directionZ * oneOverLength; + + this->inv_directionX = T(1.0 / this->directionX); // ACHTUNG: BEWUSST KEINE ==0 Abfrage + this->inv_directionY = T(1.0 / this->directionY); // Alg verwendet exlitzit INF + this->inv_directionZ = T(1.0 / this->directionZ); + + if (this->inv_directionX < 0.0) + this->signX = 1; + else + this->signX = 0; + if (this->inv_directionY < 0.0) + this->signY = 1; + else + this->signY = 0; + if (this->inv_directionZ < 0.0) + this->signZ = 1; + else + this->signZ = 0; + } + + T originX; + T originY; + T originZ; + + T directionX; + T directionY; + T directionZ; + + T inv_directionX; + T inv_directionY; + T inv_directionZ; + + int signX; + int signY; + int signZ; +}; +} // namespace Kd + +#endif // KDRAY_H diff --git a/src/basics/geometry3d/KdTree/KdSplitCandidate.h b/src/basics/geometry3d/KdTree/KdSplitCandidate.h new file mode 100644 index 0000000000000000000000000000000000000000..cfd2fc3bca2ca1eccae8418c11ad4c69fe892954 --- /dev/null +++ b/src/basics/geometry3d/KdTree/KdSplitCandidate.h @@ -0,0 +1,75 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file KdSplitCandidate.h +//! \ingroup KdTree +//! \author Soeren Textor, Sebastian Bindick +//======================================================================================= +#ifndef KDSPLITCANDIDATE_H +#define KDSPLITCANDIDATE_H + +#include <basics/utilities/UbMath.h> + +namespace Kd +{ +template <typename T> +class SplitCandidate +{ +public: + SplitCandidate() = default; + /* ======================================================================================= */ + SplitCandidate(const int &axis, const T &position, const int &starting, const int &ending, const int &insidePlane) + : axis(axis), position(position), starting(starting), ending(ending), np(insidePlane), + isValid(true) // FIXME: isValid default false is correct? + { + } + /* ======================================================================================= */ + bool operator!() const { return isValid; } + /* ======================================================================================= */ + friend inline bool operator<(const SplitCandidate &lhs, const SplitCandidate &rhs) + { + return lhs.position < rhs.position; + } + /* ======================================================================================= */ + +public: + int axis{ 0 }; + T Cn{ 0.0 }; + T position{ 0.0 }; + int nl{ 0 }; + int nr{ 0 }; + int np; + int starting{ 0 }; + int ending{ 0 }; + bool np_left{ false }; + bool np_right{ false }; + bool isValid{ false }; +}; +} // namespace Kd + +#endif // KDSPLITCANDIDATE_H diff --git a/src/basics/geometry3d/KdTree/KdSplitCandidateManager.h b/src/basics/geometry3d/KdTree/KdSplitCandidateManager.h new file mode 100644 index 0000000000000000000000000000000000000000..d7f4bdf10f141ef6358759708ef9d4fa9d5b9e11 --- /dev/null +++ b/src/basics/geometry3d/KdTree/KdSplitCandidateManager.h @@ -0,0 +1,100 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file KdSplitCandidateManager.h +//! \ingroup KdTree +//! \author Soeren Textor, Sebastian Bindick +//======================================================================================= +#ifndef KDSPLITCANDIDATEMANAGER_H +#define KDSPLITCANDIDATEMANAGER_H + +#include <geometry3d/KdTree/KdSplitCandidate.h> + +#include <algorithm> +#include <map> +#include <vector> + +namespace Kd +{ +template <typename T> +class SplitCandidateManager +{ +public: + SplitCandidateManager() + + = default; + /* ======================================================================================= */ + SplitCandidate<T> &operator[](const std::size_t &i) + { +#ifdef DEBUG + return splitCandidatesVec.at(i); +#else + return splitCandidatesVec[i]; +#endif + } + /* ======================================================================================= */ + typename std::vector<SplitCandidate<T>>::size_type size() { return splitCandidatesVec.size(); } + /* ======================================================================================= */ + void add(const T &pos, const int &axis, const int &starting, const int &ending, const int &np) + { + typename std::map<T, SplitCandidate<T>>::iterator it = splitCandidates.find(pos); + if (it != splitCandidates + .end()) // split candidate is already available -> increase parameter (starting, ending and np) + { + SplitCandidate<T> &sc = it->second; + sc.np += np; + sc.starting += starting; + sc.ending += ending; + } else // split candidate is not available -> add new split candidate + { + this->splitCandidates[pos] = SplitCandidate<T>(axis, pos, starting, ending, np); + } + } + /* ======================================================================================= */ + void createSortedArray() + { + splitCandidatesVec.clear(); + typename std::map<T, SplitCandidate<T>>::iterator it; + for (it = splitCandidates.begin(); it != splitCandidates.end(); ++it) + splitCandidatesVec.push_back(it->second); + splitCandidates.clear(); + std::sort(splitCandidatesVec.begin(), splitCandidatesVec.end(), std::less<SplitCandidate<T>>()); + } + /* ======================================================================================= */ + +public: + int objects_starting_outside_left{ 0 }; + int objects_fully_outside_node{ 0 }; + +private: + std::map<T, SplitCandidate<T>> splitCandidates; + std::vector<SplitCandidate<T>> splitCandidatesVec; +}; +} // namespace Kd + +#endif // KDSPLITCANDIDATEMANAGER_H diff --git a/src/basics/geometry3d/KdTree/KdTree.h b/src/basics/geometry3d/KdTree/KdTree.h new file mode 100644 index 0000000000000000000000000000000000000000..b290c3c61a0591e04cc9358769ef3ce087192f30 --- /dev/null +++ b/src/basics/geometry3d/KdTree/KdTree.h @@ -0,0 +1,135 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file KdTree.h +//! \ingroup KdTree +//! \author Soeren Textor, Sebastian Bindick +//======================================================================================= +#ifndef KDTREE_H +#define KDTREE_H + +#include <basics/utilities/UbKeys.h> +#include <basics/writer/WbWriterVtkXmlBinary.h> +#include <geometry3d/GbTriFaceMesh3D.h> + +#include <geometry3d/KdTree/KdNode.h> +#include <geometry3d/KdTree/KdRay.h> +#include <geometry3d/KdTree/KdSplitCandidate.h> +#include <geometry3d/KdTree/splitalgorithms/KdSplitAlgorithm.h> + +#include <cmath> +#include <string> + +namespace Kd +{ +template <typename T> +class Tree +{ +public: + /* ======================================================================================= */ + Tree(GbTriFaceMesh3D &mesh, const SplitAlgorithm<T> &splitAlg) : rootNode(NULL) { this->buildTree(mesh, splitAlg); } + /* ======================================================================================= */ + ~Tree() + { + if (rootNode) { + delete rootNode; + rootNode = NULL; + } + } + /* ======================================================================================= */ + // the IntersectionHandler specifies how to handle the intersection + bool intersectLine(const UbTuple<T, T, T> &n1, const UbTuple<T, T, T> &n2, + const LineIntersectionHandler<T> &iHandler) + { + return rootNode->intersectLine(n1, n2, iHandler); + } + /* ======================================================================================= */ + // the IntersectionHandler specifies how to handle the intersection + int intersectRay(const Ray<T> &ray, const RayIntersectionHandler<T> &iHandler) + { + std::set<UbKeys::Key3<int>> mailbox; + return rootNode->intersectRay(ray, iHandler, mailbox); + } + /* ======================================================================================= */ + int getNumOfNodes() + { + if (rootNode) + return rootNode->getNumOfNodes(); + return 0; + } + /* ======================================================================================= */ + int getNumOfTriFaces() + { + if (rootNode) + return rootNode->getNumOfTriFaces(); + return 0; + } + /* ======================================================================================= */ + std::string toString() + { + return ""; // Tree:: num of nodes: " + rootNode.getNumOfNodes() + ", primitives:" + + // rootNode.getNumOfPrimitives() + ", root_primitives:" + getNumOfPrimitives() + ", max_level:" + + // max_level; + } + /* ======================================================================================= */ + void buildTree(GbTriFaceMesh3D &mesh, const SplitAlgorithm<T> &splitAlg) + { + if (rootNode) + delete rootNode; + + // create a copy of triangles + MbSmartPtr<std::vector<GbTriFaceMesh3D::TriFace>> triFaces( + new std::vector<GbTriFaceMesh3D::TriFace>(*mesh.getTriangles())); + + const int maxLevel = + static_cast<int>(std::lround(8.0 + 1.3 * std::log((double)triFaces->size()))); // TODO: remove magic numbers + + rootNode = + new Node<T>(T(mesh.getX1Minimum()), T(mesh.getX2Minimum()), T(mesh.getX3Minimum()), T(mesh.getX1Maximum()), + T(mesh.getX2Maximum()), T(mesh.getX3Maximum()), triFaces, mesh.getNodes()); + + rootNode->buildTree(0, maxLevel, splitAlg); + } + void writeTree(const std::string &filename, WbWriter *writer = WbWriterVtkXmlBinary::getInstance()) + { + if (rootNode) { + std::vector<UbTupleFloat3> nodes; + std::vector<UbTupleInt8> cubes; + std::vector<std::string> datanames; + std::vector<std::vector<double>> cubesdata; + rootNode->addCubeInfo(nodes, cubes, datanames, cubesdata); + writer->writeOctsWithCellData(filename, nodes, cubes, datanames, cubesdata); + } + } + +private: + Node<T> *rootNode; +}; +} // namespace Kd + +#endif // KDTREE_H diff --git a/src/basics/geometry3d/KdTree/KdUtilities.cpp b/src/basics/geometry3d/KdTree/KdUtilities.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0dca20ad16b1f2bd89a7591ffe1264e6d1098c82 --- /dev/null +++ b/src/basics/geometry3d/KdTree/KdUtilities.cpp @@ -0,0 +1,45 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file KdUtilities.cpp +//! \ingroup KdTree +//! \author Soeren Textor, Sebastian Bindick +//======================================================================================= +#include <geometry3d/KdTree/KdUtilities.h> + +namespace Kd +{ +const int Axis::X = 0; +const int Axis::Y = 1; +const int Axis::Z = 2; + +const int Intersection::ON_BOUNDARY = -2; +const int Intersection::INTERSECT_EDGE = -1; +const int Intersection::INTERSECTION = 1; +const int Intersection::NO_INTERSECTION = 0; +} // namespace Kd diff --git a/src/basics/geometry3d/KdTree/KdUtilities.h b/src/basics/geometry3d/KdTree/KdUtilities.h new file mode 100644 index 0000000000000000000000000000000000000000..7a304102c7effd2ce1cc487427aa712b1ada2592 --- /dev/null +++ b/src/basics/geometry3d/KdTree/KdUtilities.h @@ -0,0 +1,196 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file KdUtilities.h +//! \ingroup KdTree +//! \author Soeren Textor, Sebastian Bindick +//======================================================================================= +#ifndef KDUTILIES_H +#define KDUTILIES_H + +#include <basics/utilities/UbException.h> +#include <basics/utilities/UbMath.h> +#include <basics/utilities/UbTuple.h> + +#include <geometry3d/GbTriFaceMesh3D.h> + +#include <algorithm> +#include <vector> + +namespace Kd +{ +struct Axis { + static const int X; // = 0; + static const int Y; // = 1; + static const int Z; // = 2; +}; +/* ======================================================================================= */ +struct Intersection { + static const int ON_BOUNDARY; // = -2; + static const int INTERSECT_EDGE; // = -1; + static const int INTERSECTION; // = 1; + static const int NO_INTERSECTION; // = 0; +}; +/* ======================================================================================= */ +template <typename T> +inline void project2Axis(GbTriFaceMesh3D::TriFace &triFace, std::vector<GbTriFaceMesh3D::Vertex> &nodes, + const int &axis, std::vector<T> &projection) +{ + projection.resize(3); + + if (axis == Axis::X) { + projection[0] = triFace.getV1x(nodes); + projection[1] = triFace.getV2x(nodes); + projection[2] = triFace.getV3x(nodes); + } else if (axis == Axis::Y) { + projection[0] = triFace.getV1y(nodes); + projection[1] = triFace.getV2y(nodes); + projection[2] = triFace.getV3y(nodes); + } else if (axis == Axis::Z) { + projection[0] = triFace.getV1z(nodes); + projection[1] = triFace.getV2z(nodes); + projection[2] = triFace.getV3z(nodes); + } else + throw UbException(UB_EXARGS, "unknown axis"); + + std::sort(projection.begin(), projection.end(), std::less<>()); +} +/* ======================================================================================= */ +template <typename T> +inline bool isPointOnPlane(const T &px, const T &py, const T &pz, const T &precision, + GbTriFaceMesh3D::Vertex &pointOfTriFace, GbTriFaceMesh3D::TriFace &triFace) +{ + return std::fabs((px - pointOfTriFace.x) * triFace.nx + (py - pointOfTriFace.y) * triFace.ny + + (pz - pointOfTriFace.z) * triFace.nz) < precision; +} +/* ======================================================================================= */ +template <typename T> +inline bool isPointOnTriangle(const T &px, const T &py, const T &pz, const T &precision, GbTriFaceMesh3D::Vertex &p1, + GbTriFaceMesh3D::Vertex &p2, GbTriFaceMesh3D::Vertex &p3, + GbTriFaceMesh3D::TriFace &triFace) +{ + if (Kd::isPointOnPlane(px, py, pz, precision, p1, triFace)) { + T a_x = p1.x - px; + T a_y = p1.y - py; + T a_z = p1.z - pz; + T b_x = p2.x - px; + T b_y = p2.y - py; + T b_z = p2.z - pz; + T c_x = p3.x - px; + T c_y = p3.y - py; + T c_z = p3.z - pz; + + const T factor = 0.5; + T Q1_x = (a_y * b_z - a_z * b_y) * factor; + T Q1_y = (a_z * b_x - a_x * b_z) * factor; + T Q1_z = (a_x * b_y - a_y * b_x) * factor; + + T Q2_x = (b_y * c_z - b_z * c_y) * factor; + T Q2_y = (b_z * c_x - b_x * c_z) * factor; + T Q2_z = (b_x * c_y - b_y * c_x) * factor; + + T Q3_x = (c_y * a_z - c_z * a_y) * factor; + T Q3_y = (c_z * a_x - c_x * a_z) * factor; + T Q3_z = (c_x * a_y - c_y * a_x) * factor; + + T Q_x = Q1_x + Q2_x + Q3_x; + T Q_y = Q1_y + Q2_y + Q3_y; + T Q_z = Q1_z + Q2_z + Q3_z; + + if (UbMath::zero(Q_x * Q1_x + Q_y * Q1_y + Q_z * Q1_z)) + return true; + else if (UbMath::zero(Q_x * Q2_x + Q_y * Q2_y + Q_z * Q2_z)) + return true; + else if (UbMath::zero(Q_x * Q3_x + Q_y * Q3_y + Q_z * Q3_z)) + return true; + else if (UbMath::less(Q_x * Q1_x + Q_y * Q1_y + Q_z * Q1_z, T(0.0))) + return false; + else if (UbMath::less(Q_x * Q2_x + Q_y * Q2_y + Q_z * Q2_z, T(0.0))) + return false; + else if (UbMath::less(Q_x * Q3_x + Q_y * Q3_y + Q_z * Q3_z, T(0.0))) + return false; + + return true; + } + + return false; +} +/* ======================================================================================= */ +template <typename T> +inline bool intersectLine(const UbTuple<T, T, T> &n1, const UbTuple<T, T, T> &n2, GbTriFaceMesh3D::TriFace &triFace, + std::vector<GbTriFaceMesh3D::Vertex> &nodes) +{ + GbTriFaceMesh3D::Vertex &p0 = triFace.getNode(0, nodes); + + const T &n1X = val<1>(n1); + const T &n1Y = val<2>(n1); + const T &n1Z = val<3>(n1); + + const T &n2X = val<1>(n2); + const T &n2Y = val<2>(n2); + const T &n2Z = val<3>(n2); + + // if( Kd::isPointOnPlane(n1X, n1Y, n1Z, T(1.0E-6), p0, triFace) + // && Kd::isPointOnPlane(n2X, n2Y, n2Z, T(1.0E-6), p0, triFace)) + //{ + // return true; + //} + + T denom = (n2X - n1X) * triFace.nx + (n2Y - n1Y) * triFace.ny + (n2Z - n1Z) * triFace.nz; + + if (UbMath::zero(denom)) // line does not intersect the plane of the triangle ! + { + return false; + } else { + T d = -triFace.nx * p0.x - triFace.ny * p0.y - triFace.nz * p0.z; + T mu = T(-1.0 * (d + n1X * triFace.nx + n1Y * triFace.ny + n1Z * triFace.nz) / denom); + + if (!UbMath::inClosedInterval(mu, T(0.0), + T(1.0))) // Point of intersection of line and plane does not lie on the triangle + { + return false; + } else { + // intersection with plane + + // Test whether Point lies inside the triangle or not + GbTriFaceMesh3D::Vertex &p1 = triFace.getNode(1, nodes); + GbTriFaceMesh3D::Vertex &p2 = triFace.getNode(2, nodes); + + return Kd::isPointOnTriangle(n1X + ((n2X - n1X) * mu) // intersectionPointX + , + n1Y + ((n2Y - n1Y) * mu) // intersectionPointY + , + n1Z + ((n2Z - n1Z) * mu) // intersectionPointZ + , + T(0.001), p0, p1, p2, triFace); + } + } +} +} // namespace Kd + +#endif // KDUTILIES_H diff --git a/src/basics/geometry3d/KdTree/intersectionhandler/KdCountLineIntersectionHandler.h b/src/basics/geometry3d/KdTree/intersectionhandler/KdCountLineIntersectionHandler.h new file mode 100644 index 0000000000000000000000000000000000000000..49b2754d6f3d6180e16c09b4d74d6dfde8dd4528 --- /dev/null +++ b/src/basics/geometry3d/KdTree/intersectionhandler/KdCountLineIntersectionHandler.h @@ -0,0 +1,85 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file KdCountLineIntersectionHandler.h +//! \ingroup splitalgorithms +//! \author Soeren Textor, Sebastian Bindick +//======================================================================================= +#ifndef KDCOUNTLINEINTERSECTIONHANDLER_H +#define KDCOUNTLINEINTERSECTIONHANDLER_H + +#include <basics/utilities/UbKeys.h> +#include <basics/utilities/UbTuple.h> + +#include <geometry3d/GbTriFaceMesh3D.h> + +#include <geometry3d/KdTree/KdNode.h> +#include <geometry3d/KdTree/KdUtilities.h> +#include <geometry3d/KdTree/intersectionhandler/KdLineIntersectionHandler.h> + +#include <set> + +namespace Kd +{ +template <typename T> +class CountLineIntersectionHandler : public LineIntersectionHandler<T> +{ +public: + bool intersectLine(const UbTuple<T, T, T> &n1, const UbTuple<T, T, T> &n2, Node<T> &parent, Node<T> *&child1, + Node<T> *&child2) const override + { + if (parent.intersectLineBoundingBox(n1, n2) == Intersection::INTERSECTION) { + if (parent.isLeaf()) { + std::vector<GbTriFaceMesh3D::TriFace> &triFaces = *parent.getTriFaces(); + std::vector<GbTriFaceMesh3D::Vertex> &nodes = parent.getNodes(); + + for (std::size_t i = 0; i < triFaces.size(); i++) { + GbTriFaceMesh3D::TriFace &triFace = triFaces[i]; + + if (Kd::intersectLine(n1, n2, triFace, nodes)) + return true; + } + return false; + } else { + if (child1) { + if (child1->intersectLine(n1, n2, *this)) + return true; + } + if (child2) { + if (child2->intersectLine(n1, n2, *this)) + return true; + } + } + } + return false; + } + /* ======================================================================================= */ +}; +} // namespace Kd + +#endif // KDCOUNTLINEINTERSECTIONHANDLER_H diff --git a/src/basics/geometry3d/KdTree/intersectionhandler/KdCountRayIntersectionHandler.h b/src/basics/geometry3d/KdTree/intersectionhandler/KdCountRayIntersectionHandler.h new file mode 100644 index 0000000000000000000000000000000000000000..7ca7ed3ee3e9eba80b7ee3cf090502c929df3fc9 --- /dev/null +++ b/src/basics/geometry3d/KdTree/intersectionhandler/KdCountRayIntersectionHandler.h @@ -0,0 +1,191 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file KdCountRayIntersectionHandler.h +//! \ingroup splitalgorithms +//! \author Soeren Textor, Sebastian Bindick +//======================================================================================= +#ifndef KDCOUNTRAYINTERSECTIONHANDLER_H +#define KDCOUNTRAYINTERSECTIONHANDLER_H + +#include <basics/utilities/UbKeys.h> +#include <basics/utilities/UbTuple.h> + +#include <geometry3d/GbTriFaceMesh3D.h> + +#include <geometry3d/KdTree/KdNode.h> +//#include <geometry3d/KdTree/KdUtilities.h> +#include <geometry3d/KdTree/intersectionhandler/KdRayIntersectionHandler.h> + +#include <set> + +namespace Kd +{ +template <typename T> +class CountRayIntersectionHandler : public RayIntersectionHandler<T> +{ +public: + int intersectRay(const Ray<T> &ray, Node<T> &parent, Node<T> *&child1, Node<T> *&child2, + std::set<UbKeys::Key3<int>> &mailbox) const override + { + if (parent.intersectRayBoundingBox(ray) == Intersection::INTERSECTION) { + if (parent.isLeaf()) { + return this->checkIntersectionWithTriFaces(ray, *parent.getTriFaces(), parent.getNodes(), mailbox); + } else { + int sum = 0; + if (child1) { + int erg = child1->intersectRay(ray, *this, mailbox); + if (erg < 0) { + return erg; + } + sum += erg; + } + if (child2) { + int erg = child2->intersectRay(ray, *this, mailbox); + if (erg < 0) { + return erg; + } + sum += erg; + } + return sum; + } + } else { + return 0; + } + } + /* ======================================================================================= */ + +private: + int checkIntersectionWithTriFaces(const Ray<T> &ray, std::vector<GbTriFaceMesh3D::TriFace> &triFaces, + std::vector<GbTriFaceMesh3D::Vertex> &nodes, + std::set<UbKeys::Key3<int>> &mailbox) const + { + T e1x, e1y, e1z, e2x, e2y, e2z, px, py, pz, a, f, sx, sy, sz, u, qx, qy, qz, v, factor; + + int counter = 0; + + for (std::size_t i = 0; i < triFaces.size(); i++) { + GbTriFaceMesh3D::TriFace &triFace = triFaces[i]; + + if (mailbox.find(UbKeys::Key3<int>(triFace.getIndexVertex1(), triFace.getIndexVertex2(), + triFace.getIndexVertex3())) == mailbox.end()) { + mailbox.insert( + UbKeys::Key3<int>(triFace.getIndexVertex1(), triFace.getIndexVertex2(), + triFace.getIndexVertex3())); // schon hier rein, ansonsten muss man es unten bei + // JEDEm continue und am ende des ifs machen + + GbTriFaceMesh3D::Vertex &v1 = triFace.getNode(0, nodes); + GbTriFaceMesh3D::Vertex &v2 = triFace.getNode(1, nodes); + GbTriFaceMesh3D::Vertex &v3 = triFace.getNode(2, nodes); + + ////////////////////////////////////////////////////////////////////////// + // Raytracing - start( Anm.: pr�ft NUR in Strahlrichtung + // Grundidee: Schnittpunkt in Baryzentrischen Koordinaten besimmten + // t(u,v,w) = w*v0 + u*v1 + v*v2 + // mit w = 1.0-u-v, da fuer alle Punkte (u,v,w) im Dreick gilt u+v+w = 1 + // wenn u, v oder w == 0 -> Punkt liegt auf Kante + // wenn u, v oder w == 1 -> Punkt liegt auf Eckpunkt (-> die anderen Werte muessen 0 ) + + // e1 = v1 - v0 + e1x = v2.x - v1.x; + e1y = v2.y - v1.y; + e1z = v2.z - v1.z; + + // e2 = v2 - v0 + e2x = v3.x - v1.x; + e2y = v3.y - v1.y; + e2z = v3.z - v1.z; + + // p = d x e2 + px = ray.directionY * e2z - ray.directionZ * e2y; + py = ray.directionZ * e2x - ray.directionX * e2z; + pz = ray.directionX * e2y - ray.directionY * e2x; + + // a = e1 dot p + a = e1x * px + e1y * py + e1z * pz; + // if( fabs(a)<1.E-10 ) continue; + if (fabs(a) < UbMath::Epsilon<T>::val()) + continue; + f = T(1.0 / a); + + // s = o - v0 + sx = ray.originX - v1.x; + sy = ray.originY - v1.y; + sz = ray.originZ - v1.z; + + // u = f * ( s dot p) + u = f * (sx * px + sy * py + sz * pz); + + // u ist nur gueltig in [0;1] + if ((UbMath::less(u, T(0.0))) || (UbMath::greater(u, T(1.0)))) { + continue; + } + + // q = s x e1 + qx = sy * e1z - sz * e1y; + qy = sz * e1x - sx * e1z; + qz = sx * e1y - sy * e1x; + + // v = f*(e2 dot q) + v = f * (ray.directionX * qx + ray.directionY * qy + ray.directionZ * qz); + + // v ist nur gueltig in [0;1] da aber v bereits gueltig ist -> u+v darf nicht > 1.0 sein ;-) + if ((UbMath::less(v, T(0.0))) || (UbMath::greater(u + v, T(1.0)))) { + continue; + } + + // t = f * (e2 dot q) + factor = f * (e2x * qx + e2y * qy + e2z * qz); + // Raytracing - end + ////////////////////////////////////////////////////////////////////////// + + if (UbMath::zero(factor)) { + return Intersection::ON_BOUNDARY; // ray.Org liegt direkt auf einem dreieck --> boundary + } + if (factor < 0.0) { + continue; // Schnittpunkt liegt in entgegengesetzter Strahlrichtung + } + + // edge tests + // wenn u, v oder w ==0 -> Punkt liegt auf Kante bzw. Eckpunkt + if (UbMath::zero(u)) + return Intersection::INTERSECT_EDGE; + if (UbMath::zero(v)) + return Intersection::INTERSECT_EDGE; + if (UbMath::zero(T(1.0) - u - v)) + return Intersection::INTERSECT_EDGE; + + counter++; + } + } + return counter; + } +}; +} // namespace Kd + +#endif // KDCOUNTRAYLINEINTERSECTIONHANDLER_H diff --git a/src/basics/geometry3d/KdTree/intersectionhandler/KdLineIntersectionHandler.h b/src/basics/geometry3d/KdTree/intersectionhandler/KdLineIntersectionHandler.h new file mode 100644 index 0000000000000000000000000000000000000000..0895f740894341b8cf5b3d340b114eb76b88a58e --- /dev/null +++ b/src/basics/geometry3d/KdTree/intersectionhandler/KdLineIntersectionHandler.h @@ -0,0 +1,63 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file KdLineIntersectionHandler.h +//! \ingroup splitalgorithms +//! \author Soeren Textor, Sebastian Bindick +//======================================================================================= +#ifndef KDLINEINTERSECTIONHANDLER_H +#define KDLINEINTERSECTIONHANDLER_H + +#include <basics/utilities/UbTuple.h> +//#include <geometry3d/GbTriFaceMesh3D.h> + +#include <set> + +// #ifdef CAB_RCF +// # include <3rdParty/rcf/RcfSerializationIncludes.h> +// #end +namespace Kd +{ +template <typename T> +class Node; + +template <typename T> +class LineIntersectionHandler +{ +public: + virtual bool intersectLine(const UbTuple<T, T, T> &n1, const UbTuple<T, T, T> &n2, Node<T> &parent, + Node<T> *&child1, Node<T> *&child2) const = 0; + virtual ~LineIntersectionHandler() = default; +}; +} // namespace Kd + +// #if defined(RCF_USE_SF_SERIALIZATION) && !defined(SWIG) +// SF_NO_CTOR(Kd::LineIntersectionHandler<float>); +// SF_NO_CTOR(Kd::LineIntersectionHandler<double>); +// #endif //RCF_USE_SF_SERIALIZATI +#endif // KDLINEINTERSECTIONHANDLER_H diff --git a/src/basics/geometry3d/KdTree/intersectionhandler/KdRayIntersectionHandler.h b/src/basics/geometry3d/KdTree/intersectionhandler/KdRayIntersectionHandler.h new file mode 100644 index 0000000000000000000000000000000000000000..e38fcd5340a94200b961c27f092aec1258722c13 --- /dev/null +++ b/src/basics/geometry3d/KdTree/intersectionhandler/KdRayIntersectionHandler.h @@ -0,0 +1,53 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file KdRayIntersectionHandler.h +//! \ingroup splitalgorithms +//! \author Soeren Textor, Sebastian Bindick +//======================================================================================= +#ifndef KDRAYINTERSECTIONHANDLER_H +#define KDRAYINTERSECTIONHANDLER_H + +#include <basics/utilities/UbTuple.h> +#include <geometry3d/KdTree/KdRay.h> + +#include <set> + +namespace Kd +{ +template <typename T> +class RayIntersectionHandler +{ +public: + virtual int intersectRay(const Ray<T> &ray, Node<T> &parent, Node<T> *&child1, Node<T> *&child2, + std::set<UbKeys::Key3<int>> &mailbox) const = 0; + virtual ~RayIntersectionHandler() = default; +}; +} // namespace Kd + +#endif // KDRAYINTERSECTIONHANDLER_H diff --git a/src/basics/geometry3d/KdTree/splitalgorithms/KdSAHSplit.cpp b/src/basics/geometry3d/KdTree/splitalgorithms/KdSAHSplit.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b1437df34892146645692691894ace02b509871b --- /dev/null +++ b/src/basics/geometry3d/KdTree/splitalgorithms/KdSAHSplit.cpp @@ -0,0 +1,39 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file KdSAHSplit.cpp +//! \ingroup splitalgorithms +//! \author Soeren Textor, Sebastian Bindick +//======================================================================================= +//#include <geometry3d/KdTree/SAHSplit.h> + +// namespace Kd +// { +// const double SAHSplit::Ct = 3.0; //traversal cost +// const double SAHSplit::Ci = 4.0; //ray-patch-intersection-cost +// } diff --git a/src/basics/geometry3d/KdTree/splitalgorithms/KdSAHSplit.h b/src/basics/geometry3d/KdTree/splitalgorithms/KdSAHSplit.h new file mode 100644 index 0000000000000000000000000000000000000000..334c911fb8fc68bf3b1c82a9757d026320edcf8e --- /dev/null +++ b/src/basics/geometry3d/KdTree/splitalgorithms/KdSAHSplit.h @@ -0,0 +1,287 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file KdSAHSplit.h +//! \ingroup splitalgorithms +//! \author Soeren Textor, Sebastian Bindick +//======================================================================================= +#ifndef KDSAHSPLIT_H +#define KDSAHSPLIT_H + +#include <basics/utilities/UbException.h> +#include <basics/utilities/UbInfinity.h> +#include <basics/utilities/UbMath.h> +#include <geometry3d/GbTriFaceMesh3D.h> + +#include <geometry3d/KdTree/KdNode.h> +#include <geometry3d/KdTree/KdSplitCandidateManager.h> +#include <geometry3d/KdTree/KdUtilities.h> +#include <geometry3d/KdTree/splitalgorithms/KdSplitAlgorithm.h> + +#include <cmath> +#include <vector> + +namespace Kd +{ +template <typename T> +class SAHSplit : public SplitAlgorithm<T> +{ +public: + /* ======================================================================================= */ + SplitCandidate<T> findBestSplitCandidate(const int &level, const int &maxLevel, Node<T> &node) const override + { + if (!node.getTriFaces()) + throw UbException(UB_EXARGS, "triFace NULL pointer"); + + if (node.getTriFaces()->size() <= 1 // max triangles in node + || level >= maxLevel) { + return SplitCandidate<T>(); + } + + SplitCandidate<T> bestSplitCandidate; + T minCN = Ub::inf; + + for (int splitAxis = 0; splitAxis < 3; splitAxis++) { + SplitCandidateManager<T> sc; + findPossibleSplitCandidates(splitAxis, node, sc); + + // incremental sweep to find best split position + for (std::size_t i = 0; i < sc.size(); i++) { + if (i == 0) { + sc[i].nl = sc.objects_starting_outside_left + sc.objects_fully_outside_node; + sc[i].nr = int(node.getTriFaces()->size()) - sc[0].np - sc[0].ending; + } else { + sc[i].nl = sc[i - 1].nl + sc[i - 1].starting + sc[i - 1].np; + sc[i].nr = sc[i - 1].nr - sc[i].ending - sc[i].np; + } + + this->calcSAH(sc[i], node); + + if (sc[i].Cn < minCN) { + minCN = sc[i].Cn; + bestSplitCandidate = sc[i]; + } + } + } + + // automatic termination criterion (SAH) + if (bestSplitCandidate.isValid && bestSplitCandidate.Cn >= node.getTriFaces()->size() * Ci) { + return SplitCandidate<T>(); + } + + return bestSplitCandidate; + } + /* ======================================================================================= */ + void distributeTriFaces(const SplitCandidate<T> &candidate, + std::vector<GbTriFaceMesh3D::TriFace> &triFacesForChild1, + std::vector<GbTriFaceMesh3D::TriFace> &triFacesForChild2, Node<T> &node) const override + { + if (!node.getTriFaces()) + throw UbException(UB_EXARGS, "null pointer at triface list"); + + std::vector<GbTriFaceMesh3D::TriFace> &srcTriFaces = *node.getTriFaces(); + std::vector<GbTriFaceMesh3D::Vertex> &srcNodes = node.getNodes(); + std::vector<T> projection; + + for (std::size_t i = 0; i < srcTriFaces.size(); i++) { + GbTriFaceMesh3D::TriFace &triFace = srcTriFaces[i]; + Kd::project2Axis(triFace, srcNodes, candidate.axis, projection); + + T &min = projection[0]; + T &max = projection[2]; + // --------------------------------------------------- // + // case 1 : object inside plane + if (UbMath::equal(min, max)) { + if (UbMath::equal(min, candidate.position)) { + if (candidate.np_left) { + triFacesForChild1.push_back(triFace); + } else if (candidate.np_right) { + triFacesForChild2.push_back(triFace); + } + } else if (UbMath::less(min, candidate.position)) { + triFacesForChild1.push_back(triFace); + } else // if( UbMath::greater(min, candidate.position) + { + triFacesForChild2.push_back(triFace); + } + } // + // --------------------------------------------------- // + // case 2 : object on left side of plane + else if (UbMath::lessEqual(max, candidate.position)) { + triFacesForChild1.push_back(triFace); + } // --------------------------------------------------- // + // case 3 : object on right side of plane + else if (UbMath::greaterEqual(min, candidate.position)) { + triFacesForChild2.push_back(triFace); + } // + // --------------------------------------------------- // + // case 4 : object in both nodes + else { + triFacesForChild1.push_back(triFace); + triFacesForChild2.push_back(triFace); + } // + // --------------------------------------------------- // + } + + node.deleteTriFaces(); + } + +private: + /* ======================================================================================= */ + // cost function + inline T calcCosts(const int &nl, const int &nr, const T &SA_VL, const T &SA_VR, const T &SA_V) const + { + return Ct + Ci * (nl * SA_VL / SA_V + nr * SA_VR / SA_V); + } + /* ======================================================================================= */ + void findPossibleSplitCandidates(const int &splitAxis, Node<T> &node, + SplitCandidateManager<T> &splitCandidateManager) const + { + T p1_node = (splitAxis == Axis::X ? node.x[0] : splitAxis == Axis::Y ? node.y[0] : node.z[0]); + T p2_node = (splitAxis == Axis::X ? node.x[1] : splitAxis == Axis::Y ? node.y[1] : node.z[1]); + + if (!node.getTriFaces()) + throw UbException(UB_EXARGS, "null pointer"); + + std::vector<GbTriFaceMesh3D::TriFace> &srcTriFaces = *node.getTriFaces(); + std::vector<GbTriFaceMesh3D::Vertex> &srcNodes = node.getNodes(); + std::vector<T> projection; + + for (std::size_t i = 0; i < srcTriFaces.size(); i++) { + GbTriFaceMesh3D::TriFace &triFace = srcTriFaces[i]; + + // project object to axis + Kd::project2Axis(triFace, srcNodes, splitAxis, projection); + // left point + T &p1 = projection[0]; + // right point + T &p2 = projection[2]; + + // --------------------------------------------------- // + // --------------------------------------------------- // + // case 1 : object is fully inside the current node + if (UbMath::greaterEqual(p1, p1_node) && UbMath::lessEqual(p2, p2_node)) { + if (UbMath::equal(p1, p2)) { + // object is inside the plane + splitCandidateManager.add(p1, splitAxis, 0, 0, 1); + } else { + splitCandidateManager.add(p1, splitAxis, 1, 0, 0); + splitCandidateManager.add(p2, splitAxis, 0, 1, 0); + } + } // + // --------------------------------------------------- // + // --------------------------------------------------- // + // case 2 : just the right point (p2) is inside the current node + else if (UbMath::less(p1, p1_node) && UbMath::lessEqual(p2, p2_node) && UbMath::greaterEqual(p2, p1_node)) { + splitCandidateManager.add(p2, splitAxis, 0, 1, 0); + splitCandidateManager.objects_starting_outside_left++; + } // + // --------------------------------------------------- // + // --------------------------------------------------- // + // case 3 : just the left point (p1) is inside the current node + else if (UbMath::greaterEqual(p1, p1_node) && UbMath::greater(p2, p2_node) && + UbMath::lessEqual(p1, p2_node)) { + splitCandidateManager.add(p1, splitAxis, 1, 0, 0); + } // + // --------------------------------------------------- // + // --------------------------------------------------- // + // case 4 : left and right point are outside the current node + else if (UbMath::less(p1, p1_node) && UbMath::greater(p2, p2_node)) { + splitCandidateManager.objects_fully_outside_node++; + } // + // --------------------------------------------------- // + // --------------------------------------------------- // + } + + splitCandidateManager.createSortedArray(); + } + + /* ======================================================================================= */ + // calculates the costs for a given splitCandidate based on the Surface Area Heuristic (SAH) + void calcSAH(SplitCandidate<T> &candidate, Node<T> &node) const + { + T p1_node = (candidate.axis == Axis::X ? node.x[0] : candidate.axis == Axis::Y ? node.y[0] : node.z[0]); + + // edges of (root) voxel + T dx = std::fabs(node.x[1] - node.x[0]); + T dy = std::fabs(node.y[1] - node.y[0]); + T dz = std::fabs(node.z[1] - node.z[0]); + + // surface area (root) voxel + T SA_V = T((2.0 * dx * dy) + (2.0 * dx * dz) + (2.0 * dy * dz)); + + T delta = (candidate.axis == Axis::X ? dx : candidate.axis == Axis::Y ? dy : dz); + T deltaL = std::fabs(candidate.position - p1_node); + T deltaR = std::fabs(delta - deltaL); + + // edges of sub voxel left + T dx_l = (candidate.axis == Axis::X ? deltaL : dx), dy_l = (candidate.axis == Axis::Y ? deltaL : dy), + dz_l = (candidate.axis == Axis::Z ? deltaL : dz); + + // surface area sub voxel left + T SA_VL = T((2.0 * dx_l * dy_l) + (2.0 * dx_l * dz_l) + (2.0 * dy_l * dz_l)); + + // edges of sub voxel right + T dx_r = (candidate.axis == Axis::X ? deltaR : dx), dy_r = (candidate.axis == Axis::Y ? deltaR : dy), + dz_r = (candidate.axis == Axis::Z ? deltaR : dz); + + // surface area sub voxel right + T SA_VR = T((2.0 * dx_r * dy_r) + (2.0 * dx_r * dz_r) + (2.0 * dy_r * dz_r)); + + if (candidate.np == 0) { + candidate.Cn = calcCosts(candidate.nl, candidate.nr, SA_VL, SA_VR, SA_V); + return; + } + + // once putting np with nl, and once with nr - and select the one with lowest cost + // see: Wald, Havran: "On building fast kd-Trees for Ray Tracing, and doing that in O(N log N)", 2006 + T CP_L = calcCosts(candidate.nl + candidate.np, candidate.nr, SA_VL, SA_VR, SA_V); + T CP_R = calcCosts(candidate.nl, candidate.nr + candidate.np, SA_VL, SA_VR, SA_V); + + if (CP_L < CP_R) { + candidate.Cn = CP_L; + candidate.np_right = true; + } else { + candidate.Cn = CP_R; + candidate.np_left = true; + } + } + /* ======================================================================================= */ + +protected: + static const T Ct; // = 3.0; traversal cost + static const T Ci; // = 4.0; ray-patch-intersection-cost +}; + +template <typename T> +const T SAHSplit<T>::Ct = 3.0; // traversal cost +template <typename T> +const T SAHSplit<T>::Ci = 4.0; // ray-patch-intersection-cost +} // namespace Kd + +#endif // KDSAHSPLIT_H diff --git a/src/basics/geometry3d/KdTree/splitalgorithms/KdSpatiallMedianSplit.h b/src/basics/geometry3d/KdTree/splitalgorithms/KdSpatiallMedianSplit.h new file mode 100644 index 0000000000000000000000000000000000000000..57a3eef3b9e2d2698b307fcac124f932b8b0b148 --- /dev/null +++ b/src/basics/geometry3d/KdTree/splitalgorithms/KdSpatiallMedianSplit.h @@ -0,0 +1,115 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file KdSpacialMedianSplit.h +//! \ingroup splitalgorithms +//! \author Soeren Textor, Sebastian Bindick +//======================================================================================= +#ifndef SPATIALLMEDIANSPLIT_H +#define SPATIALLMEDIANSPLIT_H + +#include <basics/utilities/UbMath.h> +#include <geometry3d/GbTriFaceMesh3D.h> + +#include <geometry3d/KdTree/splitalgorithms/KdSplitAlgorithm.h> + +namespace Kd +{ +template <typename T> +class SpatialMedianSplit : public SplitAlgorithm<T> +{ + /* ======================================================================================= */ + SplitCandidate<T> findBestSplitCandidate(const int &level, const int &maxLevel, Node<T> &node) const override + { + if (node.getTriFaces()->size() <= 24 // max triangles in node + || level >= maxLevel) { + return SplitCandidate<T>(); + } + + T dx = std::fabs(node.x[1] - node.x[0]); + T dy = std::fabs(node.y[1] - node.y[0]); + T dz = std::fabs(node.z[1] - node.z[0]); + + if (UbMath::equal(dx, UbMath::max(dx, dy, dz))) + return SplitCandidate<T>(Axis::X, node.x[0] + 0.5 * dx, 0, 0, 0); + else if (UbMath::equal(dy, UbMath::max(dy, dz))) + return SplitCandidate<T>(Axis::Y, node.y[0] + 0.5 * dy, 0, 0, 0); + + return SplitCandidate<T>(Axis::Z, node.z[0] + 0.5 * dz, 0, 0, 0); + } + /* ======================================================================================= */ + void distributeTriFaces(const SplitCandidate<T> &candidate, + std::vector<GbTriFaceMesh3D::TriFace> &primitives_child1, + std::vector<GbTriFaceMesh3D::TriFace> &primitives_child2, Node<T> &node) const override + { + if (!node.getTriFaces()) + throw UbException(UB_EXARGS, "null pointer"); + + std::vector<GbTriFaceMesh3D::TriFace> &srcTriFaces = *node.getTriFaces(); + std::vector<GbTriFaceMesh3D::Vertex> &srcNodes = node.getNodes(); + std::vector<T> projection; + + for (std::size_t i = 0; i < srcTriFaces.size(); i++) { + GbTriFaceMesh3D::TriFace &triFace = srcTriFaces[i]; + Kd::project2Axis(triFace, srcNodes, candidate.axis, projection); + + T &min = projection[0]; + T &max = projection[2]; + + // case 1 : object inside plane + if (UbMath::equal(min, max)) { + if (UbMath::equal(min, candidate.position)) { + primitives_child1.push_back(triFace); + primitives_child2.push_back(triFace); + } else if (UbMath::less(min, candidate.position)) { + primitives_child1.push_back(triFace); + } else if (UbMath::greater(min, candidate.position)) { + primitives_child2.push_back(triFace); + } + } + // case 2 : object on left side of plane + else if (UbMath::lessEqual(max, candidate.position)) { + primitives_child1.push_back(triFace); + } + // case 3 : object on right side of plane + else if (UbMath::greaterEqual(min, candidate.position)) { + primitives_child2.push_back(triFace); + } + // case 4 : object in both nodes + else { + primitives_child1.push_back(triFace); + primitives_child2.push_back(triFace); + } + } + + node.deleteTriFaces(); + } +}; +} // namespace Kd + +#endif // SPATIALLMEDIANSPLIT_H diff --git a/src/basics/geometry3d/KdTree/splitalgorithms/KdSplitAlgorithm.h b/src/basics/geometry3d/KdTree/splitalgorithms/KdSplitAlgorithm.h new file mode 100644 index 0000000000000000000000000000000000000000..b6901241e9dd36a1f687ff87a9a292ef95daa1b8 --- /dev/null +++ b/src/basics/geometry3d/KdTree/splitalgorithms/KdSplitAlgorithm.h @@ -0,0 +1,59 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file KdSplitAlgorithm.h +//! \ingroup splitalgorithms +//! \author Soeren Textor, Sebastian Bindick +//======================================================================================= +#ifndef KDSPLITALGORITHM_H +#define KDSPLITALGORITHM_H + +#include <geometry3d/GbTriFaceMesh3D.h> +//#include <geometry3d/KdTree/Node.h> +#include <geometry3d/KdTree/KdSplitCandidate.h> + +#include <vector> + +namespace Kd +{ +template <typename T> +class Node; + +template <typename T> +class SplitAlgorithm +{ +public: + virtual SplitCandidate<T> findBestSplitCandidate(const int &level, const int &maxLevel, Node<T> &node) const = 0; + virtual void distributeTriFaces(const SplitCandidate<T> &candidate, + std::vector<GbTriFaceMesh3D::TriFace> &triFacesForChild1, + std::vector<GbTriFaceMesh3D::TriFace> &triFacesForChild2, Node<T> &node) const = 0; + virtual ~SplitAlgorithm() = default; +}; +} // namespace Kd + +#endif // KDSPLITALGORITHM_H diff --git a/src/gpu/GksGpu/BoundaryConditions/BoundaryCondition.cpp b/src/gpu/GksGpu/BoundaryConditions/BoundaryCondition.cpp index 781ba46d26df995446312199a805f6c8d499998e..b9abb50130e18df11062c144a53e21461dae7fbf 100644 --- a/src/gpu/GksGpu/BoundaryConditions/BoundaryCondition.cpp +++ b/src/gpu/GksGpu/BoundaryConditions/BoundaryCondition.cpp @@ -43,6 +43,8 @@ #include "DataBase/DataBaseAllocator.h" #include "DataBase/DataBaseStruct.h" +using namespace vf::gpu; + BoundaryCondition::BoundaryCondition( SPtr<DataBase> dataBase ) : myAllocator ( dataBase->myAllocator ) { diff --git a/src/gpu/GksMeshAdapter/GksMeshAdapter.cpp b/src/gpu/GksMeshAdapter/GksMeshAdapter.cpp index fcff658b3662bf5ce55bdc42c0a8d07e8e7c872d..28a0b87d12e9de452a3a42b8ddfa0fe3e5add8e7 100644 --- a/src/gpu/GksMeshAdapter/GksMeshAdapter.cpp +++ b/src/gpu/GksMeshAdapter/GksMeshAdapter.cpp @@ -53,6 +53,8 @@ #include "MeshCell.h" #include "MeshFace.h" +using namespace vf::gpu; + GksMeshAdapter::GksMeshAdapter(SPtr<MultipleGridBuilder> gridBuilder) : gridBuilder(gridBuilder) {} diff --git a/src/gpu/GksMeshAdapter/MeshCell.cpp b/src/gpu/GksMeshAdapter/MeshCell.cpp index 65a931c84deca244abf78e100bb838dd9c1870f3..349d308ee498e89f9705091c72d3ca7013bf3d4e 100644 --- a/src/gpu/GksMeshAdapter/MeshCell.cpp +++ b/src/gpu/GksMeshAdapter/MeshCell.cpp @@ -34,6 +34,8 @@ #include "GridGenerator/grid/NodeValues.h" +using namespace vf::gpu; + MeshCell::MeshCell(){ level = INVALID_INDEX; diff --git a/src/gpu/GridGenerator/CMakeLists.txt b/src/gpu/GridGenerator/CMakeLists.txt index 9168222045a58a498b23f69ff4dce1a9e9ee5ac5..07b6125d6ecd83dca59e20e7c286ebc2b8d14715 100644 --- a/src/gpu/GridGenerator/CMakeLists.txt +++ b/src/gpu/GridGenerator/CMakeLists.txt @@ -1,16 +1,7 @@ -project(GridGenerator LANGUAGES CUDA CXX) - +project(GridGenerator LANGUAGES CXX) vf_add_library(PRIVATE_LINK basics OpenMP::OpenMP_CXX) -vf_get_library_name(library_name) -set_target_properties(${library_name} PROPERTIES CUDA_SEPARABLE_COMPILATION ON) - -# according to linker error when building static libraries. -# https://stackoverflow.com/questions/50033435/cmake-cuda-separate-compilation-static-lib-link-error-on-windows-but-not-on-ubun -if (NOT BUILD_SHARED_LIBRARY) - set_target_properties(${library_name} PROPERTIES CUDA_RESOLVE_DEVICE_SYMBOLS ON) -endif() - -# we want to suppress all cuda warnings so far for this library. -target_compile_options(${library_name} PUBLIC $<$<COMPILE_LANGUAGE:CUDA>:-Xcudafe "-w" >) \ No newline at end of file +if(NOT MSVC) + target_compile_options(GridGenerator PRIVATE "-Wno-strict-aliasing") +endif() \ No newline at end of file diff --git a/src/gpu/GridGenerator/StreetPointFinder/JunctionReader.cpp b/src/gpu/GridGenerator/StreetPointFinder/JunctionReader.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bac17264d1c00389bbefacc4063d7801e8f5baa7 --- /dev/null +++ b/src/gpu/GridGenerator/StreetPointFinder/JunctionReader.cpp @@ -0,0 +1,145 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file JunctionReader.cpp +//! \ingroup StreetPointFinder +//! \author Stephan Lenz +//======================================================================================= +#include "JunctionReader.h" + +#include <fstream> +#include <iostream> +#include <string> + + +JunctionReaderData::JunctionReaderData(std::vector<uint> inCells, std::vector<uint> outCells, std::vector<int> carCanNotEnterThisOutCell, uint trafficLightSwitchTime = 0) : + inCells{ inCells }, outCells{ outCells }, carCanNotEnterThisOutCell{ carCanNotEnterThisOutCell }, trafficLightSwitchTime{ trafficLightSwitchTime } +{} + +void JunctionReader::readJunctions(std::string filename, StreetPointFinder* streetPointFinder) +{ + *logging::out << logging::Logger::INFO_INTERMEDIATE << "StreetPointFinder::readJunctions( " << filename << " )" << "\n"; + + std::ifstream file; + file.open(filename.c_str()); + if (!file.is_open()) std::cerr << "File not found" << std::endl; + this->streetPointFinder = streetPointFinder; + + uint numberOfJunctions; + file >> numberOfJunctions; + + std::string inOutDummy; + int streetIndex = 0; + uint trafficLightTime = 0; + bool onlyNeighbors = false; + + file >> inOutDummy; + + for (uint i = 0; i < numberOfJunctions; i++) { + std::vector<uint> inCells, outCells; + std::vector<int> carCanNotEnterThisOutCell; + + //inCells + file >> inOutDummy; + while (inOutDummy.compare("out") != 0) { + streetIndex = std::stoi(inOutDummy); + + if (streetIndex >= 0) + inCells.push_back(getCellIndex(streetIndex, 'e')); + + file >> inOutDummy; + } + + //outCells + file >> inOutDummy; + while (inOutDummy.compare("in") != 0 && inOutDummy.compare("end") != 0 && inOutDummy.compare("t") != 0 && inOutDummy.compare("c") != 0) { + streetIndex = std::stoi(inOutDummy); + + if (streetIndex >= 0) { + outCells.push_back(getCellIndex(streetIndex, 's')); + if (carCanNotEnterThisOutCell.size() < inCells.size()) + carCanNotEnterThisOutCell.push_back(getCellIndex(streetIndex, 's')); + } + else if (streetIndex == -2) //no prohibited outCell + carCanNotEnterThisOutCell.push_back(-2); + + file >> inOutDummy; + } + + //trafficLightTime + if (inOutDummy.compare("t") == 0) { + file >> inOutDummy; + trafficLightTime = std::stoi(inOutDummy); + file >> inOutDummy; + } + else + trafficLightTime = 0; + + // only neighbors (used for curves) + if (inOutDummy.compare("c") == 0) { + onlyNeighbors = true; + file >> inOutDummy; + } + + + //make Junction or neighbors + if (onlyNeighbors) { + if (inCells.size() == 2 && outCells.size() == 2) { + specialNeighbors.cells.insert(specialNeighbors.cells.end(), inCells.begin(), inCells.end()); + specialNeighbors.neighbors.push_back(outCells[1]); + specialNeighbors.neighbors.push_back(outCells[0]); + + onlyNeighbors = false; + } + else + { + // TODO: this could be a bug, as before this change "continue" was not guarded by the "else" + // https://git.rz.tu-bs.de/irmb/VirtualFluids_dev/-/issues/11 + std::cerr << "can't add curve" << std::endl; + continue; + } + } + else + junctions.push_back(JunctionReaderData(inCells, outCells, carCanNotEnterThisOutCell, trafficLightTime)); + + } +} + + +unsigned int JunctionReader::getCellIndex(unsigned int streetIndex, char startOrEnd) +{ + uint i = 0; + unsigned int cellIndex = 0; + while (i < streetIndex) { + cellIndex += streetPointFinder->streets[i].numberOfCells; + ++i; + } + if (startOrEnd == 's') return cellIndex; + return cellIndex + streetPointFinder->streets[streetIndex].numberOfCells - 1; +} + diff --git a/src/gpu/GridGenerator/StreetPointFinder/JunctionReader.h b/src/gpu/GridGenerator/StreetPointFinder/JunctionReader.h new file mode 100644 index 0000000000000000000000000000000000000000..5b68b0357ea2432dfde6d167b27908fe1aa4348a --- /dev/null +++ b/src/gpu/GridGenerator/StreetPointFinder/JunctionReader.h @@ -0,0 +1,78 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file JunctionReader.h +//! \ingroup StreetPointFinder +//! \author Stephan Lenz +//======================================================================================= +#ifndef JUNCTIONREADER_H +#define JUNCTIONREADER_H + +#include <vector> + +#include "GridGenerator_export.h" + +#include "Core/DataTypes.h" +#include "Core/Logger/Logger.h" + +#include "StreetPointFinder.h" + + + +struct GRIDGENERATOR_EXPORT JunctionReaderData +{ + std::vector<uint> inCells; + std::vector<uint> outCells; + std::vector<int> carCanNotEnterThisOutCell; + uint trafficLightSwitchTime; + + JunctionReaderData(std::vector<uint> inCells, std::vector<uint> outCells, std::vector<int> carCanNotEnterThisOutCell, uint trafficLightSwitchTime); +}; + + +struct GRIDGENERATOR_EXPORT Neighbors +{ + std::vector<int> cells; + std::vector<int> neighbors; +}; + + + +struct GRIDGENERATOR_EXPORT JunctionReader +{ + std::vector<JunctionReaderData> junctions; + Neighbors specialNeighbors; + StreetPointFinder* streetPointFinder; + + void readJunctions(std::string filename, StreetPointFinder* streetPointFinder); + + +private: + unsigned int getCellIndex(unsigned int streetIndex, char startOrEnd); +}; +#endif diff --git a/src/gpu/GridGenerator/StreetPointFinder/SinkReader.cpp b/src/gpu/GridGenerator/StreetPointFinder/SinkReader.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1224f1bf7cad8e535e842426406aacc619dad314 --- /dev/null +++ b/src/gpu/GridGenerator/StreetPointFinder/SinkReader.cpp @@ -0,0 +1,75 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file SinkReader.cpp +//! \ingroup StreetPointFinder +//! \author Stephan Lenz +//======================================================================================= +#include "SinkReader.h" + +#include <fstream> +#include <iostream> + +SinkReaderData::SinkReaderData(uint sinkIndex, float sinkBlockedPossibility) : + sinkIndex{ sinkIndex }, sinkBlockedPossibility{ sinkBlockedPossibility } +{} + +void SinkReader::readSinks(std::string filename, StreetPointFinder* streetPointFinder) +{ + *logging::out << logging::Logger::INFO_INTERMEDIATE << "StreetPointFinder::readSinks( " << filename << " )" << "\n"; + + this->streetPointFinder = streetPointFinder; + + std::ifstream file; + file.open(filename.c_str()); + if (!file.is_open()) std::cerr << "File not found" << std::endl; + + uint numberOfSinks; + file >> numberOfSinks; + + uint streetIndex; + float sinkBlockedPossibility; + + + for (uint i = 0; i < numberOfSinks; i++) { + file >> streetIndex >> sinkBlockedPossibility; + sinks.push_back(SinkReaderData(getCellIndexEnd(streetIndex), sinkBlockedPossibility)); + } +} + +unsigned int SinkReader::getCellIndexEnd(unsigned int streetIndex) +{ + uint i = 0; + unsigned int cellIndex = 0; + while (i < streetIndex) { + cellIndex += streetPointFinder->streets[i].numberOfCells; + ++i; + } + + return cellIndex + streetPointFinder->streets[streetIndex].numberOfCells - 1; +} diff --git a/src/gpu/GridGenerator/StreetPointFinder/SinkReader.h b/src/gpu/GridGenerator/StreetPointFinder/SinkReader.h new file mode 100644 index 0000000000000000000000000000000000000000..ba28596b0eb63954eb5f7162c4849f863e15f657 --- /dev/null +++ b/src/gpu/GridGenerator/StreetPointFinder/SinkReader.h @@ -0,0 +1,65 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file SinkReader.h +//! \ingroup StreetPointFinder +//! \author Stephan Lenz +//======================================================================================= +#ifndef SINKREADER_H +#define SINKREADER_H + +#include <vector> + +#include "GridGenerator_export.h" + +#include "Core/DataTypes.h" +#include "Core/Logger/Logger.h" + +#include "StreetPointFinder.h" + + + +struct GRIDGENERATOR_EXPORT SinkReaderData{ + uint sinkIndex; + float sinkBlockedPossibility; + SinkReaderData(uint sinkIndex, float sinkBlockedPossibility); +}; + +struct GRIDGENERATOR_EXPORT SinkReader +{ + std::vector<SinkReaderData> sinks; + StreetPointFinder* streetPointFinder; + + void readSinks(std::string filename, StreetPointFinder* streetPointFinder); + +private: + unsigned int getCellIndexEnd(unsigned int streetIndex); +}; + + +#endif \ No newline at end of file diff --git a/src/gpu/GridGenerator/StreetPointFinder/SourceReader.cpp b/src/gpu/GridGenerator/StreetPointFinder/SourceReader.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a3a62f942f96fa1faf9e49448ed3ae627d985273 --- /dev/null +++ b/src/gpu/GridGenerator/StreetPointFinder/SourceReader.cpp @@ -0,0 +1,78 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file SourceReader.cpp +//! \ingroup StreetPointFinder +//! \author Stephan Lenz +//======================================================================================= +#include "SourceReader.h" + +#include <fstream> +#include <iostream> + +SourceReaderData::SourceReaderData(unsigned int sourceIndex, float sourcePossibility): + sourceIndex{sourceIndex}, sourcePossibility{sourcePossibility} +{} + + +void SourceReader::readSources(std::string filename, StreetPointFinder* streetPointFinder) +{ + *logging::out << logging::Logger::INFO_INTERMEDIATE << "StreetPointFinder::readSources( " << filename << " )" << "\n"; + + this->streetPointFinder = streetPointFinder; + + std::ifstream file; + file.open(filename.c_str()); + if (!file.is_open()) std::cerr << "File not found" << std::endl; + + uint numberOfSources; + file >> numberOfSources; + + uint streetIndex; + float sourcePossibility; + + + for (uint i = 0; i < numberOfSources; i++) { + file >> streetIndex >> sourcePossibility; + sources.push_back(SourceReaderData(getCellIndexStart(streetIndex), sourcePossibility)); + } +} + + +unsigned int SourceReader::getCellIndexStart(unsigned int streetIndex) +{ + uint i = 0; + unsigned int cellIndex = 0; + while (i < streetIndex) { + cellIndex += streetPointFinder->streets[i].numberOfCells; + ++i; + } + return cellIndex; +} + + diff --git a/src/gpu/GridGenerator/StreetPointFinder/SourceReader.h b/src/gpu/GridGenerator/StreetPointFinder/SourceReader.h new file mode 100644 index 0000000000000000000000000000000000000000..f79c618d06ff9f72738c7b69767a8dd3c5443fac --- /dev/null +++ b/src/gpu/GridGenerator/StreetPointFinder/SourceReader.h @@ -0,0 +1,63 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file SourceReader.h +//! \ingroup StreetPointFinder +//! \author Stephan Lenz +//======================================================================================= +#ifndef SOURCEREADER_H +#define SOURCEREADER_H + +#include <vector> + +#include "Core/DataTypes.h" +#include "Core/Logger/Logger.h" + +#include "StreetPointFinder.h" + + + +struct GRIDGENERATOR_EXPORT SourceReaderData { + unsigned int sourceIndex; + float sourcePossibility; + SourceReaderData(unsigned int sourceIndex, float sourcePossibility); +}; + +struct GRIDGENERATOR_EXPORT SourceReader +{ + std::vector<SourceReaderData> sources; + StreetPointFinder* streetPointFinder; + + void readSources(std::string filename, StreetPointFinder* streetPointFinder); + +private: + unsigned int getCellIndexStart(unsigned int streetIndex); +}; + + +#endif \ No newline at end of file diff --git a/src/gpu/GridGenerator/StreetPointFinder/StreetPointFinder.cpp b/src/gpu/GridGenerator/StreetPointFinder/StreetPointFinder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9fbd3933a5457e96d2d1aa01f1fadcf675be1980 --- /dev/null +++ b/src/gpu/GridGenerator/StreetPointFinder/StreetPointFinder.cpp @@ -0,0 +1,790 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file StreetPointFinder.cpp +//! \ingroup StreetPointFinder +//! \author Stephan Lenz +//======================================================================================= +#include "StreetPointFinder.h" + +#include "Core/Logger/Logger.h" + +#include <string> +#include <sstream> +#include <fstream> +#include <iostream> +#include <cmath> +#include <algorithm> +#include <numeric> + +#include "grid/Grid.h" +#include "grid/NodeValues.h" + +using namespace vf::gpu; + +Street::Street(real xStartCell, real yStartCell, real xEndCell, real yEndCell, real dx) +{ + real length = std::sqrt((xEndCell - xStartCell)*(xEndCell - xStartCell) + + (yEndCell - yStartCell)*(yEndCell - yStartCell)); + + this->numberOfCells = std::floor(length / dx); + + real realLength = dx * (this->numberOfCells); + + real vectorX = (xEndCell - xStartCell) / length; + real vectorY = (yEndCell - yStartCell) / length; + + this->xStart = xStartCell - 0.5 * (realLength - length) * vectorX + 0.5 * dx * vectorX; + this->yStart = yStartCell - 0.5 * (realLength - length) * vectorY + 0.5 * dx * vectorY; + + this->xEnd = xEndCell + 0.5 * (realLength - length) * vectorX - 0.5 * dx * vectorX; + this->yEnd = yEndCell + 0.5 * (realLength - length) * vectorY - 0.5 * dx * vectorY; + + //this->xStart = xStart + dx * (xEnd - xStart) / length; + //this->yStart = yStart + dx * (yEnd - yStart) / length; + // + //this->xEnd = xEnd - dx * (xEnd - xStart) / length; + //this->yEnd = yEnd - dx * (yEnd - yStart) / length; + + //this->numberOfCells = std::lround( length / dx ) + 1; +} + +real Street::getCoordinateX(int cellIndex) +{ + return xStart + real(cellIndex) / real(numberOfCells - 1) * (xEnd - xStart); +} + +real Street::getCoordinateY(int cellIndex) +{ + return yStart + real(cellIndex) / real(numberOfCells - 1) * (yEnd - yStart); +} + +real Street::getVectorX() +{ + real vecX = this->xEnd - this->xStart; + real vecY = this->yEnd - this->yStart; + + real length = sqrt(vecX*vecX + vecY*vecY); + + return vecX / length; +} + +real Street::getVectorY() +{ + real vecX = this->xEnd - this->xStart; + real vecY = this->yEnd - this->yStart; + + real length = sqrt(vecX*vecX + vecY*vecY); + + return vecY / length; +} + +void Street::findIndicesLB(SPtr<Grid> grid, real initialSearchHeight) +{ + for (uint i = 0; i < numberOfCells; i++) + { + real x = getCoordinateX(i); + real y = getCoordinateY(i); + + uint matrixIndex = grid->transCoordToIndex(x, y, initialSearchHeight); + + real xLB, yLB, zLB; + grid->transIndexToCoords(matrixIndex, xLB, yLB, zLB); + + while (grid->getFieldEntry(matrixIndex) != BC_SOLID || + grid->getFieldEntry(grid->transCoordToIndex(xLB, yLB, zLB-grid->getDelta())) != STOPPER_SOLID) + { + zLB -= grid->getDelta(); + matrixIndex = grid->transCoordToIndex(xLB, yLB, zLB); + } + + std::stringstream msg; + + + msg << "( " << x << ", " << y << " )" << " ==> "; + msg << "( " << xLB << ", " << yLB << ", " << zLB << " ), type = [" << (int)grid->getFieldEntry(matrixIndex) << "], z = " << zLB << " \n"; + + *logging::out << logging::Logger::INFO_LOW << msg.str(); + + this->matrixIndicesLB.push_back(matrixIndex); + this->sparseIndicesLB.push_back(grid->getSparseIndex(matrixIndex)); + } +} + +void StreetPointFinder::prepareSimulationFileData() +{ + ////////////////////////////////////////////////////////////////////////// + // Concatenate sparseIndicesLB + + for (auto& street : this->streets) this->sparseIndicesLB.insert(this->sparseIndicesLB.end(), street.sparseIndicesLB.begin(), street.sparseIndicesLB.end()); + + ////////////////////////////////////////////////////////////////////////// + // prepare vectors + + uint numberOfCells = (uint)this->sparseIndicesLB.size(); + + mapNashToConc.resize(numberOfCells); + + std::vector<uint> indexMap(numberOfCells); + std::iota(indexMap.begin(), indexMap.end(), 0); + + ////////////////////////////////////////////////////////////////////////// + // sort vectors + + std::stable_sort(indexMap.begin(), + indexMap.end(), + [&](uint lhs, uint rhs) { + return this->sparseIndicesLB[lhs] <= this->sparseIndicesLB[rhs]; + }); + + std::stable_sort(this->sparseIndicesLB.begin(), + this->sparseIndicesLB.end(), + [](uint lhs, uint rhs) { + return lhs <= rhs; + }); + ////////////////////////////////////////////////////////////////////////// + // invert idxMap + + { + std::vector<uint> buffer = indexMap; + for (uint idx = 0; idx < indexMap.size(); idx++) + indexMap[buffer[idx]] = idx; + } + + ////////////////////////////////////////////////////////////////////////// + // identify duplicates and find correct mapping indices + + std::vector<uint> reducedIndexMap(numberOfCells); + + uint currentSparseIndex = this->sparseIndicesLB[0]; + uint reducedIndex = 0; + for (uint index = 1; index < numberOfCells; index++) + { + if (this->sparseIndicesLB[index] == currentSparseIndex) + { + reducedIndexMap[index] = reducedIndex; + } + else + { + currentSparseIndex = this->sparseIndicesLB[index]; + reducedIndexMap[index] = ++reducedIndex; + } + } + + for (uint index = 0; index < numberOfCells; index++) + { + mapNashToConc[index] = reducedIndexMap[indexMap[index]]; + } + + ////////////////////////////////////////////////////////////////////////// + // erase duplicated + + auto newEnd = std::unique(this->sparseIndicesLB.begin(), this->sparseIndicesLB.end()); + + this->sparseIndicesLB.resize(std::distance(this->sparseIndicesLB.begin(), newEnd)); + + ////////////////////////////////////////////////////////////////////////// +} + +void StreetPointFinder::readStreets(std::string filename) +{ + *logging::out << logging::Logger::INFO_INTERMEDIATE << "StreetPointFinder::readStreets( " << filename << " )" << "\n"; + + uint numberOfStreets; + + std::ifstream file; + + file.open(filename.c_str()); + + file >> numberOfStreets; + + for (uint i = 0; i < numberOfStreets; i++) + { + real xStart, yStart, xEnd, yEnd; + + real dx; + + file >> xStart >> yStart >> xEnd >> yEnd >> dx; + + streets.push_back(Street(xStart, yStart, xEnd, yEnd, dx)); + } + + file.close(); + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "done!\n"; +} + +void StreetPointFinder::findIndicesLB(SPtr<Grid> grid, real initialSearchHeight) +{ + *logging::out << logging::Logger::INFO_INTERMEDIATE << "StreetPointFinder::findIndicesLB()\n"; + + for (auto& street : streets) street.findIndicesLB(grid, initialSearchHeight); + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "done!\n"; +} + +void StreetPointFinder::writeVTK(std::string filename, const std::vector<int>& cars) +{ + uint numberOfCells = 0; + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "StreetPointFinder::writeVTK( " << filename << " )" << "\n"; + + std::ofstream file; + + file.open(filename); + + prepareWriteVTK(file, numberOfCells); + + ////////////////////////////////////////////////////////////////////////// + + file << "FIELD Label " << 3 << std::endl; + + ////////////////////////////////////////////////////////////////////////// + + writeStreetsVTK(file, numberOfCells); + + writeLengthsVTK(file, numberOfCells); + + writeCarsVTK(file, numberOfCells, cars); + + //////////////////////////////////////////////////////////////////////////// + + file.close(); + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "done!\n"; +} + + +void StreetPointFinder::writeReducedVTK(std::string filename, const std::vector<int>& cars) +{ + uint numberOfCells = 0; + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "StreetPointFinder::writeVTK( " << filename << " )" << "\n"; + + std::ofstream file; + + file.open(filename); + + prepareWriteVTK(file, numberOfCells); + + ////////////////////////////////////////////////////////////////////////// + + file << "FIELD Label " << 1 << std::endl; + + ////////////////////////////////////////////////////////////////////////// + + writeCarsVTK(file, numberOfCells, cars); + + //////////////////////////////////////////////////////////////////////////// + + file.close(); + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "done!\n"; +} + +void StreetPointFinder::prepareWriteVTK(std::ofstream & file, uint & numberOfCells) +{ + + uint numberOfNodes = 0; + + for (auto& street : streets) + { + numberOfCells += street.numberOfCells; + numberOfNodes += street.numberOfCells + 1; + } + + file << "# vtk DataFile Version 3.0\n"; + file << "by MeshGenerator\n"; + file << "ASCII\n"; + file << "DATASET UNSTRUCTURED_GRID\n"; + + file << "POINTS " << numberOfNodes << " float" << std::endl; + + for (auto& street : streets) + { + for (uint i = 0; i <= street.numberOfCells; i++) + { + file << 0.5 * (street.getCoordinateX(i - 1) + street.getCoordinateX(i)) << " " + << 0.5 * (street.getCoordinateY(i - 1) + street.getCoordinateY(i)) << " " << 0.0 << std::endl; + } + } + + ////////////////////////////////////////////////////////////////////////// + + file << "CELLS " << numberOfCells << " " << 3 * numberOfCells << std::endl; + + + uint nodeIndex = 0; + for (auto& street : streets) + { + for (uint i = 0; i < street.numberOfCells; i++) + { + file << "2 " << nodeIndex << " " << nodeIndex + 1 << std::endl; + nodeIndex++; + } + nodeIndex++; + } + + ////////////////////////////////////////////////////////////////////////// + + file << "CELL_TYPES " << numberOfCells << std::endl; + + for (uint i = 0; i < numberOfCells; i++) { + file << "3" << std::endl; + } + ////////////////////////////////////////////////////////////////////////// + + file << "\nCELL_DATA " << numberOfCells << std::endl; +} + + +void StreetPointFinder::writeStreetsVTK(std::ofstream & file, uint numberOfCells) +{ + file << "StreetIndex 1 " << numberOfCells << " int" << std::endl; + + uint streetIndex = 0; + for (auto& street : streets) + { + for (uint i = 0; i < street.numberOfCells; i++) + { + file << streetIndex << std::endl; + } + streetIndex++; + } +} + + + +void StreetPointFinder::writeCarsVTK(std::ofstream& file, uint numberOfCells, const std::vector<int>& cars) +{ + file << "Cars 1 " << numberOfCells << " float" << std::endl; + + uint index = 0; + for (auto& street : streets) + { + for (uint i = 0; i < street.numberOfCells; i++) + { + if (index < cars.size()) + file << cars[index] << std::endl; + else + file << -1 << std::endl; + index++; + } + } +} + + +void StreetPointFinder::writeLengthsVTK(std::ofstream & file, uint numberOfCells) +{ + file << "StreetLength 1 " << numberOfCells << " float" << std::endl; + + for (auto& street : streets) + { + for (uint i = 0; i < street.numberOfCells; i++) + { + real length = std::sqrt((street.getCoordinateX(i) - street.getCoordinateX(0)) * (street.getCoordinateX(i) - street.getCoordinateX(0)) + + (street.getCoordinateY(i) - street.getCoordinateY(0)) * (street.getCoordinateY(i) - street.getCoordinateY(0))); + + file << length << std::endl; + } + } +} + + +void StreetPointFinder::writeConnectionVTK(std::string filename, SPtr<Grid> grid) +{ + uint numberOfCells = 0; + + for (auto& street : streets) + { + numberOfCells += street.numberOfCells; + } + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "StreetPointFinder::writeConnectionVTK( " << filename << " )" << "\n"; + + std::ofstream file; + + file.open(filename); + + file << "# vtk DataFile Version 3.0\n"; + file << "by MeshGenerator\n"; + file << "ASCII\n"; + file << "DATASET UNSTRUCTURED_GRID\n"; + + file << "POINTS " << 2 * numberOfCells << " float" << std::endl; + + for (auto& street : streets) + { + for (uint i = 0; i < street.numberOfCells; i++) + { + real xLB, yLB, zLB; + grid->transIndexToCoords(street.matrixIndicesLB[i], xLB, yLB, zLB); + + file << street.getCoordinateX(i) << " " << street.getCoordinateY(i) << " " << 5.0 << std::endl; + file << xLB << " " << yLB << " " << zLB << std::endl; + } + } + + ////////////////////////////////////////////////////////////////////////// + + file << "CELLS " << numberOfCells << " " << 3 * numberOfCells << std::endl; + + + uint nodeIndex = 0; + for (auto& street : streets) + { + for (uint i = 0; i < street.numberOfCells; i++) + { + file << "2 " << nodeIndex << " " << nodeIndex + 1 << std::endl; + nodeIndex += 2; + } + } + + ////////////////////////////////////////////////////////////////////////// + + file << "CELL_TYPES " << numberOfCells << std::endl; + + for (uint i = 0; i < numberOfCells; i++) { + file << "3" << std::endl; + } + + ////////////////////////////////////////////////////////////////////////// + + file.close(); + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "done!\n"; +} + +void StreetPointFinder::writeSimulationFile(std::string gridPath, real concentration, uint numberOfLevels, uint level) +{ + *logging::out << logging::Logger::INFO_INTERMEDIATE << "StreetPointFinder::writeSimulationFile( " << gridPath << "conc.dat )" << "\n"; + + std::ofstream file; + + file.open(gridPath + "conc.dat"); + + file << "concentration\n"; + + file << numberOfLevels - 1 << "\n"; + + for (uint currentLevel = 0; currentLevel < numberOfLevels; currentLevel++) + { + if (currentLevel == level) + { + uint numberOfCells = 0; + for (auto& street : streets) + { + numberOfCells += street.numberOfCells; + } + + file << numberOfCells << "\n"; + + for (auto& street : streets) + { + for (auto& sparseIndexLB : street.sparseIndicesLB) + { + // + 1 for numbering shift between GridGenerator and VF_GPU + file << sparseIndexLB + 1 << "\n"; + } + } + } + else + { + file << "0\n"; + } + } + + file.close(); + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "done!\n"; +} + +void StreetPointFinder::writeStreetVectorFile(std::string gridPath, real concentration, uint numberOfLevels, uint level) +{ + *logging::out << logging::Logger::INFO_INTERMEDIATE << "StreetPointFinder::writeStreetVectorFile( " << gridPath << "streetVector.dat )" << "\n"; + + std::ofstream file; + + file.open(gridPath + "streetVector.dat"); + + file << "streetVector\n"; + + file << numberOfLevels - 1 << "\n"; + + for (uint currentLevel = 0; currentLevel < numberOfLevels; currentLevel++) + { + if (currentLevel == level) + { + uint numberOfCells = 0; + for (auto& street : streets) + { + numberOfCells += street.numberOfCells; + } + + file << numberOfCells << "\n"; + + for (auto& street : streets) + { + for (auto& sparseIndexLB : street.sparseIndicesLB) + { + (void) sparseIndexLB; + // + 1 for numbering shift between GridGenerator and VF_GPU + file << street.getVectorX() << " " << street.getVectorY() << "\n"; + } + } + } + else + { + file << "0\n"; + } + } + + file.close(); + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "done!\n"; +} + +void StreetPointFinder::writeSimulationFileSorted(std::string gridPath, real concentration, uint numberOfLevels, uint level) +{ + *logging::out << logging::Logger::INFO_INTERMEDIATE << "StreetPointFinder::writeSimulationFile( " << gridPath << "concSorted.dat )" << "\n"; + + std::ofstream file; + + file.open(gridPath + "concSorted.dat"); + + file << "concentration\n"; + + file << numberOfLevels - 1 << "\n"; + + for (uint currentLevel = 0; currentLevel < numberOfLevels; currentLevel++) + { + if (currentLevel == level) + { + file << this->sparseIndicesLB.size() << "\n"; + + for (auto& sparseIndexLB : this->sparseIndicesLB) + { + // + 1 for numbering shift between GridGenerator and VF_GPU + file << sparseIndexLB + 1 << "\n"; + } + } + else + { + file << "0\n"; + } + } + + file.close(); + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "done!\n"; +} + +void StreetPointFinder::writeMappingFile(std::string gridPath) +{ + *logging::out << logging::Logger::INFO_INTERMEDIATE << "StreetPointFinder::writeMappingFile( " << gridPath << "mappingNashToConc.dat )" << "\n"; + + std::ofstream file; + + file.open(gridPath + "mappingNashToConc.dat"); + + file << this->mapNashToConc.size() << "\n"; + + for (auto& index : this->mapNashToConc) + { + file << index << "\n"; + } + + file.close(); + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "done!\n"; +} + + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Speed hackend by Stephan Lenz, not tested + +void StreetPointFinder::write3DVTK(std::string filename, const std::vector<int>& cars) +{ + uint numberOfCells = 0; + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "StreetPointFinder::writeVTK( " << filename << " )" << "\n"; + + std::ofstream file; + + file.open(filename); + + prepareWrite3DVTK(file, numberOfCells, cars); + + //////////////////////////////////////////////////////////////////////////// + + file.close(); + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "done!\n"; +} + +void StreetPointFinder::prepareWrite3DVTK(std::ofstream & file, uint & numberOfCells, const std::vector<int>& cars) +{ + + uint numberOfNodes = 0; + + for (auto& street : streets) + { + numberOfCells += street.numberOfCells; + numberOfNodes += street.numberOfCells + 1; + } + + file << "# vtk DataFile Version 3.0\n"; + file << "by MeshGenerator\n"; + file << "ASCII\n"; + file << "DATASET UNSTRUCTURED_GRID\n"; + + uint index = 0; + uint numberOfCars = 0; + + for (auto& street : streets) + { + for (uint i = 0; i < street.numberOfCells; i++) + { + if (index < cars.size() && cars[index] != -1) + { + numberOfCars++; + } + + index++; + } + } + + file << "POINTS " << 8 * numberOfCars << " float" << std::endl; + + index = 0; + for (auto& street : streets) + { + for (uint i = 0; i < street.numberOfCells; i++) + { + if(index < cars.size() && cars[index] != -1 ) + { + real xStart = 0.5 * (street.getCoordinateX(i - 1) + street.getCoordinateX(i)); + real yStart = 0.5 * (street.getCoordinateY(i - 1) + street.getCoordinateY(i)); + + real xEnd = 0.5 * (street.getCoordinateX(i) + street.getCoordinateX(i + 1)); + real yEnd = 0.5 * (street.getCoordinateY(i) + street.getCoordinateY(i + 1)); + + real vecX = xEnd - xStart; + real vecY = yEnd - yStart; + + file << xStart + vecY << " " << yStart - vecX << " " << 0.0 << std::endl; + file << xStart - vecY << " " << yStart + vecX << " " << 0.0 << std::endl; + + file << xEnd + vecY << " " << yEnd - vecX << " " << 0.0 << std::endl; + file << xEnd - vecY << " " << yEnd + vecX << " " << 0.0 << std::endl; + + file << xStart + vecY << " " << yStart - vecX << " " << 1.5 << std::endl; + file << xStart - vecY << " " << yStart + vecX << " " << 1.5 << std::endl; + + file << xEnd + vecY << " " << yEnd - vecX << " " << 1.5 << std::endl; + file << xEnd - vecY << " " << yEnd + vecX << " " << 1.5 << std::endl; + } + + index++; + } + } + + ////////////////////////////////////////////////////////////////////////// + + file << "CELLS " << numberOfCars << " " << 9 * numberOfCars << std::endl; + + index = 0; + uint carIndex = 0; + for (auto& street : streets) + { + for (uint i = 0; i < street.numberOfCells; i++) + { + if (index < cars.size() && cars[index] != -1) + { + file << "8 " + << 8 * carIndex + 0 << " " + << 8 * carIndex + 1 << " " + << 8 * carIndex + 3 << " " + << 8 * carIndex + 2 << " " + << 8 * carIndex + 4 << " " + << 8 * carIndex + 5 << " " + << 8 * carIndex + 7 << " " + << 8 * carIndex + 6 << " " + << std::endl; + + carIndex++; + } + index++; + } + } + + ////////////////////////////////////////////////////////////////////////// + + file << "CELL_TYPES " << numberOfCars << std::endl; + + for (uint i = 0; i < numberOfCars; i++) { + file << "12" << std::endl; + } + + ////////////////////////////////////////////////////////////////////////// + + file << "\nCELL_DATA " << numberOfCars << std::endl; + + ////////////////////////////////////////////////////////////////////////// + + file << "FIELD Label " << 1 << std::endl; + + ////////////////////////////////////////////////////////////////////////// + + file << "Cars 1 " << numberOfCars << " float" << std::endl; + + index = 0; + for (auto& street : streets) + { + for (uint i = 0; i < street.numberOfCells; i++) + { + if (index < cars.size() && cars[index] != -1) + file << cars[index] << std::endl; + + index++; + } + } +} + + + + diff --git a/src/gpu/GridGenerator/StreetPointFinder/StreetPointFinder.h b/src/gpu/GridGenerator/StreetPointFinder/StreetPointFinder.h new file mode 100644 index 0000000000000000000000000000000000000000..feb3618f64b0a6f757930772594878a6ca7c0144 --- /dev/null +++ b/src/gpu/GridGenerator/StreetPointFinder/StreetPointFinder.h @@ -0,0 +1,120 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file StreetPointFinder.h +//! \ingroup StreetPointFinder +//! \author Stephan Lenz +//======================================================================================= +#ifndef StreetPointFinder_H +#define StreetPointFinder_H + +#include <vector> +#include <string> + +#include "GridGenerator_export.h" + +#include "PointerDefinitions.h" +#include "Core/DataTypes.h" + + + +class Grid; + +struct GRIDGENERATOR_EXPORT Street +{ + // The start and end coordinates are stored for cell centers! + // + // |---x---|---x---|---x---|---x---|---x---|---x---|---x---|---x---|---x---|---x---| + // |---> |<----->| <---| + // xStart dx xEnd + // + // dx = (xStart - xEnd) / (numberOfCells - 1) + + uint numberOfCells; + real xStart, yStart, xEnd, yEnd; + + std::vector<uint> matrixIndicesLB; + std::vector<uint> sparseIndicesLB; + + // The constructor expect start and end for cells + Street( real xStartCell, real yStartCell, real xEndCell, real yEndCell, real dx ); + + real getCoordinateX( int cellIndex ); + real getCoordinateY( int cellIndex ); + + real getVectorX(); + real getVectorY(); + + void findIndicesLB( SPtr<Grid> grid, real initialSearchHeight); +}; + +struct GRIDGENERATOR_EXPORT StreetPointFinder +{ + std::vector<Street> streets; + + std::vector<uint> sparseIndicesLB; + std::vector<uint> mapNashToConc; + + void prepareSimulationFileData(); + + void readStreets(std::string filename); + + void findIndicesLB( SPtr<Grid> grid, real initialSearchHeight ); + + void writeVTK(std::string filename, const std::vector<int>& cars = std::vector<int>()); + + void writeReducedVTK(std::string filename, const std::vector<int>& cars = std::vector<int>()); + + void prepareWriteVTK(std::ofstream& file, uint & numberOfCells); + + void writeCarsVTK(std::ofstream& file, uint numberOfCells, const std::vector<int>& cars); + + void writeLengthsVTK(std::ofstream& file, uint numberOfCells); + + void writeStreetsVTK(std::ofstream& file, uint numberOfCells); + + void writeConnectionVTK(std::string filename, SPtr<Grid> grid); + + void writeSimulationFile(std::string gridPath, real concentration, uint numberOfLevels, uint level); + + void writeStreetVectorFile(std::string gridPath, real concentration, uint numberOfLevels, uint level); + + void writeSimulationFileSorted( std::string gridPath, real concentration, uint numberOfLevels, uint level ); + + void writeMappingFile( std::string gridPath ); + + ////////////////////////////////////////////////////////////////////////// + // 3D cars writer hacked by Stephan L. + + void write3DVTK(std::string filename, const std::vector<int>& cars = std::vector<int>()); + + void prepareWrite3DVTK(std::ofstream& file, uint & numberOfCells, const std::vector<int>& cars); +}; + + +#endif \ No newline at end of file diff --git a/src/gpu/GridGenerator/geometries/Arrow/Arrow.h b/src/gpu/GridGenerator/geometries/Arrow/Arrow.h new file mode 100644 index 0000000000000000000000000000000000000000..945f1e3a8af7bd14fb9c3a8d5d9d26ab7405a7b7 --- /dev/null +++ b/src/gpu/GridGenerator/geometries/Arrow/Arrow.h @@ -0,0 +1,55 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file Arrow.h +//! \ingroup geometries +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#ifndef Arrow_H +#define Arrow_H + +#include <memory> + +struct Vertex; + +class Arrow +{ +public: + virtual ~Arrow() {}; +protected: + Arrow() {}; + +public: + virtual std::shared_ptr<Vertex> getStart() const = 0; + virtual std::shared_ptr<Vertex> getEnd() const = 0; + virtual void print() const = 0; +}; + + + +#endif diff --git a/src/gpu/GridGenerator/geometries/Arrow/ArrowImp.cpp b/src/gpu/GridGenerator/geometries/Arrow/ArrowImp.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f7ee7330c6c57f076fd4f45c8bf7a3f0749df6a1 --- /dev/null +++ b/src/gpu/GridGenerator/geometries/Arrow/ArrowImp.cpp @@ -0,0 +1,69 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file ArrowImp.cpp +//! \ingroup geometries +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#include "ArrowImp.h" + +#include "../Vertex/Vertex.h" + + std::shared_ptr<Arrow> ArrowImp::make(const Vertex &start, const Vertex &end) +{ + return std::shared_ptr<ArrowImp>(new ArrowImp(start, end)); +} + +ArrowImp::ArrowImp(const Vertex &start, const Vertex &end) : start(std::make_shared<Vertex>(start)), end(std::make_shared<Vertex>(end)) +{ + +} + +ArrowImp::~ArrowImp() +{ + +} + +std::shared_ptr<Vertex> ArrowImp::getStart() const +{ + return this->start; +} + +std::shared_ptr<Vertex> ArrowImp::getEnd() const +{ + return this->end; +} + +void ArrowImp::print() const +{ + printf("v1: "); + start->print(); + printf("v2: "); + end->print(); +} + diff --git a/src/gpu/GridGenerator/grid/GridStrategy/GridStrategy.h b/src/gpu/GridGenerator/geometries/Arrow/ArrowImp.h similarity index 60% rename from src/gpu/GridGenerator/grid/GridStrategy/GridStrategy.h rename to src/gpu/GridGenerator/geometries/Arrow/ArrowImp.h index 6d7f0f2c0aa83b1155db10df5b49729bd157a195..ef145b7def48803b7e2d043f7a5862ee21f954c4 100644 --- a/src/gpu/GridGenerator/grid/GridStrategy/GridStrategy.h +++ b/src/gpu/GridGenerator/geometries/Arrow/ArrowImp.h @@ -1,67 +1,64 @@ //======================================================================================= -// ____ ____ __ ______ __________ __ __ __ __ -// \ \ | | | | | _ \ |___ ___| | | | | / \ | | -// \ \ | | | | | |_) | | | | | | | / \ | | -// \ \ | | | | | _ / | | | | | | / /\ \ | | -// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ -// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| -// \ \ | | ________________________________________________________________ -// \ \ | | | ______________________________________________________________| -// \ \| | | | __ __ __ __ ______ _______ -// \ | | |_____ | | | | | | | | | _ \ / _____) -// \ | | _____| | | | | | | | | | | \ \ \_______ +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ // \ | | | | |_____ | \_/ | | | | |_/ / _____ | -// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ // -// This file is part of VirtualFluids. VirtualFluids is free software: you can +// This file is part of VirtualFluids. VirtualFluids is free software: you can // redistribute it and/or modify it under the terms of the GNU General Public -// License as published by the Free Software Foundation, either version 3 of +// License as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. -// -// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. -// +// // You should have received a copy of the GNU General Public License along // with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. // -//! \file GridStrategy.h -//! \ingroup grid +//! \file ArrowImp.h +//! \ingroup geometries //! \author Soeren Peters, Stephan Lenz //======================================================================================= -#ifndef GRID_STRATEGY_H -#define GRID_STRATEGY_H +#ifndef ArrowImp_H +#define ArrowImp_H -#include "Core/LbmOrGks.h" +#include <memory> #include "global.h" +#include "GridGenerator_export.h" -#include "grid/Field.h" +#include "Arrow.h" struct Vertex; -class GridImp; -class GRIDGENERATOR_EXPORT GridStrategy +class ArrowImp : public Arrow { public: - virtual ~GridStrategy() {} - - virtual void allocateFieldMemory(Field* field) = 0; - virtual void freeFieldMemory(Field* field) = 0; - - virtual void allocateGridMemory(SPtr<GridImp> grid) = 0; + GRIDGENERATOR_EXPORT virtual ~ArrowImp(); + GRIDGENERATOR_EXPORT static std::shared_ptr<Arrow> make(const Vertex &start, const Vertex &end); - virtual void initalNodesToOutOfGrid(SPtr<GridImp> grid) = 0; - virtual void findInnerNodes(SPtr<GridImp> grid) = 0; + GRIDGENERATOR_EXPORT std::shared_ptr<Vertex> getStart() const; + GRIDGENERATOR_EXPORT std::shared_ptr<Vertex> getEnd() const; - virtual void findEndOfGridStopperNodes(SPtr<GridImp> grid) = 0; - - virtual void findSparseIndices(SPtr<GridImp> coarseGrid, SPtr<GridImp> fineGrid) = 0; + GRIDGENERATOR_EXPORT void print() const; +private: + ArrowImp(const Vertex &start, const Vertex &end); + std::shared_ptr<Vertex> start; + std::shared_ptr<Vertex> end; +}; - virtual void freeMemory(SPtr<GridImp> grid) = 0; -}; #endif diff --git a/src/gpu/GridGenerator/geometries/BoundingBox/BoundingBox.cu b/src/gpu/GridGenerator/geometries/BoundingBox/BoundingBox.cpp similarity index 88% rename from src/gpu/GridGenerator/geometries/BoundingBox/BoundingBox.cu rename to src/gpu/GridGenerator/geometries/BoundingBox/BoundingBox.cpp index 52295a1501720b260b75199cce4fad229246b256..1532e57e8cc4b0db93ed79c03074d7845ff9c87f 100644 --- a/src/gpu/GridGenerator/geometries/BoundingBox/BoundingBox.cu +++ b/src/gpu/GridGenerator/geometries/BoundingBox/BoundingBox.cpp @@ -26,12 +26,13 @@ // You should have received a copy of the GNU General Public License along // with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. // -//! \file BoundingBox.cu +//! \file BoundingBox.cpp //! \ingroup geometries //! \author Soeren Peters, Stephan Lenz //======================================================================================= #include "BoundingBox.h" +#include "../Triangle/Triangle.h" #include "../Vertex/Vertex.h" #include <GridGenerator/utilities/math/Math.h> @@ -41,17 +42,6 @@ BoundingBox::BoundingBox(real minX, real maxX, real minY, real maxY, real minZ, real maxZ) : minX(minX), maxX(maxX), minY(minY), maxY(maxY), minZ(minZ), maxZ(maxZ) {} - BoundingBox::BoundingBox() : - minX(0), - maxX(0), - minY(0), - maxY(0), - minZ(0), - maxZ(0) {} - - BoundingBox::BoundingBox(const BoundingBox &t) : minX(t.minX), maxX(t.maxX), minY(t.minY), maxY(t.maxY), minZ(t.minZ), maxZ(t.maxZ) {} - - BoundingBox BoundingBox::makeInvalidMinMaxBox() { BoundingBox box = BoundingBox(std::numeric_limits<real>::max(), @@ -63,6 +53,39 @@ return box; } + void BoundingBox::setMinMax(const Triangle &t) + { + real minX, maxX, minY, maxY, minZ, maxZ; + t.setMinMax(minX, maxX, minY, maxY, minZ, maxZ); + if (minX < this->minX) + this->minX = minX; + if (minY < this->minY) + this->minY = minY; + if (minZ < this->minZ) + this->minZ = minZ; + + if (maxX > this->maxX) + this->maxX = maxX; + if (maxY > this->maxY) + this->maxY = maxY; + if (maxZ > this->maxZ) + this->maxZ = maxZ; + } + + bool BoundingBox::intersect(const Triangle &t) const + { + if (isInside(t.v1) || isInside(t.v2) || isInside(t.v3)) + return true; + return false; + } + + bool BoundingBox::isInside(const Triangle &t) const + { + if (isInside(t.v1) && isInside(t.v2) && isInside(t.v3)) + return true; + return false; + } + bool BoundingBox::isInside(const real x, const real y, const real z) const { return this->isInside(Vertex(x,y,z)); diff --git a/src/gpu/GridGenerator/geometries/BoundingBox/BoundingBox.h b/src/gpu/GridGenerator/geometries/BoundingBox/BoundingBox.h index 161db459bf4ef7cc8b86a08c28948860fd9cf5f6..2a495d3a4b7a4854079b62ba979baaea0d7db5f0 100644 --- a/src/gpu/GridGenerator/geometries/BoundingBox/BoundingBox.h +++ b/src/gpu/GridGenerator/geometries/BoundingBox/BoundingBox.h @@ -34,7 +34,6 @@ #define BoundingBox_h #include <vector> -#include <cuda_runtime.h> #include "global.h" @@ -53,15 +52,17 @@ public: real maxZ; BoundingBox(real minX, real maxX, real minY, real maxY, real minZ, real maxZ); - BoundingBox(); - BoundingBox(const BoundingBox &t); + BoundingBox() = default; public: static BoundingBox makeInvalidMinMaxBox(); - void print() const; + void setMinMax(const Triangle &t); + void print() const; - bool isInside(const real x, const real y, const real z) const; + bool isInside(const Triangle &t) const; + bool isInside(const real x, const real y, const real z) const; + bool intersect(const Triangle &t) const; std::vector<std::vector<Vertex> > getIntersectionPoints(const BoundingBox &b) const; bool intersect(const BoundingBox &box) const; diff --git a/src/gpu/GridGenerator/geometries/Conglomerate/Conglomerate.cpp b/src/gpu/GridGenerator/geometries/Conglomerate/Conglomerate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..331b928c6f5542584cffdcc1b17df7207981b8f8 --- /dev/null +++ b/src/gpu/GridGenerator/geometries/Conglomerate/Conglomerate.cpp @@ -0,0 +1,197 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file Conglomerate.cpp +//! \ingroup geometries +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#include "Conglomerate.h" + +Conglomerate::Conglomerate() +{ + addObjects = new Object*[MAX_NUMBER_OF_OBJECTS]; + subtractObjects = new Object*[MAX_NUMBER_OF_OBJECTS]; +} + +Conglomerate::~Conglomerate() +{ + for (uint i = 0; i < numberOfAddObjects; i++) + delete addObjects[i]; + + for (uint i = 0; i < numberOfSubtractObjects; i++) + delete subtractObjects[i]; + + delete[] addObjects; + delete[] subtractObjects; +} + +SPtr<Conglomerate> Conglomerate::makeShared() +{ + return SPtr<Conglomerate>(new Conglomerate()); +} + +void Conglomerate::add(Object* object) +{ + if (numberOfAddObjects < MAX_NUMBER_OF_OBJECTS) + { + addObjects[numberOfAddObjects] = object; + numberOfAddObjects++; + } else + printf("[WARNING] max numbers of %d reached! Object was not added.\n", MAX_NUMBER_OF_OBJECTS); +} + +void Conglomerate::subtract(Object* object) +{ + if (numberOfSubtractObjects < MAX_NUMBER_OF_OBJECTS) + { + subtractObjects[numberOfSubtractObjects] = object; + numberOfSubtractObjects++; + } + else + printf("[WARNING] max numbers of %d reached! Object was not added.\n", MAX_NUMBER_OF_OBJECTS); +} + +Object* Conglomerate::clone() const +{ + auto conglomerate = new Conglomerate(); + for (uint i = 0; i < numberOfAddObjects; i++) + conglomerate->add(addObjects[i]->clone()); + + for (uint i = 0; i < numberOfSubtractObjects; i++) + conglomerate->subtract(subtractObjects[i]->clone()); + + return conglomerate; +} + +double Conglomerate::getX1Centroid() +{ + return (getX1Minimum() + getX1Maximum()) * 0.5; +} + +double Conglomerate::getX1Minimum() +{ + double minimum = addObjects[0]->getX1Minimum(); + for(uint i = 1; i < numberOfAddObjects; i++) + minimum = getMinimum(minimum, addObjects[i]->getX1Minimum()); + return minimum; +} + +double Conglomerate::getX1Maximum() +{ + double maximum = addObjects[0]->getX1Maximum(); + for (uint i = 1; i < numberOfAddObjects; i++) + maximum = getMaximum(maximum, addObjects[i]->getX1Maximum()); + return maximum; +} + +double Conglomerate::getX2Centroid() +{ + return (getX2Minimum() + getX2Maximum()) * 0.5; +} + +double Conglomerate::getX2Minimum() +{ + double minimum = addObjects[0]->getX2Minimum(); + for (uint i = 1; i < numberOfAddObjects; i++) + minimum = getMinimum(minimum, addObjects[i]->getX2Minimum()); + return minimum; +} + +double Conglomerate::getX2Maximum() +{ + double maximum = addObjects[0]->getX2Maximum(); + for (uint i = 1; i < numberOfAddObjects; i++) + maximum = getMaximum(maximum, addObjects[i]->getX2Maximum()); + return maximum; +} + +double Conglomerate::getX3Centroid() +{ + return (getX3Minimum() + getX3Maximum()) * 0.5; +} + +double Conglomerate::getX3Minimum() +{ + double minimum = addObjects[0]->getX3Minimum(); + for (uint i = 1; i < numberOfAddObjects; i++) + minimum = getMinimum(minimum, addObjects[i]->getX3Minimum()); + return minimum; +} + +double Conglomerate::getX3Maximum() +{ + double maximum = addObjects[0]->getX3Maximum(); + for (uint i = 1; i < numberOfAddObjects; i++) + maximum = getMaximum(maximum, addObjects[i]->getX3Maximum()); + return maximum; +} + +double Conglomerate::getMinimum(double val1, double val2) +{ + if (val1 > val2) + return val2; + return val1; +} + +double Conglomerate::getMaximum(double val1, double val2) +{ + if (val1 < val2) + return val2; + return val1; +} + +bool Conglomerate::isPointInObject(const double& x1, const double& x2, const double& x3, const double& minOffset, const double& maxOffset) +{ + for (uint i = 0; i < numberOfSubtractObjects; i++) + if (subtractObjects[i]->isPointInObject(x1, x2, x3, minOffset, maxOffset)) + return false; + + for (uint i = 0; i < numberOfAddObjects; i++) + if (addObjects[i]->isPointInObject(x1, x2, x3, minOffset, maxOffset)) + return true; + + return false; +} + +void Conglomerate::scale(double delta) +{ + for (uint i = 0; i < numberOfAddObjects; i++) + addObjects[i]->scale(delta); + + for (uint i = 0; i < numberOfSubtractObjects; i++) + subtractObjects[i]->scale(delta); +} + +void Conglomerate::findInnerNodes(SPtr<GridImp> grid) +{ + for (uint i = 0; i < numberOfAddObjects; i++) + addObjects[i]->findInnerNodes(grid); + + if( numberOfSubtractObjects > 0 ) + *logging::out << logging::Logger::INFO_INTERMEDIATE << "Warning: Conglomerate::substract() is currently nut fully implemented!\n"; +} diff --git a/src/gpu/GridGenerator/geometries/Conglomerate/Conglomerate.h b/src/gpu/GridGenerator/geometries/Conglomerate/Conglomerate.h new file mode 100644 index 0000000000000000000000000000000000000000..8cb26137d6ab4e4c52bed34aa1d044121ac4bf3d --- /dev/null +++ b/src/gpu/GridGenerator/geometries/Conglomerate/Conglomerate.h @@ -0,0 +1,85 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file Conglomerate.h +//! \ingroup geometries +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#ifndef CONGLOMERATE_H +#define CONGLOMERATE_H + +#include "global.h" + +#include "geometries/Object.h" + +#define MAX_NUMBER_OF_OBJECTS 20 + +class GRIDGENERATOR_EXPORT Conglomerate : public Object +{ +public: + Conglomerate(); + virtual ~Conglomerate(); + + static SPtr<Conglomerate> makeShared(); + + void add(Object* object); + void subtract(Object* objectStub); + + + Object* clone() const override; + + double getX1Centroid() override; + double getX1Minimum() override; + double getX1Maximum() override; + double getX2Centroid() override; + double getX2Minimum() override; + double getX2Maximum() override; + double getX3Centroid() override; + double getX3Minimum() override; + double getX3Maximum() override; + + void scale(double delta) override; + + bool isPointInObject(const double& x1, const double& x2, const double& x3, const double& minOffset, const double& maxOffset) override; + + void findInnerNodes(SPtr<GridImp> grid) override; + +protected: + static double getMinimum(double val1, double val2); + static double getMaximum(double val1, double val2); + + + Object** addObjects; + Object** subtractObjects; + uint numberOfAddObjects = 0; + uint numberOfSubtractObjects = 0; +}; + + + +#endif diff --git a/src/gpu/GridGenerator/geometries/Cuboid/Cuboid.cu b/src/gpu/GridGenerator/geometries/Cuboid/Cuboid.cpp similarity index 99% rename from src/gpu/GridGenerator/geometries/Cuboid/Cuboid.cu rename to src/gpu/GridGenerator/geometries/Cuboid/Cuboid.cpp index 7636c2bafd03be5bd18cb7dcd8546fbd09b42c96..e64a202ca9bcd5a33fcc9ba85e7bd35fa67a1d4e 100644 --- a/src/gpu/GridGenerator/geometries/Cuboid/Cuboid.cu +++ b/src/gpu/GridGenerator/geometries/Cuboid/Cuboid.cpp @@ -26,7 +26,7 @@ // You should have received a copy of the GNU General Public License along // with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. // -//! \file Cuboid.cu +//! \file Cuboid.cpp //! \ingroup geometries //! \author Soeren Peters, Stephan Lenz //======================================================================================= diff --git a/src/gpu/GridGenerator/geometries/Object.cu b/src/gpu/GridGenerator/geometries/Object.cpp similarity index 92% rename from src/gpu/GridGenerator/geometries/Object.cu rename to src/gpu/GridGenerator/geometries/Object.cpp index 1b369d708fe6dc527fdee3e45c93a80de38bb4c7..c162b3b1db8654f36a0fe6f3c20f79b34a157338 100644 --- a/src/gpu/GridGenerator/geometries/Object.cu +++ b/src/gpu/GridGenerator/geometries/Object.cpp @@ -26,15 +26,19 @@ // You should have received a copy of the GNU General Public License along // with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. // -//! \file Object.cu +//! \file Object.cpp //! \ingroup geometries //! \author Soeren Peters, Stephan Lenz //======================================================================================= #include "Object.h" #include "grid/GridImp.h" -#include "grid/GridStrategy/GridStrategy.h" void Object::findInnerNodes(SPtr<GridImp> grid) { - grid->getGridStrategy()->findInnerNodes( grid ); + grid->findInnerNodes(); +} + +int Object::getIntersection(const Vertex &P, const Vertex &direction, Vertex &pointOnObject, real &qVal) +{ + return 1; } diff --git a/src/gpu/GridGenerator/geometries/Object.h b/src/gpu/GridGenerator/geometries/Object.h index 88f09253612c4d1d73cb2ecdb8112b504702b0ad..b92cca7992dcb06c1f230da8d8c9ce46bb7a3416 100644 --- a/src/gpu/GridGenerator/geometries/Object.h +++ b/src/gpu/GridGenerator/geometries/Object.h @@ -38,6 +38,7 @@ #include "global.h" class GridImp; +struct Vertex; class GRIDGENERATOR_EXPORT Object { @@ -74,6 +75,8 @@ public: } virtual void findInnerNodes(SPtr<GridImp> grid); + + virtual int getIntersection(const Vertex &P, const Vertex &direction, Vertex &pointOnObject, real &qVal); }; diff --git a/src/gpu/GridGenerator/geometries/Sphere/Sphere.cpp b/src/gpu/GridGenerator/geometries/Sphere/Sphere.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fa460bc021cdca1159f272e3bcb4d4dad50fc352 --- /dev/null +++ b/src/gpu/GridGenerator/geometries/Sphere/Sphere.cpp @@ -0,0 +1,173 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file Sphere.cpp +//! \ingroup geometries +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#include "Sphere.h" + +#include <algorithm> // std::min +#include <float.h> +#include <cmath> + +#include "geometries/Vertex/Vertex.h" + +Sphere::Sphere(const double& centerX, const double& centerY, const double& centerZ, const double& radius) + : centerX(centerX), centerY(centerY), centerZ(centerZ), radius(radius) +{ + +} + +Sphere::~Sphere() +{ +} + +SPtr<Sphere> Sphere::makeShared(double centerX, double centerY, double centerZ, double radius) +{ + return SPtr<Sphere>(new Sphere(centerX, centerY, centerZ, radius)); +} + +Object* Sphere::clone() const +{ + return new Sphere(centerX, centerY, centerZ, radius); +} + +double Sphere::getX1Centroid() +{ + return centerX; +} + +double Sphere::getX1Minimum() +{ + return centerX - radius; +} + +double Sphere::getX1Maximum() +{ + return centerX + radius; +} + +double Sphere::getX2Centroid() +{ + return centerY; +} + +double Sphere::getX2Minimum() +{ + return centerY - radius; +} + +double Sphere::getX2Maximum() +{ + return centerY + radius; +} + +double Sphere::getX3Centroid() +{ + return centerZ; +} + +double Sphere::getX3Minimum() +{ + return centerZ - radius; +} + +double Sphere::getX3Maximum() +{ + return centerZ + radius; +} + +bool Sphere::isPointInObject(const double& x1, const double& x2, const double& x3, const double& minOffset, + const double& maxOffset) +{ + double offset = maxOffset; + if (x1 < centerX || x2 < centerY || x3 < centerZ) + offset = minOffset; + + + const double deltaX1 = x1 - centerX; + const double deltaX2 = x2 - centerY; + const double deltaX3 = x3 - centerZ; + + return (deltaX1*deltaX1 + deltaX2*deltaX2 + deltaX3*deltaX3) < ((this->radius - offset) * (this->radius - offset)); +} + + +void Sphere::scale(double delta) +{ + this->radius += delta; +} + +int Sphere::getIntersection(const Vertex & point, const Vertex & direction, Vertex & pointOnObject, real & qVal) +{ + + Vertex relativePoint( point.x - this->centerX, + point.y - this->centerY, + point.z - this->centerZ ); + + real directionSquare = direction.x * direction.x + + direction.y * direction.y + + direction.z * direction.z; + + real p = 2* ( relativePoint.x * direction.x + + relativePoint.y * direction.y + + relativePoint.z * direction.z ) + / directionSquare; + + real q = ( relativePoint.x * relativePoint.x + + relativePoint.y * relativePoint.y + + relativePoint.z * relativePoint.z + - (real)this->radius * (real)this->radius ) + / directionSquare; + + real discriminant = 0.25 * p * p - q; + + + if( discriminant < 0.0 ) return 1; + + real result1 = - 0.5 * p + std::sqrt( discriminant ); + real result2 = - 0.5 * p - std::sqrt( discriminant ); + + if( result1 < 0.0 && result2 < 0.0 ) return 1; + + if (result1 < 0.0) + result1 = (real)FLT_MAX; + if (result2 < 0.0) + result2 = (real)FLT_MAX; + + real t = std::min( result1, result2 ); + + pointOnObject.x = point.x + t * direction.x; + pointOnObject.y = point.y + t * direction.y; + pointOnObject.z = point.z + t * direction.z; + + qVal = t; + + return 0; +} diff --git a/src/gpu/GridGenerator/geometries/Sphere/Sphere.h b/src/gpu/GridGenerator/geometries/Sphere/Sphere.h new file mode 100644 index 0000000000000000000000000000000000000000..ba5821f5bfed5b4d25c1ee3c5abecb168db462e7 --- /dev/null +++ b/src/gpu/GridGenerator/geometries/Sphere/Sphere.h @@ -0,0 +1,78 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file Sphere.h +//! \ingroup geometries +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#ifndef SPHERE_H +#define SPHERE_H + +#include "global.h" +#include "GridGenerator_export.h" +#include "geometries/Object.h" + +class GRIDGENERATOR_EXPORT Sphere : public Object +{ +public: + Sphere(const double& centerX, const double& centerY, const double& centerZ, const double& radius); + virtual ~Sphere(); + + static SPtr<Sphere> makeShared(double centerX, double centerY, double centerZ, double radius); + + Object* clone() const override; + + double getX1Centroid() override; + double getX1Minimum() override; + double getX1Maximum() override; + double getX2Centroid() override; + double getX2Minimum() override; + double getX2Maximum() override; + double getX3Centroid() override; + double getX3Minimum() override; + double getX3Maximum() override; + + bool isPointInObject(const double& x1, const double& x2, const double& x3, const double& minOffset, const double& maxOffset) override; + + + void scale(double delta) override; + + int getIntersection(const Vertex &P, const Vertex &direction, Vertex &pointOnObject, real &qVal) override; + + +protected: + double centerX; + double centerY; + double centerZ; + + double radius; +}; + + + +#endif diff --git a/src/gpu/GridGenerator/geometries/Triangle/Triangle.cpp b/src/gpu/GridGenerator/geometries/Triangle/Triangle.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bf272b9e7f46c413ae6edce62c05d1be20d327de --- /dev/null +++ b/src/gpu/GridGenerator/geometries/Triangle/Triangle.cpp @@ -0,0 +1,356 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file Triangle.cpp +//! \ingroup geometries +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#include "Triangle.h" + +#include "utilities/math/Math.h" + +#include "grid/NodeValues.h" + +using namespace vf::gpu; + +Triangle::Triangle(Vertex &v1, Vertex &v2, Vertex &v3, Vertex &normal) : v1(v1), v2(v2), v3(v3), normal(normal), patchIndex(INVALID_INDEX) {} +Triangle::Triangle(Vertex &v1, Vertex &v2, Vertex &v3) : v1(v1), v2(v2), v3(v3), patchIndex(INVALID_INDEX) { calcNormal(); } +Triangle::Triangle(){} + +void Triangle::set(const Vertex &v1, const Vertex &v2, const Vertex &v3) +{ + this->v1 = v1; + this->v2 = v2; + this->v3 = v3; + this->calcNormal(); +} + +void Triangle::set(int index, Vertex value) +{ + if (index == 0) + v1 = value; + if (index == 1) + v2 = value; + if (index == 2) + v3 = value; +} + +Vertex Triangle::get(int index) +{ + if (index == 0) + return v1; + if (index == 1) + return v2; + if (index == 2) + return v3; + else + return Vertex((real)-999999999999999, (real)-99999999999999, (real)-9999999999999); +} + +void Triangle::calcNormal() +{ + Vertex edge1 = v2 - v1; + Vertex edge2 = v3 - v1; + normal = edge1.crossProduct(edge2); + normal.normalize(); +} + +void Triangle::initalLayerThickness(real delta) +{ + this->layerThickness = delta * (std::abs(this->normal.x) + std::abs(this->normal.y) + std::abs(this->normal.z)); +} + + +char Triangle::isUnderFace(const Vertex &point) const +{ + real s; + + if (this->isUnterExtendedFace(point, s)) { + if (this->isNotNextToFace(point)) { + if (this->isUnderAngleToNeighbors(point)) { + if (this->isNegativeDirectionBorder(point)) { + return NEGATIVE_DIRECTION_BORDER; + } else { + return INSIDE; + } + } else { + return 4; + } + } else { + return 3; + } + } + + + if (this->isQNode(point, s)) + return Q_DEPRECATED; + + return FLUID; +} + +bool Triangle::isUnterExtendedFace(const Vertex & point, real &s) const +{ + s = this->getPerpedicularDistanceFrom(point); + return ((vf::Math::greaterEqual(s, 0.0f)) && s < this->layerThickness); +} + +real Triangle::getPerpedicularDistanceFrom(const Vertex &P) const +{ + Vertex v = P - v1; + return (v * -1.0f) * normal; +} + +Vertex Triangle::getPerpedicularPointFrom(const Vertex &P) const +{ + return P + normal * getPerpedicularDistanceFrom(P); +} + +bool Triangle::isQNode(const Vertex & point, const real &s) const +{ + return (s < 0 && vf::Math::lessEqual(-s, this->layerThickness)); + //calculateQs(actualPoint, actualTriangle); +} + +bool Triangle::isNegativeDirectionBorder(const Vertex &point) const +{ + return normal.x < 0.0f || normal.y < 0.0f || normal.z < 0.0f; + //return (sVector.x < 0.0f && sVector.y < 0.0f && sVector.z < 0.0f); +} + +bool Triangle::isNotNextToFace(const Vertex &point) const +{ + Vertex Pb = getPerpedicularPointFrom(point); + + Vertex w1 = Pb - v1; + Vertex w2 = Pb - v2; + Vertex w3 = Pb - v3; + + Vertex t1 = w1.crossProduct(v2 - v1); + Vertex t2 = w2.crossProduct(v3 - v2); + Vertex t3 = w3.crossProduct(v1 - v3); + + real g1 = t1 * normal; + real g2 = t2 * normal; + real g3 = t3 * normal; + + return vf::Math::lessEqual(g1, 0.0f) && vf::Math::lessEqual(g2, 0.0f) && vf::Math::lessEqual(g3, 0.0f); +} + +bool Triangle::isUnderAngleToNeighbors(const Vertex &point) const +{ + Vertex Pci[3]; + this->getClosestPointsOnEdges(Pci, point); + Vertex Pb = this->getPerpedicularPointFrom(point); + + Vertex q[3]; + Vertex r[3]; + + real betaAngles[3]; + for (int i = 0; i < 3; i++) + { + q[i] = point - Pci[i]; + r[i] = Pb - Pci[i]; + betaAngles[i] = q[i].getInnerAngle(r[i]); + } + + real eps = EPSILON * 100.0f; + return (vf::Math::lessEqual(betaAngles[0], alphaAngles[0], eps) && vf::Math::lessEqual(betaAngles[1], alphaAngles[1], eps) && vf::Math::lessEqual(betaAngles[2], alphaAngles[2], eps)); +} + +void Triangle::getClosestPointsOnEdges(Vertex arr[], const Vertex &P) const +{ + Vertex Pc1, Pc2, Pc3; + Vertex v4 = P - v1; + Vertex v5 = P - v2; + Vertex v6 = P - v3; + + Vertex d1 = v2 - v1; + Vertex d2 = v3 - v2; + Vertex d3 = v1 - v3; + + real temp = (v4 * d1) / (d1 * d1); + Vertex tempV = d1 * temp; + Pc1 = v1 + tempV; + + temp = (v5 * d2) / (d2 * d2); + tempV = d2 * temp; + Pc2 = v2 + tempV; + + temp = (v6 * d3) / (d3 * d3); + tempV = d3 * temp; + Pc3 = v3 + tempV; + + arr[0] = Pc1; + arr[1] = Pc2; + arr[2] = Pc3; +} + +Vertex Triangle::getCenterOfMass() const +{ + return (v1 + v2 + v3) * (1.0f / 3.0f); +} + +real Triangle::getHalfAngleBetweenToAdjacentTriangle(const Triangle &t2) const +{ + if (isEqual(t2)) return 0.0f; + + real alpha = normal.getInnerAngle(t2.normal); + if (alpha == 0.0f) + return 90.0f; + + if(doesNormalsShowToEachOther(t2)) + return (180.0f + alpha) / 2.0f; + else + return (180.0f - alpha) / 2.0f; +} + +int Triangle::isEqual(const Triangle &t2) const +{ + return getNumberOfCommonEdge(t2) == 3; +} + +bool Triangle::doesNormalsShowToEachOther(const Triangle &t2) const +{ + Vertex s1 = getCenterOfMass(); + Vertex s2 = t2.getCenterOfMass(); + + Vertex s1s2 = s1 - s2; + real X = s1s2 * t2.normal; + return X > 0 ? true : false; +} + +int Triangle::getCommonEdge(const Triangle &t2) const +{ + bool edgeOneCommon = false; + bool edgeTwoCommon = false; + bool edgeThreeCommon = false; + + edgeOneCommon = t2.contains(v1); + edgeTwoCommon = t2.contains(v2); + edgeThreeCommon = t2.contains(v3); + + if (edgeOneCommon && edgeTwoCommon) + return 0; + else if (edgeTwoCommon && edgeThreeCommon) + return 1; + else if (edgeThreeCommon && edgeOneCommon) + return 2; + else + return -1; +} + +bool Triangle::contains(const Vertex& v) const +{ + return (v == v1 || v == v2 || v == v3); +} + + +int Triangle::getNumberOfCommonEdge(const Triangle &t2) const +{ + int commonEdge = 0; + if (t2.contains(v1)) + commonEdge++; + if (t2.contains(v2)) + commonEdge++; + if (t2.contains(v3)) + commonEdge++; + + if (commonEdge == 2 || commonEdge == 3) return commonEdge; + return 0; +} + + +int Triangle::getTriangleIntersection(const Vertex &P, const Vertex &direction, Vertex &pointOnTri, real &qVal) const +{ + ///// taken from ///// + //http://www.scratchapixel.com/lessons/3d-basic-rendering/ray-tracing-rendering-a-triangle/moller-trumbore-ray-triangle-intersection + + + Vertex edge1, edge2, tvec, pvec, qvec, tuv; + float det, inv_det; + + edge1 = v2 - v1; + edge2 = v3 - v1; + + pvec = direction.crossProduct(edge2); + det = edge1 * pvec; + + if (det < EPSILON) + return 3; + + inv_det = 1.0 / det; + + tvec = P - v1; + tuv.y = (tvec * pvec) * inv_det; + + if (!vf::Math::greaterEqual(tuv.y, 0.0) || !vf::Math::lessEqual(tuv.y, 1.0)) + //if (tuv.y < 0.0 || tuv.y > 1.0) + return 1; + + qvec = tvec.crossProduct(edge1); + tuv.z = (direction * qvec) * inv_det; + + if ( !vf::Math::greaterEqual(tuv.z, 0.0) || !vf::Math::lessEqual((tuv.y + tuv.z), 1.0)) + //if (tuv.z < 0.0 || (tuv.y + tuv.z) > 1.0) + return 2; + + tuv.x = (edge2 * qvec) * inv_det; + + pointOnTri.x = (1.0 - tuv.y - tuv.z) * v1.x + tuv.y * v2.x + tuv.z * v3.x; + pointOnTri.y = (1.0 - tuv.y - tuv.z) * v1.y + tuv.y * v2.y + tuv.z * v3.y; + pointOnTri.z = (1.0 - tuv.y - tuv.z) * v1.z + tuv.y * v2.z + tuv.z * v3.z; + + qVal = tuv.x; + + return 0; +} + +void Triangle::print() const +{ + printf("v1: "); + v1.print(); + printf("v2: "); + v2.print(); + printf("v3: "); + v3.print(); + printf("normal: "); + normal.print(); +} + +bool Triangle::operator==(const Triangle &t) const +{ + return v1 == t.v1 && v2 == t.v2 && v3 == t.v3 + && vf::Math::equal(alphaAngles[0], t.alphaAngles[0]) && vf::Math::equal(alphaAngles[1], t.alphaAngles[1]) && vf::Math::equal(alphaAngles[2], t.alphaAngles[2]); +} + + +void Triangle::setMinMax(real &minX, real &maxX, real &minY, real &maxY, real &minZ, real &maxZ) const +{ + Vertex::setMinMax(minX, maxX, minY, maxY, minZ, maxZ, v1, v2, v3); +} + diff --git a/src/gpu/GridGenerator/geometries/Triangle/Triangle.h b/src/gpu/GridGenerator/geometries/Triangle/Triangle.h new file mode 100644 index 0000000000000000000000000000000000000000..0017d2f71145f2608976a95018816bf81cef44b7 --- /dev/null +++ b/src/gpu/GridGenerator/geometries/Triangle/Triangle.h @@ -0,0 +1,95 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file Triangle.h +//! \ingroup geometries +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#ifndef Triangle_h +#define Triangle_h + +#include <memory> + +#include "global.h" +#include "GridGenerator_export.h" +#include "geometries/Vertex/Vertex.h" + +class TriangleMemento; + +struct GRIDGENERATOR_EXPORT Triangle +{ + Vertex v1, v2, v3, normal; + real alphaAngles[3]; + real layerThickness; + + uint patchIndex; + + Triangle(Vertex &v1, Vertex &v2, Vertex &v3, Vertex &normal); + Triangle(Vertex &v1, Vertex &v2, Vertex &v3); + Triangle(); + + void set(const Vertex &v1, const Vertex &v2, const Vertex &v3); + void set(int index, Vertex value); + Vertex get(int index); + void calcNormal(); + + void initalLayerThickness(real delta); + + + Vertex getCenterOfMass() const; + real getHalfAngleBetweenToAdjacentTriangle(const Triangle &t2) const; + int isEqual(const Triangle &t2) const; + bool doesNormalsShowToEachOther(const Triangle &t2) const; + int getCommonEdge(const Triangle &t2) const; + + bool contains(const Vertex& v)const; + int getNumberOfCommonEdge(const Triangle &t2) const; + int getTriangleIntersection(const Vertex &P, const Vertex &direction, Vertex &pointOnTri, real &qVal) const; + void print() const; + + char isUnderFace(const Vertex &point) const; + + bool isUnterExtendedFace(const Vertex & point, real &s) const; + bool isNotNextToFace(const Vertex &point) const; + bool isUnderAngleToNeighbors(const Vertex &point) const; + void getClosestPointsOnEdges(Vertex arr[], const Vertex &P) const; + real getPerpedicularDistanceFrom(const Vertex &P) const; + Vertex getPerpedicularPointFrom(const Vertex &P) const; + bool isQNode(const Vertex & point, const real &s) const; + bool isNegativeDirectionBorder(const Vertex & point) const; + + bool operator==(const Triangle &t) const; + + TriangleMemento getState() const; + void setState(const TriangleMemento &memento); + + + void setMinMax(real &minX, real &maxX, real &minY, real &maxY, real &minZ, real &maxZ) const; +}; + +#endif diff --git a/src/gpu/GridGenerator/geometries/TriangularMesh/TriangularMesh.cpp b/src/gpu/GridGenerator/geometries/TriangularMesh/TriangularMesh.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a11384887074aa6b42bff77dd8b7ee1ade8fc9e0 --- /dev/null +++ b/src/gpu/GridGenerator/geometries/TriangularMesh/TriangularMesh.cpp @@ -0,0 +1,290 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file TriangularMesh.cpp +//! \ingroup geometries +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#include "TriangularMesh.h" + +#include "Core/Timer/Timer.h" + +#include "basics/geometry3d/GbTriFaceMesh3D.h" + +#include "geometries/TriangularMesh/triangleNeighborFinder/TriangleNeighborFinder.h" +#include "geometries/TriangularMesh/TriangularMeshStrategy.h" + +#include "io/STLReaderWriter/STLWriter.h" +#include "io/STLReaderWriter/STLReader.h" + +#include "grid/GridImp.h" +#include "grid/NodeValues.h" + +#include "utilities/transformator/TransformatorImp.h" + +using namespace vf::gpu; + + +TriangularMesh* TriangularMesh::make(const std::string& fileName, const std::vector<uint> ignorePatches) +{ + TriangularMesh* triangularMesh = new TriangularMesh(fileName, ignorePatches); + return triangularMesh; +} + +TriangularMesh::TriangularMesh(const std::string& input, const BoundingBox& box) +{ + this->triangleVec = STLReader::readSTL(box, input); + initalizeDataFromTriangles(); + this->findNeighbors(); +} + +TriangularMesh::TriangularMesh(const std::string& inputPath, const std::vector<uint> ignorePatches) +{ + this->minmax = BoundingBox::makeInvalidMinMaxBox(); + + this->triangleVec = STLReader::readSTL(inputPath, STLReader::ascii, ignorePatches); + //this->triangleVec = STLReader::readSTL(inputPath); + initalizeDataFromTriangles(); + this->findNeighbors(); +} + + +TriangularMesh::TriangularMesh() +{ + this->minmax = BoundingBox::makeInvalidMinMaxBox(); // blame Lenz +} + +TriangularMesh::~TriangularMesh() +{ + +} + +Object* TriangularMesh::clone() const +{ + auto mesh = new TriangularMesh(); + mesh->setTriangles(this->triangleVec); + return mesh; +} + + +uint TriangularMesh::getNumberOfTriangles() const +{ + return (uint)triangleVec.size(); +} + + +void TriangularMesh::findNeighbors() +{ + *logging::out << logging::Logger::INFO_INTERMEDIATE << "start finding neighbors ...\n"; + + auto t = Timer::makeStart(); + + TriangleNeighborFinder finder(triangles, size); + finder.fillWithNeighborAngles(this); + + t->end(); + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "time finding neighbors: " << t->getTimeInSeconds() << "s\n"; +} + +void TriangularMesh::setTriangles(std::vector<Triangle> triangles) +{ + this->triangleVec = triangles; + initalizeDataFromTriangles(); +} + +void TriangularMesh::setMinMax(BoundingBox minmax) +{ + this->minmax = minmax; +} + +void TriangularMesh::initalizeDataFromTriangles() +{ + this->triangles = triangleVec.data(); + this->size = long(triangleVec.size()); + + for (std::size_t i = 0; i < (size_t)this->size; i++) { + this->minmax.setMinMax(this->triangleVec[i]); + } +} + +bool TriangularMesh::operator==(const TriangularMesh &geometry) const +{ + if (!(minmax == geometry.minmax)) + return false; + + if (size != geometry.size) + return false; + + for (int i = 0; i < size ; i++) + if (!(triangleVec[i] == geometry.triangleVec[i])) + return false; + return true; +} + + +GbTriFaceMesh3D* TriangularMesh::getGbTriFaceMesh3D() const +{ + return this->VF_GbTriFaceMesh3D.get(); +} + +GRIDGENERATOR_EXPORT void TriangularMesh::generateGbTriFaceMesh3D() +{ + if( this->VF_GbTriFaceMesh3D ) return; + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start generating GbTriFaceMesh3D:\n"; + + std::vector<GbTriFaceMesh3D::Vertex> *gbVertices = new std::vector<GbTriFaceMesh3D::Vertex>(this->triangleVec.size() * 3); + std::vector<GbTriFaceMesh3D::TriFace> *gbTriangles = new std::vector<GbTriFaceMesh3D::TriFace>(this->triangleVec.size()); + + for (int i = 0; i < (int)this->triangleVec.size(); i++) + { + (*gbVertices)[i * 3] = GbTriFaceMesh3D::Vertex(triangles[i].v1.x, triangles[i].v1.y, triangles[i].v1.z); + (*gbVertices)[i * 3 + 1] = GbTriFaceMesh3D::Vertex(triangles[i].v2.x, triangles[i].v2.y, triangles[i].v2.z); + (*gbVertices)[i * 3 + 2] = GbTriFaceMesh3D::Vertex(triangles[i].v3.x, triangles[i].v3.y, triangles[i].v3.z); + + (*gbTriangles)[i] = GbTriFaceMesh3D::TriFace(i * 3, i * 3 + 1, i * 3 + 2); + } + + this->VF_GbTriFaceMesh3D = std::make_shared<GbTriFaceMesh3D>( "stl", gbVertices, gbTriangles, GbTriFaceMesh3D::KDTREE_SAHPLIT, false ); + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "Done generating GbTriFaceMesh3D\n"; +} + + +bool intersectPlane(const Vertex &normal, const Vertex &pointOnPlane, const Vertex &originLine, const Vertex &directionLine, Vertex &intersectionPoint) +{ + // assuming vectors are all normalized + real denom = normal * directionLine; + if (denom > 1e-6) { + Vertex p0l0 = pointOnPlane - originLine; + real distance = p0l0 * normal / denom; + intersectionPoint = originLine + directionLine * distance; + return (distance >= 0); + } + + return false; +} + +void TriangularMesh::scale(double offset) +{ + std::vector<Triangle> triangles = this->triangleVec; + + TriangleNeighborFinder finder(this->triangles, this->size); + + auto trianglesPerVertex = finder.getTrianglesPerVertex(); + auto averrageNormals = getAverrageNormalsPerVertex(trianglesPerVertex); + + + for (std::size_t vertexID = 0; vertexID < this->getNumberOfTriangles() * 3; vertexID++) + { + int coordinatedID = finder.sortedToTriangles[vertexID][IDS::coordinateID]; + Vertex averrageNormal = averrageNormals[coordinatedID]; + + //auto triangleIds = finder.getTriangleIDsWithCommonVertex(vertexID); + //for(auto index : triangleIds) + //{ + // auto triangle = origin->triangleVec[index]; + // Vertex intersection; + // real d = 10; + // triangle.normal.normalize(); + // Vertex p = triangle.v2 + triangle.normal * d; + // // p.normalize(); + // Vertex lineOrigin = origin->triangleVec[triangleID].get(vertexTriangleID); + // // lineOrigin.normalize(); + // //averrageNormal.normalize(); + // //triangle.print(); + + // //printf("average: \n"); + // //averrageNormal.print(); + + // //printf("line origin: \n"); + // //lineOrigin.print(); + + // //printf("plane normal: \n"); + // //triangle.normal.print(); + + // //printf("plane point: \n"); + // //p.print(); + + // bool b = intersectPlane(triangle.normal, p, lineOrigin, averrageNormal, intersection); + // //intersection.print(); + // //printf("\n"); + //} + //printf("\n\n"); + + averrageNormal.normalize(); + const int triangleID = (int)vertexID / 3; + const int vertexTriangleID = (int)vertexID % 3; + + Vertex intersection; + Vertex p = this->triangleVec[triangleID].v1 + this->triangleVec[triangleID].normal * offset; + Vertex lineOrigin = this->triangleVec[triangleID].get(vertexTriangleID); + //bool b = intersectPlane(this->triangleVec[triangleID].normal, p, lineOrigin, averrageNormal, intersection); + triangles[triangleID].set(vertexTriangleID, intersection); + triangles[triangleID].calcNormal(); + + triangles[triangleID].set(vertexTriangleID, lineOrigin + averrageNormal * offset); + } + + this->setTriangles(triangles); +} + +std::vector<Vertex> TriangularMesh::getAverrageNormalsPerVertex(std::vector<std::vector<Triangle>> trianglesPerVertex) +{ + std::vector<Vertex> averrageNormals; + for (auto triangles : trianglesPerVertex) + { + eliminateTriangleswithIdenticialNormal(triangles); + + Vertex sumNormal; + for (auto triangle : triangles) + { + triangle.calcNormal(); + sumNormal = sumNormal + triangle.normal; + } + real magnitude = sumNormal.getMagnitude(); + averrageNormals.push_back(Vertex(sumNormal / magnitude)); + } + return averrageNormals; +} + +void TriangularMesh::eliminateTriangleswithIdenticialNormal(std::vector<Triangle> &triangles) +{ + for (std::size_t i = 0; i < triangles.size() - 1; i++) { + for (std::size_t j = i + 1; j < triangles.size(); j++) { + if (triangles[i].normal == triangles[j].normal) + triangles.erase(triangles.begin() + i); + } + } +} + +void TriangularMesh::findInnerNodes(SPtr<GridImp> grid) +{ + grid->getTriangularMeshDiscretizationStrategy()->discretize(this, grid.get(), FLUID, INVALID_OUT_OF_GRID); +} diff --git a/src/gpu/GridGenerator/geometries/TriangularMesh/TriangularMesh.h b/src/gpu/GridGenerator/geometries/TriangularMesh/TriangularMesh.h new file mode 100644 index 0000000000000000000000000000000000000000..2d31de98bf1f5530ada555e548ac6bb40e5e51b7 --- /dev/null +++ b/src/gpu/GridGenerator/geometries/TriangularMesh/TriangularMesh.h @@ -0,0 +1,114 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file TriangularMesh.h +//! \ingroup geometries +//! \author Soeren Peters, Stephan Lenz, Martin Schoenherr +//======================================================================================= +#ifndef TriangularMesh_h +#define TriangularMesh_h + +#include <stdio.h> +#include <vector> +#include <string> +#include <memory> +#include "GridGenerator_export.h" +#include "global.h" + +#include "geometries/Triangle/Triangle.h" +#include "geometries/BoundingBox/BoundingBox.h" + +#include "geometries/Object.h" + +class GeometryMemento; +class GbTriFaceMesh3D; + +enum class DiscretizationMethod { RAYCASTING, POINT_IN_OBJECT, POINT_UNDER_TRIANGLE }; + + +class TriangularMesh : public Object +{ +public: + + GRIDGENERATOR_EXPORT static TriangularMesh* make(const std::string& fileName, const std::vector<uint> ignorePatches = std::vector<uint>()); + GRIDGENERATOR_EXPORT TriangularMesh(); + GRIDGENERATOR_EXPORT TriangularMesh(const std::string& inputPath, const std::vector<uint> ignorePatches = std::vector<uint>()); + GRIDGENERATOR_EXPORT TriangularMesh(const std::string& inputPath, const BoundingBox &box); + GRIDGENERATOR_EXPORT ~TriangularMesh(); + + GRIDGENERATOR_EXPORT uint getNumberOfTriangles() const; + + GRIDGENERATOR_EXPORT void setTriangles(std::vector<Triangle> triangles); + GRIDGENERATOR_EXPORT void setMinMax(BoundingBox minmax); + + std::vector<Triangle> triangleVec; + Triangle *triangles; + long size; + BoundingBox minmax; + + SPtr<GbTriFaceMesh3D> VF_GbTriFaceMesh3D; + + GRIDGENERATOR_EXPORT bool operator==(const TriangularMesh &geometry) const; + + GRIDGENERATOR_EXPORT void findNeighbors(); + + GRIDGENERATOR_EXPORT GbTriFaceMesh3D* getGbTriFaceMesh3D() const; + + GRIDGENERATOR_EXPORT void generateGbTriFaceMesh3D(); + +private: + + void initalizeDataFromTriangles(); + + static std::vector<Vertex> getAverrageNormalsPerVertex(std::vector<std::vector<Triangle> > trianglesPerVertex); + static void eliminateTriangleswithIdenticialNormal(std::vector<Triangle> &triangles); + +public: + Object* clone() const override; + double getX1Centroid() override { throw "Not implemented in TriangularMesh"; } + double getX1Minimum() override { return minmax.minX; } + double getX1Maximum() override { return minmax.maxX; } + double getX2Centroid() override { throw "Not implemented in TriangularMesh"; } + double getX2Minimum() override { return minmax.minY; } + double getX2Maximum() override { return minmax.maxY; } + double getX3Centroid() override { throw "Not implemented in TriangularMesh"; } + double getX3Minimum() override { return minmax.minZ; } + double getX3Maximum() override { return minmax.maxZ; } + void scale(double delta) override; + bool isPointInObject(const double& x1, const double& x2, const double& x3, const double& minOffset, + const double& maxOffset) override { + return false; + } + + void findInnerNodes(SPtr<GridImp> grid) override; +}; + + + +#endif + diff --git a/src/gpu/GridGenerator/geometries/TriangularMesh/TriangularMeshStrategy.cpp b/src/gpu/GridGenerator/geometries/TriangularMesh/TriangularMeshStrategy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d9c1486e2ca9469d55174eca673f22f180a78294 --- /dev/null +++ b/src/gpu/GridGenerator/geometries/TriangularMesh/TriangularMeshStrategy.cpp @@ -0,0 +1,310 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file TriangularMeshStrategy.cpp +//! \ingroup geometries +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#include "TriangularMeshStrategy.h" + +#include "Core/Timer/Timer.h" + +#include "basics/geometry3d/GbTriFaceMesh3D.h" + +#include "geometries/Triangle/Triangle.h" +#include "geometries/TriangularMesh/TriangularMesh.h" + +#include "grid/GridImp.h" +#include "grid/NodeValues.h" + +using namespace vf::gpu; + +void TriangularMeshDiscretizationStrategy::removeOddBoundaryCellNodes(GridImp* grid) +{ +#pragma omp parallel for + for (int index = 0; index < (int)grid->getSize(); index++) + grid->fixOddCell(index); +} + + +void PointInObjectDiscretizationStrategy::doDiscretize(TriangularMesh* triangularMesh, GridImp* grid, char InnerType, char OuterType) +{ + triangularMesh->generateGbTriFaceMesh3D(); + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start Point-In-Object Test:\n"; + + // trigger the GbTriFaceMesh3D to generate a kd-tree + triangularMesh->getGbTriFaceMesh3D()->isPointInGbObject3D(0.0, 0.0, 0.0); + + auto timer = Timer::makeStart(); + + real outputTime = 60.0; + +#pragma omp parallel for + for (int index = 0; index < (int)grid->getSize(); index++) + { + if( grid->getFieldEntry(index) == InnerType ) continue; + + real x, y, z; + grid->transIndexToCoords(index, x, y, z); + + if (triangularMesh->getGbTriFaceMesh3D()->isPointInGbObject3D(x, y, z)) + grid->setNodeTo(index, InnerType); + //else + // grid->setNodeTo(i, OuterType); + + if( timer->getCurrentRuntimeInSeconds() > outputTime ){ + *logging::out << logging::Logger::INFO_INTERMEDIATE << " " << index << "/" << grid->getSize() <<" nodes tested!\n"; + timer->start(); + } + } + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "Done Point-In-Object Test\n"; +} + + +void RayCastingDiscretizationStrategy::doDiscretize(TriangularMesh* triangularMesh, GridImp* grid, char InnerType, char OuterType) +{ + auto mesh = triangularMesh->getGbTriFaceMesh3D(); + + const real minXExact = triangularMesh->minmax.minX; + const real minYExact = triangularMesh->minmax.minY; + const real minZExact = triangularMesh->minmax.minZ; + + const real maxXExact = triangularMesh->minmax.maxX; + const real maxYExact = triangularMesh->minmax.maxY; + const real maxZExact = triangularMesh->minmax.maxZ; + + const auto min = grid->getMinimumOnNode(Vertex(minXExact, minYExact, minZExact)); + + const real minX = min.x; + const real minY = min.y; + const real minZ = min.z; + + const auto max = grid->getMaximumOnNode(Vertex(maxXExact, maxYExact, maxZExact)); + + const real maxX = max.x; + const real maxY = max.y; + const real maxZ = max.z; + + + real x, y, z; + for (z = minZ; z <= maxZ; z += grid->getDelta()) + { + for (y = minY; y <= maxY; y += grid->getDelta()) + { + for (x = minX; x <= maxX; x += grid->getDelta()) + { + grid->setNodeTo(grid->transCoordToIndex(x, y, z), InnerType); + } + } + } + + + + int counter = 0; + + // Test line intersection + for (z = minZ; z <= maxZ; z += grid->getDelta()) + { + for (y = minY; y <= maxY; y += grid->getDelta()) + { + for (x = minX; x <= maxX; x += grid->getDelta()) + { + counter++; + if (mesh->intersectLine((x - grid->getDelta()), y, z, x, y, z)) + break; + grid->setNodeTo(grid->transCoordToIndex(x, y, z), OuterType); + } + } + } + + // Test line intersection from opposite direction + for (z = minZ; z <= maxZ; z += grid->getDelta()) + { + for (y = minY; y <= maxY; y += grid->getDelta()) + { + for (x = maxX; x >= minX; x -= grid->getDelta()) + { + if (!grid->isNode(grid->transCoordToIndex(x, y, z), OuterType)) + { + counter++; + if (mesh->intersectLine((x + grid->getDelta()), y, z, x, y, z)) + break; + grid->setNodeTo(grid->transCoordToIndex(x, y, z), OuterType); + } + } + } + } + + // Test line intersection + for (z = minZ; z <= maxZ; z += grid->getDelta()) + { + for (x = minX; x <= maxX; x += grid->getDelta()) + { + for (y = minY; y <= maxY; y += grid->getDelta()) + { + if (!grid->isNode(grid->transCoordToIndex(x, y, z), OuterType)) + { + counter++; + if (mesh->intersectLine(x, (y - grid->getDelta()), z, x, y, z)) + break; + grid->setNodeTo(grid->transCoordToIndex(x, y, z), OuterType); + } + } + } + } + + // Test line intersection from opposite direction + for (z = minZ; z <= maxZ; z += grid->getDelta()) + { + for (x = minX; x <= maxX; x += grid->getDelta()) + { + for (y = maxY; y >= minY; y -= grid->getDelta()) + { + if (!grid->isNode(grid->transCoordToIndex(x, y, z), OuterType)) + { + counter++; + if (mesh->intersectLine(x, (y + grid->getDelta()), z, x, y, z)) + break; + grid->setNodeTo(grid->transCoordToIndex(x, y, z), OuterType); + } + } + } + } + + // Test line intersection + for (x = minX; x <= maxX; x += grid->getDelta()) + { + for (y = minY; y <= maxY; y += grid->getDelta()) + { + for (z = minZ; z <= maxZ; z += grid->getDelta()) + { + if (!grid->isNode(grid->transCoordToIndex(x, y, z), OuterType)) + { + counter++; + if (mesh->intersectLine(x, y, (z - grid->getDelta()), x, y, z)) + break; + grid->setNodeTo(grid->transCoordToIndex(x, y, z), OuterType); + } + } + } + } + + // Test line intersection from opposite direction + for (x = minX; x <= maxX; x += grid->getDelta()) + { + for (y = minY; y <= maxY; y += grid->getDelta()) + { + for (z = maxZ; z >= minZ; z -= grid->getDelta()) + { + if (!grid->isNode(grid->transCoordToIndex(x, y, z), OuterType)) + { + counter++; + if (mesh->intersectLine(x, y, (z + grid->getDelta()), x, y, z)) + break; + grid->setNodeTo(grid->transCoordToIndex(x, y, z), OuterType); + } + } + } + } + + delete mesh; +} + + + +void PointUnderTriangleStrategy::doDiscretize(TriangularMesh* triangularMesh, GridImp* grid, char innerType, char outerType) +{ +#pragma omp parallel for + for (long i = 0; i < triangularMesh->size; i++) + this->meshReverse(triangularMesh->triangles[i], grid, innerType); + + this->findInsideNodes(grid, innerType); + +#pragma omp parallel for + for (int i = 0; i < (int)grid->getSize(); i++) + this->setNegativeDirBorderTo(grid, i, innerType); +} + +void PointUnderTriangleStrategy::meshReverse(Triangle& triangle, GridImp* grid, char innerType) +{ + auto box = grid->getBoundingBoxOnNodes(triangle); + + const real delta = grid->getDelta(); + triangle.initalLayerThickness(delta); + + for (real x = box.minX; x <= box.maxX; x += delta) + { + for (real y = box.minY; y <= box.maxY; y += delta) + { + for (real z = box.minZ; z <= box.maxZ; z += delta) + { + const uint index = grid->transCoordToIndex(x, y, z); + + const Vertex point(x, y, z); + + const char pointValue = triangle.isUnderFace(point); + + if (pointValue == NEGATIVE_DIRECTION_BORDER) + grid->setNodeTo(index, NEGATIVE_DIRECTION_BORDER); + else if (pointValue == INSIDE) + grid->setNodeTo(index, innerType); + } + } + } +} + +void PointUnderTriangleStrategy::findInsideNodes(GridImp* grid, char innerType) +{ + bool foundInsideNode = true; + while (foundInsideNode) + { + foundInsideNode = false; + for (uint index = 0; index < grid->getSize(); index++) + this->setInsideNode(grid, index, foundInsideNode, innerType); + } +} + +void PointUnderTriangleStrategy::setInsideNode(GridImp* grid, const uint &index, bool &insideNodeFound, char innerType) +{ + if (grid->isNode(index, NEGATIVE_DIRECTION_BORDER)) + return; + + if (!grid->isNode(index, innerType) && grid->nodeInNextCellIs(index, innerType)) + { + grid->setNodeTo(index, innerType); + insideNodeFound = true; + } +} + +void PointUnderTriangleStrategy::setNegativeDirBorderTo(GridImp* grid, const uint &index, char innerType) +{ + if (grid->isNode(index, NEGATIVE_DIRECTION_BORDER)) + grid->setNodeTo(index, innerType); +} \ No newline at end of file diff --git a/src/gpu/GridGenerator/geometries/TriangularMesh/TriangularMeshStrategy.h b/src/gpu/GridGenerator/geometries/TriangularMesh/TriangularMeshStrategy.h new file mode 100644 index 0000000000000000000000000000000000000000..573a464844ac769ebd1127c666481b87f363099f --- /dev/null +++ b/src/gpu/GridGenerator/geometries/TriangularMesh/TriangularMeshStrategy.h @@ -0,0 +1,101 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file TriangularMeshStrategy.h +//! \ingroup geometries +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#ifndef TriangularMeshStrategy_H +#define TriangularMeshStrategy_H + +#include "global.h" +#include "GridGenerator_export.h" + +class GridImp; +class TriangularMesh; +struct Triangle; + +class GRIDGENERATOR_EXPORT TriangularMeshDiscretizationStrategy +{ +public: + TriangularMeshDiscretizationStrategy() {} + virtual ~TriangularMeshDiscretizationStrategy() {} + + + void discretize(TriangularMesh* triangularMesh, GridImp* grid, char InnerType, char OuterType) + { + this->doDiscretize(triangularMesh, grid, InnerType, OuterType); + } + +private: + virtual void doDiscretize(TriangularMesh* triangularMesh, GridImp* grid, char InnerType, char OuterType) = 0; + void removeOddBoundaryCellNodes(GridImp* grid); +}; + + + +class GRIDGENERATOR_EXPORT PointInObjectDiscretizationStrategy : public TriangularMeshDiscretizationStrategy +{ +public: + PointInObjectDiscretizationStrategy() {} + virtual ~PointInObjectDiscretizationStrategy() {} + + virtual void doDiscretize(TriangularMesh* triangularMesh, GridImp* grid, char InnerType, char OuterType); +}; + +class GRIDGENERATOR_EXPORT RayCastingDiscretizationStrategy : public TriangularMeshDiscretizationStrategy +{ +public: + RayCastingDiscretizationStrategy() {} + virtual ~RayCastingDiscretizationStrategy() {} + + virtual void doDiscretize(TriangularMesh* triangularMesh, GridImp* grid, char InnerType, char OuterType); +}; + +class GRIDGENERATOR_EXPORT PointUnderTriangleStrategy : public TriangularMeshDiscretizationStrategy +{ +public: + PointUnderTriangleStrategy() {} + virtual ~PointUnderTriangleStrategy() {} + void doDiscretize(TriangularMesh* triangularMesh, GridImp* grid, char innerType, char outerType) override; + +private: + void meshReverse(Triangle& triangle, GridImp* grid, char innerType); + + void findInsideNodes(GridImp* grid, char innerType); + + void setInsideNode(GridImp* grid, const uint &index, bool &insideNodeFound, char innerType); + + void setNegativeDirBorderTo(GridImp* grid, const uint &index, char innerType); + +}; + + + +#endif + diff --git a/src/gpu/GridGenerator/geometries/TriangularMesh/triangleNeighborFinder/TriangleNeighborFinder.cpp b/src/gpu/GridGenerator/geometries/TriangularMesh/triangleNeighborFinder/TriangleNeighborFinder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..08984d872ebf07cbe1d88658b48a7850077f188f --- /dev/null +++ b/src/gpu/GridGenerator/geometries/TriangularMesh/triangleNeighborFinder/TriangleNeighborFinder.cpp @@ -0,0 +1,356 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file TriangleNeighborFinder.cpp +//! \ingroup geometries +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#include "TriangleNeighborFinder.h" +#include <omp.h> + +#include <GridGenerator/geometries/Triangle/Triangle.h> +#include <GridGenerator/geometries/TriangularMesh/TriangularMesh.h> + + + + +int compare2DArrayAccordingToXYZ(const void *pa, const void *pb) { + + real *a = *((real **)pa); + real *b = *((real **)pb); + + //compare X + if (a[IDS::x] < b[IDS::x]) return -1; + else if (a[IDS::x] > b[IDS::x]) return +1; + //compare Y + else if (a[IDS::y] < b[IDS::y]) return -1; + else if (a[IDS::y] > b[IDS::y]) return +1; + //compare Z + else if (a[IDS::z] < b[IDS::z]) return -1; + else if (a[IDS::z] > b[IDS::z]) return +1; + //compare Index + else if (a[IDS::vertexID] < b[IDS::vertexID]) return -1; + else if (a[IDS::vertexID] > b[IDS::vertexID]) return +1; + + return 0; +} + +int compare2DArrayAccordingToIndex(const void *pa, const void *pb) { + + real *a = *((real **)pa); + real *b = *((real **)pb); + + if (a[IDS::vertexID] < b[IDS::vertexID]) return -1; + else if (a[IDS::vertexID] > b[IDS::vertexID]) return +1; + return 0; +} + +TriangleNeighborFinder::TriangleNeighborFinder(Triangle *triangles, int size) : triangles(triangles) +{ + numberOfRows = size * DIMENSION; + + this->initalSortedInSpaceWithCoords(triangles, size); + + qsort(sortedInSpace, numberOfRows, sizeof sortedInSpace[0], compare2DArrayAccordingToXYZ); + + this->fillSortedInSpaceWithFirstVertexAndCoordinateIDs(numberOfRows); + + //copy the array: + sortedToTriangles = new real*[numberOfRows]; + for (int i = 0; i < numberOfRows; i++) { + sortedToTriangles[i] = new real[4]; + sortedToTriangles[i][IDS::vertexID] = sortedInSpace[i][IDS::vertexID]; + sortedToTriangles[i][IDS::firstVertexID] = sortedInSpace[i][IDS::firstVertexID]; + sortedToTriangles[i][IDS::coordinateID] = sortedInSpace[i][IDS::coordinateID]; + sortedToTriangles[i][IDS::uniqueCoordID] = (real)i; + } + + qsort(sortedToTriangles, numberOfRows, sizeof sortedToTriangles[0], compare2DArrayAccordingToIndex); + + indicesOfTriangleNeighbors.resize(size); + + this->fillVectorWithIndicesOfTriangleNeighbors(); +} + + +void TriangleNeighborFinder::initalSortedInSpaceWithCoords(Triangle *triangles, int size) +{ + sortedInSpace = new real*[numberOfRows]; + + int vertexCounter = 0; + const int numberOfColumns = 6; + for (int i = 0; i < size; i++){ + sortedInSpace[vertexCounter] = new real[numberOfColumns]; + sortedInSpace[vertexCounter][IDS::vertexID] = (real)vertexCounter; + sortedInSpace[vertexCounter][IDS::firstVertexID] = 0.0f; + sortedInSpace[vertexCounter][IDS::coordinateID] = 0.0f; + sortedInSpace[vertexCounter][IDS::x] = triangles[i].v1.x; + sortedInSpace[vertexCounter][IDS::y] = triangles[i].v1.y; + sortedInSpace[vertexCounter][IDS::z] = triangles[i].v1.z; + + vertexCounter++; + sortedInSpace[vertexCounter] = new real[numberOfColumns]; + sortedInSpace[vertexCounter][IDS::vertexID] = (real)vertexCounter; + sortedInSpace[vertexCounter][IDS::firstVertexID] = 0.0f; + sortedInSpace[vertexCounter][IDS::coordinateID] = 0.0f; + sortedInSpace[vertexCounter][IDS::x] = triangles[i].v2.x; + sortedInSpace[vertexCounter][IDS::y] = triangles[i].v2.y; + sortedInSpace[vertexCounter][IDS::z] = triangles[i].v2.z; + + vertexCounter++; + sortedInSpace[vertexCounter] = new real[numberOfColumns]; + sortedInSpace[vertexCounter][IDS::vertexID] = (real)vertexCounter; + sortedInSpace[vertexCounter][IDS::firstVertexID] = 0.0f; + sortedInSpace[vertexCounter][IDS::coordinateID] = 0.0f; + sortedInSpace[vertexCounter][IDS::x] = triangles[i].v3.x; + sortedInSpace[vertexCounter][IDS::y] = triangles[i].v3.y; + sortedInSpace[vertexCounter][IDS::z] = triangles[i].v3.z; + vertexCounter++; + } +} + +TriangleNeighborFinder::~TriangleNeighborFinder() +{ + for (int i = 0; i < numberOfRows; i++){ + delete[] sortedToTriangles[i]; + delete[] sortedInSpace[i]; + } + delete[] sortedToTriangles; + delete[] sortedInSpace; +} + +void TriangleNeighborFinder::fillSortedInSpaceWithFirstVertexAndCoordinateIDs(int numberOfRows) +{ + int firstVertexID = 0; + int compareID = 0; + int coordinateID = 0; + int duplicates = 0; + + while (firstVertexID < numberOfRows) { + Vertex a = Vertex(sortedInSpace[firstVertexID][IDS::x], sortedInSpace[firstVertexID][IDS::y], sortedInSpace[firstVertexID][IDS::z]); + Vertex b = Vertex(sortedInSpace[compareID][IDS::x], sortedInSpace[compareID][IDS::y], sortedInSpace[compareID][IDS::z]); + while (a.getEuclideanDistanceTo(b) < 1e-7) + { + sortedInSpace[compareID][IDS::firstVertexID] = sortedInSpace[firstVertexID][0]; + sortedInSpace[compareID][IDS::coordinateID] = (real)coordinateID; + duplicates++; + + compareID++; + if (compareID == numberOfRows) + break; + b = Vertex(sortedInSpace[compareID][IDS::x], sortedInSpace[compareID][IDS::y], sortedInSpace[compareID][IDS::z]); + } + firstVertexID += duplicates; + duplicates = 0; + coordinateID++; + } +} + +void TriangleNeighborFinder::fillVectorWithIndicesOfTriangleNeighbors() +{ + for (unsigned int triangleID = 0; triangleID < indicesOfTriangleNeighbors.size(); triangleID++){ + + Vertex coordinateIDsFromTriangle = getCoordinatesIDfromTriangle(triangleID); + + for (unsigned int vertex = 0; vertex < DIMENSION; vertex++){ + unsigned int vertexID = triangleID * DIMENSION + vertex; + unsigned int firstVertexID = (int)sortedToTriangles[vertexID][IDS::firstVertexID]; + unsigned int uniqueCoordID = (int)sortedToTriangles[firstVertexID][IDS::uniqueCoordID]; + + while (firstVertexID == sortedInSpace[uniqueCoordID][IDS::firstVertexID]){ + unsigned int jTriangle = findTriangleID(uniqueCoordID); + + uniqueCoordID++; + if (uniqueCoordID >= indicesOfTriangleNeighbors.size()*DIMENSION) + break; + if (jTriangle == triangleID) + continue; + + Vertex coordinateIDsFromTriangleNeighbor = getCoordinatesIDfromTriangle(jTriangle); + + if (isTriangleNeighborOfParentTriangle(coordinateIDsFromTriangle, coordinateIDsFromTriangleNeighbor) + && isNeighborNotAlreadyInside(triangleID, jTriangle)) + indicesOfTriangleNeighbors[triangleID].push_back(jTriangle); + } + + } + } +} + +unsigned int TriangleNeighborFinder::findTriangleID(unsigned int uniqueCoordID) +{ + return (int)sortedInSpace[uniqueCoordID][IDS::vertexID] / DIMENSION; +} + +Vertex TriangleNeighborFinder::getCoordinatesIDfromTriangle(int triangleID) +{ + real coordinateID1 = sortedToTriangles[triangleID * DIMENSION + 0][IDS::coordinateID]; + real coordinateID2 = sortedToTriangles[triangleID * DIMENSION + 1][IDS::coordinateID]; + real coordinateID3 = sortedToTriangles[triangleID * DIMENSION + 2][IDS::coordinateID]; + return Vertex(coordinateID1, coordinateID2, coordinateID3); +} + + +bool TriangleNeighborFinder::isTriangleNeighborOfParentTriangle(Vertex v1, Vertex v2) +{ + int countSameID = 0; + if (v1.x == v2.x) + countSameID++; + else if (v1.x == v2.y) + countSameID++; + else if (v1.x == v2.z) + countSameID++; + + if (v1.y == v2.x) + countSameID++; + else if (v1.y == v2.y) + countSameID++; + else if (v1.y == v2.z) + countSameID++; + + if (v1.z == v2.x) + countSameID++; + else if (v1.z == v2.y) + countSameID++; + else if (v1.z == v2.z) + countSameID++; + + if (countSameID == 2 || countSameID == 3) + return true; + + return false; +} + +bool TriangleNeighborFinder::isNeighborNotAlreadyInside(unsigned int iTriangle, unsigned int jTriangle) +{ + for (unsigned int i = 0; i < indicesOfTriangleNeighbors[iTriangle].size(); i++){ + if (indicesOfTriangleNeighbors[iTriangle][i] == jTriangle) + return false; + } + return true; +} + +void TriangleNeighborFinder::fillWithNeighborIndices(IntegerPtr2D *neighborIndices, Triangle *triangles) +{ + for (unsigned int i = 0; i < indicesOfTriangleNeighbors.size(); i++){ + int row = i * neighborIndices->DIM; + neighborIndices->ptr[row + 0] = neighborIndices->ptr[row + 1] = neighborIndices->ptr[row + 2] = -1; + for (unsigned int j = 0; j < indicesOfTriangleNeighbors[i].size(); j++){ + int index = triangles[i].getCommonEdge(triangles[indicesOfTriangleNeighbors[i][j]]); + neighborIndices->ptr[row + index] = indicesOfTriangleNeighbors[i][j]; + } + } +} + +void TriangleNeighborFinder::fillWithNeighborAngles(TriangularMesh *geom) const +{ + int j, index, indexNeighbor; + //#pragma omp parallel for private(j, row, index, indexNeighbor) shared(neighborAngles->ptr) + for (int i = 0; i < (int)indicesOfTriangleNeighbors.size(); i++){ + geom->triangles[i].alphaAngles[0] = geom->triangles[i].alphaAngles[1] = geom->triangles[i].alphaAngles[2] = 90.0f; + for (j = 0; j < (int)indicesOfTriangleNeighbors[i].size(); j++){ + indexNeighbor = indicesOfTriangleNeighbors[i][j]; + index = geom->triangles[i].getCommonEdge(geom->triangles[indexNeighbor]); + geom->triangles[i].alphaAngles[index] = geom->triangles[i].getHalfAngleBetweenToAdjacentTriangle(geom->triangles[indexNeighbor]); + } + } + + //for (size_t i = 0; i < neighborAngles->size; i++) + //{ + // int row = i * 3; + // printf("triangle : %d\n", i); + // for (size_t j = 0; j < 3; j++) + // { + // printf(" %d ", neighborAngles->ptr[row + j]); + // } + // printf("\n"); + //} +} + +std::vector<int> TriangleNeighborFinder::getTriangleIDsWithCommonVertex(int vertexID) const +{ + std::vector<int> triangleIDs; + + const int firstVertexId = sortedToTriangles[vertexID][IDS::firstVertexID]; + int uniqueCoordID = sortedToTriangles[firstVertexId][IDS::uniqueCoordID]; + const int coordinateID = sortedInSpace[uniqueCoordID][IDS::coordinateID]; + while (coordinateID == sortedInSpace[uniqueCoordID][IDS::coordinateID]) + { + int triangleID = sortedInSpace[uniqueCoordID][IDS::vertexID] / 3; + triangleIDs.push_back(triangleID); + uniqueCoordID++; + if (uniqueCoordID == numberOfRows) + break; + } + + return triangleIDs; +} + +std::vector< std::vector<Triangle> > TriangleNeighborFinder::getTrianglesPerVertex() const +{ + std::vector< std::vector<Triangle> > connected; + int uniqueCoordID = 0; + while (uniqueCoordID < numberOfRows) + { + std::vector<Triangle> triangles; + + int nextCoordinateID = this->sortedInSpace[uniqueCoordID][IDS::coordinateID]; + int currentCoordinateID = this->sortedInSpace[uniqueCoordID][IDS::coordinateID]; + while (nextCoordinateID == currentCoordinateID) + { + const int vertexID = this->sortedInSpace[uniqueCoordID][IDS::vertexID]; + const int triangleID = vertexID / 3; + triangles.push_back(this->triangles[triangleID]); + + uniqueCoordID++; + if (uniqueCoordID >= numberOfRows) + break; + currentCoordinateID = nextCoordinateID; + nextCoordinateID = this->sortedInSpace[uniqueCoordID][IDS::coordinateID]; + } + connected.push_back(triangles); + } + return connected; +} + + +void TriangleNeighborFinder::printSortedToTriangles() const +{ + printf("VertexID | FirstVertexID | CoordID | UniqueCoordID\n"); + for (int row = 0; row < numberOfRows; row++) { + printf("%d \t %d \t %d \t %d\n", int(sortedToTriangles[row][IDS::vertexID]), int(sortedToTriangles[row][IDS::firstVertexID]), int(sortedToTriangles[row][IDS::coordinateID]), int(sortedToTriangles[row][IDS::uniqueCoordID])); + } +} + +void TriangleNeighborFinder::printSortedInSpace() const +{ + printf("VertexID | X | Y | Z | FirstVertexID | CoordID | UniqueCoordID\n"); + for (int row = 0; row < numberOfRows; row++) { + printf("%d \t %2.2f \t %2.2f \t %2.2f \t %d \t %d \t %d\n", int(sortedInSpace[row][IDS::vertexID]), sortedInSpace[row][IDS::x], sortedInSpace[row][IDS::y], sortedInSpace[row][IDS::z], int(sortedInSpace[row][IDS::firstVertexID]), int(sortedInSpace[row][IDS::coordinateID]), int(sortedInSpace[row][IDS::uniqueCoordID])); + } +} diff --git a/src/gpu/GridGenerator/geometries/TriangularMesh/triangleNeighborFinder/TriangleNeighborFinder.h b/src/gpu/GridGenerator/geometries/TriangularMesh/triangleNeighborFinder/TriangleNeighborFinder.h new file mode 100644 index 0000000000000000000000000000000000000000..b0dda279c5f95a621b5875e78b5cdb7479b98a54 --- /dev/null +++ b/src/gpu/GridGenerator/geometries/TriangularMesh/triangleNeighborFinder/TriangleNeighborFinder.h @@ -0,0 +1,88 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file TriangleNeighborFinder.h +//! \ingroup geometries +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#ifndef TriangleNeighborFinder_h +#define TriangleNeighborFinder_h + +#include "GridGenerator/global.h" +#include "GridGenerator_export.h" +#include <vector> + +struct IDS { + enum IDs { vertexID = 0, firstVertexID = 1, coordinateID = 2, uniqueCoordID = 3, x = 3, y = 4, z = 5 }; +}; + +struct Triangle; +struct Vertex; +class TriangularMesh; + +struct IntegerPtr2D { + int *ptr; + int size; + int DIM; +}; + +class TriangleNeighborFinder +{ +public: + GRIDGENERATOR_EXPORT TriangleNeighborFinder(Triangle *triangles, int size); + GRIDGENERATOR_EXPORT ~TriangleNeighborFinder(); + + std::vector<int> getTriangleIDsWithCommonVertex(int vertexID) const; + std::vector< std::vector<Triangle> > getTrianglesPerVertex() const; + + void GRIDGENERATOR_EXPORT fillWithNeighborIndices(IntegerPtr2D *indices, Triangle *triangles); + void GRIDGENERATOR_EXPORT fillWithNeighborAngles(TriangularMesh *geom) const; + + void printSortedToTriangles() const; + void printSortedInSpace() const; + +private: + void initalSortedInSpaceWithCoords(Triangle *triangles_ptr, int size); + void fillSortedInSpaceWithFirstVertexAndCoordinateIDs(int numberOfRows); + void fillVectorWithIndicesOfTriangleNeighbors(); + unsigned int findTriangleID(unsigned int uniqueCoordID); + Vertex getCoordinatesIDfromTriangle(int triangleID); + bool isNeighborNotAlreadyInside(unsigned int iTriangle, unsigned int jTriangle); + + bool isTriangleNeighborOfParentTriangle(Vertex, Vertex); + + int numberOfRows; + Triangle *triangles; + +public: + std::vector<std::vector<uint> > indicesOfTriangleNeighbors; + real **sortedToTriangles; + real **sortedInSpace; +}; + +#endif diff --git a/src/gpu/GridGenerator/geometries/TriangularMesh/triangleRefinement/TriangleRefinement.cpp b/src/gpu/GridGenerator/geometries/TriangularMesh/triangleRefinement/TriangleRefinement.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c1babac2324e80362c62c2b448cd1e309d7c5adf --- /dev/null +++ b/src/gpu/GridGenerator/geometries/TriangularMesh/triangleRefinement/TriangleRefinement.cpp @@ -0,0 +1,249 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file TriangleRefinement.cpp +//! \ingroup geometries +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#include "TriangleRefinement.h" + +#include <GridGenerator/geometries/Triangle/Triangle.h> + +TriangleRefinement::TriangleRefinement(std::vector<Triangle> *triangles) +{ + this->triangles = triangles; +} + +TriangleRefinement::~TriangleRefinement() +{ + +} + +void TriangleRefinement::redoubleTriangles() +{ + int counter = 0; + for (size_t i = 0; i < triangles->size(); i++) + { + refine((int)i); + counter++; + if (counter % 50 == 0) + printf("triangle refine: %d\n", (counter / 2)); + } +} + +void TriangleRefinement::refineUntilMinDistance(double d_min) +{ + double d = 10e9; + int counter = 0; + + while (d > d_min) { + int triangleToRefine = findIndexFromTriangleWithLongestEdge(&d); + refine(triangleToRefine); + + counter++; + if (counter % 50 == 0) + printf("triangle refine: %d, actual dMAX = %2.6f, d_min = %2.6f\n", counter, d, d_min); + + } +} + +void TriangleRefinement::refineUntilcountTriangle(int countTri) +{ + double d = 10e9; + int counter = 0; + + while (counter < countTri) { + int triangleToRefine = findIndexFromTriangleWithLongestEdge(&d); + refine(triangleToRefine); + + counter++; + if (counter % 100 == 0) + printf("triangle refine: %d, countTri = %d\n", counter, countTri); + } +} + +int TriangleRefinement::findIndexFromTriangleWithLongestEdge(double *d) +{ + *d = 0; + double dTemp; + int triangleToRefine = 0; + for (size_t i = 0; i < triangles->size(); i++) + { + dTemp = getLongestEdgeDistance((*triangles)[i]); + if (*d < dTemp) { + *d = dTemp; + triangleToRefine = (int)i; + } + } + return triangleToRefine; +} + + +void TriangleRefinement::refine(int iTriangle) +{ + sortNeighborIndices(); + + Triangle t = (*triangles)[iTriangle]; + int edge = getEdgeWithLongestDistance(t); + + std::vector<Vertex> v = getVertexArray(iTriangle); + Vertex newVertex = getNewhalfVertexFromTrianglesEdge(v, edge); + + createTwoTriangles(v, edge, newVertex); + + int indexNeighbor = this->indices.ptr[iTriangle * indices.DIM + edge]; + v = getVertexArray(indexNeighbor); + int commonEdgeNeigbor = findCommonEdgeFromTriangles(indexNeighbor, iTriangle); + createTwoTriangles(v, commonEdgeNeigbor, newVertex); + + eraseOldTrianglesFromVector(iTriangle, indexNeighbor); +} + +void TriangleRefinement::sortNeighborIndices() +{ + indices.DIM = 3; + indices.size = (int)triangles->size(); + indices.ptr = new int[indices.DIM * indices.size]; + TriangleNeighborFinder neighbors((*triangles).data(), indices.size); + neighbors.fillWithNeighborIndices(&indices, (*triangles).data()); +} + +std::vector<Vertex> TriangleRefinement::getVertexArray(int iTriangle) +{ + Triangle t = (*triangles)[iTriangle]; + + std::vector<Vertex> v; + v.resize(4); + v[0] = t.v1; + v[1] = t.v2; + v[2] = t.v3; + v[3] = t.normal; + return v; +} + +Vertex TriangleRefinement::getNewhalfVertexFromTrianglesEdge(std::vector<Vertex> v, int edge) +{ + return getHalfVertex(v[edge], v[edge == 2 ? 0 : edge + 1]); +} + +void TriangleRefinement::createTwoTriangles(std::vector<Vertex> v, int edge, Vertex newEdge) +{ + Vertex againstNewEdge = v[edge - 1 < 0 ? 2 : edge - 1]; + Vertex firstOldVertex = v[edge]; + Vertex secondOldVertex = v[edge + 1 > 2 ? 0 : edge + 1]; + + Triangle firstNewTriangle(newEdge, againstNewEdge, firstOldVertex, v[3]); + Triangle secondNewTriangle(newEdge, secondOldVertex, againstNewEdge, v[3]); + + (*triangles).push_back(firstNewTriangle); + (*triangles).push_back(secondNewTriangle); +} + +int TriangleRefinement::findCommonEdgeFromTriangles(int indexNeighbor, int iTriangle) +{ + int commonEdgeNeigbor = -1; + for (int i = 0; i < indices.DIM; i++) { + if (indices.ptr[indexNeighbor * indices.DIM + i] == iTriangle) + commonEdgeNeigbor = i; + } + return commonEdgeNeigbor; +} + +void TriangleRefinement::eraseOldTrianglesFromVector(int iTriangle, int indexNeighbor) +{ + (*triangles).erase((*triangles).begin() + iTriangle); + if (iTriangle < indexNeighbor) + indexNeighbor--; + (*triangles).erase((*triangles).begin() + indexNeighbor); +} + +void TriangleRefinement::refine(Triangle t, Triangle &firstNewTriangle, Triangle &secondNewTriangle) +{ + int edge = getEdgeWithLongestDistance(t); + + std::vector<Vertex> v; + v.resize(4); + v[0] = t.v1; + v[1] = t.v2; + v[2] = t.v3; + v[3] = t.normal; + Vertex newEdge = getHalfVertex(v[edge], v[edge == 2 ? 0 : edge + 1]); + + Vertex againstNewEdge = v[edge - 1 < 0 ? 2 : edge - 1]; + Vertex firstOldVertex = v[edge]; + Vertex secondOldVertex = v[edge + 1 > 2 ? 0 : edge + 1]; + + firstNewTriangle = Triangle(newEdge, againstNewEdge, firstOldVertex, v[3]); + secondNewTriangle = Triangle(newEdge, secondOldVertex, againstNewEdge, v[3]); +} + + +int TriangleRefinement::getEdgeWithLongestDistance(Triangle &t) +{ + real d1 = t.v2.getEuclideanDistanceTo(t.v1); + real d2 = t.v3.getEuclideanDistanceTo(t.v2); + real d3 = t.v1.getEuclideanDistanceTo(t.v3); + + real max = d1; + int edge = 0; + + if (d2 > d1) { + edge = 1; + max = d2; + } + + if (d3 > max){ + edge = 2; + max = d3; + } + + return edge; +} + +real TriangleRefinement::getLongestEdgeDistance(Triangle &t) { + + int edge = getEdgeWithLongestDistance(t); + Vertex v[3]; + v[0] = t.v1; + v[1] = t.v2; + v[2] = t.v3; + + if (edge == 2) + return v[0].getEuclideanDistanceTo(v[2]); + + return v[edge + 1].getEuclideanDistanceTo(v[edge]); +} + +Vertex TriangleRefinement::getHalfVertex(const Vertex &v, const Vertex &w) +{ + Vertex r; + r.x = (v.x + w.x) / 2.0f; + r.y = (v.y + w.y) / 2.0f; + r.z = (v.z + w.z) / 2.0f; + return r; +} diff --git a/src/gpu/GridGenerator/geometries/TriangularMesh/triangleRefinement/TriangleRefinement.h b/src/gpu/GridGenerator/geometries/TriangularMesh/triangleRefinement/TriangleRefinement.h new file mode 100644 index 0000000000000000000000000000000000000000..a9c5262fbf0ee701e26885fb54d96cd079038a87 --- /dev/null +++ b/src/gpu/GridGenerator/geometries/TriangularMesh/triangleRefinement/TriangleRefinement.h @@ -0,0 +1,79 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file TriangleRefinement.h +//! \ingroup geometries +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#ifndef TriangleRefinement_h +#define TriangleRefinement_h + +#include <vector> + +#include "global.h" + +#include "geometries/TriangularMesh/triangleNeighborFinder/TriangleNeighborFinder.h" + +struct Triangle; +struct Vertex; +struct IntegerPtr2D; + +class TriangleRefinement +{ +public: + GRIDGENERATOR_EXPORT TriangleRefinement(std::vector<Triangle> *triangles); + GRIDGENERATOR_EXPORT ~TriangleRefinement(); + + void GRIDGENERATOR_EXPORT refine(int iTriangle); + static void GRIDGENERATOR_EXPORT refine(Triangle t, Triangle &firstNewTriangle, Triangle &secondNewTriangle); + + void GRIDGENERATOR_EXPORT refineUntilMinDistance(double d_min); + void GRIDGENERATOR_EXPORT refineUntilcountTriangle(int countTri); + void GRIDGENERATOR_EXPORT redoubleTriangles(); + + static GRIDGENERATOR_EXPORT Vertex getHalfVertex(const Vertex &v, const Vertex &w); + +private: + std::vector<Triangle> *triangles; + IntegerPtr2D indices; + + int findIndexFromTriangleWithLongestEdge(double *d); + std::vector<Vertex> getVertexArray(int iTriangle); + Vertex getNewhalfVertexFromTrianglesEdge(std::vector<Vertex> v, int edge); + void sortNeighborIndices(); + void createTwoTriangles(std::vector<Vertex> v, int edge, Vertex newEdge); + void eraseOldTrianglesFromVector(int iTriangle, int indexNeighbor); + int findCommonEdgeFromTriangles(int indexNeighbor, int iTriangle); + +public: + static int GRIDGENERATOR_EXPORT getEdgeWithLongestDistance(Triangle &t); + static real GRIDGENERATOR_EXPORT getLongestEdgeDistance(Triangle &t); +}; + + +#endif diff --git a/src/gpu/GridGenerator/geometries/Vertex/Vertex.cu b/src/gpu/GridGenerator/geometries/Vertex/Vertex.cpp similarity index 96% rename from src/gpu/GridGenerator/geometries/Vertex/Vertex.cu rename to src/gpu/GridGenerator/geometries/Vertex/Vertex.cpp index 23d49efa9d350a3a56ff754f33c0a7eb2351a974..5fe27a28b8833a3f7a5bdcc73b9863e82b3ea973 100644 --- a/src/gpu/GridGenerator/geometries/Vertex/Vertex.cu +++ b/src/gpu/GridGenerator/geometries/Vertex/Vertex.cpp @@ -26,7 +26,7 @@ // You should have received a copy of the GNU General Public License along // with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. // -//! \file Vertex.cu +//! \file Vertex.cpp //! \ingroup geometries //! \author Soeren Peters, Stephan Lenz //======================================================================================= @@ -37,14 +37,7 @@ Vertex::Vertex(real x, real y, real z) : x(x), y(y), z(z){} Vertex::Vertex() { x = 0.0f; y = 0.0f; z = 0.0f; } -Vertex::Vertex(const Vertex& v) -{ - this->x = v.x; - this->y = v.y; - this->z = v.z; -} - - real Vertex::getEuclideanDistanceTo(const Vertex &w) const +real Vertex::getEuclideanDistanceTo(const Vertex &w) const { return vf::Math::sqrtReal((x - w.x)*(x - w.x) + (y - w.y)*(y - w.y) + (z - w.z)*(z - w.z)); } @@ -120,7 +113,7 @@ real Vertex::getInnerAngle(const Vertex &w) const real mag = this->getMagnitude() * w.getMagnitude(); real skal = *this * w; - if (mag - fabs(skal) < 0.0001) + if (mag - std::abs(skal) < 0.0001) return 0.0f; return vf::Math::acosReal(skal / mag) * 180.0f / vf::Math::acosReal(-1.0f); // acos(-1.0f) = PI } diff --git a/src/gpu/GridGenerator/geometries/Vertex/Vertex.h b/src/gpu/GridGenerator/geometries/Vertex/Vertex.h index 824f89c77a630ef8e12dd5332bf462afa96ec342..7b27d853f652459143699204c59a5843de6eaf39 100644 --- a/src/gpu/GridGenerator/geometries/Vertex/Vertex.h +++ b/src/gpu/GridGenerator/geometries/Vertex/Vertex.h @@ -34,7 +34,6 @@ #define VERTEX_H #include <stdio.h> -#include <cuda_runtime.h> #include <memory> #include <ostream> @@ -47,7 +46,6 @@ public: Vertex(real x, real y, real z); Vertex(); - Vertex(const Vertex& v); ~Vertex() {} real getEuclideanDistanceTo(const Vertex &w) const; diff --git a/src/gpu/GridGenerator/geometries/VerticalCylinder/VerticalCylinder.cpp b/src/gpu/GridGenerator/geometries/VerticalCylinder/VerticalCylinder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..89bcd50349fe1a7591c5a873b5924a0c8ce8c2f3 --- /dev/null +++ b/src/gpu/GridGenerator/geometries/VerticalCylinder/VerticalCylinder.cpp @@ -0,0 +1,122 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file VerticalCylinder.cpp +//! \ingroup geometries +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#include "VerticalCylinder.h" + +VerticalCylinder::VerticalCylinder(const double& centerX, const double& centerY, const double& centerZ, const double& radius, const double& height) + : centerX(centerX), centerY(centerY), centerZ(centerZ), radius(radius), height(height) +{ + +} + +VerticalCylinder::~VerticalCylinder() +{ +} + +SPtr<VerticalCylinder> VerticalCylinder::makeShared(double centerX, double centerY, double centerZ, double radius, double height) +{ + return SPtr<VerticalCylinder>(new VerticalCylinder(centerX, centerY, centerZ, radius, height)); +} + +Object* VerticalCylinder::clone() const +{ + return new VerticalCylinder(centerX, centerY, centerZ, radius, height); +} + +double VerticalCylinder::getX1Centroid() +{ + return centerX; +} + +double VerticalCylinder::getX1Minimum() +{ + return centerX - radius; +} + +double VerticalCylinder::getX1Maximum() +{ + return centerX + radius; +} + +double VerticalCylinder::getX2Centroid() +{ + return centerY; +} + +double VerticalCylinder::getX2Minimum() +{ + return centerY - radius; +} + +double VerticalCylinder::getX2Maximum() +{ + return centerY + radius; +} + +double VerticalCylinder::getX3Centroid() +{ + return centerZ; +} + +double VerticalCylinder::getX3Minimum() +{ + return centerZ - 0.5 * height; +} + +double VerticalCylinder::getX3Maximum() +{ + return centerZ + 0.5 * height; +} + +bool VerticalCylinder::isPointInObject(const double& x1, const double& x2, const double& x3, const double& minOffset, const double& maxOffset) +{ + double offset = maxOffset; + if (x1 < centerX || x2 < centerY || x3 < centerZ) + offset = minOffset; + + + const double deltaX1 = x1 - centerX; + const double deltaX2 = x2 - centerY; + const double deltaX3 = x3 - centerZ; + + if( deltaX3 > 0.5 * height || deltaX3 < - 0.5 * height ) + return false; + + return (deltaX1*deltaX1 + deltaX2*deltaX2) < ((this->radius - offset) * (this->radius - offset)); +} + + +void VerticalCylinder::scale(double delta) +{ + this->radius += delta; + this->height += delta; +} diff --git a/src/gpu/GridGenerator/geometries/VerticalCylinder/VerticalCylinder.h b/src/gpu/GridGenerator/geometries/VerticalCylinder/VerticalCylinder.h new file mode 100644 index 0000000000000000000000000000000000000000..24d9383bf5628e46b1d634874f79ceb73eaa6cae --- /dev/null +++ b/src/gpu/GridGenerator/geometries/VerticalCylinder/VerticalCylinder.h @@ -0,0 +1,76 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file VerticalCylinder.h +//! \ingroup geometries +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#ifndef VERTICAL_CYLINDER_H +#define VERTICAL_CYLINDER_H + +#include "global.h" +#include "GridGenerator_export.h" +#include "geometries/Object.h" + +class GRIDGENERATOR_EXPORT VerticalCylinder : public Object +{ +public: + VerticalCylinder(const double& centerX, const double& centerY, const double& centerZ, const double& radius, const double& height); + virtual ~VerticalCylinder(); + + static SPtr<VerticalCylinder> makeShared(double centerX, double centerY, double centerZ, double radius, double height); + + Object* clone() const override; + + double getX1Centroid() override; + double getX1Minimum() override; + double getX1Maximum() override; + double getX2Centroid() override; + double getX2Minimum() override; + double getX2Maximum() override; + double getX3Centroid() override; + double getX3Minimum() override; + double getX3Maximum() override; + + bool isPointInObject(const double& x1, const double& x2, const double& x3, const double& minOffset, const double& maxOffset) override; + + + void scale(double delta) override; + +protected: + double centerX; + double centerY; + double centerZ; + + double radius; + double height; +}; + + + +#endif diff --git a/src/gpu/GridGenerator/grid/BoundaryConditions/BoundaryCondition.cpp b/src/gpu/GridGenerator/grid/BoundaryConditions/BoundaryCondition.cpp index 4081aeffd9165e838959c78e39c9b51d6082c4a7..8930bdf3b165b4e0dbb497773fd0b6cf6ec6f8f7 100644 --- a/src/gpu/GridGenerator/grid/BoundaryConditions/BoundaryCondition.cpp +++ b/src/gpu/GridGenerator/grid/BoundaryConditions/BoundaryCondition.cpp @@ -42,6 +42,19 @@ bool gg::BoundaryCondition::isSide( SideType side ) const return this->side->whoAmI() == side; } +void VelocityBoundaryCondition::setVelocityProfile( + SPtr<Grid> grid, std::function<void(real, real, real, real &, real &, real &)> velocityProfile) +{ + for (uint index = 0; index < this->indices.size(); index++) { + + real x, y, z; + + grid->transIndexToCoords(this->indices[index], x, y, z); + + velocityProfile(x, y, z, this->vxList[index], this->vyList[index], this->vzList[index]); + } +} + void GeometryBoundaryCondition::setTangentialVelocityForPatch(SPtr<Grid> grid, uint patch, real p1x, real p1y, real p1z, real p2x, real p2y, real p2z, diff --git a/src/gpu/GridGenerator/grid/BoundaryConditions/BoundaryCondition.h b/src/gpu/GridGenerator/grid/BoundaryConditions/BoundaryCondition.h index 28570b46e2bdf92f88cb7696cc7748c767957afb..9ae5f09e208e92213ca90ff75f095eddd5dbeaf1 100644 --- a/src/gpu/GridGenerator/grid/BoundaryConditions/BoundaryCondition.h +++ b/src/gpu/GridGenerator/grid/BoundaryConditions/BoundaryCondition.h @@ -28,12 +28,13 @@ // //! \file BoundaryCondition.h //! \ingroup grid -//! \author Soeren Peters, Stephan Lenz +//! \author Soeren Peters, Stephan Lenz, Martin Schoenherr //======================================================================================= #ifndef BoundaryCondition_H #define BoundaryCondition_H #include <vector> +#include <functional> #include "global.h" @@ -86,7 +87,7 @@ protected: public: char getType() const override { - return BC_PRESSURE; + return vf::gpu::BC_PRESSURE; } real getRho() @@ -113,7 +114,7 @@ protected: public: virtual char getType() const override { - return BC_SLIP; + return vf::gpu::BC_SLIP; } void fillSlipNormalLists() @@ -153,7 +154,7 @@ protected: public: virtual char getType() const override { - return BC_VELOCITY; + return vf::gpu::BC_VELOCITY; } void fillVelocityLists() @@ -173,6 +174,8 @@ public: real getVx(uint index) { return this->vxList[index]; } real getVy(uint index) { return this->vyList[index]; } real getVz(uint index) { return this->vzList[index]; } + + void setVelocityProfile( SPtr<Grid> grid, std::function<void(real,real,real,real&,real&,real&)> velocityProfile ); }; ////////////////////////////////////////////////////////////////////////// @@ -192,7 +195,7 @@ private: public: char getType() const override { - return BC_SOLID; + return vf::gpu::BC_SOLID; } void setVelocityForPatch( uint patch, real vx, real vy, real vz ){ diff --git a/src/gpu/GridGenerator/grid/BoundaryConditions/Side.cpp b/src/gpu/GridGenerator/grid/BoundaryConditions/Side.cpp index 99097a393735a31abad0dd717a2dcfc2b1d35326..02d61a83456090a3b96b207de5761b70d9b30fca 100644 --- a/src/gpu/GridGenerator/grid/BoundaryConditions/Side.cpp +++ b/src/gpu/GridGenerator/grid/BoundaryConditions/Side.cpp @@ -49,11 +49,11 @@ void Side::addIndices(SPtr<Grid> grid, SPtr<BoundaryCondition> boundaryCondition { const uint index = getIndex(grid, coord, constant, v1, v2); - if ((index != INVALID_INDEX) && ( grid->getFieldEntry(index) == FLUID - || grid->getFieldEntry(index) == FLUID_CFC - || grid->getFieldEntry(index) == FLUID_CFF - || grid->getFieldEntry(index) == FLUID_FCC - || grid->getFieldEntry(index) == FLUID_FCF ) ) + if ((index != INVALID_INDEX) && ( grid->getFieldEntry(index) == vf::gpu::FLUID + || grid->getFieldEntry(index) == vf::gpu::FLUID_CFC + || grid->getFieldEntry(index) == vf::gpu::FLUID_CFF + || grid->getFieldEntry(index) == vf::gpu::FLUID_FCC + || grid->getFieldEntry(index) == vf::gpu::FLUID_FCF ) ) { grid->setFieldEntry(index, boundaryCondition->getType()); boundaryCondition->indices.push_back(index); @@ -107,9 +107,9 @@ void Side::setQs(SPtr<Grid> grid, SPtr<BoundaryCondition> boundaryCondition, uin uint neighborIndex = grid->transCoordToIndex( x, y, z ); - if( grid->getFieldEntry(neighborIndex) == STOPPER_OUT_OF_GRID_BOUNDARY || - grid->getFieldEntry(neighborIndex) == STOPPER_OUT_OF_GRID || - grid->getFieldEntry(neighborIndex) == STOPPER_SOLID ) + if( grid->getFieldEntry(neighborIndex) == vf::gpu::STOPPER_OUT_OF_GRID_BOUNDARY || + grid->getFieldEntry(neighborIndex) == vf::gpu::STOPPER_OUT_OF_GRID || + grid->getFieldEntry(neighborIndex) == vf::gpu::STOPPER_SOLID ) qNode[dir] = 0.5; else qNode[dir] = -1.0; diff --git a/src/gpu/GridGenerator/grid/Field.cu b/src/gpu/GridGenerator/grid/Field.cpp similarity index 94% rename from src/gpu/GridGenerator/grid/Field.cu rename to src/gpu/GridGenerator/grid/Field.cpp index 6067cb66e7e56ff7fa5a4aae0ec197298d9172ca..d8ac2a80ea6fc5da879c5378aac2eab70016ff72 100644 --- a/src/gpu/GridGenerator/grid/Field.cu +++ b/src/gpu/GridGenerator/grid/Field.cpp @@ -26,38 +26,29 @@ // You should have received a copy of the GNU General Public License along // with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. // -//! \file Field.cu +//! \file Field.cpp //! \ingroup grid -//! \author Soeren Peters, Stephan Lenz +//! \author Soeren Peters, Stephan Lenz, Martin Schoenherr //======================================================================================= #include "Field.h" #include "grid/NodeValues.h" -#include "grid/GridStrategy/GridStrategy.h" -Field::Field(SPtr<GridStrategy> gridStrategy, uint size) : gridStrategy(gridStrategy), size(size) -{ - -} - -Field::Field() -{ - -} +using namespace vf::gpu; -Field::~Field() +Field::Field(uint size) : size(size) { } void Field::allocateMemory() { - gridStrategy->allocateFieldMemory(this); + this->field = new char[this->size]; } void Field::freeMemory() { - gridStrategy->freeFieldMemory(this); + delete[] this->field; } // --------------------------------------------------------- // @@ -132,6 +123,11 @@ bool Field::isStopper(uint index) const return isStopperOutOfGrid(index) || isStopperCoarseUnderFine(index) || isStopperSolid(index) || is(index, STOPPER_OUT_OF_GRID_BOUNDARY); } +bool Field::isQ(uint index) const +{ + return field[index] == Q_DEPRECATED; +} + bool Field::isBoundaryConditionNode(uint index) const { return field[index] == BC_SOLID || field[index] == BC_OUTFLOW || field[index] == BC_VELOCITY || field[index] == BC_PRESSURE || field[index] == BC_SLIP; diff --git a/src/gpu/GridGenerator/grid/Field.h b/src/gpu/GridGenerator/grid/Field.h index 8b66c56d8fc50f4b7caa99f43a1e4ab73451305b..002c8c108bd405f4077cd2779f5e59232135ace9 100644 --- a/src/gpu/GridGenerator/grid/Field.h +++ b/src/gpu/GridGenerator/grid/Field.h @@ -28,7 +28,7 @@ // //! \file Field.h //! \ingroup grid -//! \author Soeren Peters, Stephan Lenz +//! \author Soeren Peters, Stephan Lenz, Martin Schoenherr //======================================================================================= #ifndef FIELD_H #define FIELD_H @@ -36,14 +36,12 @@ #include "global.h" struct Vertex; -class GridStrategy; class GRIDGENERATOR_EXPORT Field : public enableSharedFromThis<Field> { public: - Field(SPtr<GridStrategy> gridStrategy, uint size); - Field(); - ~Field(); + Field(uint size); + Field() = default; void allocateMemory(); void freeMemory(); @@ -55,6 +53,7 @@ public: bool isFineToCoarseNode(uint index) const; bool isFluid(uint index) const; bool isInvalidSolid(uint index) const; + bool isQ(uint index) const; bool isBoundaryConditionNode(uint index) const; bool isInvalidCoarseUnderFine(uint index) const; bool isStopperOutOfGrid(uint index) const; @@ -73,13 +72,8 @@ public: void setFieldEntryToInvalidOutOfGrid(uint index); private: - SPtr<GridStrategy> gridStrategy; - char *field; uint size; - - friend class GridGpuStrategy; - friend class GridCpuStrategy; }; #endif diff --git a/src/gpu/GridGenerator/grid/Grid.h b/src/gpu/GridGenerator/grid/Grid.h index 1582c0bb6c1243d8f162c4240d498ca0e46e6a48..3407b23c1efbb4143d06ded7880c26d7c0eb6599 100644 --- a/src/gpu/GridGenerator/grid/Grid.h +++ b/src/gpu/GridGenerator/grid/Grid.h @@ -28,7 +28,7 @@ // //! \file Grid.h //! \ingroup grid -//! \author Soeren Peters, Stephan Lenz +//! \author Soeren Peters, Stephan Lenz, Martin Schönherr //======================================================================================= #ifndef GRID_H #define GRID_H @@ -41,9 +41,9 @@ #include "grid/Cell.h" +class TriangularMesh; struct Vertex; struct Triangle; -class GridStrategy; class GridInterface; class Object; class BoundingBox; @@ -51,7 +51,7 @@ class BoundingBox; class GRIDGENERATOR_EXPORT Grid { public: - virtual ~Grid() {} + virtual ~Grid() = default; virtual const Object* getObject() const = 0; @@ -67,32 +67,66 @@ public: virtual real getEndY() const = 0; virtual real getEndZ() const = 0; + virtual Vertex getMinimumOnNode(Vertex exact) const = 0; + virtual Vertex getMaximumOnNode(Vertex exact) const = 0; + virtual uint getNumberOfNodesX() const = 0; virtual uint getNumberOfNodesY() const = 0; virtual uint getNumberOfNodesZ() const = 0; - virtual int getSparseIndex(uint matrixIndex) const = 0; + virtual uint getNumberOfNodesCF() const = 0; + virtual uint getNumberOfNodesFC() const = 0; + + virtual int getSparseIndex(uint matrixIndex) const = 0; virtual char getFieldEntry(uint matrixIndex) const = 0; virtual void setFieldEntry(uint matrixIndex, char type) = 0; + virtual void getGridInterfaceIndices(uint* iCellCfc, uint* iCellCff, uint* iCellFcc, uint* iCellFcf) const = 0; + virtual int *getNeighborsX() const = 0; virtual int *getNeighborsY() const = 0; virtual int *getNeighborsZ() const = 0; virtual int *getNeighborsNegative() const = 0; - virtual real* getDistribution() const = 0; + virtual uint *getCF_coarse() const = 0; + virtual uint *getCF_fine() const = 0; + virtual uint *getCF_offset() const = 0; + + virtual uint *getFC_coarse() const = 0; + virtual uint *getFC_fine() const = 0; + virtual uint *getFC_offset() const = 0; + + virtual real *getDistribution() const = 0; virtual int* getDirection() const = 0; virtual int getStartDirection() const = 0; virtual int getEndDirection() const = 0; virtual void getNodeValues(real *xCoords, real *yCoords, real *zCoords, uint *neighborX, uint *neighborY, uint *neighborZ, uint *neighborNegative, uint *geo) const = 0; - virtual SPtr<GridStrategy> getGridStrategy() const = 0; virtual void transIndexToCoords(uint index, real &x, real &y, real &z) const = 0; virtual uint transCoordToIndex(const real &x, const real &y, const real &z) const = 0; virtual void inital(const SPtr<Grid> fineGrid, uint numberOfLayers) = 0; + virtual void setOddStart(bool xOddStart, bool yOddStart, bool zOddStart) = 0; + + virtual void findGridInterface(SPtr<Grid> grid, LbmOrGks lbmOrGks) = 0; + + virtual void repairGridInterfaceOnMultiGPU(SPtr<Grid> fineGrid) = 0; + + virtual void limitToSubDomain(SPtr<BoundingBox> subDomainBox, LbmOrGks lbmOrGks) = 0; + + virtual void enableFindSolidBoundaryNodes() = 0; + virtual void enableComputeQs() = 0; + + virtual void mesh(TriangularMesh &geometry) = 0; + virtual void mesh(Object *object) = 0; + + virtual void closeNeedleCells() = 0; + virtual void closeNeedleCellsThinWall() = 0; + + virtual void findQs(Object *object) = 0; + virtual void setPeriodicity(bool periodicityX, bool periodicityY, bool periodicityZ) = 0; virtual void setPeriodicityX(bool periodicity) = 0; virtual void setPeriodicityY(bool periodicity) = 0; @@ -102,6 +136,8 @@ public: virtual bool getPeriodicityY() = 0; virtual bool getPeriodicityZ() = 0; + virtual void setEnableFixRefinementIntoTheWall(bool enableFixRefinementIntoTheWall) = 0; + virtual void freeMemory() = 0; virtual bool nodeInCellIs(Cell& cell, char type) const = 0; @@ -110,6 +146,27 @@ public: virtual real getFirstFluidNode(real coords[3], int direction, real startCoord) const = 0; virtual real getLastFluidNode(real coords[3], int direction, real startCoord) const = 0; + + virtual uint getNumberOfSolidBoundaryNodes() const = 0; + virtual void setNumberOfSolidBoundaryNodes(uint numberOfSolidBoundaryNodes) = 0; + + virtual real getQValue(const uint index, const uint dir) const = 0; + virtual uint getQPatch(const uint index) const = 0; + + virtual void setInnerRegionFromFinerGrid(bool innerRegionFromFinerGrid) = 0; + + virtual void setNumberOfLayers(uint numberOfLayers) = 0; + + virtual void findCommunicationIndices(int direction, SPtr<BoundingBox> subDomainBox, LbmOrGks lbmOrGks) = 0; + + virtual uint getNumberOfSendNodes(int direction) = 0; + virtual uint getNumberOfReceiveNodes(int direction) = 0; + + virtual uint getSendIndex(int direction, uint index) = 0; + virtual uint getReceiveIndex(int direction, uint index) = 0; + + virtual void repairCommunicationInices(int direction) = 0; + }; #endif diff --git a/src/gpu/GridGenerator/grid/GridBuilder/GridBuilder.h b/src/gpu/GridGenerator/grid/GridBuilder/GridBuilder.h index 63ea9b188cc5559e55cf7e7bddb611e6672004dd..57290025c3f6e48554e1dafe9bd101ae237b3288 100644 --- a/src/gpu/GridGenerator/grid/GridBuilder/GridBuilder.h +++ b/src/gpu/GridGenerator/grid/GridBuilder/GridBuilder.h @@ -28,7 +28,7 @@ // //! \file GridBuilder.h //! \ingroup grid -//! \author Soeren Peters, Stephan Lenz +//! \author Soeren Peters, Stephan Lenz, Martin Schönherr //======================================================================================= #ifndef GridBuilder_H #define GridBuilder_H @@ -78,7 +78,9 @@ public: virtual void getGridInformations(std::vector<int>& gridX, std::vector<int>& gridY, std::vector<int>& gridZ, std::vector<int>& distX, std::vector<int>& distY, std::vector<int>& distZ) = 0; virtual GRIDGENERATOR_EXPORT uint getNumberOfGridLevels() const = 0; - virtual SPtr<Grid> getGrid(uint level) = 0; + virtual void writeArrows(std::string fileName) const = 0; + + virtual SPtr<Grid> getGrid(uint level) = 0; virtual unsigned int getNumberOfNodes(unsigned int level) const = 0; virtual void getNodeValues(real *xCoords, real *yCoords, real *zCoords, @@ -100,8 +102,26 @@ public: virtual void getVelocityValues(real* vx, real* vy, real* vz, int* indices, int level) const = 0; virtual void getVelocityQs(real* qs[27], int level) const = 0; - virtual SPtr<gg::BoundaryCondition> getBoundaryCondition( SideType side, uint level ) const = 0; + virtual uint getPressureSize(int level) const = 0; + virtual void getPressureValues(real *rho, int *indices, int *neighborIndices, int level) const = 0; + virtual void getPressureQs(real *qs[27], int level) const = 0; + + virtual uint getGeometrySize(int level) const = 0; + virtual void getGeometryIndices(int *indices, int level) const = 0; + virtual void getGeometryQs(real *qs[27], int level) const = 0; + virtual bool hasGeometryValues() const = 0; + virtual void getGeometryValues(real *vx, real *vy, real *vz, int level) const = 0; + + virtual SPtr<gg::BoundaryCondition> getBoundaryCondition(SideType side, uint level) const = 0; + + virtual SPtr<GeometryBoundaryCondition> getGeometryBoundaryCondition(uint level) const = 0; + + virtual uint getCommunicationProcess(int direction) = 0; + virtual uint getNumberOfSendIndices(int direction, uint level) = 0; + virtual uint getNumberOfReceiveIndices(int direction, uint level) = 0; + virtual void getSendIndices(int *sendIndices, int direction, int level) = 0; + virtual void getReceiveIndices(int *sendIndices, int direction, int level) = 0; }; #endif diff --git a/src/gpu/GridGenerator/grid/GridBuilder/LevelGridBuilder.cpp b/src/gpu/GridGenerator/grid/GridBuilder/LevelGridBuilder.cpp index 73bcbdf2b7ee5956236842771e6d8891f6226de9..20c285c13aa2c7644fc1ac6ea6a87b5d8dc7f72c 100644 --- a/src/gpu/GridGenerator/grid/GridBuilder/LevelGridBuilder.cpp +++ b/src/gpu/GridGenerator/grid/GridBuilder/LevelGridBuilder.cpp @@ -28,33 +28,50 @@ // //! \file LevelGridBuilder.cpp //! \ingroup grid -//! \author Soeren Peters, Stephan Lenz +//! \author Soeren Peters, Stephan Lenz, Martin Schönherr //======================================================================================= #include "LevelGridBuilder.h" #include <stdio.h> #include <iostream> +#include "geometries/Arrow/ArrowImp.h" #include "geometries/BoundingBox/BoundingBox.h" +#include "geometries/Triangle/Triangle.h" +#include "geometries/TriangularMesh/TriangularMesh.h" #include "grid/BoundaryConditions/BoundaryCondition.h" #include "grid/BoundaryConditions/Side.h" -#include "grid/GridStrategy/GridCpuStrategy/GridCpuStrategy.h" -#include "grid/NodeValues.h" -#include "grid/GridFactory.h" #include "grid/Grid.h" +#include "grid/GridFactory.h" +#include "grid/GridInterface.h" +#include "grid/NodeValues.h" + +#include "io/GridVTKWriter/GridVTKWriter.h" +#include "io/QLineWriter.h" +#include "io/SimulationFileWriter/SimulationFileWriter.h" + +#include "utilities/communication.h" +#include "utilities/transformator/ArrowTransformator.h" #define GEOFLUID 19 #define GEOSOLID 16 -LevelGridBuilder::LevelGridBuilder(Device device, const std::string& d3qxx) : d3qxx(d3qxx) +using namespace vf::gpu; + +LevelGridBuilder::LevelGridBuilder() { - (void)device; + this->communicationProcesses[CommunicationDirections::MX] = INVALID_INDEX; + this->communicationProcesses[CommunicationDirections::PX] = INVALID_INDEX; + this->communicationProcesses[CommunicationDirections::MY] = INVALID_INDEX; + this->communicationProcesses[CommunicationDirections::PY] = INVALID_INDEX; + this->communicationProcesses[CommunicationDirections::MZ] = INVALID_INDEX; + this->communicationProcesses[CommunicationDirections::PZ] = INVALID_INDEX; } -std::shared_ptr<LevelGridBuilder> LevelGridBuilder::makeShared(Device device, const std::string& d3qxx) +std::shared_ptr<LevelGridBuilder> LevelGridBuilder::makeShared() { - return SPtr<LevelGridBuilder>(new LevelGridBuilder(device, d3qxx)); + return SPtr<LevelGridBuilder>(new LevelGridBuilder()); } void LevelGridBuilder::setSlipBoundaryCondition(SideType sideType, real nomalX, real normalY, real normalZ) @@ -89,6 +106,42 @@ void LevelGridBuilder::setVelocityBoundaryCondition(SideType sideType, real vx, *logging::out << logging::Logger::INFO_INTERMEDIATE << "Set Velocity BC on level " << 0 << " with " << (int)velocityBoundaryCondition->indices.size() <<"\n"; } +void LevelGridBuilder::setVelocityGeometryBoundaryCondition(real vx, real vy, real vz) +{ + geometryHasValues = true; + + for (uint level = 0; level < getNumberOfGridLevels(); level++) + { + if (boundaryConditions[level]->geometryBoundaryCondition != nullptr) + { + boundaryConditions[level]->geometryBoundaryCondition->vx = vx; + boundaryConditions[level]->geometryBoundaryCondition->vy = vy; + boundaryConditions[level]->geometryBoundaryCondition->vz = vz; + boundaryConditions[level]->geometryBoundaryCondition->side->addIndices(grids, level, boundaryConditions[level]->geometryBoundaryCondition); + + boundaryConditions[level]->geometryBoundaryCondition->fillVelocityLists(); + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "Set Geometry Velocity BC on level " << level << " with " << (int)boundaryConditions[level]->geometryBoundaryCondition->indices.size() <<"\n"; + } + } +} + +void LevelGridBuilder::setPressureBoundaryCondition(SideType sideType, real rho) +{ + for (uint level = 0; level < getNumberOfGridLevels(); level++) + { + SPtr<PressureBoundaryCondition> pressureBoundaryCondition = PressureBoundaryCondition::make(rho); + + auto side = SideFactory::make(sideType); + pressureBoundaryCondition->side = side; + pressureBoundaryCondition->side->addIndices(grids, level, pressureBoundaryCondition); + + boundaryConditions[level]->pressureBoundaryConditions.push_back(pressureBoundaryCondition); + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "Set Pressure BC on level " << level << " with " << (int)pressureBoundaryCondition->indices.size() <<"\n"; + } +} + void LevelGridBuilder::setPeriodicBoundaryCondition(bool periodic_X, bool periodic_Y, bool periodic_Z) { for( uint level = 0; level < this->grids.size(); level++ ) @@ -110,6 +163,22 @@ void LevelGridBuilder::setNoSlipBoundaryCondition(SideType sideType) } } +GRIDGENERATOR_EXPORT void LevelGridBuilder::setEnableFixRefinementIntoTheWall(bool enableFixRefinementIntoTheWall) +{ + for (uint level = 0; level < this->grids.size(); level++) + grids[level]->setEnableFixRefinementIntoTheWall(enableFixRefinementIntoTheWall); +} + +GRIDGENERATOR_EXPORT void LevelGridBuilder::setCommunicationProcess(int direction, uint process) +{ + this->communicationProcesses[direction] = process; +} + +GRIDGENERATOR_EXPORT uint LevelGridBuilder::getCommunicationProcess(int direction) +{ + return this->communicationProcesses[direction]; +} + LevelGridBuilder::~LevelGridBuilder() { for (const auto& grid : grids) @@ -146,24 +215,69 @@ uint LevelGridBuilder::getNumberOfGridLevels() const uint LevelGridBuilder::getNumberOfNodesCF(int level) { - return 0; + return this->grids[level]->getNumberOfNodesCF(); } uint LevelGridBuilder::getNumberOfNodesFC(int level) { - return 0; + return this->grids[level]->getNumberOfNodesFC(); } void LevelGridBuilder::getGridInterfaceIndices(uint* iCellCfc, uint* iCellCff, uint* iCellFcc, uint* iCellFcf, int level) const { + this->grids[level]->getGridInterfaceIndices(iCellCfc, iCellCff, iCellFcc, iCellFcf); } void LevelGridBuilder::getOffsetFC(real * xOffFC, real * yOffFC, real * zOffFC, int level) { + for (uint i = 0; i < getNumberOfNodesFC(level); i++) + { + uint offset = this->grids[level]->getFC_offset()[i]; + + xOffFC[i] = - this->grids[level]->getDirection()[ 3*offset + 0 ]; + yOffFC[i] = - this->grids[level]->getDirection()[ 3*offset + 1 ]; + zOffFC[i] = - this->grids[level]->getDirection()[ 3*offset + 2 ]; + } } void LevelGridBuilder::getOffsetCF(real * xOffCF, real * yOffCF, real * zOffCF, int level) { + for (uint i = 0; i < getNumberOfNodesCF(level); i++) + { + uint offset = this->grids[level]->getCF_offset()[i]; + + xOffCF[i] = - this->grids[level]->getDirection()[ 3*offset + 0 ]; + yOffCF[i] = - this->grids[level]->getDirection()[ 3*offset + 1 ]; + zOffCF[i] = - this->grids[level]->getDirection()[ 3*offset + 2 ]; + } +} + +GRIDGENERATOR_EXPORT uint LevelGridBuilder::getNumberOfSendIndices(int direction, uint level) +{ + return this->grids[level]->getNumberOfSendNodes(direction); +} + +GRIDGENERATOR_EXPORT uint LevelGridBuilder::getNumberOfReceiveIndices(int direction, uint level) +{ + return this->grids[level]->getNumberOfReceiveNodes(direction); +} + +GRIDGENERATOR_EXPORT void LevelGridBuilder::getSendIndices(int * sendIndices, int direction, int level) +{ + SPtr<Grid> grid = this->grids[level]; + for( uint i = 0; i < getNumberOfSendIndices(direction, level); i++ ) + { + sendIndices[i] = grid->getSparseIndex( grid->getSendIndex(direction, i) ) + 1; + } +} + +GRIDGENERATOR_EXPORT void LevelGridBuilder::getReceiveIndices(int * receiveIndices, int direction, int level) +{ + SPtr<Grid> grid = this->grids[level]; + for( uint i = 0; i < getNumberOfReceiveIndices(direction, level); i++ ) + { + receiveIndices[i] = grid->getSparseIndex( grid->getReceiveIndex(direction, i) ) + 1; + } } uint LevelGridBuilder::getNumberOfNodes(unsigned int level) const @@ -287,12 +401,119 @@ void LevelGridBuilder::getVelocityQs(real* qs[27], int level) const } } +uint LevelGridBuilder::getPressureSize(int level) const +{ + uint size = 0; + for (auto boundaryCondition : boundaryConditions[level]->pressureBoundaryConditions) + { + size += uint(boundaryCondition->indices.size()); + } + return size; +} + +void LevelGridBuilder::getPressureValues(real* rho, int* indices, int* neighborIndices, int level) const +{ + int allIndicesCounter = 0; + for (auto boundaryCondition : boundaryConditions[level]->pressureBoundaryConditions) + { + for (std::size_t i = 0; i < boundaryCondition->indices.size(); i++) + { + indices[allIndicesCounter] = grids[level]->getSparseIndex(boundaryCondition->indices[i]) + 1; + + neighborIndices[allIndicesCounter] = grids[level]->getSparseIndex(boundaryCondition->neighborIndices[i]) + 1; + + rho[allIndicesCounter] = boundaryCondition->rho; + allIndicesCounter++; + } + } +} + +void LevelGridBuilder::getPressureQs(real* qs[27], int level) const +{ + int allIndicesCounter = 0; + for (auto boundaryCondition : boundaryConditions[level]->pressureBoundaryConditions) + { + for ( uint index = 0; index < boundaryCondition->indices.size(); index++ ) + { + for (int dir = 0; dir <= grids[level]->getEndDirection(); dir++) + { + qs[dir][allIndicesCounter] = boundaryCondition->qs[index][dir]; + } + allIndicesCounter++; + } + } +} + +uint LevelGridBuilder::getGeometrySize(int level) const +{ + if (boundaryConditions[level]->geometryBoundaryCondition) + return (uint)boundaryConditions[level]->geometryBoundaryCondition->indices.size(); + + return 0; +} + +void LevelGridBuilder::getGeometryIndices(int* indices, int level) const +{ + for (uint i = 0; i < boundaryConditions[level]->geometryBoundaryCondition->indices.size(); i++) + { + indices[i] = grids[level]->getSparseIndex(boundaryConditions[level]->geometryBoundaryCondition->indices[i]) + 1; + } +} + +bool LevelGridBuilder::hasGeometryValues() const +{ + return geometryHasValues; +} + +void LevelGridBuilder::getGeometryValues(real* vx, real* vy, real* vz, int level) const +{ + for (uint i = 0; i < boundaryConditions[level]->geometryBoundaryCondition->indices.size(); i++) + { + vx[i] = boundaryConditions[level]->geometryBoundaryCondition->getVx(i); + vy[i] = boundaryConditions[level]->geometryBoundaryCondition->getVy(i); + vz[i] = boundaryConditions[level]->geometryBoundaryCondition->getVz(i); + } +} + +void LevelGridBuilder::getGeometryQs(real* qs[27], int level) const +{ + for (std::size_t i = 0; i < boundaryConditions[level]->geometryBoundaryCondition->indices.size(); i++) + { + for (int dir = 0; dir <= grids[level]->getEndDirection(); dir++) + { + qs[dir][i] = boundaryConditions[level]->geometryBoundaryCondition->qs[i][dir]; + } + } +} + +void LevelGridBuilder::writeArrows(std::string fileName) const +{ + QLineWriter::writeArrows(fileName, boundaryConditions[getNumberOfGridLevels() - 1]->geometryBoundaryCondition, grids[getNumberOfGridLevels() - 1]); +} + GRIDGENERATOR_EXPORT SPtr<gg::BoundaryCondition> LevelGridBuilder::getBoundaryCondition(SideType side, uint level) const { - for( auto bc : this->boundaryConditions[level]->velocityBoundaryConditions ) + for (auto bc : this->boundaryConditions[level]->slipBoundaryConditions) + if (bc->isSide(side)) + return bc; + + for (auto bc : this->boundaryConditions[level]->velocityBoundaryConditions) if( bc->isSide(side) ) return bc; + for (auto bc : this->boundaryConditions[level]->pressureBoundaryConditions) + if (bc->isSide(side)) + return bc; + + auto bc = this->boundaryConditions[level]->geometryBoundaryCondition; + + if (bc && bc->isSide(side)) + return bc; + return nullptr; } +GRIDGENERATOR_EXPORT SPtr<GeometryBoundaryCondition> LevelGridBuilder::getGeometryBoundaryCondition(uint level) const +{ + return this->boundaryConditions[level]->geometryBoundaryCondition; +} diff --git a/src/gpu/GridGenerator/grid/GridBuilder/LevelGridBuilder.h b/src/gpu/GridGenerator/grid/GridBuilder/LevelGridBuilder.h index 8e0f79a7aa833af59b0eb5e74a70aaaefdd5a7aa..f2325435d99140f33eee9844c13908de87788558 100644 --- a/src/gpu/GridGenerator/grid/GridBuilder/LevelGridBuilder.h +++ b/src/gpu/GridGenerator/grid/GridBuilder/LevelGridBuilder.h @@ -28,7 +28,7 @@ // //! \file LevelGridBuilder.h //! \ingroup grid -//! \author Soeren Peters, Stephan Lenz +//! \author Soeren Peters, Stephan Lenz, Martin Schönherr //======================================================================================= #ifndef LEVEL_GRID_BUILDER_H #define LEVEL_GRID_BUILDER_H @@ -46,13 +46,16 @@ struct Vertex; class Grid; +class Transformator; +class ArrowTransformator; class PolyDataWriterWrapper; class BoundingBox; -enum class Device; class Side; class VelocityBoundaryCondition; class SlipBoundaryCondition; +class PressureBoundaryCondition; +class GeometryBoundaryCondition; enum class SideType; @@ -60,10 +63,10 @@ enum class SideType; class LevelGridBuilder : public GridBuilder { protected: - GRIDGENERATOR_EXPORT LevelGridBuilder(Device device, const std::string& d3qxx); + GRIDGENERATOR_EXPORT LevelGridBuilder(); public: - GRIDGENERATOR_EXPORT static std::shared_ptr<LevelGridBuilder> makeShared(Device device, const std::string& d3qxx); + GRIDGENERATOR_EXPORT static std::shared_ptr<LevelGridBuilder> makeShared(); GRIDGENERATOR_EXPORT SPtr<Grid> getGrid(uint level) override; @@ -71,9 +74,16 @@ public: GRIDGENERATOR_EXPORT void setSlipBoundaryCondition(SideType sideType, real nomalX, real normalY, real normalZ); GRIDGENERATOR_EXPORT void setVelocityBoundaryCondition(SideType sideType, real vx, real vy, real vz); + GRIDGENERATOR_EXPORT void setPressureBoundaryCondition(SideType sideType, real rho); GRIDGENERATOR_EXPORT void setPeriodicBoundaryCondition(bool periodic_X, bool periodic_Y, bool periodic_Z); GRIDGENERATOR_EXPORT void setNoSlipBoundaryCondition(SideType sideType); + GRIDGENERATOR_EXPORT void setEnableFixRefinementIntoTheWall(bool enableFixRefinementIntoTheWall); + + GRIDGENERATOR_EXPORT void setCommunicationProcess(int direction, uint process); + + GRIDGENERATOR_EXPORT uint getCommunicationProcess(int direction) override; + GRIDGENERATOR_EXPORT virtual std::shared_ptr<Grid> getGrid(int level, int box); GRIDGENERATOR_EXPORT virtual unsigned int getNumberOfNodes(unsigned int level) const override; @@ -93,7 +103,20 @@ public: GRIDGENERATOR_EXPORT virtual void getVelocityValues(real* vx, real* vy, real* vz, int* indices, int level) const override; GRIDGENERATOR_EXPORT virtual void getVelocityQs(real* qs[27], int level) const override; + GRIDGENERATOR_EXPORT uint getPressureSize(int level) const override; + GRIDGENERATOR_EXPORT void getPressureValues(real* rho, int* indices, int* neighborIndices, int level) const override; + GRIDGENERATOR_EXPORT virtual void getPressureQs(real* qs[27], int level) const override; + + GRIDGENERATOR_EXPORT virtual void getGeometryQs(real *qs[27], int level) const override; + GRIDGENERATOR_EXPORT virtual uint getGeometrySize(int level) const override; + GRIDGENERATOR_EXPORT virtual void getGeometryIndices(int *indices, int level) const override; + GRIDGENERATOR_EXPORT virtual bool hasGeometryValues() const override; + GRIDGENERATOR_EXPORT virtual void getGeometryValues(real *vx, real *vy, real *vz, int level) const override; + + GRIDGENERATOR_EXPORT void writeArrows(std::string fileName) const override; + GRIDGENERATOR_EXPORT SPtr<gg::BoundaryCondition> getBoundaryCondition( SideType side, uint level ) const override; + GRIDGENERATOR_EXPORT SPtr<GeometryBoundaryCondition> getGeometryBoundaryCondition(uint level) const override; protected: @@ -106,17 +129,30 @@ protected: std::vector<SPtr<VelocityBoundaryCondition>> velocityBoundaryConditions; + std::vector<SPtr<PressureBoundaryCondition>> pressureBoundaryConditions; + std::vector<SPtr<VelocityBoundaryCondition> > noSlipBoundaryConditions; + + SPtr<GeometryBoundaryCondition> geometryBoundaryCondition; }; bool geometryHasValues = false; std::vector<std::shared_ptr<Grid> > grids; std::vector<SPtr<BoundaryConditions> > boundaryConditions; + std::array<uint, 6> communicationProcesses; + void checkLevel(int level); -private: - std::string d3qxx; +protected: + void setVelocityGeometryBoundaryCondition(real vx, real vy, real vz); + + void createBCVectors(); + void addShortQsToVector(int index); + void addQsToVector(int index); + void fillRBForNode(int index, int direction, int directionSign, int rb); + + Vertex getVertex(const int matrixIndex) const; public: GRIDGENERATOR_EXPORT void getGridInformations(std::vector<int>& gridX, std::vector<int>& gridY, @@ -132,6 +168,10 @@ public: GRIDGENERATOR_EXPORT void getOffsetFC(real* xOffCf, real* yOffCf, real* zOffCf, int level) override; GRIDGENERATOR_EXPORT void getOffsetCF(real* xOffFc, real* yOffFc, real* zOffFc, int level) override; + GRIDGENERATOR_EXPORT uint getNumberOfSendIndices(int direction, uint level) override; + GRIDGENERATOR_EXPORT uint getNumberOfReceiveIndices(int direction, uint level) override; + GRIDGENERATOR_EXPORT void getSendIndices(int *sendIndices, int direction, int level) override; + GRIDGENERATOR_EXPORT void getReceiveIndices(int *sendIndices, int direction, int level) override; }; #endif diff --git a/src/gpu/GridGenerator/grid/GridBuilder/MultipleGridBuilder.cpp b/src/gpu/GridGenerator/grid/GridBuilder/MultipleGridBuilder.cpp index f3fdaa25d1eca3c60f0bd6c477b0a3984089b46f..565a02a2807ef15679bf08fa001ea9a03f78ca4e 100644 --- a/src/gpu/GridGenerator/grid/GridBuilder/MultipleGridBuilder.cpp +++ b/src/gpu/GridGenerator/grid/GridBuilder/MultipleGridBuilder.cpp @@ -28,7 +28,7 @@ // //! \file MultipleGridBuilder.cpp //! \ingroup grid -//! \author Soeren Peters, Stephan Lenz +//! \author Soeren Peters, Stephan Lenz, Martin Schönherr //======================================================================================= #include "MultipleGridBuilder.h" @@ -46,15 +46,17 @@ #include "grid/Grid.h" #include "grid/GridFactory.h" -MultipleGridBuilder::MultipleGridBuilder(SPtr<GridFactory> gridFactory, Device device, const std::string &d3qxx) : - LevelGridBuilder(device, d3qxx), gridFactory(gridFactory), numberOfLayersFine(12), numberOfLayersBetweenLevels(8), subDomainBox(nullptr) +#include "io/GridVTKWriter/GridVTKWriter.h" +#include "io/STLReaderWriter/STLWriter.h" + +MultipleGridBuilder::MultipleGridBuilder() : LevelGridBuilder(), numberOfLayersFine(12), numberOfLayersBetweenLevels(8), subDomainBox(nullptr) { } -SPtr<MultipleGridBuilder> MultipleGridBuilder::makeShared(SPtr<GridFactory> gridFactory) +SPtr<MultipleGridBuilder> MultipleGridBuilder::makeShared() { - return SPtr<MultipleGridBuilder>(new MultipleGridBuilder(gridFactory)); + return SPtr<MultipleGridBuilder>(new MultipleGridBuilder()); } void MultipleGridBuilder::addCoarseGrid(real startX, real startY, real startZ, real endX, real endY, real endZ, real delta) @@ -72,9 +74,128 @@ void MultipleGridBuilder::addCoarseGrid(real startX, real startY, real startZ, r addGridToList(grid); } +void MultipleGridBuilder::addGeometry(Object* solidObject) +{ + this->solidObject = solidObject; + + for(auto bcs : boundaryConditions) + { + bcs->geometryBoundaryCondition = GeometryBoundaryCondition::make(); + bcs->geometryBoundaryCondition->side = SideFactory::make(SideType::GEOMETRY); + } +} + +void MultipleGridBuilder::addGeometry(Object* solidObject, uint level) +{ + this->solidObject = solidObject; + auto gridShape = solidObject->clone(); + gridShape->scale(4.0); + + this->addGrid(gridShape, level); +} + +void MultipleGridBuilder::addGrid(Object* gridShape) +{ + if (!coarseGridExists()) + return emitNoCoarseGridExistsWarning(); + + const auto grid = makeGrid(gridShape, getNumberOfLevels(), 0); + + addGridToListIfValid(grid); +} + +void MultipleGridBuilder::addGrid(Object* gridShape, uint levelFine) +{ + if (!coarseGridExists()) + return emitNoCoarseGridExistsWarning(); + + for( uint level = this->getNumberOfLevels(); level <= levelFine; level++ ){ + const auto grid = makeGrid(gridShape, level, levelFine); + + + if(level != levelFine){ + grid->setInnerRegionFromFinerGrid(true); + grid->setNumberOfLayers( this->numberOfLayersBetweenLevels ); + } + else{ + grid->setNumberOfLayers( this->numberOfLayersFine ); + } + + grids.push_back(grid); + } + + ////////////////////////////////////////////////////////////////////////// + // this old code by Soeren P. scaled the object + // this did not work for concave geometries + ////////////////////////////////////////////////////////////////////////// + + //const uint nodesBetweenGrids = 12; + //const uint levelDifference = levelFine - getNumberOfLevels(); + //const uint oldGridSize = this->getNumberOfLevels(); + + //addIntermediateGridsToList(levelDifference, levelFine, nodesBetweenGrids, gridShape); + //addFineGridToList(levelFine, gridShape->clone()); + + + //eraseGridsFromListIfInvalid(oldGridSize); +} + +void MultipleGridBuilder::addFineGridToList(uint level, Object* gridShape) +{ + const auto grid = makeGrid(gridShape, level, 0); + grids.push_back(grid); +} + +void MultipleGridBuilder::addIntermediateGridsToList(uint levelDifference, uint levelFine, uint nodesBetweenGrids, Object* gridShape) +{ + if (levelDifference > 0) + { + auto spacings = getSpacingFactors(levelDifference); + + uint level = getNumberOfLevels(); + for (int i = levelDifference - 1; i >= 0; i--) + { + const real scalingFactor = nodesBetweenGrids * spacings[i] * calculateDelta(levelFine); + Object* gridShapeClone = gridShape->clone(); + gridShapeClone->scale(scalingFactor); + + const auto grid = makeGrid(gridShapeClone, level++, 0); + grids.push_back(grid); + } + } +} + +std::vector<uint> MultipleGridBuilder::getSpacingFactors(uint levelDifference) const +{ + std::vector<uint> spacings(levelDifference); + + spacings[0] = uint(std::pow(2, 1)); + for (uint i = 1; i < levelDifference; i++) + spacings[i] = spacings[i - 1] + uint(std::pow(2, i + 1)); + + return spacings; +} + +void MultipleGridBuilder::eraseGridsFromListIfInvalid(uint oldSize) +{ + if (!isGridInCoarseGrid(grids[oldSize])) + { + this->grids.erase(grids.begin() + oldSize, grids.end()); + emitGridIsNotInCoarseGridWarning(); + } +} + +void MultipleGridBuilder::addGridToListIfValid(SPtr<Grid> grid) +{ + if (!isGridInCoarseGrid(grid)) + return emitGridIsNotInCoarseGridWarning(); + + addGridToList(grid); +} + SPtr<Grid> MultipleGridBuilder::makeGrid(Object* gridShape, real startX, real startY, real startZ, real endX, real endY, real endZ, real delta, uint level) const { - return gridFactory->makeGrid(gridShape, startX, startY, startZ, endX, endY, endZ, delta, level); + return GridImp::makeShared(gridShape, startX, startY, startZ, endX, endY, endZ, delta, "D3Q27", level); } bool MultipleGridBuilder::coarseGridExists() const @@ -82,6 +203,196 @@ bool MultipleGridBuilder::coarseGridExists() const return !grids.empty(); } +SPtr<Grid> MultipleGridBuilder::makeGrid(Object* gridShape, uint level, uint levelFine) +{ + boundaryConditions.push_back(SPtr<BoundaryConditions>(new BoundaryConditions)); + + const real delta = calculateDelta(level); + + bool xOddStart = false, yOddStart = false, zOddStart = false; + + auto staggeredCoordinates = getStaggeredCoordinates(gridShape, level, levelFine, xOddStart, yOddStart, zOddStart); + + SPtr<Grid> newGrid = this->makeGrid(gridShape, staggeredCoordinates[0], + staggeredCoordinates[1], + staggeredCoordinates[2], + staggeredCoordinates[3], + staggeredCoordinates[4], + staggeredCoordinates[5], delta, level); + + newGrid->setOddStart( xOddStart, yOddStart, zOddStart ); + + return newGrid; +} + +real MultipleGridBuilder::calculateDelta(uint level) const +{ + real delta = this->getDelta(0); + for (uint i = 0; i < level; i++) + delta *= 0.5; + return delta; +} + +std::array<real, 6> MultipleGridBuilder::getStaggeredCoordinates(Object* gridShape, uint level, uint levelFine, bool& xOddStart, bool& yOddStart, bool& zOddStart) const +{ + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // This method computes the start and end coordinates with respect to the coarse grid + // The following sketch visualizes this procedure for level 2: + // + // /----------------------- domain --------------------------------/ + // | /----------------- refinement region ------------------------/ + // | | | | + // | | | | + // Level 2: | 2 2| 2 2 2 2 2 2 2 2 2 2 | 2 (2) (2) (2) | + // Level 1: 1 | 1 1 1 | 1 1 1 1 1 | 1 (1) | + // Level 0: 0 | 0 |0 0 0 | 0 | + // | | | | + // | out of refinement | inside refinement | out of domain | out of refinement + // | | | | + // Step 1) ------------------>x | | x<------------------------------------------- + // Step 2) | ------>x------>x------>x | | + // Step 3) | | x< | >x | + // Step 4) | x<------ | ------>x | + // Step 5) | | | x<--x<--x<-- | + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + const real deltaCoarse = this->grids[level-1]->getDelta(); + const real delta = 0.5 * deltaCoarse; + + + std::array<real, 6> staggeredCoordinates; + + real X1Minimum = gridShape->getX1Minimum(); + real X2Minimum = gridShape->getX2Minimum(); + real X3Minimum = gridShape->getX3Minimum(); + real X1Maximum = gridShape->getX1Maximum(); + real X2Maximum = gridShape->getX2Maximum(); + real X3Maximum = gridShape->getX3Maximum(); + + if( levelFine >= level ){ + real overlap = 0.0; + + if(level != levelFine) + { + overlap += ( this->numberOfLayersBetweenLevels + 1 ) * delta; + + // use geometric series to account for overlap of higher levels: + // overlap + overlap/2 + overlap/4 + ... + overlap *= 2.0 * ( 1.0 - pow(0.5, levelFine - level ) ); + } + + // add overlap for finest level + overlap += this->numberOfLayersFine * delta * pow(0.5, levelFine - level); + + X1Minimum -= overlap; + X2Minimum -= overlap; + X3Minimum -= overlap; + X1Maximum += overlap; + X2Maximum += overlap; + X3Maximum += overlap; + } + + // Step 1 + // go to boundary of coarse grid + staggeredCoordinates[0] = this->grids[level-1]->getStartX(); + staggeredCoordinates[1] = this->grids[level-1]->getStartY(); + staggeredCoordinates[2] = this->grids[level-1]->getStartZ(); + staggeredCoordinates[3] = this->grids[level-1]->getEndX(); + staggeredCoordinates[4] = this->grids[level-1]->getEndY(); + staggeredCoordinates[5] = this->grids[level-1]->getEndZ(); + + // Step 2 + // move to first coarse node in refinement region + while (staggeredCoordinates[0] < X1Minimum) staggeredCoordinates[0] += deltaCoarse; + while (staggeredCoordinates[1] < X2Minimum) staggeredCoordinates[1] += deltaCoarse; + while (staggeredCoordinates[2] < X3Minimum) staggeredCoordinates[2] += deltaCoarse; + while (staggeredCoordinates[3] > X1Maximum) staggeredCoordinates[3] -= deltaCoarse; + while (staggeredCoordinates[4] > X2Maximum) staggeredCoordinates[4] -= deltaCoarse; + while (staggeredCoordinates[5] > X3Maximum) staggeredCoordinates[5] -= deltaCoarse; + + // Step 3 + // make the grid staggered with one layer of stopper nodes on the outside + staggeredCoordinates[0] -= 0.25 * deltaCoarse; + staggeredCoordinates[1] -= 0.25 * deltaCoarse; + staggeredCoordinates[2] -= 0.25 * deltaCoarse; + staggeredCoordinates[3] += 0.25 * deltaCoarse; + staggeredCoordinates[4] += 0.25 * deltaCoarse; + staggeredCoordinates[5] += 0.25 * deltaCoarse; + + // Step 4 + // add two layers until the refinement region is completely inside the fine grid + if (staggeredCoordinates[0] > X1Minimum) staggeredCoordinates[0] -= deltaCoarse; + if (staggeredCoordinates[1] > X2Minimum) staggeredCoordinates[1] -= deltaCoarse; + if (staggeredCoordinates[2] > X3Minimum) staggeredCoordinates[2] -= deltaCoarse; + if (staggeredCoordinates[3] < X1Maximum) staggeredCoordinates[3] += deltaCoarse; + if (staggeredCoordinates[4] < X2Maximum) staggeredCoordinates[4] += deltaCoarse; + if (staggeredCoordinates[5] < X3Maximum) staggeredCoordinates[5] += deltaCoarse; + + // Step 5 + + // if the mesh is bigger than the domain then it has an odd start + if (staggeredCoordinates[0] < this->grids[level - 1]->getStartX()) xOddStart = true; + if (staggeredCoordinates[1] < this->grids[level - 1]->getStartY()) yOddStart = true; + if (staggeredCoordinates[2] < this->grids[level - 1]->getStartZ()) zOddStart = true; + + // if the refinement region is larger than the domain, then the start and end points are moved inwards again + while (staggeredCoordinates[0] < this->grids[level - 1]->getStartX()) staggeredCoordinates[0] += delta; + while (staggeredCoordinates[1] < this->grids[level - 1]->getStartY()) staggeredCoordinates[1] += delta; + while (staggeredCoordinates[2] < this->grids[level - 1]->getStartZ()) staggeredCoordinates[2] += delta; + while (staggeredCoordinates[3] > this->grids[level - 1]->getEndX() ) staggeredCoordinates[3] -= delta; + while (staggeredCoordinates[4] > this->grids[level - 1]->getEndY() ) staggeredCoordinates[4] -= delta; + while (staggeredCoordinates[5] > this->grids[level - 1]->getEndZ() ) staggeredCoordinates[5] -= delta; + + return staggeredCoordinates; +} + +std::array<real, 6> MultipleGridBuilder::getStaggeredCoordinates(real startX, real startY, real startZ, real endX, real endY, real endZ, real delta, uint level) const +{ + //previous version of Soeren P. + auto offset = getOffset(delta); + + const real startXStaggered = std::floor(startX) - offset[0]; + const real startYStaggered = std::floor(startY) - offset[1]; + const real startZStaggered = std::floor(startZ) - offset[2]; + + const real endXStaggered = std::ceil(endX) + offset[0]; + const real endYStaggered = std::ceil(endY) + offset[1]; + const real endZStaggered = std::ceil(endZ) + offset[2]; + + auto temporaryGrid = this->makeGrid(nullptr, startXStaggered, startYStaggered, startZStaggered, endXStaggered, endYStaggered, endZStaggered, delta, level); + auto startStaggered = temporaryGrid->getMinimumOnNode(Vertex(startX, startY, startZ)); + auto endStaggered = temporaryGrid->getMaximumOnNode(Vertex(endX, endY, endZ)); + + return std::array<real, 6>{startStaggered.x, startStaggered.y, startStaggered.z, endStaggered.x, endStaggered.y, endStaggered.z}; +} + +std::array<real, 3> MultipleGridBuilder::getOffset(real delta) const +{ + real offsetToNullStart = delta * 0.5; + + for (uint level = 1; level < getNumberOfLevels(); level++) + offsetToNullStart += getDelta(level) * 0.5; + + const real offsetX = getStartX(0) - int(getStartX(0)) + offsetToNullStart; + const real offsetY = getStartY(0) - int(getStartY(0)) + offsetToNullStart; + const real offsetZ = getStartZ(0) - int(getStartZ(0)) + offsetToNullStart; + return std::array<real, 3>{offsetX, offsetY, offsetZ}; +} + +bool MultipleGridBuilder::isGridInCoarseGrid(SPtr<Grid> grid) const +{ + return + vf::Math::greaterEqual(grid->getStartX(), grids[0]->getStartX()) && + vf::Math::greaterEqual(grid->getStartY(), grids[0]->getStartY()) && + vf::Math::greaterEqual(grid->getStartZ(), grids[0]->getStartZ()) && + vf::Math::lessEqual(grid->getEndX(), grids[0]->getEndX()) && + vf::Math::lessEqual(grid->getEndY(), grids[0]->getEndY()) && + vf::Math::lessEqual(grid->getEndZ(), grids[0]->getEndZ()); +} + + uint MultipleGridBuilder::getNumberOfLevels() const { return uint(grids.size()); @@ -134,18 +445,157 @@ std::vector<SPtr<Grid> > MultipleGridBuilder::getGrids() const return this->grids; } +// this method initiates the actual grid generation +// +// => before calling this MultipleGridBuilder::buildGrids(...), several options +// parameters and similar have to be set for the grid generation: +// => MultipleGridBuilder::addCoarseGrid(...) => background grid +// => MultipleGridBuilder::setNumberOfLayers(...) => additional layers outside refinement region +// => MultipleGridBuilder::addGrid(..) => refinement region +// => MultipleGridBuilder::setSubDomainBox(...) => sub domain for Multi GPU +// => MultipleGridBuilder::addGeometry(...) => object for solid domain +// => MultipleGridBuilder::setPeriodicBoundaryCondition(...) => periodicity +// +// => LBM boundary conditions are set after MultipleGridBuilder::buildGrids(...): +// => LevelGridBuilder::setVelocityBoundaryCondition(...) +// => LevelGridBuilder::setPressureBoundaryCondition(...) +// => GeometryBoundaryCondition::setTangentialVelocityForPatch(...) +// => VelocityBoundaryCondition::setVelocityProfile(...) +// +// => Multi GPU connectivity is set after MultipleGridBuilder::buildGrids(...): +// => MultipleGridBuilder::findCommunicationIndices(...) +// => LevelGridBuilder::setCommunicationProcess(...) +// void MultipleGridBuilder::buildGrids( LbmOrGks lbmOrGks, bool enableThinWalls ) { - *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start initializing level " << 0 << "\n"; + ////////////////////////////////////////////////////////////////////////// + + // initialize the grids: + // => allocate memory + // => set everything to INVALID_OUT_OF_GRID + // => find nodes inside the refinement region, either based on + // an object or on the shape of the underlying fine grid + // => add overlap as specified by MultipleGridBuilder::setNumberOfLayers + // => fix odd cells, such that we obtain steps of size on the + // boundary of the grid (for complete cells for interpolation) + // => fix refinement into the wall, i.e. make sure the refinement + // goes straight into the walls + // => set stopper nodes to STOPPER_OUT_OF_GRID and STOPPER_OUT_OF_GRID_BOUNDARY + // + // the number of layers is passed to the Grid::initial(...) method as argument + // + // For further documentation of the grid initialization see Section 5.2.2 and + // Figure 5.2 in the Dissertation of Stephan Lenz: + // https://publikationsserver.tu-braunschweig.de/receive/dbbs_mods_00068716 + // + for( int level = (int)grids.size()-1; level >= 0; level-- ) { - grids[0]->inital( nullptr, 0 ); + *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start initializing level " << level << "\n"; - *logging::out << logging::Logger::INFO_INTERMEDIATE << "Done initializing level " << 0 << "\n"; + // On the coarse grid every thing is Fluid (w.r.t. the refinement) + // On the finest grid the Fluid region is defined by the Object + // On the intermediate levels the Fluid region is defined by the fluid region of the finer level + if(level == 0) + grids[level]->inital( nullptr, 0 ); + else if(level == (int)grids.size() - 1) + grids[level]->inital( nullptr, this->numberOfLayersFine ); + else + grids[level]->inital( grids[level+1], this->numberOfLayersBetweenLevels ); + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "Done initializing level " << level << "\n"; + } ////////////////////////////////////////////////////////////////////////// - if (lbmOrGks == LBM) - grids[0]->findSparseIndices(nullptr); + // set the solid region and find Qs + // this is only done if a solid object was added to the GridBuilder + // + // For further documentation of the treatment of solid objects see Section 5.2.3 + // and figure 5.3 in the Dissertation of Stephan Lenz: + // https://publikationsserver.tu-braunschweig.de/receive/dbbs_mods_00068716 + // + if (solidObject) + { + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start with Q Computation\n"; + + // Currently the solid object is only used on the finest grid, + // because refinement into solid objects is not yet implemented. + // If the solid object does not intersect the interfaces, it + // might be possible to have a solid object on more than the finest + // level (See Bachelor thesis of Lennard Lux). To enable this, + // change the following two lines. This is not tested though! + + //for( uint level = 0; level < grids.size(); level++ ) + uint level = (uint)grids.size() - 1; + { + // the Grid::mesh(...) method distinguishes inside and ouside regions + // of the solid domain.: + // => set inner nodes to INVALID_SOLID + // => close needle sells + // => set one layer of STOPPER_SOLID nodes in the solid domain + // => set one layer of BC_SOLID nodes in the fluid domain + grids[level]->mesh(solidObject); + + // if thin walls are enables additional BC_SOLID nodes are found by + // Grid::findOs(...). To prevent the actual Q computation, + // Grid::enableFindSolidBoundaryNodes() and Grid::enableComputeQs() + // set a flag that changes the behavior of Grid::findOs(...); + // additionally some needle cells are closed in this process. + if (enableThinWalls) { + grids[level]->enableFindSolidBoundaryNodes(); + grids[level]->findQs(solidObject); + grids[level]->closeNeedleCellsThinWall(); + grids[level]->enableComputeQs(); + } + + // compute the sub grid distances + // this works for STL and Sphere objects, but not yet for other primitives! + if( lbmOrGks == LBM ) + grids[level]->findQs(solidObject); + } + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "Done with Q Computation\n"; + } + + ////////////////////////////////////////////////////////////////////////// + + // find the interface interpolations cells + // For further documentation see Section 5.2.4 and Figure 5.3 in the dissertation + // of Stephan Lenz: + // https://publikationsserver.tu-braunschweig.de/receive/dbbs_mods_00068716 + // + for (size_t i = 0; i < grids.size() - 1; i++) + grids[i]->findGridInterface(grids[i + 1], lbmOrGks); + + ////////////////////////////////////////////////////////////////////////// + + // set all points outside the sub domain to STOPPER_OUT_OF_GRID_BOUNDARY + // and INVALID_OUT_OF_GRID + if( this->subDomainBox ) + for (size_t i = 0; i < grids.size(); i++) + grids[i]->limitToSubDomain( this->subDomainBox, lbmOrGks ); + + ////////////////////////////////////////////////////////////////////////// + + // shrinks the interface cell lists to the correct size + for (size_t i = 0; i < grids.size() - 1; i++) + grids[i]->repairGridInterfaceOnMultiGPU(grids[i + 1]); + + ////////////////////////////////////////////////////////////////////////// + + // unrolls the matrix + // => computes the sparse indices + // => generates neighbor connectivity taking into account periodic boundaries + // => undates the interface connectivity to sparse indices (overwrites matrix indices!) + if (lbmOrGks == LBM) { + for (size_t i = 0; i < grids.size() - 1; i++) + grids[i]->findSparseIndices(grids[i + 1]); + + grids[grids.size() - 1]->findSparseIndices(nullptr); + } + + ////////////////////////////////////////////////////////////////////////// } GRIDGENERATOR_EXPORT void MultipleGridBuilder::setNumberOfLayers(uint numberOfLayersFine, uint numberOfLayersBetweenLevels) @@ -154,3 +604,42 @@ GRIDGENERATOR_EXPORT void MultipleGridBuilder::setNumberOfLayers(uint numberOfLa this->numberOfLayersBetweenLevels = numberOfLayersBetweenLevels; } +void MultipleGridBuilder::emitNoCoarseGridExistsWarning() +{ + *logging::out << logging::Logger::WARNING << "No Coarse grid was added before. Actual Grid is not added, please create coarse grid before.\n"; +} + + +void MultipleGridBuilder::emitGridIsNotInCoarseGridWarning() +{ + *logging::out << logging::Logger::WARNING << "Grid lies not inside of coarse grid. Actual Grid is not added.\n"; +} + +void MultipleGridBuilder::findCommunicationIndices(int direction, LbmOrGks lbmOrGks) +{ + *logging::out << logging::Logger::INFO_HIGH << "Start findCommunicationIndices()\n"; + + if( this->subDomainBox ) + for (size_t i = 0; i < grids.size(); i++) + grids[i]->findCommunicationIndices(direction, this->subDomainBox, lbmOrGks); + + *logging::out << logging::Logger::INFO_HIGH << "Done with findCommunicationIndices()\n"; +} + +void MultipleGridBuilder::writeGridsToVtk(const std::string& path) const +{ + for(uint level = 0; level < grids.size(); level++) + { + std::stringstream ss; + ss << path << level << ".vtk"; + + GridVTKWriter::writeGridToVTKXML(grids[level], ss.str()); + + } +} + +GRIDGENERATOR_EXPORT void MultipleGridBuilder::setSubDomainBox(SPtr<BoundingBox> subDomainBox) +{ + this->subDomainBox = subDomainBox; +} + diff --git a/src/gpu/GridGenerator/grid/GridBuilder/MultipleGridBuilder.h b/src/gpu/GridGenerator/grid/GridBuilder/MultipleGridBuilder.h index df13fa31f14d88546df08e9b68549b82bed42bf3..839e0036bbc6b0f5d28bec5da3a0abe637b7adca 100644 --- a/src/gpu/GridGenerator/grid/GridBuilder/MultipleGridBuilder.h +++ b/src/gpu/GridGenerator/grid/GridBuilder/MultipleGridBuilder.h @@ -28,20 +28,20 @@ // //! \file MultipleGridBuilder.h //! \ingroup grid -//! \author Soeren Peters, Stephan Lenz +//! \author Soeren Peters, Stephan Lenz, Martin Schoenherr //======================================================================================= #ifndef MULTIPLE_GRID_BUILDER_H #define MULTIPLE_GRID_BUILDER_H #include <vector> #include <array> - +#include "GridGenerator_export.h" #include "Core/LbmOrGks.h" #include "global.h" #include "grid/GridBuilder/LevelGridBuilder.h" -#include "grid/GridFactory.h" +#include "grid/distributions/Distribution.h" class Object; class BoundingBox; @@ -49,12 +49,17 @@ class BoundingBox; class MultipleGridBuilder : public LevelGridBuilder { private: - GRIDGENERATOR_EXPORT MultipleGridBuilder(SPtr<GridFactory> gridFactory, Device device = Device::CPU, const std::string &d3qxx = "D3Q27"); + GRIDGENERATOR_EXPORT MultipleGridBuilder(); public: - GRIDGENERATOR_EXPORT static SPtr<MultipleGridBuilder> makeShared(SPtr<GridFactory> gridFactory); + GRIDGENERATOR_EXPORT static SPtr<MultipleGridBuilder> makeShared(); GRIDGENERATOR_EXPORT void addCoarseGrid(real startX, real startY, real startZ, real endX, real endY, real endZ, real delta); + GRIDGENERATOR_EXPORT void addGrid(Object *gridShape); + GRIDGENERATOR_EXPORT void addGrid(Object *gridShape, uint levelFine); + + GRIDGENERATOR_EXPORT void addGeometry(Object *gridShape); + GRIDGENERATOR_EXPORT void addGeometry(Object *solidObject, uint level); GRIDGENERATOR_EXPORT uint getNumberOfLevels() const; GRIDGENERATOR_EXPORT real getDelta(uint level) const; @@ -72,21 +77,41 @@ public: GRIDGENERATOR_EXPORT void setNumberOfLayers( uint numberOfLayersFine, uint numberOfLayersBetweenLevels ); + GRIDGENERATOR_EXPORT void writeGridsToVtk(const std::string &path) const; + + GRIDGENERATOR_EXPORT void setSubDomainBox(SPtr<BoundingBox> subDomainBox); private: void addGridToList(SPtr<Grid> grid); + real calculateDelta(uint level) const; bool coarseGridExists() const; + bool isGridInCoarseGrid(SPtr<Grid> grid) const; - SPtr<Grid> makeGrid(Object* gridShape, real startX, real startY, real startZ, real endX, real endY, real endZ, real delta, uint level) const; + void addFineGridToList(uint level, Object *gridShape); + void addIntermediateGridsToList(uint levelDifference, uint levelFine, uint nodesBetweenGrids, Object *gridShape); + void eraseGridsFromListIfInvalid(uint oldSize); + void addGridToListIfValid(SPtr<Grid> grid); + std::array<real, 6> getStaggeredCoordinates(Object *gridShape, uint level, uint levelFine, bool &xOddStart, bool &yOddStart, bool &zOddStart) const; + std::array<real, 6> getStaggeredCoordinates(real startX, real startY, real startZ, real endX, real endY, real endZ, real delta, uint level) const; + std::array<real, 3> getOffset(real delta) const; + std::vector<uint> getSpacingFactors(uint levelDifference) const; - SPtr<GridFactory> gridFactory; + SPtr<Grid> makeGrid(Object *gridShape, uint level, uint levelFine); + SPtr<Grid> makeGrid(Object *gridShape, real startX, real startY, real startZ, real endX, real endY, real endZ, real delta, uint level) const; + + static void emitNoCoarseGridExistsWarning(); + static void emitGridIsNotInCoarseGridWarning(); + + Object *solidObject = nullptr; uint numberOfLayersFine; uint numberOfLayersBetweenLevels; SPtr<BoundingBox> subDomainBox; +public: + GRIDGENERATOR_EXPORT void findCommunicationIndices(int direction, LbmOrGks lbmOrGks); }; #endif diff --git a/src/gpu/GridGenerator/grid/GridFactory.h b/src/gpu/GridGenerator/grid/GridFactory.h index 9ebf1e3a13184a9b3aea75694c74e039fc987ad5..b525596fa670a026d60b1297c75ef69c46b23498 100644 --- a/src/gpu/GridGenerator/grid/GridFactory.h +++ b/src/gpu/GridGenerator/grid/GridFactory.h @@ -37,15 +37,8 @@ #include "geometries/Cuboid/Cuboid.h" -#include "grid/GridStrategy/GridCpuStrategy/GridCpuStrategy.h" -#include "grid/distributions/Distribution.h" #include "grid/GridImp.h" -enum class Device -{ - CPU, GPU -}; - enum class TriangularMeshDiscretizationMethod { RAYCASTING, POINT_IN_OBJECT, POINT_UNDER_TRIANGLE @@ -59,43 +52,10 @@ public: return SPtr<GridFactory>(new GridFactory()); } -private: - GridFactory() - { - gridStrategy = SPtr<GridStrategy>(new GridCpuStrategy()); - } - -public: SPtr<Grid> makeGrid(Object* gridShape, real startX, real startY, real startZ, real endX, real endY, real endZ, real delta, uint level, const std::string& d3Qxx = "D3Q27") { - Distribution distribution = DistributionHelper::getDistribution(d3Qxx); - - SPtr<GridImp> grid; - - grid = GridImp::makeShared(gridShape, startX, startY, startZ, endX, endY, endZ, delta, gridStrategy, distribution, level); - - return grid; - } - - - void setGridStrategy(Device device) - { - switch (device) - { - case Device::CPU: - gridStrategy = SPtr<GridStrategy>(new GridCpuStrategy()); break; - case Device::GPU: - throw std::runtime_error("GPU Device for GridGenerator not supported."); - } + return GridImp::makeShared(gridShape, startX, startY, startZ, endX, endY, endZ, delta, d3Qxx, level); } - - void setGridStrategy(SPtr<GridStrategy> gridStrategy) - { - this->gridStrategy = gridStrategy; - } - -private: - SPtr<GridStrategy> gridStrategy; }; diff --git a/src/gpu/GridGenerator/grid/GridImp.cpp b/src/gpu/GridGenerator/grid/GridImp.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9b64d8260a69226a5481405b0f33f91de4dbf09d --- /dev/null +++ b/src/gpu/GridGenerator/grid/GridImp.cpp @@ -0,0 +1,1983 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file GridImp.cpp +//! \ingroup grid +//! \author Soeren Peters, Stephan Lenz, Martin Schoenherr +//======================================================================================= +#include "GridImp.h" + +#include <stdio.h> +#include <time.h> +#include <iostream> +#include <omp.h> +#include <sstream> +#include <cmath> + +#include "global.h" + +#include "geometries/Object.h" +#include "geometries/Vertex/Vertex.h" +#include "geometries/Triangle/Triangle.h" +#include "geometries/TriangularMesh/TriangularMesh.h" +#include "geometries/TriangularMesh/TriangularMeshStrategy.h" +#include "geometries/BoundingBox/BoundingBox.h" + +#include "grid/distributions/Distribution.h" +#include "grid/Field.h" +#include "grid/GridInterface.h" +#include "grid/NodeValues.h" + +#include "io/GridVTKWriter/GridVTKWriter.h" + +#include "utilities/communication.h" +#include "utilities/math/Math.h" + +int DIRECTIONS[DIR_END_MAX][DIMENSION]; + +using namespace vf::gpu; + +GridImp::GridImp(Object* object, real startX, real startY, real startZ, real endX, real endY, real endZ, real delta, Distribution distribution, uint level) + : object(object), + startX(startX), + startY(startY), + startZ(startZ), + endX(endX), + endY(endY), + endZ(endZ), + delta(delta), + distribution(distribution), + level(level), + periodicityX(false), + periodicityY(false), + periodicityZ(false), + enableFixRefinementIntoTheWall(false), + gridInterface(nullptr), + neighborIndexX(nullptr), + neighborIndexY(nullptr), + neighborIndexZ(nullptr), + neighborIndexNegative(nullptr), + sparseIndices(nullptr), + qIndices(nullptr), + qValues(nullptr), + qPatches(nullptr), + innerRegionFromFinerGrid(false), + numberOfLayers(0), + qComputationStage(qComputationStageType::ComputeQs) +{ + initalNumberOfNodesAndSize(); +} + +SPtr<GridImp> GridImp::makeShared(Object* object, real startX, real startY, real startZ, real endX, real endY, real endZ, real delta, std::string d3Qxx, uint level) +{ + Distribution distribution = DistributionHelper::getDistribution(d3Qxx); + SPtr<GridImp> grid(new GridImp(object, startX, startY, startZ, endX, endY, endZ, delta, distribution, level)); + return grid; +} + + +void GridImp::initalNumberOfNodesAndSize() +{ + const real length = endX - startX; + const real width = endY - startY; + const real height = endZ - startZ; + + nx = std::lround((length + delta) / delta); + ny = std::lround((width + delta) / delta); + nz = std::lround((height + delta) / delta); + + this->size = nx * ny * nz; + this->sparseSize = size; + distribution.setSize(size); +} + +void GridImp::inital(const SPtr<Grid> fineGrid, uint numberOfLayers) +{ + field = Field(size); + field.allocateMemory(); + + this->neighborIndexX = new int[this->size]; + this->neighborIndexY = new int[this->size]; + this->neighborIndexZ = new int[this->size]; + this->neighborIndexNegative = new int[this->size]; + + this->sparseIndices = new int[this->size]; + + this->qIndices = new uint[this->size]; + for (uint i = 0; i < this->size; i++) + this->qIndices[i] = INVALID_INDEX; + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start initalNodesToOutOfGrid()\n"; +#pragma omp parallel for + for (int index = 0; index < (int)this->size; index++) + this->initalNodeToOutOfGrid(index); + + if( this->innerRegionFromFinerGrid ){ + *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start setInnerBasedOnFinerGrid()\n"; + this->setInnerBasedOnFinerGrid(fineGrid); + } + else{ + *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start findInnerNodes()\n"; + this->object->findInnerNodes( shared_from_this() ); + } + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start addOverlap()\n"; + this->addOverlap(); + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start fixOddCells()\n"; +#pragma omp parallel for + for (int index = 0; index < (int)this->size; index++) + this->fixOddCell(index); + + if( enableFixRefinementIntoTheWall ) + { + *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start fixRefinementIntoWall()\n"; +#pragma omp parallel for + for (int xIdx = 0; xIdx < (int)this->nx; xIdx++) { + for (uint yIdx = 0; yIdx < this->ny; yIdx++) { + this->fixRefinementIntoWall(xIdx, yIdx, 0, 3); + this->fixRefinementIntoWall(xIdx, yIdx, this->nz - 1, -3); + } + } + +#pragma omp parallel for + for (int xIdx = 0; xIdx < (int)this->nx; xIdx++) { + for (uint zIdx = 0; zIdx < this->nz; zIdx++) { + this->fixRefinementIntoWall(xIdx, 0, zIdx, 2); + this->fixRefinementIntoWall(xIdx, this->ny - 1, zIdx, -2); + } + } + +#pragma omp parallel for + for (int yIdx = 0; yIdx < (int)this->ny; yIdx++) { + for (uint zIdx = 0; zIdx < this->nz; zIdx++) { + this->fixRefinementIntoWall(0, yIdx, zIdx, 1); + this->fixRefinementIntoWall(this->nx - 1, yIdx, zIdx, -1); + } + } + } + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start findEndOfGridStopperNodes()\n"; +#pragma omp parallel for + for (int index = 0; index < (int)this->size; index++) + this->findEndOfGridStopperNode(index); + + *logging::out << logging::Logger::INFO_INTERMEDIATE + << "Grid created: " << "from (" << this->startX << ", " << this->startY << ", " << this->startZ << ") to (" << this->endX << ", " << this->endY << ", " << this->endZ << ")\n" + << "nodes: " << this->nx << " x " << this->ny << " x " << this->nz << " = " << this->size << "\n"; +} + +void GridImp::setOddStart(bool xOddStart, bool yOddStart, bool zOddStart) +{ + this->xOddStart = xOddStart; + this->yOddStart = yOddStart; + this->zOddStart = zOddStart; +} + +void GridImp::initalNodeToOutOfGrid(uint index) { + this->field.setFieldEntryToInvalidOutOfGrid(index); +} + +void GridImp::freeMemory() +{ + if( this->neighborIndexX != nullptr ) { delete[] this->neighborIndexX; this->neighborIndexX = nullptr; } + if( this->neighborIndexY != nullptr ) { delete[] this->neighborIndexY; this->neighborIndexY = nullptr; } + if( this->neighborIndexZ != nullptr ) { delete[] this->neighborIndexZ; this->neighborIndexZ = nullptr; } + if( this->neighborIndexNegative != nullptr ) { delete[] this->neighborIndexNegative; this->neighborIndexNegative = nullptr; } + if( this->sparseIndices != nullptr ) { delete[] this->sparseIndices; this->sparseIndices = nullptr; } + if( this->qIndices != nullptr ) { delete[] this->qIndices; this->qIndices = nullptr; } + if( this->qValues != nullptr ) { delete[] this->qValues; this->qValues = nullptr; } + if( this->qPatches != nullptr ) { delete[] this->qPatches; this->qPatches = nullptr; } + + field.freeMemory(); +} + +void GridImp::findInnerNodes() +{ +#pragma omp parallel for + for (int index = 0; index < (int)this->size; index++) + this->findInnerNode(index); +} + +void GridImp::findInnerNode(uint index) +{ + this->sparseIndices[index] = index; + + if( this->level != 0 ){ + const Cell cell = getOddCellFromIndex(index); + if (isInside(cell)) + this->field.setFieldEntryToFluid(index); + } + else{ + real x, y, z; + this->transIndexToCoords(index, x, y, z); + const uint xIndex = getXIndex(x); + const uint yIndex = getYIndex(y); + const uint zIndex = getZIndex(z); + + if( xIndex != 0 && xIndex != this->nx-1 && + yIndex != 0 && yIndex != this->ny-1 && + zIndex != 0 && zIndex != this->nz-1 ) + this->field.setFieldEntryToFluid(index); + } +} + +void GridImp::discretize(Object* solidObject, char innerType, char outerType) +{ +#pragma omp parallel for + for (int index = 0; index < (int)this->size; index++) + { + this->sparseIndices[index] = index; + + if( this->getFieldEntry(index) == innerType ) continue; + + real x, y, z; + this->transIndexToCoords(index, x, y, z); + + if( solidObject->isPointInObject(x, y, z, 0.0, 0.0) ) + this->setFieldEntry(index, innerType); + //else + // this->setFieldEntry(index, outerType); + } +} + +bool GridImp::isInside(const Cell& cell) const +{ + return object->isCellInObject(cell); +} + +////TODO: check where the fine grid starts (0.25 or 0.75) and if even or odd-cell is needed +// Cell numbering: +// even start odd start +// +---------+ +---------+ +// | +-----+-----+-----+ | +-----+-----+-----+ +// | | | | | | | | | | | | +// | +-----+-----+-----+ | +-----+-----+-----+ +// +---------+ +---------+ +// 0 1 2 0 1 2 +// even even even +// odd odd odd +// +Cell GridImp::getOddCellFromIndex(uint index) const +{ + real x, y, z; + this->transIndexToCoords(index, x, y, z); + + const uint xIndex = getXIndex(x); + const uint yIndex = getYIndex(y); + const uint zIndex = getZIndex(z); + + real xCellStart; + if( this->xOddStart ) xCellStart = xIndex % 2 != 0 ? x - this->delta : x; + else xCellStart = xIndex % 2 != 0 ? x : x - this->delta; + + real yCellStart; + if( this->yOddStart ) yCellStart = yIndex % 2 != 0 ? y - this->delta : y; + else yCellStart = yIndex % 2 != 0 ? y : y - this->delta; + + real zCellStart; + if( this->zOddStart ) zCellStart = zIndex % 2 != 0 ? z - this->delta : z; + else zCellStart = zIndex % 2 != 0 ? z : z - this->delta; + + return Cell(xCellStart, yCellStart, zCellStart, delta); +} + +void GridImp::setInnerBasedOnFinerGrid(const SPtr<Grid> fineGrid) +{ + for( uint index = 0; index < this->size; index++ ){ + + real x, y, z; + this->transIndexToCoords(index, x, y, z); + + uint childIndex[8]; + + childIndex[0] = fineGrid->transCoordToIndex( x + 0.25 * this->delta, y + 0.25 * this->delta, z + 0.25 * this->delta ); + childIndex[1] = fineGrid->transCoordToIndex( x + 0.25 * this->delta, y + 0.25 * this->delta, z - 0.25 * this->delta ); + childIndex[2] = fineGrid->transCoordToIndex( x + 0.25 * this->delta, y - 0.25 * this->delta, z + 0.25 * this->delta ); + childIndex[3] = fineGrid->transCoordToIndex( x + 0.25 * this->delta, y - 0.25 * this->delta, z - 0.25 * this->delta ); + childIndex[4] = fineGrid->transCoordToIndex( x - 0.25 * this->delta, y + 0.25 * this->delta, z + 0.25 * this->delta ); + childIndex[5] = fineGrid->transCoordToIndex( x - 0.25 * this->delta, y + 0.25 * this->delta, z - 0.25 * this->delta ); + childIndex[6] = fineGrid->transCoordToIndex( x - 0.25 * this->delta, y - 0.25 * this->delta, z + 0.25 * this->delta ); + childIndex[7] = fineGrid->transCoordToIndex( x - 0.25 * this->delta, y - 0.25 * this->delta, z - 0.25 * this->delta ); + + for( uint i = 0; i < 8; i++ ){ + if( childIndex[i] != INVALID_INDEX && fineGrid->getFieldEntry( childIndex[i] ) == FLUID ){ + this->setFieldEntry(index, FLUID); + break; + } + } + } +} + +void GridImp::addOverlap() +{ + for( uint layer = 0; layer < this->numberOfLayers; layer++ ){ +#pragma omp parallel for + for (int index = 0; index < (int)this->size; index++) + this->setOverlapTmp(index); + +#pragma omp parallel for + for (int index = 0; index < (int)this->size; index++) + this->setOverlapFluid(index); + } +} + +void GridImp::setOverlapTmp( uint index ) +{ + if( this->field.is( index, INVALID_OUT_OF_GRID ) ){ + + if( this->hasNeighborOfType(index, FLUID) ){ + this->field.setFieldEntry( index, OVERLAP_TMP ); + } + } +} + +void GridImp::setOverlapFluid( uint index ) +{ + if( this->field.is( index, OVERLAP_TMP ) ){ + this->field.setFieldEntry( index, FLUID ); + } +} + +void GridImp::fixRefinementIntoWall(uint xIndex, uint yIndex, uint zIndex, int dir) +{ + + real x = this->startX + this->delta * xIndex; + real y = this->startY + this->delta * yIndex; + real z = this->startZ + this->delta * zIndex; + + uint index = this->transCoordToIndex(x, y, z); + + if( !this->xOddStart && ( dir == 1 || dir == -1 ) && ( xIndex % 2 == 1 || xIndex == 0 ) ) return; + if( !this->yOddStart && ( dir == 2 || dir == -2 ) && ( yIndex % 2 == 1 || yIndex == 0 ) ) return; + if( !this->zOddStart && ( dir == 3 || dir == -3 ) && ( zIndex % 2 == 1 || zIndex == 0 ) ) return; + + // Dont do this if inside of the domain + if( this->xOddStart && ( dir == 1 || dir == -1 ) && ( xIndex % 2 == 0 && xIndex != 0 ) ) return; + if( this->yOddStart && ( dir == 2 || dir == -2 ) && ( yIndex % 2 == 0 && yIndex != 0 ) ) return; + if( this->zOddStart && ( dir == 3 || dir == -3 ) && ( zIndex % 2 == 0 && zIndex != 0 ) ) return; + + ////////////////////////////////////////////////////////////////////////// + + real dx{ 0.0 }, dy{ 0.0 }, dz{ 0.0 }; + + if ( dir == 1 ){ dx = this->delta; dy = 0.0; dz = 0.0; } + else if ( dir == -1 ){ dx = - this->delta; dy = 0.0; dz = 0.0; } + else if ( dir == 2 ){ dx = 0.0; dy = this->delta; dz = 0.0; } + else if ( dir == -2 ){ dx = 0.0; dy = - this->delta; dz = 0.0; } + else if ( dir == 3 ){ dx = 0.0; dy = 0.0; dz = this->delta; } + else if ( dir == -3 ){ dx = 0.0; dy = 0.0; dz = - this->delta; } + + ////////////////////////////////////////////////////////////////////////// + + char type = this->field.getFieldEntry(index); + + char type2 = ( type == FLUID ) ? ( INVALID_OUT_OF_GRID ) : ( FLUID ); + uint distance = ( type == FLUID ) ? ( 9 ) : ( 5 ); + + bool allTypesAreTheSame = true; + + for( uint i = 1; i <= distance; i++ ){ + uint neighborIndex = this->transCoordToIndex(x + i * dx, y + i * dy, z + i * dz); + + if( neighborIndex != INVALID_INDEX && !this->field.is( neighborIndex, type ) ) + allTypesAreTheSame = false; + } + + ////////////////////////////////////////////////////////////////////////// + + if( allTypesAreTheSame ) + return; + + this->setFieldEntry(index, type2); + + for( uint i = 1; i <= distance; i++ ){ + uint neighborIndex = this->transCoordToIndex(x + i * dx, y + i * dy, z + i * dz); + + this->setFieldEntry(neighborIndex, type2); + } +} + +void GridImp::findStopperNode(uint index) // deprecated +{ + if(isValidEndOfGridStopper(index)) + this->field.setFieldEntryToStopperOutOfGrid(index); + + if (isValidSolidStopper(index)) + this->field.setFieldEntry(index, STOPPER_SOLID); +} + +void GridImp::findEndOfGridStopperNode(uint index) +{ + if (isValidEndOfGridStopper(index)){ + if( this->level != 0 ) + this->field.setFieldEntryToStopperOutOfGrid(index); + else + this->field.setFieldEntryToStopperOutOfGridBoundary(index); + } + + if (isValidEndOfGridBoundaryStopper(index)) + this->field.setFieldEntryToStopperOutOfGridBoundary(index); +} + +void GridImp::findSolidStopperNode(uint index) +{ + if (isValidSolidStopper(index)) + this->field.setFieldEntry(index, STOPPER_SOLID); +} + +void GridImp::findBoundarySolidNode(uint index) +{ + if (shouldBeBoundarySolidNode(index)) + { + this->field.setFieldEntry(index, BC_SOLID); + this->qIndices[index] = this->numberOfSolidBoundaryNodes++; + //grid->setNumberOfSolidBoundaryNodes(grid->getNumberOfSolidBoundaryNodes() + 1); + } +} + +void GridImp::fixOddCell(uint index) +{ + Cell cell = getOddCellFromIndex(index); + if (isOutSideOfGrid(cell)) + return; + if (contains(cell, FLUID)) + setNodeTo(cell, FLUID); +} + +bool GridImp::isOutSideOfGrid(Cell &cell) const +{ + for (const auto point : cell) { + if (point.x < startX || point.x > endX + || point.y < startY || point.y > endY + || point.z < startZ || point.z > endZ) + return true; + } + return false; +} + +bool GridImp::contains(Cell &cell, char type) const +{ + for (const auto point : cell) { + uint index = transCoordToIndex(point.x, point.y, point.z); + if (index == INVALID_INDEX) + continue; + if (field.is(index, type)) + return true; + } + return false; +} + +bool GridImp::cellContainsOnly(Cell &cell, char type) const +{ + for (const auto point : cell) { + uint index = transCoordToIndex(point.x, point.y, point.z); + if (index == INVALID_INDEX) + return false; + if (!field.is(index, type)) + return false; + } + return true; +} + +bool GridImp::cellContainsOnly(Cell &cell, char typeA, char typeB) const +{ + for (const auto point : cell) { + uint index = transCoordToIndex(point.x, point.y, point.z); + if (index == INVALID_INDEX) + return false; + if (!field.is(index, typeA) && !field.is(index, typeB)) + return false; + } + return true; +} + +const Object * GridImp::getObject() const +{ + return this->object; +} + +void GridImp::setNodeTo(Cell &cell, char type) +{ + for (const auto point : cell) { + uint index = transCoordToIndex(point.x, point.y, point.z); + if (index == INVALID_INDEX) + continue; + field.setFieldEntry(index, type); + } +} + +void GridImp::setNodeTo(uint index, char type) +{ + if( index != INVALID_INDEX ) + field.setFieldEntry(index, type); +} + +bool GridImp::isNode(uint index, char type) const +{ + if( index != INVALID_INDEX ) + return field.is(index, type); + + throw std::runtime_error("GridImp::isNode() -> index == INVALID_INDEX not supported."); +} + +bool GridImp::isValidEndOfGridStopper(uint index) const +{ + // Lenz: also includes corner stopper nodes + if (!this->field.is(index, INVALID_OUT_OF_GRID)) + return false; + + return hasNeighborOfType(index, FLUID); +} + +bool GridImp::isValidEndOfGridBoundaryStopper(uint index) const +{ + // Lenz: also includes corner stopper nodes + if (!this->field.is(index, FLUID)) + return false; + + return ! hasAllNeighbors(index); +} + +bool GridImp::isValidSolidStopper(uint index) const +{ + // Lenz: also includes corner stopper nodes + if (!this->field.is(index, INVALID_SOLID)) + return false; + + return hasNeighborOfType(index, FLUID); +} + +bool GridImp::shouldBeBoundarySolidNode(uint index) const +{ + if (!this->field.is(index, FLUID)) + return false; + + return hasNeighborOfType(index, STOPPER_SOLID); +} + +bool GridImp::hasAllNeighbors(uint index) const +{ + // new version by Lenz, utilizes the range based for loop for all directions + real x, y, z; + this->transIndexToCoords(index, x, y, z); + for (const auto dir : this->distribution) { + const uint neighborIndex = this->transCoordToIndex(x + dir[0] * this->getDelta(), y + dir[1] * this->getDelta(), z + dir[2] * this->getDelta()); + + if (neighborIndex == INVALID_INDEX) return false; + } + + return true; +} + +bool GridImp::hasNeighborOfType(uint index, char type) const +{ + // new version by Lenz, utilizes the range based for loop for all directions + real x, y, z; + this->transIndexToCoords(index, x, y, z); + for (const auto dir : this->distribution) { + const uint neighborIndex = this->transCoordToIndex(x + dir[0] * this->getDelta(), y + dir[1] * this->getDelta(), z + dir[2] * this->getDelta()); + + if (neighborIndex == INVALID_INDEX) continue; + + if (this->field.is(neighborIndex, type)) + return true; + } + + return false; +} + +bool GridImp::nodeInNextCellIs(int index, char type) const +{ + real x, y, z; + this->transIndexToCoords(index, x, y, z); + + const real neighborX = x + this->delta > endX ? endX : x + this->delta; + const real neighborY = y + this->delta > endY ? endY : y + this->delta; + const real neighborZ = z + this->delta > endZ ? endZ : z + this->delta; + + const uint indexX = transCoordToIndex(neighborX, y, z); + const uint indexY = transCoordToIndex(x, neighborY, z); + const uint indexZ = transCoordToIndex(x, y, neighborZ); + + const uint indexXY = transCoordToIndex(neighborX, neighborY, z); + const uint indexYZ = transCoordToIndex(x, neighborY, neighborZ); + const uint indexXZ = transCoordToIndex(neighborX, y, neighborZ); + + const uint indexXYZ = transCoordToIndex(neighborX, neighborY, neighborZ); + + const bool typeX = indexX == INVALID_INDEX ? false : this->field.is(indexX, type); + const bool typeY = indexY == INVALID_INDEX ? false : this->field.is(indexY, type); + const bool typeXY = indexXY == INVALID_INDEX ? false : this->field.is(indexXY, type); + const bool typeZ = indexZ == INVALID_INDEX ? false : this->field.is(indexZ, type); + const bool typeYZ = indexYZ == INVALID_INDEX ? false : this->field.is(indexYZ, type); + const bool typeXZ = indexXZ == INVALID_INDEX ? false : this->field.is(indexXZ, type); + const bool typeXYZ = indexXYZ == INVALID_INDEX ? false : this->field.is(indexXYZ, type); + + return typeX || typeY || typeXY || typeZ || typeYZ + || typeXZ || typeXYZ; +} + +bool GridImp::nodeInPreviousCellIs(int index, char type) const +{ + real x, y, z; + this->transIndexToCoords(index, x, y, z); + + const real neighborX = x - this->delta < startX ? startX : x - this->delta; + const real neighborY = y - this->delta < startY ? startY : y - this->delta; + const real neighborZ = z - this->delta < startZ ? startZ : z - this->delta; + + const uint indexX = transCoordToIndex(neighborX, y, z); + const uint indexY = transCoordToIndex(x, neighborY, z); + const uint indexZ = transCoordToIndex(x, y, neighborZ); + + const uint indexXY = transCoordToIndex(neighborX, neighborY, z); + const uint indexYZ = transCoordToIndex(x, neighborY, neighborZ); + const uint indexXZ = transCoordToIndex(neighborX, y, neighborZ); + + const uint indexXYZ = transCoordToIndex(neighborX, neighborY, neighborZ); + + const bool typeX = indexX == INVALID_INDEX ? false : this->field.is(indexX , type); + const bool typeY = indexY == INVALID_INDEX ? false : this->field.is(indexY , type); + const bool typeXY = indexXY == INVALID_INDEX ? false : this->field.is(indexXY , type); + const bool typeZ = indexZ == INVALID_INDEX ? false : this->field.is(indexZ , type); + const bool typeYZ = indexYZ == INVALID_INDEX ? false : this->field.is(indexYZ , type); + const bool typeXZ = indexXZ == INVALID_INDEX ? false : this->field.is(indexXZ , type); + const bool typeXYZ = indexXYZ == INVALID_INDEX ? false : this->field.is(indexXYZ, type); + + return typeX || typeY || typeXY || typeZ || typeYZ + || typeXZ || typeXYZ; +} + +bool GridImp::nodeInCellIs(Cell& cell, char type) const +{ + for (const auto node : cell) + { + const uint index = transCoordToIndex(node.x, node.y, node.z); + if (index == INVALID_INDEX) + continue; + if (field.is(index, type)) + return true; + } + return false; +} + + +void GridImp::setCellTo(uint index, char type) +{ + real x, y, z; + this->transIndexToCoords(index, x, y, z); + + Cell cell(x, y, z, this->delta); + for (const auto node : cell) + { + const uint nodeIndex = transCoordToIndex(node.x, node.y, node.z); + if (nodeIndex == INVALID_INDEX) + continue; + this->field.setFieldEntry(nodeIndex, type); + } +} + + +void GridImp::setNonStopperOutOfGridCellTo(uint index, char type) +{ + real x, y, z; + this->transIndexToCoords(index, x, y, z); + + Cell cell(x, y, z, this->delta); + for (const auto node : cell) + { + const uint nodeIndex = transCoordToIndex(node.x, node.y, node.z); + if (nodeIndex == INVALID_INDEX) + continue; + + if( this->getFieldEntry( nodeIndex ) != STOPPER_OUT_OF_GRID && + this->getFieldEntry( nodeIndex ) != STOPPER_OUT_OF_GRID_BOUNDARY ) + this->field.setFieldEntry(nodeIndex, type); + } +} + + +void GridImp::setPeriodicity(bool periodicityX, bool periodicityY, bool periodicityZ) +{ + this->periodicityX = periodicityX; + this->periodicityY = periodicityY; + this->periodicityZ = periodicityZ; +} + +void GridImp::setPeriodicityX(bool periodicity) +{ + this->periodicityX = periodicity; +} + +void GridImp::setPeriodicityY(bool periodicity) +{ + this->periodicityY = periodicity; +} + +void GridImp::setPeriodicityZ(bool periodicity) +{ + this->periodicityZ = periodicity; +} + +bool GridImp::getPeriodicityX() +{ + return this->periodicityX; +} + +bool GridImp::getPeriodicityY() +{ + return this->periodicityY; +} + +bool GridImp::getPeriodicityZ() +{ + return this->periodicityZ; +} + +void GridImp::setEnableFixRefinementIntoTheWall(bool enableFixRefinementIntoTheWall) +{ + this->enableFixRefinementIntoTheWall = enableFixRefinementIntoTheWall; +} + +uint GridImp::transCoordToIndex(const real &x, const real &y, const real &z) const +{ + const uint xIndex = getXIndex(x); + const uint yIndex = getYIndex(y); + const uint zIndex = getZIndex(z); + + if (xIndex >= nx || yIndex >= ny || zIndex >= nz) + return INVALID_INDEX; + + return xIndex + nx * (yIndex + ny * zIndex); +} + +void GridImp::transIndexToCoords(uint index, real &x, real &y, real &z) const +{ + if (index == INVALID_INDEX) + printf("Function: transIndexToCoords. GridImp Index: %d, size: %d. Exit Program!\n", index, size); + + x = (real)(index % nx); + y = (real)((index / nx) % ny); + z = (real)(((index / nx) / ny) % nz); + + x = (x * delta) + startX; + y = (y * delta) + startY; + z = (z * delta) + startZ; +} + +uint GridImp::getLevel(real startDelta) const +{ + uint level = 0; + real delta = this->delta; + while(!vf::Math::equal(delta, startDelta)) + { + delta *= 2; + level++; + } + return level; +} + +uint GridImp::getLevel() const +{ + return this->level; +} + +void GridImp::setTriangularMeshDiscretizationStrategy(TriangularMeshDiscretizationStrategy* triangularMeshDiscretizationStrategy) +{ + this->triangularMeshDiscretizationStrategy = triangularMeshDiscretizationStrategy; +} + +TriangularMeshDiscretizationStrategy * GridImp::getTriangularMeshDiscretizationStrategy() +{ + return this->triangularMeshDiscretizationStrategy; +} + +uint GridImp::getNumberOfSolidBoundaryNodes() const +{ + return this->numberOfSolidBoundaryNodes; +} + +void GridImp::setNumberOfSolidBoundaryNodes(uint numberOfSolidBoundaryNodes) +{ + if (numberOfSolidBoundaryNodes < INVALID_INDEX) + this->numberOfSolidBoundaryNodes = numberOfSolidBoundaryNodes; +} + +real GridImp::getQValue(const uint index, const uint dir) const +{ + const int qIndex = dir * this->numberOfSolidBoundaryNodes + this->qIndices[index]; + + return this->qValues[qIndex]; +} + +uint GridImp::getQPatch(const uint index) const +{ + return this->qPatches[ this->qIndices[index] ]; +} + +void GridImp::setInnerRegionFromFinerGrid(bool innerRegionFromFinerGrid) +{ + this->innerRegionFromFinerGrid = innerRegionFromFinerGrid; +} + +void GridImp::setNumberOfLayers(uint numberOfLayers) +{ + this->numberOfLayers = numberOfLayers; +} + +// --------------------------------------------------------- // +// Set Sparse Indices // +// --------------------------------------------------------- // + +void GridImp::findSparseIndices(SPtr<Grid> finerGrid) +{ + *logging::out << logging::Logger::INFO_INTERMEDIATE << "Find sparse indices..."; + auto fineGrid = std::static_pointer_cast<GridImp>(finerGrid); + + this->updateSparseIndices(); + +#pragma omp parallel for + for (int index = 0; index < (int)this->getSize(); index++) + this->setNeighborIndices(index); + + if (fineGrid) { + fineGrid->updateSparseIndices(); + } + + const uint newGridSize = this->getSparseSize(); + *logging::out << logging::Logger::INFO_INTERMEDIATE << "... done. new size: " << newGridSize + << ", delete nodes:" << this->getSize() - newGridSize << "\n"; +} + + +void GridImp::updateSparseIndices() +{ + int removedNodes = 0; + int newIndex = 0; + for (uint index = 0; index < size; index++) + { + if (this->field.isInvalidCoarseUnderFine(index) || this->field.isInvalidOutOfGrid(index) || this->field.isInvalidSolid(index)) + { + sparseIndices[index] = -1; + removedNodes++; + } + else + { + sparseIndices[index] = newIndex; + newIndex++; + } + } + sparseSize = size - removedNodes; +} + +void GridImp::setNeighborIndices(uint index) +{ + real x, y, z; + this->transIndexToCoords(index, x, y, z); + + this->neighborIndexX[index] = -1; + this->neighborIndexY[index] = -1; + this->neighborIndexZ[index] = -1; + this->neighborIndexNegative[index] = -1; + + if (this->field.isStopper(index) || this->field.is(index, STOPPER_OUT_OF_GRID_BOUNDARY)) + { + this->setStopperNeighborCoords(index); + return; + } + + if (this->sparseIndices[index] == -1) + return; + + + real neighborXCoord, neighborYCoord, neighborZCoord; + this->getNeighborCoords(neighborXCoord, neighborYCoord, neighborZCoord, x, y, z); + const int neighborX = getSparseIndex(neighborXCoord, y, z); + const int neighborY = getSparseIndex(x, neighborYCoord, z); + const int neighborZ = getSparseIndex(x, y, neighborZCoord); + + this->getNegativeNeighborCoords(neighborXCoord, neighborYCoord, neighborZCoord, x, y, z); + const int neighborNegative = getSparseIndex(neighborXCoord, neighborYCoord, neighborZCoord); + + this->neighborIndexX[index] = neighborX; + this->neighborIndexY[index] = neighborY; + this->neighborIndexZ[index] = neighborZ; + this->neighborIndexNegative[index] = neighborNegative; +} + +void GridImp::setStopperNeighborCoords(uint index) +{ + real x, y, z; + this->transIndexToCoords(index, x, y, z); + + if (vf::Math::lessEqual(x + delta, endX) && !this->field.isInvalidOutOfGrid(this->transCoordToIndex(x + delta, y, z))) + neighborIndexX[index] = getSparseIndex(x + delta, y, z); + + if (vf::Math::lessEqual(y + delta, endY) && !this->field.isInvalidOutOfGrid(this->transCoordToIndex(x, y + delta, z))) + neighborIndexY[index] = getSparseIndex(x, y + delta, z); + + if (vf::Math::lessEqual(z + delta, endZ) && !this->field.isInvalidOutOfGrid(this->transCoordToIndex(x, y, z + delta))) + neighborIndexZ[index] = getSparseIndex(x, y, z + delta); + + if (vf::Math::greaterEqual(x - delta, endX) && + vf::Math::greaterEqual(y - delta, endY) && + vf::Math::greaterEqual(z - delta, endZ) && + !this->field.isInvalidOutOfGrid(this->transCoordToIndex(x - delta, y - delta, z - delta))) + { + neighborIndexNegative[index] = getSparseIndex(x - delta, y - delta, z - delta); + } +} + +void GridImp::getNeighborCoords(real &neighborX, real &neighborY, real &neighborZ, real x, real y, real z) const +{ + real coords[3] = { x, y, z }; + neighborX = getNeighborCoord(periodicityX, startX, coords, 0); + neighborY = getNeighborCoord(periodicityY, startY, coords, 1); + neighborZ = getNeighborCoord(periodicityZ, startZ, coords, 2); +} + +real GridImp::getNeighborCoord(bool periodicity, real startCoord, real coords[3], int direction) const +{ + if (periodicity) + { + real neighborCoords[3] = {coords[0], coords[1] , coords[2] }; + neighborCoords[direction] = neighborCoords[direction] + delta; + const int neighborIndex = this->transCoordToIndex(neighborCoords[0], neighborCoords[1], neighborCoords[2]); + + ////////////////////////////////////////////////////////////////////////// + + if( field.is(neighborIndex, STOPPER_OUT_OF_GRID_BOUNDARY) ) + return getFirstFluidNode(coords, direction, startCoord); + else + return coords[direction] + delta; + + } + + return coords[direction] + delta; +} + +void GridImp::getNegativeNeighborCoords(real &neighborX, real &neighborY, real &neighborZ, real x, real y, real z) const +{ + real coords[3] = { x, y, z }; + + neighborX = getNegativeNeighborCoord(periodicityX, endX, coords, 0); + neighborY = getNegativeNeighborCoord(periodicityY, endY, coords, 1); + neighborZ = getNegativeNeighborCoord(periodicityZ, endZ, coords, 2); +} + +real GridImp::getNegativeNeighborCoord(bool periodicity, real startCoord, real coords[3], int direction) const +{ + if (periodicity) + { + real neighborCoords[3] = {coords[0], coords[1] , coords[2] }; + neighborCoords[direction] = neighborCoords[direction] - delta; + const uint neighborIndex = this->transCoordToIndex(neighborCoords[0], neighborCoords[1], neighborCoords[2]); + + if(neighborIndex != INVALID_INDEX && !field.isStopperOutOfGrid(neighborIndex) && !field.is(neighborIndex, STOPPER_OUT_OF_GRID_BOUNDARY) ) + return coords[direction] - delta; + + return getLastFluidNode(coords, direction, startCoord); + } + + return coords[direction] - delta; +} + + +real GridImp::getLastFluidNode(real coords[3], int direction, real startCoord) const +{ + coords[direction] = startCoord; + uint index = this->transCoordToIndex(coords[0], coords[1], coords[2]); + while (index != INVALID_INDEX && !field.isFluid(index)) + { + coords[direction] -= delta; + index = this->transCoordToIndex(coords[0], coords[1], coords[2]); + } + return coords[direction]; +} + +real GridImp::getFirstFluidNode(real coords[3], int direction, real startCoord) const +{ + coords[direction] = startCoord; + uint index = this->transCoordToIndex(coords[0], coords[1], coords[2]); + while (!field.isFluid(index)) + { + coords[direction] += delta; + index = this->transCoordToIndex(coords[0], coords[1], coords[2]); + } + return coords[direction]; +} + + +int GridImp::getSparseIndex(const real &x, const real &y, const real &z) const +{ + const int matrixIndex = transCoordToIndex(x, y, z); + return sparseIndices[matrixIndex]; +} + +// --------------------------------------------------------- // +// Find Interface // +// --------------------------------------------------------- // +void GridImp::findGridInterface(SPtr<Grid> finerGrid, LbmOrGks lbmOrGks) +{ + auto fineGrid = std::static_pointer_cast<GridImp>(finerGrid); + const auto coarseLevel = this->getLevel(); + const auto fineLevel = fineGrid->getLevel(); + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "find interface level " << coarseLevel << " -> " + << fineLevel; + + this->gridInterface = new GridInterface(); + // TODO: this is stupid! concave refinements can easily have many more interface cells + const uint sizeCF = 10 * (fineGrid->nx * fineGrid->ny + fineGrid->ny * fineGrid->nz + fineGrid->nx * fineGrid->nz); + this->gridInterface->cf.coarse = new uint[sizeCF]; + this->gridInterface->cf.fine = new uint[sizeCF]; + this->gridInterface->cf.offset = new uint[sizeCF]; + this->gridInterface->fc.coarse = new uint[sizeCF]; + this->gridInterface->fc.fine = new uint[sizeCF]; + this->gridInterface->fc.offset = new uint[sizeCF]; + + for (uint index = 0; index < this->getSize(); index++) + this->findGridInterfaceCF(index, *fineGrid, lbmOrGks); + + for (uint index = 0; index < this->getSize(); index++) + this->findGridInterfaceFC(index, *fineGrid); + + for (uint index = 0; index < this->getSize(); index++) + this->findOverlapStopper(index, *fineGrid); + + if (lbmOrGks == GKS) { + for (uint index = 0; index < this->getSize(); index++) + this->findInvalidBoundaryNodes(index); + } + + *logging::out << logging::Logger::INFO_INTERMEDIATE << " ... done. \n"; +} + +void GridImp::repairGridInterfaceOnMultiGPU(SPtr<Grid> fineGrid) +{ + this->gridInterface->repairGridInterfaceOnMultiGPU( shared_from_this(), std::static_pointer_cast<GridImp>(fineGrid) ); +} + +void GridImp::limitToSubDomain(SPtr<BoundingBox> subDomainBox, LbmOrGks lbmOrGks) +{ + for( uint index = 0; index < this->size; index++ ){ + + real x, y, z; + this->transIndexToCoords( index, x, y, z ); + + { + BoundingBox tmpSubDomainBox = *subDomainBox; + + // one layer for receive nodes and one for stoppers + if( lbmOrGks == LBM ) + tmpSubDomainBox.extend(this->delta); + + if (!tmpSubDomainBox.isInside(x, y, z) + && ( this->getFieldEntry(index) == FLUID || + this->getFieldEntry(index) == FLUID_CFC || + this->getFieldEntry(index) == FLUID_CFF || + this->getFieldEntry(index) == FLUID_FCC || + this->getFieldEntry(index) == FLUID_FCF || + this->getFieldEntry(index) == BC_SOLID ) ) + { + this->setFieldEntry(index, STOPPER_OUT_OF_GRID_BOUNDARY); + } + } + + { + BoundingBox tmpSubDomainBox = *subDomainBox; + + // one layer for receive nodes and one for stoppers + if( lbmOrGks == LBM ) + tmpSubDomainBox.extend(2.0 * this->delta); + else + tmpSubDomainBox.extend(1.0 * this->delta); + + if (!tmpSubDomainBox.isInside(x, y, z)) + this->setFieldEntry(index, INVALID_OUT_OF_GRID); + } + } +} + +void GridImp::findGridInterfaceCF(uint index, GridImp& finerGrid, LbmOrGks lbmOrGks) +{ + if (lbmOrGks == LBM) + { + gridInterface->findInterfaceCF (index, this, &finerGrid); + gridInterface->findBoundaryGridInterfaceCF(index, this, &finerGrid); + } + else if (lbmOrGks == GKS) + gridInterface->findInterfaceCF_GKS(index, this, &finerGrid); +} + +void GridImp::findGridInterfaceFC(uint index, GridImp& finerGrid) +{ + gridInterface->findInterfaceFC(index, this, &finerGrid); +} + +void GridImp::findOverlapStopper(uint index, GridImp& finerGrid) +{ + gridInterface->findOverlapStopper(index, this, &finerGrid); +} + +void GridImp::findInvalidBoundaryNodes(uint index) +{ + gridInterface->findInvalidBoundaryNodes(index, this); +} + +// --------------------------------------------------------- // +// Mesh Triangle // +// --------------------------------------------------------- // +void GridImp::mesh(Object* object) +{ + TriangularMesh* triangularMesh = dynamic_cast<TriangularMesh*>(object); + if (triangularMesh) + triangularMeshDiscretizationStrategy->discretize(triangularMesh, this, INVALID_SOLID, FLUID); + else + //new method for geometric primitives (not cell based) to be implemented + this->discretize(object, INVALID_SOLID, FLUID); + + this->closeNeedleCells(); + + #pragma omp parallel for + for (int index = 0; index < (int)this->size; index++) + this->findSolidStopperNode(index); + + //#pragma omp parallel for + for (int index = 0; index < (int)this->size; index++) { + this->findBoundarySolidNode(index); + } +} + + +void GridImp::mesh(TriangularMesh &triangularMesh) +{ + const clock_t begin = clock(); + +#pragma omp parallel for + for (int i = 0; i < triangularMesh.size; i++) + this->mesh(triangularMesh.triangles[i]); + + const clock_t end = clock(); + const real time = (real)(real(end - begin) / CLOCKS_PER_SEC); + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "time grid generation: " << time << "s\n"; +} + +void GridImp::mesh(Triangle &triangle) +{ + auto box = this->getBoundingBoxOnNodes(triangle); + triangle.initalLayerThickness(getDelta()); + + for (real x = box.minX; x <= box.maxX; x += delta) + { + for (real y = box.minY; y <= box.maxY; y += delta) + { + for (real z = box.minZ; z <= box.maxZ; z += delta) + { + const uint index = this->transCoordToIndex(x, y, z); + if (!field.isFluid(index)) + continue; + + const Vertex point(x, y, z); + const int value = triangle.isUnderFace(point); + //setDebugPoint(index, value); + + if (value == Q_DEPRECATED) + calculateQs(point, triangle); + } + } + } +} + +void GridImp::closeNeedleCells() +{ + *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start closeNeedleCells()\n"; + + uint numberOfClosedNeedleCells = 0; + + do{ +#pragma omp parallel for reduction(+ : numberOfClosedNeedleCells) + for (int index = 0; index < (int)this->size; index++) { + if (this->closeCellIfNeedle(index)) + numberOfClosedNeedleCells++; + } + + *logging::out << logging::Logger::INFO_INTERMEDIATE << numberOfClosedNeedleCells << " cells closed!\n"; + } + while( numberOfClosedNeedleCells > 0 ); +} + +bool GridImp::closeCellIfNeedle(uint index) +{ + if( !this->getField().is( index, FLUID ) ) return false; + + real x, y, z; + this->transIndexToCoords(index, x, y, z); + + bool noValidNeighborInX = this->getField().is( this->transCoordToIndex( x + this->delta, y, z ) , INVALID_SOLID ) && + this->getField().is( this->transCoordToIndex( x - this->delta, y, z ) , INVALID_SOLID ); + bool noValidNeighborInY = this->getField().is( this->transCoordToIndex( x, y + this->delta, z ) , INVALID_SOLID ) && + this->getField().is( this->transCoordToIndex( x, y - this->delta, z ) , INVALID_SOLID ); + bool noValidNeighborInZ = this->getField().is( this->transCoordToIndex( x, y, z + this->delta ) , INVALID_SOLID ) && + this->getField().is( this->transCoordToIndex( x, y, z - this->delta ) , INVALID_SOLID ); + + if( noValidNeighborInX || noValidNeighborInY || noValidNeighborInZ ){ + this->setFieldEntry(index, INVALID_SOLID); + return true; + } + + return false; +} + +void GridImp::closeNeedleCellsThinWall() +{ + *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start closeNeedleCellsThinWall()\n"; + + uint numberOfClosedNeedleCells = 0; + + do{ +#pragma omp parallel for reduction(+ : numberOfClosedNeedleCells) + for (int index = 0; index < (int)this->size; index++) { + if (this->closeCellIfNeedleThinWall(index)) + numberOfClosedNeedleCells++; + } + + *logging::out << logging::Logger::INFO_INTERMEDIATE << numberOfClosedNeedleCells << " cells closed!\n"; + } + while( numberOfClosedNeedleCells > 0 ); +} + +bool GridImp::closeCellIfNeedleThinWall(uint index) +{ + if( !this->getField().is( index, BC_SOLID ) ) return false; + + real x, y, z; + this->transIndexToCoords(index, x, y, z); + + if( !this->hasNeighborOfType(index, FLUID) ){ + this->setFieldEntry(index, STOPPER_SOLID); + return true; + } + + return false; +} + + + +void GridImp::findQs(Object* object) //TODO: enable qs for primitive objects +{ + TriangularMesh* triangularMesh = dynamic_cast<TriangularMesh*>(object); + if (triangularMesh) + findQs(*triangularMesh); + else + findQsPrimitive(object); +} + +void GridImp::allocateQs() +{ + this->qPatches = new uint[this->getNumberOfSolidBoundaryNodes()]; + + for (uint i = 0; i < this->getNumberOfSolidBoundaryNodes(); i++) + this->qPatches[i] = INVALID_INDEX; + + const uint numberOfQs = this->getNumberOfSolidBoundaryNodes() * (this->distribution.dir_end + 1); + this->qValues = new real[numberOfQs]; +#pragma omp parallel for + for (int i = 0; i < (int)numberOfQs; i++) + this->qValues[i] = -1.0; +} + +void GridImp::findQs(TriangularMesh &triangularMesh) +{ + const clock_t begin = clock(); + + if( this->qComputationStage == qComputationStageType::ComputeQs ) + allocateQs(); + + +#pragma omp parallel for + for (int i = 0; i < triangularMesh.size; i++) + this->findQs(triangularMesh.triangles[i]); + + const clock_t end = clock(); + const real time = (real)(real(end - begin) / CLOCKS_PER_SEC); + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "time finding qs: " << time << "s\n"; +} + +void GridImp::findQs(Triangle &triangle) +{ + auto box = this->getBoundingBoxOnNodes(triangle); + triangle.initalLayerThickness(getDelta()); + + for (real x = box.minX; x <= box.maxX; x += delta) + { + for (real y = box.minY; y <= box.maxY; y += delta) + { + for (real z = box.minZ; z <= box.maxZ; z += delta) + { + const uint index = this->transCoordToIndex(x, y, z); + //if (!field.isFluid(index)) + // continue; + + if( index == INVALID_INDEX ) continue; + + const Vertex point(x, y, z); + + if( this->qComputationStage == qComputationStageType::ComputeQs ){ + if(this->field.is(index, BC_SOLID)) + { + calculateQs(index, point, triangle); + } + } + else if( this->qComputationStage == qComputationStageType::FindSolidBoundaryNodes ) + { + //if( this->field.is(index, BC_SOLID) || this->field.is(index, STOPPER_SOLID ) ) continue; + + if( !this->field.is(index, FLUID) ) continue; + + if( checkIfAtLeastOneValidQ(index, point, triangle) ) + { + // similar as in void GridImp::findBoundarySolidNode(uint index) + this->field.setFieldEntry( index, BC_SOLID ); + this->qIndices[index] = this->numberOfSolidBoundaryNodes++; + } + } + } + } + } +} + +void GridImp::findQsPrimitive(Object * object) +{ + + if( this->qComputationStage == qComputationStageType::ComputeQs ) + allocateQs(); + + + for( int index = 0; index < (int)this->size; index++ ) + { + + if( this->qIndices[index] == INVALID_INDEX ) continue; + + real x,y,z; + + this->transIndexToCoords(index,x,y,z); + + const Vertex point(x, y, z); + + if( this->qComputationStage == qComputationStageType::ComputeQs ){ + if(this->field.is(index, BC_SOLID)) + { + calculateQs(index, point, object); + } + } + else if( this->qComputationStage == qComputationStageType::FindSolidBoundaryNodes ) + { + if( !this->field.is(index, FLUID) ) continue; + + if( checkIfAtLeastOneValidQ(index, point, object) ) + { + // similar as in void GridImp::findBoundarySolidNode(uint index) + this->field.setFieldEntry( index, BC_SOLID ); + this->qIndices[index] = this->numberOfSolidBoundaryNodes++; + } + } + + } +} + +void GridImp::calculateQs(const uint index, const Vertex &point, Object* object) const +{ + Vertex pointOnTriangle, direction; + + real subdistance; + int error; + for (int i = distribution.dir_start; i <= distribution.dir_end; i++) + { + direction = Vertex( real(distribution.dirs[i * DIMENSION + 0]), + real(distribution.dirs[i * DIMENSION + 1]), + real(distribution.dirs[i * DIMENSION + 2]) ); + + uint neighborIndex = this->transCoordToIndex(point.x + direction.x * this->delta, + point.y + direction.y * this->delta, + point.z + direction.z * this->delta); + + if (neighborIndex == INVALID_INDEX) continue; + + error = object->getIntersection(point, direction, pointOnTriangle, subdistance); + + subdistance /= this->delta; + + if (error == 0 && vf::Math::lessEqual(subdistance, 1.0) && vf::Math::greaterEqual(subdistance, 0.0)) + { + if ( -0.5 > this->qValues[i*this->numberOfSolidBoundaryNodes + this->qIndices[index]] || + subdistance < this->qValues[i*this->numberOfSolidBoundaryNodes + this->qIndices[index]] ) + { + + this->qValues[i*this->numberOfSolidBoundaryNodes + this->qIndices[index]] = subdistance; + + this->qPatches[ this->qIndices[index] ] = 0; + + //printf("%d %f \n", this->qIndices[index], subdistance); + } + } + } +} + +bool GridImp::checkIfAtLeastOneValidQ(const uint index, const Vertex &point, Object* object) const +{ + Vertex pointOnTriangle, direction; + + real subdistance; + int error; + for (int i = distribution.dir_start; i <= distribution.dir_end; i++) + { + direction = Vertex( real(distribution.dirs[i * DIMENSION + 0]), + real(distribution.dirs[i * DIMENSION + 1]), + real(distribution.dirs[i * DIMENSION + 2]) ); + + uint neighborIndex = this->transCoordToIndex(point.x + direction.x * this->delta, + point.y + direction.y * this->delta, + point.z + direction.z * this->delta); + + if (neighborIndex == INVALID_INDEX) continue; + + error = object->getIntersection(point, direction, pointOnTriangle, subdistance); + + subdistance /= this->delta; + + if (error == 0 && vf::Math::lessEqual(subdistance, 1.0) && vf::Math::greaterEqual(subdistance, 0.0)) + { + return true; + } + } + return false; +} + +void GridImp::setDebugPoint(uint index, int pointValue) +{ + if (field.isInvalidCoarseUnderFine(index) && pointValue == INVALID_SOLID) + field.setFieldEntry(index, pointValue); + + if(!field.isInvalidSolid(index) && !field.isQ(index) && !field.isInvalidCoarseUnderFine(index) && pointValue != 3 && pointValue != 2) + field.setFieldEntry(index, pointValue); +} + +void GridImp::calculateQs(const Vertex &point, const Triangle &triangle) const // NOT USED !!!! +{ + Vertex pointOnTriangle, direction; + real subdistance; + int error; + for (int i = distribution.dir_start; i <= distribution.dir_end; i++) + { +#if defined(__CUDA_ARCH__) + direction = Vertex(DIRECTIONS[i][0], DIRECTIONS[i][1], DIRECTIONS[i][2]); +#else + direction = Vertex(real(distribution.dirs[i * DIMENSION + 0]), real(distribution.dirs[i * DIMENSION + 1]), + real(distribution.dirs[i * DIMENSION + 2])); +#endif + + error = triangle.getTriangleIntersection(point, direction, pointOnTriangle, subdistance); + + subdistance /= this->delta; + + if (error == 0 && subdistance < 1.0 && subdistance > 0.0) + { + distribution.f[i*size + transCoordToIndex(point.x, point.y, point.z)] = subdistance; + } + } +} + + +void GridImp::calculateQs(const uint index, const Vertex &point, const Triangle &triangle) const +{ + Vertex pointOnTriangle, direction; + real subdistance; + int error; + for (int i = distribution.dir_start; i <= distribution.dir_end; i++) + { +#if defined(__CUDA_ARCH__) + direction = Vertex(DIRECTIONS[i][0], DIRECTIONS[i][1], DIRECTIONS[i][2]); +#else + direction = Vertex( real(distribution.dirs[i * DIMENSION + 0]), + real(distribution.dirs[i * DIMENSION + 1]), + real(distribution.dirs[i * DIMENSION + 2]) ); +#endif + + uint neighborIndex = this->transCoordToIndex(point.x + direction.x * this->delta, + point.y + direction.y * this->delta, + point.z + direction.z * this->delta); + + if (neighborIndex == INVALID_INDEX) continue; + + error = triangle.getTriangleIntersection(point, direction, pointOnTriangle, subdistance); + + subdistance /= this->delta; + + if (error == 0 && vf::Math::lessEqual(subdistance, 1.0) && vf::Math::greaterEqual(subdistance, 0.0)) + { + if ( -0.5 > this->qValues[i*this->numberOfSolidBoundaryNodes + this->qIndices[index]] || + subdistance < this->qValues[i*this->numberOfSolidBoundaryNodes + this->qIndices[index]] ) + { + this->qValues[i*this->numberOfSolidBoundaryNodes + this->qIndices[index]] = subdistance; + + this->qPatches[ this->qIndices[index] ] = triangle.patchIndex; + } + } + } +} + +bool GridImp::checkIfAtLeastOneValidQ(const uint index, const Vertex & point, const Triangle & triangle) const +{ + Vertex pointOnTriangle, direction; + real subdistance; + int error; + for (int i = distribution.dir_start; i <= distribution.dir_end; i++) + { +#if defined(__CUDA_ARCH__) + direction = Vertex(DIRECTIONS[i][0], DIRECTIONS[i][1], DIRECTIONS[i][2]); +#else + direction = Vertex(real(distribution.dirs[i * DIMENSION + 0]), + real(distribution.dirs[i * DIMENSION + 1]), + real(distribution.dirs[i * DIMENSION + 2])); +#endif + + uint neighborIndex = this->transCoordToIndex(point.x + direction.x * this->delta, + point.y + direction.y * this->delta, + point.z + direction.z * this->delta); + if (neighborIndex == INVALID_INDEX) continue; + + error = triangle.getTriangleIntersection(point, direction, pointOnTriangle, subdistance); + + subdistance /= this->delta; + + if (error == 0 && vf::Math::lessEqual(subdistance, 1.0) && vf::Math::greaterEqual(subdistance, 0.0)) + { + return true; + } + } + return false; +} + +void GridImp::findCommunicationIndices(int direction, SPtr<BoundingBox> subDomainBox, LbmOrGks lbmOrGks) +{ + for( uint index = 0; index < this->size; index++ ){ + + real x, y, z; + this->transIndexToCoords(index, x, y, z); + + if( this->getFieldEntry(index) == INVALID_OUT_OF_GRID || + this->getFieldEntry(index) == INVALID_SOLID || + this->getFieldEntry(index) == INVALID_COARSE_UNDER_FINE || + this->getFieldEntry(index) == STOPPER_OUT_OF_GRID || + this->getFieldEntry(index) == STOPPER_COARSE_UNDER_FINE ) continue; + + if( lbmOrGks == LBM && this->getFieldEntry(index) == STOPPER_OUT_OF_GRID_BOUNDARY ) continue; + if( lbmOrGks == LBM && this->getFieldEntry(index) == STOPPER_SOLID ) continue; + + if( direction == CommunicationDirections::MX ) findCommunicationIndex( index, x, subDomainBox->minX, direction); + if( direction == CommunicationDirections::PX ) findCommunicationIndex( index, x, subDomainBox->maxX, direction); + if( direction == CommunicationDirections::MY ) findCommunicationIndex( index, y, subDomainBox->minY, direction); + if( direction == CommunicationDirections::PY ) findCommunicationIndex( index, y, subDomainBox->maxY, direction); + if( direction == CommunicationDirections::MZ ) findCommunicationIndex( index, z, subDomainBox->minZ, direction); + if( direction == CommunicationDirections::PZ ) findCommunicationIndex( index, z, subDomainBox->maxZ, direction); + } +} + +void GridImp::findCommunicationIndex( uint index, real coordinate, real limit, int direction ){ + // negative direction get a negative sign + real s = ( direction % 2 == 0 ) ? ( -1.0 ) : ( 1.0 ); + + + if (std::abs(coordinate - (limit + s * 0.5 * this->delta)) < 0.1 * this->delta) { + this->communicationIndices[direction].receiveIndices.push_back(index); + } + + if (std::abs(coordinate - (limit - s * 0.5 * this->delta)) < 0.1 * this->delta) { + this->communicationIndices[direction].sendIndices.push_back(index); + } +} + +uint GridImp::getNumberOfSendNodes(int direction) +{ + return (uint)this->communicationIndices[direction].sendIndices.size(); +} + +uint GridImp::getNumberOfReceiveNodes(int direction) +{ + return (uint)this->communicationIndices[direction].receiveIndices.size(); +} + +uint GridImp::getSendIndex(int direction, uint index) +{ + return this->communicationIndices[direction].sendIndices[ index ]; +} + +uint GridImp::getReceiveIndex(int direction, uint index) +{ + return this->communicationIndices[direction].receiveIndices[ index ]; +} + +void GridImp::repairCommunicationInices(int direction ) +{ + this->communicationIndices[direction].sendIndices.insert( this->communicationIndices[direction].sendIndices.end(), + this->communicationIndices[direction+1].sendIndices.begin(), + this->communicationIndices[direction+1].sendIndices.end() ); + + + + this->communicationIndices[direction+1].receiveIndices.insert( this->communicationIndices[direction+1].receiveIndices.end(), + this->communicationIndices[direction].receiveIndices.begin(), + this->communicationIndices[direction].receiveIndices.end() ); + + this->communicationIndices[direction].receiveIndices = this->communicationIndices[direction+1].receiveIndices; + + + + + + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "size send " << (int)this->communicationIndices[direction].sendIndices.size() << "\n"; + *logging::out << logging::Logger::INFO_INTERMEDIATE << "recv send " << (int)this->communicationIndices[direction].receiveIndices.size() << "\n"; +} + + +// --------------------------------------------------------- // +// Getter // +// --------------------------------------------------------- // +int GridImp::getSparseIndex(uint matrixIndex) const +{ + return this->sparseIndices[matrixIndex]; +} + +real* GridImp::getDistribution() const +{ + return this->distribution.f; +} + +int* GridImp::getDirection() const +{ + return this->distribution.dirs; +} + +int GridImp::getStartDirection() const +{ + return this->distribution.dir_start; +} + +int GridImp::getEndDirection() const +{ + return this->distribution.dir_end; +} + +BoundingBox GridImp::getBoundingBoxOnNodes(Triangle &triangle) const +{ + real minX, maxX, minY, maxY, minZ, maxZ; + triangle.setMinMax(minX, maxX, minY, maxY, minZ, maxZ); + + int minXIndex = std::lround(floor((minX - this->startX) / this->delta)) - 1; + int minYIndex = std::lround(floor((minY - this->startY) / this->delta)) - 1; + int minZIndex = std::lround(floor((minZ - this->startZ) / this->delta)) - 1; + + int maxXIndex = std::lround(ceil((maxX - this->startX) / this->delta)) + 1; + int maxYIndex = std::lround(ceil((maxY - this->startY) / this->delta)) + 1; + int maxZIndex = std::lround(ceil((maxZ - this->startZ) / this->delta)) + 1; + + minX = this->startX + minXIndex * this->delta; + minY = this->startY + minYIndex * this->delta; + minZ = this->startZ + minZIndex * this->delta; + + maxX = this->startX + maxXIndex * this->delta; + maxY = this->startY + maxYIndex * this->delta; + maxZ = this->startZ + maxZIndex * this->delta; + + return BoundingBox(minX, maxX, minY, maxY, minZ, maxZ); +} + +Vertex GridImp::getMinimumOnNode(Vertex exact) const // deprecated +{ + const real minX = getMinimumOnNodes(exact.x, vf::Math::getDecimalPart(startX), delta); + const real minY = getMinimumOnNodes(exact.y, vf::Math::getDecimalPart(startY), delta); + const real minZ = getMinimumOnNodes(exact.z, vf::Math::getDecimalPart(startZ), delta); + return Vertex(minX, minY, minZ); +} + +real GridImp::getMinimumOnNodes(const real &minExact, const real &decimalStart, const real &delta) // deprecated +{ + real minNode = ceil(minExact - 1.0); + minNode += decimalStart; + while (minNode > minExact) + minNode -= delta; + + while (minNode + delta < minExact) + minNode += delta; + return minNode; +} + +Vertex GridImp::getMaximumOnNode(Vertex exact) const // deprecated +{ + const real maxX = getMaximumOnNodes(exact.x, vf::Math::getDecimalPart(startX), delta); + const real maxY = getMaximumOnNodes(exact.y, vf::Math::getDecimalPart(startY), delta); + const real maxZ = getMaximumOnNodes(exact.z, vf::Math::getDecimalPart(startZ), delta); + return Vertex(maxX, maxY, maxZ); +} + +real GridImp::getMaximumOnNodes(const real &maxExact, const real &decimalStart, const real &delta) // deprecated +{ + real maxNode = ceil(maxExact - 1.0); + maxNode += decimalStart; + + while (maxNode <= maxExact) + maxNode += delta; + return maxNode; +} + +uint GridImp::getXIndex(real x) const +{ + return std::lround((x - startX) / delta); +} + +uint GridImp::getYIndex(real y) const +{ + return std::lround((y - startY) / delta); +} + +uint GridImp::getZIndex(real z) const +{ + return std::lround((z - startZ) / delta); +} + +real GridImp::getDelta() const +{ + return delta; +} + +uint GridImp::getSize() const +{ + return this->size; +} + +uint GridImp::getSparseSize() const +{ + return this->sparseSize; +} + +Field GridImp::getField() const +{ + return this->field; +} + +char GridImp::getFieldEntry(uint index) const +{ + return this->field.getFieldEntry(index); +} + +void GridImp::setFieldEntry(uint matrixIndex, char type) +{ + this->field.setFieldEntry(matrixIndex, type); +} + + +real GridImp::getStartX() const +{ + return startX; +} + +real GridImp::getStartY() const +{ + return startY; +} + +real GridImp::getStartZ() const +{ + return startZ; +} + +real GridImp::getEndX() const +{ + return endX; +} + +real GridImp::getEndY() const +{ + return endY; +} + +real GridImp::getEndZ() const +{ + return endZ; +} + +uint GridImp::getNumberOfNodesX() const +{ + return nx; +} + +uint GridImp::getNumberOfNodesY() const +{ + return ny; +} + +uint GridImp::getNumberOfNodesZ() const +{ + return nz; +} + + +int* GridImp::getNeighborsX() const +{ + return this->neighborIndexX; +} + +int* GridImp::getNeighborsY() const +{ + return this->neighborIndexY; +} + +int* GridImp::getNeighborsZ() const +{ + return this->neighborIndexZ; +} + +int* GridImp::getNeighborsNegative() const +{ + return this->neighborIndexNegative; +} + +uint GridImp::getNumberOfNodesCF() const +{ + if(this->gridInterface) + return this->gridInterface->cf.numberOfEntries; + return 0; +} + +uint GridImp::getNumberOfNodesFC() const +{ + if (this->gridInterface) + return this->gridInterface->fc.numberOfEntries; + return 0; +} + +uint* GridImp::getCF_coarse() const +{ + return this->gridInterface->cf.coarse; +} + +uint* GridImp::getCF_fine() const +{ + return this->gridInterface->cf.fine; +} + +uint * GridImp::getCF_offset() const +{ + return this->gridInterface->cf.offset; +} + +uint* GridImp::getFC_coarse() const +{ + return this->gridInterface->fc.coarse; +} + +uint* GridImp::getFC_fine() const +{ + return this->gridInterface->fc.fine; +} + +uint * GridImp::getFC_offset() const +{ + return this->gridInterface->fc.offset; +} + +void GridImp::getGridInterfaceIndices(uint* iCellCfc, uint* iCellCff, uint* iCellFcc, uint* iCellFcf) const +{ + getGridInterface(iCellCfc, this->gridInterface->cf.coarse, this->gridInterface->cf.numberOfEntries); + getGridInterface(iCellCff, this->gridInterface->cf.fine, this->gridInterface->cf.numberOfEntries); + getGridInterface(iCellFcc, this->gridInterface->fc.coarse, this->gridInterface->fc.numberOfEntries); + getGridInterface(iCellFcf, this->gridInterface->fc.fine, this->gridInterface->fc.numberOfEntries); +} + +void GridImp::getGridInterface(uint* gridInterfaceList, const uint* oldGridInterfaceList, uint size) +{ + for (uint i = 0; i < size; i++) + gridInterfaceList[i] = oldGridInterfaceList[i] + 1; // + 1 for numbering shift between GridGenerator and VF_GPU +} + +#define GEOFLUID 19 +#define GEOSOLID 16 + +void GridImp::getNodeValues(real *xCoords, real *yCoords, real *zCoords, uint *neighborX, uint *neighborY, uint *neighborZ, uint *neighborNegative, uint *geo) const +{ + xCoords[0] = 0; + yCoords[0] = 0; + zCoords[0] = 0; + neighborX[0] = 0; + neighborY[0] = 0; + neighborZ[0] = 0; + geo[0] = GEOSOLID; + + int nodeNumber = 0; + for (uint i = 0; i < this->getSize(); i++) + { + if (this->sparseIndices[i] == -1) + continue; + + real x, y, z; + this->transIndexToCoords(i, x, y, z); + + // + 1 for numbering shift between GridGenerator and VF_GPU + const uint neighborXIndex = uint(this->neighborIndexX[i] + 1); + const uint neighborYIndex = uint(this->neighborIndexY[i] + 1); + const uint neighborZIndex = uint(this->neighborIndexZ[i] + 1); + const uint neighborNegativeIndex = uint(this->neighborIndexNegative[i] + 1); + + const uint type = uint(this->field.isFluid(i) ? GEOFLUID : GEOSOLID); + + xCoords[nodeNumber + 1] = x; + yCoords[nodeNumber + 1] = y; + zCoords[nodeNumber + 1] = z; + + neighborX [nodeNumber + 1] = neighborXIndex; + neighborY [nodeNumber + 1] = neighborYIndex; + neighborZ [nodeNumber + 1] = neighborZIndex; + neighborNegative[nodeNumber + 1] = neighborNegativeIndex; + + geo[nodeNumber + 1] = type; + nodeNumber++; + } +} + +void GridImp::print() const +{ + printf("min: (%2.4f, %2.4f, %2.4f), max: (%2.4f, %2.4f, %2.4f), size: %d, delta: %2.4f\n", startX, startY, startZ, + endX, endY, endZ, size, delta); + if(this->gridInterface) + this->gridInterface->print(); +} \ No newline at end of file diff --git a/src/gpu/GridGenerator/grid/GridImp.cu b/src/gpu/GridGenerator/grid/GridImp.cu deleted file mode 100644 index 2684893e37a7336ee00ff75d52a9821727c6be4a..0000000000000000000000000000000000000000 --- a/src/gpu/GridGenerator/grid/GridImp.cu +++ /dev/null @@ -1,866 +0,0 @@ -//======================================================================================= -// ____ ____ __ ______ __________ __ __ __ __ -// \ \ | | | | | _ \ |___ ___| | | | | / \ | | -// \ \ | | | | | |_) | | | | | | | / \ | | -// \ \ | | | | | _ / | | | | | | / /\ \ | | -// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ -// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| -// \ \ | | ________________________________________________________________ -// \ \ | | | ______________________________________________________________| -// \ \| | | | __ __ __ __ ______ _______ -// \ | | |_____ | | | | | | | | | _ \ / _____) -// \ | | _____| | | | | | | | | | | \ \ \_______ -// \ | | | | |_____ | \_/ | | | | |_/ / _____ | -// \ _____| |__| |________| \_______/ |__| |______/ (_______/ -// -// This file is part of VirtualFluids. VirtualFluids is free software: you can -// redistribute it and/or modify it under the terms of the GNU General Public -// License as published by the Free Software Foundation, either version 3 of -// the License, or (at your option) any later version. -// -// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -// for more details. -// -// You should have received a copy of the GNU General Public License along -// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. -// -//! \file GridImp.cu -//! \ingroup grid -//! \author Soeren Peters, Stephan Lenz -//======================================================================================= -#include "GridImp.h" - -#include <stdio.h> -#include <time.h> -#include <iostream> -#include <omp.h> -#include <sstream> - -#include "global.h" - -#include "geometries/Object.h" -#include "geometries/Vertex/Vertex.h" -#include "geometries/BoundingBox/BoundingBox.h" - -#include "grid/GridStrategy/GridStrategy.h" -#include "grid/distributions/Distribution.h" -#include "grid/Field.h" -#include "grid/NodeValues.h" - -#include "utilities/math/Math.h" - -int DIRECTIONS[DIR_END_MAX][DIMENSION]; - - -GridImp::GridImp(Object* object, real startX, real startY, real startZ, real endX, real endY, real endZ, real delta, SPtr<GridStrategy> gridStrategy, Distribution distribution, uint level) - : object(object), - startX(startX), - startY(startY), - startZ(startZ), - endX(endX), - endY(endY), - endZ(endZ), - delta(delta), - gridStrategy(gridStrategy), - distribution(distribution), - level(level), - periodicityX(false), - periodicityY(false), - periodicityZ(false), - neighborIndexX(nullptr), - neighborIndexY(nullptr), - neighborIndexZ(nullptr), - neighborIndexNegative(nullptr), - sparseIndices(nullptr) -{ - initalNumberOfNodesAndSize(); -} - -SPtr<GridImp> GridImp::makeShared(Object* object, real startX, real startY, real startZ, real endX, real endY, real endZ, real delta, SPtr<GridStrategy> gridStrategy, Distribution d, uint level) -{ - SPtr<GridImp> grid(new GridImp(object, startX, startY, startZ, endX, endY, endZ, delta, gridStrategy, d, level)); - return grid; -} - - -void GridImp::initalNumberOfNodesAndSize() -{ - const real length = endX - startX; - const real width = endY - startY; - const real height = endZ - startZ; - - nx = lround((length + delta) / delta); - ny = lround((width + delta) / delta); - nz = lround((height + delta) / delta); - - this->size = nx * ny * nz; - this->sparseSize = size; - distribution.setSize(size); -} - -void GridImp::inital(const SPtr<Grid> fineGrid, uint numberOfLayers) -{ - field = Field(gridStrategy, size); - field.allocateMemory(); - gridStrategy->allocateGridMemory(shared_from_this()); - - *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start initalNodesToOutOfGrid()\n"; - gridStrategy->initalNodesToOutOfGrid(shared_from_this()); - - *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start findInnerNodes()\n"; - this->object->findInnerNodes( shared_from_this() ); - - *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start findEndOfGridStopperNodes()\n"; - gridStrategy->findEndOfGridStopperNodes(shared_from_this()); - - *logging::out << logging::Logger::INFO_INTERMEDIATE - << "Grid created: " << "from (" << this->startX << ", " << this->startY << ", " << this->startZ << ") to (" << this->endX << ", " << this->endY << ", " << this->endZ << ")\n" - << "nodes: " << this->nx << " x " << this->ny << " x " << this->nz << " = " << this->size << "\n"; -} - -void GridImp::initalNodeToOutOfGrid(uint index) -{ - this->field.setFieldEntryToInvalidOutOfGrid(index); -} - -void GridImp::freeMemory() -{ - gridStrategy->freeMemory(shared_from_this()); -} - -GridImp::GridImp() -{ -} - -GridImp::~GridImp() -{ -} - -void GridImp::findInnerNode(uint index) -{ - this->sparseIndices[index] = index; - - real x, y, z; - this->transIndexToCoords(index, x, y, z); - const uint xIndex = getXIndex(x); - const uint yIndex = getYIndex(y); - const uint zIndex = getZIndex(z); - - if( xIndex != 0 && xIndex != this->nx-1 && - yIndex != 0 && yIndex != this->ny-1 && - zIndex != 0 && zIndex != this->nz-1 ) - this->field.setFieldEntryToFluid(index); -} - -void GridImp::findEndOfGridStopperNode(uint index) -{ - if (isValidEndOfGridStopper(index)){ - if( this->level != 0 ) - this->field.setFieldEntryToStopperOutOfGrid(index); - else - this->field.setFieldEntryToStopperOutOfGridBoundary(index); - } - - if (isValidEndOfGridBoundaryStopper(index)) - this->field.setFieldEntryToStopperOutOfGridBoundary(index); -} - -bool GridImp::isOutSideOfGrid(Cell &cell) const -{ - for (const auto point : cell) { - if (point.x < startX || point.x > endX - || point.y < startY || point.y > endY - || point.z < startZ || point.z > endZ) - return true; - } - return false; -} - -bool GridImp::contains(Cell &cell, char type) const -{ - for (const auto point : cell) { - uint index = transCoordToIndex(point.x, point.y, point.z); - if (index == INVALID_INDEX) - continue; - if (field.is(index, type)) - return true; - } - return false; -} - -bool GridImp::cellContainsOnly(Cell &cell, char type) const -{ - for (const auto point : cell) { - uint index = transCoordToIndex(point.x, point.y, point.z); - if (index == INVALID_INDEX) - return false; - if (!field.is(index, type)) - return false; - } - return true; -} - -bool GridImp::cellContainsOnly(Cell &cell, char typeA, char typeB) const -{ - for (const auto point : cell) { - uint index = transCoordToIndex(point.x, point.y, point.z); - if (index == INVALID_INDEX) - return false; - if (!field.is(index, typeA) && !field.is(index, typeB)) - return false; - } - return true; -} - -const Object * GridImp::getObject() const -{ - return this->object; -} - -void GridImp::setNodeTo(Cell &cell, char type) -{ - for (const auto point : cell) { - uint index = transCoordToIndex(point.x, point.y, point.z); - if (index == INVALID_INDEX) - continue; - field.setFieldEntry(index, type); - } -} - -void GridImp::setNodeTo(uint index, char type) -{ - if( index != INVALID_INDEX ) - field.setFieldEntry(index, type); -} - -bool GridImp::isNode(uint index, char type) const -{ - if( index != INVALID_INDEX ) - return field.is(index, type); - - throw std::runtime_error("GridImp::isNode() -> index == INVALID_INDEX not supported."); -} - -bool GridImp::isValidEndOfGridStopper(uint index) const -{ - // Lenz: also includes corner stopper nodes - if (!this->field.is(index, INVALID_OUT_OF_GRID)) - return false; - - return hasNeighborOfType(index, FLUID); -} - -bool GridImp::isValidEndOfGridBoundaryStopper(uint index) const -{ - // Lenz: also includes corner stopper nodes - if (!this->field.is(index, FLUID)) - return false; - - return ! hasAllNeighbors(index); -} - -bool GridImp::isValidSolidStopper(uint index) const -{ - // Lenz: also includes corner stopper nodes - if (!this->field.is(index, INVALID_SOLID)) - return false; - - return hasNeighborOfType(index, FLUID); -} - -bool GridImp::shouldBeBoundarySolidNode(uint index) const -{ - if (!this->field.is(index, FLUID)) - return false; - - return hasNeighborOfType(index, STOPPER_SOLID); -} - -bool GridImp::hasAllNeighbors(uint index) const -{ - // new version by Lenz, utilizes the range based for loop for all directions - real x, y, z; - this->transIndexToCoords(index, x, y, z); - for (const auto dir : this->distribution) { - const uint neighborIndex = this->transCoordToIndex(x + dir[0] * this->getDelta(), y + dir[1] * this->getDelta(), z + dir[2] * this->getDelta()); - - if (neighborIndex == INVALID_INDEX) return false; - } - - return true; -} - -bool GridImp::hasNeighborOfType(uint index, char type) const -{ - // new version by Lenz, utilizes the range based for loop for all directions - real x, y, z; - this->transIndexToCoords(index, x, y, z); - for (const auto dir : this->distribution) { - const uint neighborIndex = this->transCoordToIndex(x + dir[0] * this->getDelta(), y + dir[1] * this->getDelta(), z + dir[2] * this->getDelta()); - - if (neighborIndex == INVALID_INDEX) continue; - - if (this->field.is(neighborIndex, type)) - return true; - } - - return false; -} - -bool GridImp::nodeInNextCellIs(int index, char type) const -{ - real x, y, z; - this->transIndexToCoords(index, x, y, z); - - const real neighborX = x + this->delta > endX ? endX : x + this->delta; - const real neighborY = y + this->delta > endY ? endY : y + this->delta; - const real neighborZ = z + this->delta > endZ ? endZ : z + this->delta; - - const uint indexX = transCoordToIndex(neighborX, y, z); - const uint indexY = transCoordToIndex(x, neighborY, z); - const uint indexZ = transCoordToIndex(x, y, neighborZ); - - const uint indexXY = transCoordToIndex(neighborX, neighborY, z); - const uint indexYZ = transCoordToIndex(x, neighborY, neighborZ); - const uint indexXZ = transCoordToIndex(neighborX, y, neighborZ); - - const uint indexXYZ = transCoordToIndex(neighborX, neighborY, neighborZ); - - const bool typeX = indexX == INVALID_INDEX ? false : this->field.is(indexX, type); - const bool typeY = indexY == INVALID_INDEX ? false : this->field.is(indexY, type); - const bool typeXY = indexXY == INVALID_INDEX ? false : this->field.is(indexXY, type); - const bool typeZ = indexZ == INVALID_INDEX ? false : this->field.is(indexZ, type); - const bool typeYZ = indexYZ == INVALID_INDEX ? false : this->field.is(indexYZ, type); - const bool typeXZ = indexXZ == INVALID_INDEX ? false : this->field.is(indexXZ, type); - const bool typeXYZ = indexXYZ == INVALID_INDEX ? false : this->field.is(indexXYZ, type); - - return typeX || typeY || typeXY || typeZ || typeYZ - || typeXZ || typeXYZ; -} - -bool GridImp::nodeInPreviousCellIs(int index, char type) const -{ - real x, y, z; - this->transIndexToCoords(index, x, y, z); - - const real neighborX = x - this->delta < startX ? startX : x - this->delta; - const real neighborY = y - this->delta < startY ? startY : y - this->delta; - const real neighborZ = z - this->delta < startZ ? startZ : z - this->delta; - - const uint indexX = transCoordToIndex(neighborX, y, z); - const uint indexY = transCoordToIndex(x, neighborY, z); - const uint indexZ = transCoordToIndex(x, y, neighborZ); - - const uint indexXY = transCoordToIndex(neighborX, neighborY, z); - const uint indexYZ = transCoordToIndex(x, neighborY, neighborZ); - const uint indexXZ = transCoordToIndex(neighborX, y, neighborZ); - - const uint indexXYZ = transCoordToIndex(neighborX, neighborY, neighborZ); - - const bool typeX = indexX == INVALID_INDEX ? false : this->field.is(indexX , type); - const bool typeY = indexY == INVALID_INDEX ? false : this->field.is(indexY , type); - const bool typeXY = indexXY == INVALID_INDEX ? false : this->field.is(indexXY , type); - const bool typeZ = indexZ == INVALID_INDEX ? false : this->field.is(indexZ , type); - const bool typeYZ = indexYZ == INVALID_INDEX ? false : this->field.is(indexYZ , type); - const bool typeXZ = indexXZ == INVALID_INDEX ? false : this->field.is(indexXZ , type); - const bool typeXYZ = indexXYZ == INVALID_INDEX ? false : this->field.is(indexXYZ, type); - - return typeX || typeY || typeXY || typeZ || typeYZ - || typeXZ || typeXYZ; -} - -bool GridImp::nodeInCellIs(Cell& cell, char type) const -{ - for (const auto node : cell) - { - const uint index = transCoordToIndex(node.x, node.y, node.z); - if (index == INVALID_INDEX) - continue; - if (field.is(index, type)) - return true; - } - return false; -} - - -void GridImp::setCellTo(uint index, char type) -{ - real x, y, z; - this->transIndexToCoords(index, x, y, z); - - Cell cell(x, y, z, this->delta); - for (const auto node : cell) - { - const uint nodeIndex = transCoordToIndex(node.x, node.y, node.z); - if (nodeIndex == INVALID_INDEX) - continue; - this->field.setFieldEntry(nodeIndex, type); - } -} - - -void GridImp::setNonStopperOutOfGridCellTo(uint index, char type) -{ - real x, y, z; - this->transIndexToCoords(index, x, y, z); - - Cell cell(x, y, z, this->delta); - for (const auto node : cell) - { - const uint nodeIndex = transCoordToIndex(node.x, node.y, node.z); - if (nodeIndex == INVALID_INDEX) - continue; - - if( this->getFieldEntry( nodeIndex ) != STOPPER_OUT_OF_GRID && - this->getFieldEntry( nodeIndex ) != STOPPER_OUT_OF_GRID_BOUNDARY ) - this->field.setFieldEntry(nodeIndex, type); - } -} - - -void GridImp::setPeriodicity(bool periodicityX, bool periodicityY, bool periodicityZ) -{ - this->periodicityX = periodicityX; - this->periodicityY = periodicityY; - this->periodicityZ = periodicityZ; -} - -void GridImp::setPeriodicityX(bool periodicity) -{ - this->periodicityX = periodicityX; -} - -void GridImp::setPeriodicityY(bool periodicity) -{ - this->periodicityY = periodicityY; -} - -void GridImp::setPeriodicityZ(bool periodicity) -{ - this->periodicityZ = periodicityZ; -} - -bool GridImp::getPeriodicityX() -{ - return this->periodicityX; -} - -bool GridImp::getPeriodicityY() -{ - return this->periodicityY; -} - -bool GridImp::getPeriodicityZ() -{ - return this->periodicityZ; -} - -uint GridImp::transCoordToIndex(const real &x, const real &y, const real &z) const -{ - const uint xIndex = getXIndex(x); - const uint yIndex = getYIndex(y); - const uint zIndex = getZIndex(z); - - if (xIndex >= nx || yIndex >= ny || zIndex >= nz) - return INVALID_INDEX; - - return xIndex + nx * (yIndex + ny * zIndex); -} - -void GridImp::transIndexToCoords(uint index, real &x, real &y, real &z) const -{ - if (index == INVALID_INDEX) - printf("Function: transIndexToCoords. GridImp Index: %d, size: %d. Exit Program!\n", index, size); - - x = (real)(index % nx); - y = (real)((index / nx) % ny); - z = (real)(((index / nx) / ny) % nz); - - x = (x * delta) + startX; - y = (y * delta) + startY; - z = (z * delta) + startZ; -} - -uint GridImp::getLevel(real startDelta) const -{ - uint level = 0; - real delta = this->delta; - while(!vf::Math::equal(delta, startDelta)) - { - delta *= 2; - level++; - } - return level; -} - -uint GridImp::getLevel() const -{ - return this->level; -} - -// --------------------------------------------------------- // -// Set Sparse Indices // -// --------------------------------------------------------- // - -void GridImp::findSparseIndices(SPtr<Grid> fineGrid) -{ - this->gridStrategy->findSparseIndices(shared_from_this(), std::static_pointer_cast<GridImp>(fineGrid)); -} - - -void GridImp::updateSparseIndices() -{ - int removedNodes = 0; - int newIndex = 0; - for (uint index = 0; index < size; index++) - { - if (this->field.isInvalidCoarseUnderFine(index) || this->field.isInvalidOutOfGrid(index) || this->field.isInvalidSolid(index)) - { - sparseIndices[index] = -1; - removedNodes++; - } - else - { - sparseIndices[index] = newIndex; - newIndex++; - } - } - sparseSize = size - removedNodes; -} - -void GridImp::setNeighborIndices(uint index) -{ - real x, y, z; - this->transIndexToCoords(index, x, y, z); - - this->neighborIndexX[index] = -1; - this->neighborIndexY[index] = -1; - this->neighborIndexZ[index] = -1; - this->neighborIndexNegative[index] = -1; - - if (this->field.isStopper(index) || this->field.is(index, STOPPER_OUT_OF_GRID_BOUNDARY)) - { - this->setStopperNeighborCoords(index); - return; - } - - if (this->sparseIndices[index] == -1) - return; - - - real neighborXCoord, neighborYCoord, neighborZCoord; - this->getNeighborCoords(neighborXCoord, neighborYCoord, neighborZCoord, x, y, z); - const int neighborX = getSparseIndex(neighborXCoord, y, z); - const int neighborY = getSparseIndex(x, neighborYCoord, z); - const int neighborZ = getSparseIndex(x, y, neighborZCoord); - - this->getNegativeNeighborCoords(neighborXCoord, neighborYCoord, neighborZCoord, x, y, z); - const int neighborNegative = getSparseIndex(neighborXCoord, neighborYCoord, neighborZCoord); - - this->neighborIndexX[index] = neighborX; - this->neighborIndexY[index] = neighborY; - this->neighborIndexZ[index] = neighborZ; - this->neighborIndexNegative[index] = neighborNegative; -} - -void GridImp::setStopperNeighborCoords(uint index) -{ - real x, y, z; - this->transIndexToCoords(index, x, y, z); - - if (vf::Math::lessEqual(x + delta, endX) && !this->field.isInvalidOutOfGrid(this->transCoordToIndex(x + delta, y, z))) - neighborIndexX[index] = getSparseIndex(x + delta, y, z); - - if (vf::Math::lessEqual(y + delta, endY) && !this->field.isInvalidOutOfGrid(this->transCoordToIndex(x, y + delta, z))) - neighborIndexY[index] = getSparseIndex(x, y + delta, z); - - if (vf::Math::lessEqual(z + delta, endZ) && !this->field.isInvalidOutOfGrid(this->transCoordToIndex(x, y, z + delta))) - neighborIndexZ[index] = getSparseIndex(x, y, z + delta); - - if (vf::Math::greaterEqual(x - delta, endX) && - vf::Math::greaterEqual(y - delta, endY) && - vf::Math::greaterEqual(z - delta, endZ) && - !this->field.isInvalidOutOfGrid(this->transCoordToIndex(x - delta, y - delta, z - delta))) - { - neighborIndexNegative[index] = getSparseIndex(x - delta, y - delta, z - delta); - } -} - -void GridImp::getNeighborCoords(real &neighborX, real &neighborY, real &neighborZ, real x, real y, real z) const -{ - real coords[3] = { x, y, z }; - neighborX = getNeighborCoord(periodicityX, startX, coords, 0); - neighborY = getNeighborCoord(periodicityY, startY, coords, 1); - neighborZ = getNeighborCoord(periodicityZ, startZ, coords, 2); -} - -real GridImp::getNeighborCoord(bool periodicity, real startCoord, real coords[3], int direction) const -{ - if (periodicity) - { - real neighborCoords[3] = {coords[0], coords[1] , coords[2] }; - neighborCoords[direction] = neighborCoords[direction] + delta; - const int neighborIndex = this->transCoordToIndex(neighborCoords[0], neighborCoords[1], neighborCoords[2]); - - ////////////////////////////////////////////////////////////////////////// - - if( field.is(neighborIndex, STOPPER_OUT_OF_GRID_BOUNDARY) ) - return getFirstFluidNode(coords, direction, startCoord); - else - return coords[direction] + delta; - - } - - return coords[direction] + delta; -} - -void GridImp::getNegativeNeighborCoords(real &neighborX, real &neighborY, real &neighborZ, real x, real y, real z) const -{ - real coords[3] = { x, y, z }; - - neighborX = getNegativeNeighborCoord(periodicityX, endX, coords, 0); - neighborY = getNegativeNeighborCoord(periodicityY, endY, coords, 1); - neighborZ = getNegativeNeighborCoord(periodicityZ, endZ, coords, 2); -} - -real GridImp::getNegativeNeighborCoord(bool periodicity, real startCoord, real coords[3], int direction) const -{ - if (periodicity) - { - real neighborCoords[3] = {coords[0], coords[1] , coords[2] }; - neighborCoords[direction] = neighborCoords[direction] - delta; - const int neighborIndex = this->transCoordToIndex(neighborCoords[0], neighborCoords[1], neighborCoords[2]); - - if(neighborIndex != INVALID_INDEX && !field.isStopperOutOfGrid(neighborIndex) && !field.is(neighborIndex, STOPPER_OUT_OF_GRID_BOUNDARY) ) - return coords[direction] - delta; - - return getLastFluidNode(coords, direction, startCoord); - } - - return coords[direction] - delta; -} - - -real GridImp::getLastFluidNode(real coords[3], int direction, real startCoord) const -{ - coords[direction] = startCoord; - int index = this->transCoordToIndex(coords[0], coords[1], coords[2]); - while (index != INVALID_INDEX && !field.isFluid(index)) - { - coords[direction] -= delta; - index = this->transCoordToIndex(coords[0], coords[1], coords[2]); - } - return coords[direction]; -} - -real GridImp::getFirstFluidNode(real coords[3], int direction, real startCoord) const -{ - coords[direction] = startCoord; - uint index = this->transCoordToIndex(coords[0], coords[1], coords[2]); - while (!field.isFluid(index)) - { - coords[direction] += delta; - index = this->transCoordToIndex(coords[0], coords[1], coords[2]); - } - return coords[direction]; -} - - -int GridImp::getSparseIndex(const real &x, const real &y, const real &z) const -{ - const int matrixIndex = transCoordToIndex(x, y, z); - return sparseIndices[matrixIndex]; -} - -// --------------------------------------------------------- // -// Getter // -// --------------------------------------------------------- // -int GridImp::getSparseIndex(uint matrixIndex) const -{ - return this->sparseIndices[matrixIndex]; -} - -real* GridImp::getDistribution() const -{ - return this->distribution.f; -} - -int* GridImp::getDirection() const -{ - return this->distribution.dirs; -} - -int GridImp::getStartDirection() const -{ - return this->distribution.dir_start; -} - -int GridImp::getEndDirection() const -{ - return this->distribution.dir_end; -} - -uint GridImp::getXIndex(real x) const -{ - return lround((x - startX) / delta); -} - -uint GridImp::getYIndex(real y) const -{ - return lround((y - startY) / delta); -} - -uint GridImp::getZIndex(real z) const -{ - return lround((z - startZ) / delta); -} - -real GridImp::getDelta() const -{ - return delta; -} - -uint GridImp::getSize() const -{ - return this->size; -} - -uint GridImp::getSparseSize() const -{ - return this->sparseSize; -} - -Field GridImp::getField() const -{ - return this->field; -} - -char GridImp::getFieldEntry(uint index) const -{ - return this->field.getFieldEntry(index); -} - -void GridImp::setFieldEntry(uint matrixIndex, char type) -{ - this->field.setFieldEntry(matrixIndex, type); -} - - -real GridImp::getStartX() const -{ - return startX; -} - -real GridImp::getStartY() const -{ - return startY; -} - -real GridImp::getStartZ() const -{ - return startZ; -} - -real GridImp::getEndX() const -{ - return endX; -} - -real GridImp::getEndY() const -{ - return endY; -} - -real GridImp::getEndZ() const -{ - return endZ; -} - -uint GridImp::getNumberOfNodesX() const -{ - return nx; -} - -uint GridImp::getNumberOfNodesY() const -{ - return ny; -} - -uint GridImp::getNumberOfNodesZ() const -{ - return nz; -} - -SPtr<GridStrategy> GridImp::getGridStrategy() const -{ - return gridStrategy; -} - - -int* GridImp::getNeighborsX() const -{ - return this->neighborIndexX; -} - -int* GridImp::getNeighborsY() const -{ - return this->neighborIndexY; -} - -int* GridImp::getNeighborsZ() const -{ - return this->neighborIndexZ; -} - -int* GridImp::getNeighborsNegative() const -{ - return this->neighborIndexNegative; -} - -#define GEOFLUID 19 -#define GEOSOLID 16 - -void GridImp::getNodeValues(real *xCoords, real *yCoords, real *zCoords, uint *neighborX, uint *neighborY, uint *neighborZ, uint *neighborNegative, uint *geo) const -{ - xCoords[0] = 0; - yCoords[0] = 0; - zCoords[0] = 0; - neighborX[0] = 0; - neighborY[0] = 0; - neighborZ[0] = 0; - geo[0] = GEOSOLID; - - int nodeNumber = 0; - for (uint i = 0; i < this->getSize(); i++) - { - if (this->sparseIndices[i] == -1) - continue; - - real x, y, z; - this->transIndexToCoords(i, x, y, z); - - // + 1 for numbering shift between GridGenerator and VF_GPU - const uint neighborXIndex = uint(this->neighborIndexX[i] + 1); - const uint neighborYIndex = uint(this->neighborIndexY[i] + 1); - const uint neighborZIndex = uint(this->neighborIndexZ[i] + 1); - const uint neighborNegativeIndex = uint(this->neighborIndexNegative[i] + 1); - - const char type2 = this->field.getFieldEntry(i); - - const uint type = uint(this->field.isFluid(i) ? GEOFLUID : GEOSOLID); - - xCoords[nodeNumber + 1] = x; - yCoords[nodeNumber + 1] = y; - zCoords[nodeNumber + 1] = z; - - neighborX [nodeNumber + 1] = neighborXIndex; - neighborY [nodeNumber + 1] = neighborYIndex; - neighborZ [nodeNumber + 1] = neighborZIndex; - neighborNegative[nodeNumber + 1] = neighborNegativeIndex; - - geo[nodeNumber + 1] = type; - nodeNumber++; - } -} diff --git a/src/gpu/GridGenerator/grid/GridImp.h b/src/gpu/GridGenerator/grid/GridImp.h index c81aa67b42852cc2fc974513c01e9fbc0d87343c..7d44b0bb58168a6bf4da87ad94cf5a8f533002ed 100644 --- a/src/gpu/GridGenerator/grid/GridImp.h +++ b/src/gpu/GridGenerator/grid/GridImp.h @@ -28,7 +28,7 @@ // //! \file GridImp.h //! \ingroup grid -//! \author Soeren Peters, Stephan Lenz +//! \author Soeren Peters, Stephan Lenz, Martin Schönherr //======================================================================================= #ifndef GRID_IMP_H #define GRID_IMP_H @@ -44,25 +44,42 @@ #include "grid/Cell.h" #include "grid/Field.h" +class TriangularMesh; struct Vertex; -class GridStrategy; +struct Triangle; +class GridInterface; class Object; class BoundingBox; +class TriangularMeshDiscretizationStrategy; +#ifdef __GNUC__ +#ifndef __clang__ +#pragma push +#pragma diag_suppress = 3156 +#endif +#endif + +// GCC: warning #3156-D: extern declaration of the entity DIRECTIONS is treated as a static definition extern int DIRECTIONS[DIR_END_MAX][DIMENSION]; +#ifdef __GNUC__ +#ifndef __clang__ +#pragma pop +#endif +#endif + class GRIDGENERATOR_EXPORT GridImp : public enableSharedFromThis<GridImp>, public Grid { private: - GridImp(); - GridImp(Object* object, real startX, real startY, real startZ, real endX, real endY, real endZ, real delta, SPtr<GridStrategy> gridStrategy, Distribution d, uint level); + GridImp() = default; + GridImp(Object* object, real startX, real startY, real startZ, real endX, real endY, real endZ, real delta, Distribution d, uint level); public: - virtual ~GridImp(); - static SPtr<GridImp> makeShared(Object* object, real startX, real startY, real startZ, real endX, real endY, real endZ, real delta, SPtr<GridStrategy> gridStrategy, Distribution d, uint level); + static SPtr<GridImp> makeShared(Object* object, real startX, real startY, real startZ, real endX, real endY, real endZ, real delta, std::string d3Qxx, uint level); private: void initalNumberOfNodesAndSize(); + Cell getOddCellFromIndex(uint index) const; bool isValidSolidStopper(uint index) const; bool shouldBeBoundarySolidNode(uint index) const; bool isValidEndOfGridStopper(uint index) const; @@ -94,6 +111,7 @@ private: Field field; Object* object; + GridInterface *gridInterface; int *neighborIndexX, *neighborIndexY, *neighborIndexZ, *neighborIndexNegative; int *sparseIndices; @@ -102,10 +120,20 @@ private: real *qValues; uint *qPatches; - SPtr<GridStrategy> gridStrategy; + bool innerRegionFromFinerGrid; + + uint numberOfLayers; + + TriangularMeshDiscretizationStrategy *triangularMeshDiscretizationStrategy; + + uint numberOfSolidBoundaryNodes; + + bool enableFixRefinementIntoTheWall; public: void inital(const SPtr<Grid> fineGrid, uint numberOfLayers) override; + void setOddStart(bool xOddStart, bool yOddStart, bool zOddStart) override; + void fixOddCell(uint index); void setPeriodicity(bool periodicityX, bool periodicityY, bool periodicityZ) override; void setPeriodicityX(bool periodicity) override; @@ -116,25 +144,66 @@ public: bool getPeriodicityY() override; bool getPeriodicityZ() override; + void setEnableFixRefinementIntoTheWall(bool enableFixRefinementIntoTheWall) override; + void setCellTo(uint index, char type); void setNonStopperOutOfGridCellTo(uint index, char type); uint transCoordToIndex(const real &x, const real &y, const real &z) const override; void transIndexToCoords(uint index, real &x, real &y, real &z) const override; + virtual void findGridInterface(SPtr<Grid> grid, LbmOrGks lbmOrGks) override; + + void repairGridInterfaceOnMultiGPU(SPtr<Grid> fineGrid) override; + + virtual void limitToSubDomain(SPtr<BoundingBox> subDomainBox, LbmOrGks lbmOrGks) override; + void freeMemory() override; uint getLevel(real levelNull) const; uint getLevel() const; + void setTriangularMeshDiscretizationStrategy(TriangularMeshDiscretizationStrategy *triangularMeshDiscretizationStrategy); + TriangularMeshDiscretizationStrategy *getTriangularMeshDiscretizationStrategy(); + + uint getNumberOfSolidBoundaryNodes() const override; + void setNumberOfSolidBoundaryNodes(uint numberOfSolidBoundaryNodes) override; + + real getQValue(const uint index, const uint dir) const override; + uint getQPatch(const uint index) const override; + + void setInnerRegionFromFinerGrid(bool innerRegionFromFinerGrid) override; + + void setNumberOfLayers(uint numberOfLayers) override; + public: Distribution distribution; void initalNodeToOutOfGrid(uint index); + void findInnerNodes(); void findInnerNode(uint index); - void findEndOfGridStopperNode(uint index); + void discretize(Object *object, char innerType, char outerType); + + bool isInside(const Cell &cell) const; + + void setInnerBasedOnFinerGrid(const SPtr<Grid> fineGrid); + + void addOverlap(); + void setOverlapTmp(uint index); + void setOverlapFluid(uint index); + + void fixRefinementIntoWall(uint xIndex, uint yIndex, uint zIndex, int dir); + void findStopperNode(uint index); + void findEndOfGridStopperNode(uint index); + void findSolidStopperNode(uint index); + void findBoundarySolidNode(uint index); + + void findGridInterfaceCF(uint index, GridImp &finerGrid, LbmOrGks lbmOrGks); + void findGridInterfaceFC(uint index, GridImp &finerGrid); + void findOverlapStopper(uint index, GridImp &finerGrid); + void findInvalidBoundaryNodes(uint index); void setNodeTo(uint index, char type); bool isNode(uint index, char type) const; @@ -160,6 +229,9 @@ public: int getStartDirection() const override; int getEndDirection() const override; + Vertex getMinimumOnNode(Vertex exact) const override; + Vertex getMaximumOnNode(Vertex exact) const override; + real getStartX() const override; real getStartY() const override; real getStartZ() const override; @@ -171,13 +243,25 @@ public: uint getNumberOfNodesZ() const override; void getNodeValues(real *xCoords, real *yCoords, real *zCoords, uint *neighborX, uint *neighborY, uint *neighborZ, uint *neighborNegative, uint *geo) const override; - int* getNeighborsX() const override; + uint getNumberOfNodesCF() const override; + uint getNumberOfNodesFC() const override; + void getGridInterfaceIndices(uint *iCellCfc, uint *iCellCff, uint *iCellFcc, uint *iCellFcf) const override; + static void getGridInterface(uint *gridInterfaceList, const uint *oldGridInterfaceList, uint size); + + int *getNeighborsX() const override; int* getNeighborsY() const override; int* getNeighborsZ() const override; int* getNeighborsNegative() const override; - SPtr<GridStrategy> getGridStrategy() const override; + uint *getCF_coarse() const override; + uint *getCF_fine() const override; + uint *getCF_offset() const override; + uint *getFC_coarse() const override; + uint *getFC_fine() const override; + uint *getFC_offset() const override; + + void print() const; public: virtual void findSparseIndices(SPtr<Grid> fineGrid) override; @@ -196,9 +280,71 @@ private: int getSparseIndex(const real &expectedX, const real &expectedY, const real &expectedZ) const; + static real getMinimumOnNodes(const real &minExact, const real &decimalStart, const real &delta); + static real getMaximumOnNodes(const real &maxExact, const real &decimalStart, const real &delta); + +public: + BoundingBox getBoundingBoxOnNodes(Triangle &triangle) const; + + void mesh(Object *object) override; + + void mesh(TriangularMesh &geometry) override; + void mesh(Triangle &triangle); + + void closeNeedleCells() override; + bool closeCellIfNeedle(uint index); + + void closeNeedleCellsThinWall() override; + bool closeCellIfNeedleThinWall(uint index); + + void findQs(Object *object) override; + void findQs(TriangularMesh &triangularMesh); + void findQs(Triangle &triangle); + + void findQsPrimitive(Object *object); + +private: + enum class qComputationStageType { FindSolidBoundaryNodes, ComputeQs } qComputationStage; + +public: + void enableFindSolidBoundaryNodes() override + { + qComputationStage = qComputationStageType::FindSolidBoundaryNodes; + } + void enableComputeQs() override { qComputationStage = qComputationStageType::ComputeQs; } + private: - friend class GridGpuStrategy; - friend class GridCpuStrategy; + void setDebugPoint(uint index, int pointValue); + void calculateQs(const Vertex &point, const Triangle &triangle) const; + void calculateQs(const uint index, const Vertex &point, const Triangle &triangle) const; + void calculateQs(const uint index, const Vertex &point, Object *object) const; + + bool checkIfAtLeastOneValidQ(const uint index, const Vertex &point, const Triangle &triangle) const; + + bool checkIfAtLeastOneValidQ(const uint index, const Vertex &point, Object *object) const; + + void allocateQs(); + +public: + void findCommunicationIndices(int direction, SPtr<BoundingBox> subDomainBox, LbmOrGks lbmOrGks) override; + void findCommunicationIndex(uint index, real coordinate, real limit, int direction); + + uint getNumberOfSendNodes(int direction) override; + uint getNumberOfReceiveNodes(int direction) override; + + uint getSendIndex(int direction, uint index) override; + uint getReceiveIndex(int direction, uint index) override; + + void repairCommunicationInices(int direction) override; + +public: + struct CommunicationIndices { + std::vector<uint> sendIndices; + std::vector<uint> receiveIndices; + }; + + std::array<CommunicationIndices, 6> communicationIndices; + }; #endif diff --git a/src/gpu/GridGenerator/grid/GridInterface.cpp b/src/gpu/GridGenerator/grid/GridInterface.cpp new file mode 100644 index 0000000000000000000000000000000000000000..47cb8ef9dd7c4704e420ca68888ce0d56c48a59e --- /dev/null +++ b/src/gpu/GridGenerator/grid/GridInterface.cpp @@ -0,0 +1,441 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file GridInterface.cpp +//! \ingroup grid +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#include "GridInterface.h" + +#include <iostream> +#include <cstring> + +#include "grid/distributions/D3Q27.h" +#include "grid/GridImp.h" +#include "grid/Field.h" +#include "grid/NodeValues.h" + +using namespace vf::gpu; + +GridInterface::GridInterface() +{ + +} + +GridInterface::~GridInterface() +{ + +} + + +void GridInterface::findInterfaceCF(const uint& indexOnCoarseGrid, GridImp* coarseGrid, GridImp* fineGrid) +{ + const bool nodeOnCoarseGridIsFluid = coarseGrid->getField().isFluid(indexOnCoarseGrid); + if (!nodeOnCoarseGridIsFluid) + return; + + const uint indexOnFineGridCF = getCoarseToFineIndexOnFineGrid(indexOnCoarseGrid, coarseGrid, fineGrid); + if (indexOnFineGridCF == INVALID_INDEX) + return; + + const bool fineGridNodeIsFluid = fineGrid->getField().isFluid(indexOnFineGridCF); + if (!fineGridNodeIsFluid) + return; + + real x, y, z; + coarseGrid->transIndexToCoords(indexOnCoarseGrid, x, y, z); + + for(const auto dir : coarseGrid->distribution) + { + const bool isFineGridNeighborInvalid = isNeighborFineInvalid(x + dir[0] * coarseGrid->getDelta(), y + dir[1] * coarseGrid->getDelta(), z + dir[2] * coarseGrid->getDelta(), coarseGrid, fineGrid); + if(isFineGridNeighborInvalid) + { + cf.coarse[cf.numberOfEntries] = this->findOffsetCF(indexOnCoarseGrid, coarseGrid, cf.numberOfEntries); + cf.fine[cf.numberOfEntries] = indexOnFineGridCF; + + cf.numberOfEntries++; + + coarseGrid->setNonStopperOutOfGridCellTo(indexOnCoarseGrid, FLUID_CFC); + fineGrid->setNonStopperOutOfGridCellTo(indexOnFineGridCF, FLUID_CFF); + break; + } + } +} + + +void GridInterface::findBoundaryGridInterfaceCF(const uint& indexOnCoarseGrid, GridImp* coarseGrid, GridImp* fineGrid) +{ + const bool nodeOnCoarseGridIsBoundaryStopper = coarseGrid->getField().is(indexOnCoarseGrid, STOPPER_OUT_OF_GRID_BOUNDARY); + if (!nodeOnCoarseGridIsBoundaryStopper) + return; + + const uint indexOnFineGridCF = getCoarseToFineIndexOnFineGrid(indexOnCoarseGrid, coarseGrid, fineGrid); + if (indexOnFineGridCF == INVALID_INDEX) + return; + + const bool fineGridNodeIsBoundaryStopper = fineGrid->getField().is(indexOnFineGridCF, STOPPER_OUT_OF_GRID_BOUNDARY); + if (!fineGridNodeIsBoundaryStopper) + return; + + real x, y, z; + coarseGrid->transIndexToCoords(indexOnCoarseGrid, x, y, z); + + for(const auto dir : coarseGrid->distribution) + { + const bool isFineGridNeighborInvalid = isNeighborFineInvalid(x + dir[0] * coarseGrid->getDelta(), y + dir[1] * coarseGrid->getDelta(), z + dir[2] * coarseGrid->getDelta(), coarseGrid, fineGrid); + if(isFineGridNeighborInvalid) + { + cf.coarse[cf.numberOfEntries] = this->findOffsetCF(indexOnCoarseGrid, coarseGrid, cf.numberOfEntries); + cf.fine[cf.numberOfEntries] = indexOnFineGridCF; + + cf.numberOfEntries++; + + coarseGrid->setNonStopperOutOfGridCellTo(indexOnCoarseGrid, FLUID_CFC); + fineGrid->setNonStopperOutOfGridCellTo(indexOnFineGridCF, FLUID_CFF); + break; + } + } +} + +void GridInterface::findInterfaceCF_GKS(const uint& indexOnCoarseGrid, GridImp* coarseGrid, GridImp* fineGrid) +{ + const bool nodeOnCoarseGridIsFluid = coarseGrid->getField().isFluid(indexOnCoarseGrid); + if (!nodeOnCoarseGridIsFluid) + return; + + real x, y, z; + coarseGrid->transIndexToCoords(indexOnCoarseGrid, x, y, z); + + for (const auto dir : coarseGrid->distribution) + { + const uint indexOnFineGrid = fineGrid->transCoordToIndex(x + 0.25 * dir[0] * coarseGrid->getDelta(), + y + 0.25 * dir[1] * coarseGrid->getDelta(), + z + 0.25 * dir[2] * coarseGrid->getDelta()); + + if (indexOnFineGrid != INVALID_INDEX && fineGrid->getField().is(indexOnFineGrid, STOPPER_OUT_OF_GRID)) + { + coarseGrid->getField().setFieldEntry(indexOnCoarseGrid, FLUID_CFC); + break; + } + } +} + +void GridInterface::findInterfaceFC(const uint& indexOnCoarseGrid, GridImp* coarseGrid, GridImp* fineGrid) +{ + const bool nodeOnCoarseGridIsFluid = coarseGrid->getField().isFluid(indexOnCoarseGrid); + const bool nodeOnCoarseGridIsCoarseToFine = coarseGrid->getField().isCoarseToFineNode(indexOnCoarseGrid); + if (!nodeOnCoarseGridIsFluid || nodeOnCoarseGridIsCoarseToFine) + return; + + const uint indexOnFineGridFC = getFineToCoarseIndexOnFineGrid(indexOnCoarseGrid, coarseGrid, fineGrid); + if (indexOnFineGridFC == INVALID_INDEX) + return; + + const bool fineGridNodeIsFluid = fineGrid->getField().isFluid(indexOnFineGridFC); + if (!fineGridNodeIsFluid) + return; + + real x, y, z; + coarseGrid->transIndexToCoords(indexOnCoarseGrid, x, y, z); + + for (const auto dir : coarseGrid->distribution) + { + const uint neighborIndex = coarseGrid->transCoordToIndex(x + dir[0] * coarseGrid->getDelta(), y + dir[1] * coarseGrid->getDelta(), z + dir[2] * coarseGrid->getDelta()); + if (neighborIndex != INVALID_INDEX) + { + const bool neighborBelongsToCoarseToFineInterpolationCell = coarseGrid->getField().isCoarseToFineNode(neighborIndex); + if (neighborBelongsToCoarseToFineInterpolationCell) + { + fc.coarse[fc.numberOfEntries] = indexOnCoarseGrid; + fc.fine[fc.numberOfEntries] = this->findOffsetFC(indexOnFineGridFC, fineGrid, fc.numberOfEntries); + + fc.numberOfEntries++; + + fineGrid->setNonStopperOutOfGridCellTo(indexOnFineGridFC, FLUID_FCF); + coarseGrid->getField().setFieldEntry(indexOnCoarseGrid, FLUID_FCC); + break; + } + } + } +} + +void GridInterface::findOverlapStopper(const uint& indexOnCoarseGrid, GridImp* coarseGrid, GridImp* fineGrid) +{ + const bool nodeOnCoarseGridIsFluid = coarseGrid->getField().isFluid(indexOnCoarseGrid); + const bool nodeOnCoarseGridIsCoarseToFine = coarseGrid->getField().isCoarseToFineNode(indexOnCoarseGrid); + const bool nodeOnCoarseGridIsFineToCoarse = coarseGrid->getField().isFineToCoarseNode(indexOnCoarseGrid); + if (!nodeOnCoarseGridIsFluid || nodeOnCoarseGridIsCoarseToFine || nodeOnCoarseGridIsFineToCoarse) + return; + + const int indexOnFineGridFC = getFineToCoarseIndexOnFineGrid(indexOnCoarseGrid, coarseGrid, fineGrid); + if (indexOnFineGridFC == -1) + return; + + real x, y, z; + coarseGrid->transIndexToCoords(indexOnCoarseGrid, x, y, z); + + bool neighborBelongsToFineToCoarseInterpolationCell = false; + for (const auto dir : coarseGrid->distribution) + { + //if (dir[0] > 0 || dir[1] > 0 || dir[2] > 0) //only Esoteric Twist stopper, not perfectly implemented + // continue; //should not be here, should be made conditional + + const uint neighborIndex = coarseGrid->transCoordToIndex(x + dir[0] * coarseGrid->getDelta(), y + dir[1] * coarseGrid->getDelta(), z + dir[2] * coarseGrid->getDelta()); + neighborBelongsToFineToCoarseInterpolationCell = neighborIndex != INVALID_INDEX ? coarseGrid->getField().isFineToCoarseNode(neighborIndex) : false; + if (neighborBelongsToFineToCoarseInterpolationCell) + { + coarseGrid->getField().setFieldEntryToStopperCoarseUnderFine(indexOnCoarseGrid); + break; + } + } + + //should be inside of fine grid and can be deleted + if(!neighborBelongsToFineToCoarseInterpolationCell && (fineGrid->getField().isInvalidSolid(indexOnFineGridFC) || + fineGrid->getField().isFluid(indexOnFineGridFC) || + fineGrid->getField().is(indexOnFineGridFC, STOPPER_SOLID) || + fineGrid->getField().is(indexOnFineGridFC, BC_SOLID))) + coarseGrid->getField().setFieldEntryToInvalidCoarseUnderFine(indexOnCoarseGrid); +} + + void GridInterface::findInvalidBoundaryNodes(const uint& indexOnCoarseGrid, GridImp* coarseGrid) +{ + if( !coarseGrid->getField().is(indexOnCoarseGrid, STOPPER_OUT_OF_GRID_BOUNDARY ) ) return; + + if( !coarseGrid->hasNeighborOfType(indexOnCoarseGrid, FLUID) && + !coarseGrid->hasNeighborOfType(indexOnCoarseGrid, FLUID_CFC) && + !coarseGrid->hasNeighborOfType(indexOnCoarseGrid, FLUID_CFF) ) + coarseGrid->getField().setFieldEntryToInvalidCoarseUnderFine(indexOnCoarseGrid); +} + +bool GridInterface::isNeighborFineInvalid(real x, real y, real z, const GridImp* coarseGrid, const GridImp* fineGrid) +{ + const uint neighbor = coarseGrid->transCoordToIndex(x, y, z); + + if( neighbor == INVALID_INDEX ) + return false; + + if( (neighbor != INVALID_INDEX) && (coarseGrid->getField().isStopperOutOfGrid(neighbor) || coarseGrid->getField().is(neighbor, STOPPER_OUT_OF_GRID_BOUNDARY)) ) + return false; + + const uint indexOnFineGrid = getCoarseToFineIndexOnFineGrid(neighbor, coarseGrid, fineGrid); + if (indexOnFineGrid == INVALID_INDEX) + return true; + + return fineGrid->getField().isInvalidOutOfGrid(indexOnFineGrid) || fineGrid->getField().isStopperOutOfGrid(indexOnFineGrid); +} + +uint GridInterface::getCoarseToFineIndexOnFineGrid(const uint& indexOnCoarseGrid, const GridImp* coarseGrid, const GridImp* fineGrid) +{ + if( indexOnCoarseGrid == INVALID_INDEX ) + return INVALID_INDEX; + + real x, y, z; + coarseGrid->transIndexToCoords(indexOnCoarseGrid, x, y, z); + const real xFine = x + (fineGrid->getDelta() * 0.5); + const real yFine = y + (fineGrid->getDelta() * 0.5); + const real zFine = z + (fineGrid->getDelta() * 0.5); + + return fineGrid->transCoordToIndex(xFine, yFine, zFine); +} + +uint GridInterface::getFineToCoarseIndexOnFineGrid(const uint& indexOnCoarseGrid, const GridImp* coarseGrid, const GridImp* fineGrid) +{ + real x, y, z; + coarseGrid->transIndexToCoords(indexOnCoarseGrid, x, y, z); + const real xFine = x - (fineGrid->getDelta() * 0.5); + const real yFine = y - (fineGrid->getDelta() * 0.5); + const real zFine = z - (fineGrid->getDelta() * 0.5); + + return fineGrid->transCoordToIndex(xFine, yFine, zFine); +} + +void GridInterface::findForGridInterfaceSparseIndexCF(GridImp* coarseGrid, GridImp* fineGrid, uint index) +{ + findSparseIndex(cf.coarse, coarseGrid, index); + findSparseIndex(cf.fine, fineGrid, index); + + if( cf.coarse[index] == 686916 ) + printf("%d ===> %d \n", cf.coarse[index], cf.fine[index]); +} + +void GridInterface::findForGridInterfaceSparseIndexFC(GridImp* coarseGrid, GridImp* fineGrid, uint index) +{ + findSparseIndex(fc.coarse, coarseGrid, index); + findSparseIndex(fc.fine, fineGrid, index); +} + +void GRIDGENERATOR_EXPORT GridInterface::repairGridInterfaceOnMultiGPU(SPtr<GridImp> coarseGrid, SPtr<GridImp> fineGrid) +{ + { + std::vector<uint> tmpCFC; + std::vector<uint> tmpCFF; + std::vector<uint> tmpCFOffset; + + for (uint index = 0; index < cf.numberOfEntries; index++) { + + real x, y, z; + coarseGrid->transIndexToCoords(this->cf.coarse[index], x, y, z); + Cell cell(x, y, z, coarseGrid->getDelta()); + + if (coarseGrid->cellContainsOnly(cell, FLUID_CFC)) { + tmpCFC.push_back (this->cf.coarse[index]); + tmpCFF.push_back (this->cf.fine[index]); + tmpCFOffset.push_back(this->cf.offset[index]); + } + } + + delete[] cf.coarse; + delete[] cf.fine; + delete[] cf.offset; + + cf.numberOfEntries = (uint)tmpCFC.size(); + + cf.coarse = new uint[cf.numberOfEntries]; + cf.fine = new uint[cf.numberOfEntries]; + cf.offset = new uint[cf.numberOfEntries]; + + memcpy(cf.coarse, tmpCFC.data() , sizeof(uint)*cf.numberOfEntries); + memcpy(cf.fine , tmpCFF.data() , sizeof(uint)*cf.numberOfEntries); + memcpy(cf.offset, tmpCFOffset.data(), sizeof(uint)*cf.numberOfEntries); + } + + { + std::vector<uint> tmpFCF; + std::vector<uint> tmpFCC; + std::vector<uint> tmpFCOffset; + + for (uint index = 0; index < fc.numberOfEntries; index++) { + + real x, y, z; + fineGrid->transIndexToCoords(this->fc.fine[index], x, y, z); + Cell cell(x, y, z, fineGrid->getDelta()); + + if (fineGrid->cellContainsOnly(cell, FLUID_FCF)) { + tmpFCF.push_back (this->fc.fine[index]); + tmpFCC.push_back (this->fc.coarse[index]); + tmpFCOffset.push_back(this->fc.offset[index]); + } + } + + delete[] fc.fine; + delete[] fc.coarse; + delete[] fc.offset; + + fc.numberOfEntries = (uint)tmpFCC.size(); + + fc.fine = new uint[fc.numberOfEntries]; + fc.coarse = new uint[fc.numberOfEntries]; + fc.offset = new uint[fc.numberOfEntries]; + + memcpy(fc.fine , tmpFCF.data() , sizeof(uint)*fc.numberOfEntries); + memcpy(fc.coarse, tmpFCC.data() , sizeof(uint)*fc.numberOfEntries); + memcpy(fc.offset, tmpFCOffset.data(), sizeof(uint)*fc.numberOfEntries); + } +} + +void GridInterface::findSparseIndex(uint* indices, GridImp* grid, uint index) +{ + const uint matrixIndex = indices[index]; + const uint sparseIndex = grid->getSparseIndex(matrixIndex); + indices[index] = sparseIndex; +} + +uint GridInterface::findOffsetCF(const uint& indexOnCoarseGrid, GridImp* coarseGrid, uint interfaceIndex) +{ + real x, y, z; + coarseGrid->transIndexToCoords(indexOnCoarseGrid, x, y, z); + + Cell cell(x, y, z, coarseGrid->getDelta()); + + if( coarseGrid->cellContainsOnly( cell, FLUID, FLUID_CFC ) ){ + this->cf.offset[ interfaceIndex ] = DIR_27_ZERO; + return indexOnCoarseGrid; + } + + uint dirIndex = 0; + for(const auto dir : coarseGrid->distribution){ + + Cell neighborCell( x + dir[0] * coarseGrid->getDelta(), + y + dir[1] * coarseGrid->getDelta(), + z + dir[2] * coarseGrid->getDelta(), + coarseGrid->getDelta() ); + + if( coarseGrid->cellContainsOnly( neighborCell, FLUID, FLUID_CFC ) ){ + this->cf.offset[ interfaceIndex ] = dirIndex; + + return coarseGrid->transCoordToIndex( x + dir[0] * coarseGrid->getDelta(), + y + dir[1] * coarseGrid->getDelta(), + z + dir[2] * coarseGrid->getDelta() ); + } + + dirIndex++; + } + + // this point should never be reached + return indexOnCoarseGrid; +} + +uint GridInterface::findOffsetFC(const uint& indexOnFineGrid, GridImp* fineGrid, uint interfaceIndex) +{ + real x, y, z; + fineGrid->transIndexToCoords(indexOnFineGrid, x, y, z); + + Cell cell(x, y, z, fineGrid->getDelta()); + + if( fineGrid->cellContainsOnly( cell, FLUID, FLUID_FCF ) ){ + this->fc.offset[ interfaceIndex ] = DIR_27_ZERO; + return indexOnFineGrid; + } + + uint dirIndex = 0; + for(const auto dir : fineGrid->distribution){ + + Cell neighborCell( x + dir[0] * fineGrid->getDelta(), + y + dir[1] * fineGrid->getDelta(), + z + dir[2] * fineGrid->getDelta(), + fineGrid->getDelta() ); + + if( fineGrid->cellContainsOnly( neighborCell, FLUID, FLUID_CFC ) ){ + this->fc.offset[interfaceIndex] = dirIndex; + + return fineGrid->transCoordToIndex(x + dir[0] * fineGrid->getDelta(), + y + dir[1] * fineGrid->getDelta(), + z + dir[2] * fineGrid->getDelta()); + } + + dirIndex++; + } + + // this point should never be reached + return indexOnFineGrid; +} + +void GridInterface::print() const +{ + printf("Grid Interface - CF nodes: %d, FC nodes: %d\n", cf.numberOfEntries, fc.numberOfEntries); +} diff --git a/src/gpu/GridGenerator/grid/GridInterface.h b/src/gpu/GridGenerator/grid/GridInterface.h new file mode 100644 index 0000000000000000000000000000000000000000..303d79d4995ea04fe30b2a004c5738bf9c926cf2 --- /dev/null +++ b/src/gpu/GridGenerator/grid/GridInterface.h @@ -0,0 +1,86 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file GridInterface.h +//! \ingroup grid +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#ifndef GRID_INTERFACE_H +#define GRID_INTERFACE_H + +#include "global.h" + +class GridImp; + +class GridInterface +{ +public: + GRIDGENERATOR_EXPORT GridInterface(); + GRIDGENERATOR_EXPORT ~GridInterface(); + + void GRIDGENERATOR_EXPORT findInterfaceCF(const uint& indexOnCoarseGrid, GridImp* coarseGrid, GridImp* fineGrid); + void GRIDGENERATOR_EXPORT findBoundaryGridInterfaceCF(const uint& indexOnCoarseGrid, GridImp* coarseGrid, GridImp* fineGrid); + + + void GRIDGENERATOR_EXPORT findInterfaceCF_GKS(const uint& indexOnCoarseGrid, GridImp* coarseGrid, GridImp* fineGrid); + + void GRIDGENERATOR_EXPORT findInterfaceFC(const uint& indexOnCoarseGrid, GridImp* coarseGrid, GridImp* fineGrid); + void GRIDGENERATOR_EXPORT findOverlapStopper(const uint& indexOnCoarseGrid, GridImp* coarseGrid, GridImp* fineGrid); + + void GRIDGENERATOR_EXPORT findInvalidBoundaryNodes(const uint& indexOnCoarseGrid, GridImp* coarseGrid); + + void GRIDGENERATOR_EXPORT findForGridInterfaceSparseIndexCF(GridImp* coarseGrid, GridImp* fineGrid, uint index); + void GRIDGENERATOR_EXPORT findForGridInterfaceSparseIndexFC(GridImp* coarseGrid, GridImp* fineGrid, uint index); + + void GRIDGENERATOR_EXPORT repairGridInterfaceOnMultiGPU(SPtr<GridImp> coarseGrid, SPtr<GridImp> fineGrid); + + void GRIDGENERATOR_EXPORT print() const; + + struct Interface + { + uint *fine, *coarse; + uint numberOfEntries = 0; + uint *offset; + } fc, cf; + + +private: + uint getCoarseToFineIndexOnFineGrid(const uint& indexOnCoarseGrid, const GridImp* coarseGrid, const GridImp* fineGrid); + bool isNeighborFineInvalid(real x, real y, real z, const GridImp* coarseGrid, const GridImp* fineGrid); + + uint getFineToCoarseIndexOnFineGrid(const uint& indexOnCoarseGrid, const GridImp* coarseGrid, const GridImp* fineGrid); + + static void findSparseIndex(uint* indices, GridImp* grid, uint index); + + uint findOffsetCF( const uint& indexOnCoarseGrid, GridImp* coarseGrid, uint interfaceIndex ); + + uint findOffsetFC( const uint& indexOnCoarseGrid, GridImp* coarseGrid, uint interfaceIndex ); +}; + + +#endif \ No newline at end of file diff --git a/src/gpu/GridGenerator/grid/GridStrategy/GridCpuStrategy/GridCpuStrategy.cpp b/src/gpu/GridGenerator/grid/GridStrategy/GridCpuStrategy/GridCpuStrategy.cpp deleted file mode 100644 index ac63339582e3aed6c2d644807dbd44db9725b3c3..0000000000000000000000000000000000000000 --- a/src/gpu/GridGenerator/grid/GridStrategy/GridCpuStrategy/GridCpuStrategy.cpp +++ /dev/null @@ -1,125 +0,0 @@ -//======================================================================================= -// ____ ____ __ ______ __________ __ __ __ __ -// \ \ | | | | | _ \ |___ ___| | | | | / \ | | -// \ \ | | | | | |_) | | | | | | | / \ | | -// \ \ | | | | | _ / | | | | | | / /\ \ | | -// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ -// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| -// \ \ | | ________________________________________________________________ -// \ \ | | | ______________________________________________________________| -// \ \| | | | __ __ __ __ ______ _______ -// \ | | |_____ | | | | | | | | | _ \ / _____) -// \ | | _____| | | | | | | | | | | \ \ \_______ -// \ | | | | |_____ | \_/ | | | | |_/ / _____ | -// \ _____| |__| |________| \_______/ |__| |______/ (_______/ -// -// This file is part of VirtualFluids. VirtualFluids is free software: you can -// redistribute it and/or modify it under the terms of the GNU General Public -// License as published by the Free Software Foundation, either version 3 of -// the License, or (at your option) any later version. -// -// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -// for more details. -// -// You should have received a copy of the GNU General Public License along -// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. -// -//! \file GridCpuStrategy.cpp -//! \ingroup grid -//! \author Soeren Peters, Stephan Lenz -//======================================================================================= -#include "GridCpuStrategy.h" - -#include <time.h> -#include <stdio.h> -#include <omp.h> -#include <vector> -#include <iostream> - -#include "grid/distributions/Distribution.h" -#include "grid/GridImp.h" -#include "grid/NodeValues.h" - -void GridCpuStrategy::allocateGridMemory(SPtr<GridImp> grid) -{ - grid->neighborIndexX = new int[grid->size]; - grid->neighborIndexY = new int[grid->size]; - grid->neighborIndexZ = new int[grid->size]; - grid->neighborIndexNegative = new int[grid->size]; - - grid->sparseIndices = new int[grid->size]; - - grid->qIndices = new uint[grid->size]; - for (uint i = 0; i < grid->size; i++) - grid->qIndices[i] = INVALID_INDEX; -} - -void GridCpuStrategy::initalNodesToOutOfGrid(SPtr<GridImp> grid) -{ -#pragma omp parallel for - for (int index = 0; index < (int)grid->size; index++) - grid->initalNodeToOutOfGrid(index); -} - -void GridCpuStrategy::allocateFieldMemory(Field* field) -{ - field->field = new char[field->size]; -} - - -void GridCpuStrategy::findInnerNodes(SPtr<GridImp> grid) -{ -#pragma omp parallel for - for (int index = 0; index < (int)grid->size; index++) - grid->findInnerNode(index); -} - -void GridCpuStrategy::findEndOfGridStopperNodes(SPtr<GridImp> grid) -{ -#pragma omp parallel for - for (int index = 0; index < (int)grid->size; index++) - grid->findEndOfGridStopperNode(index); -} - -void GridCpuStrategy::findSparseIndices(SPtr<GridImp> coarseGrid, SPtr<GridImp> fineGrid) -{ - *logging::out << logging::Logger::INFO_INTERMEDIATE << "Find sparse indices..."; - - coarseGrid->updateSparseIndices(); - findForNeighborsNewIndices(coarseGrid); - if (fineGrid) - { - fineGrid->updateSparseIndices(); - } - - const uint newGridSize = coarseGrid->getSparseSize(); - *logging::out << logging::Logger::INFO_INTERMEDIATE << "... done. new size: " << newGridSize << ", delete nodes:" << coarseGrid->getSize() - newGridSize << "\n"; -} - - -void GridCpuStrategy::findForNeighborsNewIndices(SPtr<GridImp> grid) -{ -#pragma omp parallel for - for (int index = 0; index < (int)grid->getSize(); index++) - grid->setNeighborIndices(index); -} - -void GridCpuStrategy::freeFieldMemory(Field* field) -{ - delete[] field->field; -} - -void GridCpuStrategy::freeMemory(SPtr<GridImp> grid) -{ - if( grid->neighborIndexX != nullptr ) { delete[] grid->neighborIndexX; grid->neighborIndexX = nullptr; } - if( grid->neighborIndexY != nullptr ) { delete[] grid->neighborIndexY; grid->neighborIndexY = nullptr; } - if( grid->neighborIndexZ != nullptr ) { delete[] grid->neighborIndexZ; grid->neighborIndexZ = nullptr; } - if( grid->neighborIndexNegative != nullptr ) { delete[] grid->neighborIndexNegative; grid->neighborIndexNegative = nullptr; } - if( grid->sparseIndices != nullptr ) { delete[] grid->sparseIndices; grid->sparseIndices = nullptr; } - if( grid->qIndices != nullptr ) { delete[] grid->qIndices; grid->qIndices = nullptr; } - if( grid->qValues != nullptr ) { delete[] grid->qValues; grid->qValues = nullptr; } - if( grid->qPatches != nullptr ) { delete[] grid->qPatches; grid->qPatches = nullptr; } -} - diff --git a/src/gpu/GridGenerator/grid/NodeValues.h b/src/gpu/GridGenerator/grid/NodeValues.h index 36ed127de4cafa3a6a2b5dca88cfad3a79fea566..c726fdf85c8199633e118d8f8a5365ee658d4e6a 100644 --- a/src/gpu/GridGenerator/grid/NodeValues.h +++ b/src/gpu/GridGenerator/grid/NodeValues.h @@ -28,39 +28,51 @@ // //! \file NodeValues.h //! \ingroup grid -//! \author Soeren Peters, Stephan Lenz +//! \author Soeren Peters, Stephan Lenz, Martin Schoenherr //======================================================================================= #ifndef NodeValues_H #define NodeValues_H -#define FLUID 0 +namespace vf +{ +namespace gpu +{ -#define FLUID_CFC 1 -#define FLUID_CFF 2 +static constexpr char FLUID = 0; -#define FLUID_FCC 3 -#define FLUID_FCF 4 +static constexpr char FLUID_CFC = 1; +static constexpr char FLUID_CFF = 2; -#define MULTI_GPU_SEND 10 -#define MULTI_GPU_RECIEVE 11 +static constexpr char FLUID_FCC = 3; +static constexpr char FLUID_FCF = 4; -#define BC_PRESSURE 20 -#define BC_VELOCITY 21 -#define BC_SOLID 22 +static constexpr char MULTI_GPU_SEND = 10; +static constexpr char MULTI_GPU_RECIEVE = 11; -#define BC_SLIP 23 -#define BC_NOSLIP 24 -#define BC_OUTFLOW 25 +static constexpr char BC_PRESSURE = 20; +static constexpr char BC_VELOCITY = 21; +static constexpr char BC_SOLID = 22; -#define STOPPER_OUT_OF_GRID 30 -#define STOPPER_COARSE_UNDER_FINE 31 -#define STOPPER_SOLID 32 -#define STOPPER_OUT_OF_GRID_BOUNDARY 33 +static constexpr char BC_SLIP = 23; +static constexpr char BC_NOSLIP = 24; +static constexpr char BC_OUTFLOW = 25; -#define INVALID_OUT_OF_GRID 40 -#define INVALID_COARSE_UNDER_FINE 41 -#define INVALID_SOLID 42 +static constexpr char STOPPER_OUT_OF_GRID = 30; +static constexpr char STOPPER_COARSE_UNDER_FINE = 31; +static constexpr char STOPPER_SOLID = 32; +static constexpr char STOPPER_OUT_OF_GRID_BOUNDARY = 33; -#define OVERLAP_TMP 60 +static constexpr char INVALID_OUT_OF_GRID = 40; +static constexpr char INVALID_COARSE_UNDER_FINE = 41; +static constexpr char INVALID_SOLID = 42; + +static constexpr char INSIDE = 50; +static constexpr char NEGATIVE_DIRECTION_BORDER = 51; +static constexpr char Q_DEPRECATED = 52; + +static constexpr char OVERLAP_TMP = 60; + +} // namespace gpu +} // namespace vf #endif diff --git a/src/gpu/GridGenerator/grid/distributions/D3Q7.h b/src/gpu/GridGenerator/grid/distributions/D3Q7.h new file mode 100644 index 0000000000000000000000000000000000000000..f43aeb01c5ebf85f4b2f97e90f61585d4dd6da88 --- /dev/null +++ b/src/gpu/GridGenerator/grid/distributions/D3Q7.h @@ -0,0 +1,73 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file D3Q7.h +//! \ingroup grid +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#ifndef D3Q7_H +#define D3Q7_H + +#define DIR_7_E 0 +#define DIR_7_W 1 +#define DIR_7_N 2 +#define DIR_7_S 3 +#define DIR_7_T 4 +#define DIR_7_B 5 +#define DIR_7_ZERO 6 + +#define DIR_7_START 0 +#define DIR_7_END 6 + + +#define DIR_7_E_X 1 +#define DIR_7_E_Y 0 +#define DIR_7_E_Z 0 + +#define DIR_7_W_X -1 +#define DIR_7_W_Y 0 +#define DIR_7_W_Z 0 + +#define DIR_7_N_X 0 +#define DIR_7_N_Y 1 +#define DIR_7_N_Z 0 + +#define DIR_7_S_X 0 +#define DIR_7_S_Y -1 +#define DIR_7_S_Z 0 + +#define DIR_7_T_X 0 +#define DIR_7_T_Y 0 +#define DIR_7_T_Z 1 + +#define DIR_7_B_X 0 +#define DIR_7_B_Y 0 +#define DIR_7_B_Z -1 + + +#endif diff --git a/src/gpu/GridGenerator/io/GridVTKWriter/GridVTKWriter.cpp b/src/gpu/GridGenerator/io/GridVTKWriter/GridVTKWriter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2c8624732d70e52ac24d843888548bdaf5585686 --- /dev/null +++ b/src/gpu/GridGenerator/io/GridVTKWriter/GridVTKWriter.cpp @@ -0,0 +1,439 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file GridVTKWriter.cpp +//! \ingroup io +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#define _CRT_SECURE_NO_DEPRECATE +#include "GridVTKWriter.h" + +#include <iostream> +#include <fstream> +#include <sstream> +#include <memory> + +#include "basics/basics/writer/WbWriterVtkXmlBinary.h" +#include "basics/basics/container/CbArray3D.h" + +#include "geometries/Vertex/Vertex.h" + +#include "grid/Grid.h" +#include "grid/NodeValues.h" +#include "grid/Cell.h" + +using namespace vf::gpu; + +FILE* GridVTKWriter::file = nullptr; +WRITING_FORMAT GridVTKWriter::format = WRITING_FORMAT::ASCII; + + +void GridVTKWriter::writeSparseGridToVTK(SPtr<Grid> grid, const std::string& name, WRITING_FORMAT format) +{ + initalVtkWriter(format, name); + writeVtkFile(grid); +} + +void GridVTKWriter::writeGridToVTKXML(SPtr<Grid> grid, const std::string& name, WRITING_FORMAT format) +{ + + const uint chunkSize = 20000000; + + const uint chunkSizeZ = chunkSize / ( grid->getNumberOfNodesX() * grid->getNumberOfNodesY() ); + + for( uint startZ_Loop = 0, endZ_Loop = chunkSizeZ, part = 0; + endZ_Loop < grid->getNumberOfNodesZ() + chunkSizeZ; + startZ_Loop += chunkSizeZ, endZ_Loop += chunkSizeZ, part++ ) + + { + int endZ = endZ_Loop; + int startZ = startZ_Loop - 1; + + if(endZ >= (int)grid->getNumberOfNodesZ()) + endZ = grid->getNumberOfNodesZ(); + + if( startZ < 0 ) + startZ = 0; + + std::vector<UbTupleFloat3> nodes; + std::vector<UbTupleUInt8> cells; + std::vector<std::string> nodedatanames; + std::vector< std::vector<double> > nodedata; + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "Write Grid to XML VTK (*.vtu) output file : " + name + "_Part_" + std::to_string(part) + "\n"; + + nodedatanames.push_back("types"); + nodedatanames.push_back("sparse_id"); + nodedatanames.push_back("matrix_id"); + + nodedata.resize(nodedatanames.size()); + + CbArray3D<int> nodeNumbers(grid->getNumberOfNodesX(), grid->getNumberOfNodesY(), grid->getNumberOfNodesZ(), -1); + int nr = 0; + + for (uint xIndex = 0; xIndex < grid->getNumberOfNodesX(); xIndex++) + { + for (uint yIndex = 0; yIndex < grid->getNumberOfNodesY(); yIndex++) + { + for (int zIndex = startZ; zIndex < endZ; zIndex++) + { + real x, y, z; + uint index = + grid->getNumberOfNodesX() * grid->getNumberOfNodesY() * zIndex + + grid->getNumberOfNodesX() * yIndex + + xIndex; + + grid->transIndexToCoords(index, x, y, z); + + nodeNumbers(xIndex, yIndex, zIndex) = nr++; + nodes.push_back(UbTupleFloat3(float(x), float(y), float(z))); + + const char type = grid->getFieldEntry(grid->transCoordToIndex(x, y, z)); + nodedata[0].push_back(type); + nodedata[1].push_back(grid->getSparseIndex(index)); + nodedata[2].push_back(index); + } + } + } + + int SWB, SEB, NEB, NWB, SWT, SET, NET, NWT; + for (uint xIndex = 0; xIndex < grid->getNumberOfNodesX() - 1; xIndex++) + { + for (uint yIndex = 0; yIndex < grid->getNumberOfNodesY() - 1; yIndex++) + { + for (int zIndex = startZ; zIndex < endZ - 1; zIndex++) + { + real x, y, z; + uint index = grid->getNumberOfNodesX() * grid->getNumberOfNodesY() * zIndex + + grid->getNumberOfNodesX() * yIndex + + xIndex; + + grid->transIndexToCoords(index, x, y, z); + + if ((SWB = nodeNumbers(xIndex, yIndex, zIndex)) >= 0 + && (SEB = nodeNumbers(xIndex + 1, yIndex, zIndex)) >= 0 + && (NEB = nodeNumbers(xIndex + 1, yIndex + 1, zIndex)) >= 0 + && (NWB = nodeNumbers(xIndex, yIndex + 1, zIndex)) >= 0 + && (SWT = nodeNumbers(xIndex, yIndex, zIndex + 1)) >= 0 + && (SET = nodeNumbers(xIndex + 1, yIndex, zIndex + 1)) >= 0 + && (NET = nodeNumbers(xIndex + 1, yIndex + 1, zIndex + 1)) >= 0 + && (NWT = nodeNumbers(xIndex, yIndex + 1, zIndex + 1)) >= 0) + { + Cell cell(x, y, z, grid->getDelta()); + //if (grid->nodeInCellIs(cell, INVALID_OUT_OF_GRID) || grid->nodeInCellIs(cell, INVALID_COARSE_UNDER_FINE)) + // continue; + + cells.push_back(makeUbTuple(uint(SWB), uint(SEB), uint(NEB), uint(NWB), uint(SWT), uint(SET), uint(NET), uint(NWT))); + } + } + } + } + WbWriterVtkXmlBinary::getInstance()->writeOctsWithNodeData(name + "_Part_" + std::to_string(part), nodes, cells, nodedatanames, nodedata); + *logging::out << logging::Logger::INFO_INTERMEDIATE << "done. \n"; + } + +} + +void GridVTKWriter::writeInterpolationCellsToVTKXML(SPtr<Grid> grid, SPtr<Grid> gridCoarse, const std::string& name, WRITING_FORMAT format) +{ + std::vector<char> nodeInterpolationCellType( grid->getSize() ); + for( auto& type : nodeInterpolationCellType ) type = -1; + + std::vector<char> nodeOffset( grid->getSize() ); + for( auto& offset : nodeOffset ) offset = -1; + + std::vector<uint> matrixIndices( grid->getSparseSize() ); + + for( uint matrixIndex = 0; matrixIndex < grid->getSize(); matrixIndex++ ){ + uint sparseIndex = grid->getSparseIndex(matrixIndex); + if( sparseIndex != INVALID_INDEX ) + matrixIndices[ sparseIndex ] = matrixIndex; + } + + for( uint index = 0; index < grid->getNumberOfNodesCF(); index++ ){ + nodeInterpolationCellType[ matrixIndices[ grid->getCF_coarse()[index] ] ] = grid->getFieldEntry( matrixIndices[ grid->getCF_coarse()[index] ] ); + + nodeOffset [ matrixIndices[ grid->getCF_coarse()[index] ] ] = grid->getCF_offset()[index]; + } + + //for( int index = 0; index < grid->getNumberOfNodesFC(); index++ ){ + // nodeInterpolationCellType[ grid->getFC_coarse()[index] ] = grid->getFieldEntry( grid->getFC_coarse()[index] ); + //} + + if( gridCoarse ){ + + for( uint index = 0; index < gridCoarse->getNumberOfNodesCF(); index++ ){ + nodeInterpolationCellType[ matrixIndices[ gridCoarse->getCF_fine()[index] ] ] = grid->getFieldEntry( matrixIndices[ gridCoarse->getCF_fine()[index] ] ); + } + + for( uint index = 0; index < gridCoarse->getNumberOfNodesFC(); index++ ){ + nodeInterpolationCellType[ matrixIndices[ gridCoarse->getFC_fine()[index] ] ] = grid->getFieldEntry( matrixIndices[ gridCoarse->getFC_fine()[index] ] ); + + nodeOffset [ matrixIndices[ gridCoarse->getFC_fine()[index] ] ] = gridCoarse->getFC_offset()[index]; + } + } + + std::vector<UbTupleFloat3> nodes; + std::vector<UbTupleInt8> cells; + std::vector<std::string> celldatanames; + std::vector< std::vector<double> > celldata; + + celldatanames.push_back("InterpolationCells"); + celldatanames.push_back("Offset"); + + celldata.resize(celldatanames.size()); + + CbArray3D<int> nodeNumbers(grid->getNumberOfNodesX(), grid->getNumberOfNodesY(), grid->getNumberOfNodesZ(), -1); + int nr = 0; + + for (uint xIndex = 0; xIndex < grid->getNumberOfNodesX(); xIndex++) + { + for (uint yIndex = 0; yIndex < grid->getNumberOfNodesY(); yIndex++) + { + for (uint zIndex = 0; zIndex < grid->getNumberOfNodesZ(); zIndex++) + { + real x, y, z; + uint index = + grid->getNumberOfNodesX() * grid->getNumberOfNodesY() * zIndex + + grid->getNumberOfNodesX() * yIndex + + xIndex; + + grid->transIndexToCoords(index, x, y, z); + + nodeNumbers(xIndex, yIndex, zIndex) = nr++; + nodes.push_back(UbTupleFloat3(float(x), float(y), float(z))); + } + } + } + + int SWB, SEB, NEB, NWB, SWT, SET, NET, NWT; + for (uint xIndex = 0; xIndex < grid->getNumberOfNodesX() - 1; xIndex++) + { + for (uint yIndex = 0; yIndex < grid->getNumberOfNodesY() - 1; yIndex++) + { + for (uint zIndex = 0; zIndex < grid->getNumberOfNodesZ() - 1; zIndex++) + { + real x, y, z; + uint index = grid->getNumberOfNodesX() * grid->getNumberOfNodesY() * zIndex + + grid->getNumberOfNodesX() * yIndex + + xIndex; + + grid->transIndexToCoords(index, x, y, z); + + if ((SWB = nodeNumbers(xIndex, yIndex, zIndex)) >= 0 + && (SEB = nodeNumbers(xIndex + 1, yIndex, zIndex)) >= 0 + && (NEB = nodeNumbers(xIndex + 1, yIndex + 1, zIndex)) >= 0 + && (NWB = nodeNumbers(xIndex, yIndex + 1, zIndex)) >= 0 + && (SWT = nodeNumbers(xIndex, yIndex, zIndex + 1)) >= 0 + && (SET = nodeNumbers(xIndex + 1, yIndex, zIndex + 1)) >= 0 + && (NET = nodeNumbers(xIndex + 1, yIndex + 1, zIndex + 1)) >= 0 + && (NWT = nodeNumbers(xIndex, yIndex + 1, zIndex + 1)) >= 0) + { + Cell cell(x, y, z, grid->getDelta()); + //if (grid->nodeInCellIs(cell, INVALID_OUT_OF_GRID) || grid->nodeInCellIs(cell, INVALID_COARSE_UNDER_FINE)) + // continue; + + cells.push_back(makeUbTuple(SWB, SEB, NEB, NWB, SWT, SET, NET, NWT)); + + //const char type = grid->getFieldEntry(grid->transCoordToIndex(nodes[SWB].v1, nodes[SWB].v2.v1, nodes[SWB].v2.v2)); + //const char type = grid->getFieldEntry(grid->transCoordToIndex(val<1>(nodes[SWB]), val<2>(nodes[SWB]), val<3>(nodes[SWB]))); + const char type = nodeInterpolationCellType[ grid->transCoordToIndex(val<1>(nodes[SWB]), val<2>(nodes[SWB]), val<3>(nodes[SWB])) ]; + const char offset = nodeOffset [ grid->transCoordToIndex(val<1>(nodes[SWB]), val<2>(nodes[SWB]), val<3>(nodes[SWB])) ]; + + celldata[0].push_back( type ); + celldata[1].push_back( offset ); + } + } + } + } + WbWriterVtkXmlBinary::getInstance()->writeOctsWithCellData(name, nodes, cells, celldatanames, celldata); +} + + +/*#################################################################################*/ +/*---------------------------------private methods---------------------------------*/ +/*---------------------------------------------------------------------------------*/ +void GridVTKWriter::initalVtkWriter(WRITING_FORMAT format, const std::string& name) +{ + GridVTKWriter::format = format; + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "Write Grid to vtk output file : " + name + "\n"; + + std::string mode = "w"; + if (isBinaryWritingFormat()) + mode = "wb"; + GridVTKWriter::openFile(name, mode); + + *logging::out << logging::Logger::INFO_INTERMEDIATE << " Output file opened ...\n"; +} + +bool GridVTKWriter::isBinaryWritingFormat() +{ + return GridVTKWriter::format == WRITING_FORMAT::BINARY; +} + +void GridVTKWriter::writeVtkFile(SPtr<Grid> grid) +{ + GridVTKWriter::writeHeader(); + GridVTKWriter::writePoints(grid); + GridVTKWriter::writeCells(grid->getSize()); + GridVTKWriter::writeTypeHeader(grid->getSize()); + GridVTKWriter::writeTypes(grid); + GridVTKWriter::closeFile(); + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "Output file closed\n"; +} + +void GridVTKWriter::openFile(const std::string& name, const std::string& mode) +{ + file = fopen(name.c_str(), mode.c_str()); + if(file==NULL) + *logging::out << logging::Logger::INFO_HIGH << " cannot open file ...\n"; +} + +void GridVTKWriter::closeFile() +{ + GridVTKWriter::end_line(); + fclose(file); +} + +void GridVTKWriter::writeHeader() +{ + fprintf(file, "# vtk DataFile Version 3.0\n"); + fprintf(file, "by MeshGenerator\n"); + if (isBinaryWritingFormat()) + fprintf(file, "BINARY\n"); + else + fprintf(file, "ASCII\n"); + fprintf(file, "DATASET UNSTRUCTURED_GRID\n"); +} + +void GridVTKWriter::writePoints(SPtr<Grid> grid) +{ + fprintf(file, "POINTS %d float\n", grid->getSize()); + real x, y, z; + for (unsigned int i = 0; i < grid->getSize(); i++) { + + /*if (grid->getSparseIndex(i) == -1) + continue;*/ + + grid->transIndexToCoords(i, x, y, z); + + if (isBinaryWritingFormat()) { + write_float(float(x)); + write_float(float(y)); + write_float(float(z)); + } + else + fprintf(file, "%f %f %f\n", x, y, z); + } +} + +void GridVTKWriter::writeCells(const unsigned int &size) +{ + fprintf(file, "\nCELLS %d %d\n", size, size * 2); + for (unsigned int i = 0; i < size; ++i) + { + if (isBinaryWritingFormat()){ + write_int(1); + write_int(i); + } + else + fprintf(file, "1 %d\n", i); + } + + fprintf(file, "\nCELL_TYPES %d\n", size); + for (unsigned int i = 0; i < size; ++i) + { + if (isBinaryWritingFormat()) + write_int(1); + else + fprintf(file, "1 "); + } + if (!isBinaryWritingFormat()) + GridVTKWriter::end_line(); +} + +void GridVTKWriter::writeTypeHeader(const unsigned int &size) +{ + fprintf(file, "\nPOINT_DATA %d\n", size); + fprintf(file, "SCALARS type int\n"); + fprintf(file, "LOOKUP_TABLE default\n"); +} + +void GridVTKWriter::writeTypes(SPtr<Grid> grid) +{ + for (unsigned int i = 0; i < grid->getSize(); i++) + { + /*if (grid->getSparseIndex(i) == -1) + continue;*/ + + if (isBinaryWritingFormat()) + write_int(grid->getFieldEntry(i)); + else + fprintf(file, "%d ", grid->getFieldEntry(i)); + } +} + +void GridVTKWriter::end_line() +{ + char str2[8] = "\n"; + fprintf(file, "%s", str2); +} + +void GridVTKWriter::write_int(int val) +{ + force_big_endian((unsigned char *)&val); + fwrite(&val, sizeof(int), 1, file); +} + +void GridVTKWriter::write_float(float val) +{ + force_big_endian((unsigned char *)&val); + fwrite(&val, sizeof(float), 1, file); +} + + +void GridVTKWriter::force_big_endian(unsigned char *bytes) +{ + bool shouldSwap = false; + int tmp1 = 1; + unsigned char *tmp2 = (unsigned char *)&tmp1; + if (*tmp2 != 0) + shouldSwap = true; + + if (shouldSwap) + { + unsigned char tmp = bytes[0]; + bytes[0] = bytes[3]; + bytes[3] = tmp; + tmp = bytes[1]; + bytes[1] = bytes[2]; + bytes[2] = tmp; + } +} diff --git a/src/gpu/GridGenerator/io/GridVTKWriter/GridVTKWriter.h b/src/gpu/GridGenerator/io/GridVTKWriter/GridVTKWriter.h new file mode 100644 index 0000000000000000000000000000000000000000..cf33df096a6e670b65f79831d59927e3d7cea389 --- /dev/null +++ b/src/gpu/GridGenerator/io/GridVTKWriter/GridVTKWriter.h @@ -0,0 +1,81 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file GridVTKWriter.h +//! \ingroup io +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#ifndef GridVTKWriter_h +#define GridVTKWriter_h + +#include <string> + +#include "global.h" +#include "GridGenerator_export.h" + +enum class WRITING_FORMAT { BINARY, ASCII }; + +class Grid; + +class GRIDGENERATOR_EXPORT GridVTKWriter +{ +public: + static void writeSparseGridToVTK(SPtr<Grid> grid, const std::string& name, WRITING_FORMAT format = WRITING_FORMAT::ASCII); + static void writeGridToVTKXML(SPtr<Grid> grid, const std::string& name, WRITING_FORMAT format = WRITING_FORMAT::ASCII); + static void writeInterpolationCellsToVTKXML(SPtr<Grid> grid, SPtr<Grid> gridCoarse, const std::string& name, WRITING_FORMAT format = WRITING_FORMAT::ASCII); + +private: + GridVTKWriter() {} + ~GridVTKWriter() {} + + static FILE *file; + static WRITING_FORMAT format; + + static void initalVtkWriter(WRITING_FORMAT format, const std::string& name); + + static bool isBinaryWritingFormat(); + + static void writeVtkFile(SPtr<Grid> grid); + + static void openFile(const std::string& name, const std::string& mode); + static void closeFile(); + + static void writeHeader(); + static void writePoints(SPtr<Grid> grid); + static void writeCells(const unsigned int &size); + static void writeTypeHeader(const unsigned int &size); + static void writeTypes(SPtr<Grid> grid); + + static void end_line(); + static void force_big_endian(unsigned char *bytes); + static void write_int(int val); + static void write_float(float val); +}; + + +#endif diff --git a/src/gpu/GridGenerator/io/QLineWriter.cpp b/src/gpu/GridGenerator/io/QLineWriter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..29894e8d589fb59c1dbf57e08692dddfc03619a1 --- /dev/null +++ b/src/gpu/GridGenerator/io/QLineWriter.cpp @@ -0,0 +1,174 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file QLineWriter.cpp +//! \ingroup io +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#include "QLineWriter.h" + +#include <vector> +#include <string> +#include <fstream> + +#include "basics/basics/utilities/UbTuple.h" + +#include "geometries/Vertex/Vertex.h" + +#include "grid/BoundaryConditions/BoundaryCondition.h" +#include "grid/Grid.h" + +using namespace std; +void writeLines(std::string filename, std::vector<UbTupleFloat3> nodes, std::vector<UbTupleInt2> lines); + +void QLineWriter::writeArrows(std::string fileName, SPtr<GeometryBoundaryCondition> geometryBoundaryCondition, SPtr<Grid> grid) +{ + if (geometryBoundaryCondition == nullptr) + { + *logging::out << logging::Logger::WARNING << "(QLineWriter::writeArrows) no geometry bc on this grid level.\n"; + return; + } + std::vector<UbTupleFloat3> nodes; + std::vector<UbTupleInt2> cells; + + int actualNodeNumber = 0; + for (std::size_t index = 0; index < geometryBoundaryCondition->indices.size(); index++) + { + Vertex startNode = getVertex(geometryBoundaryCondition->indices[index], grid); + for (int qi = 0; qi <= 26; qi++) + { + real qval = geometryBoundaryCondition->qs[index][qi]; + if (qval > 0.0f) + { + Vertex dir((real)grid->getDirection()[qi * DIMENSION + 0], (real)grid->getDirection()[qi * DIMENSION + 1], (real)grid->getDirection()[qi * DIMENSION + 2]); + Vertex nodeOnGeometry(startNode + (dir * qval)*grid->getDelta()); + + nodes.push_back(makeUbTuple(float(startNode.x), float(startNode.y), float(startNode.z))); + nodes.push_back(makeUbTuple(float(nodeOnGeometry.x), float(nodeOnGeometry.y), float(nodeOnGeometry.z))); + actualNodeNumber += 2; + cells.push_back(makeUbTuple(actualNodeNumber - 2, actualNodeNumber - 1)); + } + } + } + + writeLines(fileName, nodes, cells); +} + +Vertex QLineWriter::getVertex(int matrixIndex, SPtr<Grid> grid) +{ + real x, y, z; + grid->transIndexToCoords(matrixIndex, x, y, z); + return Vertex(x, y, z); +} + + +void writeLines(std::string filename, std::vector<UbTupleFloat3> nodes, std::vector<UbTupleInt2> lines) +{ + string vtkfilename = filename + ".bin.vtu"; + + ofstream out(vtkfilename.c_str(), ios::out | ios::binary); + + int nofNodes = (int)nodes.size(); + int nofCells = (int)lines.size(); + + int bytesPerByteVal = 4; //==sizeof(int) + int bytesPoints = 3 /*x1/x2/x3 */ * nofNodes * sizeof(float); + int bytesCellConnectivty = 2 /*nodes per line */ * nofCells * sizeof(int); + int bytesCellOffsets = 1 /*offset per line */ * nofCells * sizeof(int); + int bytesCellTypes = 1 /*type of line */ * nofCells * sizeof(unsigned char); + + int offset = 0; + //VTK FILE + out << "<?xml version=\"1.0\"?>\n"; + out << "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\" byte_order=\"LittleEndian\" >" << "\n"; + out << " <UnstructuredGrid>" << "\n"; + out << " <Piece NumberOfPoints=\"" << nofNodes << "\" NumberOfCells=\"" << nofCells << "\">\n"; + + //POINTS SECTION + out << " <Points>\n"; + out << " <DataArray type=\"Float32\" NumberOfComponents=\"3\" format=\"appended\" offset=\"" << offset << "\" />\n"; + out << " </Points>\n"; + offset += (bytesPerByteVal + bytesPoints); + + //CELLS SECTION + out << " <Cells>\n"; + out << " <DataArray type=\"Int32\" Name=\"connectivity\" format=\"appended\" offset=\"" << offset << "\" />\n"; + offset += (bytesPerByteVal + bytesCellConnectivty); + out << " <DataArray type=\"Int32\" Name=\"offsets\" format=\"appended\" offset=\"" << offset << "\" />\n"; + offset += (bytesPerByteVal + bytesCellOffsets); + out << " <DataArray type=\"UInt8\" Name=\"types\" format=\"appended\" offset=\"" << offset << "\" />\n "; + offset += (bytesPerByteVal + bytesCellTypes); + out << " </Cells>\n"; + + out << " </Piece>\n"; + out << " </UnstructuredGrid>\n"; + + // AppendedData SECTION + out << " <AppendedData encoding=\"raw\">\n"; + out << "_"; + + //POINTS SECTION + out.write((char*)&bytesPoints, bytesPerByteVal); + for (int n = 0; n < nofNodes; n++) + { + out.write((char*)&val<1>(nodes[n]), sizeof(float)); + out.write((char*)&val<2>(nodes[n]), sizeof(float)); + out.write((char*)&val<3>(nodes[n]), sizeof(float)); + } + + //CELLS SECTION + //cellConnectivity + out.write((char*)&bytesCellConnectivty, bytesPerByteVal); + for (int c = 0; c < nofCells; c++) + { + out.write((char*)&val<1>(lines[c]), sizeof(int)); + out.write((char*)&val<2>(lines[c]), sizeof(int)); + + } + + //cellOffsets + out.write((char*)&bytesCellOffsets, bytesPerByteVal); + int itmp; + for (int c = 1; c <= nofCells; c++) + { + itmp = 2 * c; + out.write((char*)&itmp, sizeof(int)); + } + + //cellTypes + out.write((char*)&bytesCellTypes, bytesPerByteVal); + unsigned char vtkCellType = 3; + for (int c = 0; c < nofCells; c++) + { + out.write((char*)&vtkCellType, sizeof(unsigned char)); + } + out << "\n</AppendedData>\n"; + out << "</VTKFile>"; + out << endl; + out.close(); +} diff --git a/src/gpu/GridGenerator/io/QLineWriter.h b/src/gpu/GridGenerator/io/QLineWriter.h new file mode 100644 index 0000000000000000000000000000000000000000..c7fed1a8ff16e81398e18c7fdde347cd09a93452 --- /dev/null +++ b/src/gpu/GridGenerator/io/QLineWriter.h @@ -0,0 +1,57 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file QLineWriter.h +//! \ingroup io +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#ifndef QLINEWRITER_H +#define QLINEWRITER_H + +#include <vector> +#include <string> +#include <fstream> + +#include "global.h" + +class GeometryBoundaryCondition; +class Grid; +struct Vertex; + + +class QLineWriter +{ +public: + static void writeArrows(std::string fileName, SPtr<GeometryBoundaryCondition> geometryBoundaryCondition, SPtr<Grid> grid); + +private: + static Vertex getVertex(int matrixIndex, SPtr<Grid> grid); +}; + + +#endif diff --git a/src/gpu/GridGenerator/io/STLReaderWriter/STLReader.cpp b/src/gpu/GridGenerator/io/STLReaderWriter/STLReader.cpp new file mode 100644 index 0000000000000000000000000000000000000000..173f79c184c0a455ffd5b27cae59e07fa6dd4fa6 --- /dev/null +++ b/src/gpu/GridGenerator/io/STLReaderWriter/STLReader.cpp @@ -0,0 +1,387 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file STLReader.cpp +//! \ingroup io +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#define _CRT_SECURE_NO_DEPRECATE +#include "STLReader.h" + +#include <iostream> +#include <fstream> +#include <sstream> +#include <string> +#include <cstring> +#include <stdexcept> +#include <algorithm> + +#include "geometries/Vertex/Vertex.h" +#include "geometries/Triangle/Triangle.h" +#include "geometries/BoundingBox/BoundingBox.h" + + +std::vector<Triangle> STLReader::readSTL(const std::string& name) +{ + std::ifstream file(name.c_str()); + if (file.is_open()) { + std::string line; + std::getline(file, line); + line[strcspn(line.c_str(), "\r\n")] = 0; + if (strcmp(line.c_str(), "solid ascii") == 0) { + file.close(); + *logging::out << logging::Logger::INFO_INTERMEDIATE << "start reading ascii STL file: " + name + "\n"; + return readASCIISTL(name); + } + else { + file.close(); + *logging::out << logging::Logger::INFO_INTERMEDIATE << "start reading binary STL file: " + name + "\n"; + return readBinarySTL(name); + } + } + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "can't open STL-file" + name + " ... exit program! \n"; + exit(1); +} + +std::vector<Triangle> STLReader::readSTL(const std::string & name, FileType fileType, const std::vector<uint> ignorePatches) +{ + if ( fileType == ascii ) return readASCIISTLWithPatches(name, ignorePatches); + else return readBinarySTL(name); +} + + +std::vector<Triangle> STLReader::readASCIISTL(const std::string& name) +{ + const int lines = countLinesInFile(name); + const int nTriangles = (lines) / 7; // seven lines per triangle + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "Number of Triangles: " << nTriangles << "\n"; + std::vector<Triangle> triangles; + + std::string line; + std::ifstream file; + file.open(name.c_str(), std::ifstream::in); + std::getline(file, line); // solid ascii + + for (int t = 0; t < nTriangles; t++) { + Vertex normal = parseLineToCoordinates(file, "%*s %*s %f %f %f"); + getline(file, line); // outer loop + Vertex p1 = parseLineToCoordinates(file, "%*s %f %f %f"); + Vertex p2 = parseLineToCoordinates(file, "%*s %f %f %f"); + Vertex p3 = parseLineToCoordinates(file, "%*s %f %f %f"); + getline(file, line); //endloop + getline(file, line); //endfacet + + Triangle tri = Triangle(p1, p2, p3, normal); + tri.calcNormal(); + triangles.push_back(tri); + } + file.close(); + return triangles; +} + + +std::vector<Triangle> STLReader::readASCIISTLWithPatches(const std::string& name, const std::vector<uint> ignorePatches) +{ + *logging::out << logging::Logger::INFO_HIGH << "Start reading ascii STL file:\n"; + *logging::out << logging::Logger::INFO_HIGH << " " + name + "\n"; + + std::vector<Triangle> triangles; + + std::string line; + std::ifstream file; + file.open(name.c_str(), std::ifstream::in); + + if( !file.is_open() ) throw std::runtime_error(name + "cannot be opened!"); + + uint currentPatchIndex = 0; + + uint currentFacetLine = 0; + + bool ignoreCurrentPatch = false; + + Vertex vertex1, vertex2, vertex3, normal; + + while( std::getline(file, line) ){ + + // trim the string + line = line.substr( line.find_first_not_of(" "), line.find_last_not_of(" ") + 1 ); + + if( line.substr( 0, line.find(" ") ) == "color" ) continue; + + // ======================================================================================== + if ( currentFacetLine == 0 && line.substr( 0, line.find(" ") ) == "solid" ) + { + ignoreCurrentPatch = std::find( ignorePatches.begin(), ignorePatches.end(), currentPatchIndex ) != ignorePatches.end(); + + if( !ignoreCurrentPatch ) + *logging::out << logging::Logger::INFO_INTERMEDIATE << " Reading STL-Group " << line.substr( line.find(' ') + 1 ) << " as patch " << currentPatchIndex << "\n"; + else + *logging::out << logging::Logger::WARNING << " Ignoring STL-Group " << line.substr( line.find(' ') + 1 ) << " as patch " << currentPatchIndex << "\n"; + + currentFacetLine++; + } + else if( currentFacetLine == 1 && line.substr( 0, line.find(" ") ) == "endsolid" ) + { + currentFacetLine = 0; + currentPatchIndex++; + } + // ======================================================================================== + else if( currentFacetLine == 1 && line.substr( 0, line.find(" ") ) == "facet" ) + { + normal = parseLineToCoordinates(line, "%*s %*s %f %f %f"); + currentFacetLine++; + } + else if( currentFacetLine == 2 && line.substr( 0, line.find(" ") ) == "outer" ) + { + currentFacetLine++; + } + else if( currentFacetLine == 3 && line.substr( 0, line.find(" ") ) == "vertex" ) + { + vertex1 = parseLineToCoordinates(line, "%*s %f %f %f"); + currentFacetLine++; + } + else if( currentFacetLine == 4 && line.substr( 0, line.find(" ") ) == "vertex" ) + { + vertex2 = parseLineToCoordinates(line, "%*s %f %f %f"); + currentFacetLine++; + } + else if( currentFacetLine == 5 && line.substr( 0, line.find(" ") ) == "vertex" ) + { + vertex3 = parseLineToCoordinates(line, "%*s %f %f %f"); + currentFacetLine++; + } + else if( currentFacetLine == 6 && line.substr( 0, line.find(" ") ) == "endloop" ) + { + currentFacetLine++; + } + else if( currentFacetLine == 7 && line.substr( 0, line.find(" ") ) == "endfacet" ) + { + if( !ignoreCurrentPatch ){ + Triangle tri = Triangle(vertex1, vertex2, vertex3, normal); + tri.calcNormal(); + + tri.patchIndex = currentPatchIndex; + + triangles.push_back(tri); + } + + currentFacetLine = 1; + } + else + { + throw std::runtime_error("STL-File does not comply with standard: " + line + "|\n"); + } + } + + file.close(); + + *logging::out << logging::Logger::INFO_HIGH << "Done reading ascii STL file\n"; + + return triangles; +} + +std::vector<Triangle> STLReader::readBinarySTL(const std::string& name) +{ + const std::string mode = "rb"; + FILE *file = fopen(name.c_str(), mode.c_str()); + + char header_info[80] = ""; + size_t sizef = fread(header_info, sizeof(char), 80, file); + + char nTri[4]; + sizef = fread(nTri, sizeof(char), 4, file); + unsigned long nTriLong = *((unsigned long*)nTri); + *logging::out << logging::Logger::INFO_INTERMEDIATE << "Number of Triangles: " << nTriLong << "\n"; + std::vector<Triangle> triangles; + + char facet[50]; + for (unsigned int i = 0; i < nTriLong; i++){ + sizef = fread(facet, sizeof(char), 50, file); + + Vertex normal = getVertexFromChar(facet); + + Vertex p1 = getVertexFromChar(facet + 12); + Vertex p2 = getVertexFromChar(facet + 24); + Vertex p3 = getVertexFromChar(facet + 36); + + triangles.push_back(Triangle(p1, p2, p3, normal)); + } + (void)sizef; + fclose(file); + + return triangles; +} + +std::vector<Triangle> STLReader::readSTL(const BoundingBox &box, const std::string& name) +{ + std::ifstream file(name.c_str()); + if (file.is_open()) { + std::string line; + std::getline(file, line); + line[strcspn(line.c_str(), "\r\n")] = 0; + if (strcmp(line.c_str(), "solid ascii") == 0) { + file.close(); + *logging::out << logging::Logger::INFO_INTERMEDIATE << "start reading ascii STL file: " + name + "\n"; + return readASCIISTL(box, name); + } + else { + file.close(); + *logging::out << logging::Logger::INFO_INTERMEDIATE << "start reading binary STL file: " + name + "\n"; + std::vector<Triangle> triangles = readBinarySTL(box, name); + return triangles; + } + } + else { + *logging::out << logging::Logger::INFO_INTERMEDIATE << "can't open STL-file" + name + "\n"; + exit(1); + } +} + +std::vector<Triangle> STLReader::readASCIISTL(const BoundingBox &box, const std::string& name) +{ + int lines = countLinesInFile(name); + int nTriangles = (lines) / 7; // seven lines per triangle + std::cout << "Number of Triangles: " << nTriangles << std::endl; + std::vector<Triangle> triangles; + + std::string line; + std::ifstream file; + file.open(name.c_str(), std::ifstream::in); + std::getline(file, line); // solid ascii + + for (int i= 0; i < nTriangles; i++) { + Vertex normal = parseLineToCoordinates(file, "%*s %*s %f %f %f"); + getline(file, line); // outer loop + Vertex p1 = parseLineToCoordinates(file, "%*s %f %f %f"); + Vertex p2 = parseLineToCoordinates(file, "%*s %f %f %f"); + Vertex p3 = parseLineToCoordinates(file, "%*s %f %f %f"); + getline(file, line); //endloop + getline(file, line); //endfacet + + Triangle t(p1, p2, p3, normal); + t.calcNormal(); + if (box.isInside(t) || box.intersect(t)) + triangles.push_back(t); + } + file.close(); + return triangles; +} + + +std::vector<Triangle> STLReader::readBinarySTL(const BoundingBox &box, const std::string& name) +{ + FILE *file; + std::string mode = "rb"; + file = fopen(name.c_str(), mode.c_str()); + + char header_info[80] = ""; + char nTri[4]; + unsigned long nTriLong; + + size_t sizef = fread(header_info, sizeof(char), 80, file); + + + sizef = fread(nTri, sizeof(char), 4, file); + nTriLong = *((unsigned long*)nTri); + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "Number of Triangles complete geometry: " << nTriLong << "\n"; + std::vector<Triangle> triangles; + + char facet[50]; + for (unsigned int i = 0; i < nTriLong; i++){ + sizef = fread(facet, sizeof(char), 50, file); + + Vertex normal = getVertexFromChar(facet); + + Vertex p1 = getVertexFromChar(facet + 12); + Vertex p2 = getVertexFromChar(facet + 24); + Vertex p3 = getVertexFromChar(facet + 36); + + Triangle t(p1, p2, p3, normal); + if (box.isInside(t) || box.intersect(t)) + triangles.push_back(t); + } + int size = (int)triangles.size(); + *logging::out << logging::Logger::INFO_INTERMEDIATE << "Number of Triangles in process: " << size << "\n"; + *logging::out << logging::Logger::INFO_INTERMEDIATE << "Complete reading STL file. \n"; + (void)sizef; + fclose(file); + + return triangles; +} + + +/*#################################################################################*/ +/*---------------------------------private methods---------------------------------*/ +/*---------------------------------------------------------------------------------*/ +Vertex STLReader::parseLineToCoordinates(std::ifstream& file, std::string format) +{ + std::string line; + getline(file, line); + const char* buffer = line.c_str(); + float x, y, z; + sscanf(buffer, format.c_str(), &x, &y, &z); + return Vertex(x, y, z); +} + +Vertex STLReader::parseLineToCoordinates(const std::string& line, const std::string format) +{ + const char* buffer = line.c_str(); + float x, y, z; + sscanf(buffer, format.c_str(), &x, &y, &z); + return Vertex(x, y, z); +} + +int STLReader::countLinesInFile(std::string name) +{ + std::ifstream file; + file.open(name.c_str(), std::ifstream::in); + int nTriLong = (int)std::count(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>(), '\n'); + file.close(); + return nTriLong; +} + +Vertex STLReader::getVertexFromChar(const char* facet) +{ + char f1[4] = { facet[0], + facet[1], facet[2], facet[3] }; + + char f2[4] = { facet[4], + facet[5], facet[6], facet[7] }; + + char f3[4] = { facet[8], + facet[9], facet[10], facet[11] }; + + float xx = *((float*)f1); + float yy = *((float*)f2); + float zz = *((float*)f3); + + return Vertex((real)(xx), (real)(yy), (real)(zz)); +} diff --git a/src/gpu/GridGenerator/io/STLReaderWriter/STLReader.h b/src/gpu/GridGenerator/io/STLReaderWriter/STLReader.h new file mode 100644 index 0000000000000000000000000000000000000000..333313727530ae551c76a76984cd63f6cd0f11ce --- /dev/null +++ b/src/gpu/GridGenerator/io/STLReaderWriter/STLReader.h @@ -0,0 +1,72 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file STLReader.h +//! \ingroup io +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#ifndef STLReader_H +#define STLReader_H + + +#include <vector> +#include <string> + +#include "global.h" + +struct Triangle; +struct Vertex; +class BoundingBox; + +class GRIDGENERATOR_EXPORT STLReader +{ +public: + + enum FileType { ascii, binary }; + + static std::vector<Triangle> readSTL(const std::string& name); + static std::vector<Triangle> readSTL(const std::string& name, FileType fileType, const std::vector<uint> ignorePatches = std::vector<uint>() ); + static std::vector<Triangle> readSTL(const BoundingBox &box, const std::string& name); + + static std::vector<Triangle> readBinarySTL(const std::string& name); + static std::vector<Triangle> readASCIISTL(const std::string& name); + static std::vector<Triangle> readASCIISTLWithPatches(const std::string& name, const std::vector<uint> ignorePatches); + static std::vector<Triangle> readBinarySTL(const BoundingBox &box, const std::string& name); + static std::vector<Triangle> readASCIISTL(const BoundingBox &box, const std::string& name); + +private: + STLReader(){}; + ~STLReader(){}; + + static int countLinesInFile(std::string name); + static Vertex parseLineToCoordinates(std::ifstream& file, std::string format); + static Vertex parseLineToCoordinates(const std::string& file, const std::string format); + static Vertex getVertexFromChar(const char* facet); +}; + +#endif diff --git a/src/gpu/GridGenerator/io/STLReaderWriter/STLWriter.cpp b/src/gpu/GridGenerator/io/STLReaderWriter/STLWriter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e29320cbd6867e1ae5a65cf41623780cd83aead7 --- /dev/null +++ b/src/gpu/GridGenerator/io/STLReaderWriter/STLWriter.cpp @@ -0,0 +1,116 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file STLWriter.cpp +//! \ingroup io +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#define _CRT_SECURE_NO_DEPRECATE +#include "STLWriter.h" + +#include <fstream> +#include <sstream> + +#include "geometries/Vertex/Vertex.h" +#include "geometries/Triangle/Triangle.h" + +void STLWriter::writeSTL(std::vector<Triangle> &vec, const std::string &name, bool writeBinary) +{ + const int size = (int)vec.size(); + *logging::out << logging::Logger::INFO_INTERMEDIATE << "Write " << size << " Triangles to STL : " + name + "\n"; + + std::ios_base::openmode mode = std::ios::out; + if (writeBinary) + mode = std::ios::out | std::ios::binary; + + std::ofstream ofstream(name, mode); + + if (!ofstream.is_open()) { + *logging::out << logging::Logger::INFO_HIGH << " Output file not open - exit function\n"; + return; + } + + if (writeBinary) + writeBinarySTL(ofstream, vec); + else + writeAsciiSTL(ofstream, vec); + + ofstream.close(); + *logging::out << logging::Logger::INFO_INTERMEDIATE << "Output file closed\n"; +} + + +void STLWriter::writeAsciiSTL(std::ofstream &ofstream, std::vector<Triangle> &vec) +{ + ofstream << "solid ascii\n"; + for (size_t i = 0; i < vec.size(); i++) + { + Triangle t = vec[i]; + + ofstream << "facet normal "; + t.normal.printFormatted(ofstream); + ofstream << "\n"; + + ofstream << "outer loop\n"; + + ofstream << "vertex "; + t.v1.printFormatted(ofstream); + ofstream << "\n"; + ofstream << "vertex "; + t.v2.printFormatted(ofstream); + ofstream << "\n"; + ofstream << "vertex "; + t.v3.printFormatted(ofstream); + ofstream << "\n"; + + ofstream << "endloop\n"; + ofstream << "endfacet\n"; + } + ofstream << "endsolid\n"; +} + +void STLWriter::writeBinarySTL(std::ofstream &ofstream, std::vector<Triangle> &vec) +{ + char header_info[80] = "GridGeneration-File iRMB"; + unsigned long nTriLong = (unsigned long)vec.size(); + ofstream.write(header_info, sizeof(header_info)); + ofstream.write((char*)&nTriLong, 4); + char attribute[2] = "0"; + for (size_t i = 0; i < vec.size(); i++) + { + Triangle t = vec[i]; + + t.normal.print(ofstream); + + t.v1.print(ofstream); + t.v2.print(ofstream); + t.v3.print(ofstream); + + ofstream.write(attribute, 2); + } +} diff --git a/src/gpu/GridGenerator/io/STLReaderWriter/STLWriter.h b/src/gpu/GridGenerator/io/STLReaderWriter/STLWriter.h new file mode 100644 index 0000000000000000000000000000000000000000..4ba87fd82e147fd94507d5557a078f5c581c6d07 --- /dev/null +++ b/src/gpu/GridGenerator/io/STLReaderWriter/STLWriter.h @@ -0,0 +1,60 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file STLWriter.h +//! \ingroup io +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#ifndef STLWriter_H +#define STLWriter_H + +#include <vector> +#include <string> +#include <memory> +#include <fstream> + +#include "global.h" + +class Transformator; +struct Triangle; + +class GRIDGENERATOR_EXPORT STLWriter +{ +public: + static void writeSTL(std::vector<Triangle> &vec, const std::string &name, bool writeBinary = false); + +private: + STLWriter() {} + STLWriter(const STLWriter &) {} + virtual ~STLWriter() {} + + static void writeAsciiSTL(std::ofstream &ofstream, std::vector<Triangle> &vec); + static void writeBinarySTL(std::ofstream &ofstream, std::vector<Triangle> &vec); +}; + +#endif diff --git a/src/gpu/GridGenerator/io/SimulationFileWriter/SimulationFileNames.cpp b/src/gpu/GridGenerator/io/SimulationFileWriter/SimulationFileNames.cpp new file mode 100644 index 0000000000000000000000000000000000000000..34b6b1d3c30b15333afb0afeb5d35d2894e07e52 --- /dev/null +++ b/src/gpu/GridGenerator/io/SimulationFileWriter/SimulationFileNames.cpp @@ -0,0 +1,77 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file SimulationFileNames.cpp +//! \ingroup io +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#include "SimulationFileNames.h" + +const std::string fileEnding = ".dat"; + +const std::string simulationFileNames::coordX = "coordX" + fileEnding; +const std::string simulationFileNames::coordY = "coordY" + fileEnding; +const std::string simulationFileNames::coordZ = "coordZ" + fileEnding; +const std::string simulationFileNames::neighborX = "neighborX" + fileEnding; +const std::string simulationFileNames::neighborY = "neighborY" + fileEnding; +const std::string simulationFileNames::neighborZ = "neighborZ" + fileEnding; +const std::string simulationFileNames::neighborWSB = "neighborWSB" + fileEnding; +const std::string simulationFileNames::geoVec = "geoVec" + fileEnding; + +const std::string simulationFileNames::scaleCFC = "scaleCFC" + fileEnding; +const std::string simulationFileNames::scaleCFF = "scaleCFF" + fileEnding; +const std::string simulationFileNames::scaleFCC = "scaleFCC" + fileEnding; +const std::string simulationFileNames::scaleFCF = "scaleFCF" + fileEnding; + +const std::string simulationFileNames::offsetVecCF = "offsetVecCF" + fileEnding; +const std::string simulationFileNames::offsetVecFC = "offsetVecFC" + fileEnding; + +const std::string simulationFileNames::geomBoundaryQ = "geomBoundaryQs" + fileEnding; +const std::string simulationFileNames::geomBoundaryValues = "geomBoundaryValues" + fileEnding; + +const std::string simulationFileNames::topBoundaryQ = "topBoundaryQs" + fileEnding; +const std::string simulationFileNames::topBoundaryValues = "topBoundaryValues" + fileEnding; + +const std::string simulationFileNames::bottomBoundaryQ = "bottomBoundaryQs" + fileEnding; +const std::string simulationFileNames::bottomBoundaryValues = "bottomBoundaryValues" + fileEnding; + +const std::string simulationFileNames::frontBoundaryQ = "frontBoundaryQs" + fileEnding; +const std::string simulationFileNames::frontBoundaryValues = "frontBoundaryValues" + fileEnding; + +const std::string simulationFileNames::backBoundaryQ = "backBoundaryQs" + fileEnding; +const std::string simulationFileNames::backBoundaryValues = "backBoundaryValues" + fileEnding; + +const std::string simulationFileNames::inletBoundaryQ = "inletBoundaryQs" + fileEnding; +const std::string simulationFileNames::inletBoundaryValues = "inletBoundaryValues" + fileEnding; + +const std::string simulationFileNames::outletBoundaryQ = "outletBoundaryQs" + fileEnding; +const std::string simulationFileNames::outletBoundaryValues = "outletBoundaryValues" + fileEnding; + +const std::string simulationFileNames::numberNodes = "numberNodes" + fileEnding; +const std::string simulationFileNames::LBMvsSI = "LBMvsSI" + fileEnding; + diff --git a/src/gpu/GridGenerator/io/SimulationFileWriter/SimulationFileNames.h b/src/gpu/GridGenerator/io/SimulationFileWriter/SimulationFileNames.h new file mode 100644 index 0000000000000000000000000000000000000000..4be5b44bd4760764da672239052e17bd406316d3 --- /dev/null +++ b/src/gpu/GridGenerator/io/SimulationFileWriter/SimulationFileNames.h @@ -0,0 +1,85 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file SimulationFileNames.h +//! \ingroup io +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#ifndef SimulationFileNames_H +#define SimulationFileNames_H + +#include <string> + +#include "global.h" + +struct GRIDGENERATOR_EXPORT simulationFileNames +{ + static const std::string coordX; + static const std::string coordY; + static const std::string coordZ; + static const std::string neighborX; + static const std::string neighborY; + static const std::string neighborZ; + static const std::string neighborWSB; + static const std::string geoVec; + + static const std::string scaleCFC; + static const std::string scaleCFF; + static const std::string scaleFCC; + static const std::string scaleFCF; + + static const std::string offsetVecCF; + static const std::string offsetVecFC; + + static const std::string geomBoundaryQ; + static const std::string geomBoundaryValues; + + static const std::string topBoundaryQ; + static const std::string topBoundaryValues; + + static const std::string bottomBoundaryQ; + static const std::string bottomBoundaryValues; + + static const std::string frontBoundaryQ; + static const std::string frontBoundaryValues; + + static const std::string backBoundaryQ; + static const std::string backBoundaryValues; + + static const std::string inletBoundaryQ; + static const std::string inletBoundaryValues; + + static const std::string outletBoundaryQ; + static const std::string outletBoundaryValues; + + static const std::string numberNodes; + static const std::string LBMvsSI; +}; + + +#endif diff --git a/src/gpu/GridGenerator/io/SimulationFileWriter/SimulationFileWriter.cpp b/src/gpu/GridGenerator/io/SimulationFileWriter/SimulationFileWriter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..320a6e5fb7bb8e52a335722bca71d7d6a2a0c6de --- /dev/null +++ b/src/gpu/GridGenerator/io/SimulationFileWriter/SimulationFileWriter.cpp @@ -0,0 +1,784 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file SimulationFileWriter.cpp +//! \ingroup io +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#define _CRT_SECURE_NO_DEPRECATE +#include "SimulationFileWriter.h" + +#include <iostream> +#include <iomanip> +#include <omp.h> +#include <cmath> +#include <stdint.h> + +#include "Core/Timer/Timer.h" + +#include "grid/NodeValues.h" +#include "grid/Grid.h" +#include "grid/GridBuilder/GridBuilder.h" +#include "grid/BoundaryConditions/Side.h" +#include "grid/BoundaryConditions/BoundaryCondition.h" + +#include "io/SimulationFileWriter/SimulationFileNames.h" + +#include "utilities/communication.h" + +using namespace vf::gpu; + +/*#################################################################################*/ +/*---------------------------------public methods----------------------------------*/ +/*---------------------------------------------------------------------------------*/ +void SimulationFileWriter::write(std::string folder, SPtr<GridBuilder> builder, FILEFORMAT format) +{ + SimulationFileWriter::folder = folder; + + *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start writing simulation files to " << folder << ":\n"; + auto timer = Timer::makeStart(); + + write(builder, format); + + *logging::out << logging::Logger::INFO_INTERMEDIATE << " Time writing files: " << timer->getCurrentRuntimeInSeconds() << " sec\n"; + *logging::out << logging::Logger::INFO_INTERMEDIATE << "Done writing simulation Files!\n"; +} + + +/*#################################################################################*/ +/*---------------------------------private methods---------------------------------*/ +/*---------------------------------------------------------------------------------*/ +void SimulationFileWriter::write(SPtr<GridBuilder> builder, FILEFORMAT format) +{ + const uint numberOfLevel = builder->getNumberOfGridLevels(); + openFiles(builder); + writeLevel(numberOfLevel); + //auto qs = createBCVectors(builder->getGrid(0)); + + *logging::out << logging::Logger::INFO_INTERMEDIATE << " Coordinate and neighbor files:\n"; + for (uint level = 0; level < numberOfLevel; level++) + { + writeNumberNodes(builder, level); + writeLBMvsSI(builder, level); + + writeLevelSize(builder->getNumberOfNodes(level), format); + writeCoordFiles(builder, level, format); + + if (level < numberOfLevel - 1) + { + writeLevelSizeGridInterface(builder->getNumberOfNodesCF(level), builder->getNumberOfNodesFC(level)); + writeGridInterfaceToFile(builder, level); + } + } + + *logging::out << logging::Logger::INFO_INTERMEDIATE << " Boundary Condition files:\n"; + writeBoundaryQsFile(builder); + + *logging::out << logging::Logger::INFO_INTERMEDIATE << " Communication files:\n"; + writeCommunicationFiles(builder); + + closeFiles(); +} + +void SimulationFileWriter::openFiles(SPtr<GridBuilder> builder) +{ + std::string path = folder; + xCoordFile.open(( path + simulationFileNames::coordX).c_str(), std::ios::out | std::ios::binary); + yCoordFile.open(( path + simulationFileNames::coordY).c_str(), std::ios::out | std::ios::binary); + zCoordFile.open(( path + simulationFileNames::coordZ).c_str(), std::ios::out | std::ios::binary); + xNeighborFile.open(( path + simulationFileNames::neighborX).c_str(), std::ios::out | std::ios::binary); + yNeighborFile.open(( path + simulationFileNames::neighborY).c_str(), std::ios::out | std::ios::binary); + zNeighborFile.open(( path + simulationFileNames::neighborZ).c_str(), std::ios::out | std::ios::binary); + wsbNeighborFile.open(( path + simulationFileNames::neighborWSB).c_str(), std::ios::out | std::ios::binary); + geoVecFile.open(( path + simulationFileNames::geoVec).c_str(), std::ios::out | std::ios::binary); + + scaleCF_coarse_File.open((path + simulationFileNames::scaleCFC).c_str(), std::ios::out | std::ios::binary); + scaleCF_fine_File.open((path + simulationFileNames::scaleCFF).c_str(), std::ios::out | std::ios::binary); + scaleFC_coarse_File.open((path + simulationFileNames::scaleFCC).c_str(), std::ios::out | std::ios::binary); + scaleFC_fine_File.open((path + simulationFileNames::scaleFCF).c_str(), std::ios::out | std::ios::binary); + + offsetVecCF_File.open((path + simulationFileNames::offsetVecCF).c_str(), std::ios::out | std::ios::binary); + offsetVecFC_File.open((path + simulationFileNames::offsetVecFC).c_str(), std::ios::out | std::ios::binary); + + + std::vector<std::string> qNames; + qNames.push_back(path + simulationFileNames::inletBoundaryQ); + qNames.push_back(path + simulationFileNames::outletBoundaryQ); + qNames.push_back(path + simulationFileNames::topBoundaryQ); + qNames.push_back(path + simulationFileNames::bottomBoundaryQ); + qNames.push_back(path + simulationFileNames::frontBoundaryQ); + qNames.push_back(path + simulationFileNames::backBoundaryQ); + qNames.push_back(path + simulationFileNames::geomBoundaryQ); + + std::vector<std::string> valueNames; + valueNames.push_back(path + simulationFileNames::inletBoundaryValues); + valueNames.push_back(path + simulationFileNames::outletBoundaryValues); + valueNames.push_back(path + simulationFileNames::topBoundaryValues); + valueNames.push_back(path + simulationFileNames::bottomBoundaryValues); + valueNames.push_back(path + simulationFileNames::frontBoundaryValues); + valueNames.push_back(path + simulationFileNames::backBoundaryValues); + valueNames.push_back(path + simulationFileNames::geomBoundaryValues); + + for (int i = 0; i < QFILES; i++){ + SPtr<std::ofstream> outQ(new std::ofstream); + outQ->open(qNames[i].c_str(), std::ios::out | std::ios::binary); + qStreams.push_back(outQ); + + SPtr<std::ofstream> outV(new std::ofstream); + outV->open(valueNames[i].c_str(), std::ios::out | std::ios::binary); + valueStreams.push_back(outV); + } + + if(builder->getCommunicationProcess(CommunicationDirections::MX) != INVALID_INDEX) sendFiles [CommunicationDirections::MX].open( (path + std::to_string(builder->getCommunicationProcess(CommunicationDirections::MX)) + "Xs.dat").c_str() ); + if(builder->getCommunicationProcess(CommunicationDirections::PX) != INVALID_INDEX) sendFiles [CommunicationDirections::PX].open( (path + std::to_string(builder->getCommunicationProcess(CommunicationDirections::PX)) + "Xs.dat").c_str() ); + if(builder->getCommunicationProcess(CommunicationDirections::MY) != INVALID_INDEX) sendFiles [CommunicationDirections::MY].open( (path + std::to_string(builder->getCommunicationProcess(CommunicationDirections::MY)) + "Ys.dat").c_str() ); + if(builder->getCommunicationProcess(CommunicationDirections::PY) != INVALID_INDEX) sendFiles [CommunicationDirections::PY].open( (path + std::to_string(builder->getCommunicationProcess(CommunicationDirections::PY)) + "Ys.dat").c_str() ); + if(builder->getCommunicationProcess(CommunicationDirections::MZ) != INVALID_INDEX) sendFiles [CommunicationDirections::MZ].open( (path + std::to_string(builder->getCommunicationProcess(CommunicationDirections::MZ)) + "Zs.dat").c_str() ); + if(builder->getCommunicationProcess(CommunicationDirections::PZ) != INVALID_INDEX) sendFiles [CommunicationDirections::PZ].open( (path + std::to_string(builder->getCommunicationProcess(CommunicationDirections::PZ)) + "Zs.dat").c_str() ); + + if(builder->getCommunicationProcess(CommunicationDirections::MX) != INVALID_INDEX) receiveFiles[CommunicationDirections::MX].open( (path + std::to_string(builder->getCommunicationProcess(CommunicationDirections::MX)) + "Xr.dat").c_str() ); + if(builder->getCommunicationProcess(CommunicationDirections::PX) != INVALID_INDEX) receiveFiles[CommunicationDirections::PX].open( (path + std::to_string(builder->getCommunicationProcess(CommunicationDirections::PX)) + "Xr.dat").c_str() ); + if(builder->getCommunicationProcess(CommunicationDirections::MY) != INVALID_INDEX) receiveFiles[CommunicationDirections::MY].open( (path + std::to_string(builder->getCommunicationProcess(CommunicationDirections::MY)) + "Yr.dat").c_str() ); + if(builder->getCommunicationProcess(CommunicationDirections::PY) != INVALID_INDEX) receiveFiles[CommunicationDirections::PY].open( (path + std::to_string(builder->getCommunicationProcess(CommunicationDirections::PY)) + "Yr.dat").c_str() ); + if(builder->getCommunicationProcess(CommunicationDirections::MZ) != INVALID_INDEX) receiveFiles[CommunicationDirections::MZ].open( (path + std::to_string(builder->getCommunicationProcess(CommunicationDirections::MZ)) + "Zr.dat").c_str() ); + if(builder->getCommunicationProcess(CommunicationDirections::PZ) != INVALID_INDEX) receiveFiles[CommunicationDirections::PZ].open( (path + std::to_string(builder->getCommunicationProcess(CommunicationDirections::PZ)) + "Zr.dat").c_str() ); + + numberNodes_File.open((path + simulationFileNames::numberNodes).c_str(), std::ios::out | std::ios::binary); + LBMvsSI_File.open((path + simulationFileNames::LBMvsSI).c_str(), std::ios::out | std::ios::binary); +} + +void SimulationFileWriter::writeNumberNodes(SPtr<GridBuilder> builder, uint level) +{ + SPtr<Grid> grid = builder->getGrid(level); + numberNodes_File << level << '\n'; + + numberNodes_File << grid->getNumberOfNodesX() << ' '; + numberNodes_File << grid->getNumberOfNodesY() << ' '; + numberNodes_File << grid->getNumberOfNodesZ() << ' '; + numberNodes_File << '\n'; +} + +void SimulationFileWriter::writeLBMvsSI(SPtr<GridBuilder> builder, uint level) +{ + SPtr<Grid> grid = builder->getGrid(level); + + LBMvsSI_File << grid->getStartX() << ' '; + LBMvsSI_File << grid->getStartY() << ' '; + LBMvsSI_File << grid->getStartZ() << ' '; + + LBMvsSI_File << grid->getEndX() << ' '; + LBMvsSI_File << grid->getEndY() << ' '; + LBMvsSI_File << grid->getEndZ() << ' '; + LBMvsSI_File << '\n'; +} + +void SimulationFileWriter::writeLevel(uint numberOfLevels) +{ + const std::string level = std::to_string(numberOfLevels - 1); + + xCoordFile << level << "\n"; + yCoordFile << level << "\n"; + zCoordFile << level << "\n"; + xNeighborFile << level << "\n"; + yNeighborFile << level << "\n"; + zNeighborFile << level << "\n"; + wsbNeighborFile << level << "\n"; + geoVecFile << level << "\n"; + + scaleCF_coarse_File << level << "\n"; + scaleCF_fine_File << level << "\n"; + scaleFC_coarse_File << level << "\n"; + scaleFC_fine_File << level << "\n"; + + offsetVecCF_File << level << "\n"; + offsetVecFC_File << level << "\n"; + + //const std::string geoRB = "noSlip\n"; + + //for (int rb = 0; rb < QFILES; rb++) { + // *qStreams[rb] << level << "\n"; + // *valueStreams[rb] << geoRB << level << "\n"; + //} +} + +void SimulationFileWriter::writeLevelSize(uint numberOfNodes, FILEFORMAT format) +{ + const std::string zeroIndex = "0 "; + const std::string zeroGeo = "16 "; + + if (format == FILEFORMAT::BINARY) + { + //const uint zeroIndex = 0; + //const uint zeroGeo = 16; + + //xCoordFile.write((char*)&zeroIndex, sizeof(double)); + //yCoordFile.write((char*)&zeroIndex, sizeof(double)); + //zCoordFile.write((char*)&zeroIndex, sizeof(double)); + + //// + 1 for numbering shift between GridGenerator and VF_GPU + //xNeighborFile.write((char*)(&zeroIndex), sizeof(unsigned int)); + //yNeighborFile.write((char*)(&zeroIndex), sizeof(unsigned int)); + //zNeighborFile.write((char*)(&zeroIndex), sizeof(unsigned int)); + //wsbNeighborFile.write((char*)(&zeroIndex), sizeof(unsigned int)); + + //geoVecFile.write((char*)&zeroGeo, sizeof(unsigned int)); + + xCoordFile << numberOfNodes << "\n" << zeroIndex; + yCoordFile << numberOfNodes << "\n" << zeroIndex; + zCoordFile << numberOfNodes << "\n" << zeroIndex; + xNeighborFile << numberOfNodes << "\n" << zeroIndex; + yNeighborFile << numberOfNodes << "\n" << zeroIndex; + zNeighborFile << numberOfNodes << "\n" << zeroIndex; + wsbNeighborFile << numberOfNodes << "\n" << zeroIndex; + geoVecFile << numberOfNodes << "\n" << zeroGeo ; + } + else + { + xCoordFile << numberOfNodes << "\n" << zeroIndex << "\n"; + yCoordFile << numberOfNodes << "\n" << zeroIndex << "\n"; + zCoordFile << numberOfNodes << "\n" << zeroIndex << "\n"; + xNeighborFile << numberOfNodes << "\n" << zeroIndex << "\n"; + yNeighborFile << numberOfNodes << "\n" << zeroIndex << "\n"; + zNeighborFile << numberOfNodes << "\n" << zeroIndex << "\n"; + wsbNeighborFile << numberOfNodes << "\n" << zeroIndex << "\n"; + geoVecFile << numberOfNodes << "\n" << zeroGeo << "\n"; + } +} + +void SimulationFileWriter::writeLevelSizeGridInterface(uint sizeCF, uint sizeFC) +{ + scaleCF_coarse_File << sizeCF << "\n"; + scaleCF_fine_File << sizeCF << "\n"; + scaleFC_coarse_File << sizeFC << "\n"; + scaleFC_fine_File << sizeFC << "\n"; + + offsetVecCF_File << sizeCF << "\n"; + offsetVecFC_File << sizeFC << "\n"; +} + +void SimulationFileWriter::writeCoordFiles(SPtr<GridBuilder> builder, uint level, FILEFORMAT format) +{ + for (uint index = 0; index < builder->getGrid(level)->getSize(); index++){ + writeCoordsNeighborsGeo(builder, index, level, format); + } + + xCoordFile << "\n"; + yCoordFile << "\n"; + zCoordFile << "\n"; + + xNeighborFile << "\n"; + yNeighborFile << "\n"; + zNeighborFile << "\n"; + wsbNeighborFile << "\n"; + + geoVecFile << "\n"; +} + +void SimulationFileWriter::writeCoordsNeighborsGeo(SPtr<GridBuilder> builder, int index, uint level, FILEFORMAT format) +{ + SPtr<Grid> grid = builder->getGrid(level); + if (grid->getSparseIndex(index) == -1) + return; + + // Lenz: in the GPU code all nodes that perform collisions have to be fluid = 19 + bool isStopper = grid->getFieldEntry(index) == STOPPER_SOLID || + grid->getFieldEntry(index) == STOPPER_OUT_OF_GRID || + grid->getFieldEntry(index) == STOPPER_OUT_OF_GRID_BOUNDARY || + grid->getFieldEntry(index) == STOPPER_COARSE_UNDER_FINE; + int type = !isStopper ? 19 : 16; + + // old code from Soeren P. + //int type = grid->getFieldEntry(index) == FLUID ? 19 : 16; + + real x, y, z; + grid->transIndexToCoords(index, x, y, z); + + if (format == FILEFORMAT::BINARY) + { + double tmpX = (double)x; + double tmpY = (double)y; + double tmpZ = (double)z; + + xCoordFile.write((char*)&tmpX, sizeof(double)); + yCoordFile.write((char*)&tmpY, sizeof(double)); + zCoordFile.write((char*)&tmpZ, sizeof(double)); + + // + 1 for numbering shift between GridGenerator and VF_GPU + int tmpNeighborX = grid->getNeighborsX()[index] + 1; + int tmpNeighborY = grid->getNeighborsY()[index] + 1; + int tmpNeighborZ = grid->getNeighborsZ()[index] + 1; + int tmpNeighborNegative = grid->getNeighborsNegative()[index] + 1; + + xNeighborFile.write ((char*)(&tmpNeighborX ), sizeof(unsigned int)); + yNeighborFile.write ((char*)(&tmpNeighborY ), sizeof(unsigned int)); + zNeighborFile.write ((char*)(&tmpNeighborZ ), sizeof(unsigned int)); + wsbNeighborFile.write((char*)(&tmpNeighborNegative), sizeof(unsigned int)); + + geoVecFile.write((char*)&type, sizeof(unsigned int)); + } + else + { + xCoordFile << x << "\n"; + yCoordFile << y << "\n"; + zCoordFile << z << "\n"; + + // + 1 for numbering shift between GridGenerator and VF_GPU + xNeighborFile << (grid->getNeighborsX()[index] + 1) << "\n"; + yNeighborFile << (grid->getNeighborsY()[index] + 1) << "\n"; + zNeighborFile << (grid->getNeighborsZ()[index] + 1) << "\n"; + wsbNeighborFile << (grid->getNeighborsNegative()[index] + 1) << "\n"; + + geoVecFile << type << "\n"; + } +} + +void SimulationFileWriter::writeGridInterfaceToFile(SPtr<GridBuilder> builder, uint level) +{ + const uint numberOfNodesCF = builder->getNumberOfNodesCF(level); + const uint numberOfNodesFC = builder->getNumberOfNodesFC(level); + + { + uint* cf_coarse = new uint[numberOfNodesCF]; + uint* cf_fine = new uint[numberOfNodesCF]; + uint* fc_coarse = new uint[numberOfNodesFC]; + uint* fc_fine = new uint[numberOfNodesFC]; + + builder->getGridInterfaceIndices(cf_coarse, cf_fine, fc_coarse, fc_fine, level); + + if (numberOfNodesCF > 0) + { + writeGridInterfaceToFile(numberOfNodesCF, scaleCF_coarse_File, cf_coarse, scaleCF_fine_File, cf_fine); + } + + if (numberOfNodesFC > 0) + { + writeGridInterfaceToFile(numberOfNodesFC, scaleFC_coarse_File, fc_coarse, scaleFC_fine_File, fc_fine); + } + + delete [] cf_coarse; + delete [] cf_fine; + delete [] fc_coarse; + delete [] fc_fine; + } + + { + real* cf_offset_X = new real[numberOfNodesCF]; + real* cf_offset_Y = new real[numberOfNodesCF]; + real* cf_offset_Z = new real[numberOfNodesCF]; + + real* fc_offset_X = new real[numberOfNodesFC]; + real* fc_offset_Y = new real[numberOfNodesFC]; + real* fc_offset_Z = new real[numberOfNodesFC]; + + builder->getOffsetCF(cf_offset_X, cf_offset_Y, cf_offset_Z, level); + builder->getOffsetFC(fc_offset_X, fc_offset_Y, fc_offset_Z, level); + + if (numberOfNodesCF > 0) + { + writeGridInterfaceOffsetToFile(numberOfNodesCF, offsetVecCF_File, cf_offset_X, cf_offset_Y, cf_offset_Z); + } + + if (numberOfNodesFC > 0) + { + writeGridInterfaceOffsetToFile(numberOfNodesFC, offsetVecFC_File, fc_offset_X, fc_offset_Y, fc_offset_Z); + } + + delete[] cf_offset_X; + delete[] cf_offset_Y; + delete[] cf_offset_Z; + + delete[] fc_offset_X; + delete[] fc_offset_Y; + delete[] fc_offset_Z; + } +} + +void SimulationFileWriter::writeGridInterfaceToFile(const uint numberOfNodes, std::ofstream& coarseFile, uint* coarse, std::ofstream& fineFile, uint* fine) +{ + for (uint index = 0; index < numberOfNodes; index++) + { + coarseFile << coarse[index] << " \n"; + fineFile << fine[index] << " \n"; + } + coarseFile << "\n"; + fineFile << "\n"; +} + +void SimulationFileWriter::writeGridInterfaceOffsetToFile(uint numberOfNodes, std::ofstream & offsetFile, real* offset_X, real* offset_Y, real* offset_Z) +{ + for (uint index = 0; index < numberOfNodes; index++) + { + offsetFile << offset_X[index] << " " << offset_Y[index] << " " << offset_Z[index] << " \n"; + } + offsetFile << "\n"; +} + + + +/*#################################################################################*/ +/*---------------------------------private methods---------------------------------*/ +/*---------------------------------------------------------------------------------*/ +std::vector<std::vector<std::vector<real> > > SimulationFileWriter::createBCVectors(SPtr<Grid> grid) +{ + std::vector<std::vector<std::vector<real> > > qs; + qs.resize(QFILES); + for (uint i = 0; i < grid->getSize(); i++) + { + real x, y, z; + grid->transIndexToCoords(i, x, y, z); + + if (grid->getFieldEntry(i) == BC_SOLID) addShortQsToVector(i, qs, grid); //addQsToVector(i, qs, grid); + //if (x == 0 && y < grid->getNumberOfNodesY() - 1 && z < grid->getNumberOfNodesZ() - 1) fillRBForNode(i, 0, -1, INLETQS, qs, grid); + //if (x == grid->getNumberOfNodesX() - 2 && y < grid->getNumberOfNodesY() - 1 && z < grid->getNumberOfNodesZ() - 1) fillRBForNode(i, 0, 1, OUTLETQS, qs, grid); + + //if (z == grid->getNumberOfNodesZ() - 2 && x < grid->getNumberOfNodesX() - 1 && y < grid->getNumberOfNodesY() - 1) fillRBForNode(i, 2, 1, TOPQS, qs, grid); + //if (z == 0 && x < grid->getNumberOfNodesX() - 1 && y < grid->getNumberOfNodesY() - 1) fillRBForNode(i, 2, -1, BOTTOMQS, qs, grid); + + //if (y == 0 && x < grid->getNumberOfNodesX() - 1 && z < grid->getNumberOfNodesZ() - 1) fillRBForNode(i, 1, -1, FRONTQS, qs, grid); + //if (y == grid->getNumberOfNodesY() - 2 && x < grid->getNumberOfNodesX() - 1 && z < grid->getNumberOfNodesZ() - 1) fillRBForNode(i, 1, 1, BACKQS, qs, grid); + } + return qs; +} + +void SimulationFileWriter::addShortQsToVector(int index, std::vector<std::vector<std::vector<real> > > &qs, SPtr<Grid> grid) +{ + uint32_t qKey = 0; + std::vector<real> qNode; + + for (int i = grid->getEndDirection(); i >= 0; i--) + { + /*int qIndex = i * grid->getSize() + grid->getSparseIndex(index); + real q = grid->getDistribution()[qIndex];*/ + real q = grid->getQValue(index, i); + if (q > 0) { + //printf("Q%d (old:%d, new:%d), : %2.8f \n", i, coordsVec[index].matrixIndex, index, grid.d.f[i * grid.size + coordsVec[index].matrixIndex]); + qKey += (uint32_t)pow(2, 26 - i); + qNode.push_back(q); + } + } + if (qKey > 0) { + real transportKey = *((real*)&qKey); + qNode.push_back(transportKey); + qNode.push_back((real)index); + qs[GEOMQS].push_back(qNode); + } + qNode.clear(); +} + +void SimulationFileWriter::addQsToVector(int index, std::vector<std::vector<std::vector<real> > > &qs, SPtr<Grid> grid) +{ + std::vector<real> qNode; + qNode.push_back((real)index); + + for (int i = grid->getEndDirection(); i >= 0; i--) + { + //int qIndex = i * grid->getSize() + grid->getSparseIndex(index); + //real q = grid->getDistribution()[qIndex]; + real q = grid->getQValue(index, i); + qNode.push_back(q); + if (q > 0) + printf("Q= %f; Index = %d \n", q, index); + //qNode.push_back(q); + // else + // qNode.push_back(-1); + } + qs[GEOMQS].push_back(qNode); + qNode.clear(); +} + +void SimulationFileWriter::fillRBForNode(int index, int direction, int directionSign, int rb, std::vector<std::vector<std::vector<real> > > &qs, SPtr<Grid> grid) +{ + uint32_t qKey = 0; + std::vector<real> qNode; + + for (int i = grid->getEndDirection(); i >= 0; i--) + { + if (grid->getDirection()[i * DIMENSION + direction] != directionSign) + continue; + + qKey += (uint32_t)pow(2, 26 - i); + qNode.push_back(0.5f); + } + if (qKey > 0) { + real transportKey = *((real*)&qKey); + qNode.push_back(transportKey); + qNode.push_back((real)index); + qs[rb].push_back(qNode); + } + qNode.clear(); +} + + +void SimulationFileWriter::writeBoundaryQsFile(SPtr<GridBuilder> builder) +{ + // old code of Soeren P. + // for (int rb = 0; rb < QFILES; rb++) { + // for (int index = 0; index < qFiles[rb].size(); index++) { + // //writeBoundary(qFiles[rb][index], rb); + // writeBoundaryShort(qFiles[rb][index], rb); + //} + // } + + SideType sides[] = {SideType::MX, SideType::PX, SideType::PZ, SideType::MZ, SideType::MY, SideType::PY, SideType::GEOMETRY}; + + for (uint side = 0; side < QFILES; side++) { + + for (uint level = 0; level < builder->getNumberOfGridLevels(); level++) { + + auto bc = builder->getBoundaryCondition( sides[side], level ); + + if( level == 0 ){ + + if ( !bc ) *valueStreams[side] << "noSlip\n"; + else if( bc->getType() == BC_PRESSURE ) *valueStreams[side] << "pressure\n"; + else if( bc->getType() == BC_VELOCITY ) *valueStreams[side] << "velocity\n"; + else if( bc->getType() == BC_SOLID ) *valueStreams[side] << "noSlip\n"; + else if( bc->getType() == BC_SLIP ) *valueStreams[side] << "slip\n"; + else if( bc->getType() == BC_OUTFLOW ) *valueStreams[side] << "outflow\n"; + + *valueStreams[side] << builder->getNumberOfGridLevels() - 1 << "\n"; + *qStreams[side] << builder->getNumberOfGridLevels() - 1 << "\n"; + } + + if( !bc ){ + *valueStreams[side] << "0\n"; + *qStreams[side] << "0\n"; + } + else{ + writeBoundaryShort( builder->getGrid(level), bc, side ); + } + } + } +} + +void SimulationFileWriter::writeBoundary(std::vector<real> boundary, int rb) +{ + int index = (int)boundary[0]; + + *qStreams[rb] << (index + 1); + + for (std::size_t i = 1; i < boundary.size(); i++) { + *qStreams[rb] << " " << std::fixed << std::setprecision(16) << boundary[i]; + } + *valueStreams[rb] << (index+1) << " 0 0 0"; + + *qStreams[rb] << "\n"; + *valueStreams[rb] << "\n"; +} + +void SimulationFileWriter::writeBoundaryShort(std::vector<real> boundary, int rb) +{ + uint32_t key = *((uint32_t*)&boundary[boundary.size() - 2]); + int index = (int)boundary[boundary.size() - 1]; + + *qStreams[rb] << (index + 1) << " " << key; + + for (std::size_t i = 0; i < boundary.size() - 2; i++) { + *qStreams[rb] << " " << std::fixed << std::setprecision(16) << boundary[i]; + } + *valueStreams[rb] << (index + 1) << " 0 0 0"; + + *qStreams[rb] << "\n"; + *valueStreams[rb] << "\n"; +} + +void SimulationFileWriter::writeBoundaryShort(SPtr<Grid> grid, SPtr<gg::BoundaryCondition> boundaryCondition, uint side) +{ + uint numberOfBoundaryNodes = (uint)boundaryCondition->indices.size(); + + *valueStreams[side] << numberOfBoundaryNodes << "\n"; + *qStreams[side] << numberOfBoundaryNodes << "\n"; + + for( uint index = 0; index < numberOfBoundaryNodes; index++ ){ + + // + 1 for numbering shift between GridGenerator and VF_GPU + *valueStreams[side] << grid->getSparseIndex( boundaryCondition->indices[index] ) + 1 << " "; + *qStreams[side] << grid->getSparseIndex( boundaryCondition->indices[index] ) + 1 << " "; + + { + uint32_t key = 0; + + for (int dir = 26; dir >= 0; dir--) + { + real q = boundaryCondition->getQ(index,dir); + if (q > 0) { + key += (uint32_t)pow(2, 26 - dir); + } + } + + *qStreams[side] << key << " "; + + for (int dir = 26; dir >= 0; dir--) + { + real q = boundaryCondition->getQ(index,dir); + if (q > 0) { + *qStreams[side] << std::fixed << std::setprecision(16) << q << " "; + } + } + + *qStreams[side] << "\n"; + } + + if( boundaryCondition->getType() == BC_PRESSURE ) + { + auto bcPressure = dynamic_cast< PressureBoundaryCondition* >( boundaryCondition.get() ); + + *valueStreams[side] << bcPressure->getRho() << " "; + // + 1 for numbering shift between GridGenerator and VF_GPU + *valueStreams[side] << grid->getSparseIndex( bcPressure->neighborIndices[index] ) + 1 << " "; + } + + if( boundaryCondition->getType() == BC_VELOCITY ) + { + auto bcVelocity = dynamic_cast< VelocityBoundaryCondition* >( boundaryCondition.get() ); + + *valueStreams[side] << bcVelocity->getVx(index) << " "; + *valueStreams[side] << bcVelocity->getVy(index) << " "; + *valueStreams[side] << bcVelocity->getVz(index) << " "; + } + + if( boundaryCondition->getType() == BC_SOLID ) + { + auto bcGeometry = dynamic_cast< GeometryBoundaryCondition* >( boundaryCondition.get() ); + + *valueStreams[side] << bcGeometry->getVx(index) << " "; + *valueStreams[side] << bcGeometry->getVy(index) << " "; + *valueStreams[side] << bcGeometry->getVz(index) << " "; + } + + *valueStreams[side] << "\n"; + } + +} + +void SimulationFileWriter::writeCommunicationFiles(SPtr<GridBuilder> builder) +{ + const uint numberOfLevel = builder->getNumberOfGridLevels(); + + for( uint direction = 0; direction < 6; direction++ ){ + + if(builder->getCommunicationProcess(direction) == INVALID_INDEX) continue; + + sendFiles[direction] << "processor\n"; + sendFiles[direction] << builder->getNumberOfGridLevels() - 1 << "\n"; + + receiveFiles[direction] << "processor\n"; + receiveFiles[direction] << builder->getNumberOfGridLevels() - 1 << "\n"; + + for (uint level = 0; level < numberOfLevel; level++){ + + uint numberOfSendNodes = builder->getGrid(level)->getNumberOfSendNodes(direction); + uint numberOfReceiveNodes = builder->getGrid(level)->getNumberOfReceiveNodes(direction); + + sendFiles[direction] << numberOfSendNodes << "\n"; + receiveFiles[direction] << numberOfReceiveNodes << "\n"; + + for( uint index = 0; index < numberOfSendNodes; index++ ) + // + 1 for numbering shift between GridGenerator and VF_GPU + sendFiles[direction] << builder->getGrid(level)->getSparseIndex( builder->getGrid(level)->getSendIndex (direction, index) ) + 1 << "\n"; + + for( uint index = 0; index < numberOfReceiveNodes; index++ ) + // + 1 for numbering shift between GridGenerator and VF_GPU + receiveFiles[direction] << builder->getGrid(level)->getSparseIndex( builder->getGrid(level)->getReceiveIndex(direction, index) ) + 1 << "\n"; + + } + } +} + +void SimulationFileWriter::closeFiles() +{ + xCoordFile.close(); + yCoordFile.close(); + zCoordFile.close(); + xNeighborFile.close(); + yNeighborFile.close(); + zNeighborFile.close(); + wsbNeighborFile.close(); + geoVecFile.close(); + + scaleCF_coarse_File.close(); + scaleCF_fine_File.close(); + scaleFC_coarse_File.close(); + scaleFC_fine_File.close(); + + offsetVecCF_File.close(); + offsetVecFC_File.close(); + + for (int rb = 0; rb < QFILES; rb++) { + qStreams[rb]->close(); + valueStreams[rb]->close(); + } + + sendFiles[CommunicationDirections::MX].close(); + sendFiles[CommunicationDirections::PX].close(); + sendFiles[CommunicationDirections::MY].close(); + sendFiles[CommunicationDirections::PY].close(); + sendFiles[CommunicationDirections::MZ].close(); + sendFiles[CommunicationDirections::PZ].close(); + + receiveFiles[CommunicationDirections::MX].close(); + receiveFiles[CommunicationDirections::PX].close(); + receiveFiles[CommunicationDirections::MY].close(); + receiveFiles[CommunicationDirections::PY].close(); + receiveFiles[CommunicationDirections::MZ].close(); + receiveFiles[CommunicationDirections::PZ].close(); + + numberNodes_File.close(); + LBMvsSI_File.close(); +} + + +/*#################################################################################*/ +/*-------------------------------static attributes---------------------------------*/ +/*---------------------------------------------------------------------------------*/ +std::vector<SPtr<std::ofstream> > SimulationFileWriter::qStreams; +std::vector<SPtr<std::ofstream> > SimulationFileWriter::valueStreams; + +std::ofstream SimulationFileWriter::xCoordFile; +std::ofstream SimulationFileWriter::yCoordFile; +std::ofstream SimulationFileWriter::zCoordFile; +std::ofstream SimulationFileWriter::xNeighborFile; +std::ofstream SimulationFileWriter::yNeighborFile; +std::ofstream SimulationFileWriter::zNeighborFile; +std::ofstream SimulationFileWriter::wsbNeighborFile; +std::ofstream SimulationFileWriter::geoVecFile; +std::string SimulationFileWriter::folder; + +std::ofstream SimulationFileWriter::scaleCF_coarse_File; +std::ofstream SimulationFileWriter::scaleCF_fine_File; +std::ofstream SimulationFileWriter::scaleFC_coarse_File; +std::ofstream SimulationFileWriter::scaleFC_fine_File; + +std::ofstream SimulationFileWriter::offsetVecCF_File; +std::ofstream SimulationFileWriter::offsetVecFC_File; + +std::ofstream SimulationFileWriter::numberNodes_File; +std::ofstream SimulationFileWriter::LBMvsSI_File; + +std::array<std::ofstream, 6> SimulationFileWriter::sendFiles; +std::array<std::ofstream, 6> SimulationFileWriter::receiveFiles; \ No newline at end of file diff --git a/src/gpu/GridGenerator/io/SimulationFileWriter/SimulationFileWriter.h b/src/gpu/GridGenerator/io/SimulationFileWriter/SimulationFileWriter.h new file mode 100644 index 0000000000000000000000000000000000000000..d5d2a377b33697704b86f8b78987fd0af75be415 --- /dev/null +++ b/src/gpu/GridGenerator/io/SimulationFileWriter/SimulationFileWriter.h @@ -0,0 +1,129 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file SimulationFileWriter.h +//! \ingroup io +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#ifndef SimulationFileWriter_H +#define SimulationFileWriter_H + +#include <string> +#include <vector> +#include <fstream> +#include <memory> +#include <vector> +#include <array> + +#include "Core/NonCreatable.h" + +#include "global.h" + +class UnstructuredGridBuilder; +class GridBuilder; +class Grid; +namespace gg +{ +class BoundaryCondition; +} + +enum class FILEFORMAT +{ + BINARY, ASCII +}; + +class SimulationFileWriter : private NonCreatable +{ +public: + GRIDGENERATOR_EXPORT static void write(std::string folder, SPtr<GridBuilder> builder, FILEFORMAT format); + +private: + static void write(SPtr<GridBuilder> builder, FILEFORMAT format); + static void openFiles(SPtr<GridBuilder> builder); + + static void writeNumberNodes(SPtr<GridBuilder> builder, uint level); + static void writeLBMvsSI(SPtr<GridBuilder> builder, uint level); + + static void writeLevel(uint numberOfLevels); + static void writeLevelSize(uint numberOfNodes, FILEFORMAT format); + static void writeCoordFiles(SPtr<GridBuilder> builder, uint level, FILEFORMAT format); + static void writeCoordsNeighborsGeo(SPtr<GridBuilder> builder, int index, uint level, FILEFORMAT format); + + static void writeLevelSizeGridInterface(uint sizeCF, uint sizeFC); + static void writeGridInterfaceToFile(SPtr<GridBuilder> builder, uint level); + static void writeGridInterfaceToFile(uint numberOfNodes, std::ofstream& coarseFile, uint* coarse, std::ofstream& fineFile, uint* fine); + static void writeGridInterfaceOffsetToFile(uint numberOfNodes, std::ofstream& offsetFile, real* cf_offset_X, real* cf_offset_Y, real* cf_offset_Z); + + static void writeBoundaryQsFile(SPtr<GridBuilder> builder); + static std::vector<std::vector<std::vector<real> > > createBCVectors(SPtr<Grid> grid); + static void addShortQsToVector(int index, std::vector<std::vector<std::vector<real> > > &qs, SPtr<Grid> grid); + static void addQsToVector(int index, std::vector<std::vector<std::vector<real> > > &qs, SPtr<Grid> grid); + static void fillRBForNode(int index, int direction, int directionSign, int rb, std::vector<std::vector<std::vector<real> > > &qs, SPtr<Grid> grid); + static void writeBoundary(std::vector<real> boundary, int rb); + static void writeBoundaryShort(std::vector<real> boundary, int rb); + static void writeBoundaryShort(SPtr<Grid> grid, SPtr<gg::BoundaryCondition> boundaryCondition, uint side); + + static void writeCommunicationFiles(SPtr<GridBuilder> builder); + + static void closeFiles(); + + + static std::ofstream xCoordFile; + static std::ofstream yCoordFile; + static std::ofstream zCoordFile; + static std::ofstream xNeighborFile; + static std::ofstream yNeighborFile; + static std::ofstream zNeighborFile; + static std::ofstream wsbNeighborFile; + static std::ofstream geoVecFile; + + static std::ofstream scaleCF_coarse_File; + static std::ofstream scaleCF_fine_File; + static std::ofstream scaleFC_coarse_File; + static std::ofstream scaleFC_fine_File; + + static std::ofstream offsetVecCF_File; + static std::ofstream offsetVecFC_File; + + static std::vector<SPtr<std::ofstream> > qStreams; + static std::vector<SPtr<std::ofstream> > valueStreams; + + static std::vector<std::ofstream> qFiles; + static std::vector<std::ofstream> valueFiles; + + static std::array<std::ofstream, 6> sendFiles; + static std::array<std::ofstream, 6> receiveFiles; + + static std::ofstream numberNodes_File; + static std::ofstream LBMvsSI_File; + + static std::string folder; +}; + + +#endif diff --git a/src/gpu/GridGenerator/utilities/communication.h b/src/gpu/GridGenerator/utilities/communication.h new file mode 100644 index 0000000000000000000000000000000000000000..11a1085f6a21db1dfb26025514d8b3a9501fba5e --- /dev/null +++ b/src/gpu/GridGenerator/utilities/communication.h @@ -0,0 +1,47 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file Communication.h +//! \ingroup utilities +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#ifndef Communication_H +#define Communication_H + +namespace CommunicationDirections { + enum { + MX = 0, + PX = 1, + MY = 2, + PY = 3, + MZ = 4, + PZ = 5 + }; +} + +#endif // Communication_H \ No newline at end of file diff --git a/src/gpu/GridGenerator/utilities/math/Math.cu b/src/gpu/GridGenerator/utilities/math/Math.cpp similarity index 99% rename from src/gpu/GridGenerator/utilities/math/Math.cu rename to src/gpu/GridGenerator/utilities/math/Math.cpp index 404ecaf33d5dd21e0b789468b6d0e9858c3bc640..0f5f5cc8e05c9ce08a2854c0354371e18964610e 100644 --- a/src/gpu/GridGenerator/utilities/math/Math.cu +++ b/src/gpu/GridGenerator/utilities/math/Math.cpp @@ -26,7 +26,7 @@ // You should have received a copy of the GNU General Public License along // with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. // -//! \file Math.cu +//! \file Math.cpp //! \ingroup utilities //! \author Soeren Peters, Stephan Lenz //======================================================================================= diff --git a/src/gpu/GridGenerator/utilities/transformator/ArrowTransformator.cpp b/src/gpu/GridGenerator/utilities/transformator/ArrowTransformator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..74a33c31b4b87edd736e9beea783075906772829 --- /dev/null +++ b/src/gpu/GridGenerator/utilities/transformator/ArrowTransformator.cpp @@ -0,0 +1,40 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file ArrowTransformator.h +//! \ingroup utilities +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#include "ArrowTransformator.h" + +#include "utilities/transformator/TransformatorImp.h" + +std::shared_ptr<ArrowTransformator> ArrowTransformator::makeTransformator(real delta, real dx, real dy, real dz) +{ + return std::shared_ptr<ArrowTransformator>(new TransformatorImp(delta, dx, dy, dz)); +} diff --git a/src/gpu/GridGenerator/utilities/transformator/ArrowTransformator.h b/src/gpu/GridGenerator/utilities/transformator/ArrowTransformator.h new file mode 100644 index 0000000000000000000000000000000000000000..ad80114945c9e9be4cc38afa46c493edc1c55b66 --- /dev/null +++ b/src/gpu/GridGenerator/utilities/transformator/ArrowTransformator.h @@ -0,0 +1,56 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file ArrowTransformator.h +//! \ingroup utilities +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#ifndef ArrowTransformator_h +#define ArrowTransformator_h + +#include <memory> + +#include "global.h" + +class Arrow; + +class ArrowTransformator +{ +public: + static GRIDGENERATOR_EXPORT std::shared_ptr<ArrowTransformator> makeTransformator(real delta, real dx, real dy, real dz); + virtual ~ArrowTransformator() {} + +protected: + ArrowTransformator() {} + +public: + virtual void transformGridToWorld(std::shared_ptr<Arrow> arrow) const = 0; +}; + + +#endif diff --git a/src/gpu/GridGenerator/utilities/transformator/Transformator.cpp b/src/gpu/GridGenerator/utilities/transformator/Transformator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7e854c4baa21bb6d59834b2e099c5857389fd50c --- /dev/null +++ b/src/gpu/GridGenerator/utilities/transformator/Transformator.cpp @@ -0,0 +1,40 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file Transformator.cpp +//! \ingroup utilities +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#include "Transformator.h" + +#include "utilities/transformator/TransformatorImp.h" + +std::shared_ptr<Transformator> Transformator::makeTransformator(real delta, real dx, real dy, real dz) +{ + return std::shared_ptr<Transformator>(new TransformatorImp(delta, dx, dy, dz)); +} \ No newline at end of file diff --git a/src/gpu/GridGenerator/grid/GridStrategy/GridCpuStrategy/GridCpuStrategy.h b/src/gpu/GridGenerator/utilities/transformator/Transformator.h similarity index 58% rename from src/gpu/GridGenerator/grid/GridStrategy/GridCpuStrategy/GridCpuStrategy.h rename to src/gpu/GridGenerator/utilities/transformator/Transformator.h index 2b3d5a8d939924c198c53b8625622b1bd6e96dff..9510e818f3467bc4346fc9e8ece58a83c139e11d 100644 --- a/src/gpu/GridGenerator/grid/GridStrategy/GridCpuStrategy/GridCpuStrategy.h +++ b/src/gpu/GridGenerator/utilities/transformator/Transformator.h @@ -1,69 +1,69 @@ //======================================================================================= -// ____ ____ __ ______ __________ __ __ __ __ -// \ \ | | | | | _ \ |___ ___| | | | | / \ | | -// \ \ | | | | | |_) | | | | | | | / \ | | -// \ \ | | | | | _ / | | | | | | / /\ \ | | -// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ -// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| -// \ \ | | ________________________________________________________________ -// \ \ | | | ______________________________________________________________| -// \ \| | | | __ __ __ __ ______ _______ -// \ | | |_____ | | | | | | | | | _ \ / _____) -// \ | | _____| | | | | | | | | | | \ \ \_______ +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ // \ | | | | |_____ | \_/ | | | | |_/ / _____ | -// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ // -// This file is part of VirtualFluids. VirtualFluids is free software: you can +// This file is part of VirtualFluids. VirtualFluids is free software: you can // redistribute it and/or modify it under the terms of the GNU General Public -// License as published by the Free Software Foundation, either version 3 of +// License as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. -// -// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. -// +// // You should have received a copy of the GNU General Public License along // with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. // -//! \file GridCpuStrategy.h -//! \ingroup grid +//! \file Transformator.h +//! \ingroup utilities //! \author Soeren Peters, Stephan Lenz //======================================================================================= -#ifndef GRID_CPU_STRATEGY_H -#define GRID_CPU_STRATEGY_H +#ifndef Transformator_h +#define Transformator_h -#include "global.h" +#include <memory> -#include "grid/GridStrategy/GridStrategy.h" +#include "global.h" -class GridImp; +class BoundingBox; +struct Triangle; class TriangularMesh; +struct Vertex; -class GRIDGENERATOR_EXPORT GridCpuStrategy : public GridStrategy + +class Transformator { public: - virtual ~GridCpuStrategy() {}; - - void allocateGridMemory(SPtr<GridImp> grid) override; - - void initalNodesToOutOfGrid(SPtr<GridImp> grid) override; - void findInnerNodes(SPtr<GridImp> grid) override; - void findEndOfGridStopperNodes(SPtr<GridImp> grid) override; - - void freeMemory(SPtr<GridImp> grid) override; - - - - virtual void copyDataFromGPU() {}; + static GRIDGENERATOR_EXPORT std::shared_ptr<Transformator> makeTransformator(real delta, real dx, real dy, real dz); + virtual ~Transformator() {} protected: - static void findForNeighborsNewIndices(SPtr<GridImp> grid); + Transformator(){} + public: - void allocateFieldMemory(Field* field) override; - void freeFieldMemory(Field* field) override; - void findSparseIndices(SPtr<GridImp> coarseGrid, SPtr<GridImp> fineGrid) override; + virtual void transformWorldToGrid(Triangle &value) const = 0; + virtual void transformWorldToGrid(TriangularMesh &geom) const = 0; + virtual void transformWorldToGrid(Vertex &value) const = 0; + + virtual void transformGridToWorld(Triangle &t) const = 0; + virtual void transformGridToWorld(Vertex &value) const = 0; + + virtual void transformGridToWorld(BoundingBox &box) const = 0; + virtual void transformWorldToGrid(BoundingBox &box) const = 0; }; -#endif \ No newline at end of file + +#endif diff --git a/src/gpu/GridGenerator/utilities/transformator/TransformatorImp.cpp b/src/gpu/GridGenerator/utilities/transformator/TransformatorImp.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3c7a3b675104eabab89c59d481797ff41b2033c8 --- /dev/null +++ b/src/gpu/GridGenerator/utilities/transformator/TransformatorImp.cpp @@ -0,0 +1,190 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file TransformatorImp.cpp +//! \ingroup utilities +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#include "TransformatorImp.h" + +#include <memory> + +#include "geometries/BoundingBox/BoundingBox.h" +#include "geometries/Triangle/Triangle.h" +#include "geometries/TriangularMesh/TriangularMesh.h" +#include "geometries/Vertex/Vertex.h" +#include "geometries/Arrow/Arrow.h" + +TransformatorImp::TransformatorImp() +{ + this->translater = std::shared_ptr<Vertex>(new Vertex()); + this->delta = 1.0; + this->translater->x = 0; + this->translater->y = 0; + this->translater->z = 0; +} + +TransformatorImp::TransformatorImp(real delta, const Vertex& translater) : delta(delta), translater(std::make_shared<Vertex>(translater)) +{ + this->verifyDelta(delta); +} + +TransformatorImp::TransformatorImp(real delta, real dx, real dy, real dz) : TransformatorImp(delta, Vertex(dx,dy,dz)) +{ + +} + +TransformatorImp::TransformatorImp(const TransformatorImp& trafo) +{ + this->delta = trafo.delta; + this->translater = std::shared_ptr<Vertex>(new Vertex(*trafo.translater.get())); +} + +TransformatorImp::~TransformatorImp() +{ + +} + +void TransformatorImp::transformWorldToGrid(TriangularMesh &geom) const +{ + for (int i = 0; i < geom.size; i++) + transformWorldToGrid(geom.triangleVec[i]); +} + +void TransformatorImp::transformWorldToGrid(Triangle &value) const +{ + transformWorldToGrid(value.v1); + transformWorldToGrid(value.v2); + transformWorldToGrid(value.v3); +} + +void TransformatorImp::transformGridToWorld(std::shared_ptr<Arrow> arrow) const +{ + transformGridToWorld(*arrow->getStart()); + transformGridToWorld(*arrow->getEnd()); +} + +void TransformatorImp::transformWorldToGrid(Vertex &v) const +{ + translateWorldToView(v); + scaleWorldToView(v); +} + + +void TransformatorImp::translateWorldToView(Vertex& v) const +{ + v = *translater.get() + v; +} + +void TransformatorImp::scaleWorldToView(Vertex& v) const +{ + v = v * (1.0f / this->delta); +} + + +void TransformatorImp::transformGridToWorld(Triangle & t) const +{ + transformGridToWorld(t.v1); + transformGridToWorld(t.v2); + transformGridToWorld(t.v3); +} + +void TransformatorImp::transformGridToWorld(Vertex &value) const +{ + scaleGridToWorld(value); + translateGridToWorld(value); +} + +void TransformatorImp::scaleGridToWorld(Vertex & value) const +{ + value = value * this->delta; +} + + +void TransformatorImp::translateGridToWorld(Vertex & value) const +{ + value = value - *translater.get(); +} + + +void TransformatorImp::transformGridToWorld(BoundingBox &box) const +{ + //scale + box.minX = (box.minX * this->delta); + box.minY = (box.minY * this->delta); + box.minZ = (box.minZ * this->delta); + + box.maxX = (box.maxX * this->delta); + box.maxY = (box.maxY * this->delta); + box.maxZ = (box.maxZ * this->delta); + + //translate + box.minX = (box.minX - this->translater->x); + box.minY = (box.minY - this->translater->y); + box.minZ = (box.minZ - this->translater->z); + + box.maxX = (box.maxX - this->translater->x); + box.maxY = (box.maxY - this->translater->y); + box.maxZ = (box.maxZ - this->translater->z); +} + +void TransformatorImp::transformWorldToGrid(BoundingBox &box) const +{ + //translate + box.minX += this->translater->x; + box.minY += this->translater->y; + box.minZ += this->translater->z; + + box.maxX += this->translater->x; + box.maxY += this->translater->y; + box.maxZ += this->translater->z; + + //scale + box.minX *= (1.0f / this->delta); + box.minY *= (1.0f / this->delta); + box.minZ *= (1.0f / this->delta); + + box.maxX *= (1.0f / this->delta); + box.maxY *= (1.0f / this->delta); + box.maxZ *= (1.0f / this->delta); +} + + +void TransformatorImp::verifyDelta(real delta) const +{ + if (delta <= 0.0) + throw invalidDelta(); +} + +bool TransformatorImp::operator==(const TransformatorImp& trafo) const +{ + return (this->delta == trafo.delta + && this->translater->x == trafo.translater->x + && this->translater->y == trafo.translater->y + && this->translater->z == trafo.translater->z); +} diff --git a/src/gpu/GridGenerator/utilities/transformator/TransformatorImp.h b/src/gpu/GridGenerator/utilities/transformator/TransformatorImp.h new file mode 100644 index 0000000000000000000000000000000000000000..81ba5a25badc879aa501256ed67eed0a4b39961c --- /dev/null +++ b/src/gpu/GridGenerator/utilities/transformator/TransformatorImp.h @@ -0,0 +1,103 @@ +//======================================================================================= +// ____ ____ __ ______ __________ __ __ __ __ +// \ \ | | | | | _ \ |___ ___| | | | | / \ | | +// \ \ | | | | | |_) | | | | | | | / \ | | +// \ \ | | | | | _ / | | | | | | / /\ \ | | +// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____ +// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______| +// \ \ | | ________________________________________________________________ +// \ \ | | | ______________________________________________________________| +// \ \| | | | __ __ __ __ ______ _______ +// \ | | |_____ | | | | | | | | | _ \ / _____) +// \ | | _____| | | | | | | | | | | \ \ \_______ +// \ | | | | |_____ | \_/ | | | | |_/ / _____ | +// \ _____| |__| |________| \_______/ |__| |______/ (_______/ +// +// This file is part of VirtualFluids. VirtualFluids is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file TransformatorImp.h +//! \ingroup utilities +//! \author Soeren Peters, Stephan Lenz +//======================================================================================= +#ifndef TransformatorImp_h +#define TransformatorImp_h + +#include <exception> +#include <sstream> + +#include "global.h" +#include "GridGenerator_export.h" + +#include "utilities/transformator/Transformator.h" +#include "utilities/transformator/ArrowTransformator.h" + +class BoundingBox; +struct Triangle; +class TriangularMesh; +struct Vertex; + +class invalidDelta : public std::exception +{ + public: + invalidDelta() : error_message ("Delta cant be < Null. To enable no changes change delta to 1.0.") + {} + + const char* what() const noexcept + { + return error_message.c_str(); + } + + private: + std::string error_message; +}; + +class TransformatorImp + : public Transformator, public ArrowTransformator +{ +public: + GRIDGENERATOR_EXPORT TransformatorImp(); + GRIDGENERATOR_EXPORT TransformatorImp(const TransformatorImp& trafo); + GRIDGENERATOR_EXPORT TransformatorImp(real delta, const Vertex& translater); + GRIDGENERATOR_EXPORT TransformatorImp(real delta, real dx, real dy, real dz); + GRIDGENERATOR_EXPORT virtual ~TransformatorImp(); + + GRIDGENERATOR_EXPORT void transformWorldToGrid(Triangle &value) const override; + GRIDGENERATOR_EXPORT void transformWorldToGrid(TriangularMesh &geom) const override; + GRIDGENERATOR_EXPORT void transformWorldToGrid(Vertex &value) const override; + + GRIDGENERATOR_EXPORT void transformGridToWorld(Triangle &t) const override; + GRIDGENERATOR_EXPORT void transformGridToWorld(Vertex &value) const override; + + GRIDGENERATOR_EXPORT void transformGridToWorld(BoundingBox &box) const override; + GRIDGENERATOR_EXPORT void transformWorldToGrid(BoundingBox &box) const override; + + GRIDGENERATOR_EXPORT bool operator==(const TransformatorImp& trafo) const; + + GRIDGENERATOR_EXPORT virtual void transformGridToWorld(std::shared_ptr<Arrow> arrow) const override; + +private: + real delta; + std::shared_ptr<Vertex> translater; + + void scaleWorldToView(Vertex & v) const; + void translateWorldToView(Vertex & v) const; + + void translateGridToWorld(Vertex & value) const; + void scaleGridToWorld(Vertex & value) const; + + void verifyDelta(real delta) const; +}; + + +#endif