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

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