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

Last change on this file since 1440 was 1440, checked in by ymipsl, 3 years ago

Bug fix : for temporal filter, to detect_missing value, default_value attribute must be defined in the incoming field. This is not requiere any more since default value is automatically fixed to NaN in the internal workflow.

YM

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