#ifndef __XIOS_CGrid__ #define __XIOS_CGrid__ /// XIOS headers /// #include "xios_spl.hpp" #include "group_factory.hpp" #include "declare_group.hpp" #include "domain.hpp" #include "axis.hpp" #include "scalar.hpp" #include "array_new.hpp" #include "attribute_array.hpp" #include "distribution_server.hpp" #include "client_server_mapping.hpp" #include "utils.hpp" #include "transformation_enum.hpp" namespace xios { /// ////////////////////// Déclarations ////////////////////// /// class CGridGroup; class CGridAttributes; class CDomainGroup; class CAxisGroup; class CScalarGroup; class CGrid; class CDistributionClient; class CDistributionServer; class CServerDistributionDescription; class CClientServerMapping; class CGridTransformation; ///-------------------------------------------------------------- // Declare/Define CGridAttribute BEGIN_DECLARE_ATTRIBUTE_MAP(CGrid) # include "grid_attribute.conf" END_DECLARE_ATTRIBUTE_MAP(CGrid) ///-------------------------------------------------------------- class CGrid : public CObjectTemplate , public CGridAttributes { /// typedef /// typedef CObjectTemplate SuperClass; typedef CGridAttributes SuperClassAttribute; public: typedef CGridAttributes RelAttributes; typedef CGridGroup RelGroup; enum EEventId { EVENT_ID_INDEX, EVENT_ID_ADD_DOMAIN, EVENT_ID_ADD_AXIS, EVENT_ID_ADD_SCALAR }; /// Constructeurs /// CGrid(void); explicit CGrid(const StdString& id); CGrid(const CGrid& grid); // Not implemented yet. CGrid(const CGrid* const grid); // Not implemented yet. /// Traitements /// // void solveReference(void); void checkEligibilityForCompressedOutput(); void solveDomainAxisRef(bool areAttributesChecked); void checkMaskIndex(bool doCalculateIndex); // virtual void toBinary (StdOStream& os) const; // virtual void fromBinary(StdIStream& is); void addRelFileCompressed(const StdString& filename); /// Tests /// bool isCompressible(void) const; bool isWrittenCompressed(const StdString& filename) const; public: /// Accesseurs /// StdSize getDimension(void); StdSize getDataSize(void) const; /// Entrées-sorties de champs template void inputField(const CArray& field, CArray& stored) const; template void outputField(const CArray& stored, CArray& field) const; template void uncompressField(const CArray& data, CArray& outData) const; virtual void parse(xml::CXMLNode& node); /// Destructeur /// virtual ~CGrid(void); public: /// Accesseurs statiques /// static StdString GetName(void); static StdString GetDefName(void); static ENodeType GetType(void); /// Instanciateurs Statiques /// static CGrid* createGrid(CDomain* domain); static CGrid* createGrid(CDomain* domain, CAxis* axis); static CGrid* createGrid(const std::vector& domains, const std::vector& axis, const CArray& axisDomainOrder = CArray()); static CGrid* createGrid(StdString id, const std::vector& domains, const std::vector& axis, const std::vector& scalars, const CArray& axisDomainOrder = CArray()); static CGrid* createGrid(const std::vector& domains, const std::vector& axis, const std::vector& scalars, const CArray& axisDomainOrder); static StdString generateId(const std::vector& domains, const std::vector& axis, const std::vector& scalars, const CArray& axisDomainOrder = CArray()); static StdString generateId(const CGrid* gridSrc, const CGrid* gridDest); static CGrid* cloneGrid(const StdString& idNewGrid, CGrid* gridSrc); public: void computeIndexServer(void); void computeIndex(void); void computeIndexScalarGrid(); void computeWrittenIndex(); void solveDomainRef(bool checkAtt); void solveAxisRef(bool checkAtt); void solveScalarRef(bool checkAtt); void solveDomainAxisRefInheritance(bool apply = true); void solveTransformations(); void solveDomainAxisBaseRef(); CDomain* addDomain(const std::string& id=StdString()); CAxis* addAxis(const std::string& id=StdString()); CScalar* addScalar(const std::string& id=StdString()); void sendAddDomain(const std::string& id=""); void sendAddAxis(const std::string& id=""); void sendAddScalar(const std::string& id=""); void sendAllDomains(); void sendAllAxis(); void sendAllScalars(); static void recvAddDomain(CEventServer& event); void recvAddDomain(CBufferIn& buffer); static void recvAddAxis(CEventServer& event); void recvAddAxis(CBufferIn& buffer); static void recvAddScalar(CEventServer& event); void recvAddScalar(CBufferIn& buffer); static bool dispatchEvent(CEventServer& event); static void recvIndex(CEventServer& event); void recvIndex(vector ranks, vector buffers); void sendIndex(void); void sendIndexScalarGrid(); void computeDomConServer(); std::map getDomConServerSide(); std::map getAttributesBufferSize(CContextClient* client); std::map getDataBufferSize(CContextClient* client, const std::string& id = ""); std::vector getDomainList(); std::vector getAxisList(); std::vector getScalarList(); std::vector getDomains(); std::vector getAxis(); std::vector getScalars(); CDomain* getDomain(int domainIndex); CAxis* getAxis(int axisIndex); CScalar* getScalar(int scalarIndex); std::vector getAxisOrder(); std::vector getGlobalDimension(); bool isScalarGrid() const; bool doGridHaveDataToWrite(); bool doGridHaveDataDistributed(CContextClient* client = 0); size_t getWrittenDataSize() const; int getNumberWrittenIndexes() const; int getTotalNumberWrittenIndexes() const; int getOffsetWrittenIndexes() const; CDistributionServer* getDistributionServer(); CDistributionClient* getDistributionClient(); CGridTransformation* getTransformations(); void transformGrid(CGrid* transformGridSrc); void completeGrid(CGrid* transformGridSrc = 0); void doAutoDistribution(CGrid* transformGridSrc); bool isTransformed(); void setTransformed(); bool isGenerated(); void setGenerated(); void addTransGridSource(CGrid* gridSrc); std::map >& getTransGridSource(); bool hasTransform(); size_t getGlobalWrittenSize(void) ; public: CArray storeIndex_client; /** Map containing indexes that will be sent in sendIndex(). */ std::map > > storeIndex_toSrv; /** Map storing the number of senders. Key = size of receiver's intracomm */ std::map > nbSenders; std::map > nbReadSenders; map > storeIndex_fromSrv; // Support, for now, reading with level-1 server map > outIndexFromClient, compressedOutIndexFromClient, outGlobalIndexFromClient; // A client receives global index from other clients (via recvIndex) // then does mapping these index into local index of STORE_CLIENTINDEX // In this way, store_clientIndex can be used as an input of a source filter // Maybe we need a flag to determine whether a client wants to write. TODO map > outLocalIndexStoreOnClient; /** Indexes calculated based on server distribution (serverDistribution_). They are used for writing data into a file. */ CArray localIndexToWriteOnServer; /** Indexes calculated based on client distribution (clientDistribution_). They are not used at all. They should be the same as localIndexToWriteOnServer and potentially can be used as an additional check.*/ CArray localIndexToWriteOnClient; CArray indexFromClients; void checkMask(void); void createMask(void); void modifyMask(const CArray& indexToModify, bool valueToModify = false); void modifyMaskSize(const std::vector& newDimensionSize, bool newValue = false); void computeGridGlobalDimension(const std::vector& domains, const std::vector& axis, const std::vector& scalars, const CArray& axisDomainOrder); private: template void checkGridMask(CArray& gridMask, const std::vector* >& domainMasks, const std::vector* >& axisMasks, const CArray& axisDomainOrder, bool createMask = false); template void modifyGridMask(CArray& gridMask, const CArray& indexToModify, bool valueToModify); template void modifyGridMaskSize(CArray& gridMask, const std::vector& eachDimSize, bool newValue); void storeField_arr(const double* const data, CArray& stored) const; void restoreField_arr(const CArray& stored, double* const data) const; void uncompressField_arr(const double* const data, CArray& outData) const; void setVirtualDomainGroup(CDomainGroup* newVDomainGroup); void setVirtualAxisGroup(CAxisGroup* newVAxisGroup); void setVirtualScalarGroup(CScalarGroup* newVScalarGroup); void setDomainList(const std::vector domains = std::vector()); void setAxisList(const std::vector axis = std::vector()); void setScalarList(const std::vector scalars = std::vector()); CDomainGroup* getVirtualDomainGroup() const; CAxisGroup* getVirtualAxisGroup() const; CScalarGroup* getVirtualScalarGroup() const; void checkAttributesAfterTransformation(); void setTransformationAlgorithms(); void computeIndexByElement(const std::vector > >& indexServerOnElement, const CContextClient* client, CClientServerMapping::GlobalIndexMap& globalIndexOnServer); int computeGridGlobalDimension(std::vector& globalDim, const std::vector domains, const std::vector axis, const std::vector scalars, const CArray& axisDomainOrder); int getDistributedDimension(); void computeClientIndex(); void computeConnectedClients(); void computeClientIndexScalarGrid(); void computeConnectedClientsScalarGrid(); private: bool isChecked; bool isDomainAxisChecked; bool isIndexSent; CDomainGroup* vDomainGroup_; CAxisGroup* vAxisGroup_; CScalarGroup* vScalarGroup_; std::vector axisList_, domList_, scalarList_; bool isAxisListSet, isDomListSet, isScalarListSet; /** Distribution calculated in computeClientIndex() based on the knowledge of the entire grid */ CDistributionClient* clientDistribution_; /** Distribution calculated upon receiving indexes */ CDistributionServer* serverDistribution_; CClientServerMapping* clientServerMap_; size_t writtenDataSize_; int numberWrittenIndexes_, totalNumberWrittenIndexes_, offsetWrittenIndexes_; /** Map storing local ranks of connected receivers. Key = size of receiver's intracomm */ std::map > connectedServerRank_; /** Map storing the size of data to be send. Key = size of receiver's intracomm */ std::map > connectedDataSize_; bool isDataDistributed_; //! True if and only if the data defined on the grid can be outputted in a compressed way bool isCompressible_; std::set relFilesCompressed; bool isTransformed_, isGenerated_; bool computedWrittenIndex_; std::vector axisPositionInGrid_; CGridTransformation* transformations_; bool hasDomainAxisBaseRef_; std::map > gridSrc_; bool hasTransform_; /** Map storing global indexes of server-like (band-wise) distribution for sending to receivers. * Key = size of receiver's intracomm. */ // std::map globalIndexOnServer_; std::map globalIndexOnServer_; /** List order of axis and domain in a grid, if there is a domain, it will take value 1 (true), axis 0 (false) */ std::vector order_; }; // class CGrid ///-------------------------------------------------------------- template void CGrid::inputField(const CArray& field, CArray& stored) const { if (this->getDataSize() != field.numElements()) ERROR("void CGrid::inputField(const CArray& field, CArray& stored) const", << "[ Awaiting data of size = " << this->getDataSize() << ", " << "Received data size = " << field.numElements() << " ] " << "The data array does not have the right size! " << "Grid = " << this->GetName()) this->storeField_arr(field.dataFirst(), stored); } template void CGrid::outputField(const CArray& stored, CArray& field) const { if (this->getDataSize() != field.numElements()) ERROR("void CGrid::outputField(const CArray& stored, CArray& field) const", << "[ Size of the data = " << this->getDataSize() << ", " << "Output data size = " << field.numElements() << " ] " << "The ouput array does not have the right size! " << "Grid = " << this->GetName()) this->restoreField_arr(stored, field.dataFirst()); } /*! This function removes the effect of mask on received data on the server. This function only serve for the checking purpose. TODO: Something must be done to seperate mask and data_index from each other in received data \data data received data with masking effect on the server \outData data without masking effect */ template void CGrid::uncompressField(const CArray& data, CArray& outData) const { uncompressField_arr(data.dataFirst(), outData); } template void CGrid::checkGridMask(CArray& gridMask, const std::vector* >& domainMasks, const std::vector* >& axisMasks, const CArray& axisDomainOrder, bool createMask) { int idx = 0; int numElement = axisDomainOrder.numElements(); int dim = domainMasks.size() * 2 + axisMasks.size(); std::vector domainP = this->getDomains(); std::vector idxLoop(dim,0), indexMap(numElement), eachDimSize(dim); std::vector currentIndex(dim); int idxDomain = 0, idxAxis = 0; for (int i = 0; i < numElement; ++i) { indexMap[i] = idx; if (2 == axisDomainOrder(i)) { eachDimSize[indexMap[i]] = domainP[idxDomain]->ni; eachDimSize[indexMap[i]+1] = domainP[idxDomain]->nj; idx += 2; ++idxDomain; } else if (1 == axisDomainOrder(i)) { eachDimSize[indexMap[i]] = axisMasks[idxAxis]->numElements(); ++idx; ++idxAxis; } else {}; } if (!gridMask.isEmpty() && !createMask) { for (int i = 0; i < dim; ++i) { if (gridMask.extent(i) != eachDimSize[i]) ERROR("CGrid::checkMask(void)", << "The mask has one dimension whose size is different from the one of the local grid." << std::endl << "Local size of dimension " << i << " is " << eachDimSize[i] << "." << std::endl << "Mask size for dimension " << i << " is " << gridMask.extent(i) << "." << std::endl << "Grid = " << this->GetName()) } } else { CArrayBoolTraits >::resizeArray(gridMask,eachDimSize); gridMask = true; } int ssize = gridMask.numElements(); idx = 0; while (idx < ssize) { for (int i = 0; i < dim-1; ++i) { if (idxLoop[i] == eachDimSize[i]) { idxLoop[i] = 0; ++idxLoop[i+1]; } } // Find out outer index idxDomain = idxAxis = 0; bool maskValue = true; for (int i = 0; i < numElement; ++i) { if (2 == axisDomainOrder(i)) { maskValue = maskValue && (*domainMasks[idxDomain])(idxLoop[indexMap[i]] + idxLoop[indexMap[i]+1] * eachDimSize[indexMap[i]]); ++idxDomain; } else if (1 == axisDomainOrder(i)) { maskValue = maskValue && (*axisMasks[idxAxis])(idxLoop[indexMap[i]]); ++idxAxis; } } int maskIndex = idxLoop[0]; int mulDim = 1; for (int k = 1; k < dim; ++k) { mulDim *= eachDimSize[k-1]; maskIndex += idxLoop[k]*mulDim; } *(gridMask.dataFirst()+maskIndex) &= maskValue; ++idxLoop[0]; ++idx; } } template void CGrid::modifyGridMaskSize(CArray& gridMask, const std::vector& eachDimSize, bool newValue) { if (N != eachDimSize.size()) { // ERROR("CGrid::modifyGridMaskSize(CArray& gridMask, // const std::vector& eachDimSize, // bool newValue)", // << "Dimension size of the mask is different from input dimension size." << std::endl // << "Mask dimension is " << N << "." << std::endl // << "Input dimension is " << eachDimSize.size() << "." << std::endl // << "Grid = " << this->GetName()) } CArrayBoolTraits >::resizeArray(gridMask,eachDimSize); gridMask = newValue; } /*! Modify the current mask of grid, the local index to be modified will take value false \param [in/out] gridMask current mask of grid \param [in] indexToModify local index to modify */ template void CGrid::modifyGridMask(CArray& gridMask, const CArray& indexToModify, bool valueToModify) { int num = indexToModify.numElements(); for (int idx = 0; idx < num; ++idx) { *(gridMask.dataFirst()+indexToModify(idx)) = valueToModify; } } ///-------------------------------------------------------------- // Declare/Define CGridGroup and CGridDefinition DECLARE_GROUP(CGrid); ///-------------------------------------------------------------- } // namespace xios #endif // __XIOS_CGrid__