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

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

XIOS_COUPLING branch : more comments and cleaning

YM

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