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

Last change on this file since 1994 was 1988, checked in by ymipsl, 4 years ago

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