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

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