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

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

Coupling branch
Fix compilation error due to deleted .hpp . Problem appear only after a full compilation.

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