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

Last change on this file since 1704 was 1704, checked in by yushan, 5 years ago

Introducing the new graph functionality. Attribute build_workflow_graph=.TRUE. is used in the field definition section in the xml file to enable the workflow graph of the field and other fields referecing to it. A more detailed document will be available soon on the graph fuctionality.

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