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

Last change on this file since 2011 was 2011, checked in by ymipsl, 3 years ago
  • bug fix when createing mask on server side when overlapping grid
  • implement axis interpolation on pressure coordinate
  • big cleaning in transformation

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: 46.3 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 "pass_through_filter.hpp"
18#include "filter_expr_node.hpp"
19#include "lex_parser.hpp"
20#include "temporal_filter.hpp"
21#include "spatial_transform_filter.hpp"
22#include "server_from_client_source_filter.hpp"
23#include "file_reader_source_filter.hpp"
24#include "tracer.hpp"
25
26namespace xios
27{
28
29  /// ////////////////////// Définitions ////////////////////// ///
30
31  CField::CField(void)
32    : CObjectTemplate<CField>(), CFieldAttributes()
33    , written(false)
34    , hasOutputFile(false)
35    , domAxisScalarIds_(vector<StdString>(3,""))
36    , areAllReferenceSolved(false), isReferenceSolved(false), isReferenceSolvedAndTransformed(false)
37    , isGridChecked(false)
38    , useCompressedOutput(false)
39    , hasTimeInstant(false)
40    , hasTimeCentered(false)
41    , mustAutoTrigger(false)
42  { setVirtualVariableGroup(CVariableGroup::create(getId() + "_virtual_variable_group")); }
43
44  CField::CField(const StdString& id)
45    : CObjectTemplate<CField>(id), CFieldAttributes()
46    , written(false)
47    , hasOutputFile(false)
48    , domAxisScalarIds_(vector<StdString>(3,""))
49    , areAllReferenceSolved(false), isReferenceSolved(false), isReferenceSolvedAndTransformed(false)
50    , isGridChecked(false)
51    , useCompressedOutput(false)
52    , hasTimeInstant(false)
53    , hasTimeCentered(false)
54    , mustAutoTrigger(false)
55    { setVirtualVariableGroup(CVariableGroup::create(getId() + "_virtual_variable_group")); }
56
57  CField::~CField(void)
58  {}
59
60  //----------------------------------------------------------------
61
62  void CField::setVirtualVariableGroup(CVariableGroup* newVVariableGroup)
63  TRY
64  {
65    this->vVariableGroup = newVVariableGroup;
66  }
67  CATCH
68
69  CVariableGroup* CField::getVirtualVariableGroup(void) const
70  TRY
71  {
72     return this->vVariableGroup;
73  }
74  CATCH
75
76  std::vector<CVariable*> CField::getAllVariables(void) const
77  TRY
78  {
79    return this->vVariableGroup->getAllChildren();
80  }
81  CATCH
82
83  void CField::solveDescInheritance(bool apply, const CAttributeMap* const parent)
84  TRY
85  {
86    SuperClassAttribute::setAttributes(parent, apply);
87    this->getVirtualVariableGroup()->solveDescInheritance(apply, NULL);
88  }
89  CATCH_DUMP_ATTR
90
91  //----------------------------------------------------------------
92
93  bool CField::dispatchEvent(CEventServer& event)
94  TRY
95  {
96    if (SuperClass::dispatchEvent(event)) return true;
97    else
98    {
99      switch(event.type)
100      {
101        case EVENT_ID_UPDATE_DATA :
102          recvUpdateData(event);
103          return true;
104          break;
105
106        case EVENT_ID_READ_DATA :
107          recvReadDataRequest(event);
108          return true;
109          break;
110
111        case EVENT_ID_READ_DATA_READY :
112          recvReadDataReady(event);
113          return true;
114          break;
115
116        case EVENT_ID_ADD_VARIABLE :
117          recvAddVariable(event);
118          return true;
119          break;
120
121        case EVENT_ID_ADD_VARIABLE_GROUP :
122          recvAddVariableGroup(event);
123          return true;
124          break;
125     
126        case EVENT_ID_GRID_COMPLETED :
127          recvGridCompleted(event);
128          return true;
129          break;
130        default :
131          ERROR("bool CField::dispatchEvent(CEventServer& event)", << "Unknown Event");
132          return false;
133      }
134    }
135  }
136  CATCH
137
138
139  void CField::recvUpdateData(CEventServer& event)
140  TRY
141  {
142    string fieldId;
143    for (auto& subEvent : event.subEvents) (*subEvent.buffer) >> fieldId  ;
144    get(fieldId)->receiveUpdateData(event);
145  }
146  CATCH
147
148  void  CField::receiveUpdateData(CEventServer& event)
149  TRY
150  {
151    if (hasCouplerIn()) clientFromClientSourceFilter_->streamData(event) ;
152    else serverFromClientSourceFilter_->streamData(event) ;
153  }
154  CATCH
155
156  /*
157    Send a request for reading data.
158    Client sends a request to server for demanding server to read data and send back to it.
159    For now, this function is called only by client
160    In the future, it can be called by level-1 servers
161    \param [in] tsDataRequested timestamp when the call is made
162  */
163  bool CField::sendReadDataRequest(const CDate& tsDataRequested)
164  TRY
165  {
166    return clientFromServerSourceFilter_->sendReadDataRequest(tsDataRequested) ;
167  }
168  CATCH_DUMP_ATTR
169 
170 
171  /*!
172  Send request new data read from file if need be, that is the current data is out-of-date.
173  \return true if and only if some data was requested
174  */
175  bool CField::sendReadDataRequestIfNeeded(void)
176  TRY
177  {
178    return clientFromServerSourceFilter_->sendReadDataRequestIfNeeded() ;
179  }
180  CATCH_DUMP_ATTR
181
182
183  void CField::recvReadDataRequest(CEventServer& event)
184  TRY
185  {
186    CBufferIn* buffer = event.subEvents.begin()->buffer;
187    StdString fieldId;
188    *buffer >> fieldId;
189    get(fieldId)->recvReadDataRequest();
190  }
191  CATCH
192 
193  /*!
194    Receive data request sent from client and process it
195    Every time server receives this request, it will try to read data and sent read data back to client
196    At the moment, this function is called by server level 1
197    In the future, this should (only) be done by the last level servers.
198  */
199  void CField::recvReadDataRequest(void)
200  TRY
201  {
202    fileReaderSourceFilter_->streamData() ;
203  }
204  CATCH_DUMP_ATTR 
205
206 
207  /*
208    Receive read data from server.
209    At the moment, this function is called in the client side.
210    In the future, this function can be called hiearachically (server n-1, server n -2, ..., client)
211    \param event event containing read data
212  */
213  void CField::recvReadDataReady(CEventServer& event)
214  TRY
215  {
216    string fieldId;
217    for (auto& subEvent : event.subEvents) (*subEvent.buffer) >> fieldId  ;
218    get(fieldId)->receiveReadDataReady(event);
219  }
220  CATCH
221
222  void CField::receiveReadDataReady(CEventServer& event)
223  TRY
224  {
225    clientFromServerSourceFilter_->streamData(event) ;   
226  }
227  CATCH_DUMP_ATTR
228
229
230  void CField::checkForLateDataFromCoupler(void)
231  TRY
232  {
233    CContext* context = CContext::getCurrent();
234    const CDate& currentDate = context->getCalendar()->getCurrentDate();
235
236    CTimer timer("CField::checkForLateDataFromCoupler");
237    timer.resume();
238    traceOff() ;
239    timer.suspend();
240   
241    bool isDataLate; 
242    do
243    {
244      isDataLate=clientFromClientSourceFilter_->isDataLate() ;
245      if (isDataLate)
246      {
247        timer.resume();
248        context->globalEventLoop();
249        timer.suspend();
250      }
251    } while (isDataLate && timer.getCumulatedTime() < CXios::recvFieldTimeout);
252   
253    timer.resume();
254    traceOn() ;
255    timer.suspend() ;
256
257    if (isDataLate) ERROR("void CField::checkForLateDataFromCoupler(void)",
258                            << "Late data at timestep = " << currentDate);
259  }
260  CATCH_DUMP_ATTR
261
262  void CField::checkForLateDataFromServer(void)
263  TRY
264  {
265    clientFromServerSourceFilter_->checkForLateData() ;
266  }
267  CATCH_DUMP_ATTR
268 
269 
270  void CField::triggerLateField(void)
271  TRY
272  {
273    if (hasFileIn()) 
274    {
275      checkForLateDataFromServer() ;
276      clientFromServerSourceFilter_->trigger(CContext::getCurrent()->getCalendar()->getCurrentDate()) ;
277    } 
278    else if (hasCouplerIn())
279    {
280      checkForLateDataFromCoupler() ;
281      clientFromClientSourceFilter_->trigger(CContext::getCurrent()->getCalendar()->getCurrentDate()) ;
282    }
283  }
284  CATCH_DUMP_ATTR
285
286
287  void CField::checkIfMustAutoTrigger(void)
288  TRY
289  {
290    mustAutoTrigger = clientFromServerSourceFilter_ ? clientFromServerSourceFilter_->mustAutoTrigger() : false;
291  }
292  CATCH_DUMP_ATTR
293
294  void CField::autoTriggerIfNeeded(void)
295  TRY
296  {
297    if (mustAutoTrigger)
298      clientFromServerSourceFilter_->trigger(CContext::getCurrent()->getCalendar()->getCurrentDate());
299  }
300  CATCH_DUMP_ATTR
301
302
303  //----------------------------------------------------------------
304
305  StdString CField::GetName(void)    { return StdString("field"); }
306  StdString CField::GetDefName(void) { return CField::GetName(); }
307  ENodeType CField::GetType(void)    { return eField; }
308
309  //----------------------------------------------------------------
310
311  CGrid* CField::getRelGrid(void) const
312  TRY
313  {
314    return this->grid_;
315  }
316  CATCH
317
318  //----------------------------------------------------------------
319
320  CFile* CField::getRelFile(void) const
321  TRY
322  {
323    if (hasFileIn()) return this->fileIn_;
324    else if (hasFileOut()) return this->fileOut_ ;
325    else return nullptr ;
326  }
327  CATCH
328
329  func::CFunctor::ETimeType CField::getOperationTimeType() const
330  TRY
331  {
332    return operationTimeType;
333  }
334  CATCH
335
336
337  //----------------------------------------------------------------
338
339  bool CField::isActive(bool atCurrentTimestep /*= false*/) const
340  TRY
341  {
342    if (modelToClientSourceFilter_) 
343      return atCurrentTimestep ? modelToClientSourceFilter_->isDataExpected(CContext::getCurrent()->getCalendar()->getCurrentDate()) : true;
344    else if (clientToModelStoreFilter_)  return true;
345    else if (instantDataFilter)
346      ERROR("bool CField::isActive(bool atCurrentTimestep)",
347            << "Impossible to check if field [ id = " << getId() << " ] is active as it cannot be used to receive nor send data.");
348
349    return false;
350  }
351  CATCH
352
353  //----------------------------------------------------------------
354
355  bool CField::wasWritten() const
356  TRY
357  {
358    return written;
359  }
360  CATCH
361
362  void CField::setWritten()
363  TRY
364  {
365    written = true;
366  }
367  CATCH_DUMP_ATTR
368
369  //----------------------------------------------------------------
370
371  bool CField::getUseCompressedOutput() const
372  TRY
373  {
374    return useCompressedOutput;
375  }
376  CATCH
377
378  void CField::setUseCompressedOutput()
379  TRY
380  {
381    useCompressedOutput = true;
382  }
383  CATCH_DUMP_ATTR
384
385 
386  //----------------------------------------------------------------
387
388  void CField::updateRef(CGrid* grid)
389  TRY
390  {
391    if (!grid_ref.isEmpty()) grid_ref.setValue(grid->getId());
392    else
393    {
394      std::vector<CAxis*> axisTmp = grid->getAxis();
395      std::vector<CDomain*> domainTmp = grid->getDomains();
396      if ((1<axisTmp.size()) || (1<domainTmp.size()))
397        ERROR("void CField::updateRef(CGrid* grid)",
398          << "More than one domain or axis is available for domain_ref/axis_ref of field " << this->getId());
399
400      if ((!domain_ref.isEmpty()) && (domainTmp.empty()))
401        ERROR("void CField::updateRef(CGrid* grid)",
402          << "Incoherent between available domain and domain_ref of field " << this->getId());
403      if ((!axis_ref.isEmpty()) && (axisTmp.empty()))
404        ERROR("void CField::updateRef(CGrid* grid)",
405          << "Incoherent between available axis and axis_ref of field " << this->getId());
406
407      if (!domain_ref.isEmpty()) domain_ref.setValue(domainTmp[0]->getId());
408      if (!axis_ref.isEmpty()) axis_ref.setValue(axisTmp[0]->getId());
409    }
410  }
411  CATCH_DUMP_ATTR
412   
413
414  void CField::checkGridOfEnabledFields()
415  TRY
416  {
417    if (!isGridChecked)
418    {
419      isGridChecked = true;
420      solveCheckMaskIndex(false);
421    }
422  }
423  CATCH_DUMP_ATTR
424
425  void CField::sendGridComponentOfEnabledFields()
426  TRY
427  {
428    solveGridDomainAxisRef(true);
429    // solveCheckMaskIndex(true);
430  }
431  CATCH_DUMP_ATTR
432
433  void CField::sendGridOfEnabledFields()
434  TRY
435  {
436    // solveGridDomainAxisRef(true);
437    solveCheckMaskIndex(true);
438  }   
439  CATCH_DUMP_ATTR
440
441  /*!
442   * Compute the required buffer size to send the fields data.
443   * \param [in/out] bufferSize Modifying the bufferSize for the client context
444   * \param [in/out] maxEventSize Modifying the maximum event size for the client context
445   * \param [in] bufferForWriting True if buffers are used for sending data for writing
446   */ 
447  void CField::setContextClientDataBufferSize(map<CContextClient*,map<int,size_t>>& bufferSize, 
448                                              map<CContextClient*,map<int,size_t>>& maxEventSize, 
449                                              bool bufferForWriting)
450  {
451    auto& contextBufferSize = bufferSize[client] ;
452    auto& contextMaxEventSize = maxEventSize[client] ;
453    const std::map<int, size_t> mapSize = grid_->getDataBufferSize(client, getId(), bufferForWriting);
454    for(auto& it : mapSize )
455    {
456      // If contextBufferSize[it.first] does not exist, it will be zero-initialized
457      // so we can use it safely without checking for its existance
458      if (CXios::isOptPerformance) contextBufferSize[it.first] += it.second;
459      else if (contextBufferSize[it.first] < it.second) contextBufferSize[it.first] = it.second;
460
461      if (contextMaxEventSize[it.first] < it.second) contextMaxEventSize[it.first] = it.second;
462    }
463
464  }
465
466  void CField::setContextClientAttributesBufferSize(map<CContextClient*,map<int,size_t>>& bufferSize, 
467                                                   map<CContextClient*,map<int,size_t>>& maxEventSize, 
468                                                   bool bufferForWriting)
469  {
470    auto& contextBufferSize = bufferSize[client] ;
471    auto& contextMaxEventSize = maxEventSize[client] ;
472    const std::map<int, size_t> mapSize = grid_->getAttributesBufferSize(client, bufferForWriting);
473    for(auto& it : mapSize )
474    {
475      // If contextBufferSize[it.first] does not exist, it will be zero-initialized
476      // so we can use it safely without checking for its existance
477      if (contextBufferSize[it.first] < it.second) contextBufferSize[it.first] = it.second;
478      if (contextMaxEventSize[it.first] < it.second) contextMaxEventSize[it.first] = it.second;
479    }
480
481  }
482
483
484// ym obsolete to be removed
485  std::map<int, StdSize> CField::getGridAttributesBufferSize(CContextClient* client, bool bufferForWriting /*= "false"*/)
486  TRY
487  {
488    return grid_->getAttributesBufferSize(client, bufferForWriting);
489  }
490  CATCH_DUMP_ATTR
491
492// ym obsolete to be removed
493  std::map<int, StdSize> CField::getGridDataBufferSize(CContextClient* client, bool bufferForWriting /*= "false"*/)
494  TRY
495  {
496    return grid_->getDataBufferSize(client, getId(), bufferForWriting);
497  }
498  CATCH_DUMP_ATTR
499
500
501
502  size_t CField::getGlobalWrittenSize()
503  TRY
504  {
505    return grid_->getGlobalWrittenSize();
506  }
507  CATCH_DUMP_ATTR
508
509  //----------------------------------------------------------------
510
511  void CField::solveServerOperation(void)
512  TRY
513  {
514    CContext* context = CContext::getCurrent();
515
516    if (freq_op.isEmpty()) freq_op.setValue(TimeStep);
517
518    if (freq_offset.isEmpty()) freq_offset.setValue(NoneDu);
519
520    if (operation.isEmpty())
521      ERROR("void CField::solveServerOperation(void)",
522            << "An operation must be defined for field \"" << getId() << "\".");
523
524    std::shared_ptr<func::CFunctor> functor;
525    CArray<double, 1> dummyData;
526
527#define DECLARE_FUNCTOR(MType, mtype) \
528    if (operation.getValue().compare(#mtype) == 0) \
529    { \
530      functor.reset(new func::C##MType(dummyData)); \
531    }
532
533#include "functor_type.conf"
534
535    if (!functor)
536      ERROR("void CField::solveServerOperation(void)",
537            << "\"" << operation << "\" is not a valid operation.");
538
539    operationTimeType = functor->timeType();
540  }
541  CATCH_DUMP_ATTR
542
543 //----------------------------------------------------------------
544
545  bool CField::buildWorkflowGraph(CGarbageCollector& gc)
546  {
547    if (buildWorkflowGraphDone_) return true ;
548   
549    const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
550    const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
551
552    if (!inputFilter) inputFilter = std::shared_ptr<CPassThroughFilter>(new CPassThroughFilter(gc)); 
553     
554    if (hasDirectFieldReference())
555    {
556      CField* fieldRef = getDirectFieldReference();
557      bool ret=fieldRef->buildWorkflowGraph(gc); 
558      if (!ret) return false ; // workflow graph cannot be built at this stage
559    }
560
561    // now construct grid and check if element are enabled
562    solveGridReference() ; // grid_ is now defined
563    if (!isGridCompleted()) return false;
564
565    // Check if we have an expression to parse
566    std::shared_ptr<COutputPin> filterExpr ;
567    if (hasExpression())
568    {
569      boost::scoped_ptr<IFilterExprNode> expr(parseExpr(getExpression() + '\0'));
570      filterExpr = expr->reduce(gc, *this);
571      if (!filterExpr) return false ; // workflow graph cannot be built at this stage
572    }
573   
574    // prepare transformation. Need to know before if workflow of auxillary field can be built
575    if (hasDirectFieldReference())
576    {
577      auto gridPath=getGridPath() ;
578      gridPath.push_back(grid_) ;
579
580      CGrid* gridSrc=getDirectFieldReference()->getGrid() ;
581      std::shared_ptr<COutputPin> lastFilter ;
582      if (filterExpr) lastFilter=filterExpr ;
583      else lastFilter = inputFilter ;
584      CGrid* newGrid ;   
585     
586      for(auto grid : gridPath)
587      {
588        grid->solveElementsRefInheritance() ;
589       
590        // new
591       
592        std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters = grid->buildTransformationGraph(gc, false,  gridSrc, detectMissingValues, defaultValue, newGrid) ;
593        lastFilter->connectOutput(filters.first, 0);
594        lastFilter = filters.second;
595        gridSrc = newGrid ;
596
597        // end new
598/*
599        grid->completeGrid(gridSrc); // grid generation, to be checked
600        grid->checkElementsAttributes() ;
601        grid->prepareTransformGrid(gridSrc) ; // prepare the grid tranformation
602        for(auto fieldId : grid->getAuxInputTransformGrid()) // try to build workflow graph for auxillary field tranformation
603          if (!CField::get(fieldId)->buildWorkflowGraph(gc)) return false ;
604        gridSrc=grid ;
605*/
606      }
607
608    /* 
609      std::shared_ptr<COutputPin> lastFilter ;
610      if (filterExpr) lastFilter=filterExpr ;
611      else lastFilter = inputFilter ;
612     
613      gridSrc=getDirectFieldReference()->getGrid() ;
614      for(auto grid : gridPath)
615      {
616        grid->makeTransformGrid() ; // make the grid transformation
617        if (grid->hasTransform())
618        {
619          std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters = CSpatialTransformFilter::buildFilterGraph(gc, gridSrc, grid, detectMissingValues, defaultValue);
620          lastFilter->connectOutput(filters.first, 0);
621          lastFilter = filters.second;
622          gridSrc=grid ;
623        }
624      }
625    */
626      grid_=newGrid ;
627      grid_ref=grid_->getId() ; // for server
628      instantDataFilter = lastFilter ;
629     
630      // connect the input Filter to the reference
631      getDirectFieldReference()->getInstantDataFilter()->connectOutput(inputFilter,0);
632    }
633    else 
634    {
635      if (hasFileIn()) // input file, attemp to read the grid from file
636      {
637         // must be checked
638         fileIn_->initRead() ;
639         fileIn_->checkReadFile();
640         grid_->solveElementsRefInheritance() ;
641         if (fileIn_->isClientSide()) fileIn_->readFieldAttributesMetaData(this);
642         CGrid* newGrid ;
643         std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters = grid_->buildTransformationGraph(gc, true, nullptr, detectMissingValues, defaultValue, newGrid) ;
644         grid_ = newGrid ;
645         grid_ref=grid_->getId() ; // for server
646         //grid_->completeGrid(); // grid generation, to be checked
647         if (fileIn_->isClientSide()) fileIn_->readFieldAttributesValues(this);
648         grid_->checkElementsAttributes() ;
649//         grid_->solveDomainAxisBaseRef();
650         // probably in future tag grid incomplete if coming from a reading
651         instantDataFilter=inputFilter ;
652      } 
653      else if (hasCouplerIn())
654      {
655        grid_->checkElementsAttributes() ;
656        instantDataFilter=inputFilter ;
657      }
658      else
659      {
660        setModelIn() ; // no reference, the field is potentially a source field from model
661
662        grid_->solveElementsRefInheritance() ;
663        CGrid* newGrid ;
664        std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters = grid_->buildTransformationGraph(gc, true, nullptr, detectMissingValues, defaultValue, newGrid) ;
665        newGrid->duplicateAttributes(grid_) ; // for grid attributes (mask)
666        grid_ = newGrid ;
667        grid_ref=grid_->getId() ; // for server
668//        grid_->completeGrid(); // grid generation, to be checked => later
669        grid_->checkElementsAttributes() ;
670        instantDataFilter=inputFilter ;
671      }
672    }
673   
674    if (hasFileOut())
675    {
676      if (fileOut_->isServerSide())
677      {
678        this->solveServerOperation() ;
679      }
680    }
681
682    buildWorkflowGraphDone_ = true ;
683    workflowEnabled_ = true ;
684    return true ;
685  }
686   
687  /*!
688   * Connect field to filter to send data to server. A temporal filter is inserted before accordingly to the
689   * output frequency of the file
690   * \param gc the garbage collector to use when building the filter graph
691   */
692  void CField::connectToFileServer(CGarbageCollector& gc)
693  {
694    // insert temporal filter before sending to files
695    clientToServerStoreFilter_ = std::shared_ptr<CClientToServerStoreFilter>(new CClientToServerStoreFilter(gc, this, client));
696    // insert temporal filter before sending to files
697    getTemporalDataFilter(gc, fileOut_->output_freq)->connectOutput(clientToServerStoreFilter_, 0);
698  } 
699
700  void CField::connectToCouplerOut(CGarbageCollector& gc)
701  {
702    // insert temporal filter before sending to files
703    clientToServerStoreFilter_ = std::shared_ptr<CClientToServerStoreFilter>(new CClientToServerStoreFilter(gc, this, client));
704    instantDataFilter->connectOutput(clientToServerStoreFilter_, 0);
705  } 
706
707 
708  /*!
709   * Connect field to a source filter to receive data from model.
710   */
711  void CField::connectToModelInput(CGarbageCollector& gc)
712  {
713    const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
714    const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
715
716    if (check_if_active.isEmpty()) check_if_active = false; 
717    modelToClientSourceFilter_ = std::shared_ptr<CModelToClientSourceFilter>(new CModelToClientSourceFilter(gc, grid_, detectMissingValues, defaultValue));
718    modelToClientSourceFilter_ -> connectOutput(inputFilter,0) ;
719  } 
720 
721  /*!
722   * Connect field to a source filter to receive data from a client (on server side).
723   */
724  void CField::connectToClientInput(CGarbageCollector& gc)
725  {
726    serverFromClientSourceFilter_ = std::shared_ptr<CServerFromClientSourceFilter>(new CServerFromClientSourceFilter(gc,  grid_));
727    serverFromClientSourceFilter_ -> connectOutput(inputFilter,0) ;
728  } 
729
730
731  /*!
732   * Connect field to a source filter to receive data from a server (on client side).
733   */
734  void CField::connectToServerInput(CGarbageCollector& gc)
735  {
736    checkTimeAttributes();
737    clientFromServerSourceFilter_ = std::shared_ptr<CClientFromServerSourceFilter>(new CClientFromServerSourceFilter(gc,this)) ;
738    clientFromServerSourceFilter_ -> connectOutput(inputFilter,0) ;
739  } 
740
741  /*!
742   * Connect field to a source filter to receive data from coupler (on client side).
743   */
744   void CField::connectToCouplerIn(CGarbageCollector& gc)
745  {
746    CContext* context = CContext::getCurrent();
747
748    if (freq_op.isEmpty()) freq_op.setValue(TimeStep);
749    if (freq_offset.isEmpty()) freq_offset.setValue(freq_op.getValue() - TimeStep);
750    clientFromClientSourceFilter_ = std::shared_ptr<CClientFromClientSourceFilter>(new CClientFromClientSourceFilter(gc, this)) ;
751    clientFromClientSourceFilter_ -> connectOutput(inputFilter,0) ;
752   
753  } 
754
755  /*!
756   * Connect field to a file writer filter to write data in file (on server side).
757   */
758  void CField::connectToFileWriter(CGarbageCollector& gc)
759  {
760    fileWriterStoreFilter_ = std::shared_ptr<CFileWriterStoreFilter>(new CFileWriterStoreFilter(gc, this));
761    instantDataFilter->connectOutput(fileWriterStoreFilter_, 0);
762  } 
763
764  /*!
765   * Connect field to a file reader filter to read data from file (on server side).
766   */
767  void CField::connectToFileReader(CGarbageCollector& gc)
768  {
769    fileReaderSourceFilter_ = std::shared_ptr<CFileReaderSourceFilter>(new CFileReaderSourceFilter(gc, this));
770    fileReaderSourceFilter_->connectOutput(inputFilter, 0);
771  }
772
773
774  /*!
775   * Connect field to a store filter to output data to model on client Side
776   */
777  void CField::connectToModelOutput(CGarbageCollector& gc)
778  {
779    clientToModelStoreFilter_ = std::shared_ptr<CClientToModelStoreFilter>(new CClientToModelStoreFilter(gc, this));
780    instantDataFilter->connectOutput(clientToModelStoreFilter_, 0);
781  }
782
783
784 
785  void CField::connectToServerToClient(CGarbageCollector& gc)
786  {
787    serverToClientStoreFilter_ = std::shared_ptr<CServerToClientStoreFilter>(new CServerToClientStoreFilter(gc, this, client));
788    instantDataFilter->connectOutput(serverToClientStoreFilter_, 0);
789  }
790
791  /*!
792   * Transform the grid_path attribut into vector of grid.
793   * \return the vector CGrid* containing the list of grid path for tranformation
794   */ 
795  vector<CGrid*> CField::getGridPath(void)
796  {
797    std::vector<CGrid*> gridPath;
798
799    if (hasDirectFieldReference() && grid_ != getDirectFieldReference()->grid_)
800    {
801      if (!grid_path.isEmpty())
802      {
803        std::string gridId;
804        size_t start = 0, end;
805
806        do
807        {
808          end = grid_path.getValue().find(',', start);
809          if (end != std::string::npos)
810          {
811            gridId = grid_path.getValue().substr(start, end - start);
812            start = end + 1;
813          }
814          else gridId = grid_path.getValue().substr(start);
815
816          if (!CGrid::has(gridId))
817            ERROR("void CField::solveTransformedGrid()",
818               << "Invalid grid_path, the grid '" << gridId << "' does not exist.");
819
820          gridPath.push_back(CGrid::get(gridId));
821        }
822        while (end != std::string::npos);
823      }
824    }
825    return gridPath ;
826  }
827
828 
829 
830  /*!
831   * Returns the filter needed to handle a self reference in the field's expression.
832   * If the needed filter does not exist, it is created, otherwise it is reused.
833   * This method should only be called when building the filter graph corresponding
834   * to the field's expression.
835   *
836   * \param gc the garbage collector to use
837   * \return the output pin corresponding to a self reference
838   */
839
840/* old version
841  std::shared_ptr<COutputPin> CField::getSelfReference(CGarbageCollector& gc)
842  TRY
843  {
844    if (instantDataFilter || !hasExpression())
845      ERROR("COutputPin* CField::getSelfReference(CGarbageCollector& gc)",
846            "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
847
848    if (!selfReferenceFilter)
849    {
850      const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
851      const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
852
853      if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
854      {
855        if (!serverSourceFilter)
856        {
857          checkTimeAttributes();
858          serverSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid_, true, false, freq_offset, true,
859                                                              detectMissingValues, defaultValue));
860         }
861
862        selfReferenceFilter = serverSourceFilter;
863      }
864      else if (!field_ref.isEmpty())
865      {
866        CField* fieldRef = CField::get(field_ref);
867        fieldRef->buildFilterGraph(gc, false);
868        selfReferenceFilter = fieldRef->getInstantDataFilter();
869      }
870      else
871      {
872        if (!clientSourceFilter)
873        {
874          if (check_if_active.isEmpty()) check_if_active = false;
875          clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid_, true, true, NoneDu, false,
876                                                                                detectMissingValues, defaultValue));
877        }
878
879        selfReferenceFilter = clientSourceFilter;
880      }
881    }
882
883    return selfReferenceFilter;
884  }
885  CATCH_DUMP_ATTR
886*/
887  std::shared_ptr<COutputPin> CField::getSelfReference(CGarbageCollector& gc)
888  TRY
889  {
890    return inputFilter ;
891  } 
892  CATCH_DUMP_ATTR
893
894  /*!
895   * Returns the temporal filter corresponding to the field's temporal operation
896   * for the specified operation frequency. The filter is created if it does not
897   * exist, otherwise it is reused.
898   *
899   * \param gc the garbage collector to use
900   * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
901   * \return the output pin corresponding to the requested temporal filter
902   */
903  std::shared_ptr<COutputPin> CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
904  TRY
905  {
906    std::map<CDuration, std::shared_ptr<COutputPin> >::iterator it = temporalDataFilters.find(outFreq);
907
908    if (it == temporalDataFilters.end())
909    {
910      if (operation.isEmpty())
911        ERROR("void CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
912              << "An operation must be defined for field \"" << getId() << "\".");
913
914      checkTimeAttributes(&outFreq);
915
916      const bool detectMissingValues = (!detect_missing_value.isEmpty()  && detect_missing_value == true);
917      std::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
918                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
919                                                                             freq_op, freq_offset, outFreq, detectMissingValues));
920
921      instantDataFilter->connectOutput(temporalFilter, 0);
922
923      it = temporalDataFilters.insert(std::make_pair(outFreq, temporalFilter)).first;
924    }
925
926    return it->second;
927  }
928  CATCH_DUMP_ATTR
929
930  /*!
931    * Returns the temporal filter corresponding to the field's temporal operation
932    * for the specified operation frequency.
933    *
934    * \param gc the garbage collector to use
935    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
936    * \return the output pin corresponding to the requested temporal filter
937    */
938
939  std::shared_ptr<COutputPin> CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
940  TRY
941  {
942    if (instantDataFilter || !hasExpression())
943      ERROR("COutputPin* CField::getSelfTemporalDataFilter(CGarbageCollector& gc)",
944            "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
945   
946    if (selfTemporalDataFilter) return selfTemporalDataFilter;
947
948    if (hasDirectFieldReference())
949    {
950      CField* fieldRef=getDirectFieldReference();
951      return fieldRef->getTemporalDataFilter(gc, outFreq) ;
952    }
953    else
954    {
955      if (selfTemporalDataFilter) return selfTemporalDataFilter ;
956
957      if (operation.isEmpty())
958        ERROR("void CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
959              << "An operation must be defined for field \"" << getId() << "\".");
960
961      checkTimeAttributes(&outFreq); //bof
962
963      const bool detectMissingValues = (!detect_missing_value.isEmpty() && detect_missing_value == true);
964      selfTemporalDataFilter = std::shared_ptr<CTemporalFilter>(new CTemporalFilter(gc, operation,
965                                                                CContext::getCurrent()->getCalendar()->getInitDate(),
966                                                                freq_op, freq_offset, outFreq, detectMissingValues));
967
968      inputFilter->connectOutput(selfTemporalDataFilter, 0);
969      return selfTemporalDataFilter ;
970    }
971  }
972  CATCH_DUMP_ATTR
973
974/* old version   
975  std::shared_ptr<COutputPin> CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
976  TRY
977  {
978    if (instantDataFilter || !hasExpression())
979      ERROR("COutputPin* CField::getSelfTemporalDataFilter(CGarbageCollector& gc)",
980            "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
981
982    if (!selfReferenceFilter) getSelfReference(gc) ;
983
984    if (serverSourceFilter || clientSourceFilter)
985    {
986      if (operation.isEmpty())
987        ERROR("void CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
988              << "An operation must be defined for field \"" << getId() << "\".");
989
990      checkTimeAttributes(&outFreq);
991
992      const bool detectMissingValues = (!detect_missing_value.isEmpty() && detect_missing_value == true);
993      std::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
994                                                                          CContext::getCurrent()->getCalendar()->getInitDate(),
995                                                                          freq_op, freq_offset, outFreq, detectMissingValues));
996
997      selfReferenceFilter->connectOutput(temporalFilter, 0);
998      return temporalFilter ;
999    }
1000    else if (!field_ref.isEmpty())
1001    {
1002      CField* fieldRef = CField::get(field_ref);
1003      fieldRef->buildFilterGraph(gc, false);
1004      return fieldRef->getTemporalDataFilter(gc, outFreq) ;
1005    }
1006  }
1007  CATCH_DUMP_ATTR
1008*/
1009
1010  //----------------------------------------------------------------
1011/*
1012   void CField::fromBinary(StdIStream& is)
1013   {
1014      SuperClass::fromBinary(is);
1015#define CLEAR_ATT(name_)\
1016      SuperClassAttribute::operator[](#name_)->reset()
1017
1018         CLEAR_ATT(domain_ref);
1019         CLEAR_ATT(axis_ref);
1020#undef CLEAR_ATT
1021
1022   }
1023*/
1024   //----------------------------------------------------------------
1025
1026  void CField::solveGridReference(void)
1027  TRY
1028  {
1029    if (grid_!=nullptr) return ; // already done
1030
1031    if (grid_ref.isEmpty() && domain_ref.isEmpty() && axis_ref.isEmpty() && scalar_ref.isEmpty())
1032    {
1033      ERROR("CField::solveGridReference(void)",
1034            << "A grid must be defined for field '" << getFieldOutputName() << "' .");
1035    }
1036    else if (!grid_ref.isEmpty() && (!domain_ref.isEmpty() || !axis_ref.isEmpty() || !scalar_ref.isEmpty()))
1037    {
1038      ERROR("CField::solveGridReference(void)",
1039            << "Field '" << getFieldOutputName() << "' has both a grid and a domain/axis/scalar." << std::endl
1040            << "Please define either 'grid_ref' or 'domain_ref'/'axis_ref'/'scalar_ref'.");
1041    }
1042
1043    if (grid_ref.isEmpty())
1044    {
1045      std::vector<CDomain*> vecDom;
1046      std::vector<CAxis*> vecAxis;
1047      std::vector<CScalar*> vecScalar;
1048      std::vector<int> axisDomainOrderTmp;
1049
1050      std::vector<CDomain*> vecDomRef;
1051      std::vector<CAxis*> vecAxisRef;
1052      std::vector<CScalar*> vecScalarRef;
1053       
1054      if (!domain_ref.isEmpty())
1055      {
1056        StdString tmp = domain_ref.getValue();
1057        if (CDomain::has(domain_ref))
1058        {
1059          vecDom.push_back(CDomain::get(domain_ref));
1060          vecDomRef.push_back(CDomain::createDomain());
1061          vecDomRef.back()->domain_ref=domain_ref;
1062          axisDomainOrderTmp.push_back(2);
1063        }
1064        else  ERROR("CField::solveGridReference(void)",
1065                    << "Invalid reference to domain '" << domain_ref.getValue() << "'.");
1066      }
1067
1068      if (!axis_ref.isEmpty())
1069      {
1070        if (CAxis::has(axis_ref))
1071        {
1072          vecAxis.push_back(CAxis::get(axis_ref));
1073          vecAxisRef.push_back(CAxis::createAxis());
1074          vecAxisRef.back()->axis_ref=axis_ref;
1075          axisDomainOrderTmp.push_back(1);
1076        }
1077        else  ERROR("CField::solveGridReference(void)",
1078                    << "Invalid reference to axis '" << axis_ref.getValue() << "'.");
1079      }
1080
1081      if (!scalar_ref.isEmpty())
1082      {
1083        if (CScalar::has(scalar_ref))
1084        {
1085          vecScalar.push_back(CScalar::get(scalar_ref));
1086          vecScalarRef.push_back(CScalar::createScalar());
1087          vecScalarRef.back()->scalar_ref=scalar_ref;
1088          axisDomainOrderTmp.push_back(0);
1089        }
1090        else ERROR("CField::solveGridReference(void)",
1091                   << "Invalid reference to scalar '" << scalar_ref.getValue() << "'.");
1092      }
1093       
1094      CArray<int,1> axisDomainOrder(axisDomainOrderTmp.size());
1095      for (int idx = 0; idx < axisDomainOrderTmp.size(); ++idx)
1096      {
1097        axisDomainOrder(idx) = axisDomainOrderTmp[idx];
1098      }
1099
1100      // Warning: the gridId shouldn't be set as the grid_ref since it could be inherited
1101      StdString gridId = CGrid::generateId(vecDom, vecAxis, vecScalar,axisDomainOrder);
1102      if (CGrid::has(gridId)) this->grid_ = CGrid::get(gridId);
1103      else  this->grid_ = CGrid::createGrid(gridId, vecDomRef, vecAxisRef, vecScalarRef,axisDomainOrder);
1104    }
1105    else
1106    {
1107      if (CGrid::has(grid_ref)) this->grid_ = CGrid::get(grid_ref);
1108      else  ERROR("CField::solveGridReference(void)",
1109                   << "Invalid reference to grid '" << grid_ref.getValue() << "'.");
1110    }
1111  }
1112  CATCH_DUMP_ATTR
1113
1114  void CField::solveGridDomainAxisRef(bool checkAtt)
1115  TRY
1116  {
1117    grid_->solveDomainAxisRef(checkAtt);
1118  }
1119  CATCH_DUMP_ATTR
1120
1121  void CField::solveCheckMaskIndex(bool doSendingIndex)
1122  TRY
1123  {
1124    grid_->checkMaskIndex(doSendingIndex);
1125  }
1126  CATCH_DUMP_ATTR
1127
1128 
1129  void CField::solveGridDomainAxisBaseRef()
1130  TRY
1131  {
1132    grid_->solveDomainAxisRef(false);
1133    grid_->solveDomainAxisBaseRef();
1134  }
1135  CATCH_DUMP_ATTR
1136
1137  ///-------------------------------------------------------------------
1138
1139  template <>
1140  void CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)
1141  TRY
1142  {
1143    if (this->group_ref.isEmpty()) return;
1144    StdString gref = this->group_ref.getValue();
1145
1146    if (!CFieldGroup::has(gref))
1147      ERROR("CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)",
1148         << "[ gref = " << gref << "]"
1149         << " invalid group name !");
1150
1151    CFieldGroup* group = CFieldGroup::get(gref);
1152    CFieldGroup* owner = CFieldGroup::get(boost::polymorphic_downcast<CFieldGroup*>(this));
1153    owner->setAttributes(group); // inherite of attributes of group reference
1154     
1155    std::vector<CField*> allChildren  = group->getAllChildren();
1156    std::vector<CField*>::iterator it = allChildren.begin(), end = allChildren.end();
1157
1158    for (; it != end; it++)
1159    {
1160      CField* child = *it;
1161     if (child->hasId()) owner->createChild()->field_ref.setValue(child->getId());
1162    }
1163  }
1164  CATCH_DUMP_ATTR
1165
1166  ///-------------------------------------------------------------------
1167
1168  void CField::parse(xml::CXMLNode& node)
1169  TRY
1170  {
1171    string newContent ;
1172    SuperClass::parse(node);
1173    if (node.goToChildElement())
1174    {
1175      do
1176      {
1177        if (node.getElementName() == "variable" || node.getElementName() == "variable_group") this->getVirtualVariableGroup()->parseChild(node);
1178        else if (node.getElementName() == "expr") if (node.getContent(newContent)) content+=newContent ;
1179      } while (node.goToNextElement());
1180      node.goToParentElement();
1181    }
1182    if (node.getContent(newContent)) content=newContent ;
1183  }
1184  CATCH_DUMP_ATTR
1185
1186 /*!
1187   This function retrieves Id of corresponding domain_ref and axis_ref (if any)
1188   of a field. In some cases, only domain exists but axis doesn't
1189   \return pair of Domain and Axis id
1190  */
1191  const std::vector<StdString>& CField::getRefDomainAxisIds()
1192  TRY
1193  {
1194    CGrid* cgPtr = getRelGrid();
1195    if (NULL != cgPtr)
1196    {
1197      std::vector<StdString>::iterator it;
1198      if (!domain_ref.isEmpty())
1199      {
1200        std::vector<StdString> domainList = cgPtr->getDomainList();
1201        it = std::find(domainList.begin(), domainList.end(), domain_ref.getValue());
1202        if (domainList.end() != it) domAxisScalarIds_[0] = *it;
1203      }
1204
1205      if (!axis_ref.isEmpty())
1206      {
1207        std::vector<StdString> axisList = cgPtr->getAxisList();
1208        it = std::find(axisList.begin(), axisList.end(), axis_ref.getValue());
1209        if (axisList.end() != it) domAxisScalarIds_[1] = *it;
1210      }
1211
1212      if (!scalar_ref.isEmpty())
1213      {
1214        std::vector<StdString> scalarList = cgPtr->getScalarList();
1215        it = std::find(scalarList.begin(), scalarList.end(), scalar_ref.getValue());
1216        if (scalarList.end() != it) domAxisScalarIds_[2] = *it;
1217      }
1218    }
1219    return (domAxisScalarIds_);
1220  }
1221  CATCH_DUMP_ATTR
1222
1223  CVariable* CField::addVariable(const string& id)
1224  TRY
1225  {
1226    return vVariableGroup->createChild(id);
1227  }
1228  CATCH
1229
1230  CVariableGroup* CField::addVariableGroup(const string& id)
1231  TRY
1232  {
1233    return vVariableGroup->createChildGroup(id);
1234  }
1235  CATCH
1236
1237  void CField::setContextClient(CContextClient* contextClient)
1238  TRY
1239  {
1240    CContext* context = CContext::getCurrent();
1241    client = contextClient;
1242 
1243    // A grid is sent by a client (both for read or write) or by primary server (write only)
1244    if (context->getServiceType()==CServicesManager::GATHERER)
1245    {
1246      if (getRelFile()->mode.isEmpty() || (!getRelFile()->mode.isEmpty() && getRelFile()->mode == CFile::mode_attr::write))
1247        grid_->setContextClient(contextClient);
1248    }
1249    else if (context->getServiceType()==CServicesManager::CLIENT)
1250      grid_->setContextClient(contextClient);
1251  }
1252  CATCH_DUMP_ATTR
1253
1254  void CField::sendCloseDefinition(void)
1255  {
1256    CContext::getCurrent()->sendCloseDefinition(client) ;
1257  }
1258
1259  void CField::sendFieldToFileServer(void)
1260  {
1261    CContext::getCurrent()->sendContextToFileServer(client);
1262    getRelFile()->sendFileToFileServer(client);
1263    sentGrid_ = grid_-> duplicateSentGrid() ;
1264    sentGrid_->sendGridToFileServer(client);
1265    name = getFieldOutputName() ;
1266    this->sendAllAttributesToServer(client);
1267    this->sendAddAllVariables(client);
1268  }
1269
1270  void CField::sendFieldToInputFileServer(void)
1271  {
1272    CContext::getCurrent()->sendContextToFileServer(client);
1273    getRelFile()->sendFileToFileServer(client);
1274    sentGrid_ = grid_-> duplicateSentGrid() ;
1275    sentGrid_->sendGridToFileServer(client);
1276    read_access=true ; // not the best solution, but on server side, the field must be a starting point of the workflow
1277                       // must be replace by a better solution when implementing filters for reading and send to client
1278                       // on server side
1279    this->sendAllAttributesToServer(client);
1280    this->sendAddAllVariables(client);
1281  }
1282
1283  void CField::sendFieldToCouplerOut(void)
1284  {
1285    if (sendFieldToCouplerOut_done_) return ;
1286    else sendFieldToCouplerOut_done_=true ;
1287    grid_->sendGridToCouplerOut(client, this->getId());
1288    this->sendGridCompleted();
1289
1290  }
1291 
1292  void CField::makeGridAliasForCoupling(void) 
1293  { 
1294    grid_->makeAliasForCoupling(this->getId()); 
1295  }
1296
1297 //! Client side: Send a message  announcing that the grid definition has been received from a coupling context
1298   void CField::sendGridCompleted(void)
1299   TRY
1300   {
1301      CEventClient event(getType(),EVENT_ID_GRID_COMPLETED);
1302
1303      if (client->isServerLeader())
1304      {
1305        CMessage msg;
1306        msg<<this->getId();
1307        for (auto& rank : client->getRanksServerLeader()) event.push(rank,1,msg);
1308        client->sendEvent(event);
1309      }
1310      else client->sendEvent(event);
1311   }
1312   CATCH_DUMP_ATTR
1313
1314   //! Server side: Receive a message announcing that the grid definition has been received from a coupling context
1315   void CField::recvGridCompleted(CEventServer& event)
1316   TRY
1317   {
1318      CBufferIn* buffer=event.subEvents.begin()->buffer;
1319      string id;
1320      *buffer>>id ;
1321      get(id)->recvGridCompleted(*buffer);
1322   }
1323   CATCH
1324
1325   //! Server side: Receive a message  message  announcing that the grid definition has been received from a coupling context
1326   void CField::recvGridCompleted(CBufferIn& buffer)
1327   TRY
1328   {
1329      setGridCompleted() ;
1330   }
1331   CATCH_DUMP_ATTR
1332
1333
1334  void CField::sendAddAllVariables(CContextClient* client)
1335  TRY
1336  {
1337    std::vector<CVariable*> allVar = getAllVariables();
1338    std::vector<CVariable*>::const_iterator it = allVar.begin();
1339    std::vector<CVariable*>::const_iterator itE = allVar.end();
1340
1341    for (; it != itE; ++it)
1342    {
1343      this->sendAddVariable((*it)->getId(), client);
1344      (*it)->sendAllAttributesToServer(client);
1345      (*it)->sendValue(client);
1346    }
1347  }
1348  CATCH_DUMP_ATTR
1349
1350  /*!
1351   * Send all Attributes to server. This method is overloaded, since only grid_ref attribute
1352   * must be sent to server and not domain_ref/axis_ref/scalar_ref.
1353   */
1354   
1355  void CField::sendAllAttributesToServer(CContextClient* client)
1356  TRY
1357  {
1358    if (grid_ref.isEmpty())
1359    {
1360      grid_ref=sentGrid_->getId() ;
1361      SuperClass::sendAllAttributesToServer(client) ;
1362      domain_ref.reset() ;
1363      axis_ref.reset() ;
1364      scalar_ref.reset() ;
1365      grid_ref.reset();
1366    }
1367    else 
1368    {
1369      string tmp = grid_ref;
1370      grid_ref = sentGrid_->getId() ;
1371      SuperClass::sendAllAttributesToServer(client) ;
1372      grid_ref = tmp ;
1373    }
1374  }
1375  CATCH_DUMP_ATTR
1376   
1377  void CField::sendAddVariable(const string& id, CContextClient* client)
1378  TRY
1379  {
1380    sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE, client);
1381  }
1382  CATCH_DUMP_ATTR
1383
1384  void CField::sendAddVariableGroup(const string& id, CContextClient* client)
1385  TRY
1386  {
1387    sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE_GROUP, client);
1388  }
1389  CATCH_DUMP_ATTR
1390
1391  void CField::recvAddVariable(CEventServer& event)
1392  TRY
1393  {
1394    CBufferIn* buffer = event.subEvents.begin()->buffer;
1395    string id;
1396    *buffer >> id;
1397    get(id)->recvAddVariable(*buffer);
1398  }
1399  CATCH
1400
1401  void CField::recvAddVariable(CBufferIn& buffer)
1402  TRY
1403  {
1404    string id;
1405    buffer >> id;
1406    addVariable(id);
1407  }
1408  CATCH_DUMP_ATTR
1409
1410  void CField::recvAddVariableGroup(CEventServer& event)
1411  TRY
1412  {
1413    CBufferIn* buffer = event.subEvents.begin()->buffer;
1414    string id;
1415    *buffer >> id;
1416    get(id)->recvAddVariableGroup(*buffer);
1417  }
1418  CATCH
1419
1420  void CField::recvAddVariableGroup(CBufferIn& buffer)
1421  TRY
1422  {
1423    string id;
1424    buffer >> id;
1425    addVariableGroup(id);
1426  }
1427  CATCH_DUMP_ATTR
1428
1429  /*!
1430   * Check on freq_off and freq_op attributes.
1431   */
1432  void CField::checkTimeAttributes(CDuration* freqOp)
1433  TRY
1434  {
1435    if (hasFileIn() && !(operation.getValue() == "instant" || operation.getValue() == "once") )     
1436      ERROR("void CField::checkTimeAttributes(void)",
1437         << "Unsupported operation for field '" << getFieldOutputName() << "'." << std::endl
1438         << "Currently only \"instant\" is supported for fields read from file.")
1439
1440    if (freq_op.isEmpty())
1441    {
1442      if (operation.getValue() == "instant")
1443      {
1444        if (hasFileIn() || hasFileOut()) freq_op.setValue(getRelFile()->output_freq.getValue());
1445        else freq_op=*freqOp ;
1446      }
1447      else freq_op.setValue(TimeStep);
1448    }
1449    if (freq_offset.isEmpty()) freq_offset.setValue(hasFileIn() ? NoneDu : (freq_op.getValue() - TimeStep));
1450  }
1451  CATCH_DUMP_ATTR
1452
1453  /*!
1454   * Returns string arithmetic expression associated to the field.
1455   * \return if content is defined return content string, otherwise, if "expr" attribute is defined, return expr string.
1456   */
1457  const string& CField::getExpression(void)
1458  TRY
1459  {
1460    if (!expr.isEmpty() && content.empty())
1461    {
1462      content = expr;
1463      expr.reset();
1464    }
1465
1466    return content;
1467  }
1468  CATCH_DUMP_ATTR
1469
1470  bool CField::hasExpression(void) const
1471  TRY
1472  {
1473    return (!expr.isEmpty() || !content.empty());
1474  }
1475  CATCH
1476
1477  bool CField::hasGridMask(void) const
1478  TRY
1479  {
1480    return (this->grid_->hasMask());
1481  }
1482  CATCH
1483
1484  DEFINE_REF_FUNC(Field,field)
1485} // namespace xios
Note: See TracBrowser for help on using the repository browser.