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

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

Some cleaning of old transformation dead code

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