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

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

Coupling branch : replace hasServer and hasClient combination by the name of correct service : CLIENT, GATHERER or OUT_SERVER.

YM

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