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

Last change on this file since 2544 was 2544, checked in by ymipsl, 9 months ago

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