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

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

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