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

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

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

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