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

Last change on this file since 1071 was 1071, checked in by oabramkina, 7 years ago

dev: test for secondary servers added.

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