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

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

New management of client-server buffers.

  • buffers can grow automatically in intialization phase
  • buffers is evaluated after the close context definition phase and fixed at optimal value.

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