Optimisation du temps de calcul sur 3 boucles imbriquées
Bonjour,
J'ai récemment découvert VBA et je commence à peu près à me débrouiller mais je suis loin d'être une experte.
Je suis actuellement en train de coder un VPP (sorte de code qui me permet d'obtenir la vitesse d'un bateau) et j'ai donc besoin de trouver l'équilibre entre 3 équations à 3 variables. J'ai donc 3 fonctions Fn1, Fn2, et Fn3 qui dépendent de 3 variables V_var, lambda_var et phi_var. Pour que mes équations puissent converger, j'ai besoin d'une time step d'environ 1000, ce qui équivaut à plus 2 millions d'itérations. Le code tourne donc pendant plus de 30h. Est-ce que vous auriez des astuces pour diminuer ce temps ? J'ai regardé sur d'autres forums et ai déjà amélioré le temps mais ça reste encore beaucoup trop long...
Voici la plus grosse partie du code qui cherche la solution. Fn1, Fn2 et Fn3 sont calculés dans d'autres fonctions, qui sont elles même calculées avec d'autres fonctions. (La physique derrière est assez compliquée et les équations n'en finissent plus)
Sub Used_Grid_Voiles()
'Créer les variables
Dim V_min As Double, V_max As Double, lambda_max As Double, lambda_min As Double, phi_max As Double, phi_min As Double
Dim V_var As Double, lambda_var As Double, phi_var As Double
Dim max_step As Integer
Dim V_best As Double, lambda_best As Double, phi_best As Double
Dim D_fn1_best, D_fn1_var As Double
Dim D_best_A As Double, D_var_A As Double
Dim D_best_B As Double, D_var_B As Double
Dim rho_h As Double, WSA As Double, rho_a As Double, TWS As Double, TWA As Double
Dim S As Double
Dim V_S As Double, leeway As Double, heel As Double
Dim GM As Double, Displ As Double, h As Double
Dim i As Integer, j As Integer
Dim Oa As Double, Pa As Double, Qa As Double, Ra As Double, Sa As Double, Ta As Double, Ua As Double
Dim Ob As Double, Pb As Double, Qb As Double, Rb As Double, Sb As Double, Tb As Double, Ub As Double
Dim CLR As Double, CE As Double, CLR_CE As Double
'Variables du rudder
Dim Tr As Double
Dim Thr As Double
Dim Ar As Double
Dim tcr As Double
Dim taur As Double
Dim delta_b_r As Double
Dim b_r As Double
Dim sweep As Double
Dim deflection As Double
'Variables du keel
Dim T_k As Double
Dim tck As Double
Dim b_k As Double
Dim delta_b_k As Double
Dim Ak As Double
Dim sweep_k As Double
'Variables du skeg
Dim Dc As Double, Ec As Double, Fc As Double, Gc As Double, Hc As Double, Ic As Double
Dim A_sh As Double
Dim coeff1 As Double, coeff2 As Double, coeff3 As Double, coeff4 As Double
'Optimize Code - ne pas changer
Call OptimizeCode_Begin
'Surface des voiles
Worksheets("Voiles").Range("M10").Copy
Worksheets("VPP").Range("F3").PasteSpecial Paste:=xlPasteValues
'Hauteur du système entier
Worksheets("Voiles").Range("E6").Copy
Worksheets("VPP").Range("F6").PasteSpecial Paste:=xlPasteValues
CLR = Worksheets("Résistance").Cells(4, "K").Value
CE = Worksheets("Voiles").Cells(10, "N").Value
CLR_CE = CLR + CE
Worksheets("VPP").Range("D3").Value = CLR_CE
'Initialise le code en commençant par la première valeur de TWS (j va de 11 à 17)
j = 11
'Pour afficher les résultats au bon endroit à la fin du code
Worksheets("Résultats").Activate
Range("C9").Select
Do
TWS = Worksheets("VPP").Range("E" & j).Value
Worksheets("VPP").Range("B11").Value = TWS
TWS = Worksheets("VPP").Cells(11, "B").Value
'Plus elles sont précises, mieux le résultat sera
V_min = Worksheets("VPP").Cells(9, "A").Value
V_max = Worksheets("VPP").Cells(9, "B").Value
phi_min = Worksheets("VPP").Cells(9, "C").Value
phi_max = Worksheets("VPP").Cells(9, "D").Value
lambda_min = Worksheets("VPP").Cells(9, "E").Value
lambda_max = Worksheets("VPP").Cells(9, "F").Value
'Initialise the loop for all the true wind angles
i = 2
Do
TWA = Worksheets("VPP").Range("H" & i).Value
V_var = V_min
lambda_var = lambda_min
phi_var = phi_min
Worksheets("VPP").Range("L" & i).Value = phi_var
Worksheets("VPP").Range("K" & i).Value = V_var
Worksheets("VPP").Range("M" & i).Value = lambda_var
V_S = V_var
leeway = lambda_var
heel = phi_var
'Démarrage de la première loop pour trouver la meilleure vitesse
'max_step multiple de 30
max_step = 30
D_best_A = Abs(fn1_voiles(V_var, lambda_var, phi_var, TWS, TWA)) + Abs(fn2_voiles(V_var, lambda_var, phi_var, TWS, TWA)) + Abs(fn3_voiles(V_var, lambda_var, phi_var, TWS, TWA))
D_best_B = Abs(fn1_voiles(V_var, lambda_var, phi_var, TWS, TWA)) + Abs(fn3_voiles(V_var, lambda_var, phi_var, TWS, TWA))
For V_step = 0 To max_step
V_var = V_min + (V_max - V_min) * V_step / max_step
V_S = V_var
For phi_step = 0 To max_step
phi_var = phi_min + (phi_max - phi_min) * phi_step / max_step
D_var_A = Abs(fn1_voiles(V_var, lambda_var, phi_var, TWS, TWA)) + Abs(fn2_voiles(V_var, lambda_var, phi_var, TWS, TWA)) + Abs(fn3_voiles(V_var, lambda_var, phi_var, TWS, TWA))
V_S = V_var
leeway = lambda_var
heel = phi_var
If D_var_A <= D_best_A Then
D_best_A = D_best_A
phi_best = phi_var
V_best = V_var
End If
Next
D_best_B = Abs(fn1_voiles(V_var, lambda_var, phi_best, TWS, TWA)) + Abs(fn3_voiles(V_var, lambda_var, phi_best, TWS, TWA))
For lambda_step = 0 To max_step
lambda_var = lambda_min + (lambda_max - lambda_min) * lambda_step / max_step
V_S = V_var
leeway = lambda_var
heel = phi_best
D_var_B = Abs(fn1_voiles(V_var, lambda_var, phi_best, TWS, TWA)) + Abs(fn3_voiles(V_var, lambda_var, phi_best, TWS, TWA))
If D_var_B <= D_best_B Then
D_best_B = D_var_B
lambda_best = lambda_var
End If
Next
V_S = V_var
leeway = lambda_best
heel = phi_best
D_var_A = Abs(fn1_voiles(V_var, lambda_best, phi_best, TWS, TWA)) + Abs(fn2_voiles(V_var, lambda_best, phi_best, TWS, TWA)) + Abs(fn3_voiles(V_var, lambda_best, phi_best, TWS, TWA))
If D_var_A <= D_best_A Then
D_best_A = D_var_A
V_best = V_var
End If
Next
Worksheets("VPP").Range("K" & i).Value = V_best
Worksheets("VPP").Range("M" & i).Value = lambda_best
Worksheets("VPP").Range("L" & i).Value = phi_best
'Les résultats sont transferrés dans le tableur
Sheets("Résultats").Select
Selection.Value = V_best
Selection.Offset(1, 0).Select
i = i + 1
'Fin de la loop pour tous les angles de vent réel
'Loop from 2 to 12
Loop Until i = 3
Sheets("Résultats").Select
Selection.Offset(-10, 1).Select
j = j + 1
'Fin de la loop pour toutes les vitesses du vent réel
'Loop from 12 to 17
Loop Until j = 13
Worksheets("Voiles").Range("U2:U11").Copy
Worksheets("VPP").Range("N2:N11").PasteSpecial Paste:=xlPasteValues
Worksheets("Voiles").Range("V2:V11").Copy
Worksheets("VPP").Range("O2:O11").PasteSpecial Paste:=xlPasteValues
Sheets("Polar").Select
'Optimize Code - ne pas changer
Call OptimizeCode_End
End SubJe ne sais pas si j'ai été assez claire sur le sujet ou si c'est suffisant pour bien comprendre. N'hésitez pas à me demander si vous avez besoin de plus d'informations pour pouvoir m'aider.
Toute aide est la bienvenue!
Merci beaucoup et bonne journée.
Bonjour,
essaie d'éviter au maximum les interactions avec les feuilles excel.
pour le reste, ce serait bien que tu nous mettes ton fichier avec les macros, fonctions et les paramètres pour faire un calcul.
d'autre part, il semble qu'il s'agisse d'un système de 3 equations à 3 inconnues, il devrait donc être possible de trouver une solution algébrique plutôt qu'une solution empirique.
Bonjour,
Merci pour votre réponse. J'ai essayé de les éviter au maximum en créant toutes mes équations comme des fonctions sur VBA.
Je joins le fichier entier excel, le bout de code que j'avais montré avant vient de l'onglet "Used_Grid_Voiles" dans VBA.
En espérant que vous pourrez y voir un peu plus clair.
Bonjour,
dans tes fonctions, tu recharges à chaque appel ces différentes variables sur base du contenu de cellules, Ceci prend beaucoup de temps.
exemple dans induced_res
Const Pi As Double = 3.14159265358979
rho_h = Worksheets("VPP").Range("B6").Value
A_sh = Worksheets("Appendices").Range("C29").Value
A_k = Worksheets("Appendices").Range("B4").Value
A_r = Worksheets("Appendices").Range("B7").Value
Dc = Worksheets("Appendices").Range("D35").Value
Ec = Worksheets("Appendices").Range("E35").Value
Fc = Worksheets("Appendices").Range("F35").Value
Gc = Worksheets("Appendices").Range("G35").Value
Hc = Worksheets("Appendices").Range("H35").Value
Ic = Worksheets("Appendices").Range("I35").Value
b_sh = Worksheets("Appendices").Range("C31").Value
Ash = Worksheets("Appendices").Range("C29").Value
coeff1 = Worksheets("Appendices").Range("I4").Value
coeff2 = Worksheets("Appendices").Range("H4").Value
Ak = Worksheets("Appendices").Range("B4").Value
b_k = Worksheets("Appendices").Range("E4").Value
delta_b_k = Worksheets("Appendices").Range("D4").Value
T_k = Worksheets("Appendices").Range("G4").Value
tck = Worksheets("Appendices").Range("F4").Value
sweep_k = Worksheets("Appendices").Range("C4").Value
Tr = Worksheets("Appendices").Range("I7").Value
Thr = Worksheets("Appendices").Range("H7").Value
Ar = Worksheets("Appendices").Range("B7").Value
deflection = Worksheets("Appendices").Range("G7").Value
tcr = Worksheets("Appendices").Range("F7").Value
taur = Worksheets("Appendices").Range("J7").Value
delta_b_r = Worksheets("Appendices").Range("D7").Value
b_r = Worksheets("Appendices").Range("E7").Value
sweep_r = Worksheets("Appendices").Range("C7").Valuece que tu devrais faire.
1) définir toutes ces variables en global et en dehors d'une sub (les sortir de la sub used_grid_voiles)
2) les initialiser au début de ta macro, Ces valeurs m'ont l'air d'être constantes pour toute la durée de la macro.
3) supprimer toutes les lignes ci-dessus dans la fonction, pour ne plus garder que la formule
Ceci demande un effort de réécriture important que je n'ai pas le temps de faire.
ceci devrait déjà montrer une nette amélioration (pour induced_res si tu fais ça tu gagnes un facteur 23), performances que tu peux encore améliorer de +/- 15% si tu évites de refaire plusieurs fois le même calcul. exemple tu peux calculer une seule fois pi180=pi/180 et utiliser pi180 dans tes formules. tu peux calculer une seule fois chp=cos(heel*pi/180) et utiliser chp dans tes formules. par exemple :
chp = Cos(heel * pi180)
vinduced_res = (((2 / (rho_h * (V_S / 1.944) ^ 2)) * (((((Dc * V_S ^ 5 + Ec * V_S ^ 4 + Fc * V_S ^ 3 + Gc * V_S ^ 2 + Hc * V_S + Ic) * _
0.5 * rho_h * (V_S / 1.944) ^ 2 * A_sh * _
(leeway * pi180) * chp)) ^ 2 / (Pi * A_sh * chp * _
(((2 * b_sh ^ 2) * chp) / Ash))) + ((((0.5 * rho_h * (V_S / 1.944) * (((2 * Pi * (1 + 0.82 * tck - (((2.24 - 5.42 * T_k + 12.3 * T_k ^ 2) / (10 * (1 - 0.878 * T_k)) * tck)) * _
(0.117 / tck + 3.2 * tck + 3.9 * tck ^ 2)) * (((2 * b_k ^ 2) / Ak) * chp)) / (2 * (1 + 0.82 * tck - (((2.24 - 5.42 * _
T_k + 12.3 * T_k ^ 2) / (10 * (1 - 0.878 * T_k)) * tck)) * (0.117 / tck + 3.2 * tck + 3.9 * tck ^ 2)) + Cos(sweep_k * pi180) * _
Sqr(((((2 * b_k ^ 2) / Ak) * chp) ^ 2 / (Cos(sweep_k * pi180)) ^ 4) + 4))) * coeff1 + ((1 + delta_b_k / b_k) ^ 2 * _
((2 * Pi * (1 + 0.82 * tck - (((2.24 - 5.42 * T_k + 12.3 * T_k ^ 2) / (10 * (1 - 0.878 * T_k)) * tck)) * _
(0.117 / tck + 3.2 * tck + 3.9 * tck ^ 2)) * (((2 * b_k ^ 2) / Ak) * chp)) / (2 * (1 + 0.82 * tck - (((2.24 - 5.42 * _
T_k + 12.3 * T_k ^ 2) / (10 * (1 - 0.878 * T_k)) * tck)) * (0.117 / tck + 3.2 * tck + 3.9 * tck ^ 2)) + Cos(sweep_k * pi180) * _
Sqr(((((2 * b_k ^ 2) / Ak) * chp) ^ 2 / (Cos(sweep_k * pi180)) ^ 4) + 4)))) * coeff2) * (leeway * pi180) * _
Ak * chp))) ^ 2 / (Pi * A_k * chp * _
(((2 * b_k ^ 2) / Ak) * chp))) + (((0.5 * rho_h * (0.8 * V_S / 1.944) ^ 2 * ((2 * Pi * (1 + 0.82 * tcr - Tan(taur * pi180) * (0.117 / tcr + 3.2 * tcr + _
3.9 * tcr ^ 2)) * ((2 * (Tr - Thr) ^ 2 * chp) / Ar) * (1 + delta_b_r / b_r) ^ 2) / _
(2 * (1 + 0.82 * tcr - Tan(taur * pi180) * (0.117 / tcr + 3.2 * tcr + 3.9 * tcr ^ 2)) + Cos(sweep_r * pi180) * _
Sqr((((2 * (Tr - Thr) ^ 2 * chp) / Ar) ^ 2 / (Cos(sweep_r * pi180)) ^ 4) + 4))) * ((leeway + deflection) * pi180) _
* (1 + Thr / Tr) ^ 2 * Ar * chp)) ^ 2 / (0.8 ^ 2 * Pi * A_r * chp _
* ((2 * (Tr - Thr) ^ 2 * chp) / Ar))))))Merci beaucoup pour cette réponse, je m'y mets de suite!
La raison pour laquelle j'attribuais la valeur de la variable directement dans la fonction est que ça ne marche qu'une fois sur deux.
Je m'explique : Si je définis la valeur dans une sub et appelle ma fonction, une fois sur deux je vais recevoir un message d'erreur "dépassement de capacité". Donc je la remets dans ma fonction, fais tourner la sub et ça marche et je la renlève, fais tourner la sub et ça marche à nouveau. Ca a l'air très aléatoire et je ne comprends pas pourquoi. Si jamais vous avez des conseils en plus !
bonjour,
Si je définis la valeur dans une sub et appelle ma fonction, une fois sur deux je vais recevoir un message d'erreur "dépassement de capacité".
si tu rencontres encore ce problème, mets le classeur, on pourra investiguer.
Je pense avoir résolu mon problème.
Merci encore pour tout. Je vais voir combien de temps je gagne maintenant !