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

Last change on this file since 1417 was 1417, checked in by oabramkina, 3 years ago

Including calculations of grid distributions for fields which are disabled but, at the same time, are referenced in arithmetic filters.

  • 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.3 KB
Line 
1#include "field.hpp"
2
3#include "attribute_template.hpp"
4#include "object_template.hpp"
5#include "group_template.hpp"
6
7#include "node_type.hpp"
8#include "calendar_util.hpp"
9#include "message.hpp"
10#include "xios_spl.hpp"
11#include "type.hpp"
12#include "timer.hpp"
13#include "context_client.hpp"
14#include "context_server.hpp"
15#include <set>
16#include "garbage_collector.hpp"
17#include "source_filter.hpp"
18#include "store_filter.hpp"
19#include "file_writer_filter.hpp"
20#include "pass_through_filter.hpp"
21#include "filter_expr_node.hpp"
22#include "lex_parser.hpp"
23#include "temporal_filter.hpp"
24#include "spatial_transform_filter.hpp"
25#include "file_server_writer_filter.hpp"
26
27namespace xios{
28
29   /// ////////////////////// Définitions ////////////////////// ///
30
31   CField::CField(void)
32      : CObjectTemplate<CField>(), CFieldAttributes()
33      , grid(), file()
34      , written(false)
35      , nstep(0), nstepMax(0)
36      , hasOutputFile(false)
37      , domAxisScalarIds_(vector<StdString>(3,""))
38      , areAllReferenceSolved(false), isReferenceSolved(false), isReferenceSolvedAndTransformed(false)
39      , 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() && !default_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,
1223                                                                             detectMissingValues, detectMissingValues ? default_value : 0.0));
1224
1225       instantDataFilter->connectOutput(temporalFilter, 0);
1226
1227       it = temporalDataFilters.insert(std::make_pair(outFreq, temporalFilter)).first;
1228     }
1229
1230     return it->second;
1231   }
1232
1233  /*!
1234    * Returns the temporal filter corresponding to the field's temporal operation
1235    * for the specified operation frequency.
1236    *
1237    * \param gc the garbage collector to use
1238    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1239    * \return the output pin corresponding to the requested temporal filter
1240    */
1241   
1242   boost::shared_ptr<COutputPin> CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1243   {
1244     if (instantDataFilter || !hasExpression())
1245       ERROR("COutputPin* CField::getSelfTemporalDataFilter(CGarbageCollector& gc)",
1246             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1247
1248     if (!selfReferenceFilter) getSelfReference(gc) ;
1249
1250     if (serverSourceFilter || clientSourceFilter)
1251     {
1252       if (operation.isEmpty())
1253         ERROR("void CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1254               << "An operation must be defined for field \"" << getId() << "\".");
1255
1256       checkTimeAttributes(&outFreq);
1257
1258       const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1259       boost::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1260                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
1261                                                                             freq_op, freq_offset, outFreq,
1262                                                                             detectMissingValues, detectMissingValues ? default_value : 0.0));
1263
1264       selfReferenceFilter->connectOutput(temporalFilter, 0);
1265       return temporalFilter ;
1266     }
1267     else if (!field_ref.isEmpty())
1268     {
1269       CField* fieldRef = CField::get(field_ref);
1270       fieldRef->buildFilterGraph(gc, false); 
1271       return fieldRef->getTemporalDataFilter(gc, outFreq) ;
1272     }
1273  }
1274
1275   //----------------------------------------------------------------
1276/*
1277   void CField::fromBinary(StdIStream& is)
1278   {
1279      SuperClass::fromBinary(is);
1280#define CLEAR_ATT(name_)\
1281      SuperClassAttribute::operator[](#name_)->reset()
1282
1283         CLEAR_ATT(domain_ref);
1284         CLEAR_ATT(axis_ref);
1285#undef CLEAR_ATT
1286
1287   }
1288*/
1289   //----------------------------------------------------------------
1290
1291   void CField::solveGridReference(void)
1292   {
1293      if (grid_ref.isEmpty() && domain_ref.isEmpty() && axis_ref.isEmpty() && scalar_ref.isEmpty())
1294      {
1295        ERROR("CField::solveGridReference(void)",
1296              << "A grid must be defined for field '" << getFieldOutputName() << "' .");
1297      }
1298      else if (!grid_ref.isEmpty() && (!domain_ref.isEmpty() || !axis_ref.isEmpty() || !scalar_ref.isEmpty()))
1299      {
1300        ERROR("CField::solveGridReference(void)",
1301              << "Field '" << getFieldOutputName() << "' has both a grid and a domain/axis/scalar." << std::endl
1302              << "Please define either 'grid_ref' or 'domain_ref'/'axis_ref'/'scalar_ref'.");
1303      }
1304
1305      if (grid_ref.isEmpty())
1306      {
1307        std::vector<CDomain*> vecDom;
1308        std::vector<CAxis*> vecAxis;
1309        std::vector<CScalar*> vecScalar;
1310        std::vector<int> axisDomainOrderTmp;
1311       
1312        if (!domain_ref.isEmpty())
1313        {
1314          StdString tmp = domain_ref.getValue();
1315          if (CDomain::has(domain_ref))
1316          {
1317            vecDom.push_back(CDomain::get(domain_ref));
1318            axisDomainOrderTmp.push_back(2);
1319          }
1320          else
1321            ERROR("CField::solveGridReference(void)",
1322                  << "Invalid reference to domain '" << domain_ref.getValue() << "'.");
1323        }
1324
1325        if (!axis_ref.isEmpty())
1326        {
1327          if (CAxis::has(axis_ref))
1328          {
1329            vecAxis.push_back(CAxis::get(axis_ref));
1330            axisDomainOrderTmp.push_back(1);
1331          }
1332          else
1333            ERROR("CField::solveGridReference(void)",
1334                  << "Invalid reference to axis '" << axis_ref.getValue() << "'.");
1335        }
1336
1337        if (!scalar_ref.isEmpty())
1338        {
1339          if (CScalar::has(scalar_ref))
1340          {
1341            vecScalar.push_back(CScalar::get(scalar_ref));
1342            axisDomainOrderTmp.push_back(0);
1343          }
1344          else
1345            ERROR("CField::solveGridReference(void)",
1346                  << "Invalid reference to scalar '" << scalar_ref.getValue() << "'.");
1347        }
1348       
1349        CArray<int,1> axisDomainOrder(axisDomainOrderTmp.size());
1350        for (int idx = 0; idx < axisDomainOrderTmp.size(); ++idx)
1351        {
1352          axisDomainOrder(idx) = axisDomainOrderTmp[idx];
1353        }
1354
1355        // Warning: the gridId shouldn't be set as the grid_ref since it could be inherited
1356        StdString gridId = CGrid::generateId(vecDom, vecAxis, vecScalar,axisDomainOrder);
1357        if (CGrid::has(gridId))
1358          this->grid = CGrid::get(gridId);
1359        else
1360          this->grid = CGrid::createGrid(gridId, vecDom, vecAxis, vecScalar,axisDomainOrder);
1361      }
1362      else
1363      {
1364        if (CGrid::has(grid_ref))
1365          this->grid = CGrid::get(grid_ref);
1366        else
1367          ERROR("CField::solveGridReference(void)",
1368                << "Invalid reference to grid '" << grid_ref.getValue() << "'.");
1369      }
1370   }
1371
1372   void CField::solveGridDomainAxisRef(bool checkAtt)
1373   {
1374     grid->solveDomainAxisRef(checkAtt);
1375   }
1376
1377   void CField::solveCheckMaskIndex(bool doSendingIndex)
1378   {
1379     grid->checkMaskIndex(doSendingIndex);
1380   }
1381
1382   void CField::solveTransformedGrid()
1383   {
1384     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
1385     {
1386       std::vector<CGrid*> grids;
1387       // Source grid
1388       grids.push_back(getDirectFieldReference()->grid);
1389       // Intermediate grids
1390       if (!grid_path.isEmpty())
1391       {
1392         std::string gridId;
1393         size_t start = 0, end;
1394
1395         do
1396         {
1397           end = grid_path.getValue().find(',', start);
1398           if (end != std::string::npos)
1399           {
1400             gridId = grid_path.getValue().substr(start, end - start);
1401             start = end + 1;
1402           }
1403           else
1404             gridId = grid_path.getValue().substr(start);
1405
1406           if (!CGrid::has(gridId))
1407             ERROR("void CField::solveTransformedGrid()",
1408                   << "Invalid grid_path, the grid '" << gridId << "' does not exist.");
1409
1410           grids.push_back(CGrid::get(gridId));
1411         }
1412         while (end != std::string::npos);
1413       }
1414       // Destination grid
1415       grids.push_back(grid);
1416
1417       for (size_t i = 0, count = grids.size() - 1; i < count; ++i)
1418       {
1419         CGrid *gridSrc  = grids[i];
1420         CGrid *gridDest = grids[i + 1];
1421         if (!gridDest->isTransformed())
1422           gridDest->transformGrid(gridSrc);
1423       }
1424     }
1425     else if (grid && grid->hasTransform() && !grid->isTransformed())
1426     {
1427       // Temporarily deactivate the self-transformation of grid
1428       // grid->transformGrid(grid);
1429     }
1430   }
1431
1432   void CField::solveGenerateGrid()
1433   {
1434     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
1435       grid->completeGrid(getDirectFieldReference()->grid);
1436     else
1437       grid->completeGrid();
1438   }
1439
1440   void CField::solveGridDomainAxisBaseRef()
1441   {
1442     grid->solveDomainAxisRef(false);
1443     grid->solveDomainAxisBaseRef();
1444   }
1445
1446   ///-------------------------------------------------------------------
1447
1448   template <>
1449   void CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)
1450   {
1451      if (this->group_ref.isEmpty()) return;
1452      StdString gref = this->group_ref.getValue();
1453
1454      if (!CFieldGroup::has(gref))
1455         ERROR("CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)",
1456               << "[ gref = " << gref << "]"
1457               << " invalid group name !");
1458
1459      CFieldGroup* group = CFieldGroup::get(gref);
1460      CFieldGroup* owner = CFieldGroup::get(boost::polymorphic_downcast<CFieldGroup*>(this));
1461
1462      std::vector<CField*> allChildren  = group->getAllChildren();
1463      std::vector<CField*>::iterator it = allChildren.begin(), end = allChildren.end();
1464
1465      for (; it != end; it++)
1466      {
1467         CField* child = *it;
1468         if (child->hasId()) owner->createChild()->field_ref.setValue(child->getId());
1469
1470      }
1471   }
1472
1473   void CField::scaleFactorAddOffset(double scaleFactor, double addOffset)
1474   {
1475     recvDataSrv = (recvDataSrv - addOffset) / scaleFactor;
1476   }
1477
1478   void CField::invertScaleFactorAddOffset(double scaleFactor, double addOffset)
1479   {
1480     recvDataSrv = recvDataSrv * scaleFactor + addOffset;
1481   }
1482
1483   void CField::outputField(CArray<double,1>& fieldOut)
1484   { 
1485      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1486      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1487      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1488      {
1489        fieldOut(outIndexServer(idx)) = recvDataSrv(outIndexClient(idx));
1490      }
1491   }
1492
1493   void CField::inputField(CArray<double,1>& fieldIn)
1494   {
1495      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1496      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1497      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1498      {
1499        recvDataSrv(outIndexClient(idx)) = fieldIn(outIndexServer(idx));
1500      }
1501
1502   }
1503
1504   void CField::outputCompressedField(CArray<double,1>& fieldOut)
1505   {
1506      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1507      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1508      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1509      {
1510        fieldOut((idx)) = recvDataSrv(outIndexClient(idx));
1511      }
1512   }
1513
1514   ///-------------------------------------------------------------------
1515
1516   void CField::parse(xml::CXMLNode& node)
1517   {
1518      string newContent ;
1519      SuperClass::parse(node);
1520      if (node.goToChildElement())
1521      {
1522        do
1523        {
1524          if (node.getElementName() == "variable" || node.getElementName() == "variable_group") this->getVirtualVariableGroup()->parseChild(node);
1525          else if (node.getElementName() == "expr") if (node.getContent(newContent)) content+=newContent ;
1526        } while (node.goToNextElement());
1527        node.goToParentElement();
1528      }
1529      if (node.getContent(newContent)) content=newContent ;
1530    }
1531
1532   /*!
1533     This function retrieves Id of corresponding domain_ref and axis_ref (if any)
1534   of a field. In some cases, only domain exists but axis doesn't
1535   \return pair of Domain and Axis id
1536   */
1537   const std::vector<StdString>& CField::getRefDomainAxisIds()
1538   {
1539     CGrid* cgPtr = getRelGrid();
1540     if (NULL != cgPtr)
1541     {
1542       std::vector<StdString>::iterator it;
1543       if (!domain_ref.isEmpty())
1544       {
1545         std::vector<StdString> domainList = cgPtr->getDomainList();
1546         it = std::find(domainList.begin(), domainList.end(), domain_ref.getValue());
1547         if (domainList.end() != it) domAxisScalarIds_[0] = *it;
1548       }
1549
1550       if (!axis_ref.isEmpty())
1551       {
1552         std::vector<StdString> axisList = cgPtr->getAxisList();
1553         it = std::find(axisList.begin(), axisList.end(), axis_ref.getValue());
1554         if (axisList.end() != it) domAxisScalarIds_[1] = *it;
1555       }
1556
1557       if (!scalar_ref.isEmpty())
1558       {
1559         std::vector<StdString> scalarList = cgPtr->getScalarList();
1560         it = std::find(scalarList.begin(), scalarList.end(), scalar_ref.getValue());
1561         if (scalarList.end() != it) domAxisScalarIds_[2] = *it;
1562       }
1563     }
1564     return (domAxisScalarIds_);
1565   }
1566
1567   CVariable* CField::addVariable(const string& id)
1568   {
1569     return vVariableGroup->createChild(id);
1570   }
1571
1572   CVariableGroup* CField::addVariableGroup(const string& id)
1573   {
1574     return vVariableGroup->createChildGroup(id);
1575   }
1576
1577   void CField::setContextClient(CContextClient* contextClient)
1578   {
1579     CContext* context = CContext::getCurrent();
1580     client = contextClient;
1581     if (context->hasClient)
1582     {
1583       // A grid is sent by a client (both for read or write) or by primary server (write only)
1584       if (context->hasServer)
1585       {
1586         if (file->mode.isEmpty() || (!file->mode.isEmpty() && file->mode == CFile::mode_attr::write))
1587           grid->setContextClient(contextClient);
1588       }
1589       else
1590           grid->setContextClient(contextClient);
1591     }
1592   }
1593
1594   CContextClient* CField::getContextClient()
1595   {
1596     return client;
1597   }
1598
1599   void CField::sendAddAllVariables(CContextClient* client)
1600   {
1601     std::vector<CVariable*> allVar = getAllVariables();
1602     std::vector<CVariable*>::const_iterator it = allVar.begin();
1603     std::vector<CVariable*>::const_iterator itE = allVar.end();
1604
1605     for (; it != itE; ++it)
1606     {
1607       this->sendAddVariable((*it)->getId(), client);
1608       (*it)->sendAllAttributesToServer(client);
1609       (*it)->sendValue(client);
1610     }
1611   }
1612
1613   void CField::sendAddVariable(const string& id, CContextClient* client)
1614   {
1615      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE, client);
1616   }
1617
1618   void CField::sendAddVariableGroup(const string& id, CContextClient* client)
1619   {
1620      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE_GROUP, client);
1621   }
1622
1623   void CField::recvAddVariable(CEventServer& event)
1624   {
1625
1626      CBufferIn* buffer = event.subEvents.begin()->buffer;
1627      string id;
1628      *buffer >> id;
1629      get(id)->recvAddVariable(*buffer);
1630   }
1631
1632   void CField::recvAddVariable(CBufferIn& buffer)
1633   {
1634      string id;
1635      buffer >> id;
1636      addVariable(id);
1637   }
1638
1639   void CField::recvAddVariableGroup(CEventServer& event)
1640   {
1641
1642      CBufferIn* buffer = event.subEvents.begin()->buffer;
1643      string id;
1644      *buffer >> id;
1645      get(id)->recvAddVariableGroup(*buffer);
1646   }
1647
1648   void CField::recvAddVariableGroup(CBufferIn& buffer)
1649   {
1650      string id;
1651      buffer >> id;
1652      addVariableGroup(id);
1653   }
1654
1655   /*!
1656    * Check on freq_off and freq_op attributes.
1657    */
1658   void CField::checkTimeAttributes(CDuration* freqOp)
1659   {
1660     bool isFieldRead  = file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read;
1661     bool isFieldWrite = file && ( file->mode.isEmpty() ||  file->mode == CFile::mode_attr::write);
1662     if (isFieldRead && operation.getValue() != "instant")
1663       ERROR("void CField::checkTimeAttributes(void)",
1664             << "Unsupported operation for field '" << getFieldOutputName() << "'." << std::endl
1665             << "Currently only \"instant\" is supported for fields read from file.")
1666
1667     if (freq_op.isEmpty())
1668     {
1669       if (operation.getValue() == "instant")
1670       {
1671         if (isFieldRead || isFieldWrite) freq_op.setValue(file->output_freq.getValue());
1672         else freq_op=*freqOp ;
1673       }
1674       else
1675         freq_op.setValue(TimeStep);
1676     }
1677     if (freq_offset.isEmpty())
1678       freq_offset.setValue(isFieldRead ? NoneDu : (freq_op.getValue() - TimeStep));
1679   }
1680
1681   /*!
1682    * Returns string arithmetic expression associated to the field.
1683    * \return if content is defined return content string, otherwise, if "expr" attribute is defined, return expr string.
1684    */
1685   const string& CField::getExpression(void)
1686   {
1687     if (!expr.isEmpty() && content.empty())
1688     {
1689       content = expr;
1690       expr.reset();
1691     }
1692
1693     return content;
1694   }
1695
1696   bool CField::hasExpression(void) const
1697   {
1698     return (!expr.isEmpty() || !content.empty());
1699   }
1700
1701
1702   DEFINE_REF_FUNC(Field,field)
1703} // namespace xios
Note: See TracBrowser for help on using the repository browser.