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

Last change on this file since 2193 was 2193, checked in by yushan, 3 years ago

workflow graph : enable unary and binary arithmetic filters

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