source: XIOS/dev/dev_oa/src/node/field.cpp @ 1989

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

Bugfix: adding a check on file pointer

  • 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.2 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
1127     
1128     const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
1129
1130     CContext* context = CContext::getCurrent();
1131     
1132     Time filter_start;
1133     if(!build_workflow_graph_start.isEmpty() && buildWorkflowGraph) filter_start = context->calendar->getInitDate()+build_workflow_graph_start;
1134     else if(build_workflow_graph_start.isEmpty() && buildWorkflowGraph) filter_start = 0;
1135     else filter_start = -1;
1136
1137     Time filter_end;
1138     if(!build_workflow_graph_end.isEmpty() && buildWorkflowGraph) filter_end = context->calendar->getInitDate()+build_workflow_graph_end;
1139     else if(build_workflow_graph_end.isEmpty() && buildWorkflowGraph) filter_end = 9223372036854775807;
1140     else filter_end = -1;
1141
1142     if(this->field_graph_start==-2) this->field_graph_start = filter_start;
1143     if(this->field_graph_end==-2) this->field_graph_end = filter_end;         // init
1144
1145
1146     if(start_graph == -1)
1147     {
1148       //nothing
1149     }
1150     else //if(start_graph != -1)
1151     {
1152       if(this->field_graph_start == -1) this->field_graph_start = start_graph;
1153       else this->field_graph_start = min(this->field_graph_start, start_graph);
1154     }
1155
1156
1157     if(end_graph == -1)
1158     {
1159       //nothing
1160     }
1161     else
1162     {
1163       if(this->field_graph_end == -1) this->field_graph_end = end_graph;
1164       else this->field_graph_end = max(this->field_graph_end, end_graph);
1165
1166     }
1167   
1168
1169     filter_start = this->field_graph_start;
1170     filter_end = this->field_graph_end;
1171
1172     
1173
1174     bool hasWriterServer = context->hasServer && !context->hasClient;
1175     bool hasIntermediateServer = context->hasServer && context->hasClient;
1176
1177     if (hasWriterServer)
1178     {
1179        if (!instantDataFilter)
1180          instantDataFilter = clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, false));
1181
1182
1183       // If the field data is to be read by the client or/and written to a file
1184       if (enableOutput && !storeFilter && !fileWriterFilter)
1185       {
1186         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
1187         {
1188           fileServerWriterFilter = std::shared_ptr<CFileServerWriterFilter>(new CFileServerWriterFilter(gc, this));
1189           instantDataFilter->connectOutput(fileServerWriterFilter, 0);
1190         }
1191       }
1192     }
1193     else if (hasIntermediateServer)
1194     {
1195       if (!instantDataFilter)
1196         instantDataFilter = clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, false, false));
1197
1198             // If the field data is to be read by the client or/and written to a file
1199       if (enableOutput && !storeFilter && !fileWriterFilter)
1200       {
1201         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
1202         {
1203           fileWriterFilter = std::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
1204           instantDataFilter->connectOutput(fileWriterFilter, 0);
1205         }
1206       }
1207     }
1208     else
1209     {
1210       // Start by building a filter which can provide the field's instant data
1211       if (!instantDataFilter)
1212       {
1213         // Check if we have an expression to parse
1214         if (hasExpression())
1215         {
1216           boost::scoped_ptr<IFilterExprNode> expr(parseExpr(getExpression() + '\0'));
1217           std::shared_ptr<COutputPin> filter = expr->reduce(gc, *this, filter_start, filter_end);
1218
1219           // Check if a spatial transformation is needed
1220           if (!field_ref.isEmpty())
1221           {
1222             CGrid* gridRef = CField::get(field_ref)->grid;
1223
1224             if (grid && grid != gridRef && grid->hasTransform())
1225             {
1226               std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters = CSpatialTransformFilter::buildFilterGraph(gc, gridRef, grid, detectMissingValues, defaultValue);
1227
1228               filter->connectOutput(filters.first, 0);
1229               filter = filters.second;
1230             }
1231           }
1232
1233           instantDataFilter = filter;
1234           instantDataFilter->field = this;
1235           filter->tag = buildWorkflowGraph;
1236           
1237           filter->start_graph = filter_start;
1238           filter->end_graph = filter_end;
1239
1240           for(int i=0; i<filter->parent_filters.size(); i++)
1241           {
1242             filter->tag = filter->tag || filter->parent_filters[i]->tag;
1243           }
1244         }
1245         // Check if we have a reference on another field
1246         else if (!field_ref.isEmpty())
1247         {
1248           instantDataFilter = getFieldReference(gc, filter_start, filter_end);
1249           instantDataFilter->tag = buildWorkflowGraph;
1250           instantDataFilter->start_graph = filter_start;
1251           instantDataFilter->end_graph = filter_end;
1252         }
1253         // Check if the data is to be read from a file
1254         else if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
1255         {
1256           checkTimeAttributes();
1257           instantDataFilter = serverSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, false, freq_offset, true,
1258                                                                                                       detectMissingValues, defaultValue));
1259           instantDataFilter->tag = buildWorkflowGraph;
1260           instantDataFilter->start_graph = filter_start;
1261           instantDataFilter->end_graph = filter_end;
1262           instantDataFilter->field = this;
1263
1264         }
1265         else // The data might be passed from the model
1266         {
1267            if (check_if_active.isEmpty()) check_if_active = false; 
1268            instantDataFilter = clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, false, true, NoneDu, false,
1269                                                                                                      detectMissingValues, defaultValue)); 
1270            instantDataFilter->tag = buildWorkflowGraph;
1271            instantDataFilter->start_graph = filter_start;
1272            instantDataFilter->end_graph = filter_end;
1273            instantDataFilter->field = this;
1274         }
1275       }
1276
1277       // If the field data is to be read by the client or/and written to a file
1278       if (enableOutput && !storeFilter && !fileWriterFilter)
1279       {
1280         if (!read_access.isEmpty() && read_access)
1281         {
1282           storeFilter = std::shared_ptr<CStoreFilter>(new CStoreFilter(gc, CContext::getCurrent(), grid,
1283                                                                          detectMissingValues, defaultValue));
1284           instantDataFilter->connectOutput(storeFilter, 0);
1285
1286           storeFilter->tag = (instantDataFilter->tag || buildWorkflowGraph);
1287           instantDataFilter->start_graph = filter_start;
1288           instantDataFilter->end_graph = filter_end;
1289
1290           instantDataFilter->setParentFiltersTag();
1291           storeFilter->start_graph = filter_start;
1292           storeFilter->end_graph = filter_end;
1293           storeFilter->field = this;
1294           storeFilter->distance = instantDataFilter->distance+1;
1295         }
1296
1297         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
1298         {
1299           fileWriterFilter = std::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
1300           getTemporalDataFilter(gc, file->output_freq)->connectOutput(fileWriterFilter, 0);
1301           
1302           fileWriterFilter->tag = (getTemporalDataFilter(gc, file->output_freq)->tag || buildWorkflowGraph);
1303           getTemporalDataFilter(gc, file->output_freq)->start_graph = filter_start;
1304           getTemporalDataFilter(gc, file->output_freq)->end_graph = filter_end;
1305           getTemporalDataFilter(gc, file->output_freq)->tag = buildWorkflowGraph;
1306           getTemporalDataFilter(gc, file->output_freq)->setParentFiltersTag();
1307           fileWriterFilter->start_graph = filter_start;
1308           fileWriterFilter->end_graph = filter_end;
1309           fileWriterFilter->distance = getTemporalDataFilter(gc, file->output_freq)->distance+1;
1310
1311
1312         }
1313       }
1314     }
1315   }
1316   CATCH_DUMP_ATTR
1317
1318   /*!
1319    * Returns the filter needed to handle the field reference.
1320    * This method should only be called when building the filter graph corresponding to the field.
1321    *
1322    * \param gc the garbage collector to use
1323    * \return the output pin corresponding to the field reference
1324    */
1325   std::shared_ptr<COutputPin> CField::getFieldReference(CGarbageCollector& gc, Time start_graph, Time end_graph)
1326   TRY
1327   {
1328     if (instantDataFilter || field_ref.isEmpty())
1329       ERROR("COutputPin* CField::getFieldReference(CGarbageCollector& gc)",
1330             "Impossible to get the field reference for a field which has already been parsed or which does not have a field_ref.");
1331
1332     CField* fieldRef = CField::get(field_ref);
1333     fieldRef->buildFilterGraph(gc, false, start_graph, end_graph);
1334     const bool buildWorkflowGraph = (!build_workflow_graph.isEmpty() && build_workflow_graph == true);
1335
1336     CContext* context = CContext::getCurrent();
1337
1338     Time filter_start;
1339     if(!build_workflow_graph_start.isEmpty() && buildWorkflowGraph) filter_start = context->calendar->getInitDate()+build_workflow_graph_start;
1340     else if(build_workflow_graph_start.isEmpty() && buildWorkflowGraph) filter_start = 0;
1341     else filter_start = -1;
1342
1343     Time filter_end;
1344     if(!build_workflow_graph_end.isEmpty() && buildWorkflowGraph) filter_end = context->calendar->getInitDate()+build_workflow_graph_end;
1345     else if(build_workflow_graph_end.isEmpty() && buildWorkflowGraph) filter_end = 9223372036854775807;
1346     else filter_end = -1;
1347
1348     if(this->field_graph_start==-2) this->field_graph_start = filter_start;
1349     if(this->field_graph_end==-2) this->field_graph_end = filter_end;         // init
1350
1351
1352     if(start_graph == -1)
1353     {
1354       //nothing
1355     }
1356     else //if(start_graph != -1)
1357     {
1358       if(this->field_graph_start == -1) this->field_graph_start = start_graph;
1359       else this->field_graph_start = min(this->field_graph_start, start_graph);
1360     }
1361
1362     if(end_graph == -1)
1363     {
1364       //nothing
1365     }
1366     else
1367     {
1368       if(this->field_graph_end == -1) this->field_graph_end = end_graph;
1369       else this->field_graph_end = max(this->field_graph_end, end_graph);
1370     }
1371
1372     filter_start = this->field_graph_start;
1373     filter_end = this->field_graph_end;
1374
1375
1376     std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters;
1377     // Check if a spatial transformation is needed
1378     if (grid && grid != fieldRef->grid && grid->hasTransform())
1379     {       
1380       bool hasMissingValue = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1381       double defaultValue  = hasMissingValue ? default_value : (!default_value.isEmpty() ? default_value : 0.0);                               
1382       filters = CSpatialTransformFilter::buildFilterGraph(gc, fieldRef->grid, grid, hasMissingValue, defaultValue);
1383
1384       fieldRef->getInstantDataFilter()->connectOutput(filters.first, 0);
1385
1386     
1387
1388       filters.second->parent_filters.resize(1);
1389       filters.second->parent_filters[0]= fieldRef->getInstantDataFilter();
1390
1391       filters.second->tag = (buildWorkflowGraph || filters.second->parent_filters[0]->tag);
1392       
1393       filters.second->start_graph = filter_start;
1394       filters.second->end_graph = filter_end;
1395       filters.second->field = this;
1396       
1397     }
1398     else
1399     {
1400       filters.first = filters.second = std::shared_ptr<CFilter>(new CPassThroughFilter(gc));
1401
1402       fieldRef->getInstantDataFilter()->connectOutput(filters.first, 0);
1403     
1404
1405       filters.second->parent_filters.resize(1);
1406       filters.second->parent_filters[0]= fieldRef->getInstantDataFilter();
1407
1408       filters.second->tag = (buildWorkflowGraph || filters.second->parent_filters[0]->tag);
1409
1410       filters.second->start_graph = filter_start;
1411       filters.second->end_graph = filter_end;
1412       filters.second->field = this;
1413
1414     }
1415
1416     return filters.second;
1417   }
1418   CATCH_DUMP_ATTR
1419
1420   /*!
1421    * Returns the filter needed to handle a self reference in the field's expression.
1422    * If the needed filter does not exist, it is created, otherwise it is reused.
1423    * This method should only be called when building the filter graph corresponding
1424    * to the field's expression.
1425    *
1426    * \param gc the garbage collector to use
1427    * \return the output pin corresponding to a self reference
1428    */
1429   std::shared_ptr<COutputPin> CField::getSelfReference(CGarbageCollector& gc, Time start_graph, Time end_graph)
1430   TRY
1431   {
1432
1433     if (instantDataFilter || !hasExpression())
1434       ERROR("COutputPin* CField::getSelfReference(CGarbageCollector& gc)",
1435             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1436     
1437     bool buildWorkflowGraph = (!build_workflow_graph.isEmpty() && build_workflow_graph == true);
1438
1439     if (!selfReferenceFilter)
1440     {
1441       const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1442       const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
1443
1444       if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
1445       {
1446         if (!serverSourceFilter)
1447         {
1448           checkTimeAttributes();
1449           serverSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, false, freq_offset, true,
1450                                                                                   detectMissingValues, defaultValue));
1451         }
1452
1453         selfReferenceFilter = serverSourceFilter;
1454       }
1455       else if (!field_ref.isEmpty())
1456       {
1457         CField* fieldRef = CField::get(field_ref);
1458         fieldRef->buildFilterGraph(gc, false);
1459         selfReferenceFilter = fieldRef->getInstantDataFilter();
1460       }
1461       else
1462       {
1463         if (!clientSourceFilter)
1464         {
1465           if (check_if_active.isEmpty()) check_if_active = false;
1466           clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, true, NoneDu, false,
1467                                                                                   detectMissingValues, defaultValue));
1468         }
1469
1470         selfReferenceFilter = clientSourceFilter;
1471       }
1472     }
1473
1474     selfReferenceFilter->tag = buildWorkflowGraph;
1475     selfReferenceFilter->field = this;
1476     return selfReferenceFilter;
1477   }
1478   CATCH_DUMP_ATTR
1479
1480   /*!
1481    * Returns the temporal filter corresponding to the field's temporal operation
1482    * for the specified operation frequency. The filter is created if it does not
1483    * exist, otherwise it is reused.
1484    *
1485    * \param gc the garbage collector to use
1486    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1487    * \return the output pin corresponding to the requested temporal filter
1488    */
1489   std::shared_ptr<COutputPin> CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1490   TRY
1491   {
1492     std::map<CDuration, std::shared_ptr<COutputPin> >::iterator it = temporalDataFilters.find(outFreq);
1493     const bool buildWorkflowGraph = (!build_workflow_graph.isEmpty() && build_workflow_graph == true);
1494
1495     CContext* context = CContext::getCurrent();
1496
1497
1498     if (it == temporalDataFilters.end())
1499     {
1500       if (operation.isEmpty())
1501         ERROR("void CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1502               << "An operation must be defined for field \"" << getId() << "\".");
1503
1504       checkTimeAttributes(&outFreq);
1505
1506       const bool detectMissingValues = (!detect_missing_value.isEmpty()  && detect_missing_value == true);
1507       std::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1508                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
1509                                                                             freq_op, freq_offset, outFreq, detectMissingValues));
1510
1511       instantDataFilter->connectOutput(temporalFilter, 0);
1512       
1513       temporalFilter->parent_filters.resize(1);
1514       temporalFilter->parent_filters[0] = instantDataFilter;
1515       
1516
1517       temporalFilter->tag = temporalFilter->parent_filters[0]->tag;
1518       temporalFilter->start_graph = temporalFilter->parent_filters[0]->start_graph;
1519       temporalFilter->end_graph = temporalFilter->parent_filters[0]->end_graph;
1520
1521       temporalFilter->field = this;
1522
1523       it = temporalDataFilters.insert(std::make_pair(outFreq, temporalFilter)).first;
1524     }
1525
1526     return it->second;
1527   }
1528   CATCH_DUMP_ATTR
1529
1530  /*!
1531    * Returns the temporal filter corresponding to the field's temporal operation
1532    * for the specified operation frequency.
1533    *
1534    * \param gc the garbage collector to use
1535    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1536    * \return the output pin corresponding to the requested temporal filter
1537    */
1538   
1539   std::shared_ptr<COutputPin> CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1540   TRY
1541   {
1542     if (instantDataFilter || !hasExpression())
1543       ERROR("COutputPin* CField::getSelfTemporalDataFilter(CGarbageCollector& gc)",
1544             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1545
1546     if (!selfReferenceFilter) getSelfReference(gc) ;
1547
1548     if (serverSourceFilter || clientSourceFilter)
1549     {
1550       if (operation.isEmpty())
1551         ERROR("void CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1552               << "An operation must be defined for field \"" << getId() << "\".");
1553
1554       checkTimeAttributes(&outFreq);
1555
1556       const bool detectMissingValues = (!detect_missing_value.isEmpty() && detect_missing_value == true);
1557       bool buildWorkflowGraph = (!build_workflow_graph.isEmpty() && build_workflow_graph == true);
1558       std::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1559                                                                           CContext::getCurrent()->getCalendar()->getInitDate(),
1560                                                                           freq_op, freq_offset, outFreq, detectMissingValues));
1561
1562       selfReferenceFilter->connectOutput(temporalFilter, 0);
1563       temporalFilter->tag = buildWorkflowGraph;
1564       temporalFilter->field = this;
1565
1566       return temporalFilter ;
1567     }
1568     else if (!field_ref.isEmpty())
1569     {
1570       CField* fieldRef = CField::get(field_ref);
1571       fieldRef->buildFilterGraph(gc, false); 
1572       return fieldRef->getTemporalDataFilter(gc, outFreq) ;
1573     }
1574  }
1575   CATCH_DUMP_ATTR
1576
1577   //----------------------------------------------------------------
1578/*
1579   void CField::fromBinary(StdIStream& is)
1580   {
1581      SuperClass::fromBinary(is);
1582#define CLEAR_ATT(name_)\
1583      SuperClassAttribute::operator[](#name_)->reset()
1584
1585         CLEAR_ATT(domain_ref);
1586         CLEAR_ATT(axis_ref);
1587#undef CLEAR_ATT
1588
1589   }
1590*/
1591   //----------------------------------------------------------------
1592
1593   void CField::solveGridReference(void)
1594   TRY
1595   {
1596      if (grid_ref.isEmpty() && domain_ref.isEmpty() && axis_ref.isEmpty() && scalar_ref.isEmpty())
1597      {
1598        ERROR("CField::solveGridReference(void)",
1599              << "A grid must be defined for field '" << getFieldOutputName() << "' .");
1600      }
1601      else if (!grid_ref.isEmpty() && (!domain_ref.isEmpty() || !axis_ref.isEmpty() || !scalar_ref.isEmpty()))
1602      {
1603        ERROR("CField::solveGridReference(void)",
1604              << "Field '" << getFieldOutputName() << "' has both a grid and a domain/axis/scalar." << std::endl
1605              << "Please define either 'grid_ref' or 'domain_ref'/'axis_ref'/'scalar_ref'.");
1606      }
1607
1608      if (grid_ref.isEmpty())
1609      {
1610        std::vector<CDomain*> vecDom;
1611        std::vector<CAxis*> vecAxis;
1612        std::vector<CScalar*> vecScalar;
1613        std::vector<int> axisDomainOrderTmp;
1614
1615        std::vector<CDomain*> vecDomRef;
1616        std::vector<CAxis*> vecAxisRef;
1617        std::vector<CScalar*> vecScalarRef;
1618
1619       
1620        if (!domain_ref.isEmpty())
1621        {
1622          StdString tmp = domain_ref.getValue();
1623          if (CDomain::has(domain_ref))
1624          {
1625            vecDom.push_back(CDomain::get(domain_ref));
1626            vecDomRef.push_back(CDomain::createDomain());
1627            vecDomRef.back()->domain_ref=domain_ref;
1628            axisDomainOrderTmp.push_back(2);
1629          }
1630          else  ERROR("CField::solveGridReference(void)",
1631                      << "Invalid reference to domain '" << domain_ref.getValue() << "'.");
1632        }
1633
1634        if (!axis_ref.isEmpty())
1635        {
1636          if (CAxis::has(axis_ref))
1637          {
1638            vecAxis.push_back(CAxis::get(axis_ref));
1639            vecAxisRef.push_back(CAxis::createAxis());
1640            vecAxisRef.back()->axis_ref=axis_ref;
1641            axisDomainOrderTmp.push_back(1);
1642          }
1643          else  ERROR("CField::solveGridReference(void)",
1644                      << "Invalid reference to axis '" << axis_ref.getValue() << "'.");
1645        }
1646
1647        if (!scalar_ref.isEmpty())
1648        {
1649          if (CScalar::has(scalar_ref))
1650          {
1651            vecScalar.push_back(CScalar::get(scalar_ref));
1652            vecScalarRef.push_back(CScalar::createScalar());
1653            vecScalarRef.back()->scalar_ref=scalar_ref;
1654            axisDomainOrderTmp.push_back(0);
1655          }
1656          else ERROR("CField::solveGridReference(void)",
1657                     << "Invalid reference to scalar '" << scalar_ref.getValue() << "'.");
1658        }
1659       
1660        CArray<int,1> axisDomainOrder(axisDomainOrderTmp.size());
1661        for (int idx = 0; idx < axisDomainOrderTmp.size(); ++idx)
1662        {
1663          axisDomainOrder(idx) = axisDomainOrderTmp[idx];
1664        }
1665
1666        // Warning: the gridId shouldn't be set as the grid_ref since it could be inherited
1667        StdString gridId = CGrid::generateId(vecDom, vecAxis, vecScalar,axisDomainOrder);
1668        if (CGrid::has(gridId)) this->grid = CGrid::get(gridId);
1669        else  this->grid = CGrid::createGrid(gridId, vecDomRef, vecAxisRef, vecScalarRef,axisDomainOrder);
1670      }
1671      else
1672      {
1673        if (CGrid::has(grid_ref)) this->grid = CGrid::get(grid_ref);
1674        else  ERROR("CField::solveGridReference(void)",
1675                     << "Invalid reference to grid '" << grid_ref.getValue() << "'.");
1676      }
1677   }
1678   CATCH_DUMP_ATTR
1679
1680   void CField::solveGridDomainAxisRef(bool checkAtt)
1681   TRY
1682   {
1683     grid->solveDomainAxisRef(checkAtt);
1684   }
1685   CATCH_DUMP_ATTR
1686
1687   void CField::solveCheckMaskIndex(bool doSendingIndex)
1688   TRY
1689   {
1690     grid->checkMaskIndex(doSendingIndex);
1691   }
1692   CATCH_DUMP_ATTR
1693
1694   void CField::solveTransformedGrid()
1695   TRY
1696   {
1697     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
1698     {
1699       std::vector<CGrid*> grids;
1700       // Source grid
1701       grids.push_back(getDirectFieldReference()->grid);
1702       // Intermediate grids
1703       if (!grid_path.isEmpty())
1704       {
1705         std::string gridId;
1706         size_t start = 0, end;
1707
1708         do
1709         {
1710           end = grid_path.getValue().find(',', start);
1711           if (end != std::string::npos)
1712           {
1713             gridId = grid_path.getValue().substr(start, end - start);
1714             start = end + 1;
1715           }
1716           else
1717             gridId = grid_path.getValue().substr(start);
1718
1719           if (!CGrid::has(gridId))
1720             ERROR("void CField::solveTransformedGrid()",
1721                   << "Invalid grid_path, the grid '" << gridId << "' does not exist.");
1722
1723           grids.push_back(CGrid::get(gridId));
1724         }
1725         while (end != std::string::npos);
1726       }
1727       // Destination grid
1728       grids.push_back(grid);
1729
1730       for (size_t i = 0, count = grids.size() - 1; i < count; ++i)
1731       {
1732         CGrid *gridSrc  = grids[i];
1733         CGrid *gridDest = grids[i + 1];
1734         if (!gridDest->isTransformed())
1735           gridDest->transformGrid(gridSrc);
1736       }
1737     }
1738     else if (grid && grid->hasTransform() && !grid->isTransformed())
1739     {
1740       // Temporarily deactivate the self-transformation of grid
1741       // grid->transformGrid(grid);
1742     }
1743   }
1744   CATCH_DUMP_ATTR
1745
1746   void CField::solveGenerateGrid()
1747   TRY
1748   {
1749     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
1750       grid->completeGrid(getDirectFieldReference()->grid);
1751     else
1752       grid->completeGrid();
1753   }
1754   CATCH_DUMP_ATTR
1755
1756   void CField::solveGridDomainAxisBaseRef()
1757   TRY
1758   {
1759     grid->solveDomainAxisRef(false);
1760     grid->solveDomainAxisBaseRef();
1761   }
1762   CATCH_DUMP_ATTR
1763
1764   ///-------------------------------------------------------------------
1765
1766   template <>
1767   void CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)
1768   TRY
1769   {
1770      if (this->group_ref.isEmpty()) return;
1771      StdString gref = this->group_ref.getValue();
1772
1773      if (!CFieldGroup::has(gref))
1774         ERROR("CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)",
1775               << "[ gref = " << gref << "]"
1776               << " invalid group name !");
1777
1778      CFieldGroup* group = CFieldGroup::get(gref);
1779      CFieldGroup* owner = CFieldGroup::get(boost::polymorphic_downcast<CFieldGroup*>(this));
1780      owner->setAttributes(group); // inherite of attributes of group reference
1781     
1782      std::vector<CField*> allChildren  = group->getAllChildren();
1783      std::vector<CField*>::iterator it = allChildren.begin(), end = allChildren.end();
1784
1785      for (; it != end; it++)
1786      {
1787         CField* child = *it;
1788         if (child->hasId()) owner->createChild()->field_ref.setValue(child->getId());
1789
1790      }
1791   }
1792   CATCH_DUMP_ATTR
1793
1794   void CField::scaleFactorAddOffset(double scaleFactor, double addOffset)
1795   TRY
1796   {
1797     recvDataSrv = (recvDataSrv - addOffset) / scaleFactor;
1798   }
1799   CATCH_DUMP_ATTR
1800
1801   void CField::invertScaleFactorAddOffset(double scaleFactor, double addOffset)
1802   TRY
1803   {
1804     recvDataSrv = recvDataSrv * scaleFactor + addOffset;
1805   }
1806   CATCH_DUMP_ATTR
1807
1808   void CField::outputField(CArray<double,1>& fieldOut)
1809   TRY
1810   { 
1811      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1812      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1813      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1814      {
1815        fieldOut(outIndexServer(idx)) = recvDataSrv(outIndexClient(idx));
1816      }
1817   }
1818   CATCH_DUMP_ATTR
1819
1820   void CField::inputField(CArray<double,1>& fieldIn)
1821   TRY
1822   {
1823      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1824      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1825      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1826      {
1827        recvDataSrv(outIndexClient(idx)) = fieldIn(outIndexServer(idx));
1828      }
1829   }
1830   CATCH_DUMP_ATTR
1831
1832   void CField::outputCompressedField(CArray<double,1>& fieldOut)
1833   TRY
1834   {
1835      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1836      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1837      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1838      {
1839        fieldOut((idx)) = recvDataSrv(outIndexClient(idx));
1840      }
1841   }
1842   CATCH_DUMP_ATTR
1843
1844   ///-------------------------------------------------------------------
1845
1846   void CField::parse(xml::CXMLNode& node)
1847   TRY
1848   {
1849      string newContent ;
1850      SuperClass::parse(node);
1851      if (node.goToChildElement())
1852      {
1853        do
1854        {
1855          if (node.getElementName() == "variable" || node.getElementName() == "variable_group") this->getVirtualVariableGroup()->parseChild(node);
1856          else if (node.getElementName() == "expr") if (node.getContent(newContent)) content+=newContent ;
1857        } while (node.goToNextElement());
1858        node.goToParentElement();
1859      }
1860      if (node.getContent(newContent)) content=newContent ;
1861    }
1862   CATCH_DUMP_ATTR
1863
1864   /*!
1865     This function retrieves Id of corresponding domain_ref and axis_ref (if any)
1866   of a field. In some cases, only domain exists but axis doesn't
1867   \return pair of Domain and Axis id
1868   */
1869   const std::vector<StdString>& CField::getRefDomainAxisIds()
1870   TRY
1871   {
1872     CGrid* cgPtr = getRelGrid();
1873     if (NULL != cgPtr)
1874     {
1875       std::vector<StdString>::iterator it;
1876       if (!domain_ref.isEmpty())
1877       {
1878         std::vector<StdString> domainList = cgPtr->getDomainList();
1879         it = std::find(domainList.begin(), domainList.end(), domain_ref.getValue());
1880         if (domainList.end() != it) domAxisScalarIds_[0] = *it;
1881       }
1882
1883       if (!axis_ref.isEmpty())
1884       {
1885         std::vector<StdString> axisList = cgPtr->getAxisList();
1886         it = std::find(axisList.begin(), axisList.end(), axis_ref.getValue());
1887         if (axisList.end() != it) domAxisScalarIds_[1] = *it;
1888       }
1889
1890       if (!scalar_ref.isEmpty())
1891       {
1892         std::vector<StdString> scalarList = cgPtr->getScalarList();
1893         it = std::find(scalarList.begin(), scalarList.end(), scalar_ref.getValue());
1894         if (scalarList.end() != it) domAxisScalarIds_[2] = *it;
1895       }
1896     }
1897     return (domAxisScalarIds_);
1898   }
1899   CATCH_DUMP_ATTR
1900
1901   CVariable* CField::addVariable(const string& id)
1902   TRY
1903   {
1904     return vVariableGroup->createChild(id);
1905   }
1906   CATCH
1907
1908   CVariableGroup* CField::addVariableGroup(const string& id)
1909   TRY
1910   {
1911     return vVariableGroup->createChildGroup(id);
1912   }
1913   CATCH
1914
1915   void CField::setContextClient(CContextClient* contextClient)
1916   TRY
1917   {
1918     CContext* context = CContext::getCurrent();
1919     client = contextClient;
1920     if (context->hasClient)
1921     {
1922       // A grid is sent by a client (both for read or write) or by primary server (write only)
1923       if (context->hasServer)
1924       {
1925         if (file->mode.isEmpty() || (!file->mode.isEmpty() && file->mode == CFile::mode_attr::write))
1926           grid->setContextClient(contextClient);
1927       }
1928       else
1929           grid->setContextClient(contextClient);
1930     }
1931   }
1932   CATCH_DUMP_ATTR
1933
1934   CContextClient* CField::getContextClient()
1935   TRY
1936   {
1937     return client;
1938   }
1939   CATCH
1940
1941   void CField::sendAddAllVariables(CContextClient* client)
1942   TRY
1943   {
1944     std::vector<CVariable*> allVar = getAllVariables();
1945     std::vector<CVariable*>::const_iterator it = allVar.begin();
1946     std::vector<CVariable*>::const_iterator itE = allVar.end();
1947
1948     for (; it != itE; ++it)
1949     {
1950       this->sendAddVariable((*it)->getId(), client);
1951       (*it)->sendAllAttributesToServer(client);
1952       (*it)->sendValue(client);
1953     }
1954   }
1955   CATCH_DUMP_ATTR
1956
1957   /*!
1958    * Send all Attributes to server. This method is overloaded, since only grid_ref attribute
1959    * must be sent to server and not domain_ref/axis_ref/scalar_ref.
1960    */
1961   
1962   void CField::sendAllAttributesToServer(CContextClient* client)
1963   TRY
1964   {
1965     if (grid_ref.isEmpty())
1966     {
1967       grid_ref=grid->getId() ;
1968       SuperClass::sendAllAttributesToServer(client) ;
1969       grid_ref.reset();
1970     }
1971     else SuperClass::sendAllAttributesToServer(client) ;
1972   }
1973   CATCH_DUMP_ATTR
1974   
1975   void CField::sendAddVariable(const string& id, CContextClient* client)
1976   TRY
1977   {
1978      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE, client);
1979   }
1980   CATCH_DUMP_ATTR
1981
1982   void CField::sendAddVariableGroup(const string& id, CContextClient* client)
1983   TRY
1984   {
1985      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE_GROUP, client);
1986   }
1987   CATCH_DUMP_ATTR
1988
1989   void CField::recvAddVariable(CEventServer& event)
1990   TRY
1991   {
1992
1993      CBufferIn* buffer = event.subEvents.begin()->buffer;
1994      string id;
1995      *buffer >> id;
1996      get(id)->recvAddVariable(*buffer);
1997   }
1998   CATCH
1999
2000   void CField::recvAddVariable(CBufferIn& buffer)
2001   TRY
2002   {
2003      string id;
2004      buffer >> id;
2005      addVariable(id);
2006   }
2007   CATCH_DUMP_ATTR
2008
2009   void CField::recvAddVariableGroup(CEventServer& event)
2010   TRY
2011   {
2012
2013      CBufferIn* buffer = event.subEvents.begin()->buffer;
2014      string id;
2015      *buffer >> id;
2016      get(id)->recvAddVariableGroup(*buffer);
2017   }
2018   CATCH
2019
2020   void CField::recvAddVariableGroup(CBufferIn& buffer)
2021   TRY
2022   {
2023      string id;
2024      buffer >> id;
2025      addVariableGroup(id);
2026   }
2027   CATCH_DUMP_ATTR
2028
2029   /*!
2030    * Check on freq_off and freq_op attributes.
2031    */
2032   void CField::checkTimeAttributes(CDuration* freqOp)
2033   TRY
2034   {
2035     bool isFieldRead  = file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read;
2036     bool isFieldWrite = file && ( file->mode.isEmpty() ||  file->mode == CFile::mode_attr::write);
2037     if (isFieldRead && !(operation.getValue() == "instant" || operation.getValue() == "once") )     
2038       ERROR("void CField::checkTimeAttributes(void)",
2039             << "Unsupported operation for field '" << getFieldOutputName() << "'." << std::endl
2040             << "Currently only \"instant\" is supported for fields read from file.")
2041
2042     if (freq_op.isEmpty())
2043     {
2044       if (operation.getValue() == "instant")
2045       {
2046         if (isFieldRead || isFieldWrite) freq_op.setValue(file->output_freq.getValue());
2047         else freq_op=*freqOp ;
2048       }
2049       else
2050         freq_op.setValue(TimeStep);
2051     }
2052     else
2053     {
2054       //if(file->output_freq.getValue() < freq_op.getValue())
2055       if(file!=nulptr && freq_op.getValue() > file->output_freq.getValue() )
2056       {
2057         ERROR("void CField::checkTimeAttributes(void)",
2058               << "output file has output_freq < freq_op" << std::endl
2059               << "field_id = "<< getId() << std::endl
2060               << "file_id = "<< file->getId() << std::endl
2061               << "output_freq = "<< file->output_freq.getValue() << std::endl
2062               << "freq_op = "<< freq_op.getValue() << std::endl)
2063       }
2064     }
2065     if (freq_offset.isEmpty())
2066       freq_offset.setValue(isFieldRead ? NoneDu : (freq_op.getValue() - TimeStep));
2067   }
2068   CATCH_DUMP_ATTR
2069
2070   /*!
2071    * Returns string arithmetic expression associated to the field.
2072    * \return if content is defined return content string, otherwise, if "expr" attribute is defined, return expr string.
2073    */
2074   const string& CField::getExpression(void)
2075   TRY
2076   {
2077     if (!expr.isEmpty() && content.empty())
2078     {
2079       content = expr;
2080       expr.reset();
2081     }
2082
2083     return content;
2084   }
2085   CATCH_DUMP_ATTR
2086
2087   bool CField::hasExpression(void) const
2088   TRY
2089   {
2090     return (!expr.isEmpty() || !content.empty());
2091   }
2092   CATCH
2093
2094   bool CField::hasGridMask(void) const
2095   TRY
2096   {
2097     return (this->grid->hasMask());
2098   }
2099   CATCH
2100
2101   DEFINE_REF_FUNC(Field,field)
2102} // namespace xios
Note: See TracBrowser for help on using the repository browser.