From b773e3e1c2c756c0ddc3f36c115e8728d349a6d0 Mon Sep 17 00:00:00 2001 From: Dark-Elektron <55360766+Dark-Elektron@users.noreply.github.com> Date: Fri, 16 Aug 2024 14:13:47 +0200 Subject: [PATCH] Initial commit. --- README.md | 95 +- cavsim2d/analysis/tune/pyTuner.py | 33 +- cavsim2d/analysis/tune/tuner.py | 50 +- .../uq/dakota_scripts/generate_nodes.py | 3 +- .../analysis/uq/dakota_scripts/py_dakota.py | 4 - cavsim2d/analysis/uq/dakota_scripts/pycall.py | 1 - .../dakota_scripts/test_dakotapy/py_dakota.py | 1 - .../uq/dakota_scripts/test_dakotapy/pycall.py | 2 - .../uq/dakota_scripts/write_dakota_input.py | 2 +- cavsim2d/analysis/wakefield/abci_code.py | 10 - cavsim2d/analysis/wakefield/abci_geometry.py | 18 +- cavsim2d/analysis/wakefield/geometry.py | 10 - cavsim2d/cavity.py | 2862 ++++++++++------- cavsim2d/data_module/abci_data.py | 23 +- cavsim2d/data_module/process_data.py | 29 +- cavsim2d/solvers/NGSolve/eigen_ngsolve.py | 12 +- cavsim2d/utils/shared_functions.py | 27 +- notebooks/optimisation.ipynb | 210 +- notebooks/sweep.ipynb | 1198 ++----- notebooks/test_notebook.ipynb | 479 +-- notebooks/tune_test.ipynb | 97 +- notebooks/wakefield_analysis.ipynb | 284 +- 22 files changed, 2454 insertions(+), 2996 deletions(-) diff --git a/README.md b/README.md index 2f598a7..4b4971f 100644 --- a/README.md +++ b/README.md @@ -186,6 +186,28 @@ cavs['TESLA'].plot_fields(mode=1, which='H') > Meshes and fields are properties of a Cavity object and not a Cavities object. Therefore, to visualise the mesh > and field profiles, use the `Cavity` object `name` or corresponding index. +--------------- + +## Configuration dictionaries + +Configuration dictionaries are used to specify simulation inputs. Each simulation has its specific configuration dictonary +format and content. The configuration files are written so that it is logical. For example, a simple eigenmode simulation +config file is shown below: + + +We will talk about uncertainty quantification (UQ) later but if we were to equip the eigenmode analysis with UQ, +we only need include a uq_config dictioanry as an entry into the eigenmode_config dictionary. For example: + + +The same goes for wakefield analysis and tuning. For optimisation control, consider that in an optimisation, we +want to optimise for a particular frequency so for any parameter set generated, we want to first tunr. Therefore, +an optimisation_config dictionary will contain a tune_config. The depending on the objectives the optimisation_config +then includes an eigenmode_config and or a wakefield_config field. It also follows that the eigenmode_config and +wakefield_config can also contain uq_config fields. + +> [!NOTE] +> For eigenmode and wakefield analysis, if a configuration dictionary is not entered, default values are used. + --------------- ## Cavity Tuning @@ -308,7 +330,14 @@ op_points = { "Nb [1e11]": 2.76 # <- Bunch population } } -cavs.run_wakefield(operating_points=op_points) +wakefield_config = { + 'bunch_length': 25, + 'wakelength': 50, + 'processes': 2, + 'rerun': True, + 'operating_points': op_points, +} +cavs.run_wakefield(wakefield_config) pp.pprint(cavs.abci_qois) ``` @@ -333,18 +362,27 @@ are the fundamental `freq [MHz]`, `Epk/Eacc []`, `Bpk/Eacc [mT/MV/m]`, `R/Q [Ohm analysis The algorithm currently implemented is genetic algorithm. The optimisation settings are controlled using a configuration dictionary. The most important parameters for the algorithm are -- `cell type`: The options are `mid-cell`, `end-cell` and `end-end-cell` depending on the parameterisation of the cavity +- `cell_type`: The options are `mid-cell`, `end-cell` and `end-end-cell` depending on the parameterisation of the cavity geometry. See Fig []. Default is `mid-cell`. ``` - 'cell type': 'mid-cell' + 'cell_type': 'mid-cell' ``` -- `tune variable`: Target operating frequency of the cavity. +- `freqs`: Target operating frequency of the cavity. ``` -'tune variable': 'Req' +'parameters': 'Req' ``` - 'tune freq.': Target operating frequency of the cavity. ``` -`tune freq.`: 1300 +`freqs`: 1300 +``` + +The preceeding parameters belong to the tune_config dictionary and so are entered this way in the optimisation_config +``` +'tune_config': { + 'freqs': 801.58, + 'parameters': 'Req', + 'cell_types': cell_type +} ``` - `bounds`: This defines the optimisation search space. All geometric variables must be entered. Note that variables excluded from optimisation should have identical upper and lower bounds.. @@ -372,31 +410,34 @@ using a configuration dictionary. The most important parameters for the algorith ``` The third parameter for the impedances `ZL`, `ZT` define the frequency interval for which to evaluate the peak impedance. The algorithm specific entries include -- `initial points`: The number of initial points to be genereated. +- `initial_points`: The number of initial points to be genereated. - `method`: Method of generating the initial points. Defaults to latin hypercube sampling (LHS). -- `no. of generations`: The number of generations to be analysed. Defaults to 20. -- `crossover factor`: The number of crossovers to create offsprings. -- `elites for crossover`: The number of elites allowed to produce offsprings. -- `mutation factor`: The number of mutations to create offsprings. -- `chaos factor`: The number of new random geometries included to improve diversity. +- `no_of_generations`: The number of generations to be analysed. Defaults to 20. +- `crossover_factor`: The number of crossovers to create offsprings. +- `elites_for_crossover`: The number of elites allowed to produce offsprings. +- `mutation_factor`: The number of mutations to create offsprings. +- `chaos_factor`: The number of new random geometries included to improve diversity. ``` -'initial points': 5, +'initial_points': 5, 'method': { 'LHS': {'seed': 5}, }, -'no. of generations': 5, -'crossover factor': 5, -'elites for crossover': 2, -'mutation factor': 5, -'chaos factor': 5, +'no_of_generations': 5, +'crossover_factor': 5, +'elites_for_crossover': 2, +'mutation_factor': 5, +'chaos_factor': 5, ``` Putting it all together, we get ```python optimisation_config = { - 'cell type': 'mid-cell', - 'tune variable': 'Req', - 'tune freq.': 1300, + 'tune_config': { + 'freqs': 1300, + 'parameters': 'Req', + 'cell_types': 'mid-cell', + 'processes': 1 + }, 'bounds': {'A': [20.0, 80.0], 'B': [20.0, 80.0], 'a': [10.0, 60.0], @@ -428,7 +469,7 @@ cavs = Cavities() # must first save cavities cavs.save('D:\Dropbox\CavityDesignHub\MuCol_Study\SimulationData\ConsoleTest') -cavs.run_optimisation(config=optimisation_config) +cavs.run_optimisation(optimisation_config) ``` ## Uncertainty Quantification Capabilities @@ -469,6 +510,12 @@ uq_config = { 'cell type': 'mid-cell', 'cell complexity': 'simplecell' } +eigenmode_config = { + 'processes': 3, + 'rerun': True, + 'boundary_conditions': 'mm', + 'uq_config': uq_config +} cavs.run_eigenmode(uq_config=uq_config) pp.pprint(cavs.eigenmode_qois) @@ -498,4 +545,8 @@ Simulations using `cavsim2d` are easily parallelised by specifying a value for t specifying the amount of processes the analysis should use. If UQ is enabled, an extra level of parallelisation can be achieved by passing `processes` also in the uq configuration dictionary. The number of processes defaults to 1. +## Understanding the geometry types + + + ## Folder structure \ No newline at end of file diff --git a/cavsim2d/analysis/tune/pyTuner.py b/cavsim2d/analysis/tune/pyTuner.py index 937726f..d6085ea 100644 --- a/cavsim2d/analysis/tune/pyTuner.py +++ b/cavsim2d/analysis/tune/pyTuner.py @@ -25,8 +25,8 @@ def __init__(self): self.plot = None def tune(self, par_mid, par_end, tune_var, target_freq, cell_type, beampipes, bc, - sim_folder, parentDir, projectDir, iter_set, proc=0, conv_list=None): - + sim_folder, parentDir, projectDir, proc=0): + convergence_list = [] # tv => tune variable indx = VAR_TO_INDEX_DICT[tune_var] @@ -73,12 +73,12 @@ def tune(self, par_mid, par_end, tune_var, target_freq, cell_type, beampipes, bc beampipes = 'both' res = ngsolve_mevp.cavity(1, 1, mid, left, right, - n_modes=1, fid=fid, f_shift=0, bc=bc, beampipes=beampipes, - sim_folder=sim_folder, parentDir=parentDir, projectDir=projectDir) + n_modes=1, fid=fid, f_shift=0, bc=bc, beampipes=beampipes, + sim_folder=sim_folder, parentDir=parentDir, projectDir=projectDir) if not res: # make functionality later for restart for the tune variable error('\tCannot continue with the tuning geometry -> Skipping degenerate geometry') - return 0, 0, 0 + return 0, 0, [], [] tv = tuned_cell[indx] @@ -90,19 +90,19 @@ def tune(self, par_mid, par_end, tune_var, target_freq, cell_type, beampipes, bc tv_list.append(tv) # first shot - tv = tv + TUNE_VAR_STEP_DIRECTION_DICT[tune_var]*0.05*tuned_cell[indx] + tv = tv + TUNE_VAR_STEP_DIRECTION_DICT[tune_var] * 0.05 * tuned_cell[indx] tuned_cell[indx] = tv enforce_Req_continuity(mid, left, right, cell_type) # run res = ngsolve_mevp.cavity(1, 1, mid, left, right, - n_modes=1, fid=fid, f_shift=0, bc=bc, beampipes=beampipes, - sim_folder=sim_folder, parentDir=parentDir, projectDir=projectDir) + n_modes=1, fid=fid, f_shift=0, bc=bc, beampipes=beampipes, + sim_folder=sim_folder, parentDir=parentDir, projectDir=projectDir) if not res: # make functionality later for restart for the tune variable error('Cannot continue with the tuning geometry -> Skipping degenerate geometry') - return 0, 0, 0 + return 0, 0, [], [] # get results and compare with set value with open(fr"{projectDir}/SimulationData/{sim_folder}/{fid}/monopole/qois.json") as json_file: @@ -112,7 +112,6 @@ def tune(self, par_mid, par_end, tune_var, target_freq, cell_type, beampipes, bc freq_list.append(freq) tv_list.append(tv) - tol = iter_set[1] tol = 1e-2 # for testing purposes to reduce tuning time. # max_iter = iter_set[2] @@ -125,7 +124,7 @@ def tune(self, par_mid, par_end, tune_var, target_freq, cell_type, beampipes, bc # solve for coefficients coeffs = np.linalg.solve(mat, np.array(tv_list)[-2:]) - max_step = 0.2*tuned_cell[indx] # control order of convergence/stability with maximum step + max_step = 0.2 * tuned_cell[indx] # control order of convergence/stability with maximum step # bound_factor = 0.1 # bound the maximum step if coeffs[0] * target_freq - (tv - coeffs[1]) > max_step: @@ -145,8 +144,8 @@ def tune(self, par_mid, par_end, tune_var, target_freq, cell_type, beampipes, bc # run res = ngsolve_mevp.cavity(1, 1, mid, left, right, - n_modes=1, fid=fid, f_shift=0, bc=bc, beampipes=beampipes, - sim_folder=sim_folder, parentDir=parentDir, projectDir=projectDir) + n_modes=1, fid=fid, f_shift=0, bc=bc, beampipes=beampipes, + sim_folder=sim_folder, parentDir=parentDir, projectDir=projectDir) if not res: # make functionality later for restart for the tune variable error('Cannot continue with the tuning of this geometry -> Skipping degenerate geometry') @@ -188,10 +187,11 @@ def tune(self, par_mid, par_end, tune_var, target_freq, cell_type, beampipes, bc # plt.scatter(tv_list, freq_list) # plt.show() # update convergence list - if conv_list is not None: - conv_list.extend([tv_list, freq_list]) + convergence_list.extend([tv_list, freq_list]) - return tv_list[key], freq_list[key], abs_err_list + # save convergence information + conv_dict = {f'{tune_var}': convergence_list[0], 'freq [MHz]': convergence_list[1]} + return tv_list[key], freq_list[key], conv_dict, abs_err_list @staticmethod def all_equal(iterable): @@ -204,4 +204,3 @@ def write_output(tv_list, freq_list, fid, projectDir): with open(fr"{projectDir}\SimulationData\SLANS_opt\{fid}\convergence_output.json", "w") as outfile: json.dump(dd, outfile, indent=4, separators=(',', ': ')) - diff --git a/cavsim2d/analysis/tune/tuner.py b/cavsim2d/analysis/tune/tuner.py index b9dce93..5a2d291 100644 --- a/cavsim2d/analysis/tune/tuner.py +++ b/cavsim2d/analysis/tune/tuner.py @@ -15,10 +15,11 @@ def __init__(self): pass def tune_ngsolve(self, pseudo_shape_space, bc, parentDir, projectDir, filename, resume="No", - proc=0, sim_folder='NGSolveMEVP', tune_variable='Req', iter_set=None, cell_type='Mid Cell', - progress_list=None, convergence_list=None, save_last=True, n_cell_last_run=1): + proc=0, sim_folder='NGSolveMEVP', tune_variable='Req', cell_type='Mid Cell', + save_last=True, n_cell_last_run=1): # tuner + abs_err_list, conv_dict = [], [] pytune_ngsolve = PyTuneNGSolve() start = time.time() @@ -35,13 +36,12 @@ def tune_ngsolve(self, pseudo_shape_space, bc, parentDir, projectDir, filename, existing_keys = list(population.keys()) - progress = 0 error_msg1 = 1 error_msg2 = 1 for key, pseudo_shape in pseudo_shape_space.items(): - A_i, B_i, a_i, b_i, Ri_i, L_i, Req = pseudo_shape['IC'][:7] - A_o, B_o, a_o, b_o, Ri_o, L_o, Req_o = pseudo_shape['OC'][:7] # Req here is none but required + A_i, B_i, a_i, b_i, Ri_i, L_i, Req = np.array(pseudo_shape['IC'])[:7] + A_o, B_o, a_o, b_o, Ri_o, L_o, Req_o = np.array(pseudo_shape['OC'])[:7] # Req here is none but required beampipes = pseudo_shape['BP'] target_freq = pseudo_shape['FREQ'] @@ -68,14 +68,16 @@ def tune_ngsolve(self, pseudo_shape_space, bc, parentDir, projectDir, filename, # edit to check for key later if key not in existing_keys: try: - tune_var, freq, abs_err_list = pytune_ngsolve.tune(inner_cell, outer_cell, tune_variable, - target_freq, - cell_type, beampipes, bc, sim_folder, - parentDir, projectDir, iter_set=iter_set, - proc=proc, - conv_list=convergence_list) + tune_var, freq, conv_dict, abs_err_list = pytune_ngsolve.tune(inner_cell, outer_cell, + tune_variable, + target_freq, + cell_type, beampipes, bc, + sim_folder, + parentDir, projectDir, + proc=proc) except FileNotFoundError: tune_var, freq = 0, 0 + if tune_var != 0 and freq != 0: if cell_type.lower() == 'mid cell' or cell_type.lower() == 'mid-cell' or cell_type.lower() == 'mid_cell': tuned_mid_cell = pseudo_shape['IC'][:7] @@ -146,14 +148,12 @@ def tune_ngsolve(self, pseudo_shape_space, bc, parentDir, projectDir, filename, d_tune_res = {'IC': list(tuned_mid_cell), 'OC': list(tuned_end_cell), 'OC_R': list(tuned_end_cell), 'TUNED VARIABLE': tune_variable, 'CELL TYPE': cell_type, 'FREQ': freq} - self.save_tune_result(d_tune_res, 'tune_res.json', projectDir, key, sim_folder) + save_tune_result(d_tune_res, 'tune_res.json', projectDir, key, sim_folder) # save convergence information - if convergence_list: - conv_dict = {f'{tune_variable}': convergence_list[0], 'freq [MHz]': convergence_list[1]} - abs_err_dict = {'abs_err': abs_err_list} - self.save_tune_result(conv_dict, 'convergence.json', projectDir, key, sim_folder) - self.save_tune_result(abs_err_dict, 'absolute_error.json', projectDir, key, sim_folder) + abs_err_dict = {'abs_err': abs_err_list} + save_tune_result(conv_dict, 'convergence.json', projectDir, key, sim_folder) + save_tune_result(abs_err_dict, 'absolute_error.json', projectDir, key, sim_folder) done(f'Done Tuning Cavity {key}: {result}') @@ -168,24 +168,10 @@ def tune_ngsolve(self, pseudo_shape_space, bc, parentDir, projectDir, filename, except FileNotFoundError: continue - # update progress - progress_list.append((progress + 1) / total_no_of_shapes) - - # Update progressbar - progress += 1 - - # print("Saving Dictionary", f"shape_space{proc}.json")◙ - # print("Done saving") - end = time.time() runtime = end - start - info(f'\tProcessor {proc} runtime: {runtime} s') - - @staticmethod - def save_tune_result(d, filename, projectDir, key, sim_folder='SLAN_Opt'): - with open(fr"{projectDir}\SimulationData\{sim_folder}\{key}\{filename}", 'w') as file: - file.write(json.dumps(d, indent=4, separators=(',', ': '))) + info(f'\tProcessor {proc} runtime: {runtime}s') # if __name__ == '__main__': # # diff --git a/cavsim2d/analysis/uq/dakota_scripts/generate_nodes.py b/cavsim2d/analysis/uq/dakota_scripts/generate_nodes.py index 2cab879..6be033c 100644 --- a/cavsim2d/analysis/uq/dakota_scripts/generate_nodes.py +++ b/cavsim2d/analysis/uq/dakota_scripts/generate_nodes.py @@ -5,12 +5,13 @@ import numpy as np import pandas as pd +from cavsim2d.utils.shared_functions import * # Get current path sCurPath = os.path.abspath(".") if len(sys.argv) != 3: - print("Usage: python myscript.py param_file output_file partitions") + error("Usage: python myscript.py param_file output_file partitions") sys.exit(1) param_file = sys.argv[1] diff --git a/cavsim2d/analysis/uq/dakota_scripts/py_dakota.py b/cavsim2d/analysis/uq/dakota_scripts/py_dakota.py index 14722bc..36046f4 100644 --- a/cavsim2d/analysis/uq/dakota_scripts/py_dakota.py +++ b/cavsim2d/analysis/uq/dakota_scripts/py_dakota.py @@ -10,7 +10,6 @@ def read_output_from_cst_sweep(sim_folder, folders, requests): d = pd.DataFrame() for folder in folders: d = pd.concat([d, pd.read_csv(fr"{sim_folder}\{folder}\Export\{request}.txt", sep="\t", header=None)]) - # print(d) df_[request] = d.loc[:, 1] @@ -53,12 +52,9 @@ def read_output_from_cst_sweep(sim_folder, folders, requests): df_data = pd.read_excel(fr"{filename}", 'Sheet1', engine='openpyxl') for indx, row in df_data.iterrows(): - # print(indx, row.tolist(), pars_in.tolist()) # match input parameters to output - # print(np.around(row.tolist()[:num_in_vars], 3), np.around(pars_in.tolist(), 3)) tolerance = 1e-3 if np.allclose(np.around(row.tolist()[:num_in_vars], 3), np.around(pars_in.tolist(), 3), rtol=tolerance, atol=tolerance): - print("Got here") # write output out = row.tolist()[num_in_vars:] with open(output_file, 'w') as f: diff --git a/cavsim2d/analysis/uq/dakota_scripts/pycall.py b/cavsim2d/analysis/uq/dakota_scripts/pycall.py index ffcc012..02a9b7e 100644 --- a/cavsim2d/analysis/uq/dakota_scripts/pycall.py +++ b/cavsim2d/analysis/uq/dakota_scripts/pycall.py @@ -4,7 +4,6 @@ # Get current path sCurPath = os.path.abspath(".") -print(sCurPath) # Get the command line arguments passed by DAKOTA num_resp = sys.argv[1] diff --git a/cavsim2d/analysis/uq/dakota_scripts/test_dakotapy/py_dakota.py b/cavsim2d/analysis/uq/dakota_scripts/test_dakotapy/py_dakota.py index fef2ab6..9958801 100644 --- a/cavsim2d/analysis/uq/dakota_scripts/test_dakotapy/py_dakota.py +++ b/cavsim2d/analysis/uq/dakota_scripts/test_dakotapy/py_dakota.py @@ -10,7 +10,6 @@ def read_output_from_cst_sweep(sim_folder, folders, requests): d = pd.DataFrame() for folder in folders: d = pd.concat([d, pd.read_csv(fr"{sim_folder}\{folder}\Export\{request}.txt", sep="\t", header=None)]) - # print(d) df_[request] = d.loc[:, 1] diff --git a/cavsim2d/analysis/uq/dakota_scripts/test_dakotapy/pycall.py b/cavsim2d/analysis/uq/dakota_scripts/test_dakotapy/pycall.py index 7fbcbcd..fa73d51 100644 --- a/cavsim2d/analysis/uq/dakota_scripts/test_dakotapy/pycall.py +++ b/cavsim2d/analysis/uq/dakota_scripts/test_dakotapy/pycall.py @@ -5,8 +5,6 @@ # Get current path sCurPath = os.path.abspath(".") -print(sCurPath) - # Get the command line arguments passed by DAKOTA num_resp = sys.argv[1] nodes_only = sys.argv[2] diff --git a/cavsim2d/analysis/uq/dakota_scripts/write_dakota_input.py b/cavsim2d/analysis/uq/dakota_scripts/write_dakota_input.py index 212ed2b..420c1c0 100644 --- a/cavsim2d/analysis/uq/dakota_scripts/write_dakota_input.py +++ b/cavsim2d/analysis/uq/dakota_scripts/write_dakota_input.py @@ -13,7 +13,7 @@ def write_input_file(self, kind, descriptors, responses, **kwargs): try: os.mkdir(os.path.join(self.folder, self.name)) except: - print("Could not create folder. Make sure target location exists.") + error("Could not create folder. Make sure target location exists.") with open(os.path.join(self.folder, self.name, f'{self.name}.in'), 'w') as f: self.environment(f) diff --git a/cavsim2d/analysis/wakefield/abci_code.py b/cavsim2d/analysis/wakefield/abci_code.py index 8428f93..047f564 100644 --- a/cavsim2d/analysis/wakefield/abci_code.py +++ b/cavsim2d/analysis/wakefield/abci_code.py @@ -104,7 +104,6 @@ def abci_bp_L(self, n, zr12_BPL, WG_L, f): """ # N1 Z R Alfa Mesh_thick Jx Jy BC_sign Vol_sign - # print("\t\tABCI_BPL::It got here") f.write('-3., 0.000\n') f.write('{} {}\n'.format(self.Rbp_L - self.c_L, WG_L - self.x_L)) f.write('{} {}\n'.format(zr12_BPL[0][1], WG_L - self.x_L + zr12_BPL[0][0])) @@ -137,7 +136,6 @@ def abci_n1_L(self, n, zr12_L, WG_L, f): ------- """ - # print("\t\tABCI_N1_L::It got here") f.write('-3., 0.000\n') f.write('{} {}\n'.format(self.ri_L + self.b_L, WG_L)) f.write('{} {}\n'.format(zr12_L[1][1], WG_L + self.L_L - zr12_L[1][0])) @@ -171,7 +169,6 @@ def abci_n1_R(self, n, zr12_R, WG_L, f): """ # N1 Z R Alfa Mesh_thick Jx Jy BC_sign Vol_sign - # print("\t\tABCI_N1_R::It got here") if n == 1: f.write('-3., 0.000\n') f.write('{} {}\n'.format(self.Req_L - self.B_R, WG_L + self.L_L)) @@ -214,7 +211,6 @@ def abci_bp_R(self, n, zr12_BPR, WG_L, f): """ # N1 Z R Alfa Mesh_thick Jx Jy BC_sign Vol_sign - # print("\t\tABCI_BPR::It got here") if n == 1: f.write('-3., 0.000\n') f.write('{} {}\n'.format(self.ri_R + self.bt_R, WG_L + self.L_L + self.L_R)) @@ -266,7 +262,6 @@ def abci_M(self, n, zr12_M, WG_L, f, i, end_type): ------- """ - # print("\t\tABCI_M::It got here") # Left and right Cell # First Half cell if i == 1 and end_type == 1: @@ -502,7 +497,6 @@ def abci_bp_L(self, n, zr12_BPL, WG_L, f): """ # N1 Z R Alfa Mesh_thick Jx Jy BC_sign Vol_sign - # print("\t\tABCI_BPL::It got here") f.write('-3., 0.000\n') f.write('{} {}\n'.format(self.Rbp_L - self.c_L, WG_L - self.x_L)) f.write('{} {}\n'.format(zr12_BPL[0][1], WG_L - self.x_L + zr12_BPL[0][0])) @@ -535,7 +529,6 @@ def abci_n1_L(self, n, zr12_L, WG_L, f): ------- """ - # print("\t\tABCI_N1_L::It got here") f.write('-3., 0.000\n') f.write('{} {}\n'.format(self.ri_L + self.b_L, WG_L)) f.write('{} {}\n'.format(zr12_L[1][1], WG_L + self.L_L - zr12_L[1][0])) @@ -569,7 +562,6 @@ def abci_n1_R(self, n, zr12_R, WG_L, f): """ # N1 Z R Alfa Mesh_thick Jx Jy BC_sign Vol_sign - # print("\t\tABCI_N1_R::It got here") if n == 1: f.write('-3., 0.000\n') f.write('{} {}\n'.format(self.Req_L - self.B_R, WG_L + self.L_L + self.l_L)) @@ -614,7 +606,6 @@ def abci_bp_R(self, n, zr12_BPR, WG_L, f): """ # N1 Z R Alfa Mesh_thick Jx Jy BC_sign Vol_sign - # print("\t\tABCI_BPR::It got here") if n == 1: f.write('-3., 0.000\n') f.write('{} {}\n'.format(self.ri_R + self.bt_R, WG_L + self.L_L + self.l_L + self.L_R)) @@ -666,7 +657,6 @@ def abci_M(self, n, zr12_M, WG_L, f, i, end_type): ------- """ - # print("\t\tABCI_M::It got here") # Left and right Cell # First Half cell if i == 1 and end_type == 1: diff --git a/cavsim2d/analysis/wakefield/abci_geometry.py b/cavsim2d/analysis/wakefield/abci_geometry.py index aea3c31..ed4d93b 100644 --- a/cavsim2d/analysis/wakefield/abci_geometry.py +++ b/cavsim2d/analysis/wakefield/abci_geometry.py @@ -4,6 +4,7 @@ from pathlib import Path from cavsim2d.analysis.wakefield.geometry import Geometry from cavsim2d.analysis.wakefield.abci_code import ABCI, ABCI_flattop +from cavsim2d.utils.shared_functions import error class ABCIGeometry(Geometry): @@ -73,7 +74,6 @@ def cavity(self, no_of_cells, no_of_modules, if WG_M == '': WG_M = self.WG_L - # print(WG_M) self.abci = ABCI(self.left_beam_pipe, self.left_end_cell, self.mid_cell, self.right_end_cell, self.right_beam_pipe) @@ -141,11 +141,9 @@ def cavity(self, no_of_cells, no_of_modules, run_save_directory = projectDir / Path(fr'SimulationData/ABCI/{sub_dir}\{fid}') fname = Path(fr'{run_save_directory}/Cavity_MROT_{MROT}.abc') - # print('filename:: ', fname) L_all_increment = 0 self.L_all = 0 - # print(fname) with open(fname, 'w') as f: f.write(f' &FILE LSAV = .{LSAV}., ITEST = 0, LREC = .F., LCPUTM = .{LCPUTM}. &END \n') f.write(' SAMPLE INPUT #1 A SIMPLE CAVITY STRUCTURE \n') @@ -177,7 +175,7 @@ def cavity(self, no_of_cells, no_of_modules, f.write('{} {} \n'.format(self.ri_L, self.WG_L + (i_mode - 1) * self.L_all)) if self.Req_L != self.Req_R: - print('Error:: The equator radius of left and right cell are not equal') + error('Error:: The equator radius of left and right cell are not equal') # if exist('L_M') != 1: # L_M = [] @@ -185,7 +183,6 @@ def cavity(self, no_of_cells, no_of_modules, if end_L == 2: self.abci.abci_bp_L(n, zr12_BPL, self.WG_L + (i_mode - 1) * self.L_all, f) - # print("GUI_ABCI::It got here") self.abci.abci_n1_L(n, zr12_L, self.WG_L + (i_mode - 1) * self.L_all, f) self.abci.abci_n1_R(n, zr12_R, self.WG_L + (i_mode - 1) * self.L_all, f) @@ -210,7 +207,6 @@ def cavity(self, no_of_cells, no_of_modules, if n > 1: for i_mode in range(1, module_nu + 1): - # print("imode:", i_mode, i_mode) # change waveguide length if module_nu == 2: if i_mode == 1: @@ -228,7 +224,6 @@ def cavity(self, no_of_cells, no_of_modules, self.WG_R = 4 * self.L_M # Total length of each cavity L_all_increment = self.WG_L + self.WG_R + self.L_L + self.L_R + 2 * (n - 1) * self.L_M - # print(self.WG_L, self.WG_R, WG_M, self.L_all) if i_mode > 1: if self.WG_L > 0: @@ -292,9 +287,7 @@ def cavity(self, no_of_cells, no_of_modules, f'LSVWA = .{LSVWA}., LSVWT = .{LSVWT}., LSVWL = .{LSVWL}., LSVF = .{LSVF}. &END\n') f.write('\nSTOP\n') - print(parentDir, projectDir) exe_path = os.path.join(parentDir / Path(fr'solvers/ABCI/ABCI_MP64+.exe')) - print('\t', exe_path, run_save_directory) if LCPUTM == 'T': subprocess.call([exe_path, Path(fr'{run_save_directory}/Cavity_MROT_{MROT}.abc')]) else: @@ -366,7 +359,6 @@ def cavity_flattop(self, no_of_cells, no_of_modules, if WG_M == '': WG_M = self.WG_L - # print(WG_M) self.abci = ABCI_flattop(self.left_beam_pipe, self.left_end_cell, self.mid_cell, self.right_end_cell, self.right_beam_pipe) @@ -417,12 +409,6 @@ def cavity_flattop(self, no_of_cells, no_of_modules, if end_R == 2: zr12_BPR, alpha_BPR = self.abci.rz_conjug('right') # zr12_R first column is z , second column is r - - # print("GUI_ABCI:: zr12_L", zr12_L) - # print("GUI_ABCI:: zr12_R", zr12_R) - # # print("GUI_ABCI:: zr12_BPL", zr12_BPL) - # # print("GUI_ABCI:: zr12_BPR", zr12_BPR) - # print("GUI_ABCI:: zr12_M", zr12_M) # # Write ABCI code # create folder for file output set diff --git a/cavsim2d/analysis/wakefield/geometry.py b/cavsim2d/analysis/wakefield/geometry.py index 58204db..4a503a0 100644 --- a/cavsim2d/analysis/wakefield/geometry.py +++ b/cavsim2d/analysis/wakefield/geometry.py @@ -29,7 +29,6 @@ def __init__(self): self.u = None def set_geom_parameters(self, n_cells, mid_cells_par=None, l_end_cell_par=None, r_end_cell_par=None): - # print(n_cells, mid_cells_par, l_end_cell_par, r_end_cell_par) if l_end_cell_par is None: l_end_cell_par = [] @@ -39,7 +38,6 @@ def set_geom_parameters(self, n_cells, mid_cells_par=None, l_end_cell_par=None, self.cell_structure = 2 self.n = n_cells - # print("Sets value") self.A_M, self.B_M, self.a_M, self.b_M, self.ri_M, self.L_M, self.Req_M = \ [i * self.u for i in mid_cells_par][0:7] self.A_L, self.B_L, self.a_L, self.b_L, self.ri_L, self.L_L, self.Req_L = \ @@ -57,7 +55,6 @@ def set_geom_parameters(self, n_cells, mid_cells_par=None, l_end_cell_par=None, self.mid_cell = [self.Req_M, self.ri_M, self.L_M, self.A_M, self.B_M, self.a_M, self.b_M] self.left_end_cell = [self.Req_L, self.ri_L, self.L_L, self.A_L, self.B_L, self.a_L, self.b_L] self.right_end_cell = [self.Req_R, self.ri_R, self.L_R, self.A_R, self.B_R, self.a_R, self.b_R] - # print(self.mid_cell) # beam pipe self.WG_L = 4 * self.L_M # self.ui.dsb_Lbp_L.value()*self.u # Length of the beam pipe connecting to the cavity @@ -84,7 +81,6 @@ def set_geom_parameters(self, n_cells, mid_cells_par=None, l_end_cell_par=None, # Slans mesh parameters self.WG_mesh = round(self.WG_L / 5) * self.u # /5 for ende_type 1 - # print(self.L_M, self.WG_L, self.WG_mesh) self.Jxy = 44 # 60 for end type 1 self.Jx1 = round((19 / 50) * self.Jxy) # 19/50 for end_type 1 self.Jx2 = self.Jxy / 2 - self.Jx1 @@ -107,7 +103,6 @@ def set_geom_parameters(self, n_cells, mid_cells_par=None, l_end_cell_par=None, self.Jxy_all_bp = [0, self.Jxy_bp, self.Jx1_bp, self.Jx2_bp, self.Jy0_bp, self.Jy1_bp, self.Jy2_bp, self.Jy3_bp] def set_geom_parameters_flattop(self, n_cells, mid_cells_par=None, l_end_cell_par=None, r_end_cell_par=None): - # print(n_cells, mid_cells_par, l_end_cell_par, r_end_cell_par) if l_end_cell_par is None: l_end_cell_par = [] @@ -117,7 +112,6 @@ def set_geom_parameters_flattop(self, n_cells, mid_cells_par=None, l_end_cell_pa self.cell_structure = 2 self.n = n_cells - # print("Sets value") self.A_M, self.B_M, self.a_M, self.b_M, self.ri_M, self.L_M, self.Req_M, self.l_M = \ [i * self.u for i in mid_cells_par][0:8] self.A_L, self.B_L, self.a_L, self.b_L, self.ri_L, self.L_L, self.Req_L, self.l_L = \ @@ -135,7 +129,6 @@ def set_geom_parameters_flattop(self, n_cells, mid_cells_par=None, l_end_cell_pa self.mid_cell = [self.Req_M, self.ri_M, self.L_M, self.A_M, self.B_M, self.a_M, self.b_M, self.l_M] self.left_end_cell = [self.Req_L, self.ri_L, self.L_L, self.A_L, self.B_L, self.a_L, self.b_L, self.l_L] self.right_end_cell = [self.Req_R, self.ri_R, self.L_R, self.A_R, self.B_R, self.a_R, self.b_R, self.l_R] - # print(self.mid_cell) # beam pipe self.WG_L = 4 * self.L_M # self.ui.dsb_Lbp_L.value()*self.u # Length of the beam pipe connecting to the cavity @@ -164,7 +157,6 @@ def set_geom_parameters_flattop(self, n_cells, mid_cells_par=None, l_end_cell_pa self.WG_mesh = round(self.WG_L / 5) * self.u # /5 for ende_type 1 # def write_cst_paramters(self, fid): - # print("Writing parameters to file") # cwd = os.getcwd() # # print(path) @@ -184,10 +176,8 @@ def set_geom_parameters_flattop(self, n_cells, mid_cells_par=None, l_end_cell_pa # for i in range(len(name_list)): # f.write("{}={}\n".format(name_list[i], value_list[i])) # - # print("Writing to file complete.") # # def write_cst_paramters_mid(self, fid): - # print("Writing parameters to file") # cwd = os.getcwd() # print(cwd) # diff --git a/cavsim2d/cavity.py b/cavsim2d/cavity.py index 51056ca..a3403f8 100644 --- a/cavsim2d/cavity.py +++ b/cavsim2d/cavity.py @@ -50,6 +50,9 @@ class Optimisation: def __init__(self): + self.mid_cell = None + self.wakefield_config = None + self.tune_config = None self.f2_interp = None self.processes_count = None self.method = None @@ -57,7 +60,7 @@ def __init__(self): self.crossover_factor = None self.elites_to_crossover = None self.chaos_factor = None - self.tune_variable = None + self.tune_parameter = None self.uq_config = None self.constraints = None self.df = None @@ -89,9 +92,8 @@ def start_optimisation(self, projectDir, config): # apply optimisation settings self.parentDir = os.getcwd() self.projectDir = projectDir - self.initial_points = config['initial points'] - self.tune_freq = config['tune freq.'] - self.ng_max = config['no. of generation'] + self.initial_points = config['initial_points'] + self.ng_max = config['no_of_generation'] self.objectives_unprocessed = config['objectives'] self.objectives, weights = self.process_objectives(config['objectives']) self.objective_vars = [obj[1] for obj in self.objectives] @@ -100,12 +102,11 @@ def start_optimisation(self, projectDir, config): assert len(self.weights) == len(weights), \ ("Length of delta must be equal to the length of the variables. For impedance Z entries, one less than" "the length of the interval list weights are needed. Eg. for ['min', 'ZL', [1, 2, 3]], two weights are" - "required. ") + " required. ") else: self.weights = weights self.bounds = config['bounds'] - self.cell_type = config['cell type'] self.constraints = self.process_constraints(config['constraints']) self.processes_count = 1 if 'processes' in config.keys(): @@ -114,18 +115,39 @@ def start_optimisation(self, projectDir, config): self.processes_count = config['processes'] self.method = config['method'] - self.mutation_factor = config['mutation factor'] - self.crossover_factor = config['crossover factor'] - self.elites_to_crossover = config['elites for crossover'] - self.chaos_factor = config['chaos factor'] - self.tune_variable = config['tune variable'] + self.mutation_factor = config['mutation_factor'] + self.crossover_factor = config['crossover_factor'] + self.elites_to_crossover = config['elites_for_crossover'] + self.chaos_factor = config['chaos_factor'] if 'uq' in config.keys(): - self.uq_config = config['uq'] + self.uq_config = config['uq_config'] if self.uq_config['delta']: assert len(self.uq_config['delta']) == len(self.uq_config['variables']), error( "The number of deltas must " "be equal to the number of " "variables.") + self.tune_config = config['tune_config'] + tune_config_keys = self.tune_config.keys() + assert 'freqs' in tune_config_keys, error('Please enter the target tune frequency.') + assert 'parameters' in tune_config_keys, error('Please enter the tune variable in tune_config_dict') + assert 'cell_types' in tune_config_keys, error('Please enter the cell_type in tune_config_dict') + + self.cell_type = self.tune_config['cell_types'] + cts = ['end-cell', 'mid-end-cell', 'end-mid-cell', 'end_cell', 'mid_end_cell', 'end_mid_cell'] + if self.cell_type in cts: + assert 'mid-cell' in config.keys(), error('To optimise an end-cell, mid cell dimensions are required') + assert len(config['mid-cell']) >= 7, error('Incomplete mid cell dimension.') + self.mid_cell = config['mid-cell'] + + self.tune_parameter = self.tune_config['parameters'] + self.tune_freq = self.tune_config['freqs'] + + self.wakefield_config = {} + if any(['ZL' in obj for obj in self.objective_vars]) or any(['ZT' in obj for obj in self.objective_vars]): + assert 'wakefield_config' in config.keys(), error('Wakefield impedance objective detected in objectives. ' + 'Please include a field for wakefield_config. An empty' + ' config entry implies that default values will be used.') + self.wakefield_config = config['wakefield_config'] self.df = None @@ -211,7 +233,8 @@ def ea(self, n, bar): # run tune n_cells = 1 - self.run_tune_parallel(pseudo_shape_space, n_cells) + # self.run_tune_parallel(pseudo_shape_space, n_cells) + self.run_tune_opt(pseudo_shape_space, self.tune_config) # get successfully tuned geometries and filter initial generation dictionary processed_keys = [] tune_result = [] @@ -223,7 +246,7 @@ def ea(self, n, bar): # get only tune_variable, alpha_i, and alpha_o and freq but why these quantities freq = tune_res['FREQ'] - tune_variable_value = tune_res['IC'][VAR_TO_INDEX_DICT[self.tune_variable]] + tune_variable_value = tune_res['IC'][VAR_TO_INDEX_DICT[self.tune_parameter]] alpha_i = tune_res['IC'][7] alpha_o = tune_res['IC'][7] @@ -234,7 +257,7 @@ def ea(self, n, bar): # after removing duplicates, dataframe might change size df = df.loc[df['key'].isin(processed_keys)] - df.loc[:, [self.tune_variable, 'alpha_i', 'alpha_o', 'freq [MHz]']] = tune_result + df.loc[:, [self.tune_parameter, 'alpha_i', 'alpha_o', 'freq [MHz]']] = tune_result # eigen objective variables # for o in self.objectives: @@ -322,7 +345,7 @@ def ea(self, n, bar): for o in self.objectives: if "ZL" in o[1] or "ZT" in o[1] or "k_loss" in o[1] or "k_kick" in o[1]: # run wakefield analysis and return shape space - wake_shape_space = self.run_wakefield_parallel(df) + wake_shape_space = self.run_wakefield_opt(df, self.wakefield_config) # process wakefield results df_wake, processed_keys = self.get_wakefield_objectives_value(wake_shape_space, @@ -408,8 +431,7 @@ def ea(self, n, bar): uq_column_names.append(fr'|E[{o[1]}] - {o[2]}| + std[{o[1]}]') df_uq = pd.DataFrame.from_dict(uq_result_dict, orient='index') - # print(uq_column_names) - # print(df_uq) + df_uq.columns = uq_column_names df_uq.index.name = 'key' df_uq.reset_index(inplace=True) @@ -439,7 +461,8 @@ def ea(self, n, bar): # rank shapes by objectives for i, obj in enumerate(self.objectives): - if self.uq_config['option']: + + if self.uq_config: if obj[0] == "min": df[f'rank_E[{obj[1]}] + 6*std[{obj[1]}]'] = df[fr'E[{obj[1]}] + 6*std[{obj[1]}]'].rank() * \ self.weights[i] @@ -493,7 +516,6 @@ def ea(self, n, bar): if i != 0: pareto_shapes = df.loc[pareto_indx_list, [obj0, obj[1]]] pareto_shapes_sorted = pareto_shapes.sort_values(obj0) - print(pareto_shapes) f1 = np.linspace(min(pareto_shapes[obj0]), max(pareto_shapes[obj0]), self.n_interp) f2_interp = np.interp(f1, pareto_shapes_sorted[obj0], pareto_shapes_sorted[obj[1]]) rel_error = np.linalg.norm(f2_interp - self.f2_interp[i]) / max(np.abs(f2_interp)) @@ -533,6 +555,7 @@ def ea(self, n, bar): error("Unfortunately, none survived the constraints and the program has to end. " "Can't even say that this was a good run.") return + done(self.df_global) # save dataframe filename = fr"{self.projectDir}\SimulationData\Optimisation\Generation{n}.xlsx" @@ -633,7 +656,6 @@ def run_uq(self, df, objectives, solver_dict, solver_args_dict, uq_config): else: shape_space[f'{index}'] = {'IC': rw, 'OC': rw, 'OC_R': rw} - uq_ngsolve_parallel(shape_space, objectives, solver_dict, solver_args_dict, uq_config) return shape_space @@ -1086,71 +1108,161 @@ def weighted_mean_obj(self, tab_var, weights): else: expe = 0 stdDev = 0 - print('Cols_sims_no != No_weights') + error('Cols_sims_no != No_weights') return list(expe.T[0]), list(stdDev.T[0]) - def run_tune_parallel(self, pseudo_shape_space, n_cells): - # split shape_space for different processes/ MPI share process by rank - keys = list(pseudo_shape_space.keys()) + def run_tune_opt(self, pseudo_shape_space, tune_config): + tune_config_keys = tune_config.keys() + freqs = tune_config['freqs'] + tune_parameters = tune_config['parameters'] + cell_types = tune_config['cell_types'] + + # perform all necessary checks + if 'processes' in tune_config.keys(): + processes = tune_config['processes'] + assert processes > 0, error('Number of proceses must be greater than zero.') + else: + processes = 1 - # check if number of processors selected is greater than the number of keys in the pseudo shape space - if self.processes_count > len(keys): - self.processes_count = len(keys) + if isinstance(freqs, float) or isinstance(freqs, int): + freqs = np.array([freqs for _ in range(len(pseudo_shape_space))]) + else: + assert len(freqs) == len(pseudo_shape_space), error( + 'Number of target frequencies must correspond to the number of cavities') + freqs = np.array(freqs) - shape_space_len = len(keys) - share = floor(shape_space_len / self.processes_count) + if isinstance(tune_parameters, str): + assert tune_config['parameters'] in ['A', 'B', 'a', 'b', 'Ri', 'L', 'Req'], error( + 'Please enter a valid tune parameter') + tune_variables = np.array([tune_parameters for _ in range(len(pseudo_shape_space))]) + cell_types = np.array([cell_types for _ in range(len(pseudo_shape_space))]) + else: + assert len(tune_parameters) == len(pseudo_shape_space), error( + 'Number of tune parameters must correspond to the number of cavities') + assert len(cell_types) == len(pseudo_shape_space), error( + 'Number of cell types must correspond to the number of cavities') + tune_variables = np.array(tune_parameters) + cell_types = np.array(cell_types) - jobs = [] - for p in range(self.processes_count): - if True: - if p < self.processes_count - 1: - proc_keys_list = keys[p * share:p * share + share] - else: - proc_keys_list = keys[p * share:] - - # self.overwriteFolder(p, self.projectDir) - # self.copyFiles(p, self.parentDir, self.projectDir) - - processor_shape_space = {} - for key, val in pseudo_shape_space.items(): - if key in proc_keys_list: - # check if folder exists - if not os.path.exists( - fr'{self.projectDir}\SimulationData\Optimisation\{key}\monopole\qois.json'): - processor_shape_space[key] = val - - tune_variable = self.tune_variable - service = mp.Process(target=self.run_sequential, - args=(processor_shape_space, "No", p, 33, self.parentDir, - self.projectDir, "EA.json", 'Optimisation', - tune_variable, ["Linear Interpolation", 1e-4, 10], self.cell_type, [], - None, True, n_cells)) - service.start() - jobs.append(service) - - for j in jobs: - j.join() - - def run_wakefield_parallel(self, df): - # get analysis parameters - n_cells = 5 - n_modules = 1 - - # change later - WG_M = [''] # half length of beam pipe between cavities in module - - # change all of these later - MROT = 2 # run both longitudinal and transverse wakefield analysis - MT = 4 # number of time steps for a beam to move one cell to another default = 3 + run_tune_parallel(pseudo_shape_space, tune_variables, freqs, cell_types, self.projectDir, + solver='NGSolveMEVP', resume=False, + n_cells=1, processes=processes, rerun=True) + + # def run_tune_parallel(self, pseudo_shape_space, n_cells): + # # split shape_space for different processes/ MPI share process by rank + # keys = list(pseudo_shape_space.keys()) + # + # # check if number of processors selected is greater than the number of keys in the pseudo shape space + # if self.processes_count > len(keys): + # self.processes_count = len(keys) + # + # shape_space_len = len(keys) + # share = floor(shape_space_len / self.processes_count) + # + # jobs = [] + # for p in range(self.processes_count): + # if True: + # if p < self.processes_count - 1: + # proc_keys_list = keys[p * share:p * share + share] + # else: + # proc_keys_list = keys[p * share:] + # + # processor_shape_space = {} + # for key, val in pseudo_shape_space.items(): + # if key in proc_keys_list: + # # check if folder exists + # if not os.path.exists( + # fr'{self.projectDir}\SimulationData\Optimisation\{key}\monopole\qois.json'): + # processor_shape_space[key] = val + # + # tune_parameter = self.tune_parameter + # service = mp.Process(target=self.run_sequential, + # args=(processor_shape_space, "No", p, 33, self.parentDir, + # self.projectDir, "EA.json", 'Optimisation', + # tune_variable, ["Linear Interpolation", 1e-4, 10], self.cell_type, [], + # None, True, n_cells)) + # service.start() + # jobs.append(service) + # + # for j in jobs: + # j.join() + + def run_wakefield_opt(self, df, wakefield_config): + # # get analysis parameters + # n_cells = 5 + # n_modules = 1 + # + # # change later + # WG_M = [''] # half length of beam pipe between cavities in module + # + # # change all of these later + # MROT = 2 # run both longitudinal and transverse wakefield analysis + # MT = 4 # number of time steps for a beam to move one cell to another default = 3 + # bunch_length = 25 + # NFS = 10000 # Number of samples in FFT (max 10000) + # UBT = 50 # Wakelength in m + # DDZ_SIG = 0.1 + # DDR_SIG = 0.1 + # proc_count = self.processes_count + + # get geometric parameters + + wakefield_config_keys = wakefield_config.keys() + MROT = 2 + MT = 10 + NFS = 10000 + wakelength = 50 bunch_length = 25 - NFS = 10000 # Number of samples in FFT (max 10000) - UBT = 50 # Wakelength in m - DDZ_SIG = 0.1 DDR_SIG = 0.1 - proc_count = self.processes_count + DDZ_SIG = 0.1 - # get geometric parameters + # check inputs + if 'bunch_length' in wakefield_config_keys: + assert not isinstance(wakefield_config['bunch_length'], str), error( + 'Bunch length must be of type integer or float.') + else: + wakefield_config['bunch_length'] = bunch_length + if 'wakelength' in wakefield_config_keys: + assert not isinstance(wakefield_config['wakelength'], str), error( + 'Wakelength must be of type integer or float.') + else: + wakefield_config['wakelength'] = wakelength + + processes = 1 + if 'processes' in wakefield_config.keys(): + assert wakefield_config['processes']> 0, error('Number of proceses must be greater than zero.') + processes = wakefield_config['processes'] + else: + wakefield_config['processes'] = processes + + rerun = True + if 'rerun' in wakefield_config_keys: + if isinstance(wakefield_config['rerun'], bool): + rerun = wakefield_config['rerun'] + + if 'polarisation' in wakefield_config_keys: + assert wakefield_config['polarisation'] in [0, 1, 2], error('Polarisation should be 0 for longitudinal, ' + '1 for transverse, 2 for both.') + else: + wakefield_config['polarisation'] = MROT + + if 'MT' in wakefield_config_keys: + assert isinstance(wakefield_config['MT'], int), error('MT must be integer between 4 and 20, with 4 and 20 ' + 'included.') + else: + wakefield_config['MT'] = MT + + if 'NFS' in wakefield_config_keys: + assert isinstance(wakefield_config['NFS'], int), error('NFS must be integer.') + else: + wakefield_config['NFS'] = NFS + + if 'DDR_SIG' not in wakefield_config_keys: + wakefield_config['DDR_SIG'] = DDR_SIG + + if 'DDZ_SIG' not in wakefield_config_keys: + wakefield_config['DDZ_SIG'] = DDZ_SIG df = df.loc[:, ['key', 'A', 'B', 'a', 'b', 'Ri', 'L', 'Req', "alpha_i", "alpha_o"]] shape_space = {} @@ -1159,63 +1271,107 @@ def run_wakefield_parallel(self, df): rw = row.tolist() if self.cell_type.lower() == 'end-mid Cell': - A_i = self.check_input(self.ui.le_A_i_opt.text())[0] - B_i = self.check_input(self.ui.le_B_i_opt.text())[0] - a_i = self.check_input(self.ui.le_a_i_opt.text())[0] - b_i = self.check_input(self.ui.le_b_i_opt.text())[0] - Ri_i = self.check_input(self.ui.le_Ri_i_opt.text())[0] - L_i = self.check_input(self.ui.le_L_i_opt.text())[0] - Req_i = self.check_input(self.ui.le_Req_i_opt.text())[0] - alpha_i = self.check_input(self.ui.le_Alpha_opt.text())[0] + A_i, B_i, a_i, b_i, Ri_i , L_i, Req_i = self.mid_cell - IC = [A_i, B_i, a_i, b_i, Ri_i, L_i, Req_i, alpha_i] + IC = [A_i, B_i, a_i, b_i, Ri_i, L_i, Req_i] - shape_space[f'{index}'] = {'IC': IC, 'OC': rw, 'OC_R': rw} + shape_space[f'{index}'] = {'IC': IC, 'OC': rw, 'OC_R': rw, 'n_cells': 1} else: - shape_space[f'{index}'] = {'IC': rw, 'OC': rw, 'OC_R': rw} - - # print(shape_space) - - # shape_space = self.get_geometric_parameters('ABCI') - - # split shape_space for different processes/ MPI share process by rank - keys = list(shape_space.keys()) - shape_space_len = len(keys) - share = round(shape_space_len / proc_count) + shape_space[f'{index}'] = {'IC': rw, 'OC': rw, 'OC_R': rw, 'n_cells': 1} - jobs = [] - for p in range(proc_count): - try: - if p < proc_count - 1: - proc_keys_list = keys[p * share:p * share + share] - else: - proc_keys_list = keys[p * share:] - - processor_shape_space = {} - for key, val in shape_space.items(): - if key in proc_keys_list: - processor_shape_space[key] = val - - service = mp.Process(target=run_sequential_wakefield, - args=(n_cells, n_modules, processor_shape_space, - MROT, MT, NFS, UBT, bunch_length, - DDR_SIG, DDZ_SIG, - self.parentDir, - self.projectDir, [], - '', '' - )) - - service.start() - jobs.append(service) - except Exception as e: - print(f"Exception in run_MP for wakefield analysis:: {e}") + shape_space_multicell = {} + for key, shape in shape_space.items(): + shape_space_multicell[key] = to_multicell(1, shape) - for p in jobs: - p.join() + run_wakefield_parallel(shape_space, shape_space_multicell, wakefield_config, + self.projectDir, marker='', rerun=rerun) - jobs = [] return shape_space + # def run_wakefield_parallel(self, df): + # # get analysis parameters + # n_cells = 5 + # n_modules = 1 + # + # # change later + # WG_M = [''] # half length of beam pipe between cavities in module + # + # # change all of these later + # MROT = 2 # run both longitudinal and transverse wakefield analysis + # MT = 4 # number of time steps for a beam to move one cell to another default = 3 + # bunch_length = 25 + # NFS = 10000 # Number of samples in FFT (max 10000) + # UBT = 50 # Wakelength in m + # DDZ_SIG = 0.1 + # DDR_SIG = 0.1 + # proc_count = self.processes_count + # + # # get geometric parameters + # df = df.loc[:, ['key', 'A', 'B', 'a', 'b', 'Ri', 'L', 'Req', "alpha_i", "alpha_o"]] + # shape_space = {} + # + # df = df.set_index('key') + # for index, row in df.iterrows(): + # rw = row.tolist() + # if self.cell_type.lower() == 'end-mid Cell': + # + # A_i = self.check_input(self.ui.le_A_i_opt.text())[0] + # B_i = self.check_input(self.ui.le_B_i_opt.text())[0] + # a_i = self.check_input(self.ui.le_a_i_opt.text())[0] + # b_i = self.check_input(self.ui.le_b_i_opt.text())[0] + # Ri_i = self.check_input(self.ui.le_Ri_i_opt.text())[0] + # L_i = self.check_input(self.ui.le_L_i_opt.text())[0] + # Req_i = self.check_input(self.ui.le_Req_i_opt.text())[0] + # alpha_i = self.check_input(self.ui.le_Alpha_opt.text())[0] + # + # IC = [A_i, B_i, a_i, b_i, Ri_i, L_i, Req_i, alpha_i] + # + # shape_space[f'{index}'] = {'IC': IC, 'OC': rw, 'OC_R': rw} + # else: + # shape_space[f'{index}'] = {'IC': rw, 'OC': rw, 'OC_R': rw} + # + # # print(shape_space) + # + # # shape_space = self.get_geometric_parameters('ABCI') + # + # # split shape_space for different processes/ MPI share process by rank + # keys = list(shape_space.keys()) + # shape_space_len = len(keys) + # share = round(shape_space_len / proc_count) + # + # jobs = [] + # for p in range(proc_count): + # try: + # if p < proc_count - 1: + # proc_keys_list = keys[p * share:p * share + share] + # else: + # proc_keys_list = keys[p * share:] + # + # processor_shape_space = {} + # for key, val in shape_space.items(): + # if key in proc_keys_list: + # processor_shape_space[key] = val + # + # service = mp.Process(target=run_sequential_wakefield, + # args=(n_cells, n_modules, processor_shape_space, + # MROT, MT, NFS, UBT, bunch_length, + # DDR_SIG, DDZ_SIG, + # self.parentDir, + # self.projectDir, [], + # '', '' + # )) + # + # service.start() + # jobs.append(service) + # except Exception as e: + # print(f"Exception in run_MP for wakefield analysis:: {e}") + # + # for p in jobs: + # p.join() + # + # jobs = [] + # return shape_space + def generate_first_men(self, initial_points, n): if list(self.method.keys())[0] == "LHS": @@ -1697,7 +1853,7 @@ def crossover(self, df, generation, f): # , rq, grq elites = {} for i, o in enumerate(self.objectives): - if self.uq_config['option']: + if self.uq_config: if o[0] == "min": elites[f'E[{o[1]}] + 6*std[{o[1]}]'] = df.sort_values(f'E[{o[1]}] + 6*std[{o[1]}]') elif o[0] == "max": @@ -1717,7 +1873,7 @@ def crossover(self, df, generation, f): # , rq, grq obj_dict = {} for o in self.objectives: - if self.uq_config['option']: + if self.uq_config: if o[0] == 'min': obj_dict[fr'E[{o[1]}] + 6*std[{o[1]}]'] = elites[fr'E[{o[1]}] + 6*std[{o[1]}]'] elif o[0] == 'max': @@ -1753,7 +1909,7 @@ def crossover(self, df, generation, f): # , rq, grq inf_dict = {"A": A_inf, "B": B_inf, "a": a_inf, "b": b_inf, "Ri": Ri_inf, "L": L_inf, "Req": Req_inf} for key, influence in inf_dict.items(): if influence == [''] or influence == ['All']: - if self.uq_config['option']: + if self.uq_config: ll = [] for o in self.objectives: if o[0] == 'min': @@ -1907,7 +2063,7 @@ def pareto_front(self, df): # reverse list or not based on objective goal: minimize or maximize # datapoints = [self.negate_list(df.loc[:, o[1]], o[0]) for o in self.objectives] - if self.uq_config['option']: + if self.uq_config: obj = [] for o in self.objectives: if o[0] == 'min': @@ -1924,12 +2080,12 @@ def pareto_front(self, df): for o in self.objectives: if o[0] == 'min': - if self.uq_config['option']: + if self.uq_config: datapoints[fr'E[{o[1]}] + 6*std[{o[1]}]'] = datapoints[fr'E[{o[1]}] + 6*std[{o[1]}]'] * (-1) else: datapoints[o[1]] = datapoints[o[1]] * (-1) elif o[0] == "equal": - if self.uq_config['option']: + if self.uq_config: datapoints[fr'|E[{o[1]}] - {o[2]}| + std[{o[1]}]'] = datapoints[ fr'|E[{o[1]}] - {o[2]}| + std[{o[1]}]'] * ( -1) @@ -2083,7 +2239,7 @@ def __init__(self, n_cells, mid_cell, end_cell_left=None, end_cell_right=None, b self.n_modes = n_cells + 1 self.n_modules = 1 - self.folder = None + self.projectDir = None self.bc = 33 self.name = name self.n_cells = n_cells @@ -2095,7 +2251,7 @@ def __init__(self, n_cells, mid_cell, end_cell_left=None, end_cell_right=None, b self.no_of_modules = 1 self.eigenmode_qois = {} self.custom_eig_qois = {} - self.abci_qois = {} + self.wakefield_qois = {} self.wake_op_points = {} self.convergence_list = [] self.eigenmode_tune_res = {} @@ -2129,14 +2285,15 @@ def __init__(self, n_cells, mid_cell, end_cell_left=None, end_cell_right=None, b self.A_er, self.B_er, self.a_er, self.b_er, self.Ri_er, self.L_er, self.Req_er = self.end_cell_right[:7] # get geometric parameters - self.shape_space = { + self.shape = { "IC": self.mid_cell[:7], "OC": self.end_cell_left[:7], "OC_R": self.end_cell_right[:7], "BP": beampipe, + "n_cells": self.n_cells, 'CELL TYPE': self.cell_type } - self.shape_space_multicell = {} + self.shape_multicell = {} self.to_multicell() # <- get multicell representation def set_name(self, name): @@ -2312,13 +2469,13 @@ def sweep(self, sweep_config, which='eigenmode', how='independent', uq_config=No else: for key, interval_def in tqdm(sweep_config.items()): # save nominal variable value form shape space - current_var = self.shape_space['IC'][VAR_TO_INDEX_DICT[key]] + current_var = self.shape['IC'][VAR_TO_INDEX_DICT[key]] par_vals = np.linspace(interval_def[0], interval_def[1], interval_def[2], endpoint=True) self.sweep_results[f'{key}'] = {} for val in par_vals: if which == 'eigenmode': # change value - self.shape_space['IC'][VAR_TO_INDEX_DICT[key]] = val + self.shape['IC'][VAR_TO_INDEX_DICT[key]] = val res = self.run_eigenmode() if res: self.sweep_results[f'{key}'][val] = copy.deepcopy(self.eigenmode_qois) @@ -2326,7 +2483,7 @@ def sweep(self, sweep_config, which='eigenmode', how='independent', uq_config=No self.sweep_results_uq[f'{key}'][val] = copy.deepcopy(self.uq_fm_results) # replace initial value - self.shape_space['IC'][VAR_TO_INDEX_DICT[key]] = current_var + self.shape['IC'][VAR_TO_INDEX_DICT[key]] = current_var # def check_uq_config(self, uq_config): # cell_type = uq_config['cell type'] @@ -2410,81 +2567,80 @@ def sweep(self, sweep_config, which='eigenmode', how='independent', uq_config=No def study_convergence(self, step_refinement, max_steps): pass - def run_tune(self, tune_variable, cell_type='Mid Cell', freq=None, solver='SLANS', proc=0, resume=False, n_cells=1): - """ - Tune current cavity geometry - - Parameters - ---------- - n_cells: int - Number of cells used for tuning. - resume: bool - Option to resume tuning or not. Only for shape space with multiple entries. - proc: int - Processor number - solver: {'SLANS', 'Native'} - Solver to be used. Native solver is still under development. Results are not as accurate as that of SLANS. - freq: float - Reference frequency in MHz - cell_type: {'mid cell', 'end-mid cell', 'mid-end cell', 'end-end cell', 'single cell'} - Type of cell to tune - tune_variable: {'Req', 'L'} - Tune variable. Currently supports only the tuning of the equator radius ``Req`` and half-cell length ``L`` - - Returns - ------- - - """ - - for _ in tqdm([1]): - iter_set = ['Linear Interpolation', TUNE_ACCURACY, 10] - - if freq is None: - # calculate freq from mid cell length - beta = 1 - freq = beta * c0 / (4 * self.mid_cell[5]) - info("Calculated freq from mid cell half length: ", freq) - - # create new shape space based on cell type - # if cell_type.lower() == 'mid cell': - shape_space = { - f'{self.name}': - { - 'IC': self.shape_space['IC'], - 'OC': self.shape_space['OC'], - 'OC_R': self.shape_space['OC_R'], - "BP": 'none', - 'FREQ': freq - } - } - - if len(self.eigenmode_tune_res.keys()) != 0: - run_tune = input("This cavity has already been tuned. Run tune again? (y/N)") - if run_tune.lower() == 'y': - # copy files required for simulation - self._overwriteFolder(proc, self.folder, self.name) - self._copyFiles(proc, SOFTWARE_DIRECTORY, self.folder, self.name) - - self.run_tune_ngsolve(shape_space, resume, proc, self.bc, - SOFTWARE_DIRECTORY, self.folder, self.name, - tune_variable, iter_set, cell_type, - progress_list=[], convergence_list=self.convergence_list, n_cells=n_cells) - - else: - self.run_tune_ngsolve(shape_space, resume, proc, self.bc, - SOFTWARE_DIRECTORY, self.folder, self.name, - tune_variable, iter_set, cell_type, - progress_list=[], convergence_list=self.convergence_list, n_cells=n_cells) - - @staticmethod - def run_tune_ngsolve(shape, resume, p, bc, parentDir, projectDir, filename, - tune_variable, iter_set, cell_type, progress_list, convergence_list, n_cells): - tuner.tune_ngsolve(shape, bc, parentDir, projectDir, filename, resume=resume, proc=p, - tune_variable=tune_variable, iter_set=iter_set, - cell_type=cell_type, sim_folder='Optimisation', - progress_list=progress_list, convergence_list=convergence_list, - save_last=True, - n_cell_last_run=n_cells) # last_key=last_key This would have to be tested again #val2 + # def run_tune(self, tune_variable, cell_type='Mid Cell', freq=None, solver='SLANS', proc=0, resume=False, n_cells=1): + # """ + # Tune current cavity geometry + # + # Parameters + # ---------- + # n_cells: int + # Number of cells used for tuning. + # resume: bool + # Option to resume tuning or not. Only for shape space with multiple entries. + # proc: int + # Processor number + # solver: {'SLANS', 'Native'} + # Solver to be used. Native solver is still under development. Results are not as accurate as that of SLANS. + # freq: float + # Reference frequency in MHz + # cell_type: {'mid cell', 'end-mid cell', 'mid-end cell', 'end-end cell', 'single cell'} + # Type of cell to tune + # tune_variable: {'Req', 'L'} + # Tune variable. Currently supports only the tuning of the equator radius ``Req`` and half-cell length ``L`` + # + # Returns + # ------- + # + # """ + # + # for _ in tqdm([1]): + # iter_set = ['Linear Interpolation', TUNE_ACCURACY, 10] + # + # if freq is None: + # # calculate freq from mid cell length + # beta = 1 + # freq = beta * c0 / (4 * self.mid_cell[5]) + # info("Calculated freq from mid cell half length: ", freq) + # + # # create new shape space based on cell type + # # if cell_type.lower() == 'mid cell': + # shape_space = { + # f'{self.name}': + # { + # 'IC': self.shape['IC'], + # 'OC': self.shape['OC'], + # 'OC_R': self.shape['OC_R'], + # "BP": 'none', + # 'FREQ': freq + # } + # } + # + # if len(self.eigenmode_tune_res.keys()) != 0: + # run_tune = input("This cavity has already been tuned. Run tune again? (y/N)") + # if run_tune.lower() == 'y': + # # copy files required for simulation + # self._overwriteFolder(proc, self.projectDir, self.name) + # self._copyFiles(proc, SOFTWARE_DIRECTORY, self.projectDir, self.name) + # + # self.run_tune_ngsolve(shape_space, resume, proc, self.bc, + # SOFTWARE_DIRECTORY, self.projectDir, self.name, + # tune_variable, iter_set, cell_type, + # progress_list=[], convergence_list=self.convergence_list, n_cells=n_cells) + # + # else: + # self.run_tune_ngsolve(shape_space, resume, proc, self.bc, + # SOFTWARE_DIRECTORY, self.projectDir, self.name, + # tune_variable, iter_set, cell_type, + # progress_list=[], convergence_list=self.convergence_list, n_cells=n_cells) + # + # @staticmethod + # def run_tune_ngsolve(shape, resume, p, bc, parentDir, projectDir, filename, + # tune_variable, iter_set, cell_type, progress_list, convergence_list, n_cells): + # tuner.tune_ngsolve(shape, bc, parentDir, projectDir, filename, resume=resume, proc=p, + # tune_variable=tune_variable, + # cell_type=cell_type, sim_folder='Optimisation', + # save_last=True, + # n_cell_last_run=n_cells) # last_key=last_key This would have to be tested again #val2 def run_eigenmode(self, solver='ngsolve', freq_shift=0, boundary_cond=None, subdir='', uq_config=None): """ @@ -2513,21 +2669,21 @@ def run_eigenmode(self, solver='ngsolve', freq_shift=0, boundary_cond=None, subd self.bc = boundary_cond if self.cell_type == 'multicell': - self._run_ngsolve(self.name, self.n_cells, self.n_modules, self.shape_space, self.shape_space_multicell, + self._run_ngsolve(self.name, self.n_cells, self.n_modules, self.shape, self.shape_multicell, self.n_modes, freq_shift, self.bc, - SOFTWARE_DIRECTORY, self.folder, sub_dir='', uq_config=uq_config) + SOFTWARE_DIRECTORY, self.projectDir, sub_dir='', uq_config=uq_config) else: - self._run_ngsolve(self.name, self.n_cells, self.n_modules, self.shape_space, self.shape_space_multicell, + self._run_ngsolve(self.name, self.n_cells, self.n_modules, self.shape, self.shape_multicell, self.n_modes, freq_shift, self.bc, - SOFTWARE_DIRECTORY, self.folder, sub_dir='', uq_config=uq_config) + SOFTWARE_DIRECTORY, self.projectDir, sub_dir='', uq_config=uq_config) # load quantities of interest try: self.get_eigenmode_qois() if uq_config: - self.get_uq_fm_results(fr"{self.folder}\SimulationData\NGSolveMEVP\{self.name}\uq.json") + self.get_uq_fm_results(fr"{self.projectDir}\SimulationData\NGSolveMEVP\{self.name}\uq.json") return True except FileNotFoundError: error("Could not find eigenmode results. Please rerun eigenmode analysis.") @@ -2584,22 +2740,22 @@ def run_wakefield(self, MROT=2, MT=10, NFS=10000, wakelength=50, bunch_length=25 self.R_Q = self.eigenmode_qois['R/Q [Ohm]'] if not exist: if solver == 'ABCI': - self._run_abci(self.name, self.n_cells, self.n_modules, self.shape_space, + self._run_abci(self.name, self.n_cells, self.n_modules, self.shape, MROT=MROT, MT=MT, NFS=NFS, UBT=wakelength, bunch_length=bunch_length, DDR_SIG=DDR_SIG, DDZ_SIG=DDZ_SIG, - parentDir=SOFTWARE_DIRECTORY, projectDir=self.folder, WG_M=WG_M, marker=marker, + parentDir=SOFTWARE_DIRECTORY, projectDir=self.projectDir, WG_M=WG_M, marker=marker, operating_points=operating_points, freq=self.freq, R_Q=self.R_Q) try: self.get_abci_data() - self.get_abci_qois() + self.get_wakefield_qois() except FileNotFoundError: error("Could not find the abci wakefield results. Please rerun wakefield analysis.") else: try: self.get_abci_data() - self.get_abci_qois() + self.get_wakefield_qois() except FileNotFoundError: error("Could not find the abci wakefield results. Please rerun wakefield analysis.") @@ -2940,91 +3096,91 @@ def _run_ngsolve(name, n_cells, n_modules, shape, shape_multi, n_modes, f_shift, # with open(uq_path / fr"uq.json", 'w') as file: # file.write(json.dumps(result_dict_eigen, indent=4, separators=(',', ': '))) - @staticmethod - def _run_abci(name, n_cells, n_modules, shape, MROT=0, MT=4.0, NFS=10000, UBT=50.0, bunch_length=20.0, - DDR_SIG=0.1, DDZ_SIG=0.1, - parentDir=None, projectDir=None, - WG_M=None, marker='', operating_points=None, freq=0, R_Q=0): - - # run abci code - if WG_M is None: - WG_M = [''] - - start_time = time.time() - # run both polarizations if MROT == 2 - for ii in WG_M: - # run abci code - # run both polarizations if MROT == 2 - if 'OC_R' in list(shape.keys()): - OC_R = 'OC_R' - else: - OC_R = 'OC' - - if MROT == 2: - for m in tqdm(range(2)): - abci_geom.cavity(n_cells, n_modules, shape['IC'], shape['OC'], shape[OC_R], - fid=name, MROT=m, MT=MT, NFS=NFS, UBT=UBT, bunch_length=bunch_length, - DDR_SIG=DDR_SIG, DDZ_SIG=DDZ_SIG, parentDir=parentDir, - projectDir=projectDir, - WG_M=ii, marker=ii) - else: - abci_geom.cavity(n_cells, n_modules, shape['IC'], shape['OC'], shape[OC_R], - fid=name, MROT=MROT, MT=MT, NFS=NFS, UBT=UBT, bunch_length=bunch_length, - DDR_SIG=DDR_SIG, DDZ_SIG=DDZ_SIG, parentDir=parentDir, projectDir=projectDir, - WG_M=ii, marker=ii) - - done(f'Cavity {name}. Time: {time.time() - start_time}') - print('its here now', operating_points) - if operating_points: - try: - if freq != 0 and R_Q != 0: - d = {} - # save qois - for key, vals in tqdm(operating_points.items()): - WP = key - I0 = float(vals['I0 [mA]']) - Nb = float(vals['Nb [1e11]']) - sigma_z = [float(vals["sigma_SR [mm]"]), float(vals["sigma_BS [mm]"])] - bl_diff = ['SR', 'BS'] - - info("Running wakefield analysis for given operating points.") - for i, s in enumerate(sigma_z): - for ii in WG_M: - fid = f"{WP}_{bl_diff[i]}_{s}mm{ii}" - OC_R = 'OC' - if 'OC_R' in shape.keys(): - OC_R = 'OC_R' - for m in range(2): - abci_geom.cavity(n_cells, n_modules, shape['IC'], shape['OC'], shape[OC_R], - fid=fid, MROT=m, MT=MT, NFS=NFS, UBT=10 * s * 1e-3, - bunch_length=s, - DDR_SIG=DDR_SIG, DDZ_SIG=DDZ_SIG, parentDir=parentDir, - projectDir=projectDir, - WG_M=ii, marker=ii, sub_dir=f"{name}") - - dirc = fr'{projectDir}\SimulationData\ABCI\{name}{marker}' - # try: - k_loss = abs(ABCIData(dirc, f'{fid}', 0).loss_factor['Longitudinal']) - k_kick = abs(ABCIData(dirc, f'{fid}', 1).loss_factor['Transverse']) - # except: - # k_loss = 0 - # k_kick = 0 - print('here now') - d[fid] = get_qois_value(freq, R_Q, k_loss, k_kick, s, I0, Nb, n_cells) - print('after here', d) - - # save qoi dictionary - run_save_directory = fr'{projectDir}\SimulationData\ABCI\{name}{marker}' - with open(fr'{run_save_directory}\qois.json', "w") as f: - json.dump(d, f, indent=4, separators=(',', ': ')) - - done("Done with the secondary analysis for working points") - else: - info("To run analysis for working points, eigenmode simulation has to be run first" - "to obtain the cavity operating frequency and R/Q") - except KeyError: - error('The working point entered is not valid. See below for the proper input structure.') - show_valid_operating_point_structure() + # @staticmethod + # def _run_abci(name, n_cells, n_modules, shape, MROT=0, MT=4.0, NFS=10000, UBT=50.0, bunch_length=20.0, + # DDR_SIG=0.1, DDZ_SIG=0.1, + # parentDir=None, projectDir=None, + # WG_M=None, marker='', operating_points=None, freq=0, R_Q=0): + # + # # run abci code + # if WG_M is None: + # WG_M = [''] + # + # start_time = time.time() + # # run both polarizations if MROT == 2 + # for ii in WG_M: + # # run abci code + # # run both polarizations if MROT == 2 + # if 'OC_R' in list(shape.keys()): + # OC_R = 'OC_R' + # else: + # OC_R = 'OC' + # + # if MROT == 2: + # for m in tqdm(range(2)): + # abci_geom.cavity(n_cells, n_modules, shape['IC'], shape['OC'], shape[OC_R], + # fid=name, MROT=m, MT=MT, NFS=NFS, UBT=UBT, bunch_length=bunch_length, + # DDR_SIG=DDR_SIG, DDZ_SIG=DDZ_SIG, parentDir=parentDir, + # projectDir=projectDir, + # WG_M=ii, marker=ii) + # else: + # abci_geom.cavity(n_cells, n_modules, shape['IC'], shape['OC'], shape[OC_R], + # fid=name, MROT=MROT, MT=MT, NFS=NFS, UBT=UBT, bunch_length=bunch_length, + # DDR_SIG=DDR_SIG, DDZ_SIG=DDZ_SIG, parentDir=parentDir, projectDir=projectDir, + # WG_M=ii, marker=ii) + # + # done(f'Cavity {name}. Time: {time.time() - start_time}') + # print('its here now', operating_points) + # if operating_points: + # try: + # if freq != 0 and R_Q != 0: + # d = {} + # # save qois + # for key, vals in tqdm(operating_points.items()): + # WP = key + # I0 = float(vals['I0 [mA]']) + # Nb = float(vals['Nb [1e11]']) + # sigma_z = [float(vals["sigma_SR [mm]"]), float(vals["sigma_BS [mm]"])] + # bl_diff = ['SR', 'BS'] + # + # info("Running wakefield analysis for given operating points.") + # for i, s in enumerate(sigma_z): + # for ii in WG_M: + # fid = f"{WP}_{bl_diff[i]}_{s}mm{ii}" + # OC_R = 'OC' + # if 'OC_R' in shape.keys(): + # OC_R = 'OC_R' + # for m in range(2): + # abci_geom.cavity(n_cells, n_modules, shape['IC'], shape['OC'], shape[OC_R], + # fid=fid, MROT=m, MT=MT, NFS=NFS, UBT=10 * s * 1e-3, + # bunch_length=s, + # DDR_SIG=DDR_SIG, DDZ_SIG=DDZ_SIG, parentDir=parentDir, + # projectDir=projectDir, + # WG_M=ii, marker=ii, sub_dir=f"{name}") + # + # dirc = fr'{projectDir}\SimulationData\ABCI\{name}{marker}' + # # try: + # k_loss = abs(ABCIData(dirc, f'{fid}', 0).loss_factor['Longitudinal']) + # k_kick = abs(ABCIData(dirc, f'{fid}', 1).loss_factor['Transverse']) + # # except: + # # k_loss = 0 + # # k_kick = 0 + # print('here now') + # d[fid] = get_qois_value(freq, R_Q, k_loss, k_kick, s, I0, Nb, n_cells) + # print('after here', d) + # + # # save qoi dictionary + # run_save_directory = fr'{projectDir}\SimulationData\ABCI\{name}{marker}' + # with open(fr'{run_save_directory}\qois.json', "w") as f: + # json.dump(d, f, indent=4, separators=(',', ': ')) + # + # done("Done with the secondary analysis for working points") + # else: + # info("To run analysis for working points, eigenmode simulation has to be run first" + # "to obtain the cavity operating frequency and R/Q") + # except KeyError: + # error('The working point entered is not valid. See below for the proper input structure.') + # show_valid_operating_point_structure() # @staticmethod # def uq(shape_space, objectives, solver_dict, solver_args_dict): @@ -3174,16 +3330,16 @@ def get_ngsolve_tune_res(self): """ tune_res = 'tune_res.json' - if os.path.exists(fr"{self.folder}\SimulationData\Optimisation\{self.name}\{tune_res}"): - with open(fr"{self.folder}\SimulationData\Optimisation\{self.name}\{tune_res}", 'r') as json_file: + if os.path.exists(fr"{self.projectDir}\SimulationData\Optimisation\{self.name}\{tune_res}"): + with open(fr"{self.projectDir}\SimulationData\Optimisation\{self.name}\{tune_res}", 'r') as json_file: self.eigenmode_tune_res = json.load(json_file) self.freq = self.eigenmode_tune_res['FREQ'] - self.shape_space['IC'] = self.eigenmode_tune_res['IC'] - self.shape_space['OC'] = self.eigenmode_tune_res['OC'] - self.shape_space['OC_R'] = self.eigenmode_tune_res['OC_R'] - self.mid_cell = self.shape_space['IC'] - self.end_cell_left = self.shape_space['OC'] - self.end_cell_right = self.shape_space['OC_R'] + self.shape['IC'] = self.eigenmode_tune_res['IC'] + self.shape['OC'] = self.eigenmode_tune_res['OC'] + self.shape['OC_R'] = self.eigenmode_tune_res['OC_R'] + self.mid_cell = self.shape['IC'] + self.end_cell_left = self.shape['OC'] + self.end_cell_right = self.shape['OC_R'] else: error("Tune results not found. Please tune the cavity") @@ -3197,9 +3353,9 @@ def get_eigenmode_qois(self): """ qois = 'qois.json' - assert os.path.exists(fr"{self.folder}/SimulationData/NGSolveMEVP/{self.name}/monopole/{qois}"), ( + assert os.path.exists(fr"{self.projectDir}/SimulationData/NGSolveMEVP/{self.name}/monopole/{qois}"), ( error('Eigenmode result does not exist, please run eigenmode simulation.')) - with open(fr"{self.folder}/SimulationData/NGSolveMEVP/{self.name}/monopole/{qois}") as json_file: + with open(fr"{self.projectDir}/SimulationData/NGSolveMEVP/{self.name}/monopole/{qois}") as json_file: self.eigenmode_qois = json.load(json_file) self.freq = self.eigenmode_qois['freq [MHz]'] @@ -3213,11 +3369,11 @@ def get_eigenmode_qois(self): self.b = self.eigenmode_qois['Bpk/Eacc [mT/MV/m]'] # # get axis field - # self.axis_field = fr.txt_reader(fr"{self.folder}\SimulationData\SLANS\{self.name}\cavity_33_{self.n_cells}.af", + # self.axis_field = fr.txt_reader(fr"{self.projectDir}\SimulationData\SLANS\{self.name}\cavity_33_{self.n_cells}.af", # ' ') # # get surface field # self.surface_field = fr.txt_reader( - # fr"{self.folder}\SimulationData\SLANS\{self.name}\cavity_33_{self.n_cells}.sf", ' ') + # fr"{self.projectDir}\SimulationData\SLANS\{self.name}\cavity_33_{self.n_cells}.sf", ' ') # # print(self.surface_field) def get_uq_fm_results(self, folder): @@ -3234,10 +3390,10 @@ def get_uq_fm_results(self, folder): # """ # qois = 'qois.json' # - # with open(fr"{self.folder}\SimulationData\NativeEig\{self.name}\{qois}") as json_file: + # with open(fr"{self.projectDir}\SimulationData\NativeEig\{self.name}\{qois}") as json_file: # self.custom_eig_qois = json.load(json_file) - def get_abci_qois(self): + def get_wakefield_qois(self): """ Get the quantities of interest written by the ABCI code @@ -3253,11 +3409,11 @@ def get_abci_qois(self): """ qois = 'qois.json' - if os.path.exists(fr"{self.folder}\SimulationData\ABCI\{self.name}\{qois}"): - with open(fr"{self.folder}\SimulationData\ABCI\{self.name}\{qois}") as json_file: - self.abci_qois = json.load(json_file) + if os.path.exists(fr"{self.projectDir}\SimulationData\ABCI\{self.name}\{qois}"): + with open(fr"{self.projectDir}\SimulationData\ABCI\{self.name}\{qois}") as json_file: + self.wakefield_qois = json.load(json_file) - for key, val in self.abci_qois.items(): + for key, val in self.wakefield_qois.items(): self.k_fm[key] = val['k_FM [V/pC]'] self.k_loss[key] = val['|k_loss| [V/pC]'] self.k_kick[key] = val['|k_kick| [V/pC/m]'] @@ -3265,7 +3421,7 @@ def get_abci_qois(self): self.I0[key] = val['I0 [mA]'] def get_abci_data(self): - abci_data_dir = os.path.join(self.folder, "SimulationData", "ABCI") + abci_data_dir = os.path.join(self.projectDir, "SimulationData", "ABCI") self.abci_data = {'Long': ABCIData(abci_data_dir, self.name, 0), 'Trans': ABCIData(abci_data_dir, self.name, 1)} @@ -3326,16 +3482,16 @@ def plot(self, what, ax=None, **kwargs): info("Convergence data not available.") def plot_mesh(self, plotter='ngsolve'): - ngsolve_mevp.plot_mesh(fr'{self.folder}\SimulationData\NGSolveMEVP\{self.name}\monopole', plotter=plotter) + ngsolve_mevp.plot_mesh(fr'{self.projectDir}\SimulationData\NGSolveMEVP\{self.name}\monopole', plotter=plotter) def plot_fields(self, mode=1, which='E', plotter='ngsolve'): - ngsolve_mevp.plot_fields(fr'{self.folder}\SimulationData\NGSolveMEVP\{self.name}\monopole', + ngsolve_mevp.plot_fields(fr'{self.projectDir}\SimulationData\NGSolveMEVP\{self.name}\monopole', mode, which, plotter) def _plot_convergence(self, ax): keys = list(ax.keys()) # plot convergence - conv_filepath = fr"{self.folder}\SimulationData\Optimisation\{self.name}\convergence.json" + conv_filepath = fr"{self.projectDir}\SimulationData\Optimisation\{self.name}\convergence.json" if os.path.exists(conv_filepath): with open(conv_filepath, 'r') as f: convergence_dict = json.load(f) @@ -3353,7 +3509,7 @@ def _plot_convergence(self, ax): headaxislength=4) # plot absolute error - abs_err_filepath = fr"{self.folder}\SimulationData\Optimisation\{self.name}\absolute_error.json" + abs_err_filepath = fr"{self.projectDir}\SimulationData\Optimisation\{self.name}\absolute_error.json" abs_err_dict = {} if os.path.exists(conv_filepath): with open(abs_err_filepath, 'r') as f: @@ -3374,7 +3530,7 @@ def inspect(self, variation=0.2): import ipywidgets as widgets from ipywidgets import HBox, VBox, Label - mid_cell = self.shape_space['IC'] + mid_cell = self.shape['IC'] A_, B_, a_, b_, Ri_, L_, Req_ = mid_cell[:7] # Define the function that plots the graph @@ -3421,18 +3577,19 @@ def plot_cavity_geometry(A, B, a, b, Ri, L, Req): display(out, ui) def to_multicell(self): - mid_cell = self.shape_space['IC'] + mid_cell = self.shape['IC'] mid_cell_multi = np.array([[[a, a] for _ in range(self.n_cells - 1)] for a in mid_cell]) - self.shape_space_multicell['OC'] = self.shape_space['OC'] - self.shape_space_multicell['OC_R'] = self.shape_space['OC_R'] - self.shape_space_multicell['IC'] = mid_cell_multi - self.shape_space_multicell['BP'] = self.shape_space['BP'] - self.shape_space_multicell['CELL TYPE'] = 'multicell' + self.shape_multicell['OC'] = self.shape['OC'] + self.shape_multicell['OC_R'] = self.shape['OC_R'] + self.shape_multicell['IC'] = mid_cell_multi + self.shape_multicell['BP'] = self.shape['BP'] + self.shape_multicell['n_cells'] = self.shape['n_cells'] + self.shape_multicell['CELL TYPE'] = 'multicell' def _create_project(self, overwrite): project_name = self.name - project_dir = self.folder + project_dir = self.projectDir if project_name != '': @@ -3470,18 +3627,18 @@ def make_dirs_from_dict(d, current_dir=fr"{project_dir}"): } try: make_dirs_from_dict(project_dir_structure) - self.folder = f2b_slashes(fr"{project_dir}\{project_name}") + self.projectDir = f2b_slashes(fr"{project_dir}\{project_name}") return True except Exception as e: - self.folder = f2b_slashes(fr"{project_dir}\{project_name}") + self.projectDir = f2b_slashes(fr"{project_dir}\{project_name}") error("An exception occurred in created project: ", e) return False else: - self.folder = f2b_slashes(fr"{project_dir}\{project_name}") + self.projectDir = f2b_slashes(fr"{project_dir}\{project_name}") return True else: info('\tPlease enter a valid project name') - self.folder = f2b_slashes(fr"{project_dir}\{project_name}") + self.projectDir = f2b_slashes(fr"{project_dir}\{project_name}") return False @staticmethod @@ -3548,6 +3705,8 @@ def __init__(self, cavities_list=None, names_list=None): """ super().__init__() + self.shape_space = {} + self.shape_space_multicell = {} self.sweep_results = None self.cavities_list = cavities_list self.cavities_dict = {} @@ -3558,14 +3717,15 @@ def __init__(self, cavities_list=None, names_list=None): self.name = 'cavities' self.eigenmode_qois = {} + self.wakefield_qois = {} self.eigenmode_tune_res = {} - self.abci_qois = {} + self.uq_fm_results = {} self.p_qois = None self.fm_results = None self.hom_results = None - self.folder = None + self.projectDir = None self.operating_points = None self.operating_points_threshold = {} @@ -3595,7 +3755,7 @@ def add_cavity(self, cavs, names=None, plot_labels=None): """ if isinstance(cavs, Cavity): - cavs.folder = self.folder + cavs.projectDir = self.projectDir if names: cavs.set_name(names) else: @@ -3608,6 +3768,8 @@ def add_cavity(self, cavs, names=None, plot_labels=None): self.cavities_list.append(cavs) self.cavities_dict[cavs.name] = cavs + self.shape_space[cavs.name] = cavs.shape + self.shape_space_multicell[cavs.name] = cavs.shape_multicell else: if names is not None: assert len(cavs) == len(names), "Number of cavities does not correspond to number of names." @@ -3620,12 +3782,14 @@ def add_cavity(self, cavs, names=None, plot_labels=None): plot_labels = names for i1, cav in enumerate(cavs): - cav.folder = self.folder + cav.projectDir = self.projectDir cav.set_name(names[i1]) cav.set_plot_label(plot_labels[i1]) self.cavities_list.append(cav) self.cavities_dict[cav.name] = cav + self.shape_space[cav.name] = cav.shape + self.shape_space_multicell[cav.name] = cav.shape_multicell def set_name(self, name): """ @@ -3661,7 +3825,7 @@ def save(self, project_folder, overwrite=False): return else: try: - self.folder = project_folder + self.projectDir = project_folder success = self._create_project(overwrite) if not success: error(f"Project {project_folder} could not be created. Please check the folder and try again.") @@ -3673,7 +3837,7 @@ def save(self, project_folder, overwrite=False): return if project_folder is None: - self.folder = Path(os.getcwd()) + self.projectDir = Path(os.getcwd()) def save_plot_as_json(self, ax): ax_children = ax.get_children() @@ -3832,7 +3996,7 @@ def get_figure_properties(fig): def _create_project(self, overwrite): project_name = self.name - project_dir = self.folder + project_dir = self.projectDir if project_name != '': @@ -3870,19 +4034,19 @@ def make_dirs_from_dict(d, current_dir=fr"{project_dir}"): } try: make_dirs_from_dict(project_dir_structure) - self.folder = f2b_slashes(fr"{project_dir}\{project_name}") + self.projectDir = f2b_slashes(fr"{project_dir}\{project_name}") return True except Exception as e: - self.folder = f2b_slashes(fr"{project_dir}\{project_name}") + self.projectDir = f2b_slashes(fr"{project_dir}\{project_name}") print("An exception occurred in created project: ", e) return False else: - # self.folder = os.path.join(project_dir, project_name) - self.folder = f2b_slashes(fr"{project_dir}\{project_name}") + # self.projectDir = os.path.join(project_dir, project_name) + self.projectDir = f2b_slashes(fr"{project_dir}\{project_name}") return True else: print('\tPlease enter a valid project name') - self.folder = f2b_slashes(fr"{project_dir}\{project_name}") + self.projectDir = f2b_slashes(fr"{project_dir}\{project_name}") return False @staticmethod @@ -3928,203 +4092,377 @@ def check_uq_config(self, uq_config): uq_ok[cav.name] = res info(uq_ok) - def run_tune(self, tune_variables, freqs, cell_types='mid cell', solver='NGSolveMEVP', resume=False, - n_cells=1, processes=1, rerun=True): + def run_tune(self, tune_config=None): + """ - # perform all necessary checks - assert processes > 0, error('Number of proceses must be greater than zero.') - - if isinstance(freqs, float) or isinstance(freqs, int): - freqs = np.array([freqs for _ in range(len(self.cavities_list))]) - else: - assert len(freqs) == len(self.cavities_list), error( - 'Number of target frequencies must correspond to the number of cavities') - freqs = np.array(freqs) - if isinstance(tune_variables, str): - tune_variables = np.array([tune_variables for _ in range(len(self.cavities_list))]) - cell_types = np.array([cell_types for _ in range(len(self.cavities_list))]) - else: - assert len(tune_variables) == len(self.cavities_list), error( - 'Number of tune parameters must correspond to the number of cavities') - assert len(cell_types) == len(self.cavities_list), error( - 'Number of cell types must correspond to the number of cavities') - tune_variables = np.array(tune_variables) - cell_types = np.array(cell_types) - - # split shape_space for different processes/ MPI share process by rank - keys = list(self.cavities_dict.keys()) - shape_space_len = len(keys) - share = round(shape_space_len / processes) - jobs = [] - for p in range(processes): - # try: - if p < processes - 1: - proc_keys_list = keys[p * share:p * share + share] - proc_tune_variables = tune_variables[p * share:p * share + share] - proc_freqs = freqs[p * share:p * share + share] - proc_cell_types = cell_types[p * share:p * share + share] - else: - proc_keys_list = keys[p * share:] - proc_tune_variables = tune_variables[p * share:] - proc_freqs = freqs[p * share:] - proc_cell_types = cell_types[p * share:] - - processor_shape_space = {key: self.cavities_dict[key] for key in proc_keys_list} - service = mp.Process(target=self.run_tune_s, args=(processor_shape_space, proc_tune_variables, - proc_freqs, proc_cell_types, - solver, resume, n_cells, rerun)) - - service.start() - jobs.append(service) - - for job in jobs: - job.join() - - # get tune results - self.get_tune_res() - - def run_tune_s(self, processor_shape_space, tune_variables, freqs, cell_types, solver, resume, n_cells, rerun): - """ - Tune current cavity geometries - - Parameters - ---------- - n_cells: int - Number of cells used for tuning. - resume: bool - Option to resume tuning or not. Only for shape space with multiple entries. - proc: int - Processor number - solver: {'SLANS', 'Native'} - Solver to be used. Native solver is still under development. Results are not as accurate as that of SLANS. - freqs: float, list, ndarray - Reference frequency or list of reference frequencies if different for each cavity in MHz - cell_types: {'mid cell', 'end-mid cell', 'mid-end cell', 'single cell'} - Type of cell to tune or list of type of cell to tune for the different cavities - tune_variables: {'Req', 'L'} - Tune variable or list of tune variables. Currently supports only the tuning of the equator radius ``Req`` and half-cell length ``L`` + Parameters + ---------- + tune_config: dict + .. code-block:: python + + tune_config = { + 'freqs': 801.58, + 'parameters': 'Req', + 'cell_types': 'mid-cell', + 'processes': 1, + 'rerun': True + } Returns ------- """ - for i, (key, cav) in enumerate(tqdm(processor_shape_space.items())): - print('in for', id(cav)) - if os.path.exists(os.path.join(self.folder, "SimulationData", "Optimisation", cav.name)): - if rerun: - # clear previous results - shutil.rmtree(os.path.join(self.folder, "SimulationData", "Optimisation", cav.name)) - os.mkdir(os.path.join(self.folder, "SimulationData", "Optimisation", cav.name)) + if tune_config is None: + tune_config = {} - cav.run_tune(tune_variables[i], freq=freqs[i], cell_type=cell_types[i], - solver='ngsolvemevp', n_cells=n_cells) - else: - # check if tune results exist - if os.path.exists( - os.path.join(self.folder, "SimulationData", "Optimisation", cav.name, "tune_res.json")): - cav.get_ngsolve_tune_res(tune_variables[i], cell_types[i]) - else: - cav.run_tune(tune_variables[i], freq=freqs[i], cell_type=cell_types[i], - solver='ngsolvemevp', n_cells=n_cells) - else: - cav.run_tune(tune_variables[i], freq=freqs[i], cell_type=cell_types[i], - solver='ngsolvemevp', n_cells=n_cells) + tune_config_keys = tune_config.keys() - def run_eigenmode(self, solver='NGSolveMEVP', freq_shifts=0, boundary_conds=None, subdir='', - uq_config=None, rerun=True, processes=1): + assert 'freqs' in tune_config_keys, error('Please enter the target tune frequency.') + assert 'parameters' in tune_config_keys, error('Please enter the tune variable in tune_config_dict') + assert 'cell_types' in tune_config_keys, error('Please enter the cell_type in tune_config_dict') + freqs = tune_config['freqs'] + tune_parameters = tune_config['parameters'] + cell_types = tune_config['cell_types'] # perform all necessary checks - assert processes > 0, error('Number of proceses must be greater than zero.') - if uq_config: - assert len(uq_config['delta']) == len(uq_config['variables']), error("The number of deltas must " - "be equal to the number of " - "variables.") + if 'processes' in tune_config.keys(): + processes = tune_config['processes'] + assert processes > 0, error('Number of proceses must be greater than zero.') + else: + processes = 1 - # split shape_space for different processes/ MPI share process by rank - keys = list(self.cavities_dict.keys()) - shape_space_len = len(keys) - share = round(shape_space_len / processes) + rerun = True + if 'rerun' in tune_config_keys: + if isinstance(tune_config['rerun'], bool): + rerun = tune_config['rerun'] - jobs = [] - for p in range(processes): - # try: - if p < processes - 1: - proc_keys_list = keys[p * share:p * share + share] - else: - proc_keys_list = keys[p * share:] + if isinstance(freqs, float) or isinstance(freqs, int): + freqs = np.array([freqs for _ in range(len(self.shape_space))]) + else: + assert len(freqs) == len(self.shape_space), error( + 'Number of target frequencies must correspond to the number of cavities') + freqs = np.array(freqs) - processor_shape_space = {key: self.cavities_dict[key] for key in proc_keys_list} - service = mp.Process(target=self.run_eigenmode_s, args=(processor_shape_space, self.folder, - solver, freq_shifts, boundary_conds, subdir, - uq_config, rerun)) + if isinstance(tune_parameters, str): + assert tune_config['parameters'] in ['A', 'B', 'a', 'b', 'Ri', 'L', 'Req'], error( + 'Please enter a valid tune parameter') + tune_variables = np.array([tune_parameters for _ in range(len(self.shape_space))]) + cell_types = np.array([cell_types for _ in range(len(self.shape_space))]) + else: + assert len(tune_parameters) == len(self.shape_space), error( + 'Number of tune parameters must correspond to the number of cavities') + assert len(cell_types) == len(self.shape_space), error( + 'Number of cell types must correspond to the number of cavities') + tune_variables = np.array(tune_parameters) + cell_types = np.array(cell_types) - service.start() - jobs.append(service) + run_tune_parallel(self.shape_space, tune_variables, freqs, cell_types, self.projectDir, solver='NGSolveMEVP', + resume=False, n_cells=1, processes=processes, rerun=rerun) - for job in jobs: - job.join() + # get tune results + self.get_tune_res() - self.get_eigenmode_qois(uq_config) + # def run_tune_(self, tune_variables, freqs, cell_types='mid cell', solver='NGSolveMEVP', resume=False, + # n_cells=1, processes=1, rerun=True): + # + # # perform all necessary checks + # assert processes > 0, error('Number of proceses must be greater than zero.') + # + # if isinstance(freqs, float) or isinstance(freqs, int): + # freqs = np.array([freqs for _ in range(len(self.cavities_list))]) + # else: + # assert len(freqs) == len(self.cavities_list), error( + # 'Number of target frequencies must correspond to the number of cavities') + # freqs = np.array(freqs) + # if isinstance(tune_variables, str): + # tune_variables = np.array([tune_variables for _ in range(len(self.cavities_list))]) + # cell_types = np.array([cell_types for _ in range(len(self.cavities_list))]) + # else: + # assert len(tune_variables) == len(self.cavities_list), error( + # 'Number of tune parameters must correspond to the number of cavities') + # assert len(cell_types) == len(self.cavities_list), error( + # 'Number of cell types must correspond to the number of cavities') + # tune_variables = np.array(tune_variables) + # cell_types = np.array(cell_types) + # + # # split shape_space for different processes/ MPI share process by rank + # keys = list(self.cavities_dict.keys()) + # + # # check if number of processors selected is greater than the number of keys in the pseudo shape space + # if processes > len(keys): + # processes = len(keys) + # + # shape_space_len = len(keys) + # share = round(shape_space_len / processes) + # jobs = [] + # for p in range(processes): + # # try: + # if p < processes - 1: + # proc_keys_list = keys[p * share:p * share + share] + # proc_tune_variables = tune_variables[p * share:p * share + share] + # proc_freqs = freqs[p * share:p * share + share] + # proc_cell_types = cell_types[p * share:p * share + share] + # else: + # proc_keys_list = keys[p * share:] + # proc_tune_variables = tune_variables[p * share:] + # proc_freqs = freqs[p * share:] + # proc_cell_types = cell_types[p * share:] + # + # processor_shape_space = {key: self.cavities_dict[key] for key in proc_keys_list} + # service = mp.Process(target=self.run_tune_s, args=(processor_shape_space, proc_tune_variables, + # proc_freqs, proc_cell_types, + # solver, resume, n_cells, rerun)) + # + # service.start() + # jobs.append(service) + # + # for job in jobs: + # job.join() + # + # # get tune results + # self.get_tune_res() + # + # def run_tune_s(self, processor_shape_space, tune_variables, freqs, cell_types, solver, resume, n_cells, rerun): + # """ + # Tune current cavity geometries + # + # Parameters + # ---------- + # n_cells: int + # Number of cells used for tuning. + # resume: bool + # Option to resume tuning or not. Only for shape space with multiple entries. + # proc: int + # Processor number + # solver: {'SLANS', 'Native'} + # Solver to be used. Native solver is still under development. Results are not as accurate as that of SLANS. + # freqs: float, list, ndarray + # Reference frequency or list of reference frequencies if different for each cavity in MHz + # cell_types: {'mid cell', 'end-mid cell', 'mid-end cell', 'single cell'} + # Type of cell to tune or list of type of cell to tune for the different cavities + # tune_variables: {'Req', 'L'} + # Tune variable or list of tune variables. Currently supports only the tuning of the equator radius ``Req`` and half-cell length ``L`` + # + # Returns + # ------- + # + # """ + # + # for i, (key, cav) in enumerate(tqdm(processor_shape_space.items())): + # if os.path.exists(os.path.join(self.projectDir, "SimulationData", "Optimisation", cav.name)): + # if rerun: + # # clear previous results + # shutil.rmtree(os.path.join(self.projectDir, "SimulationData", "Optimisation", cav.name)) + # os.mkdir(os.path.join(self.projectDir, "SimulationData", "Optimisation", cav.name)) + # + # cav.run_tune(tune_variables[i], freq=freqs[i], cell_type=cell_types[i], + # solver='ngsolvemevp', n_cells=n_cells) + # else: + # # check if tune results exist + # if os.path.exists( + # os.path.join(self.projectDir, "SimulationData", "Optimisation", cav.name, "tune_res.json")): + # cav.get_ngsolve_tune_res(tune_variables[i], cell_types[i]) + # else: + # cav.run_tune(tune_variables[i], freq=freqs[i], cell_type=cell_types[i], + # solver='ngsolvemevp', n_cells=n_cells) + # else: + # cav.run_tune(tune_variables[i], freq=freqs[i], cell_type=cell_types[i], + # solver='ngsolvemevp', n_cells=n_cells) - @staticmethod - def run_eigenmode_s(shape_space, folder, solver='SLANS', freq_shifts=0, boundary_conds=None, subdir='', - uq_config=None, rerun=True): + def run_eigenmode(self, eigenmode_config=None): """ - Run eigenmode analysis on cavity Parameters ---------- - solver: {'SLANS', 'NGSolve'} - Solver to be used. Native solver is still under development. Results are not as accurate as that of SLANS. - freq_shifts: - (List of) frequency shift. Eigenmode solver searches for eigenfrequencies around this value - boundary_conds: int, list - (List of) boundary condition of left and right cell/beampipe ends - subdir: str - Sub directory to save results to - uq_config: None | dict - Provides inputs required for uncertainty quantification. Default is None and disables uncertainty quantification. + eigenmode_config: dict + .. code-block:: python + + eigenmode_config = { + 'processes': 3, + 'rerun': True, + 'boundary_conditions': 'mm', + 'uq_config': { + 'variables': ['A', 'B', 'a', 'b'], + # 'objectives': ["freq [MHz]", "R/Q [Ohm]", "Epk/Eacc []", "Bpk/Eacc [mT/MV/m]", "G [Ohm]", "kcc [%]", "ff [%]"], + 'objectives': ["Epk/Eacc []", "Bpk/Eacc [mT/MV/m]", "R/Q [Ohm]", "G [Ohm]"], + # 'objectives': ["ZL"], + 'delta': [0.05, 0.05, 0.05, 0.05], + 'processes': 4, + 'distribution': 'gaussian', + # 'method': ['QMC', 'LHS', 1000], + # 'method': ['QMC', 'Sobol', 1000], + # 'method': ['Qudrature', 'Gaussian', 1000], + 'method': ['Quadrature', 'Stroud3'], + # 'method': ['Quadrature', 'Stroud5'], + # 'gaussian': ['Quadrature', 'Gaussian'], + # 'from file': ['', columns], + 'cell type': 'mid-cell', + 'cell complexity': 'simplecell' + } + } Returns ------- """ + if eigenmode_config is None: + eigenmode_config = {} - for i, cav in enumerate(tqdm(list(shape_space.values()))): - if isinstance(freq_shifts, int) or isinstance(freq_shifts, float): - freq_shift = freq_shifts - else: - freq_shift = freq_shifts[i] + rerun = True + if 'rerun' in eigenmode_config.keys(): + assert isinstance(eigenmode_config['rerun'], bool), error('rerun must be boolean.') + rerun = eigenmode_config['rerun'] - if isinstance(boundary_conds, str) or boundary_conds is None: - boundary_cond = boundary_conds - else: - boundary_cond = boundary_conds[i] + # perform all necessary checks + processes = 1 + if 'processes' in eigenmode_config.keys(): + assert eigenmode_config['processes'] > 0, error('Number of proceses must be greater than zero.') + assert isinstance(eigenmode_config['processes'], int), error('Number of proceses must be integer.') + processes = eigenmode_config['processes'] + else: + eigenmode_config['processes'] = processes - if solver.lower() == 'slans': - solver_save_dir = 'SLANS' - else: - solver_save_dir = 'NGSolveMEVP' - - if os.path.exists(os.path.join(folder, "SimulationData", solver_save_dir, cav.name)): - if rerun: - # delete old results - shutil.rmtree(os.path.join(folder, "SimulationData", solver_save_dir, cav.name)) - cav.run_eigenmode(solver, freq_shift=freq_shift, boundary_cond=boundary_cond, uq_config=uq_config) - # print(id(cav), cav.eigenmode_qois) - else: - # check if eigenmode analysis results exist - if os.path.exists(os.path.join(folder, "SimulationData", solver_save_dir, cav.name, "monopole", - "qois.json")): - cav.get_eigenmode_qois() - cav.get_uq_fm_results(solver_save_dir) - else: - shutil.rmtree(os.path.join(folder, "SimulationData", solver_save_dir, cav.name)) - cav.run_eigenmode(solver, freq_shift=freq_shift, boundary_cond=boundary_cond, - uq_config=uq_config) - else: - cav.run_eigenmode(solver, freq_shift=freq_shift, boundary_cond=boundary_cond, uq_config=uq_config) + freq_shifts = 0 + if 'f_shifts' in eigenmode_config.keys(): + freq_shifts = eigenmode_config['f_shifts'] + + boundary_conds = 'mm' + if 'boundary_conditions' in eigenmode_config.keys(): + boundary_conds = eigenmode_config['boundary_conditions'] + else: + eigenmode_config['boundary_conditions'] = boundary_conds + + uq_config = None + if 'uq_config' in eigenmode_config.keys(): + uq_config = eigenmode_config['uq_config'] + if uq_config: + assert len(uq_config['delta']) == len(uq_config['variables']), error("The number of deltas must " + "be equal to the number of " + "variables.") + + run_eigenmode_parallel(self.shape_space, self.shape_space_multicell, eigenmode_config, freq_shifts, + self.projectDir, boundary_conds, uq_config, rerun) + self.get_eigenmode_qois(uq_config) + + # def run_eigenmode_(self, eigenmode_config): + # # solver='NGSolveMEVP', freq_shifts=0, boundary_conds=None, subdir='', + # # uq_config=None, rerun=True, processes=1): + # rerun = True + # if 'rerun' in eigenmode_config.keys(): + # assert isinstance(eigenmode_config['rerun'], bool), error('rerun must be boolean.') + # rerun = eigenmode_config['rerun'] + # + # # perform all necessary checks + # processes = 1 + # if 'processes' in eigenmode_config.keys(): + # assert eigenmode_config['processes'] > 0, error('Number of proceses must be greater than zero.') + # assert isinstance(eigenmode_config['processes'], int), error('Number of proceses must be integer.') + # processes = eigenmode_config['processes'] + # + # freq_shifts = 0 + # if 'f_shifts' in eigenmode_config.keys(): + # freq_shifts = eigenmode_config['f_shifts'] + # + # boundary_conds = 33 + # if 'boundary_conditions' in eigenmode_config.keys(): + # boundary_conds = eigenmode_config['boundary_conditions'] + # + # uq_config = None + # if 'uq_config' in eigenmode_config.keys(): + # uq_config = eigenmode_config['uq_config'] + # if uq_config: + # assert len(uq_config['delta']) == len(uq_config['variables']), error("The number of deltas must " + # "be equal to the number of " + # "variables.") + # + # # split shape_space for different processes/ MPI share process by rank + # keys = list(self.cavities_dict.keys()) + # + # # check if number of processors selected is greater than the number of keys in the pseudo shape space + # if processes > len(keys): + # processes = len(keys) + # + # shape_space_len = len(keys) + # share = round(shape_space_len / processes) + # + # jobs = [] + # for p in range(processes): + # # try: + # if p < processes - 1: + # proc_keys_list = keys[p * share:p * share + share] + # else: + # proc_keys_list = keys[p * share:] + # + # processor_shape_space = {key: self.cavities_dict[key] for key in proc_keys_list} + # service = mp.Process(target=self.run_eigenmode_s, args=(processor_shape_space, self.projectDir, + # freq_shifts, boundary_conds, '', + # uq_config, rerun)) + # + # service.start() + # jobs.append(service) + # + # for job in jobs: + # job.join() + # + # self.get_eigenmode_qois(uq_config) + # + # @staticmethod + # def run_eigenmode_s(shape_space, folder, freq_shifts=0, boundary_conds=None, subdir='', + # uq_config=None, rerun=True): + # """ + # Run eigenmode analysis on cavity + # + # Parameters + # ---------- + # solver: {'SLANS', 'NGSolve'} + # Solver to be used. Native solver is still under development. Results are not as accurate as that of SLANS. + # freq_shifts: + # (List of) frequency shift. Eigenmode solver searches for eigenfrequencies around this value + # boundary_conds: int, list + # (List of) boundary condition of left and right cell/beampipe ends + # subdir: str + # Sub directory to save results to + # uq_config: None | dict + # Provides inputs required for uncertainty quantification. Default is None and disables uncertainty quantification. + # + # Returns + # ------- + # + # """ + # + # for i, cav in enumerate(tqdm(list(shape_space.values()))): + # if isinstance(freq_shifts, int) or isinstance(freq_shifts, float): + # freq_shift = freq_shifts + # else: + # freq_shift = freq_shifts[i] + # + # if isinstance(boundary_conds, str) or boundary_conds is None: + # boundary_cond = boundary_conds + # else: + # boundary_cond = boundary_conds[i] + # + # solver_save_dir = 'NGSolveMEVP' + # + # if os.path.exists(os.path.join(folder, "SimulationData", solver_save_dir, cav.name)): + # if rerun: + # # delete old results + # shutil.rmtree(os.path.join(folder, "SimulationData", solver_save_dir, cav.name)) + # cav.run_eigenmode('ngsolve', freq_shift=freq_shift, boundary_cond=boundary_cond, + # uq_config=uq_config) + # # print(id(cav), cav.eigenmode_qois) + # else: + # # check if eigenmode analysis results exist + # if os.path.exists(os.path.join(folder, "SimulationData", solver_save_dir, cav.name, "monopole", + # "qois.json")): + # cav.get_eigenmode_qois() + # cav.get_uq_fm_results(solver_save_dir) + # else: + # shutil.rmtree(os.path.join(folder, "SimulationData", solver_save_dir, cav.name)) + # cav.run_eigenmode('ngsolve', freq_shift=freq_shift, boundary_cond=boundary_cond, + # uq_config=uq_config) + # else: + # cav.run_eigenmode('ngsolve', freq_shift=freq_shift, boundary_cond=boundary_cond, uq_config=uq_config) def get_eigenmode_qois(self, uq_config): # get results @@ -4133,7 +4471,7 @@ def get_eigenmode_qois(self, uq_config): cav.get_eigenmode_qois() self.eigenmode_qois[cav.name] = cav.eigenmode_qois if uq_config: - cav.get_uq_fm_results(fr"{self.folder}\SimulationData\NGSolveMEVP\{cav.name}\uq.json") + cav.get_uq_fm_results(fr"{self.projectDir}\SimulationData\NGSolveMEVP\{cav.name}\uq.json") self.uq_fm_results[cav.name] = cav.uq_fm_results except FileNotFoundError: error("Could not find the eigenmode results. Please rerun eigenmode analysis.") @@ -4147,64 +4485,225 @@ def get_tune_res(self): except FileNotFoundError: error("Oops! Something went wrong. Could not find the tune results. Please run tune again.") - def run_wakefield(self, MROT=2, MT=10, NFS=10000, wakelength=50, bunch_length=25, - DDR_SIG=0.1, DDZ_SIG=0.1, WG_M=None, marker='', operating_points=None, - solver='ABCI', rerun=True): + def get_wakefield_qois(self): + for key, cav in self.cavities_dict.items(): + try: + cav.get_abci_data() + cav.get_wakefield_qois() + self.wakefield_qois[cav.name] = cav.wakefield_qois + except FileNotFoundError: + error("Oops! Something went wrong. Could not find the tune results. Please run tune again.") + + def run_wakefield(self, wakefield_config=None): """ - Run wakefield analysis on cavity Parameters ---------- - MROT: {0, 1} - Polarisation 0 for longitudinal polarization and 1 for transversal polarization - MT: int - Number of time steps it takes for a beam to move from one mesh cell to the other - NFS: int - Number of frequency samples - wakelength: - Wakelength to be analysed - bunch_length: float - Length of the bunch - DDR_SIG: float - Mesh to bunch length ration in the r axis - DDZ_SIG: float - Mesh to bunch length ration in the z axis - WG_M: - For module simulation. Specifies the length of the beampipe between two cavities. - marker: str - Marker for the cavities. Adds this to the cavity name specified in a shape space json file - wp_dict: dict - Python dictionary containing relevant parameters for the wakefield analysis for a specific operating point - solver: {'ABCI'} - Only one solver is currently available + wakefield_config: + + .. code-block:: python + op_points = { + "Z": { + "freq [MHz]": 400.79, # Operating frequency + "E [GeV]": 45.6, # <- Beam energy + "I0 [mA]": 1280, # <- Beam current + "V [GV]": 0.12, # <- Total voltage + "Eacc [MV/m]": 5.72, # <- Accelerating field + "nu_s []": 0.0370, # <- Synchrotron oscillation tune + "alpha_p [1e-5]": 2.85, # <- Momentum compaction factor + "tau_z [ms]": 354.91, # <- Longitudinal damping time + "tau_xy [ms]": 709.82, # <- Transverse damping time + "f_rev [kHz]": 3.07, # <- Revolution frequency + "beta_xy [m]": 56, # <- Beta function + "N_c []": 56, # <- Number of cavities + "T [K]": 4.5, # <- Operating tempereature + "sigma_SR [mm]": 4.32, # <- Bunch length + "sigma_BS [mm]": 15.2, # <- Bunch length + "Nb [1e11]": 2.76 # <- Bunch population + } + } + wakefield_config = { + 'bunch_length': 25, + 'wakelength': 50, + 'processes': 2, + 'rerun': True, + 'operating_points': op_points, + } Returns ------- """ + if wakefield_config is None: + wakefield_config = {} + wakefield_config_keys = wakefield_config.keys() + MROT = 2 + MT = 10 + NFS = 10000 + wakelength = 50 + bunch_length = 25 + DDR_SIG = 0.1 + DDZ_SIG = 0.1 - for i, cav in enumerate(tqdm(self.cavities_list)): - if os.path.exists(os.path.join(self.folder, "SimulationData", "ABCI", cav.name)): - if rerun: - # remove old simulation results - shutil.rmtree(os.path.join(self.folder, "SimulationData", "ABCI", cav.name)) - os.mkdir(os.path.join(self.folder, "SimulationData", "ABCI", cav.name)) + # check inputs + if 'bunch_length' in wakefield_config_keys: + assert not isinstance(wakefield_config['bunch_length'], str), error( + 'Bunch length must be of type integer or float.') + else: + wakefield_config['bunch_length'] = bunch_length + if 'wakelength' in wakefield_config_keys: + assert not isinstance(wakefield_config['wakelength'], str), error( + 'Wakelength must be of type integer or float.') + else: + wakefield_config['wakelength'] = wakelength - cav.run_wakefield(MROT, MT, NFS, wakelength, bunch_length, - DDR_SIG, DDZ_SIG, WG_M, marker, operating_points, solver) - else: - # check if eigenmode analysis results exist - cav.get_abci_data() - if os.path.exists(os.path.join(self.folder, "SimulationData", "ABCI", cav.name, "qois.json")): - cav.get_abci_qois() - else: - cav.run_wakefield(MROT, MT, NFS, wakelength, bunch_length, - DDR_SIG, DDZ_SIG, WG_M, marker, operating_points, solver) - else: - cav.run_wakefield(MROT, MT, NFS, wakelength, bunch_length, - DDR_SIG, DDZ_SIG, WG_M, marker, operating_points, solver) + processes = 1 + if 'processes' in wakefield_config.keys(): + assert wakefield_config['processes']> 0, error('Number of proceses must be greater than zero.') + processes = wakefield_config['processes'] + else: + wakefield_config['processes'] = processes + + rerun = True + if 'rerun' in wakefield_config_keys: + if isinstance(wakefield_config['rerun'], bool): + rerun = wakefield_config['rerun'] + + if 'polarisation' in wakefield_config_keys: + assert wakefield_config['polarisation'] in [0, 1, 2], error('Polarisation should be 0 for longitudinal, ' + '1 for transverse, 2 for both.') + else: + wakefield_config['polarisation'] = MROT + + if 'MT' in wakefield_config_keys: + assert isinstance(wakefield_config['MT'], int), error('MT must be integer between 4 and 20, with 4 and 20 ' + 'included.') + else: + wakefield_config['MT'] = MT - self.abci_qois[cav.name] = cav.abci_qois + if 'NFS' in wakefield_config_keys: + assert isinstance(wakefield_config['NFS'], int), error('NFS must be integer.') + else: + wakefield_config['NFS'] = NFS + + if 'DDR_SIG' not in wakefield_config_keys: + wakefield_config['DDR_SIG'] = DDR_SIG + + if 'DDZ_SIG' not in wakefield_config_keys: + wakefield_config['DDZ_SIG'] = DDZ_SIG + + run_wakefield_parallel(self.shape_space, self.shape_space_multicell, wakefield_config, + self.projectDir, marker='', rerun=rerun) + + self.get_wakefield_qois() + + # def run_wakefield_(self, wakefield_config): + # wakefield_config_keys = wakefield_config.keys() + # + # MROT = 2 + # MT = 10 + # NFS = 10000 + # wakelength = 50 + # bunch_length = 25 + # DDR_SIG = 0.1 + # DDZ_SIG = 0.1 + # op_points = None + # + # # check inputs + # if 'bunch_length' in wakefield_config_keys: + # assert not isinstance(wakefield_config['bunch_length'], str), error( + # 'Bunch length must be of type integer or float.') + # bunch_length = wakefield_config['bunch_length'] + # if 'wakelength' in wakefield_config_keys: + # assert not isinstance(wakefield_config['wakelength'], str), error( + # 'Wakelength must be of type integer or float.') + # wakelength = wakefield_config['wakelength'] + # if 'operating_points' in wakefield_config_keys: + # op_points = wakefield_config['operating_points'] + # + # if 'processes' in wakefield_config.keys(): + # processes = wakefield_config['processes'] + # assert processes > 0, error('Number of proceses must be greater than zero.') + # else: + # processes = 1 + # + # rerun = True + # if 'rerun' in wakefield_config_keys: + # if isinstance(wakefield_config['rerun'], bool): + # rerun = wakefield_config['rerun'] + # + # uq_config = None + # if 'uq_config' in wakefield_config.keys(): + # uq_config = wakefield_config['uq_config'] + # if uq_config: + # assert len(uq_config['delta']) == len(uq_config['variables']), error("The number of deltas must " + # "be equal to the number of " + # "variables.") + # + # run_wake_parallel(self.shape_space, tune_variables, freqs, cell_types, self.projectDir, solver='NGSolveMEVP', + # resume=False, n_cells=1, processes=processes, rerun=rerun) + # + # # get tune results + # self.get_tune_res() + + # def run_wakefield_s(self, MROT=2, MT=10, NFS=10000, wakelength=50, bunch_length=25, + # DDR_SIG=0.1, DDZ_SIG=0.1, WG_M=None, marker='', operating_points=None, + # solver='ABCI', rerun=True): + # """ + # Run wakefield analysis on cavity + # + # Parameters + # ---------- + # MROT: {0, 1} + # Polarisation 0 for longitudinal polarization and 1 for transversal polarization + # MT: int + # Number of time steps it takes for a beam to move from one mesh cell to the other + # NFS: int + # Number of frequency samples + # wakelength: + # Wakelength to be analysed + # bunch_length: float + # Length of the bunch + # DDR_SIG: float + # Mesh to bunch length ration in the r axis + # DDZ_SIG: float + # Mesh to bunch length ration in the z axis + # WG_M: + # For module simulation. Specifies the length of the beampipe between two cavities. + # marker: str + # Marker for the cavities. Adds this to the cavity name specified in a shape space json file + # wp_dict: dict + # Python dictionary containing relevant parameters for the wakefield analysis for a specific operating point + # solver: {'ABCI'} + # Only one solver is currently available + # + # Returns + # ------- + # + # """ + # + # for i, cav in enumerate(tqdm(self.cavities_list)): + # if os.path.exists(os.path.join(self.projectDir, "SimulationData", "ABCI", cav.name)): + # if rerun: + # # remove old simulation results + # shutil.rmtree(os.path.join(self.projectDir, "SimulationData", "ABCI", cav.name)) + # os.mkdir(os.path.join(self.projectDir, "SimulationData", "ABCI", cav.name)) + # + # cav.run_wakefield(MROT, MT, NFS, wakelength, bunch_length, + # DDR_SIG, DDZ_SIG, WG_M, marker, operating_points, solver) + # else: + # # check if eigenmode analysis results exist + # cav.get_abci_data() + # if os.path.exists(os.path.join(self.projectDir, "SimulationData", "ABCI", cav.name, "qois.json")): + # cav.get_wakefield_qois() + # else: + # cav.run_wakefield(MROT, MT, NFS, wakelength, bunch_length, + # DDR_SIG, DDZ_SIG, WG_M, marker, operating_points, solver) + # else: + # cav.run_wakefield(MROT, MT, NFS, wakelength, bunch_length, + # DDR_SIG, DDZ_SIG, WG_M, marker, operating_points, solver) + # + # self.wakefield_qois[cav.name] = cav.abci_qois def plot(self, what, ax=None, **kwargs): for cav in self.cavities_list: @@ -4342,7 +4841,7 @@ def qois_hom(self, opt): results = [] for cavity in self.cavities_list: - cavity.get_abci_qois() + cavity.get_wakefield_qois() results.append({ r"$|k_\parallel| \mathrm{[V/pC]}$": cavity.k_loss[opt], r"$|k_\perp| \mathrm{[V/pC/m]}$": cavity.k_kick[opt], @@ -4351,7 +4850,7 @@ def qois_hom(self, opt): results_norm_units = [] for cavity in self.cavities_list: - cavity.get_abci_qois() + cavity.get_wakefield_qois() results_norm_units.append({ r"$k_\parallel$": cavity.k_loss[opt], r"$k_\perp$": cavity.k_kick[opt], @@ -4405,7 +4904,7 @@ def plot_uq_geometries(self): for cav, ax in zip(self.cavities_list, axd.values()): # plot nominal cav.plot('geometry', ax=ax, mid_cell=True, zorder=10) - directory = f'{self.folder}/SimulationData/NGSolveMEVP/{cav.name}' + directory = f'{self.projectDir}/SimulationData/NGSolveMEVP/{cav.name}' tag = f'{cav.name}_Q' uq_geom_folders = self.find_folders_with_tag(directory, tag) @@ -5470,121 +5969,121 @@ def write_contour(self, cav, opt='mid', n_cells=1): # plt.show() - def ql_pin(self, labels, geometry, RF, QOI, Machine, p_data=None): - """ - Calculate the value of input power as a function of loaded quality factor - - Parameters - ---------- - labels: list, array like - Descriptive labels on matplotlib plot - geometry: list, array like - List of grouped geometric input parameters - RF: list, array like - List of grouped radio-frequency (RF) properties - QOI: - List of quantities of interest for cavities - Machine: - List of grouped machine related materials - p_data: - - - Returns - ------- - - """ - # check if entries are of same length - - it = iter(geometry) - the_len = len(next(it)) - if not all(len(l) == the_len for l in it): - raise ValueError('not all lists have same length!') - - it = iter(RF) - the_len = len(next(it)) - if not all(len(l) == the_len for l in it): - raise ValueError('not all lists have same length!') - - it = iter(QOI) - the_len = len(next(it)) - if not all(len(l) == the_len for l in it): - raise ValueError('not all lists have same length!') - - it = iter(Machine) - the_len = len(next(it)) - if not all(len(l) == the_len for l in it): - raise ValueError('not all lists have same length!') - - n_cells, l_cells, G, b = [np.array(x) for x in geometry] - E_acc, Vrf = [np.array(x) for x in RF] - - fig, ax = plt.subplots() - ax.margins(x=0) - - # QOI - f0, R_Q = [np.array(x) for x in QOI] - - # Machine - I0, rho, E0 = [np.array(x) for x in Machine] - - l_active = 2 * n_cells * l_cells - l_cavity = l_active + 8 * l_cells - - # CALCULATED - v_cav = E_acc * l_active - - U_loss = 88.46 * E0 ** 4 / rho * 1e-6 # GeV # energy lost per turn per beam - v_loss = U_loss * 1e9 # V # v loss per beam - - print(v_loss, Vrf, v_loss / Vrf) - phi = np.arccos(v_loss / Vrf) - delta_f = -R_Q * f0 * I0 * np.sin(phi) / (2 * v_cav) # optimal df - QL_0_x = v_cav / (R_Q * I0 * np.cos(phi)) # optimal Q loaded - - QL_0 = np.linspace(1e4, 1e9, 1000000) - - xy_list = [(0.15, 0.13), (0.1, 0.16), (0.1, 0.19), (0.1, 0.21)] - for i in range(len(E_acc)): - f1_2 = f0[i] / (2 * QL_0) # 380.6 - print(R_Q[i], v_cav[i], Vrf[i]) - pin = v_cav[i] ** 2 / (4 * R_Q[i] * QL_0) * \ - ((1 + ((R_Q[i] * QL_0 * I0[i]) / v_cav[i]) * np.cos(phi[i])) ** 2 + - ((delta_f[i] / f1_2) + ((R_Q[i] * QL_0 * I0[i]) / v_cav[i]) * np.sin(phi[i])) ** 2) - - # material/ wall power - e_acc = np.linspace(0.5, 25, 1000) * 1e6 # MV/m - - txt = labels[i] - - if "*" in labels[i]: - l = ax.plot(QL_0, pin * 1e-3, label=txt, lw=4, - ls='--') - else: - l = ax.plot(QL_0, pin * 1e-3, label=txt, lw=4) - - # add annotations - print(l_active) - - # annotext = ax.annotate(txt, xy=xy_list[i], xycoords='figure fraction', size=8, rotation=0, - # c=l[0].get_color()) - - if p_data: - # plot QL with penetration - ax_2 = ax.twinx() - data = fr.excel_reader(p_data) - data_ = data[list(data.keys())[0]] - ax_2.plot(data_["QL"], data_["penetration"], lw=4) - - # plot decorations - ax.set_xlabel(r"$Q_{L,0}$") - ax.set_ylabel(r"$P_\mathrm{in} ~[\mathrm{kW}]$") - ax.set_xscale('log') - ax.set_xlim(5e3, 1e9) - ax.set_ylim(0, 3000) - ax.legend(loc='upper left') # - ax.minorticks_on() - # ax.grid(which='both') - fig.show() + # def ql_pin(self, labels, geometry, RF, QOI, Machine, p_data=None): + # """ + # Calculate the value of input power as a function of loaded quality factor + # + # Parameters + # ---------- + # labels: list, array like + # Descriptive labels on matplotlib plot + # geometry: list, array like + # List of grouped geometric input parameters + # RF: list, array like + # List of grouped radio-frequency (RF) properties + # QOI: + # List of quantities of interest for cavities + # Machine: + # List of grouped machine related materials + # p_data: + # + # + # Returns + # ------- + # + # """ + # # check if entries are of same length + # + # it = iter(geometry) + # the_len = len(next(it)) + # if not all(len(l) == the_len for l in it): + # raise ValueError('not all lists have same length!') + # + # it = iter(RF) + # the_len = len(next(it)) + # if not all(len(l) == the_len for l in it): + # raise ValueError('not all lists have same length!') + # + # it = iter(QOI) + # the_len = len(next(it)) + # if not all(len(l) == the_len for l in it): + # raise ValueError('not all lists have same length!') + # + # it = iter(Machine) + # the_len = len(next(it)) + # if not all(len(l) == the_len for l in it): + # raise ValueError('not all lists have same length!') + # + # n_cells, l_cells, G, b = [np.array(x) for x in geometry] + # E_acc, Vrf = [np.array(x) for x in RF] + # + # fig, ax = plt.subplots() + # ax.margins(x=0) + # + # # QOI + # f0, R_Q = [np.array(x) for x in QOI] + # + # # Machine + # I0, rho, E0 = [np.array(x) for x in Machine] + # + # l_active = 2 * n_cells * l_cells + # l_cavity = l_active + 8 * l_cells + # + # # CALCULATED + # v_cav = E_acc * l_active + # + # U_loss = 88.46 * E0 ** 4 / rho * 1e-6 # GeV # energy lost per turn per beam + # v_loss = U_loss * 1e9 # V # v loss per beam + # + # print(v_loss, Vrf, v_loss / Vrf) + # phi = np.arccos(v_loss / Vrf) + # delta_f = -R_Q * f0 * I0 * np.sin(phi) / (2 * v_cav) # optimal df + # QL_0_x = v_cav / (R_Q * I0 * np.cos(phi)) # optimal Q loaded + # + # QL_0 = np.linspace(1e4, 1e9, 1000000) + # + # xy_list = [(0.15, 0.13), (0.1, 0.16), (0.1, 0.19), (0.1, 0.21)] + # for i in range(len(E_acc)): + # f1_2 = f0[i] / (2 * QL_0) # 380.6 + # print(R_Q[i], v_cav[i], Vrf[i]) + # pin = v_cav[i] ** 2 / (4 * R_Q[i] * QL_0) * \ + # ((1 + ((R_Q[i] * QL_0 * I0[i]) / v_cav[i]) * np.cos(phi[i])) ** 2 + + # ((delta_f[i] / f1_2) + ((R_Q[i] * QL_0 * I0[i]) / v_cav[i]) * np.sin(phi[i])) ** 2) + # + # # material/ wall power + # e_acc = np.linspace(0.5, 25, 1000) * 1e6 # MV/m + # + # txt = labels[i] + # + # if "*" in labels[i]: + # l = ax.plot(QL_0, pin * 1e-3, label=txt, lw=4, + # ls='--') + # else: + # l = ax.plot(QL_0, pin * 1e-3, label=txt, lw=4) + # + # # add annotations + # print(l_active) + # + # # annotext = ax.annotate(txt, xy=xy_list[i], xycoords='figure fraction', size=8, rotation=0, + # # c=l[0].get_color()) + # + # if p_data: + # # plot QL with penetration + # ax_2 = ax.twinx() + # data = fr.excel_reader(p_data) + # data_ = data[list(data.keys())[0]] + # ax_2.plot(data_["QL"], data_["penetration"], lw=4) + # + # # plot decorations + # ax.set_xlabel(r"$Q_{L,0}$") + # ax.set_ylabel(r"$P_\mathrm{in} ~[\mathrm{kW}]$") + # ax.set_xscale('log') + # ax.set_xlim(5e3, 1e9) + # ax.set_ylim(0, 3000) + # ax.legend(loc='upper left') # + # ax.minorticks_on() + # # ax.grid(which='both') + # fig.show() def run_abci(self): for cav in self.cavities_list: @@ -5825,7 +6324,7 @@ def make_latex_summary_tables(self): fname = [cav.name for cav in self.cavities_list] fname = '_'.join(fname) print(fname) - with open(fr"D:\Dropbox\Quick presentation files\{self.folder}\{fname}_latex_summary.txt", 'w') as f: + with open(fr"D:\Dropbox\Quick presentation files\{self.projectDir}\{fname}_latex_summary.txt", 'w') as f: for ll in all_lines: f.write(ll + '\n') except KeyError as e: @@ -5886,7 +6385,7 @@ def make_excel_summary(self): df = pd.DataFrame.from_dict(data) df.to_excel( - fr"D:\Dropbox\CavityDesignHub\MuCol_Study\SimulationData\Summaries\{self.folder}_excel_summary.xlsx", + fr"D:\Dropbox\CavityDesignHub\MuCol_Study\SimulationData\Summaries\{self.projectDir}_excel_summary.xlsx", sheet_name='Cavities') except Exception as e: print("Either SLANS or ABCI results not available. Please use '.set_slans_qois()' " @@ -5919,17 +6418,17 @@ def save_all_plots(self, plot_name): ------- """ - if self.folder != '': + if self.projectDir != '': # check if folder exists - if os.path.exists(fr"{self.folder}\PostProcessingData\Plots"): - save_folder = fr"{self.folder}\PostProcessingData\Plots" + if os.path.exists(fr"{self.projectDir}\PostProcessingData\Plots"): + save_folder = fr"{self.projectDir}\PostProcessingData\Plots" plt.savefig(f"{save_folder}/{plot_name}") else: - if not os.exists(fr"{self.folder}\PostProcessingData"): - os.mkdir(fr"{self.folder}\PostProcessingData") - os.mkdir(fr"{self.folder}\PostProcessingData\Plots") + if not os.exists(fr"{self.projectDir}\PostProcessingData"): + os.mkdir(fr"{self.projectDir}\PostProcessingData") + os.mkdir(fr"{self.projectDir}\PostProcessingData\Plots") - save_folder = fr"{self.folder}\PostProcessingData\Plots" + save_folder = fr"{self.projectDir}\PostProcessingData\Plots" os.mkdir(save_folder) plt.savefig(f"{save_folder}/{plot_name}") @@ -6175,8 +6674,8 @@ def calculate_beampipe_cutoff(Ri_list, which): return f_list - def run_optimisation(self, config): - self.start_optimisation(self.folder, config) + def run_optimisation(self, optimisation_config): + self.start_optimisation(self.projectDir, optimisation_config) @staticmethod def calc_cutoff(Ri, mode): @@ -6320,7 +6819,7 @@ def run_tune(self, tune_variable, cell_type='Mid Cell', freq=None, solver='SLANS run_tune = input("This cavity has already been tuned. Run tune again? (y/N)") if run_tune.lower() == 'y': self.run_tune_ngsolve(shape_space, resume, proc, self.bc, - SOFTWARE_DIRECTORY, self.folder, self.name, + SOFTWARE_DIRECTORY, self.projectDir, self.name, tune_variable, iter_set, cell_type, progress_list=[], convergence_list=self.convergence_list, n_cells=n_cells) @@ -6332,7 +6831,7 @@ def run_tune(self, tune_variable, cell_type='Mid Cell', freq=None, solver='SLANS else: self.run_tune_ngsolve(shape_space, resume, proc, self.bc, - SOFTWARE_DIRECTORY, self.folder, self.name, + SOFTWARE_DIRECTORY, self.projectDir, self.name, tune_variable, iter_set, cell_type, progress_list=[], convergence_list=self.convergence_list, n_cells=n_cells) try: @@ -6378,7 +6877,7 @@ def run_eigenmode(self, solver='ngsolve', freq_shift=0, boundary_cond=None, subd self.bc = boundary_cond self._run_ngsolve(self.name, self.n_cells, self.n_modules, self.shape_space, self.n_modes, freq_shift, - self.bc, SOFTWARE_DIRECTORY, self.folder, sub_dir='', uq_config=uq_config) + self.bc, SOFTWARE_DIRECTORY, self.projectDir, sub_dir='', uq_config=uq_config) # load quantities of interest try: self.get_eigenmode_qois() @@ -6429,19 +6928,19 @@ def run_wakefield(self, MROT=2, MT=10, NFS=10000, wakelength=50, bunch_length=25 self._run_abci(self.name, self.n_cells, self.n_modules, self.shape_space, MROT=MROT, MT=MT, NFS=NFS, UBT=wakelength, bunch_length=bunch_length, DDR_SIG=DDR_SIG, DDZ_SIG=DDZ_SIG, - parentDir=SOFTWARE_DIRECTORY, projectDir=self.folder, WG_M=WG_M, marker=marker, + parentDir=SOFTWARE_DIRECTORY, projectDir=self.projectDir, WG_M=WG_M, marker=marker, operating_points=operating_points, freq=self.freq, R_Q=self.R_Q) try: self.get_abci_data() - self.get_abci_qois() + self.get_wakefield_qois() except FileNotFoundError: error("Could not find the abci wakefield results. Please rerun wakefield analysis.") else: try: self.get_abci_data() - self.get_abci_qois() + self.get_wakefield_qois() except FileNotFoundError: error("Could not find the abci wakefield results. Please rerun wakefield analysis.") @@ -6665,11 +7164,11 @@ def run_tune(self, tune_variable, cell_type='Mid Cell', freq=None, solver='SLANS if solver.lower() == 'slans': if run_tune.lower() == 'y': # copy files required for simulation - self._overwriteFolder(proc, self.folder, self.name) - self._copyFiles(proc, SOFTWARE_DIRECTORY, self.folder, self.name) + self._overwriteFolder(proc, self.projectDir, self.name) + self._copyFiles(proc, SOFTWARE_DIRECTORY, self.projectDir, self.name) self.run_tune_slans(shape_space, resume, proc, self.bc, - SOFTWARE_DIRECTORY, self.folder, self.name, tuner, + SOFTWARE_DIRECTORY, self.projectDir, self.name, tuner, tune_variable, iter_set, cell_type, progress_list=[], convergence_list=self.convergence_list, n_cells=n_cells) @@ -6681,11 +7180,11 @@ def run_tune(self, tune_variable, cell_type='Mid Cell', freq=None, solver='SLANS else: if run_tune.lower() == 'y': # copy files required for simulation - self._overwriteFolder(proc, self.folder, self.name) - self._copyFiles(proc, SOFTWARE_DIRECTORY, self.folder, self.name) + self._overwriteFolder(proc, self.projectDir, self.name) + self._copyFiles(proc, SOFTWARE_DIRECTORY, self.projectDir, self.name) self.run_tune_ngsolve(shape_space, resume, proc, self.bc, - SOFTWARE_DIRECTORY, self.folder, self.name, + SOFTWARE_DIRECTORY, self.projectDir, self.name, tune_variable, iter_set, cell_type, progress_list=[], convergence_list=self.convergence_list, n_cells=n_cells) @@ -6697,11 +7196,11 @@ def run_tune(self, tune_variable, cell_type='Mid Cell', freq=None, solver='SLANS else: if solver.lower() == 'slans': # copy files required for simulation - self._overwriteFolder(proc, self.folder, self.name) - self._copyFiles(proc, SOFTWARE_DIRECTORY, self.folder, self.name) + self._overwriteFolder(proc, self.projectDir, self.name) + self._copyFiles(proc, SOFTWARE_DIRECTORY, self.projectDir, self.name) self.run_tune_slans(shape_space, resume, proc, self.bc, - SOFTWARE_DIRECTORY, self.folder, self.name, tuner, + SOFTWARE_DIRECTORY, self.projectDir, self.name, tuner, tune_variable, iter_set, cell_type, progress_list=[], convergence_list=self.convergence_list, n_cells=n_cells) @@ -6711,11 +7210,11 @@ def run_tune(self, tune_variable, cell_type='Mid Cell', freq=None, solver='SLANS error("Oops! Something went wrong. Could not find the tune results. Please run tune again.") else: # copy files required for simulation - self._overwriteFolder(proc, self.folder, self.name) - self._copyFiles(proc, SOFTWARE_DIRECTORY, self.folder, self.name) + self._overwriteFolder(proc, self.projectDir, self.name) + self._copyFiles(proc, SOFTWARE_DIRECTORY, self.projectDir, self.name) self.run_tune_ngsolve(shape_space, resume, proc, self.bc, - SOFTWARE_DIRECTORY, self.folder, self.name, + SOFTWARE_DIRECTORY, self.projectDir, self.name, tune_variable, iter_set, cell_type, progress_list=[], convergence_list=self.convergence_list, n_cells=n_cells) try: @@ -6761,7 +7260,7 @@ def run_eigenmode(self, solver='ngsolve', freq_shift=0, boundary_cond=None, subd self.bc = boundary_cond self._run_ngsolve(self.name, self.n_cells, self.n_modules, self.shape_space, self.n_modes, freq_shift, - self.bc, SOFTWARE_DIRECTORY, self.folder, sub_dir='', uq_config=uq_config) + self.bc, SOFTWARE_DIRECTORY, self.projectDir, sub_dir='', uq_config=uq_config) # load quantities of interest try: self.get_eigenmode_qois() @@ -6812,19 +7311,19 @@ def run_wakefield(self, MROT=2, MT=10, NFS=10000, wakelength=50, bunch_length=25 self._run_abci(self.name, self.n_cells, self.n_modules, self.shape_space, MROT=MROT, MT=MT, NFS=NFS, UBT=wakelength, bunch_length=bunch_length, DDR_SIG=DDR_SIG, DDZ_SIG=DDZ_SIG, - parentDir=SOFTWARE_DIRECTORY, projectDir=self.folder, WG_M=WG_M, marker=marker, + parentDir=SOFTWARE_DIRECTORY, projectDir=self.projectDir, WG_M=WG_M, marker=marker, operating_points=operating_points, freq=self.freq, R_Q=self.R_Q) try: self.get_abci_data() - self.get_abci_qois() + self.get_wakefield_qois() except FileNotFoundError: error("Could not find the abci wakefield results. Please rerun wakefield analysis.") else: try: self.get_abci_data() - self.get_abci_qois() + self.get_wakefield_qois() except FileNotFoundError: error("Could not find the abci wakefield results. Please rerun wakefield analysis.") @@ -6949,7 +7448,7 @@ def __init__(self, folder, name, scripts_folder=None): self.sim_results = None assert f'/' in folder, error('Please ensure directory paths use forward slashes.') - self.folder = folder + self.projectDir = folder if scripts_folder is None: self.scripts_folder = r'D:/Dropbox/CavityDesignHub/analysis_modules/uq/dakota_scripts' else: @@ -6967,13 +7466,13 @@ def write_input_file(self, **kwargs): method_config = kwargs['method_config'] # check if folder exists, if not, create folder - if not os.path.exists(os.path.join(self.folder, self.name)): + if not os.path.exists(os.path.join(self.projectDir, self.name)): try: - os.mkdir(os.path.join(self.folder, self.name)) + os.mkdir(os.path.join(self.projectDir, self.name)) except FileExistsError: print("Could not create folder. Make sure target location exists.") - with open(os.path.join(self.folder, self.name, f'{self.name}.in'), 'w') as f: + with open(os.path.join(self.projectDir, self.name, f'{self.name}.in'), 'w') as f: self.environment(f) self.method(f, **method_config) self.variables(f, **variables_config) @@ -7112,36 +7611,36 @@ def nodes_to_cst_sweep_input(self, partitions=1): else: df_part = self.nodes.loc[i * row_partition:] - df_part.to_csv(fr"{self.folder}/{self.name}/cst_sweep_files/cst_par_in_{i + 1}.txt", sep="\t", index=None) + df_part.to_csv(fr"{self.projectDir}/{self.name}/cst_sweep_files/cst_par_in_{i + 1}.txt", sep="\t", index=None) def run_analysis(self, write_cst=True, partitions=1): - cwd = os.path.join(self.folder, self.name) - dakota_in = f'{os.path.join(self.folder, self.name, f"{self.name}.in")}' - dakota_out = f'{os.path.join(self.folder, self.name, f"{self.name}.out")}' + cwd = os.path.join(self.projectDir, self.name) + dakota_in = f'{os.path.join(self.projectDir, self.name, f"{self.name}.in")}' + dakota_out = f'{os.path.join(self.projectDir, self.name, f"{self.name}.out")}' subprocess.run(['dakota', '-i', dakota_in, '-o', dakota_out], cwd=cwd, shell=True) # read results - filepath = fr"{self.folder}/{self.name}/sim_result_table.dat" + filepath = fr"{self.projectDir}/{self.name}/sim_result_table.dat" self.sim_results = pd.read_csv(filepath, sep='\s+') # delete unnecessary columns self.nodes = self.sim_results.drop(self.sim_results.filter(regex='response|interface|eval_id').columns, axis=1) - self.sim_results.to_excel(fr"{self.folder}/{self.name}/nodes.xlsx", index=False) + self.sim_results.to_excel(fr"{self.projectDir}/{self.name}/nodes.xlsx", index=False) if write_cst: # check if folder exist and clear - if os.path.exists(os.path.join(self.folder, self.name, 'cst_sweep_files')): - shutil.rmtree(os.path.join(self.folder, self.name, 'cst_sweep_files')) - os.mkdir(os.path.join(self.folder, self.name, 'cst_sweep_files')) + if os.path.exists(os.path.join(self.projectDir, self.name, 'cst_sweep_files')): + shutil.rmtree(os.path.join(self.projectDir, self.name, 'cst_sweep_files')) + os.mkdir(os.path.join(self.projectDir, self.name, 'cst_sweep_files')) else: - os.mkdir(os.path.join(self.folder, self.name, 'cst_sweep_files')) + os.mkdir(os.path.join(self.projectDir, self.name, 'cst_sweep_files')) # post processes self.nodes_to_cst_sweep_input(partitions) else: - if os.path.exists(os.path.join(self.folder, self.name, 'cst_sweep_files')): - shutil.rmtree(os.path.join(self.folder, self.name, 'cst_sweep_files')) + if os.path.exists(os.path.join(self.projectDir, self.name, 'cst_sweep_files')): + shutil.rmtree(os.path.join(self.projectDir, self.name, 'cst_sweep_files')) class OperationPoints: @@ -7398,398 +7897,452 @@ def get_default_operating_points(self): }) -# -# def uq_multicell(shape_space, objectives, solver_dict, solver_args_dict, uq_config): -# """ -# -# Parameters -# ---------- -# key: str | int -# Cavity geomery identifier -# shape: dict -# Dictionary containing geometric dimensions of cavity geometry -# qois: list -# Quantities of interest considered in uncertainty quantification -# n_cells: int -# Number of cavity cells -# n_modules: int -# Number of modules -# n_modes: int -# Number of eigenmodes to be calculated -# f_shift: float -# Since the eigenmode solver uses the power method, a shift can be provided -# bc: int -# Boundary conditions {1:inner contour, 2:Electric wall Et = 0, 3:Magnetic Wall En = 0, 4:Axis, 5:metal} -# bc=33 means `Magnetic Wall En = 0` boundary condition at both ends -# pol: int {Monopole, Dipole} -# Defines whether to calculate for monopole or dipole modes -# parentDir: str | path -# Parent directory -# projectDir: str|path -# Project directory -# -# Returns -# ------- -# :param objectives: -# :param shape_space: -# -# """ -# -# parentDir = solver_args_dict['parentDir'] -# projectDir = solver_args_dict['projectDir'] -# cell_type = uq_config['cell type'] -# analysis_folder = solver_args_dict['analysis folder'] -# opt = solver_args_dict['optimisation'] -# delta = uq_config['delta'] -# method = uq_config['method'] -# n_cells = solver_args_dict['ngsolvemevp']['n_cells'] -# uq_vars = uq_config['variables'] -# assert len(uq_vars) == len(delta), error('Ensure number of variables equal number of deltas') -# -# for key, shape in shape_space.items(): -# uq_path = projectDir / fr'SimulationData\NGSolveMEVP\{key}' -# -# err = False -# result_dict_eigen, result_dict_abci = {}, {} -# run_eigen, run_abci = False, False -# eigen_obj_list, abci_obj_list = [], [] -# -# for o in objectives: -# if o in ["Req", "freq [MHz]", "Epk/Eacc []", "Bpk/Eacc [mT/MV/m]", "R/Q [Ohm]", -# "G [Ohm]", "Q []", 'kcc [%]', "ff [%]"]: -# result_dict_eigen[o] = {'expe': [], 'stdDev': []} -# run_eigen = True -# eigen_obj_list.append(o) -# -# if o.split(' ')[0] in ['ZL', 'ZT', 'k_loss', 'k_kick']: -# result_dict_abci[o] = {'expe': [], 'stdDev': []} -# run_abci = True -# abci_obj_list.append(o) -# n_cells = shape['IC'].shape[2] -# # expected input -# # l_end_cell = np.array([73.52, 131.75, 106.25, 118.7, 150, 187, 350]) -# # -# # mid_cell = np.array([[[60, 60], [56, 54], [76, 56]], # <- A -# # [[60, 43], [73, 65], [65, 45]], # <- B -# # [[34, 50], [54, 50], [37, 40]], # <- a -# # [[40, 36], [56, 57], [54, 56]], # <- b -# # [[150, 151], [170, 165], [150, 155]], # <- Ri -# # [[187, 187], [184, 176], [178, 170]], # <- L -# # [[369.6321578127116, 345], [340, 350], [350, 360]]]) -# # -# # r_end_cell = np.array([70, 120, 100, 110, 130, 176, 340]) -# cav_var_list = ['A', 'B', 'a', 'b', 'Ri', 'L', 'Req'] -# midcell_var_dict = dict() -# for i1 in range(len(cav_var_list)): -# for i2 in range(n_cells): -# for i3 in range(2): -# midcell_var_dict[f'{cav_var_list[i1]}_{i2}_m{i3}'] = [i1, i2, i3] -# -# # EXAMPLE: p_true = np.array([1, 2, 3, 4, 5]).T -# print(shape['IC']) -# p_true = [np.array(shape['OC'])[:7], shape['IC'][:7], np.array(shape['OC_R'])[:7]] -# # print(shape_space) -# -# rdim = len(np.array(shape['OC'])[:7]) + shape['IC'].size + len(np.array(shape['OC_R'])[:7]) -# -# degree = 1 -# -# flag_stroud = 'stroud3' -# if flag_stroud == 'stroud3': -# nodes_, weights_, bpoly_ = quad_stroud3(rdim, degree) -# nodes_ = 2. * nodes_ - 1. -# # nodes_, weights_ = cn_leg_03_1(rdim) # <- for some reason unknown this gives a less accurate answer. the nodes are not the same as the custom function -# elif flag_stroud == 'stroud5': -# nodes_, weights_ = cn_leg_05_2(rdim) -# elif flag_stroud == 'cn_gauss': -# nodes_, weights_ = cn_gauss(rdim, 2) -# else: -# return 0 -# -# no_parm, no_sims = np.shape(nodes_) -# delta = 0.01 # or 0.1 -# -# Ttab_val_f = [] -# -# sub_dir = fr'{key}' # the simulation runs at the quadrature points are saved to the key of mean value run -# # par_end = shape['OC'] -# # save nodes -# print(eigen_obj_list) -# data_table = pd.DataFrame(nodes_.T, columns=uq_vars) -# data_table.to_csv(uq_path / 'nodes.csv', index=False, sep='\t', float_format='%.32f') -# -# for i in range(no_sims): -# skip = False -# p_init_el = p_true[0] + nodes_[0:len(p_true[0]), i] -# -# p_init_m = p_true[1] + nodes_[len(p_true[0]):len(p_true[0]) + p_true[1].size, i].reshape( -# np.shape(p_true[1])) -# -# p_init_er = p_true[2] + nodes_[len(p_true[0]) + p_true[1].size:, i] -# -# par_mid = p_init_m -# par_end_l = p_init_el -# par_end_r = p_init_er -# # ic(par_end_r) -# -# # # perform checks on geometry -# # ok = perform_geometry_checks(par_mid, par_end) -# # if not ok: -# # err = True -# # break -# fid = fr'{key}_Q{i}' -# -# # skip analysis if folder already exists. -# if not skip: -# solver = ngsolve_mevp -# # run model using SLANS or CST -# # # create folders for all keys -# solver.createFolder(fid, projectDir, subdir=sub_dir) -# -# solver.cavity_multicell(n_cells, 1, par_mid, par_end_l, par_end_r, -# n_modes=n_cells, fid=fid, f_shift=0, bc=33, pol='monopole', -# beampipes=shape['BP'], -# parentDir=parentDir, projectDir=projectDir, subdir=sub_dir) -# -# filename = uq_path / f'{fid}/monopole/qois.json' -# if os.path.exists(filename): -# # params = fr.svl_reader(filename) -# # norm_length = 2 * n_cells * shape['IC'][5] -# -# qois_result_dict = dict() -# -# with open(filename) as json_file: -# qois_result_dict.update(json.load(json_file)) -# -# qois_result = get_qoi_value(qois_result_dict, eigen_obj_list) -# # print_(qois_result) -# # sometimes some degenerate shapes are still generated and the solver returns zero -# # for the objective functions, such shapes are considered invalid -# for objr in qois_result: -# if objr == 0: -# # skip key -# err = True -# break -# -# tab_val_f = qois_result -# -# Ttab_val_f.append(tab_val_f) -# else: -# err = True -# -# data_table = pd.DataFrame(Ttab_val_f, columns=list(eigen_obj_list)) -# data_table.to_csv(uq_path / 'table.csv', index=False, sep='\t', float_format='%.32f') -# -# # # add original point -# # filename = fr'{projectDir}\SimulationData\SLANS\{key}\cavity_33.svl' -# # params = fr.svl_reader(filename) -# # obj_result, tune_result = get_objectives_value(params, slans_obj_list) -# # tab_val_f = obj_result -# # Ttab_val_f.append(tab_val_f) -# -# # import matplotlib.pyplot as plt -# print(np.atleast_2d(Ttab_val_f), weights_) -# if not err: -# v_expe_fobj, v_stdDev_fobj = weighted_mean_obj(np.atleast_2d(Ttab_val_f), weights_) -# -# # append results to dict -# for i, o in enumerate(eigen_obj_list): -# result_dict_eigen[o]['expe'].append(v_expe_fobj[i]) -# result_dict_eigen[o]['stdDev'].append(v_stdDev_fobj[i]) -# -# # pdf = normal_dist(np.sort(np.array(Ttab_val_f).T[i]), v_expe_fobj[i], v_stdDev_fobj[i]) -# # plt.plot(np.sort(np.array(Ttab_val_f).T[i]), pdf) -# -# # plt.show() -# print(result_dict_eigen) -# with open(uq_path / fr"uq.json", 'w') as file: -# file.write(json.dumps(result_dict_eigen, indent=4, separators=(',', ': '))) -# else: -# error(fr"There was a problem running UQ analysis for {key}") -# - -# def uq_ngsolve(key, shape, qois, n_cells, n_modules, n_modes, f_shift, bc, pol, parentDir, projectDir, mesh_args, -# select_solver='ngsolvemevp'): -# """ -# -# Parameters -# ---------- -# key: str | int -# Cavity geomery identifier -# shape: dict -# Dictionary containing geometric dimensions of cavity geometry -# qois: list -# Quantities of interest considered in uncertainty quantification -# n_cells: int -# Number of cavity cells -# n_modules: int -# Number of modules -# n_modes: int -# Number of eigenmodes to be calculated -# f_shift: float -# Since the eigenmode solver uses the power method, a shift can be provided -# bc: int -# Boundary conditions {1:inner contour, 2:Electric wall Et = 0, 3:Magnetic Wall En = 0, 4:Axis, 5:metal} -# bc=33 means `Magnetic Wall En = 0` boundary condition at both ends -# pol: int {Monopole, Dipole} -# Defines whether to calculate for monopole or dipole modes -# parentDir: str | path -# Parent directory -# projectDir: str|path -# Project directory -# -# Returns -# ------- -# :param select_solver: -# -# """ -# -# if select_solver.lower() == 'slans': -# uq_path = projectDir / fr'SimulationData\SLANS\{key}' -# else: -# uq_path = projectDir / fr'SimulationData\NGSolveMEVP\{key}' -# -# err = False -# result_dict_eigen = {} -# eigen_obj_list = qois -# for o in qois: -# result_dict_eigen[o] = {'expe': [], 'stdDev': []} -# -# rdim = n_cells * 3 # How many variables will be considered as random in our case 5 -# degree = 1 -# -# # for 1D opti you can use stroud5 (please test your code for stroud3 less quadrature nodes 2rdim) -# flag_stroud = 'stroud5' -# -# if flag_stroud == 'stroud3': -# nodes_, weights_, bpoly_ = quad_stroud3(rdim, degree) -# nodes_ = 2. * nodes_ - 1. -# # nodes_, weights_ = cn_leg_03_1(rdim) # <- for some reason unknown this gives a less accurate answer. the nodes are not the same as the custom function -# elif flag_stroud == 'stroud5': -# nodes_, weights_ = cn_leg_05_2(rdim) -# elif flag_stroud == 'cn_gauss': -# nodes_, weights_ = cn_gauss(rdim, 2) -# else: -# ic('flag_stroud==1 or flag_stroud==2') -# return 0 -# -# ic(nodes_) -# # save nodes -# data_table = pd.DataFrame(nodes_.T, columns=list(eigen_obj_list)) -# data_table.to_csv(uq_path / 'nodes.csv', index=False, sep='\t', float_format='%.32f') -# -# # mean value of geometrical parameters -# no_parm, no_sims = np.shape(nodes_) -# -# Ttab_val_f = [] -# -# sub_dir = fr'{key}' # the simulation runs at the quadrature points are saved to the key of mean value run -# -# for i in range(no_sims): -# skip = False -# # perform checks on geometry -# ok = perform_geometry_checks(shape['IC'], shape['OC']) -# if not ok: -# err = True -# break -# fid = fr'{key}_Q{i}' -# -# # skip analysis if folder already exists. -# if not skip: -# solver = ngsolve_mevp -# # run model using SLANS or CST -# # # create folders for all keys -# solver.createFolder(fid, projectDir, subdir=sub_dir) -# -# if "CELL TYPE" in shape.keys(): -# if shape['CELL TYPE'] == 'flattop': -# # write_cst_paramters(fid, shape['IC'], shape['OC'], shape['OC_R'], -# # projectDir=projectDir, cell_type="None", solver=select_solver.lower()) -# try: -# print(' in flattop') -# solver.cavity_flattop(n_cells, n_modules, shape['IC'], shape['OC'], shape['OC'], -# n_modes=n_modes, fid=fid, f_shift=f_shift, bc=bc, pol=pol, -# beampipes=shape['BP'], -# parentDir=parentDir, projectDir=projectDir, subdir=sub_dir, -# mesh_args=mesh_args, -# deformation_params=nodes_[:, i]) -# except KeyError: -# solver.cavity_flattop(n_cells, n_modules, shape['IC'], shape['OC'], shape['OC'], -# n_modes=n_modes, fid=fid, f_shift=f_shift, bc=bc, pol=pol, -# beampipes=shape['BP'], -# parentDir=parentDir, projectDir=projectDir, subdir=sub_dir, -# mesh_args=mesh_args, -# deformation_params=nodes_[:, i]) -# else: -# try: -# solver.cavity(n_cells, n_modules, shape['IC'], shape['OC'], shape['OC'], -# n_modes=n_modes, fid=fid, f_shift=f_shift, bc=bc, pol=pol, beampipes=shape['BP'], -# parentDir=parentDir, projectDir=projectDir, subdir=sub_dir, mesh_args=mesh_args, -# deformation_params=nodes_[:, i]) -# except KeyError: -# solver.cavity(n_cells, n_modules, shape['IC'], shape['OC'], shape['OC'], -# n_modes=n_modes, fid=fid, f_shift=f_shift, bc=bc, pol=pol, beampipes=shape['BP'], -# parentDir=parentDir, projectDir=projectDir, subdir=sub_dir, mesh_args=mesh_args, -# deformation_params=nodes_[:, i]) -# -# filename = uq_path / f'{fid}/monopole/qois.json' -# print(filename) -# if os.path.exists(filename): -# # params = fr.svl_reader(filename) -# # norm_length = 2 * n_cells * shape['IC'][5] -# -# qois_result_dict = dict() -# -# with open(filename) as json_file: -# qois_result_dict.update(json.load(json_file)) -# -# qois_result = get_qoi_value(qois_result_dict, eigen_obj_list) -# # print_(qois_result) -# # sometimes some degenerate shapes are still generated and the solver returns zero -# # for the objective functions, such shapes are considered invalid -# for objr in qois_result: -# if objr == 0: -# # skip key -# err = True -# break -# -# tab_val_f = qois_result -# -# Ttab_val_f.append(tab_val_f) -# else: -# err = True -# -# # # add original point -# # filename = fr'{projectDir}\SimulationData\SLANS\{key}\cavity_33.svl' -# # params = fr.svl_reader(filename) -# # obj_result, tune_result = get_objectives_value(params, slans_obj_list) -# # tab_val_f = obj_result -# # Ttab_val_f.append(tab_val_f) -# # save table -# data_table = pd.DataFrame(Ttab_val_f, columns=list(eigen_obj_list)) -# data_table.to_csv(uq_path / 'table.csv', index=False, sep='\t', float_format='%.32f') -# -# print(np.atleast_2d(Ttab_val_f), weights_) -# if not err: -# v_expe_fobj, v_stdDev_fobj = weighted_mean_obj(np.atleast_2d(Ttab_val_f), weights_) -# -# # append results to dict -# for i, o in enumerate(eigen_obj_list): -# result_dict_eigen[o]['expe'].append(v_expe_fobj[i]) -# result_dict_eigen[o]['stdDev'].append(v_stdDev_fobj[i]) -# -# # pdf = normal_dist(np.sort(np.array(Ttab_val_f).T[i]), v_expe_fobj[i], v_stdDev_fobj[i]) -# # plt.plot(np.sort(np.array(Ttab_val_f).T[i]), pdf) -# -# # plt.show() -# print(result_dict_eigen) -# with open(uq_path / fr"uq.json", 'w') as file: -# file.write(json.dumps(result_dict_eigen, indent=4, separators=(',', ': '))) -# else: -# error(fr"There was a problem running UQ analysis for {key}") +def run_tune_parallel(shape_space, tune_variables, freqs, cell_types, projectDir, solver='NGSolveMEVP', + resume=False, + n_cells=1, processes=1, rerun=True): + # split shape_space for different processes/ MPI share process by rank + keys = list(shape_space.keys()) + + # check if number of processors selected is greater than the number of keys in the pseudo shape space + if processes > len(keys): + processes = len(keys) + + shape_space_len = len(keys) + share = round(shape_space_len / processes) + jobs = [] + for p in range(processes): + # try: + if p < processes - 1: + proc_keys_list = keys[p * share:p * share + share] + proc_tune_variables = tune_variables[p * share:p * share + share] + proc_freqs = freqs[p * share:p * share + share] + proc_cell_types = cell_types[p * share:p * share + share] + else: + proc_keys_list = keys[p * share:] + proc_tune_variables = tune_variables[p * share:] + proc_freqs = freqs[p * share:] + proc_cell_types = cell_types[p * share:] + + processor_shape_space = {key: shape_space[key] for key in proc_keys_list} + service = mp.Process(target=run_tune_s, args=(processor_shape_space, proc_tune_variables, + proc_freqs, proc_cell_types, projectDir, resume, n_cells, p, + rerun)) + + service.start() + jobs.append(service) + + for job in jobs: + job.join() + + +def run_tune_s(processor_shape_space, proc_tune_variables, proc_freqs, proc_cell_types, projectDir, resume, n_cells, p, + rerun): + for i, (key, shape) in enumerate(tqdm(processor_shape_space.items())): + shape['FREQ'] = proc_freqs[i] + if os.path.exists(os.path.join(projectDir, "SimulationData", "Optimisation", key)): + if rerun: + # clear previous results + shutil.rmtree(os.path.join(projectDir, "SimulationData", "Optimisation", key)) + os.mkdir(os.path.join(projectDir, "SimulationData", "Optimisation", key)) + + tuner.tune_ngsolve({key: shape}, 33, SOFTWARE_DIRECTORY, projectDir, key, resume=resume, proc=p, + tune_variable=proc_tune_variables[i], + cell_type=proc_cell_types[i], sim_folder='Optimisation', + save_last=True, + n_cell_last_run=n_cells) # last_key=last_key This would have to be tested again#val2 + else: + tuner.tune_ngsolve({key: shape}, 33, SOFTWARE_DIRECTORY, projectDir, key, resume=resume, proc=p, + tune_variable=proc_tune_variables[i], + cell_type=proc_cell_types[i], sim_folder='Optimisation', + save_last=True, + n_cell_last_run=n_cells) # last_key=last_key This would have to be tested again#val2 + + +def run_eigenmode_parallel(shape_space, shape_space_multi, eigenmode_config, freq_shifts, + projectDir, boundary_conds, uq_config, rerun): + processes = eigenmode_config['processes'] + # split shape_space for different processes/ MPI share process by rank + keys = list(shape_space.keys()) + + # check if number of processors selected is greater than the number of keys in the pseudo shape space + if processes > len(keys): + processes = len(keys) + + shape_space_len = len(keys) + share = round(shape_space_len / processes) + + jobs = [] + for p in range(processes): + # try: + if p < processes - 1: + proc_keys_list = keys[p * share:p * share + share] + else: + proc_keys_list = keys[p * share:] + processor_shape_space = {key: shape_space[key] for key in proc_keys_list} + processor_shape_space_multi = {key: shape_space_multi[key] for key in proc_keys_list} + service = mp.Process(target=run_eigenmode_s, args=(processor_shape_space, processor_shape_space_multi, + projectDir, + freq_shifts, boundary_conds, '', + uq_config, rerun)) -def uq_ngsolve_parallel(shape_space, objectives, solver_dict, solver_args_dict, uq_config): + service.start() + jobs.append(service) + + for job in jobs: + job.join() + + +def run_eigenmode_s(shape_space, shape_space_multi, projectDir, freq_shifts=0, boundary_conds=None, subdir='', + uq_config=None, rerun=True): + """ + Run eigenmode analysis on cavity + + Parameters + ---------- + solver: {'SLANS', 'NGSolve'} + Solver to be used. Native solver is still under development. Results are not as accurate as that of SLANS. + freq_shifts: + (List of) frequency shift. Eigenmode solver searches for eigenfrequencies around this value + boundary_conds: int, list + (List of) boundary condition of left and right cell/beampipe ends + subdir: str + Sub directory to save results to + uq_config: None | dict + Provides inputs required for uncertainty quantification. Default is None and disables uncertainty quantification. + + Returns + ------- + + """ + + def _run_ngsolve(name, n_cells, n_modules, shape, shape_multi, n_modes, f_shift, bc, parentDir, projectDir, + sub_dir='', + uq_config=None): + parallel = False + start_time = time.time() + # create folders for all keys + ngsolve_mevp.createFolder(name, projectDir, subdir=sub_dir) + + if 'OC_R' in shape.keys(): + OC_R = 'OC_R' + else: + OC_R = 'OC' + + # ngsolve_mevp.cavity(n_cells, n_modules, shape['IC'], shape['OC'], shape[OC_R], + # n_modes=n_modes, fid=f"{name}", f_shift=f_shift, bc=bc, beampipes=shape['BP'], + # parentDir=parentDir, projectDir=projectDir, subdir=sub_dir) + if shape['CELL TYPE'] == 'flattop': + # write_cst_paramters(f"{key}_n{n_cell}", shape['IC'], shape['OC'], shape['OC_R'], + # projectDir=projectDir, cell_type="None", solver=select_solver.lower()) + + ngsolve_mevp.cavity_flattop(n_cells, n_modules, shape['IC'], shape['OC'], shape[OC_R], + n_modes=n_modes, fid=f"{name}", f_shift=f_shift, bc=bc, + beampipes=shape['BP'], + parentDir=parentDir, projectDir=projectDir, subdir=sub_dir) + + elif shape['CELL TYPE'] == 'multicell': + # write_cst_paramters(f"{key}_n{n_cell}", shape['IC'], shape['OC'], shape['OC_R'], + # projectDir=projectDir, cell_type="None", solver=select_solver.lower()) + ngsolve_mevp.cavity_multicell(n_cells, n_modules, shape_multi['IC'], shape_multi['OC'], shape_multi[OC_R], + n_modes=n_modes, fid=f"{name}", f_shift=f_shift, bc=bc, + beampipes=shape['BP'], + parentDir=parentDir, projectDir=projectDir, subdir=sub_dir) + else: + # write_cst_paramters(f"{key}_n{n_cell}", shape['IC'], shape['OC'], shape['OC_R'], + # projectDir=projectDir, cell_type="None", solver=select_solver.lower()) + ngsolve_mevp.cavity(n_cells, n_modules, shape['IC'], shape['OC'], shape[OC_R], + n_modes=n_modes, fid=f"{name}", f_shift=f_shift, bc=bc, beampipes=shape['BP'], + parentDir=parentDir, projectDir=projectDir, subdir=sub_dir) + + # run UQ + if uq_config: + objectives = uq_config['objectives'] + solver_dict = {'ngsolvemevp': ngsolve_mevp} + solver_args_dict = {'ngsolvemevp': + {'n_cells': n_cells, 'n_modules': n_modules, 'f_shift': f_shift, 'bc': bc, + 'beampipes': shape['BP'] + }, + 'parentDir': parentDir, + 'projectDir': projectDir, + 'analysis folder': 'NGSolveMEVP', + 'cell type': 'mid cell', + 'optimisation': False + } + + uq_cell_complexity = 'simplecell' + if 'cell complexity' in uq_config.keys(): + uq_cell_complexity = uq_config['cell complexity'] + + # if not parallel: + # # convert to proper shape space + # if uq_cell_complexity == 'multicell': + # print('it is in here now owow ow') + # shape_space = {name: shape_multi} + # uq_multicell(shape_space, objectives, solver_dict, solver_args_dict, uq_config) + # else: + # shape_space = {name: shape} + # uq(shape_space, objectives, solver_dict, solver_args_dict, uq_config) + # else: + if uq_cell_complexity == 'multicell': + shape_space = {name: shape_multi} + uq_ngsolve_parallel_multicell(shape_space, objectives, solver_dict, solver_args_dict, uq_config) + else: + shape_space = {name: shape} + uq_ngsolve_parallel(shape_space, objectives, solver_dict, solver_args_dict, uq_config) + + done(f'Done with Cavity {name}. Time: {time.time() - start_time}') + + for i, (key, shape) in enumerate(tqdm(list(shape_space.items()))): + if isinstance(freq_shifts, int) or isinstance(freq_shifts, float): + freq_shift = freq_shifts + else: + freq_shift = freq_shifts[i] + + if isinstance(boundary_conds, str) or boundary_conds is None: + boundary_cond = boundary_conds + else: + boundary_cond = boundary_conds[i] + + solver_save_dir = 'NGSolveMEVP' + + if os.path.exists(os.path.join(projectDir, "SimulationData", solver_save_dir, key)): + if rerun: + # delete old results + shutil.rmtree(os.path.join(projectDir, "SimulationData", solver_save_dir, key)) + _run_ngsolve(key, shape['n_cells'], 1, shape, shape_space_multi[key], shape['n_cells'], freq_shift, + boundary_cond, SOFTWARE_DIRECTORY, projectDir, sub_dir='', uq_config=uq_config) + # print(id(cav), cav.eigenmode_qois) + else: + # check if eigenmode analysis results exist + if os.path.exists(os.path.join(projectDir, "SimulationData", solver_save_dir, key, "monopole", + "qois.json")): + pass + else: + shutil.rmtree(os.path.join(projectDir, "SimulationData", solver_save_dir, key)) + _run_ngsolve(key, shape['n_cells'], 1, shape, shape_space_multi[key], shape['n_cells'], freq_shift, + boundary_cond, SOFTWARE_DIRECTORY, projectDir, sub_dir='', uq_config=uq_config) + else: + _run_ngsolve(key, shape['n_cells'], 1, shape, shape_space_multi[key], shape['n_cells'], freq_shift, + boundary_cond, SOFTWARE_DIRECTORY, projectDir, sub_dir='', uq_config=uq_config) + + +def run_wakefield_parallel(shape_space, shape_space_multi, wakefield_config, projectDir, marker='', rerun=True): + processes = wakefield_config['processes'] + MROT = wakefield_config['polarisation'] + MT = wakefield_config['MT'] + NFS = wakefield_config['NFS'] + UBT = wakefield_config['wakelength'] + bunch_length = wakefield_config['bunch_length'] + DDR_SIG = wakefield_config['DDR_SIG'] + DDZ_SIG = wakefield_config['DDZ_SIG'] + op_points = None + if 'operating_points' in wakefield_config.keys(): + op_points = wakefield_config['operating_points'] + + uq_config = None + if 'uq_config' in wakefield_config.keys(): + uq_config = wakefield_config['uq_config'] + assert len(uq_config['delta']) == len(uq_config['variables']), error("The number of deltas must " + "be equal to the number of " + "variables.") + WG_M = None + # split shape_space for different processes/ MPI share process by rank + keys = list(shape_space.keys()) + + # check if number of processors selected is greater than the number of keys in the pseudo shape space + if processes > len(keys): + processes = len(keys) + + shape_space_len = len(keys) + share = round(shape_space_len / processes) + jobs = [] + for p in range(processes): + # try: + if p < processes - 1: + proc_keys_list = keys[p * share:p * share + share] + else: + proc_keys_list = keys[p * share:] + + processor_shape_space = {key: shape_space[key] for key in proc_keys_list} + processor_shape_space_multi = {key: shape_space_multi[key] for key in proc_keys_list} + service = mp.Process(target=run_wakefield_s, args=(processor_shape_space, processor_shape_space_multi, + MROT, MT, NFS, UBT, bunch_length, + DDR_SIG, DDZ_SIG, projectDir, op_points, + WG_M, marker, rerun)) + + service.start() + jobs.append(service) + + for job in jobs: + job.join() + + +def run_wakefield_s(shape_space, shape_space_multi, + MROT, MT, NFS, UBT, bunch_length, + DDR_SIG, DDZ_SIG, projectDir, operating_points, + WG_M, marker, rerun): + def _run_abci(name, n_cells, n_modules, shape, MROT, MT, NFS, UBT, bunch_length, + DDR_SIG, DDZ_SIG, projectDir=None, WG_M=None, marker='', + operating_points=None, freq=0, R_Q=0): + + # run abci code + if WG_M is None: + WG_M = [''] + + start_time = time.time() + # run both polarizations if MROT == 2 + for ii in WG_M: + # run abci code + # run both polarizations if MROT == 2 + if 'OC_R' in list(shape.keys()): + OC_R = 'OC_R' + else: + OC_R = 'OC' + + if MROT == 2: + for m in tqdm(range(2)): + abci_geom.cavity(n_cells, n_modules, shape['IC'], shape['OC'], shape[OC_R], + fid=name, MROT=m, MT=MT, NFS=NFS, UBT=UBT, bunch_length=bunch_length, + DDR_SIG=DDR_SIG, DDZ_SIG=DDZ_SIG, parentDir=SOFTWARE_DIRECTORY, + projectDir=projectDir, + WG_M=ii, marker=ii) + else: + for m in tqdm(range(2)): + abci_geom.cavity(n_cells, n_modules, shape['IC'], shape['OC'], shape[OC_R], + fid=name, MROT=m, MT=MT, NFS=NFS, UBT=UBT, bunch_length=bunch_length, + DDR_SIG=DDR_SIG, DDZ_SIG=DDZ_SIG, parentDir=SOFTWARE_DIRECTORY, + projectDir=projectDir, + WG_M=ii, marker=ii) + + done(f'Cavity {name}. Time: {time.time() - start_time}') + + if operating_points: + try: + # check folder for freq and R/Q + folder = fr'{projectDir}/SimulationData/NGSolveMEVP/{name}/monopole/qois.json' + if os.path.exists(folder): + try: + with open(folder, 'r') as json_file: + fm_results = json.load(json_file) + freq = fm_results['freq [MHz]'] + R_Q = fm_results['R/Q [Ohm]'] + except OSError: + info("To run analysis for working points, eigenmode simulation has to be run first" + "to obtain the cavity operating frequency and R/Q") + + if freq != 0 and R_Q != 0: + d = {} + # save qois + for key, vals in tqdm(operating_points.items()): + WP = key + I0 = float(vals['I0 [mA]']) + Nb = float(vals['Nb [1e11]']) + sigma_z = [float(vals["sigma_SR [mm]"]), float(vals["sigma_BS [mm]"])] + bl_diff = ['SR', 'BS'] + + info("Running wakefield analysis for given operating points.") + for i, s in enumerate(sigma_z): + for ii in WG_M: + fid = f"{WP}_{bl_diff[i]}_{s}mm{ii}" + OC_R = 'OC' + if 'OC_R' in shape.keys(): + OC_R = 'OC_R' + for m in range(2): + abci_geom.cavity(n_cells, n_modules, shape['IC'], shape['OC'], shape[OC_R], + fid=fid, MROT=m, MT=MT, NFS=NFS, UBT=10 * s * 1e-3, + bunch_length=s, + DDR_SIG=DDR_SIG, DDZ_SIG=DDZ_SIG, parentDir=SOFTWARE_DIRECTORY, + projectDir=projectDir, + WG_M=ii, marker=ii, sub_dir=f"{name}") + + dirc = fr'{projectDir}\SimulationData\ABCI\{name}{marker}' + # try: + k_loss = abs(ABCIData(dirc, f'{fid}', 0).loss_factor['Longitudinal']) + k_kick = abs(ABCIData(dirc, f'{fid}', 1).loss_factor['Transverse']) + # except: + # k_loss = 0 + # k_kick = 0 + print('here now') + d[fid] = get_qois_value(freq, R_Q, k_loss, k_kick, s, I0, Nb, n_cells) + print('after here', d) + + # save qoi dictionary + run_save_directory = fr'{projectDir}\SimulationData\ABCI\{name}{marker}' + with open(fr'{run_save_directory}\qois.json', "w") as f: + json.dump(d, f, indent=4, separators=(',', ': ')) + + done("Done with the secondary analysis for working points") + else: + info("To run analysis for working points, eigenmode simulation has to be run first" + "to obtain the cavity operating frequency and R/Q") + except KeyError: + error('The working point entered is not valid. See below for the proper input structure.') + show_valid_operating_point_structure() + + for i, (key, shape) in enumerate(tqdm(shape_space.items())): + if os.path.exists(os.path.join(projectDir, "SimulationData", "ABCI", key)): + if rerun: + # remove old simulation results + shutil.rmtree(os.path.join(projectDir, "SimulationData", "ABCI", key)) + os.mkdir(os.path.join(projectDir, "SimulationData", "ABCI", key)) + + _run_abci(key, shape['n_cells'], 1, shape, MROT, MT, NFS, UBT, bunch_length, + DDR_SIG, DDZ_SIG, projectDir, WG_M, marker, operating_points) + else: + # check if eigenmode analysis results exist + if os.path.exists(os.path.join(projectDir, "SimulationData", "ABCI", key, "qois.json")): + pass + else: + _run_abci(key, shape['n_cells'], 1, shape, MROT, MT, NFS, UBT, bunch_length, + DDR_SIG, DDZ_SIG, projectDir, WG_M, marker, operating_points) + else: + _run_abci(key, shape['n_cells'], 1, shape, MROT, MT, NFS, UBT, bunch_length, + DDR_SIG, DDZ_SIG, projectDir, WG_M, marker, operating_points) + + +def run_sequential_wakefield(n_cells, n_modules, processor_shape_space, + MROT=0, MT=4, NFS=10000, UBT=50, bunch_length=20, + DDR_SIG=0.1, DDZ_SIG=0.1, + parentDir=None, projectDir=None, progress_list=None, + WG_M=None, marker=''): + progress = 0 + # get length of processor + total_no_of_shapes = len(list(processor_shape_space.keys())) + for key, shape in processor_shape_space.items(): + skip = False + if os.path.exists(fr'{projectDir}\SimulationData\ABCI\{key}'): + skip = True + + start_time = time.time() + if not skip: + # run abci code + # run both polarizations if MROT == 2 + if 'OC_R' in list(shape.keys()): + OC_R = 'OC_R' + else: + OC_R = 'OC' + + if MROT == 2: + for m in range(2): + abci_geom.cavity(n_cells, n_modules, shape['IC'], shape['OC'], shape[OC_R], + fid=key, MROT=m, MT=MT, NFS=NFS, UBT=UBT, bunch_length=bunch_length, + DDR_SIG=DDR_SIG, DDZ_SIG=DDZ_SIG, parentDir=parentDir, + projectDir=projectDir, + WG_M='', marker='') + else: + abci_geom.cavity(n_cells, n_modules, shape['IC'], shape['OC'], shape[OC_R], + fid=key, MROT=MROT, MT=MT, NFS=NFS, UBT=UBT, bunch_length=bunch_length, + DDR_SIG=DDR_SIG, DDZ_SIG=DDZ_SIG, parentDir=parentDir, projectDir=projectDir, + WG_M='', marker='') + + print(f'Cavity {key}. Time: {time.time() - start_time}') + + # update progress + progress_list.append((progress + 1) / total_no_of_shapes) + + +def uq_ngsolve_parallel(shape_space, objectives, solver_dict, solver_args_dict, uq_config): """ Parameters @@ -7950,7 +8503,7 @@ def uq_ngsolve_parallel(shape_space, objectives, solver_dict, solver_args_dict, qois_result_dict = {} Ttab_val_f = [] keys = [] - for i1 in range(no_sims): + for i1 in range(proc_count): if i1 == 0: df = pd.read_csv(uq_path / fr'table_{i1}.csv', sep='\t', engine='python') else: @@ -8082,11 +8635,11 @@ def uq(key, objectives, pol, uq_config, uq_path, # delta = [0.05 for _ in range(len(uq_vars))] perturbed_cell_node = np.array(cell_node) - for i1 in proc_keys_list: + for i1, proc_key in enumerate(proc_keys_list): skip = False for j, uq_var in enumerate(uq_vars): uq_var_indx = VAR_TO_INDEX_DICT[uq_var] - perturbed_cell_node[uq_var_indx] = cell_node[uq_var_indx] * (1 + delta[j] * processor_nodes[j]) + perturbed_cell_node[uq_var_indx] = cell_node[uq_var_indx] * (1 + delta[j] * processor_nodes[j, i1]) if cell_type.lower() == 'mid cell' or cell_type.lower() == 'mid-cell' or cell_type.lower() == 'mid_cell': # cell_node = shape['IC'] @@ -8114,7 +8667,7 @@ def uq(key, objectives, pol, uq_config, uq_path, enforce_Req_continuity(mid, left, right, cell_type) # perform checks on geometry - fid = fr'{key}_Q{i1}' + fid = fr'{key}_Q{proc_key}' # check if folder exists and skip if it does if os.path.exists(fr'{projectDir}\SimulationData\{analysis_folder}\{key}\{fid}'): @@ -8542,46 +9095,19 @@ def uq_multicell_sequential(n_cells, n_modules, shape, qois, n_modes, f_shift, b # print(np.atleast_2d(Ttab_val_f), processor_weights) -def run_sequential_wakefield(n_cells, n_modules, processor_shape_space, - MROT=0, MT=4, NFS=10000, UBT=50, bunch_length=20, - DDR_SIG=0.1, DDZ_SIG=0.1, - parentDir=None, projectDir=None, progress_list=None, - WG_M=None, marker=''): - progress = 0 - # get length of processor - total_no_of_shapes = len(list(processor_shape_space.keys())) - for key, shape in processor_shape_space.items(): - skip = False - if os.path.exists(fr'{projectDir}\SimulationData\ABCI\{key}'): - skip = True - - start_time = time.time() - if not skip: - # run abci code - # run both polarizations if MROT == 2 - if 'OC_R' in list(shape.keys()): - OC_R = 'OC_R' - else: - OC_R = 'OC' - - if MROT == 2: - for m in range(2): - abci_geom.cavity(n_cells, n_modules, shape['IC'], shape['OC'], shape[OC_R], - fid=key, MROT=m, MT=MT, NFS=NFS, UBT=UBT, bunch_length=bunch_length, - DDR_SIG=DDR_SIG, DDZ_SIG=DDZ_SIG, parentDir=parentDir, - projectDir=projectDir, - WG_M='', marker='') - else: - abci_geom.cavity(n_cells, n_modules, shape['IC'], shape['OC'], shape[OC_R], - fid=key, MROT=MROT, MT=MT, NFS=NFS, UBT=UBT, bunch_length=bunch_length, - DDR_SIG=DDR_SIG, DDZ_SIG=DDZ_SIG, parentDir=parentDir, projectDir=projectDir, - WG_M='', marker='') - - print(f'Cavity {key}. Time: {time.time() - start_time}') +def to_multicell(n_cells, shape): + shape_multicell = {} + mid_cell = shape['IC'] + mid_cell_multi = np.array([[[a, a] for _ in range(n_cells - 1)] for a in mid_cell]) - # update progress - progress_list.append((progress + 1) / total_no_of_shapes) + shape_multicell['OC'] = shape['OC'] + shape_multicell['OC_R'] = shape['OC_R'] + shape_multicell['IC'] = mid_cell_multi + # shape_multicell['BP'] = shape['BP'] + shape_multicell['n_cells'] = shape['n_cells'] + shape_multicell['CELL TYPE'] = 'multicell' + return shape_multicell def get_objectives_value(d, obj, norm_length, n_cells): Req = d['CAVITY RADIUS'][n_cells - 1] * 10 # convert to mm diff --git a/cavsim2d/data_module/abci_data.py b/cavsim2d/data_module/abci_data.py index 656056c..36b6362 100644 --- a/cavsim2d/data_module/abci_data.py +++ b/cavsim2d/data_module/abci_data.py @@ -9,17 +9,14 @@ import numpy as np from termcolor import colored +from cavsim2d.utils.shared_functions import info, error, done + file_color = 'cyan' # DEBUG = False DEBUG = True -def print_(*arg): - if DEBUG: - print(colored(f'\t\t{arg}', file_color)) - - class ABCIData: def __init__(self, dirc, fid, MROT): self.title_dict = {} @@ -37,7 +34,7 @@ def checks(self, fid, MROT): if os.path.exists(dirc): self._get_plot_data(dirc) else: - print_("Hey chief, there seems to be a problem with the ABCI file directory. Please check.") + info("Hey chief, there seems to be a problem with the ABCI file directory. Please check.") def _get_plot_data(self, dirc): frame_objects = {} @@ -79,10 +76,8 @@ def _get_plot_data(self, dirc): # add titles to frame_title if 'TITLE' in line or 'MORE' in line: frame_title.append(line) - # print(line) # if 'Transverse Wake' in line: # key = 'Transverse' - # print('True') # get other parameters from title # try: @@ -90,13 +85,10 @@ def _get_plot_data(self, dirc): key = 'Azimuthal' if 'Transverse Wake' in line: key = 'Transverse' - # print("it got here to transverse wake") if 'Longitudinal Wake' in line: key = 'Longitudinal' - # print("it got here to longitudinal wake") if 'Loss Factor' in line and key: - # print("Got in here", key) indx_0 = line.index('= ') indx_1 = line.index('V/pC') loss_factor = float(line[indx_0 + 2:indx_1]) @@ -167,7 +159,6 @@ def _get_plot_data(self, dirc): # y = np.insert(y, -1, 0).tolist() self.data_dict[key] = [x, y] - # print("At least it got here") # include impedance magnitude if {'Real Part of Longitudinal Impedance', 'Imaginary Part of Longitudinal Impedance'}.issubset(self.data_dict.keys()): # longitudinal @@ -197,7 +188,6 @@ def get_data(self, key): if isinstance(key, int): key = plot_decorations[key] - # print_(self.data_dict) self.x = self.data_dict[key][0] self.y = self.data_dict[key][1] @@ -294,7 +284,7 @@ def _get_bands(self): # print_(group_dict) return group_dict except Exception as e: - print_(f"Bands cannot be gotten without getting the peaks first. {e}") + info(f"Bands cannot be gotten without getting the peaks first. {e}") def _interp_fl(self): fl_list = [] @@ -447,7 +437,6 @@ def append_geom_parameters(values): def calc_k_loss(): for key, value in d.items(): - print(f"Processing for Cavity {key}") abci_data_long = ABCIData(abci_data_dir, key, 0) abci_data_trans = ABCIData(abci_data_dir, key, 1) @@ -456,7 +445,7 @@ def calc_k_loss(): k_loss_trans = abci_data_trans.loss_factor['Transverse'] if math.isnan(k_loss_trans): - print_(f"Encountered an exception: Check shape {key}") + info(f"Encountered an exception: Check shape {key}") continue # long @@ -565,7 +554,7 @@ def all(mon_interval, dip_interval): k_loss_trans = abci_data_dip.loss_factor['Transverse'] if math.isnan(k_loss_trans): - print_(f"Encountered an exception: Check shape {key}") + info(f"Encountered an exception: Check shape {key}") continue # long diff --git a/cavsim2d/data_module/process_data.py b/cavsim2d/data_module/process_data.py index 393c61d..418e877 100644 --- a/cavsim2d/data_module/process_data.py +++ b/cavsim2d/data_module/process_data.py @@ -9,6 +9,8 @@ from utils.file_reader import FileReader from utils.shared_functions import ellipse_tangent +from cavsim2d.utils.shared_functions import error + fr = FileReader() @@ -63,7 +65,7 @@ def weed_maintain_key(self, d, bp, dirc): try: d = fr.svl_reader(fr"{dirc}\{key}\cavity_33.svl") freq = d['FREQUENCY'][0] - print(key, freq) + ic = [A_m, B_m, a_m, b_m, Ri_m, L_m, Req_m, alpha_ic] oc = [A_le, B_le, a_le, b_le, Ri_le, L_le, Req_le, alpha_oc] cell_type = val['IC'], val['OC'], 'Mid Cell' @@ -92,7 +94,6 @@ def combine_results(self, dir1, dir2, save_excel='recent_save'): d_HOM = fr.excel_reader(dir2) d_FM = d_FM['Sheet1'] d_HOM = d_HOM['Sheet1'] - # print(d_HOM.iloc[0]) ob_FM_key_align_dict, ob_HOM_key_align_dict = {}, {} for key, val in d_FM.iterrows(): @@ -101,10 +102,6 @@ def combine_results(self, dir1, dir2, save_excel='recent_save'): for key, val in d_HOM.iterrows(): ob_HOM_key_align_dict[int(val['key'])] = list(val)[2:] - # print(ob_FM_key_align_dict) - # print() - # print(ob_HOM_key_align_dict) - save_new = {'key': [], 'A': [], 'B': [], 'a': [], 'b': [], 'Ri': [], 'L': [], 'Req': [], 'alpha': [], 'E_stored': [], 'Rsh': [], 'Q': [], 'Epk': [], 'Hpk': [], 'Eacc': [], 'Rsh/Q': [], 'Epk/Eacc': [], 'Bpk/Eacc': [], 'kcc': [], @@ -118,7 +115,6 @@ def combine_results(self, dir1, dir2, save_excel='recent_save'): try: A_m, B_m, a_m, b_m, Ri_m, L_m, Req_m, L_bp = val[0], val[1], val[2], val[3], val[4], val[5], val[6], 0 alpha = self._calculate_alpha(A_m, B_m, a_m, b_m, Ri_m, L_m, Req_m, L_bp) - # print(key, alpha, val[-10]) if key in list(ob_HOM_key_align_dict.keys()): # update save new @@ -150,12 +146,9 @@ def combine_results(self, dir1, dir2, save_excel='recent_save'): self.write_cst_paramters(key, A_m, B_m, a_m, b_m, Ri_m, L_m, Req_m) except Exception as e: - print(f"Key not in both -> {e}") + error(f"Key not in both -> {e}") problem_keys.append(key) - print(len(problem_keys), problem_keys) - print(len(save_new['k_loss_M0'])) - df = pd.DataFrame.from_dict(save_new) df.to_excel(f'{save_excel}.xlsx', sheet_name='Sheet1') @@ -165,7 +158,6 @@ def combine_results_2(self, dir1, dir2, save_excel): d_2 = fr.excel_reader(dir2) d_1 = d_1['Sheet1'] d_2 = d_2['Sheet1'] - # print(d_2.iloc[0]) d1_key_align_dict, d2_key_align_dict = {}, {} for key, val in d_1.iterrows(): @@ -174,10 +166,6 @@ def combine_results_2(self, dir1, dir2, save_excel): for key, val in d_2.iterrows(): d2_key_align_dict[int(val['key'])] = list(val)[2:] - # print(ob_FM_key_align_dict) - # print() - # print(ob_HOM_key_align_dict) - save_new = {'key': [], 'A': [], 'B': [], 'a': [], 'b': [], 'Ri': [], 'L': [], 'Req': [], 'alpha': [], 'E_stored': [], 'Rsh': [], 'Q': [], 'Epk': [], 'Hpk': [], 'Eacc': [], 'Rsh/Q': [], 'Epk/Eacc': [], 'Bpk/Eacc': [], 'kcc': [], @@ -190,7 +178,6 @@ def combine_results_2(self, dir1, dir2, save_excel): try: A_m, B_m, a_m, b_m, Ri_m, L_m, Req_m, L_bp = val[0], val[1], val[2], val[3], val[4], val[5], val[6], 0 alpha = self._calculate_alpha(A_m, B_m, a_m, b_m, Ri_m, L_m, Req_m, L_bp) - # print(key, alpha, val[-10]) if key in list(d2_key_align_dict.keys()): # update save new @@ -223,12 +210,9 @@ def combine_results_2(self, dir1, dir2, save_excel): self.write_cst_paramters(key, A_m, B_m, a_m, b_m, Ri_m, L_m, Req_m) except Exception as e: - print(f"Key not in both -> {e}") + error(f"Key not in both -> {e}") problem_keys.append(key) - print(len(problem_keys), problem_keys) - print(len(save_new['k_loss_M0'])) - df = pd.DataFrame.from_dict(save_new) df.to_excel(f'{save_excel}.xlsx', sheet_name='Sheet1') @@ -275,9 +259,6 @@ def join_excel(self, generic_name, proc_range, save_excel='Combined', request='H d_combine[f'Z_long[max(f>{0.5})]'].append(val[9]) d_combine[f'Z_trans[max(f>{0.6})]'].append(val[10]) - # print(len(list(d_combine))) - # print(d_combine) - df = pd.DataFrame.from_dict(d_combine) df.to_excel(f'{save_excel}.xlsx', sheet_name='Sheet1') diff --git a/cavsim2d/solvers/NGSolve/eigen_ngsolve.py b/cavsim2d/solvers/NGSolve/eigen_ngsolve.py index 7097603..d3d34de 100644 --- a/cavsim2d/solvers/NGSolve/eigen_ngsolve.py +++ b/cavsim2d/solvers/NGSolve/eigen_ngsolve.py @@ -599,13 +599,10 @@ def cavity(self, no_of_cells=1, no_of_modules=1, mid_cells_par=None, l_end_cell_ evals, evecs = solvers.PINVIT(a.mat, m.mat, pre=projpre, num=no_of_cells + 1, maxit=mesh_args[1], printrates=False) - # print out eigenvalues - # print("Eigenvalues") freq_fes = [] evals[0] = 1 # <- replace nan with zero for i, lam in enumerate(evals): freq_fes.append(c0 * np.sqrt(lam) / (2 * np.pi) * 1e-6) - # print(i, lam, 'freq: ', c0 * np.sqrt(lam) / (2 * np.pi) * 1e-6, "MHz") # plot results gfu_E = [] @@ -625,13 +622,11 @@ def cavity(self, no_of_cells=1, no_of_modules=1, mid_cells_par=None, l_end_cell_ # u = GridFunction(fes, multidim=30, name='resonances') # lamarnoldi = ArnoldiSolver(a.mat, m.mat, fes.FreeDofs(), # list(u.vecs), shift=300) - # print(np.sort(c0*np.sqrt(lamarnoldi)/(2*np.pi) * 1e-6)) # save json file shape = {'IC': update_alpha(mid_cells_par), 'OC': update_alpha(l_end_cell_par), 'OC_R': update_alpha(r_end_cell_par)} - # print(run_save_directory) with open(Path(fr"{run_save_directory}/geometric_parameters.json"), 'w') as f: json.dump(shape, f, indent=4, separators=(',', ': ')) @@ -808,12 +803,10 @@ def cavity_multicell(self, no_of_cells=1, no_of_modules=1, mid_cells_par=None, l # ic('Time to complete sim: ', time.time()-start) # print out eigenvalues - # print("Eigenvalues") # freq_fes = [] evals[0] = 1 # <- replace nan with zero # for i, lam in enumerate(evals): freq_fes = c0 * np.sqrt(evals) / (2 * np.pi) * 1e-6 - # print(i, lam, 'freq: ', c0 * np.sqrt(lam) / (2 * np.pi) * 1e-6, "MHz") # plot results gfu_E = [] @@ -833,13 +826,12 @@ def cavity_multicell(self, no_of_cells=1, no_of_modules=1, mid_cells_par=None, l # u = GridFunction(fes, multidim=30, name='resonances') # lamarnoldi = ArnoldiSolver(a.mat, m.mat, fes.FreeDofs(), # list(u.vecs), shift=300) - # print(np.sort(c0*np.sqrt(lamarnoldi)/(2*np.pi) * 1e-6)) # save json file shape = {'IC': mid_cells_par.tolist(), 'OC': l_end_cell_par.tolist(), 'OC_R': r_end_cell_par.tolist()} - # print(run_save_directory) + with open(Path(fr"{run_save_directory}/geometric_parameters.json"), 'w') as f: json.dump(shape, f, indent=4, separators=(',', ': ')) @@ -921,7 +913,6 @@ def cavity_flattop(self, no_of_cells=1, no_of_modules=1, # write self.write_geometry(run_save_directory, no_of_cells, mid_cells_par, l_end_cell_par, r_end_cell_par, beampipes, cell_type='flattop', plot=False) - # print('done writing geometry') # read geometry cav_geom = pd.read_csv(f'{run_save_directory}\geodata.n', @@ -1005,7 +996,6 @@ def cavity_flattop(self, no_of_cells=1, no_of_modules=1, evals[0] = 1 # <- replace nan with zero for i, lam in enumerate(evals): freq_fes.append(c0 * np.sqrt(lam) / (2 * np.pi) * 1e-6) - # print(i, lam, 'freq: ', c0 * np.sqrt(lam) / (2 * np.pi) * 1e-6, "MHz") # plot results gfu_E = [] diff --git a/cavsim2d/utils/shared_functions.py b/cavsim2d/utils/shared_functions.py index bd3ac95..05874ae 100644 --- a/cavsim2d/utils/shared_functions.py +++ b/cavsim2d/utils/shared_functions.py @@ -298,10 +298,8 @@ def write_cst_paramters(key, ic_, oc_l, oc_r, projectDir, cell_type, opt=False, folder = 'Optimisation' if cell_type is None: - # print("Writing parameters to file") path = fr'{projectDir}/SimulationData/{folder}/{key}/{key}.txt' - # print(path) with open(path, 'w') as f: name_list = ['Aeq', 'Beq', 'ai', 'bi', 'Ri', 'L', 'Req', 'alpha', 'Aeq_e', 'Beq_e', 'ai_e', 'bi_e', 'Ri_e', 'L_e', 'Req', 'alpha_e', 'key'] @@ -316,11 +314,9 @@ def write_cst_paramters(key, ic_, oc_l, oc_r, projectDir, cell_type, opt=False, f.write(f'{name_list[i]} = "{value_list[i]}" ""\n') else: - # print("Writing parameters to file") path = fr'{projectDir}/SimulationData/{folder}/{key}/{key}.txt' path_mc = fr'{projectDir}/SimulationData/{folder}/{key}/{key}_Multicell.txt' - # print(path) with open(path, 'w') as f: name_list = ['Aeq', 'Beq', 'ai', 'bi', 'Ri', 'L', 'Req', 'alpha', 'Aeq_e', 'Beq_e', 'ai_e', 'bi_e', 'Ri_e', 'L_e', 'Req_e', 'alpha_e', 'key'] @@ -362,8 +358,6 @@ def write_cst_paramters(key, ic_, oc_l, oc_r, projectDir, cell_type, opt=False, else: f.write(f'{name_list[i]} = "{value_list[i]}" ""\n') - # print("Writing to file complete.") - def stroud(p): """ @@ -445,9 +439,9 @@ def quad_stroud3(rdim, degree): def c1_leg_monomial_integral(expon): if expon < 0: - print("\n") - print("C1_LEG_MONOMIAL_INTEGRAL - Fatal error!") - print("EXPON < 0.") + error("\n") + error("C1_LEG_MONOMIAL_INTEGRAL - Fatal error!") + error("EXPON < 0.") raise ValueError("C1_LEG_MONOMIAL_INTEGRAL - Fatal error!") if expon % 2 == 1: @@ -533,16 +527,16 @@ def r8_mop(i): def cn_leg_05_1(n, option=1): # Check if the value of n is 4, 5, or 6 if n not in [4, 5, 6]: - print("\n") - print("CN_LEG_05_1 - Fatal error!") - print("The value of N must be 4, 5, or 6.") + error("\n") + error("CN_LEG_05_1 - Fatal error!") + error("The value of N must be 4, 5, or 6.") raise ValueError("CN_LEG_05_1 - Fatal error!") # Check for valid option when n = 4 or 5 if n in [4, 5] and option not in [1, 2]: - print("\n") - print("CN_LEG_05_1 - Fatal error!") - print("When N = 4 or 5, OPTION must be 1 or 2.") + error("\n") + error("CN_LEG_05_1 - Fatal error!") + error("When N = 4 or 5, OPTION must be 1 or 2.") raise ValueError("CN_LEG_05_1 - Fatal error!") o = n ** 2 + n + 2 @@ -4592,6 +4586,9 @@ def enforce_Req_continuity(par_mid, par_end_l, par_end_r, cell_type): par_mid[6] = par_end_r[6] par_end_l[6] = par_end_r[6] +def save_tune_result(d, filename, projectDir, key, sim_folder='SLAN_Opt'): + with open(fr"{projectDir}\SimulationData\{sim_folder}\{key}\{filename}", 'w') as file: + file.write(json.dumps(d, indent=4, separators=(',', ': '))) def error(*arg): print(colored(f'{arg[0]}', 'red')) diff --git a/notebooks/optimisation.ipynb b/notebooks/optimisation.ipynb index 37b253d..3d29bfa 100644 --- a/notebooks/optimisation.ipynb +++ b/notebooks/optimisation.ipynb @@ -43,14 +43,13 @@ "name": "stdout", "output_type": "stream", "text": [ - "\u001b[32mProject D:\\Dropbox\\CavityDesignHub\\MuCol_Study\\SimulationData\\ConsoleTest created successfully/already exists.\u001b[0m\n", - "D:\\Dropbox\\CavityDesignHub\\MuCol_Study\\SimulationData\\ConsoleTest\\cavities\n" + "\u001b[32mProject D:\\Dropbox\\CavityDesignHub\\MuCol_Study\\SimulationData\\ConsoleTest created successfully/already exists.\u001b[0m\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "4ed220f53826496ba684c9cb55f0d2f2", + "model_id": "3e0528e5a9ea42d8859ef403e5b3defe", "version_major": 2, "version_minor": 0 }, @@ -65,19 +64,34 @@ "name": "stdout", "output_type": "stream", "text": [ - "Pareto: 3 optimal values, 3 objects\n", - " Epk/Eacc [] Bpk/Eacc [mT/MV/m]\n", - "0 1.912193 4.733067\n", - "1 1.791248 5.481455\n", - "2 1.803702 5.537501\n", - "================================================================================\n" + "['G0_C1_P', 'G0_C2_P', 'G0_C4_P'] []\n", + "Pareto: 2 optimal values, 2 objects\n", + "\u001b[32m key A B a b Ri L Req alpha_i \\\n", + "0 G0_C2_P 38.0 50.0 25.0 25.0 77.5 93.5 183.668236 119.362648 \n", + "1 G0_C1_P 62.0 74.0 15.0 15.0 72.5 93.5 174.812717 114.818083 \n", + "2 G0_C4_P 26.0 26.0 35.0 35.0 62.5 93.5 182.457954 114.271513 \n", + "\n", + " alpha_o freq [MHz] Epk/Eacc [] Bpk/Eacc [mT/MV/m] ZL [max(1" ] @@ -121,24 +170,28 @@ "cavs.save('D:\\Dropbox\\CavityDesignHub\\MuCol_Study\\SimulationData\\ConsoleTest')\n", "cell_type = 'end-end-cell'\n", "optimisation_config = {\n", - " 'initial points': 5,\n", + " 'initial_points': 5,\n", " 'method': {\n", " 'LHS': {'seed': 5},\n", " # 'Sobol Sequence': {'index': 2},\n", " # 'Random': {},\n", " # 'Uniform': {},\n", " },\n", - " 'cell type': cell_type,\n", - " # 'mid cell': [1, 2, 3, 3, 6, 5, 2], # must enter if mid-end cell selected\n", - " 'tune freq.': 801.58,\n", - " 'tune variable': 'Req',\n", + " # 'mid-cell': [1, 2, 3, 3, 6, 5, 2], # must enter if mid-end cell selected\n", + " 'tune_config': {\n", + " 'freqs': 801.58,\n", + " 'parameters': 'Req',\n", + " 'cell_types': cell_type,\n", + " 'processes': 1\n", + " },\n", + " 'wakefield_config': {},\n", " 'optimisation by': 'pareto',\n", - " 'crossover factor': 5,\n", - " 'elites for crossover': 2,\n", - " 'mutation factor': 5,\n", - " 'chaos factor': 5,\n", + " 'crossover_factor': 5,\n", + " 'elites_for_crossover': 2,\n", + " 'mutation_factor': 5,\n", + " 'chaos_factor': 5,\n", " 'processes': 3,\n", - " 'no. of generation': 2,\n", + " 'no_of_generation': 2,\n", " 'bounds': {'A': [20.0, 80.0],\n", " 'B': [20.0, 80.0],\n", " 'a': [10.0, 60.0],\n", @@ -153,12 +206,11 @@ " # ['equal', 'freq [MHz]', 801.58],\n", " ['min', 'Epk/Eacc []'],\n", " ['min', 'Bpk/Eacc [mT/MV/m]'],\n", - " # ['min', 'ZL', [1, 2, 5]],\n", + " ['min', 'ZL', [1, 2, 5]],\n", " ],\n", - " 'weights': [1, 1],\n", - " 'uq': {\n", - " 'option': True,\n", - " 'processes': 2,\n", + " 'weights': [1, 1, 1, 1],\n", + " 'uq_config': {\n", + " 'processes': 5,\n", " 'variables': ['A', 'a'],\n", " 'delta': [0.05, 0.05],\n", " 'distribution': 'gaussian',\n", @@ -205,52 +257,60 @@ "widgets": { "application/vnd.jupyter.widget-state+json": { "state": { - "2138e5c6ef7c4766a97ea1c4da5a3202": { + "0ce092c28e194f83b106ca3c0b2a2917": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", - "model_name": "HTMLStyleModel", + "model_name": "ProgressStyleModel", "state": { - "description_width": "", - "font_size": null, - "text_color": null + "description_width": "" } }, - "21b94bbea4de4dcd851f881cccf26fea": { + "22d18e08f5284e9a9a255ad06bb578ad": { "model_module": "@jupyter-widgets/base", "model_module_version": "2.0.0", "model_name": "LayoutModel", "state": {} }, - "4e7737ea73444fbbae05db8b6926e7f4": { + "3e0528e5a9ea42d8859ef403e5b3defe": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "HBoxModel", + "state": { + "children": [ + "IPY_MODEL_4fbcde1fcf0b4d139ac4493436b98bb0", + "IPY_MODEL_a2bb2e385e0c4dd19e41bc9237f4e78e", + "IPY_MODEL_4403629e73964c059d4a4e503800c290" + ], + "layout": "IPY_MODEL_3eb13d022e63474491137fe3cff64b26" + } + }, + "3eb13d022e63474491137fe3cff64b26": { "model_module": "@jupyter-widgets/base", "model_module_version": "2.0.0", "model_name": "LayoutModel", "state": {} }, - "4ed220f53826496ba684c9cb55f0d2f2": { + "4403629e73964c059d4a4e503800c290": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", - "model_name": "HBoxModel", + "model_name": "HTMLModel", "state": { - "children": [ - "IPY_MODEL_c7e4210614934f4d9de89f2a8870bc6e", - "IPY_MODEL_a3d2c47b9c5b47a48ef982909c9a46ca", - "IPY_MODEL_50e56b0e554e4d8f94e2768735ffe442" - ], - "layout": "IPY_MODEL_4e7737ea73444fbbae05db8b6926e7f4" + "layout": "IPY_MODEL_22d18e08f5284e9a9a255ad06bb578ad", + "style": "IPY_MODEL_6e5ca72c42be4896a95c91435d4c8897", + "value": " 2/2 [19:04<00:00, 601.72s/it]" } }, - "50e56b0e554e4d8f94e2768735ffe442": { + "4fbcde1fcf0b4d139ac4493436b98bb0": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", "model_name": "HTMLModel", "state": { - "layout": "IPY_MODEL_21b94bbea4de4dcd851f881cccf26fea", - "style": "IPY_MODEL_2138e5c6ef7c4766a97ea1c4da5a3202", - "value": " 2/2 [03:58<00:00, 121.50s/it]" + "layout": "IPY_MODEL_d2662d062a624aab992d39b14e3055ec", + "style": "IPY_MODEL_569cefea2abb4c71bb49227407419d31", + "value": "100%" } }, - "7858fc86516b4f9389e13e7f32620ca0": { + "569cefea2abb4c71bb49227407419d31": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", "model_name": "HTMLStyleModel", @@ -260,42 +320,34 @@ "text_color": null } }, - "8b2e102f0e704bee9079e3b708182272": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "a3d2c47b9c5b47a48ef982909c9a46ca": { + "6e5ca72c42be4896a95c91435d4c8897": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", - "model_name": "FloatProgressModel", + "model_name": "HTMLStyleModel", "state": { - "layout": "IPY_MODEL_f4ba32aae19d4b519da481295cc9a333", - "max": 2, - "style": "IPY_MODEL_d59e4f8578864008b25357f3fc2d4e79", - "value": 2 + "description_width": "", + "font_size": null, + "text_color": null } }, - "c7e4210614934f4d9de89f2a8870bc6e": { + "a2bb2e385e0c4dd19e41bc9237f4e78e": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", - "model_name": "HTMLModel", + "model_name": "FloatProgressModel", "state": { - "layout": "IPY_MODEL_8b2e102f0e704bee9079e3b708182272", - "style": "IPY_MODEL_7858fc86516b4f9389e13e7f32620ca0", - "value": "100%" + "layout": "IPY_MODEL_eca2821452794432b4882e5687ca8f67", + "max": 2, + "style": "IPY_MODEL_0ce092c28e194f83b106ca3c0b2a2917", + "value": 2 } }, - "d59e4f8578864008b25357f3fc2d4e79": { - "model_module": "@jupyter-widgets/controls", + "d2662d062a624aab992d39b14e3055ec": { + "model_module": "@jupyter-widgets/base", "model_module_version": "2.0.0", - "model_name": "ProgressStyleModel", - "state": { - "description_width": "" - } + "model_name": "LayoutModel", + "state": {} }, - "f4ba32aae19d4b519da481295cc9a333": { + "eca2821452794432b4882e5687ca8f67": { "model_module": "@jupyter-widgets/base", "model_module_version": "2.0.0", "model_name": "LayoutModel", diff --git a/notebooks/sweep.ipynb b/notebooks/sweep.ipynb index cfa1e36..91987b6 100644 --- a/notebooks/sweep.ipynb +++ b/notebooks/sweep.ipynb @@ -83,7 +83,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "df24b53b3e424caf8ede3e232f662017", + "model_id": "3155e589f95443a58f278eb2650e3eee", "version_major": 2, "version_minor": 0 }, @@ -97,7 +97,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "0991cd1a6794423ca3af350689f7b598", + "model_id": "ef8fc030d9024c68932cc802482f9792", "version_major": 2, "version_minor": 0 }, @@ -112,13 +112,16 @@ "name": "stdout", "output_type": "stream", "text": [ - "\u001b[32mDone with Cavity tesla. Time: 12.043213605880737\u001b[0m\n" + "D:\\Dropbox\\CavityDesignHub\\MuCol_Study\\SimulationData\\ConsoleTest\\cavities tesla\n", + "here now now\n", + "\u001b[32mDone with Cavity tesla. Time: 10.399182558059692\u001b[0m\n", + "D:\\Dropbox\\CavityDesignHub\\MuCol_Study\\SimulationData\\ConsoleTest\\cavities/SimulationData/NGSolveMEVP/tesla/monopole/qois.json\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "24e87c341dbf40788af1e6697d14bfbe", + "model_id": "40976ffdca6c4581b9990a81010b540c", "version_major": 2, "version_minor": 0 }, @@ -133,13 +136,16 @@ "name": "stdout", "output_type": "stream", "text": [ - "\u001b[32mDone with Cavity tesla. Time: 12.225771188735962\u001b[0m\n" + "D:\\Dropbox\\CavityDesignHub\\MuCol_Study\\SimulationData\\ConsoleTest\\cavities tesla\n", + "here now now\n", + "\u001b[32mDone with Cavity tesla. Time: 9.837846279144287\u001b[0m\n", + "D:\\Dropbox\\CavityDesignHub\\MuCol_Study\\SimulationData\\ConsoleTest\\cavities/SimulationData/NGSolveMEVP/tesla/monopole/qois.json\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "23fb17607e91411aa501b5cdda43c695", + "model_id": "f3a3864a1275487489e29b4c227f97f4", "version_major": 2, "version_minor": 0 }, @@ -154,13 +160,16 @@ "name": "stdout", "output_type": "stream", "text": [ - "\u001b[32mDone with Cavity tesla. Time: 12.151230096817017\u001b[0m\n" + "D:\\Dropbox\\CavityDesignHub\\MuCol_Study\\SimulationData\\ConsoleTest\\cavities tesla\n", + "here now now\n", + "\u001b[32mDone with Cavity tesla. Time: 9.976190090179443\u001b[0m\n", + "D:\\Dropbox\\CavityDesignHub\\MuCol_Study\\SimulationData\\ConsoleTest\\cavities/SimulationData/NGSolveMEVP/tesla/monopole/qois.json\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "0334bdf0d1ec499494b135bedf513d0f", + "model_id": "2580861754c445d29ea55ac99f9653de", "version_major": 2, "version_minor": 0 }, @@ -175,13 +184,16 @@ "name": "stdout", "output_type": "stream", "text": [ - "\u001b[32mDone with Cavity tesla. Time: 12.74089527130127\u001b[0m\n" + "D:\\Dropbox\\CavityDesignHub\\MuCol_Study\\SimulationData\\ConsoleTest\\cavities tesla\n", + "here now now\n", + "\u001b[32mDone with Cavity tesla. Time: 9.525193214416504\u001b[0m\n", + "D:\\Dropbox\\CavityDesignHub\\MuCol_Study\\SimulationData\\ConsoleTest\\cavities/SimulationData/NGSolveMEVP/tesla/monopole/qois.json\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "a6152319c8754b199ca33909768300cc", + "model_id": "3c28e4732ae54a35b13669a5c0fd3e28", "version_major": 2, "version_minor": 0 }, @@ -196,125 +208,17 @@ "name": "stdout", "output_type": "stream", "text": [ - "\u001b[32mDone with Cavity tesla. Time: 11.466621160507202\u001b[0m\n" - ] - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "8d95f8815e0f4db3b6a302eb5f60bf4d", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - " 0%| | 0/1 [00:00" ] @@ -385,582 +289,33 @@ }, "file_extension": ".py", "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.9" - }, - "widgets": { - "application/vnd.jupyter.widget-state+json": { - "state": { - "032d434d655c427da7e402a8102630cc": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "0334bdf0d1ec499494b135bedf513d0f": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HBoxModel", - "state": { - "children": [ - "IPY_MODEL_23814384374b4b1681a30e6bf7da82e6", - "IPY_MODEL_6315c3fd8f8b4fd09d8c6c4cfb85ec37", - "IPY_MODEL_6464e14b06b34cd190312ace46e4f295" - ], - "layout": "IPY_MODEL_7bdab20ea7b8438d9bfc1a535f2b5b10" - } - }, - "0429204e07f84ba0aeb980a7931ec8a3": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLStyleModel", - "state": { - "description_width": "", - "font_size": null, - "text_color": null - } - }, - "0435dd678c144c278ce2e69ef90828e1": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "05c122605f3b429995790275971a613f": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLModel", - "state": { - "layout": "IPY_MODEL_032d434d655c427da7e402a8102630cc", - "style": "IPY_MODEL_748944c6ea11477190599555c29100c4", - "value": "100%" - } - }, - "061a02a4f9aa4a378fc1a50135136460": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "ProgressStyleModel", - "state": { - "description_width": "" - } - }, - "07746a0d558e40d5b8aca2e78ea6ef5d": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "ProgressStyleModel", - "state": { - "description_width": "" - } - }, - "0991cd1a6794423ca3af350689f7b598": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HBoxModel", - "state": { - "children": [ - "IPY_MODEL_bc0e187751d64db9abb6907bfc03b5cc", - "IPY_MODEL_6bc3322393ad4a21a47ea1f9d7e33495", - "IPY_MODEL_f8960ece08ec4f058b899abd6588b8e5" - ], - "layout": "IPY_MODEL_7ba737ac8b22437fb70f654ef98d42f0" - } - }, - "12005b6597904d7e9b38f32bfc830e6a": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLModel", - "state": { - "layout": "IPY_MODEL_544b1d85d01743c5be3e9389fcfbb5c9", - "style": "IPY_MODEL_df93f3cbf66c4f7b93f67c6adad39e97", - "value": "  0%" - } - }, - "166dccf9829e437fb6b5437ef0e6d075": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "17466a3f71b74ebda0a08ca6c7c9aad3": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HBoxModel", - "state": { - "children": [ - "IPY_MODEL_5431e26c812b413f9c79561111b71d66", - "IPY_MODEL_bf971c36cb3b4669a4208c9513e294ef", - "IPY_MODEL_b2f2661776a0476299484494f7aa3c0f" - ], - "layout": "IPY_MODEL_68ca7c3405e849a9a88cc5578ac491ca" - } - }, - "192c9922a68f4ebcb9cbb95c0db02a8d": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLStyleModel", - "state": { - "description_width": "", - "font_size": null, - "text_color": null - } - }, - "19f2be5cc5464c50b2f58dff840806ed": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "1f62ae7c9b4f449bb52f2def49a6ec8a": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "FloatProgressModel", - "state": { - "bar_style": "danger", - "layout": "IPY_MODEL_3a6ad004bd6b4bc2b381836ed5d5899d", - "max": 1, - "style": "IPY_MODEL_07746a0d558e40d5b8aca2e78ea6ef5d" - } - }, - "23814384374b4b1681a30e6bf7da82e6": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLModel", - "state": { - "layout": "IPY_MODEL_acaf918bec7049c3b50cbc7f4cca9bdf", - "style": "IPY_MODEL_8d29c325515146e0bf69bb4a92eef242", - "value": "  0%" - } - }, - "23fb17607e91411aa501b5cdda43c695": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HBoxModel", - "state": { - "children": [ - "IPY_MODEL_4694f533abf940adb7a912b3ebef8516", - "IPY_MODEL_e52404edaad2429db77efb94ae86f3cc", - "IPY_MODEL_dc1c93ea5fad4ffd8630167026e21957" - ], - "layout": "IPY_MODEL_a1627bbf343b4eae906e16d9a25ccf54" - } - }, - "24e87c341dbf40788af1e6697d14bfbe": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HBoxModel", - "state": { - "children": [ - "IPY_MODEL_8504ba9d3dfb40a087f449998126ee89", - "IPY_MODEL_724cb481d1f94993b00e13fc99e81457", - "IPY_MODEL_637f100cfd9647929fb730a24650ffa7" - ], - "layout": "IPY_MODEL_46b9d6330f204601aa65faa410ecf919" - } - }, - "27109fca95ea4c9685921e6889d4c086": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "ProgressStyleModel", - "state": { - "description_width": "" - } - }, - "27671aba5be140f380b3711a4c14672d": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "ProgressStyleModel", - "state": { - "description_width": "" - } - }, - "28fa27db88b84327bbfa634da50187a0": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "30a3d2a249844cfb80965c23f886e8ac": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "34ecf76f0c7d4d62ac52c2f4349570f9": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "3708acb45ee74d629dab4e34d6779441": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "37632f7562a541fab32872d51f8fa2c4": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "3852aaee5a874094b1c86ea1e5cf1879": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLModel", - "state": { - "layout": "IPY_MODEL_acec631e71104a01a96c667628ed4f55", - "style": "IPY_MODEL_8e54726e348b48fe9d41db2209c73948", - "value": "  0%" - } - }, - "3a6ad004bd6b4bc2b381836ed5d5899d": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "3c20f734d7b845a7b7c77cc2510367f9": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLStyleModel", - "state": { - "description_width": "", - "font_size": null, - "text_color": null - } - }, - "449995e3d8924eec96ad4b6d41dbb081": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLModel", - "state": { - "layout": "IPY_MODEL_acb742e58eb94b92a0306fbb07c8729a", - "style": "IPY_MODEL_3c20f734d7b845a7b7c77cc2510367f9", - "value": " 0/1 [00:11<?, ?it/s]" - } - }, - "467ed931e4d64812b76ffe70dcaafb21": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "4694f533abf940adb7a912b3ebef8516": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLModel", - "state": { - "layout": "IPY_MODEL_bd0eaedcbcb04d2cb03151b4f74e5f0a", - "style": "IPY_MODEL_b9de4b11040448869104c2bb18fe0087", - "value": "  0%" - } - }, - "46b9d6330f204601aa65faa410ecf919": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "5431e26c812b413f9c79561111b71d66": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLModel", - "state": { - "layout": "IPY_MODEL_c4505ad000e44809bbef8c84009ac684", - "style": "IPY_MODEL_75bd6aa43b6c4e75b56d1e10d5f15073", - "value": "  0%" - } - }, - "544b1d85d01743c5be3e9389fcfbb5c9": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "55416e0eb9ff4a1ba1ca2777118dee65": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "FloatProgressModel", - "state": { - "bar_style": "danger", - "layout": "IPY_MODEL_166dccf9829e437fb6b5437ef0e6d075", - "max": 1, - "style": "IPY_MODEL_971720ae2bb74633b8f2b21a4fb91442" - } - }, - "56712dae79ea42f3a0e05908fd1d63a3": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "5e078cbfec644e7f840ad014fa39d5a7": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLModel", - "state": { - "layout": "IPY_MODEL_f0c19a9d3b244225b9bf2e5a4eeaefa8", - "style": "IPY_MODEL_bc233a36fd01470589a786126f8253eb", - "value": " 0/1 [00:09<?, ?it/s]" - } - }, - "5ee72f71328f409cadb07c58655f6b61": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "ProgressStyleModel", - "state": { - "description_width": "" - } - }, - "618523b5bcc74b6a849330913cf646c6": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "62dd0b8f54cb44098697c66d857068fc": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "ProgressStyleModel", - "state": { - "description_width": "" - } - }, - "6315c3fd8f8b4fd09d8c6c4cfb85ec37": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "FloatProgressModel", - "state": { - "bar_style": "danger", - "layout": "IPY_MODEL_676b74a77f564b18aa4821ffb0a50c8b", - "max": 1, - "style": "IPY_MODEL_061a02a4f9aa4a378fc1a50135136460" - } - }, - "637f100cfd9647929fb730a24650ffa7": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLModel", - "state": { - "layout": "IPY_MODEL_ba734146be6b47dbb2ae24e682476247", - "style": "IPY_MODEL_65afd45edbc241d3bc11c167a9d1f2f9", - "value": " 0/1 [00:12<?, ?it/s]" - } - }, - "6417c1d6251e4fb5b1d560a3e69a4c2d": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLStyleModel", - "state": { - "description_width": "", - "font_size": null, - "text_color": null - } - }, - "6464e14b06b34cd190312ace46e4f295": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLModel", - "state": { - "layout": "IPY_MODEL_e264a2771aea449a86746f42514b7506", - "style": "IPY_MODEL_e2e41fa733df414fbccc980dd2513789", - "value": " 0/1 [00:12<?, ?it/s]" - } - }, - "65afd45edbc241d3bc11c167a9d1f2f9": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLStyleModel", - "state": { - "description_width": "", - "font_size": null, - "text_color": null - } - }, - "6666ccddbd974c5ca1ef01939aef2d48": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "676b74a77f564b18aa4821ffb0a50c8b": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "68ca7c3405e849a9a88cc5578ac491ca": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "6aab425f3c8948c59303e1072dec9213": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLModel", - "state": { - "layout": "IPY_MODEL_34ecf76f0c7d4d62ac52c2f4349570f9", - "style": "IPY_MODEL_81920c1985304916a542bb398b3286ae", - "value": " 0/1 [00:00<?, ?it/s]" - } - }, - "6bc3322393ad4a21a47ea1f9d7e33495": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "FloatProgressModel", - "state": { - "bar_style": "danger", - "layout": "IPY_MODEL_b95300ca56b2429db75b20c4479e70e5", - "max": 1, - "style": "IPY_MODEL_e76a0a93b6894530bca21b50ea6b5c1c" - } - }, - "6c17ce8a37c04c39bdbbfb02cf3acb37": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLStyleModel", - "state": { - "description_width": "", - "font_size": null, - "text_color": null - } - }, - "6e487fe9eb13423ba8f2d185abb779fa": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLModel", - "state": { - "layout": "IPY_MODEL_19f2be5cc5464c50b2f58dff840806ed", - "style": "IPY_MODEL_0429204e07f84ba0aeb980a7931ec8a3", - "value": " 1/1 [01:32<00:00, 93.00s/it]" - } - }, - "70c193ed404d4e90ab7c919578215c6e": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLStyleModel", - "state": { - "description_width": "", - "font_size": null, - "text_color": null - } - }, - "71c35d39490742a0a736bb6bad5bf97b": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "724cb481d1f94993b00e13fc99e81457": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "FloatProgressModel", - "state": { - "bar_style": "danger", - "layout": "IPY_MODEL_da0e012014fe47718b0dcee37faeffe3", - "max": 1, - "style": "IPY_MODEL_a78b9db3b42441ab8063d53f772a1eea" - } - }, - "748944c6ea11477190599555c29100c4": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLStyleModel", - "state": { - "description_width": "", - "font_size": null, - "text_color": null - } - }, - "75bd6aa43b6c4e75b56d1e10d5f15073": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLStyleModel", - "state": { - "description_width": "", - "font_size": null, - "text_color": null - } - }, - "767b0fe7cc224014b53ea14454b60e7c": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HBoxModel", - "state": { - "children": [ - "IPY_MODEL_88d11f9814cb4a94bbb3875d8024d819", - "IPY_MODEL_c21bcb601e8c46c4944137b3c52a49f1", - "IPY_MODEL_6aab425f3c8948c59303e1072dec9213" - ], - "layout": "IPY_MODEL_79beae25147c46358a88a99ded5f1319" - } - }, - "79beae25147c46358a88a99ded5f1319": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "7b8dd9578b174825b2763b19da2160a6": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "FloatProgressModel", - "state": { - "bar_style": "success", - "layout": "IPY_MODEL_e7c29079eb3a4b8db2415cb10338b1c7", - "max": 1, - "style": "IPY_MODEL_62dd0b8f54cb44098697c66d857068fc", - "value": 1 - } - }, - "7ba737ac8b22437fb70f654ef98d42f0": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "7bdab20ea7b8438d9bfc1a535f2b5b10": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "8062721d10c247268bc5da1ca2171cf2": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "81920c1985304916a542bb398b3286ae": { + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.9" + }, + "widgets": { + "application/vnd.jupyter.widget-state+json": { + "state": { + "0135f155b6a244dcaaf00afd7c89a5e9": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", - "model_name": "HTMLStyleModel", + "model_name": "HTMLModel", "state": { - "description_width": "", - "font_size": null, - "text_color": null + "layout": "IPY_MODEL_c2ad40e465c34490af32e54806adc3cb", + "style": "IPY_MODEL_76fdbe249a364973be765a0fcb7ea58c", + "value": "  0%" } }, - "831e6824c5ad403e9a56721238307300": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "8504ba9d3dfb40a087f449998126ee89": { + "0d4c0afb88dc478fbcb979362d57e036": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", - "model_name": "HTMLModel", + "model_name": "ProgressStyleModel", "state": { - "layout": "IPY_MODEL_37632f7562a541fab32872d51f8fa2c4", - "style": "IPY_MODEL_fdbb738659f44334a9172f09de7a90b3", - "value": "  0%" + "description_width": "" } }, - "86d1d4b7b3e44426a459e0fef3503d44": { + "1f88acbdfb7a490988a2b45b7b20e3ce": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", "model_name": "HTMLStyleModel", @@ -970,17 +325,7 @@ "text_color": null } }, - "88d11f9814cb4a94bbb3875d8024d819": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLModel", - "state": { - "layout": "IPY_MODEL_8062721d10c247268bc5da1ca2171cf2", - "style": "IPY_MODEL_6c17ce8a37c04c39bdbbfb02cf3acb37", - "value": "  0%" - } - }, - "8d29c325515146e0bf69bb4a92eef242": { + "24296f3cb09945e48ff6f0adfcd0e515": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", "model_name": "HTMLStyleModel", @@ -990,40 +335,55 @@ "text_color": null } }, - "8d95f8815e0f4db3b6a302eb5f60bf4d": { + "2580861754c445d29ea55ac99f9653de": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", "model_name": "HBoxModel", "state": { "children": [ - "IPY_MODEL_c7be2ab8c7c54e399555d7bbdb5c1718", - "IPY_MODEL_1f62ae7c9b4f449bb52f2def49a6ec8a", - "IPY_MODEL_94dacf7bb6eb4da7b169d6903e3dc0fb" + "IPY_MODEL_32b6bfa0deef4809abf9e3b51a10046a", + "IPY_MODEL_74e42ddc1a59480cb2d70248e69f9a9e", + "IPY_MODEL_f9d318be0eff416db1c62c64a1bc4752" ], - "layout": "IPY_MODEL_cac239b0a769434aba5348b52867b05d" + "layout": "IPY_MODEL_80834d467ccc44339490f07cfcf10a45" } }, - "8e54726e348b48fe9d41db2209c73948": { + "2ab4263268b44e8cb0401981f14f9d01": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": {} + }, + "3155e589f95443a58f278eb2650e3eee": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", - "model_name": "HTMLStyleModel", + "model_name": "HBoxModel", "state": { - "description_width": "", - "font_size": null, - "text_color": null + "children": [ + "IPY_MODEL_b416fea506bd4f5aa6e1f17678d76823", + "IPY_MODEL_51597a24b5e14d6785c6be0f8ec11e39", + "IPY_MODEL_76781df6822f4f65bebcb6583f6d9a04" + ], + "layout": "IPY_MODEL_5481bcbc673448f6970b9ab6501664b9" } }, - "94dacf7bb6eb4da7b169d6903e3dc0fb": { + "32b6bfa0deef4809abf9e3b51a10046a": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", "model_name": "HTMLModel", "state": { - "layout": "IPY_MODEL_6666ccddbd974c5ca1ef01939aef2d48", - "style": "IPY_MODEL_70c193ed404d4e90ab7c919578215c6e", - "value": " 0/1 [00:12<?, ?it/s]" + "layout": "IPY_MODEL_f6454a6a6f7b4c95a37047ab1ea9abf8", + "style": "IPY_MODEL_ceecc0e6d80a43c386d1837e428b72c1", + "value": "  0%" } }, - "971720ae2bb74633b8f2b21a4fb91442": { + "340ffa849db847228647aafb82b4a3fa": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": {} + }, + "3b52794e25164c8db273f6dda3de5586": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", "model_name": "ProgressStyleModel", @@ -1031,107 +391,125 @@ "description_width": "" } }, - "97f4d1c03786418490ab357e2281289f": { + "3c28e4732ae54a35b13669a5c0fd3e28": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", - "model_name": "ProgressStyleModel", + "model_name": "HBoxModel", "state": { - "description_width": "" + "children": [ + "IPY_MODEL_c4deaf5be24f4ae4b716ab2dfde257b1", + "IPY_MODEL_82d8b53d4e9e4dd9a45afb9c78f08a51", + "IPY_MODEL_437af6f5e2fb47e6841aafb4ab8ab478" + ], + "layout": "IPY_MODEL_764cf715b93c49d79be1b08214b332b1" } }, - "a1627bbf343b4eae906e16d9a25ccf54": { + "3d44f10e1f8a4624a1c3d848f7090e06": { "model_module": "@jupyter-widgets/base", "model_module_version": "2.0.0", "model_name": "LayoutModel", "state": {} }, - "a6152319c8754b199ca33909768300cc": { + "40976ffdca6c4581b9990a81010b540c": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", "model_name": "HBoxModel", "state": { "children": [ - "IPY_MODEL_ad11a757078443a58e5bb483888bcb12", - "IPY_MODEL_55416e0eb9ff4a1ba1ca2777118dee65", - "IPY_MODEL_449995e3d8924eec96ad4b6d41dbb081" + "IPY_MODEL_0135f155b6a244dcaaf00afd7c89a5e9", + "IPY_MODEL_6dc2e1e98fd54aa78343487909d408c6", + "IPY_MODEL_54710d4880e2487299a24d8a45a2295e" ], - "layout": "IPY_MODEL_30a3d2a249844cfb80965c23f886e8ac" + "layout": "IPY_MODEL_ba92cc6393834e2397432d8a04b5f3c5" } }, - "a78b9db3b42441ab8063d53f772a1eea": { + "4299df6974b54a84bf9965ef40eb38c3": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": {} + }, + "437af6f5e2fb47e6841aafb4ab8ab478": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", - "model_name": "ProgressStyleModel", + "model_name": "HTMLModel", "state": { - "description_width": "" + "layout": "IPY_MODEL_f8918065bea342629ad9cb73b4e06e57", + "style": "IPY_MODEL_e56d1db6f2e3489bb7c46a10a7b51db4", + "value": " 0/1 [00:08<?, ?it/s]" } }, - "aab2efe2c51846d6b67dfebd00375b4b": { + "47a3dcb62f664eba9566822c1509f560": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", - "model_name": "HTMLModel", + "model_name": "HTMLStyleModel", "state": { - "layout": "IPY_MODEL_dbff5962c9c641208be9efa0210f5b26", - "style": "IPY_MODEL_86d1d4b7b3e44426a459e0fef3503d44", - "value": " 0/1 [00:00<?, ?it/s]" + "description_width": "", + "font_size": null, + "text_color": null } }, - "acaf918bec7049c3b50cbc7f4cca9bdf": { - "model_module": "@jupyter-widgets/base", + "48d83a4e86e54e52abcf616d91119740": { + "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} + "model_name": "HTMLModel", + "state": { + "layout": "IPY_MODEL_fcb22d583d11491698dbe9127ead28e0", + "style": "IPY_MODEL_8c180babe22447239fe6089fb70368bb", + "value": " 0/1 [00:10<?, ?it/s]" + } }, - "acb742e58eb94b92a0306fbb07c8729a": { + "4d1d026ec2e2473fab6630872ab2753e": { "model_module": "@jupyter-widgets/base", "model_module_version": "2.0.0", "model_name": "LayoutModel", "state": {} }, - "acec631e71104a01a96c667628ed4f55": { - "model_module": "@jupyter-widgets/base", + "51597a24b5e14d6785c6be0f8ec11e39": { + "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} + "model_name": "FloatProgressModel", + "state": { + "bar_style": "success", + "layout": "IPY_MODEL_f732820efeb349108f9747b2d09bba4e", + "max": 1, + "style": "IPY_MODEL_0d4c0afb88dc478fbcb979362d57e036", + "value": 1 + } }, - "ad11a757078443a58e5bb483888bcb12": { + "54710d4880e2487299a24d8a45a2295e": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", "model_name": "HTMLModel", "state": { - "layout": "IPY_MODEL_831e6824c5ad403e9a56721238307300", - "style": "IPY_MODEL_ebff389513564d41b7bffcdfda59e2f7", - "value": "  0%" + "layout": "IPY_MODEL_aeeae04c37c7413f8342ac79a4471c6a", + "style": "IPY_MODEL_1f88acbdfb7a490988a2b45b7b20e3ce", + "value": " 0/1 [00:09<?, ?it/s]" } }, - "b044e54c283846a4ad5be72d37f89276": { + "5481bcbc673448f6970b9ab6501664b9": { "model_module": "@jupyter-widgets/base", "model_module_version": "2.0.0", "model_name": "LayoutModel", "state": {} }, - "b08a0afca66a47d1961de999bc4a4db0": { + "55ce887525a242f0baed3e47a9900ac6": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", - "model_name": "FloatProgressModel", + "model_name": "ProgressStyleModel", "state": { - "bar_style": "danger", - "layout": "IPY_MODEL_71c35d39490742a0a736bb6bad5bf97b", - "max": 1, - "style": "IPY_MODEL_5ee72f71328f409cadb07c58655f6b61" + "description_width": "" } }, - "b2f2661776a0476299484494f7aa3c0f": { + "5d3af82be4844e878b49216988aac99f": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", - "model_name": "HTMLModel", + "model_name": "ProgressStyleModel", "state": { - "layout": "IPY_MODEL_cf987a4af45a4f3f984208c6fd246c31", - "style": "IPY_MODEL_b399d7f359634321a56bb02dbe646d55", - "value": " 0/1 [00:10<?, ?it/s]" + "description_width": "" } }, - "b399d7f359634321a56bb02dbe646d55": { + "6479e9c16c1a4e5bbb584fa83a1e66ac": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", "model_name": "HTMLStyleModel", @@ -1141,26 +519,30 @@ "text_color": null } }, - "b76d07c5cc634cb49af9bc7bca823fb1": { - "model_module": "@jupyter-widgets/controls", + "687fe941b6c84d59b174191302cf5994": { + "model_module": "@jupyter-widgets/base", "model_module_version": "2.0.0", - "model_name": "HBoxModel", - "state": { - "children": [ - "IPY_MODEL_12005b6597904d7e9b38f32bfc830e6a", - "IPY_MODEL_b08a0afca66a47d1961de999bc4a4db0", - "IPY_MODEL_5e078cbfec644e7f840ad014fa39d5a7" - ], - "layout": "IPY_MODEL_cb27d1566f634c3db7c6f9275de6d194" - } + "model_name": "LayoutModel", + "state": {} }, - "b95300ca56b2429db75b20c4479e70e5": { + "6b6bdc68218e40c39c6dd67e3a480178": { "model_module": "@jupyter-widgets/base", "model_module_version": "2.0.0", "model_name": "LayoutModel", "state": {} }, - "b9de4b11040448869104c2bb18fe0087": { + "6dc2e1e98fd54aa78343487909d408c6": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "FloatProgressModel", + "state": { + "bar_style": "danger", + "layout": "IPY_MODEL_da1d26b4f90d41369e2898a22c3c8bb6", + "max": 1, + "style": "IPY_MODEL_ad4eab880b7e40afb299ab34b8e9db8f" + } + }, + "722b1e3acb414ed2b33b964e605ee015": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", "model_name": "HTMLStyleModel", @@ -1170,23 +552,34 @@ "text_color": null } }, - "ba734146be6b47dbb2ae24e682476247": { + "74e42ddc1a59480cb2d70248e69f9a9e": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "FloatProgressModel", + "state": { + "bar_style": "danger", + "layout": "IPY_MODEL_687fe941b6c84d59b174191302cf5994", + "max": 1, + "style": "IPY_MODEL_ca977fe004874adf848b8089ed334653" + } + }, + "764cf715b93c49d79be1b08214b332b1": { "model_module": "@jupyter-widgets/base", "model_module_version": "2.0.0", "model_name": "LayoutModel", "state": {} }, - "bc0e187751d64db9abb6907bfc03b5cc": { + "76781df6822f4f65bebcb6583f6d9a04": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", "model_name": "HTMLModel", "state": { - "layout": "IPY_MODEL_d149948e2a404571a3e130a28e3703c6", - "style": "IPY_MODEL_cdeecbdf227345dfbf7f737467763748", - "value": "  0%" + "layout": "IPY_MODEL_4d1d026ec2e2473fab6630872ab2753e", + "style": "IPY_MODEL_24296f3cb09945e48ff6f0adfcd0e515", + "value": " 1/1 [00:48<00:00, 48.84s/it]" } }, - "bc233a36fd01470589a786126f8253eb": { + "76fdbe249a364973be765a0fcb7ea58c": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", "model_name": "HTMLStyleModel", @@ -1196,140 +589,142 @@ "text_color": null } }, - "bd0eaedcbcb04d2cb03151b4f74e5f0a": { + "80834d467ccc44339490f07cfcf10a45": { "model_module": "@jupyter-widgets/base", "model_module_version": "2.0.0", "model_name": "LayoutModel", "state": {} }, - "bf971c36cb3b4669a4208c9513e294ef": { + "82d8b53d4e9e4dd9a45afb9c78f08a51": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", "model_name": "FloatProgressModel", "state": { "bar_style": "danger", - "layout": "IPY_MODEL_d8e25ea71dc84dd0968a8438627a42f7", + "layout": "IPY_MODEL_4299df6974b54a84bf9965ef40eb38c3", "max": 1, - "style": "IPY_MODEL_27109fca95ea4c9685921e6889d4c086" + "style": "IPY_MODEL_55ce887525a242f0baed3e47a9900ac6" } }, - "c21bcb601e8c46c4944137b3c52a49f1": { + "8c180babe22447239fe6089fb70368bb": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", - "model_name": "FloatProgressModel", + "model_name": "HTMLStyleModel", "state": { - "bar_style": "danger", - "layout": "IPY_MODEL_618523b5bcc74b6a849330913cf646c6", - "max": 1, - "style": "IPY_MODEL_c7aef3de677b4d9a898899c33aa2162a" + "description_width": "", + "font_size": null, + "text_color": null } }, - "c4505ad000e44809bbef8c84009ac684": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "c7aef3de677b4d9a898899c33aa2162a": { + "aaeca78e3ebc4d9289708854f3dc74cc": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", - "model_name": "ProgressStyleModel", + "model_name": "HTMLStyleModel", "state": { - "description_width": "" + "description_width": "", + "font_size": null, + "text_color": null } }, - "c7be2ab8c7c54e399555d7bbdb5c1718": { + "ad4eab880b7e40afb299ab34b8e9db8f": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", - "model_name": "HTMLModel", + "model_name": "ProgressStyleModel", "state": { - "layout": "IPY_MODEL_d9e90e42e2a8470b91c0c3a6c032aa97", - "style": "IPY_MODEL_ecb6a89059c940f183b6f8bbd27c01e2", - "value": "  0%" + "description_width": "" } }, - "cac239b0a769434aba5348b52867b05d": { + "aeeae04c37c7413f8342ac79a4471c6a": { "model_module": "@jupyter-widgets/base", "model_module_version": "2.0.0", "model_name": "LayoutModel", "state": {} }, - "cb27d1566f634c3db7c6f9275de6d194": { + "b3720ff87795455eb6eb365cb56bc8b8": { "model_module": "@jupyter-widgets/base", "model_module_version": "2.0.0", "model_name": "LayoutModel", "state": {} }, - "cdeecbdf227345dfbf7f737467763748": { + "b416fea506bd4f5aa6e1f17678d76823": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", - "model_name": "HTMLStyleModel", + "model_name": "HTMLModel", "state": { - "description_width": "", - "font_size": null, - "text_color": null + "layout": "IPY_MODEL_e3966d5cdff14361b4649860ad532b22", + "style": "IPY_MODEL_cce35b0f04854b4e975a113a825e75df", + "value": "100%" } }, - "cf987a4af45a4f3f984208c6fd246c31": { - "model_module": "@jupyter-widgets/base", + "b539058eb7c34befb1899b9f2f017d59": { + "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} + "model_name": "FloatProgressModel", + "state": { + "bar_style": "danger", + "layout": "IPY_MODEL_d422e7d0de5942c98d3edeac5ed6d6b5", + "max": 1, + "style": "IPY_MODEL_3b52794e25164c8db273f6dda3de5586" + } }, - "d149948e2a404571a3e130a28e3703c6": { + "ba92cc6393834e2397432d8a04b5f3c5": { "model_module": "@jupyter-widgets/base", "model_module_version": "2.0.0", "model_name": "LayoutModel", "state": {} }, - "d8e25ea71dc84dd0968a8438627a42f7": { - "model_module": "@jupyter-widgets/base", + "bee1b35e8a554ceda1a1b02e7993f6a4": { + "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} + "model_name": "FloatProgressModel", + "state": { + "bar_style": "danger", + "layout": "IPY_MODEL_c4ccfc98518641199fc4b743bc1b4690", + "max": 1, + "style": "IPY_MODEL_5d3af82be4844e878b49216988aac99f" + } }, - "d9e90e42e2a8470b91c0c3a6c032aa97": { + "c2ad40e465c34490af32e54806adc3cb": { "model_module": "@jupyter-widgets/base", "model_module_version": "2.0.0", "model_name": "LayoutModel", "state": {} }, - "da0e012014fe47718b0dcee37faeffe3": { + "c4ccfc98518641199fc4b743bc1b4690": { "model_module": "@jupyter-widgets/base", "model_module_version": "2.0.0", "model_name": "LayoutModel", "state": {} }, - "dbff5962c9c641208be9efa0210f5b26": { - "model_module": "@jupyter-widgets/base", + "c4deaf5be24f4ae4b716ab2dfde257b1": { + "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} + "model_name": "HTMLModel", + "state": { + "layout": "IPY_MODEL_6b6bdc68218e40c39c6dd67e3a480178", + "style": "IPY_MODEL_aaeca78e3ebc4d9289708854f3dc74cc", + "value": "  0%" + } }, - "dc1c93ea5fad4ffd8630167026e21957": { + "c901aa8c57a541bf82297416004ed735": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", "model_name": "HTMLModel", "state": { - "layout": "IPY_MODEL_467ed931e4d64812b76ffe70dcaafb21", - "style": "IPY_MODEL_192c9922a68f4ebcb9cbb95c0db02a8d", - "value": " 0/1 [00:12<?, ?it/s]" + "layout": "IPY_MODEL_2ab4263268b44e8cb0401981f14f9d01", + "style": "IPY_MODEL_6479e9c16c1a4e5bbb584fa83a1e66ac", + "value": "  0%" } }, - "df24b53b3e424caf8ede3e232f662017": { + "ca977fe004874adf848b8089ed334653": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", - "model_name": "HBoxModel", + "model_name": "ProgressStyleModel", "state": { - "children": [ - "IPY_MODEL_05c122605f3b429995790275971a613f", - "IPY_MODEL_7b8dd9578b174825b2763b19da2160a6", - "IPY_MODEL_6e487fe9eb13423ba8f2d185abb779fa" - ], - "layout": "IPY_MODEL_28fa27db88b84327bbfa634da50187a0" + "description_width": "" } }, - "df93f3cbf66c4f7b93f67c6adad39e97": { + "cce35b0f04854b4e975a113a825e75df": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", "model_name": "HTMLStyleModel", @@ -1339,13 +734,17 @@ "text_color": null } }, - "e264a2771aea449a86746f42514b7506": { - "model_module": "@jupyter-widgets/base", + "cec4bdb730194a5e9d7dcc44af437cce": { + "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} + "model_name": "HTMLModel", + "state": { + "layout": "IPY_MODEL_340ffa849db847228647aafb82b4a3fa", + "style": "IPY_MODEL_722b1e3acb414ed2b33b964e605ee015", + "value": " 0/1 [00:10<?, ?it/s]" + } }, - "e2e41fa733df414fbccc980dd2513789": { + "ceecc0e6d80a43c386d1837e428b72c1": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", "model_name": "HTMLStyleModel", @@ -1355,32 +754,41 @@ "text_color": null } }, - "e52404edaad2429db77efb94ae86f3cc": { - "model_module": "@jupyter-widgets/controls", + "d3b53c1730e04dad9488355fa2d9fd2a": { + "model_module": "@jupyter-widgets/base", "model_module_version": "2.0.0", - "model_name": "FloatProgressModel", - "state": { - "bar_style": "danger", - "layout": "IPY_MODEL_56712dae79ea42f3a0e05908fd1d63a3", - "max": 1, - "style": "IPY_MODEL_97f4d1c03786418490ab357e2281289f" - } + "model_name": "LayoutModel", + "state": {} + }, + "d422e7d0de5942c98d3edeac5ed6d6b5": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": {} + }, + "da1d26b4f90d41369e2898a22c3c8bb6": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": {} }, - "e76a0a93b6894530bca21b50ea6b5c1c": { + "dfca41d0880c410294b692772f84d02e": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", - "model_name": "ProgressStyleModel", + "model_name": "HTMLModel", "state": { - "description_width": "" + "layout": "IPY_MODEL_b3720ff87795455eb6eb365cb56bc8b8", + "style": "IPY_MODEL_fa4870c0c9554989bb6919fb5968a97a", + "value": "  0%" } }, - "e7c29079eb3a4b8db2415cb10338b1c7": { + "e3966d5cdff14361b4649860ad532b22": { "model_module": "@jupyter-widgets/base", "model_module_version": "2.0.0", "model_name": "LayoutModel", "state": {} }, - "ebff389513564d41b7bffcdfda59e2f7": { + "e56d1db6f2e3489bb7c46a10a7b51db4": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", "model_name": "HTMLStyleModel", @@ -1390,44 +798,67 @@ "text_color": null } }, - "ecb6a89059c940f183b6f8bbd27c01e2": { + "ef8fc030d9024c68932cc802482f9792": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", - "model_name": "HTMLStyleModel", + "model_name": "HBoxModel", "state": { - "description_width": "", - "font_size": null, - "text_color": null + "children": [ + "IPY_MODEL_c901aa8c57a541bf82297416004ed735", + "IPY_MODEL_b539058eb7c34befb1899b9f2f017d59", + "IPY_MODEL_48d83a4e86e54e52abcf616d91119740" + ], + "layout": "IPY_MODEL_d3b53c1730e04dad9488355fa2d9fd2a" + } + }, + "f3a3864a1275487489e29b4c227f97f4": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "HBoxModel", + "state": { + "children": [ + "IPY_MODEL_dfca41d0880c410294b692772f84d02e", + "IPY_MODEL_bee1b35e8a554ceda1a1b02e7993f6a4", + "IPY_MODEL_cec4bdb730194a5e9d7dcc44af437cce" + ], + "layout": "IPY_MODEL_3d44f10e1f8a4624a1c3d848f7090e06" } }, - "f0c19a9d3b244225b9bf2e5a4eeaefa8": { + "f6454a6a6f7b4c95a37047ab1ea9abf8": { "model_module": "@jupyter-widgets/base", "model_module_version": "2.0.0", "model_name": "LayoutModel", "state": {} }, - "f80033bff5324b84b0968a8891b16ae0": { - "model_module": "@jupyter-widgets/controls", + "f732820efeb349108f9747b2d09bba4e": { + "model_module": "@jupyter-widgets/base", "model_module_version": "2.0.0", - "model_name": "FloatProgressModel", - "state": { - "bar_style": "danger", - "layout": "IPY_MODEL_3708acb45ee74d629dab4e34d6779441", - "max": 1, - "style": "IPY_MODEL_27671aba5be140f380b3711a4c14672d" - } + "model_name": "LayoutModel", + "state": {} + }, + "f7e0b53698d146d48f6f0fb8f35011ab": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": {} + }, + "f8918065bea342629ad9cb73b4e06e57": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": {} }, - "f8960ece08ec4f058b899abd6588b8e5": { + "f9d318be0eff416db1c62c64a1bc4752": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", "model_name": "HTMLModel", "state": { - "layout": "IPY_MODEL_0435dd678c144c278ce2e69ef90828e1", - "style": "IPY_MODEL_6417c1d6251e4fb5b1d560a3e69a4c2d", - "value": " 0/1 [00:12<?, ?it/s]" + "layout": "IPY_MODEL_f7e0b53698d146d48f6f0fb8f35011ab", + "style": "IPY_MODEL_47a3dcb62f664eba9566822c1509f560", + "value": " 0/1 [00:09<?, ?it/s]" } }, - "fdbb738659f44334a9172f09de7a90b3": { + "fa4870c0c9554989bb6919fb5968a97a": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", "model_name": "HTMLStyleModel", @@ -1437,18 +868,11 @@ "text_color": null } }, - "fe8ab9dc21924f8285d80d7e1ca99078": { - "model_module": "@jupyter-widgets/controls", + "fcb22d583d11491698dbe9127ead28e0": { + "model_module": "@jupyter-widgets/base", "model_module_version": "2.0.0", - "model_name": "HBoxModel", - "state": { - "children": [ - "IPY_MODEL_3852aaee5a874094b1c86ea1e5cf1879", - "IPY_MODEL_f80033bff5324b84b0968a8891b16ae0", - "IPY_MODEL_aab2efe2c51846d6b67dfebd00375b4b" - ], - "layout": "IPY_MODEL_b044e54c283846a4ad5be72d37f89276" - } + "model_name": "LayoutModel", + "state": {} } }, "version_major": 2, diff --git a/notebooks/test_notebook.ipynb b/notebooks/test_notebook.ipynb index 65a76f3..bb49cb3 100644 --- a/notebooks/test_notebook.ipynb +++ b/notebooks/test_notebook.ipynb @@ -107,7 +107,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "b0b6d16ee8474df79828b0f10a15805f", + "model_id": "d4e4610bed59405d85f9bc51d5027ebd", "version_major": 2, "version_minor": 0 }, @@ -121,7 +121,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "e2f0f5d178ec456a8a58c15199e217c9", + "model_id": "0177ed8a710b45c19e51687f7de376d6", "version_major": 2, "version_minor": 0 }, @@ -178,28 +178,31 @@ "# cavs.add_cavity([cav0, cav, cav1], names=['cav0', 'C3795_1300MHz', 'TESLA'], plot_labels=['cav0', 'C3795$_{1300MHz}$', 'TESLA'])\n", "cavs.add_cavity([cav0, cav1], names=['cav0', 'TESLA'], plot_labels=['cav0', 'TESLA'])\n", "\n", - "uq_config = {\n", - " 'option': True,\n", - " 'variables': ['A', 'B', 'a', 'b'],\n", - " # 'objectives': [\"freq [MHz]\", \"R/Q [Ohm]\", \"Epk/Eacc []\", \"Bpk/Eacc [mT/MV/m]\", \"G [Ohm]\", \"kcc [%]\", \"ff [%]\"],\n", - " 'objectives': [\"Epk/Eacc []\", \"Bpk/Eacc [mT/MV/m]\", \"R/Q [Ohm]\", \"G [Ohm]\"],\n", - " # 'objectives': [\"ZL\"],\n", - " 'delta': [0.05, 0.05, 0.05, 0.05],\n", - " 'processes': 8,\n", - " 'distribution': 'gaussian',\n", - " # 'method': ['QMC', 'LHS', 1000],\n", - " # 'method': ['QMC', 'Sobol', 1000],\n", - " # 'method': ['Qudrature', 'Gaussian', 1000],\n", - " 'method': ['Quadrature', 'Stroud3'],\n", - " # 'method': ['Quadrature', 'Stroud5'],\n", - " # 'gaussian': ['Quadrature', 'Gaussian'],\n", - " # 'from file': ['', columns],\n", - " 'cell type': 'mid-cell',\n", - " 'cell complexity': 'simplecell'\n", - "}\n", - "\n", + "eigenmode_config = {\n", + " 'processes': 3,\n", + " 'rerun': True,\n", + " 'boundary_conditions': 'mm',\n", + " 'uq_config': {\n", + " 'variables': ['A', 'B', 'a', 'b'],\n", + " # 'objectives': [\"freq [MHz]\", \"R/Q [Ohm]\", \"Epk/Eacc []\", \"Bpk/Eacc [mT/MV/m]\", \"G [Ohm]\", \"kcc [%]\", \"ff [%]\"],\n", + " 'objectives': [\"Epk/Eacc []\", \"Bpk/Eacc [mT/MV/m]\", \"R/Q [Ohm]\", \"G [Ohm]\"],\n", + " # 'objectives': [\"ZL\"],\n", + " 'delta': [0.05, 0.05, 0.05, 0.05],\n", + " 'processes': 4,\n", + " 'distribution': 'gaussian',\n", + " # 'method': ['QMC', 'LHS', 1000],\n", + " # 'method': ['QMC', 'Sobol', 1000],\n", + " # 'method': ['Qudrature', 'Gaussian', 1000],\n", + " 'method': ['Quadrature', 'Stroud3'],\n", + " # 'method': ['Quadrature', 'Stroud5'],\n", + " # 'gaussian': ['Quadrature', 'Gaussian'],\n", + " # 'from file': ['', columns],\n", + " 'cell type': 'mid-cell',\n", + " 'cell complexity': 'simplecell'\n", + " }\n", + " }\n", "# run eigenmode analysis\n", - "cavs.run_eigenmode('ngsolve', rerun=True, procs=3, uq_config=uq_config) #modify to delete UQ results if rerun=True is selected" + "cavs.run_eigenmode(eigenmode_config) #modify to delete UQ results if rerun=True is selected" ] }, { @@ -212,58 +215,58 @@ "name": "stdout", "output_type": "stream", "text": [ - "{ 'TESLA': { 'Bpk [mT]': 0.0001301560269215204,\n", - " 'Bpk/Eacc [mT/MV/m]': 4.252639339184189,\n", - " 'Eacc [MV/m]': 3.060594057959524e-05,\n", - " 'Epk [MV/m]': 6.203239549797946e-05,\n", - " 'Epk/Eacc []': 2.0268089894723254,\n", - " 'G [Ohm]': 269.9796641560736,\n", - " 'GR/Q [Ohm^2]': 59192.05082672443,\n", - " 'Hpk [A/m]': 0.10357487528880889,\n", + "{ 'TESLA': { 'Bpk [mT]': 0.00013015602692150808,\n", + " 'Bpk/Eacc [mT/MV/m]': 4.252639234576093,\n", + " 'Eacc [MV/m]': 3.060594133244932e-05,\n", + " 'Epk [MV/m]': 6.203237641622353e-05,\n", + " 'Epk/Eacc []': 2.0268083161505306,\n", + " 'G [Ohm]': 269.97966415619595,\n", + " 'GR/Q [Ohm^2]': 59192.05373878088,\n", + " 'Hpk [A/m]': 0.10357487528879908,\n", " 'N Cells': 2,\n", " 'Normalization Length [mm]': 115.3048,\n", - " 'Q []': 29093.54246900789,\n", - " 'R/Q [Ohm]': 219.24633105886767,\n", + " 'Q []': 29093.542469021053,\n", + " 'R/Q [Ohm]': 219.246341844975,\n", " 'Req [mm]': 103.353,\n", - " 'Rsh [MOhm]': 6.37865244383533,\n", - " 'Vacc [MV]': 7.058023714684227e-06,\n", - " 'ff [%]': -50.13744457290053,\n", - " 'freq [MHz]': 1300.036120609818,\n", - " 'kcc [%]': 0.9508546083796799},\n", - " 'cav0': { 'Bpk [mT]': 0.00013016210292825939,\n", - " 'Bpk/Eacc [mT/MV/m]': 4.257329561095384,\n", - " 'Eacc [MV/m]': 3.057364976339052e-05,\n", - " 'Epk [MV/m]': 6.197952399989432e-05,\n", - " 'Epk/Eacc []': 2.027220318135187,\n", - " 'G [Ohm]': 270.1483974703567,\n", - " 'GR/Q [Ohm^2]': 59197.66455269878,\n", - " 'Hpk [A/m]': 0.10357971042134272,\n", + " 'Rsh [MOhm]': 6.3786527576442875,\n", + " 'Vacc [MV]': 7.058023888299604e-06,\n", + " 'ff [%]': -100.18279743359737,\n", + " 'freq [MHz]': 1300.036120609819,\n", + " 'kcc [%]': 0.9508546083794145},\n", + " 'cav0': { 'Bpk [mT]': 0.0001301621029283634,\n", + " 'Bpk/Eacc [mT/MV/m]': 4.257329727977345,\n", + " 'Eacc [MV/m]': 3.05736485649664e-05,\n", + " 'Epk [MV/m]': 6.197951031197608e-05,\n", + " 'Epk/Eacc []': 2.0272199498949197,\n", + " 'G [Ohm]': 270.1483974704925,\n", + " 'GR/Q [Ohm^2]': 59197.65991184883,\n", + " 'Hpk [A/m]': 0.10357971042142548,\n", " 'N Cells': 2,\n", " 'Normalization Length [mm]': 115.4,\n", - " 'Q []': 29110.71651111651,\n", - " 'R/Q [Ohm]': 219.1301710727139,\n", + " 'Q []': 29110.716511131137,\n", + " 'R/Q [Ohm]': 219.13015389371247,\n", " 'Req [mm]': 100.0,\n", - " 'Rsh [MOhm]': 6.379036289130237,\n", - " 'Vacc [MV]': 7.056398365390532e-06,\n", - " 'ff [%]': 99.84159220898744,\n", + " 'Rsh [MOhm]': 6.379035789040402,\n", + " 'Vacc [MV]': 7.056398088794245e-06,\n", + " 'ff [%]': -50.118004913275584,\n", " 'freq [MHz]': 1300.1262421098031,\n", - " 'kcc [%]': 0.9493751970188723}}\n", - "{ 'TESLA': { 'Bpk/Eacc [mT/MV/m]': { 'expe': [4.167097013525],\n", - " 'stdDev': [0.07055876730405068]},\n", - " 'Epk/Eacc []': { 'expe': [2.005418375514232],\n", - " 'stdDev': [0.0376619012012734]},\n", - " 'G [Ohm]': { 'expe': [264.7022073454016],\n", - " 'stdDev': [2.3854836708849505]},\n", - " 'R/Q [Ohm]': { 'expe': [113.56995679733262],\n", - " 'stdDev': [1.0036599241051891]}},\n", - " 'cav0': { 'Bpk/Eacc [mT/MV/m]': { 'expe': [4.248865208260158],\n", - " 'stdDev': [0.06741743513653965]},\n", - " 'Epk/Eacc []': { 'expe': [2.0073288412868644],\n", - " 'stdDev': [0.04424476680337121]},\n", - " 'G [Ohm]': { 'expe': [272.5085053849415],\n", - " 'stdDev': [2.567625397838322]},\n", - " 'R/Q [Ohm]': { 'expe': [113.66323572444745],\n", - " 'stdDev': [0.9927458702775238]}}}\n" + " 'kcc [%]': 0.9493751970197728}}\n", + "{ 'TESLA': { 'Bpk/Eacc [mT/MV/m]': { 'expe': [4.167097022970719],\n", + " 'stdDev': [0.07055875840433681]},\n", + " 'Epk/Eacc []': { 'expe': [2.005418456334632],\n", + " 'stdDev': [0.037661851210438815]},\n", + " 'G [Ohm]': { 'expe': [264.70220734520814],\n", + " 'stdDev': [2.385483670900201]},\n", + " 'R/Q [Ohm]': { 'expe': [113.56995626879217],\n", + " 'stdDev': [1.00365931028529]}},\n", + " 'cav0': { 'Bpk/Eacc [mT/MV/m]': { 'expe': [4.248865202498145],\n", + " 'stdDev': [0.06741742921371062]},\n", + " 'Epk/Eacc []': { 'expe': [2.0073288269206726],\n", + " 'stdDev': [0.04424481376825849]},\n", + " 'G [Ohm]': { 'expe': [272.50850538495365],\n", + " 'stdDev': [2.5676253978751604]},\n", + " 'R/Q [Ohm]': { 'expe': [113.66323602548458],\n", + " 'stdDev': [0.9927455966171562]}}}\n" ] } ], @@ -349,7 +352,7 @@ "metadata": {}, "outputs": [], "source": [ - "cavs.run_wakefield(bunch_length=25, rerun=False)" + "cavs.run_wakefield(bunch_length=25, rerun=True)" ] }, { @@ -394,7 +397,7 @@ "metadata": {}, "outputs": [], "source": [ - "cavs.cavities_list[0].abci_data['Long'].data_dict.keys()" + "cavs.cavities_list[1].abci_data['Trans'].data_dict.keys()" ] }, { @@ -588,341 +591,7 @@ }, "widgets": { "application/vnd.jupyter.widget-state+json": { - "state": { - "132c23360b724189a1e308bbb09c77e3": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "FloatSliderModel", - "state": { - "behavior": "drag-tap", - "description": "L", - "layout": "IPY_MODEL_9ca709c9e03a46a9826bf2c3cee7e24e", - "max": 86.4786, - "min": 28.8262, - "step": 0.1, - "style": "IPY_MODEL_7167a73b655a4b5491244c7143551c10", - "value": 57.6262 - } - }, - "2ac902abf1a046f8b532458f7461b879": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "FloatSliderModel", - "state": { - "behavior": "drag-tap", - "description": "Req", - "layout": "IPY_MODEL_a60d7b1d12d54ef1921e2ab45f8cc481", - "max": 155.02949999999998, - "min": 51.6765, - "step": 0.1, - "style": "IPY_MODEL_a67261b8fae34f8fb93228bdb49d2659", - "value": 103.37650000000001 - } - }, - "2b717ae55dc84c5484ecb9342af032f7": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "3e1ddb34222949b79207447f8e900f90": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "SliderStyleModel", - "state": { - "description_width": "" - } - }, - "40d06840211c40088858ab0b1cd7558b": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "LabelStyleModel", - "state": { - "description_width": "", - "font_family": null, - "font_size": null, - "font_style": null, - "font_variant": null, - "font_weight": null, - "text_color": null, - "text_decoration": null - } - }, - "43565f0149864134878314f8dc3d7a67": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "486b8aa933da4e5398250681d9d5e228": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HBoxModel", - "state": { - "children": [ - "IPY_MODEL_4dc6b858e8604db8a1c6f5462887a802", - "IPY_MODEL_8b2b7ef7b58441eaa49deb8ed5787297", - "IPY_MODEL_132c23360b724189a1e308bbb09c77e3" - ], - "layout": "IPY_MODEL_796c8b45edbc41ab9bc21ea668e32c23" - } - }, - "4dc6b858e8604db8a1c6f5462887a802": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "FloatSliderModel", - "state": { - "behavior": "drag-tap", - "description": "b", - "layout": "IPY_MODEL_2b717ae55dc84c5484ecb9342af032f7", - "max": 28.5, - "min": 9.5, - "step": 0.1, - "style": "IPY_MODEL_bee45db547604afa861d09c11e8120fd", - "value": 19 - } - }, - "5705e96e5f0849fbb0caf6d33139be7e": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "5cdac8dcf5374c3a8654a69856fa1005": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "FloatSliderModel", - "state": { - "behavior": "drag-tap", - "description": "A", - "layout": "IPY_MODEL_5705e96e5f0849fbb0caf6d33139be7e", - "max": 63, - "min": 21, - "step": 0.1, - "style": "IPY_MODEL_a86b8f560b244e3fa510e2fd3a9ad694", - "value": 42 - } - }, - "5fa0a54e5b5241249889982645b7796b": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "FloatSliderModel", - "state": { - "behavior": "drag-tap", - "description": "B", - "layout": "IPY_MODEL_f934096ee25c48cdafee89ead7b599b1", - "max": 63, - "min": 21, - "step": 0.1, - "style": "IPY_MODEL_d1349dc315824e8190cb7bea13b4bb2a", - "value": 42 - } - }, - "7167a73b655a4b5491244c7143551c10": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "SliderStyleModel", - "state": { - "description_width": "" - } - }, - "7947c65cbf584e0081fe49df8da176cc": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "SliderStyleModel", - "state": { - "description_width": "" - } - }, - "796c8b45edbc41ab9bc21ea668e32c23": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "88506956a1ce43c98e529ae97396be44": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "8b2b7ef7b58441eaa49deb8ed5787297": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "FloatSliderModel", - "state": { - "behavior": "drag-tap", - "description": "Ri", - "layout": "IPY_MODEL_d55d301f9ce94dfda84092795827d8e9", - "max": 52.5, - "min": 17.5, - "step": 0.1, - "style": "IPY_MODEL_7947c65cbf584e0081fe49df8da176cc", - "value": 35 - } - }, - "9ca709c9e03a46a9826bf2c3cee7e24e": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "a174bb3745b44db6aab4e77d459667f0": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "a60d7b1d12d54ef1921e2ab45f8cc481": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "a67261b8fae34f8fb93228bdb49d2659": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "SliderStyleModel", - "state": { - "description_width": "" - } - }, - "a86b8f560b244e3fa510e2fd3a9ad694": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "SliderStyleModel", - "state": { - "description_width": "" - } - }, - "abad1922f5504fc2b4ef2f7b6dff713a": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "FloatSliderModel", - "state": { - "behavior": "drag-tap", - "description": "a", - "layout": "IPY_MODEL_c36e5b39e83f42bf8044f372716be705", - "max": 18, - "min": 6, - "step": 0.1, - "style": "IPY_MODEL_3e1ddb34222949b79207447f8e900f90", - "value": 12 - } - }, - "adb447827d3247dc9dd12f00bb8d8ec5": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HBoxModel", - "state": { - "children": [ - "IPY_MODEL_2ac902abf1a046f8b532458f7461b879" - ], - "layout": "IPY_MODEL_88506956a1ce43c98e529ae97396be44" - } - }, - "b0b6d16ee8474df79828b0f10a15805f": { - "model_module": "@jupyter-widgets/output", - "model_module_version": "1.0.0", - "model_name": "OutputModel", - "state": { - "layout": "IPY_MODEL_c750de8c246643bd88416bc09aecada4", - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": "
" - }, - "metadata": {}, - "output_type": "display_data" - } - ] - } - }, - "bee45db547604afa861d09c11e8120fd": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "SliderStyleModel", - "state": { - "description_width": "" - } - }, - "c36e5b39e83f42bf8044f372716be705": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "c750de8c246643bd88416bc09aecada4": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "d1349dc315824e8190cb7bea13b4bb2a": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "SliderStyleModel", - "state": { - "description_width": "" - } - }, - "d4db552278d5442b8e208ba8e2112a3a": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "d55d301f9ce94dfda84092795827d8e9": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "df4d09b70d55473981631824c8a502eb": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "LabelModel", - "state": { - "layout": "IPY_MODEL_a174bb3745b44db6aab4e77d459667f0", - "style": "IPY_MODEL_40d06840211c40088858ab0b1cd7558b", - "value": "Sum of A + a: 54.00, L: 57.6262, delta: -3.626199999999997" - } - }, - "e2f0f5d178ec456a8a58c15199e217c9": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "VBoxModel", - "state": { - "children": [ - "IPY_MODEL_f875beb810d2492a884ead334abf0781", - "IPY_MODEL_486b8aa933da4e5398250681d9d5e228", - "IPY_MODEL_adb447827d3247dc9dd12f00bb8d8ec5", - "IPY_MODEL_df4d09b70d55473981631824c8a502eb" - ], - "layout": "IPY_MODEL_43565f0149864134878314f8dc3d7a67" - } - }, - "f875beb810d2492a884ead334abf0781": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HBoxModel", - "state": { - "children": [ - "IPY_MODEL_5cdac8dcf5374c3a8654a69856fa1005", - "IPY_MODEL_5fa0a54e5b5241249889982645b7796b", - "IPY_MODEL_abad1922f5504fc2b4ef2f7b6dff713a" - ], - "layout": "IPY_MODEL_d4db552278d5442b8e208ba8e2112a3a" - } - }, - "f934096ee25c48cdafee89ead7b599b1": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - } - }, + "state": {}, "version_major": 2, "version_minor": 0 } diff --git a/notebooks/tune_test.ipynb b/notebooks/tune_test.ipynb index e1424ce..edb79d1 100644 --- a/notebooks/tune_test.ipynb +++ b/notebooks/tune_test.ipynb @@ -35,7 +35,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "201c33f6-0d61-4e6c-bf9a-dcdde6fb1460", "metadata": {}, "outputs": [ @@ -43,8 +43,59 @@ "name": "stdout", "output_type": "stream", "text": [ - "\u001b[32mProject D:\\Dropbox\\CavityDesignHub\\MuCol_Study\\SimulationData\\ConsoleTest created successfully/already exists.\u001b[0m\n" + "\u001b[32mProject D:\\Dropbox\\CavityDesignHub\\MuCol_Study\\SimulationData\\ConsoleTest created successfully/already exists.\u001b[0m\n", + "{'cavs_degenerate': {'IC': array([ 42. , 23. , 42.5 , 57.5 , 70.2423896,\n", + " 93.5 , 170. ]), 'OC': array([ 47. , 23. , 42.5 , 57.5 ,\n", + " 70.59919029, 93.5 , 170. ]), 'OC_R': array([ 47. , 23. , 42.5 , 57.5 ,\n", + " 70.59919029, 93.5 , 170. ]), 'BP': 'both', 'CELL TYPE': 'simplecell'}}\n", + "{ 'cavs_degenerate': { 'CELL TYPE': 'mid-cell',\n", + " 'FREQ': 801.5800812536467,\n", + " 'IC': [ 42.0,\n", + " 23.0,\n", + " 42.5,\n", + " 57.5,\n", + " 70.24238959559739,\n", + " 93.5,\n", + " 172.95431796913266,\n", + " 104.87188638070597],\n", + " 'OC': [ 47.0,\n", + " 23.0,\n", + " 42.5,\n", + " 57.5,\n", + " 70.59919028624745,\n", + " 93.5,\n", + " 172.95431796913266,\n", + " 98.09182146953505],\n", + " 'OC_R': [ 47.0,\n", + " 23.0,\n", + " 42.5,\n", + " 57.5,\n", + " 70.59919028624745,\n", + " 93.5,\n", + " 172.95431796913266,\n", + " 98.09182146953505],\n", + " 'TUNED VARIABLE': 'Req'}}\n" ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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ebJ0X10uSndGx44dtXXrVuXn55fu27RpU52fl4IeAABXs26OlHdce91a68mTVysq2FfvTxigiCDuB69KcGMv/evv/RTdsokWnb5UG23RUnG+tOZRq6MBQL3Lz89XRkaGMjIytGPHDt133306ceJE6cr1N954o4KDgzVy5EitW7dOKSkp+vrrr3X//ffr119/rfS4//jHP/TMM88oMTFRu3bt0rRp05ScnKz777+/yjwzZszQ7NmzSxe727Ztm5YsWaIXXnih0j6RkZH6/vvvlZqaqqysLNntdvXr108+Pj56+OGHtWfPHi1dulQJCQkO/Y5q4oYbbpDdbtedd96pHTt2aNWqVXr++ecllb9ioTZR0AMA4EpOHZU2lTw3+NHTY+Xv66OEW/uomb/3OTpCkvy9PbTklj5q2dRH006Pk12GtGuFdHiX1dEAoF6tXLlS4eHhCg8PV79+/fTDDz/ovffe06BBgyRJPj4++uabb9SqVStde+216tSpk2677TadPn1a/v7+lR534sSJeuCBB/TAAw+oW7duWrlypZYvX15mhfuK/P3vf9cbb7yhhIQEdevWTZdeeqkSEhKqnKF/8MEH5ebmps6dOyskJERpaWlq2rSp/v3vf2vFihXq1q2bli1bphkzZjjyK6oRf39/ffLJJ0pOTlZ0dLSmT5+uxx57TJLK3Fdf2wyzPi7sr6b58+frueeeU3p6urp06aL4+HjFxsZW2DY9PV0PPPCANm/erN27d2vixImKj48v0yYhIUG33nprub6nT5+u9i81JydHAQEBys7OrnLgAgBQLzYtlj6drO32CA0veFpv3taPy+wdsP1QjkbO+1bzbc/rcrfN0iX/kP76iNWxALiQvLw8paSkKCoqqk4LNriut99+W7feequys7PVqFGjcu9XNYaqW4c6zQx9YmKiJk2apOnTpyspKUmxsbG64oorlJaWVmH7/Px8hYSEaPr06erRo0elx/X391d6enqZjf/DAQBc1v71kqTPivvoul4tKeYd1Lm5v+66pI1WFJesQGzuXm1xIgCAq3vrrbf07bffKiUlRR9//LGmTp2qMWPGVFjM1xanKehfeOEF3X777fr73/+uTp06KT4+Xi1btix9lMLZIiMjNXfuXN10001VPsrgzOME/rwBAOCq8jJ+kSTtUStNvrzqyxdRtQmD2mi7ZxdJkvnbdqm4/CrIAABUV0ZGhsaNG6dOnTpp8uTJGj16tF577bU6PadTFPQFBQXavHmzhgwZUmb/kCFDtH79+vM69okTJxQREaEWLVroqquuUlJSUpXt8/PzlZOTU2YDAMApmKZ0tOTZvyGRndUi0MfiQK6tsZe7BvaMVp7pIZu9UDpe8VWBAABUxz//+U+lpqaWXkr/4osvysenbv9b7RQFfVZWloqLixUaGlpmf2hoqDIyMhw+bseOHZWQkKDly5dr2bJl8vb21sUXX6zdu3dX2mf27NkKCAgo3Vq2bOnw+QEAqFWnjsi7+IQkqX3HbhaHaRgGdwpTqvn71XtH91kbBgCAGnKKgv6Ms5fzN03zvJb479+/v8aNG6cePXooNjZW7777rtq3b6+XX3650j4PPfSQsrOzS7cDBw44fH4AAGrVkZLZ+YNmkKLCgy0O0zD0aNmktKDP/+0Xi9MAAFAz7lYHkKTg4GC5ubmVm43PzMwsN2t/Pmw2m/r06VPlDL2Xl5e8vLxq7ZwAANSWosN75C4p1R6mNiGNrY7TIAQ08tBvHhdJ9h+Ue3Cn+BcAAMCVOMUMvaenp2JiYrRmzZoy+9esWaOBAwfW2nlM01RycrLCw8Nr7ZgAANSXnIM7JUm/2por1J/Ss7bk+ZU847g4a4/FSQAAqBmnmKGXpClTpmj8+PHq3bu3BgwYoNdee01paWmaMGGCpJJL4Q8ePKi33nqrtE9ycrKkkoXvDh8+rOTkZHl6eqpz586SpJkzZ6p///5q166dcnJy9NJLLyk5OVnz5s2r988HAMD5ys8sucLsROOI87olDWW5hbSRsiWvnFSrowAAUCNOU9DHxcXpyJEjmjVrltLT09W1a1etWLFCERERkqT09PRyz6Tv2bNn6c+bN2/W0qVLFRERodTUVEnS8ePHdeeddyojI0MBAQHq2bOnvvnmG/Xt27fePhcAALXF/VjJPfRm09YWJ2lY/Jp3kPZI/vkZUlGB5O5pdSQAsJxpmrrrrrv0/vvv69ixY0pKSlJ0dLTVsRwWGRmpSZMmadKkSVZHqVWGaZqm1SGcWU5OjgICApSdnS1/f3+r4wAALlSmqfxZYfIy8/R2n/d145WXW52owVj3S6Z6vt1NjY086Z4fpJD2VkcC4ALOPJosKipK3t7eVsdxyPr16xUbG6vLL79cK1euLPPeZ599ppEjR2rt2rVq3bq1goOD5eHhoY8++kijRo2qkzx1WXQfPnxYvr6+df4YuZqoagxVtw51invoAQDAOZz4TV5mnopNQyGtOlidpkFpG+qn/WbJIrxFh1npHsCFY/Hixbrvvvv07bfflrsaeu/evQoPD9fAgQMVFhYmd/fau7i7sLCw1o5VXSEhIU5VzNcWCnoAAFyA/fcF2w6awWod2tTiNA1LmL+3DhglC+Ye/3WnxWkAoH6cPHlS7777ru6++25dddVVSkhIKH3vlltu0X333ae0tDQZhqHIyEhFRkZKkq655prSfWd88skniomJkbe3t1q3bq2ZM2eqqKio9H3DMLRw4UKNHDlSvr6+evLJJ8vlGTRokPbv36/JkyfLMIzStWJmzJhR7lL/+Pj4Mue/5ZZbNGrUKD3//PMKDw9XUFCQ7rnnnjJfHERGRio+Pr5MpjfeeEPXXHONfHx81K5dOy1fvrzMeZYvX6527dqpUaNGGjx4sN58800ZhqHjx49X75dcDyjoAQBwATkHd0mS9itcEUENb4bBSoZhKNunZM2eUxnM0AM4D6YpFZys/82Bu6gTExPVoUMHdejQQePGjdOSJUt05m7suXPnatasWWrRooXS09P1ww8/6IcffpAkLVmypHSfJK1atUrjxo3TxIkTtX37dr366qtKSEjQU089VeZ8jz/+uEaOHKlt27bptttuK5fnww8/VIsWLUrXVEtPT6/R5/nqq6+0d+9effXVV3rzzTeVkJBQ5kuKisycOVNjxozR1q1bNXz4cN144406evSoJCk1NVXXX3+9Ro0apeTkZN11112aPn16jTLVB6dZFA8AAFQu59BONZGU5dVSHm58H1/bipu0lk5LtqP7rI4CwJUVnpKebl7/5334kOTpW6MuixYt0rhx4yRJw4YN04kTJ/TFF1/osssuU0BAgPz8/OTm5qawsLAy/Zo0aVJm31NPPaVp06bp5ptvliS1bt1aTzzxhP75z3/q8ccfL213ww03VFjIn9G0aVO5ubnJz8+v3DmrIzAwUK+88orc3NzUsWNHXXnllfriiy90xx13VNrnlltu0f/8z/9Ikp5++mm9/PLL2rhxo4YNG6aFCxeqQ4cOeu655yRJHTp00E8//VTuiwqr8S8CAABcgD2rZIX7fP9Ia4M0UF6h7SRJvif2W5wEAOrerl27tHHjRo0dO1aS5O7u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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" } ], "source": [ @@ -62,7 +113,15 @@ "\n", "cavs_degenerate.add_cavity(cav_degenerate, 'cavs_degenerate')\n", "\n", - "cavs_degenerate.run_tune('A', freqs=801.58, cell_types='end cell', rerun=True, solver='ngsolve', n_cells=1)\n", + "tune_config = {\n", + " 'freqs': 801.58,\n", + " 'parameters': 'Req',\n", + " 'cell_types': 'mid-cell',\n", + " 'processes': 1,\n", + " 'rerun': True\n", + "}\n", + "cavs_degenerate.run_tune(tune_config)\n", + "# cavs_degenerate.run_tune('A', freqs=801.58, cell_types='end cell', rerun=True, solver='ngsolve', n_cells=1)\n", "pp.pprint(cavs_degenerate.eigenmode_tune_res)\n", "\n", "# plot geometry after tuning\n", @@ -71,7 +130,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "id": "38573fb5-9e9c-4f04-9a01-fb937495aa96", "metadata": { "scrolled": true @@ -83,20 +142,42 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "01b90a13-4ad4-43bc-bfee-a21a8bf65b3b", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "cavs_degenerate.plot_from_json(ax_obj_dict)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "4dfdb1a0-3b09-4867-9697-f454c893d291", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABLsAAAGbCAYAAAAskpJqAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAAA9hAAAPYQGoP6dpAACjXUlEQVR4nOzdeVhUdfvH8fcwLAoKLiiKormUiuIG5JJWmmmZmvuWW1lp2WIu7T1PWWqaaf0UM81yy8K11RazTR83QFwQlzQXUBBXEFGWmfn9cRIltECBw/J5XddcOd8ZZj5znie7uec+32NxOBwOREREREREREREigEnswOIiIiIiIiIiIjkFTW7RERERERERESk2FCzS0REREREREREig01u0REREREREREpNhQs0tERERERERERIoNNbtERERERERERKTYULNLRERERERERESKDWezAxQGdrud48ePU7ZsWSwWi9lxREREpAhxOBycP38eX19fnJz0PeI/Uc0lIiIiNyOndZeaXcDx48fx8/MzO4aIiIgUYTExMVSvXt3sGIWaai4RERHJC/9Wd6nZBZQtWxYwDpanp6fJaURERKQoSUpKws/PL7OekOtTzSUiIiI3I6d1l5pdkDlG7+npqcJLREREbohOy/t3qrlEREQkL/xb3aWNJUREREREREREpNhQs0tERERERERERIoNNbtERERERERERKTYULNLRERERERERESKDTW7RERERERERESk2FCzS0REREREREREig01u0REREQkx7755hvq1avHrbfeykcffWR2HBEREZFsnM0OICIiIiJFQ0ZGBmPGjOGXX37B09OT5s2b07NnTypUqGB2NBEREZFManblM5vNxvr164mLi6Nq1aq0bdsWq9VqdiwRERGRXNu6dSsNGzakWrVqAHTu3JkffviBAQMGmJxMNZeIiIhcodMY89GqVauoVbsO7dq1Y+DAgbRr145ateuwatUqs6OJiIhICfT777/TtWtXfH19sVgsfPHFF9meM3v2bGrVqkWpUqUIDAxk/fr1mY8dP348s9EFUL16dY4dO1YQ0f+Rai4RERG5mppd+WTVqlX07t2b064+VBk0Db/nllNl0DROu/rQu3dvFV8iIiJS4C5cuECTJk2YNWvWNR8PDQ1l9OjRvPLKK0RGRtK2bVvuv/9+jh49CoDD4cj2MxaL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1Y9tql5sT/Vie5K2aI7vxeaWM/PVb80tX6D55cx89Z+25MwL1BMRERERERERkd7gyi4iIiIiIiIiItIbnOwiIiIiIiIiIiK9wckuIiIiIiIiIiLSG5zsIiIiIiIiIiIivcHJLi1y7NgxDBs2DE5OTpBIJEhISKhW5+rVq3jllVdgbW0NS0tL9O3bF+np6QCA+/fvY8qUKejUqRPMzMzQpk0bTJ06Fbm5uU2cifZoaJs+TgiBl156qdb9NAfqas+TJ0/ihRdegLm5OVq0aAE/Pz8UFRU1URbaQx3tmZWVhZCQEDg4OMDc3By9evXC7t27mzAL7VFXe0okkhofn332mbzOo0ePMGXKFNja2sLc3ByvvPIKfv/99ybORDs0tD35mUTqsnbtWrRr1w4mJibw9PREUlLSE+snJibC09MTJiYmaN++PdavX1+tzp49e+Du7g5jY2O4u7sjPj6+scJXmSr5xsXF4cUXX4SdnR2srKzQr18//Pjjjwp1YmJiauyrf//9d2OnohRV8j169GiNufz2228K9bT5/AKq5RwaGlpjzl26dJHX0dZzrMw4pypd77+q5qzrfVjVfHW9D6uary73XwCIjIxEnz59YGlpidatW2P48OG4du1andtpSz/mZJcWKSwsRPfu3bF69eoaX09LS0P//v3RuXNnHD16FBcvXsS8efNgYmICALh79y7u3r2LqKgo/Prrr4iJicH+/fsxfvz4pkxDqzS0TR+3cuVKSCSSxg5Zq6mjPU+ePInBgwfD398fZ86cwdmzZzF58mQYGDS/f47U0Z4hISG4du0a9u7di19//RVBQUEYOXIkUlJSmioNrVFXe2ZmZio8Nm3aBIlEgtdee01eJyIiAvHx8dixYweOHz+OgoICDB06FGVlZU2VhtZoaHvyM4nUITY2FhEREfjoo4+QkpICHx8fvPTSSzV+KQUAt27dwpAhQ+Dj44OUlBT84x//wNSpU7Fnzx55nZMnT2LkyJEICQnBxYsXERISguDgYJw+fbqp0qqVqvkeO3YML774In744QckJydjwIABGDZsWLXPACsrq2p9tqaxTlNTNd9K165dU8jl6aeflr+mzecXUD3nL774QiHXjIwM2NjY4PXXX1eop43nuK7Pkap0vf8Cques631Y1Xwr6WofVjVfXe6/QMWk1aRJk3Dq1CkcPHgQpaWl8Pf3R2FhYa3baFU/FqSVAIj4+HiFspEjR4rRo0ertJ+dO3cKmUwmSkpK1BidbmpIm164cEE4OzuLzMzMGvfTHNW3Pb28vMTcuXMbMTLdVN/2NDc3F19//bVCmY2NjfjXv/6l7hB1ijL9NDAwULzwwgvy53/99ZcwMjISO3bskJf98ccfwsDAQOzfv7+xQtUJ9WnPmvAziVT17LPPiokTJyqUde7cWcyZM6fG+rNnzxadO3dWKAsLCxN9+/aVPw8ODhaDBw9WqBMQECDeeOMNNUVdf6rmWxN3d3fxySefyJ9v3rxZWFtbqytEtVI13yNHjggA4sGDB7XuU5vPrxANP8fx8fFCIpGI27dvy8u0+RxXUuZzRNf7b1X1/T+DLvXhxymTrz704Ur1Ob+62n8rZWdnCwAiMTGx1jra1I+b31IKHVVeXo7vv/8eHTt2REBAAFq3bg0vL686l07m5ubCysoKhoaGTROoDlG2TR8+fIg333wTq1evhoODg2aC1QHKtGd2djZOnz6N1q1bw9vbG/b29vD19cXx48c1F7iWUvb92b9/f8TGxuL+/fsoLy/Hjh078OjRI/j5+Wkkbl1x7949fP/99wqrjJKTk1FSUgJ/f395mZOTEzw8PHDixAlNhKkzamrPmvAziVRRXFyM5ORkhT4JAP7+/rX2yZMnT1arHxAQgHPnzqGkpOSJdTTdz+uTb1Xl5eXIz8+HjY2NQnlBQQHatm0LZ2dnDB06VCtW/zYk3549e8LR0REDBw7EkSNHFF7T1vMLqOccb9y4EYMGDULbtm0VyrXxHKtKl/uvuuhSH24IXe3DDaXr/bfyUhRV35+P06Z+zMkuHZGdnY2CggIsXboUgwcPxoEDB/Dqq68iKCgIiYmJNW7z3//+F4sWLUJYWFgTR6sblG3T6dOnw9vbG4GBgRqMVvsp0543b94EACxYsAATJkzA/v370atXLwwcOBA3btzQZPhaR9n3Z2xsLEpLS9GqVSsYGxsjLCwM8fHxcHNz02D02m/Lli2wtLREUFCQvCwrKwsymQwtW7ZUqGtvb4+srKymDlGn1NSeVfEziVSVk5ODsrIy2NvbK5Q/qU9mZWXVWL+0tBQ5OTlPrKPpfl6ffKv6/PPPUVhYiODgYHlZ586dERMTg71792L79u0wMTHBc889p/HP3frk6+joiA0bNmDPnj2Ii4tDp06dMHDgQBw7dkxeR1vPL9Dwc5yZmYn//Oc/eOeddxTKtfUcq0qX+6+66FIfrg9d78MNoev9VwiBGTNmoH///vDw8Ki1njb1Y361qiPKy8sBAIGBgZg+fToAoEePHjhx4gTWr18PX19fhfp5eXl4+eWX4e7ujvnz5zd5vLpAmTbdu3cvDh8+rLWz69pEmfasrBMWFoZx48YBqPhm56effsKmTZsQGRmpmeC1kLJ9fu7cuXjw4AEOHToEW1tbJCQk4PXXX0dSUhK6du2qsfi13aZNm/DWW28pdT0EIUSzv15fXepqT34mUUNU7X919cma6lctV3WfTam+sW3fvh0LFizAd999h9atW8vL+/bti759+8qfP/fcc+jVqxdWrVqFL7/8Un2B15Mq+Xbq1AmdOnWSP+/Xrx8yMjIQFRWF559/vl771IT6xhcTE4MWLVpg+PDhCuXafo5Voev9tyF0tQ+rQl/6cH3oev+dPHkyfvnlF6V+kaMt/Zgru3SEra0tDA0N4e7urlD+zDPPVLugZX5+PgYPHgwLCwvEx8fDyMioKUPVGcq06eHDh5GWloYWLVrA0NBQ/tOb1157jT8Tq0KZ9nR0dAQApd7HzZ0y7ZmWlobVq1dj06ZNGDhwILp374758+ejd+/eWLNmjSbC1glJSUm4du1atW/WHBwcUFxcjAcPHiiUZ2dnV/v2if6ntvasxM8kqi9bW1tIpdJq3/Q+qU86ODjUWN/Q0BCtWrV6Yh1N9/P65FspNjYW48ePx86dOzFo0KAn1jUwMECfPn00vmqgIfk+rm/fvgq5aOv5BRqWsxACmzZtQkhICGQy2RPrass5VpUu99+G0sU+rC661IfrS9f775QpU7B3714cOXIEzs7OT6yrTf2Yk106QiaToU+fPtVu9Xn9+nWF3/zm5eXB398fMpkMe/fu1Yq7OGgrZdp0zpw5+OWXX3DhwgX5AwCio6OxefPmpg5ZqynTnq6urnBycqrzfUzKtefDhw8BoNqdLKVSqXxlGFW3ceNGeHp6onv37grlnp6eMDIywsGDB+VlmZmZuHTpEry9vZs6TJ1RW3sC/EyihpHJZPD09FTokwBw8ODBWvtkv379qtU/cOAAevfuLZ9ora2Opvt5ffIFKlaDhIaG4ttvv8XLL79c53GEELhw4YL8CyhNqW++VaWkpCjkoq3nF2hYzomJiUhNTVXqjrbaco5Vpcv9tyF0tQ+riy714frS1f4rhMDkyZMRFxeHw4cPo127dnVuo1X9WK2Xu6cGyc/PFykpKSIlJUUAECtWrBApKSnizp07Qggh4uLihJGRkdiwYYO4ceOGWLVqlZBKpSIpKUkIIUReXp7w8vISXbt2FampqSIzM1P+KC0t1WRqGtPQNq0JmvHdGNXRntHR0cLKykrs2rVL3LhxQ8ydO1eYmJiI1NRUTaWlMQ1tz+LiYtGhQwfh4+MjTp8+LVJTU0VUVJSQSCTi+++/12RqGlFXewohRG5urjAzMxPr1q2rcR8TJ04Uzs7O4tChQ+L8+fPihRdeEN27d2+W/4Y2tD35mUTqsGPHDmFkZCQ2btworly5IiIiIoS5ubn8TlZz5swRISEh8vo3b94UZmZmYvr06eLKlSti48aNwsjISOzevVte5+effxZSqVQsXbpUXL16VSxdulQYGhqKU6dONXl+Vama77fffisMDQ3FmjVrFPrYX3/9Ja+zYMECsX//fpGWliZSUlLEuHHjhKGhoTh9+nST51eVqvlGR0eL+Ph4cf36dXHp0iUxZ84cAUDs2bNHXkebz68QqudcafTo0cLLy6vGfWrrOa7rc0Tf+q8Qques631Y1Xx1vQ+rmm8lXey/Qgjx3nvvCWtra3H06FGF9+fDhw/ldbS5H3OyS4tU3oq16mPs2LHyOhs3bhQdOnQQJiYmonv37iIhIaHO7QGIW7duNX1CWqChbVqT5jzZpa72jIyMFM7OzsLMzEz069fviZOL+kwd7Xn9+nURFBQkWrduLczMzES3bt3E119/3cSZaAdl2vOrr74SpqamCoPIxxUVFYnJkycLGxsbYWpqKoYOHSrS09ObKAPt0tD25GcSqcuaNWtE27ZthUwmE7169VK45fnYsWOFr6+vQv2jR4+Knj17CplMJlxdXWucjN21a5fo1KmTMDIyEp07d1b4j5amqZKvr69vnf00IiJCtGnTRshkMmFnZyf8/f3FiRMnmjCjJ1Ml32XLlgk3NzdhYmIiWrZsKfr371/jlzvafH6FUP09/ddffwlTU1OxYcOGGvenree4rs8Rfey/quas631Y1Xx1vQ/X5z2tq/1XCFHrOG7z5s3yOtrcjyX/nwQREREREREREZHO4zW7iIiIiIiIiIhIb3Cyi4iIiIiIiIiI9AYnu4iIiIiIiIiISG9wsouIiIiIiIiIiPQGJ7uIiIiIiIiIiEhvcLKLiIiIiIiIiIj0Bie7iIiIiIiIiIhIb3Cyi4iIiIiIiIiI9AYnu4iIiIiIiEhnuLq6YuXKlZoOg4i0GCe7iEhrhYaGQiKRQCKRwMjICO3bt8fMmTNRWFio6dDqhQMzIiIi0jWhoaEYPnw4AMDPzw8RERFNduyYmBi0aNGiWvnZs2fx7rvvNlkcRKR7DDUdABHRkwwePBibN29GSUkJkpKS8M4776CwsBDr1q1TaT9CCJSVlcHQUPf/2SsuLoZMJtN0GERERET10tCxjJ2dnRqjISJ9xJVdRKTVjI2N4eDgABcXF4waNQpvvfUWEhISsG3bNvTu3RuWlpZwcHDAqFGjkJ2dLd/u6NGjkEgk+PHHH9G7d28YGxsjKSkJaWlpCAwMhL29PSwsLNCnTx8cOnRI4Ziurq5YvHgxxowZAwsLC7Rt2xbfffcd/vzzTwQGBsLCwgJdu3bFuXPnFLY7ceIEnn/+eZiamsLFxQVTp06Vr0Lz8/PDnTt3MH36dPlqNWW2ezye0NBQWFtbY8KECY3R1ERERES1Cg0NRWJiIr744gv5WOb27dsAgCtXrmDIkCGwsLCAvb09QkJCkJOTI9/Wz88PkydPxowZM2Bra4sXX3wRALBixQp07doV5ubmcHFxQXh4OAoKCgBUjOXGjRuH3Nxc+fEWLFgAoPpq+fT0dPkYzcrKCsHBwbh375789QULFqBHjx7YunUrXF1dYW1tjTfeeAP5+fmN22hEpDGc7CIinWJqaoqSkhIUFxdj0aJFuHjxIhISEnDr1i2EhoZWqz979mxERkbi6tWr6NatGwoKCjBkyBAcOnQIKSkpCAgIwLBhw5Cenq6wXXR0NJ577jmkpKTg5ZdfRkhICMaMGYPRo0fj/Pnz6NChA8aMGQMhBADg119/RUBAAIKCgvDLL78gNjYWx48fx+TJkwEAcXFxcHZ2xsKFC5GZmYnMzEyltqv02WefwcPDA8nJyZg3b14jtCwRERFR7b744gv069cPEyZMkI9lXFxckJmZCV9fX/To0QPnzp3D/v37ce/ePQQHBytsv2XLFhgaGuLnn3/GV199BQAwMDDAl19+iUuXLmHLli04fPgwZs+eDQDw9vbGypUrYWVlJT/ezJkzq8UlhMDw4cNx//59JCYm4uDBg0hLS8PIkSMV6qWlpSEhIQH79u3Dvn37kJiYiKVLlzZSaxGRxgkiIi01duxYERgYKH9++vRp0apVKxEcHFyt7pkzZwQAkZ+fL4QQ4siRIwKASEhIqPM47u7uYtWqVfLnbdu2FaNHj5Y/z8zMFADEvHnz5GUnT54UAERmZqYQQoiQkBDx7rvvKuw3KSlJGBgYiKKiIvl+o6OjFeoou93w4cPrzIOIiIhI3R4fj/n6+opp06YpvD5v3jzh7++vUJaRkSEAiGvXrsm369GjR53H2rlzp2jVqpX8+ebNm4W1tXW1eo+PqQ4cOCCkUqlIT0+Xv3758mUBQJw5c0YIIcT8+fOFmZmZyMvLk9eZNWuW8PLyqjMmItJNun/xGiLSa/v27YOFhQVKS0tRUlKCwMBArFq1CikpKViwYAEuXLiA+/fvo7y8HEDFMnZ3d3f59r1791bYX2FhIT755BPs27cPd+/eRWlpKYqKiqqt7OrWrZv87/b29gCArl27VivLzs6Gg4MDkpOTkZqaim+++UZeRwiB8vJy3Lp1C88880yN+Sm7XdU8iIiIiLRBcnIyjhw5AgsLi2qvpaWloWPHjgBqHsscOXIEn376Ka5cuYK8vDyUlpbi77//RmFhIczNzZU6/tWrV+Hi4gIXFxd5mbu7O1q0aIGrV6+iT58+ACp++mhpaSmv4+joqHAJDCLSL5zsIiKtNmDAAKxbtw5GRkZwcnKCkZERCgsL4e/vD39/f2zbtg12dnZIT09HQEAAiouLFbavOlCaNWsWfvzxR0RFRaFDhw4wNTXFiBEjqm1nZGQk/3vl9bVqKqucZCsvL0dYWBimTp1aLYc2bdrUmp+y2yk74CMiIiJqSuXl5Rg2bBiWLVtW7TVHR0f536uOZe7cuYMhQ4Zg4sSJWLRoEWxsbHD8+HGMHz8eJSUlSh9fCKFwLdTayh8fxwEVY7nKcRwR6R9OdhGRVjM3N0eHDh0Uyn777Tfk5ORg6dKl8m/xql4svjZJSUkIDQ3Fq6++CgAoKCiQX1y1IXr16oXLly9Xi/VxMpkMZWVlKm9HREREpA1qG8vs2bMHrq6uKt31+ty5cygtLcXnn38OA4OKS0nv3LmzzuNV5e7ujvT0dGRkZMjHhVeuXEFubm6tK+uJSP/xAvVEpHPatGkDmUyGVatW4ebNm9i7dy8WLVqk1LYdOnRAXFwcLly4gIsXL2LUqFFq+Vbvgw8+wMmTJzFp0iRcuHABN27cwN69ezFlyhR5HVdXVxw7dgx//PGH/A5FymxHREREpA1cXV1x+vRp3L59Gzk5OSgvL8ekSZNw//59vPnmmzhz5gxu3ryJAwcO4O23337iRJWbmxtKS0vl47mtW7di/fr11Y5XUFCAn376CTk5OXj48GG1/QwaNAjdunXDW2+9hfPnz+PMmTMYM2YMfH19eRkIomaMk11EpHPs7OwQExODXbt2wd3dHUuXLkVUVJRS20ZHR6Nly5bw9vbGsGHDEBAQgF69ejU4pm7duiExMRE3btyAj48PevbsiXnz5iks31+4cCFu374NNzc32NnZKb0dERERkTaYOXMmpFIp3N3d5ZeRcHJyws8//4yysjIEBATAw8MD06ZNg7W1tXzFVk169OiBFStWYNmyZfDw8MA333yDyMhIhTre3t6YOHEiRo4cCTs7OyxfvrzafiQSCRISEtCyZUs8//zzGDRoENq3b4/Y2Fi1509EukMihBCaDoKIiIiIiIiIiEgduLKLiIiIiIiIiIj0Bie7iIiIiIiIiIhIb3Cyi4iIiIiIiIiI9AYnu4iIiIiIiIiISG9wsouIiIiIiIiIiPQGJ7uIiIiIiIiIiEhvcLKLiIiIiIiIiIj0Bie7iIiIiIiIiIhIb3Cyi4iIiIiIiIiI9AYnu4iIiIiIiIiISG9wsouIiIiIiIiIiPTG/wHmT2bQRIwuhwAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "cavs_degenerate.plot('convergence')\n", "plt.show()" diff --git a/notebooks/wakefield_analysis.ipynb b/notebooks/wakefield_analysis.ipynb index 9b41bb8..f644c95 100644 --- a/notebooks/wakefield_analysis.ipynb +++ b/notebooks/wakefield_analysis.ipynb @@ -22,80 +22,21 @@ "name": "stdout", "output_type": "stream", "text": [ - "\u001b[32mProject D:\\Dropbox\\CavityDesignHub\\MuCol_Study\\SimulationData\\ConsoleTest created successfully/already exists.\u001b[0m\n" - ] - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "49d047ec22a54d0395d8a8f7303cf667", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - " 0%| | 0/1 [00:00" ] @@ -201,202 +150,7 @@ }, "widgets": { "application/vnd.jupyter.widget-state+json": { - "state": { - "0b98aeabafd84378b5babcb90692854f": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "0da2e1de5a4c46cfaed3f233c52b6989": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLModel", - "state": { - "layout": "IPY_MODEL_0b98aeabafd84378b5babcb90692854f", - "style": "IPY_MODEL_d4f1c50ce9ed4f41994350ef48ea39a1", - "value": "100%" - } - }, - "22b32b9a370844aaae4c258250fc63fd": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLStyleModel", - "state": { - "description_width": "", - "font_size": null, - "text_color": null - } - }, - "3c7a03d51a9e4524a771561442e3980c": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "FloatProgressModel", - "state": { - "bar_style": "success", - "layout": "IPY_MODEL_470a77b4a0a8421c900fccfb96b2d0f0", - "max": 1, - "style": "IPY_MODEL_f2c0b2ecb329414cbb177dbc26b3d379", - "value": 1 - } - }, - "45cb4d39349b4528be13ee76129a8816": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HBoxModel", - "state": { - "children": [ - "IPY_MODEL_df24a891f18040f3999d49381944e9b1", - "IPY_MODEL_3c7a03d51a9e4524a771561442e3980c", - "IPY_MODEL_ebc22afc36b146b4a643e199395dd938" - ], - "layout": "IPY_MODEL_fdc67f648af849308ce4e062da65f07a" - } - }, - "470a77b4a0a8421c900fccfb96b2d0f0": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "49d047ec22a54d0395d8a8f7303cf667": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HBoxModel", - "state": { - "children": [ - "IPY_MODEL_0da2e1de5a4c46cfaed3f233c52b6989", - "IPY_MODEL_f962916a52f947a8a9b6c19e1662b086", - "IPY_MODEL_ed407f58077e473087eb301a21d666dd" - ], - "layout": "IPY_MODEL_987fecb821c2462e9c932f66e61d5cf2" - } - }, - "4d1d3092aed4475688af2c05e839c84e": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLStyleModel", - "state": { - "description_width": "", - "font_size": null, - "text_color": null - } - }, - "61e1a07e5e554c76a590361fbf80cbfd": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLStyleModel", - "state": { - "description_width": "", - "font_size": null, - "text_color": null - } - }, - "6c8475a85d6a4ea0947bc1ca4fd8c410": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "987fecb821c2462e9c932f66e61d5cf2": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "ae552f2735fc4ce8b1ea8c5ebe841db5": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "d4f1c50ce9ed4f41994350ef48ea39a1": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLStyleModel", - "state": { - "description_width": "", - "font_size": null, - "text_color": null - } - }, - "db118c1efa0a44f8b70f4d7ea51b0c08": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "ProgressStyleModel", - "state": { - "description_width": "" - } - }, - "df24a891f18040f3999d49381944e9b1": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLModel", - "state": { - "layout": "IPY_MODEL_6c8475a85d6a4ea0947bc1ca4fd8c410", - "style": "IPY_MODEL_61e1a07e5e554c76a590361fbf80cbfd", - "value": "100%" - } - }, - "e2593cdea0484f218139045815f50423": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "ebc22afc36b146b4a643e199395dd938": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLModel", - "state": { - "layout": "IPY_MODEL_f0b28c04b75f4e5fad913097c3d25387", - "style": "IPY_MODEL_22b32b9a370844aaae4c258250fc63fd", - "value": " 1/1 [00:12<00:00, 12.42s/it]" - } - }, - "ed407f58077e473087eb301a21d666dd": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLModel", - "state": { - "layout": "IPY_MODEL_ae552f2735fc4ce8b1ea8c5ebe841db5", - "style": "IPY_MODEL_4d1d3092aed4475688af2c05e839c84e", - "value": " 1/1 [01:07<00:00, 67.04s/it]" - } - }, - "f0b28c04b75f4e5fad913097c3d25387": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "f2c0b2ecb329414cbb177dbc26b3d379": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "ProgressStyleModel", - "state": { - "description_width": "" - } - }, - "f962916a52f947a8a9b6c19e1662b086": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "FloatProgressModel", - "state": { - "bar_style": "success", - "layout": "IPY_MODEL_e2593cdea0484f218139045815f50423", - "max": 1, - "style": "IPY_MODEL_db118c1efa0a44f8b70f4d7ea51b0c08", - "value": 1 - } - }, - "fdc67f648af849308ce4e062da65f07a": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - } - }, + "state": {}, "version_major": 2, "version_minor": 0 }