source: XIOS/dev/branch_openmp/src/node/field.cpp @ 1482

Last change on this file since 1482 was 1482, checked in by yushan, 6 years ago

Branch EP merged with Dev_cmip6 @r1481

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