/************************************************************************************* Grid physics library, www.github.com/paboyle/Grid Source file: Hadrons/Environment.hpp Copyright (C) 2015-2019 Author: Antonin Portelli 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 2 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. See the full license in the file "LICENSE" in the top level distribution directory *************************************************************************************/ /* END LEGAL */ #ifndef Hadrons_Environment_hpp_ #define Hadrons_Environment_hpp_ #include BEGIN_HADRONS_NAMESPACE /****************************************************************************** * Global environment * ******************************************************************************/ class Object { public: Object(void) = default; virtual ~Object(void) = default; }; template class Holder: public Object { public: Holder(void) = default; Holder(T *pt); virtual ~Holder(void) = default; T & get(void) const; T * getPt(void) const; void reset(T *pt); private: std::unique_ptr objPt_{nullptr}; }; #define DEFINE_ENV_ALIAS \ inline Environment & env(void) const\ {\ return Environment::getInstance();\ } #define DEFINE_ENV_LAMBDA \ auto env = [](void)->Environment &{return Environment::getInstance();} class Environment { SINGLETON(Environment); public: typedef SITE_SIZE_TYPE Size; typedef std::unique_ptr GridPt; typedef std::unique_ptr GridRbPt; typedef std::unique_ptr RngPt; enum class Storage {object, cache, temporary}; private: struct ObjInfo { Size size{0}; Storage storage{Storage::object}; unsigned int Ls{0}; const std::type_info *type{nullptr}, *derivedType{nullptr}; std::string name; int module{-1}; std::unique_ptr data{nullptr}; }; typedef std::pair FineGridKey; typedef std::pair> CoarseGridKey; public: // grids template void createGrid(const unsigned int Ls); template void createCoarseGrid(const std::vector &blockSize, const unsigned int Ls); template GridCartesian * getGrid(void); template GridRedBlackCartesian * getRbGrid(void); template GridCartesian * getCoarseGrid(const std::vector &blockSize); template GridCartesian * getGrid(const unsigned int Ls); template GridRedBlackCartesian * getRbGrid(const unsigned int Ls); template GridCartesian * getCoarseGrid(const std::vector &blockSize, const unsigned int Ls); std::vector getDim(void) const; int getDim(const unsigned int mu) const; unsigned int getNd(void) const; double getVolume(void) const; // random number generator GridParallelRNG * get4dRng(void); // general memory management void addObject(const std::string name, const int moduleAddress = -1); template void createDerivedObject(const std::string name, const Environment::Storage storage, const unsigned int Ls, Ts && ... args); template void createObject(const std::string name, const Environment::Storage storage, const unsigned int Ls, Ts && ... args); void setObjectModule(const unsigned int objAddress, const int modAddress); template T * getDerivedObject(const unsigned int address) const; template T * getDerivedObject(const std::string name) const; template T * getObject(const unsigned int address) const; template T * getObject(const std::string name) const; unsigned int getMaxAddress(void) const; unsigned int getObjectAddress(const std::string name) const; std::string getObjectName(const unsigned int address) const; std::string getObjectType(const unsigned int address) const; std::string getObjectType(const std::string name) const; Size getObjectSize(const unsigned int address) const; Size getObjectSize(const std::string name) const; Storage getObjectStorage(const unsigned int address) const; Storage getObjectStorage(const std::string name) const; int getObjectModule(const unsigned int address) const; int getObjectModule(const std::string name) const; unsigned int getObjectLs(const unsigned int address) const; unsigned int getObjectLs(const std::string name) const; bool hasObject(const unsigned int address) const; bool hasObject(const std::string name) const; bool hasCreatedObject(const unsigned int address) const; bool hasCreatedObject(const std::string name) const; bool isObject5d(const unsigned int address) const; bool isObject5d(const std::string name) const; template bool isObjectOfType(const unsigned int address) const; template bool isObjectOfType(const std::string name) const; Environment::Size getTotalSize(void) const; void freeObject(const unsigned int address); void freeObject(const std::string name); void freeAll(void); void protectObjects(const bool protect); bool objectsProtected(void) const; // print environment content void printContent(void) const; private: // general double vol_; bool protect_{true}; // grids std::vector dim_; std::map grid4d_; std::map grid5d_; std::map gridRb4d_; std::map gridRb5d_; std::map gridCoarse4d_; std::map gridCoarse5d_; unsigned int nd_; // random number generator RngPt rng4d_; // object store std::vector object_; std::map objectAddress_; }; /****************************************************************************** * Holder template implementation * ******************************************************************************/ // constructor ///////////////////////////////////////////////////////////////// template Holder::Holder(T *pt) : objPt_(pt) {} // access ////////////////////////////////////////////////////////////////////// template T & Holder::get(void) const { return *objPt_.get(); } template T * Holder::getPt(void) const { return objPt_.get(); } template void Holder::reset(T *pt) { objPt_.reset(pt); } /****************************************************************************** * Environment template implementation * ******************************************************************************/ // grids /////////////////////////////////////////////////////////////////////// #define HADRONS_DUMP_GRID(...)\ LOG(Debug) << "New grid " << (__VA_ARGS__) << std::endl;\ LOG(Debug) << " - cb : " << (__VA_ARGS__)->_isCheckerBoarded << std::endl;\ LOG(Debug) << " - fdim: " << (__VA_ARGS__)->_fdimensions << std::endl;\ LOG(Debug) << " - gdim: " << (__VA_ARGS__)->_gdimensions << std::endl;\ LOG(Debug) << " - ldim: " << (__VA_ARGS__)->_ldimensions << std::endl;\ LOG(Debug) << " - rdim: " << (__VA_ARGS__)->_rdimensions << std::endl; template void Environment::createGrid(const unsigned int Ls) { size_t hash = typeHash(); if (grid4d_.find({hash, 1}) == grid4d_.end()) { grid4d_[{hash, 1}].reset( SpaceTimeGrid::makeFourDimGrid(getDim(), GridDefaultSimd(getNd(), VType::Nsimd()), GridDefaultMpi())); HADRONS_DUMP_GRID(grid4d_[{hash, 1}].get()); gridRb4d_[{hash, 1}].reset( SpaceTimeGrid::makeFourDimRedBlackGrid(grid4d_[{hash, 1}].get())); HADRONS_DUMP_GRID(gridRb4d_[{hash, 1}].get()); } if (grid5d_.find({hash, Ls}) == grid5d_.end()) { auto g = grid4d_[{hash, 1}].get(); grid5d_[{hash, Ls}].reset(SpaceTimeGrid::makeFiveDimGrid(Ls, g)); HADRONS_DUMP_GRID(grid5d_[{hash, Ls}].get()); gridRb5d_[{hash, Ls}].reset(SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls, g)); HADRONS_DUMP_GRID(gridRb5d_[{hash, Ls}].get()); } } template void Environment::createCoarseGrid(const std::vector &blockSize, const unsigned int Ls) { int nd = getNd(); std::vector fineDim = getDim(), coarseDim(nd); unsigned int cLs; auto key4d = blockSize, key5d = blockSize; size_t hash = typeHash(); createGrid(Ls); for (int d = 0; d < coarseDim.size(); d++) { coarseDim[d] = fineDim[d]/blockSize[d]; if (coarseDim[d]*blockSize[d] != fineDim[d]) { HADRONS_ERROR(Size, "Fine dimension " + std::to_string(d) + " (" + std::to_string(fineDim[d]) + ") not divisible by coarse dimension (" + std::to_string(coarseDim[d]) + ")"); } } if (blockSize.size() > nd) { cLs = Ls/blockSize[nd]; if (cLs*blockSize[nd] != Ls) { HADRONS_ERROR(Size, "Fine Ls (" + std::to_string(Ls) + ") not divisible by coarse Ls (" + std::to_string(cLs) + ")"); } } else { cLs = Ls; } key4d.resize(nd); key5d.push_back(Ls); CoarseGridKey hkey4d = {hash, key4d}, hkey5d = {hash, key5d}; if (gridCoarse4d_.find(hkey4d) == gridCoarse4d_.end()) { gridCoarse4d_[hkey4d].reset( SpaceTimeGrid::makeFourDimGrid(coarseDim, GridDefaultSimd(nd, VType::Nsimd()), GridDefaultMpi())); HADRONS_DUMP_GRID(gridCoarse4d_[hkey4d].get()); } if (gridCoarse5d_.find(hkey5d) == gridCoarse5d_.end()) { gridCoarse5d_[hkey5d].reset( SpaceTimeGrid::makeFiveDimGrid(cLs, gridCoarse4d_[hkey4d].get())); HADRONS_DUMP_GRID(gridCoarse5d_[hkey5d].get()); } } #undef HADRONS_DUMP_GRID template GridCartesian * Environment::getGrid(void) { FineGridKey key = {typeHash(), 1}; auto it = grid4d_.find(key); if (it != grid4d_.end()) { return it->second.get(); } else { createGrid(1); return grid4d_.at(key).get(); } } template GridRedBlackCartesian * Environment::getRbGrid(void) { FineGridKey key = {typeHash(), 1}; auto it = gridRb4d_.find(key); if (it != gridRb4d_.end()) { return it->second.get(); } else { createGrid(1); return gridRb4d_.at(key).get(); } } template GridCartesian * Environment::getCoarseGrid(const std::vector &blockSize) { std::vector s = blockSize; s.resize(getNd()); CoarseGridKey key = {typeHash(), s}; auto it = gridCoarse4d_.find(key); if (it != gridCoarse4d_.end()) { return it->second.get(); } else { createCoarseGrid(blockSize, 1); return gridCoarse4d_.at(key).get(); } } template GridCartesian * Environment::getGrid(const unsigned int Ls) { FineGridKey key = {typeHash(), Ls}; auto it = grid5d_.find(key); if (it != grid5d_.end()) { return it->second.get(); } else { createGrid(Ls); return grid5d_.at(key).get(); } } template GridRedBlackCartesian * Environment::getRbGrid(const unsigned int Ls) { FineGridKey key = {typeHash(), Ls}; auto it = gridRb5d_.find(key); if (it != gridRb5d_.end()) { return it->second.get(); } else { createGrid(Ls); return gridRb5d_.at(key).get(); } } template GridCartesian * Environment::getCoarseGrid(const std::vector &blockSize, const unsigned int Ls) { std::vector s = blockSize; s.push_back(Ls); CoarseGridKey key = {typeHash(), s}; auto it = gridCoarse5d_.find(key); if (it != gridCoarse5d_.end()) { return it->second.get(); } else { createCoarseGrid(blockSize, Ls); return gridCoarse5d_.at(key).get(); } } // general memory management /////////////////////////////////////////////////// template void Environment::createDerivedObject(const std::string name, const Environment::Storage storage, const unsigned int Ls, Ts && ... args) { if (!hasObject(name)) { addObject(name); } unsigned int address = getObjectAddress(name); if (!object_[address].data or !objectsProtected()) { MemoryStats memStats; if (!MemoryProfiler::stats) { MemoryProfiler::stats = &memStats; } size_t initMem = MemoryProfiler::stats->currentlyAllocated; object_[address].storage = storage; object_[address].Ls = Ls; object_[address].data.reset(new Holder(new T(std::forward(args)...))); object_[address].size = MemoryProfiler::stats->maxAllocated - initMem; object_[address].type = typeIdPt(); object_[address].derivedType = typeIdPt(); if (MemoryProfiler::stats == &memStats) { MemoryProfiler::stats = nullptr; } } // object already exists, no error if it is a cache, error otherwise else if ((object_[address].storage != Storage::cache) or (object_[address].storage != storage) or (object_[address].name != name) or (typeHash(object_[address].type) != typeHash()) or (typeHash(object_[address].derivedType) != typeHash())) { HADRONS_ERROR_REF(ObjectDefinition, "object '" + name + "' already allocated", address); } } template void Environment::createObject(const std::string name, const Environment::Storage storage, const unsigned int Ls, Ts && ... args) { createDerivedObject(name, storage, Ls, std::forward(args)...); } template T * Environment::getDerivedObject(const unsigned int address) const { if (hasObject(address)) { if (hasCreatedObject(address)) { if (auto h = dynamic_cast *>(object_[address].data.get())) { if (&typeid(T) == &typeid(B)) { return dynamic_cast(h->getPt()); } else { if (auto hder = dynamic_cast(h->getPt())) { return hder; } else { HADRONS_ERROR_REF(ObjectType, "object with address " + std::to_string(address) + " cannot be casted to '" + typeName(&typeid(T)) + "' (has type '" + typeName(&typeid(h->get())) + "')", address); } } } else { HADRONS_ERROR_REF(ObjectType, "object with address " + std::to_string(address) + " does not have type '" + typeName(&typeid(B)) + "' (has type '" + getObjectType(address) + "')", address); } } else { HADRONS_ERROR_REF(ObjectDefinition, "object with address " + std::to_string(address) + " is empty", address); } } else { HADRONS_ERROR_REF(ObjectDefinition, "no object with address " + std::to_string(address), address); } } template T * Environment::getDerivedObject(const std::string name) const { return getDerivedObject(getObjectAddress(name)); } template T * Environment::getObject(const unsigned int address) const { return getDerivedObject(address); } template T * Environment::getObject(const std::string name) const { return getObject(getObjectAddress(name)); } template bool Environment::isObjectOfType(const unsigned int address) const { if (hasObject(address)) { if (auto h = dynamic_cast *>(object_[address].data.get())) { return true; } else { return false; } } else { HADRONS_ERROR_REF(ObjectDefinition, "no object with address " + std::to_string(address), address); } } template bool Environment::isObjectOfType(const std::string name) const { return isObjectOfType(getObjectAddress(name)); } END_HADRONS_NAMESPACE #endif // Hadrons_Environment_hpp_