source: XIOS/dev/dev_olga/src/node/field.cpp @ 1612

Last change on this file since 1612 was 1612, checked in by oabramkina, 5 years ago

Dev: adding exception handling.

To activate it, compilation flag -DXIOS_EXCEPTION should be added.

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