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

Last change on this file since 1473 was 1473, checked in by oabramkina, 6 years ago

DEV_CMIP6: bugfix for certain cases of monthly output and freq_offset such as 1mo-2ts.

  • Property copyright set to
    Software name : XIOS (Xml I/O Server)
    http://forge.ipsl.jussieu.fr/ioserver
    Creation date : January 2009
    Licence : CeCCIL version2
    see license file in root directory : Licence_CeCILL_V2-en.txt
    or http://www.cecill.info/licences/Licence_CeCILL_V2-en.html
    Holder : CEA/LSCE (Laboratoire des Sciences du CLimat et de l'Environnement)
    CNRS/IPSL (Institut Pierre Simon Laplace)
    Project Manager : Yann Meurdesoif
    yann.meurdesoif@cea.fr
  • Property svn:executable set to *
File size: 55.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 = boost::shared_ptr<func::CFunctor>(new func::CInstant(recvDataSrv));
222    }
223
224    CArray<double,1> recv_data_tmp(recvDataSrv.numElements());   
225    const CDate& currDate = context->getCalendar()->getCurrentDate();
226    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   boost::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      boost::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 = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid,true));
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 = boost::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 = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true));
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 = boost::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           boost::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<boost::shared_ptr<CFilter>, boost::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 = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, 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 = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, false, 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 = boost::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 = boost::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   boost::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<boost::shared_ptr<CFilter>, boost::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 = boost::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   boost::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 = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, 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 = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, 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   boost::shared_ptr<COutputPin> CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1216   {
1217     std::map<CDuration, boost::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       boost::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   boost::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       boost::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        if (!domain_ref.isEmpty())
1319        {
1320          StdString tmp = domain_ref.getValue();
1321          if (CDomain::has(domain_ref))
1322          {
1323            vecDom.push_back(CDomain::get(domain_ref));
1324            axisDomainOrderTmp.push_back(2);
1325          }
1326          else
1327            ERROR("CField::solveGridReference(void)",
1328                  << "Invalid reference to domain '" << domain_ref.getValue() << "'.");
1329        }
1330
1331        if (!axis_ref.isEmpty())
1332        {
1333          if (CAxis::has(axis_ref))
1334          {
1335            vecAxis.push_back(CAxis::get(axis_ref));
1336            axisDomainOrderTmp.push_back(1);
1337          }
1338          else
1339            ERROR("CField::solveGridReference(void)",
1340                  << "Invalid reference to axis '" << axis_ref.getValue() << "'.");
1341        }
1342
1343        if (!scalar_ref.isEmpty())
1344        {
1345          if (CScalar::has(scalar_ref))
1346          {
1347            vecScalar.push_back(CScalar::get(scalar_ref));
1348            axisDomainOrderTmp.push_back(0);
1349          }
1350          else
1351            ERROR("CField::solveGridReference(void)",
1352                  << "Invalid reference to scalar '" << scalar_ref.getValue() << "'.");
1353        }
1354       
1355        CArray<int,1> axisDomainOrder(axisDomainOrderTmp.size());
1356        for (int idx = 0; idx < axisDomainOrderTmp.size(); ++idx)
1357        {
1358          axisDomainOrder(idx) = axisDomainOrderTmp[idx];
1359        }
1360
1361        // Warning: the gridId shouldn't be set as the grid_ref since it could be inherited
1362        StdString gridId = CGrid::generateId(vecDom, vecAxis, vecScalar,axisDomainOrder);
1363        if (CGrid::has(gridId))
1364          this->grid = CGrid::get(gridId);
1365        else
1366          this->grid = CGrid::createGrid(gridId, vecDom, vecAxis, vecScalar,axisDomainOrder);
1367      }
1368      else
1369      {
1370        if (CGrid::has(grid_ref))
1371          this->grid = CGrid::get(grid_ref);
1372        else
1373          ERROR("CField::solveGridReference(void)",
1374                << "Invalid reference to grid '" << grid_ref.getValue() << "'.");
1375      }
1376   }
1377
1378   void CField::solveGridDomainAxisRef(bool checkAtt)
1379   {
1380     grid->solveDomainAxisRef(checkAtt);
1381   }
1382
1383   void CField::solveCheckMaskIndex(bool doSendingIndex)
1384   {
1385     grid->checkMaskIndex(doSendingIndex);
1386   }
1387
1388   void CField::solveTransformedGrid()
1389   {
1390     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
1391     {
1392       std::vector<CGrid*> grids;
1393       // Source grid
1394       grids.push_back(getDirectFieldReference()->grid);
1395       // Intermediate grids
1396       if (!grid_path.isEmpty())
1397       {
1398         std::string gridId;
1399         size_t start = 0, end;
1400
1401         do
1402         {
1403           end = grid_path.getValue().find(',', start);
1404           if (end != std::string::npos)
1405           {
1406             gridId = grid_path.getValue().substr(start, end - start);
1407             start = end + 1;
1408           }
1409           else
1410             gridId = grid_path.getValue().substr(start);
1411
1412           if (!CGrid::has(gridId))
1413             ERROR("void CField::solveTransformedGrid()",
1414                   << "Invalid grid_path, the grid '" << gridId << "' does not exist.");
1415
1416           grids.push_back(CGrid::get(gridId));
1417         }
1418         while (end != std::string::npos);
1419       }
1420       // Destination grid
1421       grids.push_back(grid);
1422
1423       for (size_t i = 0, count = grids.size() - 1; i < count; ++i)
1424       {
1425         CGrid *gridSrc  = grids[i];
1426         CGrid *gridDest = grids[i + 1];
1427         if (!gridDest->isTransformed())
1428           gridDest->transformGrid(gridSrc);
1429       }
1430     }
1431     else if (grid && grid->hasTransform() && !grid->isTransformed())
1432     {
1433       // Temporarily deactivate the self-transformation of grid
1434       // grid->transformGrid(grid);
1435     }
1436   }
1437
1438   void CField::solveGenerateGrid()
1439   {
1440     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
1441       grid->completeGrid(getDirectFieldReference()->grid);
1442     else
1443       grid->completeGrid();
1444   }
1445
1446   void CField::solveGridDomainAxisBaseRef()
1447   {
1448     grid->solveDomainAxisRef(false);
1449     grid->solveDomainAxisBaseRef();
1450   }
1451
1452   ///-------------------------------------------------------------------
1453
1454   template <>
1455   void CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)
1456   {
1457      if (this->group_ref.isEmpty()) return;
1458      StdString gref = this->group_ref.getValue();
1459
1460      if (!CFieldGroup::has(gref))
1461         ERROR("CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)",
1462               << "[ gref = " << gref << "]"
1463               << " invalid group name !");
1464
1465      CFieldGroup* group = CFieldGroup::get(gref);
1466      CFieldGroup* owner = CFieldGroup::get(boost::polymorphic_downcast<CFieldGroup*>(this));
1467
1468      std::vector<CField*> allChildren  = group->getAllChildren();
1469      std::vector<CField*>::iterator it = allChildren.begin(), end = allChildren.end();
1470
1471      for (; it != end; it++)
1472      {
1473         CField* child = *it;
1474         if (child->hasId()) owner->createChild()->field_ref.setValue(child->getId());
1475
1476      }
1477   }
1478
1479   void CField::scaleFactorAddOffset(double scaleFactor, double addOffset)
1480   {
1481     recvDataSrv = (recvDataSrv - addOffset) / scaleFactor;
1482   }
1483
1484   void CField::invertScaleFactorAddOffset(double scaleFactor, double addOffset)
1485   {
1486     recvDataSrv = recvDataSrv * scaleFactor + addOffset;
1487   }
1488
1489   void CField::outputField(CArray<double,1>& fieldOut)
1490   { 
1491      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1492      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1493      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1494      {
1495        fieldOut(outIndexServer(idx)) = recvDataSrv(outIndexClient(idx));
1496      }
1497   }
1498
1499   void CField::inputField(CArray<double,1>& fieldIn)
1500   {
1501      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1502      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1503      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1504      {
1505        recvDataSrv(outIndexClient(idx)) = fieldIn(outIndexServer(idx));
1506      }
1507
1508   }
1509
1510   void CField::outputCompressedField(CArray<double,1>& fieldOut)
1511   {
1512      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1513      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1514      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1515      {
1516        fieldOut((idx)) = recvDataSrv(outIndexClient(idx));
1517      }
1518   }
1519
1520   ///-------------------------------------------------------------------
1521
1522   void CField::parse(xml::CXMLNode& node)
1523   {
1524      string newContent ;
1525      SuperClass::parse(node);
1526      if (node.goToChildElement())
1527      {
1528        do
1529        {
1530          if (node.getElementName() == "variable" || node.getElementName() == "variable_group") this->getVirtualVariableGroup()->parseChild(node);
1531          else if (node.getElementName() == "expr") if (node.getContent(newContent)) content+=newContent ;
1532        } while (node.goToNextElement());
1533        node.goToParentElement();
1534      }
1535      if (node.getContent(newContent)) content=newContent ;
1536    }
1537
1538   /*!
1539     This function retrieves Id of corresponding domain_ref and axis_ref (if any)
1540   of a field. In some cases, only domain exists but axis doesn't
1541   \return pair of Domain and Axis id
1542   */
1543   const std::vector<StdString>& CField::getRefDomainAxisIds()
1544   {
1545     CGrid* cgPtr = getRelGrid();
1546     if (NULL != cgPtr)
1547     {
1548       std::vector<StdString>::iterator it;
1549       if (!domain_ref.isEmpty())
1550       {
1551         std::vector<StdString> domainList = cgPtr->getDomainList();
1552         it = std::find(domainList.begin(), domainList.end(), domain_ref.getValue());
1553         if (domainList.end() != it) domAxisScalarIds_[0] = *it;
1554       }
1555
1556       if (!axis_ref.isEmpty())
1557       {
1558         std::vector<StdString> axisList = cgPtr->getAxisList();
1559         it = std::find(axisList.begin(), axisList.end(), axis_ref.getValue());
1560         if (axisList.end() != it) domAxisScalarIds_[1] = *it;
1561       }
1562
1563       if (!scalar_ref.isEmpty())
1564       {
1565         std::vector<StdString> scalarList = cgPtr->getScalarList();
1566         it = std::find(scalarList.begin(), scalarList.end(), scalar_ref.getValue());
1567         if (scalarList.end() != it) domAxisScalarIds_[2] = *it;
1568       }
1569     }
1570     return (domAxisScalarIds_);
1571   }
1572
1573   CVariable* CField::addVariable(const string& id)
1574   {
1575     return vVariableGroup->createChild(id);
1576   }
1577
1578   CVariableGroup* CField::addVariableGroup(const string& id)
1579   {
1580     return vVariableGroup->createChildGroup(id);
1581   }
1582
1583   void CField::setContextClient(CContextClient* contextClient)
1584   {
1585     CContext* context = CContext::getCurrent();
1586     client = contextClient;
1587     if (context->hasClient)
1588     {
1589       // A grid is sent by a client (both for read or write) or by primary server (write only)
1590       if (context->hasServer)
1591       {
1592         if (file->mode.isEmpty() || (!file->mode.isEmpty() && file->mode == CFile::mode_attr::write))
1593           grid->setContextClient(contextClient);
1594       }
1595       else
1596           grid->setContextClient(contextClient);
1597     }
1598   }
1599
1600   CContextClient* CField::getContextClient()
1601   {
1602     return client;
1603   }
1604
1605   void CField::sendAddAllVariables(CContextClient* client)
1606   {
1607     std::vector<CVariable*> allVar = getAllVariables();
1608     std::vector<CVariable*>::const_iterator it = allVar.begin();
1609     std::vector<CVariable*>::const_iterator itE = allVar.end();
1610
1611     for (; it != itE; ++it)
1612     {
1613       this->sendAddVariable((*it)->getId(), client);
1614       (*it)->sendAllAttributesToServer(client);
1615       (*it)->sendValue(client);
1616     }
1617   }
1618
1619   void CField::sendAddVariable(const string& id, CContextClient* client)
1620   {
1621      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE, client);
1622   }
1623
1624   void CField::sendAddVariableGroup(const string& id, CContextClient* client)
1625   {
1626      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE_GROUP, client);
1627   }
1628
1629   void CField::recvAddVariable(CEventServer& event)
1630   {
1631
1632      CBufferIn* buffer = event.subEvents.begin()->buffer;
1633      string id;
1634      *buffer >> id;
1635      get(id)->recvAddVariable(*buffer);
1636   }
1637
1638   void CField::recvAddVariable(CBufferIn& buffer)
1639   {
1640      string id;
1641      buffer >> id;
1642      addVariable(id);
1643   }
1644
1645   void CField::recvAddVariableGroup(CEventServer& event)
1646   {
1647
1648      CBufferIn* buffer = event.subEvents.begin()->buffer;
1649      string id;
1650      *buffer >> id;
1651      get(id)->recvAddVariableGroup(*buffer);
1652   }
1653
1654   void CField::recvAddVariableGroup(CBufferIn& buffer)
1655   {
1656      string id;
1657      buffer >> id;
1658      addVariableGroup(id);
1659   }
1660
1661   /*!
1662    * Check on freq_off and freq_op attributes.
1663    */
1664   void CField::checkTimeAttributes(CDuration* freqOp)
1665   {
1666     bool isFieldRead  = file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read;
1667     bool isFieldWrite = file && ( file->mode.isEmpty() ||  file->mode == CFile::mode_attr::write);
1668     if (isFieldRead && operation.getValue() != "instant")
1669       ERROR("void CField::checkTimeAttributes(void)",
1670             << "Unsupported operation for field '" << getFieldOutputName() << "'." << std::endl
1671             << "Currently only \"instant\" is supported for fields read from file.")
1672
1673     if (freq_op.isEmpty())
1674     {
1675       if (operation.getValue() == "instant")
1676       {
1677         if (isFieldRead || isFieldWrite) freq_op.setValue(file->output_freq.getValue());
1678         else freq_op=*freqOp ;
1679       }
1680       else
1681         freq_op.setValue(TimeStep);
1682     }
1683     if (freq_offset.isEmpty())
1684       freq_offset.setValue(isFieldRead ? NoneDu : (freq_op.getValue() - TimeStep));
1685   }
1686
1687   /*!
1688    * Returns string arithmetic expression associated to the field.
1689    * \return if content is defined return content string, otherwise, if "expr" attribute is defined, return expr string.
1690    */
1691   const string& CField::getExpression(void)
1692   {
1693     if (!expr.isEmpty() && content.empty())
1694     {
1695       content = expr;
1696       expr.reset();
1697     }
1698
1699     return content;
1700   }
1701
1702   bool CField::hasExpression(void) const
1703   {
1704     return (!expr.isEmpty() || !content.empty());
1705   }
1706
1707
1708   DEFINE_REF_FUNC(Field,field)
1709} // namespace xios
Note: See TracBrowser for help on using the repository browser.