#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" #include "grid_local_connector.hpp" #include "grid_elements.hpp" #include "grid_scatterer_connector.hpp" #include "grid_gatherer_connector.hpp" namespace xios { /// ////////////////////// Declarations ////////////////////// /// 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; private: // define a structure to store elements (CDomain, CAxis, CScalar) using a void* and a type to cast the pointer enum EElementType { TYPE_SCALAR, TYPE_AXIS, TYPE_DOMAIN } ; struct SElement {void* ptr ; EElementType type ; CScalar* scalar ; CAxis* axis ; CDomain* domain ; } ; vector elements_ ; bool elementsComputed_ = false ; /** retrieve the vector of elements as a structure containing a void* and the type of pointer */ vector& getElements(void) { if (!elementsComputed_) computeElements() ; return elements_ ; } void computeElements(void) ; /** List order of axis and domain in a grid, if there is a domain, it will take value 2, axis 1, scalar 0 */ std::vector order_; public: typedef CGridAttributes RelAttributes; typedef CGridGroup RelGroup; enum EEventId { EVENT_ID_INDEX, EVENT_ID_ADD_DOMAIN, EVENT_ID_ADD_AXIS, EVENT_ID_ADD_SCALAR, EVENT_ID_SEND_MASK, }; /// 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 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) ; /** * Get the local data grid size, ie the size of the compressed grid (inside the workflow) * \return The size od the compressed grid */ StdSize getLocalDataSize(void) ; /// Entrees-sorties de champs template void inputField(const CArray& field, CArray& stored) ; template void maskField(const CArray& field, CArray& stored) ; template void outputField(const CArray& stored, CArray& field) ; template void uncompressField(const CArray& data, CArray& outData) ; 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 solveDomainAxisRef(bool areAttributesChecked); void checkElementsAttributes(void) ; void solveDomainRef(bool checkAtt); void solveAxisRef(bool checkAtt); void solveScalarRef(bool checkAtt); void solveElementsRefInheritance(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()); public: void sendGridToFileServer(CContextClient* client) ; private: std::set sendGridToFileServer_done_ ; public: void sendGridToCouplerOut(CContextClient* client, const string& fieldId) ; private: std::set sendGridToCouplerOut_done_ ; public: void makeAliasForCoupling(const string& fieldId) ; public: void sendAddDomain(const std::string& id,CContextClient* contextClient); void sendAddAxis(const std::string& id,CContextClient* contextClient); void sendAddScalar(const std::string& id,CContextClient* contextClient); void sendAllDomains(CContextClient* contextClient); void sendAllAxis(CContextClient* contextClient); void sendAllScalars(CContextClient* contextClient); 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, CContextServer* server); public: void sendIndex(CContextClient* client, const string& gridId=""); private: set sendIndex_done_ ; public: void sendIndexScalarGrid(CContextClient* client, const string& gridId=""); private: set sendIndexScalarGrid_done_ ; public: void setContextClient(CContextClient* contextClient); void computeDomConServer(); std::map getDomConServerSide(); std::map getAttributesBufferSize(CContextClient* client, bool bufferForWriting = false); std::map getDataBufferSize(CContextClient* client, const std::string& id = "", bool bufferForWriting = false); 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() ; int getNumberWrittenIndexes() const; int getTotalNumberWrittenIndexes() const; int getOffsetWrittenIndexes() const; CGridTransformation* getTransformations(); void transformGrid(CGrid* transformGridSrc); void prepareTransformGrid(CGrid* transformGridSrc); bool prepareTransformGrid_done_ = false ; void makeTransformGrid(void); bool makeTransformGrid_done_ = false ; std::vector getAuxInputTransformGrid(void) ; 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) ; bool isCompleted(void) ; void setCompleted(void) ; void unsetCompleted(void) ; bool hasMask(void) const; void checkMask(void); void createMask(void); void modifyMask(const CArray& indexToModify, bool valueToModify = false); void modifyMaskSize(const std::vector& newDimensionSize, bool newValue = false); /** get mask pointer stored in mask_1d, or mask_2d, or..., or mask_7d */ CArray mask_ ; CArray& getMask(void) ; void computeGridGlobalDimension(const std::vector& domains, const std::vector& axis, const std::vector& scalars, const CArray& axisDomainOrder); void computeGridIndexToFileServer(CContextClient* client) ; private: /** Client-like distribution calculated based on the knowledge of the entire grid */ CDistributionClient* clientDistribution_; public: void computeClientDistribution(void) ; private: bool computeClientDistribution_done_ = false ; public: CDistributionClient* getClientDistribution(void); private: /** Server-like distribution calculated upon receiving indexes */ CDistributionServer* serverDistribution_; void computeServerDistribution(void) ; bool computeServerDistribution_done_=false ; public: CDistributionServer* getServerDistribution(void) { if (!computeServerDistribution_done_) computeServerDistribution() ; return serverDistribution_ ;} 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) ; void restoreField_arr(const CArray& stored, double* const data) ; void uncompressField_arr(const double* const data, CArray& outData) ; void maskField_arr(const double* const data, CArray& stored) ; 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 computeConnectedClients(CContextClient* client); set computeConnectedClients_done_ ; void computeConnectedClientsScalarGrid(CContextClient* client); set computeConnectedClientsScalarGrid_done_ ; public: /** Array containing the local index of the grid * storeIndex_client[local_workflow_grid_index] -> local_model_grid_index. * Used to store field from model into the worklow, or to return field into models. * The size of the array is the number of local index of the workflow grid */ CArray storeIndex_client_; void computeStoreIndex_client(void) ; bool computeStoreIndex_client_done_ = false ; CArray& getStoreIndex_client(void) { if (!computeStoreIndex_client_done_) computeStoreIndex_client() ; return storeIndex_client_ ;} /** Array containing the grid mask masked defined by the mask_nd grid attribute. * The corresponding masked field value provided by the model will be replaced by a NaN value * in the workflow. */ CArray storeMask_client_; void computeStoreMask_client(void) ; bool computeStoreMask_client_done_ = false ; CArray& getStoreMask_client(void) { if (!computeStoreMask_client_done_) computeStoreMask_client() ; return storeMask_client_ ;} /** Map containing the indexes on client side that will be sent to each connected server. * storeIndex_toSrv[&contextClient] -> map concerning the contextClient for which the data will be sent (client side) * storeIndex_toSrv[&contextClient][rank] -> array of indexes that will be sent to each "rank" of the connected servers * storeIndex_toSrv[&contextClient][rank](index_of_buffer_sent_to_server) -> local index of the field of the workflow * grid that will be sent to server */ std::map > > storeIndex_toSrv_; /** Map containing the indexes on client side that will be received from each connected server. * This map is used to agreggate field data received from server (for reading) into a single array, which will be an entry * point of the worklow on client side. * storeIndex_toSrv[rank] -> array of indexes that will be received from each "rank" of the connected servers * storeIndex_toSrv[rank](index_of_buffer_received_from_server) -> local index of the field in the "workflow grid" * that has been received from server */ std::map > storeIndex_fromSrv_; // Support, for now, reading with level-1 server /** Maps storing the number of participating clients for data sent a specific server for a given contextClient, identified * by the servers communicator size. In future must be direcly identified by context. * nbSender_[context_server_size] -> map the number of client sender by connected rank of servers * nbSender_[context_server_size] [rank_server] -> the number of client participating to a send message for a server of rank "rank_server" * Usefull to indicate in a message the number of participant needed by the transfer protocol */ std::map > nbSenders_; private: /** Maps storing the number of participating servers for data sent a specific client for a given contextClient. * Symetric of nbSenders_, but for server side which want to send data to client. * nbReadSender_[context_client_size] -> map the number of server sender by connected rank of clients * nbReadSender_[context_client_size] [rank_client] -> the number of server participating to a send message for a client of rank "rank_client" * Usefull to indicate in a message the number of participant needed by the transfer protocol */ std::map > nbReadSenders_; public: std::map& getNbReadSenders(CContextClient* client) { if (nbReadSenders_.count(client)==0) computeNbReadSenders(client) ; return nbReadSenders_[client] ;} private: void computeNbReadSenders(CContextClient* client) ; // Manh Ha's comment: " 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 " private: /** Map storing received data on server side. This map is the equivalent to the storeIndex_client, but for data received from client * instead that from model. This map is used to concatenate data received from several clients into a single array on server side * which match the local workflow grid. * outLocalIndexStoreOnClient_[client_rank] -> Array of index from client of rank "client_rank" * outLocalIndexStoreOnClient_[client_rank](index of buffer from client) -> local index of the workflow grid * The map is created in CGrid::computeClientIndex and filled upon receiving data in CField::recvUpdateData(). * Symetrically it is also used to send data from a server to several client for reading case. */ map> outLocalIndexStoreOnClient_; public: void computeOutLocalIndexStoreOnClient(void) ; private: bool computeOutLocalIndexStoreOnClient_done_ = false ; public: map>& getOutLocalIndexStoreOnClient(void) { if (!computeOutLocalIndexStoreOnClient_done_) computeOutLocalIndexStoreOnClient(); return outLocalIndexStoreOnClient_ ; } public: /** Indexes calculated based on server-like distribution. * They are used for writing/reading data and only calculated for server level that does the writing/reading. * Along with localIndexToWriteOnClient, these indexes are used to correctly place incoming data. * size of the array : numberWrittenIndexes_ : number of index written in a compressed way * localIndexToWriteOnServer_(compressed_written_index) : -> local uncompressed index that will be written in the file */ CArray localIndexToWriteOnServer_; /** Indexes calculated based on client-like distribution. * They are used for writing/reading data and only calculated for server level that does the writing/reading. * Along with localIndexToWriteOnServer, these indexes are used to correctly place incoming data. * size of the array : numberWrittenIndexes_ * localIndexToWriteOnClient_(compressed_written_index) -> local index of the workflow grid*/ CArray localIndexToWriteOnClient_; public: bool isDataDistributed(void) ; private: /** Clients that have to send a grid. There can be multiple clients in case of secondary server, otherwise only one client. */ std::list clients; std::set clientsSet; private: /** Map storing received indexes on server side sent by clients. Key = sender rank, value = global index array. Later, the global indexes received will be mapped onto local index computed with the local distribution. outGlobalIndexFromClient_[rank] -> array of global index send by client of rank "rank" outGlobalIndexFromClient_[rank](n) -> global index of datav n sent by client */ map > outGlobalIndexFromClient_; public: map >& getOutGlobalIndexFromClient() { return outGlobalIndexFromClient_ ;} private: bool isChecked; bool isDomainAxisChecked; bool isIndexSent; CDomainGroup* vDomainGroup_; CAxisGroup* vAxisGroup_; CScalarGroup* vScalarGroup_; std::vector axisList_, domList_, scalarList_; bool isAxisListSet, isDomListSet, isScalarListSet; CClientServerMapping* clientServerMap_; int numberWrittenIndexes_, totalNumberWrittenIndexes_, offsetWrittenIndexes_; /** Map storing local ranks of connected receivers. Key = size of receiver's intracomm. * It is calculated in computeConnectedClients(). */ std::map > connectedServerRank_; /** Map storing the size of data to be send. Key = size of receiver's intracomm * It is calculated in computeConnectedClients(). */ std::map > connectedDataSize_; /** Ranks of connected receivers in case of reading. It is calculated in recvIndex(). */ std::vector connectedServerRankRead_; /** Size of data to be send in case of reading. It is calculated in recvIndex(). */ std::map connectedDataSizeRead_; //! 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_; void computeAxisPositionInGrid(void) ; bool computeAxisPositionInGrid_done_ = false ; std::vector& getAxisPositionInGrid(void) { if (!computeAxisPositionInGrid_done_) computeAxisPositionInGrid() ; return axisPositionInGrid_ ;} CGridTransformation* transformations_; bool hasDomainAxisBaseRef_; std::map > gridSrc_; bool hasTransform_; /** Map storing global indexes of server-like (band-wise) distribution for sending to receivers (client side). * Key = size of receiver's intracomm (i.e. number of servers) * ~ map >> globalIndexOnServer_ * globalIndexOnServer_[servers_size] -> map for a distribution of size "servers_size" (number of servers) * globalIndexOnServer_[servers_size][server_rank] -> array of global index managed by server of rank "server_rank" * globalIndexOnServer_[servers_size][server_rank][n] -> global index of data to be send to the server by client based on sub element of the grid. * -> grid masking is not included. */ // std::map globalIndexOnServer_; std::map globalIndexOnServer_; ////////////////////////////////////////////////////////////////////////////////////// // this part is related to distribution, element definition, views and connectors // ////////////////////////////////////////////////////////////////////////////////////// private: static void recvMask(CEventServer& event) ; void receiveMask(CEventServer& event) ; private: CGridLocalElements* gridLocalElements_= nullptr ; void computeGridLocalElements(void) ; public: CGridLocalElements* getGridLocalElements(void) { if (gridLocalElements_==nullptr) computeGridLocalElements() ; return gridLocalElements_ ;} private: CGridLocalConnector* modelToWorkflowConnector_ ; public: void computeModelToWorkflowConnector(void) ; CGridLocalConnector* getModelToWorkflowConnector(void) { if (modelToWorkflowConnector_==nullptr) computeModelToWorkflowConnector() ; return modelToWorkflowConnector_;} private: CGridLocalConnector* workflowToModelConnector_ ; public: void computeWorkflowToModelConnector(void) ; CGridLocalConnector* getWorkflowToModelConnector(void) { if (workflowToModelConnector_==nullptr) computeWorkflowToModelConnector() ; return workflowToModelConnector_;} public: //? void distributeGridToFileServer(CContextClient* client); private: CGridLocalConnector* workflowToFullConnector_ = nullptr; public: void computeWorkflowToFullConnector(void) ; CGridLocalConnector* getWorkflowToFullConnector(void) { if (workflowToFullConnector_==nullptr) computeWorkflowToFullConnector() ; return workflowToFullConnector_;} private: CGridLocalConnector* fullToWorkflowConnector_ = nullptr; public: void computeFullToWorkflowConnector(void) ; CGridLocalConnector* getFullToWorkflowConnector(void) { if (fullToWorkflowConnector_==nullptr) computeFullToWorkflowConnector() ; return fullToWorkflowConnector_;} private: CGridGathererConnector* clientFromClientConnector_ = nullptr ; public: CGridGathererConnector* getClientFromClientConnector(void) { if (clientFromClientConnector_==nullptr) computeClientFromClientConnector() ; return clientFromClientConnector_;} void computeClientFromClientConnector(void) ; private: map clientToClientConnector_ ; public: CGridScattererConnector* getClientToClientConnector(CContextClient* client) { return clientToClientConnector_[client] ;} // make some test to see if connector exits for the given client private: map clientFromServerConnector_ ; public: CGridGathererConnector* getClientFromServerConnector(CContextClient* client) { return clientFromServerConnector_[client];} void computeClientFromServerConnector(void) ; private: CGridScattererConnector* serverToClientConnector_=nullptr ; public: CGridScattererConnector* getServerToClientConnector(void) { if (serverToClientConnector_==nullptr) computeServerToClientConnector() ; return serverToClientConnector_;} void computeServerToClientConnector(void) ; private: map clientToServerConnector_ ; public: CGridScattererConnector* getClientToServerConnector(CContextClient* client) { return clientToServerConnector_[client] ;} // make some test to see if connector exits for the given client private: CGridGathererConnector* serverFromClientConnector_ = nullptr ; public: CGridGathererConnector* getServerFromClientConnector(void) { if (serverFromClientConnector_==nullptr) computeServerFromClientConnector() ; return serverFromClientConnector_;} void computeServerFromClientConnector(void) ; }; // class CGrid ///-------------------------------------------------------------- template void CGrid::inputField(const CArray& field, CArray& stored) TRY { //#ifdef __XIOS_DEBUG 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->getId()) //#endif this->storeField_arr(field.dataFirst(), stored); } CATCH /* obsolete template void CGrid::maskField(const CArray& field, CArray& stored) { //#ifdef __XIOS_DEBUG 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->getId()) //#endif this->maskField_arr(field.dataFirst(), stored); } */ template void CGrid::maskField(const CArray& field, CArray& stored) { auto connector = getModelToWorkflowConnector() ; if (connector->getSrcSize() != 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->getId()) const double nanValue = std::numeric_limits::quiet_NaN(); connector->transfer(field, stored, nanValue) ; } template void CGrid::outputField(const CArray& stored, CArray& field) TRY { //#ifdef __XIOS_DEBUG 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->getId()) //#endif this->restoreField_arr(stored, field.dataFirst()); } CATCH /*! 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) TRY { uncompressField_arr(data.dataFirst(), outData); } CATCH template void CGrid::checkGridMask(CArray& gridMask, const std::vector* >& domainMasks, const std::vector* >& axisMasks, const CArray& axisDomainOrder, bool createMask) TRY { int idx = 0; int numElement = axisDomainOrder.numElements(); int dim = domainMasks.size() * 2 + axisMasks.size(); std::vector domainP = this->getDomains(); std::vector axisP = this->getAxis(); 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(); eachDimSize[indexMap[i]] = axisP[idxAxis]->n; ++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->getId()) } } 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)) { int idxTmp = idxLoop[indexMap[i]] + idxLoop[indexMap[i]+1] * eachDimSize[indexMap[i]]; if (idxTmp < (*domainMasks[idxDomain]).numElements()) maskValue = maskValue && (*domainMasks[idxDomain])(idxTmp); else maskValue = false; ++idxDomain; } else if (1 == axisDomainOrder(i)) { int idxTmp = idxLoop[indexMap[i]]; if (idxTmp < (*axisMasks[idxAxis]).numElements()) maskValue = maskValue && (*axisMasks[idxAxis])(idxTmp); else maskValue = false; ++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; } } CATCH_DUMP_ATTR template void CGrid::modifyGridMaskSize(CArray& gridMask, const std::vector& eachDimSize, bool newValue) TRY { 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->getId()) } CArrayBoolTraits >::resizeArray(gridMask,eachDimSize); gridMask = newValue; } CATCH_DUMP_ATTR /*! 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) TRY { int num = indexToModify.numElements(); for (int idx = 0; idx < num; ++idx) { *(gridMask.dataFirst()+indexToModify(idx)) = valueToModify; } } CATCH_DUMP_ATTR ///-------------------------------------------------------------- // Declare/Define CGridGroup and CGridDefinition DECLARE_GROUP(CGrid); ///-------------------------------------------------------------- } // namespace xios #endif // __XIOS_CGrid__