def test_derivative(self): """Check that numerical and analytical derivatives of Q match.""" full_resolution_level = 4 neighbourhood_level = 2 full_spde = SphereMeshSPDE(level=full_resolution_level) active_triangles = full_spde.neighbours_at_level( neighbourhood_level, 0) spde = SphereMeshView(full_resolution_level, active_triangles) Q = spde.build_Q_stationary(numpy.log(1.0), numpy.log(1.0), 2) epsilon = 0.000001 expected_dQ0 = \ ((spde.build_Q_stationary(numpy.log(1.0)+epsilon, numpy.log(1.0), 2) - spde.build_Q_stationary(numpy.log(1.0)-epsilon, numpy.log(1.0), 2)) / (2.0 * epsilon)).todense() expected_dQ1 = \ ((spde.build_Q_stationary(numpy.log(1.0), numpy.log(1.0)+epsilon, 2) - spde.build_Q_stationary(numpy.log(1.0), numpy.log(1.0)-epsilon, 2)) / (2.0 * epsilon)).todense() dQ0 = spde.build_dQdp_stationary(numpy.log(1.0), numpy.log(1.0), 2, 0).todense() dQ1 = spde.build_dQdp_stationary(numpy.log(1.0), numpy.log(1.0), 2, 1).todense() # print numpy.abs(dQ0 - expected_dQ0).ravel().max() / numpy.abs(expected_dQ0).ravel().max() # print numpy.abs(dQ1 - expected_dQ1).ravel().max() / numpy.abs(expected_dQ1).ravel().max() numpy.testing.assert_almost_equal(dQ0, expected_dQ0, decimal=7) numpy.testing.assert_almost_equal(dQ1, expected_dQ1, decimal=7)
def test_design_function(self): spde = SphereMeshSPDE(level=1, sparse_format=SPARSEFORMAT) design = SeasonalElementDesign( TestSeasonalElement.SimulatedObservationStructure(), spde, n_harmonics=3, include_local_mean=True) # Initialise zero state vector state_vector = numpy.zeros((294, 1)) # Get indices of nonzero design elements A_simulated = spde.build_A( TestSeasonalElement.SimulatedObservationStructure( ).location_polar_coordinates()) observation_indices, vertex_indices = A_simulated.sorted_indices( ).nonzero() # This should select observation 1 state_vector[vertex_indices[3:6], 0] = 1.0 # And this will add 0.309016994375 to it state_vector[vertex_indices[3:6] + 84, 0] = 1.0 # Apply state vector y = design.design_function(state_vector) # Check observation 1 selected with appropriate sum numpy.testing.assert_almost_equal( y, numpy.array([[0.0], [1.309016994375]]))
def test_harmonic_index_for_spatial_component(self): prior_a = SeasonalElementPrior( SeasonalHyperparameters(n_spatial_components=3, common_log_sigma=0.8, common_log_rho=1.0), spde=SphereMeshSPDE(level=1, sparse_format=SPARSEFORMAT), n_harmonics=2, include_local_mean=True, alpha=2) self.assertEqual(0, prior_a.harmonic_index_for_spatial_component(0)) self.assertEqual(1, prior_a.harmonic_index_for_spatial_component(1)) self.assertEqual(1, prior_a.harmonic_index_for_spatial_component(2)) self.assertEqual(2, prior_a.harmonic_index_for_spatial_component(3)) self.assertEqual(2, prior_a.harmonic_index_for_spatial_component(4)) prior_b = SeasonalElementPrior( SeasonalHyperparameters(n_spatial_components=2, common_log_sigma=0.8, common_log_rho=1.0), spde=SphereMeshSPDE(level=1, sparse_format=SPARSEFORMAT), n_harmonics=2, include_local_mean=False, alpha=2) self.assertEqual(0, prior_b.harmonic_index_for_spatial_component(0)) self.assertEqual(0, prior_b.harmonic_index_for_spatial_component(1)) self.assertEqual(1, prior_b.harmonic_index_for_spatial_component(2)) self.assertEqual(1, prior_b.harmonic_index_for_spatial_component(3))
def test_covariance_function(self): """Check that inverse precision follows matern covariance patterns.""" # Generate spde = SphereMeshSPDE(level=5) # Index 12 in the mesh is 0 latitude, 0 longitude # - The covariance evaluated will relate to distance from this chosen point # but the same shape of graph should be obtained for any point - # there is nothing special about this choice. reference_index = 12 # nu and rho as used in matern definition nu = 1.0 rho = 0.3 # Make precision precision = spde.build_Q_stationary(log_sigma=numpy.log( numpy.sqrt(1.0)), log_rho=numpy.log(2.0 * rho), alpha=2) # Sample covariance at reference index # This is the vector with 1 in the reference location and zeros everywhere else # like [ 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 ... ] reference_unit = scipy.sparse.csc_matrix( ([1.0], ([reference_index], [0])), shape=(precision.shape[0], 1)) # Solve Q.x = reference unit # This is like picking the column of inverse(Q) corresponding to reference index # and so is the covariance with respect to that reference location covariance_wrt_reference = scipy.sparse.linalg.spsolve( precision, reference_unit) # Great arc distances from reference point points = spde.triangulation.points refpoint = points[reference_index, :] dotprod = points.dot(refpoint) distance_from_reference = numpy.arccos(dotprod) # There is a scale factor difference between estimated covariance and Matern model sigma0 = numpy.sqrt(covariance_wrt_reference[reference_index]) # Compute disparity (taking into account scale factor difference) disparity = max( numpy.abs(covariance_wrt_reference - TestSphereMeshSPDE.matern( distance_from_reference, sigma0, nu, rho))) # Convert to percentage and check disparity_percent = 100.0 * disparity / (sigma0**2) # print 'Disparity (%): ', disparity_percent self.assertTrue(disparity_percent < 2.0)
def test_design_function(self): obs = TestSpaceTimeKroneckerElement.SimulatedObservationStructure() spde_space = SphereMeshSPDE(level=1) spde_time = LatticeSPDE.construct(dimension_specification=[(23, 27, 5) ], basis_function=WendlandC4Basis(), overlap_factor=2.5) design = SpaceTimeKroneckerDesign(observationstructure=obs, spatial_model=spde_space, alpha=2, temporal_model=spde_time, H=1.01) # Get and check indices of nonzero design elements A_space = spde_space.build_A(obs.location_polar_coordinates()) observation_indices, vertex_indices = A_space.sorted_indices().nonzero( ) numpy.testing.assert_equal(observation_indices, [0, 0, 0, 1, 1, 1]) self.assertEqual((6, ), vertex_indices.shape) # Vertices of observations 0 and 1 # (one row per vertex, one column per coordinate) vertices0 = spde_space.triangulation.points[vertex_indices[0:3], :] vertices1 = spde_space.triangulation.points[vertex_indices[3:6], :] # Multiply vertices by the weights from A and sum to get cartesian locations testpoint0 = A_space[0, vertex_indices[0:3]] * vertices0 testpoint1 = A_space[1, vertex_indices[3:6]] * vertices1 # Check results correspond to original polar coordinates numpy.testing.assert_almost_equal(cartesian_to_polar2d(testpoint0), [[15.0, -7.0]]) numpy.testing.assert_almost_equal(cartesian_to_polar2d(testpoint1), [[5.0, 100.0]]) # So the function with those indices set should give required values, provided it's evaluated at time index == 24 state_vector = numpy.zeros((210, )) state_vector[42 + vertex_indices[0:3]] = 40.0 state_vector[42 + vertex_indices[3:6]] = 28.0 numpy.testing.assert_almost_equal(design.design_function(state_vector), [40.0, 28.0]) # But if we change to a time far away then we get nothing state_vector = numpy.zeros((210, )) state_vector[(42 * 4) + vertex_indices[0:3]] = 40.0 state_vector[(42 * 4) + vertex_indices[3:6]] = 28.0 numpy.testing.assert_almost_equal(design.design_function(state_vector), [0.0, 0.0])
def __init__(self, level, neighbourhood_level, centre_index_at_level, sparse_format='csr'): full_sphere = SphereMeshSPDE(level) active_triangle_indices = full_sphere.neighbours_at_level( neighbourhood_level=neighbourhood_level, centre_index_at_level=centre_index_at_level) super(SphereMeshViewLocal, self).__init__(level, active_triangle_indices, sparse_format=sparse_format)
def __init__(self, level, super_triangle_level, super_triangle_index, sparse_format='csr'): full_sphere = SphereMeshSPDE(level) active_triangle_indices = full_sphere.super_triangle_at_level( super_triangle_level=super_triangle_level, super_triangle_index=super_triangle_index) super(SphereMeshViewSuperTriangle, self).__init__(level, active_triangle_indices, sparse_format=sparse_format)
def test_design_jacobian(self): design = LocalDesign(TestLocalElement.SimulatedObservationStructure(), SphereMeshSPDE(level=1)) numpy.testing.assert_equal( design.design_matrix().todense(), design.design_jacobian(currentstate=None).todense())
def test_design_jacobian(self): obs = TestSpaceTimeKroneckerElement.SimulatedObservationStructure() spde_space = SphereMeshSPDE(level=1) spde_time = LatticeSPDE.construct(dimension_specification=[(23, 27, 5) ], basis_function=WendlandC4Basis(), overlap_factor=2.5) design = SpaceTimeKroneckerDesign(observationstructure=obs, spatial_model=spde_space, alpha=2, temporal_model=spde_time, H=1.01) # Build a candidate state vector (as used above for function testing) A_space = spde_space.build_A(obs.location_polar_coordinates()) observation_indices, vertex_indices = A_space.sorted_indices().nonzero( ) state_vector = numpy.zeros((210, )) state_vector[42 + vertex_indices[0:3]] = 40.0 state_vector[42 + vertex_indices[3:6]] = 28.0 # Numerical jacobian J_numerical = numpy.zeros((2, 210)) epsilon = 0.01 for parameter_index in range(210): x0 = numpy.copy(state_vector) x1 = numpy.copy(state_vector) x0[parameter_index] -= epsilon x1[parameter_index] += epsilon J_numerical[:, parameter_index] = (design.design_function(x1) - design.design_function(x0)) / ( 2.0 * epsilon) # Computed jacobian J_calculated = design.design_jacobian(state_vector) # Should be the same numpy.testing.assert_almost_equal(J_calculated.todense(), J_numerical) # And numbers of nonzeros also the same self.assertEqual(J_calculated.nnz, scipy.sparse.csc_matrix(J_numerical).nnz)
def test_design_number_of_state_parameters(self): design = SeasonalElementDesign( TestSeasonalElement.SimulatedObservationStructure(), SphereMeshSPDE(level=1), n_harmonics=3, include_local_mean=True) self.assertEqual(294, design.design_number_of_state_parameters())
def __init__(self, n_triangulation_divisions, n_harmonics, include_local_mean): """Initialise for given number of harmonics.""" super(SeasonalElement, self).__init__() self.spde = SphereMeshSPDE(level=n_triangulation_divisions, sparse_format=SPARSEFORMAT) self.n_harmonics = n_harmonics self.include_local_mean = include_local_mean self.alpha = 2
def test_derivative(self): """Check that numerical and analytical derivatives of Q match.""" spde = SphereMeshSPDE(level=3) Q = spde.build_Q_stationary(numpy.log(1.0), numpy.log(1.0), 2) epsilon = 0.000001 expected_dQ0 = \ ((spde.build_Q_stationary(numpy.log(1.0)+epsilon, numpy.log(1.0), 2) - spde.build_Q_stationary(numpy.log(1.0)-epsilon, numpy.log(1.0), 2)) / (2.0 * epsilon)).todense() expected_dQ1 = \ ((spde.build_Q_stationary(numpy.log(1.0), numpy.log(1.0)+epsilon, 2) - spde.build_Q_stationary(numpy.log(1.0), numpy.log(1.0)-epsilon, 2)) / (2.0 * epsilon)).todense() dQ0 = spde.build_dQdp_stationary(numpy.log(1.0), numpy.log(1.0), 2, 0).todense() dQ1 = spde.build_dQdp_stationary(numpy.log(1.0), numpy.log(1.0), 2, 1).todense() # print numpy.abs(dQ0 - expected_dQ0).ravel().max() / numpy.abs(expected_dQ0).ravel().max() # print numpy.abs(dQ1 - expected_dQ1).ravel().max() / numpy.abs(expected_dQ1).ravel().max() numpy.testing.assert_almost_equal(dQ0, expected_dQ0, decimal=7) numpy.testing.assert_almost_equal(dQ1, expected_dQ1, decimal=7)
def test_init(self): obs = TestCombinationElement.SimulatedObservationStructure() spde = SphereMeshSPDE(0) design = CombinationDesign( [GrandMeanDesign(2), LocalDesign(obs, spde)]) self.assertEqual(2, len(design.designlist)) self.assertTrue(isinstance(design.designlist[0], GrandMeanDesign)) self.assertTrue(isinstance(design.designlist[1], LocalDesign))
def test_isnonlinear(self): spde = SphereMeshSPDE(level=1, sparse_format=SPARSEFORMAT) design = SeasonalElementDesign( TestSeasonalElement.SimulatedObservationStructure(), spde, n_harmonics=3, include_local_mean=True) self.assertFalse(design.isnonlinear())
def __init__(self, level, sparse_format='csr'): full_sphere = SphereMeshSPDE(level) active_triangle_indices = np.arange( full_sphere.triangulation.triangles.shape[0]) super(SphereMeshViewGlobal, self).__init__(level, active_triangle_indices, sparse_format=sparse_format)
def test_prior_precision_derivative(self): dQ_0 = self.prior.prior_precision_derivative(0) dQ_1 = self.prior.prior_precision_derivative(1) dQ_2 = self.prior.prior_precision_derivative(2) self.assertEqual(SPARSEFORMAT, dQ_0.getformat()) self.assertEqual(SPARSEFORMAT, dQ_1.getformat()) self.assertEqual(SPARSEFORMAT, dQ_2.getformat()) self.assertEqual((210, 210), dQ_0.shape) self.assertEqual((210, 210), dQ_1.shape) self.assertEqual((210, 210), dQ_2.shape) # Numerical derivative numerical = [[], [], []] epsilon = 0.0001 for parameter_index in range(3): for sign_index, sign in enumerate([-epsilon, +epsilon]): parameter_vector = numpy.array( [numpy.log(1.0), numpy.log(1.1), numpy.log(1.2)]) parameter_vector[parameter_index] += sign Q_numerical = SpaceTimeKroneckerPrior( hyperparameters=SpaceTimeSPDEHyperparameters( parameter_vector[0], parameter_vector[1], parameter_vector[2]), spatial_model=SphereMeshSPDE(level=1), alpha=2, temporal_model=LatticeSPDE.construct( dimension_specification=[(23, 27, 5)], basis_function=WendlandC4Basis(), overlap_factor=2.5), H=1.01).prior_precision() numerical[parameter_index].append(Q_numerical) numerical_dQ0 = ((numerical[0][1]) - (numerical[0][0])) / (2.0 * epsilon) numerical_dQ1 = ((numerical[1][1]) - (numerical[1][0])) / (2.0 * epsilon) numerical_dQ2 = ((numerical[2][1]) - (numerical[2][0])) / (2.0 * epsilon) # Check numerical derivative corresponds to computed one numpy.testing.assert_almost_equal(dQ_0.todense(), numerical_dQ0.todense()) numpy.testing.assert_almost_equal(dQ_1.todense(), numerical_dQ1.todense()) numpy.testing.assert_almost_equal(dQ_2.todense(), numerical_dQ2.todense(), decimal=7)
def setUp(self): self.prior = SpaceTimeFactorPrior( hyperparameters=SpaceTimeSPDEHyperparameters(numpy.log(1.0), numpy.log(1.1), numpy.log(1.2)), spatial_model=SphereMeshSPDE(level=1), alpha=2, temporal_model=LatticeSPDE.construct( dimension_specification = [(23, 27, 5)], basis_function=WendlandC4Basis(), overlap_factor=2.5), H=1.01)
def test_design_jacobian(self): spde = SphereMeshSPDE(level=2, sparse_format=SPARSEFORMAT) design = SeasonalElementDesign( TestSeasonalElement.SimulatedObservationStructure(), spde, n_harmonics=2, include_local_mean=False) A = design.design_matrix() J = design.design_jacobian(numpy.array([])) self.assertEqual(SPARSEFORMAT, J.getformat()) numpy.testing.assert_almost_equal(J.todense(), A.todense())
def __init__(self, groupname, n_triangulation_divisions): """ Setup triangulation of sphere for LocalBias model. Args: * groupname: The name of the bias group that this bias corresponds to. Not currently used. * n_triangulation_divisions (int): Number of subdivisions of icosohedron for triangulation of sphere. """ super(SpatialBiasElement, self).__init__() self.groupname = groupname self.spde = SphereMeshSPDE(level=n_triangulation_divisions, sparse_format=SPARSEFORMAT) self.number_of_biases = self.spde.n_latent_variables()
def __init__(self, n_triangulation_divisions, alpha, starttime, endtime, n_nodes, overlap_factor, H, wrap_dimensions=None): """Initialise space and time SPDE definitions.""" super(SpaceTimeSPDEElement, self).__init__() self.spatial_model = SphereMeshSPDE(level=n_triangulation_divisions, sparse_format=SPARSEFORMAT) self.alpha = alpha self.temporal_model = LatticeSPDE.construct( dimension_specification = [(starttime, endtime, n_nodes)], basis_function = WendlandC4Basis(), overlap_factor = overlap_factor, wrap_dimensions = wrap_dimensions) self.H = H
def test_design_jacobian(self): obs = TestCombinationElement.SimulatedObservationStructure() spde = SphereMeshSPDE(1) design = CombinationDesign( [GrandMeanDesign(2), LocalDesign(obs, spde)]) # Make a state vector full of a test value 561 which should never actually get accessed state_vector = numpy.tile(561.0, (47, 1)) J = design.design_jacobian(state_vector) # A-matrix for comparison A = spde.build_A(obs.location_polar_coordinates()) # Should have ones at start for global mean J_expected = numpy.hstack([numpy.array([[1.0], [1.0]]), A.todense()]) # Check as exepcted self.assertEqual(SPARSEFORMAT, J.getformat()) numpy.testing.assert_equal(J_expected, J.todense())
def test_init(self): design = SeasonalElementDesign( TestSeasonalElement.SimulatedObservationStructure(), SphereMeshSPDE(level=2), n_harmonics=5, include_local_mean=True) self.assertTrue( isinstance(design.observationstructure, TestSeasonalElement.SimulatedObservationStructure)) self.assertEqual(2, design.spde.triangulation.level) self.assertEqual(5, design.n_harmonics) self.assertEqual(True, design.include_local_mean)
def __init__(self, n_triangulation_divisions): """ Setup triangulation of sphere for :class:`LocalModel`. Args: * n_triangulation_divisions (int): Number of subdivisions of icosohedron for triangulation of sphere. """ super(LocalElement, self).__init__() self.spde = SphereMeshSPDE(level=n_triangulation_divisions, sparse_format=SPARSEFORMAT)
def test_design_function(self): obs = TestCombinationElement.SimulatedObservationStructure() spde = SphereMeshSPDE(1) design = CombinationDesign( [GrandMeanDesign(2), LocalDesign(obs, spde)]) A = spde.build_A(obs.location_polar_coordinates()) observation_indices, vertex_indices = A.sorted_indices().nonzero() # Make a state vector full of a test value 561 which should never actually get accessed state_vector = numpy.tile(561.0, (47, 1)) # Set the grand mean to 20.0 state_vector[0, 0] = 20.0 # Choose some numbers for observations of interest state_vector[(vertex_indices[0:3] + 1), 0] = 43.5 state_vector[(vertex_indices[3:6] + 1), 0] = -27.0 # Should end up with (20.0 + 43.5) and (20.0 - 27.0) y = design.design_function(state_vector) numpy.testing.assert_almost_equal(y, [[63.5], [-7.0]])
def test_n_spatial_components(self): # With local mean 2 harmonics plus mean = (1 + 2*2) = 5 parameters self.assertEqual( 5, SeasonalElementPrior( SeasonalHyperparameters(n_spatial_components=3, common_log_sigma=0.8, common_log_rho=1.0), spde=SphereMeshSPDE(level=1, sparse_format=SPARSEFORMAT), n_harmonics=2, include_local_mean=True, alpha=2).n_spatial_components()) # Without local mean 2 harmonics = 2*2 = 4 parameters self.assertEqual( 4, SeasonalElementPrior( SeasonalHyperparameters(n_spatial_components=2, common_log_sigma=0.8, common_log_rho=1.0), spde=SphereMeshSPDE(level=1, sparse_format=SPARSEFORMAT), n_harmonics=2, include_local_mean=False, alpha=2).n_spatial_components()) # Also check state parameters self.assertEqual( 210, SeasonalElementPrior( SeasonalHyperparameters(n_spatial_components=3, common_log_sigma=0.8, common_log_rho=1.0), spde=SphereMeshSPDE(level=1, sparse_format=SPARSEFORMAT), n_harmonics=2, include_local_mean=True, alpha=2).prior_number_of_state_parameters())
def test_init(self): prior = SeasonalElementPrior( SeasonalHyperparameters(n_spatial_components=3, common_log_sigma=0.8, common_log_rho=1.0), spde=SphereMeshSPDE(level=1, sparse_format=SPARSEFORMAT), n_harmonics=2, include_local_mean=True, alpha=3) numpy.testing.assert_equal(prior.hyperparameters.get_array(), [0.8, 1.0, 0.8, 1.0, 0.8, 1.0]) self.assertEqual(2, prior.n_harmonics) self.assertTrue(prior.include_local_mean) self.assertEqual(3, prior.alpha)
def test_prior_precision_derivative(self): prior = SeasonalElementPrior( SeasonalHyperparameters(n_spatial_components=3, common_log_sigma=0.8, common_log_rho=1.0), spde=SphereMeshSPDE(level=1, sparse_format=SPARSEFORMAT), n_harmonics=2, include_local_mean=True, alpha=2) dQ = prior.prior_precision_derivative(1) # For now just check size and format of result self.assertEqual(SPARSEFORMAT, dQ.getformat()) self.assertEqual((210, 210), dQ.shape)
def test_init(self): design = SpaceTimeFactorDesign( observationstructure=TestSpaceTimeFactorElement.SimulatedObservationStructure(), spatial_model=SphereMeshSPDE(level=1), alpha=2, temporal_model=LatticeSPDE.construct( dimension_specification = [(23, 27, 5)], basis_function=WendlandC4Basis(), overlap_factor=2.5), H=1.01) self.assertEqual(2, design.alpha) self.assertEqual(1.01, design.H) self.assertEqual(1, design.spatial_model.triangulation.level) self.assertEqual(2.5, design.temporal_model.lattice.basis_function.basis_span) numpy.testing.assert_almost_equal(design.temporal_model.lattice.axis_coordinates, [ [ 23.0 ], [ 24.0 ], [ 25.0 ], [ 26.0 ], [ 27.0 ] ])
def test_element_states(self): obs = TestCombinationElement.SimulatedObservationStructure() spde = SphereMeshSPDE(0) design = CombinationDesign( [GrandMeanDesign(obs), LocalDesign(obs, spde)]) states = design.element_states( numpy.array([ 270.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0 ])) self.assertTrue(isinstance(states, list)) self.assertEqual(2, len(states)) numpy.testing.assert_equal(states[0], [270.0]) numpy.testing.assert_equal( states[1], [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0])
def test_design_matrix(self): spde = SphereMeshSPDE(level=1, sparse_format=SPARSEFORMAT) design = SeasonalElementDesign( TestSeasonalElement.SimulatedObservationStructure(), spde, n_harmonics=3, include_local_mean=True) A = design.design_matrix() # Check shape and sparse format self.assertEqual((2, 294), A.shape) self.assertEqual(SPARSEFORMAT, A.getformat()) # Check that kronecker expansion worked as expected numpy.testing.assert_almost_equal( A[:, 0:42].todense() * 0.951056516295, A[:, 42:84].todense()) numpy.testing.assert_almost_equal( A[:, 0:42].todense() * -0.809016994375, A[:, 252:294].todense())