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

Last change on this file since 2507 was 2507, checked in by ymipsl, 12 months ago

Merging XIOS3_ATTACHED branch into XIOS3 trunk.

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