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