source: XIOS/dev/branch_openmp/src/node/field.cpp @ 1642

Last change on this file since 1642 was 1642, checked in by yushan, 5 years ago

dev on ADA. add flag switch _usingEP/_usingMPI

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