source: XIOS/dev/dev_olga/src/node/field.cpp @ 1612

Last change on this file since 1612 was 1612, checked in by oabramkina, 5 years ago

Dev: adding exception handling.

To activate it, compilation flag -DXIOS_EXCEPTION should be added.

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