Calculettes pour l'hydraulique
dichotomie.class.php
Aller à la documentation de ce fichier.
1 <?php
2 /**
3  * @file ouvrage.class.php
4  * Gestion des calculs au niveau des Ouvrages en travers
5  */
6 
7 /* Copyright 2009-2012 Dorch <dorch@dorch.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22  * MA 02110-1301, USA.
23  */
24 
25 
26 /**
27  * Dichotomie
28  */
29 class cDichotomie {
30 
31  const DBG = false; /// Pour loguer les messages de debug de cette classe
32 
33  private $oLog; ///< Journal de calcul
34 
35  //~ const IDEFINT = 100; /// Pas de parcours de l'intervalle pour initialisation dichotomie
36  //~ const IDICMAX = 100; /// Itérations maximum de la dichotomie
37  // ***** DEBUG *****
38  const IDEFINT = 10; /// Pas de parcours de l'intervalle pour initialisation dichotomie
39  const IDICMAX = 20; /// Itérations maximum de la dichotomie
40  // ***** FIN DEBUG *****
41 
42  private $objet; ///< Objet contenant la méthode de calcul du débit
43  private $sFnCalculQ; /// Nom de la méthode de calcul du débit
44  private $bLogError; /// true pour afficher les messages d'erreur en cas de non convergence
45 
46  /**
47  * Construction de la classe.
48  * @param $oLog Journal de calcul
49  * @param $objet Objet contenant la méthode de calcul du débit et la
50  * propriété VarCal pointeur vers la variable à calculer
51  * @param $sFnCalculQ Nom de la méthode de calcul du débit
52  */
53  public function __construct(&$oLog,&$objet,$sFnCalculQ, $bLogError=true) {
54  $this->oLog = &$oLog;
55  $this->objet = &$objet;
56  $this->sFnCalculQ = $sFnCalculQ;
57  $this->bLogError = $bLogError;
58  }
59 
60  private function CalculQ() {
62  $res = $this->objet->$sFnCalculQ();
63  if(!is_array($res)) {
64  $res = array($res,0);
65  }
66  if(self::DBG) spip_log('CalculQ('.$this->objet->VarCal.')='.$res[0],'hydraulic',_LOG_DEBUG);
67  return $res;
68  }
69 
70  /**
71  * Calcul à l'ouvrage
72  * @param $sCalc Variable à calculer (Nom de la propriété de l'objet)
73  * @param $QT Débit cible
74  * @param $rTol Précision attendue
75  * @param $rInit Valeur initiale
76  */
77  public function calculer($QT,$rTol,$rInit=0.) {
78  if(self::DBG) spip_log("Dichotomie->calculer($QT,$rTol,$rInit)",'hydraulic.'._LOG_DEBUG);
79  $this->objet->VarCal = $rInit;
80  list($Q,$nFlag) = $this->CalculQ();
81  $XminInit = 1E-8;
82  $this->objet->VarCal = $XminInit;
83  list($Q1,$nFlag) = $this->CalculQ();
84  if($Q1 < $Q xor $Q > $QT) $Q1 = $Q;
85  $XmaxInit = max(1,$rInit)*100;
86  $this->objet->VarCal = $XmaxInit;
87  list($Q2,$nFlag) = $this->CalculQ();
88  if($QT < $Q xor $Q > $Q2) $Q1 = $Q;
89  $DX = ($XmaxInit - $XminInit) / floatval(self::IDEFINT);
90  $nIterMax = floor(max($XmaxInit - $rInit,$rInit - $XminInit) / $DX + 1);
91  if(self::DBG) spip_log("QT=$QT nIterMax=$nIterMax XminInit=$XminInit XmaxInit=$XmaxInit DX=$DX",'hydraulic',_LOG_DEBUG);
92  $Xmin = $rInit;
93  $Xmax = $rInit;
94  $X1 = $rInit;
95  $X2 = $rInit;
96  $this->objet->VarCal = $rInit;
97  list($Q,$nFlag) = $this->CalculQ();
98  $Q1 = $Q;
99  $Q2 = $Q;
100  ///< @todo : Chercher en dehors de l'intervalle en le décalant à droite ou à gauche en fonction de la valeur
101 
102  for($nIter=1;$nIter<=$nIterMax;$nIter++) {
103  //Ouverture de l'intervalle des deux côtés : à droite puis à gauche
104  $Xmax = $Xmax + $DX;
105  if($Xmax > $XmaxInit xor $DX <= 0) $Xmax = $XmaxInit;
106  $this->objet->VarCal = $Xmax;
107  list($Q,$nFlag) = $this->CalculQ();
108  if($Q1 < $Q2 xor $Q <= $Q2) {
109  $Q2 = $Q;
110  $X2 = $Xmax;
111  }
112  if($Q1 < $Q2 xor $Q >= $Q1) {
113  $Q1 = $Q;
114  $X1 = $Xmax;
115  }
116  $Xmin = $Xmin - $DX;
117  if($Xmin < $XminInit xor $DX <= 0) {
118  $Xmin = $XminInit;
119  }
120  $this->objet->VarCal = $Xmin;
121  list($Q,$nFlag) = $this->CalculQ();
122  if($Q1 < $Q2 xor $Q <= $Q2) {
123  $Q2 = $Q;
124  $X2 = $Xmin;
125  }
126  if($Q1 < $Q2 xor $Q >= $Q1) {
127  $Q1 = $Q;
128  $X1 = $Xmin;
129  }
130 
131  if(self::DBG) spip_log("nIter=$nIter Xmin=$Xmin Xmax=$Xmax",'hydraulic',_LOG_DEBUG);
132  if(self::DBG) spip_log("X1=$X1 Q1=$Q1 X2=$X2 Q2=$Q2",'hydraulic',_LOG_DEBUG);
133  if(self::DBG) spip_log('$QT > $Q1 xor $QT >= $Q2 = '.($QT > $Q1 xor $QT >= $Q2),'hydraulic',_LOG_DEBUG);
134 
135  if($QT > $Q1 xor $QT >= $Q2) {break;}
136  }
137 
138  if($nIter >= self::IDEFINT) {
139  // Pas d'intervalle trouvé avec au moins une solution
140  if($Q2 < $QT and $Q1 < $QT) {
141  // Cote de l'eau trop basse pour passer le débit il faut ouvrir un autre ouvrage
142  $this->objet->VarCal = $XmaxInit;
143  }
144  else {
145  // Cote de l'eau trop grande il faut fermer l'ouvrage
146  $this->objet->VarCal = $XminInit;
147  }
148  list($Q,$nFlag) = $this->CalculQ();
149  $nFlag = -1;
150  if($this->bLogError) {
151  $sLog = ($Q1<$Q2)?"Q($X1)=$Q1 &lt; Q($X2)=$Q2":"Q($X2)=$Q2 &lt; Q($X1)=$Q1";
152  $sLog = ($QT<$Q1)?"$QT &lt; $sLog":"$sLog &lt; $QT";
153  $this->oLog->Add(_T('hydraulic:dichotomie_intervalle').' : '.
154  $sLog,true);
155  }
156  }
157  else {
158  // Dichotomie
159  $X = $rInit;
160  $nFlag = 0;
161  for($nIter = 1; $nIter<=self::IDICMAX;$nIter++) {
162  $this->objet->VarCal=$X;
163  if(self::DBG) spip_log("nIter=$nIter nFlag=$nFlag".' rVarC='.$this->objet->VarCal,'hydraulic',_LOG_DEBUG);
164  list($Q,$nFlag) = $this->CalculQ();
165  //~ if($QT!=0 && abs($Q/$QT-1.) <= $rTol) {break;}
166  if($QT!=0 && abs($X1-$X2) <= $rTol) {break;}
167  if($QT < $Q xor $Q1 <= $Q2) {
168  // QT < IQ et Q(X1) > Q(X2) ou pareil en inversant les inégalités
169  $X1=$this->objet->VarCal;
170  }
171  else {
172  // QT < IQ et Q(X1) < Q(X2) ou pareil en inversant les inégalités
173  $X2=$this->objet->VarCal;
174  }
175  $X=($X2+$X1)*0.5;
176  }
177  if($nIter == self::IDICMAX) {
178  $this->oLog->Add(
179  _T('hydraulic:dichotomie_non_convergence').' '.format_nombre($Q, $this->data['iPrec']),
180  true);
181  $nFlag = -1;
182  }
183  }
184  if(self::DBG) spip_log('rVarC='.$this->objet->VarCal." nFlag=$nFlag",'hydraulic.'._LOG_DEBUG);
185  return array($this->objet->VarCal,$nFlag);
186  }
187 
188 }
189 
190 ?>
calculer($QT, $rTol, $rInit=0.)
Calcul à l&#39;ouvrage.
$oLog
Pour loguer les messages de debug de cette classe.
Dichotomie.
$bLogError
Nom de la méthode de calcul du débit.
__construct(&$oLog, &$objet, $sFnCalculQ, $bLogError=true)
true pour afficher les messages d&#39;erreur en cas de non convergence
$objet
Itérations maximum de la dichotomie.
format_nombre($nombre, $dec)
Definition: cache.php:55
const IDICMAX
Pas de parcours de l&#39;intervalle pour initialisation dichotomie.