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

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

temporal commit for merging graph into XIOS_coupling

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