source: XIOS/trunk/src/node/field.cpp @ 1318

Last change on this file since 1318 was 1318, checked in by rlacroix, 7 years ago

Fix: Handle end-of-file correctly for files in read mode.

Previously desynchronizations between clients could occur, leading to invalid events being received by the server(s).

  • 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: 49.1 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
26namespace xios{
27
28   /// ////////////////////// Définitions ////////////////////// ///
29
30   CField::CField(void)
31      : CObjectTemplate<CField>(), CFieldAttributes()
32      , grid(), file()
33      , written(false)
34      , nstep(0), nstepMax(0)
35      , hasOutputFile(false)
36      , domAxisScalarIds_(vector<StdString>(3,"")), areAllReferenceSolved(false), isReferenceSolved(false)
37      , useCompressedOutput(false)
38      , hasTimeInstant(false)
39      , hasTimeCentered(false)
40      , wasDataRequestedFromServer(false)
41      , wasDataAlreadyReceivedFromServer(false)
42      , isEOF(false)
43   { setVirtualVariableGroup(CVariableGroup::create(getId() + "_virtual_variable_group")); }
44
45   CField::CField(const StdString& id)
46      : CObjectTemplate<CField>(id), CFieldAttributes()
47      , grid(), file()
48      , written(false)
49      , nstep(0), nstepMax(0)
50      , hasOutputFile(false)
51      , domAxisScalarIds_(vector<StdString>(3,"")), areAllReferenceSolved(false), isReferenceSolved(false)
52      , useCompressedOutput(false)
53      , hasTimeInstant(false)
54      , hasTimeCentered(false)
55      , wasDataRequestedFromServer(false)
56      , wasDataAlreadyReceivedFromServer(false)
57      , isEOF(false)
58   { setVirtualVariableGroup(CVariableGroup::create(getId() + "_virtual_variable_group")); }
59
60   CField::~CField(void)
61   {}
62
63  //----------------------------------------------------------------
64
65   void CField::setVirtualVariableGroup(CVariableGroup* newVVariableGroup)
66   {
67      this->vVariableGroup = newVVariableGroup;
68   }
69
70   CVariableGroup* CField::getVirtualVariableGroup(void) const
71   {
72      return this->vVariableGroup;
73   }
74
75   std::vector<CVariable*> CField::getAllVariables(void) const
76   {
77      return this->vVariableGroup->getAllChildren();
78   }
79
80   void CField::solveDescInheritance(bool apply, const CAttributeMap* const parent)
81   {
82      SuperClassAttribute::setAttributes(parent, apply);
83      this->getVirtualVariableGroup()->solveDescInheritance(apply, NULL);
84   }
85
86  //----------------------------------------------------------------
87
88  bool CField::dispatchEvent(CEventServer& event)
89  {
90    if (SuperClass::dispatchEvent(event)) return true;
91    else
92    {
93      switch(event.type)
94      {
95        case EVENT_ID_UPDATE_DATA :
96          recvUpdateData(event);
97          return true;
98          break;
99
100        case EVENT_ID_READ_DATA :
101          recvReadDataRequest(event);
102          return true;
103          break;
104
105        case EVENT_ID_READ_DATA_READY :
106          recvReadDataReady(event);
107          return true;
108          break;
109
110        case EVENT_ID_ADD_VARIABLE :
111          recvAddVariable(event);
112          return true;
113          break;
114
115        case EVENT_ID_ADD_VARIABLE_GROUP :
116          recvAddVariableGroup(event);
117          return true;
118          break;
119
120        default :
121          ERROR("bool CField::dispatchEvent(CEventServer& event)", << "Unknown Event");
122          return false;
123      }
124    }
125  }
126
127  void CField::sendUpdateData(const CArray<double,1>& data)
128  {
129    CTimer::get("Field : send data").resume();
130
131    CContext* context = CContext::getCurrent();
132    CContextClient* client = context->client;
133
134    CEventClient event(getType(), EVENT_ID_UPDATE_DATA);
135
136    map<int, CArray<int,1> >::iterator it;
137    list<CMessage> list_msg;
138    list<CArray<double,1> > list_data;
139
140    if (!grid->doGridHaveDataDistributed())
141    {
142       if (client->isServerLeader())
143       {
144          for (it = grid->storeIndex_toSrv.begin(); it != grid->storeIndex_toSrv.end(); it++)
145          {
146            int rank = it->first;
147            CArray<int,1>& index = it->second;
148
149            list_msg.push_back(CMessage());
150            list_data.push_back(CArray<double,1>(index.numElements()));
151
152            CArray<double,1>& data_tmp = list_data.back();
153            for (int n = 0; n < data_tmp.numElements(); n++) data_tmp(n) = data(index(n));
154
155            list_msg.back() << getId() << data_tmp;
156            event.push(rank, 1, list_msg.back());
157          }
158          client->sendEvent(event);
159       } 
160       else client->sendEvent(event);
161    }
162    else
163    {
164      for (it = grid->storeIndex_toSrv.begin(); it != grid->storeIndex_toSrv.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, grid->nbSenders[rank], list_msg.back());
177      }
178      client->sendEvent(event);
179    }
180
181    CTimer::get("Field : send data").suspend();
182  }
183
184  void CField::recvUpdateData(CEventServer& event)
185  {
186    vector<int> ranks;
187    vector<CBufferIn*> buffers;
188
189    list<CEventServer::SSubEvent>::iterator it;
190    string fieldId;
191    CTimer::get("Field : recv data").resume();
192    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
193    {
194      int rank = it->rank;
195      CBufferIn* buffer = it->buffer;
196      *buffer >> fieldId;
197      ranks.push_back(rank);
198      buffers.push_back(buffer);
199    }
200    get(fieldId)->recvUpdateData(ranks,buffers);
201    CTimer::get("Field : recv data").suspend();
202  }
203
204  void  CField::recvUpdateData(vector<int>& ranks, vector<CBufferIn*>& buffers)
205  {
206    if (data_srv.empty())
207    {
208      for (map<int, CArray<size_t, 1> >::iterator it = grid->outIndexFromClient.begin(); it != grid->outIndexFromClient.end(); ++it)
209      {
210        int rank = it->first;
211        data_srv.insert(std::make_pair(rank, CArray<double,1>(it->second.numElements())));
212        foperation_srv.insert(pair<int,boost::shared_ptr<func::CFunctor> >(rank,boost::shared_ptr<func::CFunctor>(new func::CInstant(data_srv[rank]))));
213      }
214    }
215
216    CContext* context = CContext::getCurrent();
217    const CDate& currDate = context->getCalendar()->getCurrentDate();
218    const CDate opeDate      = last_operation_srv +freq_op + freq_operation_srv - freq_op;
219    const CDate writeDate    = last_Write_srv     + freq_write_srv;
220
221    if (opeDate <= currDate)
222    {
223      for (int n = 0; n < ranks.size(); n++)
224      {
225        CArray<double,1> data_tmp;
226        *buffers[n] >> data_tmp;
227        (*foperation_srv[ranks[n]])(data_tmp);
228      }
229      last_operation_srv = currDate;
230    }
231
232    if (writeDate < (currDate + freq_operation_srv))
233    {
234      for (int n = 0; n < ranks.size(); n++)
235      {
236        this->foperation_srv[ranks[n]]->final();
237      }
238
239      last_Write_srv = writeDate;
240      writeField();
241      lastlast_Write_srv = last_Write_srv;
242    }
243  }
244
245  void CField::writeField(void)
246  {
247    if (!getRelFile()->allDomainEmpty)
248    {
249      if (grid->doGridHaveDataToWrite() || getRelFile()->type == CFile::type_attr::one_file)
250      {
251        getRelFile()->checkFile();
252        this->incrementNStep();
253        getRelFile()->getDataOutput()->writeFieldData(CField::get(this));
254      }
255    }
256  }
257
258  bool CField::sendReadDataRequest(const CDate& tsDataRequested)
259  {
260    CContext* context = CContext::getCurrent();
261    CContextClient* client = context->client;
262
263    lastDataRequestedFromServer = tsDataRequested;
264
265    // No need to send the request if we are sure that we are already at EOF
266    if (!isEOF || context->getCalendar()->getCurrentDate() <= dateEOF)
267    {
268      CEventClient event(getType(), EVENT_ID_READ_DATA);
269      if (client->isServerLeader())
270      {
271        CMessage msg;
272        msg << getId();
273        const std::list<int>& ranks = client->getRanksServerLeader();
274        for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
275          event.push(*itRank, 1, msg);
276        client->sendEvent(event);
277      }
278      else client->sendEvent(event);
279    }
280    else
281      serverSourceFilter->signalEndOfStream(tsDataRequested);
282
283    wasDataRequestedFromServer = true;
284
285    return !isEOF;
286  }
287
288  /*!
289  Send request new data read from file if need be, that is the current data is out-of-date.
290  \return true if and only if some data was requested
291  */
292  bool CField::sendReadDataRequestIfNeeded(void)
293  {
294    const CDate& currentDate = CContext::getCurrent()->getCalendar()->getCurrentDate();
295
296    bool dataRequested = false;
297
298    while (currentDate >= lastDataRequestedFromServer)
299    {
300      info(20) << "currentDate : " << currentDate << endl ;
301      info(20) << "lastDataRequestedFromServer : " << lastDataRequestedFromServer << endl ;
302      info(20) << "file->output_freq.getValue() : " << file->output_freq.getValue() << endl ;
303      info(20) << "lastDataRequestedFromServer + file->output_freq.getValue() : " << lastDataRequestedFromServer + file->output_freq << endl ;
304
305      dataRequested |= sendReadDataRequest(lastDataRequestedFromServer + file->output_freq);
306    }
307
308    return dataRequested;
309  }
310
311  void CField::recvReadDataRequest(CEventServer& event)
312  {
313    CBufferIn* buffer = event.subEvents.begin()->buffer;
314    StdString fieldId;
315    *buffer >> fieldId;
316    get(fieldId)->recvReadDataRequest();
317  }
318
319  void CField::recvReadDataRequest(void)
320  {
321    CContext* context = CContext::getCurrent();
322    CContextClient* client = context->client;
323
324    CEventClient event(getType(), EVENT_ID_READ_DATA_READY);
325    std::list<CMessage> msgs;
326
327    bool hasData = readField();
328
329    map<int, CArray<double,1> >::iterator it;
330    if (!grid->doGridHaveDataDistributed())
331    {
332       if (client->isServerLeader())
333       {
334          if (!data_srv.empty())
335          {
336            it = data_srv.begin();
337            const std::list<int>& ranks = client->getRanksServerLeader();
338            for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
339            {
340              msgs.push_back(CMessage());
341              CMessage& msg = msgs.back();
342              msg << getId();
343              if (hasData)
344                msg << getNStep() - 1 << it->second;
345              else
346                msg << int(-1);
347              event.push(*itRank, 1, msg);
348            }
349          }
350          client->sendEvent(event);
351       } 
352       else 
353       {
354          // if (!data_srv.empty())
355          // {
356          //   it = data_srv.begin();
357          //   const std::list<int>& ranks = client->getRanksServerNotLeader();
358          //   for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
359          //   {
360          //     msgs.push_back(CMessage());
361          //     CMessage& msg = msgs.back();
362          //     msg << getId();
363          //     if (hasData)
364          //       msg << getNStep() - 1 << it->second;
365          //     else
366          //       msg << int(-1);
367          //     event.push(*itRank, 1, msg);
368          //   }
369          // }
370          client->sendEvent(event);
371       }
372    }
373    else
374    {
375      for (it = data_srv.begin(); it != data_srv.end(); it++)
376      {
377        msgs.push_back(CMessage());
378        CMessage& msg = msgs.back();
379        msg << getId();
380        if (hasData)
381          msg << getNStep() - 1 << it->second;
382        else
383          msg << int(-1);
384        event.push(it->first, grid->nbSenders[it->first], msg);
385      }
386      client->sendEvent(event);
387    }
388  }
389
390  bool CField::readField(void)
391  {
392    if (!getRelFile()->allDomainEmpty)
393    {
394      if (grid->doGridHaveDataToWrite() || getRelFile()->type == CFile::type_attr::one_file)
395      {
396        if (data_srv.empty())
397        {
398          for (map<int, CArray<size_t, 1> >::iterator it = grid->outIndexFromClient.begin(); it != grid->outIndexFromClient.end(); ++it)
399            data_srv.insert(std::make_pair(it->first, CArray<double,1>(it->second.numElements())));
400        }
401
402        getRelFile()->checkFile();
403        if (!nstepMax)
404        {
405          nstepMax = getRelFile()->getDataInput()->getFieldNbRecords(CField::get(this));
406        }
407
408        this->incrementNStep();
409
410        if (getNStep() > nstepMax && (getRelFile()->cyclic.isEmpty() || !getRelFile()->cyclic) )
411          return false;
412
413        getRelFile()->getDataInput()->readFieldData(CField::get(this));
414      }
415    }
416
417    return true;
418  }
419
420  void CField::recvReadDataReady(CEventServer& event)
421  {
422    string fieldId;
423    vector<int> ranks;
424    vector<CBufferIn*> buffers;
425
426    list<CEventServer::SSubEvent>::iterator it;
427    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
428    {
429      ranks.push_back(it->rank);
430      CBufferIn* buffer = it->buffer;
431      *buffer >> fieldId;
432      buffers.push_back(buffer);
433    }
434    get(fieldId)->recvReadDataReady(ranks, buffers);
435  }
436
437  void CField::recvReadDataReady(vector<int> ranks, vector<CBufferIn*> buffers)
438  {
439    CContext* context = CContext::getCurrent();
440    std::map<int, CArray<double,1> > data;
441    const bool wasEOF = isEOF;
442
443    for (int i = 0; i < ranks.size(); i++)
444    {
445      int rank = ranks[i];
446      int record;
447      *buffers[i] >> record;
448      isEOF = (record == int(-1));
449
450      if (!isEOF)
451        *buffers[i] >> data[rank];
452      else
453        break;
454    }
455
456    if (wasDataAlreadyReceivedFromServer)
457      lastDataReceivedFromServer = lastDataReceivedFromServer + file->output_freq;
458    else
459    {
460      lastDataReceivedFromServer = context->getCalendar()->getInitDate();
461      wasDataAlreadyReceivedFromServer = true;
462    }
463
464    if (isEOF)
465    {
466      if (!wasEOF)
467        dateEOF = lastDataReceivedFromServer;
468
469      serverSourceFilter->signalEndOfStream(lastDataReceivedFromServer);
470    }
471    else
472      serverSourceFilter->streamDataFromServer(lastDataReceivedFromServer, data);
473  }
474
475  void CField::checkForLateDataFromServer(void)
476  {
477    CContext* context = CContext::getCurrent();
478    const CDate& currentDate = context->getCalendar()->getCurrentDate();
479
480    // Check if data previously requested has been received as expected
481    if (wasDataRequestedFromServer && (!isEOF || context->getCalendar()->getCurrentDate() <= dateEOF))
482    {
483      CTimer timer("CField::checkForLateDataFromServer");
484
485      bool isDataLate = !wasDataAlreadyReceivedFromServer || lastDataReceivedFromServer + file->output_freq < currentDate;
486      while (isDataLate && timer.getCumulatedTime() < CXios::recvFieldTimeout)
487      {
488        timer.resume();
489
490        context->checkBuffersAndListen();
491
492        timer.suspend();
493
494        isDataLate = !wasDataAlreadyReceivedFromServer || lastDataReceivedFromServer + file->output_freq < currentDate;
495      }
496
497      if (isDataLate)
498        ERROR("void CField::checkForLateDataFromServer(void)",
499              << "Late data at timestep = " << currentDate);
500    }
501  }
502
503   //----------------------------------------------------------------
504
505   void CField::setRelFile(CFile* _file)
506   {
507      this->file = _file;
508      hasOutputFile = true;
509   }
510
511   //----------------------------------------------------------------
512
513   StdString CField::GetName(void)    { return StdString("field"); }
514   StdString CField::GetDefName(void) { return CField::GetName(); }
515   ENodeType CField::GetType(void)    { return eField; }
516
517   //----------------------------------------------------------------
518
519   CGrid* CField::getRelGrid(void) const
520   {
521      return this->grid;
522   }
523
524   //----------------------------------------------------------------
525
526   CFile* CField::getRelFile(void) const
527   {
528      return this->file;
529   }
530
531   int CField::getNStep(void) const
532   {
533      return this->nstep;
534   }
535
536   func::CFunctor::ETimeType CField::getOperationTimeType() const
537   {
538     return operationTimeType;
539   }
540
541   //----------------------------------------------------------------
542
543   void CField::incrementNStep(void)
544   {
545      this->nstep++;
546   }
547
548   void CField::resetNStep(int nstep /*= 0*/)
549   {
550      this->nstep = nstep;
551   }
552
553   void CField::resetNStepMax(void)
554   {
555      this->nstepMax = 0;
556   }
557
558   //----------------------------------------------------------------
559
560   bool CField::isActive(bool atCurrentTimestep /*= false*/) const
561   {
562      if (clientSourceFilter)
563        return atCurrentTimestep ? clientSourceFilter->isDataExpected(CContext::getCurrent()->getCalendar()->getCurrentDate()) : true;
564      else if (storeFilter)
565        return true;
566      else if (instantDataFilter)
567        ERROR("bool CField::isActive(bool atCurrentTimestep)",
568              << "Impossible to check if field [ id = " << getId() << " ] is active as it cannot be used to receive nor send data.");
569
570      return false;
571   }
572
573   //----------------------------------------------------------------
574
575   bool CField::wasWritten() const
576   {
577     return written;
578   }
579
580   void CField::setWritten()
581   {
582     written = true;
583   }
584
585   //----------------------------------------------------------------
586
587   bool CField::getUseCompressedOutput() const
588   {
589     return useCompressedOutput;
590   }
591
592   void CField::setUseCompressedOutput()
593   {
594     useCompressedOutput = true;
595   }
596
597   //----------------------------------------------------------------
598
599   boost::shared_ptr<COutputPin> CField::getInstantDataFilter()
600   {
601     return instantDataFilter;
602   }
603
604   //----------------------------------------------------------------
605
606   void CField::solveOnlyReferenceEnabledField(bool doSending2Server)
607   {
608     CContext* context = CContext::getCurrent();
609     if (!isReferenceSolved)
610     {
611        isReferenceSolved = true;
612
613        if (context->hasClient)
614        {
615          solveRefInheritance(true);
616          if (hasDirectFieldReference()) getDirectFieldReference()->solveOnlyReferenceEnabledField(false);
617        }
618        else if (context->hasServer)
619          solveServerOperation();
620
621        solveGridReference();
622
623       if (context->hasClient)
624       {
625         solveGenerateGrid();
626         buildGridTransformationGraph();
627       }
628     }
629   }
630
631   /*!
632     Build up graph of grids which plays role of destination and source in grid transformation
633     This function should be called before \func solveGridReference()
634   */
635   void CField::buildGridTransformationGraph()
636   {
637     CContext* context = CContext::getCurrent();
638     if (context->hasClient)
639     {
640       if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
641       {
642         grid->addTransGridSource(getDirectFieldReference()->grid);
643       }
644     }
645   }
646
647   /*!
648     Generate a new grid destination if there are more than one grid source pointing to a same grid destination
649   */
650   void CField::generateNewTransformationGridDest()
651   {
652     CContext* context = CContext::getCurrent();
653     if (context->hasClient)
654     {
655       std::map<CGrid*,std::pair<bool,StdString> >& gridSrcMap = grid->getTransGridSource();
656       if (1 < gridSrcMap.size())
657       {
658         // Search for grid source
659         CGrid* gridSrc = grid;
660         CField* currField = this;
661         std::vector<CField*> hieraField;
662
663         while (currField->hasDirectFieldReference() && (gridSrc == grid))
664         {
665           hieraField.push_back(currField);
666           CField* tmp = currField->getDirectFieldReference();
667           currField = tmp;
668           gridSrc = currField->grid;
669         }
670
671         if (gridSrcMap.end() != gridSrcMap.find(gridSrc))
672         {
673           CGrid* gridTmp;
674           std::pair<bool,StdString> newGridDest = gridSrcMap[gridSrc];
675           if (newGridDest.first)
676           {
677             StdString newIdGridDest = newGridDest.second;
678             if (!CGrid::has(newIdGridDest))
679             {
680                ERROR("CGrid* CGrid::generateNewTransformationGridDest()",
681                  << " Something wrong happened! Grid whose id " << newIdGridDest
682                  << "should exist ");
683             }
684             gridTmp = CGrid::get(newIdGridDest);
685           }
686           else
687           {
688             StdString newIdGridDest = CGrid::generateId(gridSrc, grid);
689             gridTmp = CGrid::cloneGrid(newIdGridDest, grid);
690
691             (gridSrcMap[gridSrc]).first = true;
692             (gridSrcMap[gridSrc]).second = newIdGridDest;
693           }
694
695           // Update all descendants
696           for (std::vector<CField*>::iterator it = hieraField.begin(); it != hieraField.end(); ++it)
697           {
698             (*it)->grid = gridTmp;
699             (*it)->updateRef((*it)->grid);
700           }
701         }
702       }
703     }
704   }
705
706   void CField::updateRef(CGrid* grid)
707   {
708     if (!grid_ref.isEmpty()) grid_ref.setValue(grid->getId());
709     else
710     {
711       std::vector<CAxis*> axisTmp = grid->getAxis();
712       std::vector<CDomain*> domainTmp = grid->getDomains();
713       if ((1<axisTmp.size()) || (1<domainTmp.size()))
714         ERROR("void CField::updateRef(CGrid* grid)",
715           << "More than one domain or axis is available for domain_ref/axis_ref of field " << this->getId());
716
717       if ((!domain_ref.isEmpty()) && (domainTmp.empty()))
718         ERROR("void CField::updateRef(CGrid* grid)",
719           << "Incoherent between available domain and domain_ref of field " << this->getId());
720       if ((!axis_ref.isEmpty()) && (axisTmp.empty()))
721         ERROR("void CField::updateRef(CGrid* grid)",
722           << "Incoherent between available axis and axis_ref of field " << this->getId());
723
724       if (!domain_ref.isEmpty()) domain_ref.setValue(domainTmp[0]->getId());
725       if (!axis_ref.isEmpty()) axis_ref.setValue(axisTmp[0]->getId());
726     }
727   }
728
729   void CField::solveAllReferenceEnabledField(bool doSending2Server)
730   {
731     CContext* context = CContext::getCurrent();
732     solveOnlyReferenceEnabledField(doSending2Server);
733
734     if (!areAllReferenceSolved)
735     {
736        areAllReferenceSolved = true;
737
738        if (context->hasClient)
739        {
740          solveRefInheritance(true);
741          if (hasDirectFieldReference()) getDirectFieldReference()->solveAllReferenceEnabledField(false);
742        }
743        else if (context->hasServer)
744          solveServerOperation();
745
746        solveGridReference();
747     }
748
749     solveGridDomainAxisRef(doSending2Server);
750
751     if (context->hasClient)
752     {
753       solveTransformedGrid();
754     }
755
756     solveCheckMaskIndex(doSending2Server);
757   }
758
759   std::map<int, StdSize> CField::getGridAttributesBufferSize()
760   {
761     return grid->getAttributesBufferSize();
762   }
763
764   std::map<int, StdSize> CField::getGridDataBufferSize()
765   {
766     return grid->getDataBufferSize(getId());
767   }
768
769   //----------------------------------------------------------------
770
771   void CField::solveServerOperation(void)
772   {
773      CContext* context = CContext::getCurrent();
774
775      if (!context->hasServer || !hasOutputFile) return;
776
777      if (freq_op.isEmpty())
778        freq_op.setValue(TimeStep);
779
780      if (freq_offset.isEmpty())
781        freq_offset.setValue(NoneDu);
782
783      freq_operation_srv = file->output_freq.getValue();
784      freq_write_srv     = file->output_freq.getValue();
785
786      lastlast_Write_srv = context->getCalendar()->getInitDate();
787      last_Write_srv     = context->getCalendar()->getInitDate();
788      last_operation_srv = context->getCalendar()->getInitDate();
789
790      const CDuration toffset = freq_operation_srv - freq_offset.getValue() - context->getCalendar()->getTimeStep();
791      last_operation_srv     = last_operation_srv - toffset;
792
793      if (operation.isEmpty())
794        ERROR("void CField::solveServerOperation(void)",
795              << "An operation must be defined for field \"" << getId() << "\".");
796
797      boost::shared_ptr<func::CFunctor> functor;
798      CArray<double, 1> dummyData;
799
800#define DECLARE_FUNCTOR(MType, mtype) \
801      if (operation.getValue().compare(#mtype) == 0) \
802      { \
803        functor.reset(new func::C##MType(dummyData)); \
804      }
805
806#include "functor_type.conf"
807
808      if (!functor)
809        ERROR("void CField::solveServerOperation(void)",
810              << "\"" << operation << "\" is not a valid operation.");
811
812      operationTimeType = functor->timeType();
813   }
814
815   //----------------------------------------------------------------
816
817   /*!
818    * Constructs the graph filter for the field, enabling or not the data output.
819    * This method should not be called more than once with enableOutput equal to true.
820    *
821    * \param gc the garbage collector to use when building the filter graph
822    * \param enableOutput must be true when the field data is to be
823    *                     read by the client or/and written to a file
824    */
825   void CField::buildFilterGraph(CGarbageCollector& gc, bool enableOutput)
826   {
827     if (!areAllReferenceSolved) solveAllReferenceEnabledField(false);
828
829     checkAttributes();
830
831     const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
832     const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
833
834     // Start by building a filter which can provide the field's instant data
835     if (!instantDataFilter)
836     {
837       // Check if we have an expression to parse
838       if (hasExpression())
839       {
840         boost::scoped_ptr<IFilterExprNode> expr(parseExpr(getExpression() + '\0'));
841         boost::shared_ptr<COutputPin> filter = expr->reduce(gc, *this);
842
843         // Check if a spatial transformation is needed
844         if (!field_ref.isEmpty())
845         {
846           CGrid* gridRef = CField::get(field_ref)->grid;
847
848           if (grid && grid != gridRef && grid->hasTransform())
849           {
850             std::pair<boost::shared_ptr<CFilter>, boost::shared_ptr<CFilter> > filters = CSpatialTransformFilter::buildFilterGraph(gc, gridRef, grid, detectMissingValues, defaultValue);
851
852             filter->connectOutput(filters.first, 0);
853             filter = filters.second;
854           }
855         }
856
857         instantDataFilter = filter;
858       }
859       // Check if we have a reference on another field
860       else if (!field_ref.isEmpty())
861         instantDataFilter = getFieldReference(gc);
862       // Check if the data is to be read from a file
863       else if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
864         instantDataFilter = serverSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, freq_offset, true,
865                                                                                                     detectMissingValues, defaultValue));
866       else // The data might be passed from the model
867       {
868          if (check_if_active.isEmpty()) check_if_active = false;
869          instantDataFilter = clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, NoneDu, false,
870                                                                                                      detectMissingValues, defaultValue));
871       }
872     }
873
874     // If the field data is to be read by the client or/and written to a file
875     if (enableOutput && !storeFilter && !fileWriterFilter)
876     {
877       if (!read_access.isEmpty() && read_access)
878       {
879         storeFilter = boost::shared_ptr<CStoreFilter>(new CStoreFilter(gc, CContext::getCurrent(), grid,
880                                                                        detectMissingValues, defaultValue));
881         instantDataFilter->connectOutput(storeFilter, 0);
882       }
883
884       if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
885       {
886         fileWriterFilter = boost::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
887         getTemporalDataFilter(gc, file->output_freq)->connectOutput(fileWriterFilter, 0);
888       }
889     }
890   }
891
892   /*!
893    * Returns the filter needed to handle the field reference.
894    * This method should only be called when building the filter graph corresponding to the field.
895    *
896    * \param gc the garbage collector to use
897    * \return the output pin corresponding to the field reference
898    */
899   boost::shared_ptr<COutputPin> CField::getFieldReference(CGarbageCollector& gc)
900   {
901     if (instantDataFilter || field_ref.isEmpty())
902       ERROR("COutputPin* CField::getFieldReference(CGarbageCollector& gc)",
903             "Impossible to get the field reference for a field which has already been parsed or which does not have a field_ref.");
904
905     CField* fieldRef = CField::get(field_ref);
906     fieldRef->buildFilterGraph(gc, false);
907
908     std::pair<boost::shared_ptr<CFilter>, boost::shared_ptr<CFilter> > filters;
909     // Check if a spatial transformation is needed
910     if (grid && grid != fieldRef->grid && grid->hasTransform())
911     {       
912       bool hasMissingValue = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
913       double defaultValue  = hasMissingValue ? default_value : (!default_value.isEmpty() ? default_value : 0.0);                               
914       filters = CSpatialTransformFilter::buildFilterGraph(gc, fieldRef->grid, grid, hasMissingValue, defaultValue);
915     }
916     else
917       filters.first = filters.second = boost::shared_ptr<CFilter>(new CPassThroughFilter(gc));
918
919     fieldRef->getInstantDataFilter()->connectOutput(filters.first, 0);
920
921     return filters.second;
922   }
923
924   /*!
925    * Returns the filter needed to handle a self reference in the field's expression.
926    * If the needed filter does not exist, it is created, otherwise it is reused.
927    * This method should only be called when building the filter graph corresponding
928    * to the field's expression.
929    *
930    * \param gc the garbage collector to use
931    * \return the output pin corresponding to a self reference
932    */
933   boost::shared_ptr<COutputPin> CField::getSelfReference(CGarbageCollector& gc)
934   {
935     if (instantDataFilter || !hasExpression())
936       ERROR("COutputPin* CField::getSelfReference(CGarbageCollector& gc)",
937             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
938
939     if (!selfReferenceFilter)
940     {
941       checkAttributes();
942
943       const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
944       const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
945
946       if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
947       {
948         if (!serverSourceFilter)
949           serverSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, freq_offset, true,
950                                                                                   detectMissingValues, defaultValue));
951
952         selfReferenceFilter = serverSourceFilter;
953       }
954       else if (!field_ref.isEmpty())
955       {
956         CField* fieldRef = CField::get(field_ref);
957         fieldRef->buildFilterGraph(gc, false); 
958         selfReferenceFilter = fieldRef->getInstantDataFilter();
959       }
960       else
961       {
962         if (!clientSourceFilter)
963         {
964           if (check_if_active.isEmpty()) check_if_active = false;
965           clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, NoneDu, false,
966                                                                                   detectMissingValues, defaultValue));
967         }
968
969         selfReferenceFilter = clientSourceFilter;
970       }
971     }
972
973     return selfReferenceFilter;
974   }
975
976   /*!
977    * Returns the temporal filter corresponding to the field's temporal operation
978    * for the specified operation frequency. The filter is created if it does not
979    * exist, otherwise it is reused.
980    *
981    * \param gc the garbage collector to use
982    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
983    * \return the output pin corresponding to the requested temporal filter
984    */
985   boost::shared_ptr<COutputPin> CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
986   {
987     std::map<CDuration, boost::shared_ptr<COutputPin> >::iterator it = temporalDataFilters.find(outFreq);
988
989     if (it == temporalDataFilters.end())
990     {
991       if (operation.isEmpty())
992         ERROR("void CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
993               << "An operation must be defined for field \"" << getId() << "\".");
994
995       checkAttributes();
996
997       const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
998       boost::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
999                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
1000                                                                             freq_op, freq_offset, outFreq,
1001                                                                             detectMissingValues, detectMissingValues ? default_value : 0.0));
1002       instantDataFilter->connectOutput(temporalFilter, 0);
1003
1004       it = temporalDataFilters.insert(std::make_pair(outFreq, temporalFilter)).first;
1005     }
1006
1007     return it->second;
1008   }
1009
1010  /*!
1011    * Returns the temporal filter corresponding to the field's temporal operation
1012    * for the specified operation frequency.
1013    *
1014    * \param gc the garbage collector to use
1015    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1016    * \return the output pin corresponding to the requested temporal filter
1017    */
1018   
1019   boost::shared_ptr<COutputPin> CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1020   {
1021     if (instantDataFilter || !hasExpression())
1022       ERROR("COutputPin* CField::getSelfTemporalDataFilter(CGarbageCollector& gc)",
1023             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1024
1025     if (!selfReferenceFilter) getSelfReference(gc) ;
1026
1027     if (serverSourceFilter || clientSourceFilter)
1028     {
1029       if (operation.isEmpty())
1030         ERROR("void CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1031               << "An operation must be defined for field \"" << getId() << "\".");
1032
1033       checkAttributes();
1034
1035       const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1036       boost::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1037                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
1038                                                                             freq_op, freq_offset, outFreq,
1039                                                                             detectMissingValues, detectMissingValues ? default_value : 0.0));
1040       selfReferenceFilter->connectOutput(temporalFilter, 0);
1041       return temporalFilter ;
1042     }
1043     else if (!field_ref.isEmpty())
1044     {
1045       CField* fieldRef = CField::get(field_ref);
1046       fieldRef->buildFilterGraph(gc, false); 
1047       return fieldRef->getTemporalDataFilter(gc, outFreq) ;
1048     }
1049  }
1050
1051   //----------------------------------------------------------------
1052/*
1053   void CField::fromBinary(StdIStream& is)
1054   {
1055      SuperClass::fromBinary(is);
1056#define CLEAR_ATT(name_)\
1057      SuperClassAttribute::operator[](#name_)->reset()
1058
1059         CLEAR_ATT(domain_ref);
1060         CLEAR_ATT(axis_ref);
1061#undef CLEAR_ATT
1062
1063   }
1064*/
1065   //----------------------------------------------------------------
1066
1067   void CField::solveGridReference(void)
1068   {
1069      if (grid_ref.isEmpty() && domain_ref.isEmpty() && axis_ref.isEmpty() && scalar_ref.isEmpty())
1070      {
1071        ERROR("CField::solveGridReference(void)",
1072              << "A grid must be defined for field '" << getFieldOutputName() << "' .");
1073      }
1074      else if (!grid_ref.isEmpty() && (!domain_ref.isEmpty() || !axis_ref.isEmpty() || !scalar_ref.isEmpty()))
1075      {
1076        ERROR("CField::solveGridReference(void)",
1077              << "Field '" << getFieldOutputName() << "' has both a grid and a domain/axis/scalar." << std::endl
1078              << "Please define either 'grid_ref' or 'domain_ref'/'axis_ref'/'scalar_ref'.");
1079      }
1080
1081      if (grid_ref.isEmpty())
1082      {
1083        std::vector<CDomain*> vecDom;
1084        std::vector<CAxis*> vecAxis;
1085        std::vector<CScalar*> vecScalar;
1086        std::vector<int> axisDomainOrderTmp;
1087       
1088        if (!domain_ref.isEmpty())
1089        {
1090          StdString tmp = domain_ref.getValue();
1091          if (CDomain::has(domain_ref))
1092          {
1093            vecDom.push_back(CDomain::get(domain_ref));
1094            axisDomainOrderTmp.push_back(2);
1095          }
1096          else
1097            ERROR("CField::solveGridReference(void)",
1098                  << "Invalid reference to domain '" << domain_ref.getValue() << "'.");
1099        }
1100
1101        if (!axis_ref.isEmpty())
1102        {
1103          if (CAxis::has(axis_ref))
1104          {
1105            vecAxis.push_back(CAxis::get(axis_ref));
1106            axisDomainOrderTmp.push_back(1);
1107          }
1108          else
1109            ERROR("CField::solveGridReference(void)",
1110                  << "Invalid reference to axis '" << axis_ref.getValue() << "'.");
1111        }
1112
1113        if (!scalar_ref.isEmpty())
1114        {
1115          if (CScalar::has(scalar_ref))
1116          {
1117            vecScalar.push_back(CScalar::get(scalar_ref));
1118            axisDomainOrderTmp.push_back(0);
1119          }
1120          else
1121            ERROR("CField::solveGridReference(void)",
1122                  << "Invalid reference to scalar '" << scalar_ref.getValue() << "'.");
1123        }
1124       
1125        CArray<int,1> axisDomainOrder(axisDomainOrderTmp.size());
1126        for (int idx = 0; idx < axisDomainOrderTmp.size(); ++idx)
1127        {
1128          axisDomainOrder(idx) = axisDomainOrderTmp[idx];
1129        }
1130
1131        // Warning: the gridId shouldn't be set as the grid_ref since it could be inherited
1132        StdString gridId = CGrid::generateId(vecDom, vecAxis, vecScalar,axisDomainOrder);
1133        if (CGrid::has(gridId))
1134          this->grid = CGrid::get(gridId);
1135        else
1136          this->grid = CGrid::createGrid(gridId, vecDom, vecAxis, vecScalar,axisDomainOrder);
1137      }
1138      else
1139      {
1140        if (CGrid::has(grid_ref))
1141          this->grid = CGrid::get(grid_ref);
1142        else
1143          ERROR("CField::solveGridReference(void)",
1144                << "Invalid reference to grid '" << grid_ref.getValue() << "'.");
1145      }
1146   }
1147
1148   void CField::solveGridDomainAxisRef(bool checkAtt)
1149   {
1150     grid->solveDomainAxisRef(checkAtt);
1151   }
1152
1153   void CField::solveCheckMaskIndex(bool doSendingIndex)
1154   {
1155     grid->checkMaskIndex(doSendingIndex);
1156   }
1157
1158   void CField::solveTransformedGrid()
1159   {
1160     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
1161     {
1162       std::vector<CGrid*> grids;
1163       // Source grid
1164       grids.push_back(getDirectFieldReference()->grid);
1165       // Intermediate grids
1166       if (!grid_path.isEmpty())
1167       {
1168         std::string gridId;
1169         size_t start = 0, end;
1170
1171         do
1172         {
1173           end = grid_path.getValue().find(',', start);
1174           if (end != std::string::npos)
1175           {
1176             gridId = grid_path.getValue().substr(start, end - start);
1177             start = end + 1;
1178           }
1179           else
1180             gridId = grid_path.getValue().substr(start);
1181
1182           if (!CGrid::has(gridId))
1183             ERROR("void CField::solveTransformedGrid()",
1184                   << "Invalid grid_path, the grid '" << gridId << "' does not exist.");
1185
1186           grids.push_back(CGrid::get(gridId));
1187         }
1188         while (end != std::string::npos);
1189       }
1190       // Destination grid
1191       grids.push_back(grid);
1192
1193       for (size_t i = 0, count = grids.size() - 1; i < count; ++i)
1194       {
1195         CGrid *gridSrc  = grids[i];
1196         CGrid *gridDest = grids[i + 1];
1197         if (!gridDest->isTransformed())
1198           gridDest->transformGrid(gridSrc);
1199       }
1200     }
1201     else if (grid && grid->hasTransform() && !grid->isTransformed())
1202     {
1203       // Temporarily deactivate the self-transformation of grid
1204       //grid->transformGrid(grid);
1205     }
1206   }
1207
1208   void CField::solveGenerateGrid()
1209   {
1210     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
1211       grid->completeGrid(getDirectFieldReference()->grid);
1212     else
1213       grid->completeGrid();
1214   }
1215
1216   void CField::solveGridDomainAxisBaseRef()
1217   {
1218     grid->solveDomainAxisRef(false);
1219     grid->solveDomainAxisBaseRef();
1220   }
1221
1222   ///-------------------------------------------------------------------
1223
1224   template <>
1225   void CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)
1226   {
1227      if (this->group_ref.isEmpty()) return;
1228      StdString gref = this->group_ref.getValue();
1229
1230      if (!CFieldGroup::has(gref))
1231         ERROR("CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)",
1232               << "[ gref = " << gref << "]"
1233               << " invalid group name !");
1234
1235      CFieldGroup* group = CFieldGroup::get(gref);
1236      CFieldGroup* owner = CFieldGroup::get(boost::polymorphic_downcast<CFieldGroup*>(this));
1237
1238      std::vector<CField*> allChildren  = group->getAllChildren();
1239      std::vector<CField*>::iterator it = allChildren.begin(), end = allChildren.end();
1240
1241      for (; it != end; it++)
1242      {
1243         CField* child = *it;
1244         if (child->hasId()) owner->createChild()->field_ref.setValue(child->getId());
1245
1246      }
1247   }
1248
1249   void CField::scaleFactorAddOffset(double scaleFactor, double addOffset)
1250   {
1251     map<int, CArray<double,1> >::iterator it;
1252     for (it = data_srv.begin(); it != data_srv.end(); it++) it->second = (it->second - addOffset) / scaleFactor;
1253   }
1254
1255   void CField::invertScaleFactorAddOffset(double scaleFactor, double addOffset)
1256   {
1257     map<int, CArray<double,1> >::iterator it;
1258     for (it = data_srv.begin(); it != data_srv.end(); it++) it->second = it->second * scaleFactor + addOffset;
1259   }
1260
1261   void CField::outputField(CArray<double,3>& fieldOut)
1262   {
1263      map<int, CArray<double,1> >::iterator it;
1264      for (it = data_srv.begin(); it != data_srv.end(); it++)
1265      {
1266        grid->outputField(it->first, it->second, fieldOut.dataFirst());
1267      }
1268   }
1269
1270   void CField::outputField(CArray<double,2>& fieldOut)
1271   {
1272      map<int, CArray<double,1> >::iterator it;
1273      for(it=data_srv.begin();it!=data_srv.end();it++)
1274      {
1275         grid->outputField(it->first, it->second, fieldOut.dataFirst());
1276      }
1277   }
1278
1279   void CField::outputField(CArray<double,1>& fieldOut)
1280   {
1281      map<int, CArray<double,1> >::iterator it;
1282
1283      for (it = data_srv.begin(); it != data_srv.end(); it++)
1284      {
1285         grid->outputField(it->first, it->second, fieldOut.dataFirst());
1286      }
1287   }
1288
1289   void CField::inputField(CArray<double,3>& fieldOut)
1290   {
1291      map<int, CArray<double,1> >::iterator it;
1292      for (it = data_srv.begin(); it != data_srv.end(); it++)
1293      {
1294        grid->inputField(it->first, fieldOut.dataFirst(), it->second);
1295      }
1296   }
1297
1298   void CField::inputField(CArray<double,2>& fieldOut)
1299   {
1300      map<int, CArray<double,1> >::iterator it;
1301      for(it = data_srv.begin(); it != data_srv.end(); it++)
1302      {
1303         grid->inputField(it->first, fieldOut.dataFirst(), it->second);
1304      }
1305   }
1306
1307   void CField::inputField(CArray<double,1>& fieldOut)
1308   {
1309      map<int, CArray<double,1> >::iterator it;
1310      for (it = data_srv.begin(); it != data_srv.end(); it++)
1311      {
1312         grid->inputField(it->first, fieldOut.dataFirst(), it->second);
1313      }
1314   }
1315
1316   void CField::outputCompressedField(CArray<double,1>& fieldOut)
1317   {
1318      map<int, CArray<double,1> >::iterator it;
1319
1320      for (it = data_srv.begin(); it != data_srv.end(); it++)
1321      {
1322         grid->outputCompressedField(it->first, it->second, fieldOut.dataFirst());
1323      }
1324   }
1325
1326   ///-------------------------------------------------------------------
1327
1328   void CField::parse(xml::CXMLNode& node)
1329   {
1330      SuperClass::parse(node);
1331      if (!node.getContent(this->content))
1332      {
1333        if (node.goToChildElement())
1334        {
1335          do
1336          {
1337            if (node.getElementName() == "variable" || node.getElementName() == "variable_group") this->getVirtualVariableGroup()->parseChild(node);
1338          } while (node.goToNextElement());
1339          node.goToParentElement();
1340        }
1341      }
1342    }
1343
1344   /*!
1345     This function retrieves Id of corresponding domain_ref and axis_ref (if any)
1346   of a field. In some cases, only domain exists but axis doesn't
1347   \return pair of Domain and Axis id
1348   */
1349   const std::vector<StdString>& CField::getRefDomainAxisIds()
1350   {
1351     CGrid* cgPtr = getRelGrid();
1352     if (NULL != cgPtr)
1353     {
1354       std::vector<StdString>::iterator it;
1355       if (!domain_ref.isEmpty())
1356       {
1357         std::vector<StdString> domainList = cgPtr->getDomainList();
1358         it = std::find(domainList.begin(), domainList.end(), domain_ref.getValue());
1359         if (domainList.end() != it) domAxisScalarIds_[0] = *it;
1360       }
1361
1362       if (!axis_ref.isEmpty())
1363       {
1364         std::vector<StdString> axisList = cgPtr->getAxisList();
1365         it = std::find(axisList.begin(), axisList.end(), axis_ref.getValue());
1366         if (axisList.end() != it) domAxisScalarIds_[1] = *it;
1367       }
1368
1369       if (!scalar_ref.isEmpty())
1370       {
1371         std::vector<StdString> scalarList = cgPtr->getScalarList();
1372         it = std::find(scalarList.begin(), scalarList.end(), scalar_ref.getValue());
1373         if (scalarList.end() != it) domAxisScalarIds_[2] = *it;
1374       }
1375     }
1376     return (domAxisScalarIds_);
1377   }
1378
1379   CVariable* CField::addVariable(const string& id)
1380   {
1381     return vVariableGroup->createChild(id);
1382   }
1383
1384   CVariableGroup* CField::addVariableGroup(const string& id)
1385   {
1386     return vVariableGroup->createChildGroup(id);
1387   }
1388
1389   void CField::sendAddAllVariables()
1390   {
1391     std::vector<CVariable*> allVar = getAllVariables();
1392     std::vector<CVariable*>::const_iterator it = allVar.begin();
1393     std::vector<CVariable*>::const_iterator itE = allVar.end();
1394
1395     for (; it != itE; ++it)
1396     {
1397       this->sendAddVariable((*it)->getId());
1398       (*it)->sendAllAttributesToServer();
1399       (*it)->sendValue();
1400     }
1401   }
1402
1403   void CField::sendAddVariable(const string& id)
1404   {
1405    CContext* context = CContext::getCurrent();
1406
1407    if (!context->hasServer)
1408    {
1409       CContextClient* client = context->client;
1410
1411       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE);
1412       if (client->isServerLeader())
1413       {
1414         CMessage msg;
1415         msg << this->getId();
1416         msg << id;
1417         const std::list<int>& ranks = client->getRanksServerLeader();
1418         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1419           event.push(*itRank,1,msg);
1420         client->sendEvent(event);
1421       }
1422       else client->sendEvent(event);
1423    }
1424   }
1425
1426   void CField::sendAddVariableGroup(const string& id)
1427   {
1428    CContext* context = CContext::getCurrent();
1429    if (!context->hasServer)
1430    {
1431       CContextClient* client = context->client;
1432
1433       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE_GROUP);
1434       if (client->isServerLeader())
1435       {
1436         CMessage msg;
1437         msg << this->getId();
1438         msg << id;
1439         const std::list<int>& ranks = client->getRanksServerLeader();
1440         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1441           event.push(*itRank,1,msg);
1442         client->sendEvent(event);
1443       }
1444       else client->sendEvent(event);
1445    }
1446   }
1447
1448   void CField::recvAddVariable(CEventServer& event)
1449   {
1450
1451      CBufferIn* buffer = event.subEvents.begin()->buffer;
1452      string id;
1453      *buffer >> id;
1454      get(id)->recvAddVariable(*buffer);
1455   }
1456
1457   void CField::recvAddVariable(CBufferIn& buffer)
1458   {
1459      string id;
1460      buffer >> id;
1461      addVariable(id);
1462   }
1463
1464   void CField::recvAddVariableGroup(CEventServer& event)
1465   {
1466
1467      CBufferIn* buffer = event.subEvents.begin()->buffer;
1468      string id;
1469      *buffer >> id;
1470      get(id)->recvAddVariableGroup(*buffer);
1471   }
1472
1473   void CField::recvAddVariableGroup(CBufferIn& buffer)
1474   {
1475      string id;
1476      buffer >> id;
1477      addVariableGroup(id);
1478   }
1479
1480   /*!
1481    * Check on freq_off and freq_op attributes.
1482    */
1483   void CField::checkAttributes(void)
1484   {
1485     bool isFieldRead = file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read;
1486     if (isFieldRead && operation.getValue() != "instant")
1487       ERROR("void CField::checkAttributes(void)",
1488             << "Unsupported operation for field '" << getFieldOutputName() << "'." << std::endl
1489             << "Currently only \"instant\" is supported for fields read from file.")
1490
1491     if (freq_op.isEmpty())
1492     {
1493       if (operation.getValue() == "instant")
1494         freq_op.setValue(file->output_freq.getValue());
1495       else
1496         freq_op.setValue(TimeStep);
1497     }
1498     if (freq_offset.isEmpty())
1499       freq_offset.setValue(isFieldRead ? NoneDu : (freq_op.getValue() - TimeStep));
1500   }
1501
1502   /*!
1503    * Returns string arithmetic expression associated to the field.
1504    * \return if content is defined return content string, otherwise, if "expr" attribute is defined, return expr string.
1505    */
1506   const string& CField::getExpression(void)
1507   {
1508     if (!expr.isEmpty() && content.empty())
1509     {
1510       content = expr;
1511       expr.reset();
1512     }
1513
1514     return content;
1515   }
1516
1517   bool CField::hasExpression(void) const
1518   {
1519     return (!expr.isEmpty() || !content.empty());
1520   }
1521
1522   DEFINE_REF_FUNC(Field,field)
1523} // namespace xios
Note: See TracBrowser for help on using the repository browser.