diffenix 0.0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- diffenix/Constantes.py +761 -0
- diffenix/__init__.py +26 -0
- diffenix/chemains.py +110 -0
- diffenix/classes.py +0 -0
- diffenix/generation_configs.py +146 -0
- diffenix/m/303/251thodes_num/303/251riques.py +332 -0
- diffenix/numericals_methods.py +230 -0
- diffenix/solve_asteroid_belt.py +1510 -0
- diffenix/systems.py +7309 -0
- diffenix/time_integration.py +265 -0
- diffenix-0.0.0.1.dist-info/METADATA +7 -0
- diffenix-0.0.0.1.dist-info/RECORD +14 -0
- diffenix-0.0.0.1.dist-info/WHEEL +5 -0
- diffenix-0.0.0.1.dist-info/top_level.txt +1 -0
diffenix/__init__.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import numpy as np
|
|
3
|
+
import sys
|
|
4
|
+
import os
|
|
5
|
+
from diffenix.Constantes import *
|
|
6
|
+
|
|
7
|
+
if __name__ == '__main__':
|
|
8
|
+
|
|
9
|
+
from diffenix.time_integration import time_integration, restart
|
|
10
|
+
if len(sys.argv) > 1:
|
|
11
|
+
import os
|
|
12
|
+
if sys.argv[1] == "configs":
|
|
13
|
+
l = os.listdir("./configs")
|
|
14
|
+
l.sort()
|
|
15
|
+
if int(sys.argv[2]) < len(l):
|
|
16
|
+
params = dict(np.load("./configs/" + l[int(sys.argv[2])]))
|
|
17
|
+
print(int(sys.argv[2]), l[int(sys.argv[2])], params["Simulation"])
|
|
18
|
+
if not os.path.exists(results + "/" + params["Simulation"]):
|
|
19
|
+
time_integration(consts_params=params)
|
|
20
|
+
# else:
|
|
21
|
+
# restart(params["Simulation"], rtol=np.double(1e-4))
|
|
22
|
+
else:
|
|
23
|
+
print("argv :", sys.argv[1])
|
|
24
|
+
restart(int(sys.argv[1]), -1)
|
|
25
|
+
else:
|
|
26
|
+
time_integration()
|
diffenix/chemains.py
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
# Defaults values
|
|
5
|
+
|
|
6
|
+
racine: str = "."
|
|
7
|
+
results: str = racine + "/Results"
|
|
8
|
+
data_leiden: str = racine + "/Leiden_database/"
|
|
9
|
+
data_stars: str = racine + "/data_stars/data_fus.npz"
|
|
10
|
+
data_radmc: str = racine + "/data_radmc"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def load_from_files(path_to_file: str = "paths.txt") -> None:
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
Load the path from a txt file
|
|
17
|
+
|
|
18
|
+
Parameters
|
|
19
|
+
----------
|
|
20
|
+
path_to_file : str
|
|
21
|
+
The path to the txt file
|
|
22
|
+
One path per line, the delimiter between the name of path and the path is `,`
|
|
23
|
+
The names are racine, results, data_leiden and data_stars
|
|
24
|
+
|
|
25
|
+
Returns
|
|
26
|
+
-------
|
|
27
|
+
None
|
|
28
|
+
|
|
29
|
+
"""
|
|
30
|
+
if not os.path.exists(path_to_file):
|
|
31
|
+
raise UserWarning("Constante.load_from_files : ", path_to_file, "does not exist")
|
|
32
|
+
global racine, results, data_leiden, data_stars, data_radmc
|
|
33
|
+
|
|
34
|
+
paths = dict(np.loadtxt("paths.txt", dtype=str, delimiter=","))
|
|
35
|
+
print("Paths : ", paths)
|
|
36
|
+
if "racine" in paths.keys():
|
|
37
|
+
if not os.path.exists(paths["racine"]):
|
|
38
|
+
raise UserWarning("Constante.load_from_files : ", paths["racine"], "does not exist")
|
|
39
|
+
if not os.path.isdir(paths["racine"]):
|
|
40
|
+
raise UserWarning("Constante.load_from_files : ", paths["racine"], "is not a directory")
|
|
41
|
+
racine = paths["racine"]
|
|
42
|
+
|
|
43
|
+
if "results" in paths.keys():
|
|
44
|
+
if not os.path.exists(paths["results"]) and not os.path.exists(racine + paths["results"]):
|
|
45
|
+
raise UserWarning("Constante.load_from_files : ", paths["results"], "does not exist")
|
|
46
|
+
if not os.path.isdir(paths["results"]) and not os.path.isdir(racine + paths["results"]):
|
|
47
|
+
raise UserWarning("Constante.load_from_files : ", paths["results"], "is not a directory")
|
|
48
|
+
|
|
49
|
+
if os.path.exists(paths["results"]):
|
|
50
|
+
results = paths["results"]
|
|
51
|
+
else:
|
|
52
|
+
results = racine + paths["results"]
|
|
53
|
+
|
|
54
|
+
if "data_leiden" in paths.keys():
|
|
55
|
+
if not os.path.exists(paths["data_leiden"]) and not os.path.exists(racine + paths["data_leiden"]):
|
|
56
|
+
raise UserWarning("Constante.load_from_files : ", paths["data_leiden"], "does not exist")
|
|
57
|
+
if not os.path.isdir(paths["data_leiden"]) and not os.path.isdir(racine + paths["data_leiden"]):
|
|
58
|
+
raise UserWarning("Constante.load_from_files : ", paths["data_leiden"], "is not a directory")
|
|
59
|
+
|
|
60
|
+
if os.path.exists(paths["data_leiden"]):
|
|
61
|
+
data_leiden = paths["data_leiden"]
|
|
62
|
+
else:
|
|
63
|
+
data_leiden = racine + paths["data_leiden"]
|
|
64
|
+
|
|
65
|
+
if "data_stars" in paths.keys():
|
|
66
|
+
if not os.path.exists(paths["data_stars"]) and not os.path.exists(racine + paths["data_stars"]):
|
|
67
|
+
raise UserWarning("Constante.load_from_files : ", paths["data_stars"], "does not exist")
|
|
68
|
+
|
|
69
|
+
if os.path.exists(paths["data_stars"]):
|
|
70
|
+
data_stars = paths["data_stars"]
|
|
71
|
+
else:
|
|
72
|
+
data_stars = racine + paths["data_stars"]
|
|
73
|
+
|
|
74
|
+
if "data_radmc" in paths.keys():
|
|
75
|
+
# if not os.path.exists(paths["data_radmc"]) and not os.path.exists(racine + paths["data_radmc"]):
|
|
76
|
+
# raise UserWarning("Constante.load_from_files : ", paths["data_radmc"], "does not exist")
|
|
77
|
+
|
|
78
|
+
if os.path.exists(paths["data_radmc"]):
|
|
79
|
+
data_radmc = paths["data_radmc"]
|
|
80
|
+
else:
|
|
81
|
+
data_radmc = racine + paths["data_radmc"]
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
if os.path.exists("./paths.txt"):
|
|
85
|
+
load_from_files("./paths.txt")
|
|
86
|
+
if not os.path.exists(racine):
|
|
87
|
+
raise UserWarning("Constante.load_from_files : ", racine, "does not exist")
|
|
88
|
+
if not os.path.isdir(racine):
|
|
89
|
+
raise UserWarning("Constante.load_from_files : ", racine, "is not a directory")
|
|
90
|
+
|
|
91
|
+
if not os.path.exists(results):
|
|
92
|
+
raise UserWarning("Constante.load_from_files : ", results, "does not exist")
|
|
93
|
+
if not os.path.isdir(results):
|
|
94
|
+
raise UserWarning("Constante.load_from_files : ", results, "is not a directory")
|
|
95
|
+
|
|
96
|
+
if not os.path.exists(data_stars):
|
|
97
|
+
print("User warning : no data to model the central star as been found. A constant luminosity will be assumed.")
|
|
98
|
+
# raise UserWarning("Constante.load_from_files : ", data_stars, "does not exist")
|
|
99
|
+
|
|
100
|
+
if not os.path.exists(data_leiden):
|
|
101
|
+
raise UserWarning("Constante.load_from_files : ", data_leiden, "does not exist")
|
|
102
|
+
if not os.path.isdir(data_leiden):
|
|
103
|
+
raise UserWarning("Constante.load_from_files : ", data_leiden, "is not a directory")
|
|
104
|
+
|
|
105
|
+
# if not os.path.exists(data_radmc):
|
|
106
|
+
# raise UserWarning("Constante.load_from_files : ", data_radmc, "does not exist")
|
|
107
|
+
# if not os.path.isdir(data_radmc):
|
|
108
|
+
# raise UserWarning("Constante.load_from_files : ", data_radmc, "is not a directory")
|
|
109
|
+
else:
|
|
110
|
+
print("No path.txt file has been found. Working directory : ", os.getcwd())
|
diffenix/classes.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import os.path
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
from scipy.optimize import root
|
|
5
|
+
from wx.py.editor import directory
|
|
6
|
+
|
|
7
|
+
from diffenix.Constantes import *
|
|
8
|
+
|
|
9
|
+
dic_ref: dict = {"racine": racine, "results": results,
|
|
10
|
+
"C_L": C_L, "C_M": C_M, "C_t": C_t,
|
|
11
|
+
"Ms": Msun, "Ts": np.double(5500.), "Rs": Rsun, "Ls": Lsun,
|
|
12
|
+
"a_in": .05 * au, "a_out": 10 * a0, "a0": 2.65 * au,
|
|
13
|
+
"T0": T0, "pls_temp": np.double(-1/2), "mH_init": zero,
|
|
14
|
+
"alpha": np.double(1e-3), "gamma": np.double(1.),
|
|
15
|
+
"AB_mdot_st_init": np.double(1e-10) * Mearth / Myr,
|
|
16
|
+
"AB_Mbelt": np.double(0.12) * Mearth,
|
|
17
|
+
"AB_Abelt": np.double(0.06),
|
|
18
|
+
"AB_a0": np.double(2.65) * au, "AB_delta_r": np.double(2.65 / 2.) * au,
|
|
19
|
+
"AB_K": np.double(1e-5 * C_L * C_L / C_t), "AB_Phi": np.double(0.6), "AB_rp": np.double(1e-6 * C_L),
|
|
20
|
+
"AB_f_ice": np.double(0.2), "AB_rho_refr": np.double(2.5e3 * C_M / (C_L * C_L * C_L)) ,
|
|
21
|
+
"AB_rho_ice": np.double(1.e3 * C_M / (C_L * C_L * C_L)), "AB_sublimation_model": "thermal_full",
|
|
22
|
+
"AB_const_mdot": zero,
|
|
23
|
+
"AB_SD_amax": np.double(1.e6) * C_L, "AB_SD_abig": np.double(120e3) * C_L,
|
|
24
|
+
"AB_SD_amed": np.double(20.e3) * C_L, "AB_SD_amin": C_L,
|
|
25
|
+
"AB_SD_qh": np.double(-4.5), "AB_SD_qm": np.double(-1.2), "AB_SD_ql": np.double(-3.6),
|
|
26
|
+
"AB_sb": np.double(316) * C_L, "AB_e": np.double(0.075), "AB_i": np.double(0.075 / 2.),
|
|
27
|
+
"AB_As": np.double(5.) * C_E / C_M , "AB_bs": np.double(-0.1), "AB_bg": np.double(0.5),
|
|
28
|
+
"AB_t0_diss": 150 * Myr, "AB_t1_diss": Myr,
|
|
29
|
+
"KB_mdot_st_init": zero,
|
|
30
|
+
"KB_Mbelt": np.double(0.01 * Mearth), "KB_Abelt": np.double(0.06),
|
|
31
|
+
"KB_a0": np.double(44) * au, "KB_delta_r": np.double(8) * au,
|
|
32
|
+
"KB_K": np.double(1e-10 * C_L * C_L / C_t), "KB_Phi": np.double(0.6), "KB_rp": np.double(1e-6 * C_L),
|
|
33
|
+
"KB_f_ice": np.double(0.2), "KB_rho_refr": np.double(2.5e3 * C_M / (C_L * C_L * C_L)),
|
|
34
|
+
"KB_rho_ice": np.double(1.e3 * C_M / (C_L * C_L * C_L)), "KB_sublimation_model": "none",
|
|
35
|
+
"KB_const_mdot": zero,
|
|
36
|
+
"KB_SD_amax": np.double(1.e6) * C_L, "KB_SD_abig": np.double(120e3) * C_L,
|
|
37
|
+
"KB_SD_amed": np.double(20.e3) * C_L, "KB_SD_amin": C_L,
|
|
38
|
+
"KB_SD_qh": np.double(-4.5), "KB_SD_qm": np.double(-1.2), "KB_SD_ql": np.double(-3.6),
|
|
39
|
+
"KB_sb": np.double(316) * C_L, "KB_e": np.double(0.075), "KB_i": np.double(0.075 / 2.),
|
|
40
|
+
"KB_As": np.double(5.) * C_E / C_M, "KB_bs": np.double(-0.1), "KB_bg": np.double(0.5),
|
|
41
|
+
"KB_t0_diss": np.double(10.) * Gyr, "KB_t1_diss": np.double(10.) * Gyr,
|
|
42
|
+
"a_planets": np.array([au]), "m_planets": np.array([Mearth]), "f_accr": np.double(0.5),
|
|
43
|
+
"t0": np.double(5. * Myr),
|
|
44
|
+
"IT_s": 3000, "dip": 10, "rtol": np.double(1e-6), "atol": np.double(1e-250), "method_root": 'RK45',
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def temp_ppd(r: np.ndarray[np.float64] | np.float64,
|
|
49
|
+
consts: dict, mdot: np.float64 = zero
|
|
50
|
+
) -> np.float64 | np.ndarray[np.float64]:
|
|
51
|
+
"""
|
|
52
|
+
The temperature of the protoplanetary disc
|
|
53
|
+
Parameters
|
|
54
|
+
----------
|
|
55
|
+
r : np.float64 | np.ndarray[np.float64]
|
|
56
|
+
The distance to the central star
|
|
57
|
+
consts : dict
|
|
58
|
+
All the constants needed
|
|
59
|
+
mdot : np.float, optional, default=0
|
|
60
|
+
The accretion rate on the central star
|
|
61
|
+
|
|
62
|
+
Returns
|
|
63
|
+
-------
|
|
64
|
+
np.float64 | np.ndarray[np.float64]
|
|
65
|
+
The temperature of the protoplanetary disc at the dissipation time
|
|
66
|
+
|
|
67
|
+
"""
|
|
68
|
+
C: np.float64 = 5 # Ratio between h the heigh at wich the disc became optically thick and Hz the typical scale-heigh
|
|
69
|
+
# asssumed to be a constant
|
|
70
|
+
# primordial disc protertys
|
|
71
|
+
M0 = 0.01 * Msun # total disc mass
|
|
72
|
+
r0 = 10 * au # reference radius
|
|
73
|
+
rout = 200 * au # outer radius
|
|
74
|
+
rin = 0. #inner radius
|
|
75
|
+
kappa_r = C_L * C_L / C_M # Rosseland opacity
|
|
76
|
+
sigma0 = M0 / (2. * Pi * au * (r0 - rin + 2 * np.sqrt(au) * (np.sqrt(rout) - np.sqrt(r0))))
|
|
77
|
+
tau = np.zeros_like(r)
|
|
78
|
+
if isinstance(r, np.ndarray):
|
|
79
|
+
tau[r < r0] = kappa_r * sigma0 * (au / r[r < r0])
|
|
80
|
+
tau[r >= r0] = kappa_r * sigma0 * ((r[r >= r0] / au) ** (-3 / 2))
|
|
81
|
+
elif r < r0:
|
|
82
|
+
tau[r < r0] = kappa_r * sigma0 * (au / r)
|
|
83
|
+
else:
|
|
84
|
+
tau[r < r0] = kappa_r * sigma0 * ((r / au) ** (-3 / 2))
|
|
85
|
+
|
|
86
|
+
return ((0.2 * interpRs(consts["t0"], consts["Ms"]) / r
|
|
87
|
+
+ (C / 7) * ((Rgp * consts["Rs"] / (G * consts["Ms"] * 2.33 * 1e-3 * C_M)) ** (4 / 7))
|
|
88
|
+
* ((interpLbol(consts["t0"], consts["Ms"]) / (4. * Pi * sigma * interpRs(consts["t0"], consts["Ms"])
|
|
89
|
+
- interpRs(consts["t0"], consts["Ms"]))) ** (1 / 7))
|
|
90
|
+
* (r / interpRs(consts["t0"], consts["Ms"])) ** (2 / 7))
|
|
91
|
+
* (interpLbol(consts["t0"], consts["Ms"]) / (4. * Pi * sigma * r * r))
|
|
92
|
+
+ ((3 / 4) * (tau + 2 / 3))
|
|
93
|
+
* 3 * G * consts["Ms"] * mdot * (1. - np.sqrt(interpRs(consts["t0"], consts["Ms"]) / r))
|
|
94
|
+
/ (8. * Pi * sigma * r * r * r)) ** (1 / 4)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def ice_line(consts: dict, mdot: np.float64 = zero) -> np.float64:
|
|
98
|
+
"""
|
|
99
|
+
Return the lacation of the iceline when the protoplanetary disc dissipate
|
|
100
|
+
|
|
101
|
+
Parameters
|
|
102
|
+
----------
|
|
103
|
+
consts : dict
|
|
104
|
+
All the constants needed
|
|
105
|
+
mdot : np.float, optional, default=0
|
|
106
|
+
The accretion rate on the central star
|
|
107
|
+
|
|
108
|
+
Returns
|
|
109
|
+
-------
|
|
110
|
+
np.float64
|
|
111
|
+
the ice-line location
|
|
112
|
+
"""
|
|
113
|
+
def null(r: np.float64 | np.ndarray[np.float64]) -> np.ndarray[np.float64] | np.float64:
|
|
114
|
+
return temp_ppd(r, consts=consts, mdot=mdot) - 170
|
|
115
|
+
return root(null, x0 = au).x
|
|
116
|
+
|
|
117
|
+
directory: str = "./configs"
|
|
118
|
+
|
|
119
|
+
if not os.path.exists(directory):
|
|
120
|
+
os.mkdir(directory)
|
|
121
|
+
mstars = np.linspace(wfus["M"].min(), wfus["M"].max(), 5) * Msun
|
|
122
|
+
mds = [0.1 * Mearth, 1e-3 * Mearth]
|
|
123
|
+
tinits = [Myr, np.double(5.) * Myr]
|
|
124
|
+
alphas = [1e-3, 1e-1]
|
|
125
|
+
|
|
126
|
+
for im in range(len(mstars)):
|
|
127
|
+
for imd in range(len(mds)):
|
|
128
|
+
for it in range(len(tinits)):
|
|
129
|
+
consts_ms = dic_ref.copy()
|
|
130
|
+
consts_ms["Ms"] = mstars[im]
|
|
131
|
+
consts_ms["t0"] = tinits[it]
|
|
132
|
+
a0: np.float64 = ice_line(consts_ms, 1e-10 * Msun / yr)
|
|
133
|
+
a0s = [0.7 * a0, a0, 1.3 * a0]
|
|
134
|
+
for ialpha in range(len(alphas)):
|
|
135
|
+
for ia0 in range(len(a0s)):
|
|
136
|
+
consts_msi = consts_ms.copy()
|
|
137
|
+
consts_msi["AB_Mbelt"] = mds[imd]
|
|
138
|
+
consts_msi["alpha"] = alphas[ialpha]
|
|
139
|
+
consts_msi["a0"] = a0s[ia0]
|
|
140
|
+
consts_msi["a_planets"] = 0.7 * a0s[ia0] * np.double(1 - 0.5)
|
|
141
|
+
consts_msi["a_out"] = np.double(100.) * a0s[ia0]
|
|
142
|
+
consts_msi["AB_a0"] = a0s[ia0]
|
|
143
|
+
consts_msi["AB_delta_r"] = a0s[ia0] * np.double(0.5)
|
|
144
|
+
consts_msi["Simulation"] = "Simulation_" + str(im + 1) + str(imd + 1) + str(it + 1) + str(ialpha + 1) + str(ia0 + 1)
|
|
145
|
+
print(consts_msi["Simulation"])
|
|
146
|
+
np.savez_compressed(directory + "/" + consts_msi["Simulation"], **consts_msi)
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import numpy as np
|
|
3
|
+
from numpy.linalg import LinAlgError
|
|
4
|
+
from scipy.integrate import solve_ivp
|
|
5
|
+
from scipy.linalg import solve, LinAlgWarning
|
|
6
|
+
from scipy.optimize import approx_fprime
|
|
7
|
+
from scipy.optimize import root
|
|
8
|
+
import phenigraph as g
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def gradient_weno5(y: np.ndarray, dx: np.float64 = 1.0, axis: int = -1) -> np.ndarray:
|
|
12
|
+
"""
|
|
13
|
+
Compute the spatial derivative of y following the WENO discretization scheme, robust to discontinuity,
|
|
14
|
+
along a specified axis.
|
|
15
|
+
|
|
16
|
+
Parameters
|
|
17
|
+
----------
|
|
18
|
+
y : np.ndarray
|
|
19
|
+
The array to be derived
|
|
20
|
+
dx : np.float64, optional, default: 1.0
|
|
21
|
+
The space step, the space domain should be evenly spaced with dx
|
|
22
|
+
axis : int, optional, default: -1
|
|
23
|
+
The axis along which to compute the derivative
|
|
24
|
+
|
|
25
|
+
Returns
|
|
26
|
+
-------
|
|
27
|
+
np.ndarray
|
|
28
|
+
The order 1 spatial derivative of y at each point along the specified axis
|
|
29
|
+
"""
|
|
30
|
+
eps: np.float64 = np.double(1e-200)
|
|
31
|
+
|
|
32
|
+
# Move the specified axis to the last position for easier manipulation
|
|
33
|
+
y = np.moveaxis(y, axis, -1)
|
|
34
|
+
|
|
35
|
+
# Initialize arrays for alpha0, alpha1, alpha2
|
|
36
|
+
alpha0 = ((13. / 12.) * (y[..., :-4] - 2. * y[..., 1:-3] + y[..., 2:-2]) ** 2
|
|
37
|
+
+ (1. / 4.) * (y[..., :-4] - 4. * y[..., 1:-3] + 3. * y[..., 2:-2]) ** 2)
|
|
38
|
+
alpha1 = ((13. / 12.) * (y[..., 2:-2] - 2. * y[..., 3:-1] + y[..., 4:]) ** 2
|
|
39
|
+
+ (1. / 4.) * (y[..., 2:-2] - y[..., 4:]) ** 2)
|
|
40
|
+
alpha2 = ((13. / 12.) * (y[..., 1:-3] - 2. * y[..., 2:-2] + y[..., 3:-1]) ** 2
|
|
41
|
+
+ (1. / 4.) * (y[..., 1:-3] - 4. * y[..., 2:-2] + 3. * y[..., 3:-1]) ** 2)
|
|
42
|
+
# alpha0 = ((13. / 12.) * (y[..., 2:-2] - 2. * y[..., 3:-1] + y[..., 4:]) ** 2
|
|
43
|
+
# + (1. / 4.) * (3. * y[..., 2:-2] - 4. * y[..., 3:-1] + y[..., 4:]) ** 2)
|
|
44
|
+
# alpha1 = ((13. / 12.) * (y[..., 1:-3] - 2. * y[..., 2:-2] + y[..., 3:-1]) ** 2
|
|
45
|
+
# + (1. / 4.) * (y[..., 1:-3] - y[..., 3:-1]) ** 2)
|
|
46
|
+
# alpha2 = ((13. / 12.) * (y[..., :-4] - 2. * y[..., 1:-3] + y[..., 2:-2]) ** 2
|
|
47
|
+
# + (1. / 4.) * (y[..., :-4] - 4. * y[..., 1:-3] + 3. * y[..., 2:-2]) ** 2)
|
|
48
|
+
eps = 1e-6 * np.min([abs(alpha0), abs(alpha1), abs(alpha2)]) + 1e-150
|
|
49
|
+
# eps = 1e200
|
|
50
|
+
# print(eps, np.argwhere(np.isnan(alpha0)), np.argwhere(np.isnan(alpha1)), np.argwhere(np.isnan(alpha2)))
|
|
51
|
+
# Compute alpha0, alpha1, alpha2 along the last axis
|
|
52
|
+
|
|
53
|
+
alpha0 = 0.1 / ((eps + alpha0) * (eps + alpha0))
|
|
54
|
+
|
|
55
|
+
alpha1 = 0.6 / ((eps + alpha1) * (eps + alpha1))
|
|
56
|
+
|
|
57
|
+
alpha2 = 0.3 / ((eps + alpha2) * (eps + alpha2))
|
|
58
|
+
|
|
59
|
+
# print(alpha0, alpha1, alpha2)
|
|
60
|
+
|
|
61
|
+
# Compute fp
|
|
62
|
+
fp = (alpha0 * ((2. / 6.) * y[..., :-4] - (7. / 6.) * y[..., 1:-3] + (11. / 6.) * y[..., 2:-2])
|
|
63
|
+
+ alpha1 * (-(1. / 6.) * y[..., 1:-3] + (5. / 6.) * y[..., 2:-2] + (2. / 6.) * y[..., 3:-1])
|
|
64
|
+
+ alpha2 * ((2. / 6.) * y[..., 2:-2] + (5. / 6.) * y[..., 3:-1] - (1. / 6.) * y[..., 4:])) / (
|
|
65
|
+
alpha0 + alpha1 + alpha2)
|
|
66
|
+
# fp = (alpha0 * ((-1. / 6.) * y[..., :-4] + (5. / 6.) * y[..., 1:-3] + (2. / 6.) * y[..., 2:-2])
|
|
67
|
+
# + alpha1 * ((2. / 6.) * y[..., 1:-3] + (5. / 6.) * y[..., 2:-2] - (1. / 6.) * y[..., 3:-1])
|
|
68
|
+
# + alpha2 * ((11. / 6.) * y[..., 2:-2] - (7. / 6.) * y[..., 3:-1] + (2. / 6.) * y[..., 4:])) / (
|
|
69
|
+
# alpha0 + alpha1 + alpha2)
|
|
70
|
+
# Initialize result array
|
|
71
|
+
res = np.zeros_like(y)
|
|
72
|
+
|
|
73
|
+
# Compute the derivative along the last axis
|
|
74
|
+
res[..., 3:-2] = (fp[..., 1:] - fp[..., :-1]) / dx
|
|
75
|
+
# res[..., :3] = (y[..., 1:4] - y[..., :3]) / dx
|
|
76
|
+
res[..., 1:3] = (res[..., 2:4] - res[..., :2]) * 2 / dx
|
|
77
|
+
res[..., 0] = (y[..., 1] - y[..., 0]) / dx
|
|
78
|
+
res[..., -2:] = (y[..., -2:] - y[..., -3:-1]) / dx
|
|
79
|
+
|
|
80
|
+
# Move the axis back to its original position
|
|
81
|
+
res = np.moveaxis(res, -1, axis)
|
|
82
|
+
# return np.gradient(y, axis=axis) / dx
|
|
83
|
+
# return fp
|
|
84
|
+
return res
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def gradient_g(y: np.ndarray[np.float64], dx: np.float64 = np.double(1), axis: int = -1) -> np.ndarray[np.float64]:
|
|
88
|
+
y = np.moveaxis(y, axis, -1)
|
|
89
|
+
res = np.zeros_like(y)
|
|
90
|
+
res[..., 1:] = (y[..., 1:] - y[..., :-1]) / dx
|
|
91
|
+
res[..., 0] = (y[..., 1] - y[..., 0]) / dx
|
|
92
|
+
res = np.moveaxis(res, -1, axis)
|
|
93
|
+
return res
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def gradient_d(y: np.ndarray[np.float64], dx: np.float64 = np.double(1), axis: int = -1) -> np.ndarray[np.float64]:
|
|
97
|
+
y = np.moveaxis(y, axis, -1)
|
|
98
|
+
res = np.zeros_like(y)
|
|
99
|
+
res[..., :-1] = (y[..., 1:] - y[..., :-1]) / dx
|
|
100
|
+
res[..., -1] = (y[..., -1] - y[..., -2]) / dx
|
|
101
|
+
res = np.moveaxis(res, -1, axis)
|
|
102
|
+
return res
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def gradient(y: np.ndarray[np.float64], dx: np.float64 = np.double(1), axis: int = -1,
|
|
106
|
+
radial_speed: np.ndarray[np.float64] = None) -> np.ndarray[np.float64]:
|
|
107
|
+
y = np.moveaxis(y, axis, -1)
|
|
108
|
+
dg = gradient_g(y, dx, axis)
|
|
109
|
+
dd = gradient_d(y, dx, axis)
|
|
110
|
+
if radial_speed is None:
|
|
111
|
+
res = (dg+dd) / 2
|
|
112
|
+
else:
|
|
113
|
+
res = dd
|
|
114
|
+
if np.any(radial_speed < 0):
|
|
115
|
+
idx_negs: np.ndarray[int] = np.argwhere(radial_speed < 0)[:, 0]
|
|
116
|
+
res[..., idx_negs] = dg[..., idx_negs]
|
|
117
|
+
res = np.moveaxis(res, -1, axis)
|
|
118
|
+
return res
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def gradient2(y: np.ndarray[np.float64], dx: np.float64 = np.double(1), axis: int = -1) -> np.ndarray[np.float64]:
|
|
122
|
+
y = np.moveaxis(y, axis, -1)
|
|
123
|
+
res = np.zeros_like(y)
|
|
124
|
+
res[..., 1:-1] = (y[..., 2:] + y[..., :-2] - 2. * y[..., 1:-1]) / (dx * dx)
|
|
125
|
+
# res[..., 0] = (y[..., 0] - 2 * y[..., 1] + y[..., 2]) / (dx * dx)
|
|
126
|
+
# res[..., -1] = (y[..., -3] - 2 * y[..., -2] + y[..., -1]) / (dx * dx)
|
|
127
|
+
# res[wleft * wright == 0] = 0.
|
|
128
|
+
res = np.moveaxis(res, -1, axis)
|
|
129
|
+
return res
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def dleft(y: np.ndarray[np.float64], dx: np.float64 = np.double(1), axis: int = -1) -> np.ndarray[np.float64]:
|
|
133
|
+
y = np.moveaxis(y, axis, -1)
|
|
134
|
+
dleft: np.ndarray[np.float64] = np.zeros_like(y)
|
|
135
|
+
dright: np.ndarray[np.float64] = np.zeros_like(y)
|
|
136
|
+
wleft: np.ndarray[np.float64] = np.zeros_like(y)
|
|
137
|
+
wright: np.ndarray[np.float64] = np.zeros_like(y)
|
|
138
|
+
dleft[2:] = (1.5 * y[..., 2:] - 2. * y[..., 1:-1] + 0.5 * y[..., :-2]) / dx
|
|
139
|
+
|
|
140
|
+
dleft = np.moveaxis(dleft, -1, axis)
|
|
141
|
+
return dleft
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def dright(y: np.ndarray[np.float64], dx: np.float64 = np.double(1), axis: int = -1) -> np.ndarray[np.float64]:
|
|
145
|
+
y = np.moveaxis(y, axis, -1)
|
|
146
|
+
dright: np.ndarray[np.float64] = np.zeros_like(y)
|
|
147
|
+
dright[..., :-2] = (-1.5 * y[..., :-2] + 2. * y[..., 1:-1] - 0.5 * y[..., 2:]) / dx
|
|
148
|
+
|
|
149
|
+
dright = np.moveaxis(dright, -1, axis)
|
|
150
|
+
return dright
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def doublons(tab: np.ndarray, prec: np.float64 = np.double(1e-13)) -> np.ndarray:
|
|
155
|
+
res: list = []
|
|
156
|
+
idx_poubelle: list = []
|
|
157
|
+
for i in range(len(tab)):
|
|
158
|
+
if i not in idx_poubelle:
|
|
159
|
+
idx = np.argwhere(np.abs((tab - tab[i]) / tab[i]) < prec)[:, 0]
|
|
160
|
+
if len(idx) > 0:
|
|
161
|
+
res.append(idx[0])
|
|
162
|
+
else:
|
|
163
|
+
res.append(i)
|
|
164
|
+
idx_poubelle.extend(list(idx))
|
|
165
|
+
return np.array(res)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
# Opérations diverses
|
|
169
|
+
def factorielle(n: int) -> int:
|
|
170
|
+
"""
|
|
171
|
+
Calcul récursivement la factorielle de n
|
|
172
|
+
:param n: entier naturel dont on souhaite calculer la factorielle
|
|
173
|
+
:return: n!
|
|
174
|
+
"""
|
|
175
|
+
if n < 0:
|
|
176
|
+
raise UserWarning("La factorielle d'un nombre négatif ({}) n'est pas définie".format(n))
|
|
177
|
+
elif n == 0 or n == 1:
|
|
178
|
+
return 1
|
|
179
|
+
else:
|
|
180
|
+
return n * factorielle(n - 1)
|
|
181
|
+
|
|
182
|
+
def puissance_entière(x: np.float64 | float | np.ndarray, n: int) -> np.float64 | float | np.ndarray:
|
|
183
|
+
"""Calcul la puissance n de x"""
|
|
184
|
+
if type(n) is not (int or np.longlong):
|
|
185
|
+
raise UserWarning("Une puissance entière ne peut être calculé avec un exposant de type :" + str(type(n)))
|
|
186
|
+
if n == 0:
|
|
187
|
+
return np.ones_like(x)
|
|
188
|
+
elif n == -1:
|
|
189
|
+
return 1 / x
|
|
190
|
+
elif n == 1:
|
|
191
|
+
return x
|
|
192
|
+
else:
|
|
193
|
+
res: np.float64 | float | np.ndarray = np.copy(x)
|
|
194
|
+
for k in range(2, n + 1):
|
|
195
|
+
res *= x
|
|
196
|
+
return res
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def calcul_coefficients_pondération(
|
|
200
|
+
X: np.ndarray | list[float | np.float64],
|
|
201
|
+
x0: float | np.float64 = np.double(0), ordre: int = 1) -> np.ndarray:
|
|
202
|
+
""" Cette fonction calcule les coefficients de pondération à appliquer devant les évaluations d'une fonction f aux
|
|
203
|
+
pas de temps dts autour du point à dériver
|
|
204
|
+
:param X: Valeurs des point d'évaluation de la fonction
|
|
205
|
+
:type X : list[double|float] | Array[double|float]
|
|
206
|
+
|
|
207
|
+
:param x0: Valeur autour de laquelle on souhaite dériver (option à choisir si x0 n'est pas présent dans x)
|
|
208
|
+
:type x0: float | double
|
|
209
|
+
|
|
210
|
+
:param ordre: Ordre de la dérivation. Par défaut 1. Ne peut être plus grand que le nombre de pas de temps
|
|
211
|
+
:type ordre : int
|
|
212
|
+
|
|
213
|
+
:return: K, tableau de la dimension de X contenant les coefficients à appliquer devant les évaluations de la
|
|
214
|
+
fonction f à dériver aux pas de temps correspondant
|
|
215
|
+
:rtype : Array[double | float]
|
|
216
|
+
|
|
217
|
+
Remarques :
|
|
218
|
+
- Le premier pas de temps peut être nul, et les pas de temps peuvent être positifs ou négatifs.
|
|
219
|
+
- La dérivation sera précise à l'ordre correspondant à la taille de X
|
|
220
|
+
Exemples :
|
|
221
|
+
- Cas le plus simple : dérivée d'ordre 1, schéma d'Euler
|
|
222
|
+
-- On fournit X=[0 ,dt] et la fonction retourne [-1 / dt, 1 / dt]
|
|
223
|
+
- Dérivation centrée d'ordre 1 :
|
|
224
|
+
-- On fournit X=[-dt,0,dt] et la fonction retourne [-1 / 2*dt, 0, 1 / 2*dt]
|
|
225
|
+
"""
|
|
226
|
+
if ordre >= len(X):
|
|
227
|
+
raise UserWarning(
|
|
228
|
+
"Attention, pour calculer une dérivée d'ordre " + str(ordre) + ", on doit avoir au moins " + str(
|
|
229
|
+
ordre) + " pas de temps. Les " + str(len(X)) + " results sont insuffisantes")
|
|
230
|
+
|
|
231
|
+
Delta_X: np.ndarray = np.array(X) - x0
|
|
232
|
+
# mini: np.float64 = np.double(np.min(abs(Delta_X[Delta_X != 0])))
|
|
233
|
+
# maxi: np.float64 = np.double(np.max(abs(Delta_X[Delta_X != 0])))
|
|
234
|
+
# alpha: np.float64 = 10 ** ((np.log10(mini) + np.log10(maxi)) / 2)
|
|
235
|
+
# Delta_X /= alpha # On rééchelonne les abscisses pour ne pas avoir de trop petites results dans la matrice A
|
|
236
|
+
|
|
237
|
+
A: np.ndarray = np.array([list(puissance_entière(Delta_X, i)) for i in range(len(X))])
|
|
238
|
+
B: np.ndarray = np.zeros_like(X)
|
|
239
|
+
# B[ordre] = factorielle(ordre) / puissance_entière(alpha, ordre)
|
|
240
|
+
B[ordre] = factorielle(ordre)
|
|
241
|
+
K: np.ndarray
|
|
242
|
+
K = solve(A, B, overwrite_a=True, overwrite_b=True)
|
|
243
|
+
return K
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def calcul_matrice_derivation(x: np.ndarray | list, ordre_derivation: int = 1, ordre_discrétisation: int = 2
|
|
247
|
+
) -> np.ndarray:
|
|
248
|
+
"""
|
|
249
|
+
Retourne une matrice qui multipliée avec tout y=f(x) retourne la dérivée d'ordre ordre_dérivation de f selon l'axe x
|
|
250
|
+
discrétisé à l'ordre ordre_discrétisation
|
|
251
|
+
:param x: tableau 1d represantant l'axe de dérivation
|
|
252
|
+
:param ordre_derivation: ordre de la dérivée voulue
|
|
253
|
+
:param ordre_discrétisation: ordre de la discrétisation de la dérivée, >= ordre_dérivation < len(x)
|
|
254
|
+
:return: matrice à multiplier avec y
|
|
255
|
+
"""
|
|
256
|
+
if type(x) is list:
|
|
257
|
+
x: np.ndarray = np.array(x)
|
|
258
|
+
if len(x.shape) > 1:
|
|
259
|
+
raise UserWarning("calcul_matrice_derivation : l'axe de dérivation doit être de dimension 1."
|
|
260
|
+
"Ici x.shape=", x.shape)
|
|
261
|
+
if ordre_discrétisation < ordre_derivation:
|
|
262
|
+
raise UserWarning("calcul_matrice_derivation : l'ordre de discrétisation doit être supérieur "
|
|
263
|
+
"à l'ordre de dérivation, ici ordre_dérivation=", ordre_derivation,
|
|
264
|
+
"et ordre discrétisation=", ordre_discrétisation)
|
|
265
|
+
if ordre_discrétisation >= len(x):
|
|
266
|
+
raise UserWarning("calcul_matrice_derivation : l'ordre de discrétisation doit être inférieur "
|
|
267
|
+
"à la taille du tableau x. Ici ordre discrétisation=", ordre_discrétisation,
|
|
268
|
+
"len(x)=", len(x))
|
|
269
|
+
K: np.ndarray = np.zeros((len(x), len(x)), dtype=type(x[0]))
|
|
270
|
+
for i in range(len(x)):
|
|
271
|
+
i_inf: int = max(0, i - (ordre_discrétisation + 1) // 2)
|
|
272
|
+
i_sup: int = min(len(x) - 1, i + (ordre_discrétisation + 1) // 2 + (ordre_discrétisation + 1) % 2)
|
|
273
|
+
i_inf -= max(i + (ordre_discrétisation + 1) // 2 + (ordre_discrétisation + 1) % 2 - (len(x) - 1), 0)
|
|
274
|
+
i_sup += - min(i - (ordre_discrétisation + 1) // 2, 0)
|
|
275
|
+
K[i, i_inf:i_sup] = calcul_coefficients_pondération(X=x[i_inf:i_sup], x0=x[i], ordre=ordre_derivation)
|
|
276
|
+
return K
|
|
277
|
+
|
|
278
|
+
#
|
|
279
|
+
# def gradient2(f: np.ndarray, x: np.ndarray | None = None, axis: int = 0,
|
|
280
|
+
# tab_dx: np.ndarray | None = None, derivation_order: int = 1,
|
|
281
|
+
# discretisation_order: int = 2) -> np.ndarray:
|
|
282
|
+
# """
|
|
283
|
+
# Calculate the spatial derivative of f along x
|
|
284
|
+
# :param f: value to differentiate
|
|
285
|
+
# :param x: abscisse, if None and tab_dx None = arange(len(f))
|
|
286
|
+
# :param axis: axis along with the derivative is done (default 0)
|
|
287
|
+
# :param tab_dx: matrix used to calculate the derivative. If None tab_dx is calculated using x, derivation_order
|
|
288
|
+
# and discretisation_order
|
|
289
|
+
# :param derivation_order: int = 1 if tab_dx is None
|
|
290
|
+
# :param discretisation_order: int = 2 if tab_dx is None
|
|
291
|
+
# :return:
|
|
292
|
+
# """
|
|
293
|
+
# if tab_dx is None:
|
|
294
|
+
# tab_dx = calcul_matrice_derivation(x, derivation_order, discretisation_order)
|
|
295
|
+
# # return tab_dx @ f
|
|
296
|
+
# # return np.tensordot(tab_dx, f, axes=([1], [axis]))
|
|
297
|
+
# return np.tensordot(f, tab_dx, axes=([axis], [1]))
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
def linear_interpolation(x, y):
|
|
301
|
+
"""
|
|
302
|
+
Interpolation linéaire vectorisée.
|
|
303
|
+
|
|
304
|
+
:param x: Points de données pour la variable indépendante.
|
|
305
|
+
:param y: Points de données pour les fonctions dépendantes (2D array).
|
|
306
|
+
:param x_new: Points pour lesquels interpoler.
|
|
307
|
+
:return: Valeurs interpolées pour chaque dimension.
|
|
308
|
+
"""
|
|
309
|
+
def result(x_new: np.float64 | np.ndarray) -> np.float64 | np.ndarray:
|
|
310
|
+
if isinstance(x_new, np.ndarray):
|
|
311
|
+
# Calculer les indices et les poids pour l'interpolation
|
|
312
|
+
idx = np.searchsorted(x, x_new) - 1
|
|
313
|
+
idx = np.clip(idx, 0, len(x) - 2)
|
|
314
|
+
|
|
315
|
+
# Calculer les poids pour chaque intervalle
|
|
316
|
+
x1 = x[idx]
|
|
317
|
+
x2 = x[idx + 1]
|
|
318
|
+
alpha = (x_new - x1) / (x2 - x1)
|
|
319
|
+
|
|
320
|
+
# Interpolation linéaire vectorisée
|
|
321
|
+
y_new = (1 - alpha[:, np.newaxis]) * y[idx] + alpha[:, np.newaxis] * y[idx + 1]
|
|
322
|
+
|
|
323
|
+
return y_new
|
|
324
|
+
else:
|
|
325
|
+
i = np.searchsorted(x, x_new)
|
|
326
|
+
i = np.clip(i, 0, len(x) - 2)
|
|
327
|
+
x1 = x[i]
|
|
328
|
+
x2 = x[i + 1]
|
|
329
|
+
alpha = (x_new - x1) / (x2 - x1)
|
|
330
|
+
y_new = (1 - alpha) * y[i] + alpha*y[i + 1]
|
|
331
|
+
return y_new
|
|
332
|
+
return result
|