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

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

Replacing Boost's unordered_map and shared_pointer by its STL counterparts.

Two notes for Curie:

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