source: XIOS3/branches/xios-3.0-beta/src/node/field.cpp @ 2432

Last change on this file since 2432 was 2432, checked in by jderouillat, 17 months ago

Fix the evaluated buffer sizes for fields, and shrink the memory overbooking of buffers on servers (legacy)

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