def simulate_and_compare(varparams, varparamkeys, system, data_arrays, to, light, powers=None, which='pulse', irf_args={'fwhm': 55 * ps}, N_coarse=500, roll_value=0, comparison='linear', absolute=True, limits=None, norm=True, roll_criterion='max', maxavgnum=10, condensed_output=True, verbose=False): """ Returns an array or list of arrays of differences between a set of simulated data and a set of experimental data, after aligning them. The parameters and output of this functions are eventually to be passed to an optimization function such as ``scipy.optimize.least_sqares``. Parameters ---------- varparams : list Rate equation parameters or other simulation parameters that determine the output of `system`. It does not need to be the comprehensive list of parameters that define the system, simply the parameters with respect to which the system output is to be optimized. varparams must have been obtained as list(dictionary.keys()) of the same dictionary that varparamkeys are extracted. varparamkeys : dictionary keys Names of varied parameters. system : object A system object to which `params` are passed, which contains a function that can output an array of PL signals. The system object needs to have been created previously in the code with dummy or guess parameters. It is then redefined with different parameters every time the ``simulate_and_compare`` function is called. data_list : array or list of 1D arrays Array or list of 1D arrays containing experimental data to be compared to the simulation. The output of ``system.PLsig`` must have the same shape as `data_list`. to : dictionary Dictionary with time parameters. light : object Excitation object that determines simulation powers : dictionary List of powers at which experiment is conducted, in SI units which : string, 'pulse' or 'cw' whether the varied powers represent the pulsed or CW laser irf_args: float, optional Arguments for constructing the Instrument Response Function used for convolution. See ``convolve_irf`` function. N_coarse : integer N_coarse parameter of refined_simulation function. roll_value : float, optional Value on ``to['array']`` to which maxima of aligned arrays will be shifted to. comparison : 'linear' or 'log' see ``elementwise_diff`` function. Default is linear. absolute : boolean, optional see ``elementwise_diff`` function. Default is False. limits : list of 2 values, optional lower and upper limit on time axis for which fitting is desired. Default is None (whole time axis fitted). norm : Boolean Determines whether each data/simulation transient should be normalized with respect to itself. If false, all simulation and data traces are normalized by the simulation and data trace corresponding to the highest power, respectively. roll_criterion : string, 'steep' or 'max' Determines whether the alignment of the two arrays happens by their maximum or their steepest point. Default is 'max' maxavgnum : integer If `roll_criterion` is `"max"`, maxavgnum determines the `avgnum` keyword in ``KinetiKit.kit.align_by_max().`` verbose : boolean Whether to print the cost function at the end of each iteration. Returns ------- diffs : array or list of 1D arrays Array(s) of the differences or relative differences between the passed experimental data and simulation array(s). al_data_list : array or list of 1D arrays Aligned data arrays. al_sim_list : array or list of 1D arrays Aligned simulation arrays. """ param_dict = kin_kit.dict_from_list(varparams, varparamkeys) system.update(**param_dict) # print(system.params()) if light is not None: pulse = light.pulse dtime = to['array'][::to['subsample']] global counter if counter % settings['display_counter_every'] == 0: if settings['display_counter']: print(counter) counter += 1 if system.populations is None: pl, converged = sim.lib.simulate_func(system, dtime) sim_arrays = sim.lib.convolve_irf(pl, dtime, irf_args) else: if powers is None: transient, converged = sim.lib.refined_simulation( system, to, light, N_coarse=N_coarse) pl = system.PLsig(transient) sim_arrays = sim.lib.convolve_irf(pl, dtime, irf_args) #sim_arrays /= max(sim_arrays) #data_arrays /= max(data_arrays) else: for i, power in enumerate(powers): if which == 'pulse': light = light.updated_with(pulse={'power': power}) elif which == 'cw': light = light.updated_with(cw={'power': power}) else: print('parameter "which" should be "pulse" or "cw".') transient, converged = sim.lib.refined_simulation( system, to, light, N_coarse=N_coarse) pl_at_this_power = system.PLsig(transient) if i == 0: pl = pl_at_this_power else: pl = np.vstack((pl, pl_at_this_power)) sim_arrays = sim.lib.convolve_irf(pl, dtime, irf_args) if roll_criterion == 'max': al_data_arrays = kin_kit.align_by_max(data_arrays, dtime, avgnum=maxavgnum, value=roll_value) al_sim_arrays = kin_kit.align_by_max(sim_arrays, dtime, avgnum=maxavgnum, value=roll_value) elif roll_criterion == 'steep': al_data_arrays = kin_kit.align_by_steep(data_arrays, dtime, avgnum=maxavgnum, value=roll_value) al_sim_arrays = kin_kit.align_by_steep(sim_arrays, dtime, avgnum=maxavgnum, value=roll_value) else: print('Roll_criterion must be max or steep.') sim_arrays = kin_kit.make_2d(sim_arrays) data_arrays = kin_kit.make_2d(data_arrays) if not norm: # divide all traces by maximum value of highest-power trace sim_arrays /= max(sim_arrays[np.argmax(powers)]) data_arrays /= max(data_arrays[np.argmax(powers)]) if limits is not None: al_data_arrays = slice_by_time(al_data_arrays, dtime, limits[0], limits[1]) al_sim_arrays = slice_by_time(al_sim_arrays, dtime, limits[0], limits[1]) diffs = elementwise_diff(al_data_arrays, al_sim_arrays, norm=norm, comparison=comparison, absolute=absolute) #print("diff : %0.3e"%(np.sum(diffs**2)/(to['N']/to['subsample']))) if condensed_output: if verbose: print(np.average(np.sum(diffs**2))) return np.sum(diffs**2) else: if verbose: print(np.average(diffs.flatten())) return diffs.flatten()
system = sim.systems.Biexp() #--- Parameters of simulation and initializing of system params = { 'A1': 1.9974e-1, 'tau1': 1.774e-9, 'tau2': 1e-10, 'offset': 0, } system.update(**params) pl, converged = sim.lib.simulate_func(system, dtime) sims = sim.lib.convolve_irf(pl, dtime, fwhm=40 * ps) # Aligns simulation aligned_sims = kin_kit.align_by_steep(sims, dtime, value=0.5 * ns) #--- Plot art.plot3scales.plot(dtime, aligned_sims, system, t_dict=to, ivtype='none', annotate=True, fig=None, ResetColorCyc=True, linewidth=6, opaq=0.4, mlabel='biexp sim')
sims = sim.lib.convolve_irf(pl, dtime, irf_args) # PL signal convolved with IRF # alignment if roll_criterion == 'max': aligned_data = kin_kit.align_by_max(all_y, dtime, value=align_to, avgnum=avgnum) aligned_sims = kin_kit.align_by_max(sims, dtime, value=align_to, avgnum=avgnum) elif roll_criterion == 'steep': aligned_data = kin_kit.align_by_steep(all_y, dtime, value=align_to, avgnum=avgnum) aligned_sims = kin_kit.align_by_steep(sims, dtime, value=align_to, avgnum=avgnum) #--- Plot fig = None for i in range(len(aligned_data)): color = ['#E24A33', '#348ABD'][i] fig = artists.plot3scales.plot(dtime, aligned_data[i], sys_obj=None, t_dict=None, annotate=False,
def FuncViz(system, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, to=sim.time.linear(), N_coarse=500, power=1e-6, irf_args={}, data=None, power_list=[1], power_unit='microWatt', align_by='steep', avgnum=5, slidepower=False, xmin=0.1, xmax=None, ymin=1e-3, ymax=1.2): args = p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14,\ p15, p16, p17, p18, p19, p20, param_names = system.params().keys() trunc_args = args[:len(list(param_names))] params = kin_kit.dict_from_list(trunc_args, param_names) system.update( **params ) # system is updated according to the parameters provided as *args #--- Creating Time Array dtime = to['array'][::to['subsample']] pl = system.PLsig(dtime) sims = sim.lib.convolve_irf(pl, dtime, irf_args) # Aligns data with sim either by max. or steep if align_by == 'steep': aligned_sims = kin_kit.align_by_steep(sims, dtime, value=0.5 * ns, avgnum=avgnum) elif align_by == 'max': aligned_sims = kin_kit.align_by_max(sims, dtime, value=0.5 * ns, avgnum=avgnum) else: print('\'align_by\' must be \'steep\' or \'max\'') aligned_sims = kin_kit.make_2d(aligned_sims) fig = None data_ended = False sims_ended = False for i in range(20): if data is None: pass else: data = kin_kit.make_2d(data) try: d = data[i] fig = art.plot3scales.plot(dtime, d, sys_obj=None, t_dict=None, annotate=False, fig=fig, linewidth=1, color=color_range[i], mlabel='data_%0.3f' % (power_list[i]), xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax) except IndexError: data_ended = True pass try: aligned_sim = aligned_sims[i] art.plot3scales.plot(dtime, aligned_sim, system, t_dict=to, ivtype='none', annotate=True, fig=fig, ResetColorCyc=i == 0, color=color_range[i], linewidth=8, opaq=0.4, mlabel='sim_%0.3f' % (power_list[i]), xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax) except IndexError: sims_ended = True pass if sims_ended and data_ended: break return
def MultiPowerViz(system, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, to=sim.time.linear(), refined=True, N_coarse=500, pulse_power=1, cw_power=0, which=None, irf_args={'fwhm': 55 * ps}, data=None, ids=['one', 'two'], power_unit='microWatt', light=sim.lib.Excitation(), align_by='steep', avgnum=5, xmin=0.1, xmax=None, ymin=1e-3, ymax=1.2): """ more functionality to allow for CW and pulsed power variations """ args = p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14,\ p15, p16, p17, p18, p19, p20, param_names = system.params().keys() trunc_args = args[:len(list(param_names))] params = kin_kit.dict_from_list(trunc_args, param_names) system.update( **params ) # system is updated according to the parameters provided as *args #--- Creating Time Array dtime = to['array'][::to['subsample']] if which is None: pulse_power *= units[power_unit] cw_power *= units[power_unit] light = light.updated_with(pulse={'power': pulse_power}, cw={'power': cw_power}) if refined: transient, converged = sim.lib.refined_simulation( system, to, light, N_coarse=N_coarse) else: transient, converged = sim.lib.simulate_until_steady( system, to, light) pl = kin_kit.make_2d(system.PLsig(transient)) sims = sim.lib.convolve_irf(pl, dtime, args=irf_args) # Aligns data with sim either by max. or steep if align_by == 'steep': aligned_sims = kin_kit.align_by_steep(sims, dtime, value=0.5 * ns, avgnum=avgnum) elif align_by == 'max': aligned_sims = kin_kit.align_by_max(sims, dtime, value=0.5 * ns, avgnum=avgnum) else: print('\'align_by\' must be \'steep\' or \'max\'') aligned_sims = kin_kit.make_2d(aligned_sims) fig = None data_ended = False sims_ended = False for i in range(20): if data is None: pass else: data = kin_kit.make_2d(data) try: d = data[i] fig = art.plot3scales.plot(dtime, d, sys_obj=None, t_dict=None, annotate=False, fig=fig, linewidth=1, color=color_range[i], mlabel='data_%s' % (ids[i]), xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax) except IndexError: data_ended = True pass try: aligned_sim = aligned_sims[i] art.plot3scales.plot(dtime, aligned_sim, system, t_dict=to, ivtype='none', annotate=True, fig=fig, ResetColorCyc=i == 0, color=color_range[i], linewidth=8, opaq=0.4, mlabel='sim_%s' % (ids[i]), xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax) except IndexError: sims_ended = True pass if sims_ended and data_ended: break return else: fig = None data_ended = False for i in range(20): if data is None: pass else: data = kin_kit.make_2d(data) try: d = data[i] fig = art.plot3scales.plot(dtime, d, sys_obj=None, t_dict=None, annotate=False, fig=fig, linewidth=1, color=color_range[i], mlabel='data_%s' % (ids[i]), xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax) except IndexError: data_ended = True pass if data_ended: break if which == 'pulse': var_power = np.array(pulse_power) * units[power_unit] set_power = cw_power * units[power_unit] if which == 'cw': var_power = np.array(cw_power) * units[power_unit] set_power = pulse_power * units[power_unit] for p, power in enumerate(var_power): if which == 'pulse': light = light.updated_with(pulse={'power': power}, cw={'power': set_power}) elif which == 'cw': light = light.updated_with(pulse={'power': set_power}, cw={'power': power}) else: print(' "which" should be "cw" or "pulse" ') #print('cw_power ', light.cw_power) if refined: transient, converged = sim.lib.refined_simulation( system, to, light, N_coarse=N_coarse) else: transient, converged = sim.lib.simulate_until_steady( system, to, light) pl = system.PLsig(transient) sims = sim.lib.convolve_irf(pl, dtime, args=irf_args) # Aligns data with sim either by max. or steep if align_by == 'steep': aligned_sims = kin_kit.align_by_steep(sims, dtime, value=0.5 * ns, avgnum=avgnum) elif align_by == 'max': aligned_sims = kin_kit.align_by_max(sims, dtime, value=0.5 * ns, avgnum=avgnum) else: print('\'align_by\' must be \'steep\' or \'max\'') art.plot3scales.plot(dtime, aligned_sims, system, t_dict=to, ivtype='none', annotate=True, fig=fig, ResetColorCyc=i == 0, color=color_range[p], linewidth=8, opaq=0.4, mlabel='sim_%s' % (ids[p]), xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax) return
def MonoViz(system, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, to=sim.time.linear(), N_coarse=500, pulse_power=1e-6, irf_args={}, data=None, power_unit='microWatt', light=sim.lib.Excitation(), align_by='steep', avgnum=5, xmin=0.1, xmax=None, ymin=1e-3, ymax=1.2): args = p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14,\ p15, p16, p17, p18, p19, p20, param_names = system.params().keys() trunc_args = args[:len(list(param_names))] params = kin_kit.dict_from_list(trunc_args, param_names) system.update( **params ) # system is updated according to the parameters provided as *args #--- Creating Time Array dtime = to['array'][::to['subsample']] if isinstance(pulse_power, np.float) or isinstance(pulse_power, np.int): power_list = [pulse_power] pulse_power *= units[power_unit] light = light.updated_with(pulse={'power': pulse_power}) transient, converged = sim.lib.refined_simulation(system, to, light, N_coarse=N_coarse) pl = system.PLsig(transient) elif isinstance(pulse_power, list): print('list') power_list = pulse_power for i, power in enumerate(power_list): power *= units[power_unit] light = light.updated_with(pulse={'power': power}) transient, converged = sim.lib.refined_simulation( system, to, light, N_coarse=N_coarse) pl_at_this_power = system.PLsig(transient) if i == 0: pl = pl_at_this_power else: pl = np.vstack((pl, pl_at_this_power)) sims = sim.lib.convolve_irf(pl, dtime, irf_args) # Aligns data with sim either by max. or steep if align_by == 'steep': aligned_sims = kin_kit.align_by_steep(sims, dtime, value=0.5 * ns, avgnum=avgnum) elif align_by == 'max': aligned_sims = kin_kit.align_by_max(sims, dtime, value=0.5 * ns, avgnum=avgnum) else: print('\'align_by\' must be \'steep\' or \'max\'') aligned_sims = kin_kit.make_2d(aligned_sims) fig = None data_ended = False sims_ended = False for i in range(20): if data is None: pass else: data = kin_kit.make_2d(data) try: d = data[i] fig = art.plot3scales.plot(dtime, d, sys_obj=None, t_dict=None, annotate=False, fig=fig, linewidth=1, color=color_range[i], mlabel='data_%0.3f' % (power_list[i]), xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax) except IndexError: data_ended = True pass try: aligned_sim = aligned_sims[i] art.plot3scales.plot(dtime, aligned_sim, system, t_dict=to, ivtype='none', annotate=True, fig=fig, ResetColorCyc=i == 0, color=color_range[i], linewidth=8, opaq=0.4, mlabel='sim_%0.3f' % (power_list[i]), xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax) except IndexError: sims_ended = True pass if sims_ended and data_ended: break return