def test_gaussian_distribution(): """Check that the Gaussian generator samples resemble the distribution.""" n_samples = 10000 mean = 2 * units("m") var = 1 * units("m") gen = opt.dist.Gaussian(mean, var) samples = [gen.draw() for i in range(n_samples)] check_samples_match(samples, avg=mean, var=var, rtol=0.05)
def test_uniform_distribution(): """Check that the uniform generator samples resemble the distribution.""" n_samples = 10000 limit = 5 * units("m") gen = opt.dist.Uniform(-limit, limit) true_avg = 0 * units("m") true_var = limit * limit / 3 samples = [gen.draw() for i in range(n_samples)] check_samples_match(samples, min=-limit, max=limit, avg=true_avg, var=true_var, rtol=0.05, atol=0.1)
def test_sensitivity_running(): """Check that the results are as expected for a simple model.""" doubler = Doubler() limit = 5 * units("dimensionless") sa = opt.SensitivityAnalyser(doubler) sa.add_variable(gen=opt.dist.Uniform(-limit, limit), component=opt.sel.facility(), collection="inputs", item="x") sa.add_output("y", component=opt.sel.facility(), item="y") sa.parameters["numberOfSamples"] = 1000 sa.run() output = sa.outputs["y"] # From properties of uniform distribution: Min and max should be twice that # of the input; mean should be the same (0), variance 4 times as much. # Note that checks are quite tolerant, as we are unlikely to get exact # matches without more samples. # Also note that assert_allclose does not do any unit conversion, but seems # to just consider the magnitude. This is not a problem here as the spec is # dimensioness, but it's worth keeping in mind if the tests change! assert_allclose(output["min"], -2 * limit, rtol=0.1) assert_allclose(output["max"], 2 * limit, rtol=0.1) # This test uses absolute tolerance because the target value is 0, # and relative tolerance is therefore meaningless # TODO better to switch target and actual values around? assert_allclose(output["avg"], 0, atol=0.5) input_var = limit * limit / 3 # var = (max-min)^2 / 12 = 4 * limit^2 / 12 assert_allclose(output["var"], 4 * input_var, rtol=0.1)
def test_triangular_distribution(): """Check that the triangular generator samples resemble the distribution.""" n_samples = 10000 min = 1 * units("m") max = 5 * units("m") gen = opt.dist.Triangular(min, max) true_avg = (min + max) / 2 # Variance of triangular distribution with (min, max, mode) = (a, b, c) is: # (a^2 + b^2 + c^2 - a*b - a*c -b*c) / 18 # which for symmetric distributions reduces to: true_var = (min - max)**2 / 24 samples = [gen.draw() for i in range(n_samples)] check_samples_match(samples, min=min, max=max, avg=true_avg, var=true_var, rtol=0.05)
def test_units(): spec = { 'dless': Q('dimensionless', ''), 'count': Q('count', ''), 'metre': Q('metre', ''), 'm_per_s': Q('m / s', ''), 'money': Q('GBP', '') } d = SpecifiedDict(spec, 'test') d['dless'] = units.Quantity(1) assert d['dless'].magnitude == 1 assert d['dless'].units == units.dimensionless d['count'] = 2 assert d['count'] == 2 assert d['count'] == 2 * units.count assert d['count'].units == units.count d['count'] = units('4') assert d['count'] == 4 d['metre'] = 3 * units.m assert d['metre'] == 3 * units.m d['metre'] = 3 * units.cm assert d['metre'].units == units.m assert d['metre'] == 0.03 * units.m d['metre'] = units('1 m') assert d['metre'] == 1 * units.m d['metre'] = units('2 * m') assert d['metre'] == 2 * units.m d['m_per_s'] = 4 * (units.m**2) / (units.m * units.s) assert d['m_per_s'] == 4 * units.m / units.s d['money'] = 5 * units.GBP assert d['money'] == 5 * units.GBP d['money'] = 5 * units.EUR assert d['money'] == 0.8 * 5 * units.GBP with raises(SpecificationViolatedError) as excinfo: d['metre'] = 2 excinfo.match( r'Invalid value provided for test metre: ' r'Number "2" provided but quantity with units meter required') with raises(SpecificationViolatedError) as excinfo: d['metre'] = 2 * units.s excinfo.match(r'Invalid value provided for test metre: ' r'Value "2 second" does not have units meter')
def load_data(file_name, folder=None, sections={'inputs', 'outputs'}): """Helper function used by the ref_data fixture, that tests can also call directly.""" if folder is None: # Default to the data folder adjacent to this file folder = data_dir() data_path = folder.join(file_name) with data_path.open() as f: data = yaml.safe_load(f) # Parse all entries as values with units, unless they're booleans! for section in sections: for key, value in data[section].items(): if isinstance(value, bool): data[section][key] = value else: data[section][key] = units(str(value)) return data
def test_minimise_variance(): """Check that minimising the variance of an output works as expected.""" target = 5 * units("dimensionless") # Set up the sensitivity analysis, which will not actually vary anything analyser = opt.SensitivityAnalyser(Fussy(target, 100)) analyser.add_output("y", component=opt.sel.facility(), item="y") analyser.parameters["numberOfSamples"] = 10 # Set up the optimiser to minimise the variance of the output optimiser = opt.Optimiser(analyser) optimiser.add_variable(gen=opt.gen.RangeGenerator(0 * target, 2 * target), component=opt.sel.facility(), item='p') optimiser.add_objective(component=opt.sel.self(), item=("y", "var"), minimise=True) optimiser.parameters["maxGenerations"] = 5 # Run combined optimisation + SA, and check we get the expected result optimiser.run() best = optimiser.outputs["bestIndividuals"][0] assert best.get_variable('Fussy', 'p').value == target