source: XIOS3/trunk/src/node/field.cpp @ 2628

Last change on this file since 2628 was 2628, checked in by jderouillat, 7 weeks ago

New timers integration/reporting

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