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

Last change on this file since 2150 was 2144, checked in by yushan, 3 years ago

Big commit on graph functionality. Enable the workflow graph when going through field dependency graph

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