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

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

Big cleaning on XIOS coupling branch
YM

  • Property copyright set to
    Software name : XIOS (Xml I/O Server)
    http://forge.ipsl.jussieu.fr/ioserver
    Creation date : January 2009
    Licence : CeCCIL version2
    see license file in root directory : Licence_CeCILL_V2-en.txt
    or http://www.cecill.info/licences/Licence_CeCILL_V2-en.html
    Holder : CEA/LSCE (Laboratoire des Sciences du CLimat et de l'Environnement)
    CNRS/IPSL (Institut Pierre Simon Laplace)
    Project Manager : Yann Meurdesoif
    yann.meurdesoif@cea.fr
  • Property svn:executable set to *
File size: 58.2 KB
RevLine 
[219]1#include "field.hpp"
2
[352]3#include "attribute_template.hpp"
4#include "object_template.hpp"
5#include "group_template.hpp"
[219]6
7#include "node_type.hpp"
8#include "calendar_util.hpp"
[352]9#include "message.hpp"
[591]10#include "xios_spl.hpp"
[352]11#include "type.hpp"
[638]12#include "timer.hpp"
[352]13#include "context_client.hpp"
[586]14#include "context_server.hpp"
[459]15#include <set>
[640]16#include "garbage_collector.hpp"
[641]17#include "pass_through_filter.hpp"
[642]18#include "filter_expr_node.hpp"
19#include "lex_parser.hpp"
[643]20#include "temporal_filter.hpp"
[644]21#include "spatial_transform_filter.hpp"
[1930]22#include "server_from_client_source_filter.hpp"
23#include "file_reader_source_filter.hpp"
[1751]24#include "tracer.hpp"
[219]25
[1869]26namespace xios
27{
[509]28
[1869]29  /// ////////////////////// Définitions ////////////////////// ///
[219]30
[1869]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")); }
[219]43
[1869]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)
[1962]55    { setVirtualVariableGroup(CVariableGroup::create(getId() + "_virtual_variable_group")); }
[219]56
[1869]57  CField::~CField(void)
58  {}
[509]59
[472]60  //----------------------------------------------------------------
61
[1869]62  void CField::setVirtualVariableGroup(CVariableGroup* newVVariableGroup)
63  TRY
64  {
65    this->vVariableGroup = newVVariableGroup;
66  }
67  CATCH
[509]68
[1869]69  CVariableGroup* CField::getVirtualVariableGroup(void) const
70  TRY
71  {
72     return this->vVariableGroup;
73  }
74  CATCH
[472]75
[1869]76  std::vector<CVariable*> CField::getAllVariables(void) const
77  TRY
78  {
79    return this->vVariableGroup->getAllChildren();
80  }
81  CATCH
[509]82
[1869]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
[219]90
[645]91  //----------------------------------------------------------------
[509]92
[598]93  bool CField::dispatchEvent(CEventServer& event)
[1622]94  TRY
[300]95  {
[562]96    if (SuperClass::dispatchEvent(event)) return true;
[300]97    else
98    {
99      switch(event.type)
100      {
101        case EVENT_ID_UPDATE_DATA :
[562]102          recvUpdateData(event);
103          return true;
104          break;
[472]105
[598]106        case EVENT_ID_READ_DATA :
107          recvReadDataRequest(event);
108          return true;
109          break;
[509]110
[598]111        case EVENT_ID_READ_DATA_READY :
112          recvReadDataReady(event);
113          return true;
114          break;
[509]115
[598]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;
[1875]125     
126        case EVENT_ID_GRID_COMPLETED :
127          recvGridCompleted(event);
128          return true;
129          break;
[300]130        default :
[562]131          ERROR("bool CField::dispatchEvent(CEventServer& event)", << "Unknown Event");
132          return false;
[300]133      }
134    }
135  }
[1622]136  CATCH
[509]137
[1930]138
[300]139  void CField::recvUpdateData(CEventServer& event)
[1622]140  TRY
[300]141  {
[562]142    string fieldId;
[1930]143    for (auto& subEvent : event.subEvents) (*subEvent.buffer) >> fieldId  ;
144    get(fieldId)->receiveUpdateData(event);
145  }
146  CATCH
[1875]147
[1930]148  void  CField::receiveUpdateData(CEventServer& event)
[1622]149  TRY
[300]150  {
[1930]151    if (hasCouplerIn()) clientFromClientSourceFilter_->streamData(event) ;
152    else serverFromClientSourceFilter_->streamData(event) ;
[1875]153  }
154  CATCH
155
[1232]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  */
[1934]163  bool CField::sendReadDataRequest(const CDate& tsDataRequested)
[1622]164  TRY
[598]165  {
[1934]166    return clientFromServerSourceFilter_->sendReadDataRequest(tsDataRequested) ;
[598]167  }
[1622]168  CATCH_DUMP_ATTR
[1934]169 
170 
[598]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)
[1622]176  TRY
[598]177  {
[1934]178    return clientFromServerSourceFilter_->sendReadDataRequestIfNeeded() ;
[598]179  }
[1622]180  CATCH_DUMP_ATTR
[598]181
[1934]182
[598]183  void CField::recvReadDataRequest(CEventServer& event)
[1622]184  TRY
[598]185  {
186    CBufferIn* buffer = event.subEvents.begin()->buffer;
187    StdString fieldId;
188    *buffer >> fieldId;
[1930]189    get(fieldId)->recvReadDataRequest();
[598]190  }
[1622]191  CATCH
[1930]192 
[1232]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  */
[1930]199  void CField::recvReadDataRequest(void)
200  TRY
201  {
202    fileReaderSourceFilter_->streamData() ;
203  }
204  CATCH_DUMP_ATTR 
205
[1934]206 
[1930]207  /*
[1232]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  */
[598]213  void CField::recvReadDataReady(CEventServer& event)
[1622]214  TRY
[598]215  {
216    string fieldId;
[1930]217    for (auto& subEvent : event.subEvents) (*subEvent.buffer) >> fieldId  ;
[1934]218    get(fieldId)->receiveReadDataReady(event);
[598]219  }
[1622]220  CATCH
[598]221
[1934]222  void CField::receiveReadDataReady(CEventServer& event)
223  TRY
224  {
225    clientFromServerSourceFilter_->streamData(event) ;   
226  }
227  CATCH_DUMP_ATTR
[1930]228
[1875]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();
[1930]240   
241    bool isDataLate; 
[1875]242    do
243    {
[1930]244      isDataLate=clientFromClientSourceFilter_->isDataLate() ;
[1875]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
[1318]262  void CField::checkForLateDataFromServer(void)
[1622]263  TRY
[1318]264  {
[1934]265    clientFromServerSourceFilter_->checkForLateData() ;
[1318]266  }
[1934]267  CATCH_DUMP_ATTR
268 
269 
[1875]270  void CField::triggerLateField(void)
271  TRY
272  {
273    if (hasFileIn()) 
274    {
275      checkForLateDataFromServer() ;
[1930]276      clientFromServerSourceFilter_->trigger(CContext::getCurrent()->getCalendar()->getCurrentDate()) ;
[1875]277    } 
278    else if (hasCouplerIn())
279    {
280      checkForLateDataFromCoupler() ;
[1930]281      clientFromClientSourceFilter_->trigger(CContext::getCurrent()->getCalendar()->getCurrentDate()) ;
[1875]282    }
283  }
284  CATCH_DUMP_ATTR
285
286
[1358]287  void CField::checkIfMustAutoTrigger(void)
[1622]288  TRY
[1358]289  {
[1930]290    mustAutoTrigger = clientFromServerSourceFilter_ ? clientFromServerSourceFilter_->mustAutoTrigger() : false;
[1358]291  }
[1622]292  CATCH_DUMP_ATTR
[1358]293
294  void CField::autoTriggerIfNeeded(void)
[1622]295  TRY
[1358]296  {
297    if (mustAutoTrigger)
[1930]298      clientFromServerSourceFilter_->trigger(CContext::getCurrent()->getCalendar()->getCurrentDate());
[1358]299  }
[1622]300  CATCH_DUMP_ATTR
[1358]301
[1962]302
[1869]303  //----------------------------------------------------------------
[219]304
[1869]305  StdString CField::GetName(void)    { return StdString("field"); }
306  StdString CField::GetDefName(void) { return CField::GetName(); }
307  ENodeType CField::GetType(void)    { return eField; }
[219]308
[1869]309  //----------------------------------------------------------------
[219]310
[1869]311  CGrid* CField::getRelGrid(void) const
312  TRY
313  {
314    return this->grid_;
315  }
316  CATCH
[219]317
[1869]318  //----------------------------------------------------------------
[219]319
[1869]320  CFile* CField::getRelFile(void) const
321  TRY
322  {
[1872]323    if (hasFileIn()) return this->fileIn_;
324    else if (hasFileOut()) return this->fileOut_ ;
325    else return nullptr ;
[1869]326  }
327  CATCH
[509]328
[1869]329  func::CFunctor::ETimeType CField::getOperationTimeType() const
330  TRY
331  {
332    return operationTimeType;
333  }
334  CATCH
[645]335
336
[1869]337  //----------------------------------------------------------------
[219]338
[1869]339  bool CField::isActive(bool atCurrentTimestep /*= false*/) const
340  TRY
341  {
[1930]342    if (modelToClientSourceFilter_) 
343      return atCurrentTimestep ? modelToClientSourceFilter_->isDataExpected(CContext::getCurrent()->getCalendar()->getCurrentDate()) : true;
344    else if (clientToModelStoreFilter_)  return true;
[1869]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.");
[1158]348
[1869]349    return false;
350  }
351  CATCH
[562]352
[1869]353  //----------------------------------------------------------------
[509]354
[1869]355  bool CField::wasWritten() const
356  TRY
357  {
358    return written;
359  }
360  CATCH
[707]361
[1869]362  void CField::setWritten()
363  TRY
364  {
365    written = true;
366  }
367  CATCH_DUMP_ATTR
[707]368
[1869]369  //----------------------------------------------------------------
[707]370
[1869]371  bool CField::getUseCompressedOutput() const
372  TRY
373  {
374    return useCompressedOutput;
375  }
376  CATCH
[676]377
[1869]378  void CField::setUseCompressedOutput()
379  TRY
380  {
381    useCompressedOutput = true;
382  }
383  CATCH_DUMP_ATTR
[676]384
[1869]385  //----------------------------------------------------------------
[676]386
[1869]387  std::shared_ptr<COutputPin> CField::getInstantDataFilter()
388  TRY
389  {
390    return instantDataFilter;
391  }
392  CATCH_DUMP_ATTR
[641]393
[1869]394  //----------------------------------------------------------------
[641]395
[1869]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
[687]413
[1869]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        }
[687]437
[1869]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_);
[823]457
[1869]458            (gridSrcMap[gridSrc]).first = true;
459            (gridSrcMap[gridSrc]).second = newIdGridDest;
460          }
[823]461
[1869]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
[823]473
[1869]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());
[823]485
[1869]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());
[823]492
[1869]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
[1025]498   
[1869]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();
[823]507
[1869]508    if (!isReferenceSolvedAndTransformed)
509    {
510      isReferenceSolvedAndTransformed = true;
[1025]511
[1869]512      if (context->getServiceType()==CServicesManager::CLIENT)
513      {
514        solveRefInheritance(true);
515        if (hasDirectFieldReference()) getDirectFieldReference()->solveAllEnabledFieldsAndTransform();
516      }
[1025]517
[1869]518      if (context->getServiceType()==CServicesManager::GATHERER || context->getServiceType()==CServicesManager::OUT_SERVER)
519        solveServerOperation();
[1025]520
[1869]521      solveGridReference();
[1025]522
[1869]523      if (context->getServiceType()==CServicesManager::CLIENT)
524      {
525        solveGenerateGrid();
526        buildGridTransformationGraph();
527      }
[1025]528
[1869]529      solveGridDomainAxisRef(false);
[1025]530
[1869]531      if (context->getServiceType()==CServicesManager::CLIENT)
532      {
533        solveTransformedGrid();
534      }
[1025]535
[1869]536      solveGridDomainAxisRef(false);
537    }
538  }
539  CATCH_DUMP_ATTR
[1025]540
[1869]541  void CField::checkGridOfEnabledFields()
542  TRY
543  {
544    if (!isGridChecked)
545    {
546      isGridChecked = true;
547      solveCheckMaskIndex(false);
548    }
549  }
550  CATCH_DUMP_ATTR
[1025]551
[1869]552  void CField::sendGridComponentOfEnabledFields()
553  TRY
554  {
555    solveGridDomainAxisRef(true);
556    // solveCheckMaskIndex(true);
557  }
558  CATCH_DUMP_ATTR
[1025]559
[1869]560  void CField::sendGridOfEnabledFields()
561  TRY
562  {
563    // solveGridDomainAxisRef(true);
564    solveCheckMaskIndex(true);
565  }   
566  CATCH_DUMP_ATTR
[1025]567
[1869]568  void CField::solveOnlyReferenceEnabledField(void)
569  TRY
570  {
571    CContext* context = CContext::getCurrent();
572    if (!isReferenceSolved)
573    {
574      isReferenceSolved = true;
[1025]575
[1869]576      if (context->getServiceType()==CServicesManager::CLIENT)
577      {
578        solveRefInheritance(true);
579        if (hasDirectFieldReference()) getDirectFieldReference()->solveOnlyReferenceEnabledField();
580      }
[1144]581
[1869]582      if (context->getServiceType()==CServicesManager::GATHERER || context->getServiceType()==CServicesManager::OUT_SERVER)
583        solveServerOperation();
[1025]584
[1869]585      solveGridReference();
586      grid_->solveElementsRefInheritance(true); // make it again to solve grid reading from file
[1025]587
[1869]588      if (context->getServiceType()==CServicesManager::CLIENT)
589      {
590        solveGenerateGrid();
591        buildGridTransformationGraph();
592      }
593    }
594  }
595  CATCH_DUMP_ATTR
[1622]596
[1869]597  void CField::solveAllReferenceEnabledField(bool doSending2Server)
598  TRY
599  {
600    CContext* context = CContext::getCurrent();
601    solveOnlyReferenceEnabledField();
[823]602
[1869]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();
[823]614
[1869]615      solveGridReference();
616    }
[823]617
[1869]618    solveGridDomainAxisRef(doSending2Server);
[823]619
[1869]620    if (context->getServiceType()==CServicesManager::CLIENT)
621    {
622      solveTransformedGrid();
623    }
[687]624
[1869]625  }
626  CATCH_DUMP_ATTR
[509]627
[1870]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
[1869]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
[509]678
[1870]679// ym obsolete to be removed
[1869]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
[731]686
[1870]687
688
[1869]689  size_t CField::getGlobalWrittenSize()
690  TRY
691  {
692    return grid_->getGlobalWrittenSize();
693  }
694  CATCH_DUMP_ATTR
[1215]695
[1869]696  //----------------------------------------------------------------
[219]697
[1869]698  void CField::solveServerOperation(void)
699  TRY
700  {
701    CContext* context = CContext::getCurrent();
[509]702
[1869]703    if (freq_op.isEmpty()) freq_op.setValue(TimeStep);
[509]704
[1869]705    if (freq_offset.isEmpty()) freq_offset.setValue(NoneDu);
[219]706
[1869]707    if (operation.isEmpty())
708      ERROR("void CField::solveServerOperation(void)",
709            << "An operation must be defined for field \"" << getId() << "\".");
[509]710
[1869]711    std::shared_ptr<func::CFunctor> functor;
712    CArray<double, 1> dummyData;
[598]713
[562]714#define DECLARE_FUNCTOR(MType, mtype) \
[1869]715    if (operation.getValue().compare(#mtype) == 0) \
716    { \
717      functor.reset(new func::C##MType(dummyData)); \
718    }
[509]719
[219]720#include "functor_type.conf"
[509]721
[1869]722    if (!functor)
723      ERROR("void CField::solveServerOperation(void)",
724            << "\"" << operation << "\" is not a valid operation.");
[645]725
[1869]726    operationTimeType = functor->timeType();
727  }
728  CATCH_DUMP_ATTR
[509]729
[1869]730 //----------------------------------------------------------------
[640]731
[1869]732  bool CField::buildWorkflowGraph(CGarbageCollector& gc)
733  {
734    if (buildWorkflowGraphDone_) return true ;
[1875]735   
[1869]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
[1875]748    // now construct grid and check if element are enabled
749    solveGridReference() ; // grid_ is now defined
750    if (!isGridCompleted()) return false;
751
[1869]752    // Check if we have an expression to parse
753    std::shared_ptr<COutputPin> filterExpr ;
754    if (hasExpression())
755    {
756      boost::scoped_ptr<IFilterExprNode> expr(parseExpr(getExpression() + '\0'));
757      filterExpr = expr->reduce(gc, *this);
758      if (!filterExpr) return false ; // workflow graph cannot be built at this stage
759    }
760   
761    // prepare transformation. Need to know before if workflow of auxillary field can be built
762    if (hasDirectFieldReference())
763    {
764      auto gridPath=getGridPath() ;
765      gridPath.push_back(grid_) ;
766
767      CGrid* gridSrc=getDirectFieldReference()->getGrid() ;
768      for(auto grid : gridPath)
769      {
770        grid->solveElementsRefInheritance() ;
[1875]771        grid->completeGrid(gridSrc); // grid generation, to be checked
772        grid->checkElementsAttributes() ;
[1869]773        grid->prepareTransformGrid(gridSrc) ; // prepare the grid tranformation
774        for(auto fieldId : grid->getAuxInputTransformGrid()) // try to build workflow graph for auxillary field tranformation
775          if (!CField::get(fieldId)->buildWorkflowGraph(gc)) return false ;
776        gridSrc=grid ;
777      }
778     
779      std::shared_ptr<COutputPin> lastFilter ;
780      if (filterExpr) lastFilter=filterExpr ;
781      else lastFilter = inputFilter ;
782     
783      gridSrc=getDirectFieldReference()->getGrid() ;
784      for(auto grid : gridPath) 
785      {
786        grid->makeTransformGrid() ; // make the grid transformation
[1871]787        if (grid->hasTransform()) 
788        {
789          std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters = CSpatialTransformFilter::buildFilterGraph(gc, gridSrc, grid, detectMissingValues, defaultValue); 
790          lastFilter->connectOutput(filters.first, 0);
791          lastFilter = filters.second;
792          gridSrc=grid ;
793        }
[1869]794      }
795      instantDataFilter = lastFilter ;
796     
797      // connect the input Filter to the reference
798      getDirectFieldReference()->getInstantDataFilter()->connectOutput(inputFilter,0);
799    }
800    else 
801    {
[1871]802      if (hasFileIn()) // input file, attemp to read the grid from file
803      {
804         // must be checked
805         fileIn_->initRead() ;
806         fileIn_->checkReadFile();
807         grid_->solveElementsRefInheritance() ;
808         if (fileIn_->isClientSide()) fileIn_->readFieldAttributesMetaData(this);
809         grid_->completeGrid(); // grid generation, to be checked
810         if (fileIn_->isClientSide()) fileIn_->readFieldAttributesValues(this);
811         grid_->checkElementsAttributes() ;
812         grid_->solveDomainAxisBaseRef();
813         // probably in future tag grid incomplete if coming from a reading
814         instantDataFilter=inputFilter ;
815      } 
[1875]816      else if (hasCouplerIn())
[1871]817      {
[1875]818        grid_->checkElementsAttributes() ;
819        instantDataFilter=inputFilter ;
820      }
821      else
822      {
[1871]823        setModelIn() ; // no reference, the field is potentially a source field from model
824
825        grid_->solveElementsRefInheritance() ;
826        grid_->completeGrid(); // grid generation, to be checked
827        grid_->checkElementsAttributes() ;
828        instantDataFilter=inputFilter ;
829      }
[1869]830    }
831   
[1872]832    if (hasFileOut())
833    {
834      if (fileOut_->isServerSide())
835      {
836        this->solveServerOperation() ;
837      }
838    }
839
[1869]840    buildWorkflowGraphDone_ = true ;
841    workflowEnabled_ = true ;
842    return true ;
843  }
844   
[1870]845  /*!
846   * Connect field to filter to send data to server. A temporal filter is inserted before accordingly to the
847   * output frequency of the file
848   * \param gc the garbage collector to use when building the filter graph
849   */
[1869]850  void CField::connectToFileServer(CGarbageCollector& gc)
851  {
852    // insert temporal filter before sending to files
[1935]853    clientToServerStoreFilter_ = std::shared_ptr<CClientToServerStoreFilter>(new CClientToServerStoreFilter(gc, this, client));
[1869]854    // insert temporal filter before sending to files
[1935]855    getTemporalDataFilter(gc, fileOut_->output_freq)->connectOutput(clientToServerStoreFilter_, 0);
[1869]856  } 
857
[1875]858  void CField::connectToCouplerOut(CGarbageCollector& gc)
859  {
860    // insert temporal filter before sending to files
[1935]861    clientToServerStoreFilter_ = std::shared_ptr<CClientToServerStoreFilter>(new CClientToServerStoreFilter(gc, this, client));
862    instantDataFilter->connectOutput(clientToServerStoreFilter_, 0);
[1875]863  } 
864
[1973]865 
[1870]866  /*!
867   * Connect field to a source filter to receive data from model.
868   */
869  void CField::connectToModelInput(CGarbageCollector& gc)
870  {
871    const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
872    const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
873
874    if (check_if_active.isEmpty()) check_if_active = false; 
[1930]875    modelToClientSourceFilter_ = std::shared_ptr<CModelToClientSourceFilter>(new CModelToClientSourceFilter(gc, grid_, detectMissingValues, defaultValue));
876    modelToClientSourceFilter_ -> connectOutput(inputFilter,0) ;
[1870]877  } 
878 
879  /*!
[1871]880   * Connect field to a source filter to receive data from a client (on server side).
881   */
882  void CField::connectToClientInput(CGarbageCollector& gc)
883  {
[1930]884    serverFromClientSourceFilter_ = std::shared_ptr<CServerFromClientSourceFilter>(new CServerFromClientSourceFilter(gc,  grid_));
885    serverFromClientSourceFilter_ -> connectOutput(inputFilter,0) ;
[1871]886  } 
887
888
889  /*!
890   * Connect field to a source filter to receive data from a server (on client side).
891   */
892  void CField::connectToServerInput(CGarbageCollector& gc)
893  {
[1872]894    checkTimeAttributes();
[1934]895    clientFromServerSourceFilter_ = std::shared_ptr<CClientFromServerSourceFilter>(new CClientFromServerSourceFilter(gc,this)) ;
896    clientFromServerSourceFilter_ -> connectOutput(inputFilter,0) ;
[1871]897  } 
898
899  /*!
[1875]900   * Connect field to a source filter to receive data from coupler (on client side).
901   */
902   void CField::connectToCouplerIn(CGarbageCollector& gc)
903  {
904    CContext* context = CContext::getCurrent();
905
906    if (freq_op.isEmpty()) freq_op.setValue(TimeStep);
907    if (freq_offset.isEmpty()) freq_offset.setValue(freq_op.getValue() - TimeStep);
[1930]908    clientFromClientSourceFilter_ = std::shared_ptr<CClientFromClientSourceFilter>(new CClientFromClientSourceFilter(gc, this)) ;
909    clientFromClientSourceFilter_ -> connectOutput(inputFilter,0) ;
910   
[1875]911  } 
912
913  /*!
[1871]914   * Connect field to a file writer filter to write data in file (on server side).
915   */
916  void CField::connectToFileWriter(CGarbageCollector& gc)
917  {
[1935]918    fileWriterStoreFilter_ = std::shared_ptr<CFileWriterStoreFilter>(new CFileWriterStoreFilter(gc, this));
919    instantDataFilter->connectOutput(fileWriterStoreFilter_, 0);
[1871]920  } 
[1930]921
[1883]922  /*!
923   * Connect field to a file reader filter to read data from file (on server side).
924   */
925  void CField::connectToFileReader(CGarbageCollector& gc)
926  {
[1930]927    fileReaderSourceFilter_ = std::shared_ptr<CFileReaderSourceFilter>(new CFileReaderSourceFilter(gc, this));
[1934]928    fileReaderSourceFilter_->connectOutput(inputFilter, 0);
[1930]929  }
[1871]930
[1930]931
[1871]932  /*!
933   * Connect field to a store filter to output data to model on client Side
934   */
935  void CField::connectToModelOutput(CGarbageCollector& gc)
936  {
[1930]937    clientToModelStoreFilter_ = std::shared_ptr<CClientToModelStoreFilter>(new CClientToModelStoreFilter(gc, this));
938    instantDataFilter->connectOutput(clientToModelStoreFilter_, 0);
[1871]939  }
940
[1883]941
942 
943  void CField::connectToServerToClient(CGarbageCollector& gc)
944  {
[1934]945    serverToClientStoreFilter_ = std::shared_ptr<CServerToClientStoreFilter>(new CServerToClientStoreFilter(gc, this, client));
946    instantDataFilter->connectOutput(serverToClientStoreFilter_, 0);
[1883]947  }
948
[1871]949  /*!
[1869]950   * Transform the grid_path attribut into vector of grid.
951   * \return the vector CGrid* containing the list of grid path for tranformation
952   */ 
953  vector<CGrid*> CField::getGridPath(void)
954  {
955    std::vector<CGrid*> gridPath;
956
957    if (hasDirectFieldReference() && grid_ != getDirectFieldReference()->grid_)
958    {
959      if (!grid_path.isEmpty())
960      {
961        std::string gridId;
962        size_t start = 0, end;
963
964        do
965        {
966          end = grid_path.getValue().find(',', start);
967          if (end != std::string::npos)
968          {
969            gridId = grid_path.getValue().substr(start, end - start);
970            start = end + 1;
971          }
972          else gridId = grid_path.getValue().substr(start);
973
974          if (!CGrid::has(gridId))
975            ERROR("void CField::solveTransformedGrid()",
976               << "Invalid grid_path, the grid '" << gridId << "' does not exist.");
977
978          gridPath.push_back(CGrid::get(gridId));
979        }
980        while (end != std::string::npos);
981      }
982    }
983    return gridPath ;
984  }
985
986  /*!
987   * Constructs the graph filter for the field, enabling or not the data output.
988   * This method should not be called more than once with enableOutput equal to true.
989   *
990   * \param gc the garbage collector to use when building the filter graph
991   * \param enableOutput must be true when the field data is to be
992   *                     read by the client or/and written to a file
993   */
[1870]994   // ym obselete : to be removed later....
[1869]995  void CField::buildFilterGraph(CGarbageCollector& gc, bool enableOutput)
996  TRY
997  {     
[1935]998   //  ==> before removing, solving dependency in spatial_transform_filter.cpp about auxilairy field
999/*
[1129]1000    if (!isReferenceSolvedAndTransformed) solveAllEnabledFieldsAndTransform();
[1417]1001    if (!isGridChecked) checkGridOfEnabledFields();
[1201]1002
[1869]1003    const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1004    const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
[1201]1005
[1869]1006    CContext* context = CContext::getCurrent();
1007    bool hasWriterServer = context->getServiceType()==CServicesManager::OUT_SERVER ;
1008    bool hasIntermediateServer = context->getServiceType()==CServicesManager::GATHERER ;
[641]1009
[1869]1010    if (hasWriterServer)
1011    {
1012      if (!instantDataFilter)
1013        instantDataFilter = clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid_, true, false));
[1025]1014
[1294]1015
[1869]1016      // If the field data is to be read by the client or/and written to a file
[1930]1017      if (enableOutput && !clientToModelStoreFilter_ && !fileWriterFilter)
[1869]1018      {
[1872]1019        if (getRelFile() && (getRelFile()->mode.isEmpty() || getRelFile()->mode == CFile::mode_attr::write))
[1869]1020        {
1021          fileServerWriterFilter = std::shared_ptr<CFileServerWriterFilter>(new CFileServerWriterFilter(gc, this));
1022          instantDataFilter->connectOutput(fileServerWriterFilter, 0);
1023        }
1024      }
1025    }
1026    else if (hasIntermediateServer)
1027    {
1028      if (!instantDataFilter)
1029        instantDataFilter = clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid_, false, false));
[1025]1030
[1869]1031      // If the field data is to be read by the client or/and written to a file
[1930]1032      if (enableOutput && !clientToModelStoreFilter_ && !fileWriterFilter)
[1869]1033      {
[1872]1034        if (getRelFile() && (getRelFile()->mode.isEmpty() || getRelFile()->mode == CFile::mode_attr::write))
[1869]1035        {
[1872]1036          fileWriterFilter = std::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this, getRelFile()->getContextClient()));
[1869]1037          instantDataFilter->connectOutput(fileWriterFilter, 0);
1038        }
1039      }
1040    }
1041    else
1042    {
1043      // Start by building a filter which can provide the field's instant data
1044      if (!instantDataFilter)
1045      {
1046        // Check if we have an expression to parse
1047        if (hasExpression())
1048        {
1049          boost::scoped_ptr<IFilterExprNode> expr(parseExpr(getExpression() + '\0'));
1050          std::shared_ptr<COutputPin> filter = expr->reduce(gc, *this);
[1021]1051
[1869]1052          // Check if a spatial transformation is needed
1053          if (!field_ref.isEmpty())
1054          {
1055            CGrid* gridRef = CField::get(field_ref)->grid_;
1056            if (grid_ && grid_ != gridRef && grid_->hasTransform())
1057            {
1058                std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters = CSpatialTransformFilter::buildFilterGraph(gc, gridRef, grid_, detectMissingValues, defaultValue);
[1021]1059
[1869]1060              filter->connectOutput(filters.first, 0);
1061              filter = filters.second;
1062            }
1063          }
[1158]1064
[1869]1065          instantDataFilter = filter;
1066        }
1067        // Check if we have a reference on another field
1068        else if (!field_ref.isEmpty()) instantDataFilter = getFieldReference(gc);
1069        // Check if the data is to be read from a file
[1872]1070        else if (getRelFile() && !getRelFile()->mode.isEmpty() && getRelFile()->mode == CFile::mode_attr::read)
[1869]1071        {
1072          checkTimeAttributes();
1073          instantDataFilter = serverSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid_, true, false, freq_offset, true,
[1201]1074                                                                                                       detectMissingValues, defaultValue));
[1869]1075        }
1076        else // The data might be passed from the model
1077        {
1078          if (check_if_active.isEmpty()) check_if_active = false;
1079          instantDataFilter = clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid_, false, true, NoneDu, false,
1080                                                                                                      detectMissingValues, defaultValue));
1081        }
1082      }
[640]1083
[1869]1084      // If the field data is to be read by the client or/and written to a file
[1930]1085      if (enableOutput && !clientToModelStoreFilter_ && !fileWriterFilter)
[1869]1086      {
1087        if (!read_access.isEmpty() && read_access)
1088        {
[1930]1089          clientToModelStoreFilter_ = std::shared_ptr<CClientToModelStoreFilter>(new CClientToModelStoreFilter(gc, this));
1090          instantDataFilter->connectOutput(clientToModelStoreFilter_, 0);
[1869]1091        }
[640]1092
[1872]1093        if (getRelFile() && (getRelFile()->mode.isEmpty() || getRelFile()->mode == CFile::mode_attr::write))
[1869]1094        {
[1872]1095          fileWriterFilter = std::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this, getRelFile()->getContextClient()));
1096          getTemporalDataFilter(gc, getRelFile()->output_freq)->connectOutput(fileWriterFilter, 0);
[1869]1097        }
1098      }
1099    }
[1935]1100*/ 
[1869]1101  }
1102  CATCH_DUMP_ATTR
[640]1103
[1869]1104  /*!
1105   * Returns the filter needed to handle the field reference.
1106   * This method should only be called when building the filter graph corresponding to the field.
1107   *
1108   * \param gc the garbage collector to use
1109   * \return the output pin corresponding to the field reference
1110   */
1111  std::shared_ptr<COutputPin> CField::getFieldReference(CGarbageCollector& gc)
1112  TRY
1113  {
1114    if (instantDataFilter || field_ref.isEmpty())
1115      ERROR("COutputPin* CField::getFieldReference(CGarbageCollector& gc)",
1116            "Impossible to get the field reference for a field which has already been parsed or which does not have a field_ref.");
[737]1117
[1869]1118    CField* fieldRef = CField::get(field_ref);
1119    fieldRef->buildFilterGraph(gc, false);
[737]1120
[1869]1121    std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters;
1122    // Check if a spatial transformation is needed
1123    if (grid_ && grid_ != fieldRef->grid_ && grid_->hasTransform())
1124    {       
1125      bool hasMissingValue = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1126      double defaultValue  = hasMissingValue ? default_value : (!default_value.isEmpty() ? default_value : 0.0);                               
1127      filters = CSpatialTransformFilter::buildFilterGraph(gc, fieldRef->grid_, grid_, hasMissingValue, defaultValue);
1128    }
1129    else
1130      filters.first = filters.second = std::shared_ptr<CFilter>(new CPassThroughFilter(gc));
[873]1131
[1869]1132    fieldRef->getInstantDataFilter()->connectOutput(filters.first, 0);
[737]1133
[1869]1134    return filters.second;
1135  }
1136  CATCH_DUMP_ATTR
[737]1137
[1869]1138  /*!
1139   * Returns the filter needed to handle a self reference in the field's expression.
1140   * If the needed filter does not exist, it is created, otherwise it is reused.
1141   * This method should only be called when building the filter graph corresponding
1142   * to the field's expression.
1143   *
1144   * \param gc the garbage collector to use
1145   * \return the output pin corresponding to a self reference
1146   */
[642]1147
[1869]1148/* old version
1149  std::shared_ptr<COutputPin> CField::getSelfReference(CGarbageCollector& gc)
1150  TRY
1151  {
1152    if (instantDataFilter || !hasExpression())
1153      ERROR("COutputPin* CField::getSelfReference(CGarbageCollector& gc)",
1154            "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
[1201]1155
[1869]1156    if (!selfReferenceFilter)
1157    {
1158      const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1159      const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
[1201]1160
[1869]1161      if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
1162      {
1163        if (!serverSourceFilter)
1164        {
1165          checkTimeAttributes();
1166          serverSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid_, true, false, freq_offset, true,
1167                                                              detectMissingValues, defaultValue));
[1158]1168         }
[642]1169
[1869]1170        selfReferenceFilter = serverSourceFilter;
1171      }
1172      else if (!field_ref.isEmpty())
1173      {
1174        CField* fieldRef = CField::get(field_ref);
1175        fieldRef->buildFilterGraph(gc, false);
1176        selfReferenceFilter = fieldRef->getInstantDataFilter();
1177      }
1178      else
1179      {
1180        if (!clientSourceFilter)
1181        {
1182          if (check_if_active.isEmpty()) check_if_active = false;
1183          clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid_, true, true, NoneDu, false,
1184                                                                                detectMissingValues, defaultValue));
1185        }
[737]1186
[1869]1187        selfReferenceFilter = clientSourceFilter;
1188      }
1189    }
[642]1190
[1869]1191    return selfReferenceFilter;
1192  }
1193  CATCH_DUMP_ATTR
1194*/
1195  std::shared_ptr<COutputPin> CField::getSelfReference(CGarbageCollector& gc)
1196  TRY
1197  {
1198    return inputFilter ;
1199  } 
1200  CATCH_DUMP_ATTR
[643]1201
[1869]1202  /*!
1203   * Returns the temporal filter corresponding to the field's temporal operation
1204   * for the specified operation frequency. The filter is created if it does not
1205   * exist, otherwise it is reused.
1206   *
1207   * \param gc the garbage collector to use
1208   * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1209   * \return the output pin corresponding to the requested temporal filter
1210   */
1211  std::shared_ptr<COutputPin> CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1212  TRY
1213  {
1214    std::map<CDuration, std::shared_ptr<COutputPin> >::iterator it = temporalDataFilters.find(outFreq);
[643]1215
[1869]1216    if (it == temporalDataFilters.end())
1217    {
1218      if (operation.isEmpty())
1219        ERROR("void CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1220              << "An operation must be defined for field \"" << getId() << "\".");
[1315]1221
[1869]1222      checkTimeAttributes(&outFreq);
1223
1224      const bool detectMissingValues = (!detect_missing_value.isEmpty()  && detect_missing_value == true);
1225      std::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
[643]1226                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
[1440]1227                                                                             freq_op, freq_offset, outFreq, detectMissingValues));
[1278]1228
[1869]1229      instantDataFilter->connectOutput(temporalFilter, 0);
[643]1230
[1869]1231      it = temporalDataFilters.insert(std::make_pair(outFreq, temporalFilter)).first;
1232    }
[643]1233
[1869]1234    return it->second;
1235  }
1236  CATCH_DUMP_ATTR
[643]1237
[1158]1238  /*!
1239    * Returns the temporal filter corresponding to the field's temporal operation
1240    * for the specified operation frequency.
1241    *
1242    * \param gc the garbage collector to use
1243    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1244    * \return the output pin corresponding to the requested temporal filter
1245    */
1246
[1869]1247  std::shared_ptr<COutputPin> CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1248  TRY
1249  {
1250    if (instantDataFilter || !hasExpression())
1251      ERROR("COutputPin* CField::getSelfTemporalDataFilter(CGarbageCollector& gc)",
1252            "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1253   
1254    if (selfTemporalDataFilter) return selfTemporalDataFilter;
[1158]1255
[1869]1256    if (hasDirectFieldReference())
1257    {
1258      CField* fieldRef=getDirectFieldReference();
1259      return fieldRef->getTemporalDataFilter(gc, outFreq) ;
1260    }
1261    else
1262    {
1263      if (selfTemporalDataFilter) return selfTemporalDataFilter ;
[1158]1264
[1869]1265      if (operation.isEmpty())
1266        ERROR("void CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1267              << "An operation must be defined for field \"" << getId() << "\".");
[1315]1268
[1869]1269      checkTimeAttributes(&outFreq); //bof
[1278]1270
[1869]1271      const bool detectMissingValues = (!detect_missing_value.isEmpty() && detect_missing_value == true);
1272      selfTemporalDataFilter = std::shared_ptr<CTemporalFilter>(new CTemporalFilter(gc, operation,
1273                                                                CContext::getCurrent()->getCalendar()->getInitDate(),
1274                                                                freq_op, freq_offset, outFreq, detectMissingValues));
1275
1276      inputFilter->connectOutput(selfTemporalDataFilter, 0);
1277      return selfTemporalDataFilter ;
1278    }
[1158]1279  }
[1869]1280  CATCH_DUMP_ATTR
[1158]1281
[1869]1282/* old version   
1283  std::shared_ptr<COutputPin> CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1284  TRY
1285  {
1286    if (instantDataFilter || !hasExpression())
1287      ERROR("COutputPin* CField::getSelfTemporalDataFilter(CGarbageCollector& gc)",
1288            "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1289
1290    if (!selfReferenceFilter) getSelfReference(gc) ;
1291
1292    if (serverSourceFilter || clientSourceFilter)
1293    {
1294      if (operation.isEmpty())
1295        ERROR("void CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1296              << "An operation must be defined for field \"" << getId() << "\".");
1297
1298      checkTimeAttributes(&outFreq);
1299
1300      const bool detectMissingValues = (!detect_missing_value.isEmpty() && detect_missing_value == true);
1301      std::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1302                                                                          CContext::getCurrent()->getCalendar()->getInitDate(),
1303                                                                          freq_op, freq_offset, outFreq, detectMissingValues));
1304
1305      selfReferenceFilter->connectOutput(temporalFilter, 0);
1306      return temporalFilter ;
1307    }
1308    else if (!field_ref.isEmpty())
1309    {
1310      CField* fieldRef = CField::get(field_ref);
1311      fieldRef->buildFilterGraph(gc, false);
1312      return fieldRef->getTemporalDataFilter(gc, outFreq) ;
1313    }
1314  }
1315  CATCH_DUMP_ATTR
1316*/
1317
1318  //----------------------------------------------------------------
[369]1319/*
[562]1320   void CField::fromBinary(StdIStream& is)
[219]1321   {
1322      SuperClass::fromBinary(is);
1323#define CLEAR_ATT(name_)\
[369]1324      SuperClassAttribute::operator[](#name_)->reset()
[219]1325
1326         CLEAR_ATT(domain_ref);
1327         CLEAR_ATT(axis_ref);
1328#undef CLEAR_ATT
1329
1330   }
[369]1331*/
[219]1332   //----------------------------------------------------------------
1333
[1869]1334  void CField::solveGridReference(void)
1335  TRY
1336  {
1337    if (grid_!=nullptr) return ; // already done
[219]1338
[1869]1339    if (grid_ref.isEmpty() && domain_ref.isEmpty() && axis_ref.isEmpty() && scalar_ref.isEmpty())
1340    {
1341      ERROR("CField::solveGridReference(void)",
1342            << "A grid must be defined for field '" << getFieldOutputName() << "' .");
1343    }
1344    else if (!grid_ref.isEmpty() && (!domain_ref.isEmpty() || !axis_ref.isEmpty() || !scalar_ref.isEmpty()))
1345    {
1346      ERROR("CField::solveGridReference(void)",
1347            << "Field '" << getFieldOutputName() << "' has both a grid and a domain/axis/scalar." << std::endl
1348            << "Please define either 'grid_ref' or 'domain_ref'/'axis_ref'/'scalar_ref'.");
1349    }
[1524]1350
[1869]1351    if (grid_ref.isEmpty())
1352    {
1353      std::vector<CDomain*> vecDom;
1354      std::vector<CAxis*> vecAxis;
1355      std::vector<CScalar*> vecScalar;
1356      std::vector<int> axisDomainOrderTmp;
[1524]1357
[1869]1358      std::vector<CDomain*> vecDomRef;
1359      std::vector<CAxis*> vecAxisRef;
1360      std::vector<CScalar*> vecScalarRef;
[894]1361       
[1869]1362      if (!domain_ref.isEmpty())
1363      {
1364        StdString tmp = domain_ref.getValue();
1365        if (CDomain::has(domain_ref))
[744]1366        {
[1869]1367          vecDom.push_back(CDomain::get(domain_ref));
1368          vecDomRef.push_back(CDomain::createDomain());
1369          vecDomRef.back()->domain_ref=domain_ref;
1370          axisDomainOrderTmp.push_back(2);
[744]1371        }
[1869]1372        else  ERROR("CField::solveGridReference(void)",
1373                    << "Invalid reference to domain '" << domain_ref.getValue() << "'.");
1374      }
[219]1375
[1869]1376      if (!axis_ref.isEmpty())
1377      {
1378        if (CAxis::has(axis_ref))
[742]1379        {
[1869]1380          vecAxis.push_back(CAxis::get(axis_ref));
1381          vecAxisRef.push_back(CAxis::createAxis());
1382          vecAxisRef.back()->axis_ref=axis_ref;
1383          axisDomainOrderTmp.push_back(1);
[742]1384        }
[1869]1385        else  ERROR("CField::solveGridReference(void)",
1386                    << "Invalid reference to axis '" << axis_ref.getValue() << "'.");
1387      }
[744]1388
[1869]1389      if (!scalar_ref.isEmpty())
1390      {
1391        if (CScalar::has(scalar_ref))
[887]1392        {
[1869]1393          vecScalar.push_back(CScalar::get(scalar_ref));
1394          vecScalarRef.push_back(CScalar::createScalar());
1395          vecScalarRef.back()->scalar_ref=scalar_ref;
1396          axisDomainOrderTmp.push_back(0);
[887]1397        }
[1869]1398        else ERROR("CField::solveGridReference(void)",
1399                   << "Invalid reference to scalar '" << scalar_ref.getValue() << "'.");
1400      }
[894]1401       
[1869]1402      CArray<int,1> axisDomainOrder(axisDomainOrderTmp.size());
1403      for (int idx = 0; idx < axisDomainOrderTmp.size(); ++idx)
[586]1404      {
[1869]1405        axisDomainOrder(idx) = axisDomainOrderTmp[idx];
[586]1406      }
[459]1407
[1869]1408      // Warning: the gridId shouldn't be set as the grid_ref since it could be inherited
1409      StdString gridId = CGrid::generateId(vecDom, vecAxis, vecScalar,axisDomainOrder);
1410      if (CGrid::has(gridId)) this->grid_ = CGrid::get(gridId);
1411      else  this->grid_ = CGrid::createGrid(gridId, vecDomRef, vecAxisRef, vecScalarRef,axisDomainOrder);
1412    }
1413    else
1414    {
1415      if (CGrid::has(grid_ref)) this->grid_ = CGrid::get(grid_ref);
1416      else  ERROR("CField::solveGridReference(void)",
1417                   << "Invalid reference to grid '" << grid_ref.getValue() << "'.");
1418    }
1419  }
1420  CATCH_DUMP_ATTR
[219]1421
[1869]1422  void CField::solveGridDomainAxisRef(bool checkAtt)
1423  TRY
1424  {
1425    grid_->solveDomainAxisRef(checkAtt);
1426  }
1427  CATCH_DUMP_ATTR
[219]1428
[1869]1429  void CField::solveCheckMaskIndex(bool doSendingIndex)
1430  TRY
1431  {
1432    grid_->checkMaskIndex(doSendingIndex);
1433  }
1434  CATCH_DUMP_ATTR
[790]1435
[1869]1436  void CField::solveTransformedGrid()
1437  TRY
1438  {
1439    if (grid_ && !grid_->isTransformed() && hasDirectFieldReference() && grid_ != getDirectFieldReference()->grid_)
1440    {
1441      std::vector<CGrid*> grids;
1442      // Source grid
1443      grids.push_back(getDirectFieldReference()->grid_);
1444      auto gridPath = getGridPath() ;
1445      grids.insert(grids.begin(), gridPath.begin(), gridPath.end());
[790]1446
[1869]1447      for (size_t i = 0, count = grids.size() - 1; i < count; ++i)
1448      {
1449        CGrid *gridSrc  = grids[i];
1450        CGrid *gridDest = grids[i + 1];
1451        if (!gridDest->isTransformed()) gridDest->transformGrid(gridSrc);
1452      }
1453    }
1454    else if (grid_ && grid_->hasTransform() && !grid_->isTransformed())
1455    {
1456      // Temporarily deactivate the self-transformation of grid
1457      // grid_->transformGrid(grid_);
1458    }
1459  }
1460  CATCH_DUMP_ATTR
[790]1461
[1869]1462  void CField::solveGenerateGrid()
1463  TRY
1464  {
1465    if (grid_ && !grid_->isTransformed() && hasDirectFieldReference() && grid_ != getDirectFieldReference()->grid_)
1466      grid_->completeGrid(getDirectFieldReference()->grid_);
1467    else grid_->completeGrid();
1468  }
1469  CATCH_DUMP_ATTR
[790]1470
[1869]1471  void CField::solveGridDomainAxisBaseRef()
1472  TRY
1473  {
1474    grid_->solveDomainAxisRef(false);
1475    grid_->solveDomainAxisBaseRef();
1476  }
1477  CATCH_DUMP_ATTR
[619]1478
[1869]1479  ///-------------------------------------------------------------------
[687]1480
[1869]1481  template <>
1482  void CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)
1483  TRY
1484  {
1485    if (this->group_ref.isEmpty()) return;
1486    StdString gref = this->group_ref.getValue();
[775]1487
[1869]1488    if (!CFieldGroup::has(gref))
1489      ERROR("CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)",
1490         << "[ gref = " << gref << "]"
1491         << " invalid group name !");
[219]1492
[1869]1493    CFieldGroup* group = CFieldGroup::get(gref);
1494    CFieldGroup* owner = CFieldGroup::get(boost::polymorphic_downcast<CFieldGroup*>(this));
1495    owner->setAttributes(group); // inherite of attributes of group reference
1496     
1497    std::vector<CField*> allChildren  = group->getAllChildren();
1498    std::vector<CField*>::iterator it = allChildren.begin(), end = allChildren.end();
[219]1499
[1869]1500    for (; it != end; it++)
1501    {
1502      CField* child = *it;
1503     if (child->hasId()) owner->createChild()->field_ref.setValue(child->getId());
1504    }
1505  }
1506  CATCH_DUMP_ATTR
[219]1507
[1869]1508  ///-------------------------------------------------------------------
1509
1510  void CField::parse(xml::CXMLNode& node)
1511  TRY
1512  {
1513    string newContent ;
1514    SuperClass::parse(node);
1515    if (node.goToChildElement())
1516    {
1517      do
[1129]1518      {
[1869]1519        if (node.getElementName() == "variable" || node.getElementName() == "variable_group") this->getVirtualVariableGroup()->parseChild(node);
1520        else if (node.getElementName() == "expr") if (node.getContent(newContent)) content+=newContent ;
1521      } while (node.goToNextElement());
1522      node.goToParentElement();
1523    }
1524    if (node.getContent(newContent)) content=newContent ;
1525  }
1526  CATCH_DUMP_ATTR
[1129]1527
[1869]1528 /*!
1529   This function retrieves Id of corresponding domain_ref and axis_ref (if any)
1530   of a field. In some cases, only domain exists but axis doesn't
1531   \return pair of Domain and Axis id
1532  */
1533  const std::vector<StdString>& CField::getRefDomainAxisIds()
1534  TRY
1535  {
1536    CGrid* cgPtr = getRelGrid();
1537    if (NULL != cgPtr)
1538    {
1539      std::vector<StdString>::iterator it;
1540      if (!domain_ref.isEmpty())
[599]1541      {
[1869]1542        std::vector<StdString> domainList = cgPtr->getDomainList();
1543        it = std::find(domainList.begin(), domainList.end(), domain_ref.getValue());
1544        if (domainList.end() != it) domAxisScalarIds_[0] = *it;
[599]1545      }
1546
[1869]1547      if (!axis_ref.isEmpty())
[676]1548      {
[1869]1549        std::vector<StdString> axisList = cgPtr->getAxisList();
1550        it = std::find(axisList.begin(), axisList.end(), axis_ref.getValue());
1551        if (axisList.end() != it) domAxisScalarIds_[1] = *it;
[676]1552      }
1553
[1869]1554      if (!scalar_ref.isEmpty())
[472]1555      {
[1869]1556        std::vector<StdString> scalarList = cgPtr->getScalarList();
1557        it = std::find(scalarList.begin(), scalarList.end(), scalar_ref.getValue());
1558        if (scalarList.end() != it) domAxisScalarIds_[2] = *it;
[472]1559      }
[459]1560    }
[1869]1561    return (domAxisScalarIds_);
1562  }
1563  CATCH_DUMP_ATTR
[509]1564
[1869]1565  CVariable* CField::addVariable(const string& id)
1566  TRY
1567  {
1568    return vVariableGroup->createChild(id);
1569  }
1570  CATCH
[472]1571
[1869]1572  CVariableGroup* CField::addVariableGroup(const string& id)
1573  TRY
1574  {
1575    return vVariableGroup->createChildGroup(id);
1576  }
1577  CATCH
[887]1578
[1869]1579  void CField::setContextClient(CContextClient* contextClient)
1580  TRY
1581  {
1582    CContext* context = CContext::getCurrent();
1583    client = contextClient;
[1853]1584 
[1869]1585    // A grid is sent by a client (both for read or write) or by primary server (write only)
1586    if (context->getServiceType()==CServicesManager::GATHERER)
1587    {
[1872]1588      if (getRelFile()->mode.isEmpty() || (!getRelFile()->mode.isEmpty() && getRelFile()->mode == CFile::mode_attr::write))
[1869]1589        grid_->setContextClient(contextClient);
1590    }
1591    else if (context->getServiceType()==CServicesManager::CLIENT)
1592      grid_->setContextClient(contextClient);
1593  }
1594  CATCH_DUMP_ATTR
[1294]1595
[1875]1596  void CField::sendCloseDefinition(void)
[1869]1597  {
[1875]1598    CContext::getCurrent()->sendCloseDefinition(client) ;
[1869]1599  }
[1294]1600
[1870]1601  void CField::sendFieldToFileServer(void)
1602  {
1603    CContext::getCurrent()->sendContextToFileServer(client);
[1872]1604    getRelFile()->sendFileToFileServer(client);
[1870]1605    grid_->sendGridToFileServer(client);
1606    this->sendAllAttributesToServer(client);
1607    this->sendAddAllVariables(client);
1608  }
[1875]1609
[1934]1610  void CField::sendFieldToInputFileServer(void)
1611  {
1612    CContext::getCurrent()->sendContextToFileServer(client);
1613    getRelFile()->sendFileToFileServer(client);
1614    grid_->sendGridToFileServer(client);
1615    read_access=true ; // not the best solution, but on server side, the field must be a starting point of the workflow
1616                       // must be replace by a better solution when implementing filters for reading and send to client
1617                       // on server side
1618    this->sendAllAttributesToServer(client);
1619    this->sendAddAllVariables(client);
1620  }
1621
[1875]1622  void CField::sendFieldToCouplerOut(void)
1623  {
1624    if (sendFieldToCouplerOut_done_) return ;
1625    else sendFieldToCouplerOut_done_=true ;
1626    grid_->sendGridToCouplerOut(client, this->getId());
1627    this->sendGridCompleted();
1628
1629  }
[1872]1630 
[1875]1631  void CField::makeGridAliasForCoupling(void) 
1632  { 
1633    grid_->makeAliasForCoupling(this->getId()); 
1634  }
1635
1636 //! Client side: Send a message  announcing that the grid definition has been received from a coupling context
1637   void CField::sendGridCompleted(void)
1638   TRY
1639   {
1640      CEventClient event(getType(),EVENT_ID_GRID_COMPLETED);
1641
1642      if (client->isServerLeader())
1643      {
1644        CMessage msg;
1645        msg<<this->getId();
1646        for (auto& rank : client->getRanksServerLeader()) event.push(rank,1,msg);
1647        client->sendEvent(event);
1648      }
1649      else client->sendEvent(event);
1650   }
1651   CATCH_DUMP_ATTR
1652
1653   //! Server side: Receive a message announcing that the grid definition has been received from a coupling context
1654   void CField::recvGridCompleted(CEventServer& event)
1655   TRY
1656   {
1657      CBufferIn* buffer=event.subEvents.begin()->buffer;
1658      string id;
1659      *buffer>>id ;
1660      get(id)->recvGridCompleted(*buffer);
1661   }
1662   CATCH
1663
1664   //! Server side: Receive a message  message  announcing that the grid definition has been received from a coupling context
1665   void CField::recvGridCompleted(CBufferIn& buffer)
1666   TRY
1667   {
1668      setGridCompleted() ;
1669   }
1670   CATCH_DUMP_ATTR
1671
1672
[1869]1673  void CField::sendAddAllVariables(CContextClient* client)
1674  TRY
1675  {
1676    std::vector<CVariable*> allVar = getAllVariables();
1677    std::vector<CVariable*>::const_iterator it = allVar.begin();
1678    std::vector<CVariable*>::const_iterator itE = allVar.end();
[1009]1679
[1869]1680    for (; it != itE; ++it)
1681    {
1682      this->sendAddVariable((*it)->getId(), client);
1683      (*it)->sendAllAttributesToServer(client);
1684      (*it)->sendValue(client);
1685    }
1686  }
1687  CATCH_DUMP_ATTR
[1009]1688
[1869]1689  /*!
1690   * Send all Attributes to server. This method is overloaded, since only grid_ref attribute
1691   * must be sent to server and not domain_ref/axis_ref/scalar_ref.
1692   */
[1524]1693   
[1869]1694  void CField::sendAllAttributesToServer(CContextClient* client)
1695  TRY
1696  {
1697    if (grid_ref.isEmpty())
1698    {
1699      grid_ref=grid_->getId() ;
1700      SuperClass::sendAllAttributesToServer(client) ;
[1870]1701      domain_ref.reset() ;
1702      axis_ref.reset() ;
1703      scalar_ref.reset() ;
[1869]1704      grid_ref.reset();
1705    }
1706    else SuperClass::sendAllAttributesToServer(client) ;
1707  }
1708  CATCH_DUMP_ATTR
[1524]1709   
[1869]1710  void CField::sendAddVariable(const string& id, CContextClient* client)
1711  TRY
1712  {
1713    sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE, client);
1714  }
1715  CATCH_DUMP_ATTR
[1021]1716
[1869]1717  void CField::sendAddVariableGroup(const string& id, CContextClient* client)
1718  TRY
1719  {
1720    sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE_GROUP, client);
1721  }
1722  CATCH_DUMP_ATTR
[509]1723
[1869]1724  void CField::recvAddVariable(CEventServer& event)
1725  TRY
1726  {
1727    CBufferIn* buffer = event.subEvents.begin()->buffer;
1728    string id;
1729    *buffer >> id;
1730    get(id)->recvAddVariable(*buffer);
1731  }
1732  CATCH
[509]1733
[1869]1734  void CField::recvAddVariable(CBufferIn& buffer)
1735  TRY
1736  {
1737    string id;
1738    buffer >> id;
1739    addVariable(id);
1740  }
1741  CATCH_DUMP_ATTR
[509]1742
[1869]1743  void CField::recvAddVariableGroup(CEventServer& event)
1744  TRY
1745  {
1746    CBufferIn* buffer = event.subEvents.begin()->buffer;
1747    string id;
1748    *buffer >> id;
1749    get(id)->recvAddVariableGroup(*buffer);
1750  }
1751  CATCH
[472]1752
[1869]1753  void CField::recvAddVariableGroup(CBufferIn& buffer)
1754  TRY
1755  {
1756    string id;
1757    buffer >> id;
1758    addVariableGroup(id);
1759  }
1760  CATCH_DUMP_ATTR
[509]1761
[1869]1762  /*!
1763   * Check on freq_off and freq_op attributes.
1764   */
1765  void CField::checkTimeAttributes(CDuration* freqOp)
1766  TRY
1767  {
[1875]1768    if (hasFileIn() && !(operation.getValue() == "instant" || operation.getValue() == "once") )     
[1869]1769      ERROR("void CField::checkTimeAttributes(void)",
1770         << "Unsupported operation for field '" << getFieldOutputName() << "'." << std::endl
1771         << "Currently only \"instant\" is supported for fields read from file.")
[509]1772
[1869]1773    if (freq_op.isEmpty())
1774    {
1775      if (operation.getValue() == "instant")
1776      {
[1875]1777        if (hasFileIn() || hasFileOut()) freq_op.setValue(getRelFile()->output_freq.getValue());
[1869]1778        else freq_op=*freqOp ;
1779      }
1780      else freq_op.setValue(TimeStep);
1781    }
[1875]1782    if (freq_offset.isEmpty()) freq_offset.setValue(hasFileIn() ? NoneDu : (freq_op.getValue() - TimeStep));
[1869]1783  }
1784  CATCH_DUMP_ATTR
[472]1785
[1869]1786  /*!
1787   * Returns string arithmetic expression associated to the field.
1788   * \return if content is defined return content string, otherwise, if "expr" attribute is defined, return expr string.
1789   */
1790  const string& CField::getExpression(void)
1791  TRY
1792  {
1793    if (!expr.isEmpty() && content.empty())
1794    {
1795      content = expr;
1796      expr.reset();
1797    }
[1315]1798
[1869]1799    return content;
1800  }
1801  CATCH_DUMP_ATTR
[1278]1802
[1869]1803  bool CField::hasExpression(void) const
1804  TRY
1805  {
1806    return (!expr.isEmpty() || !content.empty());
1807  }
1808  CATCH
[1021]1809
[1869]1810  bool CField::hasGridMask(void) const
1811  TRY
1812  {
1813    return (this->grid_->hasMask());
1814  }
1815  CATCH
[1021]1816
[1869]1817  DEFINE_REF_FUNC(Field,field)
[335]1818} // namespace xios
Note: See TracBrowser for help on using the repository browser.