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

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

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