source: XIOS/dev/dev_ym/XIOS_COUPLING/src/node/field.cpp @ 1870

Last change on this file since 1870 was 1870, checked in by ymipsl, 4 years ago

Some update on XIOS_COUPLING branch...

YM

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