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

Last change on this file since 1943 was 1935, checked in by ymipsl, 4 years ago

XIOS coupling.
Reorganize filters, update of the day.

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: 65.4 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"
17#include "source_filter.hpp"
18#include "store_filter.hpp"
19#include "file_writer_filter.hpp"
[641]20#include "pass_through_filter.hpp"
[642]21#include "filter_expr_node.hpp"
22#include "lex_parser.hpp"
[643]23#include "temporal_filter.hpp"
[644]24#include "spatial_transform_filter.hpp"
[1025]25#include "file_server_writer_filter.hpp"
[1883]26#include "file_server_reader_filter.hpp"
27#include "server_to_client_filter.hpp"
[1930]28#include "server_from_client_source_filter.hpp"
29#include "file_reader_source_filter.hpp"
[1751]30#include "tracer.hpp"
[219]31
[1869]32namespace xios
33{
[509]34
[1869]35  /// ////////////////////// Définitions ////////////////////// ///
[219]36
[1869]37  CField::CField(void)
38    : CObjectTemplate<CField>(), CFieldAttributes()
39    , written(false)
40    , nstep(0), nstepMax(0)
41    , hasOutputFile(false)
42    , domAxisScalarIds_(vector<StdString>(3,""))
43    , areAllReferenceSolved(false), isReferenceSolved(false), isReferenceSolvedAndTransformed(false)
44    , isGridChecked(false)
45    , useCompressedOutput(false)
46    , hasTimeInstant(false)
47    , hasTimeCentered(false)
48    , wasDataRequestedFromServer(false)
49    , wasDataAlreadyReceivedFromServer(false)
50    , mustAutoTrigger(false)
51    , isEOF(false), nstepMaxRead(false)
52  { setVirtualVariableGroup(CVariableGroup::create(getId() + "_virtual_variable_group")); }
[219]53
[1869]54  CField::CField(const StdString& id)
55    : CObjectTemplate<CField>(id), CFieldAttributes()
56    , written(false)
57    , nstep(0), nstepMax(0)
58    , hasOutputFile(false)
59    , domAxisScalarIds_(vector<StdString>(3,""))
60    , areAllReferenceSolved(false), isReferenceSolved(false), isReferenceSolvedAndTransformed(false)
61    , isGridChecked(false)
62    , useCompressedOutput(false)
63    , hasTimeInstant(false)
64    , hasTimeCentered(false)
65    , wasDataRequestedFromServer(false)
66    , wasDataAlreadyReceivedFromServer(false)
67    , mustAutoTrigger(false)
68    , isEOF(false), nstepMaxRead(false)
69  { setVirtualVariableGroup(CVariableGroup::create(getId() + "_virtual_variable_group")); }
[219]70
[1869]71  CField::~CField(void)
72  {}
[509]73
[472]74  //----------------------------------------------------------------
75
[1869]76  void CField::setVirtualVariableGroup(CVariableGroup* newVVariableGroup)
77  TRY
78  {
79    this->vVariableGroup = newVVariableGroup;
80  }
81  CATCH
[509]82
[1869]83  CVariableGroup* CField::getVirtualVariableGroup(void) const
84  TRY
85  {
86     return this->vVariableGroup;
87  }
88  CATCH
[472]89
[1869]90  std::vector<CVariable*> CField::getAllVariables(void) const
91  TRY
92  {
93    return this->vVariableGroup->getAllChildren();
94  }
95  CATCH
[509]96
[1869]97  void CField::solveDescInheritance(bool apply, const CAttributeMap* const parent)
98  TRY
99  {
100    SuperClassAttribute::setAttributes(parent, apply);
101    this->getVirtualVariableGroup()->solveDescInheritance(apply, NULL);
102  }
103  CATCH_DUMP_ATTR
[219]104
[645]105  //----------------------------------------------------------------
[509]106
[598]107  bool CField::dispatchEvent(CEventServer& event)
[1622]108  TRY
[300]109  {
[562]110    if (SuperClass::dispatchEvent(event)) return true;
[300]111    else
112    {
113      switch(event.type)
114      {
115        case EVENT_ID_UPDATE_DATA :
[562]116          recvUpdateData(event);
117          return true;
118          break;
[472]119
[598]120        case EVENT_ID_READ_DATA :
121          recvReadDataRequest(event);
122          return true;
123          break;
[509]124
[598]125        case EVENT_ID_READ_DATA_READY :
126          recvReadDataReady(event);
127          return true;
128          break;
[509]129
[598]130        case EVENT_ID_ADD_VARIABLE :
131          recvAddVariable(event);
132          return true;
133          break;
134
135        case EVENT_ID_ADD_VARIABLE_GROUP :
136          recvAddVariableGroup(event);
137          return true;
138          break;
[1875]139     
140        case EVENT_ID_GRID_COMPLETED :
141          recvGridCompleted(event);
142          return true;
143          break;
[300]144        default :
[562]145          ERROR("bool CField::dispatchEvent(CEventServer& event)", << "Unknown Event");
146          return false;
[300]147      }
148    }
149  }
[1622]150  CATCH
[509]151
[1930]152
[300]153  void CField::recvUpdateData(CEventServer& event)
[1622]154  TRY
[300]155  {
[562]156    string fieldId;
[1930]157    for (auto& subEvent : event.subEvents) (*subEvent.buffer) >> fieldId  ;
158    get(fieldId)->receiveUpdateData(event);
159  }
160  CATCH
[1875]161
[1930]162  void  CField::receiveUpdateData(CEventServer& event)
[1622]163  TRY
[300]164  {
[1930]165    if (hasCouplerIn()) clientFromClientSourceFilter_->streamData(event) ;
166    else serverFromClientSourceFilter_->streamData(event) ;
[1875]167  }
168  CATCH
169
[1934]170 
[1025]171  void CField::writeUpdateData(const CArray<double,1>& data)
[1622]172  TRY
[1025]173  {
[1387]174    const CDate writeDate = last_Write_srv + freq_write_srv;
[1882]175    last_Write_srv = writeDate;
[1930]176    // grid_->computeWrittenIndex(); -> obselete function need to be removed
[1882]177    /*
178    recvDataSrv.resize(data.numElements()) ;
179    recvDataSrv = data ;
180    */
181    writeField(data);
182    lastlast_Write_srv = last_Write_srv;
183  }
184  CATCH_DUMP_ATTR
185
186
187  void CField::writeField(const CArray<double,1>& data)
188  TRY
189  {
[1232]190    if (!getRelFile()->isEmptyZone())
[586]191    {
[1869]192      if (grid_->doGridHaveDataToWrite() || getRelFile()->type == CFile::type_attr::one_file)
[379]193      {
[1136]194        getRelFile()->checkWriteFile();
[379]195        this->incrementNStep();
[1882]196        getRelFile()->getDataOutput()->writeFieldData(CField::get(this), data);
[379]197      }
[586]198    }
[300]199  }
[1622]200  CATCH_DUMP_ATTR
[562]201
[1232]202  /*
203    Send a request for reading data.
204    Client sends a request to server for demanding server to read data and send back to it.
205    For now, this function is called only by client
206    In the future, it can be called by level-1 servers
207    \param [in] tsDataRequested timestamp when the call is made
208  */
[1934]209  bool CField::sendReadDataRequest(const CDate& tsDataRequested)
[1622]210  TRY
[598]211  {
[1934]212    return clientFromServerSourceFilter_->sendReadDataRequest(tsDataRequested) ;
[598]213  }
[1622]214  CATCH_DUMP_ATTR
[1934]215 
216 
[598]217  /*!
218  Send request new data read from file if need be, that is the current data is out-of-date.
219  \return true if and only if some data was requested
220  */
221  bool CField::sendReadDataRequestIfNeeded(void)
[1622]222  TRY
[598]223  {
[1934]224    return clientFromServerSourceFilter_->sendReadDataRequestIfNeeded() ;
[598]225  }
[1622]226  CATCH_DUMP_ATTR
[598]227
[1934]228
[598]229  void CField::recvReadDataRequest(CEventServer& event)
[1622]230  TRY
[598]231  {
232    CBufferIn* buffer = event.subEvents.begin()->buffer;
233    StdString fieldId;
234    *buffer >> fieldId;
[1930]235    get(fieldId)->recvReadDataRequest();
[598]236  }
[1622]237  CATCH
[1930]238 
[1232]239  /*!
240    Receive data request sent from client and process it
241    Every time server receives this request, it will try to read data and sent read data back to client
242    At the moment, this function is called by server level 1
243    In the future, this should (only) be done by the last level servers.
244  */
[1930]245  void CField::recvReadDataRequest(void)
246  TRY
247  {
248    fileReaderSourceFilter_->streamData() ;
249  }
250  CATCH_DUMP_ATTR 
251
[1934]252 
[1930]253  /*
[1232]254    Receive read data from server.
255    At the moment, this function is called in the client side.
256    In the future, this function can be called hiearachically (server n-1, server n -2, ..., client)
257    \param event event containing read data
258  */
[598]259  void CField::recvReadDataReady(CEventServer& event)
[1622]260  TRY
[598]261  {
262    string fieldId;
[1930]263    for (auto& subEvent : event.subEvents) (*subEvent.buffer) >> fieldId  ;
[1934]264    get(fieldId)->receiveReadDataReady(event);
[598]265  }
[1622]266  CATCH
[598]267
[1934]268  void CField::receiveReadDataReady(CEventServer& event)
269  TRY
270  {
271    clientFromServerSourceFilter_->streamData(event) ;   
272  }
273  CATCH_DUMP_ATTR
[1930]274
275  /* old interface to be removed ..*/
[1935]276/*
[1875]277  void CField::recvUpdateDataFromCoupler(std::map<int,CBufferIn*>& rankBuffers)
278  TRY
279  {
280    CContext* context = CContext::getCurrent();
281    Time timeStamp ;
282    if (wasDataAlreadyReceivedFromServer)
283    { 
284      lastDataReceivedFromServer = lastDataReceivedFromServer + freq_op;
285    }
286    else
287    {
288      // unlikely to input from file server where data are received at ts=0
289      // for coupling, it would be after the first freq_op, because for now we don't have
290      // restart mecanism to send the value at ts=0. It mus be changed in future
[1878]291      lastDataReceivedFromServer = context->getCalendar()->getInitDate();
[1875]292      wasDataAlreadyReceivedFromServer = true;
293    }
294
295    CArray<int,1>& storeClient = grid_->getStoreIndex_client();
296    CArray<double,1> recv_data_tmp(storeClient.numElements()); 
297
298    auto& outLocalIndexStoreOnClient = grid_-> getOutLocalIndexStoreOnClient() ;
299    for (auto it = outLocalIndexStoreOnClient.begin(); it != outLocalIndexStoreOnClient.end(); ++it)
300    {
301      CArray<double,1> tmp;
302      CArray<size_t,1>& indexTmp = it->second;
303      *(rankBuffers[it->first]) >> timeStamp >> tmp;
304      for (int idx = 0; idx < indexTmp.numElements(); ++idx) recv_data_tmp(indexTmp(idx)) = tmp(idx);
305    }
306   
307    clientSourceFilter->streamData(lastDataReceivedFromServer, recv_data_tmp);
308   
309  }
310  CATCH_DUMP_ATTR
[1935]311*/ 
[1930]312
[1232]313  /*!
314    Receive read data from server
315    \param [in] ranks Ranks of sending processes
316    \param [in] buffers buffers containing read data
317  */
[1930]318  // old interface to remove
[1935]319/*
[598]320  void CField::recvReadDataReady(vector<int> ranks, vector<CBufferIn*> buffers)
[1622]321  TRY
[598]322  {
323    CContext* context = CContext::getCurrent();
[640]324    std::map<int, CArray<double,1> > data;
[1318]325    const bool wasEOF = isEOF;
[640]326
[598]327    for (int i = 0; i < ranks.size(); i++)
328    {
329      int rank = ranks[i];
[1318]330      int record;
[599]331      *buffers[i] >> record;
[959]332      isEOF = (record == int(-1));
[598]333
[599]334      if (!isEOF)
[640]335        *buffers[i] >> data[rank];
336      else
337        break;
338    }
339
[1021]340    if (wasDataAlreadyReceivedFromServer)
[1872]341      lastDataReceivedFromServer = lastDataReceivedFromServer + fileIn_->output_freq;
[1021]342    else
343    {
344      lastDataReceivedFromServer = context->getCalendar()->getInitDate();
345      wasDataAlreadyReceivedFromServer = true;
346    }
347
[640]348    if (isEOF)
[1318]349    {
350      if (!wasEOF)
351        dateEOF = lastDataReceivedFromServer;
352
[1021]353      serverSourceFilter->signalEndOfStream(lastDataReceivedFromServer);
[1318]354    }
[640]355    else
[1021]356      serverSourceFilter->streamDataFromServer(lastDataReceivedFromServer, data);
[598]357  }
[1622]358  CATCH_DUMP_ATTR
[1935]359*/
[598]360
[1875]361  void CField::checkForLateDataFromCoupler(void)
362  TRY
363  {
364    CContext* context = CContext::getCurrent();
365    const CDate& currentDate = context->getCalendar()->getCurrentDate();
366
367    CTimer timer("CField::checkForLateDataFromCoupler");
368    timer.resume();
369    traceOff() ;
370    timer.suspend();
[1930]371   
372    bool isDataLate; 
[1875]373    do
374    {
[1930]375      isDataLate=clientFromClientSourceFilter_->isDataLate() ;
[1875]376      if (isDataLate)
377      {
378        timer.resume();
379        context->globalEventLoop();
380        timer.suspend();
381      }
382    } while (isDataLate && timer.getCumulatedTime() < CXios::recvFieldTimeout);
383   
384    timer.resume();
385    traceOn() ;
386    timer.suspend() ;
387
388    if (isDataLate) ERROR("void CField::checkForLateDataFromCoupler(void)",
389                            << "Late data at timestep = " << currentDate);
390  }
391  CATCH_DUMP_ATTR
392
[1318]393  void CField::checkForLateDataFromServer(void)
[1622]394  TRY
[1318]395  {
[1934]396    clientFromServerSourceFilter_->checkForLateData() ;
[1318]397  }
[1934]398  CATCH_DUMP_ATTR
399 
400 
[1875]401  void CField::triggerLateField(void)
402  TRY
403  {
404    if (hasFileIn()) 
405    {
406      checkForLateDataFromServer() ;
[1930]407      clientFromServerSourceFilter_->trigger(CContext::getCurrent()->getCalendar()->getCurrentDate()) ;
[1875]408    } 
409    else if (hasCouplerIn())
410    {
411      checkForLateDataFromCoupler() ;
[1930]412      clientFromClientSourceFilter_->trigger(CContext::getCurrent()->getCalendar()->getCurrentDate()) ;
[1875]413    }
414  }
415  CATCH_DUMP_ATTR
416
417
[1358]418  void CField::checkIfMustAutoTrigger(void)
[1622]419  TRY
[1358]420  {
[1930]421    mustAutoTrigger = clientFromServerSourceFilter_ ? clientFromServerSourceFilter_->mustAutoTrigger() : false;
[1358]422  }
[1622]423  CATCH_DUMP_ATTR
[1358]424
425  void CField::autoTriggerIfNeeded(void)
[1622]426  TRY
[1358]427  {
428    if (mustAutoTrigger)
[1930]429      clientFromServerSourceFilter_->trigger(CContext::getCurrent()->getCalendar()->getCurrentDate());
[1358]430  }
[1622]431  CATCH_DUMP_ATTR
[1358]432
[1869]433  //----------------------------------------------------------------
[1872]434/*
[1869]435  void CField::setRelFile(CFile* _file)
436  TRY
437  {
438    this->file = _file;
439    hasOutputFile = true;
440  }
441  CATCH_DUMP_ATTR
[1872]442*/
[1869]443  //----------------------------------------------------------------
[219]444
[1869]445  StdString CField::GetName(void)    { return StdString("field"); }
446  StdString CField::GetDefName(void) { return CField::GetName(); }
447  ENodeType CField::GetType(void)    { return eField; }
[219]448
[1869]449  //----------------------------------------------------------------
[219]450
[1869]451  CGrid* CField::getRelGrid(void) const
452  TRY
453  {
454    return this->grid_;
455  }
456  CATCH
[219]457
[1869]458  //----------------------------------------------------------------
[219]459
[1869]460  CFile* CField::getRelFile(void) const
461  TRY
462  {
[1872]463    if (hasFileIn()) return this->fileIn_;
464    else if (hasFileOut()) return this->fileOut_ ;
465    else return nullptr ;
[1869]466  }
467  CATCH
[509]468
[1869]469  int CField::getNStep(void) const
470  TRY
471  {
472    return this->nstep;
473  }
474  CATCH
[509]475
[1869]476  func::CFunctor::ETimeType CField::getOperationTimeType() const
477  TRY
478  {
479    return operationTimeType;
480  }
481  CATCH
[645]482
483   //----------------------------------------------------------------
484
[1869]485  void CField::incrementNStep(void)
486  TRY
487  {
488    this->nstep++;
489  }
490  CATCH_DUMP_ATTR
[509]491
[1869]492  void CField::resetNStep(int nstep /*= 0*/)
493  TRY
494  {
495    this->nstep = nstep;
496  }
497  CATCH_DUMP_ATTR
[219]498
[1869]499  void CField::resetNStepMax(void)
500  TRY
501  {
502    this->nstepMax = 0;
503    nstepMaxRead = false;
504  }
505  CATCH_DUMP_ATTR
[599]506
[1869]507  //----------------------------------------------------------------
[219]508
[1869]509  bool CField::isActive(bool atCurrentTimestep /*= false*/) const
510  TRY
511  {
[1930]512    if (modelToClientSourceFilter_) 
513      return atCurrentTimestep ? modelToClientSourceFilter_->isDataExpected(CContext::getCurrent()->getCalendar()->getCurrentDate()) : true;
514    else if (clientToModelStoreFilter_)  return true;
[1869]515    else if (instantDataFilter)
516      ERROR("bool CField::isActive(bool atCurrentTimestep)",
517            << "Impossible to check if field [ id = " << getId() << " ] is active as it cannot be used to receive nor send data.");
[1158]518
[1869]519    return false;
520  }
521  CATCH
[562]522
[1869]523  //----------------------------------------------------------------
[509]524
[1869]525  bool CField::wasWritten() const
526  TRY
527  {
528    return written;
529  }
530  CATCH
[707]531
[1869]532  void CField::setWritten()
533  TRY
534  {
535    written = true;
536  }
537  CATCH_DUMP_ATTR
[707]538
[1869]539  //----------------------------------------------------------------
[707]540
[1869]541  bool CField::getUseCompressedOutput() const
542  TRY
543  {
544    return useCompressedOutput;
545  }
546  CATCH
[676]547
[1869]548  void CField::setUseCompressedOutput()
549  TRY
550  {
551    useCompressedOutput = true;
552  }
553  CATCH_DUMP_ATTR
[676]554
[1869]555  //----------------------------------------------------------------
[676]556
[1869]557  std::shared_ptr<COutputPin> CField::getInstantDataFilter()
558  TRY
559  {
560    return instantDataFilter;
561  }
562  CATCH_DUMP_ATTR
[641]563
[1869]564  //----------------------------------------------------------------
[641]565
[1869]566  /*!
567    Build up graph of grids which plays role of destination and source in grid transformation
568    This function should be called before \func solveGridReference()
569  */
570  void CField::buildGridTransformationGraph()
571  TRY
572  {
573    CContext* context = CContext::getCurrent();
574    if (context->getServiceType()==CServicesManager::CLIENT)
575    {
576      if (grid_ && !grid_->isTransformed() && hasDirectFieldReference() && grid_ != getDirectFieldReference()->grid_)
577      {
578        grid_->addTransGridSource(getDirectFieldReference()->grid_);
579      }
580    }
581  }
582  CATCH_DUMP_ATTR
[687]583
[1869]584  /*!
585    Generate a new grid destination if there are more than one grid source pointing to a same grid destination
586  */
587  void CField::generateNewTransformationGridDest()
588  TRY
589  {
590    CContext* context = CContext::getCurrent();
591    if (context->getServiceType()==CServicesManager::CLIENT)
592    {
593      std::map<CGrid*,std::pair<bool,StdString> >& gridSrcMap = grid_->getTransGridSource();
594      if (1 < gridSrcMap.size())
595      {
596        // Search for grid source
597        CGrid* gridSrc = grid_;
598        CField* currField = this;
599        std::vector<CField*> hieraField;
600        while (currField->hasDirectFieldReference() && (gridSrc == grid_))
601        {
602          hieraField.push_back(currField);
603          CField* tmp = currField->getDirectFieldReference();
604          currField = tmp;
605          gridSrc = currField->grid_;
606        }
[687]607
[1869]608        if (gridSrcMap.end() != gridSrcMap.find(gridSrc))
609        {
610          CGrid* gridTmp;
611          std::pair<bool,StdString> newGridDest = gridSrcMap[gridSrc];
612          if (newGridDest.first)
613          {
614            StdString newIdGridDest = newGridDest.second;
615            if (!CGrid::has(newIdGridDest))
616            {
617              ERROR("CGrid* CGrid::generateNewTransformationGridDest()",
618                << " Something wrong happened! Grid whose id " << newIdGridDest
619                << "should exist ");
620            }
621            gridTmp = CGrid::get(newIdGridDest);
622          }
623          else
624          {
625            StdString newIdGridDest = CGrid::generateId(gridSrc, grid_);
626            gridTmp = CGrid::cloneGrid(newIdGridDest, grid_);
[823]627
[1869]628            (gridSrcMap[gridSrc]).first = true;
629            (gridSrcMap[gridSrc]).second = newIdGridDest;
630          }
[823]631
[1869]632          // Update all descendants
633          for (std::vector<CField*>::iterator it = hieraField.begin(); it != hieraField.end(); ++it)
634          {
635            (*it)->grid_ = gridTmp;
636            (*it)->updateRef((*it)->grid_);
637          }
638        }
639      }
640    }
641  }
642  CATCH_DUMP_ATTR
[823]643
[1869]644  void CField::updateRef(CGrid* grid)
645  TRY
646  {
647    if (!grid_ref.isEmpty()) grid_ref.setValue(grid->getId());
648    else
649    {
650      std::vector<CAxis*> axisTmp = grid->getAxis();
651      std::vector<CDomain*> domainTmp = grid->getDomains();
652      if ((1<axisTmp.size()) || (1<domainTmp.size()))
653        ERROR("void CField::updateRef(CGrid* grid)",
654          << "More than one domain or axis is available for domain_ref/axis_ref of field " << this->getId());
[823]655
[1869]656      if ((!domain_ref.isEmpty()) && (domainTmp.empty()))
657        ERROR("void CField::updateRef(CGrid* grid)",
658          << "Incoherent between available domain and domain_ref of field " << this->getId());
659      if ((!axis_ref.isEmpty()) && (axisTmp.empty()))
660        ERROR("void CField::updateRef(CGrid* grid)",
661          << "Incoherent between available axis and axis_ref of field " << this->getId());
[823]662
[1869]663      if (!domain_ref.isEmpty()) domain_ref.setValue(domainTmp[0]->getId());
664      if (!axis_ref.isEmpty()) axis_ref.setValue(axisTmp[0]->getId());
665    }
666  }
667  CATCH_DUMP_ATTR
[1025]668   
[1869]669  /*!
670    Solve reference of all enabled fields even the source fields .
671    In this step, we do transformations.
672  */
673  void CField::solveAllEnabledFieldsAndTransform()
674  TRY
675  {
676    CContext* context = CContext::getCurrent();
[823]677
[1869]678    if (!isReferenceSolvedAndTransformed)
679    {
680      isReferenceSolvedAndTransformed = true;
[1025]681
[1869]682      if (context->getServiceType()==CServicesManager::CLIENT)
683      {
684        solveRefInheritance(true);
685        if (hasDirectFieldReference()) getDirectFieldReference()->solveAllEnabledFieldsAndTransform();
686      }
[1025]687
[1869]688      if (context->getServiceType()==CServicesManager::GATHERER || context->getServiceType()==CServicesManager::OUT_SERVER)
689        solveServerOperation();
[1025]690
[1869]691      solveGridReference();
[1025]692
[1869]693      if (context->getServiceType()==CServicesManager::CLIENT)
694      {
695        solveGenerateGrid();
696        buildGridTransformationGraph();
697      }
[1025]698
[1869]699      solveGridDomainAxisRef(false);
[1025]700
[1869]701      if (context->getServiceType()==CServicesManager::CLIENT)
702      {
703        solveTransformedGrid();
704      }
[1025]705
[1869]706      solveGridDomainAxisRef(false);
707    }
708  }
709  CATCH_DUMP_ATTR
[1025]710
[1869]711  void CField::checkGridOfEnabledFields()
712  TRY
713  {
714    if (!isGridChecked)
715    {
716      isGridChecked = true;
717      solveCheckMaskIndex(false);
718    }
719  }
720  CATCH_DUMP_ATTR
[1025]721
[1869]722  void CField::sendGridComponentOfEnabledFields()
723  TRY
724  {
725    solveGridDomainAxisRef(true);
726    // solveCheckMaskIndex(true);
727  }
728  CATCH_DUMP_ATTR
[1025]729
[1869]730  void CField::sendGridOfEnabledFields()
731  TRY
732  {
733    // solveGridDomainAxisRef(true);
734    solveCheckMaskIndex(true);
735  }   
736  CATCH_DUMP_ATTR
[1025]737
[1869]738  void CField::solveOnlyReferenceEnabledField(void)
739  TRY
740  {
741    CContext* context = CContext::getCurrent();
742    if (!isReferenceSolved)
743    {
744      isReferenceSolved = true;
[1025]745
[1869]746      if (context->getServiceType()==CServicesManager::CLIENT)
747      {
748        solveRefInheritance(true);
749        if (hasDirectFieldReference()) getDirectFieldReference()->solveOnlyReferenceEnabledField();
750      }
[1144]751
[1869]752      if (context->getServiceType()==CServicesManager::GATHERER || context->getServiceType()==CServicesManager::OUT_SERVER)
753        solveServerOperation();
[1025]754
[1869]755      solveGridReference();
756      grid_->solveElementsRefInheritance(true); // make it again to solve grid reading from file
[1025]757
[1869]758      if (context->getServiceType()==CServicesManager::CLIENT)
759      {
760        solveGenerateGrid();
761        buildGridTransformationGraph();
762      }
763    }
764  }
765  CATCH_DUMP_ATTR
[1622]766
[1869]767  void CField::solveAllReferenceEnabledField(bool doSending2Server)
768  TRY
769  {
770    CContext* context = CContext::getCurrent();
771    solveOnlyReferenceEnabledField();
[823]772
[1869]773    if (!areAllReferenceSolved)
774    {
775      areAllReferenceSolved = true;
776     
777      if (context->getServiceType()==CServicesManager::CLIENT)
778      {
779        solveRefInheritance(true);
780        if (hasDirectFieldReference()) getDirectFieldReference()->solveAllReferenceEnabledField(false);
781      }
782      else if (context->getServiceType()==CServicesManager::GATHERER || context->getServiceType()==CServicesManager::OUT_SERVER)
783        solveServerOperation();
[823]784
[1869]785      solveGridReference();
786    }
[823]787
[1869]788    solveGridDomainAxisRef(doSending2Server);
[823]789
[1869]790    if (context->getServiceType()==CServicesManager::CLIENT)
791    {
792      solveTransformedGrid();
793    }
[687]794
[1869]795    solveCheckMaskIndex(doSending2Server);
796  }
797  CATCH_DUMP_ATTR
[509]798
[1870]799  /*!
800   * Compute the required buffer size to send the fields data.
801   * \param [in/out] bufferSize Modifying the bufferSize for the client context
802   * \param [in/out] maxEventSize Modifying the maximum event size for the client context
803   * \param [in] bufferForWriting True if buffers are used for sending data for writing
804   */ 
805  void CField::setContextClientDataBufferSize(map<CContextClient*,map<int,size_t>>& bufferSize, 
806                                              map<CContextClient*,map<int,size_t>>& maxEventSize, 
807                                              bool bufferForWriting)
808  {
809    auto& contextBufferSize = bufferSize[client] ;
810    auto& contextMaxEventSize = maxEventSize[client] ;
811    const std::map<int, size_t> mapSize = grid_->getDataBufferSize(client, getId(), bufferForWriting);
812    for(auto& it : mapSize )
813    {
814      // If contextBufferSize[it.first] does not exist, it will be zero-initialized
815      // so we can use it safely without checking for its existance
816      if (CXios::isOptPerformance) contextBufferSize[it.first] += it.second;
817      else if (contextBufferSize[it.first] < it.second) contextBufferSize[it.first] = it.second;
818
819      if (contextMaxEventSize[it.first] < it.second) contextMaxEventSize[it.first] = it.second;
820    }
821
822  }
823
824  void CField::setContextClientAttributesBufferSize(map<CContextClient*,map<int,size_t>>& bufferSize, 
825                                                   map<CContextClient*,map<int,size_t>>& maxEventSize, 
826                                                   bool bufferForWriting)
827  {
828    auto& contextBufferSize = bufferSize[client] ;
829    auto& contextMaxEventSize = maxEventSize[client] ;
830    const std::map<int, size_t> mapSize = grid_->getAttributesBufferSize(client, bufferForWriting);
831    for(auto& it : mapSize )
832    {
833      // If contextBufferSize[it.first] does not exist, it will be zero-initialized
834      // so we can use it safely without checking for its existance
835      if (contextBufferSize[it.first] < it.second) contextBufferSize[it.first] = it.second;
836      if (contextMaxEventSize[it.first] < it.second) contextMaxEventSize[it.first] = it.second;
837    }
838
839  }
840
841
842// ym obsolete to be removed
[1869]843  std::map<int, StdSize> CField::getGridAttributesBufferSize(CContextClient* client, bool bufferForWriting /*= "false"*/)
844  TRY
845  {
846    return grid_->getAttributesBufferSize(client, bufferForWriting);
847  }
848  CATCH_DUMP_ATTR
[509]849
[1870]850// ym obsolete to be removed
[1869]851  std::map<int, StdSize> CField::getGridDataBufferSize(CContextClient* client, bool bufferForWriting /*= "false"*/)
852  TRY
853  {
854    return grid_->getDataBufferSize(client, getId(), bufferForWriting);
855  }
856  CATCH_DUMP_ATTR
[731]857
[1870]858
859
[1869]860  size_t CField::getGlobalWrittenSize()
861  TRY
862  {
863    return grid_->getGlobalWrittenSize();
864  }
865  CATCH_DUMP_ATTR
[1215]866
[1869]867  //----------------------------------------------------------------
[219]868
[1869]869  void CField::solveServerOperation(void)
870  TRY
871  {
872    CContext* context = CContext::getCurrent();
[509]873
[1869]874    if (freq_op.isEmpty()) freq_op.setValue(TimeStep);
[509]875
[1869]876    if (freq_offset.isEmpty()) freq_offset.setValue(NoneDu);
[219]877
[1872]878    freq_operation_srv = fileOut_->output_freq.getValue();
879    freq_write_srv     = fileOut_->output_freq.getValue();
[509]880
[1869]881    lastlast_Write_srv = context->getCalendar()->getInitDate();
882    last_Write_srv     = context->getCalendar()->getInitDate();
883    last_operation_srv = context->getCalendar()->getInitDate();
[509]884
[1869]885    const CDuration toffset = freq_operation_srv - freq_offset.getValue() - context->getCalendar()->getTimeStep();
886    last_operation_srv     = last_operation_srv - toffset;
[509]887
[1869]888    if (operation.isEmpty())
889      ERROR("void CField::solveServerOperation(void)",
890            << "An operation must be defined for field \"" << getId() << "\".");
[509]891
[1869]892    std::shared_ptr<func::CFunctor> functor;
893    CArray<double, 1> dummyData;
[598]894
[562]895#define DECLARE_FUNCTOR(MType, mtype) \
[1869]896    if (operation.getValue().compare(#mtype) == 0) \
897    { \
898      functor.reset(new func::C##MType(dummyData)); \
899    }
[509]900
[219]901#include "functor_type.conf"
[509]902
[1869]903    if (!functor)
904      ERROR("void CField::solveServerOperation(void)",
905            << "\"" << operation << "\" is not a valid operation.");
[645]906
[1869]907    operationTimeType = functor->timeType();
908  }
909  CATCH_DUMP_ATTR
[509]910
[1869]911 //----------------------------------------------------------------
[640]912
[1869]913  bool CField::buildWorkflowGraph(CGarbageCollector& gc)
914  {
915    if (buildWorkflowGraphDone_) return true ;
[1875]916   
[1869]917    const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
918    const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
919
920    if (!inputFilter) inputFilter = std::shared_ptr<CPassThroughFilter>(new CPassThroughFilter(gc)); 
921     
922    if (hasDirectFieldReference())
923    {
924      CField* fieldRef = getDirectFieldReference();
925      bool ret=fieldRef->buildWorkflowGraph(gc); 
926      if (!ret) return false ; // workflow graph cannot be built at this stage
927    }
928
[1875]929    // now construct grid and check if element are enabled
930    solveGridReference() ; // grid_ is now defined
931    if (!isGridCompleted()) return false;
932
[1869]933    // Check if we have an expression to parse
934    std::shared_ptr<COutputPin> filterExpr ;
935    if (hasExpression())
936    {
937      boost::scoped_ptr<IFilterExprNode> expr(parseExpr(getExpression() + '\0'));
938      filterExpr = expr->reduce(gc, *this);
939      if (!filterExpr) return false ; // workflow graph cannot be built at this stage
940    }
941   
942    // prepare transformation. Need to know before if workflow of auxillary field can be built
943    if (hasDirectFieldReference())
944    {
945      auto gridPath=getGridPath() ;
946      gridPath.push_back(grid_) ;
947
948      CGrid* gridSrc=getDirectFieldReference()->getGrid() ;
949      for(auto grid : gridPath)
950      {
951        grid->solveElementsRefInheritance() ;
[1875]952        grid->completeGrid(gridSrc); // grid generation, to be checked
953        grid->checkElementsAttributes() ;
[1869]954        grid->prepareTransformGrid(gridSrc) ; // prepare the grid tranformation
955        for(auto fieldId : grid->getAuxInputTransformGrid()) // try to build workflow graph for auxillary field tranformation
956          if (!CField::get(fieldId)->buildWorkflowGraph(gc)) return false ;
957        gridSrc=grid ;
958      }
959     
960      std::shared_ptr<COutputPin> lastFilter ;
961      if (filterExpr) lastFilter=filterExpr ;
962      else lastFilter = inputFilter ;
963     
964      gridSrc=getDirectFieldReference()->getGrid() ;
965      for(auto grid : gridPath) 
966      {
967        grid->makeTransformGrid() ; // make the grid transformation
[1871]968        if (grid->hasTransform()) 
969        {
970          std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters = CSpatialTransformFilter::buildFilterGraph(gc, gridSrc, grid, detectMissingValues, defaultValue); 
971          lastFilter->connectOutput(filters.first, 0);
972          lastFilter = filters.second;
973          gridSrc=grid ;
974        }
[1869]975      }
976      instantDataFilter = lastFilter ;
977     
978      // connect the input Filter to the reference
979      getDirectFieldReference()->getInstantDataFilter()->connectOutput(inputFilter,0);
980    }
981    else 
982    {
[1871]983      if (hasFileIn()) // input file, attemp to read the grid from file
984      {
985         // must be checked
986         fileIn_->initRead() ;
987         fileIn_->checkReadFile();
988         grid_->solveElementsRefInheritance() ;
989         if (fileIn_->isClientSide()) fileIn_->readFieldAttributesMetaData(this);
990         grid_->completeGrid(); // grid generation, to be checked
991         if (fileIn_->isClientSide()) fileIn_->readFieldAttributesValues(this);
992         grid_->checkElementsAttributes() ;
993         grid_->solveDomainAxisBaseRef();
994         // probably in future tag grid incomplete if coming from a reading
995         instantDataFilter=inputFilter ;
996      } 
[1875]997      else if (hasCouplerIn())
[1871]998      {
[1875]999        grid_->checkElementsAttributes() ;
1000        instantDataFilter=inputFilter ;
1001      }
1002      else
1003      {
[1871]1004        setModelIn() ; // no reference, the field is potentially a source field from model
1005
1006        grid_->solveElementsRefInheritance() ;
1007        grid_->completeGrid(); // grid generation, to be checked
1008        grid_->checkElementsAttributes() ;
1009        instantDataFilter=inputFilter ;
1010      }
[1869]1011    }
1012   
[1872]1013    if (hasFileOut())
1014    {
1015      if (fileOut_->isServerSide())
1016      {
1017        this->solveServerOperation() ;
1018      }
1019    }
1020
[1869]1021    buildWorkflowGraphDone_ = true ;
1022    workflowEnabled_ = true ;
1023    return true ;
1024  }
1025   
[1870]1026  /*!
1027   * Connect field to filter to send data to server. A temporal filter is inserted before accordingly to the
1028   * output frequency of the file
1029   * \param gc the garbage collector to use when building the filter graph
1030   */
[1869]1031  void CField::connectToFileServer(CGarbageCollector& gc)
1032  {
1033    // insert temporal filter before sending to files
[1935]1034    clientToServerStoreFilter_ = std::shared_ptr<CClientToServerStoreFilter>(new CClientToServerStoreFilter(gc, this, client));
[1869]1035    // insert temporal filter before sending to files
[1935]1036    getTemporalDataFilter(gc, fileOut_->output_freq)->connectOutput(clientToServerStoreFilter_, 0);
[1869]1037  } 
1038
[1875]1039  void CField::connectToCouplerOut(CGarbageCollector& gc)
1040  {
1041    // insert temporal filter before sending to files
[1935]1042    clientToServerStoreFilter_ = std::shared_ptr<CClientToServerStoreFilter>(new CClientToServerStoreFilter(gc, this, client));
1043    instantDataFilter->connectOutput(clientToServerStoreFilter_, 0);
[1875]1044  } 
1045
[1870]1046  /*!
1047   * Compute grid index needed to send grid and data to server
1048   */
[1869]1049  void CField::computeGridIndexToFileServer(void)
1050  {
1051    grid_->computeGridIndexToFileServer(client) ;
1052  }
1053
[1870]1054  /*!
1055   * Connect field to a source filter to receive data from model.
1056   */
1057  void CField::connectToModelInput(CGarbageCollector& gc)
1058  {
1059    const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1060    const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
1061
1062    if (check_if_active.isEmpty()) check_if_active = false; 
[1930]1063    modelToClientSourceFilter_ = std::shared_ptr<CModelToClientSourceFilter>(new CModelToClientSourceFilter(gc, grid_, detectMissingValues, defaultValue));
1064    modelToClientSourceFilter_ -> connectOutput(inputFilter,0) ;
[1870]1065  } 
1066 
1067  /*!
[1871]1068   * Connect field to a source filter to receive data from a client (on server side).
1069   */
1070  void CField::connectToClientInput(CGarbageCollector& gc)
1071  {
[1930]1072    serverFromClientSourceFilter_ = std::shared_ptr<CServerFromClientSourceFilter>(new CServerFromClientSourceFilter(gc,  grid_));
1073    serverFromClientSourceFilter_ -> connectOutput(inputFilter,0) ;
[1871]1074  } 
1075
1076
1077  /*!
1078   * Connect field to a source filter to receive data from a server (on client side).
1079   */
1080  void CField::connectToServerInput(CGarbageCollector& gc)
1081  {
[1872]1082    checkTimeAttributes();
[1934]1083    clientFromServerSourceFilter_ = std::shared_ptr<CClientFromServerSourceFilter>(new CClientFromServerSourceFilter(gc,this)) ;
1084    clientFromServerSourceFilter_ -> connectOutput(inputFilter,0) ;
[1871]1085  } 
1086
1087  /*!
[1875]1088   * Connect field to a source filter to receive data from coupler (on client side).
1089   */
1090   void CField::connectToCouplerIn(CGarbageCollector& gc)
1091  {
1092    CContext* context = CContext::getCurrent();
1093
1094    if (freq_op.isEmpty()) freq_op.setValue(TimeStep);
1095    if (freq_offset.isEmpty()) freq_offset.setValue(freq_op.getValue() - TimeStep);
[1930]1096   
1097    /* old
[1875]1098
1099    freq_operation_srv = freq_op ;
1100    last_operation_srv = context->getCalendar()->getInitDate();
1101    const CDuration toffset = freq_operation_srv - freq_offset.getValue() - context->getCalendar()->getTimeStep();
1102    last_operation_srv     = last_operation_srv - toffset;
1103
1104    clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid_, false, false, freq_offset, true)) ;
1105    clientSourceFilter -> connectOutput(inputFilter,0) ;
[1930]1106
1107    */
1108    // new
1109
1110    clientFromClientSourceFilter_ = std::shared_ptr<CClientFromClientSourceFilter>(new CClientFromClientSourceFilter(gc, this)) ;
1111    clientFromClientSourceFilter_ -> connectOutput(inputFilter,0) ;
1112   
[1875]1113  } 
1114
1115  /*!
[1871]1116   * Connect field to a file writer filter to write data in file (on server side).
1117   */
1118  void CField::connectToFileWriter(CGarbageCollector& gc)
1119  {
[1935]1120    fileWriterStoreFilter_ = std::shared_ptr<CFileWriterStoreFilter>(new CFileWriterStoreFilter(gc, this));
1121    instantDataFilter->connectOutput(fileWriterStoreFilter_, 0);
[1871]1122  } 
[1930]1123
[1883]1124  /*!
1125   * Connect field to a file reader filter to read data from file (on server side).
1126   */
1127  void CField::connectToFileReader(CGarbageCollector& gc)
1128  {
[1930]1129    fileReaderSourceFilter_ = std::shared_ptr<CFileReaderSourceFilter>(new CFileReaderSourceFilter(gc, this));
[1934]1130    fileReaderSourceFilter_->connectOutput(inputFilter, 0);
[1930]1131  }
[1871]1132
[1930]1133
[1871]1134  /*!
1135   * Connect field to a store filter to output data to model on client Side
1136   */
1137  void CField::connectToModelOutput(CGarbageCollector& gc)
1138  {
[1930]1139    clientToModelStoreFilter_ = std::shared_ptr<CClientToModelStoreFilter>(new CClientToModelStoreFilter(gc, this));
1140    instantDataFilter->connectOutput(clientToModelStoreFilter_, 0);
[1871]1141  }
1142
[1883]1143
1144 
1145  void CField::connectToServerToClient(CGarbageCollector& gc)
1146  {
[1934]1147    serverToClientStoreFilter_ = std::shared_ptr<CServerToClientStoreFilter>(new CServerToClientStoreFilter(gc, this, client));
1148    instantDataFilter->connectOutput(serverToClientStoreFilter_, 0);
[1883]1149  }
1150
[1871]1151  /*!
[1869]1152   * Transform the grid_path attribut into vector of grid.
1153   * \return the vector CGrid* containing the list of grid path for tranformation
1154   */ 
1155  vector<CGrid*> CField::getGridPath(void)
1156  {
1157    std::vector<CGrid*> gridPath;
1158
1159    if (hasDirectFieldReference() && grid_ != getDirectFieldReference()->grid_)
1160    {
1161      if (!grid_path.isEmpty())
1162      {
1163        std::string gridId;
1164        size_t start = 0, end;
1165
1166        do
1167        {
1168          end = grid_path.getValue().find(',', start);
1169          if (end != std::string::npos)
1170          {
1171            gridId = grid_path.getValue().substr(start, end - start);
1172            start = end + 1;
1173          }
1174          else gridId = grid_path.getValue().substr(start);
1175
1176          if (!CGrid::has(gridId))
1177            ERROR("void CField::solveTransformedGrid()",
1178               << "Invalid grid_path, the grid '" << gridId << "' does not exist.");
1179
1180          gridPath.push_back(CGrid::get(gridId));
1181        }
1182        while (end != std::string::npos);
1183      }
1184    }
1185    return gridPath ;
1186  }
1187
1188  /*!
1189   * Constructs the graph filter for the field, enabling or not the data output.
1190   * This method should not be called more than once with enableOutput equal to true.
1191   *
1192   * \param gc the garbage collector to use when building the filter graph
1193   * \param enableOutput must be true when the field data is to be
1194   *                     read by the client or/and written to a file
1195   */
[1870]1196   // ym obselete : to be removed later....
[1869]1197  void CField::buildFilterGraph(CGarbageCollector& gc, bool enableOutput)
1198  TRY
1199  {     
[1935]1200   //  ==> before removing, solving dependency in spatial_transform_filter.cpp about auxilairy field
1201/*
[1129]1202    if (!isReferenceSolvedAndTransformed) solveAllEnabledFieldsAndTransform();
[1417]1203    if (!isGridChecked) checkGridOfEnabledFields();
[1201]1204
[1869]1205    const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1206    const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
[1201]1207
[1869]1208    CContext* context = CContext::getCurrent();
1209    bool hasWriterServer = context->getServiceType()==CServicesManager::OUT_SERVER ;
1210    bool hasIntermediateServer = context->getServiceType()==CServicesManager::GATHERER ;
[641]1211
[1869]1212    if (hasWriterServer)
1213    {
1214      if (!instantDataFilter)
1215        instantDataFilter = clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid_, true, false));
[1025]1216
[1294]1217
[1869]1218      // If the field data is to be read by the client or/and written to a file
[1930]1219      if (enableOutput && !clientToModelStoreFilter_ && !fileWriterFilter)
[1869]1220      {
[1872]1221        if (getRelFile() && (getRelFile()->mode.isEmpty() || getRelFile()->mode == CFile::mode_attr::write))
[1869]1222        {
1223          fileServerWriterFilter = std::shared_ptr<CFileServerWriterFilter>(new CFileServerWriterFilter(gc, this));
1224          instantDataFilter->connectOutput(fileServerWriterFilter, 0);
1225        }
1226      }
1227    }
1228    else if (hasIntermediateServer)
1229    {
1230      if (!instantDataFilter)
1231        instantDataFilter = clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid_, false, false));
[1025]1232
[1869]1233      // If the field data is to be read by the client or/and written to a file
[1930]1234      if (enableOutput && !clientToModelStoreFilter_ && !fileWriterFilter)
[1869]1235      {
[1872]1236        if (getRelFile() && (getRelFile()->mode.isEmpty() || getRelFile()->mode == CFile::mode_attr::write))
[1869]1237        {
[1872]1238          fileWriterFilter = std::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this, getRelFile()->getContextClient()));
[1869]1239          instantDataFilter->connectOutput(fileWriterFilter, 0);
1240        }
1241      }
1242    }
1243    else
1244    {
1245      // Start by building a filter which can provide the field's instant data
1246      if (!instantDataFilter)
1247      {
1248        // Check if we have an expression to parse
1249        if (hasExpression())
1250        {
1251          boost::scoped_ptr<IFilterExprNode> expr(parseExpr(getExpression() + '\0'));
1252          std::shared_ptr<COutputPin> filter = expr->reduce(gc, *this);
[1021]1253
[1869]1254          // Check if a spatial transformation is needed
1255          if (!field_ref.isEmpty())
1256          {
1257            CGrid* gridRef = CField::get(field_ref)->grid_;
1258            if (grid_ && grid_ != gridRef && grid_->hasTransform())
1259            {
1260                std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters = CSpatialTransformFilter::buildFilterGraph(gc, gridRef, grid_, detectMissingValues, defaultValue);
[1021]1261
[1869]1262              filter->connectOutput(filters.first, 0);
1263              filter = filters.second;
1264            }
1265          }
[1158]1266
[1869]1267          instantDataFilter = filter;
1268        }
1269        // Check if we have a reference on another field
1270        else if (!field_ref.isEmpty()) instantDataFilter = getFieldReference(gc);
1271        // Check if the data is to be read from a file
[1872]1272        else if (getRelFile() && !getRelFile()->mode.isEmpty() && getRelFile()->mode == CFile::mode_attr::read)
[1869]1273        {
1274          checkTimeAttributes();
1275          instantDataFilter = serverSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid_, true, false, freq_offset, true,
[1201]1276                                                                                                       detectMissingValues, defaultValue));
[1869]1277        }
1278        else // The data might be passed from the model
1279        {
1280          if (check_if_active.isEmpty()) check_if_active = false;
1281          instantDataFilter = clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid_, false, true, NoneDu, false,
1282                                                                                                      detectMissingValues, defaultValue));
1283        }
1284      }
[640]1285
[1869]1286      // If the field data is to be read by the client or/and written to a file
[1930]1287      if (enableOutput && !clientToModelStoreFilter_ && !fileWriterFilter)
[1869]1288      {
1289        if (!read_access.isEmpty() && read_access)
1290        {
[1930]1291          clientToModelStoreFilter_ = std::shared_ptr<CClientToModelStoreFilter>(new CClientToModelStoreFilter(gc, this));
1292          instantDataFilter->connectOutput(clientToModelStoreFilter_, 0);
[1869]1293        }
[640]1294
[1872]1295        if (getRelFile() && (getRelFile()->mode.isEmpty() || getRelFile()->mode == CFile::mode_attr::write))
[1869]1296        {
[1872]1297          fileWriterFilter = std::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this, getRelFile()->getContextClient()));
1298          getTemporalDataFilter(gc, getRelFile()->output_freq)->connectOutput(fileWriterFilter, 0);
[1869]1299        }
1300      }
1301    }
[1935]1302*/ 
[1869]1303  }
1304  CATCH_DUMP_ATTR
[640]1305
[1869]1306  /*!
1307   * Returns the filter needed to handle the field reference.
1308   * This method should only be called when building the filter graph corresponding to the field.
1309   *
1310   * \param gc the garbage collector to use
1311   * \return the output pin corresponding to the field reference
1312   */
1313  std::shared_ptr<COutputPin> CField::getFieldReference(CGarbageCollector& gc)
1314  TRY
1315  {
1316    if (instantDataFilter || field_ref.isEmpty())
1317      ERROR("COutputPin* CField::getFieldReference(CGarbageCollector& gc)",
1318            "Impossible to get the field reference for a field which has already been parsed or which does not have a field_ref.");
[737]1319
[1869]1320    CField* fieldRef = CField::get(field_ref);
1321    fieldRef->buildFilterGraph(gc, false);
[737]1322
[1869]1323    std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters;
1324    // Check if a spatial transformation is needed
1325    if (grid_ && grid_ != fieldRef->grid_ && grid_->hasTransform())
1326    {       
1327      bool hasMissingValue = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1328      double defaultValue  = hasMissingValue ? default_value : (!default_value.isEmpty() ? default_value : 0.0);                               
1329      filters = CSpatialTransformFilter::buildFilterGraph(gc, fieldRef->grid_, grid_, hasMissingValue, defaultValue);
1330    }
1331    else
1332      filters.first = filters.second = std::shared_ptr<CFilter>(new CPassThroughFilter(gc));
[873]1333
[1869]1334    fieldRef->getInstantDataFilter()->connectOutput(filters.first, 0);
[737]1335
[1869]1336    return filters.second;
1337  }
1338  CATCH_DUMP_ATTR
[737]1339
[1869]1340  /*!
1341   * Returns the filter needed to handle a self reference in the field's expression.
1342   * If the needed filter does not exist, it is created, otherwise it is reused.
1343   * This method should only be called when building the filter graph corresponding
1344   * to the field's expression.
1345   *
1346   * \param gc the garbage collector to use
1347   * \return the output pin corresponding to a self reference
1348   */
[642]1349
[1869]1350/* old version
1351  std::shared_ptr<COutputPin> CField::getSelfReference(CGarbageCollector& gc)
1352  TRY
1353  {
1354    if (instantDataFilter || !hasExpression())
1355      ERROR("COutputPin* CField::getSelfReference(CGarbageCollector& gc)",
1356            "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
[1201]1357
[1869]1358    if (!selfReferenceFilter)
1359    {
1360      const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1361      const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
[1201]1362
[1869]1363      if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
1364      {
1365        if (!serverSourceFilter)
1366        {
1367          checkTimeAttributes();
1368          serverSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid_, true, false, freq_offset, true,
1369                                                              detectMissingValues, defaultValue));
[1158]1370         }
[642]1371
[1869]1372        selfReferenceFilter = serverSourceFilter;
1373      }
1374      else if (!field_ref.isEmpty())
1375      {
1376        CField* fieldRef = CField::get(field_ref);
1377        fieldRef->buildFilterGraph(gc, false);
1378        selfReferenceFilter = fieldRef->getInstantDataFilter();
1379      }
1380      else
1381      {
1382        if (!clientSourceFilter)
1383        {
1384          if (check_if_active.isEmpty()) check_if_active = false;
1385          clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid_, true, true, NoneDu, false,
1386                                                                                detectMissingValues, defaultValue));
1387        }
[737]1388
[1869]1389        selfReferenceFilter = clientSourceFilter;
1390      }
1391    }
[642]1392
[1869]1393    return selfReferenceFilter;
1394  }
1395  CATCH_DUMP_ATTR
1396*/
1397  std::shared_ptr<COutputPin> CField::getSelfReference(CGarbageCollector& gc)
1398  TRY
1399  {
1400    return inputFilter ;
1401  } 
1402  CATCH_DUMP_ATTR
[643]1403
[1869]1404  /*!
1405   * Returns the temporal filter corresponding to the field's temporal operation
1406   * for the specified operation frequency. The filter is created if it does not
1407   * exist, otherwise it is reused.
1408   *
1409   * \param gc the garbage collector to use
1410   * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1411   * \return the output pin corresponding to the requested temporal filter
1412   */
1413  std::shared_ptr<COutputPin> CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1414  TRY
1415  {
1416    std::map<CDuration, std::shared_ptr<COutputPin> >::iterator it = temporalDataFilters.find(outFreq);
[643]1417
[1869]1418    if (it == temporalDataFilters.end())
1419    {
1420      if (operation.isEmpty())
1421        ERROR("void CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1422              << "An operation must be defined for field \"" << getId() << "\".");
[1315]1423
[1869]1424      checkTimeAttributes(&outFreq);
1425
1426      const bool detectMissingValues = (!detect_missing_value.isEmpty()  && detect_missing_value == true);
1427      std::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
[643]1428                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
[1440]1429                                                                             freq_op, freq_offset, outFreq, detectMissingValues));
[1278]1430
[1869]1431      instantDataFilter->connectOutput(temporalFilter, 0);
[643]1432
[1869]1433      it = temporalDataFilters.insert(std::make_pair(outFreq, temporalFilter)).first;
1434    }
[643]1435
[1869]1436    return it->second;
1437  }
1438  CATCH_DUMP_ATTR
[643]1439
[1158]1440  /*!
1441    * Returns the temporal filter corresponding to the field's temporal operation
1442    * for the specified operation frequency.
1443    *
1444    * \param gc the garbage collector to use
1445    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1446    * \return the output pin corresponding to the requested temporal filter
1447    */
1448
[1869]1449  std::shared_ptr<COutputPin> CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1450  TRY
1451  {
1452    if (instantDataFilter || !hasExpression())
1453      ERROR("COutputPin* CField::getSelfTemporalDataFilter(CGarbageCollector& gc)",
1454            "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1455   
1456    if (selfTemporalDataFilter) return selfTemporalDataFilter;
[1158]1457
[1869]1458    if (hasDirectFieldReference())
1459    {
1460      CField* fieldRef=getDirectFieldReference();
1461      return fieldRef->getTemporalDataFilter(gc, outFreq) ;
1462    }
1463    else
1464    {
1465      if (selfTemporalDataFilter) return selfTemporalDataFilter ;
[1158]1466
[1869]1467      if (operation.isEmpty())
1468        ERROR("void CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1469              << "An operation must be defined for field \"" << getId() << "\".");
[1315]1470
[1869]1471      checkTimeAttributes(&outFreq); //bof
[1278]1472
[1869]1473      const bool detectMissingValues = (!detect_missing_value.isEmpty() && detect_missing_value == true);
1474      selfTemporalDataFilter = std::shared_ptr<CTemporalFilter>(new CTemporalFilter(gc, operation,
1475                                                                CContext::getCurrent()->getCalendar()->getInitDate(),
1476                                                                freq_op, freq_offset, outFreq, detectMissingValues));
1477
1478      inputFilter->connectOutput(selfTemporalDataFilter, 0);
1479      return selfTemporalDataFilter ;
1480    }
[1158]1481  }
[1869]1482  CATCH_DUMP_ATTR
[1158]1483
[1869]1484/* old version   
1485  std::shared_ptr<COutputPin> CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1486  TRY
1487  {
1488    if (instantDataFilter || !hasExpression())
1489      ERROR("COutputPin* CField::getSelfTemporalDataFilter(CGarbageCollector& gc)",
1490            "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1491
1492    if (!selfReferenceFilter) getSelfReference(gc) ;
1493
1494    if (serverSourceFilter || clientSourceFilter)
1495    {
1496      if (operation.isEmpty())
1497        ERROR("void CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1498              << "An operation must be defined for field \"" << getId() << "\".");
1499
1500      checkTimeAttributes(&outFreq);
1501
1502      const bool detectMissingValues = (!detect_missing_value.isEmpty() && detect_missing_value == true);
1503      std::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1504                                                                          CContext::getCurrent()->getCalendar()->getInitDate(),
1505                                                                          freq_op, freq_offset, outFreq, detectMissingValues));
1506
1507      selfReferenceFilter->connectOutput(temporalFilter, 0);
1508      return temporalFilter ;
1509    }
1510    else if (!field_ref.isEmpty())
1511    {
1512      CField* fieldRef = CField::get(field_ref);
1513      fieldRef->buildFilterGraph(gc, false);
1514      return fieldRef->getTemporalDataFilter(gc, outFreq) ;
1515    }
1516  }
1517  CATCH_DUMP_ATTR
1518*/
1519
1520  //----------------------------------------------------------------
[369]1521/*
[562]1522   void CField::fromBinary(StdIStream& is)
[219]1523   {
1524      SuperClass::fromBinary(is);
1525#define CLEAR_ATT(name_)\
[369]1526      SuperClassAttribute::operator[](#name_)->reset()
[219]1527
1528         CLEAR_ATT(domain_ref);
1529         CLEAR_ATT(axis_ref);
1530#undef CLEAR_ATT
1531
1532   }
[369]1533*/
[219]1534   //----------------------------------------------------------------
1535
[1869]1536  void CField::solveGridReference(void)
1537  TRY
1538  {
1539    if (grid_!=nullptr) return ; // already done
[219]1540
[1869]1541    if (grid_ref.isEmpty() && domain_ref.isEmpty() && axis_ref.isEmpty() && scalar_ref.isEmpty())
1542    {
1543      ERROR("CField::solveGridReference(void)",
1544            << "A grid must be defined for field '" << getFieldOutputName() << "' .");
1545    }
1546    else if (!grid_ref.isEmpty() && (!domain_ref.isEmpty() || !axis_ref.isEmpty() || !scalar_ref.isEmpty()))
1547    {
1548      ERROR("CField::solveGridReference(void)",
1549            << "Field '" << getFieldOutputName() << "' has both a grid and a domain/axis/scalar." << std::endl
1550            << "Please define either 'grid_ref' or 'domain_ref'/'axis_ref'/'scalar_ref'.");
1551    }
[1524]1552
[1869]1553    if (grid_ref.isEmpty())
1554    {
1555      std::vector<CDomain*> vecDom;
1556      std::vector<CAxis*> vecAxis;
1557      std::vector<CScalar*> vecScalar;
1558      std::vector<int> axisDomainOrderTmp;
[1524]1559
[1869]1560      std::vector<CDomain*> vecDomRef;
1561      std::vector<CAxis*> vecAxisRef;
1562      std::vector<CScalar*> vecScalarRef;
[894]1563       
[1869]1564      if (!domain_ref.isEmpty())
1565      {
1566        StdString tmp = domain_ref.getValue();
1567        if (CDomain::has(domain_ref))
[744]1568        {
[1869]1569          vecDom.push_back(CDomain::get(domain_ref));
1570          vecDomRef.push_back(CDomain::createDomain());
1571          vecDomRef.back()->domain_ref=domain_ref;
1572          axisDomainOrderTmp.push_back(2);
[744]1573        }
[1869]1574        else  ERROR("CField::solveGridReference(void)",
1575                    << "Invalid reference to domain '" << domain_ref.getValue() << "'.");
1576      }
[219]1577
[1869]1578      if (!axis_ref.isEmpty())
1579      {
1580        if (CAxis::has(axis_ref))
[742]1581        {
[1869]1582          vecAxis.push_back(CAxis::get(axis_ref));
1583          vecAxisRef.push_back(CAxis::createAxis());
1584          vecAxisRef.back()->axis_ref=axis_ref;
1585          axisDomainOrderTmp.push_back(1);
[742]1586        }
[1869]1587        else  ERROR("CField::solveGridReference(void)",
1588                    << "Invalid reference to axis '" << axis_ref.getValue() << "'.");
1589      }
[744]1590
[1869]1591      if (!scalar_ref.isEmpty())
1592      {
1593        if (CScalar::has(scalar_ref))
[887]1594        {
[1869]1595          vecScalar.push_back(CScalar::get(scalar_ref));
1596          vecScalarRef.push_back(CScalar::createScalar());
1597          vecScalarRef.back()->scalar_ref=scalar_ref;
1598          axisDomainOrderTmp.push_back(0);
[887]1599        }
[1869]1600        else ERROR("CField::solveGridReference(void)",
1601                   << "Invalid reference to scalar '" << scalar_ref.getValue() << "'.");
1602      }
[894]1603       
[1869]1604      CArray<int,1> axisDomainOrder(axisDomainOrderTmp.size());
1605      for (int idx = 0; idx < axisDomainOrderTmp.size(); ++idx)
[586]1606      {
[1869]1607        axisDomainOrder(idx) = axisDomainOrderTmp[idx];
[586]1608      }
[459]1609
[1869]1610      // Warning: the gridId shouldn't be set as the grid_ref since it could be inherited
1611      StdString gridId = CGrid::generateId(vecDom, vecAxis, vecScalar,axisDomainOrder);
1612      if (CGrid::has(gridId)) this->grid_ = CGrid::get(gridId);
1613      else  this->grid_ = CGrid::createGrid(gridId, vecDomRef, vecAxisRef, vecScalarRef,axisDomainOrder);
1614    }
1615    else
1616    {
1617      if (CGrid::has(grid_ref)) this->grid_ = CGrid::get(grid_ref);
1618      else  ERROR("CField::solveGridReference(void)",
1619                   << "Invalid reference to grid '" << grid_ref.getValue() << "'.");
1620    }
1621  }
1622  CATCH_DUMP_ATTR
[219]1623
[1869]1624  void CField::solveGridDomainAxisRef(bool checkAtt)
1625  TRY
1626  {
1627    grid_->solveDomainAxisRef(checkAtt);
1628  }
1629  CATCH_DUMP_ATTR
[219]1630
[1869]1631  void CField::solveCheckMaskIndex(bool doSendingIndex)
1632  TRY
1633  {
1634    grid_->checkMaskIndex(doSendingIndex);
1635  }
1636  CATCH_DUMP_ATTR
[790]1637
[1869]1638  void CField::solveTransformedGrid()
1639  TRY
1640  {
1641    if (grid_ && !grid_->isTransformed() && hasDirectFieldReference() && grid_ != getDirectFieldReference()->grid_)
1642    {
1643      std::vector<CGrid*> grids;
1644      // Source grid
1645      grids.push_back(getDirectFieldReference()->grid_);
1646      auto gridPath = getGridPath() ;
1647      grids.insert(grids.begin(), gridPath.begin(), gridPath.end());
[790]1648
[1869]1649      for (size_t i = 0, count = grids.size() - 1; i < count; ++i)
1650      {
1651        CGrid *gridSrc  = grids[i];
1652        CGrid *gridDest = grids[i + 1];
1653        if (!gridDest->isTransformed()) gridDest->transformGrid(gridSrc);
1654      }
1655    }
1656    else if (grid_ && grid_->hasTransform() && !grid_->isTransformed())
1657    {
1658      // Temporarily deactivate the self-transformation of grid
1659      // grid_->transformGrid(grid_);
1660    }
1661  }
1662  CATCH_DUMP_ATTR
[790]1663
[1869]1664  void CField::solveGenerateGrid()
1665  TRY
1666  {
1667    if (grid_ && !grid_->isTransformed() && hasDirectFieldReference() && grid_ != getDirectFieldReference()->grid_)
1668      grid_->completeGrid(getDirectFieldReference()->grid_);
1669    else grid_->completeGrid();
1670  }
1671  CATCH_DUMP_ATTR
[790]1672
[1869]1673  void CField::solveGridDomainAxisBaseRef()
1674  TRY
1675  {
1676    grid_->solveDomainAxisRef(false);
1677    grid_->solveDomainAxisBaseRef();
1678  }
1679  CATCH_DUMP_ATTR
[619]1680
[1869]1681  ///-------------------------------------------------------------------
[687]1682
[1869]1683  template <>
1684  void CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)
1685  TRY
1686  {
1687    if (this->group_ref.isEmpty()) return;
1688    StdString gref = this->group_ref.getValue();
[775]1689
[1869]1690    if (!CFieldGroup::has(gref))
1691      ERROR("CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)",
1692         << "[ gref = " << gref << "]"
1693         << " invalid group name !");
[219]1694
[1869]1695    CFieldGroup* group = CFieldGroup::get(gref);
1696    CFieldGroup* owner = CFieldGroup::get(boost::polymorphic_downcast<CFieldGroup*>(this));
1697    owner->setAttributes(group); // inherite of attributes of group reference
1698     
1699    std::vector<CField*> allChildren  = group->getAllChildren();
1700    std::vector<CField*>::iterator it = allChildren.begin(), end = allChildren.end();
[219]1701
[1869]1702    for (; it != end; it++)
1703    {
1704      CField* child = *it;
1705     if (child->hasId()) owner->createChild()->field_ref.setValue(child->getId());
1706    }
1707  }
1708  CATCH_DUMP_ATTR
[219]1709
[1882]1710  void CField::scaleFactorAddOffset(CArray<double,1>& data, double scaleFactor, double addOffset)
[1869]1711  TRY
1712  {
[1882]1713    data = (data - addOffset) / scaleFactor;
[1869]1714  }
1715  CATCH_DUMP_ATTR
[509]1716
[1882]1717  void CField::invertScaleFactorAddOffset(CArray<double,1>& data, double scaleFactor, double addOffset)
[1869]1718  TRY
1719  {
[1882]1720    data = data * scaleFactor + addOffset;
[1869]1721  }
1722  CATCH_DUMP_ATTR
[509]1723
[1882]1724  void CField::outputField(const CArray<double,1>& dataIn, CArray<double,1>& dataOut)
[1869]1725  TRY
1726  { 
1727    CArray<size_t,1>& outIndexClient = grid_->localIndexToWriteOnClient_;
1728    CArray<size_t,1>& outIndexServer = grid_->localIndexToWriteOnServer_;
1729    for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1730    {
[1882]1731      dataOut(outIndexServer(idx)) = dataIn(outIndexClient(idx));
[1869]1732    }
1733  }
1734  CATCH_DUMP_ATTR
[509]1735
[1882]1736  void CField::inputField(const CArray<double,1>& dataIn, CArray<double,1>& dataOut)
[1869]1737  TRY
1738  {
1739    CArray<size_t,1>& outIndexClient = grid_->localIndexToWriteOnClient_;
1740    CArray<size_t,1>& outIndexServer = grid_->localIndexToWriteOnServer_;
1741    for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1742    {
[1882]1743      dataOut(outIndexClient(idx)) = dataIn(outIndexServer(idx));
[1869]1744    }
1745  }
1746  CATCH_DUMP_ATTR
[509]1747
[1882]1748 void CField::outputCompressedField(const CArray<double,1>& dataIn, CArray<double,1>& dataOut)
[1869]1749 TRY
1750 {
1751    CArray<size_t,1>& outIndexClient = grid_->localIndexToWriteOnClient_;
1752    CArray<size_t,1>& outIndexServer = grid_->localIndexToWriteOnServer_;
1753    for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1754    {
[1882]1755      dataOut((idx)) = dataIn(outIndexClient(idx));
[1869]1756    }
1757  }
1758  CATCH_DUMP_ATTR
[599]1759
[1869]1760  ///-------------------------------------------------------------------
1761
1762  void CField::parse(xml::CXMLNode& node)
1763  TRY
1764  {
1765    string newContent ;
1766    SuperClass::parse(node);
1767    if (node.goToChildElement())
1768    {
1769      do
[1129]1770      {
[1869]1771        if (node.getElementName() == "variable" || node.getElementName() == "variable_group") this->getVirtualVariableGroup()->parseChild(node);
1772        else if (node.getElementName() == "expr") if (node.getContent(newContent)) content+=newContent ;
1773      } while (node.goToNextElement());
1774      node.goToParentElement();
1775    }
1776    if (node.getContent(newContent)) content=newContent ;
1777  }
1778  CATCH_DUMP_ATTR
[1129]1779
[1869]1780 /*!
1781   This function retrieves Id of corresponding domain_ref and axis_ref (if any)
1782   of a field. In some cases, only domain exists but axis doesn't
1783   \return pair of Domain and Axis id
1784  */
1785  const std::vector<StdString>& CField::getRefDomainAxisIds()
1786  TRY
1787  {
1788    CGrid* cgPtr = getRelGrid();
1789    if (NULL != cgPtr)
1790    {
1791      std::vector<StdString>::iterator it;
1792      if (!domain_ref.isEmpty())
[599]1793      {
[1869]1794        std::vector<StdString> domainList = cgPtr->getDomainList();
1795        it = std::find(domainList.begin(), domainList.end(), domain_ref.getValue());
1796        if (domainList.end() != it) domAxisScalarIds_[0] = *it;
[599]1797      }
1798
[1869]1799      if (!axis_ref.isEmpty())
[676]1800      {
[1869]1801        std::vector<StdString> axisList = cgPtr->getAxisList();
1802        it = std::find(axisList.begin(), axisList.end(), axis_ref.getValue());
1803        if (axisList.end() != it) domAxisScalarIds_[1] = *it;
[676]1804      }
1805
[1869]1806      if (!scalar_ref.isEmpty())
[472]1807      {
[1869]1808        std::vector<StdString> scalarList = cgPtr->getScalarList();
1809        it = std::find(scalarList.begin(), scalarList.end(), scalar_ref.getValue());
1810        if (scalarList.end() != it) domAxisScalarIds_[2] = *it;
[472]1811      }
[459]1812    }
[1869]1813    return (domAxisScalarIds_);
1814  }
1815  CATCH_DUMP_ATTR
[509]1816
[1869]1817  CVariable* CField::addVariable(const string& id)
1818  TRY
1819  {
1820    return vVariableGroup->createChild(id);
1821  }
1822  CATCH
[472]1823
[1869]1824  CVariableGroup* CField::addVariableGroup(const string& id)
1825  TRY
1826  {
1827    return vVariableGroup->createChildGroup(id);
1828  }
1829  CATCH
[887]1830
[1869]1831  void CField::setContextClient(CContextClient* contextClient)
1832  TRY
1833  {
1834    CContext* context = CContext::getCurrent();
1835    client = contextClient;
[1853]1836 
[1869]1837    // A grid is sent by a client (both for read or write) or by primary server (write only)
1838    if (context->getServiceType()==CServicesManager::GATHERER)
1839    {
[1872]1840      if (getRelFile()->mode.isEmpty() || (!getRelFile()->mode.isEmpty() && getRelFile()->mode == CFile::mode_attr::write))
[1869]1841        grid_->setContextClient(contextClient);
1842    }
1843    else if (context->getServiceType()==CServicesManager::CLIENT)
1844      grid_->setContextClient(contextClient);
1845  }
1846  CATCH_DUMP_ATTR
[1294]1847
[1875]1848  void CField::sendCloseDefinition(void)
[1869]1849  {
[1875]1850    CContext::getCurrent()->sendCloseDefinition(client) ;
[1869]1851  }
[1294]1852
[1870]1853  void CField::sendFieldToFileServer(void)
1854  {
1855    CContext::getCurrent()->sendContextToFileServer(client);
[1872]1856    getRelFile()->sendFileToFileServer(client);
[1870]1857    grid_->sendGridToFileServer(client);
1858    this->sendAllAttributesToServer(client);
1859    this->sendAddAllVariables(client);
1860  }
[1875]1861
[1934]1862  void CField::sendFieldToInputFileServer(void)
1863  {
1864    CContext::getCurrent()->sendContextToFileServer(client);
1865    getRelFile()->sendFileToFileServer(client);
1866    grid_->sendGridToFileServer(client);
1867    read_access=true ; // not the best solution, but on server side, the field must be a starting point of the workflow
1868                       // must be replace by a better solution when implementing filters for reading and send to client
1869                       // on server side
1870    this->sendAllAttributesToServer(client);
1871    this->sendAddAllVariables(client);
1872  }
1873
[1875]1874  void CField::sendFieldToCouplerOut(void)
1875  {
1876    if (sendFieldToCouplerOut_done_) return ;
1877    else sendFieldToCouplerOut_done_=true ;
1878    grid_->sendGridToCouplerOut(client, this->getId());
1879    this->sendGridCompleted();
1880
1881  }
[1872]1882 
[1875]1883  void CField::makeGridAliasForCoupling(void) 
1884  { 
1885    grid_->makeAliasForCoupling(this->getId()); 
1886  }
1887
1888 //! Client side: Send a message  announcing that the grid definition has been received from a coupling context
1889   void CField::sendGridCompleted(void)
1890   TRY
1891   {
1892      CEventClient event(getType(),EVENT_ID_GRID_COMPLETED);
1893
1894      if (client->isServerLeader())
1895      {
1896        CMessage msg;
1897        msg<<this->getId();
1898        for (auto& rank : client->getRanksServerLeader()) event.push(rank,1,msg);
1899        client->sendEvent(event);
1900      }
1901      else client->sendEvent(event);
1902   }
1903   CATCH_DUMP_ATTR
1904
1905   //! Server side: Receive a message announcing that the grid definition has been received from a coupling context
1906   void CField::recvGridCompleted(CEventServer& event)
1907   TRY
1908   {
1909      CBufferIn* buffer=event.subEvents.begin()->buffer;
1910      string id;
1911      *buffer>>id ;
1912      get(id)->recvGridCompleted(*buffer);
1913   }
1914   CATCH
1915
1916   //! Server side: Receive a message  message  announcing that the grid definition has been received from a coupling context
1917   void CField::recvGridCompleted(CBufferIn& buffer)
1918   TRY
1919   {
1920      setGridCompleted() ;
1921   }
1922   CATCH_DUMP_ATTR
1923
1924
[1869]1925  void CField::sendAddAllVariables(CContextClient* client)
1926  TRY
1927  {
1928    std::vector<CVariable*> allVar = getAllVariables();
1929    std::vector<CVariable*>::const_iterator it = allVar.begin();
1930    std::vector<CVariable*>::const_iterator itE = allVar.end();
[1009]1931
[1869]1932    for (; it != itE; ++it)
1933    {
1934      this->sendAddVariable((*it)->getId(), client);
1935      (*it)->sendAllAttributesToServer(client);
1936      (*it)->sendValue(client);
1937    }
1938  }
1939  CATCH_DUMP_ATTR
[1009]1940
[1869]1941  /*!
1942   * Send all Attributes to server. This method is overloaded, since only grid_ref attribute
1943   * must be sent to server and not domain_ref/axis_ref/scalar_ref.
1944   */
[1524]1945   
[1869]1946  void CField::sendAllAttributesToServer(CContextClient* client)
1947  TRY
1948  {
1949    if (grid_ref.isEmpty())
1950    {
1951      grid_ref=grid_->getId() ;
1952      SuperClass::sendAllAttributesToServer(client) ;
[1870]1953      domain_ref.reset() ;
1954      axis_ref.reset() ;
1955      scalar_ref.reset() ;
[1869]1956      grid_ref.reset();
1957    }
1958    else SuperClass::sendAllAttributesToServer(client) ;
1959  }
1960  CATCH_DUMP_ATTR
[1524]1961   
[1869]1962  void CField::sendAddVariable(const string& id, CContextClient* client)
1963  TRY
1964  {
1965    sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE, client);
1966  }
1967  CATCH_DUMP_ATTR
[1021]1968
[1869]1969  void CField::sendAddVariableGroup(const string& id, CContextClient* client)
1970  TRY
1971  {
1972    sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE_GROUP, client);
1973  }
1974  CATCH_DUMP_ATTR
[509]1975
[1869]1976  void CField::recvAddVariable(CEventServer& event)
1977  TRY
1978  {
1979    CBufferIn* buffer = event.subEvents.begin()->buffer;
1980    string id;
1981    *buffer >> id;
1982    get(id)->recvAddVariable(*buffer);
1983  }
1984  CATCH
[509]1985
[1869]1986  void CField::recvAddVariable(CBufferIn& buffer)
1987  TRY
1988  {
1989    string id;
1990    buffer >> id;
1991    addVariable(id);
1992  }
1993  CATCH_DUMP_ATTR
[509]1994
[1869]1995  void CField::recvAddVariableGroup(CEventServer& event)
1996  TRY
1997  {
1998    CBufferIn* buffer = event.subEvents.begin()->buffer;
1999    string id;
2000    *buffer >> id;
2001    get(id)->recvAddVariableGroup(*buffer);
2002  }
2003  CATCH
[472]2004
[1869]2005  void CField::recvAddVariableGroup(CBufferIn& buffer)
2006  TRY
2007  {
2008    string id;
2009    buffer >> id;
2010    addVariableGroup(id);
2011  }
2012  CATCH_DUMP_ATTR
[509]2013
[1869]2014  /*!
2015   * Check on freq_off and freq_op attributes.
2016   */
2017  void CField::checkTimeAttributes(CDuration* freqOp)
2018  TRY
2019  {
[1875]2020    if (hasFileIn() && !(operation.getValue() == "instant" || operation.getValue() == "once") )     
[1869]2021      ERROR("void CField::checkTimeAttributes(void)",
2022         << "Unsupported operation for field '" << getFieldOutputName() << "'." << std::endl
2023         << "Currently only \"instant\" is supported for fields read from file.")
[509]2024
[1869]2025    if (freq_op.isEmpty())
2026    {
2027      if (operation.getValue() == "instant")
2028      {
[1875]2029        if (hasFileIn() || hasFileOut()) freq_op.setValue(getRelFile()->output_freq.getValue());
[1869]2030        else freq_op=*freqOp ;
2031      }
2032      else freq_op.setValue(TimeStep);
2033    }
[1875]2034    if (freq_offset.isEmpty()) freq_offset.setValue(hasFileIn() ? NoneDu : (freq_op.getValue() - TimeStep));
[1869]2035  }
2036  CATCH_DUMP_ATTR
[472]2037
[1869]2038  /*!
2039   * Returns string arithmetic expression associated to the field.
2040   * \return if content is defined return content string, otherwise, if "expr" attribute is defined, return expr string.
2041   */
2042  const string& CField::getExpression(void)
2043  TRY
2044  {
2045    if (!expr.isEmpty() && content.empty())
2046    {
2047      content = expr;
2048      expr.reset();
2049    }
[1315]2050
[1869]2051    return content;
2052  }
2053  CATCH_DUMP_ATTR
[1278]2054
[1869]2055  bool CField::hasExpression(void) const
2056  TRY
2057  {
2058    return (!expr.isEmpty() || !content.empty());
2059  }
2060  CATCH
[1021]2061
[1869]2062  bool CField::hasGridMask(void) const
2063  TRY
2064  {
2065    return (this->grid_->hasMask());
2066  }
2067  CATCH
[1021]2068
[1869]2069  DEFINE_REF_FUNC(Field,field)
[335]2070} // namespace xios
Note: See TracBrowser for help on using the repository browser.