source: XIOS/dev/dev_ym/XIOS_ONE_SIDED/src/node/field.cpp @ 2326

Last change on this file since 2326 was 1751, checked in by ymipsl, 5 years ago

suspend tracing when probing to avoid too big trace

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.8 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       {
[1236]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    {
[1236]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;
[1263]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    {           
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    {
[1136]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    {
[1136]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
[1236]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        {           
500          CArray<int,1>& storeClient = grid->storeIndex_client;         
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
[1322]636          context->checkBuffersAndListen();
[1318]637
[1322]638          timer.suspend();
639        }
[1318]640      }
[1322]641      while (isDataLate && timer.getCumulatedTime() < CXios::recvFieldTimeout);
[1751]642      timer.resume();
643      traceOn() ;
644      timer.suspend() ;
[1318]645
[1751]646
[1318]647      if (isDataLate)
648        ERROR("void CField::checkForLateDataFromServer(void)",
649              << "Late data at timestep = " << currentDate);
650    }
651  }
[1622]652  CATCH_DUMP_ATTR
[1318]653
[1358]654  void CField::checkIfMustAutoTrigger(void)
[1622]655  TRY
[1358]656  {
657    mustAutoTrigger = serverSourceFilter ? serverSourceFilter->mustAutoTrigger() : false;
658  }
[1622]659  CATCH_DUMP_ATTR
[1358]660
661  void CField::autoTriggerIfNeeded(void)
[1622]662  TRY
[1358]663  {
664    if (mustAutoTrigger)
665      serverSourceFilter->trigger(CContext::getCurrent()->getCalendar()->getCurrentDate());
666  }
[1622]667  CATCH_DUMP_ATTR
[1358]668
[219]669   //----------------------------------------------------------------
670
[347]671   void CField::setRelFile(CFile* _file)
[1622]672   TRY
[509]673   {
[459]674      this->file = _file;
[562]675      hasOutputFile = true;
[219]676   }
[1622]677   CATCH_DUMP_ATTR
[219]678
679   //----------------------------------------------------------------
680
[562]681   StdString CField::GetName(void)    { return StdString("field"); }
682   StdString CField::GetDefName(void) { return CField::GetName(); }
683   ENodeType CField::GetType(void)    { return eField; }
[219]684
685   //----------------------------------------------------------------
686
[347]687   CGrid* CField::getRelGrid(void) const
[1622]688   TRY
[509]689   {
[562]690      return this->grid;
[219]691   }
[1622]692   CATCH
[219]693
694   //----------------------------------------------------------------
695
[347]696   CFile* CField::getRelFile(void) const
[1622]697   TRY
[509]698   {
[562]699      return this->file;
[219]700   }
[1622]701   CATCH
[509]702
[952]703   int CField::getNStep(void) const
[1622]704   TRY
[266]705   {
[562]706      return this->nstep;
[266]707   }
[1622]708   CATCH
[509]709
[645]710   func::CFunctor::ETimeType CField::getOperationTimeType() const
[1622]711   TRY
[645]712   {
713     return operationTimeType;
714   }
[1622]715   CATCH
[645]716
717   //----------------------------------------------------------------
718
[266]719   void CField::incrementNStep(void)
[1622]720   TRY
[266]721   {
722      this->nstep++;
723   }
[1622]724   CATCH_DUMP_ATTR
[509]725
[952]726   void CField::resetNStep(int nstep /*= 0*/)
[1622]727   TRY
[321]728   {
[707]729      this->nstep = nstep;
[321]730   }
[1622]731   CATCH_DUMP_ATTR
[219]732
[599]733   void CField::resetNStepMax(void)
[1622]734   TRY
[599]735   {
736      this->nstepMax = 0;
[1232]737      nstepMaxRead = false;
[599]738   }
[1622]739   CATCH_DUMP_ATTR
[599]740
[219]741   //----------------------------------------------------------------
742
[1158]743   bool CField::isActive(bool atCurrentTimestep /*= false*/) const
[1622]744   TRY
[509]745   {
[1158]746      if (clientSourceFilter)
747        return atCurrentTimestep ? clientSourceFilter->isDataExpected(CContext::getCurrent()->getCalendar()->getCurrentDate()) : true;
748      else if (storeFilter)
749        return true;
750      else if (instantDataFilter)
751        ERROR("bool CField::isActive(bool atCurrentTimestep)",
752              << "Impossible to check if field [ id = " << getId() << " ] is active as it cannot be used to receive nor send data.");
753
754      return false;
[310]755   }
[1622]756   CATCH
[562]757
[219]758   //----------------------------------------------------------------
[509]759
[707]760   bool CField::wasWritten() const
[1622]761   TRY
[707]762   {
763     return written;
764   }
[1622]765   CATCH
[707]766
767   void CField::setWritten()
[1622]768   TRY
[707]769   {
770     written = true;
771   }
[1622]772   CATCH_DUMP_ATTR
[707]773
774   //----------------------------------------------------------------
775
[676]776   bool CField::getUseCompressedOutput() const
[1622]777   TRY
[676]778   {
779     return useCompressedOutput;
780   }
[1622]781   CATCH
[676]782
783   void CField::setUseCompressedOutput()
[1622]784   TRY
[676]785   {
786     useCompressedOutput = true;
787   }
[1622]788   CATCH_DUMP_ATTR
[676]789
790   //----------------------------------------------------------------
791
[1542]792   std::shared_ptr<COutputPin> CField::getInstantDataFilter()
[1622]793   TRY
[641]794   {
795     return instantDataFilter;
796   }
[1622]797   CATCH_DUMP_ATTR
[641]798
799   //----------------------------------------------------------------
800
[823]801   /*!
802     Build up graph of grids which plays role of destination and source in grid transformation
803     This function should be called before \func solveGridReference()
804   */
805   void CField::buildGridTransformationGraph()
[1622]806   TRY
[823]807   {
808     CContext* context = CContext::getCurrent();
[983]809     if (context->hasClient && !context->hasServer)
[687]810     {
[823]811       if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
812       {
813         grid->addTransGridSource(getDirectFieldReference()->grid);
814       }
[687]815     }
[823]816   }
[1622]817   CATCH_DUMP_ATTR
[687]818
[823]819   /*!
820     Generate a new grid destination if there are more than one grid source pointing to a same grid destination
821   */
822   void CField::generateNewTransformationGridDest()
[1622]823   TRY
[823]824   {
825     CContext* context = CContext::getCurrent();
[983]826     if (context->hasClient && !context->hasServer)
[823]827     {
828       std::map<CGrid*,std::pair<bool,StdString> >& gridSrcMap = grid->getTransGridSource();
829       if (1 < gridSrcMap.size())
830       {
831         // Search for grid source
832         CGrid* gridSrc = grid;
833         CField* currField = this;
834         std::vector<CField*> hieraField;
[687]835
[823]836         while (currField->hasDirectFieldReference() && (gridSrc == grid))
837         {
838           hieraField.push_back(currField);
839           CField* tmp = currField->getDirectFieldReference();
840           currField = tmp;
841           gridSrc = currField->grid;
842         }
843
844         if (gridSrcMap.end() != gridSrcMap.find(gridSrc))
845         {
846           CGrid* gridTmp;
847           std::pair<bool,StdString> newGridDest = gridSrcMap[gridSrc];
848           if (newGridDest.first)
849           {
850             StdString newIdGridDest = newGridDest.second;
851             if (!CGrid::has(newIdGridDest))
852             {
853                ERROR("CGrid* CGrid::generateNewTransformationGridDest()",
854                  << " Something wrong happened! Grid whose id " << newIdGridDest
855                  << "should exist ");
856             }
857             gridTmp = CGrid::get(newIdGridDest);
858           }
859           else
860           {
861             StdString newIdGridDest = CGrid::generateId(gridSrc, grid);
862             gridTmp = CGrid::cloneGrid(newIdGridDest, grid);
863
864             (gridSrcMap[gridSrc]).first = true;
865             (gridSrcMap[gridSrc]).second = newIdGridDest;
866           }
867
868           // Update all descendants
869           for (std::vector<CField*>::iterator it = hieraField.begin(); it != hieraField.end(); ++it)
870           {
871             (*it)->grid = gridTmp;
872             (*it)->updateRef((*it)->grid);
873           }
874         }
875       }
876     }
877   }
[1622]878   CATCH_DUMP_ATTR
[823]879
880   void CField::updateRef(CGrid* grid)
[1622]881   TRY
[823]882   {
883     if (!grid_ref.isEmpty()) grid_ref.setValue(grid->getId());
884     else
885     {
886       std::vector<CAxis*> axisTmp = grid->getAxis();
887       std::vector<CDomain*> domainTmp = grid->getDomains();
888       if ((1<axisTmp.size()) || (1<domainTmp.size()))
889         ERROR("void CField::updateRef(CGrid* grid)",
890           << "More than one domain or axis is available for domain_ref/axis_ref of field " << this->getId());
891
892       if ((!domain_ref.isEmpty()) && (domainTmp.empty()))
893         ERROR("void CField::updateRef(CGrid* grid)",
894           << "Incoherent between available domain and domain_ref of field " << this->getId());
895       if ((!axis_ref.isEmpty()) && (axisTmp.empty()))
896         ERROR("void CField::updateRef(CGrid* grid)",
897           << "Incoherent between available axis and axis_ref of field " << this->getId());
898
899       if (!domain_ref.isEmpty()) domain_ref.setValue(domainTmp[0]->getId());
900       if (!axis_ref.isEmpty()) axis_ref.setValue(axisTmp[0]->getId());
901     }
902   }
[1622]903   CATCH_DUMP_ATTR
[1025]904   
[1129]905   /*!
906     Solve reference of all enabled fields even the source fields .
907     In this step, we do transformations.
908   */
909   void CField::solveAllEnabledFieldsAndTransform()
[1622]910   TRY
[1025]911   {
912     CContext* context = CContext::getCurrent();
913     bool hasClient = context->hasClient;
914     bool hasServer = context->hasServer;
[823]915
[1129]916     if (!isReferenceSolvedAndTransformed)
[1025]917     {
[1129]918        isReferenceSolvedAndTransformed = true;
[1025]919
920        if (hasClient && !hasServer)
921        {
922          solveRefInheritance(true);
[1129]923          if (hasDirectFieldReference()) getDirectFieldReference()->solveAllEnabledFieldsAndTransform();
[1025]924        }
925
926        if (hasServer)
927          solveServerOperation();
928
929        solveGridReference();
930
931        if (hasClient && !hasServer)
932       {
933         solveGenerateGrid();
934         buildGridTransformationGraph();
935       }
936
937       solveGridDomainAxisRef(false);
938
939       if (hasClient && !hasServer)
940       {
941         solveTransformedGrid();
942       }
943
944       solveGridDomainAxisRef(false);
945     }
946   }
[1622]947   CATCH_DUMP_ATTR
[1025]948
949   void CField::checkGridOfEnabledFields()
[1622]950   TRY
[1025]951   {
[1417]952     if (!isGridChecked)
953     {
954       isGridChecked = true;
955       solveCheckMaskIndex(false);
956     }
[1025]957   }
[1622]958   CATCH_DUMP_ATTR
[1025]959
[1239]960   void CField::sendGridComponentOfEnabledFields()
[1622]961   TRY
[1025]962   {
963      solveGridDomainAxisRef(true);
[1239]964      // solveCheckMaskIndex(true);
[1025]965   }
[1622]966   CATCH_DUMP_ATTR
[1025]967
[1239]968   void CField::sendGridOfEnabledFields()
[1622]969   TRY
[1239]970   {
971      // solveGridDomainAxisRef(true);
972      solveCheckMaskIndex(true);
973   }   
[1622]974   CATCH_DUMP_ATTR
[1025]975
[1239]976   void CField::solveOnlyReferenceEnabledField(bool doSending2Server)
[1622]977   TRY
[1025]978   {
979     CContext* context = CContext::getCurrent();
980     if (!isReferenceSolved)
981     {
982        isReferenceSolved = true;
983
984        if (context->hasClient && !context->hasServer)
985        {
986          solveRefInheritance(true);
987          if (hasDirectFieldReference()) getDirectFieldReference()->solveOnlyReferenceEnabledField(false);
988        }
[1144]989
[1025]990        if (context->hasServer)
991          solveServerOperation();
992
993        solveGridReference();
[1308]994        grid->solveDomainAxisRefInheritance(true); // make it again to solve grid reading from file
[1025]995
996        if (context->hasClient && !context->hasServer)
997       {
998         solveGenerateGrid();
999         buildGridTransformationGraph();
1000       }
1001     }
1002   }
[1622]1003   CATCH_DUMP_ATTR
1004
[823]1005   void CField::solveAllReferenceEnabledField(bool doSending2Server)
[1622]1006   TRY
[823]1007   {
1008     CContext* context = CContext::getCurrent();
1009     solveOnlyReferenceEnabledField(doSending2Server);
1010
1011     if (!areAllReferenceSolved)
1012     {
1013        areAllReferenceSolved = true;
[1144]1014       
[983]1015        if (context->hasClient && !context->hasServer)
[823]1016        {
1017          solveRefInheritance(true);
1018          if (hasDirectFieldReference()) getDirectFieldReference()->solveAllReferenceEnabledField(false);
1019        }
[1158]1020        else if (context->hasServer)
[823]1021          solveServerOperation();
1022
1023        solveGridReference();
1024     }
1025
1026     solveGridDomainAxisRef(doSending2Server);
1027
[1021]1028     if (context->hasClient && !context->hasServer)
[619]1029     {
1030       solveTransformedGrid();
1031     }
[687]1032
[823]1033     solveCheckMaskIndex(doSending2Server);
[509]1034   }
[1622]1035   CATCH_DUMP_ATTR
[509]1036
[1330]1037   std::map<int, StdSize> CField::getGridAttributesBufferSize(CContextClient* client, bool bufferForWriting /*= "false"*/)
[1622]1038   TRY
[509]1039   {
[1330]1040     return grid->getAttributesBufferSize(client, bufferForWriting);
[509]1041   }
[1622]1042   CATCH_DUMP_ATTR
[509]1043
[1330]1044   std::map<int, StdSize> CField::getGridDataBufferSize(CContextClient* client, bool bufferForWriting /*= "false"*/)
[1622]1045   TRY
[731]1046   {
[1330]1047     return grid->getDataBufferSize(client, getId(), bufferForWriting);
[731]1048   }
[1622]1049   CATCH_DUMP_ATTR
[731]1050
[1215]1051   size_t CField::getGlobalWrittenSize()
[1622]1052   TRY
[1215]1053   {
1054     return grid->getGlobalWrittenSize();
1055   }
[1622]1056   CATCH_DUMP_ATTR
[1215]1057
[219]1058   //----------------------------------------------------------------
1059
[645]1060   void CField::solveServerOperation(void)
[1622]1061   TRY
[219]1062   {
[640]1063      CContext* context = CContext::getCurrent();
[509]1064
[640]1065      if (!context->hasServer || !hasOutputFile) return;
1066
[645]1067      if (freq_op.isEmpty())
1068        freq_op.setValue(TimeStep);
[509]1069
[538]1070      if (freq_offset.isEmpty())
1071        freq_offset.setValue(NoneDu);
[219]1072
[645]1073      freq_operation_srv = file->output_freq.getValue();
1074      freq_write_srv     = file->output_freq.getValue();
[509]1075
[651]1076      lastlast_Write_srv = context->getCalendar()->getInitDate();
1077      last_Write_srv     = context->getCalendar()->getInitDate();
1078      last_operation_srv = context->getCalendar()->getInitDate();
[509]1079
[645]1080      const CDuration toffset = freq_operation_srv - freq_offset.getValue() - context->getCalendar()->getTimeStep();
[651]1081      last_operation_srv     = last_operation_srv - toffset;
[509]1082
[645]1083      if (operation.isEmpty())
1084        ERROR("void CField::solveServerOperation(void)",
1085              << "An operation must be defined for field \"" << getId() << "\".");
[509]1086
[1542]1087      std::shared_ptr<func::CFunctor> functor;
[645]1088      CArray<double, 1> dummyData;
[598]1089
[562]1090#define DECLARE_FUNCTOR(MType, mtype) \
[645]1091      if (operation.getValue().compare(#mtype) == 0) \
[470]1092      { \
[645]1093        functor.reset(new func::C##MType(dummyData)); \
1094      }
[509]1095
[219]1096#include "functor_type.conf"
[509]1097
[645]1098      if (!functor)
1099        ERROR("void CField::solveServerOperation(void)",
1100              << "\"" << operation << "\" is not a valid operation.");
1101
1102      operationTimeType = functor->timeType();
[219]1103   }
[1622]1104   CATCH_DUMP_ATTR
[509]1105
[219]1106   //----------------------------------------------------------------
[640]1107
1108   /*!
1109    * Constructs the graph filter for the field, enabling or not the data output.
1110    * This method should not be called more than once with enableOutput equal to true.
1111    *
1112    * \param gc the garbage collector to use when building the filter graph
1113    * \param enableOutput must be true when the field data is to be
1114    *                     read by the client or/and written to a file
1115    */
1116   void CField::buildFilterGraph(CGarbageCollector& gc, bool enableOutput)
[1622]1117   TRY
[1144]1118   {     
[1129]1119    if (!isReferenceSolvedAndTransformed) solveAllEnabledFieldsAndTransform();
[1417]1120    if (!isGridChecked) checkGridOfEnabledFields();
[1201]1121
1122     const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1123     const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
1124
[1025]1125     CContext* context = CContext::getCurrent();
1126     bool hasWriterServer = context->hasServer && !context->hasClient;
1127     bool hasIntermediateServer = context->hasServer && context->hasClient;
[641]1128
[1025]1129     if (hasWriterServer)
[640]1130     {
[1025]1131        if (!instantDataFilter)
[1637]1132          instantDataFilter = clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, false));
[1025]1133
[1294]1134
1135       // If the field data is to be read by the client or/and written to a file
[1025]1136       if (enableOutput && !storeFilter && !fileWriterFilter)
1137       {
1138         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
1139         {
[1542]1140           fileServerWriterFilter = std::shared_ptr<CFileServerWriterFilter>(new CFileServerWriterFilter(gc, this));
[1025]1141           instantDataFilter->connectOutput(fileServerWriterFilter, 0);
1142         }
1143       }
1144     }
1145     else if (hasIntermediateServer)
1146     {
1147       if (!instantDataFilter)
[1637]1148         instantDataFilter = clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, false, false));
[1025]1149
1150             // If the field data is to be read by the client or/and written to a file
1151       if (enableOutput && !storeFilter && !fileWriterFilter)
1152       {
1153         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
1154         {
[1542]1155           fileWriterFilter = std::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
[1025]1156           instantDataFilter->connectOutput(fileWriterFilter, 0);
1157         }
1158       }
1159     }
1160     else
1161     {
1162       // Start by building a filter which can provide the field's instant data
1163       if (!instantDataFilter)
1164       {
1165         // Check if we have an expression to parse
[1158]1166         if (hasExpression())
[1025]1167         {
[1158]1168           boost::scoped_ptr<IFilterExprNode> expr(parseExpr(getExpression() + '\0'));
[1542]1169           std::shared_ptr<COutputPin> filter = expr->reduce(gc, *this);
[1021]1170
[1158]1171           // Check if a spatial transformation is needed
1172           if (!field_ref.isEmpty())
[1021]1173           {
[1158]1174             CGrid* gridRef = CField::get(field_ref)->grid;
[1021]1175
[1158]1176             if (grid && grid != gridRef && grid->hasTransform())
1177             {
[1542]1178                 std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters = CSpatialTransformFilter::buildFilterGraph(gc, gridRef, grid, detectMissingValues, defaultValue); 
[1158]1179
1180               filter->connectOutput(filters.first, 0);
1181               filter = filters.second;
1182             }
[1021]1183           }
1184
[1158]1185           instantDataFilter = filter;
[1025]1186         }
1187         // Check if we have a reference on another field
1188         else if (!field_ref.isEmpty())
1189           instantDataFilter = getFieldReference(gc);
1190         // Check if the data is to be read from a file
1191         else if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
[1319]1192         {
[1405]1193           checkTimeAttributes();
[1637]1194           instantDataFilter = serverSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, false, freq_offset, true,
[1201]1195                                                                                                       detectMissingValues, defaultValue));
[1319]1196         }
[1025]1197         else // The data might be passed from the model
[1158]1198         {
[1201]1199            if (check_if_active.isEmpty()) check_if_active = false; 
[1637]1200            instantDataFilter = clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, false, true, NoneDu, false,
[1201]1201                                                                                                        detectMissingValues, defaultValue));
[1158]1202         }
[1025]1203       }
[640]1204
[1166]1205       // If the field data is to be read by the client or/and written to a file
1206       if (enableOutput && !storeFilter && !fileWriterFilter)
[640]1207       {
[1248]1208         if (!read_access.isEmpty() && read_access)
1209         {
[1542]1210           storeFilter = std::shared_ptr<CStoreFilter>(new CStoreFilter(gc, CContext::getCurrent(), grid,
[1248]1211                                                                          detectMissingValues, defaultValue));
1212           instantDataFilter->connectOutput(storeFilter, 0);
1213         }
[640]1214
[1248]1215         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
1216         {
[1542]1217           fileWriterFilter = std::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
[1248]1218           getTemporalDataFilter(gc, file->output_freq)->connectOutput(fileWriterFilter, 0);
1219         }
[640]1220       }
1221     }
1222   }
[1622]1223   CATCH_DUMP_ATTR
[640]1224
[642]1225   /*!
[737]1226    * Returns the filter needed to handle the field reference.
1227    * This method should only be called when building the filter graph corresponding to the field.
1228    *
1229    * \param gc the garbage collector to use
1230    * \return the output pin corresponding to the field reference
1231    */
[1542]1232   std::shared_ptr<COutputPin> CField::getFieldReference(CGarbageCollector& gc)
[1622]1233   TRY
[1158]1234   {
1235     if (instantDataFilter || field_ref.isEmpty())
1236       ERROR("COutputPin* CField::getFieldReference(CGarbageCollector& gc)",
1237             "Impossible to get the field reference for a field which has already been parsed or which does not have a field_ref.");
[737]1238
[1158]1239     CField* fieldRef = CField::get(field_ref);
1240     fieldRef->buildFilterGraph(gc, false);
[737]1241
[1542]1242     std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters;
[1158]1243     // Check if a spatial transformation is needed
1244     if (grid && grid != fieldRef->grid && grid->hasTransform())
1245     {       
1246       bool hasMissingValue = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1247       double defaultValue  = hasMissingValue ? default_value : (!default_value.isEmpty() ? default_value : 0.0);                               
1248       filters = CSpatialTransformFilter::buildFilterGraph(gc, fieldRef->grid, grid, hasMissingValue, defaultValue);
1249     }
1250     else
[1542]1251       filters.first = filters.second = std::shared_ptr<CFilter>(new CPassThroughFilter(gc));
[873]1252
[1158]1253     fieldRef->getInstantDataFilter()->connectOutput(filters.first, 0);
[737]1254
[1158]1255     return filters.second;
1256   }
[1622]1257   CATCH_DUMP_ATTR
[737]1258
1259   /*!
1260    * Returns the filter needed to handle a self reference in the field's expression.
1261    * If the needed filter does not exist, it is created, otherwise it is reused.
[642]1262    * This method should only be called when building the filter graph corresponding
1263    * to the field's expression.
1264    *
1265    * \param gc the garbage collector to use
1266    * \return the output pin corresponding to a self reference
1267    */
[1542]1268   std::shared_ptr<COutputPin> CField::getSelfReference(CGarbageCollector& gc)
[1622]1269   TRY
[642]1270   {
[1021]1271     if (instantDataFilter || !hasExpression())
[642]1272       ERROR("COutputPin* CField::getSelfReference(CGarbageCollector& gc)",
1273             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1274
[737]1275     if (!selfReferenceFilter)
1276     {
[1201]1277       const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1278       const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
1279
[741]1280       if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
1281       {
1282         if (!serverSourceFilter)
[1319]1283         {
[1405]1284           checkTimeAttributes();
[1637]1285           serverSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, false, freq_offset, true,
[1201]1286                                                                                   detectMissingValues, defaultValue));
[1319]1287         }
[1201]1288
[741]1289         selfReferenceFilter = serverSourceFilter;
1290       }
1291       else if (!field_ref.isEmpty())
[1021]1292       {
1293         CField* fieldRef = CField::get(field_ref);
1294         fieldRef->buildFilterGraph(gc, false);
1295         selfReferenceFilter = fieldRef->getInstantDataFilter();
1296       }
[737]1297       else
1298       {
1299         if (!clientSourceFilter)
[1158]1300         {
[1201]1301           if (check_if_active.isEmpty()) check_if_active = false;
[1637]1302           clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, true, NoneDu, false,
[1201]1303                                                                                   detectMissingValues, defaultValue));
[1158]1304         }
[642]1305
[737]1306         selfReferenceFilter = clientSourceFilter;
1307       }
1308     }
1309
1310     return selfReferenceFilter;
[642]1311   }
[1622]1312   CATCH_DUMP_ATTR
[642]1313
[643]1314   /*!
1315    * Returns the temporal filter corresponding to the field's temporal operation
1316    * for the specified operation frequency. The filter is created if it does not
1317    * exist, otherwise it is reused.
1318    *
1319    * \param gc the garbage collector to use
1320    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1321    * \return the output pin corresponding to the requested temporal filter
1322    */
[1542]1323   std::shared_ptr<COutputPin> CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
[1622]1324   TRY
[643]1325   {
[1542]1326     std::map<CDuration, std::shared_ptr<COutputPin> >::iterator it = temporalDataFilters.find(outFreq);
[643]1327
1328     if (it == temporalDataFilters.end())
1329     {
1330       if (operation.isEmpty())
1331         ERROR("void CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1332               << "An operation must be defined for field \"" << getId() << "\".");
1333
[1405]1334       checkTimeAttributes(&outFreq);
[1315]1335
[1440]1336       const bool detectMissingValues = (!detect_missing_value.isEmpty()  && detect_missing_value == true);
[1542]1337       std::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
[643]1338                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
[1440]1339                                                                             freq_op, freq_offset, outFreq, detectMissingValues));
[1278]1340
[643]1341       instantDataFilter->connectOutput(temporalFilter, 0);
1342
1343       it = temporalDataFilters.insert(std::make_pair(outFreq, temporalFilter)).first;
1344     }
1345
1346     return it->second;
1347   }
[1622]1348   CATCH_DUMP_ATTR
[643]1349
[1158]1350  /*!
1351    * Returns the temporal filter corresponding to the field's temporal operation
1352    * for the specified operation frequency.
1353    *
1354    * \param gc the garbage collector to use
1355    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1356    * \return the output pin corresponding to the requested temporal filter
1357    */
1358   
[1542]1359   std::shared_ptr<COutputPin> CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
[1622]1360   TRY
[1158]1361   {
1362     if (instantDataFilter || !hasExpression())
1363       ERROR("COutputPin* CField::getSelfTemporalDataFilter(CGarbageCollector& gc)",
1364             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1365
1366     if (!selfReferenceFilter) getSelfReference(gc) ;
1367
1368     if (serverSourceFilter || clientSourceFilter)
1369     {
1370       if (operation.isEmpty())
1371         ERROR("void CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1372               << "An operation must be defined for field \"" << getId() << "\".");
1373
[1405]1374       checkTimeAttributes(&outFreq);
[1315]1375
[1440]1376       const bool detectMissingValues = (!detect_missing_value.isEmpty() && detect_missing_value == true);
[1542]1377       std::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
[1158]1378                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
[1440]1379                                                                             freq_op, freq_offset, outFreq, detectMissingValues));
[1278]1380
[1158]1381       selfReferenceFilter->connectOutput(temporalFilter, 0);
1382       return temporalFilter ;
1383     }
1384     else if (!field_ref.isEmpty())
1385     {
1386       CField* fieldRef = CField::get(field_ref);
1387       fieldRef->buildFilterGraph(gc, false); 
1388       return fieldRef->getTemporalDataFilter(gc, outFreq) ;
1389     }
1390  }
[1622]1391   CATCH_DUMP_ATTR
[1158]1392
[640]1393   //----------------------------------------------------------------
[369]1394/*
[562]1395   void CField::fromBinary(StdIStream& is)
[219]1396   {
1397      SuperClass::fromBinary(is);
1398#define CLEAR_ATT(name_)\
[369]1399      SuperClassAttribute::operator[](#name_)->reset()
[219]1400
1401         CLEAR_ATT(domain_ref);
1402         CLEAR_ATT(axis_ref);
1403#undef CLEAR_ATT
1404
1405   }
[369]1406*/
[219]1407   //----------------------------------------------------------------
1408
1409   void CField::solveGridReference(void)
[1622]1410   TRY
[219]1411   {
[887]1412      if (grid_ref.isEmpty() && domain_ref.isEmpty() && axis_ref.isEmpty() && scalar_ref.isEmpty())
[742]1413      {
1414        ERROR("CField::solveGridReference(void)",
[770]1415              << "A grid must be defined for field '" << getFieldOutputName() << "' .");
[742]1416      }
[887]1417      else if (!grid_ref.isEmpty() && (!domain_ref.isEmpty() || !axis_ref.isEmpty() || !scalar_ref.isEmpty()))
[219]1418      {
[744]1419        ERROR("CField::solveGridReference(void)",
[887]1420              << "Field '" << getFieldOutputName() << "' has both a grid and a domain/axis/scalar." << std::endl
1421              << "Please define either 'grid_ref' or 'domain_ref'/'axis_ref'/'scalar_ref'.");
[219]1422      }
1423
[744]1424      if (grid_ref.isEmpty())
[219]1425      {
[744]1426        std::vector<CDomain*> vecDom;
1427        std::vector<CAxis*> vecAxis;
[887]1428        std::vector<CScalar*> vecScalar;
[894]1429        std::vector<int> axisDomainOrderTmp;
[1524]1430
1431        std::vector<CDomain*> vecDomRef;
1432        std::vector<CAxis*> vecAxisRef;
1433        std::vector<CScalar*> vecScalarRef;
1434
[894]1435       
[744]1436        if (!domain_ref.isEmpty())
1437        {
[823]1438          StdString tmp = domain_ref.getValue();
[744]1439          if (CDomain::has(domain_ref))
[894]1440          {
[744]1441            vecDom.push_back(CDomain::get(domain_ref));
[1524]1442            vecDomRef.push_back(CDomain::createDomain());
1443            vecDomRef.back()->domain_ref=domain_ref;
[894]1444            axisDomainOrderTmp.push_back(2);
1445          }
[1524]1446          else  ERROR("CField::solveGridReference(void)",
1447                      << "Invalid reference to domain '" << domain_ref.getValue() << "'.");
[744]1448        }
[219]1449
[744]1450        if (!axis_ref.isEmpty())
[742]1451        {
[744]1452          if (CAxis::has(axis_ref))
[894]1453          {
[744]1454            vecAxis.push_back(CAxis::get(axis_ref));
[1524]1455            vecAxisRef.push_back(CAxis::createAxis());
1456            vecAxisRef.back()->axis_ref=axis_ref;
[894]1457            axisDomainOrderTmp.push_back(1);
1458          }
[1524]1459          else  ERROR("CField::solveGridReference(void)",
1460                      << "Invalid reference to axis '" << axis_ref.getValue() << "'.");
[742]1461        }
[744]1462
[887]1463        if (!scalar_ref.isEmpty())
1464        {
1465          if (CScalar::has(scalar_ref))
[894]1466          {
[887]1467            vecScalar.push_back(CScalar::get(scalar_ref));
[1524]1468            vecScalarRef.push_back(CScalar::createScalar());
1469            vecScalarRef.back()->scalar_ref=scalar_ref;
[894]1470            axisDomainOrderTmp.push_back(0);
1471          }
[1524]1472          else ERROR("CField::solveGridReference(void)",
1473                     << "Invalid reference to scalar '" << scalar_ref.getValue() << "'.");
[887]1474        }
[894]1475       
1476        CArray<int,1> axisDomainOrder(axisDomainOrderTmp.size());
1477        for (int idx = 0; idx < axisDomainOrderTmp.size(); ++idx)
1478        {
1479          axisDomainOrder(idx) = axisDomainOrderTmp[idx];
1480        }
[887]1481
[745]1482        // Warning: the gridId shouldn't be set as the grid_ref since it could be inherited
[894]1483        StdString gridId = CGrid::generateId(vecDom, vecAxis, vecScalar,axisDomainOrder);
[1524]1484        if (CGrid::has(gridId)) this->grid = CGrid::get(gridId);
1485        else  this->grid = CGrid::createGrid(gridId, vecDomRef, vecAxisRef, vecScalarRef,axisDomainOrder);
[219]1486      }
[586]1487      else
1488      {
[1524]1489        if (CGrid::has(grid_ref)) this->grid = CGrid::get(grid_ref);
1490        else  ERROR("CField::solveGridReference(void)",
1491                     << "Invalid reference to grid '" << grid_ref.getValue() << "'.");
[586]1492      }
[509]1493   }
[1622]1494   CATCH_DUMP_ATTR
[459]1495
[509]1496   void CField::solveGridDomainAxisRef(bool checkAtt)
[1622]1497   TRY
[509]1498   {
1499     grid->solveDomainAxisRef(checkAtt);
[219]1500   }
[1622]1501   CATCH_DUMP_ATTR
[219]1502
[509]1503   void CField::solveCheckMaskIndex(bool doSendingIndex)
[1622]1504   TRY
[509]1505   {
1506     grid->checkMaskIndex(doSendingIndex);
1507   }
[1622]1508   CATCH_DUMP_ATTR
[219]1509
[619]1510   void CField::solveTransformedGrid()
[1622]1511   TRY
[619]1512   {
[746]1513     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
[790]1514     {
1515       std::vector<CGrid*> grids;
1516       // Source grid
1517       grids.push_back(getDirectFieldReference()->grid);
1518       // Intermediate grids
1519       if (!grid_path.isEmpty())
1520       {
1521         std::string gridId;
1522         size_t start = 0, end;
1523
1524         do
1525         {
1526           end = grid_path.getValue().find(',', start);
1527           if (end != std::string::npos)
1528           {
1529             gridId = grid_path.getValue().substr(start, end - start);
1530             start = end + 1;
1531           }
1532           else
1533             gridId = grid_path.getValue().substr(start);
1534
1535           if (!CGrid::has(gridId))
1536             ERROR("void CField::solveTransformedGrid()",
1537                   << "Invalid grid_path, the grid '" << gridId << "' does not exist.");
1538
1539           grids.push_back(CGrid::get(gridId));
1540         }
1541         while (end != std::string::npos);
1542       }
1543       // Destination grid
1544       grids.push_back(grid);
1545
1546       for (size_t i = 0, count = grids.size() - 1; i < count; ++i)
1547       {
1548         CGrid *gridSrc  = grids[i];
1549         CGrid *gridDest = grids[i + 1];
1550         if (!gridDest->isTransformed())
1551           gridDest->transformGrid(gridSrc);
1552       }
1553     }
[934]1554     else if (grid && grid->hasTransform() && !grid->isTransformed())
1555     {
[1021]1556       // Temporarily deactivate the self-transformation of grid
[1386]1557       // grid->transformGrid(grid);
[934]1558     }
[619]1559   }
[1622]1560   CATCH_DUMP_ATTR
[619]1561
[687]1562   void CField::solveGenerateGrid()
[1622]1563   TRY
[687]1564   {
[746]1565     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
[687]1566       grid->completeGrid(getDirectFieldReference()->grid);
[775]1567     else
1568       grid->completeGrid();
[687]1569   }
[1622]1570   CATCH_DUMP_ATTR
[687]1571
[775]1572   void CField::solveGridDomainAxisBaseRef()
[1622]1573   TRY
[775]1574   {
1575     grid->solveDomainAxisRef(false);
1576     grid->solveDomainAxisBaseRef();
1577   }
[1622]1578   CATCH_DUMP_ATTR
[775]1579
[219]1580   ///-------------------------------------------------------------------
1581
1582   template <>
[562]1583   void CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)
[1622]1584   TRY
[219]1585   {
1586      if (this->group_ref.isEmpty()) return;
1587      StdString gref = this->group_ref.getValue();
1588
[346]1589      if (!CFieldGroup::has(gref))
[219]1590         ERROR("CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)",
1591               << "[ gref = " << gref << "]"
1592               << " invalid group name !");
1593
[347]1594      CFieldGroup* group = CFieldGroup::get(gref);
1595      CFieldGroup* owner = CFieldGroup::get(boost::polymorphic_downcast<CFieldGroup*>(this));
[1574]1596      owner->setAttributes(group); // inherite of attributes of group reference
1597     
[347]1598      std::vector<CField*> allChildren  = group->getAllChildren();
[562]1599      std::vector<CField*>::iterator it = allChildren.begin(), end = allChildren.end();
[509]1600
[219]1601      for (; it != end; it++)
1602      {
[347]1603         CField* child = *it;
[562]1604         if (child->hasId()) owner->createChild()->field_ref.setValue(child->getId());
[509]1605
[219]1606      }
1607   }
[1622]1608   CATCH_DUMP_ATTR
[509]1609
[464]1610   void CField::scaleFactorAddOffset(double scaleFactor, double addOffset)
[1622]1611   TRY
[464]1612   {
[1136]1613     recvDataSrv = (recvDataSrv - addOffset) / scaleFactor;
[464]1614   }
[1622]1615   CATCH_DUMP_ATTR
[509]1616
[599]1617   void CField::invertScaleFactorAddOffset(double scaleFactor, double addOffset)
[1622]1618   TRY
[599]1619   {
[1136]1620     recvDataSrv = recvDataSrv * scaleFactor + addOffset;
[599]1621   }
[1622]1622   CATCH_DUMP_ATTR
[599]1623
[567]1624   void CField::outputField(CArray<double,1>& fieldOut)
[1622]1625   TRY
[1136]1626   { 
[1129]1627      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1628      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1629      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1630      {
1631        fieldOut(outIndexServer(idx)) = recvDataSrv(outIndexClient(idx));
1632      }
[1136]1633   }
[1622]1634   CATCH_DUMP_ATTR
[1129]1635
[1136]1636   void CField::inputField(CArray<double,1>& fieldIn)
[1622]1637   TRY
[1136]1638   {
1639      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1640      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1641      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
[599]1642      {
[1136]1643        recvDataSrv(outIndexClient(idx)) = fieldIn(outIndexServer(idx));
[599]1644      }
1645   }
[1622]1646   CATCH_DUMP_ATTR
[599]1647
[676]1648   void CField::outputCompressedField(CArray<double,1>& fieldOut)
[1622]1649   TRY
[676]1650   {
[1143]1651      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1652      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1653      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
[676]1654      {
[1143]1655        fieldOut((idx)) = recvDataSrv(outIndexClient(idx));
[676]1656      }
1657   }
[1622]1658   CATCH_DUMP_ATTR
[676]1659
[219]1660   ///-------------------------------------------------------------------
1661
[562]1662   void CField::parse(xml::CXMLNode& node)
[1622]1663   TRY
[459]1664   {
[1363]1665      string newContent ;
[459]1666      SuperClass::parse(node);
[1363]1667      if (node.goToChildElement())
[472]1668      {
[1363]1669        do
[472]1670        {
[1363]1671          if (node.getElementName() == "variable" || node.getElementName() == "variable_group") this->getVirtualVariableGroup()->parseChild(node);
1672          else if (node.getElementName() == "expr") if (node.getContent(newContent)) content+=newContent ;
1673        } while (node.goToNextElement());
1674        node.goToParentElement();
[472]1675      }
[1363]1676      if (node.getContent(newContent)) content=newContent ;
[459]1677    }
[1622]1678   CATCH_DUMP_ATTR
[509]1679
1680   /*!
1681     This function retrieves Id of corresponding domain_ref and axis_ref (if any)
1682   of a field. In some cases, only domain exists but axis doesn't
1683   \return pair of Domain and Axis id
1684   */
[887]1685   const std::vector<StdString>& CField::getRefDomainAxisIds()
[1622]1686   TRY
[569]1687   {
1688     CGrid* cgPtr = getRelGrid();
1689     if (NULL != cgPtr)
1690     {
1691       std::vector<StdString>::iterator it;
1692       if (!domain_ref.isEmpty())
1693       {
1694         std::vector<StdString> domainList = cgPtr->getDomainList();
1695         it = std::find(domainList.begin(), domainList.end(), domain_ref.getValue());
[887]1696         if (domainList.end() != it) domAxisScalarIds_[0] = *it;
[569]1697       }
[472]1698
[569]1699       if (!axis_ref.isEmpty())
1700       {
1701         std::vector<StdString> axisList = cgPtr->getAxisList();
1702         it = std::find(axisList.begin(), axisList.end(), axis_ref.getValue());
[887]1703         if (axisList.end() != it) domAxisScalarIds_[1] = *it;
[569]1704       }
[887]1705
1706       if (!scalar_ref.isEmpty())
1707       {
1708         std::vector<StdString> scalarList = cgPtr->getScalarList();
1709         it = std::find(scalarList.begin(), scalarList.end(), scalar_ref.getValue());
1710         if (scalarList.end() != it) domAxisScalarIds_[2] = *it;
1711       }
[569]1712     }
[887]1713     return (domAxisScalarIds_);
[569]1714   }
[1622]1715   CATCH_DUMP_ATTR
[569]1716
[472]1717   CVariable* CField::addVariable(const string& id)
[1622]1718   TRY
[472]1719   {
[562]1720     return vVariableGroup->createChild(id);
[472]1721   }
[1622]1722   CATCH
[472]1723
1724   CVariableGroup* CField::addVariableGroup(const string& id)
[1622]1725   TRY
[472]1726   {
[562]1727     return vVariableGroup->createChildGroup(id);
[472]1728   }
[1622]1729   CATCH
[472]1730
[1294]1731   void CField::setContextClient(CContextClient* contextClient)
[1622]1732   TRY
[1294]1733   {
[1344]1734     CContext* context = CContext::getCurrent();
[1294]1735     client = contextClient;
[1344]1736     if (context->hasClient)
1737     {
1738       // A grid is sent by a client (both for read or write) or by primary server (write only)
1739       if (context->hasServer)
1740       {
1741         if (file->mode.isEmpty() || (!file->mode.isEmpty() && file->mode == CFile::mode_attr::write))
1742           grid->setContextClient(contextClient);
1743       }
1744       else
1745           grid->setContextClient(contextClient);
1746     }
[1294]1747   }
[1622]1748   CATCH_DUMP_ATTR
[1294]1749
1750   CContextClient* CField::getContextClient()
[1622]1751   TRY
[1294]1752   {
1753     return client;
1754   }
[1622]1755   CATCH
[1294]1756
[1021]1757   void CField::sendAddAllVariables(CContextClient* client)
[1622]1758   TRY
[1009]1759   {
1760     std::vector<CVariable*> allVar = getAllVariables();
1761     std::vector<CVariable*>::const_iterator it = allVar.begin();
1762     std::vector<CVariable*>::const_iterator itE = allVar.end();
1763
1764     for (; it != itE; ++it)
1765     {
[1021]1766       this->sendAddVariable((*it)->getId(), client);
1767       (*it)->sendAllAttributesToServer(client);
1768       (*it)->sendValue(client);
[1009]1769     }
1770   }
[1622]1771   CATCH_DUMP_ATTR
[1009]1772
[1524]1773   /*!
1774    * Send all Attributes to server. This method is overloaded, since only grid_ref attribute
1775    * must be sent to server and not domain_ref/axis_ref/scalar_ref.
1776    */
1777   
1778   void CField::sendAllAttributesToServer(CContextClient* client)
[1622]1779   TRY
[1524]1780   {
1781     if (grid_ref.isEmpty())
1782     {
1783       grid_ref=grid->getId() ;
1784       SuperClass::sendAllAttributesToServer(client) ;
1785       grid_ref.reset();
1786     }
1787     else SuperClass::sendAllAttributesToServer(client) ;
1788   }
[1622]1789   CATCH_DUMP_ATTR
[1524]1790   
[1021]1791   void CField::sendAddVariable(const string& id, CContextClient* client)
[1622]1792   TRY
[1021]1793   {
1794      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE, client);
1795   }
[1622]1796   CATCH_DUMP_ATTR
[1021]1797
[1144]1798   void CField::sendAddVariableGroup(const string& id, CContextClient* client)
[1622]1799   TRY
[472]1800   {
[1144]1801      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE_GROUP, client);
[472]1802   }
[1622]1803   CATCH_DUMP_ATTR
[509]1804
[472]1805   void CField::recvAddVariable(CEventServer& event)
[1622]1806   TRY
[472]1807   {
[509]1808
[562]1809      CBufferIn* buffer = event.subEvents.begin()->buffer;
[472]1810      string id;
[562]1811      *buffer >> id;
1812      get(id)->recvAddVariable(*buffer);
[472]1813   }
[1622]1814   CATCH
[509]1815
[472]1816   void CField::recvAddVariable(CBufferIn& buffer)
[1622]1817   TRY
[472]1818   {
[562]1819      string id;
1820      buffer >> id;
1821      addVariable(id);
[472]1822   }
[1622]1823   CATCH_DUMP_ATTR
[472]1824
1825   void CField::recvAddVariableGroup(CEventServer& event)
[1622]1826   TRY
[472]1827   {
[509]1828
[562]1829      CBufferIn* buffer = event.subEvents.begin()->buffer;
[472]1830      string id;
[562]1831      *buffer >> id;
1832      get(id)->recvAddVariableGroup(*buffer);
[472]1833   }
[1622]1834   CATCH
[509]1835
[472]1836   void CField::recvAddVariableGroup(CBufferIn& buffer)
[1622]1837   TRY
[472]1838   {
[562]1839      string id;
1840      buffer >> id;
1841      addVariableGroup(id);
[472]1842   }
[1622]1843   CATCH_DUMP_ATTR
[472]1844
[1021]1845   /*!
[1278]1846    * Check on freq_off and freq_op attributes.
1847    */
[1405]1848   void CField::checkTimeAttributes(CDuration* freqOp)
[1622]1849   TRY
[1278]1850   {
[1405]1851     bool isFieldRead  = file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read;
1852     bool isFieldWrite = file && ( file->mode.isEmpty() ||  file->mode == CFile::mode_attr::write);
[1514]1853     if (isFieldRead && !(operation.getValue() == "instant" || operation.getValue() == "once") )     
[1405]1854       ERROR("void CField::checkTimeAttributes(void)",
[1315]1855             << "Unsupported operation for field '" << getFieldOutputName() << "'." << std::endl
1856             << "Currently only \"instant\" is supported for fields read from file.")
1857
[1278]1858     if (freq_op.isEmpty())
1859     {
[1315]1860       if (operation.getValue() == "instant")
[1405]1861       {
1862         if (isFieldRead || isFieldWrite) freq_op.setValue(file->output_freq.getValue());
1863         else freq_op=*freqOp ;
1864       }
[1278]1865       else
[1292]1866         freq_op.setValue(TimeStep);
[1278]1867     }
[1306]1868     if (freq_offset.isEmpty())
[1315]1869       freq_offset.setValue(isFieldRead ? NoneDu : (freq_op.getValue() - TimeStep));
[1278]1870   }
[1622]1871   CATCH_DUMP_ATTR
[1278]1872
1873   /*!
[1021]1874    * Returns string arithmetic expression associated to the field.
1875    * \return if content is defined return content string, otherwise, if "expr" attribute is defined, return expr string.
1876    */
1877   const string& CField::getExpression(void)
[1622]1878   TRY
[1021]1879   {
1880     if (!expr.isEmpty() && content.empty())
1881     {
1882       content = expr;
1883       expr.reset();
1884     }
1885
1886     return content;
1887   }
[1622]1888   CATCH_DUMP_ATTR
[1021]1889
1890   bool CField::hasExpression(void) const
[1622]1891   TRY
[1021]1892   {
1893     return (!expr.isEmpty() || !content.empty());
1894   }
[1622]1895   CATCH
[1021]1896
[1637]1897   bool CField::hasGridMask(void) const
1898   TRY
1899   {
1900     return (this->grid->hasMask());
1901   }
1902   CATCH
1903
[540]1904   DEFINE_REF_FUNC(Field,field)
[335]1905} // namespace xios
Note: See TracBrowser for help on using the repository browser.