Coverage for pySDC / projects / RayleighBenard / analysis_scripts / process_RBC3D_data.py: 96%
130 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-02-12 11:13 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-02-12 11:13 +0000
1from pySDC.projects.RayleighBenard.RBC3D_configs import get_config
2from pySDC.projects.RayleighBenard.run_experiment import parse_args
3from pySDC.helpers.fieldsIO import FieldsIO
4import matplotlib.pyplot as plt
5from tqdm import tqdm
6from mpi4py import MPI
7import numpy as np
8import pickle
9import os
12def process_RBC3D_data(base_path='./data/processed', plot=True, args=None, config=None):
13 # prepare problem instance
14 args = args if args else parse_args()
15 comm = MPI.COMM_WORLD
16 args['procs'] = [1, 1, comm.size]
17 config = config if config else get_config(args)
18 desc = config.get_description(**args)
19 P = desc['problem_class'](
20 **{
21 **desc['problem_params'],
22 'spectral_space': False,
23 'comm': comm,
24 'Dirichlet_recombination': False,
25 'left_preconditioner': False,
26 }
27 )
28 P.setUpFieldsIO()
29 zInt = P.axes[-1].get_integration_weights()
30 xp = P.xp
32 # prepare paths
33 os.makedirs(base_path, exist_ok=True)
34 fname = config.get_file_name()
35 fname_trim = fname[fname.index('RBC3D') : fname.index('.pySDC')]
36 path = f'{base_path}/{fname_trim}.pickle'
38 # open simulation data
39 data = FieldsIO.fromFile(fname)
41 # prepare arrays to store data in
42 Nu = {
43 'V': [],
44 'b': [],
45 't': [],
46 'thermal': [],
47 'kinetic': [],
48 }
49 t = []
50 profiles = {key: [] for key in ['T', 'u', 'v', 'w']}
51 rms_profiles = {key: [] for key in profiles.keys()}
52 spectrum = []
53 spectrum_all = []
55 # try to load time averaged values
56 u_mean_profile = P.u_exact()
57 if os.path.isfile(path):
58 with open(path, 'rb') as file:
59 avg_data = pickle.load(file)
60 if comm.rank == 0:
61 print(f'Read data from file {path!r}')
62 for key in profiles.keys():
63 if f'profile_{key}' in avg_data.keys():
64 u_mean_profile[P.index(key)] = avg_data[f'profile_{key}'][P.local_slice(False)[-1]]
65 elif comm.rank == 0:
66 print('No mean profiles available yet. Please rerun script after completion to get correct RMS profiles')
68 # prepare progress bar
69 indeces = range(args['restart_idx'], data.nFields)
70 if P.comm.rank == 0:
71 indeces = tqdm(indeces)
73 # loop through all data points and compute stuff
74 for i in indeces:
75 _t, u = data.readField(i)
77 # Nusselt numbers
78 _Nu = P.compute_Nusselt_numbers(u)
79 if any(me > 1e3 for me in _Nu.values()):
80 continue
82 for key in Nu.keys():
83 Nu[key].append(_Nu[key])
85 t.append(_t)
87 # profiles
88 _profiles = P.get_vertical_profiles(u, list(profiles.keys()))
89 _rms_profiles = P.get_vertical_profiles((u - u_mean_profile) ** 2, list(profiles.keys()))
90 for key in profiles.keys():
91 profiles[key].append(_profiles[key])
92 rms_profiles[key].append(_rms_profiles[key])
94 # spectrum
95 k, s = P.get_frequency_spectrum(u)
96 s_mean = zInt @ P.axes[-1].transform(s[0], axes=(0,))
97 spectrum.append(s_mean)
98 spectrum_all.append(s)
100 # make a plot of the results
101 t = xp.array(t)
102 z = P.axes[-1].get_1dgrid()
104 if config.converged == 0:
105 print('Warning: no convergence has been set for this configuration!')
107 fig, axs = plt.subplots(1, 4, figsize=(18, 4))
108 for key in Nu.keys():
109 axs[0].plot(t, Nu[key], label=f'$Nu_{{{key}}}$')
110 if config.converged > 0:
111 axs[0].axvline(config.converged, color='black')
112 axs[0].set_ylabel('$Nu$')
113 axs[0].set_xlabel('$t$')
114 axs[0].legend(frameon=False)
116 # compute differences in Nusselt numbers
117 avg_Nu = {}
118 std_Nu = {}
119 for key in Nu.keys():
120 _Nu = [Nu[key][i] for i in range(len(Nu[key])) if t[i] > config.converged]
121 avg_Nu[key] = xp.mean(_Nu)
122 std_Nu[key] = xp.std(_Nu)
124 rel_error = {
125 key: abs(avg_Nu[key] - avg_Nu['V']) / avg_Nu['V']
126 for key in [
127 't',
128 'b',
129 'thermal',
130 'kinetic',
131 ]
132 }
133 if comm.rank == 0:
134 print(
135 f'With Ra={P.Rayleigh:.0e} got Nu={avg_Nu["V"]:.2f}+-{std_Nu["V"]:.2f} with errors: Top {rel_error["t"]:.2e}, bottom: {rel_error["b"]:.2e}, thermal: {rel_error["thermal"]:.2e}, kinetic: {rel_error["kinetic"]:.2e}'
136 )
138 # compute average profiles
139 avg_profiles = {}
140 for key, values in profiles.items():
141 values_from_convergence = [values[i] for i in range(len(values)) if t[i] >= config.converged]
143 avg_profiles[key] = xp.mean(values_from_convergence, axis=0)
145 avg_rms_profiles = {}
146 for key, values in rms_profiles.items():
147 values_from_convergence = [values[i] for i in range(len(values)) if t[i] >= config.converged]
148 avg_rms_profiles[key] = xp.sqrt(xp.mean(values_from_convergence, axis=0))
150 # average T
151 avg_T = avg_profiles['T']
152 axs[1].axvline(0.5, color='black')
153 axs[1].plot(avg_T, z)
154 axs[1].set_xlabel('$T$')
155 axs[1].set_ylabel('$z$')
157 # rms profiles
158 avg_T = avg_rms_profiles['T']
159 max_idx = xp.argmax(avg_T)
160 res_in_boundary_layer = max_idx if max_idx < len(z) / 2 else len(z) - max_idx
161 boundary_layer = z[max_idx] if max_idx > len(z) / 2 else P.axes[-1].L - z[max_idx]
162 if comm.rank == 0:
163 print(
164 f'Thermal boundary layer of thickness {boundary_layer:.2f} is resolved with {res_in_boundary_layer} points'
165 )
166 axs[2].axhline(z[max_idx], color='black')
167 axs[2].plot(avg_T, z)
168 axs[2].scatter(avg_T, z)
169 axs[2].set_xlabel(r'$T_\text{rms}$')
170 axs[2].set_ylabel('$z$')
172 # spectrum
173 _s = xp.array(spectrum)
174 avg_spectrum = xp.mean(_s[t >= config.converged], axis=0)
175 axs[3].loglog(k[avg_spectrum > 1e-15], avg_spectrum[avg_spectrum > 1e-15])
176 axs[3].set_xlabel('$k$')
177 axs[3].set_ylabel(r'$\|\hat{u}_x\|$')
179 if P.comm.rank == 0:
180 write_data = {
181 't': t,
182 'Nu': Nu,
183 'avg_Nu': avg_Nu,
184 'std_Nu': std_Nu,
185 'z': P.axes[-1].get_1dgrid(),
186 'k': k,
187 'spectrum': spectrum_all,
188 'avg_spectrum': avg_spectrum,
189 'boundary_layer_thickness': boundary_layer,
190 'res_in_boundary_layer': res_in_boundary_layer,
191 }
192 for key, values in avg_profiles.items():
193 write_data[f'profile_{key}'] = values
194 for key, values in avg_rms_profiles.items():
195 write_data[f'rms_profile_{key}'] = values
197 with open(path, 'wb') as file:
198 pickle.dump(write_data, file)
199 print(f'Wrote data to file {path!r}')
201 if plot:
202 fig.tight_layout()
203 fig.savefig(f'{base_path}/{fname_trim}.pdf')
204 plt.show()
205 return path
208def get_pySDC_data(res=-1, dt=-1, config_name='RBC3DG4', base_path='data/processed'):
209 path = f'{base_path}/{config_name}-res{res}-dt{dt:.0e}.pickle'
210 with open(path, 'rb') as file:
211 data = pickle.load(file)
213 return data
216if __name__ == '__main__':
217 process_RBC3D_data()