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

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

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