1 // Copyright (C) 2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
2 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License.
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
22 // File : CalciumCouplingPolicy.hxx
23 // Author : Eric Fayolle (EDF)
27 #ifndef __CALCIUM_COUPLING_POLICY__
28 #define __CALCIUM_COUPLING_POLICY__
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"
42 class CalciumCouplingPolicy : public CouplingPolicy {
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;
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;
62 DependencyType _dependencyType;
64 DateCalSchem _dateCalSchem;
65 InterpolationSchem _interpolationSchem;
66 ExtrapolationSchem _extrapolationSchem;
69 DisconnectDirective _disconnectDirective;
72 CalciumCouplingPolicy();
74 void setDependencyType (DependencyType dependencyType);
75 DependencyType getDependencyType () const;
77 void setStorageLevel (size_t storageLevel);
78 size_t getStorageLevel () const;
80 void setDateCalSchem (DateCalSchem dateCalSchem);
81 DateCalSchem getDateCalSchem () const;
83 void setAlpha(double alpha);
84 double getAlpha() const ;
86 void setDeltaT(double deltaT );
87 double getDeltaT() const ;
89 void setInterpolationSchem (InterpolationSchem interpolationSchem);
90 void setExtrapolationSchem (ExtrapolationSchem extrapolationSchem);
91 InterpolationSchem getInterpolationSchem () const ;
92 ExtrapolationSchem getExtrapolationSchem () const ;
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;
99 typedef std::pair< TimeType , TagType > DataId;
100 typedef InternalDataIdContainer < TimeType , TagType > DataIdContainer;
101 typedef std::vector< DataId >::iterator iterator;
103 template <typename T_TIME, typename T_TAG >
104 struct InternalDataIdContainer;
106 inline TimeType getTime(const DataId &dataId) const { return dataId.first;}
107 inline TagType getTag (const DataId &dataId) const { return dataId.second;}
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;
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;
127 TimeType getEffectiveTime(TimeType ti, TimeType tf);
129 void disconnect(bool provideLastGivenValue);
131 }; //Fin de CalciumCouplingPolicy
135 //************* DEFINITION DES METHODES ET OBJETS TEMPLATES *************//
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;
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));
153 case CalciumTypes::ITERATION_DEPENDENCY:
154 this->push_back(DataId(0,dataId.second));
157 throw(CalciumException(CalciumTypes::CPIT,LOC("The dependency type must be set by setDependencyType before calling DataIdContainer contructor")));
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;
178 template <typename DataManipulator >
179 struct CalciumCouplingPolicy::BoundedDataIdProcessor<
181 typename boost::enable_if< boost::is_float< typename DataManipulator::InnerType> >::type > {
183 const CalciumCouplingPolicy & _couplingPolicy;
185 BoundedDataIdProcessor(const CalciumCouplingPolicy &couplingPolicy):
186 _couplingPolicy(couplingPolicy) {};
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 {
193 typedef typename iterator_t<MapIterator>::value_type value_type;
194 typedef typename DataManipulator::InnerType InnerType;
195 typedef typename DataManipulator::Type Type;
197 MapIterator it2=it1; ++it2;
198 size_t dataSize1 = DataManipulator::size(it1->second);
200 std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Taille de donnée dataId1 : " << dataSize1 << std::endl;
203 // Gérer dans calcium la limite de la taille du buffer donnée par
205 size_t dataSize2 = DataManipulator::size(it2->second);
207 std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Taille de donnée dataId2 : " << dataSize2 << std::endl;
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;
216 std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Valeur de t1 : " << t1 << std::endl;
217 std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Valeur de t2 : " << t2 << std::endl;
219 TimeType t = dataId.first;
221 std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Valeur de t : " << t << std::endl;
223 TimeType timeDiff = t2-t1;
225 std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Valeur de timeDiff : " << timeDiff << std::endl;
227 TimeType coeff = (t2-t)/timeDiff;
229 std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Valeur de coeff : " << coeff << std::endl;
232 InnerType const * const InIt1 = DataManipulator::getPointer(it1->second);
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;
238 InnerType const * const InIt2 = DataManipulator::getPointer(it2->second);
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;
244 Type dataOut = DataManipulator::create(dataSize);
245 InnerType * const OutIt = DataManipulator::getPointer(dataOut);
247 if ( timeDiff == 0.0 || _couplingPolicy._interpolationSchem == CalciumTypes::L0_SCHEM ) {
248 std::copy(InIt1,InIt1+dataSize,OutIt);
251 boost::lambda::placeholder1_type _1;
252 boost::lambda::placeholder2_type _2;
253 // OLD: REM : Pour des buffers de type int
254 // OLD: le compilo indiquera warning: converting to `long int' from `Double'
255 std::transform(InIt1,InIt1+dataSize,InIt2,OutIt,
256 ( _1 - _2 ) * coeff + _2 );
257 // for(size_t i =0; i < dataSize3; ++i) {
258 // OutIt[i]=(InIt1[i] - InIt2[i]) * coeff + InIt2[i];
263 std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Données calculées à t : " << std::endl;
264 std::copy(OutIt,OutIt+dataSize,std::ostream_iterator<InnerType>(std::cout," "));
265 std::cout << std::endl;
272 // Renvoie isEqual si le dataId attendu est trouvé dans storedDataIds :
273 // - l'itérateur wDataIt1 pointe alors sur ce dataId
274 // Renvoie isBounded si le dataId attendu n'est pas trouvé mais encadrable et
275 // que la politique de couplage gére ce cas de figure
276 // - l'itérateur wDataIt1 est tel que wDataIt1->first < wdataId < (wDataIt1+1)->first
277 // Le container doit être associatif
278 template < typename AssocContainer >
279 bool CalciumCouplingPolicy::isDataIdConveniant( AssocContainer & storedDatas, const typename AssocContainer::key_type & expectedDataId,
280 bool & isEqual, bool & isBounded, typename AssocContainer::iterator & wDataIt1) const {
282 // Rem : le type key_type == DataId
283 typedef typename AssocContainer::key_type key_type;
284 AdjacentFunctor< key_type > af(expectedDataId);
285 if ( _dependencyType == CalciumTypes::TIME_DEPENDENCY )
288 std::cout << "-------- time expected : " << expectedDataId.first << std::endl;
289 std::cout << "-------- time expected corrected : " << expectedDataId.first*(1.0-_deltaT) << std::endl;
291 af.setMaxValue(key_type(expectedDataId.first*(1.0-_deltaT),0));
296 // L'algo adjacent_find ne peut être utilisé avec l'AdjacentPredicate
297 // - si la table contient un seul élément l'algorithme adjacent_find retourne end()
298 // que se soit l'élément attendu ou non
299 // - si la table contient deux éléments dont le dernier est celui recherché
300 // l'algorithme adjacent_find retourne end() aussi
301 // d'ou la necessité d'effectuer un find avant ou d'écrire un algorithme ad hoc
305 // L'algo find_if ne peut être utilisé car il recopie l'AdjacentFunctor
306 // qui ne peut alors pas mémoriser ses états précédents
309 // Un codage en reverse serait plus efficace
310 typename AssocContainer::iterator prev = storedDatas.begin();
311 typename AssocContainer::iterator current = prev;
312 while ( (current != storedDatas.end()) && !af(current->first) )
315 std::cout << "------- stored time : " << current->first << std::endl;
317 // if ( af(current->first) ) break;
321 isEqual = af.isEqual();
323 // On considère qu'il n'est pas possible d'encadrer en dépendance itérative,
324 // on se veut pas calculer d'interpolation.
325 if ( _dependencyType == CalciumTypes::TIME_DEPENDENCY) isBounded = af.isBounded();
327 if ( isEqual ) wDataIt1 = current;
329 if (isBounded) wDataIt1 = prev;
331 wDataIt1 = storedDatas.end();
334 std::cout << "-------- isDataIdConvenient : isEqual : " << isEqual << " , isBounded " << isBounded << std::endl;
337 return isEqual || isBounded;
340 // TODO :PAS ENCORE TESTE AVEC UN NIVEAU POSITIONNE
341 // Supprime les DataId et les données associées
342 // du container associatif quand le nombre
343 // de données stockées dépasse le niveau CALCIUM.
344 // Cette méthode est appelée de GenericPort::get et GenericPort::next
345 // TODO : Elle devrait également être appelée dans GenericPort::Put
346 // mais il faut étudier les interactions avec GenericPort::Get et GenericPort::next
347 template < typename DataManipulator >
348 struct CalciumCouplingPolicy::EraseDataIdProcessor {
350 CalciumCouplingPolicy &_couplingPolicy;
352 EraseDataIdProcessor(CalciumCouplingPolicy &couplingPolicy):
353 _couplingPolicy(couplingPolicy) {};
355 template < typename Container >
356 void apply(Container & storedDatas,
357 typename Container::iterator & wDataIt1 ) const {
359 typedef typename Container::key_type key_type;
360 typedef typename Container::value_type value_type;
361 typedef typename Container::iterator iterator;
364 std::cout << "-------- CalciumCouplingPolicy::eraseDataId, storedDatasSize : " << storedDatas.size() << std::endl;
367 if ( _couplingPolicy._storageLevel == CalciumTypes::UNLIMITED_STORAGE_LEVEL ) return;
369 size_t storedDatasSize = storedDatas.size();
370 long s = storedDatasSize - _couplingPolicy._storageLevel;
372 size_t dist=distance(storedDatas.begin(),wDataIt1);
373 for (int i=0; i<s; ++i) {
374 //no bug if removed : DataManipulator::delete_data((*storedDatas.begin()).second);
375 DataManipulator::delete_data((*storedDatas.begin()).second);
376 storedDatas.erase(storedDatas.begin());
378 // Si l'itérateur pointait sur une valeur que l'on vient de supprimer
380 throw(CalciumException(CalciumTypes::CPNTNULL,LOC(OSS()<< "La gestion du niveau CALCIUM "
381 << _couplingPolicy._storageLevel <<
382 " vient d'entraîner la suppression de la donnée à renvoyer")));
386 std::cout << "-------- CalciumCouplingPolicy::eraseDataId, new storedDatasSize : " << storedDatas.size() << std::endl;
394 // Lorsque cette méthode est appelée depuis GenericPort::Get
395 // l'expectedDataId n'a pas été trouvé et n'est pas non plus
396 // encadré (en mode temporel).
397 // Si apply n'effectue pas de traitement particulier la méthode renvoie false
398 // Si le port a déjà reçu une directive de deconnexion STOP une exception est levée
399 // Si le port a déjà reçu une directive de deconnexion CONTINUE,
400 // on donne la dernière valeur connu et on renvoie true.
401 template < typename DataManipulator >
402 struct CalciumCouplingPolicy::DisconnectProcessor {
404 const CalciumCouplingPolicy & _couplingPolicy;
406 DisconnectProcessor(const CalciumCouplingPolicy & couplingPolicy):
407 _couplingPolicy(couplingPolicy) {};
409 template < typename Container, typename DataId >
410 bool apply(Container & storedDatas,
411 const DataId & expectedDataId,
412 typename Container::iterator & wDataIt1 ) const {
414 typedef typename Container::key_type key_type;
415 typedef typename Container::value_type value_type;
416 typedef typename Container::iterator iterator;
418 // Pas de traitement particulier a effectuer
420 std::cout << "-------- CalciumCouplingPolicy::DisconnectProcessor MARK1 ("<< _couplingPolicy._disconnectDirective<<") --------" << std::endl;
422 if ( (_couplingPolicy._disconnectDirective) == (CalciumTypes::UNDEFINED_DIRECTIVE) ) return false;
425 std::cout << "-------- CalciumCouplingPolicy::DisconnectProcessor MARK2 --------" << std::endl;
428 // TODO : Ds GenericPort::next il faut convertir en CPSTOPSEQ
429 if ( _couplingPolicy._disconnectDirective == CalciumTypes::CP_ARRET )
430 throw(CalciumException(CalciumTypes::CPINARRET,LOC(OSS()<< "La directive CP_ARRET"
431 << " provoque l'interruption de toute lecture de données")));
433 std::cout << "-------- CalciumCouplingPolicy::DisconnectProcessor MARK3 --------" << std::endl;
437 // S'il n'y a plus de données indique que l'on a pas pu effectuer de traitement
438 // TODO : Dans la gestion des niveaux il faut peut être interdire un niveau == 0
439 if ( storedDatas.empty() )
440 throw(CalciumException(CalciumTypes::CPNTNULL,LOC(OSS()<< "La directive CP_CONT"
441 << " est active mais aucune donnée n'est disponible.")));
443 // expectedDataId n'a ni été trouvé dans storedDataIds ni encadré mais il se peut
444 // qu'en mode itératif il ne soit pas plus grand que le plus grand DataId stocké auquel
445 // cas on doit renvoyer une expection car on n'est plus connecté et on ne pourra jamais
446 // fournir de données pour ce dataId.
448 std::cout << "-------- CalciumCouplingPolicy::DisconnectProcessor MARK4 " << expectedDataId <<" --------" << std::endl;
452 iterator it1 = storedDatas.lower_bound(expectedDataId);
454 std::cout << "-------- CalciumCouplingPolicy::DisconnectProcessor MARK5 " << std::endl;
455 for (iterator it=storedDatas.begin();it!=storedDatas.end();++it)
456 std::cout <<" "<<(*it).first ;
457 std::cout <<std::endl;
460 // TODO : Il faut en fait renvoyer le plus proche cf IT ou DT
461 if (it1 == storedDatas.end())
462 throw(CalciumException(CalciumTypes::CPNTNULL,LOC(OSS()<< "La directive CP_CONT"
463 << " est active mais le dataId demandé est inférieur ou égal au dernier reçu.")));
466 std::cout << "-------- CalciumCouplingPolicy::DisconnectProcessor MARK6 " << std::endl;
469 wDataIt1 = storedDatas.end();
472 std::cout << "-------- CalciumCouplingPolicy::DisconnectProcessor, CP_CONT : " << (*wDataIt1).first << std::endl;