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

Last change on this file since 2406 was 2406, checked in by ymipsl, 21 months ago

Refactor management of client context and server context.
YM

  • Property copyright set to
    Software name : XIOS (Xml I/O Server)
    http://forge.ipsl.jussieu.fr/ioserver
    Creation date : January 2009
    Licence : CeCCIL version2
    see license file in root directory : Licence_CeCILL_V2-en.txt
    or http://www.cecill.info/licences/Licence_CeCILL_V2-en.html
    Holder : CEA/LSCE (Laboratoire des Sciences du CLimat et de l'Environnement)
    CNRS/IPSL (Institut Pierre Simon Laplace)
    Project Manager : Yann Meurdesoif
    yann.meurdesoif@cea.fr
  • Property svn:executable set to *
File size: 54.1 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]=it.second+headerSize ;
578            else bufferSize[it.first]+=it.second+headerSize ;
579          }
580        }
581        else
582        {
583          for(auto& it : dataSize) 
584          {
585              if (bufferSize.count(it.first)==0) bufferSize[it.first]=it.second+headerSize ;
586              else bufferSize[it.first]=std::max(bufferSize[it.first],(size_t)(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
1459  void CField::sendFieldToFileServer(void)
1460  {
1461    CContext::getCurrent()->sendContextToFileServer(client);
1462    getRelFile()->sendFileToFileServer(client);
1463    sentGrid_ = grid_-> duplicateSentGrid() ;
1464    sentGrid_->sendGridToFileServer(client, false);
1465    name = getFieldOutputName() ;
1466    this->sendAllAttributesToServer(client);
1467    this->sendAddAllVariables(client);
1468  }
1469
1470  void CField::sendFieldToInputFileServer(void)
1471  {
1472    CContext::getCurrent()->sendContextToFileServer(client);
1473    getRelFile()->sendFileToFileServer(client);
1474    sentGrid_ = grid_-> duplicateSentGrid() ;
1475    sentGrid_->sendGridToFileServer(client, true);
1476    read_access=true ; // not the best solution, but on server side, the field must be a starting point of the workflow
1477                       // must be replace by a better solution when implementing filters for reading and send to client
1478                       // on server side
1479    this->sendAllAttributesToServer(client);
1480    this->sendAddAllVariables(client);
1481  }
1482
1483  void CField::sendFieldToCouplerOut(void)
1484  {
1485    if (sendFieldToCouplerOut_done_) return ;
1486    else sendFieldToCouplerOut_done_=true ;
1487    sentGrid_ = grid_-> duplicateSentGrid() ;
1488    sentGrid_->sendGridToCouplerOut(client, this->getId());
1489    this->sendGridCompleted();
1490
1491  }
1492 
1493  void CField::makeGridAliasForCoupling(void) 
1494  { 
1495    grid_->makeAliasForCoupling(this->getId()); 
1496  }
1497
1498 //! Client side: Send a message  announcing that the grid definition has been received from a coupling context
1499   void CField::sendGridCompleted(void)
1500   TRY
1501   {
1502      CEventClient event(getType(),EVENT_ID_GRID_COMPLETED);
1503
1504      if (client->isServerLeader())
1505      {
1506        CMessage msg;
1507        msg<<this->getId();
1508        for (auto& rank : client->getRanksServerLeader()) event.push(rank,1,msg);
1509        client->sendEvent(event);
1510      }
1511      else client->sendEvent(event);
1512   }
1513   CATCH_DUMP_ATTR
1514
1515   //! Server side: Receive a message announcing that the grid definition has been received from a coupling context
1516   void CField::recvGridCompleted(CEventServer& event)
1517   TRY
1518   {
1519      CBufferIn* buffer=event.subEvents.begin()->buffer;
1520      string id;
1521      *buffer>>id ;
1522      get(id)->recvGridCompleted(*buffer);
1523   }
1524   CATCH
1525
1526   //! Server side: Receive a message  message  announcing that the grid definition has been received from a coupling context
1527   void CField::recvGridCompleted(CBufferIn& buffer)
1528   TRY
1529   {
1530      setGridCompleted() ;
1531   }
1532   CATCH_DUMP_ATTR
1533
1534  bool CField::isGridCompleted(void)
1535  TRY
1536  { 
1537    bool isFullCompleted ;
1538    MPI_Allreduce(&isGridCompleted_,&isFullCompleted,1,MPI_C_BOOL, MPI_LAND, CContext::getCurrent()->getIntraComm() ) ;
1539    if ( (isGridCompleted_==false && isFullCompleted==true) ) ERROR("bool CField::isGridCompleted(void)",<< "incoherecy in MPI_AllReduce") ;
1540    return isFullCompleted ; 
1541  }
1542  CATCH_DUMP_ATTR
1543
1544  void CField::sendAddAllVariables(CContextClient* client)
1545  TRY
1546  {
1547    std::vector<CVariable*> allVar = getAllVariables();
1548    std::vector<CVariable*>::const_iterator it = allVar.begin();
1549    std::vector<CVariable*>::const_iterator itE = allVar.end();
1550
1551    for (; it != itE; ++it)
1552    {
1553      this->sendAddVariable((*it)->getId(), client);
1554      (*it)->sendAllAttributesToServer(client);
1555      (*it)->sendValue(client);
1556    }
1557  }
1558  CATCH_DUMP_ATTR
1559
1560  /*!
1561   * Send all Attributes to server. This method is overloaded, since only grid_ref attribute
1562   * must be sent to server and not domain_ref/axis_ref/scalar_ref.
1563   */
1564   
1565  void CField::sendAllAttributesToServer(CContextClient* client)
1566  TRY
1567  {
1568    if (grid_ref.isEmpty())
1569    {
1570      grid_ref=sentGrid_->getId() ;
1571      SuperClass::sendAllAttributesToServer(client) ;
1572      domain_ref.reset() ;
1573      axis_ref.reset() ;
1574      scalar_ref.reset() ;
1575      grid_ref.reset();
1576    }
1577    else 
1578    {
1579      string tmp = grid_ref;
1580      grid_ref = sentGrid_->getId() ;
1581      SuperClass::sendAllAttributesToServer(client) ;
1582      grid_ref = tmp ;
1583    }
1584  }
1585  CATCH_DUMP_ATTR
1586   
1587  void CField::sendAddVariable(const string& id, CContextClient* client)
1588  TRY
1589  {
1590    sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE, client);
1591  }
1592  CATCH_DUMP_ATTR
1593
1594  void CField::sendAddVariableGroup(const string& id, CContextClient* client)
1595  TRY
1596  {
1597    sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE_GROUP, client);
1598  }
1599  CATCH_DUMP_ATTR
1600
1601  void CField::recvAddVariable(CEventServer& event)
1602  TRY
1603  {
1604    CBufferIn* buffer = event.subEvents.begin()->buffer;
1605    string id;
1606    *buffer >> id;
1607    get(id)->recvAddVariable(*buffer);
1608  }
1609  CATCH
1610
1611  void CField::recvAddVariable(CBufferIn& buffer)
1612  TRY
1613  {
1614    string id;
1615    buffer >> id;
1616    addVariable(id);
1617  }
1618  CATCH_DUMP_ATTR
1619
1620  void CField::recvAddVariableGroup(CEventServer& event)
1621  TRY
1622  {
1623    CBufferIn* buffer = event.subEvents.begin()->buffer;
1624    string id;
1625    *buffer >> id;
1626    get(id)->recvAddVariableGroup(*buffer);
1627  }
1628  CATCH
1629
1630  void CField::recvAddVariableGroup(CBufferIn& buffer)
1631  TRY
1632  {
1633    string id;
1634    buffer >> id;
1635    addVariableGroup(id);
1636  }
1637  CATCH_DUMP_ATTR
1638
1639  /*!
1640   * Check on freq_off and freq_op attributes.
1641   */
1642  void CField::checkTimeAttributes(CDuration* freqOp)
1643  TRY
1644  {
1645    if (hasFileIn() && !(operation.getValue() == "instant" || operation.getValue() == "once") )     
1646      ERROR("void CField::checkTimeAttributes(void)",
1647         << "Unsupported operation for field '" << getFieldOutputName() << "'." << std::endl
1648         << "Currently only \"instant\" is supported for fields read from file.")
1649
1650    if (freq_op.isEmpty())
1651    {
1652      if (operation.getValue() == "instant")
1653      {
1654        if (hasFileIn() || hasFileOut()) freq_op.setValue(getRelFile()->output_freq.getValue());
1655        else freq_op=*freqOp ;
1656      }
1657      else freq_op.setValue(TimeStep);
1658    }
1659    if (freq_offset.isEmpty()) freq_offset.setValue(hasFileIn() ? NoneDu : (freq_op.getValue() - TimeStep));
1660  }
1661  CATCH_DUMP_ATTR
1662
1663  /*!
1664   * Returns string arithmetic expression associated to the field.
1665   * \return if content is defined return content string, otherwise, if "expr" attribute is defined, return expr string.
1666   */
1667  const string& CField::getExpression(void)
1668  TRY
1669  {
1670    if (!expr.isEmpty() && content.empty())
1671    {
1672      content = expr;
1673      expr.reset();
1674    }
1675
1676    return content;
1677  }
1678  CATCH_DUMP_ATTR
1679
1680  bool CField::hasExpression(void) const
1681  TRY
1682  {
1683    return (!expr.isEmpty() || !content.empty());
1684  }
1685  CATCH
1686
1687  bool CField::hasGridMask(void) const
1688  TRY
1689  {
1690    return (this->grid_->hasMask());
1691  }
1692  CATCH
1693
1694  DEFINE_REF_FUNC(Field,field)
1695} // namespace xios
Note: See TracBrowser for help on using the repository browser.