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

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

Coupling branch
Fix compilation error due to deleted .hpp . Problem appear only after a full compilation.

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