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

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

Some cleaning of old transformation dead code

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