source: XIOS/dev/branch_openmp/src/node/field.cpp @ 1460

Last change on this file since 1460 was 1460, checked in by yushan, 3 years ago

branch_openmp merged with XIOS_DEV_CMIP6@1459

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