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

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

Two server levels: merging with trunk r1137.
There are bugs.

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