def test_multiscaler_update_for_minimisation(): """Test the multiscaler update_for_minimisation method.""" p, e = (generated_param(), generated_exp(2)) p.reflection_selection.method = "use_all" r1 = generated_refl(id_=0) r1["intensity.sum.value"] = r1["intensity"] r1["intensity.sum.variance"] = r1["variance"] r2 = generated_refl(id_=1) r2["intensity.sum.value"] = r2["intensity"] r2["intensity.sum.variance"] = r2["variance"] p.scaling_options.nproc = 2 p.model = "physical" exp = create_scaling_model(p, e, [r1, r2]) singlescaler1 = create_scaler(p, [exp[0]], [r1]) singlescaler2 = create_scaler(p, [exp[1]], [r2]) multiscaler = MultiScaler([singlescaler1, singlescaler2]) pmg = ScalingParameterManagerGenerator( multiscaler.active_scalers, ScalingTarget, multiscaler.params.scaling_refinery.refinement_order, ) multiscaler.single_scalers[0].components["scale"].parameters /= 2.0 multiscaler.single_scalers[1].components["scale"].parameters *= 1.5 apm = pmg.parameter_managers()[0] multiscaler.update_for_minimisation(apm, 0) multiscaler.update_for_minimisation(apm, 1) # bf[0], bf[1] should be list of scales and derivatives s1, d1 = RefinerCalculator.calculate_scales_and_derivatives( apm.apm_list[0], 0) s2, d2 = RefinerCalculator.calculate_scales_and_derivatives( apm.apm_list[1], 0) s3, d3 = RefinerCalculator.calculate_scales_and_derivatives( apm.apm_list[0], 1) s4, d4 = RefinerCalculator.calculate_scales_and_derivatives( apm.apm_list[1], 1) expected_scales_for_block_1 = s1 expected_scales_for_block_1.extend(s2) expected_scales_for_block_2 = s3 expected_scales_for_block_2.extend(s4) expected_derivatives_for_block_1 = sparse.matrix( expected_scales_for_block_1.size(), apm.n_active_params) expected_derivatives_for_block_2 = sparse.matrix( expected_scales_for_block_2.size(), apm.n_active_params) expected_derivatives_for_block_1.assign_block(d1, 0, 0) expected_derivatives_for_block_1.assign_block(d2, d1.n_rows, apm.apm_data[1]["start_idx"]) expected_derivatives_for_block_2.assign_block(d3, 0, 0) expected_derivatives_for_block_2.assign_block(d4, d3.n_rows, apm.apm_data[1]["start_idx"]) block_list = multiscaler.Ih_table.blocked_data_list assert block_list[0].inverse_scale_factors == expected_scales_for_block_1 assert block_list[1].inverse_scale_factors == expected_scales_for_block_2 assert block_list[1].derivatives == expected_derivatives_for_block_2 assert block_list[0].derivatives == expected_derivatives_for_block_1
def test_SingleScaler_update_for_minimisation(): """Test the update_for_minimisation method of the singlescaler.""" # test_params.scaling_options.nproc = 1 p, e, r = (generated_param(), generated_exp(), generated_refl_2()) exp = create_scaling_model(p, e, r) p.reflection_selection.method = "use_all" single_scaler = SingleScaler(p, exp[0], r) pmg = ScalingParameterManagerGenerator( single_scaler.active_scalers, ScalingTarget(), single_scaler.params.scaling_refinery.refinement_order, ) single_scaler.components["scale"].parameters /= 2.0 apm = pmg.parameter_managers()[0] Ih_table = single_scaler.Ih_table.blocked_data_list[0] Ih_table.calc_Ih() assert list(Ih_table.inverse_scale_factors) == [1.0, 1.0] assert list(Ih_table.Ih_values) == [10.0, 1.0] single_scaler.update_for_minimisation(apm, 0) # Should set new scale factors, and calculate Ih and weights. bf = RefinerCalculator.calculate_scales_and_derivatives(apm.apm_list[0], 0) assert list(Ih_table.inverse_scale_factors) == list(bf[0]) assert list(Ih_table.Ih_values) != [1.0, 10.0] assert list(Ih_table.Ih_values) == pytest.approx( list(Ih_table.intensities / bf[0])) for i in range(Ih_table.derivatives.n_rows): for j in range(Ih_table.derivatives.n_cols): assert Ih_table.derivatives[i, j] == pytest.approx(bf[1][i, j]) assert Ih_table.derivatives.non_zeroes == bf[1].non_zeroes
def test_RefinerCalculator(small_reflection_table): """Test for the RefinerCalculator class. This calculates scale factors and derivatives for reflections based on the model components.""" # To test the basis function, need a scaling active parameter manager - to set # this up we need a components dictionary with some reflection data. # Let's use KB model components for simplicity - and have an extra fake 'abs' # component. rt = small_reflection_table components = { "scale": SingleScaleFactor(flex.double([1.0])), "decay": SingleBScaleFactor(flex.double([0.0])), "abs": SingleScaleFactor(flex.double([1.0])), } # Create empty components. components["scale"].data = {"id": rt["id"]} components["decay"].data = {"d": rt["d"]} components["abs"].data = {"id": rt["id"]} for component in components.values(): component.update_reflection_data() # Add some data to components. apm = scaling_active_parameter_manager(components, ["decay", "scale"]) # First test that scale factors can be successfully updated. # Manually change the parameters in the apm. decay = components["decay"] # Define alias _ = components["scale"] # Define alias # Note, order of params in apm.x depends on order in scaling model components. new_B = 1.0 new_S = 2.0 apm.set_param_vals(flex.double([new_S, new_B])) s, d = RefinerCalculator.calculate_scales_and_derivatives(apm, 0) slist, dlist = RefinerCalculator._calc_component_scales_derivatives(apm, 0) # Now test that the inverse scale factor is correctly calculated. calculated_sfs = s assert list(calculated_sfs) == pytest.approx( list(new_S * flex.exp(new_B / (2.0 * flex.pow2(decay.d_values[0]))))) # Now check that the derivative matrix is correctly calculated. calc_derivs = d assert calc_derivs[0, 0] == dlist[0][0, 0] * slist[1][0] assert calc_derivs[1, 0] == dlist[0][1, 0] * slist[1][1] assert calc_derivs[2, 0] == dlist[0][2, 0] * slist[1][2] assert calc_derivs[0, 1] == dlist[1][0, 0] * slist[0][0] assert calc_derivs[1, 1] == dlist[1][1, 0] * slist[0][1] assert calc_derivs[2, 1] == dlist[1][2, 0] * slist[0][2] # Repeat the test when there is only one active parameter. # First reset the parameters components["decay"].parameters = flex.double([0.0]) components["scale"].parameters = flex.double([1.0]) components["abs"].parameters = flex.double([1.0]) components["decay"].calculate_scales_and_derivatives() components["scale"].calculate_scales_and_derivatives() components["abs"].calculate_scales_and_derivatives() # Now generate a parameter manager for a single component. apm = scaling_active_parameter_manager(components, ["scale"]) new_S = 2.0 apm.set_param_vals(flex.double(components["scale"].n_params, new_S)) s, d = RefinerCalculator.calculate_scales_and_derivatives(apm, 0) slist, dlist = RefinerCalculator._calc_component_scales_derivatives(apm, 0) # Test that the scales and derivatives were correctly calculated assert list(s) == list([new_S] * slist[0].size()) assert d[0, 0] == dlist[0][0, 0] assert d[1, 0] == dlist[0][1, 0] assert d[2, 0] == dlist[0][2, 0] # Test again for two components. components["decay"].parameters = flex.double([0.0]) components["scale"].parameters = flex.double([1.0]) components["abs"].parameters = flex.double([1.0]) components["decay"].calculate_scales_and_derivatives() components["scale"].calculate_scales_and_derivatives() components["abs"].calculate_scales_and_derivatives() apm = scaling_active_parameter_manager(components, ["scale", "decay"]) _, __ = RefinerCalculator.calculate_scales_and_derivatives(apm, 0) # Test for no components apm = scaling_active_parameter_manager(components, []) _, d = RefinerCalculator.calculate_scales_and_derivatives(apm, 0) assert d.n_cols == 0 and d.n_rows == 0