source: XIOS/trunk/src/node/field.cpp @ 2250

Last change on this file since 2250 was 2131, checked in by oabramkina, 3 years ago

Merging branch dev_oa with tiling into trunk

  • 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: 66.5 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#include "workflow_graph.hpp"
27
28#include "yacc_var.hpp"
29namespace xios{
30
31   /// ////////////////////// Définitions ////////////////////// ///
32
33   CField::CField(void)
34      : CObjectTemplate<CField>(), CFieldAttributes()
35      , grid(), file()
36      , written(false)
37      , nstep(0), nstepMax(0)
38      , hasOutputFile(false)
39      , domAxisScalarIds_(vector<StdString>(3,""))
40      , areAllReferenceSolved(false), isReferenceSolved(false), isReferenceSolvedAndTransformed(false)
41      , isGridChecked(false)
42      , useCompressedOutput(false)
43      , hasTimeInstant(false)
44      , hasTimeCentered(false)
45      , wasDataRequestedFromServer(false)
46      , wasDataAlreadyReceivedFromServer(false)
47      , mustAutoTrigger(false)
48      , isEOF(false), nstepMaxRead(false)
49   { setVirtualVariableGroup(CVariableGroup::create(getId() + "_virtual_variable_group")); 
50     field_graph_start = -2;
51     field_graph_end = -2;
52   }
53
54   CField::CField(const StdString& id)
55      : CObjectTemplate<CField>(id), CFieldAttributes()
56      , grid(), file()
57      , written(false)
58      , nstep(0), nstepMax(0)
59      , hasOutputFile(false)
60      , domAxisScalarIds_(vector<StdString>(3,""))
61      , areAllReferenceSolved(false), isReferenceSolved(false), isReferenceSolvedAndTransformed(false)
62      , isGridChecked(false)
63      , useCompressedOutput(false)
64      , hasTimeInstant(false)
65      , hasTimeCentered(false)
66      , wasDataRequestedFromServer(false)
67      , wasDataAlreadyReceivedFromServer(false)
68      , mustAutoTrigger(false)
69      , isEOF(false), nstepMaxRead(false)
70   { setVirtualVariableGroup(CVariableGroup::create(getId() + "_virtual_variable_group")); 
71     field_graph_start = -2;
72     field_graph_end = -2;
73   }
74
75
76   CField::~CField(void)
77   {}
78
79  //----------------------------------------------------------------
80
81   void CField::setVirtualVariableGroup(CVariableGroup* newVVariableGroup)
82   TRY
83   {
84      this->vVariableGroup = newVVariableGroup;
85   }
86   CATCH
87
88   CVariableGroup* CField::getVirtualVariableGroup(void) const
89   TRY
90   {
91      return this->vVariableGroup;
92   }
93   CATCH
94
95   std::vector<CVariable*> CField::getAllVariables(void) const
96   TRY
97   {
98      return this->vVariableGroup->getAllChildren();
99   }
100   CATCH
101
102   void CField::solveDescInheritance(bool apply, const CAttributeMap* const parent)
103   TRY
104   {
105      SuperClassAttribute::setAttributes(parent, apply);
106      this->getVirtualVariableGroup()->solveDescInheritance(apply, NULL);
107   }
108   CATCH_DUMP_ATTR
109
110  //----------------------------------------------------------------
111
112  bool CField::dispatchEvent(CEventServer& event)
113  TRY
114  {
115    if (SuperClass::dispatchEvent(event)) return true;
116    else
117    {
118      switch(event.type)
119      {
120        case EVENT_ID_UPDATE_DATA :
121          recvUpdateData(event);
122          return true;
123          break;
124
125        case EVENT_ID_READ_DATA :
126          recvReadDataRequest(event);
127          return true;
128          break;
129
130        case EVENT_ID_READ_DATA_READY :
131          recvReadDataReady(event);
132          return true;
133          break;
134
135        case EVENT_ID_ADD_VARIABLE :
136          recvAddVariable(event);
137          return true;
138          break;
139
140        case EVENT_ID_ADD_VARIABLE_GROUP :
141          recvAddVariableGroup(event);
142          return true;
143          break;
144
145        default :
146          ERROR("bool CField::dispatchEvent(CEventServer& event)", << "Unknown Event");
147          return false;
148      }
149    }
150  }
151  CATCH
152
153  void CField::sendUpdateData(const CArray<double,1>& data)
154  TRY
155  {
156    CTimer::get("Field : send data").resume();
157
158    CContext* context = CContext::getCurrent();
159    CContextClient* client = (!context->hasServer) ? context->client : this->file->getContextClient();
160    int receiverSize = client->serverSize;
161
162    CEventClient event(getType(), EVENT_ID_UPDATE_DATA);
163
164    map<int, CArray<int,1> >::iterator it;
165    list<CMessage> list_msg;
166    list<CArray<double,1> > list_data;
167
168    if (!grid->doGridHaveDataDistributed(client))
169    {
170       if (client->isServerLeader())
171       {
172          for (it = grid->storeIndex_toSrv[client].begin(); it != grid->storeIndex_toSrv[client].end(); it++)
173          {
174            int rank = it->first;
175            CArray<int,1>& index = it->second;
176
177            list_msg.push_back(CMessage());
178            list_data.push_back(CArray<double,1>(index.numElements()));
179
180            CArray<double,1>& data_tmp = list_data.back();
181            for (int n = 0; n < data_tmp.numElements(); n++) data_tmp(n) = data(index(n));
182
183            list_msg.back() << getId() << data_tmp;
184            event.push(rank, 1, list_msg.back());
185          }
186          client->sendEvent(event);
187        }
188      else client->sendEvent(event);
189    }
190    else
191    {
192      for (it = grid->storeIndex_toSrv[client].begin(); it != grid->storeIndex_toSrv[client].end(); it++)
193      {
194        int rank = it->first;
195        CArray<int,1>& index = it->second;
196
197        list_msg.push_back(CMessage());
198        list_data.push_back(CArray<double,1>(index.numElements()));
199
200        CArray<double,1>& data_tmp = list_data.back();
201        for (int n = 0; n < data_tmp.numElements(); n++) data_tmp(n) = data(index(n));
202
203        list_msg.back() << getId() << data_tmp;
204        event.push(rank, grid->nbSenders[receiverSize][rank], list_msg.back());
205      }
206      client->sendEvent(event);
207    }
208
209    CTimer::get("Field : send data").suspend();
210  }
211  CATCH_DUMP_ATTR
212
213  void CField::recvUpdateData(CEventServer& event)
214  TRY
215  {
216    std::map<int,CBufferIn*> rankBuffers;
217
218    list<CEventServer::SSubEvent>::iterator it;
219    string fieldId;
220    CTimer::get("Field : recv data").resume();
221    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
222    {
223      int rank = it->rank;
224      CBufferIn* buffer = it->buffer;
225      *buffer >> fieldId;
226      rankBuffers[rank] = buffer;
227    }
228    get(fieldId)->recvUpdateData(rankBuffers);
229    CTimer::get("Field : recv data").suspend();
230  }
231  CATCH
232
233  void  CField::recvUpdateData(std::map<int,CBufferIn*>& rankBuffers)
234  TRY
235  {
236    CContext* context = CContext::getCurrent();
237
238    size_t sizeData = 0;
239    if (0 == recvDataSrv.numElements())
240    {           
241      CArray<int,1>& storeClient = grid->storeIndex_client;
242
243      // Gather all data from different clients     
244      recvDataSrv.resize(storeClient.numElements());
245      recvFoperationSrv = std::shared_ptr<func::CFunctor>(new func::CInstant(recvDataSrv));
246    }
247
248    CArray<double,1> recv_data_tmp(recvDataSrv.numElements());   
249    const CDate& currDate = context->getCalendar()->getCurrentDate();
250    CDuration offsetAllButMonth (freq_offset.getValue().year, 0 , freq_offset.getValue().day,
251                                   freq_offset.getValue().hour, freq_offset.getValue().minute,
252                                   freq_offset.getValue().second, freq_offset.getValue().timestep);
253    const CDate opeDate   = (last_operation_srv - offsetAllButMonth + context->getCalendar()->getTimeStep())
254                              + freq_op + freq_operation_srv - freq_op - context->getCalendar()->getTimeStep() + offsetAllButMonth;
255
256    if (opeDate <= currDate)
257    {
258      for (map<int, CArray<size_t, 1> >::iterator it = grid->outLocalIndexStoreOnClient.begin(); it != grid->outLocalIndexStoreOnClient.end(); ++it)
259      {
260        CArray<double,1> tmp;
261        CArray<size_t,1>& indexTmp = it->second;
262        *(rankBuffers[it->first]) >> tmp;
263        for (int idx = 0; idx < indexTmp.numElements(); ++idx)
264        {
265          recv_data_tmp(indexTmp(idx)) = tmp(idx);
266        }     
267      }
268    }
269
270    this->setData(recv_data_tmp);
271    // delete incomming flux for server only
272    recvFoperationSrv.reset() ;
273    recvDataSrv.reset() ;
274  }
275  CATCH_DUMP_ATTR
276
277  void CField::writeUpdateData(const CArray<double,1>& data)
278  TRY
279  {
280    CContext* context = CContext::getCurrent();
281
282    const CDate& currDate = context->getCalendar()->getCurrentDate();
283    CDuration offsetAllButMonth (freq_offset.getValue().year, 0 , freq_offset.getValue().day,
284                                   freq_offset.getValue().hour, freq_offset.getValue().minute,
285                                   freq_offset.getValue().second, freq_offset.getValue().timestep);
286    const CDate opeDate   = (last_operation_srv - offsetAllButMonth + context->getCalendar()->getTimeStep())
287                              + freq_op + freq_operation_srv - freq_op - context->getCalendar()->getTimeStep() + offsetAllButMonth;
288    const CDate writeDate = last_Write_srv + freq_write_srv;
289
290    if (opeDate <= currDate)
291    {
292      (*recvFoperationSrv)(data);
293      last_operation_srv = currDate;
294    }
295
296    if (writeDate < (currDate + freq_operation_srv))
297    {
298      recvFoperationSrv->final();
299      last_Write_srv = writeDate;
300      grid->computeWrittenIndex();
301      writeField();
302      lastlast_Write_srv = last_Write_srv;
303    }
304  }
305  CATCH_DUMP_ATTR
306
307  void CField::writeField(void)
308  TRY
309  {
310    if (!getRelFile()->isEmptyZone())
311    {
312      if (grid->doGridHaveDataToWrite() || getRelFile()->type == CFile::type_attr::one_file)
313      {
314        getRelFile()->checkWriteFile();
315        this->incrementNStep();
316        getRelFile()->getDataOutput()->writeFieldData(CField::get(this));
317      }
318    }
319  }
320  CATCH_DUMP_ATTR
321
322  /*
323    Send a request for reading data.
324    Client sends a request to server for demanding server to read data and send back to it.
325    For now, this function is called only by client
326    In the future, it can be called by level-1 servers
327    \param [in] tsDataRequested timestamp when the call is made
328  */
329  bool CField::sendReadDataRequest(const CDate& tsDataRequested)
330  TRY
331  {
332    CContext* context = CContext::getCurrent();
333    // CContextClient* client = context->client;
334
335    // This code is for future: If we want to read file with level-2 servers
336    CContextClient* client = (!context->hasServer) ? context->client : this->file->getContextClient();
337
338    lastDataRequestedFromServer = tsDataRequested;
339
340    // No need to send the request if we are sure that we are already at EOF
341    if (!isEOF || context->getCalendar()->getCurrentDate() <= dateEOF)
342    {
343      CEventClient event(getType(), EVENT_ID_READ_DATA);
344      if (client->isServerLeader())
345      {
346        CMessage msg;
347        msg << getId();
348        const std::list<int>& ranks = client->getRanksServerLeader();
349        for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
350          event.push(*itRank, 1, msg);
351        client->sendEvent(event);
352      }
353      else client->sendEvent(event);
354    }
355    else
356      serverSourceFilter->signalEndOfStream(tsDataRequested);
357
358    wasDataRequestedFromServer = true;
359
360    return !isEOF;
361  }
362  CATCH_DUMP_ATTR
363
364  /*!
365  Send request new data read from file if need be, that is the current data is out-of-date.
366  \return true if and only if some data was requested
367  */
368  bool CField::sendReadDataRequestIfNeeded(void)
369  TRY
370  {
371    const CDate& currentDate = CContext::getCurrent()->getCalendar()->getCurrentDate();
372
373    bool dataRequested = false;
374
375    while (currentDate >= lastDataRequestedFromServer)
376    {
377      info(20) << "currentDate : " << currentDate << endl ;
378      info(20) << "lastDataRequestedFromServer : " << lastDataRequestedFromServer << endl ;
379      info(20) << "file->output_freq.getValue() : " << file->output_freq.getValue() << endl ;
380      info(20) << "lastDataRequestedFromServer + file->output_freq.getValue() : " << lastDataRequestedFromServer + file->output_freq << endl ;
381
382      dataRequested |= sendReadDataRequest(lastDataRequestedFromServer + file->output_freq);
383    }
384
385    return dataRequested;
386  }
387  CATCH_DUMP_ATTR
388
389  void CField::recvReadDataRequest(CEventServer& event)
390  TRY
391  {
392    CBufferIn* buffer = event.subEvents.begin()->buffer;
393    StdString fieldId;
394    *buffer >> fieldId;
395    get(fieldId)->recvReadDataRequest();
396  }
397  CATCH
398
399  /*!
400    Receive data request sent from client and process it
401    Every time server receives this request, it will try to read data and sent read data back to client
402    At the moment, this function is called by server level 1
403    In the future, this should (only) be done by the last level servers.
404  */
405  void CField::recvReadDataRequest(void)
406  TRY
407  {
408    CContext* context = CContext::getCurrent();
409    CContextClient* client = context->client;
410
411    CEventClient event(getType(), EVENT_ID_READ_DATA_READY);
412    std::list<CMessage> msgs;
413
414    EReadField hasData = readField();
415
416    map<int, CArray<double,1> >::iterator it;
417    if (!grid->doGridHaveDataDistributed(client))
418    {
419       if (client->isServerLeader())
420       {
421          if (0 != recvDataSrv.numElements())
422          {           
423            const std::list<int>& ranks = client->getRanksServerLeader();
424            for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
425            {
426              msgs.push_back(CMessage());
427              CMessage& msg = msgs.back();
428              msg << getId();
429              switch (hasData)
430              {
431                case RF_DATA:
432                  msg << getNStep() - 1 << recvDataSrv;
433                  break;
434                case RF_NODATA:
435                  msg << int(-2) << recvDataSrv;
436                  break;
437                case RF_EOF:                 
438                default:
439                  msg << int(-1);
440                  break;
441              }
442
443              event.push(*itRank, 1, msg);
444            }
445          }
446          client->sendEvent(event);
447       }
448       else
449       {
450          client->sendEvent(event);
451       }
452    }
453    else
454    {
455      for (map<int, CArray<size_t, 1> >::iterator it = grid->outLocalIndexStoreOnClient.begin(); 
456                                                  it != grid->outLocalIndexStoreOnClient.end(); ++it)
457      {
458        CArray<size_t,1>& indexTmp = it->second;
459        CArray<double,1> tmp(indexTmp.numElements());
460        for (int idx = 0; idx < indexTmp.numElements(); ++idx)
461        {
462          tmp(idx) = recvDataSrv(indexTmp(idx));
463        } 
464
465        msgs.push_back(CMessage());
466        CMessage& msg = msgs.back();
467        msg << getId();
468        switch (hasData)
469        {
470          case RF_DATA:
471            msg << getNStep() - 1 << tmp;
472            break;
473          case RF_NODATA:
474            msg << int(-2) << tmp;
475            break;
476          case RF_EOF:                 
477          default:
478            msg << int(-1);
479            break;
480        }
481
482        event.push(it->first, grid->nbReadSenders[client][it->first], msg);
483      }
484      client->sendEvent(event);
485    }
486  }
487  CATCH_DUMP_ATTR
488
489  /*!
490    Read field from a file.
491    A field is read with the distribution of data on the server side
492    \return State of field can be read from a file
493  */
494  CField::EReadField CField::readField(void)
495  TRY
496  {
497    CContext* context = CContext::getCurrent();
498    grid->computeWrittenIndex();
499    getRelFile()->initRead();
500    EReadField readState = RF_DATA;
501
502    if (!getRelFile()->isEmptyZone())
503    {     
504      if (grid->doGridHaveDataToWrite() || getRelFile()->type == CFile::type_attr::one_file)     
505      {
506        if (0 == recvDataSrv.numElements())
507        {           
508          CArray<int,1>& storeClient = grid->storeIndex_client;         
509          recvDataSrv.resize(storeClient.numElements());         
510        }
511       
512        getRelFile()->checkReadFile();
513
514        if (!nstepMax)
515        {
516          nstepMax = getRelFile()->getDataInput()->getFieldNbRecords(CField::get(this));
517        }
518
519        this->incrementNStep();
520
521        if (getNStep() > nstepMax && (getRelFile()->cyclic.isEmpty() || !getRelFile()->cyclic) )
522          readState = RF_EOF;
523
524        if (RF_EOF != readState)
525          getRelFile()->getDataInput()->readFieldData(CField::get(this));
526      }
527    }
528    else
529    {
530      this->incrementNStep();
531      if (getNStep() > nstepMax && (getRelFile()->cyclic.isEmpty() || !getRelFile()->cyclic) )
532        readState = RF_EOF;
533      else
534        readState = RF_NODATA;
535
536      if (!nstepMaxRead) // This can be a bug if we try to read field from zero time record
537        readState = RF_NODATA;
538    }
539
540    if (!nstepMaxRead)
541    {
542       MPI_Allreduce(MPI_IN_PLACE, &nstepMax, 1, MPI_INT, MPI_MAX, context->server->intraComm);
543       nstepMaxRead = true;
544    }
545
546    return readState;
547  }
548  CATCH_DUMP_ATTR
549
550  /*
551    Receive read data from server.
552    At the moment, this function is called in the client side.
553    In the future, this function can be called hiearachically (server n-1, server n -2, ..., client)
554    \param event event containing read data
555  */
556  void CField::recvReadDataReady(CEventServer& event)
557  TRY
558  {
559    string fieldId;
560    vector<int> ranks;
561    vector<CBufferIn*> buffers;
562
563    list<CEventServer::SSubEvent>::iterator it;
564    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
565    {
566      ranks.push_back(it->rank);
567      CBufferIn* buffer = it->buffer;
568      *buffer >> fieldId;
569      buffers.push_back(buffer);
570    }
571    get(fieldId)->recvReadDataReady(ranks, buffers);
572  }
573  CATCH
574
575  /*!
576    Receive read data from server
577    \param [in] ranks Ranks of sending processes
578    \param [in] buffers buffers containing read data
579  */
580  void CField::recvReadDataReady(vector<int> ranks, vector<CBufferIn*> buffers)
581  TRY
582  {
583    CContext* context = CContext::getCurrent();
584    std::map<int, CArray<double,1> > data;
585    const bool wasEOF = isEOF;
586
587    for (int i = 0; i < ranks.size(); i++)
588    {
589      int rank = ranks[i];
590      int record;
591      *buffers[i] >> record;
592      isEOF = (record == int(-1));
593
594      if (!isEOF)
595        *buffers[i] >> data[rank];
596      else
597        break;
598    }
599
600    if (wasDataAlreadyReceivedFromServer)
601      lastDataReceivedFromServer = lastDataReceivedFromServer + file->output_freq;
602    else
603    {
604      lastDataReceivedFromServer = context->getCalendar()->getInitDate();
605      wasDataAlreadyReceivedFromServer = true;
606    }
607
608    if (isEOF)
609    {
610      if (!wasEOF)
611        dateEOF = lastDataReceivedFromServer;
612
613      serverSourceFilter->signalEndOfStream(lastDataReceivedFromServer);
614    }
615    else
616      serverSourceFilter->streamDataFromServer(lastDataReceivedFromServer, data);
617  }
618  CATCH_DUMP_ATTR
619
620  void CField::checkForLateDataFromServer(void)
621  TRY
622  {
623    CContext* context = CContext::getCurrent();
624    const CDate& currentDate = context->getCalendar()->getCurrentDate();
625
626    // Check if data previously requested has been received as expected
627    if (wasDataRequestedFromServer && !isEOF)
628    {
629      CTimer timer("CField::checkForLateDataFromServer");
630
631      bool isDataLate;
632      do
633      {
634        const CDate nextDataDue = wasDataAlreadyReceivedFromServer ? (lastDataReceivedFromServer + file->output_freq) : context->getCalendar()->getInitDate();
635        isDataLate = (nextDataDue <= currentDate);
636
637        if (isDataLate)
638        {
639          timer.resume();
640
641          context->checkBuffersAndListen();
642
643          timer.suspend();
644        }
645      }
646      while (isDataLate && timer.getCumulatedTime() < CXios::recvFieldTimeout);
647
648      if (isDataLate)
649        ERROR("void CField::checkForLateDataFromServer(void)",
650              << "Late data at timestep = " << currentDate);
651    }
652  }
653  CATCH_DUMP_ATTR
654
655  void CField::checkIfMustAutoTrigger(void)
656  TRY
657  {
658    mustAutoTrigger = serverSourceFilter ? serverSourceFilter->mustAutoTrigger() : false;
659  }
660  CATCH_DUMP_ATTR
661
662  void CField::autoTriggerIfNeeded(void)
663  TRY
664  {
665    if (mustAutoTrigger)
666      serverSourceFilter->trigger(CContext::getCurrent()->getCalendar()->getCurrentDate());
667  }
668  CATCH_DUMP_ATTR
669
670   //----------------------------------------------------------------
671
672   void CField::setRelFile(CFile* _file)
673   TRY
674   {
675      this->file = _file;
676      hasOutputFile = true;
677   }
678   CATCH_DUMP_ATTR
679
680   //----------------------------------------------------------------
681
682   StdString CField::GetName(void)    { return StdString("field"); }
683   StdString CField::GetDefName(void) { return CField::GetName(); }
684   ENodeType CField::GetType(void)    { return eField; }
685
686   //----------------------------------------------------------------
687
688   CGrid* CField::getRelGrid(void) const
689   TRY
690   {
691      return this->grid;
692   }
693   CATCH
694
695   //----------------------------------------------------------------
696
697   CFile* CField::getRelFile(void) const
698   TRY
699   {
700      return this->file;
701   }
702   CATCH
703
704   int CField::getNStep(void) const
705   TRY
706   {
707      return this->nstep;
708   }
709   CATCH
710
711   func::CFunctor::ETimeType CField::getOperationTimeType() const
712   TRY
713   {
714     return operationTimeType;
715   }
716   CATCH
717
718   //----------------------------------------------------------------
719
720   void CField::incrementNStep(void)
721   TRY
722   {
723      this->nstep++;
724   }
725   CATCH_DUMP_ATTR
726
727   void CField::resetNStep(int nstep /*= 0*/)
728   TRY
729   {
730      this->nstep = nstep;
731   }
732   CATCH_DUMP_ATTR
733
734   void CField::resetNStepMax(void)
735   TRY
736   {
737      this->nstepMax = 0;
738      nstepMaxRead = false;
739   }
740   CATCH_DUMP_ATTR
741
742   //----------------------------------------------------------------
743
744   bool CField::isActive(bool atCurrentTimestep /*= false*/) const
745   TRY
746   {
747      if (clientSourceFilter)
748        return atCurrentTimestep ? clientSourceFilter->isDataExpected(CContext::getCurrent()->getCalendar()->getCurrentDate()) : true;
749      else if (storeFilter)
750        return true;
751      else if (instantDataFilter)
752        ERROR("bool CField::isActive(bool atCurrentTimestep)",
753              << "Impossible to check if field [ id = " << getId() << " ] is active as it cannot be used to receive nor send data.");
754
755      return false;
756   }
757   CATCH
758
759   //----------------------------------------------------------------
760
761   bool CField::wasWritten() const
762   TRY
763   {
764     return written;
765   }
766   CATCH
767
768   void CField::setWritten()
769   TRY
770   {
771     written = true;
772   }
773   CATCH_DUMP_ATTR
774
775   //----------------------------------------------------------------
776
777   bool CField::getUseCompressedOutput() const
778   TRY
779   {
780     return useCompressedOutput;
781   }
782   CATCH
783
784   void CField::setUseCompressedOutput()
785   TRY
786   {
787     useCompressedOutput = true;
788   }
789   CATCH_DUMP_ATTR
790
791   //----------------------------------------------------------------
792
793   std::shared_ptr<COutputPin> CField::getInstantDataFilter()
794   TRY
795   {
796     return instantDataFilter;
797   }
798   CATCH_DUMP_ATTR
799
800   //----------------------------------------------------------------
801
802   /*!
803     Build up graph of grids which plays role of destination and source in grid transformation
804     This function should be called before \func solveGridReference()
805   */
806   void CField::buildGridTransformationGraph()
807   TRY
808   {
809     CContext* context = CContext::getCurrent();
810     if (context->hasClient && !context->hasServer)
811     {
812       if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
813       {
814         grid->addTransGridSource(getDirectFieldReference()->grid);
815       }
816     }
817   }
818   CATCH_DUMP_ATTR
819
820   /*!
821     Generate a new grid destination if there are more than one grid source pointing to a same grid destination
822   */
823   void CField::generateNewTransformationGridDest()
824   TRY
825   {
826     CContext* context = CContext::getCurrent();
827     if (context->hasClient && !context->hasServer)
828     {
829       std::map<CGrid*,std::pair<bool,StdString> >& gridSrcMap = grid->getTransGridSource();
830       if (1 < gridSrcMap.size())
831       {
832         // Search for grid source
833         CGrid* gridSrc = grid;
834         CField* currField = this;
835         std::vector<CField*> hieraField;
836
837         while (currField->hasDirectFieldReference() && (gridSrc == grid))
838         {
839           hieraField.push_back(currField);
840           CField* tmp = currField->getDirectFieldReference();
841           currField = tmp;
842           gridSrc = currField->grid;
843         }
844
845         if (gridSrcMap.end() != gridSrcMap.find(gridSrc))
846         {
847           CGrid* gridTmp;
848           std::pair<bool,StdString> newGridDest = gridSrcMap[gridSrc];
849           if (newGridDest.first)
850           {
851             StdString newIdGridDest = newGridDest.second;
852             if (!CGrid::has(newIdGridDest))
853             {
854                ERROR("CGrid* CGrid::generateNewTransformationGridDest()",
855                  << " Something wrong happened! Grid whose id " << newIdGridDest
856                  << "should exist ");
857             }
858             gridTmp = CGrid::get(newIdGridDest);
859           }
860           else
861           {
862             StdString newIdGridDest = CGrid::generateId(gridSrc, grid);
863             gridTmp = CGrid::cloneGrid(newIdGridDest, grid);
864
865             (gridSrcMap[gridSrc]).first = true;
866             (gridSrcMap[gridSrc]).second = newIdGridDest;
867           }
868
869           // Update all descendants
870           for (std::vector<CField*>::iterator it = hieraField.begin(); it != hieraField.end(); ++it)
871           {
872             (*it)->grid = gridTmp;
873             (*it)->updateRef((*it)->grid);
874           }
875         }
876       }
877     }
878   }
879   CATCH_DUMP_ATTR
880
881   void CField::updateRef(CGrid* grid)
882   TRY
883   {
884     if (!grid_ref.isEmpty()) grid_ref.setValue(grid->getId());
885     else
886     {
887       std::vector<CAxis*> axisTmp = grid->getAxis();
888       std::vector<CDomain*> domainTmp = grid->getDomains();
889       if ((1<axisTmp.size()) || (1<domainTmp.size()))
890         ERROR("void CField::updateRef(CGrid* grid)",
891           << "More than one domain or axis is available for domain_ref/axis_ref of field " << this->getId());
892
893       if ((!domain_ref.isEmpty()) && (domainTmp.empty()))
894         ERROR("void CField::updateRef(CGrid* grid)",
895           << "Incoherent between available domain and domain_ref of field " << this->getId());
896       if ((!axis_ref.isEmpty()) && (axisTmp.empty()))
897         ERROR("void CField::updateRef(CGrid* grid)",
898           << "Incoherent between available axis and axis_ref of field " << this->getId());
899
900       if (!domain_ref.isEmpty()) domain_ref.setValue(domainTmp[0]->getId());
901       if (!axis_ref.isEmpty()) axis_ref.setValue(axisTmp[0]->getId());
902     }
903   }
904   CATCH_DUMP_ATTR
905   
906   /*!
907     Solve reference of all enabled fields even the source fields .
908     In this step, we do transformations.
909   */
910   void CField::solveAllEnabledFieldsAndTransform()
911   TRY
912   {
913     CContext* context = CContext::getCurrent();
914     bool hasClient = context->hasClient;
915     bool hasServer = context->hasServer;
916
917     if (!isReferenceSolvedAndTransformed)
918     {
919        isReferenceSolvedAndTransformed = true;
920
921        if (hasClient && !hasServer)
922        {
923          solveRefInheritance(true);
924          if (hasDirectFieldReference()) getDirectFieldReference()->solveAllEnabledFieldsAndTransform();
925        }
926
927        if (hasServer)
928          solveServerOperation();
929
930        solveGridReference();
931
932        if (hasClient && !hasServer)
933       {
934         solveGenerateGrid();
935         buildGridTransformationGraph();
936       }
937
938       solveGridDomainAxisRef(false);
939
940       if (hasClient && !hasServer)
941       {
942         solveTransformedGrid();
943       }
944
945       solveGridDomainAxisRef(false);
946     }
947   }
948   CATCH_DUMP_ATTR
949
950   void CField::checkGridOfEnabledFields()
951   TRY
952   {
953     if (!isGridChecked)
954     {
955       isGridChecked = true;
956       solveCheckMaskIndex(false);
957     }
958   }
959   CATCH_DUMP_ATTR
960
961   void CField::sendGridComponentOfEnabledFields()
962   TRY
963   {
964      solveGridDomainAxisRef(true);
965      // solveCheckMaskIndex(true);
966   }
967   CATCH_DUMP_ATTR
968
969   void CField::sendGridOfEnabledFields()
970   TRY
971   {
972      // solveGridDomainAxisRef(true);
973      solveCheckMaskIndex(true);
974   }   
975   CATCH_DUMP_ATTR
976
977   void CField::solveOnlyReferenceEnabledField(bool doSending2Server)
978   TRY
979   {
980     CContext* context = CContext::getCurrent();
981     if (!isReferenceSolved)
982     {
983        isReferenceSolved = true;
984
985        if (context->hasClient && !context->hasServer)
986        {
987          solveRefInheritance(true);
988          if (hasDirectFieldReference()) getDirectFieldReference()->solveOnlyReferenceEnabledField(false);
989        }
990
991        if (context->hasServer)
992          solveServerOperation();
993
994        solveGridReference();
995        grid->solveDomainAxisRefInheritance(true); // make it again to solve grid reading from file
996
997        if (context->hasClient && !context->hasServer)
998       {
999         solveGenerateGrid();
1000         buildGridTransformationGraph();
1001       }
1002     }
1003   }
1004   CATCH_DUMP_ATTR
1005
1006   void CField::solveAllReferenceEnabledField(bool doSending2Server)
1007   TRY
1008   {
1009     CContext* context = CContext::getCurrent();
1010     solveOnlyReferenceEnabledField(doSending2Server);
1011
1012     if (!areAllReferenceSolved)
1013     {
1014        areAllReferenceSolved = true;
1015       
1016        if (context->hasClient && !context->hasServer)
1017        {
1018          solveRefInheritance(true);
1019          if (hasDirectFieldReference()) getDirectFieldReference()->solveAllReferenceEnabledField(false);
1020        }
1021        else if (context->hasServer)
1022          solveServerOperation();
1023
1024        solveGridReference();
1025     }
1026
1027     solveGridDomainAxisRef(doSending2Server);
1028
1029     if (context->hasClient && !context->hasServer)
1030     {
1031       solveTransformedGrid();
1032     }
1033
1034     solveCheckMaskIndex(doSending2Server);
1035   }
1036   CATCH_DUMP_ATTR
1037
1038   std::map<int, StdSize> CField::getGridAttributesBufferSize(CContextClient* client, bool bufferForWriting /*= "false"*/)
1039   TRY
1040   {
1041     return grid->getAttributesBufferSize(client, bufferForWriting);
1042   }
1043   CATCH_DUMP_ATTR
1044
1045   std::map<int, StdSize> CField::getGridDataBufferSize(CContextClient* client, bool bufferForWriting /*= "false"*/)
1046   TRY
1047   {
1048     return grid->getDataBufferSize(client, getId(), bufferForWriting);
1049   }
1050   CATCH_DUMP_ATTR
1051
1052   size_t CField::getGlobalWrittenSize()
1053   TRY
1054   {
1055     return grid->getGlobalWrittenSize();
1056   }
1057   CATCH_DUMP_ATTR
1058
1059   //----------------------------------------------------------------
1060
1061   void CField::solveServerOperation(void)
1062   TRY
1063   {
1064      CContext* context = CContext::getCurrent();
1065
1066      if (!context->hasServer || !hasOutputFile) return;
1067
1068      if (freq_op.isEmpty())
1069        freq_op.setValue(TimeStep);
1070
1071      if (freq_offset.isEmpty())
1072        freq_offset.setValue(NoneDu);
1073
1074      freq_operation_srv = file->output_freq.getValue();
1075      freq_write_srv     = file->output_freq.getValue();
1076
1077      lastlast_Write_srv = context->getCalendar()->getInitDate();
1078      last_Write_srv     = context->getCalendar()->getInitDate();
1079      last_operation_srv = context->getCalendar()->getInitDate();
1080
1081      const CDuration toffset = freq_operation_srv - freq_offset.getValue() - context->getCalendar()->getTimeStep();
1082      last_operation_srv     = last_operation_srv - toffset;
1083
1084      if (operation.isEmpty())
1085        ERROR("void CField::solveServerOperation(void)",
1086              << "An operation must be defined for field \"" << getId() << "\".");
1087
1088      std::shared_ptr<func::CFunctor> functor;
1089      CArray<double, 1> dummyData;
1090
1091#define DECLARE_FUNCTOR(MType, mtype) \
1092      if (operation.getValue().compare(#mtype) == 0) \
1093      { \
1094        functor.reset(new func::C##MType(dummyData)); \
1095      }
1096
1097#include "functor_type.conf"
1098
1099      if (!functor)
1100        ERROR("void CField::solveServerOperation(void)",
1101              << "\"" << operation << "\" is not a valid operation.");
1102
1103      operationTimeType = functor->timeType();
1104   }
1105   CATCH_DUMP_ATTR
1106
1107   //----------------------------------------------------------------
1108
1109   /*!
1110    * Constructs the graph filter for the field, enabling or not the data output.
1111    * This method should not be called more than once with enableOutput equal to true.
1112    *
1113    * \param gc the garbage collector to use when building the filter graph
1114    * \param enableOutput must be true when the field data is to be
1115    *                     read by the client or/and written to a file
1116    */
1117   void CField::buildFilterGraph(CGarbageCollector& gc, bool enableOutput, Time start_graph, Time end_graph)
1118   TRY
1119   {     
1120     if (!isReferenceSolvedAndTransformed) solveAllEnabledFieldsAndTransform();
1121     if (!isGridChecked) checkGridOfEnabledFields();
1122
1123     const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1124     
1125     const bool buildWorkflowGraph = (!build_workflow_graph.isEmpty() && build_workflow_graph == true);
1126     if(buildWorkflowGraph && this->operation.getValue()=="once") 
1127     {
1128       CDuration tmp_dur = 0;
1129       tmp_dur.timestep = 1;
1130       this->build_workflow_graph_start.setValue(tmp_dur) ;
1131       this->build_workflow_graph_end.setValue(tmp_dur) ;
1132     }
1133     
1134     const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
1135
1136     CContext* context = CContext::getCurrent();
1137     
1138     Time filter_start;
1139     if(!build_workflow_graph_start.isEmpty() && buildWorkflowGraph) filter_start = context->calendar->getInitDate()+build_workflow_graph_start;
1140     else if(build_workflow_graph_start.isEmpty() && buildWorkflowGraph) filter_start = 0;
1141     else filter_start = -1;
1142
1143     Time filter_end;
1144     if(!build_workflow_graph_end.isEmpty() && buildWorkflowGraph) filter_end = context->calendar->getInitDate()+build_workflow_graph_end;
1145     else if(build_workflow_graph_end.isEmpty() && buildWorkflowGraph) filter_end = 9223372036854775807;
1146     else filter_end = -1;
1147
1148     if(this->field_graph_start==-2) this->field_graph_start = filter_start;
1149     if(this->field_graph_end==-2) this->field_graph_end = filter_end;         // init
1150
1151
1152     if(start_graph == -1)
1153     {
1154       //nothing
1155     }
1156     else //if(start_graph != -1)
1157     {
1158       if(this->field_graph_start == -1) this->field_graph_start = start_graph;
1159       else this->field_graph_start = min(this->field_graph_start, start_graph);
1160     }
1161
1162
1163     if(end_graph == -1)
1164     {
1165       //nothing
1166     }
1167     else
1168     {
1169       if(this->field_graph_end == -1) this->field_graph_end = end_graph;
1170       else this->field_graph_end = max(this->field_graph_end, end_graph);
1171
1172     }
1173   
1174
1175     filter_start = this->field_graph_start;
1176     filter_end = this->field_graph_end;
1177
1178     
1179
1180     bool hasWriterServer = context->hasServer && !context->hasClient;
1181     bool hasIntermediateServer = context->hasServer && context->hasClient;
1182
1183     if (hasWriterServer)
1184     {
1185        if (!instantDataFilter)
1186          instantDataFilter = clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, false));
1187
1188
1189       // If the field data is to be read by the client or/and written to a file
1190       if (enableOutput && !storeFilter && !fileWriterFilter)
1191       {
1192         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
1193         {
1194           fileServerWriterFilter = std::shared_ptr<CFileServerWriterFilter>(new CFileServerWriterFilter(gc, this));
1195           instantDataFilter->connectOutput(fileServerWriterFilter, 0);
1196         }
1197       }
1198     }
1199     else if (hasIntermediateServer)
1200     {
1201       if (!instantDataFilter)
1202         instantDataFilter = clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, false, false));
1203
1204             // If the field data is to be read by the client or/and written to a file
1205       if (enableOutput && !storeFilter && !fileWriterFilter)
1206       {
1207         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
1208         {
1209           fileWriterFilter = std::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
1210           instantDataFilter->connectOutput(fileWriterFilter, 0);
1211         }
1212       }
1213     }
1214     else
1215     {
1216       // Start by building a filter which can provide the field's instant data
1217       if (!instantDataFilter)
1218       {
1219         // Check if we have an expression to parse
1220         if (hasExpression())
1221         {
1222           boost::scoped_ptr<IFilterExprNode> expr(parseExpr(getExpression() + '\0'));
1223           std::shared_ptr<COutputPin> filter = expr->reduce(gc, *this, filter_start, filter_end);
1224
1225           // Check if a spatial transformation is needed
1226           if (!field_ref.isEmpty())
1227           {
1228             CGrid* gridRef = CField::get(field_ref)->grid;
1229
1230             if (grid && grid != gridRef && grid->hasTransform())
1231             {
1232               std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters = CSpatialTransformFilter::buildFilterGraph(gc, gridRef, grid, detectMissingValues, defaultValue);
1233
1234               filter->connectOutput(filters.first, 0);
1235               filter = filters.second;
1236             }
1237           }
1238
1239           instantDataFilter = filter;
1240           instantDataFilter->field = this;
1241           filter->tag = buildWorkflowGraph;
1242           
1243           filter->start_graph = filter_start;
1244           filter->end_graph = filter_end;
1245
1246           for(int i=0; i<filter->parent_filters.size(); i++)
1247           {
1248             filter->tag = filter->tag || filter->parent_filters[i]->tag;
1249           }
1250         }
1251         // Check if we have a reference on another field
1252         else if (!field_ref.isEmpty())
1253         {
1254           instantDataFilter = getFieldReference(gc, filter_start, filter_end);
1255           instantDataFilter->tag = buildWorkflowGraph;
1256           instantDataFilter->start_graph = filter_start;
1257           instantDataFilter->end_graph = filter_end;
1258         }
1259         // Check if the data is to be read from a file
1260         else if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
1261         {
1262           checkTimeAttributes();
1263           instantDataFilter = serverSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, false, freq_offset, true,
1264                                                                                                       detectMissingValues, defaultValue));
1265           instantDataFilter->tag = buildWorkflowGraph;
1266           instantDataFilter->start_graph = filter_start;
1267           instantDataFilter->end_graph = filter_end;
1268           instantDataFilter->field = this;
1269
1270         }
1271         else // The data might be passed from the model
1272         {
1273            if (check_if_active.isEmpty()) check_if_active = false; 
1274            instantDataFilter = clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, false, true, NoneDu, false,
1275                                                                                                      detectMissingValues, defaultValue)); 
1276            instantDataFilter->tag = buildWorkflowGraph;
1277            instantDataFilter->start_graph = filter_start;
1278            instantDataFilter->end_graph = filter_end;
1279            instantDataFilter->field = this;
1280         }
1281       }
1282
1283       // If the field data is to be read by the client or/and written to a file
1284       if (enableOutput && !storeFilter && !fileWriterFilter)
1285       {
1286         if (!read_access.isEmpty() && read_access)
1287         {
1288           storeFilter = std::shared_ptr<CStoreFilter>(new CStoreFilter(gc, CContext::getCurrent(), grid,
1289                                                                          detectMissingValues, defaultValue));
1290           instantDataFilter->connectOutput(storeFilter, 0);
1291
1292           storeFilter->tag = (instantDataFilter->tag || buildWorkflowGraph);
1293           instantDataFilter->start_graph = filter_start;
1294           instantDataFilter->end_graph = filter_end;
1295
1296           instantDataFilter->setParentFiltersTag();
1297           storeFilter->start_graph = filter_start;
1298           storeFilter->end_graph = filter_end;
1299           storeFilter->field = this;
1300           storeFilter->distance = instantDataFilter->distance+1;
1301         }
1302
1303         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
1304         {
1305           fileWriterFilter = std::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
1306           getTemporalDataFilter(gc, file->output_freq)->connectOutput(fileWriterFilter, 0);
1307           
1308           fileWriterFilter->tag = (getTemporalDataFilter(gc, file->output_freq)->tag || buildWorkflowGraph);
1309           getTemporalDataFilter(gc, file->output_freq)->start_graph = filter_start;
1310           getTemporalDataFilter(gc, file->output_freq)->end_graph = filter_end;
1311           getTemporalDataFilter(gc, file->output_freq)->tag = buildWorkflowGraph;
1312           getTemporalDataFilter(gc, file->output_freq)->setParentFiltersTag();
1313           fileWriterFilter->start_graph = filter_start;
1314           fileWriterFilter->end_graph = filter_end;
1315           fileWriterFilter->distance = getTemporalDataFilter(gc, file->output_freq)->distance+1;
1316
1317
1318         }
1319       }
1320     }
1321   }
1322   CATCH_DUMP_ATTR
1323
1324   /*!
1325    * Returns the filter needed to handle the field reference.
1326    * This method should only be called when building the filter graph corresponding to the field.
1327    *
1328    * \param gc the garbage collector to use
1329    * \return the output pin corresponding to the field reference
1330    */
1331   std::shared_ptr<COutputPin> CField::getFieldReference(CGarbageCollector& gc, Time start_graph, Time end_graph)
1332   TRY
1333   {
1334     if (instantDataFilter || field_ref.isEmpty())
1335       ERROR("COutputPin* CField::getFieldReference(CGarbageCollector& gc)",
1336             "Impossible to get the field reference for a field which has already been parsed or which does not have a field_ref.");
1337
1338     CField* fieldRef = CField::get(field_ref);
1339     fieldRef->buildFilterGraph(gc, false, start_graph, end_graph);
1340     const bool buildWorkflowGraph = (!build_workflow_graph.isEmpty() && build_workflow_graph == true);
1341
1342     CContext* context = CContext::getCurrent();
1343
1344     Time filter_start;
1345     if(!build_workflow_graph_start.isEmpty() && buildWorkflowGraph) filter_start = context->calendar->getInitDate()+build_workflow_graph_start;
1346     else if(build_workflow_graph_start.isEmpty() && buildWorkflowGraph) filter_start = 0;
1347     else filter_start = -1;
1348
1349     Time filter_end;
1350     if(!build_workflow_graph_end.isEmpty() && buildWorkflowGraph) filter_end = context->calendar->getInitDate()+build_workflow_graph_end;
1351     else if(build_workflow_graph_end.isEmpty() && buildWorkflowGraph) filter_end = 9223372036854775807;
1352     else filter_end = -1;
1353
1354     if(this->field_graph_start==-2) this->field_graph_start = filter_start;
1355     if(this->field_graph_end==-2) this->field_graph_end = filter_end;         // init
1356
1357
1358     if(start_graph == -1)
1359     {
1360       //nothing
1361     }
1362     else //if(start_graph != -1)
1363     {
1364       if(this->field_graph_start == -1) this->field_graph_start = start_graph;
1365       else this->field_graph_start = min(this->field_graph_start, start_graph);
1366     }
1367
1368     if(end_graph == -1)
1369     {
1370       //nothing
1371     }
1372     else
1373     {
1374       if(this->field_graph_end == -1) this->field_graph_end = end_graph;
1375       else this->field_graph_end = max(this->field_graph_end, end_graph);
1376     }
1377
1378     filter_start = this->field_graph_start;
1379     filter_end = this->field_graph_end;
1380
1381
1382     std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters;
1383     // Check if a spatial transformation is needed
1384     if (grid && grid != fieldRef->grid && grid->hasTransform())
1385     {       
1386       bool hasMissingValue = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1387       double defaultValue  = hasMissingValue ? default_value : (!default_value.isEmpty() ? default_value : 0.0);                               
1388       filters = CSpatialTransformFilter::buildFilterGraph(gc, fieldRef->grid, grid, hasMissingValue, defaultValue);
1389
1390       fieldRef->getInstantDataFilter()->connectOutput(filters.first, 0);
1391
1392     
1393
1394       filters.second->parent_filters.resize(1);
1395       filters.second->parent_filters[0]= fieldRef->getInstantDataFilter();
1396
1397       filters.second->tag = (buildWorkflowGraph || filters.second->parent_filters[0]->tag);
1398       
1399       filters.second->start_graph = filter_start;
1400       filters.second->end_graph = filter_end;
1401       filters.second->field = this;
1402       
1403     }
1404     else
1405     {
1406       filters.first = filters.second = std::shared_ptr<CFilter>(new CPassThroughFilter(gc));
1407
1408       fieldRef->getInstantDataFilter()->connectOutput(filters.first, 0);
1409     
1410
1411       filters.second->parent_filters.resize(1);
1412       filters.second->parent_filters[0]= fieldRef->getInstantDataFilter();
1413
1414       filters.second->tag = (buildWorkflowGraph || filters.second->parent_filters[0]->tag);
1415
1416       filters.second->start_graph = filter_start;
1417       filters.second->end_graph = filter_end;
1418       filters.second->field = this;
1419
1420     }
1421
1422     return filters.second;
1423   }
1424   CATCH_DUMP_ATTR
1425
1426   /*!
1427    * Returns the filter needed to handle a self reference in the field's expression.
1428    * If the needed filter does not exist, it is created, otherwise it is reused.
1429    * This method should only be called when building the filter graph corresponding
1430    * to the field's expression.
1431    *
1432    * \param gc the garbage collector to use
1433    * \return the output pin corresponding to a self reference
1434    */
1435   std::shared_ptr<COutputPin> CField::getSelfReference(CGarbageCollector& gc, Time start_graph, Time end_graph)
1436   TRY
1437   {
1438
1439     if (instantDataFilter || !hasExpression())
1440       ERROR("COutputPin* CField::getSelfReference(CGarbageCollector& gc)",
1441             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1442     
1443     bool buildWorkflowGraph = (!build_workflow_graph.isEmpty() && build_workflow_graph == true);
1444
1445     if (!selfReferenceFilter)
1446     {
1447       const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1448       const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
1449
1450       if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
1451       {
1452         if (!serverSourceFilter)
1453         {
1454           checkTimeAttributes();
1455           serverSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, false, freq_offset, true,
1456                                                                                   detectMissingValues, defaultValue));
1457         }
1458
1459         selfReferenceFilter = serverSourceFilter;
1460       }
1461       else if (!field_ref.isEmpty())
1462       {
1463         CField* fieldRef = CField::get(field_ref);
1464         fieldRef->buildFilterGraph(gc, false);
1465         selfReferenceFilter = fieldRef->getInstantDataFilter();
1466       }
1467       else
1468       {
1469         if (!clientSourceFilter)
1470         {
1471           if (check_if_active.isEmpty()) check_if_active = false;
1472           clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, true, NoneDu, false,
1473                                                                                   detectMissingValues, defaultValue));
1474         }
1475
1476         selfReferenceFilter = clientSourceFilter;
1477       }
1478     }
1479
1480     selfReferenceFilter->tag = buildWorkflowGraph;
1481     selfReferenceFilter->field = this;
1482     return selfReferenceFilter;
1483   }
1484   CATCH_DUMP_ATTR
1485
1486   /*!
1487    * Returns the temporal filter corresponding to the field's temporal operation
1488    * for the specified operation frequency. The filter is created if it does not
1489    * exist, otherwise it is reused.
1490    *
1491    * \param gc the garbage collector to use
1492    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1493    * \return the output pin corresponding to the requested temporal filter
1494    */
1495   std::shared_ptr<COutputPin> CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1496   TRY
1497   {
1498     std::map<CDuration, std::shared_ptr<COutputPin> >::iterator it = temporalDataFilters.find(outFreq);
1499     const bool buildWorkflowGraph = (!build_workflow_graph.isEmpty() && build_workflow_graph == true);
1500
1501     CContext* context = CContext::getCurrent();
1502
1503
1504     if (it == temporalDataFilters.end())
1505     {
1506       if (operation.isEmpty())
1507         ERROR("void CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1508               << "An operation must be defined for field \"" << getId() << "\".");
1509
1510       checkTimeAttributes(&outFreq);
1511
1512       const bool detectMissingValues = (!detect_missing_value.isEmpty()  && detect_missing_value == true);
1513       std::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1514                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
1515                                                                             freq_op, freq_offset, outFreq, detectMissingValues));
1516
1517       instantDataFilter->connectOutput(temporalFilter, 0);
1518       
1519       temporalFilter->parent_filters.resize(1);
1520       temporalFilter->parent_filters[0] = instantDataFilter;
1521       
1522
1523       temporalFilter->tag = temporalFilter->parent_filters[0]->tag;
1524       temporalFilter->start_graph = temporalFilter->parent_filters[0]->start_graph;
1525       temporalFilter->end_graph = temporalFilter->parent_filters[0]->end_graph;
1526
1527       temporalFilter->field = this;
1528
1529       it = temporalDataFilters.insert(std::make_pair(outFreq, temporalFilter)).first;
1530     }
1531
1532     return it->second;
1533   }
1534   CATCH_DUMP_ATTR
1535
1536  /*!
1537    * Returns the temporal filter corresponding to the field's temporal operation
1538    * for the specified operation frequency.
1539    *
1540    * \param gc the garbage collector to use
1541    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1542    * \return the output pin corresponding to the requested temporal filter
1543    */
1544   
1545   std::shared_ptr<COutputPin> CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1546   TRY
1547   {
1548     if (instantDataFilter || !hasExpression())
1549       ERROR("COutputPin* CField::getSelfTemporalDataFilter(CGarbageCollector& gc)",
1550             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1551
1552     if (!selfReferenceFilter) getSelfReference(gc) ;
1553
1554     if (serverSourceFilter || clientSourceFilter)
1555     {
1556       if (operation.isEmpty())
1557         ERROR("void CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1558               << "An operation must be defined for field \"" << getId() << "\".");
1559
1560       checkTimeAttributes(&outFreq);
1561
1562       const bool detectMissingValues = (!detect_missing_value.isEmpty() && detect_missing_value == true);
1563       bool buildWorkflowGraph = (!build_workflow_graph.isEmpty() && build_workflow_graph == true);
1564       std::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1565                                                                           CContext::getCurrent()->getCalendar()->getInitDate(),
1566                                                                           freq_op, freq_offset, outFreq, detectMissingValues));
1567
1568       selfReferenceFilter->connectOutput(temporalFilter, 0);
1569       temporalFilter->tag = buildWorkflowGraph;
1570       temporalFilter->field = this;
1571
1572       return temporalFilter ;
1573     }
1574     else if (!field_ref.isEmpty())
1575     {
1576       CField* fieldRef = CField::get(field_ref);
1577       fieldRef->buildFilterGraph(gc, false); 
1578       return fieldRef->getTemporalDataFilter(gc, outFreq) ;
1579     }
1580  }
1581   CATCH_DUMP_ATTR
1582
1583   //----------------------------------------------------------------
1584/*
1585   void CField::fromBinary(StdIStream& is)
1586   {
1587      SuperClass::fromBinary(is);
1588#define CLEAR_ATT(name_)\
1589      SuperClassAttribute::operator[](#name_)->reset()
1590
1591         CLEAR_ATT(domain_ref);
1592         CLEAR_ATT(axis_ref);
1593#undef CLEAR_ATT
1594
1595   }
1596*/
1597   //----------------------------------------------------------------
1598
1599   void CField::solveGridReference(void)
1600   TRY
1601   {
1602      if (grid_ref.isEmpty() && domain_ref.isEmpty() && axis_ref.isEmpty() && scalar_ref.isEmpty())
1603      {
1604        ERROR("CField::solveGridReference(void)",
1605              << "A grid must be defined for field '" << getFieldOutputName() << "' .");
1606      }
1607      else if (!grid_ref.isEmpty() && (!domain_ref.isEmpty() || !axis_ref.isEmpty() || !scalar_ref.isEmpty()))
1608      {
1609        ERROR("CField::solveGridReference(void)",
1610              << "Field '" << getFieldOutputName() << "' has both a grid and a domain/axis/scalar." << std::endl
1611              << "Please define either 'grid_ref' or 'domain_ref'/'axis_ref'/'scalar_ref'.");
1612      }
1613
1614      if (grid_ref.isEmpty())
1615      {
1616        std::vector<CDomain*> vecDom;
1617        std::vector<CAxis*> vecAxis;
1618        std::vector<CScalar*> vecScalar;
1619        std::vector<int> axisDomainOrderTmp;
1620
1621        std::vector<CDomain*> vecDomRef;
1622        std::vector<CAxis*> vecAxisRef;
1623        std::vector<CScalar*> vecScalarRef;
1624
1625       
1626        if (!domain_ref.isEmpty())
1627        {
1628          StdString tmp = domain_ref.getValue();
1629          if (CDomain::has(domain_ref))
1630          {
1631            vecDom.push_back(CDomain::get(domain_ref));
1632            vecDomRef.push_back(CDomain::createDomain());
1633            vecDomRef.back()->domain_ref=domain_ref;
1634            axisDomainOrderTmp.push_back(2);
1635          }
1636          else  ERROR("CField::solveGridReference(void)",
1637                      << "Invalid reference to domain '" << domain_ref.getValue() << "'.");
1638        }
1639
1640        if (!axis_ref.isEmpty())
1641        {
1642          if (CAxis::has(axis_ref))
1643          {
1644            vecAxis.push_back(CAxis::get(axis_ref));
1645            vecAxisRef.push_back(CAxis::createAxis());
1646            vecAxisRef.back()->axis_ref=axis_ref;
1647            axisDomainOrderTmp.push_back(1);
1648          }
1649          else  ERROR("CField::solveGridReference(void)",
1650                      << "Invalid reference to axis '" << axis_ref.getValue() << "'.");
1651        }
1652
1653        if (!scalar_ref.isEmpty())
1654        {
1655          if (CScalar::has(scalar_ref))
1656          {
1657            vecScalar.push_back(CScalar::get(scalar_ref));
1658            vecScalarRef.push_back(CScalar::createScalar());
1659            vecScalarRef.back()->scalar_ref=scalar_ref;
1660            axisDomainOrderTmp.push_back(0);
1661          }
1662          else ERROR("CField::solveGridReference(void)",
1663                     << "Invalid reference to scalar '" << scalar_ref.getValue() << "'.");
1664        }
1665       
1666        CArray<int,1> axisDomainOrder(axisDomainOrderTmp.size());
1667        for (int idx = 0; idx < axisDomainOrderTmp.size(); ++idx)
1668        {
1669          axisDomainOrder(idx) = axisDomainOrderTmp[idx];
1670        }
1671
1672        // Warning: the gridId shouldn't be set as the grid_ref since it could be inherited
1673        StdString gridId = CGrid::generateId(vecDom, vecAxis, vecScalar,axisDomainOrder);
1674        if (CGrid::has(gridId)) this->grid = CGrid::get(gridId);
1675        else  this->grid = CGrid::createGrid(gridId, vecDomRef, vecAxisRef, vecScalarRef,axisDomainOrder);
1676      }
1677      else
1678      {
1679        if (CGrid::has(grid_ref)) this->grid = CGrid::get(grid_ref);
1680        else  ERROR("CField::solveGridReference(void)",
1681                     << "Invalid reference to grid '" << grid_ref.getValue() << "'.");
1682      }
1683   }
1684   CATCH_DUMP_ATTR
1685
1686   void CField::solveGridDomainAxisRef(bool checkAtt)
1687   TRY
1688   {
1689     grid->solveDomainAxisRef(checkAtt);
1690   }
1691   CATCH_DUMP_ATTR
1692
1693   void CField::solveCheckMaskIndex(bool doSendingIndex)
1694   TRY
1695   {
1696     grid->checkMaskIndex(doSendingIndex);
1697   }
1698   CATCH_DUMP_ATTR
1699
1700   void CField::solveTransformedGrid()
1701   TRY
1702   {
1703     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
1704     {
1705       std::vector<CGrid*> grids;
1706       // Source grid
1707       grids.push_back(getDirectFieldReference()->grid);
1708       // Intermediate grids
1709       if (!grid_path.isEmpty())
1710       {
1711         std::string gridId;
1712         size_t start = 0, end;
1713
1714         do
1715         {
1716           end = grid_path.getValue().find(',', start);
1717           if (end != std::string::npos)
1718           {
1719             gridId = grid_path.getValue().substr(start, end - start);
1720             start = end + 1;
1721           }
1722           else
1723             gridId = grid_path.getValue().substr(start);
1724
1725           if (!CGrid::has(gridId))
1726             ERROR("void CField::solveTransformedGrid()",
1727                   << "Invalid grid_path, the grid '" << gridId << "' does not exist.");
1728
1729           grids.push_back(CGrid::get(gridId));
1730         }
1731         while (end != std::string::npos);
1732       }
1733       // Destination grid
1734       grids.push_back(grid);
1735
1736       for (size_t i = 0, count = grids.size() - 1; i < count; ++i)
1737       {
1738         CGrid *gridSrc  = grids[i];
1739         CGrid *gridDest = grids[i + 1];
1740         if (!gridDest->isTransformed())
1741           gridDest->transformGrid(gridSrc);
1742       }
1743     }
1744     else if (grid && grid->hasTransform() && !grid->isTransformed())
1745     {
1746       // Temporarily deactivate the self-transformation of grid
1747       // grid->transformGrid(grid);
1748     }
1749   }
1750   CATCH_DUMP_ATTR
1751
1752   void CField::solveGenerateGrid()
1753   TRY
1754   {
1755     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
1756       grid->completeGrid(getDirectFieldReference()->grid);
1757     else
1758       grid->completeGrid();
1759   }
1760   CATCH_DUMP_ATTR
1761
1762   void CField::solveGridDomainAxisBaseRef()
1763   TRY
1764   {
1765     grid->solveDomainAxisRef(false);
1766     grid->solveDomainAxisBaseRef();
1767   }
1768   CATCH_DUMP_ATTR
1769
1770   ///-------------------------------------------------------------------
1771
1772   template <>
1773   void CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)
1774   TRY
1775   {
1776      if (this->group_ref.isEmpty()) return;
1777      StdString gref = this->group_ref.getValue();
1778
1779      if (!CFieldGroup::has(gref))
1780         ERROR("CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)",
1781               << "[ gref = " << gref << "]"
1782               << " invalid group name !");
1783
1784      CFieldGroup* group = CFieldGroup::get(gref);
1785      CFieldGroup* owner = CFieldGroup::get(boost::polymorphic_downcast<CFieldGroup*>(this));
1786      owner->setAttributes(group); // inherite of attributes of group reference
1787     
1788      std::vector<CField*> allChildren  = group->getAllChildren();
1789      std::vector<CField*>::iterator it = allChildren.begin(), end = allChildren.end();
1790
1791      for (; it != end; it++)
1792      {
1793         CField* child = *it;
1794         if (child->hasId()) owner->createChild()->field_ref.setValue(child->getId());
1795
1796      }
1797   }
1798   CATCH_DUMP_ATTR
1799
1800   void CField::scaleFactorAddOffset(double scaleFactor, double addOffset)
1801   TRY
1802   {
1803     recvDataSrv = (recvDataSrv - addOffset) / scaleFactor;
1804   }
1805   CATCH_DUMP_ATTR
1806
1807   void CField::invertScaleFactorAddOffset(double scaleFactor, double addOffset)
1808   TRY
1809   {
1810     recvDataSrv = recvDataSrv * scaleFactor + addOffset;
1811   }
1812   CATCH_DUMP_ATTR
1813
1814   void CField::outputField(CArray<double,1>& fieldOut)
1815   TRY
1816   { 
1817      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1818      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1819      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1820      {
1821        fieldOut(outIndexServer(idx)) = recvDataSrv(outIndexClient(idx));
1822      }
1823   }
1824   CATCH_DUMP_ATTR
1825
1826   void CField::inputField(CArray<double,1>& fieldIn)
1827   TRY
1828   {
1829      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1830      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1831      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1832      {
1833        recvDataSrv(outIndexClient(idx)) = fieldIn(outIndexServer(idx));
1834      }
1835   }
1836   CATCH_DUMP_ATTR
1837
1838   void CField::outputCompressedField(CArray<double,1>& fieldOut)
1839   TRY
1840   {
1841      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1842      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1843      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1844      {
1845        fieldOut((idx)) = recvDataSrv(outIndexClient(idx));
1846      }
1847   }
1848   CATCH_DUMP_ATTR
1849
1850   ///-------------------------------------------------------------------
1851
1852   void CField::parse(xml::CXMLNode& node)
1853   TRY
1854   {
1855      string newContent ;
1856      SuperClass::parse(node);
1857      if (node.goToChildElement())
1858      {
1859        do
1860        {
1861          if (node.getElementName() == "variable" || node.getElementName() == "variable_group") this->getVirtualVariableGroup()->parseChild(node);
1862          else if (node.getElementName() == "expr") if (node.getContent(newContent)) content+=newContent ;
1863        } while (node.goToNextElement());
1864        node.goToParentElement();
1865      }
1866      if (node.getContent(newContent)) content=newContent ;
1867    }
1868   CATCH_DUMP_ATTR
1869
1870   /*!
1871     This function retrieves Id of corresponding domain_ref and axis_ref (if any)
1872   of a field. In some cases, only domain exists but axis doesn't
1873   \return pair of Domain and Axis id
1874   */
1875   const std::vector<StdString>& CField::getRefDomainAxisIds()
1876   TRY
1877   {
1878     CGrid* cgPtr = getRelGrid();
1879     if (NULL != cgPtr)
1880     {
1881       std::vector<StdString>::iterator it;
1882       if (!domain_ref.isEmpty())
1883       {
1884         std::vector<StdString> domainList = cgPtr->getDomainList();
1885         it = std::find(domainList.begin(), domainList.end(), domain_ref.getValue());
1886         if (domainList.end() != it) domAxisScalarIds_[0] = *it;
1887       }
1888
1889       if (!axis_ref.isEmpty())
1890       {
1891         std::vector<StdString> axisList = cgPtr->getAxisList();
1892         it = std::find(axisList.begin(), axisList.end(), axis_ref.getValue());
1893         if (axisList.end() != it) domAxisScalarIds_[1] = *it;
1894       }
1895
1896       if (!scalar_ref.isEmpty())
1897       {
1898         std::vector<StdString> scalarList = cgPtr->getScalarList();
1899         it = std::find(scalarList.begin(), scalarList.end(), scalar_ref.getValue());
1900         if (scalarList.end() != it) domAxisScalarIds_[2] = *it;
1901       }
1902     }
1903     return (domAxisScalarIds_);
1904   }
1905   CATCH_DUMP_ATTR
1906
1907   CVariable* CField::addVariable(const string& id)
1908   TRY
1909   {
1910     return vVariableGroup->createChild(id);
1911   }
1912   CATCH
1913
1914   CVariableGroup* CField::addVariableGroup(const string& id)
1915   TRY
1916   {
1917     return vVariableGroup->createChildGroup(id);
1918   }
1919   CATCH
1920
1921   void CField::setContextClient(CContextClient* contextClient)
1922   TRY
1923   {
1924     CContext* context = CContext::getCurrent();
1925     client = contextClient;
1926     if (context->hasClient)
1927     {
1928       // A grid is sent by a client (both for read or write) or by primary server (write only)
1929       if (context->hasServer)
1930       {
1931         if (file->mode.isEmpty() || (!file->mode.isEmpty() && file->mode == CFile::mode_attr::write))
1932           grid->setContextClient(contextClient);
1933       }
1934       else
1935           grid->setContextClient(contextClient);
1936     }
1937   }
1938   CATCH_DUMP_ATTR
1939
1940   CContextClient* CField::getContextClient()
1941   TRY
1942   {
1943     return client;
1944   }
1945   CATCH
1946
1947   void CField::sendAddAllVariables(CContextClient* client)
1948   TRY
1949   {
1950     std::vector<CVariable*> allVar = getAllVariables();
1951     std::vector<CVariable*>::const_iterator it = allVar.begin();
1952     std::vector<CVariable*>::const_iterator itE = allVar.end();
1953
1954     for (; it != itE; ++it)
1955     {
1956       this->sendAddVariable((*it)->getId(), client);
1957       (*it)->sendAllAttributesToServer(client);
1958       (*it)->sendValue(client);
1959     }
1960   }
1961   CATCH_DUMP_ATTR
1962
1963   /*!
1964    * Send all Attributes to server. This method is overloaded, since only grid_ref attribute
1965    * must be sent to server and not domain_ref/axis_ref/scalar_ref.
1966    */
1967   
1968   void CField::sendAllAttributesToServer(CContextClient* client)
1969   TRY
1970   {
1971     if (grid_ref.isEmpty())
1972     {
1973       grid_ref=grid->getId() ;
1974       SuperClass::sendAllAttributesToServer(client) ;
1975       grid_ref.reset();
1976     }
1977     else SuperClass::sendAllAttributesToServer(client) ;
1978   }
1979   CATCH_DUMP_ATTR
1980   
1981   void CField::sendAddVariable(const string& id, CContextClient* client)
1982   TRY
1983   {
1984      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE, client);
1985   }
1986   CATCH_DUMP_ATTR
1987
1988   void CField::sendAddVariableGroup(const string& id, CContextClient* client)
1989   TRY
1990   {
1991      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE_GROUP, client);
1992   }
1993   CATCH_DUMP_ATTR
1994
1995   void CField::recvAddVariable(CEventServer& event)
1996   TRY
1997   {
1998
1999      CBufferIn* buffer = event.subEvents.begin()->buffer;
2000      string id;
2001      *buffer >> id;
2002      get(id)->recvAddVariable(*buffer);
2003   }
2004   CATCH
2005
2006   void CField::recvAddVariable(CBufferIn& buffer)
2007   TRY
2008   {
2009      string id;
2010      buffer >> id;
2011      addVariable(id);
2012   }
2013   CATCH_DUMP_ATTR
2014
2015   void CField::recvAddVariableGroup(CEventServer& event)
2016   TRY
2017   {
2018
2019      CBufferIn* buffer = event.subEvents.begin()->buffer;
2020      string id;
2021      *buffer >> id;
2022      get(id)->recvAddVariableGroup(*buffer);
2023   }
2024   CATCH
2025
2026   void CField::recvAddVariableGroup(CBufferIn& buffer)
2027   TRY
2028   {
2029      string id;
2030      buffer >> id;
2031      addVariableGroup(id);
2032   }
2033   CATCH_DUMP_ATTR
2034
2035   /*!
2036    * Check on freq_off and freq_op attributes.
2037    */
2038   void CField::checkTimeAttributes(CDuration* freqOp)
2039   TRY
2040   {
2041     bool isFieldRead  = file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read;
2042     bool isFieldWrite = file && ( file->mode.isEmpty() ||  file->mode == CFile::mode_attr::write);
2043     if (isFieldRead && !(operation.getValue() == "instant" || operation.getValue() == "once") )     
2044       ERROR("void CField::checkTimeAttributes(void)",
2045             << "Unsupported operation for field '" << getFieldOutputName() << "'." << std::endl
2046             << "Currently only \"instant\" is supported for fields read from file.")
2047
2048     if (freq_op.isEmpty())
2049     {
2050       if (operation.getValue() == "instant")
2051       {
2052         if (isFieldRead || isFieldWrite) freq_op.setValue(file->output_freq.getValue());
2053         else freq_op=*freqOp ;
2054       }
2055       else
2056         freq_op.setValue(TimeStep);
2057     }
2058     else
2059     {
2060       //if(file->output_freq.getValue() < freq_op.getValue())
2061       if((isFieldRead || isFieldWrite) && (file!=nullptr) && (freq_op.getValue() > file->output_freq.getValue() ))
2062       {
2063         ERROR("void CField::checkTimeAttributes(void)",
2064               << "output file has output_freq < freq_op" << std::endl
2065               << "field_id = "<< getId() << std::endl
2066               << "file_id = "<< file->getId() << std::endl
2067               << "output_freq = "<< file->output_freq.getValue() << std::endl
2068               << "freq_op = "<< freq_op.getValue() << std::endl)
2069       }
2070     }
2071     if (freq_offset.isEmpty())
2072       freq_offset.setValue(isFieldRead ? NoneDu : (freq_op.getValue() - TimeStep));
2073   }
2074   CATCH_DUMP_ATTR
2075
2076   /*!
2077    * Returns string arithmetic expression associated to the field.
2078    * \return if content is defined return content string, otherwise, if "expr" attribute is defined, return expr string.
2079    */
2080   const string& CField::getExpression(void)
2081   TRY
2082   {
2083     if (!expr.isEmpty() && content.empty())
2084     {
2085       content = expr;
2086       expr.reset();
2087     }
2088
2089     return content;
2090   }
2091   CATCH_DUMP_ATTR
2092
2093   bool CField::hasExpression(void) const
2094   TRY
2095   {
2096     return (!expr.isEmpty() || !content.empty());
2097   }
2098   CATCH
2099
2100   bool CField::hasGridMask(void) const
2101   TRY
2102   {
2103     return (this->grid->hasMask());
2104   }
2105   CATCH
2106
2107   DEFINE_REF_FUNC(Field,field)
2108} // namespace xios
Note: See TracBrowser for help on using the repository browser.