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

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

Reimplement coupling in the new infrastructure.
Tested for 2-way coupling toy model.

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: 45.5 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        std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters = grid->buildTransformationGraph(gc, false,  gridSrc, detectMissingValues, defaultValue, newGrid) ;
589        lastFilter->connectOutput(filters.first, 0);
590        lastFilter = filters.second;
591        gridSrc = newGrid ;
592      }
593
594      grid_=newGrid ;
595      grid_ref=grid_->getId() ; // for server
596      instantDataFilter = lastFilter ;
597     
598      // connect the input Filter to the reference
599      getDirectFieldReference()->getInstantDataFilter()->connectOutput(inputFilter,0);
600    }
601    else 
602    {
603      if (hasFileIn()) // input file, attemp to read the grid from file
604      {
605         // must be checked
606         fileIn_->initRead() ;
607         fileIn_->checkReadFile();
608         grid_->solveElementsRefInheritance() ;
609         if (fileIn_->isClientSide()) fileIn_->readFieldAttributesMetaData(this);
610         CGrid* newGrid ;
611         std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters = grid_->buildTransformationGraph(gc, true, nullptr, detectMissingValues, defaultValue, newGrid) ;
612         grid_ = newGrid ;
613         grid_ref=grid_->getId() ; // for server
614         //grid_->completeGrid(); // grid generation, to be checked
615         if (fileIn_->isClientSide()) fileIn_->readFieldAttributesValues(this);
616         grid_->checkElementsAttributes() ;
617//         grid_->solveDomainAxisBaseRef();
618         // probably in future tag grid incomplete if coming from a reading
619         instantDataFilter=inputFilter ;
620      } 
621      else if (hasCouplerIn())
622      {
623        grid_->checkElementsAttributes() ;
624        instantDataFilter=inputFilter ;
625      }
626      else
627      {
628        setModelIn() ; // no reference, the field is potentially a source field from model
629
630        grid_->solveElementsRefInheritance() ;
631        CGrid* newGrid ;
632        std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters = grid_->buildTransformationGraph(gc, true, nullptr, detectMissingValues, defaultValue, newGrid) ;
633        newGrid->duplicateAttributes(grid_) ; // for grid attributes (mask)
634        grid_ = newGrid ;
635        grid_ref=grid_->getId() ; // for server
636        grid_->checkElementsAttributes() ;
637        instantDataFilter=inputFilter ;
638      }
639    }
640   
641    if (hasFileOut())
642    {
643      if (fileOut_->isServerSide())
644      {
645        this->solveServerOperation() ;
646      }
647    }
648
649    buildWorkflowGraphDone_ = true ;
650    workflowEnabled_ = true ;
651    return true ;
652  }
653   
654  /*!
655   * Connect field to filter to send data to server. A temporal filter is inserted before accordingly to the
656   * output frequency of the file
657   * \param gc the garbage collector to use when building the filter graph
658   */
659  void CField::connectToFileServer(CGarbageCollector& gc)
660  {
661    // insert temporal filter before sending to files
662    clientToServerStoreFilter_ = std::shared_ptr<CClientToServerStoreFilter>(new CClientToServerStoreFilter(gc, this, client));
663    // insert temporal filter before sending to files
664    getTemporalDataFilter(gc, fileOut_->output_freq)->connectOutput(clientToServerStoreFilter_, 0);
665  } 
666
667  void CField::connectToCouplerOut(CGarbageCollector& gc)
668  {
669    // insert temporal filter before sending to files
670    clientToServerStoreFilter_ = std::shared_ptr<CClientToServerStoreFilter>(new CClientToServerStoreFilter(gc, this, client));
671    instantDataFilter->connectOutput(clientToServerStoreFilter_, 0);
672  } 
673
674 
675  /*!
676   * Connect field to a source filter to receive data from model.
677   */
678  void CField::connectToModelInput(CGarbageCollector& gc)
679  {
680    const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
681    const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
682
683    if (check_if_active.isEmpty()) check_if_active = false; 
684    modelToClientSourceFilter_ = std::shared_ptr<CModelToClientSourceFilter>(new CModelToClientSourceFilter(gc, grid_, detectMissingValues, defaultValue));
685    modelToClientSourceFilter_ -> connectOutput(inputFilter,0) ;
686  } 
687 
688  /*!
689   * Connect field to a source filter to receive data from a client (on server side).
690   */
691  void CField::connectToClientInput(CGarbageCollector& gc)
692  {
693    serverFromClientSourceFilter_ = std::shared_ptr<CServerFromClientSourceFilter>(new CServerFromClientSourceFilter(gc,  grid_));
694    serverFromClientSourceFilter_ -> connectOutput(inputFilter,0) ;
695  } 
696
697
698  /*!
699   * Connect field to a source filter to receive data from a server (on client side).
700   */
701  void CField::connectToServerInput(CGarbageCollector& gc)
702  {
703    checkTimeAttributes();
704    clientFromServerSourceFilter_ = std::shared_ptr<CClientFromServerSourceFilter>(new CClientFromServerSourceFilter(gc,this)) ;
705    clientFromServerSourceFilter_ -> connectOutput(inputFilter,0) ;
706  } 
707
708  /*!
709   * Connect field to a source filter to receive data from coupler (on client side).
710   */
711   void CField::connectToCouplerIn(CGarbageCollector& gc)
712  {
713    CContext* context = CContext::getCurrent();
714
715    if (freq_op.isEmpty()) freq_op.setValue(TimeStep);
716    if (freq_offset.isEmpty()) freq_offset.setValue(freq_op.getValue() - TimeStep);
717    clientFromClientSourceFilter_ = std::shared_ptr<CClientFromClientSourceFilter>(new CClientFromClientSourceFilter(gc, this)) ;
718    clientFromClientSourceFilter_ -> connectOutput(inputFilter,0) ;
719   
720  } 
721
722  /*!
723   * Connect field to a file writer filter to write data in file (on server side).
724   */
725  void CField::connectToFileWriter(CGarbageCollector& gc)
726  {
727    fileWriterStoreFilter_ = std::shared_ptr<CFileWriterStoreFilter>(new CFileWriterStoreFilter(gc, this));
728    instantDataFilter->connectOutput(fileWriterStoreFilter_, 0);
729  } 
730
731  /*!
732   * Connect field to a file reader filter to read data from file (on server side).
733   */
734  void CField::connectToFileReader(CGarbageCollector& gc)
735  {
736    fileReaderSourceFilter_ = std::shared_ptr<CFileReaderSourceFilter>(new CFileReaderSourceFilter(gc, this));
737    fileReaderSourceFilter_->connectOutput(inputFilter, 0);
738  }
739
740
741  /*!
742   * Connect field to a store filter to output data to model on client Side
743   */
744  void CField::connectToModelOutput(CGarbageCollector& gc)
745  {
746    clientToModelStoreFilter_ = std::shared_ptr<CClientToModelStoreFilter>(new CClientToModelStoreFilter(gc, this));
747    instantDataFilter->connectOutput(clientToModelStoreFilter_, 0);
748  }
749
750
751 
752  void CField::connectToServerToClient(CGarbageCollector& gc)
753  {
754    serverToClientStoreFilter_ = std::shared_ptr<CServerToClientStoreFilter>(new CServerToClientStoreFilter(gc, this, client));
755    instantDataFilter->connectOutput(serverToClientStoreFilter_, 0);
756  }
757
758  /*!
759   * Transform the grid_path attribut into vector of grid.
760   * \return the vector CGrid* containing the list of grid path for tranformation
761   */ 
762  vector<CGrid*> CField::getGridPath(void)
763  {
764    std::vector<CGrid*> gridPath;
765
766    if (hasDirectFieldReference() && grid_ != getDirectFieldReference()->grid_)
767    {
768      if (!grid_path.isEmpty())
769      {
770        std::string gridId;
771        size_t start = 0, end;
772
773        do
774        {
775          end = grid_path.getValue().find(',', start);
776          if (end != std::string::npos)
777          {
778            gridId = grid_path.getValue().substr(start, end - start);
779            start = end + 1;
780          }
781          else gridId = grid_path.getValue().substr(start);
782
783          if (!CGrid::has(gridId))
784            ERROR("void CField::solveTransformedGrid()",
785               << "Invalid grid_path, the grid '" << gridId << "' does not exist.");
786
787          gridPath.push_back(CGrid::get(gridId));
788        }
789        while (end != std::string::npos);
790      }
791    }
792    return gridPath ;
793  }
794
795 
796 
797  /*!
798   * Returns the filter needed to handle a self reference in the field's expression.
799   * If the needed filter does not exist, it is created, otherwise it is reused.
800   * This method should only be called when building the filter graph corresponding
801   * to the field's expression.
802   *
803   * \param gc the garbage collector to use
804   * \return the output pin corresponding to a self reference
805   */
806
807/* old version
808  std::shared_ptr<COutputPin> CField::getSelfReference(CGarbageCollector& gc)
809  TRY
810  {
811    if (instantDataFilter || !hasExpression())
812      ERROR("COutputPin* CField::getSelfReference(CGarbageCollector& gc)",
813            "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
814
815    if (!selfReferenceFilter)
816    {
817      const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
818      const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
819
820      if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
821      {
822        if (!serverSourceFilter)
823        {
824          checkTimeAttributes();
825          serverSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid_, true, false, freq_offset, true,
826                                                              detectMissingValues, defaultValue));
827         }
828
829        selfReferenceFilter = serverSourceFilter;
830      }
831      else if (!field_ref.isEmpty())
832      {
833        CField* fieldRef = CField::get(field_ref);
834        fieldRef->buildFilterGraph(gc, false);
835        selfReferenceFilter = fieldRef->getInstantDataFilter();
836      }
837      else
838      {
839        if (!clientSourceFilter)
840        {
841          if (check_if_active.isEmpty()) check_if_active = false;
842          clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid_, true, true, NoneDu, false,
843                                                                                detectMissingValues, defaultValue));
844        }
845
846        selfReferenceFilter = clientSourceFilter;
847      }
848    }
849
850    return selfReferenceFilter;
851  }
852  CATCH_DUMP_ATTR
853*/
854  std::shared_ptr<COutputPin> CField::getSelfReference(CGarbageCollector& gc)
855  TRY
856  {
857    return inputFilter ;
858  } 
859  CATCH_DUMP_ATTR
860
861  /*!
862   * Returns the temporal filter corresponding to the field's temporal operation
863   * for the specified operation frequency. The filter is created if it does not
864   * exist, otherwise it is reused.
865   *
866   * \param gc the garbage collector to use
867   * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
868   * \return the output pin corresponding to the requested temporal filter
869   */
870  std::shared_ptr<COutputPin> CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
871  TRY
872  {
873    std::map<CDuration, std::shared_ptr<COutputPin> >::iterator it = temporalDataFilters.find(outFreq);
874
875    if (it == temporalDataFilters.end())
876    {
877      if (operation.isEmpty())
878        ERROR("void CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
879              << "An operation must be defined for field \"" << getId() << "\".");
880
881      checkTimeAttributes(&outFreq);
882
883      const bool detectMissingValues = (!detect_missing_value.isEmpty()  && detect_missing_value == true);
884      std::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
885                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
886                                                                             freq_op, freq_offset, outFreq, detectMissingValues));
887
888      instantDataFilter->connectOutput(temporalFilter, 0);
889
890      it = temporalDataFilters.insert(std::make_pair(outFreq, temporalFilter)).first;
891    }
892
893    return it->second;
894  }
895  CATCH_DUMP_ATTR
896
897  /*!
898    * Returns the temporal filter corresponding to the field's temporal operation
899    * for the specified operation frequency.
900    *
901    * \param gc the garbage collector to use
902    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
903    * \return the output pin corresponding to the requested temporal filter
904    */
905
906  std::shared_ptr<COutputPin> CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
907  TRY
908  {
909    if (instantDataFilter || !hasExpression())
910      ERROR("COutputPin* CField::getSelfTemporalDataFilter(CGarbageCollector& gc)",
911            "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
912   
913    if (selfTemporalDataFilter) return selfTemporalDataFilter;
914
915    if (hasDirectFieldReference())
916    {
917      CField* fieldRef=getDirectFieldReference();
918      return fieldRef->getTemporalDataFilter(gc, outFreq) ;
919    }
920    else
921    {
922      if (selfTemporalDataFilter) return selfTemporalDataFilter ;
923
924      if (operation.isEmpty())
925        ERROR("void CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
926              << "An operation must be defined for field \"" << getId() << "\".");
927
928      checkTimeAttributes(&outFreq); //bof
929
930      const bool detectMissingValues = (!detect_missing_value.isEmpty() && detect_missing_value == true);
931      selfTemporalDataFilter = std::shared_ptr<CTemporalFilter>(new CTemporalFilter(gc, operation,
932                                                                CContext::getCurrent()->getCalendar()->getInitDate(),
933                                                                freq_op, freq_offset, outFreq, detectMissingValues));
934
935      inputFilter->connectOutput(selfTemporalDataFilter, 0);
936      return selfTemporalDataFilter ;
937    }
938  }
939  CATCH_DUMP_ATTR
940
941/* old version   
942  std::shared_ptr<COutputPin> CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
943  TRY
944  {
945    if (instantDataFilter || !hasExpression())
946      ERROR("COutputPin* CField::getSelfTemporalDataFilter(CGarbageCollector& gc)",
947            "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
948
949    if (!selfReferenceFilter) getSelfReference(gc) ;
950
951    if (serverSourceFilter || clientSourceFilter)
952    {
953      if (operation.isEmpty())
954        ERROR("void CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
955              << "An operation must be defined for field \"" << getId() << "\".");
956
957      checkTimeAttributes(&outFreq);
958
959      const bool detectMissingValues = (!detect_missing_value.isEmpty() && detect_missing_value == true);
960      std::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
961                                                                          CContext::getCurrent()->getCalendar()->getInitDate(),
962                                                                          freq_op, freq_offset, outFreq, detectMissingValues));
963
964      selfReferenceFilter->connectOutput(temporalFilter, 0);
965      return temporalFilter ;
966    }
967    else if (!field_ref.isEmpty())
968    {
969      CField* fieldRef = CField::get(field_ref);
970      fieldRef->buildFilterGraph(gc, false);
971      return fieldRef->getTemporalDataFilter(gc, outFreq) ;
972    }
973  }
974  CATCH_DUMP_ATTR
975*/
976
977  //----------------------------------------------------------------
978/*
979   void CField::fromBinary(StdIStream& is)
980   {
981      SuperClass::fromBinary(is);
982#define CLEAR_ATT(name_)\
983      SuperClassAttribute::operator[](#name_)->reset()
984
985         CLEAR_ATT(domain_ref);
986         CLEAR_ATT(axis_ref);
987#undef CLEAR_ATT
988
989   }
990*/
991   //----------------------------------------------------------------
992
993  void CField::solveGridReference(void)
994  TRY
995  {
996    if (grid_!=nullptr) return ; // already done
997
998    if (grid_ref.isEmpty() && domain_ref.isEmpty() && axis_ref.isEmpty() && scalar_ref.isEmpty())
999    {
1000      ERROR("CField::solveGridReference(void)",
1001            << "A grid must be defined for field '" << getFieldOutputName() << "' .");
1002    }
1003    else if (!grid_ref.isEmpty() && (!domain_ref.isEmpty() || !axis_ref.isEmpty() || !scalar_ref.isEmpty()))
1004    {
1005      ERROR("CField::solveGridReference(void)",
1006            << "Field '" << getFieldOutputName() << "' has both a grid and a domain/axis/scalar." << std::endl
1007            << "Please define either 'grid_ref' or 'domain_ref'/'axis_ref'/'scalar_ref'.");
1008    }
1009
1010    if (grid_ref.isEmpty())
1011    {
1012      std::vector<CDomain*> vecDom;
1013      std::vector<CAxis*> vecAxis;
1014      std::vector<CScalar*> vecScalar;
1015      std::vector<int> axisDomainOrderTmp;
1016
1017      std::vector<CDomain*> vecDomRef;
1018      std::vector<CAxis*> vecAxisRef;
1019      std::vector<CScalar*> vecScalarRef;
1020       
1021      if (!domain_ref.isEmpty())
1022      {
1023        StdString tmp = domain_ref.getValue();
1024        if (CDomain::has(domain_ref))
1025        {
1026          vecDom.push_back(CDomain::get(domain_ref));
1027          vecDomRef.push_back(CDomain::createDomain());
1028          vecDomRef.back()->domain_ref=domain_ref;
1029          axisDomainOrderTmp.push_back(2);
1030        }
1031        else  ERROR("CField::solveGridReference(void)",
1032                    << "Invalid reference to domain '" << domain_ref.getValue() << "'.");
1033      }
1034
1035      if (!axis_ref.isEmpty())
1036      {
1037        if (CAxis::has(axis_ref))
1038        {
1039          vecAxis.push_back(CAxis::get(axis_ref));
1040          vecAxisRef.push_back(CAxis::createAxis());
1041          vecAxisRef.back()->axis_ref=axis_ref;
1042          axisDomainOrderTmp.push_back(1);
1043        }
1044        else  ERROR("CField::solveGridReference(void)",
1045                    << "Invalid reference to axis '" << axis_ref.getValue() << "'.");
1046      }
1047
1048      if (!scalar_ref.isEmpty())
1049      {
1050        if (CScalar::has(scalar_ref))
1051        {
1052          vecScalar.push_back(CScalar::get(scalar_ref));
1053          vecScalarRef.push_back(CScalar::createScalar());
1054          vecScalarRef.back()->scalar_ref=scalar_ref;
1055          axisDomainOrderTmp.push_back(0);
1056        }
1057        else ERROR("CField::solveGridReference(void)",
1058                   << "Invalid reference to scalar '" << scalar_ref.getValue() << "'.");
1059      }
1060       
1061      CArray<int,1> axisDomainOrder(axisDomainOrderTmp.size());
1062      for (int idx = 0; idx < axisDomainOrderTmp.size(); ++idx)
1063      {
1064        axisDomainOrder(idx) = axisDomainOrderTmp[idx];
1065      }
1066
1067      // Warning: the gridId shouldn't be set as the grid_ref since it could be inherited
1068      StdString gridId = CGrid::generateId(vecDom, vecAxis, vecScalar,axisDomainOrder);
1069      if (CGrid::has(gridId)) this->grid_ = CGrid::get(gridId);
1070      else  this->grid_ = CGrid::createGrid(gridId, vecDomRef, vecAxisRef, vecScalarRef,axisDomainOrder);
1071    }
1072    else
1073    {
1074      if (CGrid::has(grid_ref)) this->grid_ = CGrid::get(grid_ref);
1075      else  ERROR("CField::solveGridReference(void)",
1076                   << "Invalid reference to grid '" << grid_ref.getValue() << "'.");
1077    }
1078  }
1079  CATCH_DUMP_ATTR
1080
1081  void CField::solveGridDomainAxisRef(bool checkAtt)
1082  TRY
1083  {
1084    grid_->solveDomainAxisRef(checkAtt);
1085  }
1086  CATCH_DUMP_ATTR
1087
1088  void CField::solveCheckMaskIndex(bool doSendingIndex)
1089  TRY
1090  {
1091    grid_->checkMaskIndex(doSendingIndex);
1092  }
1093  CATCH_DUMP_ATTR
1094
1095 
1096  void CField::solveGridDomainAxisBaseRef()
1097  TRY
1098  {
1099    grid_->solveDomainAxisRef(false);
1100    grid_->solveDomainAxisBaseRef();
1101  }
1102  CATCH_DUMP_ATTR
1103
1104  ///-------------------------------------------------------------------
1105
1106  template <>
1107  void CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)
1108  TRY
1109  {
1110    if (this->group_ref.isEmpty()) return;
1111    StdString gref = this->group_ref.getValue();
1112
1113    if (!CFieldGroup::has(gref))
1114      ERROR("CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)",
1115         << "[ gref = " << gref << "]"
1116         << " invalid group name !");
1117
1118    CFieldGroup* group = CFieldGroup::get(gref);
1119    CFieldGroup* owner = CFieldGroup::get(boost::polymorphic_downcast<CFieldGroup*>(this));
1120    owner->setAttributes(group); // inherite of attributes of group reference
1121     
1122    std::vector<CField*> allChildren  = group->getAllChildren();
1123    std::vector<CField*>::iterator it = allChildren.begin(), end = allChildren.end();
1124
1125    for (; it != end; it++)
1126    {
1127      CField* child = *it;
1128     if (child->hasId()) owner->createChild()->field_ref.setValue(child->getId());
1129    }
1130  }
1131  CATCH_DUMP_ATTR
1132
1133  ///-------------------------------------------------------------------
1134
1135  void CField::parse(xml::CXMLNode& node)
1136  TRY
1137  {
1138    string newContent ;
1139    SuperClass::parse(node);
1140    if (node.goToChildElement())
1141    {
1142      do
1143      {
1144        if (node.getElementName() == "variable" || node.getElementName() == "variable_group") this->getVirtualVariableGroup()->parseChild(node);
1145        else if (node.getElementName() == "expr") if (node.getContent(newContent)) content+=newContent ;
1146      } while (node.goToNextElement());
1147      node.goToParentElement();
1148    }
1149    if (node.getContent(newContent)) content=newContent ;
1150  }
1151  CATCH_DUMP_ATTR
1152
1153 /*!
1154   This function retrieves Id of corresponding domain_ref and axis_ref (if any)
1155   of a field. In some cases, only domain exists but axis doesn't
1156   \return pair of Domain and Axis id
1157  */
1158  const std::vector<StdString>& CField::getRefDomainAxisIds()
1159  TRY
1160  {
1161    CGrid* cgPtr = getRelGrid();
1162    if (NULL != cgPtr)
1163    {
1164      std::vector<StdString>::iterator it;
1165      if (!domain_ref.isEmpty())
1166      {
1167        std::vector<StdString> domainList = cgPtr->getDomainList();
1168        it = std::find(domainList.begin(), domainList.end(), domain_ref.getValue());
1169        if (domainList.end() != it) domAxisScalarIds_[0] = *it;
1170      }
1171
1172      if (!axis_ref.isEmpty())
1173      {
1174        std::vector<StdString> axisList = cgPtr->getAxisList();
1175        it = std::find(axisList.begin(), axisList.end(), axis_ref.getValue());
1176        if (axisList.end() != it) domAxisScalarIds_[1] = *it;
1177      }
1178
1179      if (!scalar_ref.isEmpty())
1180      {
1181        std::vector<StdString> scalarList = cgPtr->getScalarList();
1182        it = std::find(scalarList.begin(), scalarList.end(), scalar_ref.getValue());
1183        if (scalarList.end() != it) domAxisScalarIds_[2] = *it;
1184      }
1185    }
1186    return (domAxisScalarIds_);
1187  }
1188  CATCH_DUMP_ATTR
1189
1190  CVariable* CField::addVariable(const string& id)
1191  TRY
1192  {
1193    return vVariableGroup->createChild(id);
1194  }
1195  CATCH
1196
1197  CVariableGroup* CField::addVariableGroup(const string& id)
1198  TRY
1199  {
1200    return vVariableGroup->createChildGroup(id);
1201  }
1202  CATCH
1203
1204  void CField::setContextClient(CContextClient* contextClient)
1205  TRY
1206  {
1207    CContext* context = CContext::getCurrent();
1208    client = contextClient;
1209 
1210    // A grid is sent by a client (both for read or write) or by primary server (write only)
1211    if (context->getServiceType()==CServicesManager::GATHERER)
1212    {
1213      if (getRelFile()->mode.isEmpty() || (!getRelFile()->mode.isEmpty() && getRelFile()->mode == CFile::mode_attr::write))
1214        grid_->setContextClient(contextClient);
1215    }
1216    else if (context->getServiceType()==CServicesManager::CLIENT)
1217      grid_->setContextClient(contextClient);
1218  }
1219  CATCH_DUMP_ATTR
1220
1221  void CField::sendCloseDefinition(void)
1222  {
1223    CContext::getCurrent()->sendCloseDefinition(client) ;
1224  }
1225
1226  void CField::sendFieldToFileServer(void)
1227  {
1228    CContext::getCurrent()->sendContextToFileServer(client);
1229    getRelFile()->sendFileToFileServer(client);
1230    sentGrid_ = grid_-> duplicateSentGrid() ;
1231    sentGrid_->sendGridToFileServer(client);
1232    name = getFieldOutputName() ;
1233    this->sendAllAttributesToServer(client);
1234    this->sendAddAllVariables(client);
1235  }
1236
1237  void CField::sendFieldToInputFileServer(void)
1238  {
1239    CContext::getCurrent()->sendContextToFileServer(client);
1240    getRelFile()->sendFileToFileServer(client);
1241    sentGrid_ = grid_-> duplicateSentGrid() ;
1242    sentGrid_->sendGridToFileServer(client);
1243    read_access=true ; // not the best solution, but on server side, the field must be a starting point of the workflow
1244                       // must be replace by a better solution when implementing filters for reading and send to client
1245                       // on server side
1246    this->sendAllAttributesToServer(client);
1247    this->sendAddAllVariables(client);
1248  }
1249
1250  void CField::sendFieldToCouplerOut(void)
1251  {
1252    if (sendFieldToCouplerOut_done_) return ;
1253    else sendFieldToCouplerOut_done_=true ;
1254    sentGrid_ = grid_-> duplicateSentGrid() ;
1255    sentGrid_->sendGridToCouplerOut(client, this->getId());
1256    this->sendGridCompleted();
1257
1258  }
1259 
1260  void CField::makeGridAliasForCoupling(void) 
1261  { 
1262    grid_->makeAliasForCoupling(this->getId()); 
1263  }
1264
1265 //! Client side: Send a message  announcing that the grid definition has been received from a coupling context
1266   void CField::sendGridCompleted(void)
1267   TRY
1268   {
1269      CEventClient event(getType(),EVENT_ID_GRID_COMPLETED);
1270
1271      if (client->isServerLeader())
1272      {
1273        CMessage msg;
1274        msg<<this->getId();
1275        for (auto& rank : client->getRanksServerLeader()) event.push(rank,1,msg);
1276        client->sendEvent(event);
1277      }
1278      else client->sendEvent(event);
1279   }
1280   CATCH_DUMP_ATTR
1281
1282   //! Server side: Receive a message announcing that the grid definition has been received from a coupling context
1283   void CField::recvGridCompleted(CEventServer& event)
1284   TRY
1285   {
1286      CBufferIn* buffer=event.subEvents.begin()->buffer;
1287      string id;
1288      *buffer>>id ;
1289      get(id)->recvGridCompleted(*buffer);
1290   }
1291   CATCH
1292
1293   //! Server side: Receive a message  message  announcing that the grid definition has been received from a coupling context
1294   void CField::recvGridCompleted(CBufferIn& buffer)
1295   TRY
1296   {
1297      setGridCompleted() ;
1298   }
1299   CATCH_DUMP_ATTR
1300
1301  bool CField::isGridCompleted(void)
1302  TRY
1303  { 
1304    bool isFullCompleted ;
1305    MPI_Allreduce(&isGridCompleted_,&isFullCompleted,1,MPI_C_BOOL, MPI_LAND, CContext::getCurrent()->getIntraComm() ) ;
1306    if ( (isGridCompleted_==false && isFullCompleted==true) ) ERROR("bool CField::isGridCompleted(void)",<< "incoherecy in MPI_AllReduce") ;
1307    return isFullCompleted ; 
1308  }
1309  CATCH_DUMP_ATTR
1310
1311  void CField::sendAddAllVariables(CContextClient* client)
1312  TRY
1313  {
1314    std::vector<CVariable*> allVar = getAllVariables();
1315    std::vector<CVariable*>::const_iterator it = allVar.begin();
1316    std::vector<CVariable*>::const_iterator itE = allVar.end();
1317
1318    for (; it != itE; ++it)
1319    {
1320      this->sendAddVariable((*it)->getId(), client);
1321      (*it)->sendAllAttributesToServer(client);
1322      (*it)->sendValue(client);
1323    }
1324  }
1325  CATCH_DUMP_ATTR
1326
1327  /*!
1328   * Send all Attributes to server. This method is overloaded, since only grid_ref attribute
1329   * must be sent to server and not domain_ref/axis_ref/scalar_ref.
1330   */
1331   
1332  void CField::sendAllAttributesToServer(CContextClient* client)
1333  TRY
1334  {
1335    if (grid_ref.isEmpty())
1336    {
1337      grid_ref=sentGrid_->getId() ;
1338      SuperClass::sendAllAttributesToServer(client) ;
1339      domain_ref.reset() ;
1340      axis_ref.reset() ;
1341      scalar_ref.reset() ;
1342      grid_ref.reset();
1343    }
1344    else 
1345    {
1346      string tmp = grid_ref;
1347      grid_ref = sentGrid_->getId() ;
1348      SuperClass::sendAllAttributesToServer(client) ;
1349      grid_ref = tmp ;
1350    }
1351  }
1352  CATCH_DUMP_ATTR
1353   
1354  void CField::sendAddVariable(const string& id, CContextClient* client)
1355  TRY
1356  {
1357    sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE, client);
1358  }
1359  CATCH_DUMP_ATTR
1360
1361  void CField::sendAddVariableGroup(const string& id, CContextClient* client)
1362  TRY
1363  {
1364    sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE_GROUP, client);
1365  }
1366  CATCH_DUMP_ATTR
1367
1368  void CField::recvAddVariable(CEventServer& event)
1369  TRY
1370  {
1371    CBufferIn* buffer = event.subEvents.begin()->buffer;
1372    string id;
1373    *buffer >> id;
1374    get(id)->recvAddVariable(*buffer);
1375  }
1376  CATCH
1377
1378  void CField::recvAddVariable(CBufferIn& buffer)
1379  TRY
1380  {
1381    string id;
1382    buffer >> id;
1383    addVariable(id);
1384  }
1385  CATCH_DUMP_ATTR
1386
1387  void CField::recvAddVariableGroup(CEventServer& event)
1388  TRY
1389  {
1390    CBufferIn* buffer = event.subEvents.begin()->buffer;
1391    string id;
1392    *buffer >> id;
1393    get(id)->recvAddVariableGroup(*buffer);
1394  }
1395  CATCH
1396
1397  void CField::recvAddVariableGroup(CBufferIn& buffer)
1398  TRY
1399  {
1400    string id;
1401    buffer >> id;
1402    addVariableGroup(id);
1403  }
1404  CATCH_DUMP_ATTR
1405
1406  /*!
1407   * Check on freq_off and freq_op attributes.
1408   */
1409  void CField::checkTimeAttributes(CDuration* freqOp)
1410  TRY
1411  {
1412    if (hasFileIn() && !(operation.getValue() == "instant" || operation.getValue() == "once") )     
1413      ERROR("void CField::checkTimeAttributes(void)",
1414         << "Unsupported operation for field '" << getFieldOutputName() << "'." << std::endl
1415         << "Currently only \"instant\" is supported for fields read from file.")
1416
1417    if (freq_op.isEmpty())
1418    {
1419      if (operation.getValue() == "instant")
1420      {
1421        if (hasFileIn() || hasFileOut()) freq_op.setValue(getRelFile()->output_freq.getValue());
1422        else freq_op=*freqOp ;
1423      }
1424      else freq_op.setValue(TimeStep);
1425    }
1426    if (freq_offset.isEmpty()) freq_offset.setValue(hasFileIn() ? NoneDu : (freq_op.getValue() - TimeStep));
1427  }
1428  CATCH_DUMP_ATTR
1429
1430  /*!
1431   * Returns string arithmetic expression associated to the field.
1432   * \return if content is defined return content string, otherwise, if "expr" attribute is defined, return expr string.
1433   */
1434  const string& CField::getExpression(void)
1435  TRY
1436  {
1437    if (!expr.isEmpty() && content.empty())
1438    {
1439      content = expr;
1440      expr.reset();
1441    }
1442
1443    return content;
1444  }
1445  CATCH_DUMP_ATTR
1446
1447  bool CField::hasExpression(void) const
1448  TRY
1449  {
1450    return (!expr.isEmpty() || !content.empty());
1451  }
1452  CATCH
1453
1454  bool CField::hasGridMask(void) const
1455  TRY
1456  {
1457    return (this->grid_->hasMask());
1458  }
1459  CATCH
1460
1461  DEFINE_REF_FUNC(Field,field)
1462} // namespace xios
Note: See TracBrowser for help on using the repository browser.