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

Last change on this file since 2018 was 2018, checked in by ymipsl, 3 years ago

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