/* Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University Copyright Equnior ASA This file is part of the Open Porous Media project (OPM). OPM 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. OPM 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 OPM. If not, see . */ #ifndef Domain_INC #define Domain_INC #include #include #include #include #include #include #include #include #include #include "common/Array.h" #include "common/Utilities.h" #include "common/MPI.h" #include "common/Communication.h" #include "common/Database.h" /** * @file Domain.h * \brief Parallel Domain data structures and helper functions */ /** * \class Box * * @details * information about a box */ class Box { public: int ifirst[3]; int ilast[3]; }; class Patch; /** * \class Domain * * @details * the Domain class includes basic information to distribution 3D image data to multiple processes using MPI. * A regular domain decomposision is performed, with each MPI process getting a [Nx,Ny,Nz] sub-domain. * 8-bit image labels are retained internally. * The domain class resides on the CPU and provides utilities to support CPU-based analysis. * GPU-based data structures should be constructed separately but may utilize information that the Domain class provides. */ class Domain { public: /** * \brief Constructor * @param db input database * @param Communicator MPI communicator */ Domain(std::shared_ptr db, const Utilities::MPI &Communicator); /** * \brief Obsolete constructor */ Domain(int nx, int ny, int nz, int rnk, int npx, int npy, int npz, double lx, double ly, double lz, int BC); /** * \brief Empty constructor */ Domain() = delete; /** * \brief Copy constructor */ Domain(const Domain &) = delete; /** * \brief Assignment operator */ Domain &operator=(const Domain &) = delete; /** * \brief Destructor */ ~Domain(); /** * \brief Get the database */ inline std::shared_ptr getDatabase() const { return d_db; } /** * \brief Get the domain box */ inline const Box &getBox() const { return d_box; } /** * \brief Get local patch */ inline const Patch &getLocalPatch() const { return *d_localPatch; } /** * \brief Get all patches */ inline const std::vector &getAllPatch() const { return d_patches; } private: /** * \brief initialize from database */ void initialize(std::shared_ptr db); std::shared_ptr d_db; Box d_box; Patch *d_localPatch; std::vector d_patches; public: // Public variables (need to create accessors instead) std::shared_ptr database; double Lx, Ly, Lz, Volume, voxel_length; int Nx, Ny, Nz, N; int inlet_layers_x, inlet_layers_y, inlet_layers_z; int outlet_layers_x, outlet_layers_y, outlet_layers_z; int inlet_layers_phase; //as usual: 1->n, 2->w int outlet_layers_phase; double porosity; RankInfoStruct rank_info; Utilities::MPI Comm; // MPI Communicator for this domain int BoundaryCondition; //********************************** // MPI ranks for all 18 neighbors //********************************** /** * \brief Compute the porosity based on the current domain id file */ inline double Porosity() const { return porosity; } inline int iproc() const { return rank_info.ix; } inline int jproc() const { return rank_info.jy; } inline int kproc() const { return rank_info.kz; } inline int nprocx() const { return rank_info.nx; } inline int nprocy() const { return rank_info.ny; } inline int nprocz() const { return rank_info.nz; } inline int rank() const { return rank_info.rank[1][1][1]; } inline int rank_X() const { return rank_info.rank[2][1][1]; } inline int rank_x() const { return rank_info.rank[0][1][1]; } inline int rank_Y() const { return rank_info.rank[1][2][1]; } inline int rank_y() const { return rank_info.rank[1][0][1]; } inline int rank_Z() const { return rank_info.rank[1][1][2]; } inline int rank_z() const { return rank_info.rank[1][1][0]; } inline int rank_XY() const { return rank_info.rank[2][2][1]; } inline int rank_xy() const { return rank_info.rank[0][0][1]; } inline int rank_Xy() const { return rank_info.rank[2][0][1]; } inline int rank_xY() const { return rank_info.rank[0][2][1]; } inline int rank_XZ() const { return rank_info.rank[2][1][2]; } inline int rank_xz() const { return rank_info.rank[0][1][0]; } inline int rank_Xz() const { return rank_info.rank[2][1][0]; } inline int rank_xZ() const { return rank_info.rank[0][1][2]; } inline int rank_YZ() const { return rank_info.rank[1][2][2]; } inline int rank_yz() const { return rank_info.rank[1][0][0]; } inline int rank_Yz() const { return rank_info.rank[1][2][0]; } inline int rank_yZ() const { return rank_info.rank[1][0][2]; } //********************************** //...................................................................................... // Get the actual D3Q19 communication counts (based on location of solid phase) // Discrete velocity set symmetry implies the sendcount = recvcount //...................................................................................... inline int recvCount(const char *dir) const { return getRecvList(dir).size(); } inline int sendCount(const char *dir) const { return getSendList(dir).size(); } inline const int *recvList(const char *dir) const { return getRecvList(dir).data(); } inline const int *sendList(const char *dir) const { return getSendList(dir).data(); } //...................................................................................... // Solid indicator function std::vector id; /** * \brief Read domain IDs from file */ void ReadIDs(); /** * \brief Compute the porosity */ void ComputePorosity(); /** * \brief Read image and perform domain decomposition * @param filename - name of file to read IDs */ void Decomp(const std::string &filename); /** * \brief Perform a halo exchange using MPI * @param Mesh - array data that holds scalar values */ void CommunicateMeshHalo(DoubleArray &Mesh); /** * \brief Initialize communication data structures within Domain object. * This routine needs to be called before the communication functionality will work */ void CommInit(); /** * \brief Count number of pore nodes (labels > 1) */ int PoreCount(); /** * \brief Read array data from a file and distribute to local arrays for each MPI process * @param Filename - name of the file to read the data * @param Datatype - data type to use * @param UserData - Array to store the values that are read */ void ReadFromFile(const std::string &Filename, const std::string &Datatype, double *UserData); /** * \brief Aggregate labels from all MPI processes and write to a file * @param filename - name of the file to write */ void AggregateLabels(const std::string &filename); /** * \brief Aggregate user provided array from all MPI processes and write to a single file * @param filename - name of the file to write * @param UserData - array data to aggregate and write */ void AggregateLabels(const std::string &filename, DoubleArray &UserData); private: /** * \brief Pack halo data for 8-bit integer * @param list - list of values in the halo * @param count - count of values in the halo * @param sendbuf - memory buffer to use to pack values for MPI * @param ID - 8-bit values on mesh [Nx, Ny, Nz] */ void PackID(int *list, int count, signed char *sendbuf, signed char *ID); /** * \brief Unpack halo data for 8-bit integer * @param list - list of values in the halo * @param count - count of values in the halo * @param recvbuf - memory buffer containing values recieved by MPI * @param ID - 8-bit values on mesh [Nx, Ny, Nz] */ void UnpackID(int *list, int count, signed char *recvbuf, signed char *ID); //...................................................................................... MPI_Request req1[18], req2[18]; //...................................................................................... std::vector sendList_x, sendList_y, sendList_z, sendList_X, sendList_Y, sendList_Z; std::vector sendList_xy, sendList_yz, sendList_xz, sendList_Xy, sendList_Yz, sendList_xZ; std::vector sendList_xY, sendList_yZ, sendList_Xz, sendList_XY, sendList_YZ, sendList_XZ; //...................................................................................... std::vector recvList_x, recvList_y, recvList_z, recvList_X, recvList_Y, recvList_Z; std::vector recvList_xy, recvList_yz, recvList_xz, recvList_Xy, recvList_Yz, recvList_xZ; std::vector recvList_xY, recvList_yZ, recvList_Xz, recvList_XY, recvList_YZ, recvList_XZ; //...................................................................................... const std::vector &getRecvList(const char *dir) const; const std::vector &getSendList(const char *dir) const; }; template class PatchData; enum class DataLocation { CPU, DEVICE }; /** * \class Patch * * @details * store patch data */ class Patch { public: //! Empty constructor Patch() = delete; //! Copy constructor Patch(const Patch &) = delete; //! Assignment operator Patch &operator=(const Patch &) = delete; //! Return the box for the patch inline const Box &getBox() const { return d_box; } //! Create patch data template std::shared_ptr> createPatchData(DataLocation location) const; private: Box d_box; int d_owner; Domain *d_domain; }; // Class to hold data on a patch template class PatchData { public: //! Get the raw data pointer TYPE *data() { return d_data; } //! Get the raw data pointer const TYPE *data() const { return d_data; } //! Get the patch const Patch &getPatch() const { return *d_patch; } //! Start communication void beginCommunication(); //! End communication void endCommunication(); //! Access ghost values TYPE operator()(int, int, int) const; //! Copy data from another PatchData void copy(const PatchData &rhs); private: DataLocation d_location; const Patch *d_patch; TYPE *d_data; TYPE *d_gcw; }; void WriteCheckpoint(const char *FILENAME, const double *cDen, const double *cfq, size_t Np); void ReadCheckpoint(char *FILENAME, double *cDen, double *cfq, size_t Np); void ReadBinaryFile(char *FILENAME, double *Data, size_t N); #endif