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

Last change on this file since 2264 was 2264, checked in by ymipsl, 3 years ago

Scalar can be now distributed on server side, avoiding incorrect result coming from redondant nature of scalar grid.
YM

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