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

Last change on this file since 1292 was 1292, checked in by ymipsl, 4 years ago

Fix problems when checking field temporal attributes.

YM

  • Property copyright set to
    Software name : XIOS (Xml I/O Server)
    http://forge.ipsl.jussieu.fr/ioserver
    Creation date : January 2009
    Licence : CeCCIL version2
    see license file in root directory : Licence_CeCILL_V2-en.txt
    or http://www.cecill.info/licences/Licence_CeCILL_V2-en.html
    Holder : CEA/LSCE (Laboratoire des Sciences du CLimat et de l'Environnement)
    CNRS/IPSL (Institut Pierre Simon Laplace)
    Project Manager : Yann Meurdesoif
    yann.meurdesoif@cea.fr
  • Property svn:executable set to *
File size: 52.6 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
830        if (context->hasClient && !context->hasServer)
831       {
832         solveGenerateGrid();
833         buildGridTransformationGraph();
834       }
835     }
836   }
837     
838   void CField::solveAllReferenceEnabledField(bool doSending2Server)
839   {
840     CContext* context = CContext::getCurrent();
841     solveOnlyReferenceEnabledField(doSending2Server);
842
843     if (!areAllReferenceSolved)
844     {
845        areAllReferenceSolved = true;
846       
847        if (context->hasClient && !context->hasServer)
848        {
849          solveRefInheritance(true);
850          if (hasDirectFieldReference()) getDirectFieldReference()->solveAllReferenceEnabledField(false);
851        }
852        else if (context->hasServer)
853          solveServerOperation();
854
855        solveGridReference();
856     }
857
858     solveGridDomainAxisRef(doSending2Server);
859
860     if (context->hasClient && !context->hasServer)
861     {
862       solveTransformedGrid();
863     }
864
865     solveCheckMaskIndex(doSending2Server);
866   }
867
868   std::map<int, StdSize> CField::getGridAttributesBufferSize(CContextClient* client)
869   {
870     return grid->getAttributesBufferSize(client);
871   }
872
873   std::map<int, StdSize> CField::getGridDataBufferSize(CContextClient* client)
874   {
875     return grid->getDataBufferSize(client, getId());
876   }
877
878   size_t CField::getGlobalWrittenSize()
879   {
880     return grid->getGlobalWrittenSize();
881   }
882
883   //----------------------------------------------------------------
884
885   void CField::solveServerOperation(void)
886   {
887      CContext* context = CContext::getCurrent();
888
889      if (!context->hasServer || !hasOutputFile) return;
890
891      if (freq_op.isEmpty())
892        freq_op.setValue(TimeStep);
893
894      if (freq_offset.isEmpty())
895        freq_offset.setValue(NoneDu);
896
897      freq_operation_srv = file->output_freq.getValue();
898      freq_write_srv     = file->output_freq.getValue();
899
900      lastlast_Write_srv = context->getCalendar()->getInitDate();
901      last_Write_srv     = context->getCalendar()->getInitDate();
902      last_operation_srv = context->getCalendar()->getInitDate();
903
904      const CDuration toffset = freq_operation_srv - freq_offset.getValue() - context->getCalendar()->getTimeStep();
905      last_operation_srv     = last_operation_srv - toffset;
906
907      if (operation.isEmpty())
908        ERROR("void CField::solveServerOperation(void)",
909              << "An operation must be defined for field \"" << getId() << "\".");
910
911      boost::shared_ptr<func::CFunctor> functor;
912      CArray<double, 1> dummyData;
913
914#define DECLARE_FUNCTOR(MType, mtype) \
915      if (operation.getValue().compare(#mtype) == 0) \
916      { \
917        functor.reset(new func::C##MType(dummyData)); \
918      }
919
920#include "functor_type.conf"
921
922      if (!functor)
923        ERROR("void CField::solveServerOperation(void)",
924              << "\"" << operation << "\" is not a valid operation.");
925
926      operationTimeType = functor->timeType();
927   }
928
929   //----------------------------------------------------------------
930
931   /*!
932    * Constructs the graph filter for the field, enabling or not the data output.
933    * This method should not be called more than once with enableOutput equal to true.
934    *
935    * \param gc the garbage collector to use when building the filter graph
936    * \param enableOutput must be true when the field data is to be
937    *                     read by the client or/and written to a file
938    */
939   void CField::buildFilterGraph(CGarbageCollector& gc, bool enableOutput)
940   {     
941    if (!isReferenceSolvedAndTransformed) solveAllEnabledFieldsAndTransform();
942
943     const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
944     const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
945
946     CContext* context = CContext::getCurrent();
947     bool hasWriterServer = context->hasServer && !context->hasClient;
948     bool hasIntermediateServer = context->hasServer && context->hasClient;
949
950     if (hasWriterServer)
951     {
952        if (!instantDataFilter)
953          instantDataFilter = clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid,true));
954
955             // If the field data is to be read by the client or/and written to a file
956       if (enableOutput && !storeFilter && !fileWriterFilter)
957       {
958         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
959         {
960           fileServerWriterFilter = boost::shared_ptr<CFileServerWriterFilter>(new CFileServerWriterFilter(gc, this));
961           instantDataFilter->connectOutput(fileServerWriterFilter, 0);
962         }
963       }
964     }
965     else if (hasIntermediateServer)
966     {
967       if (!instantDataFilter)
968         instantDataFilter = clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true));
969
970             // If the field data is to be read by the client or/and written to a file
971       if (enableOutput && !storeFilter && !fileWriterFilter)
972       {
973         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
974         {
975           fileWriterFilter = boost::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
976           instantDataFilter->connectOutput(fileWriterFilter, 0);
977         }
978       }
979     }
980     else
981     {
982       // Start by building a filter which can provide the field's instant data
983       if (!instantDataFilter)
984       {
985         // Check if we have an expression to parse
986         if (hasExpression())
987         {
988           boost::scoped_ptr<IFilterExprNode> expr(parseExpr(getExpression() + '\0'));
989           boost::shared_ptr<COutputPin> filter = expr->reduce(gc, *this);
990
991           // Check if a spatial transformation is needed
992           if (!field_ref.isEmpty())
993           {
994             CGrid* gridRef = CField::get(field_ref)->grid;
995
996             if (grid && grid != gridRef && grid->hasTransform())
997             {
998                 std::pair<boost::shared_ptr<CFilter>, boost::shared_ptr<CFilter> > filters = CSpatialTransformFilter::buildFilterGraph(gc, gridRef, grid, detectMissingValues, defaultValue); 
999
1000               filter->connectOutput(filters.first, 0);
1001               filter = filters.second;
1002             }
1003           }
1004
1005           instantDataFilter = filter;
1006         }
1007         // Check if we have a reference on another field
1008         else if (!field_ref.isEmpty())
1009           instantDataFilter = getFieldReference(gc);
1010         // Check if the data is to be read from a file
1011         else if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
1012           instantDataFilter = serverSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true,
1013                                                                                                       freq_offset.isEmpty() ? NoneDu : freq_offset,
1014                                                                                                       true,
1015                                                                                                       detectMissingValues, defaultValue));
1016         else // The data might be passed from the model
1017         {
1018            if (check_if_active.isEmpty()) check_if_active = false; 
1019            instantDataFilter = clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, false, NoneDu, false,
1020                                                                                                        detectMissingValues, defaultValue));
1021         }
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 (!read_access.isEmpty() && read_access)
1028         {
1029           storeFilter = boost::shared_ptr<CStoreFilter>(new CStoreFilter(gc, CContext::getCurrent(), grid,
1030                                                                          detectMissingValues, defaultValue));
1031           instantDataFilter->connectOutput(storeFilter, 0);
1032         }
1033
1034         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
1035         {
1036           fileWriterFilter = boost::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
1037           getTemporalDataFilter(gc, file->output_freq)->connectOutput(fileWriterFilter, 0);
1038         }
1039       }
1040     }
1041   }
1042
1043   /*!
1044    * Returns the filter needed to handle the field reference.
1045    * This method should only be called when building the filter graph corresponding to the field.
1046    *
1047    * \param gc the garbage collector to use
1048    * \return the output pin corresponding to the field reference
1049    */
1050   boost::shared_ptr<COutputPin> CField::getFieldReference(CGarbageCollector& gc)
1051   {
1052     if (instantDataFilter || field_ref.isEmpty())
1053       ERROR("COutputPin* CField::getFieldReference(CGarbageCollector& gc)",
1054             "Impossible to get the field reference for a field which has already been parsed or which does not have a field_ref.");
1055
1056     CField* fieldRef = CField::get(field_ref);
1057     fieldRef->buildFilterGraph(gc, false);
1058
1059     std::pair<boost::shared_ptr<CFilter>, boost::shared_ptr<CFilter> > filters;
1060     // Check if a spatial transformation is needed
1061     if (grid && grid != fieldRef->grid && grid->hasTransform())
1062     {       
1063       bool hasMissingValue = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1064       double defaultValue  = hasMissingValue ? default_value : (!default_value.isEmpty() ? default_value : 0.0);                               
1065       filters = CSpatialTransformFilter::buildFilterGraph(gc, fieldRef->grid, grid, hasMissingValue, defaultValue);
1066     }
1067     else
1068       filters.first = filters.second = boost::shared_ptr<CFilter>(new CPassThroughFilter(gc));
1069
1070     fieldRef->getInstantDataFilter()->connectOutput(filters.first, 0);
1071
1072     return filters.second;
1073   }
1074
1075   /*!
1076    * Returns the filter needed to handle a self reference in the field's expression.
1077    * If the needed filter does not exist, it is created, otherwise it is reused.
1078    * This method should only be called when building the filter graph corresponding
1079    * to the field's expression.
1080    *
1081    * \param gc the garbage collector to use
1082    * \return the output pin corresponding to a self reference
1083    */
1084   boost::shared_ptr<COutputPin> CField::getSelfReference(CGarbageCollector& gc)
1085   {
1086     if (instantDataFilter || !hasExpression())
1087       ERROR("COutputPin* CField::getSelfReference(CGarbageCollector& gc)",
1088             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1089
1090     if (!selfReferenceFilter)
1091     {
1092       const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1093       const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
1094
1095       if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
1096       {
1097         if (!serverSourceFilter)
1098           serverSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true,
1099                                                                                   freq_offset.isEmpty() ? NoneDu : freq_offset,
1100                                                                                   true,
1101                                                                                   detectMissingValues, defaultValue));
1102
1103         selfReferenceFilter = serverSourceFilter;
1104       }
1105       else if (!field_ref.isEmpty())
1106       {
1107         CField* fieldRef = CField::get(field_ref);
1108         fieldRef->buildFilterGraph(gc, false);
1109         selfReferenceFilter = fieldRef->getInstantDataFilter();
1110       }
1111       else
1112       {
1113         if (!clientSourceFilter)
1114         {
1115           if (check_if_active.isEmpty()) check_if_active = false;
1116           clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, NoneDu, false,
1117                                                                                   detectMissingValues, defaultValue));
1118         }
1119
1120         selfReferenceFilter = clientSourceFilter;
1121       }
1122     }
1123
1124     return selfReferenceFilter;
1125   }
1126
1127   /*!
1128    * Returns the temporal filter corresponding to the field's temporal operation
1129    * for the specified operation frequency. The filter is created if it does not
1130    * exist, otherwise it is reused.
1131    *
1132    * \param gc the garbage collector to use
1133    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1134    * \return the output pin corresponding to the requested temporal filter
1135    */
1136   boost::shared_ptr<COutputPin> CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1137   {
1138     std::map<CDuration, boost::shared_ptr<COutputPin> >::iterator it = temporalDataFilters.find(outFreq);
1139
1140     if (it == temporalDataFilters.end())
1141     {
1142       if (operation.isEmpty())
1143         ERROR("void CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1144               << "An operation must be defined for field \"" << getId() << "\".");
1145
1146       const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1147       checkAttributes() ;   
1148       boost::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1149                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
1150                                                                             freq_op, freq_offset, outFreq,
1151                                                                             detectMissingValues, detectMissingValues ? default_value : 0.0));
1152
1153       instantDataFilter->connectOutput(temporalFilter, 0);
1154
1155       it = temporalDataFilters.insert(std::make_pair(outFreq, temporalFilter)).first;
1156     }
1157
1158     return it->second;
1159   }
1160
1161  /*!
1162    * Returns the temporal filter corresponding to the field's temporal operation
1163    * for the specified operation frequency.
1164    *
1165    * \param gc the garbage collector to use
1166    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1167    * \return the output pin corresponding to the requested temporal filter
1168    */
1169   
1170   boost::shared_ptr<COutputPin> CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1171   {
1172     if (instantDataFilter || !hasExpression())
1173       ERROR("COutputPin* CField::getSelfTemporalDataFilter(CGarbageCollector& gc)",
1174             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1175
1176     if (!selfReferenceFilter) getSelfReference(gc) ;
1177
1178     if (serverSourceFilter || clientSourceFilter)
1179     {
1180       if (operation.isEmpty())
1181         ERROR("void CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1182               << "An operation must be defined for field \"" << getId() << "\".");
1183
1184       const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1185       checkAttributes() ;   
1186       boost::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1187                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
1188                                                                             freq_op, freq_offset, outFreq,
1189                                                                             detectMissingValues, detectMissingValues ? default_value : 0.0));
1190
1191       selfReferenceFilter->connectOutput(temporalFilter, 0);
1192       return temporalFilter ;
1193     }
1194     else if (!field_ref.isEmpty())
1195     {
1196       CField* fieldRef = CField::get(field_ref);
1197       fieldRef->buildFilterGraph(gc, false); 
1198       return fieldRef->getTemporalDataFilter(gc, outFreq) ;
1199     }
1200  }
1201
1202   //----------------------------------------------------------------
1203/*
1204   void CField::fromBinary(StdIStream& is)
1205   {
1206      SuperClass::fromBinary(is);
1207#define CLEAR_ATT(name_)\
1208      SuperClassAttribute::operator[](#name_)->reset()
1209
1210         CLEAR_ATT(domain_ref);
1211         CLEAR_ATT(axis_ref);
1212#undef CLEAR_ATT
1213
1214   }
1215*/
1216   //----------------------------------------------------------------
1217
1218   void CField::solveGridReference(void)
1219   {
1220      if (grid_ref.isEmpty() && domain_ref.isEmpty() && axis_ref.isEmpty() && scalar_ref.isEmpty())
1221      {
1222        ERROR("CField::solveGridReference(void)",
1223              << "A grid must be defined for field '" << getFieldOutputName() << "' .");
1224      }
1225      else if (!grid_ref.isEmpty() && (!domain_ref.isEmpty() || !axis_ref.isEmpty() || !scalar_ref.isEmpty()))
1226      {
1227        ERROR("CField::solveGridReference(void)",
1228              << "Field '" << getFieldOutputName() << "' has both a grid and a domain/axis/scalar." << std::endl
1229              << "Please define either 'grid_ref' or 'domain_ref'/'axis_ref'/'scalar_ref'.");
1230      }
1231
1232      if (grid_ref.isEmpty())
1233      {
1234        std::vector<CDomain*> vecDom;
1235        std::vector<CAxis*> vecAxis;
1236        std::vector<CScalar*> vecScalar;
1237        std::vector<int> axisDomainOrderTmp;
1238       
1239        if (!domain_ref.isEmpty())
1240        {
1241          StdString tmp = domain_ref.getValue();
1242          if (CDomain::has(domain_ref))
1243          {
1244            vecDom.push_back(CDomain::get(domain_ref));
1245            axisDomainOrderTmp.push_back(2);
1246          }
1247          else
1248            ERROR("CField::solveGridReference(void)",
1249                  << "Invalid reference to domain '" << domain_ref.getValue() << "'.");
1250        }
1251
1252        if (!axis_ref.isEmpty())
1253        {
1254          if (CAxis::has(axis_ref))
1255          {
1256            vecAxis.push_back(CAxis::get(axis_ref));
1257            axisDomainOrderTmp.push_back(1);
1258          }
1259          else
1260            ERROR("CField::solveGridReference(void)",
1261                  << "Invalid reference to axis '" << axis_ref.getValue() << "'.");
1262        }
1263
1264        if (!scalar_ref.isEmpty())
1265        {
1266          if (CScalar::has(scalar_ref))
1267          {
1268            vecScalar.push_back(CScalar::get(scalar_ref));
1269            axisDomainOrderTmp.push_back(0);
1270          }
1271          else
1272            ERROR("CField::solveGridReference(void)",
1273                  << "Invalid reference to scalar '" << scalar_ref.getValue() << "'.");
1274        }
1275       
1276        CArray<int,1> axisDomainOrder(axisDomainOrderTmp.size());
1277        for (int idx = 0; idx < axisDomainOrderTmp.size(); ++idx)
1278        {
1279          axisDomainOrder(idx) = axisDomainOrderTmp[idx];
1280        }
1281
1282        // Warning: the gridId shouldn't be set as the grid_ref since it could be inherited
1283        StdString gridId = CGrid::generateId(vecDom, vecAxis, vecScalar,axisDomainOrder);
1284        if (CGrid::has(gridId))
1285          this->grid = CGrid::get(gridId);
1286        else
1287          this->grid = CGrid::createGrid(gridId, vecDom, vecAxis, vecScalar,axisDomainOrder);
1288      }
1289      else
1290      {
1291        if (CGrid::has(grid_ref))
1292          this->grid = CGrid::get(grid_ref);
1293        else
1294          ERROR("CField::solveGridReference(void)",
1295                << "Invalid reference to grid '" << grid_ref.getValue() << "'.");
1296      }
1297   }
1298
1299   void CField::solveGridDomainAxisRef(bool checkAtt)
1300   {
1301     grid->solveDomainAxisRef(checkAtt);
1302   }
1303
1304   void CField::solveCheckMaskIndex(bool doSendingIndex)
1305   {
1306     grid->checkMaskIndex(doSendingIndex);
1307   }
1308
1309   void CField::solveTransformedGrid()
1310   {
1311     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
1312     {
1313       std::vector<CGrid*> grids;
1314       // Source grid
1315       grids.push_back(getDirectFieldReference()->grid);
1316       // Intermediate grids
1317       if (!grid_path.isEmpty())
1318       {
1319         std::string gridId;
1320         size_t start = 0, end;
1321
1322         do
1323         {
1324           end = grid_path.getValue().find(',', start);
1325           if (end != std::string::npos)
1326           {
1327             gridId = grid_path.getValue().substr(start, end - start);
1328             start = end + 1;
1329           }
1330           else
1331             gridId = grid_path.getValue().substr(start);
1332
1333           if (!CGrid::has(gridId))
1334             ERROR("void CField::solveTransformedGrid()",
1335                   << "Invalid grid_path, the grid '" << gridId << "' does not exist.");
1336
1337           grids.push_back(CGrid::get(gridId));
1338         }
1339         while (end != std::string::npos);
1340       }
1341       // Destination grid
1342       grids.push_back(grid);
1343
1344       for (size_t i = 0, count = grids.size() - 1; i < count; ++i)
1345       {
1346         CGrid *gridSrc  = grids[i];
1347         CGrid *gridDest = grids[i + 1];
1348         if (!gridDest->isTransformed())
1349           gridDest->transformGrid(gridSrc);
1350       }
1351     }
1352     else if (grid && grid->hasTransform() && !grid->isTransformed())
1353     {
1354       // Temporarily deactivate the self-transformation of grid
1355       //grid->transformGrid(grid);
1356     }
1357   }
1358
1359   void CField::solveGenerateGrid()
1360   {
1361     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
1362       grid->completeGrid(getDirectFieldReference()->grid);
1363     else
1364       grid->completeGrid();
1365   }
1366
1367   void CField::solveGridDomainAxisBaseRef()
1368   {
1369     grid->solveDomainAxisRef(false);
1370     grid->solveDomainAxisBaseRef();
1371   }
1372
1373   ///-------------------------------------------------------------------
1374
1375   template <>
1376   void CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)
1377   {
1378      if (this->group_ref.isEmpty()) return;
1379      StdString gref = this->group_ref.getValue();
1380
1381      if (!CFieldGroup::has(gref))
1382         ERROR("CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)",
1383               << "[ gref = " << gref << "]"
1384               << " invalid group name !");
1385
1386      CFieldGroup* group = CFieldGroup::get(gref);
1387      CFieldGroup* owner = CFieldGroup::get(boost::polymorphic_downcast<CFieldGroup*>(this));
1388
1389      std::vector<CField*> allChildren  = group->getAllChildren();
1390      std::vector<CField*>::iterator it = allChildren.begin(), end = allChildren.end();
1391
1392      for (; it != end; it++)
1393      {
1394         CField* child = *it;
1395         if (child->hasId()) owner->createChild()->field_ref.setValue(child->getId());
1396
1397      }
1398   }
1399
1400   void CField::scaleFactorAddOffset(double scaleFactor, double addOffset)
1401   {
1402     recvDataSrv = (recvDataSrv - addOffset) / scaleFactor;
1403   }
1404
1405   void CField::invertScaleFactorAddOffset(double scaleFactor, double addOffset)
1406   {
1407     recvDataSrv = recvDataSrv * scaleFactor + addOffset;
1408   }
1409
1410   void CField::outputField(CArray<double,1>& fieldOut)
1411   { 
1412      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1413      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1414      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1415      {
1416        fieldOut(outIndexServer(idx)) = recvDataSrv(outIndexClient(idx));
1417      }
1418   }
1419
1420   void CField::inputField(CArray<double,1>& fieldIn)
1421   {
1422      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1423      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1424      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1425      {
1426        recvDataSrv(outIndexClient(idx)) = fieldIn(outIndexServer(idx));
1427      }
1428
1429   }
1430
1431   void CField::outputCompressedField(CArray<double,1>& fieldOut)
1432   {
1433      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1434      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1435      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1436      {
1437        fieldOut((idx)) = recvDataSrv(outIndexClient(idx));
1438      }
1439   }
1440
1441   ///-------------------------------------------------------------------
1442
1443   void CField::parse(xml::CXMLNode& node)
1444   {
1445      SuperClass::parse(node);
1446      if (!node.getContent(this->content))
1447      {
1448        if (node.goToChildElement())
1449        {
1450          do
1451          {
1452            if (node.getElementName() == "variable" || node.getElementName() == "variable_group") this->getVirtualVariableGroup()->parseChild(node);
1453          } while (node.goToNextElement());
1454          node.goToParentElement();
1455        }
1456      }
1457    }
1458
1459   /*!
1460     This function retrieves Id of corresponding domain_ref and axis_ref (if any)
1461   of a field. In some cases, only domain exists but axis doesn't
1462   \return pair of Domain and Axis id
1463   */
1464   const std::vector<StdString>& CField::getRefDomainAxisIds()
1465   {
1466     CGrid* cgPtr = getRelGrid();
1467     if (NULL != cgPtr)
1468     {
1469       std::vector<StdString>::iterator it;
1470       if (!domain_ref.isEmpty())
1471       {
1472         std::vector<StdString> domainList = cgPtr->getDomainList();
1473         it = std::find(domainList.begin(), domainList.end(), domain_ref.getValue());
1474         if (domainList.end() != it) domAxisScalarIds_[0] = *it;
1475       }
1476
1477       if (!axis_ref.isEmpty())
1478       {
1479         std::vector<StdString> axisList = cgPtr->getAxisList();
1480         it = std::find(axisList.begin(), axisList.end(), axis_ref.getValue());
1481         if (axisList.end() != it) domAxisScalarIds_[1] = *it;
1482       }
1483
1484       if (!scalar_ref.isEmpty())
1485       {
1486         std::vector<StdString> scalarList = cgPtr->getScalarList();
1487         it = std::find(scalarList.begin(), scalarList.end(), scalar_ref.getValue());
1488         if (scalarList.end() != it) domAxisScalarIds_[2] = *it;
1489       }
1490     }
1491     return (domAxisScalarIds_);
1492   }
1493
1494   CVariable* CField::addVariable(const string& id)
1495   {
1496     return vVariableGroup->createChild(id);
1497   }
1498
1499   CVariableGroup* CField::addVariableGroup(const string& id)
1500   {
1501     return vVariableGroup->createChildGroup(id);
1502   }
1503
1504   void CField::sendAddAllVariables(CContextClient* client)
1505   {
1506     std::vector<CVariable*> allVar = getAllVariables();
1507     std::vector<CVariable*>::const_iterator it = allVar.begin();
1508     std::vector<CVariable*>::const_iterator itE = allVar.end();
1509
1510     for (; it != itE; ++it)
1511     {
1512       this->sendAddVariable((*it)->getId(), client);
1513       (*it)->sendAllAttributesToServer(client);
1514       (*it)->sendValue(client);
1515     }
1516   }
1517
1518   void CField::sendAddVariable(const string& id, CContextClient* client)
1519   {
1520      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE, client);
1521   }
1522
1523   void CField::sendAddVariableGroup(const string& id, CContextClient* client)
1524   {
1525      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE_GROUP, client);
1526   }
1527
1528   void CField::recvAddVariable(CEventServer& event)
1529   {
1530
1531      CBufferIn* buffer = event.subEvents.begin()->buffer;
1532      string id;
1533      *buffer >> id;
1534      get(id)->recvAddVariable(*buffer);
1535   }
1536
1537   void CField::recvAddVariable(CBufferIn& buffer)
1538   {
1539      string id;
1540      buffer >> id;
1541      addVariable(id);
1542   }
1543
1544   void CField::recvAddVariableGroup(CEventServer& event)
1545   {
1546
1547      CBufferIn* buffer = event.subEvents.begin()->buffer;
1548      string id;
1549      *buffer >> id;
1550      get(id)->recvAddVariableGroup(*buffer);
1551   }
1552
1553   void CField::recvAddVariableGroup(CBufferIn& buffer)
1554   {
1555      string id;
1556      buffer >> id;
1557      addVariableGroup(id);
1558   }
1559
1560   /*!
1561    * Check on freq_off and freq_op attributes.
1562    */
1563   void CField::checkAttributes(void)
1564   {
1565     if (freq_op.isEmpty())
1566     {
1567/*
1568       if (!freq_offset.isEmpty())
1569         ERROR("CField::checkAttributes(void)",
1570               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
1571               << "Attribute freq_offset cannot be defined if attribute freq_op is not defined. "
1572               << "Please define freq_op.") */
1573       if (operation.getValue()=="instant")
1574       {
1575         freq_op.setValue(file->output_freq.getValue());
1576         if (freq_offset.isEmpty()) freq_offset.setValue(file->output_freq.getValue()-TimeStep);
1577       }
1578       else
1579       {
1580         freq_op.setValue(TimeStep);
1581         if (freq_offset.isEmpty()) freq_offset.setValue(freq_op.getValue()-TimeStep);
1582       }
1583     }
1584     else
1585     {
1586       if (freq_offset.isEmpty())
1587         freq_offset.setValue(freq_op.getValue()-TimeStep);
1588     }
1589   }
1590
1591   /*!
1592    * Returns string arithmetic expression associated to the field.
1593    * \return if content is defined return content string, otherwise, if "expr" attribute is defined, return expr string.
1594    */
1595   const string& CField::getExpression(void)
1596   {
1597     if (!expr.isEmpty() && content.empty())
1598     {
1599       content = expr;
1600       expr.reset();
1601     }
1602
1603     return content;
1604   }
1605
1606   bool CField::hasExpression(void) const
1607   {
1608     return (!expr.isEmpty() || !content.empty());
1609   }
1610
1611
1612   DEFINE_REF_FUNC(Field,field)
1613} // namespace xios
Note: See TracBrowser for help on using the repository browser.