diff --git a/CMakeLists.txt b/CMakeLists.txt index 201de083f0971f7e00d7f7ec278384ed5bce8666..57e78b71729483cb0be62688a438df0316b469fb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,7 @@ dune_enable_all_packages() add_subdirectory(doc) add_subdirectory(cmake/modules) add_subdirectory(appl) +add_subdirectory(dumux) # finalize the dune project, e.g. generating config.h etc. finalize_dune_project(GENERATE_CONFIG_H_CMAKE) diff --git a/dumux/CMakeLists.txt b/dumux/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..88dedfd800890b8f320070dcb07b574541976767 --- /dev/null +++ b/dumux/CMakeLists.txt @@ -0,0 +1,4 @@ +#install headers +install(FILES +poregeometries.hh +DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dumux/) diff --git a/dumux/poregeometries.hh b/dumux/poregeometries.hh new file mode 100644 index 0000000000000000000000000000000000000000..114fdf67a7162ea15c1c5ddedd35ff7780efc013 --- /dev/null +++ b/dumux/poregeometries.hh @@ -0,0 +1,276 @@ +// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +// vi: set et ts=4 sw=4 sts=4: +/***************************************************************************** + * See the file COPYING for full copying permissions. * + * * + * This program 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. * + * * + * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. * + *****************************************************************************/ + +/*! + * \file + * \ingroup Freeflow Porous Media Flow + * \ingroup Pore Geometry + * \brief The problem file for the evaluation of a pore geometry adjacent to a freeflow with RANS models + */ + +#ifndef DUMUX_PORE_GEOMETRIES_HH +#define DUMUX_PORE_GEOMETRIES_HH + +namespace Dumux::PoreGeometries { + +template <class PoreBlockList, class Scalar, class DimensionPair, class BoundingBox> +void buildUniformPoreGeometry(PoreBlockList& poreBlockList, + Scalar porosity, + DimensionPair numVolumes, + BoundingBox porousMediaBox) +{ + using PoreBlock = typename std::remove_reference<decltype(poreBlockList)>::type::value_type; + using GlobalPosition = typename PoreBlock::GlobalPosition; + GlobalPosition volumeSize; + volumeSize[0] = (porousMediaBox.second[0] - porousMediaBox.first[0]) / numVolumes[0]; + volumeSize[1] = (porousMediaBox.second[1] - porousMediaBox.first[1]) / numVolumes[1]; + const Scalar volumeLength = volumeSize[1]; + const Scalar poreLength = std::sqrt(volumeLength * volumeLength - (volumeLength * volumeLength * porosity)); + const Scalar poreOffset = (volumeLength - poreLength) / 2.0; + + for (int i = 0; i < numVolumes[0]; i++) + { + for (int j = 0; j < numVolumes[1]; j++) + { + PoreBlock poreBlock; + poreBlock.gridBoxMin[0] = porousMediaBox.first[0] + (volumeSize[0] * i); + poreBlock.gridBoxMin[1] = porousMediaBox.first[1] + (volumeSize[1] * j); + poreBlock.gridBoxMax[0] = porousMediaBox.first[0] + (volumeSize[0] * (i+1)); + poreBlock.gridBoxMax[1] = porousMediaBox.first[1] + (volumeSize[1] * (j+1)); + + poreBlock.poreBlockMin[0] = poreBlock.gridBoxMin[0] + (poreOffset); + poreBlock.poreBlockMax[0] = poreBlock.poreBlockMin[0] + poreLength; + poreBlock.poreBlockMin[1] = poreBlock.gridBoxMin[1] + (poreOffset); + poreBlock.poreBlockMax[1] = poreBlock.poreBlockMin[1] + poreLength; + + poreBlockList.push_back(poreBlock); + } + } +} + +template <class PoreBlockList, class Scalar, class DimensionPair, class BoundingBox> +void buildStaggeredPoreGeometry(PoreBlockList& poreBlockList, + Scalar porosity, + DimensionPair numVolumes, + BoundingBox porousMediaBox) +{ + using PoreBlock = typename std::remove_reference<decltype(poreBlockList)>::type::value_type; + using GlobalPosition = typename PoreBlock::GlobalPosition; + GlobalPosition volumeSize; + numVolumes[1] = numVolumes[1] + 1; + porousMediaBox.first[1] = porousMediaBox.first[1] - ((porousMediaBox.second[0] - porousMediaBox.first[0]) / numVolumes[0]); + volumeSize[0] = (porousMediaBox.second[0] - porousMediaBox.first[0]) / numVolumes[0]; + volumeSize[1] = (porousMediaBox.second[1] - porousMediaBox.first[1]) / numVolumes[1]; + const Scalar volumeLength = volumeSize[1]; + const Scalar poreLength = std::sqrt(volumeLength * volumeLength - (volumeLength * volumeLength * porosity)); + const Scalar poreOffset = (volumeLength - poreLength) / 2.0; + + // Shift staggered pores vertically + const Scalar staggeredOffset = volumeSize[1] / 2.0; + + for (int i = 0; i < numVolumes[0]; i++) + { + for (int j = 0; j < numVolumes[1]; j++) + { + PoreBlock poreBlock; + poreBlock.gridBoxMin[0] = porousMediaBox.first[0] + (volumeSize[0] * i); + poreBlock.gridBoxMin[1] = porousMediaBox.first[1] + (volumeSize[1] * j); + poreBlock.gridBoxMax[0] = porousMediaBox.first[0] + (volumeSize[0] * (i+1)); + poreBlock.gridBoxMax[1] = porousMediaBox.first[1] + (volumeSize[1] * (j+1)); + + poreBlock.poreBlockMin[0] = poreBlock.gridBoxMin[0] + (poreOffset); + poreBlock.poreBlockMax[0] = poreBlock.poreBlockMin[0] + poreLength; + poreBlock.poreBlockMin[1] = poreBlock.gridBoxMin[1] + (poreOffset); + poreBlock.poreBlockMax[1] = poreBlock.poreBlockMin[1] + poreLength; + + if ( i % 2 != 0) + { + poreBlock.isStaggered = true; + poreBlock.poreBlockMin[1] = (poreBlock.poreBlockMin[1] + staggeredOffset); + poreBlock.poreBlockMax[1] = (poreBlock.poreBlockMax[1] + staggeredOffset); + } + poreBlockList.push_back(poreBlock); + } + } +} + + +template <class PoreBlockList, class Scalar, class DimensionPair, class BoundingBox> +void buildRandomConstantPorosityPoreGeometry(PoreBlockList& poreBlockList, + Scalar porosity, + DimensionPair numVolumes, + BoundingBox porousMediaBox) +{ + using PoreBlock = typename std::remove_reference<decltype(poreBlockList)>::type::value_type; + using GlobalPosition = typename PoreBlock::GlobalPosition; + GlobalPosition volumeSize; + volumeSize[0] = (porousMediaBox.second[0] - porousMediaBox.first[0]) / numVolumes[0]; + volumeSize[1] = (porousMediaBox.second[1] - porousMediaBox.first[1]) / numVolumes[1]; + const Scalar volumeLength = volumeSize[1]; + const Scalar poreLength = std::sqrt(volumeLength * volumeLength - (volumeLength * volumeLength * porosity)); + + for (int i = 0; i < numVolumes[0]; i++) + { + for (int j = 0; j < numVolumes[1]; j++) + { + PoreBlock poreBlock; + poreBlock.gridBoxMin[0] = porousMediaBox.first[0] + (volumeSize[0] * i); + poreBlock.gridBoxMin[1] = porousMediaBox.first[1] + (volumeSize[1] * j); + poreBlock.gridBoxMax[0] = porousMediaBox.first[0] + (volumeSize[0] * (i+1)); + poreBlock.gridBoxMax[1] = porousMediaBox.first[1] + (volumeSize[1] * (j+1)); + poreBlock.centerPoint[0] = (poreBlock.gridBoxMax[0] + poreBlock.gridBoxMin[0]) / 2.0; + poreBlock.centerPoint[1] = (poreBlock.gridBoxMax[1] + poreBlock.gridBoxMin[1]) / 2.0; + + double r1 = ( (double) std::rand() / (RAND_MAX)); + poreBlock.poreBlockMin[0] = poreBlock.gridBoxMin[0] + ((poreBlock.centerPoint[0] - poreBlock.gridBoxMin[0]) * r1); + poreBlock.poreBlockMax[0] = poreBlock.poreBlockMin[0] + poreLength; + double r2 = ( (double) std::rand() / (RAND_MAX)); + poreBlock.poreBlockMin[1] = poreBlock.gridBoxMin[1] + ((poreBlock.centerPoint[1] - poreBlock.gridBoxMin[1]) * r2); + poreBlock.poreBlockMax[1] = poreBlock.poreBlockMin[1] + poreLength; + + poreBlockList.push_back(poreBlock); + } + } +} + +template <class PoreBlockList, class Scalar, class DimensionPair, class BoundingBox> +void buildRandomPoreGeometry(PoreBlockList& poreBlockList, + Scalar porosity, + DimensionPair numVolumes, + BoundingBox porousMediaBox) +{ + using PoreBlock = typename std::remove_reference<decltype(poreBlockList)>::type::value_type; + using GlobalPosition = typename PoreBlock::GlobalPosition; + GlobalPosition volumeSize; + volumeSize[0] = (porousMediaBox.second[0] - porousMediaBox.first[0]) / numVolumes[0]; + volumeSize[1] = (porousMediaBox.second[1] - porousMediaBox.first[1]) / numVolumes[1]; + + for (int i = 0; i < numVolumes[0]; i++) + { + for (int j = 0; j < numVolumes[1]; j++) + { + PoreBlock poreBlock; + poreBlock.gridBoxMin[0] = porousMediaBox.first[0] + (volumeSize[0] * i); + poreBlock.gridBoxMin[1] = porousMediaBox.first[1] + (volumeSize[1] * j); + poreBlock.gridBoxMax[0] = porousMediaBox.first[0] + (volumeSize[0] * (i+1)); + poreBlock.gridBoxMax[1] = porousMediaBox.first[1] + (volumeSize[1] * (j+1)); + poreBlock.centerPoint[0] = (poreBlock.gridBoxMax[0] + poreBlock.gridBoxMin[0]) / 2.0; + poreBlock.centerPoint[1] = (poreBlock.gridBoxMax[1] + poreBlock.gridBoxMin[1]) / 2.0; + + double r1 = ( (double) std::rand() / (RAND_MAX)); + poreBlock.poreBlockMin[0] = poreBlock.gridBoxMin[0] + ((poreBlock.centerPoint[0] - poreBlock.gridBoxMin[0]) * r1); + double r2 = ( (double) std::rand() / (RAND_MAX)); + poreBlock.poreBlockMin[1] = poreBlock.gridBoxMin[1] + ((poreBlock.centerPoint[1] - poreBlock.gridBoxMin[1]) * r2); + + double r3 = ( (double) std::rand() / (RAND_MAX)); + poreBlock.poreBlockMax[0] = poreBlock.centerPoint[0] + ((poreBlock.gridBoxMax[0] - poreBlock.centerPoint[0]) * r3); + double r4 = ( (double) std::rand() / (RAND_MAX)); + poreBlock.poreBlockMax[1] = poreBlock.centerPoint[1] + ((poreBlock.gridBoxMax[1] - poreBlock.centerPoint[1]) * r4); + + poreBlockList.push_back(poreBlock); + } + } +} + +template <class PoreBlockList> +void readInPoreGeometry(PoreBlockList& poreBlockList, + std::string gridInputFileName) +{ + // Open the file and make sure that the file is open + std::ifstream infile(gridInputFileName, std::ios::in); + if (!infile) + DUNE_THROW(Dune::IOError, "Unable to open file: " << gridInputFileName << " !\n"); + + using PoreBlock = typename std::remove_reference<decltype(poreBlockList)>::type::value_type; + using Scalar = typename PoreBlock::Scalar; + + std::vector<std::vector<Scalar>> coodinates; + int lineIdx = 0; + while (infile) + { + lineIdx++; + std::string s; + // If there is no further line, end loop + if (!getline(infile, s)) + break; + + // Read each line to a string + if (s[0] != '#') // ignore lines that start with the comment indicator (#) + { + std::istringstream ss(s); + std::vector<Scalar> blockRecord; + + while (ss) + { + std::string line; + if (!getline(ss, line, ',')) // delimited with a comma + break; + + blockRecord.push_back(std::stof(line)); + } + + coodinates.push_back(blockRecord); + } + } + + if (!infile.eof()) + DUNE_THROW(Dune::IOError, "Could not read file " << gridInputFileName << "!\n"); + + for (int i = 0; i < coodinates.size(); i++) + { + PoreBlock poreBlock; + poreBlock.poreBlockMin[0] = coodinates[i][0]; + poreBlock.poreBlockMax[0] = coodinates[i][1]; + poreBlock.poreBlockMin[1] = coodinates[i][2]; + poreBlock.poreBlockMax[1] = coodinates[i][3]; + poreBlockList.push_back(poreBlock); + } + std::cout << "The Pore geometry has been sucessfully created from the provided grid file. \n"; +} + + +template <class PoreBlockList> +void writeOutPoreGeometryFileToCSV(const PoreBlockList& poreBlockList, + std::string gridOutputFileName) +{ + std::string gridListFileName = "PoreGeometry_" + gridOutputFileName + ".csv"; + std::ofstream gridOutputFile; + + gridOutputFile.open(gridListFileName, std::ios::app); + gridOutputFile << "#PoreMin[0]" << "," + << "PoreMax[0]" << "," + << "PoreMin[1]" << "," + << "PoreMax[1]" << "\n"; + gridOutputFile.close();// Export the coordinates + + for (int i = 0; i < poreBlockList.size(); i++) + { + gridOutputFile.open(gridListFileName, std::ios::app); + gridOutputFile << poreBlockList[i].poreBlockMin[0] << "," + << poreBlockList[i].poreBlockMax[0] << "," + << poreBlockList[i].poreBlockMin[1] << "," + << poreBlockList[i].poreBlockMax[1] << "\n"; + gridOutputFile.close(); + } + std::cout << "The Pore geometry description is writen to the " << gridListFileName << " file. \n"; +} + +} // end namespace Dumux::PoreGeometries + +#endif