source: XIOS/dev/dev_olga/src/node/field.cpp @ 1686

Last change on this file since 1686 was 1686, checked in by yushan, 2 years ago

backup for trunk with graph

  • 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: 69.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
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     // Time filter_start;
1520     // if(!build_workflow_graph_start.isEmpty() && buildWorkflowGraph) filter_start = context->calendar->getInitDate()+build_workflow_graph_start;
1521     // else if(build_workflow_graph_start.isEmpty() && buildWorkflowGraph) filter_start = 0;
1522     // else filter_start = -1;
1523
1524     // Time filter_end;
1525     // if(!build_workflow_graph_end.isEmpty() && buildWorkflowGraph) filter_end = context->calendar->getInitDate()+build_workflow_graph_end;
1526     // else if(build_workflow_graph_end.isEmpty() && buildWorkflowGraph) filter_end = 9223372036854775807;
1527     // else filter_end = -1;
1528
1529     // filter_start = this->field_graph_start;
1530     // filter_end = this->field_graph_end;
1531
1532     // if(CXios::isClient) std::cout<<"getTemporalDataFilter field_id = "<<this->getId()<<" this->field_graph_start = "<<this->field_graph_start<<" this->field_graph_end = "<<this->field_graph_end<<std::endl;
1533
1534     if (it == temporalDataFilters.end())
1535     {
1536       if (operation.isEmpty())
1537         ERROR("void CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1538               << "An operation must be defined for field \"" << getId() << "\".");
1539
1540       checkTimeAttributes(&outFreq);
1541
1542       const bool detectMissingValues = (!detect_missing_value.isEmpty()  && detect_missing_value == true);
1543       std::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1544                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
1545                                                                             freq_op, freq_offset, outFreq, detectMissingValues));
1546
1547       instantDataFilter->connectOutput(temporalFilter, 0);
1548       // temporalFilter->tag = buildWorkflowGraph;
1549       
1550       temporalFilter->parent_filters.resize(1);
1551       temporalFilter->parent_filters[0] = instantDataFilter;
1552       
1553
1554       if(temporalFilter->parent_filters[0]->tag) temporalFilter->tag=true;
1555
1556       // temporalFilter->start_graph = filter_start;
1557       // temporalFilter->end_graph = filter_end;
1558       temporalFilter->field = this;
1559
1560       it = temporalDataFilters.insert(std::make_pair(outFreq, temporalFilter)).first;
1561     }
1562
1563     return it->second;
1564   }
1565   CATCH_DUMP_ATTR
1566
1567  /*!
1568    * Returns the temporal filter corresponding to the field's temporal operation
1569    * for the specified operation frequency.
1570    *
1571    * \param gc the garbage collector to use
1572    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1573    * \return the output pin corresponding to the requested temporal filter
1574    */
1575   
1576   std::shared_ptr<COutputPin> CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1577   TRY
1578   {
1579     if (instantDataFilter || !hasExpression())
1580       ERROR("COutputPin* CField::getSelfTemporalDataFilter(CGarbageCollector& gc)",
1581             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1582
1583     if (!selfReferenceFilter) getSelfReference(gc) ;
1584
1585     if (serverSourceFilter || clientSourceFilter)
1586     {
1587       if (operation.isEmpty())
1588         ERROR("void CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1589               << "An operation must be defined for field \"" << getId() << "\".");
1590
1591       checkTimeAttributes(&outFreq);
1592
1593       const bool detectMissingValues = (!detect_missing_value.isEmpty() && detect_missing_value == true);
1594       bool buildWorkflowGraph = (!build_workflow_graph.isEmpty() && build_workflow_graph == true);
1595       std::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1596                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
1597                                                                             freq_op, freq_offset, outFreq, detectMissingValues));
1598
1599       selfReferenceFilter->connectOutput(temporalFilter, 0);
1600       temporalFilter->tag = buildWorkflowGraph;
1601       temporalFilter->field = this;
1602
1603       return temporalFilter ;
1604     }
1605     else if (!field_ref.isEmpty())
1606     {
1607       CField* fieldRef = CField::get(field_ref);
1608       fieldRef->buildFilterGraph(gc, false); 
1609       return fieldRef->getTemporalDataFilter(gc, outFreq) ;
1610     }
1611  }
1612   CATCH_DUMP_ATTR
1613
1614   //----------------------------------------------------------------
1615/*
1616   void CField::fromBinary(StdIStream& is)
1617   {
1618      SuperClass::fromBinary(is);
1619#define CLEAR_ATT(name_)\
1620      SuperClassAttribute::operator[](#name_)->reset()
1621
1622         CLEAR_ATT(domain_ref);
1623         CLEAR_ATT(axis_ref);
1624#undef CLEAR_ATT
1625
1626   }
1627*/
1628   //----------------------------------------------------------------
1629
1630   void CField::solveGridReference(void)
1631   TRY
1632   {
1633      if (grid_ref.isEmpty() && domain_ref.isEmpty() && axis_ref.isEmpty() && scalar_ref.isEmpty())
1634      {
1635        ERROR("CField::solveGridReference(void)",
1636              << "A grid must be defined for field '" << getFieldOutputName() << "' .");
1637      }
1638      else if (!grid_ref.isEmpty() && (!domain_ref.isEmpty() || !axis_ref.isEmpty() || !scalar_ref.isEmpty()))
1639      {
1640        ERROR("CField::solveGridReference(void)",
1641              << "Field '" << getFieldOutputName() << "' has both a grid and a domain/axis/scalar." << std::endl
1642              << "Please define either 'grid_ref' or 'domain_ref'/'axis_ref'/'scalar_ref'.");
1643      }
1644
1645      if (grid_ref.isEmpty())
1646      {
1647        std::vector<CDomain*> vecDom;
1648        std::vector<CAxis*> vecAxis;
1649        std::vector<CScalar*> vecScalar;
1650        std::vector<int> axisDomainOrderTmp;
1651
1652        std::vector<CDomain*> vecDomRef;
1653        std::vector<CAxis*> vecAxisRef;
1654        std::vector<CScalar*> vecScalarRef;
1655
1656       
1657        if (!domain_ref.isEmpty())
1658        {
1659          StdString tmp = domain_ref.getValue();
1660          if (CDomain::has(domain_ref))
1661          {
1662            vecDom.push_back(CDomain::get(domain_ref));
1663            vecDomRef.push_back(CDomain::createDomain());
1664            vecDomRef.back()->domain_ref=domain_ref;
1665            axisDomainOrderTmp.push_back(2);
1666          }
1667          else  ERROR("CField::solveGridReference(void)",
1668                      << "Invalid reference to domain '" << domain_ref.getValue() << "'.");
1669        }
1670
1671        if (!axis_ref.isEmpty())
1672        {
1673          if (CAxis::has(axis_ref))
1674          {
1675            vecAxis.push_back(CAxis::get(axis_ref));
1676            vecAxisRef.push_back(CAxis::createAxis());
1677            vecAxisRef.back()->axis_ref=axis_ref;
1678            axisDomainOrderTmp.push_back(1);
1679          }
1680          else  ERROR("CField::solveGridReference(void)",
1681                      << "Invalid reference to axis '" << axis_ref.getValue() << "'.");
1682        }
1683
1684        if (!scalar_ref.isEmpty())
1685        {
1686          if (CScalar::has(scalar_ref))
1687          {
1688            vecScalar.push_back(CScalar::get(scalar_ref));
1689            vecScalarRef.push_back(CScalar::createScalar());
1690            vecScalarRef.back()->scalar_ref=scalar_ref;
1691            axisDomainOrderTmp.push_back(0);
1692          }
1693          else ERROR("CField::solveGridReference(void)",
1694                     << "Invalid reference to scalar '" << scalar_ref.getValue() << "'.");
1695        }
1696       
1697        CArray<int,1> axisDomainOrder(axisDomainOrderTmp.size());
1698        for (int idx = 0; idx < axisDomainOrderTmp.size(); ++idx)
1699        {
1700          axisDomainOrder(idx) = axisDomainOrderTmp[idx];
1701        }
1702
1703        // Warning: the gridId shouldn't be set as the grid_ref since it could be inherited
1704        StdString gridId = CGrid::generateId(vecDom, vecAxis, vecScalar,axisDomainOrder);
1705        if (CGrid::has(gridId)) this->grid = CGrid::get(gridId);
1706        else  this->grid = CGrid::createGrid(gridId, vecDomRef, vecAxisRef, vecScalarRef,axisDomainOrder);
1707      }
1708      else
1709      {
1710        if (CGrid::has(grid_ref)) this->grid = CGrid::get(grid_ref);
1711        else  ERROR("CField::solveGridReference(void)",
1712                     << "Invalid reference to grid '" << grid_ref.getValue() << "'.");
1713      }
1714   }
1715   CATCH_DUMP_ATTR
1716
1717   void CField::solveGridDomainAxisRef(bool checkAtt)
1718   TRY
1719   {
1720     grid->solveDomainAxisRef(checkAtt);
1721   }
1722   CATCH_DUMP_ATTR
1723
1724   void CField::solveCheckMaskIndex(bool doSendingIndex)
1725   TRY
1726   {
1727     grid->checkMaskIndex(doSendingIndex);
1728   }
1729   CATCH_DUMP_ATTR
1730
1731   void CField::solveTransformedGrid()
1732   TRY
1733   {
1734     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
1735     {
1736       std::vector<CGrid*> grids;
1737       // Source grid
1738       grids.push_back(getDirectFieldReference()->grid);
1739       // Intermediate grids
1740       if (!grid_path.isEmpty())
1741       {
1742         std::string gridId;
1743         size_t start = 0, end;
1744
1745         do
1746         {
1747           end = grid_path.getValue().find(',', start);
1748           if (end != std::string::npos)
1749           {
1750             gridId = grid_path.getValue().substr(start, end - start);
1751             start = end + 1;
1752           }
1753           else
1754             gridId = grid_path.getValue().substr(start);
1755
1756           if (!CGrid::has(gridId))
1757             ERROR("void CField::solveTransformedGrid()",
1758                   << "Invalid grid_path, the grid '" << gridId << "' does not exist.");
1759
1760           grids.push_back(CGrid::get(gridId));
1761         }
1762         while (end != std::string::npos);
1763       }
1764       // Destination grid
1765       grids.push_back(grid);
1766
1767       for (size_t i = 0, count = grids.size() - 1; i < count; ++i)
1768       {
1769         CGrid *gridSrc  = grids[i];
1770         CGrid *gridDest = grids[i + 1];
1771         if (!gridDest->isTransformed())
1772           gridDest->transformGrid(gridSrc);
1773       }
1774     }
1775     else if (grid && grid->hasTransform() && !grid->isTransformed())
1776     {
1777       // Temporarily deactivate the self-transformation of grid
1778       // grid->transformGrid(grid);
1779     }
1780   }
1781   CATCH_DUMP_ATTR
1782
1783   void CField::solveGenerateGrid()
1784   TRY
1785   {
1786     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
1787       grid->completeGrid(getDirectFieldReference()->grid);
1788     else
1789       grid->completeGrid();
1790   }
1791   CATCH_DUMP_ATTR
1792
1793   void CField::solveGridDomainAxisBaseRef()
1794   TRY
1795   {
1796     grid->solveDomainAxisRef(false);
1797     grid->solveDomainAxisBaseRef();
1798   }
1799   CATCH_DUMP_ATTR
1800
1801   ///-------------------------------------------------------------------
1802
1803   template <>
1804   void CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)
1805   TRY
1806   {
1807      if (this->group_ref.isEmpty()) return;
1808      StdString gref = this->group_ref.getValue();
1809
1810      if (!CFieldGroup::has(gref))
1811         ERROR("CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)",
1812               << "[ gref = " << gref << "]"
1813               << " invalid group name !");
1814
1815      CFieldGroup* group = CFieldGroup::get(gref);
1816      CFieldGroup* owner = CFieldGroup::get(boost::polymorphic_downcast<CFieldGroup*>(this));
1817      owner->setAttributes(group); // inherite of attributes of group reference
1818     
1819      std::vector<CField*> allChildren  = group->getAllChildren();
1820      std::vector<CField*>::iterator it = allChildren.begin(), end = allChildren.end();
1821
1822      for (; it != end; it++)
1823      {
1824         CField* child = *it;
1825         if (child->hasId()) owner->createChild()->field_ref.setValue(child->getId());
1826
1827      }
1828   }
1829   CATCH_DUMP_ATTR
1830
1831   void CField::scaleFactorAddOffset(double scaleFactor, double addOffset)
1832   TRY
1833   {
1834     recvDataSrv = (recvDataSrv - addOffset) / scaleFactor;
1835   }
1836   CATCH_DUMP_ATTR
1837
1838   void CField::invertScaleFactorAddOffset(double scaleFactor, double addOffset)
1839   TRY
1840   {
1841     recvDataSrv = recvDataSrv * scaleFactor + addOffset;
1842   }
1843   CATCH_DUMP_ATTR
1844
1845   void CField::outputField(CArray<double,1>& fieldOut)
1846   TRY
1847   { 
1848      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1849      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1850      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1851      {
1852        fieldOut(outIndexServer(idx)) = recvDataSrv(outIndexClient(idx));
1853      }
1854   }
1855   CATCH_DUMP_ATTR
1856
1857   void CField::inputField(CArray<double,1>& fieldIn)
1858   TRY
1859   {
1860      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1861      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1862      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1863      {
1864        recvDataSrv(outIndexClient(idx)) = fieldIn(outIndexServer(idx));
1865      }
1866   }
1867   CATCH_DUMP_ATTR
1868
1869   void CField::outputCompressedField(CArray<double,1>& fieldOut)
1870   TRY
1871   {
1872      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1873      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1874      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1875      {
1876        fieldOut((idx)) = recvDataSrv(outIndexClient(idx));
1877      }
1878   }
1879   CATCH_DUMP_ATTR
1880
1881   ///-------------------------------------------------------------------
1882
1883   void CField::parse(xml::CXMLNode& node)
1884   TRY
1885   {
1886      string newContent ;
1887      SuperClass::parse(node);
1888      if (node.goToChildElement())
1889      {
1890        do
1891        {
1892          if (node.getElementName() == "variable" || node.getElementName() == "variable_group") this->getVirtualVariableGroup()->parseChild(node);
1893          else if (node.getElementName() == "expr") if (node.getContent(newContent)) content+=newContent ;
1894        } while (node.goToNextElement());
1895        node.goToParentElement();
1896      }
1897      if (node.getContent(newContent)) content=newContent ;
1898    }
1899   CATCH_DUMP_ATTR
1900
1901   /*!
1902     This function retrieves Id of corresponding domain_ref and axis_ref (if any)
1903   of a field. In some cases, only domain exists but axis doesn't
1904   \return pair of Domain and Axis id
1905   */
1906   const std::vector<StdString>& CField::getRefDomainAxisIds()
1907   TRY
1908   {
1909     CGrid* cgPtr = getRelGrid();
1910     if (NULL != cgPtr)
1911     {
1912       std::vector<StdString>::iterator it;
1913       if (!domain_ref.isEmpty())
1914       {
1915         std::vector<StdString> domainList = cgPtr->getDomainList();
1916         it = std::find(domainList.begin(), domainList.end(), domain_ref.getValue());
1917         if (domainList.end() != it) domAxisScalarIds_[0] = *it;
1918       }
1919
1920       if (!axis_ref.isEmpty())
1921       {
1922         std::vector<StdString> axisList = cgPtr->getAxisList();
1923         it = std::find(axisList.begin(), axisList.end(), axis_ref.getValue());
1924         if (axisList.end() != it) domAxisScalarIds_[1] = *it;
1925       }
1926
1927       if (!scalar_ref.isEmpty())
1928       {
1929         std::vector<StdString> scalarList = cgPtr->getScalarList();
1930         it = std::find(scalarList.begin(), scalarList.end(), scalar_ref.getValue());
1931         if (scalarList.end() != it) domAxisScalarIds_[2] = *it;
1932       }
1933     }
1934     return (domAxisScalarIds_);
1935   }
1936   CATCH_DUMP_ATTR
1937
1938   CVariable* CField::addVariable(const string& id)
1939   TRY
1940   {
1941     return vVariableGroup->createChild(id);
1942   }
1943   CATCH
1944
1945   CVariableGroup* CField::addVariableGroup(const string& id)
1946   TRY
1947   {
1948     return vVariableGroup->createChildGroup(id);
1949   }
1950   CATCH
1951
1952   void CField::setContextClient(CContextClient* contextClient)
1953   TRY
1954   {
1955     CContext* context = CContext::getCurrent();
1956     client = contextClient;
1957     if (context->hasClient)
1958     {
1959       // A grid is sent by a client (both for read or write) or by primary server (write only)
1960       if (context->hasServer)
1961       {
1962         if (file->mode.isEmpty() || (!file->mode.isEmpty() && file->mode == CFile::mode_attr::write))
1963           grid->setContextClient(contextClient);
1964       }
1965       else
1966           grid->setContextClient(contextClient);
1967     }
1968   }
1969   CATCH_DUMP_ATTR
1970
1971   CContextClient* CField::getContextClient()
1972   TRY
1973   {
1974     return client;
1975   }
1976   CATCH
1977
1978   void CField::sendAddAllVariables(CContextClient* client)
1979   TRY
1980   {
1981     std::vector<CVariable*> allVar = getAllVariables();
1982     std::vector<CVariable*>::const_iterator it = allVar.begin();
1983     std::vector<CVariable*>::const_iterator itE = allVar.end();
1984
1985     for (; it != itE; ++it)
1986     {
1987       this->sendAddVariable((*it)->getId(), client);
1988       (*it)->sendAllAttributesToServer(client);
1989       (*it)->sendValue(client);
1990     }
1991   }
1992   CATCH_DUMP_ATTR
1993
1994   /*!
1995    * Send all Attributes to server. This method is overloaded, since only grid_ref attribute
1996    * must be sent to server and not domain_ref/axis_ref/scalar_ref.
1997    */
1998   
1999   void CField::sendAllAttributesToServer(CContextClient* client)
2000   TRY
2001   {
2002     if (grid_ref.isEmpty())
2003     {
2004       grid_ref=grid->getId() ;
2005       SuperClass::sendAllAttributesToServer(client) ;
2006       grid_ref.reset();
2007     }
2008     else SuperClass::sendAllAttributesToServer(client) ;
2009   }
2010   CATCH_DUMP_ATTR
2011   
2012   void CField::sendAddVariable(const string& id, CContextClient* client)
2013   TRY
2014   {
2015      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE, client);
2016   }
2017   CATCH_DUMP_ATTR
2018
2019   void CField::sendAddVariableGroup(const string& id, CContextClient* client)
2020   TRY
2021   {
2022      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE_GROUP, client);
2023   }
2024   CATCH_DUMP_ATTR
2025
2026   void CField::recvAddVariable(CEventServer& event)
2027   TRY
2028   {
2029
2030      CBufferIn* buffer = event.subEvents.begin()->buffer;
2031      string id;
2032      *buffer >> id;
2033      get(id)->recvAddVariable(*buffer);
2034   }
2035   CATCH
2036
2037   void CField::recvAddVariable(CBufferIn& buffer)
2038   TRY
2039   {
2040      string id;
2041      buffer >> id;
2042      addVariable(id);
2043   }
2044   CATCH_DUMP_ATTR
2045
2046   void CField::recvAddVariableGroup(CEventServer& event)
2047   TRY
2048   {
2049
2050      CBufferIn* buffer = event.subEvents.begin()->buffer;
2051      string id;
2052      *buffer >> id;
2053      get(id)->recvAddVariableGroup(*buffer);
2054   }
2055   CATCH
2056
2057   void CField::recvAddVariableGroup(CBufferIn& buffer)
2058   TRY
2059   {
2060      string id;
2061      buffer >> id;
2062      addVariableGroup(id);
2063   }
2064   CATCH_DUMP_ATTR
2065
2066   /*!
2067    * Check on freq_off and freq_op attributes.
2068    */
2069   void CField::checkTimeAttributes(CDuration* freqOp)
2070   TRY
2071   {
2072     bool isFieldRead  = file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read;
2073     bool isFieldWrite = file && ( file->mode.isEmpty() ||  file->mode == CFile::mode_attr::write);
2074     if (isFieldRead && !(operation.getValue() == "instant" || operation.getValue() == "once") )     
2075       ERROR("void CField::checkTimeAttributes(void)",
2076             << "Unsupported operation for field '" << getFieldOutputName() << "'." << std::endl
2077             << "Currently only \"instant\" is supported for fields read from file.")
2078
2079     if (freq_op.isEmpty())
2080     {
2081       if (operation.getValue() == "instant")
2082       {
2083         if (isFieldRead || isFieldWrite) freq_op.setValue(file->output_freq.getValue());
2084         else freq_op=*freqOp ;
2085       }
2086       else
2087         freq_op.setValue(TimeStep);
2088     }
2089     if (freq_offset.isEmpty())
2090       freq_offset.setValue(isFieldRead ? NoneDu : (freq_op.getValue() - TimeStep));
2091   }
2092   CATCH_DUMP_ATTR
2093
2094   /*!
2095    * Returns string arithmetic expression associated to the field.
2096    * \return if content is defined return content string, otherwise, if "expr" attribute is defined, return expr string.
2097    */
2098   const string& CField::getExpression(void)
2099   TRY
2100   {
2101     if (!expr.isEmpty() && content.empty())
2102     {
2103       content = expr;
2104       expr.reset();
2105     }
2106
2107     return content;
2108   }
2109   CATCH_DUMP_ATTR
2110
2111   bool CField::hasExpression(void) const
2112   TRY
2113   {
2114     return (!expr.isEmpty() || !content.empty());
2115   }
2116   CATCH
2117
2118   bool CField::hasGridMask(void) const
2119   TRY
2120   {
2121     return (this->grid->hasMask());
2122   }
2123   CATCH
2124
2125   DEFINE_REF_FUNC(Field,field)
2126} // namespace xios
Note: See TracBrowser for help on using the repository browser.