Calculettes pour l'hydraulique
newton.class.php
Aller à la documentation de ce fichier.
1 <?php
2 /**
3  * @file inc_hyd/newton.class.php
4  * Classe abstraite de résolution d'une équation par la méthode de Newton
5  */
6 
7 /* Copyright 2009-2012 David Dorchies <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 abstract class acNewton {
27 
28  const DBG = false; /// Debuggage
29 
30  protected $rTol;
31  protected $rDx;
32  private $iCpt; /// n° itération Newton
33  private $iCptMax=50; /// nb max itérations
34  private $rRelax=1; /// Coefficient de relaxation
35  private $rFnPrec=0; /// Mémorisation du Fn précédent pour détecter le changement de signe
36  private $iOscil=0; /// Nombre de changement de signe de Delta
37  private $oLog;
38 
39 
40  /**
41  * Constructeur de la classe
42  * @param $oSn Section sur laquelle on fait le calcul
43  * @param $oP Paramètres supplémentaires (Débit, précision...)
44  */
45  function __construct(cParam $oP) {
46  $this->rTol = $oP->rPrec;
47  $this->rDx = $oP->rPrec / 10;
48  $this->iCpt = 0;
49  }
50 
51 
52  /**
53  * Calcul de la fonction f(x) dont on cherche le zéro.
54  * @param $rX x
55  * @return Calcul de la fonction
56  */
57  abstract protected function CalcFn($rX);
58 
59  /**
60  * Calcul de la dérivée f'(x) (peut être redéfini pour calcul analytique)
61  * @param $rX x
62  * @return Calcul de la fonction
63  */
64  protected function CalcDer($x) {
65  //~ spip_log('Newton:CalcDer $rX='.$x,'hydraulic.'._LOG_DEBUG);
66  return ($this->CalcFn($x+$this->rDx)-$this->CalcFn($x-$this->rDx))/(2*$this->rDx);
67  }
68 
69  /**
70  * Test d'égalité à une tolérance près
71  * @param $rFn x
72  * @return True si égal, False sinon
73  */
74  private function FuzzyEqual($rFn) {
75  return (abs($rFn) < $this->rTol);
76  }
77 
78  /**
79  * Fonction récursive de calcul de la suite du Newton
80  * @param $rX x
81  * @return Solution du zéro de la fonction
82  */
83  public function Newton($rX) {
84  $this->iCpt++;
85  $rFn=$this->CalcFn($rX);
86  if(self::DBG) spip_log('Newton '.$this->iCpt.' Relax='.$this->rRelax.'- f('.$rX.') = '.$rFn,'hydraulic.'._LOG_DEBUG);
87  if($this->FuzzyEqual($rFn) || $this->iCpt >= $this->iCptMax) {
88  return $rX;
89  }
90  else {
91  $rDer=$this->CalcDer($rX);
92  //~ echo(' - f\' = '.$rDer);
93  if($rDer!=0) {
94  if($rFn < 0 xor $this->rFnPrec < 0) {
95  $this->nOscil++;
96  if($this->rRelax > 1) {
97  // Sur une forte relaxation, au changement de signe on réinitialise
98  $this->rRelax = 1;
99  }
100  elseif($this->nOscil>2) {
101  // On est dans le cas d'une oscillation autour de la solution
102  // On réduit le coefficient de relaxation
103  $this->rRelax *= 0.5;
104  }
105  }
106  $this->rFnPrec = $rFn;
107  $Delta = $rFn / $rDer;
108  while(abs($Delta*$this->rRelax) < $this->rTol && $rFn > 10*$this->rTol && $this->rRelax < 2^8) {
109  // On augmente le coefficicient de relaxation s'il est trop petit
110  $this->rRelax *= 2;
111  }
113  while($rX - $Delta*$rRelax <= 0 && $rRelax > 1E-4) {
114  // On diminue le coeficient de relaxation si on passe en négatif
115  $rRelax *= 0.5; // Mais on ne le mémorise pas pour les itérations suivantes
116  }
117  $rX = $rX - $Delta*$rRelax;
118  $this->rDelta = $Delta;
119  if($rX<0) {$rX = $this->rTol;} // Aucune valeur recherchée ne peut être négative ou nulle
120  return $this->Newton($rX);
121  }
122  else {
123  // Echec de la résolution
124  return false;
125  }
126  }
127  }
128 
129  /**
130  * Pour savoir si le Newton a convergé
131  * @return true si oui, false sinon
132  */ public function HasConverged() {
133  if($this->iCpt >= $this->iCptMax) {
134  return false;
135  }
136  else {
137  return true;
138  }
139  }
140 }
141 
142 ?>
CalcFn($rX)
Calcul de la fonction f(x) dont on cherche le zéro.
CalcDer($x)
Calcul de la dérivée f&#39;(x) (peut être redéfini pour calcul analytique)
$rTol
Debuggage.
const DBG
FuzzyEqual($rFn)
Test d&#39;égalité à une tolérance près.
HasConverged()
Pour savoir si le Newton a convergé
__construct(cParam $oP)
Constructeur de la classe.
$rFnPrec
Coefficient de relaxation.
$iCptMax
n° itération Newton
$oLog
Nombre de changement de signe de Delta.
Newton($rX)
Fonction récursive de calcul de la suite du Newton.
$rRelax
nb max itérations
Gestion des Paramètres du canal (hors section)
$iOscil
Mémorisation du Fn précédent pour détecter le changement de signe.