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

Last change on this file since 1344 was 1344, checked in by oabramkina, 6 years ago

Fixing a bug in r1320 which affected writing.
test_remap: ok.

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