source: XIOS/dev/branch_openmp/src/node/field.cpp @ 1642

Last change on this file since 1642 was 1642, checked in by yushan, 6 years ago

dev on ADA. add flag switch _usingEP/_usingMPI

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