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

Last change on this file since 2311 was 2311, checked in by ymipsl, 2 years ago

Add possibility to refer to a grid using the field which is attached to, using notation : "fieldId::"

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