source: XIOS/dev/branch_openmp/src/node/field.cpp @ 1545

Last change on this file since 1545 was 1545, checked in by yushan, 6 years ago

branch_openmp merged with trunk r1544

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