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

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

Correcting a minor bug on detecting server reading level

+) Reading server level should be 1 (for now). In the future, maybe level-2 server can be used
+) Correct nbReadSenders with the right ContextClient?

Test
+) On Curie
+) Work with toy

  • 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.7 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       {
[1236]145          for (it = grid->storeIndex_toSrv[client].begin(); it != grid->storeIndex_toSrv[client].end(); it++)
[1201]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    {
[1236]165      for (it = grid->storeIndex_toSrv[client].begin(); it != grid->storeIndex_toSrv[client].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;
[1236]177        event.push(rank, grid->nbSenders[client][rank], list_msg.back());
[1201]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:
[1239]378                  msg << int(-2) << recvDataSrv;
[1232]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
[1236]425        event.push(it->first, grid->nbReadSenders[client][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
[1239]799   void CField::sendGridComponentOfEnabledFields()
[1025]800   {
801      solveGridDomainAxisRef(true);
[1239]802      // solveCheckMaskIndex(true);
[1025]803   }
804
[1239]805   void CField::sendGridOfEnabledFields()
806   {
807      // solveGridDomainAxisRef(true);
808      solveCheckMaskIndex(true);
809   }   
[1025]810
[1239]811   void CField::solveOnlyReferenceEnabledField(bool doSending2Server)
[1025]812   {
813     CContext* context = CContext::getCurrent();
814     if (!isReferenceSolved)
815     {
816        isReferenceSolved = true;
817
818        if (context->hasClient && !context->hasServer)
819        {
820          solveRefInheritance(true);
821          if (hasDirectFieldReference()) getDirectFieldReference()->solveOnlyReferenceEnabledField(false);
822        }
[1144]823
[1025]824        if (context->hasServer)
825          solveServerOperation();
826
827        solveGridReference();
828
829        if (context->hasClient && !context->hasServer)
830       {
831         solveGenerateGrid();
832         buildGridTransformationGraph();
833       }
834     }
835   }
836     
[823]837   void CField::solveAllReferenceEnabledField(bool doSending2Server)
838   {
839     CContext* context = CContext::getCurrent();
840     solveOnlyReferenceEnabledField(doSending2Server);
841
842     if (!areAllReferenceSolved)
843     {
844        areAllReferenceSolved = true;
[1144]845       
[983]846        if (context->hasClient && !context->hasServer)
[823]847        {
848          solveRefInheritance(true);
849          if (hasDirectFieldReference()) getDirectFieldReference()->solveAllReferenceEnabledField(false);
850        }
[1158]851        else if (context->hasServer)
[823]852          solveServerOperation();
853
854        solveGridReference();
855     }
856
857     solveGridDomainAxisRef(doSending2Server);
858
[1021]859     if (context->hasClient && !context->hasServer)
[619]860     {
861       solveTransformedGrid();
862     }
[687]863
[823]864     solveCheckMaskIndex(doSending2Server);
[509]865   }
866
[1236]867   std::map<int, StdSize> CField::getGridAttributesBufferSize(CContextClient* client)
[509]868   {
[1236]869     return grid->getAttributesBufferSize(client);
[509]870   }
871
[1236]872   std::map<int, StdSize> CField::getGridDataBufferSize(CContextClient* client)
[731]873   {
[1236]874     return grid->getDataBufferSize(client, getId());
[731]875   }
876
[1215]877   size_t CField::getGlobalWrittenSize()
878   {
879     return grid->getGlobalWrittenSize();
880   }
881
[219]882   //----------------------------------------------------------------
883
[645]884   void CField::solveServerOperation(void)
[219]885   {
[640]886      CContext* context = CContext::getCurrent();
[509]887
[640]888      if (!context->hasServer || !hasOutputFile) return;
889
[645]890      if (freq_op.isEmpty())
891        freq_op.setValue(TimeStep);
[509]892
[538]893      if (freq_offset.isEmpty())
894        freq_offset.setValue(NoneDu);
[219]895
[645]896      freq_operation_srv = file->output_freq.getValue();
897      freq_write_srv     = file->output_freq.getValue();
[509]898
[651]899      lastlast_Write_srv = context->getCalendar()->getInitDate();
900      last_Write_srv     = context->getCalendar()->getInitDate();
901      last_operation_srv = context->getCalendar()->getInitDate();
[509]902
[645]903      const CDuration toffset = freq_operation_srv - freq_offset.getValue() - context->getCalendar()->getTimeStep();
[651]904      last_operation_srv     = last_operation_srv - toffset;
[509]905
[645]906      if (operation.isEmpty())
907        ERROR("void CField::solveServerOperation(void)",
908              << "An operation must be defined for field \"" << getId() << "\".");
[509]909
[645]910      boost::shared_ptr<func::CFunctor> functor;
911      CArray<double, 1> dummyData;
[598]912
[562]913#define DECLARE_FUNCTOR(MType, mtype) \
[645]914      if (operation.getValue().compare(#mtype) == 0) \
[470]915      { \
[645]916        functor.reset(new func::C##MType(dummyData)); \
917      }
[509]918
[219]919#include "functor_type.conf"
[509]920
[645]921      if (!functor)
922        ERROR("void CField::solveServerOperation(void)",
923              << "\"" << operation << "\" is not a valid operation.");
924
925      operationTimeType = functor->timeType();
[219]926   }
[509]927
[219]928   //----------------------------------------------------------------
[640]929
930   /*!
931    * Constructs the graph filter for the field, enabling or not the data output.
932    * This method should not be called more than once with enableOutput equal to true.
933    *
934    * \param gc the garbage collector to use when building the filter graph
935    * \param enableOutput must be true when the field data is to be
936    *                     read by the client or/and written to a file
937    */
938   void CField::buildFilterGraph(CGarbageCollector& gc, bool enableOutput)
[1144]939   {     
[1129]940    if (!isReferenceSolvedAndTransformed) solveAllEnabledFieldsAndTransform();
[1201]941
942     const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
943     const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
944
[1025]945     CContext* context = CContext::getCurrent();
946     bool hasWriterServer = context->hasServer && !context->hasClient;
947     bool hasIntermediateServer = context->hasServer && context->hasClient;
[641]948
[1025]949     if (hasWriterServer)
[640]950     {
[1025]951        if (!instantDataFilter)
[1027]952          instantDataFilter = clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid));
[1025]953
954             // If the field data is to be read by the client or/and written to a file
955       if (enableOutput && !storeFilter && !fileWriterFilter)
956       {
957         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
958         {
959           fileServerWriterFilter = boost::shared_ptr<CFileServerWriterFilter>(new CFileServerWriterFilter(gc, this));
960           instantDataFilter->connectOutput(fileServerWriterFilter, 0);
961         }
962       }
963     }
964     else if (hasIntermediateServer)
965     {
966       if (!instantDataFilter)
[1027]967         instantDataFilter = clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid));
[1025]968
969             // If the field data is to be read by the client or/and written to a file
970       if (enableOutput && !storeFilter && !fileWriterFilter)
971       {
972         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
973         {
974           fileWriterFilter = boost::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
975           instantDataFilter->connectOutput(fileWriterFilter, 0);
976         }
977       }
978     }
979     else
980     {
981       // Start by building a filter which can provide the field's instant data
982       if (!instantDataFilter)
983       {
984         // Check if we have an expression to parse
[1158]985         if (hasExpression())
[1025]986         {
[1158]987           boost::scoped_ptr<IFilterExprNode> expr(parseExpr(getExpression() + '\0'));
988           boost::shared_ptr<COutputPin> filter = expr->reduce(gc, *this);
[1021]989
[1158]990           // Check if a spatial transformation is needed
991           if (!field_ref.isEmpty())
[1021]992           {
[1158]993             CGrid* gridRef = CField::get(field_ref)->grid;
[1021]994
[1158]995             if (grid && grid != gridRef && grid->hasTransform())
996             {
[1201]997                 std::pair<boost::shared_ptr<CFilter>, boost::shared_ptr<CFilter> > filters = CSpatialTransformFilter::buildFilterGraph(gc, gridRef, grid, detectMissingValues, defaultValue); 
[1158]998
999               filter->connectOutput(filters.first, 0);
1000               filter = filters.second;
1001             }
[1021]1002           }
1003
[1158]1004           instantDataFilter = filter;
[1025]1005         }
1006         // Check if we have a reference on another field
1007         else if (!field_ref.isEmpty())
1008           instantDataFilter = getFieldReference(gc);
1009         // Check if the data is to be read from a file
1010         else if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
[1158]1011           instantDataFilter = serverSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid,
1012                                                                                                       freq_offset.isEmpty() ? NoneDu : freq_offset,
[1201]1013                                                                                                       true,
1014                                                                                                       detectMissingValues, defaultValue));
[1025]1015         else // The data might be passed from the model
[1158]1016         {
[1201]1017            if (check_if_active.isEmpty()) check_if_active = false; 
[1158]1018            instantDataFilter = clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, NoneDu, false,
[1201]1019                                                                                                        detectMissingValues, defaultValue));
[1158]1020         }
[1025]1021       }
[640]1022
[1166]1023       // If the field data is to be read by the client or/and written to a file
1024       if (enableOutput && !storeFilter && !fileWriterFilter)
[640]1025       {
[1201]1026         storeFilter = boost::shared_ptr<CStoreFilter>(new CStoreFilter(gc, CContext::getCurrent(), grid,
1027                                                                        detectMissingValues, defaultValue));
1028         instantDataFilter->connectOutput(storeFilter, 0);
1029       }
[640]1030
[1201]1031       if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
1032       {
1033         fileWriterFilter = boost::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
1034         getTemporalDataFilter(gc, file->output_freq)->connectOutput(fileWriterFilter, 0);
[640]1035       }
1036     }
1037   }
1038
[642]1039   /*!
[737]1040    * Returns the filter needed to handle the field reference.
1041    * This method should only be called when building the filter graph corresponding to the field.
1042    *
1043    * \param gc the garbage collector to use
1044    * \return the output pin corresponding to the field reference
1045    */
[1158]1046   boost::shared_ptr<COutputPin> CField::getFieldReference(CGarbageCollector& gc)
1047   {
1048     if (instantDataFilter || field_ref.isEmpty())
1049       ERROR("COutputPin* CField::getFieldReference(CGarbageCollector& gc)",
1050             "Impossible to get the field reference for a field which has already been parsed or which does not have a field_ref.");
[737]1051
[1158]1052     CField* fieldRef = CField::get(field_ref);
1053     fieldRef->buildFilterGraph(gc, false);
[737]1054
[1158]1055     std::pair<boost::shared_ptr<CFilter>, boost::shared_ptr<CFilter> > filters;
1056     // Check if a spatial transformation is needed
1057     if (grid && grid != fieldRef->grid && grid->hasTransform())
1058     {       
1059       bool hasMissingValue = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1060       double defaultValue  = hasMissingValue ? default_value : (!default_value.isEmpty() ? default_value : 0.0);                               
1061       filters = CSpatialTransformFilter::buildFilterGraph(gc, fieldRef->grid, grid, hasMissingValue, defaultValue);
1062     }
1063     else
1064       filters.first = filters.second = boost::shared_ptr<CFilter>(new CPassThroughFilter(gc));
[873]1065
[1158]1066     fieldRef->getInstantDataFilter()->connectOutput(filters.first, 0);
[737]1067
[1158]1068     return filters.second;
1069   }
[737]1070
1071   /*!
1072    * Returns the filter needed to handle a self reference in the field's expression.
1073    * If the needed filter does not exist, it is created, otherwise it is reused.
[642]1074    * This method should only be called when building the filter graph corresponding
1075    * to the field's expression.
1076    *
1077    * \param gc the garbage collector to use
1078    * \return the output pin corresponding to a self reference
1079    */
1080   boost::shared_ptr<COutputPin> CField::getSelfReference(CGarbageCollector& gc)
1081   {
[1021]1082     if (instantDataFilter || !hasExpression())
[642]1083       ERROR("COutputPin* CField::getSelfReference(CGarbageCollector& gc)",
1084             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1085
[737]1086     if (!selfReferenceFilter)
1087     {
[1201]1088       const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1089       const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
1090
[741]1091       if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
1092       {
1093         if (!serverSourceFilter)
[1021]1094           serverSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid,
1095                                                                                   freq_offset.isEmpty() ? NoneDu : freq_offset,
[1201]1096                                                                                   true,
1097                                                                                   detectMissingValues, defaultValue));
1098
[741]1099         selfReferenceFilter = serverSourceFilter;
1100       }
1101       else if (!field_ref.isEmpty())
[1021]1102       {
1103         CField* fieldRef = CField::get(field_ref);
1104         fieldRef->buildFilterGraph(gc, false);
1105         selfReferenceFilter = fieldRef->getInstantDataFilter();
1106       }
[737]1107       else
1108       {
1109         if (!clientSourceFilter)
[1158]1110         {
[1201]1111           if (check_if_active.isEmpty()) check_if_active = false;
[1158]1112           clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, NoneDu, false,
[1201]1113                                                                                   detectMissingValues, defaultValue));
[1158]1114         }
[642]1115
[737]1116         selfReferenceFilter = clientSourceFilter;
1117       }
1118     }
1119
1120     return selfReferenceFilter;
[642]1121   }
1122
[643]1123   /*!
1124    * Returns the temporal filter corresponding to the field's temporal operation
1125    * for the specified operation frequency. The filter is created if it does not
1126    * exist, otherwise it is reused.
1127    *
1128    * \param gc the garbage collector to use
1129    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1130    * \return the output pin corresponding to the requested temporal filter
1131    */
1132   boost::shared_ptr<COutputPin> CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1133   {
1134     std::map<CDuration, boost::shared_ptr<COutputPin> >::iterator it = temporalDataFilters.find(outFreq);
1135
1136     if (it == temporalDataFilters.end())
1137     {
1138       if (operation.isEmpty())
1139         ERROR("void CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1140               << "An operation must be defined for field \"" << getId() << "\".");
1141
1142       if (freq_op.isEmpty())
1143         freq_op.setValue(TimeStep);
1144       if (freq_offset.isEmpty())
1145         freq_offset.setValue(NoneDu);
1146
[1201]1147       const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1148       
[643]1149       boost::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1150                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
1151                                                                             freq_op, freq_offset, outFreq,
[1201]1152                                                                             detectMissingValues, detectMissingValues ? default_value : 0.0));
[643]1153       instantDataFilter->connectOutput(temporalFilter, 0);
1154
1155       it = temporalDataFilters.insert(std::make_pair(outFreq, temporalFilter)).first;
1156     }
1157
1158     return it->second;
1159   }
1160
[1158]1161  /*!
1162    * Returns the temporal filter corresponding to the field's temporal operation
1163    * for the specified operation frequency.
1164    *
1165    * \param gc the garbage collector to use
1166    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1167    * \return the output pin corresponding to the requested temporal filter
1168    */
1169   
1170   boost::shared_ptr<COutputPin> CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1171   {
1172     if (instantDataFilter || !hasExpression())
1173       ERROR("COutputPin* CField::getSelfTemporalDataFilter(CGarbageCollector& gc)",
1174             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1175
1176     if (!selfReferenceFilter) getSelfReference(gc) ;
1177
1178     if (serverSourceFilter || clientSourceFilter)
1179     {
1180       if (operation.isEmpty())
1181         ERROR("void CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1182               << "An operation must be defined for field \"" << getId() << "\".");
1183
1184       if (freq_op.isEmpty()) freq_op.setValue(TimeStep);
1185       if (freq_offset.isEmpty()) freq_offset.setValue(NoneDu);
1186
[1201]1187       const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
[1158]1188
1189       boost::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1190                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
1191                                                                             freq_op, freq_offset, outFreq,
[1201]1192                                                                             detectMissingValues, detectMissingValues ? default_value : 0.0));
[1158]1193       selfReferenceFilter->connectOutput(temporalFilter, 0);
1194       return temporalFilter ;
1195     }
1196     else if (!field_ref.isEmpty())
1197     {
1198       CField* fieldRef = CField::get(field_ref);
1199       fieldRef->buildFilterGraph(gc, false); 
1200       return fieldRef->getTemporalDataFilter(gc, outFreq) ;
1201     }
1202  }
1203
[640]1204   //----------------------------------------------------------------
[369]1205/*
[562]1206   void CField::fromBinary(StdIStream& is)
[219]1207   {
1208      SuperClass::fromBinary(is);
1209#define CLEAR_ATT(name_)\
[369]1210      SuperClassAttribute::operator[](#name_)->reset()
[219]1211
1212         CLEAR_ATT(domain_ref);
1213         CLEAR_ATT(axis_ref);
1214#undef CLEAR_ATT
1215
1216   }
[369]1217*/
[219]1218   //----------------------------------------------------------------
1219
1220   void CField::solveGridReference(void)
1221   {
[887]1222      if (grid_ref.isEmpty() && domain_ref.isEmpty() && axis_ref.isEmpty() && scalar_ref.isEmpty())
[742]1223      {
1224        ERROR("CField::solveGridReference(void)",
[770]1225              << "A grid must be defined for field '" << getFieldOutputName() << "' .");
[742]1226      }
[887]1227      else if (!grid_ref.isEmpty() && (!domain_ref.isEmpty() || !axis_ref.isEmpty() || !scalar_ref.isEmpty()))
[219]1228      {
[744]1229        ERROR("CField::solveGridReference(void)",
[887]1230              << "Field '" << getFieldOutputName() << "' has both a grid and a domain/axis/scalar." << std::endl
1231              << "Please define either 'grid_ref' or 'domain_ref'/'axis_ref'/'scalar_ref'.");
[219]1232      }
1233
[744]1234      if (grid_ref.isEmpty())
[219]1235      {
[744]1236        std::vector<CDomain*> vecDom;
1237        std::vector<CAxis*> vecAxis;
[887]1238        std::vector<CScalar*> vecScalar;
[894]1239        std::vector<int> axisDomainOrderTmp;
1240       
[744]1241        if (!domain_ref.isEmpty())
1242        {
[823]1243          StdString tmp = domain_ref.getValue();
[744]1244          if (CDomain::has(domain_ref))
[894]1245          {
[744]1246            vecDom.push_back(CDomain::get(domain_ref));
[894]1247            axisDomainOrderTmp.push_back(2);
1248          }
[744]1249          else
[219]1250            ERROR("CField::solveGridReference(void)",
[744]1251                  << "Invalid reference to domain '" << domain_ref.getValue() << "'.");
1252        }
[219]1253
[744]1254        if (!axis_ref.isEmpty())
[742]1255        {
[744]1256          if (CAxis::has(axis_ref))
[894]1257          {
[744]1258            vecAxis.push_back(CAxis::get(axis_ref));
[894]1259            axisDomainOrderTmp.push_back(1);
1260          }
[744]1261          else
1262            ERROR("CField::solveGridReference(void)",
1263                  << "Invalid reference to axis '" << axis_ref.getValue() << "'.");
[742]1264        }
[744]1265
[887]1266        if (!scalar_ref.isEmpty())
1267        {
1268          if (CScalar::has(scalar_ref))
[894]1269          {
[887]1270            vecScalar.push_back(CScalar::get(scalar_ref));
[894]1271            axisDomainOrderTmp.push_back(0);
1272          }
[887]1273          else
1274            ERROR("CField::solveGridReference(void)",
1275                  << "Invalid reference to scalar '" << scalar_ref.getValue() << "'.");
1276        }
[894]1277       
1278        CArray<int,1> axisDomainOrder(axisDomainOrderTmp.size());
1279        for (int idx = 0; idx < axisDomainOrderTmp.size(); ++idx)
1280        {
1281          axisDomainOrder(idx) = axisDomainOrderTmp[idx];
1282        }
[887]1283
[745]1284        // Warning: the gridId shouldn't be set as the grid_ref since it could be inherited
[894]1285        StdString gridId = CGrid::generateId(vecDom, vecAxis, vecScalar,axisDomainOrder);
[745]1286        if (CGrid::has(gridId))
1287          this->grid = CGrid::get(gridId);
1288        else
[894]1289          this->grid = CGrid::createGrid(gridId, vecDom, vecAxis, vecScalar,axisDomainOrder);
[219]1290      }
[586]1291      else
1292      {
[744]1293        if (CGrid::has(grid_ref))
1294          this->grid = CGrid::get(grid_ref);
1295        else
1296          ERROR("CField::solveGridReference(void)",
1297                << "Invalid reference to grid '" << grid_ref.getValue() << "'.");
[586]1298      }
[509]1299   }
[459]1300
[509]1301   void CField::solveGridDomainAxisRef(bool checkAtt)
1302   {
1303     grid->solveDomainAxisRef(checkAtt);
[219]1304   }
1305
[509]1306   void CField::solveCheckMaskIndex(bool doSendingIndex)
1307   {
1308     grid->checkMaskIndex(doSendingIndex);
1309   }
[219]1310
[619]1311   void CField::solveTransformedGrid()
1312   {
[746]1313     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
[790]1314     {
1315       std::vector<CGrid*> grids;
1316       // Source grid
1317       grids.push_back(getDirectFieldReference()->grid);
1318       // Intermediate grids
1319       if (!grid_path.isEmpty())
1320       {
1321         std::string gridId;
1322         size_t start = 0, end;
1323
1324         do
1325         {
1326           end = grid_path.getValue().find(',', start);
1327           if (end != std::string::npos)
1328           {
1329             gridId = grid_path.getValue().substr(start, end - start);
1330             start = end + 1;
1331           }
1332           else
1333             gridId = grid_path.getValue().substr(start);
1334
1335           if (!CGrid::has(gridId))
1336             ERROR("void CField::solveTransformedGrid()",
1337                   << "Invalid grid_path, the grid '" << gridId << "' does not exist.");
1338
1339           grids.push_back(CGrid::get(gridId));
1340         }
1341         while (end != std::string::npos);
1342       }
1343       // Destination grid
1344       grids.push_back(grid);
1345
1346       for (size_t i = 0, count = grids.size() - 1; i < count; ++i)
1347       {
1348         CGrid *gridSrc  = grids[i];
1349         CGrid *gridDest = grids[i + 1];
1350         if (!gridDest->isTransformed())
1351           gridDest->transformGrid(gridSrc);
1352       }
1353     }
[934]1354     else if (grid && grid->hasTransform() && !grid->isTransformed())
1355     {
[1021]1356       // Temporarily deactivate the self-transformation of grid
1357       //grid->transformGrid(grid);
[934]1358     }
[619]1359   }
1360
[687]1361   void CField::solveGenerateGrid()
1362   {
[746]1363     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
[687]1364       grid->completeGrid(getDirectFieldReference()->grid);
[775]1365     else
1366       grid->completeGrid();
[687]1367   }
1368
[775]1369   void CField::solveGridDomainAxisBaseRef()
1370   {
1371     grid->solveDomainAxisRef(false);
1372     grid->solveDomainAxisBaseRef();
1373   }
1374
[219]1375   ///-------------------------------------------------------------------
1376
1377   template <>
[562]1378   void CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)
[219]1379   {
1380      if (this->group_ref.isEmpty()) return;
1381      StdString gref = this->group_ref.getValue();
1382
[346]1383      if (!CFieldGroup::has(gref))
[219]1384         ERROR("CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)",
1385               << "[ gref = " << gref << "]"
1386               << " invalid group name !");
1387
[347]1388      CFieldGroup* group = CFieldGroup::get(gref);
1389      CFieldGroup* owner = CFieldGroup::get(boost::polymorphic_downcast<CFieldGroup*>(this));
[219]1390
[347]1391      std::vector<CField*> allChildren  = group->getAllChildren();
[562]1392      std::vector<CField*>::iterator it = allChildren.begin(), end = allChildren.end();
[509]1393
[219]1394      for (; it != end; it++)
1395      {
[347]1396         CField* child = *it;
[562]1397         if (child->hasId()) owner->createChild()->field_ref.setValue(child->getId());
[509]1398
[219]1399      }
1400   }
[509]1401
[464]1402   void CField::scaleFactorAddOffset(double scaleFactor, double addOffset)
1403   {
[1136]1404     recvDataSrv = (recvDataSrv - addOffset) / scaleFactor;
[464]1405   }
[509]1406
[599]1407   void CField::invertScaleFactorAddOffset(double scaleFactor, double addOffset)
1408   {
[1136]1409     recvDataSrv = recvDataSrv * scaleFactor + addOffset;
[599]1410   }
1411
[567]1412   void CField::outputField(CArray<double,1>& fieldOut)
[1136]1413   { 
[1129]1414      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1415      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1416      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1417      {
1418        fieldOut(outIndexServer(idx)) = recvDataSrv(outIndexClient(idx));
1419      }
[1136]1420   }
[1129]1421
[1136]1422   void CField::inputField(CArray<double,1>& fieldIn)
1423   {
1424      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1425      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1426      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
[599]1427      {
[1136]1428        recvDataSrv(outIndexClient(idx)) = fieldIn(outIndexServer(idx));
[599]1429      }
1430
1431   }
1432
[676]1433   void CField::outputCompressedField(CArray<double,1>& fieldOut)
1434   {
[1143]1435      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1436      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1437      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
[676]1438      {
[1143]1439        fieldOut((idx)) = recvDataSrv(outIndexClient(idx));
[676]1440      }
1441   }
1442
[219]1443   ///-------------------------------------------------------------------
1444
[562]1445   void CField::parse(xml::CXMLNode& node)
[459]1446   {
1447      SuperClass::parse(node);
[562]1448      if (!node.getContent(this->content))
[472]1449      {
[476]1450        if (node.goToChildElement())
[472]1451        {
[476]1452          do
1453          {
[562]1454            if (node.getElementName() == "variable" || node.getElementName() == "variable_group") this->getVirtualVariableGroup()->parseChild(node);
1455          } while (node.goToNextElement());
[476]1456          node.goToParentElement();
1457        }
[472]1458      }
[459]1459    }
[509]1460
1461   /*!
1462     This function retrieves Id of corresponding domain_ref and axis_ref (if any)
1463   of a field. In some cases, only domain exists but axis doesn't
1464   \return pair of Domain and Axis id
1465   */
[887]1466   const std::vector<StdString>& CField::getRefDomainAxisIds()
[569]1467   {
1468     CGrid* cgPtr = getRelGrid();
1469     if (NULL != cgPtr)
1470     {
1471       std::vector<StdString>::iterator it;
1472       if (!domain_ref.isEmpty())
1473       {
1474         std::vector<StdString> domainList = cgPtr->getDomainList();
1475         it = std::find(domainList.begin(), domainList.end(), domain_ref.getValue());
[887]1476         if (domainList.end() != it) domAxisScalarIds_[0] = *it;
[569]1477       }
[472]1478
[569]1479       if (!axis_ref.isEmpty())
1480       {
1481         std::vector<StdString> axisList = cgPtr->getAxisList();
1482         it = std::find(axisList.begin(), axisList.end(), axis_ref.getValue());
[887]1483         if (axisList.end() != it) domAxisScalarIds_[1] = *it;
[569]1484       }
[887]1485
1486       if (!scalar_ref.isEmpty())
1487       {
1488         std::vector<StdString> scalarList = cgPtr->getScalarList();
1489         it = std::find(scalarList.begin(), scalarList.end(), scalar_ref.getValue());
1490         if (scalarList.end() != it) domAxisScalarIds_[2] = *it;
1491       }
[569]1492     }
[887]1493     return (domAxisScalarIds_);
[569]1494   }
1495
[472]1496   CVariable* CField::addVariable(const string& id)
1497   {
[562]1498     return vVariableGroup->createChild(id);
[472]1499   }
1500
1501   CVariableGroup* CField::addVariableGroup(const string& id)
1502   {
[562]1503     return vVariableGroup->createChildGroup(id);
[472]1504   }
1505
[1021]1506   void CField::sendAddAllVariables(CContextClient* client)
[1009]1507   {
1508     std::vector<CVariable*> allVar = getAllVariables();
1509     std::vector<CVariable*>::const_iterator it = allVar.begin();
1510     std::vector<CVariable*>::const_iterator itE = allVar.end();
1511
1512     for (; it != itE; ++it)
1513     {
[1021]1514       this->sendAddVariable((*it)->getId(), client);
1515       (*it)->sendAllAttributesToServer(client);
1516       (*it)->sendValue(client);
[1009]1517     }
1518   }
1519
[1021]1520   void CField::sendAddVariable(const string& id, CContextClient* client)
1521   {
1522      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE, client);
1523   }
1524
[1144]1525   void CField::sendAddVariableGroup(const string& id, CContextClient* client)
[472]1526   {
[1144]1527      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE_GROUP, client);
[472]1528   }
[509]1529
[472]1530   void CField::recvAddVariable(CEventServer& event)
1531   {
[509]1532
[562]1533      CBufferIn* buffer = event.subEvents.begin()->buffer;
[472]1534      string id;
[562]1535      *buffer >> id;
1536      get(id)->recvAddVariable(*buffer);
[472]1537   }
[509]1538
[472]1539   void CField::recvAddVariable(CBufferIn& buffer)
1540   {
[562]1541      string id;
1542      buffer >> id;
1543      addVariable(id);
[472]1544   }
1545
1546   void CField::recvAddVariableGroup(CEventServer& event)
1547   {
[509]1548
[562]1549      CBufferIn* buffer = event.subEvents.begin()->buffer;
[472]1550      string id;
[562]1551      *buffer >> id;
1552      get(id)->recvAddVariableGroup(*buffer);
[472]1553   }
[509]1554
[472]1555   void CField::recvAddVariableGroup(CBufferIn& buffer)
1556   {
[562]1557      string id;
1558      buffer >> id;
1559      addVariableGroup(id);
[472]1560   }
1561
[1021]1562   /*!
1563    * Returns string arithmetic expression associated to the field.
1564    * \return if content is defined return content string, otherwise, if "expr" attribute is defined, return expr string.
1565    */
1566   const string& CField::getExpression(void)
1567   {
1568     if (!expr.isEmpty() && content.empty())
1569     {
1570       content = expr;
1571       expr.reset();
1572     }
1573
1574     return content;
1575   }
1576
1577   bool CField::hasExpression(void) const
1578   {
1579     return (!expr.isEmpty() || !content.empty());
1580   }
1581
1582
[540]1583   DEFINE_REF_FUNC(Field,field)
[335]1584} // namespace xios
Note: See TracBrowser for help on using the repository browser.