source: XIOS/dev/dev_ym/XIOS_COUPLING/src/node/field.cpp @ 1853

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

Coupling branch : replace hasServer and hasClient combination by the name of correct service : CLIENT, GATHERER or OUT_SERVER.

YM

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