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

Last change on this file since 2172 was 2172, checked in by jderouillat, 3 years ago

Re-enable arithmetic filter

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