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

Last change on this file since 2206 was 2206, checked in by ymipsl, 3 years ago

New feature : when can now use the syntax :
fieldId:domainId[n], in domain reference inside the workflow (XML). Same for axis and scalar.

YM

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