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

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

XIOS coupling.
Reorganize filters, update of the day.

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