source: XIOS/dev/dev_trunk_omp/src/node/field.cpp @ 1769

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

dev_trunk_omp : bug fix for workflowgraph

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