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

Last change on this file since 1975 was 1973, checked in by ymipsl, 4 years ago

Big cleaning on XIOS coupling branch
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: 58.2 KB
Line 
1#include "field.hpp"
2
3#include "attribute_template.hpp"
4#include "object_template.hpp"
5#include "group_template.hpp"
6
7#include "node_type.hpp"
8#include "calendar_util.hpp"
9#include "message.hpp"
10#include "xios_spl.hpp"
11#include "type.hpp"
12#include "timer.hpp"
13#include "context_client.hpp"
14#include "context_server.hpp"
15#include <set>
16#include "garbage_collector.hpp"
17#include "pass_through_filter.hpp"
18#include "filter_expr_node.hpp"
19#include "lex_parser.hpp"
20#include "temporal_filter.hpp"
21#include "spatial_transform_filter.hpp"
22#include "server_from_client_source_filter.hpp"
23#include "file_reader_source_filter.hpp"
24#include "tracer.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  std::shared_ptr<COutputPin> CField::getInstantDataFilter()
388  TRY
389  {
390    return instantDataFilter;
391  }
392  CATCH_DUMP_ATTR
393
394  //----------------------------------------------------------------
395
396  /*!
397    Build up graph of grids which plays role of destination and source in grid transformation
398    This function should be called before \func solveGridReference()
399  */
400  void CField::buildGridTransformationGraph()
401  TRY
402  {
403    CContext* context = CContext::getCurrent();
404    if (context->getServiceType()==CServicesManager::CLIENT)
405    {
406      if (grid_ && !grid_->isTransformed() && hasDirectFieldReference() && grid_ != getDirectFieldReference()->grid_)
407      {
408        grid_->addTransGridSource(getDirectFieldReference()->grid_);
409      }
410    }
411  }
412  CATCH_DUMP_ATTR
413
414  /*!
415    Generate a new grid destination if there are more than one grid source pointing to a same grid destination
416  */
417  void CField::generateNewTransformationGridDest()
418  TRY
419  {
420    CContext* context = CContext::getCurrent();
421    if (context->getServiceType()==CServicesManager::CLIENT)
422    {
423      std::map<CGrid*,std::pair<bool,StdString> >& gridSrcMap = grid_->getTransGridSource();
424      if (1 < gridSrcMap.size())
425      {
426        // Search for grid source
427        CGrid* gridSrc = grid_;
428        CField* currField = this;
429        std::vector<CField*> hieraField;
430        while (currField->hasDirectFieldReference() && (gridSrc == grid_))
431        {
432          hieraField.push_back(currField);
433          CField* tmp = currField->getDirectFieldReference();
434          currField = tmp;
435          gridSrc = currField->grid_;
436        }
437
438        if (gridSrcMap.end() != gridSrcMap.find(gridSrc))
439        {
440          CGrid* gridTmp;
441          std::pair<bool,StdString> newGridDest = gridSrcMap[gridSrc];
442          if (newGridDest.first)
443          {
444            StdString newIdGridDest = newGridDest.second;
445            if (!CGrid::has(newIdGridDest))
446            {
447              ERROR("CGrid* CGrid::generateNewTransformationGridDest()",
448                << " Something wrong happened! Grid whose id " << newIdGridDest
449                << "should exist ");
450            }
451            gridTmp = CGrid::get(newIdGridDest);
452          }
453          else
454          {
455            StdString newIdGridDest = CGrid::generateId(gridSrc, grid_);
456            gridTmp = CGrid::cloneGrid(newIdGridDest, grid_);
457
458            (gridSrcMap[gridSrc]).first = true;
459            (gridSrcMap[gridSrc]).second = newIdGridDest;
460          }
461
462          // Update all descendants
463          for (std::vector<CField*>::iterator it = hieraField.begin(); it != hieraField.end(); ++it)
464          {
465            (*it)->grid_ = gridTmp;
466            (*it)->updateRef((*it)->grid_);
467          }
468        }
469      }
470    }
471  }
472  CATCH_DUMP_ATTR
473
474  void CField::updateRef(CGrid* grid)
475  TRY
476  {
477    if (!grid_ref.isEmpty()) grid_ref.setValue(grid->getId());
478    else
479    {
480      std::vector<CAxis*> axisTmp = grid->getAxis();
481      std::vector<CDomain*> domainTmp = grid->getDomains();
482      if ((1<axisTmp.size()) || (1<domainTmp.size()))
483        ERROR("void CField::updateRef(CGrid* grid)",
484          << "More than one domain or axis is available for domain_ref/axis_ref of field " << this->getId());
485
486      if ((!domain_ref.isEmpty()) && (domainTmp.empty()))
487        ERROR("void CField::updateRef(CGrid* grid)",
488          << "Incoherent between available domain and domain_ref of field " << this->getId());
489      if ((!axis_ref.isEmpty()) && (axisTmp.empty()))
490        ERROR("void CField::updateRef(CGrid* grid)",
491          << "Incoherent between available axis and axis_ref of field " << this->getId());
492
493      if (!domain_ref.isEmpty()) domain_ref.setValue(domainTmp[0]->getId());
494      if (!axis_ref.isEmpty()) axis_ref.setValue(axisTmp[0]->getId());
495    }
496  }
497  CATCH_DUMP_ATTR
498   
499  /*!
500    Solve reference of all enabled fields even the source fields .
501    In this step, we do transformations.
502  */
503  void CField::solveAllEnabledFieldsAndTransform()
504  TRY
505  {
506    CContext* context = CContext::getCurrent();
507
508    if (!isReferenceSolvedAndTransformed)
509    {
510      isReferenceSolvedAndTransformed = true;
511
512      if (context->getServiceType()==CServicesManager::CLIENT)
513      {
514        solveRefInheritance(true);
515        if (hasDirectFieldReference()) getDirectFieldReference()->solveAllEnabledFieldsAndTransform();
516      }
517
518      if (context->getServiceType()==CServicesManager::GATHERER || context->getServiceType()==CServicesManager::OUT_SERVER)
519        solveServerOperation();
520
521      solveGridReference();
522
523      if (context->getServiceType()==CServicesManager::CLIENT)
524      {
525        solveGenerateGrid();
526        buildGridTransformationGraph();
527      }
528
529      solveGridDomainAxisRef(false);
530
531      if (context->getServiceType()==CServicesManager::CLIENT)
532      {
533        solveTransformedGrid();
534      }
535
536      solveGridDomainAxisRef(false);
537    }
538  }
539  CATCH_DUMP_ATTR
540
541  void CField::checkGridOfEnabledFields()
542  TRY
543  {
544    if (!isGridChecked)
545    {
546      isGridChecked = true;
547      solveCheckMaskIndex(false);
548    }
549  }
550  CATCH_DUMP_ATTR
551
552  void CField::sendGridComponentOfEnabledFields()
553  TRY
554  {
555    solveGridDomainAxisRef(true);
556    // solveCheckMaskIndex(true);
557  }
558  CATCH_DUMP_ATTR
559
560  void CField::sendGridOfEnabledFields()
561  TRY
562  {
563    // solveGridDomainAxisRef(true);
564    solveCheckMaskIndex(true);
565  }   
566  CATCH_DUMP_ATTR
567
568  void CField::solveOnlyReferenceEnabledField(void)
569  TRY
570  {
571    CContext* context = CContext::getCurrent();
572    if (!isReferenceSolved)
573    {
574      isReferenceSolved = true;
575
576      if (context->getServiceType()==CServicesManager::CLIENT)
577      {
578        solveRefInheritance(true);
579        if (hasDirectFieldReference()) getDirectFieldReference()->solveOnlyReferenceEnabledField();
580      }
581
582      if (context->getServiceType()==CServicesManager::GATHERER || context->getServiceType()==CServicesManager::OUT_SERVER)
583        solveServerOperation();
584
585      solveGridReference();
586      grid_->solveElementsRefInheritance(true); // make it again to solve grid reading from file
587
588      if (context->getServiceType()==CServicesManager::CLIENT)
589      {
590        solveGenerateGrid();
591        buildGridTransformationGraph();
592      }
593    }
594  }
595  CATCH_DUMP_ATTR
596
597  void CField::solveAllReferenceEnabledField(bool doSending2Server)
598  TRY
599  {
600    CContext* context = CContext::getCurrent();
601    solveOnlyReferenceEnabledField();
602
603    if (!areAllReferenceSolved)
604    {
605      areAllReferenceSolved = true;
606     
607      if (context->getServiceType()==CServicesManager::CLIENT)
608      {
609        solveRefInheritance(true);
610        if (hasDirectFieldReference()) getDirectFieldReference()->solveAllReferenceEnabledField(false);
611      }
612      else if (context->getServiceType()==CServicesManager::GATHERER || context->getServiceType()==CServicesManager::OUT_SERVER)
613        solveServerOperation();
614
615      solveGridReference();
616    }
617
618    solveGridDomainAxisRef(doSending2Server);
619
620    if (context->getServiceType()==CServicesManager::CLIENT)
621    {
622      solveTransformedGrid();
623    }
624
625  }
626  CATCH_DUMP_ATTR
627
628  /*!
629   * Compute the required buffer size to send the fields data.
630   * \param [in/out] bufferSize Modifying the bufferSize for the client context
631   * \param [in/out] maxEventSize Modifying the maximum event size for the client context
632   * \param [in] bufferForWriting True if buffers are used for sending data for writing
633   */ 
634  void CField::setContextClientDataBufferSize(map<CContextClient*,map<int,size_t>>& bufferSize, 
635                                              map<CContextClient*,map<int,size_t>>& maxEventSize, 
636                                              bool bufferForWriting)
637  {
638    auto& contextBufferSize = bufferSize[client] ;
639    auto& contextMaxEventSize = maxEventSize[client] ;
640    const std::map<int, size_t> mapSize = grid_->getDataBufferSize(client, getId(), bufferForWriting);
641    for(auto& it : mapSize )
642    {
643      // If contextBufferSize[it.first] does not exist, it will be zero-initialized
644      // so we can use it safely without checking for its existance
645      if (CXios::isOptPerformance) contextBufferSize[it.first] += it.second;
646      else if (contextBufferSize[it.first] < it.second) contextBufferSize[it.first] = it.second;
647
648      if (contextMaxEventSize[it.first] < it.second) contextMaxEventSize[it.first] = it.second;
649    }
650
651  }
652
653  void CField::setContextClientAttributesBufferSize(map<CContextClient*,map<int,size_t>>& bufferSize, 
654                                                   map<CContextClient*,map<int,size_t>>& maxEventSize, 
655                                                   bool bufferForWriting)
656  {
657    auto& contextBufferSize = bufferSize[client] ;
658    auto& contextMaxEventSize = maxEventSize[client] ;
659    const std::map<int, size_t> mapSize = grid_->getAttributesBufferSize(client, bufferForWriting);
660    for(auto& it : mapSize )
661    {
662      // If contextBufferSize[it.first] does not exist, it will be zero-initialized
663      // so we can use it safely without checking for its existance
664      if (contextBufferSize[it.first] < it.second) contextBufferSize[it.first] = it.second;
665      if (contextMaxEventSize[it.first] < it.second) contextMaxEventSize[it.first] = it.second;
666    }
667
668  }
669
670
671// ym obsolete to be removed
672  std::map<int, StdSize> CField::getGridAttributesBufferSize(CContextClient* client, bool bufferForWriting /*= "false"*/)
673  TRY
674  {
675    return grid_->getAttributesBufferSize(client, bufferForWriting);
676  }
677  CATCH_DUMP_ATTR
678
679// ym obsolete to be removed
680  std::map<int, StdSize> CField::getGridDataBufferSize(CContextClient* client, bool bufferForWriting /*= "false"*/)
681  TRY
682  {
683    return grid_->getDataBufferSize(client, getId(), bufferForWriting);
684  }
685  CATCH_DUMP_ATTR
686
687
688
689  size_t CField::getGlobalWrittenSize()
690  TRY
691  {
692    return grid_->getGlobalWrittenSize();
693  }
694  CATCH_DUMP_ATTR
695
696  //----------------------------------------------------------------
697
698  void CField::solveServerOperation(void)
699  TRY
700  {
701    CContext* context = CContext::getCurrent();
702
703    if (freq_op.isEmpty()) freq_op.setValue(TimeStep);
704
705    if (freq_offset.isEmpty()) freq_offset.setValue(NoneDu);
706
707    if (operation.isEmpty())
708      ERROR("void CField::solveServerOperation(void)",
709            << "An operation must be defined for field \"" << getId() << "\".");
710
711    std::shared_ptr<func::CFunctor> functor;
712    CArray<double, 1> dummyData;
713
714#define DECLARE_FUNCTOR(MType, mtype) \
715    if (operation.getValue().compare(#mtype) == 0) \
716    { \
717      functor.reset(new func::C##MType(dummyData)); \
718    }
719
720#include "functor_type.conf"
721
722    if (!functor)
723      ERROR("void CField::solveServerOperation(void)",
724            << "\"" << operation << "\" is not a valid operation.");
725
726    operationTimeType = functor->timeType();
727  }
728  CATCH_DUMP_ATTR
729
730 //----------------------------------------------------------------
731
732  bool CField::buildWorkflowGraph(CGarbageCollector& gc)
733  {
734    if (buildWorkflowGraphDone_) return true ;
735   
736    const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
737    const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
738
739    if (!inputFilter) inputFilter = std::shared_ptr<CPassThroughFilter>(new CPassThroughFilter(gc)); 
740     
741    if (hasDirectFieldReference())
742    {
743      CField* fieldRef = getDirectFieldReference();
744      bool ret=fieldRef->buildWorkflowGraph(gc); 
745      if (!ret) return false ; // workflow graph cannot be built at this stage
746    }
747
748    // now construct grid and check if element are enabled
749    solveGridReference() ; // grid_ is now defined
750    if (!isGridCompleted()) return false;
751
752    // Check if we have an expression to parse
753    std::shared_ptr<COutputPin> filterExpr ;
754    if (hasExpression())
755    {
756      boost::scoped_ptr<IFilterExprNode> expr(parseExpr(getExpression() + '\0'));
757      filterExpr = expr->reduce(gc, *this);
758      if (!filterExpr) return false ; // workflow graph cannot be built at this stage
759    }
760   
761    // prepare transformation. Need to know before if workflow of auxillary field can be built
762    if (hasDirectFieldReference())
763    {
764      auto gridPath=getGridPath() ;
765      gridPath.push_back(grid_) ;
766
767      CGrid* gridSrc=getDirectFieldReference()->getGrid() ;
768      for(auto grid : gridPath)
769      {
770        grid->solveElementsRefInheritance() ;
771        grid->completeGrid(gridSrc); // grid generation, to be checked
772        grid->checkElementsAttributes() ;
773        grid->prepareTransformGrid(gridSrc) ; // prepare the grid tranformation
774        for(auto fieldId : grid->getAuxInputTransformGrid()) // try to build workflow graph for auxillary field tranformation
775          if (!CField::get(fieldId)->buildWorkflowGraph(gc)) return false ;
776        gridSrc=grid ;
777      }
778     
779      std::shared_ptr<COutputPin> lastFilter ;
780      if (filterExpr) lastFilter=filterExpr ;
781      else lastFilter = inputFilter ;
782     
783      gridSrc=getDirectFieldReference()->getGrid() ;
784      for(auto grid : gridPath) 
785      {
786        grid->makeTransformGrid() ; // make the grid transformation
787        if (grid->hasTransform()) 
788        {
789          std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters = CSpatialTransformFilter::buildFilterGraph(gc, gridSrc, grid, detectMissingValues, defaultValue); 
790          lastFilter->connectOutput(filters.first, 0);
791          lastFilter = filters.second;
792          gridSrc=grid ;
793        }
794      }
795      instantDataFilter = lastFilter ;
796     
797      // connect the input Filter to the reference
798      getDirectFieldReference()->getInstantDataFilter()->connectOutput(inputFilter,0);
799    }
800    else 
801    {
802      if (hasFileIn()) // input file, attemp to read the grid from file
803      {
804         // must be checked
805         fileIn_->initRead() ;
806         fileIn_->checkReadFile();
807         grid_->solveElementsRefInheritance() ;
808         if (fileIn_->isClientSide()) fileIn_->readFieldAttributesMetaData(this);
809         grid_->completeGrid(); // grid generation, to be checked
810         if (fileIn_->isClientSide()) fileIn_->readFieldAttributesValues(this);
811         grid_->checkElementsAttributes() ;
812         grid_->solveDomainAxisBaseRef();
813         // probably in future tag grid incomplete if coming from a reading
814         instantDataFilter=inputFilter ;
815      } 
816      else if (hasCouplerIn())
817      {
818        grid_->checkElementsAttributes() ;
819        instantDataFilter=inputFilter ;
820      }
821      else
822      {
823        setModelIn() ; // no reference, the field is potentially a source field from model
824
825        grid_->solveElementsRefInheritance() ;
826        grid_->completeGrid(); // grid generation, to be checked
827        grid_->checkElementsAttributes() ;
828        instantDataFilter=inputFilter ;
829      }
830    }
831   
832    if (hasFileOut())
833    {
834      if (fileOut_->isServerSide())
835      {
836        this->solveServerOperation() ;
837      }
838    }
839
840    buildWorkflowGraphDone_ = true ;
841    workflowEnabled_ = true ;
842    return true ;
843  }
844   
845  /*!
846   * Connect field to filter to send data to server. A temporal filter is inserted before accordingly to the
847   * output frequency of the file
848   * \param gc the garbage collector to use when building the filter graph
849   */
850  void CField::connectToFileServer(CGarbageCollector& gc)
851  {
852    // insert temporal filter before sending to files
853    clientToServerStoreFilter_ = std::shared_ptr<CClientToServerStoreFilter>(new CClientToServerStoreFilter(gc, this, client));
854    // insert temporal filter before sending to files
855    getTemporalDataFilter(gc, fileOut_->output_freq)->connectOutput(clientToServerStoreFilter_, 0);
856  } 
857
858  void CField::connectToCouplerOut(CGarbageCollector& gc)
859  {
860    // insert temporal filter before sending to files
861    clientToServerStoreFilter_ = std::shared_ptr<CClientToServerStoreFilter>(new CClientToServerStoreFilter(gc, this, client));
862    instantDataFilter->connectOutput(clientToServerStoreFilter_, 0);
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  } 
878 
879  /*!
880   * Connect field to a source filter to receive data from a client (on server side).
881   */
882  void CField::connectToClientInput(CGarbageCollector& gc)
883  {
884    serverFromClientSourceFilter_ = std::shared_ptr<CServerFromClientSourceFilter>(new CServerFromClientSourceFilter(gc,  grid_));
885    serverFromClientSourceFilter_ -> connectOutput(inputFilter,0) ;
886  } 
887
888
889  /*!
890   * Connect field to a source filter to receive data from a server (on client side).
891   */
892  void CField::connectToServerInput(CGarbageCollector& gc)
893  {
894    checkTimeAttributes();
895    clientFromServerSourceFilter_ = std::shared_ptr<CClientFromServerSourceFilter>(new CClientFromServerSourceFilter(gc,this)) ;
896    clientFromServerSourceFilter_ -> connectOutput(inputFilter,0) ;
897  } 
898
899  /*!
900   * Connect field to a source filter to receive data from coupler (on client side).
901   */
902   void CField::connectToCouplerIn(CGarbageCollector& gc)
903  {
904    CContext* context = CContext::getCurrent();
905
906    if (freq_op.isEmpty()) freq_op.setValue(TimeStep);
907    if (freq_offset.isEmpty()) freq_offset.setValue(freq_op.getValue() - TimeStep);
908    clientFromClientSourceFilter_ = std::shared_ptr<CClientFromClientSourceFilter>(new CClientFromClientSourceFilter(gc, this)) ;
909    clientFromClientSourceFilter_ -> connectOutput(inputFilter,0) ;
910   
911  } 
912
913  /*!
914   * Connect field to a file writer filter to write data in file (on server side).
915   */
916  void CField::connectToFileWriter(CGarbageCollector& gc)
917  {
918    fileWriterStoreFilter_ = std::shared_ptr<CFileWriterStoreFilter>(new CFileWriterStoreFilter(gc, this));
919    instantDataFilter->connectOutput(fileWriterStoreFilter_, 0);
920  } 
921
922  /*!
923   * Connect field to a file reader filter to read data from file (on server side).
924   */
925  void CField::connectToFileReader(CGarbageCollector& gc)
926  {
927    fileReaderSourceFilter_ = std::shared_ptr<CFileReaderSourceFilter>(new CFileReaderSourceFilter(gc, this));
928    fileReaderSourceFilter_->connectOutput(inputFilter, 0);
929  }
930
931
932  /*!
933   * Connect field to a store filter to output data to model on client Side
934   */
935  void CField::connectToModelOutput(CGarbageCollector& gc)
936  {
937    clientToModelStoreFilter_ = std::shared_ptr<CClientToModelStoreFilter>(new CClientToModelStoreFilter(gc, this));
938    instantDataFilter->connectOutput(clientToModelStoreFilter_, 0);
939  }
940
941
942 
943  void CField::connectToServerToClient(CGarbageCollector& gc)
944  {
945    serverToClientStoreFilter_ = std::shared_ptr<CServerToClientStoreFilter>(new CServerToClientStoreFilter(gc, this, client));
946    instantDataFilter->connectOutput(serverToClientStoreFilter_, 0);
947  }
948
949  /*!
950   * Transform the grid_path attribut into vector of grid.
951   * \return the vector CGrid* containing the list of grid path for tranformation
952   */ 
953  vector<CGrid*> CField::getGridPath(void)
954  {
955    std::vector<CGrid*> gridPath;
956
957    if (hasDirectFieldReference() && grid_ != getDirectFieldReference()->grid_)
958    {
959      if (!grid_path.isEmpty())
960      {
961        std::string gridId;
962        size_t start = 0, end;
963
964        do
965        {
966          end = grid_path.getValue().find(',', start);
967          if (end != std::string::npos)
968          {
969            gridId = grid_path.getValue().substr(start, end - start);
970            start = end + 1;
971          }
972          else gridId = grid_path.getValue().substr(start);
973
974          if (!CGrid::has(gridId))
975            ERROR("void CField::solveTransformedGrid()",
976               << "Invalid grid_path, the grid '" << gridId << "' does not exist.");
977
978          gridPath.push_back(CGrid::get(gridId));
979        }
980        while (end != std::string::npos);
981      }
982    }
983    return gridPath ;
984  }
985
986  /*!
987   * Constructs the graph filter for the field, enabling or not the data output.
988   * This method should not be called more than once with enableOutput equal to true.
989   *
990   * \param gc the garbage collector to use when building the filter graph
991   * \param enableOutput must be true when the field data is to be
992   *                     read by the client or/and written to a file
993   */
994   // ym obselete : to be removed later....
995  void CField::buildFilterGraph(CGarbageCollector& gc, bool enableOutput)
996  TRY
997  {     
998   //  ==> before removing, solving dependency in spatial_transform_filter.cpp about auxilairy field
999/*
1000    if (!isReferenceSolvedAndTransformed) solveAllEnabledFieldsAndTransform();
1001    if (!isGridChecked) checkGridOfEnabledFields();
1002
1003    const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1004    const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
1005
1006    CContext* context = CContext::getCurrent();
1007    bool hasWriterServer = context->getServiceType()==CServicesManager::OUT_SERVER ;
1008    bool hasIntermediateServer = context->getServiceType()==CServicesManager::GATHERER ;
1009
1010    if (hasWriterServer)
1011    {
1012      if (!instantDataFilter)
1013        instantDataFilter = clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid_, true, false));
1014
1015
1016      // If the field data is to be read by the client or/and written to a file
1017      if (enableOutput && !clientToModelStoreFilter_ && !fileWriterFilter)
1018      {
1019        if (getRelFile() && (getRelFile()->mode.isEmpty() || getRelFile()->mode == CFile::mode_attr::write))
1020        {
1021          fileServerWriterFilter = std::shared_ptr<CFileServerWriterFilter>(new CFileServerWriterFilter(gc, this));
1022          instantDataFilter->connectOutput(fileServerWriterFilter, 0);
1023        }
1024      }
1025    }
1026    else if (hasIntermediateServer)
1027    {
1028      if (!instantDataFilter)
1029        instantDataFilter = clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid_, false, false));
1030
1031      // If the field data is to be read by the client or/and written to a file
1032      if (enableOutput && !clientToModelStoreFilter_ && !fileWriterFilter)
1033      {
1034        if (getRelFile() && (getRelFile()->mode.isEmpty() || getRelFile()->mode == CFile::mode_attr::write))
1035        {
1036          fileWriterFilter = std::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this, getRelFile()->getContextClient()));
1037          instantDataFilter->connectOutput(fileWriterFilter, 0);
1038        }
1039      }
1040    }
1041    else
1042    {
1043      // Start by building a filter which can provide the field's instant data
1044      if (!instantDataFilter)
1045      {
1046        // Check if we have an expression to parse
1047        if (hasExpression())
1048        {
1049          boost::scoped_ptr<IFilterExprNode> expr(parseExpr(getExpression() + '\0'));
1050          std::shared_ptr<COutputPin> filter = expr->reduce(gc, *this);
1051
1052          // Check if a spatial transformation is needed
1053          if (!field_ref.isEmpty())
1054          {
1055            CGrid* gridRef = CField::get(field_ref)->grid_;
1056            if (grid_ && grid_ != gridRef && grid_->hasTransform())
1057            {
1058                std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters = CSpatialTransformFilter::buildFilterGraph(gc, gridRef, grid_, detectMissingValues, defaultValue);
1059
1060              filter->connectOutput(filters.first, 0);
1061              filter = filters.second;
1062            }
1063          }
1064
1065          instantDataFilter = filter;
1066        }
1067        // Check if we have a reference on another field
1068        else if (!field_ref.isEmpty()) instantDataFilter = getFieldReference(gc);
1069        // Check if the data is to be read from a file
1070        else if (getRelFile() && !getRelFile()->mode.isEmpty() && getRelFile()->mode == CFile::mode_attr::read)
1071        {
1072          checkTimeAttributes();
1073          instantDataFilter = serverSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid_, true, false, freq_offset, true,
1074                                                                                                       detectMissingValues, defaultValue));
1075        }
1076        else // The data might be passed from the model
1077        {
1078          if (check_if_active.isEmpty()) check_if_active = false;
1079          instantDataFilter = clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid_, false, true, NoneDu, false,
1080                                                                                                      detectMissingValues, defaultValue));
1081        }
1082      }
1083
1084      // If the field data is to be read by the client or/and written to a file
1085      if (enableOutput && !clientToModelStoreFilter_ && !fileWriterFilter)
1086      {
1087        if (!read_access.isEmpty() && read_access)
1088        {
1089          clientToModelStoreFilter_ = std::shared_ptr<CClientToModelStoreFilter>(new CClientToModelStoreFilter(gc, this));
1090          instantDataFilter->connectOutput(clientToModelStoreFilter_, 0);
1091        }
1092
1093        if (getRelFile() && (getRelFile()->mode.isEmpty() || getRelFile()->mode == CFile::mode_attr::write))
1094        {
1095          fileWriterFilter = std::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this, getRelFile()->getContextClient()));
1096          getTemporalDataFilter(gc, getRelFile()->output_freq)->connectOutput(fileWriterFilter, 0);
1097        }
1098      }
1099    }
1100*/ 
1101  }
1102  CATCH_DUMP_ATTR
1103
1104  /*!
1105   * Returns the filter needed to handle the field reference.
1106   * This method should only be called when building the filter graph corresponding to the field.
1107   *
1108   * \param gc the garbage collector to use
1109   * \return the output pin corresponding to the field reference
1110   */
1111  std::shared_ptr<COutputPin> CField::getFieldReference(CGarbageCollector& gc)
1112  TRY
1113  {
1114    if (instantDataFilter || field_ref.isEmpty())
1115      ERROR("COutputPin* CField::getFieldReference(CGarbageCollector& gc)",
1116            "Impossible to get the field reference for a field which has already been parsed or which does not have a field_ref.");
1117
1118    CField* fieldRef = CField::get(field_ref);
1119    fieldRef->buildFilterGraph(gc, false);
1120
1121    std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters;
1122    // Check if a spatial transformation is needed
1123    if (grid_ && grid_ != fieldRef->grid_ && grid_->hasTransform())
1124    {       
1125      bool hasMissingValue = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1126      double defaultValue  = hasMissingValue ? default_value : (!default_value.isEmpty() ? default_value : 0.0);                               
1127      filters = CSpatialTransformFilter::buildFilterGraph(gc, fieldRef->grid_, grid_, hasMissingValue, defaultValue);
1128    }
1129    else
1130      filters.first = filters.second = std::shared_ptr<CFilter>(new CPassThroughFilter(gc));
1131
1132    fieldRef->getInstantDataFilter()->connectOutput(filters.first, 0);
1133
1134    return filters.second;
1135  }
1136  CATCH_DUMP_ATTR
1137
1138  /*!
1139   * Returns the filter needed to handle a self reference in the field's expression.
1140   * If the needed filter does not exist, it is created, otherwise it is reused.
1141   * This method should only be called when building the filter graph corresponding
1142   * to the field's expression.
1143   *
1144   * \param gc the garbage collector to use
1145   * \return the output pin corresponding to a self reference
1146   */
1147
1148/* old version
1149  std::shared_ptr<COutputPin> CField::getSelfReference(CGarbageCollector& gc)
1150  TRY
1151  {
1152    if (instantDataFilter || !hasExpression())
1153      ERROR("COutputPin* CField::getSelfReference(CGarbageCollector& gc)",
1154            "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1155
1156    if (!selfReferenceFilter)
1157    {
1158      const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1159      const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
1160
1161      if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
1162      {
1163        if (!serverSourceFilter)
1164        {
1165          checkTimeAttributes();
1166          serverSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid_, true, false, freq_offset, true,
1167                                                              detectMissingValues, defaultValue));
1168         }
1169
1170        selfReferenceFilter = serverSourceFilter;
1171      }
1172      else if (!field_ref.isEmpty())
1173      {
1174        CField* fieldRef = CField::get(field_ref);
1175        fieldRef->buildFilterGraph(gc, false);
1176        selfReferenceFilter = fieldRef->getInstantDataFilter();
1177      }
1178      else
1179      {
1180        if (!clientSourceFilter)
1181        {
1182          if (check_if_active.isEmpty()) check_if_active = false;
1183          clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid_, true, true, NoneDu, false,
1184                                                                                detectMissingValues, defaultValue));
1185        }
1186
1187        selfReferenceFilter = clientSourceFilter;
1188      }
1189    }
1190
1191    return selfReferenceFilter;
1192  }
1193  CATCH_DUMP_ATTR
1194*/
1195  std::shared_ptr<COutputPin> CField::getSelfReference(CGarbageCollector& gc)
1196  TRY
1197  {
1198    return inputFilter ;
1199  } 
1200  CATCH_DUMP_ATTR
1201
1202  /*!
1203   * Returns the temporal filter corresponding to the field's temporal operation
1204   * for the specified operation frequency. The filter is created if it does not
1205   * exist, otherwise it is reused.
1206   *
1207   * \param gc the garbage collector to use
1208   * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1209   * \return the output pin corresponding to the requested temporal filter
1210   */
1211  std::shared_ptr<COutputPin> CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1212  TRY
1213  {
1214    std::map<CDuration, std::shared_ptr<COutputPin> >::iterator it = temporalDataFilters.find(outFreq);
1215
1216    if (it == temporalDataFilters.end())
1217    {
1218      if (operation.isEmpty())
1219        ERROR("void CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1220              << "An operation must be defined for field \"" << getId() << "\".");
1221
1222      checkTimeAttributes(&outFreq);
1223
1224      const bool detectMissingValues = (!detect_missing_value.isEmpty()  && detect_missing_value == true);
1225      std::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1226                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
1227                                                                             freq_op, freq_offset, outFreq, detectMissingValues));
1228
1229      instantDataFilter->connectOutput(temporalFilter, 0);
1230
1231      it = temporalDataFilters.insert(std::make_pair(outFreq, temporalFilter)).first;
1232    }
1233
1234    return it->second;
1235  }
1236  CATCH_DUMP_ATTR
1237
1238  /*!
1239    * Returns the temporal filter corresponding to the field's temporal operation
1240    * for the specified operation frequency.
1241    *
1242    * \param gc the garbage collector to use
1243    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1244    * \return the output pin corresponding to the requested temporal filter
1245    */
1246
1247  std::shared_ptr<COutputPin> CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1248  TRY
1249  {
1250    if (instantDataFilter || !hasExpression())
1251      ERROR("COutputPin* CField::getSelfTemporalDataFilter(CGarbageCollector& gc)",
1252            "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1253   
1254    if (selfTemporalDataFilter) return selfTemporalDataFilter;
1255
1256    if (hasDirectFieldReference())
1257    {
1258      CField* fieldRef=getDirectFieldReference();
1259      return fieldRef->getTemporalDataFilter(gc, outFreq) ;
1260    }
1261    else
1262    {
1263      if (selfTemporalDataFilter) return selfTemporalDataFilter ;
1264
1265      if (operation.isEmpty())
1266        ERROR("void CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1267              << "An operation must be defined for field \"" << getId() << "\".");
1268
1269      checkTimeAttributes(&outFreq); //bof
1270
1271      const bool detectMissingValues = (!detect_missing_value.isEmpty() && detect_missing_value == true);
1272      selfTemporalDataFilter = std::shared_ptr<CTemporalFilter>(new CTemporalFilter(gc, operation,
1273                                                                CContext::getCurrent()->getCalendar()->getInitDate(),
1274                                                                freq_op, freq_offset, outFreq, detectMissingValues));
1275
1276      inputFilter->connectOutput(selfTemporalDataFilter, 0);
1277      return selfTemporalDataFilter ;
1278    }
1279  }
1280  CATCH_DUMP_ATTR
1281
1282/* old version   
1283  std::shared_ptr<COutputPin> CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1284  TRY
1285  {
1286    if (instantDataFilter || !hasExpression())
1287      ERROR("COutputPin* CField::getSelfTemporalDataFilter(CGarbageCollector& gc)",
1288            "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1289
1290    if (!selfReferenceFilter) getSelfReference(gc) ;
1291
1292    if (serverSourceFilter || clientSourceFilter)
1293    {
1294      if (operation.isEmpty())
1295        ERROR("void CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1296              << "An operation must be defined for field \"" << getId() << "\".");
1297
1298      checkTimeAttributes(&outFreq);
1299
1300      const bool detectMissingValues = (!detect_missing_value.isEmpty() && detect_missing_value == true);
1301      std::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1302                                                                          CContext::getCurrent()->getCalendar()->getInitDate(),
1303                                                                          freq_op, freq_offset, outFreq, detectMissingValues));
1304
1305      selfReferenceFilter->connectOutput(temporalFilter, 0);
1306      return temporalFilter ;
1307    }
1308    else if (!field_ref.isEmpty())
1309    {
1310      CField* fieldRef = CField::get(field_ref);
1311      fieldRef->buildFilterGraph(gc, false);
1312      return fieldRef->getTemporalDataFilter(gc, outFreq) ;
1313    }
1314  }
1315  CATCH_DUMP_ATTR
1316*/
1317
1318  //----------------------------------------------------------------
1319/*
1320   void CField::fromBinary(StdIStream& is)
1321   {
1322      SuperClass::fromBinary(is);
1323#define CLEAR_ATT(name_)\
1324      SuperClassAttribute::operator[](#name_)->reset()
1325
1326         CLEAR_ATT(domain_ref);
1327         CLEAR_ATT(axis_ref);
1328#undef CLEAR_ATT
1329
1330   }
1331*/
1332   //----------------------------------------------------------------
1333
1334  void CField::solveGridReference(void)
1335  TRY
1336  {
1337    if (grid_!=nullptr) return ; // already done
1338
1339    if (grid_ref.isEmpty() && domain_ref.isEmpty() && axis_ref.isEmpty() && scalar_ref.isEmpty())
1340    {
1341      ERROR("CField::solveGridReference(void)",
1342            << "A grid must be defined for field '" << getFieldOutputName() << "' .");
1343    }
1344    else if (!grid_ref.isEmpty() && (!domain_ref.isEmpty() || !axis_ref.isEmpty() || !scalar_ref.isEmpty()))
1345    {
1346      ERROR("CField::solveGridReference(void)",
1347            << "Field '" << getFieldOutputName() << "' has both a grid and a domain/axis/scalar." << std::endl
1348            << "Please define either 'grid_ref' or 'domain_ref'/'axis_ref'/'scalar_ref'.");
1349    }
1350
1351    if (grid_ref.isEmpty())
1352    {
1353      std::vector<CDomain*> vecDom;
1354      std::vector<CAxis*> vecAxis;
1355      std::vector<CScalar*> vecScalar;
1356      std::vector<int> axisDomainOrderTmp;
1357
1358      std::vector<CDomain*> vecDomRef;
1359      std::vector<CAxis*> vecAxisRef;
1360      std::vector<CScalar*> vecScalarRef;
1361       
1362      if (!domain_ref.isEmpty())
1363      {
1364        StdString tmp = domain_ref.getValue();
1365        if (CDomain::has(domain_ref))
1366        {
1367          vecDom.push_back(CDomain::get(domain_ref));
1368          vecDomRef.push_back(CDomain::createDomain());
1369          vecDomRef.back()->domain_ref=domain_ref;
1370          axisDomainOrderTmp.push_back(2);
1371        }
1372        else  ERROR("CField::solveGridReference(void)",
1373                    << "Invalid reference to domain '" << domain_ref.getValue() << "'.");
1374      }
1375
1376      if (!axis_ref.isEmpty())
1377      {
1378        if (CAxis::has(axis_ref))
1379        {
1380          vecAxis.push_back(CAxis::get(axis_ref));
1381          vecAxisRef.push_back(CAxis::createAxis());
1382          vecAxisRef.back()->axis_ref=axis_ref;
1383          axisDomainOrderTmp.push_back(1);
1384        }
1385        else  ERROR("CField::solveGridReference(void)",
1386                    << "Invalid reference to axis '" << axis_ref.getValue() << "'.");
1387      }
1388
1389      if (!scalar_ref.isEmpty())
1390      {
1391        if (CScalar::has(scalar_ref))
1392        {
1393          vecScalar.push_back(CScalar::get(scalar_ref));
1394          vecScalarRef.push_back(CScalar::createScalar());
1395          vecScalarRef.back()->scalar_ref=scalar_ref;
1396          axisDomainOrderTmp.push_back(0);
1397        }
1398        else ERROR("CField::solveGridReference(void)",
1399                   << "Invalid reference to scalar '" << scalar_ref.getValue() << "'.");
1400      }
1401       
1402      CArray<int,1> axisDomainOrder(axisDomainOrderTmp.size());
1403      for (int idx = 0; idx < axisDomainOrderTmp.size(); ++idx)
1404      {
1405        axisDomainOrder(idx) = axisDomainOrderTmp[idx];
1406      }
1407
1408      // Warning: the gridId shouldn't be set as the grid_ref since it could be inherited
1409      StdString gridId = CGrid::generateId(vecDom, vecAxis, vecScalar,axisDomainOrder);
1410      if (CGrid::has(gridId)) this->grid_ = CGrid::get(gridId);
1411      else  this->grid_ = CGrid::createGrid(gridId, vecDomRef, vecAxisRef, vecScalarRef,axisDomainOrder);
1412    }
1413    else
1414    {
1415      if (CGrid::has(grid_ref)) this->grid_ = CGrid::get(grid_ref);
1416      else  ERROR("CField::solveGridReference(void)",
1417                   << "Invalid reference to grid '" << grid_ref.getValue() << "'.");
1418    }
1419  }
1420  CATCH_DUMP_ATTR
1421
1422  void CField::solveGridDomainAxisRef(bool checkAtt)
1423  TRY
1424  {
1425    grid_->solveDomainAxisRef(checkAtt);
1426  }
1427  CATCH_DUMP_ATTR
1428
1429  void CField::solveCheckMaskIndex(bool doSendingIndex)
1430  TRY
1431  {
1432    grid_->checkMaskIndex(doSendingIndex);
1433  }
1434  CATCH_DUMP_ATTR
1435
1436  void CField::solveTransformedGrid()
1437  TRY
1438  {
1439    if (grid_ && !grid_->isTransformed() && hasDirectFieldReference() && grid_ != getDirectFieldReference()->grid_)
1440    {
1441      std::vector<CGrid*> grids;
1442      // Source grid
1443      grids.push_back(getDirectFieldReference()->grid_);
1444      auto gridPath = getGridPath() ;
1445      grids.insert(grids.begin(), gridPath.begin(), gridPath.end());
1446
1447      for (size_t i = 0, count = grids.size() - 1; i < count; ++i)
1448      {
1449        CGrid *gridSrc  = grids[i];
1450        CGrid *gridDest = grids[i + 1];
1451        if (!gridDest->isTransformed()) gridDest->transformGrid(gridSrc);
1452      }
1453    }
1454    else if (grid_ && grid_->hasTransform() && !grid_->isTransformed())
1455    {
1456      // Temporarily deactivate the self-transformation of grid
1457      // grid_->transformGrid(grid_);
1458    }
1459  }
1460  CATCH_DUMP_ATTR
1461
1462  void CField::solveGenerateGrid()
1463  TRY
1464  {
1465    if (grid_ && !grid_->isTransformed() && hasDirectFieldReference() && grid_ != getDirectFieldReference()->grid_)
1466      grid_->completeGrid(getDirectFieldReference()->grid_);
1467    else grid_->completeGrid();
1468  }
1469  CATCH_DUMP_ATTR
1470
1471  void CField::solveGridDomainAxisBaseRef()
1472  TRY
1473  {
1474    grid_->solveDomainAxisRef(false);
1475    grid_->solveDomainAxisBaseRef();
1476  }
1477  CATCH_DUMP_ATTR
1478
1479  ///-------------------------------------------------------------------
1480
1481  template <>
1482  void CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)
1483  TRY
1484  {
1485    if (this->group_ref.isEmpty()) return;
1486    StdString gref = this->group_ref.getValue();
1487
1488    if (!CFieldGroup::has(gref))
1489      ERROR("CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)",
1490         << "[ gref = " << gref << "]"
1491         << " invalid group name !");
1492
1493    CFieldGroup* group = CFieldGroup::get(gref);
1494    CFieldGroup* owner = CFieldGroup::get(boost::polymorphic_downcast<CFieldGroup*>(this));
1495    owner->setAttributes(group); // inherite of attributes of group reference
1496     
1497    std::vector<CField*> allChildren  = group->getAllChildren();
1498    std::vector<CField*>::iterator it = allChildren.begin(), end = allChildren.end();
1499
1500    for (; it != end; it++)
1501    {
1502      CField* child = *it;
1503     if (child->hasId()) owner->createChild()->field_ref.setValue(child->getId());
1504    }
1505  }
1506  CATCH_DUMP_ATTR
1507
1508  ///-------------------------------------------------------------------
1509
1510  void CField::parse(xml::CXMLNode& node)
1511  TRY
1512  {
1513    string newContent ;
1514    SuperClass::parse(node);
1515    if (node.goToChildElement())
1516    {
1517      do
1518      {
1519        if (node.getElementName() == "variable" || node.getElementName() == "variable_group") this->getVirtualVariableGroup()->parseChild(node);
1520        else if (node.getElementName() == "expr") if (node.getContent(newContent)) content+=newContent ;
1521      } while (node.goToNextElement());
1522      node.goToParentElement();
1523    }
1524    if (node.getContent(newContent)) content=newContent ;
1525  }
1526  CATCH_DUMP_ATTR
1527
1528 /*!
1529   This function retrieves Id of corresponding domain_ref and axis_ref (if any)
1530   of a field. In some cases, only domain exists but axis doesn't
1531   \return pair of Domain and Axis id
1532  */
1533  const std::vector<StdString>& CField::getRefDomainAxisIds()
1534  TRY
1535  {
1536    CGrid* cgPtr = getRelGrid();
1537    if (NULL != cgPtr)
1538    {
1539      std::vector<StdString>::iterator it;
1540      if (!domain_ref.isEmpty())
1541      {
1542        std::vector<StdString> domainList = cgPtr->getDomainList();
1543        it = std::find(domainList.begin(), domainList.end(), domain_ref.getValue());
1544        if (domainList.end() != it) domAxisScalarIds_[0] = *it;
1545      }
1546
1547      if (!axis_ref.isEmpty())
1548      {
1549        std::vector<StdString> axisList = cgPtr->getAxisList();
1550        it = std::find(axisList.begin(), axisList.end(), axis_ref.getValue());
1551        if (axisList.end() != it) domAxisScalarIds_[1] = *it;
1552      }
1553
1554      if (!scalar_ref.isEmpty())
1555      {
1556        std::vector<StdString> scalarList = cgPtr->getScalarList();
1557        it = std::find(scalarList.begin(), scalarList.end(), scalar_ref.getValue());
1558        if (scalarList.end() != it) domAxisScalarIds_[2] = *it;
1559      }
1560    }
1561    return (domAxisScalarIds_);
1562  }
1563  CATCH_DUMP_ATTR
1564
1565  CVariable* CField::addVariable(const string& id)
1566  TRY
1567  {
1568    return vVariableGroup->createChild(id);
1569  }
1570  CATCH
1571
1572  CVariableGroup* CField::addVariableGroup(const string& id)
1573  TRY
1574  {
1575    return vVariableGroup->createChildGroup(id);
1576  }
1577  CATCH
1578
1579  void CField::setContextClient(CContextClient* contextClient)
1580  TRY
1581  {
1582    CContext* context = CContext::getCurrent();
1583    client = contextClient;
1584 
1585    // A grid is sent by a client (both for read or write) or by primary server (write only)
1586    if (context->getServiceType()==CServicesManager::GATHERER)
1587    {
1588      if (getRelFile()->mode.isEmpty() || (!getRelFile()->mode.isEmpty() && getRelFile()->mode == CFile::mode_attr::write))
1589        grid_->setContextClient(contextClient);
1590    }
1591    else if (context->getServiceType()==CServicesManager::CLIENT)
1592      grid_->setContextClient(contextClient);
1593  }
1594  CATCH_DUMP_ATTR
1595
1596  void CField::sendCloseDefinition(void)
1597  {
1598    CContext::getCurrent()->sendCloseDefinition(client) ;
1599  }
1600
1601  void CField::sendFieldToFileServer(void)
1602  {
1603    CContext::getCurrent()->sendContextToFileServer(client);
1604    getRelFile()->sendFileToFileServer(client);
1605    grid_->sendGridToFileServer(client);
1606    this->sendAllAttributesToServer(client);
1607    this->sendAddAllVariables(client);
1608  }
1609
1610  void CField::sendFieldToInputFileServer(void)
1611  {
1612    CContext::getCurrent()->sendContextToFileServer(client);
1613    getRelFile()->sendFileToFileServer(client);
1614    grid_->sendGridToFileServer(client);
1615    read_access=true ; // not the best solution, but on server side, the field must be a starting point of the workflow
1616                       // must be replace by a better solution when implementing filters for reading and send to client
1617                       // on server side
1618    this->sendAllAttributesToServer(client);
1619    this->sendAddAllVariables(client);
1620  }
1621
1622  void CField::sendFieldToCouplerOut(void)
1623  {
1624    if (sendFieldToCouplerOut_done_) return ;
1625    else sendFieldToCouplerOut_done_=true ;
1626    grid_->sendGridToCouplerOut(client, this->getId());
1627    this->sendGridCompleted();
1628
1629  }
1630 
1631  void CField::makeGridAliasForCoupling(void) 
1632  { 
1633    grid_->makeAliasForCoupling(this->getId()); 
1634  }
1635
1636 //! Client side: Send a message  announcing that the grid definition has been received from a coupling context
1637   void CField::sendGridCompleted(void)
1638   TRY
1639   {
1640      CEventClient event(getType(),EVENT_ID_GRID_COMPLETED);
1641
1642      if (client->isServerLeader())
1643      {
1644        CMessage msg;
1645        msg<<this->getId();
1646        for (auto& rank : client->getRanksServerLeader()) event.push(rank,1,msg);
1647        client->sendEvent(event);
1648      }
1649      else client->sendEvent(event);
1650   }
1651   CATCH_DUMP_ATTR
1652
1653   //! Server side: Receive a message announcing that the grid definition has been received from a coupling context
1654   void CField::recvGridCompleted(CEventServer& event)
1655   TRY
1656   {
1657      CBufferIn* buffer=event.subEvents.begin()->buffer;
1658      string id;
1659      *buffer>>id ;
1660      get(id)->recvGridCompleted(*buffer);
1661   }
1662   CATCH
1663
1664   //! Server side: Receive a message  message  announcing that the grid definition has been received from a coupling context
1665   void CField::recvGridCompleted(CBufferIn& buffer)
1666   TRY
1667   {
1668      setGridCompleted() ;
1669   }
1670   CATCH_DUMP_ATTR
1671
1672
1673  void CField::sendAddAllVariables(CContextClient* client)
1674  TRY
1675  {
1676    std::vector<CVariable*> allVar = getAllVariables();
1677    std::vector<CVariable*>::const_iterator it = allVar.begin();
1678    std::vector<CVariable*>::const_iterator itE = allVar.end();
1679
1680    for (; it != itE; ++it)
1681    {
1682      this->sendAddVariable((*it)->getId(), client);
1683      (*it)->sendAllAttributesToServer(client);
1684      (*it)->sendValue(client);
1685    }
1686  }
1687  CATCH_DUMP_ATTR
1688
1689  /*!
1690   * Send all Attributes to server. This method is overloaded, since only grid_ref attribute
1691   * must be sent to server and not domain_ref/axis_ref/scalar_ref.
1692   */
1693   
1694  void CField::sendAllAttributesToServer(CContextClient* client)
1695  TRY
1696  {
1697    if (grid_ref.isEmpty())
1698    {
1699      grid_ref=grid_->getId() ;
1700      SuperClass::sendAllAttributesToServer(client) ;
1701      domain_ref.reset() ;
1702      axis_ref.reset() ;
1703      scalar_ref.reset() ;
1704      grid_ref.reset();
1705    }
1706    else SuperClass::sendAllAttributesToServer(client) ;
1707  }
1708  CATCH_DUMP_ATTR
1709   
1710  void CField::sendAddVariable(const string& id, CContextClient* client)
1711  TRY
1712  {
1713    sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE, client);
1714  }
1715  CATCH_DUMP_ATTR
1716
1717  void CField::sendAddVariableGroup(const string& id, CContextClient* client)
1718  TRY
1719  {
1720    sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE_GROUP, client);
1721  }
1722  CATCH_DUMP_ATTR
1723
1724  void CField::recvAddVariable(CEventServer& event)
1725  TRY
1726  {
1727    CBufferIn* buffer = event.subEvents.begin()->buffer;
1728    string id;
1729    *buffer >> id;
1730    get(id)->recvAddVariable(*buffer);
1731  }
1732  CATCH
1733
1734  void CField::recvAddVariable(CBufferIn& buffer)
1735  TRY
1736  {
1737    string id;
1738    buffer >> id;
1739    addVariable(id);
1740  }
1741  CATCH_DUMP_ATTR
1742
1743  void CField::recvAddVariableGroup(CEventServer& event)
1744  TRY
1745  {
1746    CBufferIn* buffer = event.subEvents.begin()->buffer;
1747    string id;
1748    *buffer >> id;
1749    get(id)->recvAddVariableGroup(*buffer);
1750  }
1751  CATCH
1752
1753  void CField::recvAddVariableGroup(CBufferIn& buffer)
1754  TRY
1755  {
1756    string id;
1757    buffer >> id;
1758    addVariableGroup(id);
1759  }
1760  CATCH_DUMP_ATTR
1761
1762  /*!
1763   * Check on freq_off and freq_op attributes.
1764   */
1765  void CField::checkTimeAttributes(CDuration* freqOp)
1766  TRY
1767  {
1768    if (hasFileIn() && !(operation.getValue() == "instant" || operation.getValue() == "once") )     
1769      ERROR("void CField::checkTimeAttributes(void)",
1770         << "Unsupported operation for field '" << getFieldOutputName() << "'." << std::endl
1771         << "Currently only \"instant\" is supported for fields read from file.")
1772
1773    if (freq_op.isEmpty())
1774    {
1775      if (operation.getValue() == "instant")
1776      {
1777        if (hasFileIn() || hasFileOut()) freq_op.setValue(getRelFile()->output_freq.getValue());
1778        else freq_op=*freqOp ;
1779      }
1780      else freq_op.setValue(TimeStep);
1781    }
1782    if (freq_offset.isEmpty()) freq_offset.setValue(hasFileIn() ? NoneDu : (freq_op.getValue() - TimeStep));
1783  }
1784  CATCH_DUMP_ATTR
1785
1786  /*!
1787   * Returns string arithmetic expression associated to the field.
1788   * \return if content is defined return content string, otherwise, if "expr" attribute is defined, return expr string.
1789   */
1790  const string& CField::getExpression(void)
1791  TRY
1792  {
1793    if (!expr.isEmpty() && content.empty())
1794    {
1795      content = expr;
1796      expr.reset();
1797    }
1798
1799    return content;
1800  }
1801  CATCH_DUMP_ATTR
1802
1803  bool CField::hasExpression(void) const
1804  TRY
1805  {
1806    return (!expr.isEmpty() || !content.empty());
1807  }
1808  CATCH
1809
1810  bool CField::hasGridMask(void) const
1811  TRY
1812  {
1813    return (this->grid_->hasMask());
1814  }
1815  CATCH
1816
1817  DEFINE_REF_FUNC(Field,field)
1818} // namespace xios
Note: See TracBrowser for help on using the repository browser.