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

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

Fixing a bug in case of output_freq defined in months to avoid adding a month to the last day of a month.

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