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

Last change on this file since 1235 was 1235, checked in by mhnguyen, 7 years ago

Fixing a bug on writting axis label

+) Axis label is correctly processed before being written
+) Do some code cleaning and add some comments

Test
+) On Curie
+) OK

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