source: XIOS/dev/dev_trunk_graph/src/node/field.cpp @ 2338

Last change on this file since 2338 was 2137, checked in by yushan, 3 years ago

temporal commit for merging graph into XIOS_coupling

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