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

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

New functionnality : domain, axis and scalar can now be retrieve with new syntax id :
ex. for domain :

id="domainId" : old syntax, working as before
id="fieldId::domainId" : get the domain related to "domainId" associated to the field "fieldId", work if only 1 domain related to domainId is associated to the field.
id="fieldId::domainId[n]" : get the nth domain related to "domainId" associated to the field "fieldId"
id="fieldId::" : get the domain associated the the field "fieldId, work if grid associated to th field is composed with exactly 1 domain (and possibly other components axis or scalars)
id="fieldId::[n] : get the nth domain composing the grid associated to the field

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.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  CDomain* CField::getAssociatedDomain(const string& domainId) const
330  {
331    if (grid_==nullptr) ERROR("CDomain* CField::getAssociatedDomain(const string& domainId)", <<" field with id="<<getId()<<" has no associated grid, "
332                              <<"check if the worklfow is enabled for this field");
333    grid_->getAssociatedDomain(domainId) ;
334  }
335
336  CAxis* CField::getAssociatedAxis(const string& axisId) const
337  {
338    if (grid_==nullptr) ERROR("CAxis* CField::getAssociatedAxis(const string& axisId)", <<" field with id="<<getId()<<" has no associated grid, "
339                              <<"check if the worklfow is enabled for this field");
340    grid_->getAssociatedAxis(axisId) ;
341  }
342
343  CScalar* CField::getAssociatedScalar(const string& scalarId) const
344  {
345    if (grid_==nullptr) ERROR("CScalar* CField::getAssociatedScalar(const string& scalarId)", <<" field with id="<<getId()<<" has no associated grid, "
346                              <<"check if the worklfow is enabled for this field");
347    grid_->getAssociatedScalar(scalarId) ;
348  }
349
350
351  func::CFunctor::ETimeType CField::getOperationTimeType() const
352  TRY
353  {
354    return operationTimeType;
355  }
356  CATCH
357
358
359  //----------------------------------------------------------------
360
361  bool CField::isActive(bool atCurrentTimestep /*= false*/) const
362  TRY
363  {
364    if (modelToClientSourceFilter_) 
365      return atCurrentTimestep ? modelToClientSourceFilter_->isDataExpected(CContext::getCurrent()->getCalendar()->getCurrentDate()) : true;
366    else if (clientToModelStoreFilter_)  return true;
367    else if (instantDataFilter)
368      ERROR("bool CField::isActive(bool atCurrentTimestep)",
369            << "Impossible to check if field [ id = " << getId() << " ] is active as it cannot be used to receive nor send data.");
370
371    return false;
372  }
373  CATCH
374
375  //----------------------------------------------------------------
376
377  bool CField::wasWritten() const
378  TRY
379  {
380    return written;
381  }
382  CATCH
383
384  void CField::setWritten()
385  TRY
386  {
387    written = true;
388  }
389  CATCH_DUMP_ATTR
390
391  //----------------------------------------------------------------
392
393  bool CField::getUseCompressedOutput() const
394  TRY
395  {
396    return useCompressedOutput;
397  }
398  CATCH
399
400  void CField::setUseCompressedOutput()
401  TRY
402  {
403    useCompressedOutput = true;
404  }
405  CATCH_DUMP_ATTR
406
407 
408  //----------------------------------------------------------------
409 
410
411  void CField::checkGridOfEnabledFields()
412  TRY
413  {
414    if (!isGridChecked)
415    {
416      isGridChecked = true;
417      solveCheckMaskIndex(false);
418    }
419  }
420  CATCH_DUMP_ATTR
421
422  void CField::sendGridComponentOfEnabledFields()
423  TRY
424  {
425    solveGridDomainAxisRef(true);
426    // solveCheckMaskIndex(true);
427  }
428  CATCH_DUMP_ATTR
429
430  void CField::sendGridOfEnabledFields()
431  TRY
432  {
433    // solveGridDomainAxisRef(true);
434    solveCheckMaskIndex(true);
435  }   
436  CATCH_DUMP_ATTR
437
438  /*!
439   * Compute the required buffer size to send the fields data.
440   * \param [in/out] bufferSize Modifying the bufferSize for the client context
441   * \param [in/out] maxEventSize Modifying the maximum event size for the client context
442   * \param [in] bufferForWriting True if buffers are used for sending data for writing
443   */ 
444  void CField::setContextClientDataBufferSize(map<CContextClient*,map<int,size_t>>& bufferSize, 
445                                              map<CContextClient*,map<int,size_t>>& maxEventSize, 
446                                              bool bufferForWriting)
447  {
448    auto& contextBufferSize = bufferSize[client] ;
449    auto& contextMaxEventSize = maxEventSize[client] ;
450    const std::map<int, size_t> mapSize = grid_->getDataBufferSize(client, getId(), bufferForWriting);
451    for(auto& it : mapSize )
452    {
453      // If contextBufferSize[it.first] does not exist, it will be zero-initialized
454      // so we can use it safely without checking for its existance
455      if (CXios::isOptPerformance) contextBufferSize[it.first] += it.second;
456      else if (contextBufferSize[it.first] < it.second) contextBufferSize[it.first] = it.second;
457
458      if (contextMaxEventSize[it.first] < it.second) contextMaxEventSize[it.first] = it.second;
459    }
460
461  }
462
463  void CField::setContextClientAttributesBufferSize(map<CContextClient*,map<int,size_t>>& bufferSize, 
464                                                   map<CContextClient*,map<int,size_t>>& maxEventSize, 
465                                                   bool bufferForWriting)
466  {
467    auto& contextBufferSize = bufferSize[client] ;
468    auto& contextMaxEventSize = maxEventSize[client] ;
469    const std::map<int, size_t> mapSize = grid_->getAttributesBufferSize(client, bufferForWriting);
470    for(auto& it : mapSize )
471    {
472      // If contextBufferSize[it.first] does not exist, it will be zero-initialized
473      // so we can use it safely without checking for its existance
474      if (contextBufferSize[it.first] < it.second) contextBufferSize[it.first] = it.second;
475      if (contextMaxEventSize[it.first] < it.second) contextMaxEventSize[it.first] = it.second;
476    }
477
478  }
479
480
481// ym obsolete to be removed
482  std::map<int, StdSize> CField::getGridAttributesBufferSize(CContextClient* client, bool bufferForWriting /*= "false"*/)
483  TRY
484  {
485    return grid_->getAttributesBufferSize(client, bufferForWriting);
486  }
487  CATCH_DUMP_ATTR
488
489// ym obsolete to be removed
490  std::map<int, StdSize> CField::getGridDataBufferSize(CContextClient* client, bool bufferForWriting /*= "false"*/)
491  TRY
492  {
493    return grid_->getDataBufferSize(client, getId(), bufferForWriting);
494  }
495  CATCH_DUMP_ATTR
496
497  bool CField::evaluateBufferSize(map<CContextClient*,map<int,size_t>>& evaluateBuffer, bool isOptPerformance)
498  {
499    CContextClient* client=nullptr ;
500
501    for(int i=0;i<2;i++)
502    {
503      map<int,int> dataSize ;
504      if (i==0  && clientToServerStoreFilter_) client = clientToServerStoreFilter_-> getTransferedDataSize(dataSize) ;
505      if (i==1  && serverToClientStoreFilter_) client = serverToClientStoreFilter_-> getTransferedDataSize(dataSize) ;
506
507      if (client!=nullptr)
508      {
509        map<int,size_t> bufferSize ;
510   
511        if (evaluateBuffer.count(client)!=0) bufferSize = evaluateBuffer[client] ;
512        if (isOptPerformance)
513        {
514          for(auto& it : dataSize) 
515          {
516            if (bufferSize.count(it.first)==0) bufferSize[it.first]=it.second ;
517            else bufferSize[it.first]+=it.second ;
518          }
519        }
520        else
521        {
522          for(auto& it : dataSize) 
523          {
524            if (bufferSize.count(it.first)==0) bufferSize[it.first]=it.second ;
525            else bufferSize[it.first]=std::max(bufferSize[it.first],(size_t)it.second) ;
526          }
527        }
528        evaluateBuffer[client] = bufferSize ;
529        client=nullptr ;
530      }
531    }
532    if (client==nullptr) return false ;
533    else return true;
534  } 
535
536
537  size_t CField::getGlobalWrittenSize()
538  TRY
539  {
540    return grid_->getGlobalWrittenSize();
541  }
542  CATCH_DUMP_ATTR
543
544  //----------------------------------------------------------------
545
546  void CField::solveServerOperation(void)
547  TRY
548  {
549    CContext* context = CContext::getCurrent();
550
551    if (freq_op.isEmpty()) freq_op.setValue(TimeStep);
552
553    if (freq_offset.isEmpty()) freq_offset.setValue(NoneDu);
554
555    if (operation.isEmpty())
556      ERROR("void CField::solveServerOperation(void)",
557            << "An operation must be defined for field \"" << getId() << "\".");
558
559    std::shared_ptr<func::CFunctor> functor;
560    CArray<double, 1> dummyData;
561
562#define DECLARE_FUNCTOR(MType, mtype) \
563    if (operation.getValue().compare(#mtype) == 0) \
564    { \
565      functor.reset(new func::C##MType(dummyData)); \
566    }
567
568#include "functor_type.conf"
569
570    if (!functor)
571      ERROR("void CField::solveServerOperation(void)",
572            << "\"" << operation << "\" is not a valid operation.");
573
574    operationTimeType = functor->timeType();
575  }
576  CATCH_DUMP_ATTR
577
578 //----------------------------------------------------------------
579
580  bool CField::buildWorkflowGraph(CGarbageCollector& gc)
581  {
582    if (buildWorkflowGraphDone_) return true ;
583
584   
585    const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
586    const double defaultValue = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
587    bool buildGraph_ = !build_workflow_graph.isEmpty() && build_workflow_graph == true ;
588
589    if (!inputFilter) inputFilter = std::shared_ptr<CPassThroughFilter>(new CPassThroughFilter(gc)); 
590   
591    if (hasDirectFieldReference())
592    {
593      CField* fieldRef = getDirectFieldReference();
594     
595      //------ build_workflow_graph start
596      if(buildGraph_)
597      {
598        (*fieldRef).build_workflow_graph.set(build_workflow_graph); 
599      }   
600      else
601      {
602        this->build_workflow_graph.set(fieldRef->build_workflow_graph);
603        buildGraph_ = !build_workflow_graph.isEmpty() && build_workflow_graph == true ;
604      }
605
606     
607      // if(buildGraph_) this->build_workflow_graph.set(build_workflow_graph);
608      //------ build_workflow_graph end
609
610      bool ret=fieldRef->buildWorkflowGraph(gc); 
611      if (!ret) return false ; // workflow graph cannot be built at this stage
612     
613      this->build_workflow_graph.set(fieldRef->build_workflow_graph);
614      buildGraph_ = !build_workflow_graph.isEmpty() && build_workflow_graph == true ;
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     
628     
629      if (!filterExpr) return false ; // workflow graph cannot be built at this stage
630    }
631   
632    // prepare transformation. Need to know before if workflow of auxillary field can be built
633    if (hasDirectFieldReference())
634    {
635      auto gridPath=getGridPath() ;
636      gridPath.push_back(grid_) ;
637
638      CGrid* gridSrc=getDirectFieldReference()->getGrid() ;
639      std::shared_ptr<COutputPin> lastFilter ;
640      if (filterExpr) lastFilter=filterExpr ;
641      else lastFilter = inputFilter ;
642      CGrid* newGrid ;   
643     
644      for(auto grid : gridPath)
645      {
646        grid->solveElementsRefInheritance() ;
647        std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters = grid->buildTransformationGraph(gc, false,  gridSrc, detectMissingValues, defaultValue, newGrid, buildGraph_, this) ;
648        lastFilter->connectOutput(filters.first, 0);
649        lastFilter = filters.second;
650        gridSrc = newGrid ;
651      }
652
653      grid_=newGrid ;
654      grid_ref=grid_->getId() ; // for server
655      instantDataFilter = lastFilter ;
656     
657      // connect the input Filter to the reference
658      getDirectFieldReference()->getInstantDataFilter()->connectOutput(inputFilter,0);
659      if(buildGraph_) 
660      {
661        inputFilter->graphEnabled=true;
662        inputFilter->graphPackage = new CGraphPackage;
663        inputFilter->graphPackage->inFields.push_back(this);
664        inputFilter->label_field_id = getDirectFieldReference()->getId(); 
665      }
666    }
667    else 
668    {
669      std::shared_ptr<COutputPin> lastFilter = inputFilter;
670      if (hasExpression())
671      {
672         if (filterExpr) 
673         {
674           lastFilter=filterExpr ;
675         }
676      }
677     
678      if (hasFileIn()) // input file, attemp to read the grid from file
679      {
680         // must be checked
681         fileIn_->initRead() ;
682         fileIn_->checkReadFile();
683         grid_->solveElementsRefInheritance() ;
684         if (fileIn_->isClientSide()) fileIn_->readFieldAttributesMetaData(this);
685         CGrid* newGrid ;
686         std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters = grid_->buildTransformationGraph(gc, true, nullptr, detectMissingValues, defaultValue, newGrid, buildGraph_, this) ;
687         grid_ = newGrid ;
688         grid_ref=grid_->getId() ; // for server
689         //grid_->completeGrid(); // grid generation, to be checked
690         if (fileIn_->isClientSide()) fileIn_->readFieldAttributesValues(this);
691         grid_->checkElementsAttributes() ;
692//         grid_->solveDomainAxisBaseRef();
693         // probably in future tag grid incomplete if coming from a reading
694         instantDataFilter=lastFilter ;
695      } 
696      else if (hasCouplerIn())
697      {
698        grid_->checkElementsAttributes() ;
699        instantDataFilter=lastFilter ;
700      }
701      else
702      {
703        setModelIn() ; // no reference, the field is potentially a source field from model
704
705        grid_->solveElementsRefInheritance() ;
706        CGrid* newGrid ;
707        std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters = grid_->buildTransformationGraph(gc, true, nullptr, detectMissingValues, defaultValue, newGrid, buildGraph_, this) ;
708        newGrid->duplicateAttributes(grid_) ; // for grid attributes (mask)
709        grid_ = newGrid ;
710        grid_ref=grid_->getId() ; // for server
711        grid_->checkElementsAttributes() ;
712        instantDataFilter=lastFilter ;
713      }
714    }
715   
716    if (hasFileOut())
717    {
718      if (fileOut_->isServerSide())
719      {
720        this->solveServerOperation() ;
721      }
722    }
723
724    buildWorkflowGraphDone_ = true ;
725    workflowEnabled_ = true ;
726    return true ;
727  }
728   
729  /*!
730   * Connect field to filter to send data to server. A temporal filter is inserted before accordingly to the
731   * output frequency of the file
732   * \param gc the garbage collector to use when building the filter graph
733   */
734  void CField::connectToFileServer(CGarbageCollector& gc)
735  {
736    // insert temporal filter before sending to files
737    clientToServerStoreFilter_ = std::shared_ptr<CClientToServerStoreFilter>(new CClientToServerStoreFilter(gc, this, client));
738    // insert temporal filter before sending to files
739    getTemporalDataFilter(gc, fileOut_->output_freq)->connectOutput(clientToServerStoreFilter_, 0);
740    const bool buildGraph_ = !build_workflow_graph.isEmpty() && build_workflow_graph == true ;
741    if(buildGraph_) 
742    {
743      clientToServerStoreFilter_->graphPackage = new CGraphPackage;
744      clientToServerStoreFilter_->graphEnabled = true;
745      clientToServerStoreFilter_->graphPackage->inFields.push_back(this);
746    }
747  } 
748
749  void CField::connectToCouplerOut(CGarbageCollector& gc)
750  {
751    // insert temporal filter before sending to files
752    clientToServerStoreFilter_ = std::shared_ptr<CClientToServerStoreFilter>(new CClientToServerStoreFilter(gc, this, client));
753    instantDataFilter->connectOutput(clientToServerStoreFilter_, 0);
754    const bool buildGraph_ = !build_workflow_graph.isEmpty() && build_workflow_graph == true ;
755    if(buildGraph_) 
756    {
757      clientToServerStoreFilter_->graphPackage = new CGraphPackage;
758      clientToServerStoreFilter_->graphEnabled = true;
759      clientToServerStoreFilter_->graphPackage->inFields.push_back(this);
760    }
761  } 
762
763 
764  /*!
765   * Connect field to a source filter to receive data from model.
766   */
767  void CField::connectToModelInput(CGarbageCollector& gc)
768  {
769    const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
770    const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
771
772    if (check_if_active.isEmpty()) check_if_active = false; 
773    modelToClientSourceFilter_ = std::shared_ptr<CModelToClientSourceFilter>(new CModelToClientSourceFilter(gc, grid_, detectMissingValues, defaultValue));
774    modelToClientSourceFilter_ -> connectOutput(inputFilter,0) ;
775    const bool buildGraph_ = !build_workflow_graph.isEmpty() && build_workflow_graph == true ;
776    if(buildGraph_ ) 
777    {
778      modelToClientSourceFilter_->graphPackage = new CGraphPackage;
779      modelToClientSourceFilter_->graphEnabled = true;
780      modelToClientSourceFilter_->graphPackage->inFields.push_back(this);
781    }
782  } 
783 
784  /*!
785   * Connect field to a source filter to receive data from a client (on server side).
786   */
787  void CField::connectToClientInput(CGarbageCollector& gc)
788  {
789    serverFromClientSourceFilter_ = std::shared_ptr<CServerFromClientSourceFilter>(new CServerFromClientSourceFilter(gc,  grid_));
790    serverFromClientSourceFilter_ -> connectOutput(inputFilter,0) ;
791    const bool buildGraph_ = !build_workflow_graph.isEmpty() && build_workflow_graph == true ;
792    if(buildGraph_)
793    {
794      serverFromClientSourceFilter_->graphPackage = new CGraphPackage;
795      serverFromClientSourceFilter_->graphEnabled = true;
796      serverFromClientSourceFilter_->graphPackage->inFields.push_back(this);
797    }
798  } 
799
800
801  /*!
802   * Connect field to a source filter to receive data from a server (on client side).
803   */
804  void CField::connectToServerInput(CGarbageCollector& gc)
805  {
806    checkTimeAttributes();
807    clientFromServerSourceFilter_ = std::shared_ptr<CClientFromServerSourceFilter>(new CClientFromServerSourceFilter(gc,this)) ;
808    clientFromServerSourceFilter_ -> connectOutput(inputFilter,0) ;
809    const bool buildGraph_ = !build_workflow_graph.isEmpty() && build_workflow_graph == true ;
810    if(buildGraph_)
811    {
812      clientFromServerSourceFilter_->graphPackage = new CGraphPackage;
813      clientFromServerSourceFilter_->graphEnabled = true;
814      clientFromServerSourceFilter_->graphPackage->inFields.push_back(this);
815    }
816  } 
817
818  /*!
819   * Connect field to a source filter to receive data from coupler (on client side).
820   */
821   void CField::connectToCouplerIn(CGarbageCollector& gc)
822  {
823    CContext* context = CContext::getCurrent();
824
825    if (freq_op.isEmpty()) freq_op.setValue(TimeStep);
826    if (freq_offset.isEmpty()) freq_offset.setValue(freq_op.getValue() - TimeStep);
827    clientFromClientSourceFilter_ = std::shared_ptr<CClientFromClientSourceFilter>(new CClientFromClientSourceFilter(gc, this)) ;
828    clientFromClientSourceFilter_ -> connectOutput(inputFilter,0) ;
829    const bool buildGraph_ = !build_workflow_graph.isEmpty() && build_workflow_graph == true ;
830    if(buildGraph_)
831    {
832      clientFromClientSourceFilter_->graphPackage = new CGraphPackage;
833      clientFromClientSourceFilter_->graphEnabled = true;
834      clientFromClientSourceFilter_->graphPackage->inFields.push_back(this);
835    }
836  } 
837
838  /*!
839   * Connect field to a file writer filter to write data in file (on server side).
840   */
841  void CField::connectToFileWriter(CGarbageCollector& gc)
842  {
843    fileWriterStoreFilter_ = std::shared_ptr<CFileWriterStoreFilter>(new CFileWriterStoreFilter(gc, this));
844    instantDataFilter->connectOutput(fileWriterStoreFilter_, 0);
845    const bool buildGraph_ = !build_workflow_graph.isEmpty() && build_workflow_graph == true ;
846    if(buildGraph_)
847    {
848      fileWriterStoreFilter_->graphPackage = new CGraphPackage;
849      fileWriterStoreFilter_->graphEnabled = true;
850      fileWriterStoreFilter_->graphPackage->inFields.push_back(this);
851    }
852  } 
853
854  /*!
855   * Connect field to a file reader filter to read data from file (on server side).
856   */
857  void CField::connectToFileReader(CGarbageCollector& gc)
858  {
859    fileReaderSourceFilter_ = std::shared_ptr<CFileReaderSourceFilter>(new CFileReaderSourceFilter(gc, this));
860    fileReaderSourceFilter_->connectOutput(inputFilter, 0);
861    const bool buildGraph_ = !build_workflow_graph.isEmpty() && build_workflow_graph == true ;
862    if(buildGraph_)
863    {
864      fileReaderSourceFilter_->graphPackage = new CGraphPackage;
865      fileReaderSourceFilter_->graphEnabled = true;
866      fileReaderSourceFilter_->graphPackage->inFields.push_back(this);
867    }
868  }
869
870
871  /*!
872   * Connect field to a store filter to output data to model on client Side
873   */
874  void CField::connectToModelOutput(CGarbageCollector& gc)
875  {
876    clientToModelStoreFilter_ = std::shared_ptr<CClientToModelStoreFilter>(new CClientToModelStoreFilter(gc, this));
877    instantDataFilter->connectOutput(clientToModelStoreFilter_, 0);
878    const bool buildGraph_ = !build_workflow_graph.isEmpty() && build_workflow_graph == true ;
879    if(buildGraph_)
880    {
881      clientToModelStoreFilter_->graphPackage = new CGraphPackage;
882      clientToModelStoreFilter_->graphEnabled = true;
883      clientToModelStoreFilter_->graphPackage->inFields.push_back(this);
884    }
885  }
886
887
888 
889  void CField::connectToServerToClient(CGarbageCollector& gc)
890  {
891    serverToClientStoreFilter_ = std::shared_ptr<CServerToClientStoreFilter>(new CServerToClientStoreFilter(gc, this, client));
892    instantDataFilter->connectOutput(serverToClientStoreFilter_, 0);
893    const bool buildGraph_ = !build_workflow_graph.isEmpty() && build_workflow_graph == true ;
894    if(buildGraph_)
895    {
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        info(100)<<"=== Workflow Graph === field "<<this->getId()<<" calls a getTemporalDataFilter  ============== "<<instantDataFilter << " _ "<<temporalFilter<<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        info(100)<<"=== Workflow Graph === field "<<this->getId()<<" calls a getSelfTemporalDataFilter  ============== "<<inputFilter << " _ "<<selfTemporalDataFilter<<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.