def checkmissing(itemlist, listname, field, identifybyfield): missing = set() for record in itemlist: if field not in record: missing.add(record[identifybyfield]) if missing: warn(listname, f"missing {field} for: {', '.join(sorted(missing))}")
def run(conf_path, output_path, definitions): try: print "configuring" if conf_path is not None: conf = cfg.load_conf(params.__dict__, conf_path) params.__dict__.update(conf) if definitions is not None: cfg.update_conf(params.__dict__, params.__dict__, definitions) if params.verbose: print "verbose output enabled" if params.lower_process_priority: if params.verbose: print "reducing process priority" warning = svc.reduce_process_priority() if warning: output.warn(warning) if params.graphs: if not output_path: raise InvocationError("no output directory") output_path = os.path.normpath(output_path) if params.verbose: print "graphs will be written to:", output_path output.output_dir = output_path print "validating" cfg.validate() with mp.TaskPool(params.num_tasks, params.extended_mode, params.__dict__) as task_pool: print "executing" if params.verbose: print "number of parallel tasks:", task_pool.num_tasks start_time = time.time() execute(task_pool) end_time = time.time() elapsed_time = end_time - start_time print output.div_line print "done" if params.verbose: print "finished in %.2f s" % elapsed_time except (cfg.ConfigurationError, core.ComputationError, model.exc.ModelError) as exc: output.print_error(str(exc)) sys.exit(1) except MemoryError: output.print_error("out of memory") sys.exit(1) except: if not debug_mode: output.print_exception() sys.exit(1) else: raise
def compute_inversion(dirname): print output.div_line print "computing population inversion" active_medium = create_medium(None) pump_system = model.pump.PumpSystem(params.pump_wavelen, params.pump_duration, params.pump_power, params.pump_efficiency) depop_model = create_depop_model(active_medium, params.depop_model_class) inv = params.inverter_class(active_medium, pump_system, depop_model) ref_inversion = inv.invert(params.inversion_rtol, params.inversion_min_count_t) rate_evals = (len(inv.inversion) - 1) * inv.evals_per_step pump_energy = params.pump_duration * params.pump_power stored_energy = model.energy.energy(params.lasing_wavelen, ref_inversion * active_medium.volume) if params.verbose: print "count_t:", len(inv.T) print "depopulation rate evaluation count:", rate_evals if params.inversion_validate: print "validating uniform ASE-induced depopulation rate approximation" ross_num_model = depop_model if isinstance(depop_model, model.depop.RossNumericalASEModel) else model.depop.RossNumericalASEModel(active_medium, params.depop_rate_rtol, params.depop_rate_min_samples) rate_rel_stddev = ross_num_model.rate_rel_stddev(ref_inversion) unitconv.print_result("depopulation rate rel. std. deviation [{}]: {}", ("%",), (rate_rel_stddev,)) if rate_rel_stddev > 10.0e-2: output.warn("uniform ASE-induced depopulation rate approximation is invalid") if isinstance(depop_model, model.depop.NumericalDepopulationModel): print "perturbing population inversion" perturb_depop_model = model.depop.PerturbedDepopulationModel(depop_model) perturb_inv = params.inverter_class(active_medium, pump_system, perturb_depop_model) perturb_ref_inversion = perturb_inv.invert(params.inversion_rtol, params.inversion_min_count_t) rel_error = model.error.perturbed_inversion_rel_error(ref_inversion, perturb_ref_inversion, params.inversion_rtol) else: rel_error = params.inversion_rtol gain_coef = ref_inversion * active_medium.doping_agent.xsection gain = math.exp(gain_coef * active_medium.length) ref_inversion_atol = ref_inversion * rel_error gain_atol = gain * (math.exp(ref_inversion_atol * active_medium.doping_agent.xsection * active_medium.length) - 1.0) stored_energy_atol = stored_energy * rel_error unitconv.print_result("pump energy [{}]: {}", ("mJ",), (pump_energy,)) unitconv.print_result("population inversion [{}]: {} ~ {}", ("cm^-3",), (ref_inversion, ref_inversion_atol)) unitconv.print_result("small signal gain: {} ~ {}", (), (gain, gain_atol)) unitconv.print_result("stored energy [{}]: {} ~ {}", ("mJ",), (stored_energy, stored_energy_atol)) if params.graphs: print output.status_writing dirname = output.init_dir(dirname) output.plot_inversion(dirname, inv) return ref_inversion, rel_error
def validate(): def validate_param_bounds(name, value): vtype = type(value) if vtype in (int, float): if vtype is float and name not in param_nan_allowed: if math.isnan(value): raise ConfigurationError("parameter \"%s\" has (or contains) an not-a-number value" % name) if vtype is float and name not in param_zero_allowed: if value <= 0.0: raise ConfigurationError("parameter \"%s\" has (or contains) a non-positive value" % name) elif value < 0.0: raise ConfigurationError("parameter \"%s\" has (or contains) a negative value" % name) if vtype is float and name not in param_infty_allowed: if math.isinf(value): raise ConfigurationError("parameter \"%s\" has (or contains) an infinite value" % name) if name in param_bounds: min_value, max_value = param_bounds[name] if min_value is not None: if value < min_value: raise ConfigurationError("parameter \"%s\" has (or contains) a value less than %s" % (name, min_value)) if max_value is not None: if value > max_value: raise ConfigurationError("parameter \"%s\" has (or contains) a value greater than %s" % (name, max_value)) elif vtype in (tuple, list): for element in value: validate_param_bounds(name, element) def validate_interval(name, values): if values[0] >= values[1]: raise ConfigurationError("parameter \"%s\" has an upper bound not greater than its lower bound" % name) def validate_list_uniques(name, values): if len(values) != len(set(values)): raise ConfigurationError("parameter \"%s\" contains duplicate values" % name) param_nan_allowed = set([ ]) param_zero_allowed = set([ "dopant_branching_ratio", "dopant_lower_lifetime", "initial_inversion", ]) param_infty_allowed = set([ "dopant_upper_lifetime", "dopant_lower_lifetime", "ext_opt_inversion_rdiff_max", "ext_opt_fluence_max", ]) param_bounds = { "train_pulse_count": (1, None), "depop_rate_min_samples": (16, None), "out_num_markers": (1, None), "out_count_rho": (1, None), "out_count_phi": (1, None), "out_count_z": (1, None), "out_count_t": (1, None), "ext_opt_pump_resolution": (1, None), "ext_opt_geom_resolution": (1, None), "dopant_branching_ratio": (None, 1.0), "pump_efficiency": (None, 1.0), } param_intervals = set([ "ext_opt_pump_duration", "ext_opt_pump_power", "ext_opt_geom_mediumradius", "ext_opt_geom_beamradius", ]) conf = copy_conf(params.__dict__) for parameter, value in conf.items(): validate_param_bounds(parameter, value) for parameter in param_intervals: values = conf[parameter] validate_interval(parameter, values) active_medium = core.create_medium(None) input_beam = core.create_beam() ref_pulse = core.create_pulse(active_medium, input_beam, input_beam.rho_ref, input_beam.phi_ref) if not (params.pump_wavelen < params.lasing_wavelen or params.initial_inversion): output.warn("pump wavelength is not less than lasing wavelength") if not (params.dopant_lower_lifetime <= params.dopant_upper_lifetime / 10.0 or params.initial_inversion): output.warn("approximation validity condition violated: lower state lifetime is not much shorter than upper state (fluorescence) lifetime") transit_time = active_medium.length / active_medium.light_speed if not (transit_time <= params.dopant_upper_lifetime / 10.0): output.warn("approximation validity condition violated: amplifier transit time is not much shorter than upper state (fluorescence) lifetime") train_duration = params.pulse_duration + (params.train_pulse_count - 1) * params.train_pulse_period if not (train_duration <= params.dopant_upper_lifetime / 10.0 or not params.amplification): output.warn("approximation validity condition violated: signal duration is not much shorter than upper state (fluorescence) lifetime") if not (params.train_pulse_period >= ref_pulse.duration or params.train_pulse_count == 1 or not params.amplification): raise ConfigurationError("invalid parameters: pulse repetition period is less than (extended) pulse duration")
def extraneousfields(itemlist, listname, knownfields): for record in itemlist: for key in record: if key not in knownfields: warn(listname, f"found extraneous field '{key}', typo?")