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

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

Fix the default "freq_offset" for fields read from files.

Also throw an error when trying to use an invalid operation for such fields (currently only "instant" are supported).

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