source: XIOS3/dev/XIOS_ATTACHED/src/node/field.cpp @ 2482

Last change on this file since 2482 was 2482, checked in by ymipsl, 16 months ago

First guess in supression of attached mode replaced by online reader and write filters

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.3 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  void CField::connectToOnlineWriter(CGarbageCollector& gc)
806  {
807    // insert temporal filter before sending to files
808    CField* fieldOut ;
809    redistributeFilter_ = std::shared_ptr<CGridRedistributeFilter>(new CGridRedistributeFilter(gc, this, fieldOut));
810    fieldOut->setFileOut(this->getFileOut());
811    fileOut_->replaceEnabledFields(this, fieldOut) ;
812    // insert temporal filter before sending to files
813    getTemporalDataFilter(gc, fileOut_->output_freq)->connectOutput(redistributeFilter_, 0);
814    fieldOut->inputFilter = std::shared_ptr<CPassThroughFilter>(new CPassThroughFilter(gc)); 
815    fieldOut->instantDataFilter = fieldOut->inputFilter ;
816    redistributeFilter_->connectOutput(fieldOut->inputFilter, 0);
817    fieldOut->connectToFileWriter(gc) ;
818    fieldOut->solveServerOperation() ; // might not be called, create a new time functor.... find a better solution later
819    const bool buildGraph_ = !build_workflow_graph.isEmpty() && build_workflow_graph == true ;
820 
821    if(buildGraph_) 
822    {
823      clientToServerStoreFilter_->graphPackage = new CGraphPackage;
824      clientToServerStoreFilter_->graphEnabled = true;
825      clientToServerStoreFilter_->graphPackage->inFields.push_back(this);
826    }
827  } 
828
829  void CField::connectToOnlineReader(CGarbageCollector& gc)
830  {
831    // insert temporal filter before sending to files
832    clientOnlineReaderFilter_ = std::shared_ptr<CClientOnlineReaderFilter>(new CClientOnlineReaderFilter(gc,this)) ;
833    clientOnlineReaderFilter_ -> connectOutput(inputFilter,0) ;
834  } 
835
836  void CField::connectToCouplerOut(CGarbageCollector& gc)
837  {
838    // insert temporal filter before sending to files
839    clientToServerStoreFilter_ = std::shared_ptr<CClientToServerStoreFilter>(new CClientToServerStoreFilter(gc, this, client_));
840    instantDataFilter->connectOutput(clientToServerStoreFilter_, 0);
841    const bool buildGraph_ = !build_workflow_graph.isEmpty() && build_workflow_graph == true ;
842    if(buildGraph_) 
843    {
844      clientToServerStoreFilter_->graphPackage = new CGraphPackage;
845      clientToServerStoreFilter_->graphEnabled = true;
846      clientToServerStoreFilter_->graphPackage->inFields.push_back(this);
847    }
848  } 
849
850 
851  /*!
852   * Connect field to a source filter to receive data from model.
853   */
854  void CField::connectToModelInput(CGarbageCollector& gc)
855  {
856    const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
857    const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
858
859    if (check_if_active.isEmpty()) check_if_active = false; 
860    modelToClientSourceFilter_ = std::shared_ptr<CModelToClientSourceFilter>(new CModelToClientSourceFilter(gc, grid_, detectMissingValues, defaultValue));
861    modelToClientSourceFilter_ -> connectOutput(inputFilter,0) ;
862    const bool buildGraph_ = !build_workflow_graph.isEmpty() && build_workflow_graph == true ;
863    if(buildGraph_ ) 
864    {
865      modelToClientSourceFilter_->graphPackage = new CGraphPackage;
866      modelToClientSourceFilter_->graphEnabled = true;
867      modelToClientSourceFilter_->graphPackage->inFields.push_back(this);
868    }
869  } 
870 
871  /*!
872   * Connect field to a source filter to receive data from a client (on server side).
873   */
874  void CField::connectToClientInput(CGarbageCollector& gc)
875  {
876    serverFromClientSourceFilter_ = std::shared_ptr<CServerFromClientSourceFilter>(new CServerFromClientSourceFilter(gc,  grid_));
877    serverFromClientSourceFilter_ -> connectOutput(inputFilter,0) ;
878    const bool buildGraph_ = !build_workflow_graph.isEmpty() && build_workflow_graph == true ;
879    if(buildGraph_)
880    {
881      serverFromClientSourceFilter_->graphPackage = new CGraphPackage;
882      serverFromClientSourceFilter_->graphEnabled = true;
883      serverFromClientSourceFilter_->graphPackage->inFields.push_back(this);
884    }
885  } 
886
887
888  /*!
889   * Connect field to a source filter to receive data from a server (on client side).
890   */
891  void CField::connectToServerInput(CGarbageCollector& gc)
892  {
893    checkTimeAttributes();
894    clientFromServerSourceFilter_ = std::shared_ptr<CClientFromServerSourceFilter>(new CClientFromServerSourceFilter(gc,this)) ;
895    clientFromServerSourceFilter_ -> connectOutput(inputFilter,0) ;
896    const bool buildGraph_ = !build_workflow_graph.isEmpty() && build_workflow_graph == true ;
897    if(buildGraph_)
898    {
899      clientFromServerSourceFilter_->graphPackage = new CGraphPackage;
900      clientFromServerSourceFilter_->graphEnabled = true;
901      clientFromServerSourceFilter_->graphPackage->inFields.push_back(this);
902    }
903  } 
904
905  /*!
906   * Connect field to a source filter to receive data from coupler (on client side).
907   */
908   void CField::connectToCouplerIn(CGarbageCollector& gc)
909  {
910    CContext* context = CContext::getCurrent();
911
912    if (freq_op.isEmpty()) freq_op.setValue(TimeStep);
913    if (freq_offset.isEmpty()) freq_offset.setValue(freq_op.getValue() - TimeStep);
914    clientFromClientSourceFilter_ = std::shared_ptr<CClientFromClientSourceFilter>(new CClientFromClientSourceFilter(gc, this)) ;
915    clientFromClientSourceFilter_ -> connectOutput(inputFilter,0) ;
916    const bool buildGraph_ = !build_workflow_graph.isEmpty() && build_workflow_graph == true ;
917    if(buildGraph_)
918    {
919      clientFromClientSourceFilter_->graphPackage = new CGraphPackage;
920      clientFromClientSourceFilter_->graphEnabled = true;
921      clientFromClientSourceFilter_->graphPackage->inFields.push_back(this);
922    }
923  } 
924
925  /*!
926   * Connect field to a file writer filter to write data in file (on server side).
927   */
928  void CField::connectToFileWriter(CGarbageCollector& gc)
929  {
930    fileWriterStoreFilter_ = std::shared_ptr<CFileWriterStoreFilter>(new CFileWriterStoreFilter(gc, this));
931    instantDataFilter->connectOutput(fileWriterStoreFilter_, 0);
932    const bool buildGraph_ = !build_workflow_graph.isEmpty() && build_workflow_graph == true ;
933    if(buildGraph_)
934    {
935      fileWriterStoreFilter_->graphPackage = new CGraphPackage;
936      fileWriterStoreFilter_->graphEnabled = true;
937      fileWriterStoreFilter_->graphPackage->inFields.push_back(this);
938    }
939  } 
940
941  /*!
942   * Connect field to a file reader filter to read data from file (on server side).
943   */
944  void CField::connectToFileReader(CGarbageCollector& gc)
945  {
946    fileReaderSourceFilter_ = std::shared_ptr<CFileReaderSourceFilter>(new CFileReaderSourceFilter(gc, this));
947    fileReaderSourceFilter_->connectOutput(inputFilter, 0);
948    const bool buildGraph_ = !build_workflow_graph.isEmpty() && build_workflow_graph == true ;
949    if(buildGraph_)
950    {
951      fileReaderSourceFilter_->graphPackage = new CGraphPackage;
952      fileReaderSourceFilter_->graphEnabled = true;
953      fileReaderSourceFilter_->graphPackage->inFields.push_back(this);
954    }
955  }
956
957
958  /*!
959   * Connect field to a store filter to output data to model on client Side
960   */
961  void CField::connectToModelOutput(CGarbageCollector& gc)
962  {
963    clientToModelStoreFilter_ = std::shared_ptr<CClientToModelStoreFilter>(new CClientToModelStoreFilter(gc, this));
964    instantDataFilter->connectOutput(clientToModelStoreFilter_, 0);
965    const bool buildGraph_ = !build_workflow_graph.isEmpty() && build_workflow_graph == true ;
966    if(buildGraph_)
967    {
968      clientToModelStoreFilter_->graphPackage = new CGraphPackage;
969      clientToModelStoreFilter_->graphEnabled = true;
970      clientToModelStoreFilter_->graphPackage->inFields.push_back(this);
971    }
972  }
973
974
975 
976  void CField::connectToServerToClient(CGarbageCollector& gc)
977  {
978    serverToClientStoreFilter_ = std::shared_ptr<CServerToClientStoreFilter>(new CServerToClientStoreFilter(gc, this, client_));
979    instantDataFilter->connectOutput(serverToClientStoreFilter_, 0);
980    const bool buildGraph_ = !build_workflow_graph.isEmpty() && build_workflow_graph == true ;
981    if(buildGraph_)
982    {
983      serverToClientStoreFilter_->graphPackage = new CGraphPackage;
984      serverToClientStoreFilter_->graphEnabled = true;
985      serverToClientStoreFilter_->graphPackage->inFields.push_back(this);
986    }
987  }
988
989  /*!
990   * Transform the grid_path attribut into vector of grid.
991   * \return the vector CGrid* containing the list of grid path for tranformation
992   */ 
993  vector<CGrid*> CField::getGridPath(void)
994  {
995    std::vector<CGrid*> gridPath;
996
997    if (hasDirectFieldReference() && grid_ != getDirectFieldReference()->grid_)
998    {
999      if (!grid_path.isEmpty())
1000      {
1001        std::string gridId;
1002        size_t start = 0, end;
1003
1004        do
1005        {
1006          end = grid_path.getValue().find(',', start);
1007          if (end != std::string::npos)
1008          {
1009            gridId = grid_path.getValue().substr(start, end - start);
1010            start = end + 1;
1011          }
1012          else gridId = grid_path.getValue().substr(start);
1013
1014          if (!CGrid::has(gridId))
1015            ERROR("void CField::solveTransformedGrid()",
1016               << "Invalid grid_path, the grid '" << gridId << "' does not exist.");
1017
1018          gridPath.push_back(CGrid::get(gridId));
1019        }
1020        while (end != std::string::npos);
1021      }
1022    }
1023    return gridPath ;
1024  }
1025
1026 
1027 
1028  /*!
1029   * Returns the filter needed to handle a self reference in the field's expression.
1030   * If the needed filter does not exist, it is created, otherwise it is reused.
1031   * This method should only be called when building the filter graph corresponding
1032   * to the field's expression.
1033   *
1034   * \param gc the garbage collector to use
1035   * \return the output pin corresponding to a self reference
1036   */
1037
1038/* old version
1039  std::shared_ptr<COutputPin> CField::getSelfReference(CGarbageCollector& gc)
1040  TRY
1041  {
1042    if (instantDataFilter || !hasExpression())
1043      ERROR("COutputPin* CField::getSelfReference(CGarbageCollector& gc)",
1044            "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1045
1046    if (!selfReferenceFilter)
1047    {
1048      const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1049      const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
1050
1051      if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
1052      {
1053        if (!serverSourceFilter)
1054        {
1055          checkTimeAttributes();
1056          serverSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid_, true, false, freq_offset, true,
1057                                                              detectMissingValues, defaultValue));
1058         }
1059
1060        selfReferenceFilter = serverSourceFilter;
1061      }
1062      else if (!field_ref.isEmpty())
1063      {
1064        CField* fieldRef = CField::get(field_ref);
1065        fieldRef->buildFilterGraph(gc, false);
1066        selfReferenceFilter = fieldRef->getInstantDataFilter();
1067      }
1068      else
1069      {
1070        if (!clientSourceFilter)
1071        {
1072          if (check_if_active.isEmpty()) check_if_active = false;
1073          clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid_, true, true, NoneDu, false,
1074                                                                                detectMissingValues, defaultValue));
1075        }
1076
1077        selfReferenceFilter = clientSourceFilter;
1078      }
1079    }
1080
1081    return selfReferenceFilter;
1082  }
1083  CATCH_DUMP_ATTR
1084*/
1085  std::shared_ptr<COutputPin> CField::getSelfReference(CGarbageCollector& gc)
1086  TRY
1087  {
1088    return inputFilter ;
1089  } 
1090  CATCH_DUMP_ATTR
1091
1092  /*!
1093   * Returns the temporal filter corresponding to the field's temporal operation
1094   * for the specified operation frequency. The filter is created if it does not
1095   * exist, otherwise it is reused.
1096   *
1097   * \param gc the garbage collector to use
1098   * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1099   * \return the output pin corresponding to the requested temporal filter
1100   */
1101  std::shared_ptr<COutputPin> CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1102  TRY
1103  {
1104    std::map<CDuration, std::shared_ptr<COutputPin> >::iterator it = temporalDataFilters.find(outFreq);
1105
1106    if (it == temporalDataFilters.end())
1107    {
1108      if (operation.isEmpty())
1109        ERROR("void CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1110              << "An operation must be defined for field \"" << getId() << "\".");
1111
1112      checkTimeAttributes(&outFreq);
1113
1114      const bool detectMissingValues = (!detect_missing_value.isEmpty()  && detect_missing_value == true);
1115      std::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1116                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
1117                                                                             freq_op, freq_offset, outFreq, detectMissingValues));
1118
1119      instantDataFilter->connectOutput(temporalFilter, 0);
1120      const bool buildGraph_ = !build_workflow_graph.isEmpty() && build_workflow_graph == true ;
1121      if(buildGraph_) 
1122      {
1123        info(100)<<"=== Workflow Graph === field "<<this->getId()<<" calls a getTemporalDataFilter  ============== "<<instantDataFilter << " _ "<<temporalFilter<<std::endl;
1124        temporalFilter->graphPackage = new CGraphPackage;
1125        temporalFilter->graphEnabled = true;
1126        temporalFilter->graphPackage->inFields.push_back(this);
1127      }
1128
1129      it = temporalDataFilters.insert(std::make_pair(outFreq, temporalFilter)).first;
1130    }
1131
1132    return it->second;
1133  }
1134  CATCH_DUMP_ATTR
1135
1136  /*!
1137    * Returns the temporal filter corresponding to the field's temporal operation
1138    * for the specified operation frequency.
1139    *
1140    * \param gc the garbage collector to use
1141    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1142    * \return the output pin corresponding to the requested temporal filter
1143    */
1144
1145  std::shared_ptr<COutputPin> CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1146  TRY
1147  {
1148    if (instantDataFilter || !hasExpression())
1149      ERROR("COutputPin* CField::getSelfTemporalDataFilter(CGarbageCollector& gc)",
1150            "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1151   
1152    if (selfTemporalDataFilter) return selfTemporalDataFilter;
1153
1154    if (hasDirectFieldReference())
1155    {
1156      CField* fieldRef=getDirectFieldReference();
1157      return fieldRef->getTemporalDataFilter(gc, outFreq) ;
1158    }
1159    else
1160    {
1161      if (selfTemporalDataFilter) return selfTemporalDataFilter ;
1162
1163      if (operation.isEmpty())
1164        ERROR("void CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1165              << "An operation must be defined for field \"" << getId() << "\".");
1166
1167      checkTimeAttributes(&outFreq); //bof
1168
1169      const bool detectMissingValues = (!detect_missing_value.isEmpty() && detect_missing_value == true);
1170      selfTemporalDataFilter = std::shared_ptr<CTemporalFilter>(new CTemporalFilter(gc, operation,
1171                                                                CContext::getCurrent()->getCalendar()->getInitDate(),
1172                                                                freq_op, freq_offset, outFreq, detectMissingValues));
1173
1174      inputFilter->connectOutput(selfTemporalDataFilter, 0);
1175      const bool buildGraph_ = !build_workflow_graph.isEmpty() && build_workflow_graph == true ;
1176      if(buildGraph_)
1177      {
1178        info(100)<<"=== Workflow Graph === field "<<this->getId()<<" calls a getSelfTemporalDataFilter  ============== "<<inputFilter << " _ "<<selfTemporalDataFilter<<std::endl;
1179        selfTemporalDataFilter->graphPackage = new CGraphPackage;
1180        selfTemporalDataFilter->graphEnabled = true;
1181        selfTemporalDataFilter->graphPackage->inFields.push_back(this);
1182      }
1183      return selfTemporalDataFilter ;
1184    }
1185  }
1186  CATCH_DUMP_ATTR
1187
1188/* old version   
1189  std::shared_ptr<COutputPin> CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1190  TRY
1191  {
1192    if (instantDataFilter || !hasExpression())
1193      ERROR("COutputPin* CField::getSelfTemporalDataFilter(CGarbageCollector& gc)",
1194            "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1195
1196    if (!selfReferenceFilter) getSelfReference(gc) ;
1197
1198    if (serverSourceFilter || clientSourceFilter)
1199    {
1200      if (operation.isEmpty())
1201        ERROR("void CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1202              << "An operation must be defined for field \"" << getId() << "\".");
1203
1204      checkTimeAttributes(&outFreq);
1205
1206      const bool detectMissingValues = (!detect_missing_value.isEmpty() && detect_missing_value == true);
1207      std::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1208                                                                          CContext::getCurrent()->getCalendar()->getInitDate(),
1209                                                                          freq_op, freq_offset, outFreq, detectMissingValues));
1210
1211      selfReferenceFilter->connectOutput(temporalFilter, 0);
1212      return temporalFilter ;
1213    }
1214    else if (!field_ref.isEmpty())
1215    {
1216      CField* fieldRef = CField::get(field_ref);
1217      fieldRef->buildFilterGraph(gc, false);
1218      return fieldRef->getTemporalDataFilter(gc, outFreq) ;
1219    }
1220  }
1221  CATCH_DUMP_ATTR
1222*/
1223
1224  //----------------------------------------------------------------
1225/*
1226   void CField::fromBinary(StdIStream& is)
1227   {
1228      SuperClass::fromBinary(is);
1229#define CLEAR_ATT(name_)\
1230      SuperClassAttribute::operator[](#name_)->reset()
1231
1232         CLEAR_ATT(domain_ref);
1233         CLEAR_ATT(axis_ref);
1234#undef CLEAR_ATT
1235
1236   }
1237*/
1238   //----------------------------------------------------------------
1239
1240  void CField::solveGridReference(void)
1241  TRY
1242  {
1243    if (grid_!=nullptr) return ; // already done
1244
1245    if (grid_ref.isEmpty() && domain_ref.isEmpty() && axis_ref.isEmpty() && scalar_ref.isEmpty())
1246    {
1247      ERROR("CField::solveGridReference(void)",
1248            << "A grid must be defined for field '" << getFieldOutputName() << "' .");
1249    }
1250    else if (!grid_ref.isEmpty() && (!domain_ref.isEmpty() || !axis_ref.isEmpty() || !scalar_ref.isEmpty()))
1251    {
1252      ERROR("CField::solveGridReference(void)",
1253            << "Field '" << getFieldOutputName() << "' has both a grid and a domain/axis/scalar." << std::endl
1254            << "Please define either 'grid_ref' or 'domain_ref'/'axis_ref'/'scalar_ref'.");
1255    }
1256
1257    if (grid_ref.isEmpty())
1258    {
1259      std::vector<CDomain*> vecDom;
1260      std::vector<CAxis*> vecAxis;
1261      std::vector<CScalar*> vecScalar;
1262      std::vector<int> axisDomainOrderTmp;
1263
1264      std::vector<CDomain*> vecDomRef;
1265      std::vector<CAxis*> vecAxisRef;
1266      std::vector<CScalar*> vecScalarRef;
1267       
1268      if (!domain_ref.isEmpty())
1269      {
1270        CField* field=CDomain::getFieldFromId(domain_ref) ;
1271        if (field!=nullptr) field->solveGridReference() ;
1272        if (CDomain::has(domain_ref))
1273        {
1274          vecDom.push_back(CDomain::get(domain_ref));
1275          vecDomRef.push_back(CDomain::createDomain());
1276          vecDomRef.back()->domain_ref=domain_ref;
1277          axisDomainOrderTmp.push_back(2);
1278        }
1279        else  ERROR("CField::solveGridReference(void)",
1280                    << "Invalid reference to domain '" << domain_ref.getValue() << "'.");
1281      }
1282
1283      if (!axis_ref.isEmpty())
1284      {
1285        CField* field=CAxis::getFieldFromId(axis_ref) ;
1286        if (field!=nullptr) field->solveGridReference() ;
1287        if (CAxis::has(axis_ref))
1288        {
1289          vecAxis.push_back(CAxis::get(axis_ref));
1290          vecAxisRef.push_back(CAxis::createAxis());
1291          vecAxisRef.back()->axis_ref=axis_ref;
1292          axisDomainOrderTmp.push_back(1);
1293        }
1294        else  ERROR("CField::solveGridReference(void)",
1295                    << "Invalid reference to axis '" << axis_ref.getValue() << "'.");
1296      }
1297
1298      if (!scalar_ref.isEmpty())
1299      {
1300        CField* field=CScalar::getFieldFromId(scalar_ref) ;
1301        if (field!=nullptr) field->solveGridReference() ;
1302        if (CScalar::has(scalar_ref))
1303        {
1304          vecScalar.push_back(CScalar::get(scalar_ref));
1305          vecScalarRef.push_back(CScalar::createScalar());
1306          vecScalarRef.back()->scalar_ref=scalar_ref;
1307          axisDomainOrderTmp.push_back(0);
1308        }
1309        else ERROR("CField::solveGridReference(void)",
1310                   << "Invalid reference to scalar '" << scalar_ref.getValue() << "'.");
1311      }
1312       
1313      CArray<int,1> axisDomainOrder(axisDomainOrderTmp.size());
1314      for (int idx = 0; idx < axisDomainOrderTmp.size(); ++idx)
1315      {
1316        axisDomainOrder(idx) = axisDomainOrderTmp[idx];
1317      }
1318
1319      // Warning: the gridId shouldn't be set as the grid_ref since it could be inherited
1320      StdString gridId = CGrid::generateId(vecDom, vecAxis, vecScalar,axisDomainOrder);
1321      if (CGrid::has(gridId)) this->grid_ = CGrid::get(gridId);
1322      else  this->grid_ = CGrid::createGrid(gridId, vecDomRef, vecAxisRef, vecScalarRef,axisDomainOrder);
1323    }
1324    else
1325    {
1326      CField* field=CGrid::getFieldFromId(grid_ref) ;
1327      if (field!=nullptr) field->solveGridReference() ;
1328      if (CGrid::has(grid_ref)) this->grid_ = CGrid::get(grid_ref);
1329      else  ERROR("CField::solveGridReference(void)",
1330                   << "Invalid reference to grid '" << grid_ref.getValue() << "'.");
1331    }
1332  }
1333  CATCH_DUMP_ATTR
1334
1335  void CField::solveGridDomainAxisRef(bool checkAtt)
1336  TRY
1337  {
1338    grid_->solveDomainAxisRef(checkAtt);
1339  }
1340  CATCH_DUMP_ATTR
1341
1342  void CField::solveCheckMaskIndex(bool doSendingIndex)
1343  TRY
1344  {
1345    grid_->checkMaskIndex(doSendingIndex);
1346  }
1347  CATCH_DUMP_ATTR
1348
1349 
1350  void CField::solveGridDomainAxisBaseRef()
1351  TRY
1352  {
1353    grid_->solveDomainAxisRef(false);
1354    grid_->solveDomainAxisBaseRef();
1355  }
1356  CATCH_DUMP_ATTR
1357
1358  ///-------------------------------------------------------------------
1359
1360  template <>
1361  void CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)
1362  TRY
1363  {
1364    if (this->group_ref.isEmpty()) return;
1365    StdString gref = this->group_ref.getValue();
1366
1367    if (!CFieldGroup::has(gref))
1368      ERROR("CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)",
1369         << "[ gref = " << gref << "]"
1370         << " invalid group name !");
1371
1372    CFieldGroup* group = CFieldGroup::get(gref);
1373    CFieldGroup* owner = CFieldGroup::get(boost::polymorphic_downcast<CFieldGroup*>(this));
1374    owner->setAttributes(group); // inherite of attributes of group reference
1375     
1376    std::vector<CField*> allChildren  = group->getAllChildren();
1377    std::vector<CField*>::iterator it = allChildren.begin(), end = allChildren.end();
1378
1379    for (; it != end; it++)
1380    {
1381      CField* child = *it;
1382     if (child->hasId()) owner->createChild()->field_ref.setValue(child->getId());
1383    }
1384  }
1385  CATCH_DUMP_ATTR
1386
1387  ///-------------------------------------------------------------------
1388
1389  void CField::parse(xml::CXMLNode& node)
1390  TRY
1391  {
1392    string newContent ;
1393    SuperClass::parse(node);
1394    if (node.goToChildElement())
1395    {
1396      do
1397      {
1398        if (node.getElementName() == "variable" || node.getElementName() == "variable_group") this->getVirtualVariableGroup()->parseChild(node);
1399        else if (node.getElementName() == "expr") if (node.getContent(newContent)) content+=newContent ;
1400      } while (node.goToNextElement());
1401      node.goToParentElement();
1402    }
1403    if (node.getContent(newContent)) content=newContent ;
1404  }
1405  CATCH_DUMP_ATTR
1406
1407 /*!
1408   This function retrieves Id of corresponding domain_ref and axis_ref (if any)
1409   of a field. In some cases, only domain exists but axis doesn't
1410   \return pair of Domain and Axis id
1411  */
1412  const std::vector<StdString>& CField::getRefDomainAxisIds()
1413  TRY
1414  {
1415    CGrid* cgPtr = getRelGrid();
1416    if (NULL != cgPtr)
1417    {
1418      std::vector<StdString>::iterator it;
1419      if (!domain_ref.isEmpty())
1420      {
1421        std::vector<StdString> domainList = cgPtr->getDomainList();
1422        it = std::find(domainList.begin(), domainList.end(), domain_ref.getValue());
1423        if (domainList.end() != it) domAxisScalarIds_[0] = *it;
1424      }
1425
1426      if (!axis_ref.isEmpty())
1427      {
1428        std::vector<StdString> axisList = cgPtr->getAxisList();
1429        it = std::find(axisList.begin(), axisList.end(), axis_ref.getValue());
1430        if (axisList.end() != it) domAxisScalarIds_[1] = *it;
1431      }
1432
1433      if (!scalar_ref.isEmpty())
1434      {
1435        std::vector<StdString> scalarList = cgPtr->getScalarList();
1436        it = std::find(scalarList.begin(), scalarList.end(), scalar_ref.getValue());
1437        if (scalarList.end() != it) domAxisScalarIds_[2] = *it;
1438      }
1439    }
1440    return (domAxisScalarIds_);
1441  }
1442  CATCH_DUMP_ATTR
1443
1444  CVariable* CField::addVariable(const string& id)
1445  TRY
1446  {
1447    return vVariableGroup->createChild(id);
1448  }
1449  CATCH
1450
1451  CVariableGroup* CField::addVariableGroup(const string& id)
1452  TRY
1453  {
1454    return vVariableGroup->createChildGroup(id);
1455  }
1456  CATCH
1457
1458  void CField::setContextClient(CContextClient* contextClient)
1459  TRY
1460  {
1461    CContext* context = CContext::getCurrent();
1462    client_ = contextClient;
1463 
1464    // A grid is sent by a client (both for read or write) or by primary server (write only)
1465    if (context->getServiceType()==CServicesManager::GATHERER)
1466    {
1467      if (getRelFile()->mode.isEmpty() || (!getRelFile()->mode.isEmpty() && getRelFile()->mode == CFile::mode_attr::write))
1468        /*grid_->setContextClient(contextClient) */; // => nothing to do with thats now, to remove...
1469    }
1470    else if (context->getServiceType()==CServicesManager::CLIENT)
1471    {
1472      if (grid_)
1473        /*grid_->setContextClient(contextClient)*/; // => nothing to do with thats now, to remove...
1474      else
1475
1476        ERROR( "CField::setContextClient(contextClient)",
1477               << "Grid not defined for " << getId()
1478               << " (if field is an input field, set read_access to true)"
1479               );
1480    }
1481  }
1482  CATCH_DUMP_ATTR
1483
1484
1485  void CField::sendFieldToFileServer(void)
1486  {
1487    CContext::getCurrent()->sendContextToFileServer(client_);
1488    getRelFile()->sendFileToFileServer(client_);
1489    sentGrid_ = grid_-> duplicateSentGrid() ;
1490    sentGrid_->sendGridToFileServer(client_, false);
1491    name = getFieldOutputName() ;
1492    this->sendAllAttributesToServer(client_);
1493    this->sendAddAllVariables(client_);
1494  }
1495
1496  void CField::sendFieldToInputFileServer(void)
1497  {
1498    CContext::getCurrent()->sendContextToFileServer(client_);
1499    getRelFile()->sendFileToFileServer(client_);
1500    sentGrid_ = grid_-> duplicateSentGrid() ;
1501    sentGrid_->sendGridToFileServer(client_, true);
1502    read_access=true ; // not the best solution, but on server side, the field must be a starting point of the workflow
1503                       // must be replace by a better solution when implementing filters for reading and send to client
1504                       // on server side
1505    this->sendAllAttributesToServer(client_);
1506    this->sendAddAllVariables(client_);
1507  }
1508
1509  void CField::sendFieldToCouplerOut(void)
1510  {
1511    if (sendFieldToCouplerOut_done_) return ;
1512    else sendFieldToCouplerOut_done_=true ;
1513    sentGrid_ = grid_-> duplicateSentGrid() ;
1514    sentGrid_->sendGridToCouplerOut(client_, this->getId());
1515    this->sendGridCompleted();
1516
1517  }
1518 
1519  void CField::makeGridAliasForCoupling(void) 
1520  { 
1521    grid_->makeAliasForCoupling(this->getId()); 
1522  }
1523
1524 //! Client side: Send a message  announcing that the grid definition has been received from a coupling context
1525   void CField::sendGridCompleted(void)
1526   TRY
1527   {
1528      CEventClient event(getType(),EVENT_ID_GRID_COMPLETED);
1529
1530      if (client_->isServerLeader())
1531      {
1532        CMessage msg;
1533        msg<<this->getId();
1534        for (auto& rank : client_->getRanksServerLeader()) event.push(rank,1,msg);
1535        client_->sendEvent(event);
1536      }
1537      else client_->sendEvent(event);
1538   }
1539   CATCH_DUMP_ATTR
1540
1541   //! Server side: Receive a message announcing that the grid definition has been received from a coupling context
1542   void CField::recvGridCompleted(CEventServer& event)
1543   TRY
1544   {
1545      CBufferIn* buffer=event.subEvents.begin()->buffer;
1546      string id;
1547      *buffer>>id ;
1548      get(id)->recvGridCompleted(*buffer);
1549   }
1550   CATCH
1551
1552   //! Server side: Receive a message  message  announcing that the grid definition has been received from a coupling context
1553   void CField::recvGridCompleted(CBufferIn& buffer)
1554   TRY
1555   {
1556      setGridCompleted() ;
1557   }
1558   CATCH_DUMP_ATTR
1559
1560  bool CField::isGridCompleted(void)
1561  TRY
1562  { 
1563    bool isFullCompleted ;
1564    MPI_Allreduce(&isGridCompleted_,&isFullCompleted,1,MPI_C_BOOL, MPI_LAND, CContext::getCurrent()->getIntraComm() ) ;
1565    if ( (isGridCompleted_==false && isFullCompleted==true) ) ERROR("bool CField::isGridCompleted(void)",<< "incoherecy in MPI_AllReduce") ;
1566    return isFullCompleted ; 
1567  }
1568  CATCH_DUMP_ATTR
1569
1570  void CField::sendAddAllVariables(CContextClient* client)
1571  TRY
1572  {
1573    std::vector<CVariable*> allVar = getAllVariables();
1574    std::vector<CVariable*>::const_iterator it = allVar.begin();
1575    std::vector<CVariable*>::const_iterator itE = allVar.end();
1576
1577    for (; it != itE; ++it)
1578    {
1579      this->sendAddVariable((*it)->getId(), client);
1580      (*it)->sendAllAttributesToServer(client);
1581      (*it)->sendValue(client);
1582    }
1583  }
1584  CATCH_DUMP_ATTR
1585
1586  /*!
1587   * Send all Attributes to server. This method is overloaded, since only grid_ref attribute
1588   * must be sent to server and not domain_ref/axis_ref/scalar_ref.
1589   */
1590   
1591  void CField::sendAllAttributesToServer(CContextClient* client)
1592  TRY
1593  {
1594    if (grid_ref.isEmpty())
1595    {
1596      grid_ref=sentGrid_->getId() ;
1597      SuperClass::sendAllAttributesToServer(client) ;
1598      domain_ref.reset() ;
1599      axis_ref.reset() ;
1600      scalar_ref.reset() ;
1601      grid_ref.reset();
1602    }
1603    else 
1604    {
1605      string tmp = grid_ref;
1606      grid_ref = sentGrid_->getId() ;
1607      SuperClass::sendAllAttributesToServer(client) ;
1608      grid_ref = tmp ;
1609    }
1610  }
1611  CATCH_DUMP_ATTR
1612   
1613  void CField::sendAddVariable(const string& id, CContextClient* client)
1614  TRY
1615  {
1616    sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE, client);
1617  }
1618  CATCH_DUMP_ATTR
1619
1620  void CField::sendAddVariableGroup(const string& id, CContextClient* client)
1621  TRY
1622  {
1623    sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE_GROUP, client);
1624  }
1625  CATCH_DUMP_ATTR
1626
1627  void CField::recvAddVariable(CEventServer& event)
1628  TRY
1629  {
1630    CBufferIn* buffer = event.subEvents.begin()->buffer;
1631    string id;
1632    *buffer >> id;
1633    get(id)->recvAddVariable(*buffer);
1634  }
1635  CATCH
1636
1637  void CField::recvAddVariable(CBufferIn& buffer)
1638  TRY
1639  {
1640    string id;
1641    buffer >> id;
1642    addVariable(id);
1643  }
1644  CATCH_DUMP_ATTR
1645
1646  void CField::recvAddVariableGroup(CEventServer& event)
1647  TRY
1648  {
1649    CBufferIn* buffer = event.subEvents.begin()->buffer;
1650    string id;
1651    *buffer >> id;
1652    get(id)->recvAddVariableGroup(*buffer);
1653  }
1654  CATCH
1655
1656  void CField::recvAddVariableGroup(CBufferIn& buffer)
1657  TRY
1658  {
1659    string id;
1660    buffer >> id;
1661    addVariableGroup(id);
1662  }
1663  CATCH_DUMP_ATTR
1664
1665  /*!
1666   * Check on freq_off and freq_op attributes.
1667   */
1668  void CField::checkTimeAttributes(CDuration* freqOp)
1669  TRY
1670  {
1671    if (hasFileIn() && !(operation.getValue() == "instant" || operation.getValue() == "once") )     
1672      ERROR("void CField::checkTimeAttributes(void)",
1673         << "Unsupported operation for field '" << getFieldOutputName() << "'." << std::endl
1674         << "Currently only \"instant\" is supported for fields read from file.")
1675
1676    if (freq_op.isEmpty())
1677    {
1678      if (operation.getValue() == "instant")
1679      {
1680        if (hasFileIn() || hasFileOut()) freq_op.setValue(getRelFile()->output_freq.getValue());
1681        else freq_op=*freqOp ;
1682      }
1683      else freq_op.setValue(TimeStep);
1684    }
1685    if (freq_offset.isEmpty()) freq_offset.setValue(hasFileIn() ? NoneDu : (freq_op.getValue() - TimeStep));
1686  }
1687  CATCH_DUMP_ATTR
1688
1689  /*!
1690   * Returns string arithmetic expression associated to the field.
1691   * \return if content is defined return content string, otherwise, if "expr" attribute is defined, return expr string.
1692   */
1693  const string& CField::getExpression(void)
1694  TRY
1695  {
1696    if (!expr.isEmpty() && content.empty())
1697    {
1698      content = expr;
1699      expr.reset();
1700    }
1701
1702    return content;
1703  }
1704  CATCH_DUMP_ATTR
1705
1706  bool CField::hasExpression(void) const
1707  TRY
1708  {
1709    return (!expr.isEmpty() || !content.empty());
1710  }
1711  CATCH
1712
1713  bool CField::hasGridMask(void) const
1714  TRY
1715  {
1716    return (this->grid_->hasMask());
1717  }
1718  CATCH
1719
1720  DEFINE_REF_FUNC(Field,field)
1721} // namespace xios
Note: See TracBrowser for help on using the repository browser.