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 Sub

Je 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.

8vpp-6.xlsm (181.40 Ko)

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").Value

ce 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 !

Rechercher des sujets similaires à "optimisation temps calcul boucles imbriquees"