source: XIOS/dev/dev_trunk_graph/src/node/field.cpp @ 2026

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

Graph intermediate commit to a tmp branch.

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