source: XIOS/dev/XIOS_DEV_CMIP6/src/node/field.cpp @ 1387

Last change on this file since 1387 was 1387, checked in by oabramkina, 6 years ago

Fixing a bug in case of output_freq defined in months to avoid adding a month to the last day of a month.

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