Shamrock 2025.10.0
Astrophysical Code
Loading...
Searching...
No Matches
DustMRNDistribution.py
1import numpy as np
2
3import shamrock
4
5
6def rank_0_print(*args, **kwargs):
7 if shamrock.sys.world_rank() == 0:
8 print(*args, **kwargs)
9
10
12 def __init__(self, codeu, mrn_pow, mrn_cutoff_si, grain_size_si_edges, rho_grains_si_edges):
13 self.codeu = codeu
14 self.mrn_pow = mrn_pow
15 self.mrn_cutoff_si = mrn_cutoff_si
16 self.grain_size_si_edges = grain_size_si_edges
17 self.rho_grains_si_edges = rho_grains_si_edges
18
19 to_m = self.codeu.get("m")
20 to_kg = self.codeu.get("kg")
21 to_dens = to_kg * to_m**-3
22
23 rank_0_print(" ---- MRN DISTRIBUTION ----")
24
25 rank_0_print("bin edges:")
26 rank_0_print(f" grains sizes (edges) = {self.grain_size_si_edges.tolist()} [m]")
27 rank_0_print(f" grains dens (edges) = {self.rho_grains_si_edges.tolist()} [kg.m^-3]")
28
29 self.grain_size_edges = self.grain_size_si_edges * to_m
30 self.rho_grains_edges = to_dens * np.array(self.rho_grains_si_edges)
31
32 rank_0_print(f" grains sizes (edges) = {self.grain_size_edges.tolist()} [code u]")
33 rank_0_print(f" grains dens (edges) = {self.rho_grains_edges.tolist()} [code u]")
34
35 rank_0_print()
36 rank_0_print("bin centers (geom averages):")
37
38 self.grain_size = np.sqrt(self.grain_size_edges[:-1] * self.grain_size_edges[1:])
39 self.rho_grains = np.sqrt(self.rho_grains_edges[:-1] * self.rho_grains_edges[1:])
40
41 self.bin_width_si = self.grain_size_si_edges[1:] - self.grain_size_si_edges[:-1]
42 self.bin_width = self.grain_size_edges[1:] - self.grain_size_edges[:-1]
43
44 self.grain_size_si = np.sqrt(self.grain_size_si_edges[:-1] * self.grain_size_si_edges[1:])
45 self.rho_grains_si = np.sqrt(self.rho_grains_si_edges[:-1] * self.rho_grains_si_edges[1:])
46
47 rank_0_print(f" grains sizes (bin) = {self.grain_size_si.tolist()} [m]")
48 rank_0_print(f" grains dens (bin) = {self.rho_grains_si.tolist()} [kg.m^-3]")
49
50 rank_0_print(f" grains sizes (bin) = {self.grain_size.tolist()} [code units]")
51 rank_0_print(f" grains dens (bin) = {self.rho_grains.tolist()} [code units]")
52
53 self.massgrid_edges = (4 * np.pi / 3) * self.rho_grains_edges * self.grain_size_edges**3
54 self.massgrid = np.sqrt(self.massgrid_edges[:-1] * self.massgrid_edges[1:])
55
56 self.massgrid_si_edges = self.massgrid_edges * self.codeu.to("kg")
57 self.massgrid_si = self.massgrid * self.codeu.to("kg")
58
59 rank_0_print(f" massgrid = {self.massgrid_si.tolist()} [kg]")
60 rank_0_print(f" massgrid = {self.massgrid.tolist()} [code units]")
61
62 rank_0_print()
63 rank_0_print("deduced:")
64
65 self.alpha = 3 - self.mrn_pow
66 rank_0_print(f" alpha = 3 - mrn_pow = {self.alpha}")
67
68 max_s = min(self.mrn_cutoff_si, max(self.grain_size_si_edges))
69 min_s = min(self.mrn_cutoff_si, min(self.grain_size_si_edges))
70 rank_0_print(f" s (edges) max = {max_s} min = {min_s} [m]")
71
72 self.grain_size_si_edges_clipped = np.clip(
73 self.grain_size_si_edges, None, self.mrn_cutoff_si
74 )
75 self.grain_size_si_clipped = np.clip(self.grain_size_si, None, self.mrn_cutoff_si)
76 rank_0_print(
77 f" grains sizes (edges) (clipped) = {self.grain_size_si_edges_clipped.tolist()} [m]"
78 )
79
80 # d espilon = epsilon_0 s^\alpha d s
81 # \int d epsilon_s = [ s^(alpha + 1) / (alpha + 1) ]^max_min
82
83 def prim(s):
84 return s ** (self.alpha + 1) / (self.alpha + 1)
85
86 self.mrn_weight = prim(self.grain_size_si_edges_clipped[1:]) - prim(
88 )
89 self.mrn_weight = self.mrn_weight / np.sum(self.mrn_weight) # normalize to 1
90 rank_0_print(f" mrn_weight = {self.mrn_weight.tolist()}")
91 rank_0_print(f" sum(mrn_weight) = {np.sum(self.mrn_weight)}")
92
93 # here sum(mrn_weight) = \int d epsilon = 1 by design
94 # S_mean = \int s depsilon / \int depsilon
95 # = (analytics) [ \epsilon_0 s^(alpha + 2) / (alpha + 2) ]^max_min
96 # / [ \epsilon_0 s^(alpha + 1) / (alpha + 1) ]^max_min
97 # (numerically)
98 # average epsilon_j = \int d epsilon / \delta_bin
99
100 def s_mean_pow_1(add_pow, val):
101 return val ** (self.alpha + add_pow) / (self.alpha + add_pow)
102
103 def s_mean_pow_2(add_pow):
104 return s_mean_pow_1(add_pow, max_s) - s_mean_pow_1(add_pow, min_s)
105
106 analytical_S_mean = s_mean_pow_2(2) / s_mean_pow_2(1)
107
108 S_mean = np.sum(self.mrn_weight * self.grain_size_si)
109 rank_0_print(
110 f" S_mean = {S_mean} S_mean_init = {analytical_S_mean} (diff = {S_mean - analytical_S_mean})"
111 )
112
113 rank_0_print(" -------------------------")