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

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

Improvements for the secondary server: each grid is only sent to secondary-server pools that need it.

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