Index: /XIOS/trunk/src/filter/spatial_transform_filter.cpp
===================================================================
--- /XIOS/trunk/src/filter/spatial_transform_filter.cpp	(revision 644)
+++ /XIOS/trunk/src/filter/spatial_transform_filter.cpp	(revision 644)
@@ -0,0 +1,128 @@
+#include "spatial_transform_filter.hpp"
+#include "grid_transformation.hpp"
+#include "context.hpp"
+#include "context_client.hpp"
+
+namespace xios
+{
+  CSpatialTransformFilter::CSpatialTransformFilter(CGarbageCollector& gc, CSpatialTransformFilterEngine* engine)
+    : CFilter(gc, 1, engine)
+  { /* Nothing to do */ }
+
+  std::pair<boost::shared_ptr<CSpatialTransformFilter>, boost::shared_ptr<CSpatialTransformFilter> >
+  CSpatialTransformFilter::buildFilterGraph(CGarbageCollector& gc, CGrid* srcGrid, CGrid* destGrid)
+  {
+    if (!srcGrid || !destGrid)
+      ERROR("std::pair<boost::shared_ptr<CSpatialTransformFilter>, boost::shared_ptr<CSpatialTransformFilter> >"
+            "buildFilterGraph(CGarbageCollector& gc, CGrid* srcGrid, CGrid* destGrid)",
+            "Impossible to build the filter graph if either the source or the destination grid are null.");
+
+    // TODO: Implement the real path finding algorithm after a solution has been found
+    //       to support initializing grid transformations during parsing.
+    CSpatialTransformFilterEngine* engine = CSpatialTransformFilterEngine::get(destGrid->getTransformations());
+    boost::shared_ptr<CSpatialTransformFilter> filter(new CSpatialTransformFilter(gc, engine));
+
+    return std::make_pair(filter, filter);
+  }
+
+  CSpatialTransformFilterEngine::CSpatialTransformFilterEngine(CGridTransformation* gridTransformation)
+    : gridTransformation(gridTransformation)
+  {
+    if (!gridTransformation)
+      ERROR("CSpatialTransformFilterEngine::CSpatialTransformFilterEngine(CGridTransformation* gridTransformation)",
+            "Impossible to construct a spatial transform filter engine without a valid grid transformation.");
+  }
+
+  std::map<CGridTransformation*, boost::shared_ptr<CSpatialTransformFilterEngine> > CSpatialTransformFilterEngine::engines;
+
+  CSpatialTransformFilterEngine* CSpatialTransformFilterEngine::get(CGridTransformation* gridTransformation)
+  {
+    if (!gridTransformation)
+      ERROR("CSpatialTransformFilterEngine& CSpatialTransformFilterEngine::get(CGridTransformation* gridTransformation)",
+            "Impossible to get the requested engine, the grid transformation is invalid.");
+
+    std::map<CGridTransformation*, boost::shared_ptr<CSpatialTransformFilterEngine> >::iterator it = engines.find(gridTransformation);
+    if (it == engines.end())
+    {
+      boost::shared_ptr<CSpatialTransformFilterEngine> engine(new CSpatialTransformFilterEngine(gridTransformation));
+      it = engines.insert(std::make_pair(gridTransformation, engine)).first;
+    }
+
+    return it->second.get();
+  }
+
+  CDataPacketPtr CSpatialTransformFilterEngine::apply(std::vector<CDataPacketPtr> data)
+  {
+    CDataPacketPtr packet(new CDataPacket);
+    packet->date = data[0]->date;
+    packet->timestamp = data[0]->timestamp;
+    packet->status = data[0]->status;
+
+    if (packet->status == CDataPacket::NO_ERROR)
+    {
+      packet->data.resize(gridTransformation->getGridDestination()->storeIndex_client.numElements());
+      apply(data[0]->data, packet->data);
+    }
+
+    return packet;
+  }
+
+  void CSpatialTransformFilterEngine::apply(const CArray<double, 1>& dataSrc, CArray<double,1>& dataDest)
+  {
+    CContextClient* client = CContext::getCurrent()->client;
+
+    const std::map<int, CArray<int,1>* >& localIndexToSend = gridTransformation->getLocalIndexToSendFromGridSource();
+    const std::map<int, std::vector<std::vector<std::pair<int,double> > > >& localIndexToReceive = gridTransformation->getLocalIndexToReceiveOnGridDest();
+
+    dataDest = 0.0;
+
+    // Sending data from field sources to do transformations
+    std::map<int, CArray<int,1>* >::const_iterator itbSend = localIndexToSend.begin(), itSend,
+                                                   iteSend = localIndexToSend.end();
+    int sendBuffSize = 0;
+    for (itSend = itbSend; itSend != iteSend; ++itSend) sendBuffSize = (sendBuffSize < (itSend->second)->numElements())
+                                                                     ? (itSend->second)->numElements(): sendBuffSize;
+    double* sendBuff;
+    if (0 != sendBuffSize) sendBuff = new double[sendBuffSize];
+    for (itSend = itbSend; itSend != iteSend; ++itSend)
+    {
+      int destRank = itSend->first;
+      CArray<int,1>* localIndex_p = itSend->second;
+      int countSize = localIndex_p->numElements();
+      for (int idx = 0; idx < countSize; ++idx)
+      {
+        sendBuff[idx] = dataSrc((*localIndex_p)(idx));
+      }
+      MPI_Send(sendBuff, countSize, MPI_DOUBLE, destRank, 12, client->intraComm);
+    }
+
+    // Receiving data on destination fields
+    std::map<int,std::vector<std::vector<std::pair<int,double> > > >::const_iterator itbRecv = localIndexToReceive.begin(), itRecv,
+                                                            iteRecv = localIndexToReceive.end();
+    int recvBuffSize = 0;
+    for (itRecv = itbRecv; itRecv != iteRecv; ++itRecv) recvBuffSize = (recvBuffSize < (itRecv->second).size())
+                                                                     ? (itRecv->second).size() : recvBuffSize;
+    double* recvBuff;
+    if (0 != recvBuffSize) recvBuff = new double[recvBuffSize];
+    for (itRecv = itbRecv; itRecv != iteRecv; ++itRecv)
+    {
+      MPI_Status status;
+      int srcRank = itRecv->first;
+      int countSize = (itRecv->second).size();
+      MPI_Recv(recvBuff, recvBuffSize, MPI_DOUBLE, srcRank, 12, client->intraComm, &status);
+      for (int idx = 0; idx < countSize; ++idx)
+      {
+        const std::vector<std::pair<int,double> >& localIndex_p = (itRecv->second)[idx];
+        int numIndex = localIndex_p.size();
+        for (int i = 0; i < numIndex; ++i)
+        {
+//        if ((localIndex_p)[i].first >= dataDest.numElements() )
+          dataDest((localIndex_p)[i].first) += recvBuff[idx] * ((localIndex_p)[i].second);
+        }
+      }
+    }
+
+    if (0 != sendBuffSize) delete [] sendBuff;
+    if (0 != recvBuffSize) delete [] recvBuff;
+  }
+} // namespace xios
Index: /XIOS/trunk/src/filter/spatial_transform_filter.hpp
===================================================================
--- /XIOS/trunk/src/filter/spatial_transform_filter.hpp	(revision 644)
+++ /XIOS/trunk/src/filter/spatial_transform_filter.hpp	(revision 644)
@@ -0,0 +1,85 @@
+#ifndef __XIOS_CSpatialTransformFilter__
+#define __XIOS_CSpatialTransformFilter__
+
+#include "filter.hpp"
+
+namespace xios
+{
+  class CGrid;
+  class CGridTransformation;
+  class CSpatialTransformFilterEngine;
+
+  /*!
+   * A generic filter with one input slot wrapping any type of spatial transformations.
+   */
+  class CSpatialTransformFilter : public CFilter
+  {
+    public:
+      /*!
+       * Constructs a filter wrapping the specified spatial transformation.
+       *
+       * \param gc the associated garbage collector
+       * \param engine the engine defining the spatial transformation
+       */
+      CSpatialTransformFilter(CGarbageCollector& gc, CSpatialTransformFilterEngine* engine);
+
+      /*!
+       * Builds the filter graph needed to transform the specified source grid into the specified destination grid.
+       *
+       * \param gc the associated garbage collector
+       * \param srcGrid the source grid
+       * \param destGrid the destination grid
+       * \return the first and the last filters of the filter graph
+       */
+      static std::pair<boost::shared_ptr<CSpatialTransformFilter>, boost::shared_ptr<CSpatialTransformFilter> >
+      buildFilterGraph(CGarbageCollector& gc, CGrid* srcGrid, CGrid* destGrid);
+  }; // class CSpatialTransformFilter
+
+  /*!
+   * A generic filter engine wrapping a grid transformation.
+   */
+  class CSpatialTransformFilterEngine : public IFilterEngine
+  {
+    public:
+      /*!
+       * Returns the engine wrapping the specified grid transformation.
+       * If the engine already exists it is reused, otherwise it is created.
+       *
+       * \param gridTransformation the grid transformation the engine will use
+       * \return the engine wrapping the specified grid transformation
+       */
+      static CSpatialTransformFilterEngine* get(CGridTransformation* gridTransformation);
+
+      /*!
+       * Applies the grid transformation to the input data and returns the result.
+       *
+       * \param data a vector of packets corresponding to each slot (one in this case)
+       * \return the result of the grid transformation
+       */
+      CDataPacketPtr virtual apply(std::vector<CDataPacketPtr> data);
+
+    protected:
+      /*!
+       * Constructs a filter engine wrapping the specified grid transformation.
+       *
+       * \param gridTransformation the grid transformation the engine will use
+       */
+      CSpatialTransformFilterEngine(CGridTransformation* gridTransformation);
+
+      /*!
+       * Applies the grid transformation to the input data and returns the result.
+       * This helper function handles all the communications.
+       *
+       * \param dataSrc the source data
+       * \param dataDest the resulting transformed data
+       */
+      void apply(const CArray<double, 1>& dataSrc, CArray<double,1>& dataDest);
+
+      CGridTransformation* gridTransformation; //!< The grid transformation used by the engine
+
+      //! The allocated engines
+      static std::map<CGridTransformation*, boost::shared_ptr<CSpatialTransformFilterEngine> > engines;
+  }; // class CSpatialTransformFilterEngine
+} // namespace xios
+
+#endif //__XIOS_CSpatialTransformFilter__
Index: /XIOS/trunk/src/node/field.cpp
===================================================================
--- /XIOS/trunk/src/node/field.cpp	(revision 643)
+++ /XIOS/trunk/src/node/field.cpp	(revision 644)
@@ -22,4 +22,5 @@
 #include "lex_parser.hpp"
 #include "temporal_filter.hpp"
