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

Last change on this file since 1972 was 1920, checked in by yushan, 4 years ago

trunk : raise error if freq_op > output_freq

  • 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.2 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);
1126
1127     
[1201]1128     const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
1129
[1025]1130     CContext* context = CContext::getCurrent();
[1704]1131     
1132     Time filter_start;
1133     if(!build_workflow_graph_start.isEmpty() && buildWorkflowGraph) filter_start = context->calendar->getInitDate()+build_workflow_graph_start;
1134     else if(build_workflow_graph_start.isEmpty() && buildWorkflowGraph) filter_start = 0;
1135     else filter_start = -1;
1136
1137     Time filter_end;
1138     if(!build_workflow_graph_end.isEmpty() && buildWorkflowGraph) filter_end = context->calendar->getInitDate()+build_workflow_graph_end;
1139     else if(build_workflow_graph_end.isEmpty() && buildWorkflowGraph) filter_end = 9223372036854775807;
1140     else filter_end = -1;
1141
1142     if(this->field_graph_start==-2) this->field_graph_start = filter_start;
1143     if(this->field_graph_end==-2) this->field_graph_end = filter_end;         // init
1144
1145
1146     if(start_graph == -1)
1147     {
1148       //nothing
1149     }
1150     else //if(start_graph != -1)
1151     {
1152       if(this->field_graph_start == -1) this->field_graph_start = start_graph;
1153       else this->field_graph_start = min(this->field_graph_start, start_graph);
1154     }
1155
1156
1157     if(end_graph == -1)
1158     {
1159       //nothing
1160     }
1161     else
1162     {
1163       if(this->field_graph_end == -1) this->field_graph_end = end_graph;
1164       else this->field_graph_end = max(this->field_graph_end, end_graph);
1165
1166     }
1167   
1168
1169     filter_start = this->field_graph_start;
1170     filter_end = this->field_graph_end;
1171
1172     
1173
[1025]1174     bool hasWriterServer = context->hasServer && !context->hasClient;
1175     bool hasIntermediateServer = context->hasServer && context->hasClient;
[641]1176
[1025]1177     if (hasWriterServer)
[640]1178     {
[1025]1179        if (!instantDataFilter)
[1637]1180          instantDataFilter = clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, false));
[1025]1181
[1294]1182
1183       // If the field data is to be read by the client or/and written to a file
[1025]1184       if (enableOutput && !storeFilter && !fileWriterFilter)
1185       {
1186         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
1187         {
[1542]1188           fileServerWriterFilter = std::shared_ptr<CFileServerWriterFilter>(new CFileServerWriterFilter(gc, this));
[1025]1189           instantDataFilter->connectOutput(fileServerWriterFilter, 0);
1190         }
1191       }
1192     }
1193     else if (hasIntermediateServer)
1194     {
1195       if (!instantDataFilter)
[1637]1196         instantDataFilter = clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, false, false));
[1025]1197
1198             // If the field data is to be read by the client or/and written to a file
1199       if (enableOutput && !storeFilter && !fileWriterFilter)
1200       {
1201         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
1202         {
[1542]1203           fileWriterFilter = std::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
[1025]1204           instantDataFilter->connectOutput(fileWriterFilter, 0);
1205         }
1206       }
1207     }
1208     else
1209     {
1210       // Start by building a filter which can provide the field's instant data
1211       if (!instantDataFilter)
1212       {
1213         // Check if we have an expression to parse
[1158]1214         if (hasExpression())
[1025]1215         {
[1158]1216           boost::scoped_ptr<IFilterExprNode> expr(parseExpr(getExpression() + '\0'));
[1704]1217           std::shared_ptr<COutputPin> filter = expr->reduce(gc, *this, filter_start, filter_end);
[1021]1218
[1158]1219           // Check if a spatial transformation is needed
1220           if (!field_ref.isEmpty())
[1021]1221           {
[1158]1222             CGrid* gridRef = CField::get(field_ref)->grid;
[1021]1223
[1158]1224             if (grid && grid != gridRef && grid->hasTransform())
1225             {
[1704]1226               std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters = CSpatialTransformFilter::buildFilterGraph(gc, gridRef, grid, detectMissingValues, defaultValue);
[1158]1227
1228               filter->connectOutput(filters.first, 0);
1229               filter = filters.second;
1230             }
[1021]1231           }
1232
[1158]1233           instantDataFilter = filter;
[1704]1234           instantDataFilter->field = this;
1235           filter->tag = buildWorkflowGraph;
1236           
1237           filter->start_graph = filter_start;
1238           filter->end_graph = filter_end;
1239
1240           for(int i=0; i<filter->parent_filters.size(); i++)
1241           {
1242             filter->tag = filter->tag || filter->parent_filters[i]->tag;
1243           }
[1025]1244         }
1245         // Check if we have a reference on another field
1246         else if (!field_ref.isEmpty())
[1704]1247         {
1248           instantDataFilter = getFieldReference(gc, filter_start, filter_end);
1249           instantDataFilter->tag = buildWorkflowGraph;
1250           instantDataFilter->start_graph = filter_start;
1251           instantDataFilter->end_graph = filter_end;
1252         }
[1025]1253         // Check if the data is to be read from a file
1254         else if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
[1319]1255         {
[1405]1256           checkTimeAttributes();
[1637]1257           instantDataFilter = serverSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, false, freq_offset, true,
[1201]1258                                                                                                       detectMissingValues, defaultValue));
[1704]1259           instantDataFilter->tag = buildWorkflowGraph;
1260           instantDataFilter->start_graph = filter_start;
1261           instantDataFilter->end_graph = filter_end;
1262           instantDataFilter->field = this;
1263
[1319]1264         }
[1025]1265         else // The data might be passed from the model
[1158]1266         {
[1201]1267            if (check_if_active.isEmpty()) check_if_active = false; 
[1637]1268            instantDataFilter = clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, false, true, NoneDu, false,
[1704]1269                                                                                                      detectMissingValues, defaultValue)); 
1270            instantDataFilter->tag = buildWorkflowGraph;
1271            instantDataFilter->start_graph = filter_start;
1272            instantDataFilter->end_graph = filter_end;
1273            instantDataFilter->field = this;
[1158]1274         }
[1025]1275       }
[640]1276
[1166]1277       // If the field data is to be read by the client or/and written to a file
1278       if (enableOutput && !storeFilter && !fileWriterFilter)
[640]1279       {
[1248]1280         if (!read_access.isEmpty() && read_access)
1281         {
[1542]1282           storeFilter = std::shared_ptr<CStoreFilter>(new CStoreFilter(gc, CContext::getCurrent(), grid,
[1248]1283                                                                          detectMissingValues, defaultValue));
1284           instantDataFilter->connectOutput(storeFilter, 0);
[1704]1285
1286           storeFilter->tag = (instantDataFilter->tag || buildWorkflowGraph);
1287           instantDataFilter->start_graph = filter_start;
1288           instantDataFilter->end_graph = filter_end;
1289
1290           instantDataFilter->setParentFiltersTag();
1291           storeFilter->start_graph = filter_start;
1292           storeFilter->end_graph = filter_end;
1293           storeFilter->field = this;
1294           storeFilter->distance = instantDataFilter->distance+1;
[1248]1295         }
[640]1296
[1248]1297         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
1298         {
[1542]1299           fileWriterFilter = std::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
[1248]1300           getTemporalDataFilter(gc, file->output_freq)->connectOutput(fileWriterFilter, 0);
[1704]1301           
1302           fileWriterFilter->tag = (getTemporalDataFilter(gc, file->output_freq)->tag || buildWorkflowGraph);
1303           getTemporalDataFilter(gc, file->output_freq)->start_graph = filter_start;
1304           getTemporalDataFilter(gc, file->output_freq)->end_graph = filter_end;
1305           getTemporalDataFilter(gc, file->output_freq)->tag = buildWorkflowGraph;
1306           getTemporalDataFilter(gc, file->output_freq)->setParentFiltersTag();
1307           fileWriterFilter->start_graph = filter_start;
1308           fileWriterFilter->end_graph = filter_end;
1309           fileWriterFilter->distance = getTemporalDataFilter(gc, file->output_freq)->distance+1;
1310
1311
[1248]1312         }
[640]1313       }
1314     }
1315   }
[1622]1316   CATCH_DUMP_ATTR
[640]1317
[642]1318   /*!
[737]1319    * Returns the filter needed to handle the field reference.
1320    * This method should only be called when building the filter graph corresponding to the field.
1321    *
1322    * \param gc the garbage collector to use
1323    * \return the output pin corresponding to the field reference
1324    */
[1704]1325   std::shared_ptr<COutputPin> CField::getFieldReference(CGarbageCollector& gc, Time start_graph, Time end_graph)
[1622]1326   TRY
[1158]1327   {
1328     if (instantDataFilter || field_ref.isEmpty())
1329       ERROR("COutputPin* CField::getFieldReference(CGarbageCollector& gc)",
1330             "Impossible to get the field reference for a field which has already been parsed or which does not have a field_ref.");
[737]1331
[1158]1332     CField* fieldRef = CField::get(field_ref);
[1704]1333     fieldRef->buildFilterGraph(gc, false, start_graph, end_graph);
1334     const bool buildWorkflowGraph = (!build_workflow_graph.isEmpty() && build_workflow_graph == true);
[737]1335
[1704]1336     CContext* context = CContext::getCurrent();
1337
1338     Time filter_start;
1339     if(!build_workflow_graph_start.isEmpty() && buildWorkflowGraph) filter_start = context->calendar->getInitDate()+build_workflow_graph_start;
1340     else if(build_workflow_graph_start.isEmpty() && buildWorkflowGraph) filter_start = 0;
1341     else filter_start = -1;
1342
1343     Time filter_end;
1344     if(!build_workflow_graph_end.isEmpty() && buildWorkflowGraph) filter_end = context->calendar->getInitDate()+build_workflow_graph_end;
1345     else if(build_workflow_graph_end.isEmpty() && buildWorkflowGraph) filter_end = 9223372036854775807;
1346     else filter_end = -1;
1347
1348     if(this->field_graph_start==-2) this->field_graph_start = filter_start;
1349     if(this->field_graph_end==-2) this->field_graph_end = filter_end;         // init
1350
1351
1352     if(start_graph == -1)
1353     {
1354       //nothing
1355     }
1356     else //if(start_graph != -1)
1357     {
1358       if(this->field_graph_start == -1) this->field_graph_start = start_graph;
1359       else this->field_graph_start = min(this->field_graph_start, start_graph);
1360     }
1361
1362     if(end_graph == -1)
1363     {
1364       //nothing
1365     }
1366     else
1367     {
1368       if(this->field_graph_end == -1) this->field_graph_end = end_graph;
1369       else this->field_graph_end = max(this->field_graph_end, end_graph);
1370     }
1371
1372     filter_start = this->field_graph_start;
1373     filter_end = this->field_graph_end;
1374
1375
[1542]1376     std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters;
[1158]1377     // Check if a spatial transformation is needed
1378     if (grid && grid != fieldRef->grid && grid->hasTransform())
1379     {       
1380       bool hasMissingValue = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1381       double defaultValue  = hasMissingValue ? default_value : (!default_value.isEmpty() ? default_value : 0.0);                               
1382       filters = CSpatialTransformFilter::buildFilterGraph(gc, fieldRef->grid, grid, hasMissingValue, defaultValue);
[1704]1383
1384       fieldRef->getInstantDataFilter()->connectOutput(filters.first, 0);
1385
1386     
1387
1388       filters.second->parent_filters.resize(1);
1389       filters.second->parent_filters[0]= fieldRef->getInstantDataFilter();
1390
1391       filters.second->tag = (buildWorkflowGraph || filters.second->parent_filters[0]->tag);
1392       
1393       filters.second->start_graph = filter_start;
1394       filters.second->end_graph = filter_end;
1395       filters.second->field = this;
1396       
[1158]1397     }
1398     else
[1704]1399     {
[1542]1400       filters.first = filters.second = std::shared_ptr<CFilter>(new CPassThroughFilter(gc));
[873]1401
[1704]1402       fieldRef->getInstantDataFilter()->connectOutput(filters.first, 0);
1403     
[737]1404
[1704]1405       filters.second->parent_filters.resize(1);
1406       filters.second->parent_filters[0]= fieldRef->getInstantDataFilter();
1407
1408       filters.second->tag = (buildWorkflowGraph || filters.second->parent_filters[0]->tag);
1409
1410       filters.second->start_graph = filter_start;
1411       filters.second->end_graph = filter_end;
1412       filters.second->field = this;
1413
1414     }
1415
[1158]1416     return filters.second;
1417   }
[1622]1418   CATCH_DUMP_ATTR
[737]1419
1420   /*!
1421    * Returns the filter needed to handle a self reference in the field's expression.
1422    * If the needed filter does not exist, it is created, otherwise it is reused.
[642]1423    * This method should only be called when building the filter graph corresponding
1424    * to the field's expression.
1425    *
1426    * \param gc the garbage collector to use
1427    * \return the output pin corresponding to a self reference
1428    */
[1704]1429   std::shared_ptr<COutputPin> CField::getSelfReference(CGarbageCollector& gc, Time start_graph, Time end_graph)
[1622]1430   TRY
[642]1431   {
[1704]1432
[1021]1433     if (instantDataFilter || !hasExpression())
[642]1434       ERROR("COutputPin* CField::getSelfReference(CGarbageCollector& gc)",
1435             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
[1704]1436     
1437     bool buildWorkflowGraph = (!build_workflow_graph.isEmpty() && build_workflow_graph == true);
[642]1438
[737]1439     if (!selfReferenceFilter)
1440     {
[1201]1441       const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1442       const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
1443
[741]1444       if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
1445       {
1446         if (!serverSourceFilter)
[1319]1447         {
[1405]1448           checkTimeAttributes();
[1637]1449           serverSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, false, freq_offset, true,
[1201]1450                                                                                   detectMissingValues, defaultValue));
[1319]1451         }
[1201]1452
[741]1453         selfReferenceFilter = serverSourceFilter;
1454       }
1455       else if (!field_ref.isEmpty())
[1021]1456       {
1457         CField* fieldRef = CField::get(field_ref);
1458         fieldRef->buildFilterGraph(gc, false);
1459         selfReferenceFilter = fieldRef->getInstantDataFilter();
1460       }
[737]1461       else
1462       {
1463         if (!clientSourceFilter)
[1158]1464         {
[1201]1465           if (check_if_active.isEmpty()) check_if_active = false;
[1637]1466           clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, true, NoneDu, false,
[1201]1467                                                                                   detectMissingValues, defaultValue));
[1158]1468         }
[642]1469
[737]1470         selfReferenceFilter = clientSourceFilter;
1471       }
1472     }
1473
[1704]1474     selfReferenceFilter->tag = buildWorkflowGraph;
1475     selfReferenceFilter->field = this;
[737]1476     return selfReferenceFilter;
[642]1477   }
[1622]1478   CATCH_DUMP_ATTR
[642]1479
[643]1480   /*!
1481    * Returns the temporal filter corresponding to the field's temporal operation
1482    * for the specified operation frequency. The filter is created if it does not
1483    * exist, otherwise it is reused.
1484    *
1485    * \param gc the garbage collector to use
1486    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1487    * \return the output pin corresponding to the requested temporal filter
1488    */
[1542]1489   std::shared_ptr<COutputPin> CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
[1622]1490   TRY
[643]1491   {
[1542]1492     std::map<CDuration, std::shared_ptr<COutputPin> >::iterator it = temporalDataFilters.find(outFreq);
[1704]1493     const bool buildWorkflowGraph = (!build_workflow_graph.isEmpty() && build_workflow_graph == true);
[643]1494
[1704]1495     CContext* context = CContext::getCurrent();
1496
1497
[643]1498     if (it == temporalDataFilters.end())
1499     {
1500       if (operation.isEmpty())
1501         ERROR("void CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1502               << "An operation must be defined for field \"" << getId() << "\".");
1503
[1405]1504       checkTimeAttributes(&outFreq);
[1315]1505
[1440]1506       const bool detectMissingValues = (!detect_missing_value.isEmpty()  && detect_missing_value == true);
[1542]1507       std::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
[643]1508                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
[1440]1509                                                                             freq_op, freq_offset, outFreq, detectMissingValues));
[1278]1510
[643]1511       instantDataFilter->connectOutput(temporalFilter, 0);
[1704]1512       
1513       temporalFilter->parent_filters.resize(1);
1514       temporalFilter->parent_filters[0] = instantDataFilter;
1515       
[643]1516
[1768]1517       temporalFilter->tag = temporalFilter->parent_filters[0]->tag;
1518       temporalFilter->start_graph = temporalFilter->parent_filters[0]->start_graph;
1519       temporalFilter->end_graph = temporalFilter->parent_filters[0]->end_graph;
[1704]1520
1521       temporalFilter->field = this;
1522
[643]1523       it = temporalDataFilters.insert(std::make_pair(outFreq, temporalFilter)).first;
1524     }
1525
1526     return it->second;
1527   }
[1622]1528   CATCH_DUMP_ATTR
[643]1529
[1158]1530  /*!
1531    * Returns the temporal filter corresponding to the field's temporal operation
1532    * for the specified operation frequency.
1533    *
1534    * \param gc the garbage collector to use
1535    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1536    * \return the output pin corresponding to the requested temporal filter
1537    */
1538   
[1542]1539   std::shared_ptr<COutputPin> CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
[1622]1540   TRY
[1158]1541   {
1542     if (instantDataFilter || !hasExpression())
1543       ERROR("COutputPin* CField::getSelfTemporalDataFilter(CGarbageCollector& gc)",
1544             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1545
1546     if (!selfReferenceFilter) getSelfReference(gc) ;
1547
1548     if (serverSourceFilter || clientSourceFilter)
1549     {
1550       if (operation.isEmpty())
1551         ERROR("void CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1552               << "An operation must be defined for field \"" << getId() << "\".");
1553
[1405]1554       checkTimeAttributes(&outFreq);
[1315]1555
[1440]1556       const bool detectMissingValues = (!detect_missing_value.isEmpty() && detect_missing_value == true);
[1704]1557       bool buildWorkflowGraph = (!build_workflow_graph.isEmpty() && build_workflow_graph == true);
[1542]1558       std::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
[1704]1559                                                                           CContext::getCurrent()->getCalendar()->getInitDate(),
1560                                                                           freq_op, freq_offset, outFreq, detectMissingValues));
[1278]1561
[1158]1562       selfReferenceFilter->connectOutput(temporalFilter, 0);
[1704]1563       temporalFilter->tag = buildWorkflowGraph;
1564       temporalFilter->field = this;
1565
[1158]1566       return temporalFilter ;
1567     }
1568     else if (!field_ref.isEmpty())
1569     {
1570       CField* fieldRef = CField::get(field_ref);
1571       fieldRef->buildFilterGraph(gc, false); 
1572       return fieldRef->getTemporalDataFilter(gc, outFreq) ;
1573     }
1574  }
[1622]1575   CATCH_DUMP_ATTR
[1158]1576
[640]1577   //----------------------------------------------------------------
[369]1578/*
[562]1579   void CField::fromBinary(StdIStream& is)
[219]1580   {
1581      SuperClass::fromBinary(is);
1582#define CLEAR_ATT(name_)\
[369]1583      SuperClassAttribute::operator[](#name_)->reset()
[219]1584
1585         CLEAR_ATT(domain_ref);
1586         CLEAR_ATT(axis_ref);
1587#undef CLEAR_ATT
1588
1589   }
[369]1590*/
[219]1591   //----------------------------------------------------------------
1592
1593   void CField::solveGridReference(void)
[1622]1594   TRY
[219]1595   {
[887]1596      if (grid_ref.isEmpty() && domain_ref.isEmpty() && axis_ref.isEmpty() && scalar_ref.isEmpty())
[742]1597      {
1598        ERROR("CField::solveGridReference(void)",
[770]1599              << "A grid must be defined for field '" << getFieldOutputName() << "' .");
[742]1600      }
[887]1601      else if (!grid_ref.isEmpty() && (!domain_ref.isEmpty() || !axis_ref.isEmpty() || !scalar_ref.isEmpty()))
[219]1602      {
[744]1603        ERROR("CField::solveGridReference(void)",
[887]1604              << "Field '" << getFieldOutputName() << "' has both a grid and a domain/axis/scalar." << std::endl
1605              << "Please define either 'grid_ref' or 'domain_ref'/'axis_ref'/'scalar_ref'.");
[219]1606      }
1607
[744]1608      if (grid_ref.isEmpty())
[219]1609      {
[744]1610        std::vector<CDomain*> vecDom;
1611        std::vector<CAxis*> vecAxis;
[887]1612        std::vector<CScalar*> vecScalar;
[894]1613        std::vector<int> axisDomainOrderTmp;
[1524]1614
1615        std::vector<CDomain*> vecDomRef;
1616        std::vector<CAxis*> vecAxisRef;
1617        std::vector<CScalar*> vecScalarRef;
1618
[894]1619       
[744]1620        if (!domain_ref.isEmpty())
1621        {
[823]1622          StdString tmp = domain_ref.getValue();
[744]1623          if (CDomain::has(domain_ref))
[894]1624          {
[744]1625            vecDom.push_back(CDomain::get(domain_ref));
[1524]1626            vecDomRef.push_back(CDomain::createDomain());
1627            vecDomRef.back()->domain_ref=domain_ref;
[894]1628            axisDomainOrderTmp.push_back(2);
1629          }
[1524]1630          else  ERROR("CField::solveGridReference(void)",
1631                      << "Invalid reference to domain '" << domain_ref.getValue() << "'.");
[744]1632        }
[219]1633
[744]1634        if (!axis_ref.isEmpty())
[742]1635        {
[744]1636          if (CAxis::has(axis_ref))
[894]1637          {
[744]1638            vecAxis.push_back(CAxis::get(axis_ref));
[1524]1639            vecAxisRef.push_back(CAxis::createAxis());
1640            vecAxisRef.back()->axis_ref=axis_ref;
[894]1641            axisDomainOrderTmp.push_back(1);
1642          }
[1524]1643          else  ERROR("CField::solveGridReference(void)",
1644                      << "Invalid reference to axis '" << axis_ref.getValue() << "'.");
[742]1645        }
[744]1646
[887]1647        if (!scalar_ref.isEmpty())
1648        {
1649          if (CScalar::has(scalar_ref))
[894]1650          {
[887]1651            vecScalar.push_back(CScalar::get(scalar_ref));
[1524]1652            vecScalarRef.push_back(CScalar::createScalar());
1653            vecScalarRef.back()->scalar_ref=scalar_ref;
[894]1654            axisDomainOrderTmp.push_back(0);
1655          }
[1524]1656          else ERROR("CField::solveGridReference(void)",
1657                     << "Invalid reference to scalar '" << scalar_ref.getValue() << "'.");
[887]1658        }
[894]1659       
1660        CArray<int,1> axisDomainOrder(axisDomainOrderTmp.size());
1661        for (int idx = 0; idx < axisDomainOrderTmp.size(); ++idx)
1662        {
1663          axisDomainOrder(idx) = axisDomainOrderTmp[idx];
1664        }
[887]1665
[745]1666        // Warning: the gridId shouldn't be set as the grid_ref since it could be inherited
[894]1667        StdString gridId = CGrid::generateId(vecDom, vecAxis, vecScalar,axisDomainOrder);
[1524]1668        if (CGrid::has(gridId)) this->grid = CGrid::get(gridId);
1669        else  this->grid = CGrid::createGrid(gridId, vecDomRef, vecAxisRef, vecScalarRef,axisDomainOrder);
[219]1670      }
[586]1671      else
1672      {
[1524]1673        if (CGrid::has(grid_ref)) this->grid = CGrid::get(grid_ref);
1674        else  ERROR("CField::solveGridReference(void)",
1675                     << "Invalid reference to grid '" << grid_ref.getValue() << "'.");
[586]1676      }
[509]1677   }
[1622]1678   CATCH_DUMP_ATTR
[459]1679
[509]1680   void CField::solveGridDomainAxisRef(bool checkAtt)
[1622]1681   TRY
[509]1682   {
1683     grid->solveDomainAxisRef(checkAtt);
[219]1684   }
[1622]1685   CATCH_DUMP_ATTR
[219]1686
[509]1687   void CField::solveCheckMaskIndex(bool doSendingIndex)
[1622]1688   TRY
[509]1689   {
1690     grid->checkMaskIndex(doSendingIndex);
1691   }
[1622]1692   CATCH_DUMP_ATTR
[219]1693
[619]1694   void CField::solveTransformedGrid()
[1622]1695   TRY
[619]1696   {
[746]1697     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
[790]1698     {
1699       std::vector<CGrid*> grids;
1700       // Source grid
1701       grids.push_back(getDirectFieldReference()->grid);
1702       // Intermediate grids
1703       if (!grid_path.isEmpty())
1704       {
1705         std::string gridId;
1706         size_t start = 0, end;
1707
1708         do
1709         {
1710           end = grid_path.getValue().find(',', start);
1711           if (end != std::string::npos)
1712           {
1713             gridId = grid_path.getValue().substr(start, end - start);
1714             start = end + 1;
1715           }
1716           else
1717             gridId = grid_path.getValue().substr(start);
1718
1719           if (!CGrid::has(gridId))
1720             ERROR("void CField::solveTransformedGrid()",
1721                   << "Invalid grid_path, the grid '" << gridId << "' does not exist.");
1722
1723           grids.push_back(CGrid::get(gridId));
1724         }
1725         while (end != std::string::npos);
1726       }
1727       // Destination grid
1728       grids.push_back(grid);
1729
1730       for (size_t i = 0, count = grids.size() - 1; i < count; ++i)
1731       {
1732         CGrid *gridSrc  = grids[i];
1733         CGrid *gridDest = grids[i + 1];
1734         if (!gridDest->isTransformed())
1735           gridDest->transformGrid(gridSrc);
1736       }
1737     }
[934]1738     else if (grid && grid->hasTransform() && !grid->isTransformed())
1739     {
[1021]1740       // Temporarily deactivate the self-transformation of grid
[1386]1741       // grid->transformGrid(grid);
[934]1742     }
[619]1743   }
[1622]1744   CATCH_DUMP_ATTR
[619]1745
[687]1746   void CField::solveGenerateGrid()
[1622]1747   TRY
[687]1748   {
[746]1749     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
[687]1750       grid->completeGrid(getDirectFieldReference()->grid);
[775]1751     else
1752       grid->completeGrid();
[687]1753   }
[1622]1754   CATCH_DUMP_ATTR
[687]1755
[775]1756   void CField::solveGridDomainAxisBaseRef()
[1622]1757   TRY
[775]1758   {
1759     grid->solveDomainAxisRef(false);
1760     grid->solveDomainAxisBaseRef();
1761   }
[1622]1762   CATCH_DUMP_ATTR
[775]1763
[219]1764   ///-------------------------------------------------------------------
1765
1766   template <>
[562]1767   void CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)
[1622]1768   TRY
[219]1769   {
1770      if (this->group_ref.isEmpty()) return;
1771      StdString gref = this->group_ref.getValue();
1772
[346]1773      if (!CFieldGroup::has(gref))
[219]1774         ERROR("CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)",
1775               << "[ gref = " << gref << "]"
1776               << " invalid group name !");
1777
[347]1778      CFieldGroup* group = CFieldGroup::get(gref);
1779      CFieldGroup* owner = CFieldGroup::get(boost::polymorphic_downcast<CFieldGroup*>(this));
[1574]1780      owner->setAttributes(group); // inherite of attributes of group reference
1781     
[347]1782      std::vector<CField*> allChildren  = group->getAllChildren();
[562]1783      std::vector<CField*>::iterator it = allChildren.begin(), end = allChildren.end();
[509]1784
[219]1785      for (; it != end; it++)
1786      {
[347]1787         CField* child = *it;
[562]1788         if (child->hasId()) owner->createChild()->field_ref.setValue(child->getId());
[509]1789
[219]1790      }
1791   }
[1622]1792   CATCH_DUMP_ATTR
[509]1793
[464]1794   void CField::scaleFactorAddOffset(double scaleFactor, double addOffset)
[1622]1795   TRY
[464]1796   {
[1136]1797     recvDataSrv = (recvDataSrv - addOffset) / scaleFactor;
[464]1798   }
[1622]1799   CATCH_DUMP_ATTR
[509]1800
[599]1801   void CField::invertScaleFactorAddOffset(double scaleFactor, double addOffset)
[1622]1802   TRY
[599]1803   {
[1136]1804     recvDataSrv = recvDataSrv * scaleFactor + addOffset;
[599]1805   }
[1622]1806   CATCH_DUMP_ATTR
[599]1807
[567]1808   void CField::outputField(CArray<double,1>& fieldOut)
[1622]1809   TRY
[1136]1810   { 
[1129]1811      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1812      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1813      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1814      {
1815        fieldOut(outIndexServer(idx)) = recvDataSrv(outIndexClient(idx));
1816      }
[1136]1817   }
[1622]1818   CATCH_DUMP_ATTR
[1129]1819
[1136]1820   void CField::inputField(CArray<double,1>& fieldIn)
[1622]1821   TRY
[1136]1822   {
1823      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1824      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1825      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
[599]1826      {
[1136]1827        recvDataSrv(outIndexClient(idx)) = fieldIn(outIndexServer(idx));
[599]1828      }
1829   }
[1622]1830   CATCH_DUMP_ATTR
[599]1831
[676]1832   void CField::outputCompressedField(CArray<double,1>& fieldOut)
[1622]1833   TRY
[676]1834   {
[1143]1835      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1836      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1837      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
[676]1838      {
[1143]1839        fieldOut((idx)) = recvDataSrv(outIndexClient(idx));
[676]1840      }
1841   }
[1622]1842   CATCH_DUMP_ATTR
[676]1843
[219]1844   ///-------------------------------------------------------------------
1845
[562]1846   void CField::parse(xml::CXMLNode& node)
[1622]1847   TRY
[459]1848   {
[1363]1849      string newContent ;
[459]1850      SuperClass::parse(node);
[1363]1851      if (node.goToChildElement())
[472]1852      {
[1363]1853        do
[472]1854        {
[1363]1855          if (node.getElementName() == "variable" || node.getElementName() == "variable_group") this->getVirtualVariableGroup()->parseChild(node);
1856          else if (node.getElementName() == "expr") if (node.getContent(newContent)) content+=newContent ;
1857        } while (node.goToNextElement());
1858        node.goToParentElement();
[472]1859      }
[1363]1860      if (node.getContent(newContent)) content=newContent ;
[459]1861    }
[1622]1862   CATCH_DUMP_ATTR
[509]1863
1864   /*!
1865     This function retrieves Id of corresponding domain_ref and axis_ref (if any)
1866   of a field. In some cases, only domain exists but axis doesn't
1867   \return pair of Domain and Axis id
1868   */
[887]1869   const std::vector<StdString>& CField::getRefDomainAxisIds()
[1622]1870   TRY
[569]1871   {
1872     CGrid* cgPtr = getRelGrid();
1873     if (NULL != cgPtr)
1874     {
1875       std::vector<StdString>::iterator it;
1876       if (!domain_ref.isEmpty())
1877       {
1878         std::vector<StdString> domainList = cgPtr->getDomainList();
1879         it = std::find(domainList.begin(), domainList.end(), domain_ref.getValue());
[887]1880         if (domainList.end() != it) domAxisScalarIds_[0] = *it;
[569]1881       }
[472]1882
[569]1883       if (!axis_ref.isEmpty())
1884       {
1885         std::vector<StdString> axisList = cgPtr->getAxisList();
1886         it = std::find(axisList.begin(), axisList.end(), axis_ref.getValue());
[887]1887         if (axisList.end() != it) domAxisScalarIds_[1] = *it;
[569]1888       }
[887]1889
1890       if (!scalar_ref.isEmpty())
1891       {
1892         std::vector<StdString> scalarList = cgPtr->getScalarList();
1893         it = std::find(scalarList.begin(), scalarList.end(), scalar_ref.getValue());
1894         if (scalarList.end() != it) domAxisScalarIds_[2] = *it;
1895       }
[569]1896     }
[887]1897     return (domAxisScalarIds_);
[569]1898   }
[1622]1899   CATCH_DUMP_ATTR
[569]1900
[472]1901   CVariable* CField::addVariable(const string& id)
[1622]1902   TRY
[472]1903   {
[562]1904     return vVariableGroup->createChild(id);
[472]1905   }
[1622]1906   CATCH
[472]1907
1908   CVariableGroup* CField::addVariableGroup(const string& id)
[1622]1909   TRY
[472]1910   {
[562]1911     return vVariableGroup->createChildGroup(id);
[472]1912   }
[1622]1913   CATCH
[472]1914
[1294]1915   void CField::setContextClient(CContextClient* contextClient)
[1622]1916   TRY
[1294]1917   {
[1344]1918     CContext* context = CContext::getCurrent();
[1294]1919     client = contextClient;
[1344]1920     if (context->hasClient)
1921     {
1922       // A grid is sent by a client (both for read or write) or by primary server (write only)
1923       if (context->hasServer)
1924       {
1925         if (file->mode.isEmpty() || (!file->mode.isEmpty() && file->mode == CFile::mode_attr::write))
1926           grid->setContextClient(contextClient);
1927       }
1928       else
1929           grid->setContextClient(contextClient);
1930     }
[1294]1931   }
[1622]1932   CATCH_DUMP_ATTR
[1294]1933
1934   CContextClient* CField::getContextClient()
[1622]1935   TRY
[1294]1936   {
1937     return client;
1938   }
[1622]1939   CATCH
[1294]1940
[1021]1941   void CField::sendAddAllVariables(CContextClient* client)
[1622]1942   TRY
[1009]1943   {
1944     std::vector<CVariable*> allVar = getAllVariables();
1945     std::vector<CVariable*>::const_iterator it = allVar.begin();
1946     std::vector<CVariable*>::const_iterator itE = allVar.end();
1947
1948     for (; it != itE; ++it)
1949     {
[1021]1950       this->sendAddVariable((*it)->getId(), client);
1951       (*it)->sendAllAttributesToServer(client);
1952       (*it)->sendValue(client);
[1009]1953     }
1954   }
[1622]1955   CATCH_DUMP_ATTR
[1009]1956
[1524]1957   /*!
1958    * Send all Attributes to server. This method is overloaded, since only grid_ref attribute
1959    * must be sent to server and not domain_ref/axis_ref/scalar_ref.
1960    */
1961   
1962   void CField::sendAllAttributesToServer(CContextClient* client)
[1622]1963   TRY
[1524]1964   {
1965     if (grid_ref.isEmpty())
1966     {
1967       grid_ref=grid->getId() ;
1968       SuperClass::sendAllAttributesToServer(client) ;
1969       grid_ref.reset();
1970     }
1971     else SuperClass::sendAllAttributesToServer(client) ;
1972   }
[1622]1973   CATCH_DUMP_ATTR
[1524]1974   
[1021]1975   void CField::sendAddVariable(const string& id, CContextClient* client)
[1622]1976   TRY
[1021]1977   {
1978      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE, client);
1979   }
[1622]1980   CATCH_DUMP_ATTR
[1021]1981
[1144]1982   void CField::sendAddVariableGroup(const string& id, CContextClient* client)
[1622]1983   TRY
[472]1984   {
[1144]1985      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE_GROUP, client);
[472]1986   }
[1622]1987   CATCH_DUMP_ATTR
[509]1988
[472]1989   void CField::recvAddVariable(CEventServer& event)
[1622]1990   TRY
[472]1991   {
[509]1992
[562]1993      CBufferIn* buffer = event.subEvents.begin()->buffer;
[472]1994      string id;
[562]1995      *buffer >> id;
1996      get(id)->recvAddVariable(*buffer);
[472]1997   }
[1622]1998   CATCH
[509]1999
[472]2000   void CField::recvAddVariable(CBufferIn& buffer)
[1622]2001   TRY
[472]2002   {
[562]2003      string id;
2004      buffer >> id;
2005      addVariable(id);
[472]2006   }
[1622]2007   CATCH_DUMP_ATTR
[472]2008
2009   void CField::recvAddVariableGroup(CEventServer& event)
[1622]2010   TRY
[472]2011   {
[509]2012
[562]2013      CBufferIn* buffer = event.subEvents.begin()->buffer;
[472]2014      string id;
[562]2015      *buffer >> id;
2016      get(id)->recvAddVariableGroup(*buffer);
[472]2017   }
[1622]2018   CATCH
[509]2019
[472]2020   void CField::recvAddVariableGroup(CBufferIn& buffer)
[1622]2021   TRY
[472]2022   {
[562]2023      string id;
2024      buffer >> id;
2025      addVariableGroup(id);
[472]2026   }
[1622]2027   CATCH_DUMP_ATTR
[472]2028
[1021]2029   /*!
[1278]2030    * Check on freq_off and freq_op attributes.
2031    */
[1405]2032   void CField::checkTimeAttributes(CDuration* freqOp)
[1622]2033   TRY
[1278]2034   {
[1405]2035     bool isFieldRead  = file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read;
2036     bool isFieldWrite = file && ( file->mode.isEmpty() ||  file->mode == CFile::mode_attr::write);
[1514]2037     if (isFieldRead && !(operation.getValue() == "instant" || operation.getValue() == "once") )     
[1405]2038       ERROR("void CField::checkTimeAttributes(void)",
[1315]2039             << "Unsupported operation for field '" << getFieldOutputName() << "'." << std::endl
2040             << "Currently only \"instant\" is supported for fields read from file.")
2041
[1278]2042     if (freq_op.isEmpty())
2043     {
[1315]2044       if (operation.getValue() == "instant")
[1405]2045       {
2046         if (isFieldRead || isFieldWrite) freq_op.setValue(file->output_freq.getValue());
2047         else freq_op=*freqOp ;
2048       }
[1278]2049       else
[1292]2050         freq_op.setValue(TimeStep);
[1278]2051     }
[1920]2052     else
2053     {
2054       //if(file->output_freq.getValue() < freq_op.getValue())
2055       if(freq_op.getValue() > file->output_freq.getValue() )
2056       {
2057         ERROR("void CField::checkTimeAttributes(void)",
2058               << "output file has output_freq < freq_op" << std::endl
2059               << "field_id = "<< getId() << std::endl
2060               << "file_id = "<< file->getId() << std::endl
2061               << "output_freq = "<< file->output_freq.getValue() << std::endl
2062               << "freq_op = "<< freq_op.getValue() << std::endl)
2063       }
2064     }
[1306]2065     if (freq_offset.isEmpty())
[1315]2066       freq_offset.setValue(isFieldRead ? NoneDu : (freq_op.getValue() - TimeStep));
[1278]2067   }
[1622]2068   CATCH_DUMP_ATTR
[1278]2069
2070   /*!
[1021]2071    * Returns string arithmetic expression associated to the field.
2072    * \return if content is defined return content string, otherwise, if "expr" attribute is defined, return expr string.
2073    */
2074   const string& CField::getExpression(void)
[1622]2075   TRY
[1021]2076   {
2077     if (!expr.isEmpty() && content.empty())
2078     {
2079       content = expr;
2080       expr.reset();
2081     }
2082
2083     return content;
2084   }
[1622]2085   CATCH_DUMP_ATTR
[1021]2086
2087   bool CField::hasExpression(void) const
[1622]2088   TRY
[1021]2089   {
2090     return (!expr.isEmpty() || !content.empty());
2091   }
[1622]2092   CATCH
[1021]2093
[1637]2094   bool CField::hasGridMask(void) const
2095   TRY
2096   {
2097     return (this->grid->hasMask());
2098   }
2099   CATCH
2100
[540]2101   DEFINE_REF_FUNC(Field,field)
[335]2102} // namespace xios
Note: See TracBrowser for help on using the repository browser.