source: XIOS/dev/dev_ym/XIOS_COUPLING/src/node/field.cpp @ 1869

Last change on this file since 1869 was 1869, checked in by ymipsl, 19 months ago

Some update...

YM

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