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

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

DEV_CMIP6: bugfix for certain cases of monthly output and freq_offset such as 1mo-2ts.

  • 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: 55.8 KB
RevLine 
[219]1#include "field.hpp"
2
[352]3#include "attribute_template.hpp"
4#include "object_template.hpp"
5#include "group_template.hpp"
[219]6
7#include "node_type.hpp"
8#include "calendar_util.hpp"
[352]9#include "message.hpp"
[591]10#include "xios_spl.hpp"
[352]11#include "type.hpp"
[638]12#include "timer.hpp"
[352]13#include "context_client.hpp"
[586]14#include "context_server.hpp"
[459]15#include <set>
[640]16#include "garbage_collector.hpp"
17#include "source_filter.hpp"
18#include "store_filter.hpp"
19#include "file_writer_filter.hpp"
[641]20#include "pass_through_filter.hpp"
[642]21#include "filter_expr_node.hpp"
22#include "lex_parser.hpp"
[643]23#include "temporal_filter.hpp"
[644]24#include "spatial_transform_filter.hpp"
[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());
[1025]221      recvFoperationSrv = boost::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
[641]718   boost::shared_ptr<COutputPin> CField::getInstantDataFilter()
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
[645]986      boost::shared_ptr<func::CFunctor> functor;
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)
[1250]1029          instantDataFilter = clientSourceFilter = boost::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         {
1037           fileServerWriterFilter = boost::shared_ptr<CFileServerWriterFilter>(new CFileServerWriterFilter(gc, this));
1038           instantDataFilter->connectOutput(fileServerWriterFilter, 0);
1039         }
1040       }
1041     }
1042     else if (hasIntermediateServer)
1043     {
1044       if (!instantDataFilter)
[1250]1045         instantDataFilter = clientSourceFilter = boost::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         {
1052           fileWriterFilter = boost::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
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'));
1066           boost::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             {
[1201]1075                 std::pair<boost::shared_ptr<CFilter>, boost::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();
[1315]1091           instantDataFilter = serverSourceFilter = boost::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; 
[1250]1097            instantDataFilter = clientSourceFilter = boost::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         {
1107           storeFilter = boost::shared_ptr<CStoreFilter>(new CStoreFilter(gc, CContext::getCurrent(), grid,
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         {
1114           fileWriterFilter = boost::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
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    */
[1158]1128   boost::shared_ptr<COutputPin> CField::getFieldReference(CGarbageCollector& gc)
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
[1158]1137     std::pair<boost::shared_ptr<CFilter>, boost::shared_ptr<CFilter> > filters;
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
1146       filters.first = filters.second = boost::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    */
1162   boost::shared_ptr<COutputPin> CField::getSelfReference(CGarbageCollector& gc)
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();
[1315]1178           serverSourceFilter = boost::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;
[1241]1195           clientSourceFilter = boost::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    */
1215   boost::shared_ptr<COutputPin> CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1216   {
1217     std::map<CDuration, boost::shared_ptr<COutputPin> >::iterator it = temporalDataFilters.find(outFreq);
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);
[643]1228       boost::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
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   
1249   boost::shared_ptr<COutputPin> CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
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);
[1158]1266       boost::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
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;
1317       
[744]1318        if (!domain_ref.isEmpty())
1319        {
[823]1320          StdString tmp = domain_ref.getValue();
[744]1321          if (CDomain::has(domain_ref))
[894]1322          {
[744]1323            vecDom.push_back(CDomain::get(domain_ref));
[894]1324            axisDomainOrderTmp.push_back(2);
1325          }
[744]1326          else
[219]1327            ERROR("CField::solveGridReference(void)",
[744]1328                  << "Invalid reference to domain '" << domain_ref.getValue() << "'.");
1329        }
[219]1330
[744]1331        if (!axis_ref.isEmpty())
[742]1332        {
[744]1333          if (CAxis::has(axis_ref))
[894]1334          {
[744]1335            vecAxis.push_back(CAxis::get(axis_ref));
[894]1336            axisDomainOrderTmp.push_back(1);
1337          }
[744]1338          else
1339            ERROR("CField::solveGridReference(void)",
1340                  << "Invalid reference to axis '" << axis_ref.getValue() << "'.");
[742]1341        }
[744]1342
[887]1343        if (!scalar_ref.isEmpty())
1344        {
1345          if (CScalar::has(scalar_ref))
[894]1346          {
[887]1347            vecScalar.push_back(CScalar::get(scalar_ref));
[894]1348            axisDomainOrderTmp.push_back(0);
1349          }
[887]1350          else
1351            ERROR("CField::solveGridReference(void)",
1352                  << "Invalid reference to scalar '" << scalar_ref.getValue() << "'.");
1353        }
[894]1354       
1355        CArray<int,1> axisDomainOrder(axisDomainOrderTmp.size());
1356        for (int idx = 0; idx < axisDomainOrderTmp.size(); ++idx)
1357        {
1358          axisDomainOrder(idx) = axisDomainOrderTmp[idx];
1359        }
[887]1360
[745]1361        // Warning: the gridId shouldn't be set as the grid_ref since it could be inherited
[894]1362        StdString gridId = CGrid::generateId(vecDom, vecAxis, vecScalar,axisDomainOrder);
[745]1363        if (CGrid::has(gridId))
1364          this->grid = CGrid::get(gridId);
1365        else
[894]1366          this->grid = CGrid::createGrid(gridId, vecDom, vecAxis, vecScalar,axisDomainOrder);
[219]1367      }
[586]1368      else
1369      {
[744]1370        if (CGrid::has(grid_ref))
1371          this->grid = CGrid::get(grid_ref);
1372        else
1373          ERROR("CField::solveGridReference(void)",
1374                << "Invalid reference to grid '" << grid_ref.getValue() << "'.");
[586]1375      }
[509]1376   }
[459]1377
[509]1378   void CField::solveGridDomainAxisRef(bool checkAtt)
1379   {
1380     grid->solveDomainAxisRef(checkAtt);
[219]1381   }
1382
[509]1383   void CField::solveCheckMaskIndex(bool doSendingIndex)
1384   {
1385     grid->checkMaskIndex(doSendingIndex);
1386   }
[219]1387
[619]1388   void CField::solveTransformedGrid()
1389   {
[746]1390     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
[790]1391     {
1392       std::vector<CGrid*> grids;
1393       // Source grid
1394       grids.push_back(getDirectFieldReference()->grid);
1395       // Intermediate grids
1396       if (!grid_path.isEmpty())
1397       {
1398         std::string gridId;
1399         size_t start = 0, end;
1400
1401         do
1402         {
1403           end = grid_path.getValue().find(',', start);
1404           if (end != std::string::npos)
1405           {
1406             gridId = grid_path.getValue().substr(start, end - start);
1407             start = end + 1;
1408           }
1409           else
1410             gridId = grid_path.getValue().substr(start);
1411
1412           if (!CGrid::has(gridId))
1413             ERROR("void CField::solveTransformedGrid()",
1414                   << "Invalid grid_path, the grid '" << gridId << "' does not exist.");
1415
1416           grids.push_back(CGrid::get(gridId));
1417         }
1418         while (end != std::string::npos);
1419       }
1420       // Destination grid
1421       grids.push_back(grid);
1422
1423       for (size_t i = 0, count = grids.size() - 1; i < count; ++i)
1424       {
1425         CGrid *gridSrc  = grids[i];
1426         CGrid *gridDest = grids[i + 1];
1427         if (!gridDest->isTransformed())
1428           gridDest->transformGrid(gridSrc);
1429       }
1430     }
[934]1431     else if (grid && grid->hasTransform() && !grid->isTransformed())
1432     {
[1021]1433       // Temporarily deactivate the self-transformation of grid
[1386]1434       // grid->transformGrid(grid);
[934]1435     }
[619]1436   }
1437
[687]1438   void CField::solveGenerateGrid()
1439   {
[746]1440     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
[687]1441       grid->completeGrid(getDirectFieldReference()->grid);
[775]1442     else
1443       grid->completeGrid();
[687]1444   }
1445
[775]1446   void CField::solveGridDomainAxisBaseRef()
1447   {
1448     grid->solveDomainAxisRef(false);
1449     grid->solveDomainAxisBaseRef();
1450   }
1451
[219]1452   ///-------------------------------------------------------------------
1453
1454   template <>
[562]1455   void CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)
[219]1456   {
1457      if (this->group_ref.isEmpty()) return;
1458      StdString gref = this->group_ref.getValue();
1459
[346]1460      if (!CFieldGroup::has(gref))
[219]1461         ERROR("CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)",
1462               << "[ gref = " << gref << "]"
1463               << " invalid group name !");
1464
[347]1465      CFieldGroup* group = CFieldGroup::get(gref);
1466      CFieldGroup* owner = CFieldGroup::get(boost::polymorphic_downcast<CFieldGroup*>(this));
[219]1467
[347]1468      std::vector<CField*> allChildren  = group->getAllChildren();
[562]1469      std::vector<CField*>::iterator it = allChildren.begin(), end = allChildren.end();
[509]1470
[219]1471      for (; it != end; it++)
1472      {
[347]1473         CField* child = *it;
[562]1474         if (child->hasId()) owner->createChild()->field_ref.setValue(child->getId());
[509]1475
[219]1476      }
1477   }
[509]1478
[464]1479   void CField::scaleFactorAddOffset(double scaleFactor, double addOffset)
1480   {
[1136]1481     recvDataSrv = (recvDataSrv - addOffset) / scaleFactor;
[464]1482   }
[509]1483
[599]1484   void CField::invertScaleFactorAddOffset(double scaleFactor, double addOffset)
1485   {
[1136]1486     recvDataSrv = recvDataSrv * scaleFactor + addOffset;
[599]1487   }
1488
[567]1489   void CField::outputField(CArray<double,1>& fieldOut)
[1136]1490   { 
[1129]1491      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1492      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1493      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1494      {
1495        fieldOut(outIndexServer(idx)) = recvDataSrv(outIndexClient(idx));
1496      }
[1136]1497   }
[1129]1498
[1136]1499   void CField::inputField(CArray<double,1>& fieldIn)
1500   {
1501      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1502      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1503      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
[599]1504      {
[1136]1505        recvDataSrv(outIndexClient(idx)) = fieldIn(outIndexServer(idx));
[599]1506      }
1507
1508   }
1509
[676]1510   void CField::outputCompressedField(CArray<double,1>& fieldOut)
1511   {
[1143]1512      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1513      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1514      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
[676]1515      {
[1143]1516        fieldOut((idx)) = recvDataSrv(outIndexClient(idx));
[676]1517      }
1518   }
1519
[219]1520   ///-------------------------------------------------------------------
1521
[562]1522   void CField::parse(xml::CXMLNode& node)
[459]1523   {
[1363]1524      string newContent ;
[459]1525      SuperClass::parse(node);
[1363]1526      if (node.goToChildElement())
[472]1527      {
[1363]1528        do
[472]1529        {
[1363]1530          if (node.getElementName() == "variable" || node.getElementName() == "variable_group") this->getVirtualVariableGroup()->parseChild(node);
1531          else if (node.getElementName() == "expr") if (node.getContent(newContent)) content+=newContent ;
1532        } while (node.goToNextElement());
1533        node.goToParentElement();
[472]1534      }
[1363]1535      if (node.getContent(newContent)) content=newContent ;
[459]1536    }
[509]1537
1538   /*!
1539     This function retrieves Id of corresponding domain_ref and axis_ref (if any)
1540   of a field. In some cases, only domain exists but axis doesn't
1541   \return pair of Domain and Axis id
1542   */
[887]1543   const std::vector<StdString>& CField::getRefDomainAxisIds()
[569]1544   {
1545     CGrid* cgPtr = getRelGrid();
1546     if (NULL != cgPtr)
1547     {
1548       std::vector<StdString>::iterator it;
1549       if (!domain_ref.isEmpty())
1550       {
1551         std::vector<StdString> domainList = cgPtr->getDomainList();
1552         it = std::find(domainList.begin(), domainList.end(), domain_ref.getValue());
[887]1553         if (domainList.end() != it) domAxisScalarIds_[0] = *it;
[569]1554       }
[472]1555
[569]1556       if (!axis_ref.isEmpty())
1557       {
1558         std::vector<StdString> axisList = cgPtr->getAxisList();
1559         it = std::find(axisList.begin(), axisList.end(), axis_ref.getValue());
[887]1560         if (axisList.end() != it) domAxisScalarIds_[1] = *it;
[569]1561       }
[887]1562
1563       if (!scalar_ref.isEmpty())
1564       {
1565         std::vector<StdString> scalarList = cgPtr->getScalarList();
1566         it = std::find(scalarList.begin(), scalarList.end(), scalar_ref.getValue());
1567         if (scalarList.end() != it) domAxisScalarIds_[2] = *it;
1568       }
[569]1569     }
[887]1570     return (domAxisScalarIds_);
[569]1571   }
1572
[472]1573   CVariable* CField::addVariable(const string& id)
1574   {
[562]1575     return vVariableGroup->createChild(id);
[472]1576   }
1577
1578   CVariableGroup* CField::addVariableGroup(const string& id)
1579   {
[562]1580     return vVariableGroup->createChildGroup(id);
[472]1581   }
1582
[1294]1583   void CField::setContextClient(CContextClient* contextClient)
1584   {
[1344]1585     CContext* context = CContext::getCurrent();
[1294]1586     client = contextClient;
[1344]1587     if (context->hasClient)
1588     {
1589       // A grid is sent by a client (both for read or write) or by primary server (write only)
1590       if (context->hasServer)
1591       {
1592         if (file->mode.isEmpty() || (!file->mode.isEmpty() && file->mode == CFile::mode_attr::write))
1593           grid->setContextClient(contextClient);
1594       }
1595       else
1596           grid->setContextClient(contextClient);
1597     }
[1294]1598   }
1599
1600   CContextClient* CField::getContextClient()
1601   {
1602     return client;
1603   }
1604
[1021]1605   void CField::sendAddAllVariables(CContextClient* client)
[1009]1606   {
1607     std::vector<CVariable*> allVar = getAllVariables();
1608     std::vector<CVariable*>::const_iterator it = allVar.begin();
1609     std::vector<CVariable*>::const_iterator itE = allVar.end();
1610
1611     for (; it != itE; ++it)
1612     {
[1021]1613       this->sendAddVariable((*it)->getId(), client);
1614       (*it)->sendAllAttributesToServer(client);
1615       (*it)->sendValue(client);
[1009]1616     }
1617   }
1618
[1021]1619   void CField::sendAddVariable(const string& id, CContextClient* client)
1620   {
1621      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE, client);
1622   }
1623
[1144]1624   void CField::sendAddVariableGroup(const string& id, CContextClient* client)
[472]1625   {
[1144]1626      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE_GROUP, client);
[472]1627   }
[509]1628
[472]1629   void CField::recvAddVariable(CEventServer& event)
1630   {
[509]1631
[562]1632      CBufferIn* buffer = event.subEvents.begin()->buffer;
[472]1633      string id;
[562]1634      *buffer >> id;
1635      get(id)->recvAddVariable(*buffer);
[472]1636   }
[509]1637
[472]1638   void CField::recvAddVariable(CBufferIn& buffer)
1639   {
[562]1640      string id;
1641      buffer >> id;
1642      addVariable(id);
[472]1643   }
1644
1645   void CField::recvAddVariableGroup(CEventServer& event)
1646   {
[509]1647
[562]1648      CBufferIn* buffer = event.subEvents.begin()->buffer;
[472]1649      string id;
[562]1650      *buffer >> id;
1651      get(id)->recvAddVariableGroup(*buffer);
[472]1652   }
[509]1653
[472]1654   void CField::recvAddVariableGroup(CBufferIn& buffer)
1655   {
[562]1656      string id;
1657      buffer >> id;
1658      addVariableGroup(id);
[472]1659   }
1660
[1021]1661   /*!
[1278]1662    * Check on freq_off and freq_op attributes.
1663    */
[1405]1664   void CField::checkTimeAttributes(CDuration* freqOp)
[1278]1665   {
[1405]1666     bool isFieldRead  = file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read;
1667     bool isFieldWrite = file && ( file->mode.isEmpty() ||  file->mode == CFile::mode_attr::write);
[1315]1668     if (isFieldRead && operation.getValue() != "instant")
[1405]1669       ERROR("void CField::checkTimeAttributes(void)",
[1315]1670             << "Unsupported operation for field '" << getFieldOutputName() << "'." << std::endl
1671             << "Currently only \"instant\" is supported for fields read from file.")
1672
[1278]1673     if (freq_op.isEmpty())
1674     {
[1315]1675       if (operation.getValue() == "instant")
[1405]1676       {
1677         if (isFieldRead || isFieldWrite) freq_op.setValue(file->output_freq.getValue());
1678         else freq_op=*freqOp ;
1679       }
[1278]1680       else
[1292]1681         freq_op.setValue(TimeStep);
[1278]1682     }
[1306]1683     if (freq_offset.isEmpty())
[1315]1684       freq_offset.setValue(isFieldRead ? NoneDu : (freq_op.getValue() - TimeStep));
[1278]1685   }
1686
1687   /*!
[1021]1688    * Returns string arithmetic expression associated to the field.
1689    * \return if content is defined return content string, otherwise, if "expr" attribute is defined, return expr string.
1690    */
1691   const string& CField::getExpression(void)
1692   {
1693     if (!expr.isEmpty() && content.empty())
1694     {
1695       content = expr;
1696       expr.reset();
1697     }
1698
1699     return content;
1700   }
1701
1702   bool CField::hasExpression(void) const
1703   {
1704     return (!expr.isEmpty() || !content.empty());
1705   }
1706
1707
[540]1708   DEFINE_REF_FUNC(Field,field)
[335]1709} // namespace xios
Note: See TracBrowser for help on using the repository browser.