source: XIOS/trunk/src/node/field.cpp @ 2133

Last change on this file since 2133 was 2131, checked in by oabramkina, 3 years ago

Merging branch dev_oa with tiling into trunk

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