data['odor_type'] = input("Enter Odor Type: ") data['seed'] = np.random.randint(0,1000000000) np.random.seed(data['seed']) if data['odor_type'] == 'reference': data['odor_vector'] = data['reference_odor'] print(np.dot(data['odor_vector'],data['reference_odor'])/np.linalg.norm(data['reference_odor'])/np.linalg.norm(data['odor_vector'])) data['odor_angle'] = np.rad2deg(np.arccos(np.clip(np.dot(data['odor_vector'],data['reference_odor'])/np.linalg.norm(data['reference_odor'])/np.linalg.norm(data['odor_vector']),-1,1))) elif data['odor_type'] == 'no_odor': data['odor_vector'] = np.zeros(data['dim_odorspace']) data['odor_angle'] = 0 elif data['odor_type'] == 'random': data['odor_vector'] = pt.generateUniform(data['odor_concentration'],dimension=data['dim_odorspace']) data['odor_angle'] = np.rad2deg(np.arccos(np.dot(data['odor_vector'],data['reference_odor'])/np.linalg.norm(data['reference_odor'])/np.linalg.norm(data['odor_vector']))) elif data['dim_odorspace'] == 2: data['odor_type'] = int(data['odor_type']) if np.random.normal() > 0: theta = np.deg2rad(data['odor_type']) else: theta = -np.deg2rad(data['odor_type']) c, s = np.cos(theta), np.sin(theta) R = np.array(((c,-s), (s, c))) data['odor_vector'] = np.matmul(R,data['reference_odor'].reshape(-1,1)).flatten() data['odor_angle'] = np.rad2deg(np.arccos(np.dot(data['odor_vector'],data['reference_odor'])/np.linalg.norm(data['reference_odor'])/np.linalg.norm(data['odor_vector']))) elif data['dim_odorspace'] == 3: data['odor_type'] = int(data['odor_type']) randVec = pt.generateUniform(1,dimension=data['dim_odorspace']) crossVec = np.cross(data['reference_odor'],randVec)
def generate_orn(orn_number, duration, resolution, odorVec, odorStart, odorEnd): # Function to generate single ORN Trace baseline = locust['baseline_firing'] * ( 1 + 0.2 * np.random.normal() ) / locust['peak_firing'] # Baseline Firing Rate Ratio trace = baseline * np.ones( int(duration / resolution)) # Set Baseline activity for the Protocol Duration rec_field = pt.generateUniform( 1, odor['dim_odorspace'], seed=int(locust['rec_seeds'] [orn_number])) # Receptive Field of ORNs in Odor Space latency = locust['latency'][ orn_number] # Latency of Response to Odor Presentation t_rise = locust['t_rise'][orn_number] # Time to Rise to Peak t_fall = locust['t_fall'][orn_number] # Response Decay Time tuning = locust['tuning'][orn_number] / 2 # Odor Tuning-width / Sensitivity def sigmoid(x, a1=locust['a1'], a2=locust['a2']): # Sigmoid for Response return 1 / (1 + np.exp(-a1 * (x - a2))) odorMag = 0.85 * np.linalg.norm(odorVec) # Odor Concentration cosSim = np.dot(odorVec, rec_field) / ( np.linalg.norm(odorVec) * np.linalg.norm(rec_field) ) # Cosine Similarity wrt Odor if np.arccos(cosSim) < np.deg2rad( locust['inh_threshold']): # Minimum Response Threshhold res_strength = (1 - baseline) * sigmoid( odorMag * np.cos(np.arccos(cosSim) / 2)**tuning) else: res_strength = -baseline * np.linalg.norm(odorVec) if locust['f_sharp'][orn_number]: # Generate Sharp Trace rise = np.arange(0, t_rise / 2, resolution) rise = baseline + res_strength * 2 * np.exp( 1) / t_rise * rise * np.exp(-2 * rise / t_rise) riseStartIndex = int((odorStart + latency) / resolution) riseEndIndex = riseStartIndex + rise.shape[0] trace[riseStartIndex:riseEndIndex] = rise peak = rise[-1] fall = np.linspace(0, duration - riseEndIndex * resolution, trace.shape[0] - riseEndIndex) fall = (peak - baseline) * np.exp(-fall / t_fall) + baseline fallStartIndex = riseEndIndex trace[fallStartIndex:] = fall else: # Generate Broad Trace rise = np.arange(0, t_rise, resolution) rise = baseline + res_strength * np.exp(1) / t_rise * rise * np.exp( -rise / t_rise) riseStartIndex = int((odorStart + latency) / resolution) riseEndIndex = int((odorStart + latency) / resolution) + rise.shape[0] trace[riseStartIndex:riseEndIndex] = rise peak_1 = rise[-1] adaptation_rate = locust['adaptation_extent'][ orn_number] # Amplitude of Adaptation-related Decay t_adaptation = locust['t_adaptation'][ orn_number] # Odor Adaptation Time adaptation = np.arange(0, (int(odorEnd / resolution) - riseEndIndex) * resolution, resolution) adaptation = (peak_1 - (adaptation_rate * res_strength + baseline)) * np.exp( -adaptation / t_adaptation) + ( adaptation_rate * res_strength + baseline) adaptationStartIndex = riseEndIndex adaptationEndIndex = adaptationStartIndex + adaptation.shape[0] trace[adaptationStartIndex:adaptationEndIndex] = adaptation peak_2 = adaptation[-1] fall = np.arange(0, (trace.shape[0] - adaptationEndIndex) * resolution, resolution) fall = (peak_2 - baseline) * np.exp(-fall / t_fall) + baseline fallStartIndex = adaptationEndIndex trace[fallStartIndex:] = fall trace = trace * locust['peak_firing'] * 5 # Scale to Peak Firing Rate return trace