source: XIOS3/trunk/src/node/field.cpp

Last change on this file was 2632, checked in by ymipsl, 9 days ago
  • Recheck grid/domain/axis/scalar after reading grid from file, otherwise some attributes are not taking into account.

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