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

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

XIOS_COUPLING branch : more comments and cleaning

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