source: XIOS/dev/dev_ym/XIOS_SERVICES/src/node/field.cpp @ 1761

Last change on this file since 1761 was 1761, checked in by ymipsl, 5 years ago

implementing first guess for service functionnalities.

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            context->eventLoop();
638
639          timer.suspend();
640        }
641      }
642      while (isDataLate && timer.getCumulatedTime() < CXios::recvFieldTimeout);
643      timer.resume();
644      traceOn() ;
645      timer.suspend() ;
646
647
648      if (isDataLate)
649        ERROR("void CField::checkForLateDataFromServer(void)",
650              << "Late data at timestep = " << currentDate);
651    }
652  }
653  CATCH_DUMP_ATTR
654
655  void CField::checkIfMustAutoTrigger(void)
656  TRY
657  {
658    mustAutoTrigger = serverSourceFilter ? serverSourceFilter->mustAutoTrigger() : false;
659  }
660  CATCH_DUMP_ATTR
661
662  void CField::autoTriggerIfNeeded(void)
663  TRY
664  {
665    if (mustAutoTrigger)
666      serverSourceFilter->trigger(CContext::getCurrent()->getCalendar()->getCurrentDate());
667  }
668  CATCH_DUMP_ATTR
669
670   //----------------------------------------------------------------
671
672   void CField::setRelFile(CFile* _file)
673   TRY
674   {
675      this->file = _file;
676      hasOutputFile = true;
677   }
678   CATCH_DUMP_ATTR
679
680   //----------------------------------------------------------------
681
682   StdString CField::GetName(void)    { return StdString("field"); }
683   StdString CField::GetDefName(void) { return CField::GetName(); }
684   ENodeType CField::GetType(void)    { return eField; }
685
686   //----------------------------------------------------------------
687
688   CGrid* CField::getRelGrid(void) const
689   TRY
690   {
691      return this->grid;
692   }
693   CATCH
694
695   //----------------------------------------------------------------
696
697   CFile* CField::getRelFile(void) const
698   TRY
699   {
700      return this->file;
701   }
702   CATCH
703
704   int CField::getNStep(void) const
705   TRY
706   {
707      return this->nstep;
708   }
709   CATCH
710
711   func::CFunctor::ETimeType CField::getOperationTimeType() const
712   TRY
713   {
714     return operationTimeType;
715   }
716   CATCH
717
718   //----------------------------------------------------------------
719
720   void CField::incrementNStep(void)
721   TRY
722   {
723      this->nstep++;
724   }
725   CATCH_DUMP_ATTR
726
727   void CField::resetNStep(int nstep /*= 0*/)
728   TRY
729   {
730      this->nstep = nstep;
731   }
732   CATCH_DUMP_ATTR
733
734   void CField::resetNStepMax(void)
735   TRY
736   {
737      this->nstepMax = 0;
738      nstepMaxRead = false;
739   }
740   CATCH_DUMP_ATTR
741
742   //----------------------------------------------------------------
743
744   bool CField::isActive(bool atCurrentTimestep /*= false*/) const
745   TRY
746   {
747      if (clientSourceFilter)
748        return atCurrentTimestep ? clientSourceFilter->isDataExpected(CContext::getCurrent()->getCalendar()->getCurrentDate()) : true;
749      else if (storeFilter)
750        return true;
751      else if (instantDataFilter)
752        ERROR("bool CField::isActive(bool atCurrentTimestep)",
753              << "Impossible to check if field [ id = " << getId() << " ] is active as it cannot be used to receive nor send data.");
754
755      return false;
756   }
757   CATCH
758
759   //----------------------------------------------------------------
760
761   bool CField::wasWritten() const
762   TRY
763   {
764     return written;
765   }
766   CATCH
767
768   void CField::setWritten()
769   TRY
770   {
771     written = true;
772   }
773   CATCH_DUMP_ATTR
774
775   //----------------------------------------------------------------
776
777   bool CField::getUseCompressedOutput() const
778   TRY
779   {
780     return useCompressedOutput;
781   }
782   CATCH
783
784   void CField::setUseCompressedOutput()
785   TRY
786   {
787     useCompressedOutput = true;
788   }
789   CATCH_DUMP_ATTR
790
791   //----------------------------------------------------------------
792
793   std::shared_ptr<COutputPin> CField::getInstantDataFilter()
794   TRY
795   {
796     return instantDataFilter;
797   }
798   CATCH_DUMP_ATTR
799
800   //----------------------------------------------------------------
801
802   /*!
803     Build up graph of grids which plays role of destination and source in grid transformation
804     This function should be called before \func solveGridReference()
805   */
806   void CField::buildGridTransformationGraph()
807   TRY
808   {
809     CContext* context = CContext::getCurrent();
810     if (context->hasClient && !context->hasServer)
811     {
812       if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
813       {
814         grid->addTransGridSource(getDirectFieldReference()->grid);
815       }
816     }
817   }
818   CATCH_DUMP_ATTR
819
820   /*!
821     Generate a new grid destination if there are more than one grid source pointing to a same grid destination
822   */
823   void CField::generateNewTransformationGridDest()
824   TRY
825   {
826     CContext* context = CContext::getCurrent();
827     if (context->hasClient && !context->hasServer)
828     {
829       std::map<CGrid*,std::pair<bool,StdString> >& gridSrcMap = grid->getTransGridSource();
830       if (1 < gridSrcMap.size())
831       {
832         // Search for grid source
833         CGrid* gridSrc = grid;
834         CField* currField = this;
835         std::vector<CField*> hieraField;
836
837         while (currField->hasDirectFieldReference() && (gridSrc == grid))
838         {
839           hieraField.push_back(currField);
840           CField* tmp = currField->getDirectFieldReference();
841           currField = tmp;
842           gridSrc = currField->grid;
843         }
844
845         if (gridSrcMap.end() != gridSrcMap.find(gridSrc))
846         {
847           CGrid* gridTmp;
848           std::pair<bool,StdString> newGridDest = gridSrcMap[gridSrc];
849           if (newGridDest.first)
850           {
851             StdString newIdGridDest = newGridDest.second;
852             if (!CGrid::has(newIdGridDest))
853             {
854                ERROR("CGrid* CGrid::generateNewTransformationGridDest()",
855                  << " Something wrong happened! Grid whose id " << newIdGridDest
856                  << "should exist ");
857             }
858             gridTmp = CGrid::get(newIdGridDest);
859           }
860           else
861           {
862             StdString newIdGridDest = CGrid::generateId(gridSrc, grid);
863             gridTmp = CGrid::cloneGrid(newIdGridDest, grid);
864
865             (gridSrcMap[gridSrc]).first = true;
866             (gridSrcMap[gridSrc]).second = newIdGridDest;
867           }
868
869           // Update all descendants
870           for (std::vector<CField*>::iterator it = hieraField.begin(); it != hieraField.end(); ++it)
871           {
872             (*it)->grid = gridTmp;
873             (*it)->updateRef((*it)->grid);
874           }
875         }
876       }
877     }
878   }
879   CATCH_DUMP_ATTR
880
881   void CField::updateRef(CGrid* grid)
882   TRY
883   {
884     if (!grid_ref.isEmpty()) grid_ref.setValue(grid->getId());
885     else
886     {
887       std::vector<CAxis*> axisTmp = grid->getAxis();
888       std::vector<CDomain*> domainTmp = grid->getDomains();
889       if ((1<axisTmp.size()) || (1<domainTmp.size()))
890         ERROR("void CField::updateRef(CGrid* grid)",
891           << "More than one domain or axis is available for domain_ref/axis_ref of field " << this->getId());
892
893       if ((!domain_ref.isEmpty()) && (domainTmp.empty()))
894         ERROR("void CField::updateRef(CGrid* grid)",
895           << "Incoherent between available domain and domain_ref of field " << this->getId());
896       if ((!axis_ref.isEmpty()) && (axisTmp.empty()))
897         ERROR("void CField::updateRef(CGrid* grid)",
898           << "Incoherent between available axis and axis_ref of field " << this->getId());
899
900       if (!domain_ref.isEmpty()) domain_ref.setValue(domainTmp[0]->getId());
901       if (!axis_ref.isEmpty()) axis_ref.setValue(axisTmp[0]->getId());
902     }
903   }
904   CATCH_DUMP_ATTR
905   
906   /*!
907     Solve reference of all enabled fields even the source fields .
908     In this step, we do transformations.
909   */
910   void CField::solveAllEnabledFieldsAndTransform()
911   TRY
912   {
913     CContext* context = CContext::getCurrent();
914     bool hasClient = context->hasClient;
915     bool hasServer = context->hasServer;
916
917     if (!isReferenceSolvedAndTransformed)
918     {
919        isReferenceSolvedAndTransformed = true;
920
921        if (hasClient && !hasServer)
922        {
923          solveRefInheritance(true);
924          if (hasDirectFieldReference()) getDirectFieldReference()->solveAllEnabledFieldsAndTransform();
925        }
926
927        if (hasServer)
928          solveServerOperation();
929
930        solveGridReference();
931
932        if (hasClient && !hasServer)
933       {
934         solveGenerateGrid();
935         buildGridTransformationGraph();
936       }
937
938       solveGridDomainAxisRef(false);
939
940       if (hasClient && !hasServer)
941       {
942         solveTransformedGrid();
943       }
944
945       solveGridDomainAxisRef(false);
946     }
947   }
948   CATCH_DUMP_ATTR
949
950   void CField::checkGridOfEnabledFields()
951   TRY
952   {
953     if (!isGridChecked)
954     {
955       isGridChecked = true;
956       solveCheckMaskIndex(false);
957     }
958   }
959   CATCH_DUMP_ATTR
960
961   void CField::sendGridComponentOfEnabledFields()
962   TRY
963   {
964      solveGridDomainAxisRef(true);
965      // solveCheckMaskIndex(true);
966   }
967   CATCH_DUMP_ATTR
968
969   void CField::sendGridOfEnabledFields()
970   TRY
971   {
972      // solveGridDomainAxisRef(true);
973      solveCheckMaskIndex(true);
974   }   
975   CATCH_DUMP_ATTR
976
977   void CField::solveOnlyReferenceEnabledField(bool doSending2Server)
978   TRY
979   {
980     CContext* context = CContext::getCurrent();
981     if (!isReferenceSolved)
982     {
983        isReferenceSolved = true;
984
985        if (context->hasClient && !context->hasServer)
986        {
987          solveRefInheritance(true);
988          if (hasDirectFieldReference()) getDirectFieldReference()->solveOnlyReferenceEnabledField(false);
989        }
990
991        if (context->hasServer)
992          solveServerOperation();
993
994        solveGridReference();
995        grid->solveDomainAxisRefInheritance(true); // make it again to solve grid reading from file
996
997        if (context->hasClient && !context->hasServer)
998       {
999         solveGenerateGrid();
1000         buildGridTransformationGraph();
1001       }
1002     }
1003   }
1004   CATCH_DUMP_ATTR
1005
1006   void CField::solveAllReferenceEnabledField(bool doSending2Server)
1007   TRY
1008   {
1009     CContext* context = CContext::getCurrent();
1010     solveOnlyReferenceEnabledField(doSending2Server);
1011
1012     if (!areAllReferenceSolved)
1013     {
1014        areAllReferenceSolved = true;
1015       
1016        if (context->hasClient && !context->hasServer)
1017        {
1018          solveRefInheritance(true);
1019          if (hasDirectFieldReference()) getDirectFieldReference()->solveAllReferenceEnabledField(false);
1020        }
1021        else if (context->hasServer)
1022          solveServerOperation();
1023
1024        solveGridReference();
1025     }
1026
1027     solveGridDomainAxisRef(doSending2Server);
1028
1029     if (context->hasClient && !context->hasServer)
1030     {
1031       solveTransformedGrid();
1032     }
1033
1034     solveCheckMaskIndex(doSending2Server);
1035   }
1036   CATCH_DUMP_ATTR
1037
1038   std::map<int, StdSize> CField::getGridAttributesBufferSize(CContextClient* client, bool bufferForWriting /*= "false"*/)
1039   TRY
1040   {
1041     return grid->getAttributesBufferSize(client, bufferForWriting);
1042   }
1043   CATCH_DUMP_ATTR
1044
1045   std::map<int, StdSize> CField::getGridDataBufferSize(CContextClient* client, bool bufferForWriting /*= "false"*/)
1046   TRY
1047   {
1048     return grid->getDataBufferSize(client, getId(), bufferForWriting);
1049   }
1050   CATCH_DUMP_ATTR
1051
1052   size_t CField::getGlobalWrittenSize()
1053   TRY
1054   {
1055     return grid->getGlobalWrittenSize();
1056   }
1057   CATCH_DUMP_ATTR
1058
1059   //----------------------------------------------------------------
1060
1061   void CField::solveServerOperation(void)
1062   TRY
1063   {
1064      CContext* context = CContext::getCurrent();
1065
1066      if (!context->hasServer || !hasOutputFile) return;
1067
1068      if (freq_op.isEmpty())
1069        freq_op.setValue(TimeStep);
1070
1071      if (freq_offset.isEmpty())
1072        freq_offset.setValue(NoneDu);
1073
1074      freq_operation_srv = file->output_freq.getValue();
1075      freq_write_srv     = file->output_freq.getValue();
1076
1077      lastlast_Write_srv = context->getCalendar()->getInitDate();
1078      last_Write_srv     = context->getCalendar()->getInitDate();
1079      last_operation_srv = context->getCalendar()->getInitDate();
1080
1081      const CDuration toffset = freq_operation_srv - freq_offset.getValue() - context->getCalendar()->getTimeStep();
1082      last_operation_srv     = last_operation_srv - toffset;
1083
1084      if (operation.isEmpty())
1085        ERROR("void CField::solveServerOperation(void)",
1086              << "An operation must be defined for field \"" << getId() << "\".");
1087
1088      std::shared_ptr<func::CFunctor> functor;
1089      CArray<double, 1> dummyData;
1090
1091#define DECLARE_FUNCTOR(MType, mtype) \
1092      if (operation.getValue().compare(#mtype) == 0) \
1093      { \
1094        functor.reset(new func::C##MType(dummyData)); \
1095      }
1096
1097#include "functor_type.conf"
1098
1099      if (!functor)
1100        ERROR("void CField::solveServerOperation(void)",
1101              << "\"" << operation << "\" is not a valid operation.");
1102
1103      operationTimeType = functor->timeType();
1104   }
1105   CATCH_DUMP_ATTR
1106
1107   //----------------------------------------------------------------
1108
1109   /*!
1110    * Constructs the graph filter for the field, enabling or not the data output.
1111    * This method should not be called more than once with enableOutput equal to true.
1112    *
1113    * \param gc the garbage collector to use when building the filter graph
1114    * \param enableOutput must be true when the field data is to be
1115    *                     read by the client or/and written to a file
1116    */
1117   void CField::buildFilterGraph(CGarbageCollector& gc, bool enableOutput)
1118   TRY
1119   {     
1120    if (!isReferenceSolvedAndTransformed) solveAllEnabledFieldsAndTransform();
1121    if (!isGridChecked) checkGridOfEnabledFields();
1122
1123     const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1124     const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
1125
1126     CContext* context = CContext::getCurrent();
1127     bool hasWriterServer = context->hasServer && !context->hasClient;
1128     bool hasIntermediateServer = context->hasServer && context->hasClient;
1129
1130     if (hasWriterServer)
1131     {
1132        if (!instantDataFilter)
1133          instantDataFilter = clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, false));
1134
1135
1136       // If the field data is to be read by the client or/and written to a file
1137       if (enableOutput && !storeFilter && !fileWriterFilter)
1138       {
1139         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
1140         {
1141           fileServerWriterFilter = std::shared_ptr<CFileServerWriterFilter>(new CFileServerWriterFilter(gc, this));
1142           instantDataFilter->connectOutput(fileServerWriterFilter, 0);
1143         }
1144       }
1145     }
1146     else if (hasIntermediateServer)
1147     {
1148       if (!instantDataFilter)
1149         instantDataFilter = clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, false, false));
1150
1151             // If the field data is to be read by the client or/and written to a file
1152       if (enableOutput && !storeFilter && !fileWriterFilter)
1153       {
1154         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
1155         {
1156           fileWriterFilter = std::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
1157           instantDataFilter->connectOutput(fileWriterFilter, 0);
1158         }
1159       }
1160     }
1161     else
1162     {
1163       // Start by building a filter which can provide the field's instant data
1164       if (!instantDataFilter)
1165       {
1166         // Check if we have an expression to parse
1167         if (hasExpression())
1168         {
1169           boost::scoped_ptr<IFilterExprNode> expr(parseExpr(getExpression() + '\0'));
1170           std::shared_ptr<COutputPin> filter = expr->reduce(gc, *this);
1171
1172           // Check if a spatial transformation is needed
1173           if (!field_ref.isEmpty())
1174           {
1175             CGrid* gridRef = CField::get(field_ref)->grid;
1176
1177             if (grid && grid != gridRef && grid->hasTransform())
1178             {
1179                 std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters = CSpatialTransformFilter::buildFilterGraph(gc, gridRef, grid, detectMissingValues, defaultValue); 
1180
1181               filter->connectOutput(filters.first, 0);
1182               filter = filters.second;
1183             }
1184           }
1185
1186           instantDataFilter = filter;
1187         }
1188         // Check if we have a reference on another field
1189         else if (!field_ref.isEmpty())
1190           instantDataFilter = getFieldReference(gc);
1191         // Check if the data is to be read from a file
1192         else if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
1193         {
1194           checkTimeAttributes();
1195           instantDataFilter = serverSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, false, freq_offset, true,
1196                                                                                                       detectMissingValues, defaultValue));
1197         }
1198         else // The data might be passed from the model
1199         {
1200            if (check_if_active.isEmpty()) check_if_active = false; 
1201            instantDataFilter = clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, false, true, NoneDu, false,
1202                                                                                                        detectMissingValues, defaultValue));
1203         }
1204       }
1205
1206       // If the field data is to be read by the client or/and written to a file
1207       if (enableOutput && !storeFilter && !fileWriterFilter)
1208       {
1209         if (!read_access.isEmpty() && read_access)
1210         {
1211           storeFilter = std::shared_ptr<CStoreFilter>(new CStoreFilter(gc, CContext::getCurrent(), grid,
1212                                                                          detectMissingValues, defaultValue));
1213           instantDataFilter->connectOutput(storeFilter, 0);
1214         }
1215
1216         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
1217         {
1218           fileWriterFilter = std::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
1219           getTemporalDataFilter(gc, file->output_freq)->connectOutput(fileWriterFilter, 0);
1220         }
1221       }
1222     }
1223   }
1224   CATCH_DUMP_ATTR
1225
1226   /*!
1227    * Returns the filter needed to handle the field reference.
1228    * This method should only be called when building the filter graph corresponding to the field.
1229    *
1230    * \param gc the garbage collector to use
1231    * \return the output pin corresponding to the field reference
1232    */
1233   std::shared_ptr<COutputPin> CField::getFieldReference(CGarbageCollector& gc)
1234   TRY
1235   {
1236     if (instantDataFilter || field_ref.isEmpty())
1237       ERROR("COutputPin* CField::getFieldReference(CGarbageCollector& gc)",
1238             "Impossible to get the field reference for a field which has already been parsed or which does not have a field_ref.");
1239
1240     CField* fieldRef = CField::get(field_ref);
1241     fieldRef->buildFilterGraph(gc, false);
1242
1243     std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters;
1244     // Check if a spatial transformation is needed
1245     if (grid && grid != fieldRef->grid && grid->hasTransform())
1246     {       
1247       bool hasMissingValue = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1248       double defaultValue  = hasMissingValue ? default_value : (!default_value.isEmpty() ? default_value : 0.0);                               
1249       filters = CSpatialTransformFilter::buildFilterGraph(gc, fieldRef->grid, grid, hasMissingValue, defaultValue);
1250     }
1251     else
1252       filters.first = filters.second = std::shared_ptr<CFilter>(new CPassThroughFilter(gc));
1253
1254     fieldRef->getInstantDataFilter()->connectOutput(filters.first, 0);
1255
1256     return filters.second;
1257   }
1258   CATCH_DUMP_ATTR
1259
1260   /*!
1261    * Returns the filter needed to handle a self reference in the field's expression.
1262    * If the needed filter does not exist, it is created, otherwise it is reused.
1263    * This method should only be called when building the filter graph corresponding
1264    * to the field's expression.
1265    *
1266    * \param gc the garbage collector to use
1267    * \return the output pin corresponding to a self reference
1268    */
1269   std::shared_ptr<COutputPin> CField::getSelfReference(CGarbageCollector& gc)
1270   TRY
1271   {
1272     if (instantDataFilter || !hasExpression())
1273       ERROR("COutputPin* CField::getSelfReference(CGarbageCollector& gc)",
1274             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1275
1276     if (!selfReferenceFilter)
1277     {
1278       const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1279       const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
1280
1281       if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
1282       {
1283         if (!serverSourceFilter)
1284         {
1285           checkTimeAttributes();
1286           serverSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, false, freq_offset, true,
1287                                                                                   detectMissingValues, defaultValue));
1288         }
1289
1290         selfReferenceFilter = serverSourceFilter;
1291       }
1292       else if (!field_ref.isEmpty())
1293       {
1294         CField* fieldRef = CField::get(field_ref);
1295         fieldRef->buildFilterGraph(gc, false);
1296         selfReferenceFilter = fieldRef->getInstantDataFilter();
1297       }
1298       else
1299       {
1300         if (!clientSourceFilter)
1301         {
1302           if (check_if_active.isEmpty()) check_if_active = false;
1303           clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, true, NoneDu, false,
1304                                                                                   detectMissingValues, defaultValue));
1305         }
1306
1307         selfReferenceFilter = clientSourceFilter;
1308       }
1309     }
1310
1311     return selfReferenceFilter;
1312   }
1313   CATCH_DUMP_ATTR
1314
1315   /*!
1316    * Returns the temporal filter corresponding to the field's temporal operation
1317    * for the specified operation frequency. The filter is created if it does not
1318    * exist, otherwise it is reused.
1319    *
1320    * \param gc the garbage collector to use
1321    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1322    * \return the output pin corresponding to the requested temporal filter
1323    */
1324   std::shared_ptr<COutputPin> CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1325   TRY
1326   {
1327     std::map<CDuration, std::shared_ptr<COutputPin> >::iterator it = temporalDataFilters.find(outFreq);
1328
1329     if (it == temporalDataFilters.end())
1330     {
1331       if (operation.isEmpty())
1332         ERROR("void CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1333               << "An operation must be defined for field \"" << getId() << "\".");
1334
1335       checkTimeAttributes(&outFreq);
1336
1337       const bool detectMissingValues = (!detect_missing_value.isEmpty()  && detect_missing_value == true);
1338       std::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1339                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
1340                                                                             freq_op, freq_offset, outFreq, detectMissingValues));
1341
1342       instantDataFilter->connectOutput(temporalFilter, 0);
1343
1344       it = temporalDataFilters.insert(std::make_pair(outFreq, temporalFilter)).first;
1345     }
1346
1347     return it->second;
1348   }
1349   CATCH_DUMP_ATTR
1350
1351  /*!
1352    * Returns the temporal filter corresponding to the field's temporal operation
1353    * for the specified operation frequency.
1354    *
1355    * \param gc the garbage collector to use
1356    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1357    * \return the output pin corresponding to the requested temporal filter
1358    */
1359   
1360   std::shared_ptr<COutputPin> CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1361   TRY
1362   {
1363     if (instantDataFilter || !hasExpression())
1364       ERROR("COutputPin* CField::getSelfTemporalDataFilter(CGarbageCollector& gc)",
1365             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1366
1367     if (!selfReferenceFilter) getSelfReference(gc) ;
1368
1369     if (serverSourceFilter || clientSourceFilter)
1370     {
1371       if (operation.isEmpty())
1372         ERROR("void CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1373               << "An operation must be defined for field \"" << getId() << "\".");
1374
1375       checkTimeAttributes(&outFreq);
1376
1377       const bool detectMissingValues = (!detect_missing_value.isEmpty() && detect_missing_value == true);
1378       std::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1379                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
1380                                                                             freq_op, freq_offset, outFreq, detectMissingValues));
1381
1382       selfReferenceFilter->connectOutput(temporalFilter, 0);
1383       return temporalFilter ;
1384     }
1385     else if (!field_ref.isEmpty())
1386     {
1387       CField* fieldRef = CField::get(field_ref);
1388       fieldRef->buildFilterGraph(gc, false); 
1389       return fieldRef->getTemporalDataFilter(gc, outFreq) ;
1390     }
1391  }
1392   CATCH_DUMP_ATTR
1393
1394   //----------------------------------------------------------------
1395/*
1396   void CField::fromBinary(StdIStream& is)
1397   {
1398      SuperClass::fromBinary(is);
1399#define CLEAR_ATT(name_)\
1400      SuperClassAttribute::operator[](#name_)->reset()
1401
1402         CLEAR_ATT(domain_ref);
1403         CLEAR_ATT(axis_ref);
1404#undef CLEAR_ATT
1405
1406   }
1407*/
1408   //----------------------------------------------------------------
1409
1410   void CField::solveGridReference(void)
1411   TRY
1412   {
1413      if (grid_ref.isEmpty() && domain_ref.isEmpty() && axis_ref.isEmpty() && scalar_ref.isEmpty())
1414      {
1415        ERROR("CField::solveGridReference(void)",
1416              << "A grid must be defined for field '" << getFieldOutputName() << "' .");
1417      }
1418      else if (!grid_ref.isEmpty() && (!domain_ref.isEmpty() || !axis_ref.isEmpty() || !scalar_ref.isEmpty()))
1419      {
1420        ERROR("CField::solveGridReference(void)",
1421              << "Field '" << getFieldOutputName() << "' has both a grid and a domain/axis/scalar." << std::endl
1422              << "Please define either 'grid_ref' or 'domain_ref'/'axis_ref'/'scalar_ref'.");
1423      }
1424
1425      if (grid_ref.isEmpty())
1426      {
1427        std::vector<CDomain*> vecDom;
1428        std::vector<CAxis*> vecAxis;
1429        std::vector<CScalar*> vecScalar;
1430        std::vector<int> axisDomainOrderTmp;
1431
1432        std::vector<CDomain*> vecDomRef;
1433        std::vector<CAxis*> vecAxisRef;
1434        std::vector<CScalar*> vecScalarRef;
1435
1436       
1437        if (!domain_ref.isEmpty())
1438        {
1439          StdString tmp = domain_ref.getValue();
1440          if (CDomain::has(domain_ref))
1441          {
1442            vecDom.push_back(CDomain::get(domain_ref));
1443            vecDomRef.push_back(CDomain::createDomain());
1444            vecDomRef.back()->domain_ref=domain_ref;
1445            axisDomainOrderTmp.push_back(2);
1446          }
1447          else  ERROR("CField::solveGridReference(void)",
1448                      << "Invalid reference to domain '" << domain_ref.getValue() << "'.");
1449        }
1450
1451        if (!axis_ref.isEmpty())
1452        {
1453          if (CAxis::has(axis_ref))
1454          {
1455            vecAxis.push_back(CAxis::get(axis_ref));
1456            vecAxisRef.push_back(CAxis::createAxis());
1457            vecAxisRef.back()->axis_ref=axis_ref;
1458            axisDomainOrderTmp.push_back(1);
1459          }
1460          else  ERROR("CField::solveGridReference(void)",
1461                      << "Invalid reference to axis '" << axis_ref.getValue() << "'.");
1462        }
1463
1464        if (!scalar_ref.isEmpty())
1465        {
1466          if (CScalar::has(scalar_ref))
1467          {
1468            vecScalar.push_back(CScalar::get(scalar_ref));
1469            vecScalarRef.push_back(CScalar::createScalar());
1470            vecScalarRef.back()->scalar_ref=scalar_ref;
1471            axisDomainOrderTmp.push_back(0);
1472          }
1473          else ERROR("CField::solveGridReference(void)",
1474                     << "Invalid reference to scalar '" << scalar_ref.getValue() << "'.");
1475        }
1476       
1477        CArray<int,1> axisDomainOrder(axisDomainOrderTmp.size());
1478        for (int idx = 0; idx < axisDomainOrderTmp.size(); ++idx)
1479        {
1480          axisDomainOrder(idx) = axisDomainOrderTmp[idx];
1481        }
1482
1483        // Warning: the gridId shouldn't be set as the grid_ref since it could be inherited
1484        StdString gridId = CGrid::generateId(vecDom, vecAxis, vecScalar,axisDomainOrder);
1485        if (CGrid::has(gridId)) this->grid = CGrid::get(gridId);
1486        else  this->grid = CGrid::createGrid(gridId, vecDomRef, vecAxisRef, vecScalarRef,axisDomainOrder);
1487      }
1488      else
1489      {
1490        if (CGrid::has(grid_ref)) this->grid = CGrid::get(grid_ref);
1491        else  ERROR("CField::solveGridReference(void)",
1492                     << "Invalid reference to grid '" << grid_ref.getValue() << "'.");
1493      }
1494   }
1495   CATCH_DUMP_ATTR
1496
1497   void CField::solveGridDomainAxisRef(bool checkAtt)
1498   TRY
1499   {
1500     grid->solveDomainAxisRef(checkAtt);
1501   }
1502   CATCH_DUMP_ATTR
1503
1504   void CField::solveCheckMaskIndex(bool doSendingIndex)
1505   TRY
1506   {
1507     grid->checkMaskIndex(doSendingIndex);
1508   }
1509   CATCH_DUMP_ATTR
1510
1511   void CField::solveTransformedGrid()
1512   TRY
1513   {
1514     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
1515     {
1516       std::vector<CGrid*> grids;
1517       // Source grid
1518       grids.push_back(getDirectFieldReference()->grid);
1519       // Intermediate grids
1520       if (!grid_path.isEmpty())
1521       {
1522         std::string gridId;
1523         size_t start = 0, end;
1524
1525         do
1526         {
1527           end = grid_path.getValue().find(',', start);
1528           if (end != std::string::npos)
1529           {
1530             gridId = grid_path.getValue().substr(start, end - start);
1531             start = end + 1;
1532           }
1533           else
1534             gridId = grid_path.getValue().substr(start);
1535
1536           if (!CGrid::has(gridId))
1537             ERROR("void CField::solveTransformedGrid()",
1538                   << "Invalid grid_path, the grid '" << gridId << "' does not exist.");
1539
1540           grids.push_back(CGrid::get(gridId));
1541         }
1542         while (end != std::string::npos);
1543       }
1544       // Destination grid
1545       grids.push_back(grid);
1546
1547       for (size_t i = 0, count = grids.size() - 1; i < count; ++i)
1548       {
1549         CGrid *gridSrc  = grids[i];
1550         CGrid *gridDest = grids[i + 1];
1551         if (!gridDest->isTransformed())
1552           gridDest->transformGrid(gridSrc);
1553       }
1554     }
1555     else if (grid && grid->hasTransform() && !grid->isTransformed())
1556     {
1557       // Temporarily deactivate the self-transformation of grid
1558       // grid->transformGrid(grid);
1559     }
1560   }
1561   CATCH_DUMP_ATTR
1562
1563   void CField::solveGenerateGrid()
1564   TRY
1565   {
1566     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
1567       grid->completeGrid(getDirectFieldReference()->grid);
1568     else
1569       grid->completeGrid();
1570   }
1571   CATCH_DUMP_ATTR
1572
1573   void CField::solveGridDomainAxisBaseRef()
1574   TRY
1575   {
1576     grid->solveDomainAxisRef(false);
1577     grid->solveDomainAxisBaseRef();
1578   }
1579   CATCH_DUMP_ATTR
1580
1581   ///-------------------------------------------------------------------
1582
1583   template <>
1584   void CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)
1585   TRY
1586   {
1587      if (this->group_ref.isEmpty()) return;
1588      StdString gref = this->group_ref.getValue();
1589
1590      if (!CFieldGroup::has(gref))
1591         ERROR("CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)",
1592               << "[ gref = " << gref << "]"
1593               << " invalid group name !");
1594
1595      CFieldGroup* group = CFieldGroup::get(gref);
1596      CFieldGroup* owner = CFieldGroup::get(boost::polymorphic_downcast<CFieldGroup*>(this));
1597      owner->setAttributes(group); // inherite of attributes of group reference
1598     
1599      std::vector<CField*> allChildren  = group->getAllChildren();
1600      std::vector<CField*>::iterator it = allChildren.begin(), end = allChildren.end();
1601
1602      for (; it != end; it++)
1603      {
1604         CField* child = *it;
1605         if (child->hasId()) owner->createChild()->field_ref.setValue(child->getId());
1606
1607      }
1608   }
1609   CATCH_DUMP_ATTR
1610
1611   void CField::scaleFactorAddOffset(double scaleFactor, double addOffset)
1612   TRY
1613   {
1614     recvDataSrv = (recvDataSrv - addOffset) / scaleFactor;
1615   }
1616   CATCH_DUMP_ATTR
1617
1618   void CField::invertScaleFactorAddOffset(double scaleFactor, double addOffset)
1619   TRY
1620   {
1621     recvDataSrv = recvDataSrv * scaleFactor + addOffset;
1622   }
1623   CATCH_DUMP_ATTR
1624
1625   void CField::outputField(CArray<double,1>& fieldOut)
1626   TRY
1627   { 
1628      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1629      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1630      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1631      {
1632        fieldOut(outIndexServer(idx)) = recvDataSrv(outIndexClient(idx));
1633      }
1634   }
1635   CATCH_DUMP_ATTR
1636
1637   void CField::inputField(CArray<double,1>& fieldIn)
1638   TRY
1639   {
1640      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1641      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1642      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1643      {
1644        recvDataSrv(outIndexClient(idx)) = fieldIn(outIndexServer(idx));
1645      }
1646   }
1647   CATCH_DUMP_ATTR
1648
1649   void CField::outputCompressedField(CArray<double,1>& fieldOut)
1650   TRY
1651   {
1652      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1653      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1654      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1655      {
1656        fieldOut((idx)) = recvDataSrv(outIndexClient(idx));
1657      }
1658   }
1659   CATCH_DUMP_ATTR
1660
1661   ///-------------------------------------------------------------------
1662
1663   void CField::parse(xml::CXMLNode& node)
1664   TRY
1665   {
1666      string newContent ;
1667      SuperClass::parse(node);
1668      if (node.goToChildElement())
1669      {
1670        do
1671        {
1672          if (node.getElementName() == "variable" || node.getElementName() == "variable_group") this->getVirtualVariableGroup()->parseChild(node);
1673          else if (node.getElementName() == "expr") if (node.getContent(newContent)) content+=newContent ;
1674        } while (node.goToNextElement());
1675        node.goToParentElement();
1676      }
1677      if (node.getContent(newContent)) content=newContent ;
1678    }
1679   CATCH_DUMP_ATTR
1680
1681   /*!
1682     This function retrieves Id of corresponding domain_ref and axis_ref (if any)
1683   of a field. In some cases, only domain exists but axis doesn't
1684   \return pair of Domain and Axis id
1685   */
1686   const std::vector<StdString>& CField::getRefDomainAxisIds()
1687   TRY
1688   {
1689     CGrid* cgPtr = getRelGrid();
1690     if (NULL != cgPtr)
1691     {
1692       std::vector<StdString>::iterator it;
1693       if (!domain_ref.isEmpty())
1694       {
1695         std::vector<StdString> domainList = cgPtr->getDomainList();
1696         it = std::find(domainList.begin(), domainList.end(), domain_ref.getValue());
1697         if (domainList.end() != it) domAxisScalarIds_[0] = *it;
1698       }
1699
1700       if (!axis_ref.isEmpty())
1701       {
1702         std::vector<StdString> axisList = cgPtr->getAxisList();
1703         it = std::find(axisList.begin(), axisList.end(), axis_ref.getValue());
1704         if (axisList.end() != it) domAxisScalarIds_[1] = *it;
1705       }
1706
1707       if (!scalar_ref.isEmpty())
1708       {
1709         std::vector<StdString> scalarList = cgPtr->getScalarList();
1710         it = std::find(scalarList.begin(), scalarList.end(), scalar_ref.getValue());
1711         if (scalarList.end() != it) domAxisScalarIds_[2] = *it;
1712       }
1713     }
1714     return (domAxisScalarIds_);
1715   }
1716   CATCH_DUMP_ATTR
1717
1718   CVariable* CField::addVariable(const string& id)
1719   TRY
1720   {
1721     return vVariableGroup->createChild(id);
1722   }
1723   CATCH
1724
1725   CVariableGroup* CField::addVariableGroup(const string& id)
1726   TRY
1727   {
1728     return vVariableGroup->createChildGroup(id);
1729   }
1730   CATCH
1731
1732   void CField::setContextClient(CContextClient* contextClient)
1733   TRY
1734   {
1735     CContext* context = CContext::getCurrent();
1736     client = contextClient;
1737     if (context->hasClient)
1738     {
1739       // A grid is sent by a client (both for read or write) or by primary server (write only)
1740       if (context->hasServer)
1741       {
1742         if (file->mode.isEmpty() || (!file->mode.isEmpty() && file->mode == CFile::mode_attr::write))
1743           grid->setContextClient(contextClient);
1744       }
1745       else
1746           grid->setContextClient(contextClient);
1747     }
1748   }
1749   CATCH_DUMP_ATTR
1750
1751   CContextClient* CField::getContextClient()
1752   TRY
1753   {
1754     return client;
1755   }
1756   CATCH
1757
1758   void CField::sendAddAllVariables(CContextClient* client)
1759   TRY
1760   {
1761     std::vector<CVariable*> allVar = getAllVariables();
1762     std::vector<CVariable*>::const_iterator it = allVar.begin();
1763     std::vector<CVariable*>::const_iterator itE = allVar.end();
1764
1765     for (; it != itE; ++it)
1766     {
1767       this->sendAddVariable((*it)->getId(), client);
1768       (*it)->sendAllAttributesToServer(client);
1769       (*it)->sendValue(client);
1770     }
1771   }
1772   CATCH_DUMP_ATTR
1773
1774   /*!
1775    * Send all Attributes to server. This method is overloaded, since only grid_ref attribute
1776    * must be sent to server and not domain_ref/axis_ref/scalar_ref.
1777    */
1778   
1779   void CField::sendAllAttributesToServer(CContextClient* client)
1780   TRY
1781   {
1782     if (grid_ref.isEmpty())
1783     {
1784       grid_ref=grid->getId() ;
1785       SuperClass::sendAllAttributesToServer(client) ;
1786       grid_ref.reset();
1787     }
1788     else SuperClass::sendAllAttributesToServer(client) ;
1789   }
1790   CATCH_DUMP_ATTR
1791   
1792   void CField::sendAddVariable(const string& id, CContextClient* client)
1793   TRY
1794   {
1795      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE, client);
1796   }
1797   CATCH_DUMP_ATTR
1798
1799   void CField::sendAddVariableGroup(const string& id, CContextClient* client)
1800   TRY
1801   {
1802      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE_GROUP, client);
1803   }
1804   CATCH_DUMP_ATTR
1805
1806   void CField::recvAddVariable(CEventServer& event)
1807   TRY
1808   {
1809
1810      CBufferIn* buffer = event.subEvents.begin()->buffer;
1811      string id;
1812      *buffer >> id;
1813      get(id)->recvAddVariable(*buffer);
1814   }
1815   CATCH
1816
1817   void CField::recvAddVariable(CBufferIn& buffer)
1818   TRY
1819   {
1820      string id;
1821      buffer >> id;
1822      addVariable(id);
1823   }
1824   CATCH_DUMP_ATTR
1825
1826   void CField::recvAddVariableGroup(CEventServer& event)
1827   TRY
1828   {
1829
1830      CBufferIn* buffer = event.subEvents.begin()->buffer;
1831      string id;
1832      *buffer >> id;
1833      get(id)->recvAddVariableGroup(*buffer);
1834   }
1835   CATCH
1836
1837   void CField::recvAddVariableGroup(CBufferIn& buffer)
1838   TRY
1839   {
1840      string id;
1841      buffer >> id;
1842      addVariableGroup(id);
1843   }
1844   CATCH_DUMP_ATTR
1845
1846   /*!
1847    * Check on freq_off and freq_op attributes.
1848    */
1849   void CField::checkTimeAttributes(CDuration* freqOp)
1850   TRY
1851   {
1852     bool isFieldRead  = file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read;
1853     bool isFieldWrite = file && ( file->mode.isEmpty() ||  file->mode == CFile::mode_attr::write);
1854     if (isFieldRead && !(operation.getValue() == "instant" || operation.getValue() == "once") )     
1855       ERROR("void CField::checkTimeAttributes(void)",
1856             << "Unsupported operation for field '" << getFieldOutputName() << "'." << std::endl
1857             << "Currently only \"instant\" is supported for fields read from file.")
1858
1859     if (freq_op.isEmpty())
1860     {
1861       if (operation.getValue() == "instant")
1862       {
1863         if (isFieldRead || isFieldWrite) freq_op.setValue(file->output_freq.getValue());
1864         else freq_op=*freqOp ;
1865       }
1866       else
1867         freq_op.setValue(TimeStep);
1868     }
1869     if (freq_offset.isEmpty())
1870       freq_offset.setValue(isFieldRead ? NoneDu : (freq_op.getValue() - TimeStep));
1871   }
1872   CATCH_DUMP_ATTR
1873
1874   /*!
1875    * Returns string arithmetic expression associated to the field.
1876    * \return if content is defined return content string, otherwise, if "expr" attribute is defined, return expr string.
1877    */
1878   const string& CField::getExpression(void)
1879   TRY
1880   {
1881     if (!expr.isEmpty() && content.empty())
1882     {
1883       content = expr;
1884       expr.reset();
1885     }
1886
1887     return content;
1888   }
1889   CATCH_DUMP_ATTR
1890
1891   bool CField::hasExpression(void) const
1892   TRY
1893   {
1894     return (!expr.isEmpty() || !content.empty());
1895   }
1896   CATCH
1897
1898   bool CField::hasGridMask(void) const
1899   TRY
1900   {
1901     return (this->grid->hasMask());
1902   }
1903   CATCH
1904
1905   DEFINE_REF_FUNC(Field,field)
1906} // namespace xios
Note: See TracBrowser for help on using the repository browser.