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

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

Adapt transformation algorithm to new infrastructure (on going...)

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