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

Last change on this file since 1321 was 1321, checked in by rlacroix, 6 years ago

Improve the check for late data added in r1318.

Avoid waiting for data at the beginning of timestep 0 of the user calls "xios_update_calendar(0)". Data expected at timestep 0 is late only if it still has not been received with switching from timestep 0 to timestep 1.

  • 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.8 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 || currentDate <= dateEOF))
569    {
570      CTimer timer("CField::checkForLateDataFromServer");
571      const CDate nextDataDue = wasDataAlreadyReceivedFromServer ? (lastDataReceivedFromServer + file->output_freq) : context->getCalendar()->getInitDate();
572
573      bool isDataLate = nextDataDue < currentDate;
574      while (isDataLate && timer.getCumulatedTime() < CXios::recvFieldTimeout)
575      {
576        timer.resume();
577
578        context->checkBuffersAndListen();
579
580        timer.suspend();
581
582        isDataLate = nextDataDue < currentDate;
583      }
584
585      if (isDataLate)
586        ERROR("void CField::checkForLateDataFromServer(void)",
587              << "Late data at timestep = " << currentDate);
588    }
589  }
590
591   //----------------------------------------------------------------
592
593   void CField::setRelFile(CFile* _file)
594   {
595      this->file = _file;
596      hasOutputFile = true;
597   }
598
599   //----------------------------------------------------------------
600
601   StdString CField::GetName(void)    { return StdString("field"); }
602   StdString CField::GetDefName(void) { return CField::GetName(); }
603   ENodeType CField::GetType(void)    { return eField; }
604
605   //----------------------------------------------------------------
606
607   CGrid* CField::getRelGrid(void) const
608   {
609      return this->grid;
610   }
611
612   //----------------------------------------------------------------
613
614   CFile* CField::getRelFile(void) const
615   {
616      return this->file;
617   }
618
619   int CField::getNStep(void) const
620   {
621      return this->nstep;
622   }
623
624   func::CFunctor::ETimeType CField::getOperationTimeType() const
625   {
626     return operationTimeType;
627   }
628
629   //----------------------------------------------------------------
630
631   void CField::incrementNStep(void)
632   {
633      this->nstep++;
634   }
635
636   void CField::resetNStep(int nstep /*= 0*/)
637   {
638      this->nstep = nstep;
639   }
640
641   void CField::resetNStepMax(void)
642   {
643      this->nstepMax = 0;
644      nstepMaxRead = false;
645   }
646
647   //----------------------------------------------------------------
648
649   bool CField::isActive(bool atCurrentTimestep /*= false*/) const
650   {
651      if (clientSourceFilter)
652        return atCurrentTimestep ? clientSourceFilter->isDataExpected(CContext::getCurrent()->getCalendar()->getCurrentDate()) : true;
653      else if (storeFilter)
654        return true;
655      else if (instantDataFilter)
656        ERROR("bool CField::isActive(bool atCurrentTimestep)",
657              << "Impossible to check if field [ id = " << getId() << " ] is active as it cannot be used to receive nor send data.");
658
659      return false;
660   }
661
662   //----------------------------------------------------------------
663
664   bool CField::wasWritten() const
665   {
666     return written;
667   }
668
669   void CField::setWritten()
670   {
671     written = true;
672   }
673
674   //----------------------------------------------------------------
675
676   bool CField::getUseCompressedOutput() const
677   {
678     return useCompressedOutput;
679   }
680
681   void CField::setUseCompressedOutput()
682   {
683     useCompressedOutput = true;
684   }
685
686   //----------------------------------------------------------------
687
688   boost::shared_ptr<COutputPin> CField::getInstantDataFilter()
689   {
690     return instantDataFilter;
691   }
692
693   //----------------------------------------------------------------
694
695   /*!
696     Build up graph of grids which plays role of destination and source in grid transformation
697     This function should be called before \func solveGridReference()
698   */
699   void CField::buildGridTransformationGraph()
700   {
701     CContext* context = CContext::getCurrent();
702     if (context->hasClient && !context->hasServer)
703     {
704       if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
705       {
706         grid->addTransGridSource(getDirectFieldReference()->grid);
707       }
708     }
709   }
710
711   /*!
712     Generate a new grid destination if there are more than one grid source pointing to a same grid destination
713   */
714   void CField::generateNewTransformationGridDest()
715   {
716     CContext* context = CContext::getCurrent();
717     if (context->hasClient && !context->hasServer)
718     {
719       std::map<CGrid*,std::pair<bool,StdString> >& gridSrcMap = grid->getTransGridSource();
720       if (1 < gridSrcMap.size())
721       {
722         // Search for grid source
723         CGrid* gridSrc = grid;
724         CField* currField = this;
725         std::vector<CField*> hieraField;
726
727         while (currField->hasDirectFieldReference() && (gridSrc == grid))
728         {
729           hieraField.push_back(currField);
730           CField* tmp = currField->getDirectFieldReference();
731           currField = tmp;
732           gridSrc = currField->grid;
733         }
734
735         if (gridSrcMap.end() != gridSrcMap.find(gridSrc))
736         {
737           CGrid* gridTmp;
738           std::pair<bool,StdString> newGridDest = gridSrcMap[gridSrc];
739           if (newGridDest.first)
740           {
741             StdString newIdGridDest = newGridDest.second;
742             if (!CGrid::has(newIdGridDest))
743             {
744                ERROR("CGrid* CGrid::generateNewTransformationGridDest()",
745                  << " Something wrong happened! Grid whose id " << newIdGridDest
746                  << "should exist ");
747             }
748             gridTmp = CGrid::get(newIdGridDest);
749           }
750           else
751           {
752             StdString newIdGridDest = CGrid::generateId(gridSrc, grid);
753             gridTmp = CGrid::cloneGrid(newIdGridDest, grid);
754
755             (gridSrcMap[gridSrc]).first = true;
756             (gridSrcMap[gridSrc]).second = newIdGridDest;
757           }
758
759           // Update all descendants
760           for (std::vector<CField*>::iterator it = hieraField.begin(); it != hieraField.end(); ++it)
761           {
762             (*it)->grid = gridTmp;
763             (*it)->updateRef((*it)->grid);
764           }
765         }
766       }
767     }
768   }
769
770   void CField::updateRef(CGrid* grid)
771   {
772     if (!grid_ref.isEmpty()) grid_ref.setValue(grid->getId());
773     else
774     {
775       std::vector<CAxis*> axisTmp = grid->getAxis();
776       std::vector<CDomain*> domainTmp = grid->getDomains();
777       if ((1<axisTmp.size()) || (1<domainTmp.size()))
778         ERROR("void CField::updateRef(CGrid* grid)",
779           << "More than one domain or axis is available for domain_ref/axis_ref of field " << this->getId());
780
781       if ((!domain_ref.isEmpty()) && (domainTmp.empty()))
782         ERROR("void CField::updateRef(CGrid* grid)",
783           << "Incoherent between available domain and domain_ref of field " << this->getId());
784       if ((!axis_ref.isEmpty()) && (axisTmp.empty()))
785         ERROR("void CField::updateRef(CGrid* grid)",
786           << "Incoherent between available axis and axis_ref of field " << this->getId());
787
788       if (!domain_ref.isEmpty()) domain_ref.setValue(domainTmp[0]->getId());
789       if (!axis_ref.isEmpty()) axis_ref.setValue(axisTmp[0]->getId());
790     }
791   }
792   
793   /*!
794     Solve reference of all enabled fields even the source fields .
795     In this step, we do transformations.
796   */
797   void CField::solveAllEnabledFieldsAndTransform()
798   {
799     CContext* context = CContext::getCurrent();
800     bool hasClient = context->hasClient;
801     bool hasServer = context->hasServer;
802
803     if (!isReferenceSolvedAndTransformed)
804     {
805        isReferenceSolvedAndTransformed = true;
806
807        if (hasClient && !hasServer)
808        {
809          solveRefInheritance(true);
810          if (hasDirectFieldReference()) getDirectFieldReference()->solveAllEnabledFieldsAndTransform();
811        }
812
813        if (hasServer)
814          solveServerOperation();
815
816        solveGridReference();
817
818        if (hasClient && !hasServer)
819       {
820         solveGenerateGrid();
821         buildGridTransformationGraph();
822       }
823
824       solveGridDomainAxisRef(false);
825
826       if (hasClient && !hasServer)
827       {
828         solveTransformedGrid();
829       }
830
831       solveGridDomainAxisRef(false);
832     }
833   }
834
835   void CField::checkGridOfEnabledFields()
836   {
837      solveCheckMaskIndex(false);
838   }
839
840   void CField::sendGridComponentOfEnabledFields()
841   {
842      solveGridDomainAxisRef(true);
843      // solveCheckMaskIndex(true);
844   }
845
846   void CField::sendGridOfEnabledFields()
847   {
848      // solveGridDomainAxisRef(true);
849      solveCheckMaskIndex(true);
850   }   
851
852   void CField::solveOnlyReferenceEnabledField(bool doSending2Server)
853   {
854     CContext* context = CContext::getCurrent();
855     if (!isReferenceSolved)
856     {
857        isReferenceSolved = true;
858
859        if (context->hasClient && !context->hasServer)
860        {
861          solveRefInheritance(true);
862          if (hasDirectFieldReference()) getDirectFieldReference()->solveOnlyReferenceEnabledField(false);
863        }
864
865        if (context->hasServer)
866          solveServerOperation();
867
868        solveGridReference();
869        grid->solveDomainAxisRefInheritance(true); // make it again to solve grid reading from file
870
871        if (context->hasClient && !context->hasServer)
872       {
873         solveGenerateGrid();
874         buildGridTransformationGraph();
875       }
876     }
877   }
878     
879   void CField::solveAllReferenceEnabledField(bool doSending2Server)
880   {
881     CContext* context = CContext::getCurrent();
882     solveOnlyReferenceEnabledField(doSending2Server);
883
884     if (!areAllReferenceSolved)
885     {
886        areAllReferenceSolved = true;
887       
888        if (context->hasClient && !context->hasServer)
889        {
890          solveRefInheritance(true);
891          if (hasDirectFieldReference()) getDirectFieldReference()->solveAllReferenceEnabledField(false);
892        }
893        else if (context->hasServer)
894          solveServerOperation();
895
896        solveGridReference();
897     }
898
899     solveGridDomainAxisRef(doSending2Server);
900
901     if (context->hasClient && !context->hasServer)
902     {
903       solveTransformedGrid();
904     }
905
906     solveCheckMaskIndex(doSending2Server);
907   }
908
909   std::map<int, StdSize> CField::getGridAttributesBufferSize(CContextClient* client)
910   {
911     return grid->getAttributesBufferSize(client);
912   }
913
914   std::map<int, StdSize> CField::getGridDataBufferSize(CContextClient* client)
915   {
916     return grid->getDataBufferSize(client, getId());
917   }
918
919   size_t CField::getGlobalWrittenSize()
920   {
921     return grid->getGlobalWrittenSize();
922   }
923
924   //----------------------------------------------------------------
925
926   void CField::solveServerOperation(void)
927   {
928      CContext* context = CContext::getCurrent();
929
930      if (!context->hasServer || !hasOutputFile) return;
931
932      if (freq_op.isEmpty())
933        freq_op.setValue(TimeStep);
934
935      if (freq_offset.isEmpty())
936        freq_offset.setValue(NoneDu);
937
938      freq_operation_srv = file->output_freq.getValue();
939      freq_write_srv     = file->output_freq.getValue();
940
941      lastlast_Write_srv = context->getCalendar()->getInitDate();
942      last_Write_srv     = context->getCalendar()->getInitDate();
943      last_operation_srv = context->getCalendar()->getInitDate();
944
945      const CDuration toffset = freq_operation_srv - freq_offset.getValue() - context->getCalendar()->getTimeStep();
946      last_operation_srv     = last_operation_srv - toffset;
947
948      if (operation.isEmpty())
949        ERROR("void CField::solveServerOperation(void)",
950              << "An operation must be defined for field \"" << getId() << "\".");
951
952      boost::shared_ptr<func::CFunctor> functor;
953      CArray<double, 1> dummyData;
954
955#define DECLARE_FUNCTOR(MType, mtype) \
956      if (operation.getValue().compare(#mtype) == 0) \
957      { \
958        functor.reset(new func::C##MType(dummyData)); \
959      }
960
961#include "functor_type.conf"
962
963      if (!functor)
964        ERROR("void CField::solveServerOperation(void)",
965              << "\"" << operation << "\" is not a valid operation.");
966
967      operationTimeType = functor->timeType();
968   }
969
970   //----------------------------------------------------------------
971
972   /*!
973    * Constructs the graph filter for the field, enabling or not the data output.
974    * This method should not be called more than once with enableOutput equal to true.
975    *
976    * \param gc the garbage collector to use when building the filter graph
977    * \param enableOutput must be true when the field data is to be
978    *                     read by the client or/and written to a file
979    */
980   void CField::buildFilterGraph(CGarbageCollector& gc, bool enableOutput)
981   {     
982    if (!isReferenceSolvedAndTransformed) solveAllEnabledFieldsAndTransform();
983
984     const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
985     const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
986
987     CContext* context = CContext::getCurrent();
988     bool hasWriterServer = context->hasServer && !context->hasClient;
989     bool hasIntermediateServer = context->hasServer && context->hasClient;
990
991     if (hasWriterServer)
992     {
993        if (!instantDataFilter)
994          instantDataFilter = clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid,true));
995
996
997       // If the field data is to be read by the client or/and written to a file
998       if (enableOutput && !storeFilter && !fileWriterFilter)
999       {
1000         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
1001         {
1002           fileServerWriterFilter = boost::shared_ptr<CFileServerWriterFilter>(new CFileServerWriterFilter(gc, this));
1003           instantDataFilter->connectOutput(fileServerWriterFilter, 0);
1004         }
1005       }
1006     }
1007     else if (hasIntermediateServer)
1008     {
1009       if (!instantDataFilter)
1010         instantDataFilter = clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true));
1011
1012             // If the field data is to be read by the client or/and written to a file
1013       if (enableOutput && !storeFilter && !fileWriterFilter)
1014       {
1015         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
1016         {
1017           fileWriterFilter = boost::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
1018           instantDataFilter->connectOutput(fileWriterFilter, 0);
1019         }
1020       }
1021     }
1022     else
1023     {
1024       // Start by building a filter which can provide the field's instant data
1025       if (!instantDataFilter)
1026       {
1027         // Check if we have an expression to parse
1028         if (hasExpression())
1029         {
1030           boost::scoped_ptr<IFilterExprNode> expr(parseExpr(getExpression() + '\0'));
1031           boost::shared_ptr<COutputPin> filter = expr->reduce(gc, *this);
1032
1033           // Check if a spatial transformation is needed
1034           if (!field_ref.isEmpty())
1035           {
1036             CGrid* gridRef = CField::get(field_ref)->grid;
1037
1038             if (grid && grid != gridRef && grid->hasTransform())
1039             {
1040                 std::pair<boost::shared_ptr<CFilter>, boost::shared_ptr<CFilter> > filters = CSpatialTransformFilter::buildFilterGraph(gc, gridRef, grid, detectMissingValues, defaultValue); 
1041
1042               filter->connectOutput(filters.first, 0);
1043               filter = filters.second;
1044             }
1045           }
1046
1047           instantDataFilter = filter;
1048         }
1049         // Check if we have a reference on another field
1050         else if (!field_ref.isEmpty())
1051           instantDataFilter = getFieldReference(gc);
1052         // Check if the data is to be read from a file
1053         else if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
1054         {
1055           checkAttributes();
1056           instantDataFilter = serverSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, freq_offset, true,
1057                                                                                                       detectMissingValues, defaultValue));
1058         }
1059         else // The data might be passed from the model
1060         {
1061            if (check_if_active.isEmpty()) check_if_active = false; 
1062            instantDataFilter = clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, false, NoneDu, false,
1063                                                                                                        detectMissingValues, defaultValue));
1064         }
1065       }
1066
1067       // If the field data is to be read by the client or/and written to a file
1068       if (enableOutput && !storeFilter && !fileWriterFilter)
1069       {
1070         if (!read_access.isEmpty() && read_access)
1071         {
1072           storeFilter = boost::shared_ptr<CStoreFilter>(new CStoreFilter(gc, CContext::getCurrent(), grid,
1073                                                                          detectMissingValues, defaultValue));
1074           instantDataFilter->connectOutput(storeFilter, 0);
1075         }
1076
1077         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
1078         {
1079           fileWriterFilter = boost::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
1080           getTemporalDataFilter(gc, file->output_freq)->connectOutput(fileWriterFilter, 0);
1081         }
1082       }
1083     }
1084   }
1085
1086   /*!
1087    * Returns the filter needed to handle the field reference.
1088    * This method should only be called when building the filter graph corresponding to the field.
1089    *
1090    * \param gc the garbage collector to use
1091    * \return the output pin corresponding to the field reference
1092    */
1093   boost::shared_ptr<COutputPin> CField::getFieldReference(CGarbageCollector& gc)
1094   {
1095     if (instantDataFilter || field_ref.isEmpty())
1096       ERROR("COutputPin* CField::getFieldReference(CGarbageCollector& gc)",
1097             "Impossible to get the field reference for a field which has already been parsed or which does not have a field_ref.");
1098
1099     CField* fieldRef = CField::get(field_ref);
1100     fieldRef->buildFilterGraph(gc, false);
1101
1102     std::pair<boost::shared_ptr<CFilter>, boost::shared_ptr<CFilter> > filters;
1103     // Check if a spatial transformation is needed
1104     if (grid && grid != fieldRef->grid && grid->hasTransform())
1105     {       
1106       bool hasMissingValue = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1107       double defaultValue  = hasMissingValue ? default_value : (!default_value.isEmpty() ? default_value : 0.0);                               
1108       filters = CSpatialTransformFilter::buildFilterGraph(gc, fieldRef->grid, grid, hasMissingValue, defaultValue);
1109     }
1110     else
1111       filters.first = filters.second = boost::shared_ptr<CFilter>(new CPassThroughFilter(gc));
1112
1113     fieldRef->getInstantDataFilter()->connectOutput(filters.first, 0);
1114
1115     return filters.second;
1116   }
1117
1118   /*!
1119    * Returns the filter needed to handle a self reference in the field's expression.
1120    * If the needed filter does not exist, it is created, otherwise it is reused.
1121    * This method should only be called when building the filter graph corresponding
1122    * to the field's expression.
1123    *
1124    * \param gc the garbage collector to use
1125    * \return the output pin corresponding to a self reference
1126    */
1127   boost::shared_ptr<COutputPin> CField::getSelfReference(CGarbageCollector& gc)
1128   {
1129     if (instantDataFilter || !hasExpression())
1130       ERROR("COutputPin* CField::getSelfReference(CGarbageCollector& gc)",
1131             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1132
1133     if (!selfReferenceFilter)
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         {
1142           checkAttributes();
1143           serverSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, freq_offset, true,
1144                                                                                   detectMissingValues, defaultValue));
1145         }
1146
1147         selfReferenceFilter = serverSourceFilter;
1148       }
1149       else if (!field_ref.isEmpty())
1150       {
1151         CField* fieldRef = CField::get(field_ref);
1152         fieldRef->buildFilterGraph(gc, false);
1153         selfReferenceFilter = fieldRef->getInstantDataFilter();
1154       }
1155       else
1156       {
1157         if (!clientSourceFilter)
1158         {
1159           if (check_if_active.isEmpty()) check_if_active = false;
1160           clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, NoneDu, false,
1161                                                                                   detectMissingValues, defaultValue));
1162         }
1163
1164         selfReferenceFilter = clientSourceFilter;
1165       }
1166     }
1167
1168     return selfReferenceFilter;
1169   }
1170
1171   /*!
1172    * Returns the temporal filter corresponding to the field's temporal operation
1173    * for the specified operation frequency. The filter is created if it does not
1174    * exist, otherwise it is reused.
1175    *
1176    * \param gc the garbage collector to use
1177    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1178    * \return the output pin corresponding to the requested temporal filter
1179    */
1180   boost::shared_ptr<COutputPin> CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1181   {
1182     std::map<CDuration, boost::shared_ptr<COutputPin> >::iterator it = temporalDataFilters.find(outFreq);
1183
1184     if (it == temporalDataFilters.end())
1185     {
1186       if (operation.isEmpty())
1187         ERROR("void CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1188               << "An operation must be defined for field \"" << getId() << "\".");
1189
1190       checkAttributes();
1191
1192       const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1193       boost::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1194                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
1195                                                                             freq_op, freq_offset, outFreq,
1196                                                                             detectMissingValues, detectMissingValues ? default_value : 0.0));
1197
1198       instantDataFilter->connectOutput(temporalFilter, 0);
1199
1200       it = temporalDataFilters.insert(std::make_pair(outFreq, temporalFilter)).first;
1201     }
1202
1203     return it->second;
1204   }
1205
1206  /*!
1207    * Returns the temporal filter corresponding to the field's temporal operation
1208    * for the specified operation frequency.
1209    *
1210    * \param gc the garbage collector to use
1211    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1212    * \return the output pin corresponding to the requested temporal filter
1213    */
1214   
1215   boost::shared_ptr<COutputPin> CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1216   {
1217     if (instantDataFilter || !hasExpression())
1218       ERROR("COutputPin* CField::getSelfTemporalDataFilter(CGarbageCollector& gc)",
1219             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1220
1221     if (!selfReferenceFilter) getSelfReference(gc) ;
1222
1223     if (serverSourceFilter || clientSourceFilter)
1224     {
1225       if (operation.isEmpty())
1226         ERROR("void CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1227               << "An operation must be defined for field \"" << getId() << "\".");
1228
1229       checkAttributes();
1230
1231       const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1232       boost::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1233                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
1234                                                                             freq_op, freq_offset, outFreq,
1235                                                                             detectMissingValues, detectMissingValues ? default_value : 0.0));
1236
1237       selfReferenceFilter->connectOutput(temporalFilter, 0);
1238       return temporalFilter ;
1239     }
1240     else if (!field_ref.isEmpty())
1241     {
1242       CField* fieldRef = CField::get(field_ref);
1243       fieldRef->buildFilterGraph(gc, false); 
1244       return fieldRef->getTemporalDataFilter(gc, outFreq) ;
1245     }
1246  }
1247
1248   //----------------------------------------------------------------
1249/*
1250   void CField::fromBinary(StdIStream& is)
1251   {
1252      SuperClass::fromBinary(is);
1253#define CLEAR_ATT(name_)\
1254      SuperClassAttribute::operator[](#name_)->reset()
1255
1256         CLEAR_ATT(domain_ref);
1257         CLEAR_ATT(axis_ref);
1258#undef CLEAR_ATT
1259
1260   }
1261*/
1262   //----------------------------------------------------------------
1263
1264   void CField::solveGridReference(void)
1265   {
1266      if (grid_ref.isEmpty() && domain_ref.isEmpty() && axis_ref.isEmpty() && scalar_ref.isEmpty())
1267      {
1268        ERROR("CField::solveGridReference(void)",
1269              << "A grid must be defined for field '" << getFieldOutputName() << "' .");
1270      }
1271      else if (!grid_ref.isEmpty() && (!domain_ref.isEmpty() || !axis_ref.isEmpty() || !scalar_ref.isEmpty()))
1272      {
1273        ERROR("CField::solveGridReference(void)",
1274              << "Field '" << getFieldOutputName() << "' has both a grid and a domain/axis/scalar." << std::endl
1275              << "Please define either 'grid_ref' or 'domain_ref'/'axis_ref'/'scalar_ref'.");
1276      }
1277
1278      if (grid_ref.isEmpty())
1279      {
1280        std::vector<CDomain*> vecDom;
1281        std::vector<CAxis*> vecAxis;
1282        std::vector<CScalar*> vecScalar;
1283        std::vector<int> axisDomainOrderTmp;
1284       
1285        if (!domain_ref.isEmpty())
1286        {
1287          StdString tmp = domain_ref.getValue();
1288          if (CDomain::has(domain_ref))
1289          {
1290            vecDom.push_back(CDomain::get(domain_ref));
1291            axisDomainOrderTmp.push_back(2);
1292          }
1293          else
1294            ERROR("CField::solveGridReference(void)",
1295                  << "Invalid reference to domain '" << domain_ref.getValue() << "'.");
1296        }
1297
1298        if (!axis_ref.isEmpty())
1299        {
1300          if (CAxis::has(axis_ref))
1301          {
1302            vecAxis.push_back(CAxis::get(axis_ref));
1303            axisDomainOrderTmp.push_back(1);
1304          }
1305          else
1306            ERROR("CField::solveGridReference(void)",
1307                  << "Invalid reference to axis '" << axis_ref.getValue() << "'.");
1308        }
1309
1310        if (!scalar_ref.isEmpty())
1311        {
1312          if (CScalar::has(scalar_ref))
1313          {
1314            vecScalar.push_back(CScalar::get(scalar_ref));
1315            axisDomainOrderTmp.push_back(0);
1316          }
1317          else
1318            ERROR("CField::solveGridReference(void)",
1319                  << "Invalid reference to scalar '" << scalar_ref.getValue() << "'.");
1320        }
1321       
1322        CArray<int,1> axisDomainOrder(axisDomainOrderTmp.size());
1323        for (int idx = 0; idx < axisDomainOrderTmp.size(); ++idx)
1324        {
1325          axisDomainOrder(idx) = axisDomainOrderTmp[idx];
1326        }
1327
1328        // Warning: the gridId shouldn't be set as the grid_ref since it could be inherited
1329        StdString gridId = CGrid::generateId(vecDom, vecAxis, vecScalar,axisDomainOrder);
1330        if (CGrid::has(gridId))
1331          this->grid = CGrid::get(gridId);
1332        else
1333          this->grid = CGrid::createGrid(gridId, vecDom, vecAxis, vecScalar,axisDomainOrder);
1334      }
1335      else
1336      {
1337        if (CGrid::has(grid_ref))
1338          this->grid = CGrid::get(grid_ref);
1339        else
1340          ERROR("CField::solveGridReference(void)",
1341                << "Invalid reference to grid '" << grid_ref.getValue() << "'.");
1342      }
1343   }
1344
1345   void CField::solveGridDomainAxisRef(bool checkAtt)
1346   {
1347     grid->solveDomainAxisRef(checkAtt);
1348   }
1349
1350   void CField::solveCheckMaskIndex(bool doSendingIndex)
1351   {
1352     grid->checkMaskIndex(doSendingIndex);
1353   }
1354
1355   void CField::solveTransformedGrid()
1356   {
1357     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
1358     {
1359       std::vector<CGrid*> grids;
1360       // Source grid
1361       grids.push_back(getDirectFieldReference()->grid);
1362       // Intermediate grids
1363       if (!grid_path.isEmpty())
1364       {
1365         std::string gridId;
1366         size_t start = 0, end;
1367
1368         do
1369         {
1370           end = grid_path.getValue().find(',', start);
1371           if (end != std::string::npos)
1372           {
1373             gridId = grid_path.getValue().substr(start, end - start);
1374             start = end + 1;
1375           }
1376           else
1377             gridId = grid_path.getValue().substr(start);
1378
1379           if (!CGrid::has(gridId))
1380             ERROR("void CField::solveTransformedGrid()",
1381                   << "Invalid grid_path, the grid '" << gridId << "' does not exist.");
1382
1383           grids.push_back(CGrid::get(gridId));
1384         }
1385         while (end != std::string::npos);
1386       }
1387       // Destination grid
1388       grids.push_back(grid);
1389
1390       for (size_t i = 0, count = grids.size() - 1; i < count; ++i)
1391       {
1392         CGrid *gridSrc  = grids[i];
1393         CGrid *gridDest = grids[i + 1];
1394         if (!gridDest->isTransformed())
1395           gridDest->transformGrid(gridSrc);
1396       }
1397     }
1398     else if (grid && grid->hasTransform() && !grid->isTransformed())
1399     {
1400       // Temporarily deactivate the self-transformation of grid
1401       //grid->transformGrid(grid);
1402     }
1403   }
1404
1405   void CField::solveGenerateGrid()
1406   {
1407     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
1408       grid->completeGrid(getDirectFieldReference()->grid);
1409     else
1410       grid->completeGrid();
1411   }
1412
1413   void CField::solveGridDomainAxisBaseRef()
1414   {
1415     grid->solveDomainAxisRef(false);
1416     grid->solveDomainAxisBaseRef();
1417   }
1418
1419   ///-------------------------------------------------------------------
1420
1421   template <>
1422   void CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)
1423   {
1424      if (this->group_ref.isEmpty()) return;
1425      StdString gref = this->group_ref.getValue();
1426
1427      if (!CFieldGroup::has(gref))
1428         ERROR("CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)",
1429               << "[ gref = " << gref << "]"
1430               << " invalid group name !");
1431
1432      CFieldGroup* group = CFieldGroup::get(gref);
1433      CFieldGroup* owner = CFieldGroup::get(boost::polymorphic_downcast<CFieldGroup*>(this));
1434
1435      std::vector<CField*> allChildren  = group->getAllChildren();
1436      std::vector<CField*>::iterator it = allChildren.begin(), end = allChildren.end();
1437
1438      for (; it != end; it++)
1439      {
1440         CField* child = *it;
1441         if (child->hasId()) owner->createChild()->field_ref.setValue(child->getId());
1442
1443      }
1444   }
1445
1446   void CField::scaleFactorAddOffset(double scaleFactor, double addOffset)
1447   {
1448     recvDataSrv = (recvDataSrv - addOffset) / scaleFactor;
1449   }
1450
1451   void CField::invertScaleFactorAddOffset(double scaleFactor, double addOffset)
1452   {
1453     recvDataSrv = recvDataSrv * scaleFactor + addOffset;
1454   }
1455
1456   void CField::outputField(CArray<double,1>& fieldOut)
1457   { 
1458      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1459      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1460      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1461      {
1462        fieldOut(outIndexServer(idx)) = recvDataSrv(outIndexClient(idx));
1463      }
1464   }
1465
1466   void CField::inputField(CArray<double,1>& fieldIn)
1467   {
1468      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1469      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1470      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1471      {
1472        recvDataSrv(outIndexClient(idx)) = fieldIn(outIndexServer(idx));
1473      }
1474
1475   }
1476
1477   void CField::outputCompressedField(CArray<double,1>& fieldOut)
1478   {
1479      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1480      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1481      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1482      {
1483        fieldOut((idx)) = recvDataSrv(outIndexClient(idx));
1484      }
1485   }
1486
1487   ///-------------------------------------------------------------------
1488
1489   void CField::parse(xml::CXMLNode& node)
1490   {
1491      SuperClass::parse(node);
1492      if (!node.getContent(this->content))
1493      {
1494        if (node.goToChildElement())
1495        {
1496          do
1497          {
1498            if (node.getElementName() == "variable" || node.getElementName() == "variable_group") this->getVirtualVariableGroup()->parseChild(node);
1499          } while (node.goToNextElement());
1500          node.goToParentElement();
1501        }
1502      }
1503    }
1504
1505   /*!
1506     This function retrieves Id of corresponding domain_ref and axis_ref (if any)
1507   of a field. In some cases, only domain exists but axis doesn't
1508   \return pair of Domain and Axis id
1509   */
1510   const std::vector<StdString>& CField::getRefDomainAxisIds()
1511   {
1512     CGrid* cgPtr = getRelGrid();
1513     if (NULL != cgPtr)
1514     {
1515       std::vector<StdString>::iterator it;
1516       if (!domain_ref.isEmpty())
1517       {
1518         std::vector<StdString> domainList = cgPtr->getDomainList();
1519         it = std::find(domainList.begin(), domainList.end(), domain_ref.getValue());
1520         if (domainList.end() != it) domAxisScalarIds_[0] = *it;
1521       }
1522
1523       if (!axis_ref.isEmpty())
1524       {
1525         std::vector<StdString> axisList = cgPtr->getAxisList();
1526         it = std::find(axisList.begin(), axisList.end(), axis_ref.getValue());
1527         if (axisList.end() != it) domAxisScalarIds_[1] = *it;
1528       }
1529
1530       if (!scalar_ref.isEmpty())
1531       {
1532         std::vector<StdString> scalarList = cgPtr->getScalarList();
1533         it = std::find(scalarList.begin(), scalarList.end(), scalar_ref.getValue());
1534         if (scalarList.end() != it) domAxisScalarIds_[2] = *it;
1535       }
1536     }
1537     return (domAxisScalarIds_);
1538   }
1539
1540   CVariable* CField::addVariable(const string& id)
1541   {
1542     return vVariableGroup->createChild(id);
1543   }
1544
1545   CVariableGroup* CField::addVariableGroup(const string& id)
1546   {
1547     return vVariableGroup->createChildGroup(id);
1548   }
1549
1550   void CField::setContextClient(CContextClient* contextClient)
1551   {
1552     client = contextClient;
1553     if (file->mode.isEmpty() || (!file->mode.isEmpty() && file->mode == CFile::mode_attr::write))
1554       grid->setContextClient(contextClient);
1555   }
1556
1557   CContextClient* CField::getContextClient()
1558   {
1559     return client;
1560   }
1561
1562   void CField::sendAddAllVariables(CContextClient* client)
1563   {
1564     std::vector<CVariable*> allVar = getAllVariables();
1565     std::vector<CVariable*>::const_iterator it = allVar.begin();
1566     std::vector<CVariable*>::const_iterator itE = allVar.end();
1567
1568     for (; it != itE; ++it)
1569     {
1570       this->sendAddVariable((*it)->getId(), client);
1571       (*it)->sendAllAttributesToServer(client);
1572       (*it)->sendValue(client);
1573     }
1574   }
1575
1576   void CField::sendAddVariable(const string& id, CContextClient* client)
1577   {
1578      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE, client);
1579   }
1580
1581   void CField::sendAddVariableGroup(const string& id, CContextClient* client)
1582   {
1583      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE_GROUP, client);
1584   }
1585
1586   void CField::recvAddVariable(CEventServer& event)
1587   {
1588
1589      CBufferIn* buffer = event.subEvents.begin()->buffer;
1590      string id;
1591      *buffer >> id;
1592      get(id)->recvAddVariable(*buffer);
1593   }
1594
1595   void CField::recvAddVariable(CBufferIn& buffer)
1596   {
1597      string id;
1598      buffer >> id;
1599      addVariable(id);
1600   }
1601
1602   void CField::recvAddVariableGroup(CEventServer& event)
1603   {
1604
1605      CBufferIn* buffer = event.subEvents.begin()->buffer;
1606      string id;
1607      *buffer >> id;
1608      get(id)->recvAddVariableGroup(*buffer);
1609   }
1610
1611   void CField::recvAddVariableGroup(CBufferIn& buffer)
1612   {
1613      string id;
1614      buffer >> id;
1615      addVariableGroup(id);
1616   }
1617
1618   /*!
1619    * Check on freq_off and freq_op attributes.
1620    */
1621   void CField::checkAttributes(void)
1622   {
1623     bool isFieldRead = file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read;
1624     if (isFieldRead && operation.getValue() != "instant")
1625       ERROR("void CField::checkAttributes(void)",
1626             << "Unsupported operation for field '" << getFieldOutputName() << "'." << std::endl
1627             << "Currently only \"instant\" is supported for fields read from file.")
1628
1629     if (freq_op.isEmpty())
1630     {
1631       if (operation.getValue() == "instant")
1632         freq_op.setValue(file->output_freq.getValue());
1633       else
1634         freq_op.setValue(TimeStep);
1635     }
1636     if (freq_offset.isEmpty())
1637       freq_offset.setValue(isFieldRead ? NoneDu : (freq_op.getValue() - TimeStep));
1638   }
1639
1640   /*!
1641    * Returns string arithmetic expression associated to the field.
1642    * \return if content is defined return content string, otherwise, if "expr" attribute is defined, return expr string.
1643    */
1644   const string& CField::getExpression(void)
1645   {
1646     if (!expr.isEmpty() && content.empty())
1647     {
1648       content = expr;
1649       expr.reset();
1650     }
1651
1652     return content;
1653   }
1654
1655   bool CField::hasExpression(void) const
1656   {
1657     return (!expr.isEmpty() || !content.empty());
1658   }
1659
1660
1661   DEFINE_REF_FUNC(Field,field)
1662} // namespace xios
Note: See TracBrowser for help on using the repository browser.