source: XIOS/dev/dev_olga/src/node/field.cpp @ 1211

Last change on this file since 1211 was 1201, checked in by oabramkina, 7 years ago

Two server levels: merging trunk r1200 (except for non-contiguous zoom) into dev. Tested on Curie. Todo: non-contiguous zoom.

  • 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: 49.0 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)
[1158]43      , isEOF(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)
[1158]58      , isEOF(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
[1201]141    if (!grid->doGridHaveDataDistributed())
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  {
[562]264    if (!getRelFile()->allDomainEmpty)
[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
[1158]275  bool CField::sendReadDataRequest(const CDate& tsDataRequested)
[598]276  {
277    CContext* context = CContext::getCurrent();
[1201]278//    CContextClient* client = context->client;
[1071]279    CContextClient* client = (!context->hasServer) ? context->client : this->file->getContextClient();
[598]280
[1021]281    lastDataRequestedFromServer = tsDataRequested;
[708]282
[1158]283    if (!isEOF) // No need to send the request if we already know we are at EOF
[598]284    {
[1158]285      CEventClient event(getType(), EVENT_ID_READ_DATA);
286      if (client->isServerLeader())
287      {
288        CMessage msg;
289        msg << getId();
290        const std::list<int>& ranks = client->getRanksServerLeader();
291        for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
292          event.push(*itRank, 1, msg);
293        client->sendEvent(event);
294      }
295      else client->sendEvent(event);
[598]296    }
[1158]297    else
298      serverSourceFilter->signalEndOfStream(tsDataRequested);
299
300    return !isEOF;
[598]301  }
302
303  /*!
304  Send request new data read from file if need be, that is the current data is out-of-date.
305  \return true if and only if some data was requested
306  */
307  bool CField::sendReadDataRequestIfNeeded(void)
308  {
309    const CDate& currentDate = CContext::getCurrent()->getCalendar()->getCurrentDate();
310
[1021]311    bool dataRequested = false;
[1158]312
[1021]313    while (currentDate >= lastDataRequestedFromServer)
[850]314    {
[1021]315      info(20) << "currentDate : " << currentDate << endl ;
316      info(20) << "lastDataRequestedFromServer : " << lastDataRequestedFromServer << endl ;
317      info(20) << "file->output_freq.getValue() : " << file->output_freq.getValue() << endl ;
318      info(20) << "lastDataRequestedFromServer + file->output_freq.getValue() : " << lastDataRequestedFromServer + file->output_freq << endl ;
[873]319
[1158]320      dataRequested |= sendReadDataRequest(lastDataRequestedFromServer + file->output_freq);
321    }
[1021]322
323    return dataRequested;
[598]324  }
325
326  void CField::recvReadDataRequest(CEventServer& event)
327  {
328    CBufferIn* buffer = event.subEvents.begin()->buffer;
329    StdString fieldId;
330    *buffer >> fieldId;
331    get(fieldId)->recvReadDataRequest();
332  }
333
334  void CField::recvReadDataRequest(void)
335  {
336    CContext* context = CContext::getCurrent();
[1158]337    CContextClient* client = context->client;
[1201]338//    CContextClient* client = (!context->hasServer) ? context->client : this->file->getContextClient();
[598]339
340    CEventClient event(getType(), EVENT_ID_READ_DATA_READY);
341    std::list<CMessage> msgs;
342
[599]343    bool hasData = readField();
[598]344
[1158]345    map<int, CArray<double,1> >::iterator it;
[1021]346    if (!grid->doGridHaveDataDistributed())
[598]347    {
[1021]348       if (client->isServerLeader())
349       {
[1136]350          if (0 != recvDataSrv.numElements())
351          {           
[1021]352            const std::list<int>& ranks = client->getRanksServerLeader();
353            for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
354            {
355              msgs.push_back(CMessage());
356              CMessage& msg = msgs.back();
357              msg << getId();
358              if (hasData)
[1136]359                msg << getNStep() - 1 << recvDataSrv;
[1021]360              else
361                msg << int(-1);
362              event.push(*itRank, 1, msg);
363            }
364          }
365          client->sendEvent(event);
366       }
367       else
368       {
369          client->sendEvent(event);
370       }
[598]371    }
[1021]372    else
373    {
[1136]374      for (map<int, CArray<size_t, 1> >::iterator it = grid->outLocalIndexStoreOnClient.begin(); 
375                                                  it != grid->outLocalIndexStoreOnClient.end(); ++it)
[1021]376      {
[1136]377        CArray<size_t,1>& indexTmp = it->second;
378        CArray<double,1> tmp(indexTmp.numElements());
379        for (int idx = 0; idx < indexTmp.numElements(); ++idx)
380        {
381          tmp(idx) = recvDataSrv(indexTmp(idx));
382        } 
383
[1021]384        msgs.push_back(CMessage());
385        CMessage& msg = msgs.back();
386        msg << getId();
387        if (hasData)
[1136]388          msg << getNStep() - 1 << tmp;
[1021]389        else
390          msg << int(-1);
[1136]391        event.push(it->first, grid->nbReadSenders[0][it->first], msg);
[1021]392      }
393      client->sendEvent(event);
394    }
[599]395  }
[598]396
[599]397  bool CField::readField(void)
398  {
[1136]399    grid->computeWrittenIndex();
[599]400    if (!getRelFile()->allDomainEmpty)
401    {
402      if (grid->doGridHaveDataToWrite() || getRelFile()->type == CFile::type_attr::one_file)
403      {
[1136]404        if (0 == recvDataSrv.numElements())
405        {           
406          CArray<int,1>& storeClient = grid->storeIndex_client;         
407          recvDataSrv.resize(storeClient.numElements());         
[599]408        }
409
[1136]410        getRelFile()->checkReadFile();
[599]411        if (!nstepMax)
412        {
413          nstepMax = getRelFile()->getDataInput()->getFieldNbRecords(CField::get(this));
414        }
[873]415
[850]416        this->incrementNStep();
[599]417
[850]418        if (getNStep() > nstepMax && (getRelFile()->cyclic.isEmpty() || !getRelFile()->cyclic) )
[599]419          return false;
420
421        getRelFile()->getDataInput()->readFieldData(CField::get(this));
422      }
423    }
424
425    return true;
[598]426  }
427
428  void CField::recvReadDataReady(CEventServer& event)
429  {
430    string fieldId;
431    vector<int> ranks;
432    vector<CBufferIn*> buffers;
433
434    list<CEventServer::SSubEvent>::iterator it;
435    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
436    {
437      ranks.push_back(it->rank);
438      CBufferIn* buffer = it->buffer;
439      *buffer >> fieldId;
440      buffers.push_back(buffer);
441    }
442    get(fieldId)->recvReadDataReady(ranks, buffers);
443  }
444
445  void CField::recvReadDataReady(vector<int> ranks, vector<CBufferIn*> buffers)
446  {
447    CContext* context = CContext::getCurrent();
[959]448    int record;
[640]449    std::map<int, CArray<double,1> > data;
450
[598]451    for (int i = 0; i < ranks.size(); i++)
452    {
453      int rank = ranks[i];
[599]454      *buffers[i] >> record;
[959]455      isEOF = (record == int(-1));
[598]456
[599]457      if (!isEOF)
[640]458        *buffers[i] >> data[rank];
459      else
460        break;
461    }
462
[1021]463    if (wasDataAlreadyReceivedFromServer)
464      lastDataReceivedFromServer = lastDataReceivedFromServer + file->output_freq;
465    else
466    {
467      lastDataReceivedFromServer = context->getCalendar()->getInitDate();
468      wasDataAlreadyReceivedFromServer = true;
469    }
470
[640]471    if (isEOF)
[1021]472      serverSourceFilter->signalEndOfStream(lastDataReceivedFromServer);
[640]473    else
[1021]474      serverSourceFilter->streamDataFromServer(lastDataReceivedFromServer, data);
[598]475  }
476
[219]477   //----------------------------------------------------------------
478
[347]479   void CField::setRelFile(CFile* _file)
[509]480   {
[459]481      this->file = _file;
[562]482      hasOutputFile = true;
[219]483   }
484
485   //----------------------------------------------------------------
486
[562]487   StdString CField::GetName(void)    { return StdString("field"); }
488   StdString CField::GetDefName(void) { return CField::GetName(); }
489   ENodeType CField::GetType(void)    { return eField; }
[219]490
491   //----------------------------------------------------------------
492
[347]493   CGrid* CField::getRelGrid(void) const
[509]494   {
[562]495      return this->grid;
[219]496   }
497
498   //----------------------------------------------------------------
499
[347]500   CFile* CField::getRelFile(void) const
[509]501   {
[562]502      return this->file;
[219]503   }
[509]504
[952]505   int CField::getNStep(void) const
[266]506   {
[562]507      return this->nstep;
[266]508   }
[509]509
[645]510   func::CFunctor::ETimeType CField::getOperationTimeType() const
511   {
512     return operationTimeType;
513   }
514
515   //----------------------------------------------------------------
516
[266]517   void CField::incrementNStep(void)
518   {
519      this->nstep++;
520   }
[509]521
[952]522   void CField::resetNStep(int nstep /*= 0*/)
[321]523   {
[707]524      this->nstep = nstep;
[321]525   }
[219]526
[599]527   void CField::resetNStepMax(void)
528   {
529      this->nstepMax = 0;
530   }
531
[219]532   //----------------------------------------------------------------
533
[1158]534   bool CField::isActive(bool atCurrentTimestep /*= false*/) const
[509]535   {
[1158]536      if (clientSourceFilter)
537        return atCurrentTimestep ? clientSourceFilter->isDataExpected(CContext::getCurrent()->getCalendar()->getCurrentDate()) : true;
538      else if (storeFilter)
539        return true;
540      else if (instantDataFilter)
541        ERROR("bool CField::isActive(bool atCurrentTimestep)",
542              << "Impossible to check if field [ id = " << getId() << " ] is active as it cannot be used to receive nor send data.");
543
544      return false;
[310]545   }
[562]546
[219]547   //----------------------------------------------------------------
[509]548
[707]549   bool CField::wasWritten() const
550   {
551     return written;
552   }
553
554   void CField::setWritten()
555   {
556     written = true;
557   }
558
559   //----------------------------------------------------------------
560
[676]561   bool CField::getUseCompressedOutput() const
562   {
563     return useCompressedOutput;
564   }
565
566   void CField::setUseCompressedOutput()
567   {
568     useCompressedOutput = true;
569   }
570
571   //----------------------------------------------------------------
572
[641]573   boost::shared_ptr<COutputPin> CField::getInstantDataFilter()
574   {
575     return instantDataFilter;
576   }
577
578   //----------------------------------------------------------------
579
[823]580   /*!
581     Build up graph of grids which plays role of destination and source in grid transformation
582     This function should be called before \func solveGridReference()
583   */
584   void CField::buildGridTransformationGraph()
585   {
586     CContext* context = CContext::getCurrent();
[983]587     if (context->hasClient && !context->hasServer)
[687]588     {
[823]589       if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
590       {
591         grid->addTransGridSource(getDirectFieldReference()->grid);
592       }
[687]593     }
[823]594   }
[687]595
[823]596   /*!
597     Generate a new grid destination if there are more than one grid source pointing to a same grid destination
598   */
599   void CField::generateNewTransformationGridDest()
600   {
601     CContext* context = CContext::getCurrent();
[983]602     if (context->hasClient && !context->hasServer)
[823]603     {
604       std::map<CGrid*,std::pair<bool,StdString> >& gridSrcMap = grid->getTransGridSource();
605       if (1 < gridSrcMap.size())
606       {
607         // Search for grid source
608         CGrid* gridSrc = grid;
609         CField* currField = this;
610         std::vector<CField*> hieraField;
[687]611
[823]612         while (currField->hasDirectFieldReference() && (gridSrc == grid))
613         {
614           hieraField.push_back(currField);
615           CField* tmp = currField->getDirectFieldReference();
616           currField = tmp;
617           gridSrc = currField->grid;
618         }
619
620         if (gridSrcMap.end() != gridSrcMap.find(gridSrc))
621         {
622           CGrid* gridTmp;
623           std::pair<bool,StdString> newGridDest = gridSrcMap[gridSrc];
624           if (newGridDest.first)
625           {
626             StdString newIdGridDest = newGridDest.second;
627             if (!CGrid::has(newIdGridDest))
628             {
629                ERROR("CGrid* CGrid::generateNewTransformationGridDest()",
630                  << " Something wrong happened! Grid whose id " << newIdGridDest
631                  << "should exist ");
632             }
633             gridTmp = CGrid::get(newIdGridDest);
634           }
635           else
636           {
637             StdString newIdGridDest = CGrid::generateId(gridSrc, grid);
638             gridTmp = CGrid::cloneGrid(newIdGridDest, grid);
639
640             (gridSrcMap[gridSrc]).first = true;
641             (gridSrcMap[gridSrc]).second = newIdGridDest;
642           }
643
644           // Update all descendants
645           for (std::vector<CField*>::iterator it = hieraField.begin(); it != hieraField.end(); ++it)
646           {
647             (*it)->grid = gridTmp;
648             (*it)->updateRef((*it)->grid);
649           }
650         }
651       }
652     }
653   }
654
655   void CField::updateRef(CGrid* grid)
656   {
657     if (!grid_ref.isEmpty()) grid_ref.setValue(grid->getId());
658     else
659     {
660       std::vector<CAxis*> axisTmp = grid->getAxis();
661       std::vector<CDomain*> domainTmp = grid->getDomains();
662       if ((1<axisTmp.size()) || (1<domainTmp.size()))
663         ERROR("void CField::updateRef(CGrid* grid)",
664           << "More than one domain or axis is available for domain_ref/axis_ref of field " << this->getId());
665
666       if ((!domain_ref.isEmpty()) && (domainTmp.empty()))
667         ERROR("void CField::updateRef(CGrid* grid)",
668           << "Incoherent between available domain and domain_ref of field " << this->getId());
669       if ((!axis_ref.isEmpty()) && (axisTmp.empty()))
670         ERROR("void CField::updateRef(CGrid* grid)",
671           << "Incoherent between available axis and axis_ref of field " << this->getId());
672
673       if (!domain_ref.isEmpty()) domain_ref.setValue(domainTmp[0]->getId());
674       if (!axis_ref.isEmpty()) axis_ref.setValue(axisTmp[0]->getId());
675     }
676   }
[1025]677   
[1129]678   /*!
679     Solve reference of all enabled fields even the source fields .
680     In this step, we do transformations.
681   */
682   void CField::solveAllEnabledFieldsAndTransform()
[1025]683   {
684     CContext* context = CContext::getCurrent();
685     bool hasClient = context->hasClient;
686     bool hasServer = context->hasServer;
[823]687
[1129]688     if (!isReferenceSolvedAndTransformed)
[1025]689     {
[1129]690        isReferenceSolvedAndTransformed = true;
[1025]691
692        if (hasClient && !hasServer)
693        {
694          solveRefInheritance(true);
[1129]695          if (hasDirectFieldReference()) getDirectFieldReference()->solveAllEnabledFieldsAndTransform();
[1025]696        }
697
698        if (hasServer)
699          solveServerOperation();
700
701        solveGridReference();
702
703        if (hasClient && !hasServer)
704       {
705         solveGenerateGrid();
706         buildGridTransformationGraph();
707       }
708
709       solveGridDomainAxisRef(false);
710
711       if (hasClient && !hasServer)
712       {
713         solveTransformedGrid();
714       }
715
716       solveGridDomainAxisRef(false);
717     }
718   }
719
720   void CField::checkGridOfEnabledFields()
721   {
722      solveCheckMaskIndex(false);
723   }
724
725   void CField::sendGridOfEnabledFields()
726   {
727      solveGridDomainAxisRef(true);
728      solveCheckMaskIndex(true);
729   }
730
731
732    void CField::solveOnlyReferenceEnabledField(bool doSending2Server)
733   {
734     CContext* context = CContext::getCurrent();
735     if (!isReferenceSolved)
736     {
737        isReferenceSolved = true;
738
739        if (context->hasClient && !context->hasServer)
740        {
741          solveRefInheritance(true);
742          if (hasDirectFieldReference()) getDirectFieldReference()->solveOnlyReferenceEnabledField(false);
743        }
[1144]744
[1025]745        if (context->hasServer)
746          solveServerOperation();
747
748        solveGridReference();
749
750        if (context->hasClient && !context->hasServer)
751       {
752         solveGenerateGrid();
753         buildGridTransformationGraph();
754       }
755     }
756   }
757     
[823]758   void CField::solveAllReferenceEnabledField(bool doSending2Server)
759   {
760     CContext* context = CContext::getCurrent();
761     solveOnlyReferenceEnabledField(doSending2Server);
762
763     if (!areAllReferenceSolved)
764     {
765        areAllReferenceSolved = true;
[1144]766       
[983]767        if (context->hasClient && !context->hasServer)
[823]768        {
769          solveRefInheritance(true);
770          if (hasDirectFieldReference()) getDirectFieldReference()->solveAllReferenceEnabledField(false);
771        }
[1158]772        else if (context->hasServer)
[823]773          solveServerOperation();
774
775        solveGridReference();
776     }
777
778     solveGridDomainAxisRef(doSending2Server);
779
[1021]780     if (context->hasClient && !context->hasServer)
[619]781     {
782       solveTransformedGrid();
783     }
[687]784
[823]785     solveCheckMaskIndex(doSending2Server);
[509]786   }
787
[731]788   std::map<int, StdSize> CField::getGridAttributesBufferSize()
[509]789   {
[731]790     return grid->getAttributesBufferSize();
[509]791   }
792
[1099]793   std::vector<std::map<int, StdSize> > CField::getGridDataBufferSize()
[731]794   {
795     return grid->getDataBufferSize(getId());
796   }
797
[219]798   //----------------------------------------------------------------
799
[645]800   void CField::solveServerOperation(void)
[219]801   {
[640]802      CContext* context = CContext::getCurrent();
[509]803
[640]804      if (!context->hasServer || !hasOutputFile) return;
805
[645]806      if (freq_op.isEmpty())
807        freq_op.setValue(TimeStep);
[509]808
[538]809      if (freq_offset.isEmpty())
810        freq_offset.setValue(NoneDu);
[219]811
[645]812      freq_operation_srv = file->output_freq.getValue();
813      freq_write_srv     = file->output_freq.getValue();
[509]814
[651]815      lastlast_Write_srv = context->getCalendar()->getInitDate();
816      last_Write_srv     = context->getCalendar()->getInitDate();
817      last_operation_srv = context->getCalendar()->getInitDate();
[509]818
[645]819      const CDuration toffset = freq_operation_srv - freq_offset.getValue() - context->getCalendar()->getTimeStep();
[651]820      last_operation_srv     = last_operation_srv - toffset;
[509]821
[645]822      if (operation.isEmpty())
823        ERROR("void CField::solveServerOperation(void)",
824              << "An operation must be defined for field \"" << getId() << "\".");
[509]825
[645]826      boost::shared_ptr<func::CFunctor> functor;
827      CArray<double, 1> dummyData;
[598]828
[562]829#define DECLARE_FUNCTOR(MType, mtype) \
[645]830      if (operation.getValue().compare(#mtype) == 0) \
[470]831      { \
[645]832        functor.reset(new func::C##MType(dummyData)); \
833      }
[509]834
[219]835#include "functor_type.conf"
[509]836
[645]837      if (!functor)
838        ERROR("void CField::solveServerOperation(void)",
839              << "\"" << operation << "\" is not a valid operation.");
840
841      operationTimeType = functor->timeType();
[219]842   }
[509]843
[219]844   //----------------------------------------------------------------
[640]845
846   /*!
847    * Constructs the graph filter for the field, enabling or not the data output.
848    * This method should not be called more than once with enableOutput equal to true.
849    *
850    * \param gc the garbage collector to use when building the filter graph
851    * \param enableOutput must be true when the field data is to be
852    *                     read by the client or/and written to a file
853    */
854   void CField::buildFilterGraph(CGarbageCollector& gc, bool enableOutput)
[1144]855   {     
[1129]856    if (!isReferenceSolvedAndTransformed) solveAllEnabledFieldsAndTransform();
[1201]857
858     const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
859     const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
860
[1025]861     CContext* context = CContext::getCurrent();
862     bool hasWriterServer = context->hasServer && !context->hasClient;
863     bool hasIntermediateServer = context->hasServer && context->hasClient;
[641]864
[1025]865     if (hasWriterServer)
[640]866     {
[1025]867        if (!instantDataFilter)
[1027]868          instantDataFilter = clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid));
[1025]869
870             // If the field data is to be read by the client or/and written to a file
871       if (enableOutput && !storeFilter && !fileWriterFilter)
872       {
873         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
874         {
875           fileServerWriterFilter = boost::shared_ptr<CFileServerWriterFilter>(new CFileServerWriterFilter(gc, this));
876           instantDataFilter->connectOutput(fileServerWriterFilter, 0);
877         }
878       }
879     }
880     else if (hasIntermediateServer)
881     {
882       if (!instantDataFilter)
[1027]883         instantDataFilter = clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid));
[1025]884
885             // If the field data is to be read by the client or/and written to a file
886       if (enableOutput && !storeFilter && !fileWriterFilter)
887       {
888         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
889         {
890           fileWriterFilter = boost::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
891           instantDataFilter->connectOutput(fileWriterFilter, 0);
892         }
893       }
894     }
895     else
896     {
897       // Start by building a filter which can provide the field's instant data
898       if (!instantDataFilter)
899       {
900         // Check if we have an expression to parse
[1158]901         if (hasExpression())
[1025]902         {
[1158]903           boost::scoped_ptr<IFilterExprNode> expr(parseExpr(getExpression() + '\0'));
904           boost::shared_ptr<COutputPin> filter = expr->reduce(gc, *this);
[1021]905
[1158]906           // Check if a spatial transformation is needed
907           if (!field_ref.isEmpty())
[1021]908           {
[1158]909             CGrid* gridRef = CField::get(field_ref)->grid;
[1021]910
[1158]911             if (grid && grid != gridRef && grid->hasTransform())
912             {
[1201]913                 std::pair<boost::shared_ptr<CFilter>, boost::shared_ptr<CFilter> > filters = CSpatialTransformFilter::buildFilterGraph(gc, gridRef, grid, detectMissingValues, defaultValue); 
[1158]914
915               filter->connectOutput(filters.first, 0);
916               filter = filters.second;
917             }
[1021]918           }
919
[1158]920           instantDataFilter = filter;
[1025]921         }
922         // Check if we have a reference on another field
923         else if (!field_ref.isEmpty())
924           instantDataFilter = getFieldReference(gc);
925         // Check if the data is to be read from a file
926         else if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
[1158]927           instantDataFilter = serverSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid,
928                                                                                                       freq_offset.isEmpty() ? NoneDu : freq_offset,
[1201]929                                                                                                       true,
930                                                                                                       detectMissingValues, defaultValue));
[1025]931         else // The data might be passed from the model
[1158]932         {
[1201]933            if (check_if_active.isEmpty()) check_if_active = false; 
[1158]934            instantDataFilter = clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, NoneDu, false,
[1201]935                                                                                                        detectMissingValues, defaultValue));
[1158]936         }
[1025]937       }
[640]938
[1166]939       // If the field data is to be read by the client or/and written to a file
940       if (enableOutput && !storeFilter && !fileWriterFilter)
[640]941       {
[1201]942         storeFilter = boost::shared_ptr<CStoreFilter>(new CStoreFilter(gc, CContext::getCurrent(), grid,
943                                                                        detectMissingValues, defaultValue));
944         instantDataFilter->connectOutput(storeFilter, 0);
945       }
[640]946
[1201]947       if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
948       {
949         fileWriterFilter = boost::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
950         getTemporalDataFilter(gc, file->output_freq)->connectOutput(fileWriterFilter, 0);
[640]951       }
952     }
953   }
954
[642]955   /*!
[737]956    * Returns the filter needed to handle the field reference.
957    * This method should only be called when building the filter graph corresponding to the field.
958    *
959    * \param gc the garbage collector to use
960    * \return the output pin corresponding to the field reference
961    */
[1158]962   boost::shared_ptr<COutputPin> CField::getFieldReference(CGarbageCollector& gc)
963   {
964     if (instantDataFilter || field_ref.isEmpty())
965       ERROR("COutputPin* CField::getFieldReference(CGarbageCollector& gc)",
966             "Impossible to get the field reference for a field which has already been parsed or which does not have a field_ref.");
[737]967
[1158]968     CField* fieldRef = CField::get(field_ref);
969     fieldRef->buildFilterGraph(gc, false);
[737]970
[1158]971     std::pair<boost::shared_ptr<CFilter>, boost::shared_ptr<CFilter> > filters;
972     // Check if a spatial transformation is needed
973     if (grid && grid != fieldRef->grid && grid->hasTransform())
974     {       
975       bool hasMissingValue = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
976       double defaultValue  = hasMissingValue ? default_value : (!default_value.isEmpty() ? default_value : 0.0);                               
977       filters = CSpatialTransformFilter::buildFilterGraph(gc, fieldRef->grid, grid, hasMissingValue, defaultValue);
978     }
979     else
980       filters.first = filters.second = boost::shared_ptr<CFilter>(new CPassThroughFilter(gc));
[873]981
[1158]982     fieldRef->getInstantDataFilter()->connectOutput(filters.first, 0);
[737]983
[1158]984     return filters.second;
985   }
[737]986
987   /*!
988    * Returns the filter needed to handle a self reference in the field's expression.
989    * If the needed filter does not exist, it is created, otherwise it is reused.
[642]990    * This method should only be called when building the filter graph corresponding
991    * to the field's expression.
992    *
993    * \param gc the garbage collector to use
994    * \return the output pin corresponding to a self reference
995    */
996   boost::shared_ptr<COutputPin> CField::getSelfReference(CGarbageCollector& gc)
997   {
[1021]998     if (instantDataFilter || !hasExpression())
[642]999       ERROR("COutputPin* CField::getSelfReference(CGarbageCollector& gc)",
1000             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1001
[737]1002     if (!selfReferenceFilter)
1003     {
[1201]1004       const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1005       const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
1006
[741]1007       if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
1008       {
1009         if (!serverSourceFilter)
[1021]1010           serverSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid,
1011                                                                                   freq_offset.isEmpty() ? NoneDu : freq_offset,
[1201]1012                                                                                   true,
1013                                                                                   detectMissingValues, defaultValue));
1014
[741]1015         selfReferenceFilter = serverSourceFilter;
1016       }
1017       else if (!field_ref.isEmpty())
[1021]1018       {
1019         CField* fieldRef = CField::get(field_ref);
1020         fieldRef->buildFilterGraph(gc, false);
1021         selfReferenceFilter = fieldRef->getInstantDataFilter();
1022       }
[737]1023       else
1024       {
1025         if (!clientSourceFilter)
[1158]1026         {
[1201]1027           if (check_if_active.isEmpty()) check_if_active = false;
[1158]1028           clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, NoneDu, false,
[1201]1029                                                                                   detectMissingValues, defaultValue));
[1158]1030         }
[642]1031
[737]1032         selfReferenceFilter = clientSourceFilter;
1033       }
1034     }
1035
1036     return selfReferenceFilter;
[642]1037   }
1038
[643]1039   /*!
1040    * Returns the temporal filter corresponding to the field's temporal operation
1041    * for the specified operation frequency. The filter is created if it does not
1042    * exist, otherwise it is reused.
1043    *
1044    * \param gc the garbage collector to use
1045    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1046    * \return the output pin corresponding to the requested temporal filter
1047    */
1048   boost::shared_ptr<COutputPin> CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1049   {
1050     std::map<CDuration, boost::shared_ptr<COutputPin> >::iterator it = temporalDataFilters.find(outFreq);
1051
1052     if (it == temporalDataFilters.end())
1053     {
1054       if (operation.isEmpty())
1055         ERROR("void CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1056               << "An operation must be defined for field \"" << getId() << "\".");
1057
1058       if (freq_op.isEmpty())
1059         freq_op.setValue(TimeStep);
1060       if (freq_offset.isEmpty())
1061         freq_offset.setValue(NoneDu);
1062
[1201]1063       const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1064       
[643]1065       boost::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1066                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
1067                                                                             freq_op, freq_offset, outFreq,
[1201]1068                                                                             detectMissingValues, detectMissingValues ? default_value : 0.0));
[643]1069       instantDataFilter->connectOutput(temporalFilter, 0);
1070
1071       it = temporalDataFilters.insert(std::make_pair(outFreq, temporalFilter)).first;
1072     }
1073
1074     return it->second;
1075   }
1076
[1158]1077  /*!
1078    * Returns the temporal filter corresponding to the field's temporal operation
1079    * for the specified operation frequency.
1080    *
1081    * \param gc the garbage collector to use
1082    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1083    * \return the output pin corresponding to the requested temporal filter
1084    */
1085   
1086   boost::shared_ptr<COutputPin> CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1087   {
1088     if (instantDataFilter || !hasExpression())
1089       ERROR("COutputPin* CField::getSelfTemporalDataFilter(CGarbageCollector& gc)",
1090             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1091
1092     if (!selfReferenceFilter) getSelfReference(gc) ;
1093
1094     if (serverSourceFilter || clientSourceFilter)
1095     {
1096       if (operation.isEmpty())
1097         ERROR("void CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1098               << "An operation must be defined for field \"" << getId() << "\".");
1099
1100       if (freq_op.isEmpty()) freq_op.setValue(TimeStep);
1101       if (freq_offset.isEmpty()) freq_offset.setValue(NoneDu);
1102
[1201]1103       const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
[1158]1104
1105       boost::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1106                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
1107                                                                             freq_op, freq_offset, outFreq,
[1201]1108                                                                             detectMissingValues, detectMissingValues ? default_value : 0.0));
[1158]1109       selfReferenceFilter->connectOutput(temporalFilter, 0);
1110       return temporalFilter ;
1111     }
1112     else if (!field_ref.isEmpty())
1113     {
1114       CField* fieldRef = CField::get(field_ref);
1115       fieldRef->buildFilterGraph(gc, false); 
1116       return fieldRef->getTemporalDataFilter(gc, outFreq) ;
1117     }
1118  }
1119
[640]1120   //----------------------------------------------------------------
[369]1121/*
[562]1122   void CField::fromBinary(StdIStream& is)
[219]1123   {
1124      SuperClass::fromBinary(is);
1125#define CLEAR_ATT(name_)\
[369]1126      SuperClassAttribute::operator[](#name_)->reset()
[219]1127
1128         CLEAR_ATT(domain_ref);
1129         CLEAR_ATT(axis_ref);
1130#undef CLEAR_ATT
1131
1132   }
[369]1133*/
[219]1134   //----------------------------------------------------------------
1135
1136   void CField::solveGridReference(void)
1137   {
[887]1138      if (grid_ref.isEmpty() && domain_ref.isEmpty() && axis_ref.isEmpty() && scalar_ref.isEmpty())
[742]1139      {
1140        ERROR("CField::solveGridReference(void)",
[770]1141              << "A grid must be defined for field '" << getFieldOutputName() << "' .");
[742]1142      }
[887]1143      else if (!grid_ref.isEmpty() && (!domain_ref.isEmpty() || !axis_ref.isEmpty() || !scalar_ref.isEmpty()))
[219]1144      {
[744]1145        ERROR("CField::solveGridReference(void)",
[887]1146              << "Field '" << getFieldOutputName() << "' has both a grid and a domain/axis/scalar." << std::endl
1147              << "Please define either 'grid_ref' or 'domain_ref'/'axis_ref'/'scalar_ref'.");
[219]1148      }
1149
[744]1150      if (grid_ref.isEmpty())
[219]1151      {
[744]1152        std::vector<CDomain*> vecDom;
1153        std::vector<CAxis*> vecAxis;
[887]1154        std::vector<CScalar*> vecScalar;
[894]1155        std::vector<int> axisDomainOrderTmp;
1156       
[744]1157        if (!domain_ref.isEmpty())
1158        {
[823]1159          StdString tmp = domain_ref.getValue();
[744]1160          if (CDomain::has(domain_ref))
[894]1161          {
[744]1162            vecDom.push_back(CDomain::get(domain_ref));
[894]1163            axisDomainOrderTmp.push_back(2);
1164          }
[744]1165          else
[219]1166            ERROR("CField::solveGridReference(void)",
[744]1167                  << "Invalid reference to domain '" << domain_ref.getValue() << "'.");
1168        }
[219]1169
[744]1170        if (!axis_ref.isEmpty())
[742]1171        {
[744]1172          if (CAxis::has(axis_ref))
[894]1173          {
[744]1174            vecAxis.push_back(CAxis::get(axis_ref));
[894]1175            axisDomainOrderTmp.push_back(1);
1176          }
[744]1177          else
1178            ERROR("CField::solveGridReference(void)",
1179                  << "Invalid reference to axis '" << axis_ref.getValue() << "'.");
[742]1180        }
[744]1181
[887]1182        if (!scalar_ref.isEmpty())
1183        {
1184          if (CScalar::has(scalar_ref))
[894]1185          {
[887]1186            vecScalar.push_back(CScalar::get(scalar_ref));
[894]1187            axisDomainOrderTmp.push_back(0);
1188          }
[887]1189          else
1190            ERROR("CField::solveGridReference(void)",
1191                  << "Invalid reference to scalar '" << scalar_ref.getValue() << "'.");
1192        }
[894]1193       
1194        CArray<int,1> axisDomainOrder(axisDomainOrderTmp.size());
1195        for (int idx = 0; idx < axisDomainOrderTmp.size(); ++idx)
1196        {
1197          axisDomainOrder(idx) = axisDomainOrderTmp[idx];
1198        }
[887]1199
[745]1200        // Warning: the gridId shouldn't be set as the grid_ref since it could be inherited
[894]1201        StdString gridId = CGrid::generateId(vecDom, vecAxis, vecScalar,axisDomainOrder);
[745]1202        if (CGrid::has(gridId))
1203          this->grid = CGrid::get(gridId);
1204        else
[894]1205          this->grid = CGrid::createGrid(gridId, vecDom, vecAxis, vecScalar,axisDomainOrder);
[219]1206      }
[586]1207      else
1208      {
[744]1209        if (CGrid::has(grid_ref))
1210          this->grid = CGrid::get(grid_ref);
1211        else
1212          ERROR("CField::solveGridReference(void)",
1213                << "Invalid reference to grid '" << grid_ref.getValue() << "'.");
[586]1214      }
[509]1215   }
[459]1216
[509]1217   void CField::solveGridDomainAxisRef(bool checkAtt)
1218   {
1219     grid->solveDomainAxisRef(checkAtt);
[219]1220   }
1221
[509]1222   void CField::solveCheckMaskIndex(bool doSendingIndex)
1223   {
1224     grid->checkMaskIndex(doSendingIndex);
1225   }
[219]1226
[619]1227   void CField::solveTransformedGrid()
1228   {
[746]1229     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
[790]1230     {
1231       std::vector<CGrid*> grids;
1232       // Source grid
1233       grids.push_back(getDirectFieldReference()->grid);
1234       // Intermediate grids
1235       if (!grid_path.isEmpty())
1236       {
1237         std::string gridId;
1238         size_t start = 0, end;
1239
1240         do
1241         {
1242           end = grid_path.getValue().find(',', start);
1243           if (end != std::string::npos)
1244           {
1245             gridId = grid_path.getValue().substr(start, end - start);
1246             start = end + 1;
1247           }
1248           else
1249             gridId = grid_path.getValue().substr(start);
1250
1251           if (!CGrid::has(gridId))
1252             ERROR("void CField::solveTransformedGrid()",
1253                   << "Invalid grid_path, the grid '" << gridId << "' does not exist.");
1254
1255           grids.push_back(CGrid::get(gridId));
1256         }
1257         while (end != std::string::npos);
1258       }
1259       // Destination grid
1260       grids.push_back(grid);
1261
1262       for (size_t i = 0, count = grids.size() - 1; i < count; ++i)
1263       {
1264         CGrid *gridSrc  = grids[i];
1265         CGrid *gridDest = grids[i + 1];
1266         if (!gridDest->isTransformed())
1267           gridDest->transformGrid(gridSrc);
1268       }
1269     }
[934]1270     else if (grid && grid->hasTransform() && !grid->isTransformed())
1271     {
[1021]1272       // Temporarily deactivate the self-transformation of grid
1273       //grid->transformGrid(grid);
[934]1274     }
[619]1275   }
1276
[687]1277   void CField::solveGenerateGrid()
1278   {
[746]1279     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
[687]1280       grid->completeGrid(getDirectFieldReference()->grid);
[775]1281     else
1282       grid->completeGrid();
[687]1283   }
1284
[775]1285   void CField::solveGridDomainAxisBaseRef()
1286   {
1287     grid->solveDomainAxisRef(false);
1288     grid->solveDomainAxisBaseRef();
1289   }
1290
[219]1291   ///-------------------------------------------------------------------
1292
1293   template <>
[562]1294   void CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)
[219]1295   {
1296      if (this->group_ref.isEmpty()) return;
1297      StdString gref = this->group_ref.getValue();
1298
[346]1299      if (!CFieldGroup::has(gref))
[219]1300         ERROR("CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)",
1301               << "[ gref = " << gref << "]"
1302               << " invalid group name !");
1303
[347]1304      CFieldGroup* group = CFieldGroup::get(gref);
1305      CFieldGroup* owner = CFieldGroup::get(boost::polymorphic_downcast<CFieldGroup*>(this));
[219]1306
[347]1307      std::vector<CField*> allChildren  = group->getAllChildren();
[562]1308      std::vector<CField*>::iterator it = allChildren.begin(), end = allChildren.end();
[509]1309
[219]1310      for (; it != end; it++)
1311      {
[347]1312         CField* child = *it;
[562]1313         if (child->hasId()) owner->createChild()->field_ref.setValue(child->getId());
[509]1314
[219]1315      }
1316   }
[509]1317
[464]1318   void CField::scaleFactorAddOffset(double scaleFactor, double addOffset)
1319   {
[1136]1320     recvDataSrv = (recvDataSrv - addOffset) / scaleFactor;
[464]1321   }
[509]1322
[599]1323   void CField::invertScaleFactorAddOffset(double scaleFactor, double addOffset)
1324   {
[1136]1325     recvDataSrv = recvDataSrv * scaleFactor + addOffset;
[599]1326   }
1327
[567]1328   void CField::outputField(CArray<double,1>& fieldOut)
[1136]1329   { 
[1129]1330      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1331      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1332      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1333      {
1334        fieldOut(outIndexServer(idx)) = recvDataSrv(outIndexClient(idx));
1335      }
[1136]1336   }
[1129]1337
[1136]1338   void CField::inputField(CArray<double,1>& fieldIn)
1339   {
1340      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1341      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1342      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
[599]1343      {
[1136]1344        recvDataSrv(outIndexClient(idx)) = fieldIn(outIndexServer(idx));
[599]1345      }
1346
1347   }
1348
[676]1349   void CField::outputCompressedField(CArray<double,1>& fieldOut)
1350   {
[1143]1351      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1352      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1353      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
[676]1354      {
[1143]1355        fieldOut((idx)) = recvDataSrv(outIndexClient(idx));
[676]1356      }
1357   }
1358
[219]1359   ///-------------------------------------------------------------------
1360
[562]1361   void CField::parse(xml::CXMLNode& node)
[459]1362   {
1363      SuperClass::parse(node);
[562]1364      if (!node.getContent(this->content))
[472]1365      {
[476]1366        if (node.goToChildElement())
[472]1367        {
[476]1368          do
1369          {
[562]1370            if (node.getElementName() == "variable" || node.getElementName() == "variable_group") this->getVirtualVariableGroup()->parseChild(node);
1371          } while (node.goToNextElement());
[476]1372          node.goToParentElement();
1373        }
[472]1374      }
[459]1375    }
[509]1376
1377   /*!
1378     This function retrieves Id of corresponding domain_ref and axis_ref (if any)
1379   of a field. In some cases, only domain exists but axis doesn't
1380   \return pair of Domain and Axis id
1381   */
[887]1382   const std::vector<StdString>& CField::getRefDomainAxisIds()
[569]1383   {
1384     CGrid* cgPtr = getRelGrid();
1385     if (NULL != cgPtr)
1386     {
1387       std::vector<StdString>::iterator it;
1388       if (!domain_ref.isEmpty())
1389       {
1390         std::vector<StdString> domainList = cgPtr->getDomainList();
1391         it = std::find(domainList.begin(), domainList.end(), domain_ref.getValue());
[887]1392         if (domainList.end() != it) domAxisScalarIds_[0] = *it;
[569]1393       }
[472]1394
[569]1395       if (!axis_ref.isEmpty())
1396       {
1397         std::vector<StdString> axisList = cgPtr->getAxisList();
1398         it = std::find(axisList.begin(), axisList.end(), axis_ref.getValue());
[887]1399         if (axisList.end() != it) domAxisScalarIds_[1] = *it;
[569]1400       }
[887]1401
1402       if (!scalar_ref.isEmpty())
1403       {
1404         std::vector<StdString> scalarList = cgPtr->getScalarList();
1405         it = std::find(scalarList.begin(), scalarList.end(), scalar_ref.getValue());
1406         if (scalarList.end() != it) domAxisScalarIds_[2] = *it;
1407       }
[569]1408     }
[887]1409     return (domAxisScalarIds_);
[569]1410   }
1411
[472]1412   CVariable* CField::addVariable(const string& id)
1413   {
[562]1414     return vVariableGroup->createChild(id);
[472]1415   }
1416
1417   CVariableGroup* CField::addVariableGroup(const string& id)
1418   {
[562]1419     return vVariableGroup->createChildGroup(id);
[472]1420   }
1421
[1021]1422   void CField::sendAddAllVariables(CContextClient* client)
[1009]1423   {
1424     std::vector<CVariable*> allVar = getAllVariables();
1425     std::vector<CVariable*>::const_iterator it = allVar.begin();
1426     std::vector<CVariable*>::const_iterator itE = allVar.end();
1427
1428     for (; it != itE; ++it)
1429     {
[1021]1430       this->sendAddVariable((*it)->getId(), client);
1431       (*it)->sendAllAttributesToServer(client);
1432       (*it)->sendValue(client);
[1009]1433     }
1434   }
1435
[1021]1436   void CField::sendAddVariable(const string& id, CContextClient* client)
1437   {
1438      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE, client);
1439   }
1440
[1144]1441   void CField::sendAddVariableGroup(const string& id, CContextClient* client)
[472]1442   {
[1144]1443      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE_GROUP, client);
[472]1444   }
[509]1445
[472]1446   void CField::recvAddVariable(CEventServer& event)
1447   {
[509]1448
[562]1449      CBufferIn* buffer = event.subEvents.begin()->buffer;
[472]1450      string id;
[562]1451      *buffer >> id;
1452      get(id)->recvAddVariable(*buffer);
[472]1453   }
[509]1454
[472]1455   void CField::recvAddVariable(CBufferIn& buffer)
1456   {
[562]1457      string id;
1458      buffer >> id;
1459      addVariable(id);
[472]1460   }
1461
1462   void CField::recvAddVariableGroup(CEventServer& event)
1463   {
[509]1464
[562]1465      CBufferIn* buffer = event.subEvents.begin()->buffer;
[472]1466      string id;
[562]1467      *buffer >> id;
1468      get(id)->recvAddVariableGroup(*buffer);
[472]1469   }
[509]1470
[472]1471   void CField::recvAddVariableGroup(CBufferIn& buffer)
1472   {
[562]1473      string id;
1474      buffer >> id;
1475      addVariableGroup(id);
[472]1476   }
1477
[1021]1478   /*!
1479    * Returns string arithmetic expression associated to the field.
1480    * \return if content is defined return content string, otherwise, if "expr" attribute is defined, return expr string.
1481    */
1482   const string& CField::getExpression(void)
1483   {
1484     if (!expr.isEmpty() && content.empty())
1485     {
1486       content = expr;
1487       expr.reset();
1488     }
1489
1490     return content;
1491   }
1492
1493   bool CField::hasExpression(void) const
1494   {
1495     return (!expr.isEmpty() || !content.empty());
1496   }
1497
1498
[540]1499   DEFINE_REF_FUNC(Field,field)
[335]1500} // namespace xios
Note: See TracBrowser for help on using the repository browser.