+#include "spatial_transform_filter.hpp"
 
 namespace xios{
@@ -629,8 +630,10 @@
      {
         areAllReferenceSolved = true;
+
         if (context->hasClient)
         {
           solveRefInheritance(true);
           solveBaseReference();
+          if (hasDirectFieldReference()) getDirectFieldReference()->solveAllReferenceEnabledField(false);
         }
 
@@ -786,9 +789,16 @@
        else if (!field_ref.isEmpty())
        {
-         boost::shared_ptr<CPassThroughFilter> passThroughFilter(new CPassThroughFilter(gc));
-         instantDataFilter = passThroughFilter;
          CField* fieldRef = CField::get(field_ref);
          fieldRef->buildFilterGraph(gc, false);
-         fieldRef->getInstantDataFilter()->connectOutput(passThroughFilter, 0);
+
+         std::pair<boost::shared_ptr<CFilter>, boost::shared_ptr<CFilter> > filters;
+         // Check if a spatial transformation is needed
+         if (!grid_ref.isEmpty() && !fieldRef->grid_ref.isEmpty() && grid_ref.getValue() != fieldRef->grid_ref.getValue())
+           filters = CSpatialTransformFilter::buildFilterGraph(gc, fieldRef->grid, grid);
+         else
+           filters.first = filters.second = boost::shared_ptr<CFilter>(new CPassThroughFilter(gc));
+
+         fieldRef->getInstantDataFilter()->connectOutput(filters.first, 0);
+         instantDataFilter = filters.second;
        }
        // Check if the data is to be read from a file
@@ -975,5 +985,9 @@
    void CField::solveTransformedGrid()
    {
-     if (!grid_ref.isEmpty() && (!field_ref.isEmpty()))
+     if (!grid_ref.isEmpty() && hasDirectFieldReference() && !getDirectFieldReference()->grid_ref.isEmpty()
+         && grid_ref.getValue() != getDirectFieldReference()->grid_ref.getValue() && !grid->isTransformed())
+       grid->transformGrid(getDirectFieldReference()->grid);
+
+     /*if (!grid_ref.isEmpty() && (!field_ref.isEmpty()))
      {
        CField* fieldRef  = this;
@@ -1008,5 +1022,5 @@
          filterSources_.push_back(fieldRef);
        }
-     }
+     }*/
    }
 
