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

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

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