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

Last change on this file since 2315 was 2315, checked in by ymipsl, 2 years ago

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