def get_labeled_collection( meas_file_base: str, iter_count: Iterable[int], samp_file: str, filepath: Union[str, None] = DATA_DIR) -> Iterable[LabeledPeakCollection]: """Returns Iterable for LabeledPeakCluster data.""" fetch_func = get_file_fetch_func(file_base_name=meas_file_base, filepath=filepath) for i in iter_count: try: meas_file = fetch_func(iteration=i) measurement_container = FileToMeasData(meas_file=meas_file, samp_file=samp_file, filepath=filepath) measurement_container = get_converted_measurement_data( meas_class=measurement_container, q_offset=Q_OFFSET) labeled_collection = LabeledPeakCollection( transmission_peak_collection=identify_peaks( meas_data=measurement_container), q_offset=Q_OFFSET) # normalized_collection = NormalizedPeakCollection(transmission_peak_collection=identify_peaks(meas_data=measurement_container), q_offset=Q_OFFSET) yield labeled_collection except FileNotFoundError: continue
def single_source_analysis(meas_file: str, samp_file: str, filepath: Union[str, None] = DATA_DIR): # Create measurement container instance measurement_container = FileToMeasData(meas_file=meas_file, samp_file=samp_file, filepath=filepath) # # # (Report specific) Plot classification process # plot_mode_classification(meas_data=measurement_container) # Plot # Apply voltage to length conversion measurement_container = get_converted_measurement_data( meas_class=measurement_container, q_offset=Q_OFFSET, verbose=False) # Peak Identification peak_collection = identify_peaks(meas_data=measurement_container) peak_ax = plot_peak_identification( collection=peak_collection, meas_class=measurement_container) # Plot # Peak clustering and mode labeling labeled_collection = LabeledPeakCollection( transmission_peak_collection=peak_collection, q_offset=Q_OFFSET) rela_ax = plot_peak_relation(collection=labeled_collection, meas_class=measurement_container) # Plot
def __init__(self, meas_file: str, samp_file: str, collection: Optional[NormalizedPeakCollection] = None): self._meas_file = meas_file self._samp_file = samp_file if collection is None: # Construct synchronized measurement object self._meas_data = get_converted_measurement_data( FileToMeasData(meas_file=meas_file, samp_file=samp_file)) self._peak_collection = NormalizedPeakCollection( identify_peaks(meas_data=self._meas_data)) else: self._peak_collection = collection self._meas_data = collection._get_data_class
def get_piezo_response(meas_class: Union[SyncMeasData, LabeledPeakCollection], verbose: bool = False, **kwargs) -> Callable[[np.ndarray], np.ndarray]: """ Returns the fitted piezo-voltage to cavity-length response. **kwargs: - q_offset: (LabeledPeakCollection) determinse the starting fundamental mode """ from src.sample_conversion import fit_piezo_response if isinstance(meas_class, SyncMeasData): initial_labeling = LabeledPeakCollection(identify_peaks(meas_class), **kwargs) else: initial_labeling = meas_class # Set voltage conversion function return fit_piezo_response( cluster_collection=initial_labeling.get_q_clusters, sample_wavelength=SAMPLE_WAVELENGTH, verbose=verbose)
def plot_3d_sequence(data_classes: List[SyncMeasData], long_mode: int, trans_mode: Union[int, None]) -> plt.axis: # Set 3D plot fig = plt.figure() axis = fig.gca(projection='3d') # Store slices to ensure equally size arrays cluster_arrays = [] q_mode_peaks = [] data_slices = [] data_slices_range = [] for data_class in data_classes: collection = LabeledPeakCollection(identify_peaks(data_class)) try: cluster_array, value_slice = collection.get_mode_sequence( long_mode=long_mode, trans_mode=trans_mode) cluster_arrays.append(cluster_array) q_mode_peaks.append(collection.q_dict[long_mode]) except ValueError: logging.warning(f'Longitudinal mode {long_mode} not well defined') return axis data_slice = get_value_to_data_slice(data_class=data_class, value_slice=value_slice) data_slices.append(data_slice) data_slices_range.append(get_slice_range(data_slice)) # Store range # Prepare plot data leading_index = data_slices_range.index(max(data_slices_range)) leading_slice = data_slices[leading_index] for i, slice in enumerate(data_slices): range_diff = get_slice_range(leading_slice) - get_slice_range(slice) padding = whole_integer_divider(num=range_diff, div=2) data_slices[i] = (slice[0] - padding[0], slice[1] + padding[1]) sliced_xs = data_classes[leading_index].x_boundless_data[ leading_slice[0]:leading_slice[1]] xs = np.arange(get_slice_range(leading_slice)) # sliced_xs # zs = np.arange(len(data_slices)) verts = [] peaks = [] for i, slice in enumerate(data_slices): data_class = data_classes[i] data_class.slicer = slice ys = data_class.y_data verts.append(list(zip(xs, ys))) # Peak scatter plot peak_list = flatten_clusters(data=cluster_arrays[i]) peaks.append(peak_list) # Collect peaks for polarisation cross section yp = [peak.get_y for peak in peak_list] xp = [peak.get_relative_index for peak in peak_list] zp = [zs[i] for j in range(len(peak_list))] axis.scatter(xp, zp, yp, marker='o') # Draw individual measurement polygons poly = PolyCollection(verts) poly.set_alpha(.7) axis.add_collection3d(poly, zs=zs, zdir='y') # Draw polarisation cross section cross_section_count = len(peaks[0]) if all(len(peak_array) == cross_section_count for peak_array in peaks): # Able to build consistent cross sections cross_peaks = list( map(list, zip(*peaks) )) # Transposes peaks-list to allow for cross section ordering xc = [] # Insert 0 bound values zc = list(zs) zc.insert(0, zc[0]) zc.append(zc[-1]) peak_verts = [] face_colors = [[v, .3, .3] for v in np.linspace(.5, 1., len(cross_peaks))] for i, cross_section in enumerate(cross_peaks): yc = [peak.get_y for peak in cross_section] # Insert 0 bound values yc.insert(0, 0) yc.append(0) xc.append( int( np.mean([ peak.get_relative_index for peak in cross_section ]))) # np.mean([peak.get_x for peak in cross_section])) # peak_verts.append(list(zip(zc, yc))) poly = PolyCollection([list(zip(zc, yc))]) # peak_verts poly.set_alpha(1) poly.set_facecolor(face_colors[i]) axis.add_collection3d(poly, zs=xc[-1], zdir='x') # poly = PolyCollection(peak_verts) # poly.set_alpha(1) # axis.add_collection3d(poly, zs=xc, zdir='x') print('plotting') else: logging.warning(f'Cross section (peak) count is not consistent') axis.set_xlabel('Relative cavity length [nm]') axis.set_xlim3d(0, len(xs)) # axis.set_xticks(xs) axis.set_ylabel('Polarisation [10 Degree]') # 'Measurement iterations') axis.set_ylim3d(-1, len(zs) + 1) # axis.set_yticks([str(10 * angle) for angle in zs]) axis.set_zlabel('Transmission [a.u.]') axis.set_zlim3d(0, 1) # Set viewport axis.view_init(elev=22, azim=-15) return axis
file_samp = 'samples_0_3s_10V_rate1300000.0' # 'samples_1s_10V_rate1300000.0' # Measurement files # filenames = ['transrefl_hene_1s_10V_PMT5_rate1300000.0itteration{}'.format(i) for i in range(10)] filenames = [ 'transrefl_hene_0_3s_10V_PMT4_rate1300000.0itteration1_pol{:0=2d}0'. format(i) for i in range(19) ] meas_iterations = [ get_converted_measurement_data( FileToMeasData(meas_file=file_meas, samp_file=file_samp)) for file_meas in filenames ] identified_peaks = [ identify_peaks(meas_data=data) for data in meas_iterations ] labeled_peaks = [ LabeledPeakCollection(transmission_peak_collection=collection) for collection in identified_peaks ] trans_mode = 2 long_mode = 0 plot_3d_sequence(data_classes=meas_iterations, long_mode=long_mode, trans_mode=trans_mode) def plot_cross_sections(): # Test index = 0
def plot_mode_classification(meas_data: SyncMeasData) -> plt.axes: """Plots report paper figure for entire classification process""" from src.peak_identifier import identify_peaks from src.peak_relation import LabeledPeakCollection, get_converted_measurement_data from src.main import Q_OFFSET _fig, ((_ax00, _ax01), (_ax10, _ax11)) = plt.subplots(2, 2, sharey='all') colors = plt.cm.jet(np.linspace(0, 1, 10)) # Plot raw data _ax00.text(1.05, 1., '(a)', horizontalalignment='center', verticalalignment='top', transform=_ax00.transAxes) _ax00 = plot_class(axis=_ax00, measurement_class=meas_data) _ax00.set_xlabel('Voltage [V]') # Plot peak locations _ax01.text(1.05, 1., '(b)', horizontalalignment='center', verticalalignment='top', transform=_ax01.transAxes) peak_collection = identify_peaks(meas_data=meas_data) _ax01 = plot_class(axis=_ax01, measurement_class=meas_data, alpha=0.2) for i, peak_data in enumerate(peak_collection): if peak_data.relevant: _ax01.plot(peak_data.get_x, peak_data.get_y, 'x', color='r', alpha=1) _ax01.set_xlabel('Voltage [V]') # Plot q mode separation and mode ordering _ax10.text(1.05, 1., '(c)', horizontalalignment='center', verticalalignment='top', transform=_ax10.transAxes) labeled_collection = LabeledPeakCollection(peak_collection) _ax10 = get_standard_axis(axis=_ax10) min_q = min(labeled_collection.q_dict.keys()) mode_sequence_range = range(min_q, max(labeled_collection.q_dict.keys()) + 2) for i in mode_sequence_range: try: cluster_array, value_slice = labeled_collection.get_mode_sequence( long_mode=i) # Get normalized measurement x_sample, y_measure = labeled_collection.get_measurement_data_slice( union_slice=value_slice) _ax10.plot( x_sample, y_measure, alpha=1, color=colors[(cluster_array[0].get_longitudinal_mode_id - min_q) % len(colors)]) except AttributeError: break for i, peak_data in enumerate(labeled_collection): if peak_data.relevant: _ax10.plot( peak_data.get_x, peak_data.get_y, 'x', color=colors[(peak_data.get_transverse_mode_id - min_q) % len(colors)], alpha=1) _ax10.set_xlabel('Voltage [V]') # Plot finalized labeled peaks _ax11.text(1.05, 1., '(d)', horizontalalignment='center', verticalalignment='top', transform=_ax11.transAxes) meas_data = get_converted_measurement_data(meas_class=meas_data, q_offset=Q_OFFSET, verbose=False) labeled_collection = LabeledPeakCollection( identify_peaks(meas_data=meas_data), q_offset=Q_OFFSET) # _ax11 = plot_class(axis=_ax11, measurement_class=meas_data, alpha=0.2) # _ax11 = plot_cluster_collection(axis=_ax11, data=labeled_collection) min_q = min(labeled_collection.q_dict.keys()) mode_sequence_range = range(min_q, max(labeled_collection.q_dict.keys()) + 2) for i in mode_sequence_range: try: cluster_array, value_slice = labeled_collection.get_mode_sequence( long_mode=i) # Get normalized measurement x_sample, y_measure = labeled_collection.get_measurement_data_slice( union_slice=value_slice) _ax11.plot( x_sample, y_measure, alpha=.2, color=colors[(cluster_array[0].get_longitudinal_mode_id - min_q) % len(colors)]) except AttributeError: print(i, f'break out of mode sequence') break for cluster in labeled_collection.get_clusters: if cluster.get_transverse_mode_id == 0: plt.gca().set_prop_cycle(None) for peak_data in cluster: if peak_data.relevant: _ax11.plot( peak_data.get_x, peak_data.get_y, 'x', color=colors[(peak_data.get_transverse_mode_id - min_q) % len(colors)], alpha=1) _ax11.text( x=cluster.get_avg_x, y=cluster.get_max_y, s= f'({cluster.get_longitudinal_mode_id}, {cluster.get_transverse_mode_id})', fontsize=10, horizontalalignment='center', verticalalignment='bottom') _ax11 = get_standard_axis(axis=_ax11) _ax11.set_xlabel('Cavity Length [nm]')
# collection_class = LabeledPeakCollection(identify_peaks(meas_data=data_class)) # # cluster_collection = collection_class.get_q_clusters # collection_class.get_clusters # piezo_response = fit_piezo_response(cluster_collection=cluster_collection, sample_wavelength=SAMPLE_WAVELENGTH) # piezo_response = fit_collection() # fit_variables = fit_calibration(voltage_array=data_class.samp_array, reference_transmission_array=import_npy(filename_base)[0], response_func=piezo_response) # print(f'TiSaph transmission: T = {1 - fit_variables[1]} (R = {fit_variables[1]})') # print(f'Cavity length delta between HeNe and TiSaph measurement: {fit_variables[2]} [nm]') for i in range(5): _filename = 'transrefl_hene_1s_10V_PMT4_rate1300000.0itteration{}'.format( i) data_class = FileToMeasData(meas_file=_filename, samp_file=file_samp, filepath='data/Trans/20210104') identified_peaks = identify_peaks(meas_data=data_class) collection_class = LabeledPeakCollection(identified_peaks) cluster_collection = collection_class.get_q_clusters # collection_class.get_clusters piezo_response = fit_piezo_response( cluster_collection=cluster_collection, sample_wavelength=SAMPLE_WAVELENGTH, verbose=True) # # Obtain mean and root-mean-square # y_values = [value for line in ax2.lines for value in line.get_ydata()] # y_mean = np.mean(y_values) # y_rms = np.sqrt(np.sum((y_values - y_mean)**2) / len(y_values)) # ax2.axhline(y=y_mean, ls='--', color='darkorange') # ax2.axhline(y=y_mean+y_rms, ls='--', color='orange', label=r'$\mu + \sigma$' + f': {round(y_mean+y_rms, 2)} [nm]') # ax2.axhline(y=y_mean-y_rms, ls='--', color='orange', label=r'$\mu - \sigma$' + f': {round(y_mean-y_rms, 2)} [nm]')
def get_polarized_comparison(filename_func: Callable[[int, int], Union[str, FileNotFoundError]], sample_file: str, long_mode: int, trans_mode: Union[int, None]): warnings.filterwarnings(action='once') height_data = [] diff_data = [] # Collect data polarization_iterator = range(0, 19) for polarization in tqdm(polarization_iterator, desc=f'Collecting data over polarization sweep'): _filenames = [] for iteration in range(0, 10): try: _filename = filename_func(iteration, polarization) except FileNotFoundError: break # Breaks out of the inner for-loop # Successfully retrieved file name _filenames.append(_filename) # Time for processing into normalized collection _meas_iterations = [ get_converted_measurement_data( FileToMeasData(meas_file=file_meas, samp_file=sample_file)) for file_meas in _filenames ] # get_converted_measurement_data _identified_peaks = [ identify_peaks(meas_data=data) for data in _meas_iterations ] # Temp solution # _norm_peaks = [NormalizedPeakCollection(optical_mode_collection=collection) for collection in _identified_peaks] _norm_peaks = [] for collection in _identified_peaks: try: normalaized_data = NormalizedPeakCollection( transmission_peak_collection=collection) except IndexError: # Sneaky catch for improper normalization (self._get_data_class) print(f'Skipped data') continue _norm_peaks.append(normalaized_data) # Process peak data # expected_number_of_peaks = 4 # Temp _mean_std_height_array = list( get_peak_height(collection_classes=_norm_peaks, long_mode=long_mode, trans_mode=trans_mode)) _mean_std_diff_array = list( get_peak_differences(collection_classes=_norm_peaks, long_mode=long_mode, trans_mode=trans_mode)) for i, (mean, std) in enumerate(_mean_std_height_array): print( f'\nPeak height {i}: mean = {round(mean, 4)}[Transmission], std = {round(std, 4)}[Transmission]' ) for i, (mean, std) in enumerate(_mean_std_diff_array): print( f'Peak difference {i}-{i + 1}: mean = {round(mean, 4)}[nm], std = {round(std, 4)}[nm]' ) # Collect data height_data.append(_mean_std_height_array) diff_data.append(_mean_std_diff_array) def get_match_index( value_array: List[float]) -> Callable[[float], List[int]]: _look_up = [] for i in range(len(value_array)): for j in range(1, 2): # len(value_array) - i + 1 _look_up.append((np.sum(np.nan_to_num(value_array[i:(i + j)])), list(range(i, i + j)))) def match_func(value_input: float) -> List[int]: look_up_array = np.array([value for value, indices in _look_up]) index = min( range(len(look_up_array)), key=lambda k: abs(look_up_array[k] - value_input) ) # find_nearest_index(array=look_up_array, value=value_input) # print(f'Compare {value_input} to:\n{_look_up}\nFinds index {index}, corresponding to {_look_up[index]}') return _look_up[index][1] return match_func def get_iterator_on_max_elements(data: List[Any], correct_len: int) -> List[int]: _iterator = list(range(len(data))) for i in _iterator: if len(data[i]) == correct_len: start = _iterator[i:] end = _iterator[0:i] _iterator = start _iterator.extend(end) break return _iterator def estimate_missing_height_data( height_data: List[List[Tuple[float, float]]], diff_data: List[List[Tuple[float, float]]] ) -> Tuple[List[List[Tuple[float, float]]], List[List[Tuple[float, float]]]]: """ Handles undetected peaks throughout data. Expects data format: List[ Polarization(0): List[ Peak(0): Tuple[ height_mean, height_std ] Peak(1): ... ] Polarization(1): ... ] The number of peaks per polarization (averaged over multiple iterations) can vary from polarization to polarization. Either through peak degeneracy or undetectability. Solution approach: - establish the max frequency number of peaks - use peak-difference data to establish missing peak indices """ # Step 1 max_peak_freq = int( max_frequent([len(polar_group) for polar_group in height_data ])) # Max number of consistent peaks found max_diff_freq = int( max_frequent([ len(polar_group) for polar_group in diff_data ])) # Max number of consistent peaks differences found # Step 2 missing_diff_data = [] # Define data iterator to correct missing data diff_iterator = get_iterator_on_max_elements( data=diff_data, correct_len=max_diff_freq) # list(range(len(diff_data))) for i, iter_index in enumerate(diff_iterator): if len(diff_data[iter_index]) != max_diff_freq: if len(diff_data[diff_iterator[i - 1]]) == max_diff_freq: # Normal execution logic corresponding_index_func = get_match_index(value_array=[ mean for mean, std in diff_data[diff_iterator[i - 1]] ]) for j, (curr_mean, curr_std) in enumerate(diff_data[iter_index]): index_array = corresponding_index_func( curr_mean) # Retrieves the reference mean-indices for k in range(j, index_array[0]): diff_data[iter_index].insert(k, (np.nan, np.nan)) missing_diff_data.append((iter_index, k)) # if len(index_array) > 1: # One or both bounding peaks are missing # for k in index_array[1:]: # diff_data[i].insert(k, (np.nan, np.nan)) # missing_diff_data.append((i, k)) else: # Problem # raise NotImplementedError? continue print(missing_diff_data) for (pol_index, list_index) in missing_diff_data: height_data[pol_index].insert(list_index, (0, np.nan)) return height_data, diff_data height_data, diff_data = estimate_missing_height_data( height_data=height_data, diff_data=diff_data) # Display data x = [i * 10 for i in polarization_iterator] height_array_mean_std = [ list(map(list, zip(*mean_std_list))) for mean_std_list in height_data ] # Polar[ Peaks[] ] y_height = list( map(list, zip(*[mean for (mean, std) in height_array_mean_std]))) y_height_err = list( map(list, zip(*[std for (mean, std) in height_array_mean_std]))) diff_array_mean_std = [ list(map(list, zip(*mean_std_list))) for mean_std_list in diff_data ] # Polar[ Peaks[] ] y_diff = list( map(list, zip(*[mean for (mean, std) in diff_array_mean_std]))) y_diff_err = list( map(list, zip(*[std for (mean, std) in diff_array_mean_std]))) # Define plot fig, (ax0, ax1) = plt.subplots(2, 1) for i in range(len(y_height)): ax0.errorbar(x=x, y=y_height[i], yerr=y_height_err[i], fmt='', label=f'Peak ({i})') for i in range(len(y_diff)): ax1.errorbar(x=x, y=y_diff[i], yerr=y_diff_err[i], fmt='', label=f'Peak ({i})-to-({i+1})') # Set labels fig.suptitle( f'Peak relations focused on (q={long_mode}, m+n={trans_mode})\n(peak labeling: min-max resonance distance)' ) ax0.set_xlabel('Polarization [Degrees]') ax0.set_ylabel('Transmission [a.u.]') # ax0.set_yscale('log') ax0.grid(True) ax0.legend(bbox_to_anchor=(1.01, 1), loc='upper left') ax1.set_xlabel('Polarization [Degrees]') ax1.set_ylabel('Peak Distance [nm]') # ax1.set_yscale('log') ax1.grid(True) ax1.legend(bbox_to_anchor=(1.01, 1), loc='upper left')