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

Last change on this file since 1322 was 1322, checked in by rlacroix, 6 years ago

Fix r1321 so that it makes some sense...

Polling a constant variable multiple times won't make its value change. If the data was received late but before the timeout, XIOS would throw an error anyway.

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