]> SALOME platform Git repositories - modules/kernel.git/blob - src/DSC/DSC_User/Datastream/Calcium/CalciumCouplingPolicy.hxx
Salome HOME
383f7a69857bfd8c26830087e86edf1d612432c7
[modules/kernel.git] / src / DSC / DSC_User / Datastream / Calcium / CalciumCouplingPolicy.hxx
1 //  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 //  File   : CalciumCouplingPolicy.hxx
23 //  Author : Eric Fayolle (EDF)
24 //  Module : KERNEL
25 // Id          : $Id$
26 //
27 #ifndef __CALCIUM_COUPLING_POLICY__ 
28 #define __CALCIUM_COUPLING_POLICY__
29
30 #include <vector>
31 #include <map>
32
33 #include "DisplayPair.hxx"
34 #include "CouplingPolicy.hxx"
35 #include "AdjacentFunctor.hxx"
36 #include <boost/lambda/lambda.hpp>
37 #include <boost/utility/enable_if.hpp>
38 #include <boost/type_traits/is_arithmetic.hpp>
39 #include "CalciumTypes.hxx"
40 #include "CalciumException.hxx"
41
42 class CalciumCouplingPolicy : public CouplingPolicy  {
43
44
45 public:
46
47   template <typename T_TIME, typename T_TAG >        class InternalDataIdContainer;
48   template <typename T_TIME, typename T_TAG > friend class InternalDataIdContainer;
49   template <typename DataManipulator, 
50     class EnableIf >                  friend class BoundedDataIdProcessor;
51   template <typename DataManipulator >        friend class EraseDataIdProcessor;
52   template <typename DataManipulator >        friend class DisconnectProcessor;
53
54   typedef CalciumTypes::DependencyType       DependencyType;
55   typedef CalciumTypes::DateCalSchem         DateCalSchem;
56   typedef CalciumTypes::InterpolationSchem   InterpolationSchem;
57   typedef CalciumTypes::ExtrapolationSchem   ExtrapolationSchem;
58   typedef CalciumTypes::DisconnectDirective  DisconnectDirective;  
59
60 private:
61
62   DependencyType      _dependencyType;
63   size_t              _storageLevel;
64   DateCalSchem        _dateCalSchem;
65   InterpolationSchem  _interpolationSchem;
66   ExtrapolationSchem  _extrapolationSchem;
67   double              _alpha;
68   double              _deltaT;
69   DisconnectDirective _disconnectDirective;
70
71 public:
72   CalciumCouplingPolicy();
73
74   void           setDependencyType (DependencyType dependencyType);
75   DependencyType getDependencyType () const;
76  
77   void   setStorageLevel   (size_t storageLevel);
78   size_t getStorageLevel   () const;
79
80   void         setDateCalSchem   (DateCalSchem   dateCalSchem);
81   DateCalSchem getDateCalSchem () const;
82
83   void   setAlpha(double alpha);
84   double getAlpha() const ;
85
86   void   setDeltaT(double deltaT );
87   double getDeltaT() const ;
88
89   void setInterpolationSchem (InterpolationSchem interpolationSchem);
90   void setExtrapolationSchem (ExtrapolationSchem extrapolationSchem);
91   InterpolationSchem getInterpolationSchem () const ;
92   ExtrapolationSchem getExtrapolationSchem () const ;
93
94   // Classe DataId rassemblant les paramètres de la méthode PORT::put 
95   // qui identifient l'instance d'une donnée pour Calcium
96   // Rem : Le DataId doit pouvoir être une key dans une map stl
97   typedef double TimeType;
98   typedef long   TagType;
99   typedef std::pair< TimeType , TagType >     DataId;
100   typedef InternalDataIdContainer < TimeType , TagType >  DataIdContainer;
101   typedef std::vector< DataId >::iterator  iterator;
102
103   template <typename T_TIME, typename T_TAG >  
104   struct InternalDataIdContainer;
105
106   inline TimeType getTime(const DataId &dataId) const { return dataId.first;}
107   inline TagType  getTag (const DataId &dataId) const { return dataId.second;}
108
109   template <typename DataManipulator, 
110             class EnableIf = void >    struct BoundedDataIdProcessor;
111   //template <typename DataManipulator>  struct BoundedDataIdProcessor;
112   template <typename DataManipulator>  struct EraseDataIdProcessor;
113   template <typename DataManipulator>  struct DisconnectProcessor;
114
115   // Renvoie isEqual si le dataId attendu est trouvé dans storedDataIds :
116   //   - l'itérateur wDataIt1 pointe alors sur ce dataId
117   // Renvoie isBounded si le dataId attendu n'est pas trouvé mais encadrable et 
118   // que la politique de couplage gére ce cas de figure 
119   //   - l'itérateur wDataIt1 est tel que wDataIt1->first < wdataId < (wDataIt1+1)->first
120   // Le container doit être associatif
121   template < typename AssocContainer >
122   bool isDataIdConveniant( AssocContainer & storedDatas, 
123                            const typename AssocContainer::key_type & expectedDataId,
124                            bool & isEqual, bool & isBounded, 
125                            typename AssocContainer::iterator & wDataIt1) const;
126
127   TimeType getEffectiveTime(TimeType ti, TimeType tf);
128
129   void disconnect(bool provideLastGivenValue);
130
131 }; //Fin de CalciumCouplingPolicy
132
133
134
135 //*************   DEFINITION DES METHODES ET OBJETS TEMPLATES *************// 
136
137
138
139 // Définition du container de DataId pour répondre au concept
140 // de mode de couplage
141 template <typename T_TIME, typename T_TAG > 
142 struct CalciumCouplingPolicy::InternalDataIdContainer : public std::vector< std::pair< T_TIME,T_TAG> >  {
143   typedef std::vector < DataId >        DataIdVect;
144     
145   InternalDataIdContainer(const DataId & dataId, 
146                           const CalciumCouplingPolicy & policy
147                           ):std::vector< std::pair< T_TIME,T_TAG> >() {
148     // Ignore les paramètres qui ne sont pas en rapport avec le type de dépendance
149     switch (policy._dependencyType) {
150     case CalciumTypes::TIME_DEPENDENCY:
151       this->push_back(DataId(dataId.first,0));
152       break;
153     case CalciumTypes::ITERATION_DEPENDENCY:
154       this->push_back(DataId(0,dataId.second));
155       break;
156     default:
157       throw(CalciumException(CalciumTypes::CPIT,LOC("The dependency type must be set by setDependencyType before calling DataIdContainer contructor")));
158       break;
159     }
160   };
161 };
162
163
164 template <typename DataManipulator, class EnableIf >
165 struct CalciumCouplingPolicy::BoundedDataIdProcessor{
166   BoundedDataIdProcessor(const CouplingPolicy & couplingPolicy) {};
167   template < typename Iterator, typename DataId > 
168   void inline apply(typename iterator_t<Iterator>::value_type & data,
169                     const DataId & dataId,
170                     const Iterator  & it1) const {
171     typedef typename iterator_t<Iterator>::value_type value_type;
172     std::cout << "-------- Calcium Generic BoundedDataIdProcessor.apply() called " << std::endl;
173
174   }
175 };
176
177
178 template <typename DataManipulator >
179 struct CalciumCouplingPolicy::BoundedDataIdProcessor<
180   DataManipulator, 
181   typename boost::enable_if< boost::is_float< typename DataManipulator::InnerType> >::type > {
182     
183   const CalciumCouplingPolicy & _couplingPolicy;
184     
185   BoundedDataIdProcessor(const CalciumCouplingPolicy &couplingPolicy):
186     _couplingPolicy(couplingPolicy) {};
187     
188   // Méthode implémentant l'interpolation temporelle
189   template < typename MapIterator > 
190   void inline apply (typename iterator_t<MapIterator>::value_type & data,
191                      const DataId & dataId, const MapIterator & it1) const {
192       
193     typedef typename iterator_t<MapIterator>::value_type value_type;
194     typedef typename DataManipulator::InnerType InnerType;
195     typedef typename DataManipulator::Type Type;
196
197     MapIterator it2=it1; ++it2;
198     size_t   dataSize1 = DataManipulator::size(it1->second);
199 #ifdef _DEBUG_
200     std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Taille de donnée dataId1 : " << dataSize1 << std::endl;
201 #endif
202  
203     // Gérer dans calcium la limite de la taille du buffer donnée par
204     // l'utilisateur.
205     size_t   dataSize2 = DataManipulator::size(it2->second);
206 #ifdef _DEBUG_
207     std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Taille de donnée dataId2 : " << dataSize2 << std::endl;
208 #endif
209
210     size_t   dataSize  = std::min< size_t >( dataSize1, dataSize2 );
211     DataId   dataId2 = it2->first;
212     DataId   dataId1 = it1->first;
213     TimeType t2      = dataId2.first;
214     TimeType t1      = dataId1.first;
215 #ifdef _DEBUG_
216     std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Valeur de t1 : " << t1 << std::endl;
217     std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Valeur de t2 : " << t2 << std::endl;
218 #endif
219     TimeType t       = dataId.first;
220 #ifdef _DEBUG_
221     std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Valeur de t : " << t << std::endl;
222 #endif
223     TimeType timeDiff  = t2-t1;
224 #ifdef _DEBUG_
225     std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Valeur de timeDiff : " << timeDiff << std::endl;
226 #endif
227     TimeType coeff   = (t2-t)/timeDiff;
228 #ifdef _DEBUG_
229     std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Valeur de coeff : " << coeff << std::endl;
230 #endif
231
232     InnerType const * const InIt1 = DataManipulator::getPointer(it1->second);
233 #ifdef _DEBUG_
234     std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Données à t1 : " << std::endl;
235     std::copy(InIt1,InIt1+dataSize1,std::ostream_iterator<InnerType>(std::cout," "));
236     std::cout << std::endl;
237 #endif
238     InnerType const * const InIt2 = DataManipulator::getPointer(it2->second);
239 #ifdef _DEBUG_
240     std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Données à t2 : " << std::endl;
241     std::copy(InIt2,InIt2+dataSize2,std::ostream_iterator<InnerType>(std::cout," "));
242     std::cout << std::endl;
243 #endif
244     Type              dataOut = DataManipulator::create(dataSize);
245     InnerType * const OutIt   = DataManipulator::getPointer(dataOut);
246  
247 #ifdef _DEBUG_
248     std::cerr << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : interpolationSchem : " << _couplingPolicy._interpolationSchem << std::endl;
249     std::cerr << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : alpha : " << _couplingPolicy._alpha << std::endl;
250     std::cerr << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : datecalschem : " << _couplingPolicy._dateCalSchem << std::endl;
251     std::cerr << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : storageLevel : " << _couplingPolicy._storageLevel << std::endl;
252 #endif
253     if ( timeDiff == 0.0 ||  _couplingPolicy._interpolationSchem == CalciumTypes::L0_SCHEM ) {
254       std::copy(InIt1,InIt1+dataSize,OutIt);
255     } else {
256
257       boost::lambda::placeholder1_type _1;
258       boost::lambda::placeholder2_type _2;
259       // OLD: REM : Pour des buffers de type int
260       // OLD: le compilo indiquera warning: converting to `long int' from `Double'
261       std::transform(InIt1,InIt1+dataSize,InIt2,OutIt,
262                      ( _1 - _2 ) * coeff + _2 );
263 //       for(size_t i =0;  i < dataSize3; ++i) {
264 //      OutIt[i]=(InIt1[i] - InIt2[i]) * coeff + InIt2[i];
265 //       }
266
267     }
268 #ifdef _DEBUG_
269     std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Données calculées à t : " << std::endl;
270     std::copy(OutIt,OutIt+dataSize,std::ostream_iterator<InnerType>(std::cout," "));
271     std::cout << std::endl;
272 #endif
273     data = dataOut;
274     
275   }
276 };
277
278 // Renvoie isEqual si le dataId attendu est trouvé dans storedDataIds :
279 //   - l'itérateur wDataIt1 pointe alors sur ce dataId
280 // Renvoie isBounded si le dataId attendu n'est pas trouvé mais encadrable et 
281 // que la politique de couplage gére ce cas de figure 
282 //   - l'itérateur wDataIt1 est tel que wDataIt1->first < wdataId < (wDataIt1+1)->first
283 // Le container doit être associatif
284 template < typename AssocContainer >
285 bool CalciumCouplingPolicy::isDataIdConveniant( AssocContainer & storedDatas, const typename AssocContainer::key_type & expectedDataId,
286                                                 bool & isEqual, bool & isBounded, typename AssocContainer::iterator & wDataIt1) const {
287  
288   // Rem : le type key_type == DataId
289   typedef typename AssocContainer::key_type key_type;
290   AdjacentFunctor< key_type > af(expectedDataId);
291   if ( _dependencyType == CalciumTypes::TIME_DEPENDENCY )
292   {
293 #ifdef _DEBUG_
294     std::cout << "-------- time expected : " << expectedDataId.first << std::endl;
295     std::cout << "-------- time expected corrected : " << expectedDataId.first*(1.0-_deltaT) << std::endl;
296 #endif
297     af.setMaxValue(key_type(expectedDataId.first*(1.0-_deltaT),0));
298   }
299   isBounded = false;
300
301   // Rem 1 :
302   // L'algo adjacent_find ne peut être utilisé avec l'AdjacentPredicate 
303   //   - si la table contient un seul élément l'algorithme adjacent_find retourne end()
304   //     que se soit l'élément attendu ou non
305   //   - si la table contient deux éléments dont le dernier est celui recherché
306   //     l'algorithme adjacent_find retourne end() aussi
307   //   d'ou la necessité d'effectuer  un find avant ou d'écrire un algorithme ad hoc
308  
309   // Rem 2 :
310   //
311   // L'algo find_if ne peut être utilisé car il recopie l'AdjacentFunctor
312   // qui ne peut alors pas mémoriser ses états précédents
313   //    
314  
315   // Un codage en reverse serait plus efficace
316   typename AssocContainer::iterator prev    = storedDatas.begin();
317   typename AssocContainer::iterator current = prev;
318   while ( (current != storedDatas.end()) && !af(current->first)  ) 
319   {
320 #ifdef _DEBUG_
321     std::cout << "------- stored time : " << current->first << std::endl;
322 #endif
323     //  if ( af(current->first) ) break;
324     prev = current++;
325   }
326
327   isEqual = af.isEqual();
328     
329   // On considère qu'il n'est pas possible d'encadrer en dépendance itérative,
330   // on se veut pas calculer d'interpolation. 
331   if  ( _dependencyType == CalciumTypes::TIME_DEPENDENCY)  isBounded = af.isBounded();
332
333   if ( isEqual ) wDataIt1 = current;
334   else 
335     if (isBounded) wDataIt1 = prev;
336     else
337       wDataIt1 = storedDatas.end();
338
339 #ifdef _DEBUG_
340   std::cout << "-------- isDataIdConvenient : isEqual : " << isEqual << " , isBounded " << isBounded << std::endl;
341 #endif
342
343   return isEqual || isBounded;
344 }
345
346 // TODO :PAS ENCORE TESTE AVEC UN NIVEAU POSITIONNE
347 // Supprime les DataId et les données associées
348 // du container associatif quand le nombre
349 // de données stockées dépasse le niveau CALCIUM.
350 // Cette méthode est appelée de GenericPort::get et GenericPort::next 
351 // TODO : Elle devrait également être appelée dans GenericPort::Put
352 // mais il faut étudier les interactions avec GenericPort::Get et GenericPort::next
353 template < typename DataManipulator > 
354 struct CalciumCouplingPolicy::EraseDataIdProcessor {
355
356   CalciumCouplingPolicy &_couplingPolicy;
357     
358   EraseDataIdProcessor(CalciumCouplingPolicy &couplingPolicy):
359     _couplingPolicy(couplingPolicy) {};
360
361   template < typename Container >
362   void apply(Container & storedDatas, 
363              typename Container::iterator & wDataIt1 ) const {
364
365     typedef typename Container::key_type   key_type;
366     typedef typename Container::value_type value_type;
367     typedef typename Container::iterator iterator;
368
369 #ifdef _DEBUG_
370     std::cout << "-------- CalciumCouplingPolicy::eraseDataId, storedDatasSize : " << storedDatas.size() << std::endl;
371 #endif
372  
373     if ( _couplingPolicy._storageLevel == CalciumTypes::UNLIMITED_STORAGE_LEVEL ) return;
374  
375     size_t storedDatasSize = storedDatas.size();
376     long   s = storedDatasSize - _couplingPolicy._storageLevel;
377     if (s > 0 ) {
378       size_t dist=distance(storedDatas.begin(),wDataIt1);
379       for (int i=0; i<s; ++i) {
380               //no bug if removed : DataManipulator::delete_data((*storedDatas.begin()).second);
381               DataManipulator::delete_data((*storedDatas.begin()).second);
382               storedDatas.erase(storedDatas.begin());
383       }
384       // Si l'itérateur pointait sur une valeur que l'on vient de supprimer
385       if (dist < s ) {
386         throw(CalciumException(CalciumTypes::CPNTNULL,LOC(OSS()<< "La gestion du niveau CALCIUM " 
387                                             << _couplingPolicy._storageLevel << 
388                                             " vient d'entraîner la suppression de la donnée à renvoyer")));
389       }
390     }
391 #ifdef _DEBUG_
392     std::cout << "-------- CalciumCouplingPolicy::eraseDataId, new storedDatasSize : " << storedDatas.size() << std::endl;
393 #endif
394     return;
395
396   }
397 };
398
399
400 // Lorsque cette méthode est appelée depuis GenericPort::Get 
401 // l'expectedDataId n'a pas été trouvé et n'est pas non plus 
402 // encadré (en mode temporel).
403 // Si apply n'effectue pas de traitement particulier la méthode renvoie false
404 // Si le port a déjà reçu une directive de deconnexion STOP une exception est levée
405 // Si le port a déjà reçu une directive de deconnexion CONTINUE, 
406 // on donne la dernière valeur connu et on renvoie true.
407 template < typename DataManipulator > 
408 struct CalciumCouplingPolicy::DisconnectProcessor {
409
410   const CalciumCouplingPolicy  & _couplingPolicy;
411     
412   DisconnectProcessor(const CalciumCouplingPolicy & couplingPolicy):
413     _couplingPolicy(couplingPolicy) {};
414
415   template < typename Container, typename DataId >
416   bool apply(Container & storedDatas,
417              const DataId & expectedDataId,
418              typename Container::iterator & wDataIt1 ) const {
419
420     typedef typename Container::key_type   key_type;
421     typedef typename Container::value_type value_type;
422     typedef typename Container::iterator   iterator;
423
424     // Pas de traitement particulier a effectuer
425 #ifdef _DEBUG_
426     std::cout << "-------- CalciumCouplingPolicy::DisconnectProcessor MARK1 ("<< _couplingPolicy._disconnectDirective<<") --------" << std::endl;
427 #endif
428     if ( (_couplingPolicy._disconnectDirective) == (CalciumTypes::UNDEFINED_DIRECTIVE) ) return false;
429   
430 #ifdef _DEBUG_
431     std::cout << "-------- CalciumCouplingPolicy::DisconnectProcessor MARK2 --------" << std::endl;
432 #endif
433
434     // TODO : Ds GenericPort::next il faut convertir en CPSTOPSEQ
435     if ( _couplingPolicy._disconnectDirective == CalciumTypes::CP_ARRET )
436       throw(CalciumException(CalciumTypes::CPINARRET,LOC(OSS()<< "La directive CP_ARRET" 
437                                            << " provoque l'interruption de toute lecture de données")));
438 #ifdef _DEBUG_
439     std::cout << "-------- CalciumCouplingPolicy::DisconnectProcessor MARK3 --------" << std::endl;
440 #endif
441
442
443     // S'il n'y a plus de données indique que l'on a pas pu effectuer de traitement
444     // TODO : Dans la gestion des niveaux il faut peut être interdire un niveau ==  0
445     if ( storedDatas.empty() ) 
446       throw(CalciumException(CalciumTypes::CPNTNULL,LOC(OSS()<< "La directive CP_CONT" 
447                                           << " est active mais aucune donnée n'est disponible.")));
448     
449     // expectedDataId n'a ni été trouvé dans storedDataIds ni encadré mais il se peut
450     // qu'en mode itératif il ne soit pas plus grand que le plus grand DataId stocké auquel
451     // cas on doit renvoyer une expection car on n'est plus connecté et on ne pourra jamais
452     // fournir de données pour ce dataId.
453 #ifdef _DEBUG_
454     std::cout << "-------- CalciumCouplingPolicy::DisconnectProcessor MARK4  " << expectedDataId <<" --------" << std::endl;
455 #endif
456
457     // >= expectedDataId
458     iterator it1 = storedDatas.lower_bound(expectedDataId);
459 #ifdef _DEBUG_
460     std::cout << "-------- CalciumCouplingPolicy::DisconnectProcessor MARK5  " << std::endl;
461     for (iterator it=storedDatas.begin();it!=storedDatas.end();++it)
462       std::cout <<" "<<(*it).first ;
463     std::cout <<std::endl;
464 #endif
465
466     // TODO : Il faut en fait renvoyer le plus proche cf IT ou DT
467     if (it1 == storedDatas.end())
468       throw(CalciumException(CalciumTypes::CPNTNULL,LOC(OSS()<< "La directive CP_CONT" 
469                                           << " est active mais le dataId demandé est inférieur ou égal au dernier reçu.")));
470   
471 #ifdef _DEBUG_
472     std::cout << "-------- CalciumCouplingPolicy::DisconnectProcessor MARK6 " << std::endl;
473 #endif
474
475     wDataIt1 = storedDatas.end();
476     --wDataIt1;
477 #ifdef _DEBUG_
478     std::cout << "-------- CalciumCouplingPolicy::DisconnectProcessor, CP_CONT : " << (*wDataIt1).first << std::endl;
479 #endif
480
481     return true;
482   }
483 };
484
485 #endif