Source code for squadds.interpolations.utils
import os
import time
import pandas as pd
from pyEPR.calcs import Convert
from squadds.core.utils import create_unified_design_options
[docs]
def get_design_from_ml_predictions(analyzer, test_data, y_pred_dnn):
"""
Generate design options DataFrame using ML predictions.
Args:
analyzer (Analyzer): An instance of the Analyzer class.
test_data (pd.DataFrame): DataFrame with target parameters.
y_pred_dnn (numpy.ndarray): Array with predicted design parameters.
Returns:
pd.DataFrame: DataFrame with design options similar to interpolated_designs_df.
"""
designs_list = []
for i, row in test_data.iterrows():
# Get target parameters
f_q_target = row['qubit_frequency_GHz']
f_res_target = row['cavity_frequency_GHz']
alpha_target = row['anharmonicity_MHz']
kappa_target = row['kappa_kHz']
g_target = row['g_MHz']
# Get the corresponding predicted design parameters
predicted_design_params = y_pred_dnn[i]
cross_length_pred = predicted_design_params[0]
claw_length_pred = predicted_design_params[1]
coupling_length_pred = predicted_design_params[2]
total_length_pred = predicted_design_params[3]
ground_spacing_pred = predicted_design_params[4]
# Now find the closest designs
# Find the closest qubit design
closest_qubit_claw_design = analyzer.find_closest(
{"qubit_frequency_GHz": f_q_target, 'anharmonicity_MHz': alpha_target, 'g_MHz': g_target},
num_top=1
)
# Find the closest cavity design
target_params_cavity = {'cavity_frequency_GHz': f_res_target, 'kappa_kHz': kappa_target}
closest_cavity_cpw_design = analyzer.find_closest(
target_params_cavity, num_top=1
)
# Now update the design options
# Get the design options from the closest designs
qubit_design_options = closest_qubit_claw_design["design_options_qubit"].iloc[0].copy()
cavity_design_options = closest_cavity_cpw_design["design_options_cavity_claw"].iloc[0].copy()
# Update the qubit design options with predicted values
qubit_design_options['cross_length'] = f"{cross_length_pred}um"
qubit_design_options["connection_pads"]["readout"]['claw_length'] = f"{claw_length_pred}um"
qubit_design_options["connection_pads"]["readout"]['ground_spacing'] = f"{ground_spacing_pred}um"
# Update the 'Lj' parameters
required_Lj = Convert.Lj_from_Ej(closest_qubit_claw_design['EJ'].iloc[0], units_in='GHz', units_out='nH')
qubit_design_options['aedt_hfss_inductance'] = required_Lj*1e-9
qubit_design_options['aedt_q3d_inductance'] = required_Lj*1e-9
qubit_design_options['q3d_inductance'] = required_Lj*1e-9
qubit_design_options['hfss_inductance'] = required_Lj*1e-9
qubit_design_options["connection_pads"]["readout"]['Lj'] = f"{required_Lj}nH"
# Set 'claw_cpw_*' parameters to zero
qubit_design_options["connection_pads"]['readout']['claw_cpw_length'] = "0um"
# qubit_design_options["connection_pads"]['readout']['claw_cpw_width'] = "0um"
# Update the cavity design options with predicted values
cavity_design_options["cpw_opts"]['total_length'] = f"{total_length_pred}um"
cavity_design_options['cplr_opts']['coupling_length'] = f"{coupling_length_pred}um"
# Update the claw of the cavity based on the one from the qubit
cavity_design_options["claw_opts"]["connection_pads"] = qubit_design_options["connection_pads"]
# Create the combined design options
device_dict = {
"coupler_type": analyzer.selected_coupler,
"design_options_qubit": qubit_design_options,
"design_options_cavity_claw": cavity_design_options,
"setup_qubit": closest_qubit_claw_design["setup_qubit"].iloc[0],
"setup_cavity_claw": closest_cavity_cpw_design["setup_cavity_claw"].iloc[0],
}
device_design_options = create_unified_design_options(device_dict)
# Add the device design options to the dictionary
device_dict["design_options"] = device_design_options
device_dict["design_options"]["qubit_options"]["connection_pads"]["readout"]["claw_cpw_length"] = "0um"
designs_list.append(device_dict)
# Now create the final DataFrame
designs_df = pd.DataFrame(designs_list)
return designs_df
[docs]
def process_dataframe(analyzer, target_params_df, index, path_to_file):
"""
Processes the dataframe by merging, filtering columns, and converting specific string columns to floats.
Args:
analyzer (Analyzer): An instance of the Analyzer class.
target_params_df (pd.DataFrame): A dataframe containing target parameters.
path_to_file (str): The file path where the processed dataframe will be saved.
Returns:
pd.DataFrame: The processed dataframe.
"""
# Merge with coupling data
merged_df = analyzer.get_complete_df(target_params_df.iloc[index])
# Define columns to keep
columns_to_keep = [
'cross_length', 'cross_gap', 'claw_length',
'ground_spacing', 'coupler_type', 'resonator_type', 'cavity_frequency_GHz',
'kappa_kHz', 'EC', 'EJ', 'EJEC', 'qubit_frequency_GHz', 'anharmonicity_MHz',
'g_MHz', 'coupling_length', 'total_length'
]
# Filter out unwanted columns
new_df = merged_df.drop(columns=[col for col in merged_df.columns if col not in columns_to_keep])
# Convert specific columns from string to float
float_col_names = ['claw_length']
new_df[float_col_names] = new_df[float_col_names].applymap(lambda x: float(x[:-2]))
# Apply conversions for design options using JSON-like structure
new_df['cross_length'] = merged_df['design_options'].apply(
lambda x: float(x['qubit_options']['cross_length'][:-2])
)
new_df["cross_gap"] = merged_df['design_options'].apply(
lambda x: float(x['qubit_options']['cross_gap'][:-2])
)
new_df['ground_spacing'] = merged_df['design_options'].apply(
lambda x: float(x['qubit_options']['connection_pads']['readout']['ground_spacing'][:-2])
)
new_df['coupling_length'] = merged_df['design_options'].apply(
lambda x: float(x['cavity_claw_options']['coupler_options']['coupling_length'][:-2])
)
new_df["total_length"] = merged_df['design_options'].apply(
lambda x: float(x['cavity_claw_options']['cpw_opts']["left_options"]['total_length'][:-2])
)
# Drop the 'coupler_type' and 'resonator_type' columns
new_df = new_df.drop(columns=['coupler_type', 'resonator_type'])
return new_df
[docs]
def generate_qubit_cavity_training_data(analyzer,target_params_df,path_to_file):
"""
Generates training data for qubit and cavity designs based on target parameters.
Args:
analyzer (Analyzer): An instance of the Analyzer class.
target_params_df (pd.DataFrame): A dataframe containing target parameters.
path_to_file (str): The file path where the processed dataframe will be saved.
"""
if analyzer.selected_resonator_type == "quarter":
# for each entry in the target_params_df, process the dataframe and concatenate the results
processed_dfs = []
for index in range(len(target_params_df)):
processed_dfs.append(process_dataframe(analyzer, target_params_df, index, path_to_file))
# concatenate the results
training_df = pd.concat(processed_dfs)
# if the file path is provided, save the processed dataframe if not create training_data foder and save the processed dataframe with unique timestamp
if path_to_file:
if path_to_file.endswith('.parquet'):
training_df.to_parquet(path_to_file)
elif path_to_file.endswith('.csv'):
training_df.to_csv(path_to_file)
else:
raise ValueError("Please provide a valid file format (.parquet or .csv) for the training data.")
print(f"Training data saved to {path_to_file}")
else:
if not os.path.exists('training_data'):
os.makedirs('training_data')
timestamp = time.strftime("%Y%m%d-%H%M%S")
training_df.to_parquet(f"training_data/training_data_{timestamp}.parquet")
print(f"Training data saved to training_data/training_data_{timestamp}.parquet")
return training_df
elif analyzer.selected_resonator_type == "half":
raise NotImplementedError("Half resonator type data generation has not been implemented yet. Please feel free to contribute!")