source: XIOS/dev/dev_olga/src/node/field.cpp @ 1594

Last change on this file since 1594 was 1594, checked in by oabramkina, 5 years ago

Bugfix on dev: NaNs? were not necessarily replaced upon writing by default_value in case of grid mask.

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