source: XIOS/dev/dev_ym/XIOS_ONE_SIDED/src/node/field.cpp @ 1751

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

suspend tracing when probing to avoid too big trace

YM

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