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

Last change on this file since 2182 was 2182, checked in by ymipsl, 3 years ago

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