Index: XIOS/dev/dev_oa/src/node/grid.cpp
===================================================================
--- XIOS/dev/dev_oa/src/node/grid.cpp	(revision 1951)
+++ XIOS/dev/dev_oa/src/node/grid.cpp	(revision 1966)
@@ -33,5 +33,5 @@
       , writtenDataSize_(0), numberWrittenIndexes_(0), totalNumberWrittenIndexes_(0), offsetWrittenIndexes_(0)
       , connectedDataSize_(), connectedServerRank_(), connectedServerRankRead_(), connectedDataSizeRead_()
-	  , isDataDistributed_(true), isCompressible_(false)
+      , isDataDistributed_(true), isCompressible_(false)
       , transformations_(0), isTransformed_(false)
       , axisPositionInGrid_(), hasDomainAxisBaseRef_(false)
@@ -39,4 +39,7 @@
       , computedWrittenIndex_(false)
       , clients()
+      , nTiles_(0)
+      , isTiled_(false)
+      , storeTileIndex()
    {
      setVirtualDomainGroup(CDomainGroup::create(getId() + "_virtual_domain_group"));
@@ -54,5 +57,5 @@
       , writtenDataSize_(0), numberWrittenIndexes_(0), totalNumberWrittenIndexes_(0), offsetWrittenIndexes_(0)
       , connectedDataSize_(), connectedServerRank_(), connectedServerRankRead_(), connectedDataSizeRead_()
-	  , isDataDistributed_(true), isCompressible_(false)
+      , isDataDistributed_(true), isCompressible_(false)
       , transformations_(0), isTransformed_(false)
       , axisPositionInGrid_(), hasDomainAxisBaseRef_(false)
@@ -60,4 +63,7 @@
       , computedWrittenIndex_(false)
       , clients()
+      , nTiles_(0)
+      , isTiled_(false)
+      , storeTileIndex()
    {
      setVirtualDomainGroup(CDomainGroup::create(getId() + "_virtual_domain_group"));
@@ -102,4 +108,74 @@
    }
    CATCH
+
+   //---------------------------------------------------------------
+   /*!
+    * Returns size of tile data
+    */
+
+   StdSize CGrid::getTileDataSize(int tileId)
+   TRY
+   {
+     StdSize tileGridSize =1 ;
+     int numElement = axis_domain_order.numElements();
+
+     std::vector<CAxis*> axisListP = this->getAxis();
+     std::vector<CDomain*> domainListP = this->getDomains();
+
+     int axisIndex = 0, domIndex = 0;
+     for (int idx = 0; idx < numElement; ++idx)
+     {
+       int eleDim = axis_domain_order(idx);
+       if (2 == eleDim)
+       {
+         tileGridSize *= domainListP[domIndex]->tile_data_ni(tileId);
+         tileGridSize *= domainListP[domIndex]->tile_data_nj(tileId);
+         ++domIndex;
+          }
+       else if (1 == eleDim)
+       {
+         tileGridSize *= axisListP[axisIndex]->n.getValue();
+         ++axisIndex;
+       }
+     } // loop over grid elements
+     return tileGridSize;
+   }
+   CATCH
+
+   //---------------------------------------------------------------
+   /*!
+    * Returns tile size
+    */
+
+   StdSize CGrid::getTileSize(int tileId)
+   TRY
+   {
+     StdSize tileGridSize =1 ;
+     int numElement = axis_domain_order.numElements();
+
+     std::vector<CAxis*> axisListP = this->getAxis();
+     std::vector<CDomain*> domainListP = this->getDomains();
+
+     int axisIndex = 0, domIndex = 0;
+     for (int idx = 0; idx < numElement; ++idx)
+     {
+       int eleDim = axis_domain_order(idx);
+       if (2 == eleDim)
+       {
+         tileGridSize *= domainListP[domIndex]->tile_ni(tileId);
+         tileGridSize *= domainListP[domIndex]->tile_nj(tileId);
+         ++domIndex;
+          }
+       else if (1 == eleDim)// So it's an axis
+       {
+         tileGridSize *= axisListP[axisIndex]->n.getValue();
+         ++axisIndex;
+       }
+     } // loop over grid elements
+     return tileGridSize;
+   }
+   CATCH
+
+   //---------------------------------------------------------------
 
    /*!
@@ -561,4 +637,5 @@
           if (sendAtt) domListP[i]->sendCheckedAttributes();
           else domListP[i]->checkAttributesOnClient();
+          if (domListP[i]->isTiled()) this->isTiled_ = true;
         }
       }
@@ -902,4 +979,5 @@
      {
        computeClientIndex();
+       if (this->isTiled_) computeTileIndex();
        if (context->hasClient)
        {
@@ -1097,4 +1175,111 @@
    }
    CATCH_DUMP_ATTR
+
+   //---------------------------------------------------------------
+
+   /*
+   */
+   void CGrid::computeTileIndex()
+   TRY
+   {
+     int numElement = axis_domain_order.numElements();
+     storeTileIndex.resize(nTiles_);
+
+     std::vector<CAxis*> axisListP = this->getAxis();
+     std::vector<CDomain*> domainListP = this->getDomains();
+
+     // First, allocate storeTileIndex[0..ntiles]
+     for (int iTile = 0; iTile < nTiles_; ++iTile)
+     {
+       int tileGridSize = 1;
+       int axisIndex = 0, domIndex = 0;
+       for (int idx = 0; idx < numElement; ++idx)
+       {
+         int eleDim = axis_domain_order(idx);
+         if (2 == eleDim)
+         {
+           tileGridSize *= domainListP[domIndex]->getTileDataISize(iTile);
+           tileGridSize *= domainListP[domIndex]->getTileDataJSize(iTile);
+           ++domIndex;
+         }
+         else if (1 == eleDim)// So it's an axis
+         {
+           tileGridSize *= axisListP[axisIndex]->n.getValue();
+           ++axisIndex;
+         }
+       } // loop over grid elements
+       storeTileIndex[iTile].resize(tileGridSize);
+       storeTileIndex[iTile] = -1;
+     } // loop over tiles
+
+     // Now fill in storeTileIndex
+     // Currently assuming two possible situations : (1) domain x axis or (2) domain
+     std::vector<int> tileIndexCount (nTiles_,0);
+     int axisSize = 1;
+     if (axisListP.size() != 0) axisSize = axisListP[0]->n.getValue();
+     int ni = domainListP[0]->ni.getValue();
+     int nj = domainListP[0]->nj.getValue();
+
+     for (int idxAxis = 0; idxAxis < axisSize; ++idxAxis)
+     {
+       for (int jIdxDom = 0; jIdxDom < nj; ++jIdxDom)
+       {
+         for (int iIdxDom = 0; iIdxDom < ni; ++iIdxDom)
+         {
+           int tile = domainListP[0]->getTileId(iIdxDom, jIdxDom);
+           int tileOffset =  domainListP[0]->tile_data_ibegin(tile);  // only sign of offset matters
+
+           // case 1: data size corresponds to tile size
+           if (tileOffset == 0)
+           {
+             storeTileIndex[tile](tileIndexCount[tile]) = idxAxis*nj*ni + jIdxDom * ni + iIdxDom;
+             ++tileIndexCount[tile];
+           }
+           // case 2: masked data
+           else if (tileOffset > 0)
+           {
+             int iBegin = domainListP[0]->tile_ibegin(tile) + domainListP[0]->tile_data_ibegin(tile); // tile data relative to domain
+             int jBegin = domainListP[0]->tile_jbegin(tile) + domainListP[0]->tile_data_jbegin(tile); // tile data relative to domain
+             int iEnd = iBegin + domainListP[0]->tile_data_ni(tile);
+             int jEnd = jBegin + domainListP[0]->tile_data_nj(tile);
+             if ((jIdxDom >= jBegin) && (jIdxDom < jEnd) && (iIdxDom >= iBegin) && (iIdxDom < iEnd))
+             {
+               storeTileIndex[tile](tileIndexCount[tile]) = idxAxis*nj*ni + jIdxDom * ni + iIdxDom;
+             }
+             ++tileIndexCount[tile];
+           }
+           // case 3: ghost zones
+           else
+           {
+             int tileDataNi = domainListP[0]->tile_data_ni(tile);
+             int tileDataNj = domainListP[0]->tile_data_nj(tile);
+             int tileDomSize = tileDataNi * tileDataNj;
+             int tileNi = domainListP[0]->tile_ni(tile);
+             int iBegin = domainListP[0]->tile_data_ibegin(tile);
+             int jBegin = domainListP[0]->tile_data_jbegin(tile);
+
+             // add the ghost zone at the beginning of a domain tile
+             if (tileIndexCount[tile] % tileDomSize == 0)
+               tileIndexCount[tile] += (abs(jBegin)*tileDataNi + abs(iBegin));
+
+             storeTileIndex[tile](tileIndexCount[tile]) = idxAxis*nj*ni + jIdxDom*ni + iIdxDom;
+             
+             // add two ghost zones at the right end of a tile
+             if ( (iIdxDom+1) % tileNi == 0 )
+               tileIndexCount[tile] += (2*abs(iBegin));
+
+             // add ghost zone at the end of a domain tile
+             if ((tileIndexCount[tile] + abs(jBegin)*tileDataNi-abs(iBegin) + 1) % tileDomSize == 0)
+               tileIndexCount[tile] += (abs(jBegin)*tileDataNi -abs(iBegin));
+
+             ++tileIndexCount[tile];
+           }
+         } // loop over domain first dimension
+       } // loop over domain second dimension
+     } // loop over axis dimension
+
+   }
+   CATCH_DUMP_ATTR
+
 //----------------------------------------------------------------
 
@@ -1359,4 +1544,5 @@
 
    void CGrid::maskField_arr(const double* const data, CArray<double, 1>& stored) const
+   TRY
    {
       const StdSize size = storeIndex_client.numElements();
@@ -1369,4 +1555,41 @@
         for(StdSize i = 0; i < size; i++) stored(i) = data[storeIndex_client(i)];
    }
+   CATCH
+
+   void CGrid::copyTile_arr(const double* const tileData, CArray<double, 1>& stored, int tileId)
+   TRY
+   {
+     StdSize tileSize = this->getTileSize(tileId);
+     const StdSize tileDataSize = this->getTileDataSize(tileId);
+
+     // case 1: data correspond in size to a tile
+     if (tileSize == tileDataSize)
+     {
+       for(StdSize i = 0; i < tileDataSize; i++)
+         stored(storeTileIndex[tileId](i)) = tileData[i];
+     }
+     // case 2: masked data
+     else if (tileSize > tileDataSize)
+     {
+       int tileDataCount = 0;
+       for(StdSize i = 0; i < tileSize; i++)
+         if (storeTileIndex[tileId](i) >= 0)
+         {
+           stored(storeTileIndex[tileId](i)) = tileData[tileDataCount];
+           ++tileDataCount;
+         }
+     }
+     // case 3: ghost zones
+     else
+     {
+       for(StdSize i = 0; i < tileDataSize; i++)
+         if (storeTileIndex[tileId](i) >= 0)
+         {
+           stored(storeTileIndex[tileId](i)) = tileData[i];
+         }
+
+     }
+   }
+   CATCH
 
    void CGrid::uncompressField_arr(const double* const data, CArray<double, 1>& out) const
@@ -2253,4 +2476,5 @@
         pDom->solveRefInheritance(apply);
         pDom->solveInheritanceTransformation();
+        if (!pDom->ntiles.isEmpty() && pDom->ntiles.getValue()>0) nTiles_=pDom->ntiles.getValue();
       }
     }
@@ -2279,4 +2503,11 @@
       }
     }
+  }
+  CATCH_DUMP_ATTR
+
+  int CGrid::getNTiles()
+  TRY
+  {
+    return nTiles_;
   }
   CATCH_DUMP_ATTR
