source: XIOS/dev/XIOS_DEV_CMIP6/src/node/field.cpp @ 1318

Last change on this file since 1318 was 1318, checked in by rlacroix, 7 years ago

Fix: Handle end-of-file correctly for files in read mode.

Previously desynchronizations between clients could occur, leading to invalid events being received by the server(s).

  • Property copyright set to
    Software name : XIOS (Xml I/O Server)
    http://forge.ipsl.jussieu.fr/ioserver
    Creation date : January 2009
    Licence : CeCCIL version2
    see license file in root directory : Licence_CeCILL_V2-en.txt
    or http://www.cecill.info/licences/Licence_CeCILL_V2-en.html
    Holder : CEA/LSCE (Laboratoire des Sciences du CLimat et de l'Environnement)
    CNRS/IPSL (Institut Pierre Simon Laplace)
    Project Manager : Yann Meurdesoif
    yann.meurdesoif@cea.fr
  • Property svn:executable set to *
File size: 53.7 KB
Line 
1#include "field.hpp"
2
3#include "attribute_template.hpp"
4#include "object_template.hpp"
5#include "group_template.hpp"
6
7#include "node_type.hpp"
8#include "calendar_util.hpp"
9#include "message.hpp"
10#include "xios_spl.hpp"
11#include "type.hpp"
12#include "timer.hpp"
13#include "context_client.hpp"
14#include "context_server.hpp"
15#include <set>
16#include "garbage_collector.hpp"
17#include "source_filter.hpp"
18#include "store_filter.hpp"
19#include "file_writer_filter.hpp"
20#include "pass_through_filter.hpp"
21#include "filter_expr_node.hpp"
22#include "lex_parser.hpp"
23#include "temporal_filter.hpp"
24#include "spatial_transform_filter.hpp"
25#include "file_server_writer_filter.hpp"
26
27namespace xios{
28
29   /// ////////////////////// Définitions ////////////////////// ///
30
31   CField::CField(void)
32      : CObjectTemplate<CField>(), CFieldAttributes()
33      , grid(), file()
34      , written(false)
35      , nstep(0), nstepMax(0)
36      , hasOutputFile(false)
37      , domAxisScalarIds_(vector<StdString>(3,""))
38      , areAllReferenceSolved(false), isReferenceSolved(false), isReferenceSolvedAndTransformed(false)
39      , useCompressedOutput(false)
40      , hasTimeInstant(false)
41      , hasTimeCentered(false)
42      , wasDataRequestedFromServer(false)
43      , wasDataAlreadyReceivedFromServer(false)
44      , isEOF(false), nstepMaxRead(false)
45   { setVirtualVariableGroup(CVariableGroup::create(getId() + "_virtual_variable_group")); }
46
47   CField::CField(const StdString& id)
48      : CObjectTemplate<CField>(id), CFieldAttributes()
49      , grid(), file()
50      , written(false)
51      , nstep(0), nstepMax(0)
52      , hasOutputFile(false)
53      , domAxisScalarIds_(vector<StdString>(3,""))
54      , areAllReferenceSolved(false), isReferenceSolved(false), isReferenceSolvedAndTransformed(false)
55      , useCompressedOutput(false)
56      , hasTimeInstant(false)
57      , hasTimeCentered(false)
58      , wasDataRequestedFromServer(false)
59      , wasDataAlreadyReceivedFromServer(false)
60      , isEOF(false), nstepMaxRead(false)
61   { setVirtualVariableGroup(CVariableGroup::create(getId() + "_virtual_variable_group")); }
62
63   CField::~CField(void)
64   {}
65
66  //----------------------------------------------------------------
67
68   void CField::setVirtualVariableGroup(CVariableGroup* newVVariableGroup)
69   {
70      this->vVariableGroup = newVVariableGroup;
71   }
72
73   CVariableGroup* CField::getVirtualVariableGroup(void) const
74   {
75      return this->vVariableGroup;
76   }
77
78   std::vector<CVariable*> CField::getAllVariables(void) const
79   {
80      return this->vVariableGroup->getAllChildren();
81   }
82
83   void CField::solveDescInheritance(bool apply, const CAttributeMap* const parent)
84   {
85      SuperClassAttribute::setAttributes(parent, apply);
86      this->getVirtualVariableGroup()->solveDescInheritance(apply, NULL);
87   }
88
89  //----------------------------------------------------------------
90
91  bool CField::dispatchEvent(CEventServer& event)
92  {
93    if (SuperClass::dispatchEvent(event)) return true;
94    else
95    {
96      switch(event.type)
97      {
98        case EVENT_ID_UPDATE_DATA :
99          recvUpdateData(event);
100          return true;
101          break;
102
103        case EVENT_ID_READ_DATA :
104          recvReadDataRequest(event);
105          return true;
106          break;
107
108        case EVENT_ID_READ_DATA_READY :
109          recvReadDataReady(event);
110          return true;
111          break;
112
113        case EVENT_ID_ADD_VARIABLE :
114          recvAddVariable(event);
115          return true;
116          break;
117
118        case EVENT_ID_ADD_VARIABLE_GROUP :
119          recvAddVariableGroup(event);
120          return true;
121          break;
122
123        default :
124          ERROR("bool CField::dispatchEvent(CEventServer& event)", << "Unknown Event");
125          return false;
126      }
127    }
128  }
129
130  void CField::sendUpdateData(const CArray<double,1>& data)
131  {
132    CTimer::get("Field : send data").resume();
133
134    CContext* context = CContext::getCurrent();
135    CContextClient* client = (!context->hasServer) ? context->client : this->file->getContextClient();
136    int receiverSize = client->serverSize;
137
138    CEventClient event(getType(), EVENT_ID_UPDATE_DATA);
139
140    map<int, CArray<int,1> >::iterator it;
141    list<CMessage> list_msg;
142    list<CArray<double,1> > list_data;
143
144    if (!grid->doGridHaveDataDistributed(client))
145    {
146       if (client->isServerLeader())
147       {
148          for (it = grid->storeIndex_toSrv[client].begin(); it != grid->storeIndex_toSrv[client].end(); it++)
149          {
150            int rank = it->first;
151            CArray<int,1>& index = it->second;
152
153            list_msg.push_back(CMessage());
154            list_data.push_back(CArray<double,1>(index.numElements()));
155
156            CArray<double,1>& data_tmp = list_data.back();
157            for (int n = 0; n < data_tmp.numElements(); n++) data_tmp(n) = data(index(n));
158
159            list_msg.back() << getId() << data_tmp;
160            event.push(rank, 1, list_msg.back());
161          }
162          client->sendEvent(event);
163        }
164      else client->sendEvent(event);
165    }
166    else
167    {
168      for (it = grid->storeIndex_toSrv[client].begin(); it != grid->storeIndex_toSrv[client].end(); it++)
169      {
170        int rank = it->first;
171        CArray<int,1>& index = it->second;
172
173        list_msg.push_back(CMessage());
174        list_data.push_back(CArray<double,1>(index.numElements()));
175
176        CArray<double,1>& data_tmp = list_data.back();
177        for (int n = 0; n < data_tmp.numElements(); n++) data_tmp(n) = data(index(n));
178
179        list_msg.back() << getId() << data_tmp;
180        event.push(rank, grid->nbSenders[receiverSize][rank], list_msg.back());
181      }
182      client->sendEvent(event);
183    }
184
185    CTimer::get("Field : send data").suspend();
186  }
187
188  void CField::recvUpdateData(CEventServer& event)
189  {
190    std::map<int,CBufferIn*> rankBuffers;
191
192    list<CEventServer::SSubEvent>::iterator it;
193    string fieldId;
194    CTimer::get("Field : recv data").resume();
195    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
196    {
197      int rank = it->rank;
198      CBufferIn* buffer = it->buffer;
199      *buffer >> fieldId;
200      rankBuffers[rank] = buffer;
201    }
202    get(fieldId)->recvUpdateData(rankBuffers);
203    CTimer::get("Field : recv data").suspend();
204  }
205
206  void  CField::recvUpdateData(std::map<int,CBufferIn*>& rankBuffers)
207  {
208    CContext* context = CContext::getCurrent();
209
210    size_t sizeData = 0;
211    if (0 == recvDataSrv.numElements())
212    {           
213      CArray<int,1>& storeClient = grid->storeIndex_client;
214
215      // Gather all data from different clients     
216      recvDataSrv.resize(storeClient.numElements());
217      recvFoperationSrv = boost::shared_ptr<func::CFunctor>(new func::CInstant(recvDataSrv));
218    }
219
220    CArray<double,1> recv_data_tmp(recvDataSrv.numElements());   
221    const CDate& currDate = context->getCalendar()->getCurrentDate();
222    const CDate opeDate   = last_operation_srv +freq_op + freq_operation_srv - freq_op;
223
224    if (opeDate <= currDate)
225    {
226      for (map<int, CArray<size_t, 1> >::iterator it = grid->outLocalIndexStoreOnClient.begin(); it != grid->outLocalIndexStoreOnClient.end(); ++it)
227      {
228        CArray<double,1> tmp;
229        CArray<size_t,1>& indexTmp = it->second;
230        *(rankBuffers[it->first]) >> tmp;
231        for (int idx = 0; idx < indexTmp.numElements(); ++idx)
232        {
233          recv_data_tmp(indexTmp(idx)) = tmp(idx);
234        }     
235      }
236    }
237
238    this->setData(recv_data_tmp);
239  }
240
241  void CField::writeUpdateData(const CArray<double,1>& data)
242  {
243    CContext* context = CContext::getCurrent();
244
245    const CDate& currDate = context->getCalendar()->getCurrentDate();
246    const CDate opeDate      = last_operation_srv +freq_op + freq_operation_srv - freq_op;
247    const CDate writeDate    = last_Write_srv     + freq_write_srv;
248
249    if (opeDate <= currDate)
250    {
251      (*recvFoperationSrv)(data);
252      last_operation_srv = currDate;
253    }
254
255    if (writeDate < (currDate + freq_operation_srv))
256    {
257      recvFoperationSrv->final();
258      last_Write_srv = writeDate;
259      grid->computeWrittenIndex();
260      writeField();
261      lastlast_Write_srv = last_Write_srv;
262    }
263  }
264
265  void CField::writeField(void)
266  {
267    if (!getRelFile()->isEmptyZone())
268    {
269      if (grid->doGridHaveDataToWrite() || getRelFile()->type == CFile::type_attr::one_file)
270      {
271        getRelFile()->checkWriteFile();
272        this->incrementNStep();
273        getRelFile()->getDataOutput()->writeFieldData(CField::get(this));
274      }
275    }
276  }
277
278  /*
279    Send a request for reading data.
280    Client sends a request to server for demanding server to read data and send back to it.
281    For now, this function is called only by client
282    In the future, it can be called by level-1 servers
283    \param [in] tsDataRequested timestamp when the call is made
284  */
285  bool CField::sendReadDataRequest(const CDate& tsDataRequested)
286  {
287    CContext* context = CContext::getCurrent();
288    // CContextClient* client = context->client;
289
290    // This code is for future: If we want to read file with level-2 servers
291    CContextClient* client = (!context->hasServer) ? context->client : this->file->getContextClient();
292
293    lastDataRequestedFromServer = tsDataRequested;
294
295    // No need to send the request if we are sure that we are already at EOF
296    if (!isEOF || context->getCalendar()->getCurrentDate() <= dateEOF)
297    {
298      CEventClient event(getType(), EVENT_ID_READ_DATA);
299      if (client->isServerLeader())
300      {
301        CMessage msg;
302        msg << getId();
303        const std::list<int>& ranks = client->getRanksServerLeader();
304        for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
305          event.push(*itRank, 1, msg);
306        client->sendEvent(event);
307      }
308      else client->sendEvent(event);
309    }
310    else
311      serverSourceFilter->signalEndOfStream(tsDataRequested);
312
313    wasDataRequestedFromServer = true;
314
315    return !isEOF;
316  }
317
318  /*!
319  Send request new data read from file if need be, that is the current data is out-of-date.
320  \return true if and only if some data was requested
321  */
322  bool CField::sendReadDataRequestIfNeeded(void)
323  {
324    const CDate& currentDate = CContext::getCurrent()->getCalendar()->getCurrentDate();
325
326    bool dataRequested = false;
327
328    while (currentDate >= lastDataRequestedFromServer)
329    {
330      info(20) << "currentDate : " << currentDate << endl ;
331      info(20) << "lastDataRequestedFromServer : " << lastDataRequestedFromServer << endl ;
332      info(20) << "file->output_freq.getValue() : " << file->output_freq.getValue() << endl ;
333      info(20) << "lastDataRequestedFromServer + file->output_freq.getValue() : " << lastDataRequestedFromServer + file->output_freq << endl ;
334
335      dataRequested |= sendReadDataRequest(lastDataRequestedFromServer + file->output_freq);
336    }
337
338    return dataRequested;
339  }
340
341  void CField::recvReadDataRequest(CEventServer& event)
342  {
343    CBufferIn* buffer = event.subEvents.begin()->buffer;
344    StdString fieldId;
345    *buffer >> fieldId;
346    get(fieldId)->recvReadDataRequest();
347  }
348
349  /*!
350    Receive data request sent from client and process it
351    Every time server receives this request, it will try to read data and sent read data back to client
352    At the moment, this function is called by server level 1
353    In the future, this should (only) be done by the last level servers.
354  */
355  void CField::recvReadDataRequest(void)
356  {
357    CContext* context = CContext::getCurrent();
358    CContextClient* client = context->client;
359
360    CEventClient event(getType(), EVENT_ID_READ_DATA_READY);
361    std::list<CMessage> msgs;
362
363    EReadField hasData = readField();
364
365    map<int, CArray<double,1> >::iterator it;
366    if (!grid->doGridHaveDataDistributed(client))
367    {
368       if (client->isServerLeader())
369       {
370          if (0 != recvDataSrv.numElements())
371          {           
372            const std::list<int>& ranks = client->getRanksServerLeader();
373            for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
374            {
375              msgs.push_back(CMessage());
376              CMessage& msg = msgs.back();
377              msg << getId();
378              switch (hasData)
379              {
380                case RF_DATA:
381                  msg << getNStep() - 1 << recvDataSrv;
382                  break;
383                case RF_NODATA:
384                  msg << int(-2) << recvDataSrv;
385                  break;
386                case RF_EOF:                 
387                default:
388                  msg << int(-1);
389                  break;
390              }
391
392              event.push(*itRank, 1, msg);
393            }
394          }
395          client->sendEvent(event);
396       }
397       else
398       {
399          client->sendEvent(event);
400       }
401    }
402    else
403    {
404      for (map<int, CArray<size_t, 1> >::iterator it = grid->outLocalIndexStoreOnClient.begin(); 
405                                                  it != grid->outLocalIndexStoreOnClient.end(); ++it)
406      {
407        CArray<size_t,1>& indexTmp = it->second;
408        CArray<double,1> tmp(indexTmp.numElements());
409        for (int idx = 0; idx < indexTmp.numElements(); ++idx)
410        {
411          tmp(idx) = recvDataSrv(indexTmp(idx));
412        } 
413
414        msgs.push_back(CMessage());
415        CMessage& msg = msgs.back();
416        msg << getId();
417        switch (hasData)
418        {
419          case RF_DATA:
420            msg << getNStep() - 1 << tmp;
421            break;
422          case RF_NODATA:
423            msg << int(-2) << tmp;
424            break;
425          case RF_EOF:                 
426          default:
427            msg << int(-1);
428            break;
429        }
430
431        event.push(it->first, grid->nbReadSenders[client][it->first], msg);
432      }
433      client->sendEvent(event);
434    }
435  }
436
437  /*!
438    Read field from a file.
439    A field is read with the distribution of data on the server side
440    \return State of field can be read from a file
441  */
442  CField::EReadField CField::readField(void)
443  {
444    CContext* context = CContext::getCurrent();
445    grid->computeWrittenIndex();
446    getRelFile()->initRead();
447    EReadField readState = RF_DATA;
448
449    if (!getRelFile()->isEmptyZone())
450    {     
451      if (grid->doGridHaveDataToWrite() || getRelFile()->type == CFile::type_attr::one_file)     
452      {
453        if (0 == recvDataSrv.numElements())
454        {           
455          CArray<int,1>& storeClient = grid->storeIndex_client;         
456          recvDataSrv.resize(storeClient.numElements());         
457        }
458       
459        getRelFile()->checkReadFile();
460
461        if (!nstepMax)
462        {
463          nstepMax = getRelFile()->getDataInput()->getFieldNbRecords(CField::get(this));
464        }
465
466        this->incrementNStep();
467
468        if (getNStep() > nstepMax && (getRelFile()->cyclic.isEmpty() || !getRelFile()->cyclic) )
469          readState = RF_EOF;
470
471        if (RF_EOF != readState)
472          getRelFile()->getDataInput()->readFieldData(CField::get(this));
473      }
474    }
475    else
476    {
477      this->incrementNStep();
478      if (getNStep() > nstepMax && (getRelFile()->cyclic.isEmpty() || !getRelFile()->cyclic) )
479        readState = RF_EOF;
480      else
481        readState = RF_NODATA;
482
483      if (!nstepMaxRead) // This can be a bug if we try to read field from zero time record
484        readState = RF_NODATA;
485    }
486
487    if (!nstepMaxRead)
488    {
489       MPI_Allreduce(MPI_IN_PLACE, &nstepMax, 1, MPI_INT, MPI_MAX, context->server->intraComm);
490       nstepMaxRead = true;
491    }
492
493    return readState;
494  }
495
496  /*
497    Receive read data from server.
498    At the moment, this function is called in the client side.
499    In the future, this function can be called hiearachically (server n-1, server n -2, ..., client)
500    \param event event containing read data
501  */
502  void CField::recvReadDataReady(CEventServer& event)
503  {
504    string fieldId;
505    vector<int> ranks;
506    vector<CBufferIn*> buffers;
507
508    list<CEventServer::SSubEvent>::iterator it;
509    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
510    {
511      ranks.push_back(it->rank);
512      CBufferIn* buffer = it->buffer;
513      *buffer >> fieldId;
514      buffers.push_back(buffer);
515    }
516    get(fieldId)->recvReadDataReady(ranks, buffers);
517  }
518
519  /*!
520    Receive read data from server
521    \param [in] ranks Ranks of sending processes
522    \param [in] buffers buffers containing read data
523  */
524  void CField::recvReadDataReady(vector<int> ranks, vector<CBufferIn*> buffers)
525  {
526    CContext* context = CContext::getCurrent();
527    std::map<int, CArray<double,1> > data;
528    const bool wasEOF = isEOF;
529
530    for (int i = 0; i < ranks.size(); i++)
531    {
532      int rank = ranks[i];
533      int record;
534      *buffers[i] >> record;
535      isEOF = (record == int(-1));
536
537      if (!isEOF)
538        *buffers[i] >> data[rank];
539      else
540        break;
541    }
542
543    if (wasDataAlreadyReceivedFromServer)
544      lastDataReceivedFromServer = lastDataReceivedFromServer + file->output_freq;
545    else
546    {
547      lastDataReceivedFromServer = context->getCalendar()->getInitDate();
548      wasDataAlreadyReceivedFromServer = true;
549    }
550
551    if (isEOF)
552    {
553      if (!wasEOF)
554        dateEOF = lastDataReceivedFromServer;
555
556      serverSourceFilter->signalEndOfStream(lastDataReceivedFromServer);
557    }
558    else
559      serverSourceFilter->streamDataFromServer(lastDataReceivedFromServer, data);
560  }
561
562  void CField::checkForLateDataFromServer(void)
563  {
564    CContext* context = CContext::getCurrent();
565    const CDate& currentDate = context->getCalendar()->getCurrentDate();
566
567    // Check if data previously requested has been received as expected
568    if (wasDataRequestedFromServer && (!isEOF || context->getCalendar()->getCurrentDate() <= dateEOF))
569    {
570      CTimer timer("CField::checkForLateDataFromServer");
571
572      bool isDataLate = !wasDataAlreadyReceivedFromServer || lastDataReceivedFromServer + file->output_freq < currentDate;
573      while (isDataLate && timer.getCumulatedTime() < CXios::recvFieldTimeout)
574      {
575        timer.resume();
576
577        context->checkBuffersAndListen();
578
579        timer.suspend();
580
581        isDataLate = !wasDataAlreadyReceivedFromServer || lastDataReceivedFromServer + file->output_freq < currentDate;
582      }
583
584      if (isDataLate)
585        ERROR("void CField::checkForLateDataFromServer(void)",
586              << "Late data at timestep = " << currentDate);
587    }
588  }
589
590   //----------------------------------------------------------------
591
592   void CField::setRelFile(CFile* _file)
593   {
594      this->file = _file;
595      hasOutputFile = true;
596   }
597
598   //----------------------------------------------------------------
599
600   StdString CField::GetName(void)    { return StdString("field"); }
601   StdString CField::GetDefName(void) { return CField::GetName(); }
602   ENodeType CField::GetType(void)    { return eField; }
603
604   //----------------------------------------------------------------
605
606   CGrid* CField::getRelGrid(void) const
607   {
608      return this->grid;
609   }
610
611   //----------------------------------------------------------------
612
613   CFile* CField::getRelFile(void) const
614   {
615      return this->file;
616   }
617
618   int CField::getNStep(void) const
619   {
620      return this->nstep;
621   }
622
623   func::CFunctor::ETimeType CField::getOperationTimeType() const
624   {
625     return operationTimeType;
626   }
627
628   //----------------------------------------------------------------
629
630   void CField::incrementNStep(void)
631   {
632      this->nstep++;
633   }
634
635   void CField::resetNStep(int nstep /*= 0*/)
636   {
637      this->nstep = nstep;
638   }
639
640   void CField::resetNStepMax(void)
641   {
642      this->nstepMax = 0;
643      nstepMaxRead = false;
644   }
645
646   //----------------------------------------------------------------
647
648   bool CField::isActive(bool atCurrentTimestep /*= false*/) const
649   {
650      if (clientSourceFilter)
651        return atCurrentTimestep ? clientSourceFilter->isDataExpected(CContext::getCurrent()->getCalendar()->getCurrentDate()) : true;
652      else if (storeFilter)
653        return true;
654      else if (instantDataFilter)
655        ERROR("bool CField::isActive(bool atCurrentTimestep)",
656              << "Impossible to check if field [ id = " << getId() << " ] is active as it cannot be used to receive nor send data.");
657
658      return false;
659   }
660
661   //----------------------------------------------------------------
662
663   bool CField::wasWritten() const
664   {
665     return written;
666   }
667
668   void CField::setWritten()
669   {
670     written = true;
671   }
672
673   //----------------------------------------------------------------
674
675   bool CField::getUseCompressedOutput() const
676   {
677     return useCompressedOutput;
678   }
679
680   void CField::setUseCompressedOutput()
681   {
682     useCompressedOutput = true;
683   }
684
685   //----------------------------------------------------------------
686
687   boost::shared_ptr<COutputPin> CField::getInstantDataFilter()
688   {
689     return instantDataFilter;
690   }
691
692   //----------------------------------------------------------------
693
694   /*!
695     Build up graph of grids which plays role of destination and source in grid transformation
696     This function should be called before \func solveGridReference()
697   */
698   void CField::buildGridTransformationGraph()
699   {
700     CContext* context = CContext::getCurrent();
701     if (context->hasClient && !context->hasServer)
702     {
703       if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
704       {
705         grid->addTransGridSource(getDirectFieldReference()->grid);
706       }
707     }
708   }
709
710   /*!
711     Generate a new grid destination if there are more than one grid source pointing to a same grid destination
712   */
713   void CField::generateNewTransformationGridDest()
714   {
715     CContext* context = CContext::getCurrent();
716     if (context->hasClient && !context->hasServer)
717     {
718       std::map<CGrid*,std::pair<bool,StdString> >& gridSrcMap = grid->getTransGridSource();
719       if (1 < gridSrcMap.size())
720       {
721         // Search for grid source
722         CGrid* gridSrc = grid;
723         CField* currField = this;
724         std::vector<CField*> hieraField;
725
726         while (currField->hasDirectFieldReference() && (gridSrc == grid))
727         {
728           hieraField.push_back(currField);
729           CField* tmp = currField->getDirectFieldReference();
730           currField = tmp;
731           gridSrc = currField->grid;
732         }
733
734         if (gridSrcMap.end() != gridSrcMap.find(gridSrc))
735         {
736           CGrid* gridTmp;
737           std::pair<bool,StdString> newGridDest = gridSrcMap[gridSrc];
738           if (newGridDest.first)
739           {
740             StdString newIdGridDest = newGridDest.second;
741             if (!CGrid::has(newIdGridDest))
742             {
743                ERROR("CGrid* CGrid::generateNewTransformationGridDest()",
744                  << " Something wrong happened! Grid whose id " << newIdGridDest
745                  << "should exist ");
746             }
747             gridTmp = CGrid::get(newIdGridDest);
748           }
749           else
750           {
751             StdString newIdGridDest = CGrid::generateId(gridSrc, grid);
752             gridTmp = CGrid::cloneGrid(newIdGridDest, grid);
753
754             (gridSrcMap[gridSrc]).first = true;
755             (gridSrcMap[gridSrc]).second = newIdGridDest;
756           }
757
758           // Update all descendants
759           for (std::vector<CField*>::iterator it = hieraField.begin(); it != hieraField.end(); ++it)
760           {
761             (*it)->grid = gridTmp;
762             (*it)->updateRef((*it)->grid);
763           }
764         }
765       }
766     }
767   }
768
769   void CField::updateRef(CGrid* grid)
770   {
771     if (!grid_ref.isEmpty()) grid_ref.setValue(grid->getId());
772     else
773     {
774       std::vector<CAxis*> axisTmp = grid->getAxis();
775       std::vector<CDomain*> domainTmp = grid->getDomains();
776       if ((1<axisTmp.size()) || (1<domainTmp.size()))
777         ERROR("void CField::updateRef(CGrid* grid)",
778           << "More than one domain or axis is available for domain_ref/axis_ref of field " << this->getId());
779
780       if ((!domain_ref.isEmpty()) && (domainTmp.empty()))
781         ERROR("void CField::updateRef(CGrid* grid)",
782           << "Incoherent between available domain and domain_ref of field " << this->getId());
783       if ((!axis_ref.isEmpty()) && (axisTmp.empty()))
784         ERROR("void CField::updateRef(CGrid* grid)",
785           << "Incoherent between available axis and axis_ref of field " << this->getId());
786
787       if (!domain_ref.isEmpty()) domain_ref.setValue(domainTmp[0]->getId());
788       if (!axis_ref.isEmpty()) axis_ref.setValue(axisTmp[0]->getId());
789     }
790   }
791   
792   /*!
793     Solve reference of all enabled fields even the source fields .
794     In this step, we do transformations.
795   */
796   void CField::solveAllEnabledFieldsAndTransform()
797   {
798     CContext* context = CContext::getCurrent();
799     bool hasClient = context->hasClient;
800     bool hasServer = context->hasServer;
801
802     if (!isReferenceSolvedAndTransformed)
803     {
804        isReferenceSolvedAndTransformed = true;
805
806        if (hasClient && !hasServer)
807        {
808          solveRefInheritance(true);
809          if (hasDirectFieldReference()) getDirectFieldReference()->solveAllEnabledFieldsAndTransform();
810        }
811
812        if (hasServer)
813          solveServerOperation();
814
815        solveGridReference();
816
817        if (hasClient && !hasServer)
818       {
819         solveGenerateGrid();
820         buildGridTransformationGraph();
821       }
822
823       solveGridDomainAxisRef(false);
824
825       if (hasClient && !hasServer)
826       {
827         solveTransformedGrid();
828       }
829
830       solveGridDomainAxisRef(false);
831     }
832   }
833
834   void CField::checkGridOfEnabledFields()
835   {
836      solveCheckMaskIndex(false);
837   }
838
839   void CField::sendGridComponentOfEnabledFields()
840   {
841      solveGridDomainAxisRef(true);
842      // solveCheckMaskIndex(true);
843   }
844
845   void CField::sendGridOfEnabledFields()
846   {
847      // solveGridDomainAxisRef(true);
848      solveCheckMaskIndex(true);
849   }   
850
851   void CField::solveOnlyReferenceEnabledField(bool doSending2Server)
852   {
853     CContext* context = CContext::getCurrent();
854     if (!isReferenceSolved)
855     {
856        isReferenceSolved = true;
857
858        if (context->hasClient && !context->hasServer)
859        {
860          solveRefInheritance(true);
861          if (hasDirectFieldReference()) getDirectFieldReference()->solveOnlyReferenceEnabledField(false);
862        }
863
864        if (context->hasServer)
865          solveServerOperation();
866
867        solveGridReference();
868        grid->solveDomainAxisRefInheritance(true); // make it again to solve grid reading from file
869
870        if (context->hasClient && !context->hasServer)
871       {
872         solveGenerateGrid();
873         buildGridTransformationGraph();
874       }
875     }
876   }
877     
878   void CField::solveAllReferenceEnabledField(bool doSending2Server)
879   {
880     CContext* context = CContext::getCurrent();
881     solveOnlyReferenceEnabledField(doSending2Server);
882
883     if (!areAllReferenceSolved)
884     {
885        areAllReferenceSolved = true;
886       
887        if (context->hasClient && !context->hasServer)
888        {
889          solveRefInheritance(true);
890          if (hasDirectFieldReference()) getDirectFieldReference()->solveAllReferenceEnabledField(false);
891        }
892        else if (context->hasServer)
893          solveServerOperation();
894
895        solveGridReference();
896     }
897
898     solveGridDomainAxisRef(doSending2Server);
899
900     if (context->hasClient && !context->hasServer)
901     {
902       solveTransformedGrid();
903     }
904
905     solveCheckMaskIndex(doSending2Server);
906   }
907
908   std::map<int, StdSize> CField::getGridAttributesBufferSize(CContextClient* client)
909   {
910     return grid->getAttributesBufferSize(client);
911   }
912
913   std::map<int, StdSize> CField::getGridDataBufferSize(CContextClient* client)
914   {
915     return grid->getDataBufferSize(client, getId());
916   }
917
918   size_t CField::getGlobalWrittenSize()
919   {
920     return grid->getGlobalWrittenSize();
921   }
922
923   //----------------------------------------------------------------
924
925   void CField::solveServerOperation(void)
926   {
927      CContext* context = CContext::getCurrent();
928
929      if (!context->hasServer || !hasOutputFile) return;
930
931      if (freq_op.isEmpty())
932        freq_op.setValue(TimeStep);
933
934      if (freq_offset.isEmpty())
935        freq_offset.setValue(NoneDu);
936
937      freq_operation_srv = file->output_freq.getValue();
938      freq_write_srv     = file->output_freq.getValue();
939
940      lastlast_Write_srv = context->getCalendar()->getInitDate();
941      last_Write_srv     = context->getCalendar()->getInitDate();
942      last_operation_srv = context->getCalendar()->getInitDate();
943
944      const CDuration toffset = freq_operation_srv - freq_offset.getValue() - context->getCalendar()->getTimeStep();
945      last_operation_srv     = last_operation_srv - toffset;
946
947      if (operation.isEmpty())
948        ERROR("void CField::solveServerOperation(void)",
949              << "An operation must be defined for field \"" << getId() << "\".");
950
951      boost::shared_ptr<func::CFunctor> functor;
952      CArray<double, 1> dummyData;
953
954#define DECLARE_FUNCTOR(MType, mtype) \
955      if (operation.getValue().compare(#mtype) == 0) \
956      { \
957        functor.reset(new func::C##MType(dummyData)); \
958      }
959
960#include "functor_type.conf"
961
962      if (!functor)
963        ERROR("void CField::solveServerOperation(void)",
964              << "\"" << operation << "\" is not a valid operation.");
965
966      operationTimeType = functor->timeType();
967   }
968
969   //----------------------------------------------------------------
970
971   /*!
972    * Constructs the graph filter for the field, enabling or not the data output.
973    * This method should not be called more than once with enableOutput equal to true.
974    *
975    * \param gc the garbage collector to use when building the filter graph
976    * \param enableOutput must be true when the field data is to be
977    *                     read by the client or/and written to a file
978    */
979   void CField::buildFilterGraph(CGarbageCollector& gc, bool enableOutput)
980   {     
981    if (!isReferenceSolvedAndTransformed) solveAllEnabledFieldsAndTransform();
982
983     checkAttributes();
984
985     const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
986     const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
987
988     CContext* context = CContext::getCurrent();
989     bool hasWriterServer = context->hasServer && !context->hasClient;
990     bool hasIntermediateServer = context->hasServer && context->hasClient;
991
992     if (hasWriterServer)
993     {
994        if (!instantDataFilter)
995          instantDataFilter = clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid,true));
996
997
998       // If the field data is to be read by the client or/and written to a file
999       if (enableOutput && !storeFilter && !fileWriterFilter)
1000       {
1001         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
1002         {
1003           fileServerWriterFilter = boost::shared_ptr<CFileServerWriterFilter>(new CFileServerWriterFilter(gc, this));
1004           instantDataFilter->connectOutput(fileServerWriterFilter, 0);
1005         }
1006       }
1007     }
1008     else if (hasIntermediateServer)
1009     {
1010       if (!instantDataFilter)
1011         instantDataFilter = clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true));
1012
1013             // If the field data is to be read by the client or/and written to a file
1014       if (enableOutput && !storeFilter && !fileWriterFilter)
1015       {
1016         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
1017         {
1018           fileWriterFilter = boost::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
1019           instantDataFilter->connectOutput(fileWriterFilter, 0);
1020         }
1021       }
1022     }
1023     else
1024     {
1025       // Start by building a filter which can provide the field's instant data
1026       if (!instantDataFilter)
1027       {
1028         // Check if we have an expression to parse
1029         if (hasExpression())
1030         {
1031           boost::scoped_ptr<IFilterExprNode> expr(parseExpr(getExpression() + '\0'));
1032           boost::shared_ptr<COutputPin> filter = expr->reduce(gc, *this);
1033
1034           // Check if a spatial transformation is needed
1035           if (!field_ref.isEmpty())
1036           {
1037             CGrid* gridRef = CField::get(field_ref)->grid;
1038
1039             if (grid && grid != gridRef && grid->hasTransform())
1040             {
1041                 std::pair<boost::shared_ptr<CFilter>, boost::shared_ptr<CFilter> > filters = CSpatialTransformFilter::buildFilterGraph(gc, gridRef, grid, detectMissingValues, defaultValue); 
1042
1043               filter->connectOutput(filters.first, 0);
1044               filter = filters.second;
1045             }
1046           }
1047
1048           instantDataFilter = filter;
1049         }
1050         // Check if we have a reference on another field
1051         else if (!field_ref.isEmpty())
1052           instantDataFilter = getFieldReference(gc);
1053         // Check if the data is to be read from a file
1054         else if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
1055           instantDataFilter = serverSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, freq_offset, true,
1056                                                                                                       detectMissingValues, defaultValue));
1057         else // The data might be passed from the model
1058         {
1059            if (check_if_active.isEmpty()) check_if_active = false; 
1060            instantDataFilter = clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, false, NoneDu, false,
1061                                                                                                        detectMissingValues, defaultValue));
1062         }
1063       }
1064
1065       // If the field data is to be read by the client or/and written to a file
1066       if (enableOutput && !storeFilter && !fileWriterFilter)
1067       {
1068         if (!read_access.isEmpty() && read_access)
1069         {
1070           storeFilter = boost::shared_ptr<CStoreFilter>(new CStoreFilter(gc, CContext::getCurrent(), grid,
1071                                                                          detectMissingValues, defaultValue));
1072           instantDataFilter->connectOutput(storeFilter, 0);
1073         }
1074
1075         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
1076         {
1077           fileWriterFilter = boost::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
1078           getTemporalDataFilter(gc, file->output_freq)->connectOutput(fileWriterFilter, 0);
1079         }
1080       }
1081     }
1082   }
1083
1084   /*!
1085    * Returns the filter needed to handle the field reference.
1086    * This method should only be called when building the filter graph corresponding to the field.
1087    *
1088    * \param gc the garbage collector to use
1089    * \return the output pin corresponding to the field reference
1090    */
1091   boost::shared_ptr<COutputPin> CField::getFieldReference(CGarbageCollector& gc)
1092   {
1093     if (instantDataFilter || field_ref.isEmpty())
1094       ERROR("COutputPin* CField::getFieldReference(CGarbageCollector& gc)",
1095             "Impossible to get the field reference for a field which has already been parsed or which does not have a field_ref.");
1096
1097     CField* fieldRef = CField::get(field_ref);
1098     fieldRef->buildFilterGraph(gc, false);
1099
1100     std::pair<boost::shared_ptr<CFilter>, boost::shared_ptr<CFilter> > filters;
1101     // Check if a spatial transformation is needed
1102     if (grid && grid != fieldRef->grid && grid->hasTransform())
1103     {       
1104       bool hasMissingValue = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1105       double defaultValue  = hasMissingValue ? default_value : (!default_value.isEmpty() ? default_value : 0.0);                               
1106       filters = CSpatialTransformFilter::buildFilterGraph(gc, fieldRef->grid, grid, hasMissingValue, defaultValue);
1107     }
1108     else
1109       filters.first = filters.second = boost::shared_ptr<CFilter>(new CPassThroughFilter(gc));
1110
1111     fieldRef->getInstantDataFilter()->connectOutput(filters.first, 0);
1112
1113     return filters.second;
1114   }
1115
1116   /*!
1117    * Returns the filter needed to handle a self reference in the field's expression.
1118    * If the needed filter does not exist, it is created, otherwise it is reused.
1119    * This method should only be called when building the filter graph corresponding
1120    * to the field's expression.
1121    *
1122    * \param gc the garbage collector to use
1123    * \return the output pin corresponding to a self reference
1124    */
1125   boost::shared_ptr<COutputPin> CField::getSelfReference(CGarbageCollector& gc)
1126   {
1127     if (instantDataFilter || !hasExpression())
1128       ERROR("COutputPin* CField::getSelfReference(CGarbageCollector& gc)",
1129             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1130
1131     if (!selfReferenceFilter)
1132     {
1133       checkAttributes();
1134
1135       const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1136       const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
1137
1138       if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
1139       {
1140         if (!serverSourceFilter)
1141           serverSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, freq_offset, true,
1142                                                                                   detectMissingValues, defaultValue));
1143
1144         selfReferenceFilter = serverSourceFilter;
1145       }
1146       else if (!field_ref.isEmpty())
1147       {
1148         CField* fieldRef = CField::get(field_ref);
1149         fieldRef->buildFilterGraph(gc, false);
1150         selfReferenceFilter = fieldRef->getInstantDataFilter();
1151       }
1152       else
1153       {
1154         if (!clientSourceFilter)
1155         {
1156           if (check_if_active.isEmpty()) check_if_active = false;
1157           clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, NoneDu, false,
1158                                                                                   detectMissingValues, defaultValue));
1159         }
1160
1161         selfReferenceFilter = clientSourceFilter;
1162       }
1163     }
1164
1165     return selfReferenceFilter;
1166   }
1167
1168   /*!
1169    * Returns the temporal filter corresponding to the field's temporal operation
1170    * for the specified operation frequency. The filter is created if it does not
1171    * exist, otherwise it is reused.
1172    *
1173    * \param gc the garbage collector to use
1174    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1175    * \return the output pin corresponding to the requested temporal filter
1176    */
1177   boost::shared_ptr<COutputPin> CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1178   {
1179     std::map<CDuration, boost::shared_ptr<COutputPin> >::iterator it = temporalDataFilters.find(outFreq);
1180
1181     if (it == temporalDataFilters.end())
1182     {
1183       if (operation.isEmpty())
1184         ERROR("void CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1185               << "An operation must be defined for field \"" << getId() << "\".");
1186
1187       checkAttributes();
1188
1189       const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1190       boost::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1191                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
1192                                                                             freq_op, freq_offset, outFreq,
1193                                                                             detectMissingValues, detectMissingValues ? default_value : 0.0));
1194
1195       instantDataFilter->connectOutput(temporalFilter, 0);
1196
1197       it = temporalDataFilters.insert(std::make_pair(outFreq, temporalFilter)).first;
1198     }
1199
1200     return it->second;
1201   }
1202
1203  /*!
1204    * Returns the temporal filter corresponding to the field's temporal operation
1205    * for the specified operation frequency.
1206    *
1207    * \param gc the garbage collector to use
1208    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1209    * \return the output pin corresponding to the requested temporal filter
1210    */
1211   
1212   boost::shared_ptr<COutputPin> CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1213   {
1214     if (instantDataFilter || !hasExpression())
1215       ERROR("COutputPin* CField::getSelfTemporalDataFilter(CGarbageCollector& gc)",
1216             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1217
1218     if (!selfReferenceFilter) getSelfReference(gc) ;
1219
1220     if (serverSourceFilter || clientSourceFilter)
1221     {
1222       if (operation.isEmpty())
1223         ERROR("void CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1224               << "An operation must be defined for field \"" << getId() << "\".");
1225
1226       checkAttributes();
1227
1228       const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1229       boost::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1230                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
1231                                                                             freq_op, freq_offset, outFreq,
1232                                                                             detectMissingValues, detectMissingValues ? default_value : 0.0));
1233
1234       selfReferenceFilter->connectOutput(temporalFilter, 0);
1235       return temporalFilter ;
1236     }
1237     else if (!field_ref.isEmpty())
1238     {
1239       CField* fieldRef = CField::get(field_ref);
1240       fieldRef->buildFilterGraph(gc, false); 
1241       return fieldRef->getTemporalDataFilter(gc, outFreq) ;
1242     }
1243  }
1244
1245   //----------------------------------------------------------------
1246/*
1247   void CField::fromBinary(StdIStream& is)
1248   {
1249      SuperClass::fromBinary(is);
1250#define CLEAR_ATT(name_)\
1251      SuperClassAttribute::operator[](#name_)->reset()
1252
1253         CLEAR_ATT(domain_ref);
1254         CLEAR_ATT(axis_ref);
1255#undef CLEAR_ATT
1256
1257   }
1258*/
1259   //----------------------------------------------------------------
1260
1261   void CField::solveGridReference(void)
1262   {
1263      if (grid_ref.isEmpty() && domain_ref.isEmpty() && axis_ref.isEmpty() && scalar_ref.isEmpty())
1264      {
1265        ERROR("CField::solveGridReference(void)",
1266              << "A grid must be defined for field '" << getFieldOutputName() << "' .");
1267      }
1268      else if (!grid_ref.isEmpty() && (!domain_ref.isEmpty() || !axis_ref.isEmpty() || !scalar_ref.isEmpty()))
1269      {
1270        ERROR("CField::solveGridReference(void)",
1271              << "Field '" << getFieldOutputName() << "' has both a grid and a domain/axis/scalar." << std::endl
1272              << "Please define either 'grid_ref' or 'domain_ref'/'axis_ref'/'scalar_ref'.");
1273      }
1274
1275      if (grid_ref.isEmpty())
1276      {
1277        std::vector<CDomain*> vecDom;
1278        std::vector<CAxis*> vecAxis;
1279        std::vector<CScalar*> vecScalar;
1280        std::vector<int> axisDomainOrderTmp;
1281       
1282        if (!domain_ref.isEmpty())
1283        {
1284          StdString tmp = domain_ref.getValue();
1285          if (CDomain::has(domain_ref))
1286          {
1287            vecDom.push_back(CDomain::get(domain_ref));
1288            axisDomainOrderTmp.push_back(2);
1289          }
1290          else
1291            ERROR("CField::solveGridReference(void)",
1292                  << "Invalid reference to domain '" << domain_ref.getValue() << "'.");
1293        }
1294
1295        if (!axis_ref.isEmpty())
1296        {
1297          if (CAxis::has(axis_ref))
1298          {
1299            vecAxis.push_back(CAxis::get(axis_ref));
1300            axisDomainOrderTmp.push_back(1);
1301          }
1302          else
1303            ERROR("CField::solveGridReference(void)",
1304                  << "Invalid reference to axis '" << axis_ref.getValue() << "'.");
1305        }
1306
1307        if (!scalar_ref.isEmpty())
1308        {
1309          if (CScalar::has(scalar_ref))
1310          {
1311            vecScalar.push_back(CScalar::get(scalar_ref));
1312            axisDomainOrderTmp.push_back(0);
1313          }
1314          else
1315            ERROR("CField::solveGridReference(void)",
1316                  << "Invalid reference to scalar '" << scalar_ref.getValue() << "'.");
1317        }
1318       
1319        CArray<int,1> axisDomainOrder(axisDomainOrderTmp.size());
1320        for (int idx = 0; idx < axisDomainOrderTmp.size(); ++idx)
1321        {
1322          axisDomainOrder(idx) = axisDomainOrderTmp[idx];
1323        }
1324
1325        // Warning: the gridId shouldn't be set as the grid_ref since it could be inherited
1326        StdString gridId = CGrid::generateId(vecDom, vecAxis, vecScalar,axisDomainOrder);
1327        if (CGrid::has(gridId))
1328          this->grid = CGrid::get(gridId);
1329        else
1330          this->grid = CGrid::createGrid(gridId, vecDom, vecAxis, vecScalar,axisDomainOrder);
1331      }
1332      else
1333      {
1334        if (CGrid::has(grid_ref))
1335          this->grid = CGrid::get(grid_ref);
1336        else
1337          ERROR("CField::solveGridReference(void)",
1338                << "Invalid reference to grid '" << grid_ref.getValue() << "'.");
1339      }
1340   }
1341
1342   void CField::solveGridDomainAxisRef(bool checkAtt)
1343   {
1344     grid->solveDomainAxisRef(checkAtt);
1345   }
1346
1347   void CField::solveCheckMaskIndex(bool doSendingIndex)
1348   {
1349     grid->checkMaskIndex(doSendingIndex);
1350   }
1351
1352   void CField::solveTransformedGrid()
1353   {
1354     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
1355     {
1356       std::vector<CGrid*> grids;
1357       // Source grid
1358       grids.push_back(getDirectFieldReference()->grid);
1359       // Intermediate grids
1360       if (!grid_path.isEmpty())
1361       {
1362         std::string gridId;
1363         size_t start = 0, end;
1364
1365         do
1366         {
1367           end = grid_path.getValue().find(',', start);
1368           if (end != std::string::npos)
1369           {
1370             gridId = grid_path.getValue().substr(start, end - start);
1371             start = end + 1;
1372           }
1373           else
1374             gridId = grid_path.getValue().substr(start);
1375
1376           if (!CGrid::has(gridId))
1377             ERROR("void CField::solveTransformedGrid()",
1378                   << "Invalid grid_path, the grid '" << gridId << "' does not exist.");
1379
1380           grids.push_back(CGrid::get(gridId));
1381         }
1382         while (end != std::string::npos);
1383       }
1384       // Destination grid
1385       grids.push_back(grid);
1386
1387       for (size_t i = 0, count = grids.size() - 1; i < count; ++i)
1388       {
1389         CGrid *gridSrc  = grids[i];
1390         CGrid *gridDest = grids[i + 1];
1391         if (!gridDest->isTransformed())
1392           gridDest->transformGrid(gridSrc);
1393       }
1394     }
1395     else if (grid && grid->hasTransform() && !grid->isTransformed())
1396     {
1397       // Temporarily deactivate the self-transformation of grid
1398       //grid->transformGrid(grid);
1399     }
1400   }
1401
1402   void CField::solveGenerateGrid()
1403   {
1404     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
1405       grid->completeGrid(getDirectFieldReference()->grid);
1406     else
1407       grid->completeGrid();
1408   }
1409
1410   void CField::solveGridDomainAxisBaseRef()
1411   {
1412     grid->solveDomainAxisRef(false);
1413     grid->solveDomainAxisBaseRef();
1414   }
1415
1416   ///-------------------------------------------------------------------
1417
1418   template <>
1419   void CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)
1420   {
1421      if (this->group_ref.isEmpty()) return;
1422      StdString gref = this->group_ref.getValue();
1423
1424      if (!CFieldGroup::has(gref))
1425         ERROR("CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)",
1426               << "[ gref = " << gref << "]"
1427               << " invalid group name !");
1428
1429      CFieldGroup* group = CFieldGroup::get(gref);
1430      CFieldGroup* owner = CFieldGroup::get(boost::polymorphic_downcast<CFieldGroup*>(this));
1431
1432      std::vector<CField*> allChildren  = group->getAllChildren();
1433      std::vector<CField*>::iterator it = allChildren.begin(), end = allChildren.end();
1434
1435      for (; it != end; it++)
1436      {
1437         CField* child = *it;
1438         if (child->hasId()) owner->createChild()->field_ref.setValue(child->getId());
1439
1440      }
1441   }
1442
1443   void CField::scaleFactorAddOffset(double scaleFactor, double addOffset)
1444   {
1445     recvDataSrv = (recvDataSrv - addOffset) / scaleFactor;
1446   }
1447
1448   void CField::invertScaleFactorAddOffset(double scaleFactor, double addOffset)
1449   {
1450     recvDataSrv = recvDataSrv * scaleFactor + addOffset;
1451   }
1452
1453   void CField::outputField(CArray<double,1>& fieldOut)
1454   { 
1455      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1456      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1457      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1458      {
1459        fieldOut(outIndexServer(idx)) = recvDataSrv(outIndexClient(idx));
1460      }
1461   }
1462
1463   void CField::inputField(CArray<double,1>& fieldIn)
1464   {
1465      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1466      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1467      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1468      {
1469        recvDataSrv(outIndexClient(idx)) = fieldIn(outIndexServer(idx));
1470      }
1471
1472   }
1473
1474   void CField::outputCompressedField(CArray<double,1>& fieldOut)
1475   {
1476      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1477      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1478      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1479      {
1480        fieldOut((idx)) = recvDataSrv(outIndexClient(idx));
1481      }
1482   }
1483
1484   ///-------------------------------------------------------------------
1485
1486   void CField::parse(xml::CXMLNode& node)
1487   {
1488      SuperClass::parse(node);
1489      if (!node.getContent(this->content))
1490      {
1491        if (node.goToChildElement())
1492        {
1493          do
1494          {
1495            if (node.getElementName() == "variable" || node.getElementName() == "variable_group") this->getVirtualVariableGroup()->parseChild(node);
1496          } while (node.goToNextElement());
1497          node.goToParentElement();
1498        }
1499      }
1500    }
1501
1502   /*!
1503     This function retrieves Id of corresponding domain_ref and axis_ref (if any)
1504   of a field. In some cases, only domain exists but axis doesn't
1505   \return pair of Domain and Axis id
1506   */
1507   const std::vector<StdString>& CField::getRefDomainAxisIds()
1508   {
1509     CGrid* cgPtr = getRelGrid();
1510     if (NULL != cgPtr)
1511     {
1512       std::vector<StdString>::iterator it;
1513       if (!domain_ref.isEmpty())
1514       {
1515         std::vector<StdString> domainList = cgPtr->getDomainList();
1516         it = std::find(domainList.begin(), domainList.end(), domain_ref.getValue());
1517         if (domainList.end() != it) domAxisScalarIds_[0] = *it;
1518       }
1519
1520       if (!axis_ref.isEmpty())
1521       {
1522         std::vector<StdString> axisList = cgPtr->getAxisList();
1523         it = std::find(axisList.begin(), axisList.end(), axis_ref.getValue());
1524         if (axisList.end() != it) domAxisScalarIds_[1] = *it;
1525       }
1526
1527       if (!scalar_ref.isEmpty())
1528       {
1529         std::vector<StdString> scalarList = cgPtr->getScalarList();
1530         it = std::find(scalarList.begin(), scalarList.end(), scalar_ref.getValue());
1531         if (scalarList.end() != it) domAxisScalarIds_[2] = *it;
1532       }
1533     }
1534     return (domAxisScalarIds_);
1535   }
1536
1537   CVariable* CField::addVariable(const string& id)
1538   {
1539     return vVariableGroup->createChild(id);
1540   }
1541
1542   CVariableGroup* CField::addVariableGroup(const string& id)
1543   {
1544     return vVariableGroup->createChildGroup(id);
1545   }
1546
1547   void CField::setContextClient(CContextClient* contextClient)
1548   {
1549     client = contextClient;
1550     grid->setContextClient(contextClient);
1551   }
1552
1553   CContextClient* CField::getContextClient()
1554   {
1555     return client;
1556   }
1557
1558   void CField::sendAddAllVariables(CContextClient* client)
1559   {
1560     std::vector<CVariable*> allVar = getAllVariables();
1561     std::vector<CVariable*>::const_iterator it = allVar.begin();
1562     std::vector<CVariable*>::const_iterator itE = allVar.end();
1563
1564     for (; it != itE; ++it)
1565     {
1566       this->sendAddVariable((*it)->getId(), client);
1567       (*it)->sendAllAttributesToServer(client);
1568       (*it)->sendValue(client);
1569     }
1570   }
1571
1572   void CField::sendAddVariable(const string& id, CContextClient* client)
1573   {
1574      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE, client);
1575   }
1576
1577   void CField::sendAddVariableGroup(const string& id, CContextClient* client)
1578   {
1579      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE_GROUP, client);
1580   }
1581
1582   void CField::recvAddVariable(CEventServer& event)
1583   {
1584
1585      CBufferIn* buffer = event.subEvents.begin()->buffer;
1586      string id;
1587      *buffer >> id;
1588      get(id)->recvAddVariable(*buffer);
1589   }
1590
1591   void CField::recvAddVariable(CBufferIn& buffer)
1592   {
1593      string id;
1594      buffer >> id;
1595      addVariable(id);
1596   }
1597
1598   void CField::recvAddVariableGroup(CEventServer& event)
1599   {
1600
1601      CBufferIn* buffer = event.subEvents.begin()->buffer;
1602      string id;
1603      *buffer >> id;
1604      get(id)->recvAddVariableGroup(*buffer);
1605   }
1606
1607   void CField::recvAddVariableGroup(CBufferIn& buffer)
1608   {
1609      string id;
1610      buffer >> id;
1611      addVariableGroup(id);
1612   }
1613
1614   /*!
1615    * Check on freq_off and freq_op attributes.
1616    */
1617   void CField::checkAttributes(void)
1618   {
1619     bool isFieldRead = file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read;
1620     if (isFieldRead && operation.getValue() != "instant")
1621       ERROR("void CField::checkAttributes(void)",
1622             << "Unsupported operation for field '" << getFieldOutputName() << "'." << std::endl
1623             << "Currently only \"instant\" is supported for fields read from file.")
1624
1625     if (freq_op.isEmpty())
1626     {
1627       if (operation.getValue() == "instant")
1628         freq_op.setValue(file->output_freq.getValue());
1629       else
1630         freq_op.setValue(TimeStep);
1631     }
1632     if (freq_offset.isEmpty())
1633       freq_offset.setValue(isFieldRead ? NoneDu : (freq_op.getValue() - TimeStep));
1634   }
1635
1636   /*!
1637    * Returns string arithmetic expression associated to the field.
1638    * \return if content is defined return content string, otherwise, if "expr" attribute is defined, return expr string.
1639    */
1640   const string& CField::getExpression(void)
1641   {
1642     if (!expr.isEmpty() && content.empty())
1643     {
1644       content = expr;
1645       expr.reset();
1646     }
1647
1648     return content;
1649   }
1650
1651   bool CField::hasExpression(void) const
1652   {
1653     return (!expr.isEmpty() || !content.empty());
1654   }
1655
1656
1657   DEFINE_REF_FUNC(Field,field)
1658} // namespace xios
Note: See TracBrowser for help on using the repository browser.