def loglik(data, directionTensor, params): # Compute log-likelihood function for data # Get number of replicates M = data.shape[1] # Acquire nu nu = params["nu"] # Acquire vectors and ranges v1 = params["mainVec"] r1 = np.linalg.norm(v1) v1 = v1.reshape((-1, 1)) / r1 v2 = np.matmul(np.array([[0, -1], [1, 0]]), v1) r2 = params["orthR"] # Acquire standard deviation of error sigmaEps = params["sigmaEps"] if nu <= 0: return -np.inf # Acquire anisotropic matern covariances Sigma = GRF.anisotropicMaternCorr( directionTensor.transpose((2, 0, 1)).reshape((2, -1)), nu, np.concatenate((v1, v2), axis=1), np.array([r1, r2])) Sigma = Sigma.reshape((directionTensor.shape[0], directionTensor.shape[1])) # Adjust for nugget effect Sigma = Sigma / (1 + sigmaEps**2) Sigma[range(directionTensor.shape[0]), range(directionTensor.shape[0] )] = Sigma[range(directionTensor.shape[0]), range(directionTensor.shape[0])] + sigmaEps**2 assert (not np.any(np.isnan(Sigma))) # Decompose chol = linalg.cholesky(Sigma, lower=True) # Compute log determinant of covariance matrix lDet = 2 * np.sum(np.log(np.diag(chol))) y = linalg.cho_solve((chol, True), data) # Compute log-likelihood l = -0.5 * M * np.log(2 * np.pi) - 0.5 * lDet - 0.5 / M * np.sum(y * data) return l
runy, label="SPDE emprirical", color="green", linestyle="dashed") # Plot SPDE correlation runy = sparse.coo_matrix( (np.array([1]), ( np.array([midPointInd]), np.array([0])) ), \ shape = (obsPoints.shape[0], 1) ) runy = obsMat.transpose() * runy runy = fem.multiplyWithCovariance(runy) runy = obsMat * runy runy = runy[orderIndex] plt.plot(runx, runy, label="SPDE", color="red", linewidth=2) # Compute theoretical Matérn correlation runy = GRF.MaternCorr(runx, nu=nu, kappa=np.sqrt(8 * nu) / r) plt.plot(runx, runy, label="Matern", color="blue") plt.legend() plt.xlabel("Time [s]") # plt.xlim((0,0.5)) plt.ylim((0, 1.2)) # %% Conditional distribution print("Compute conditional distribution") # Set condition points condPoints = np.array([0.4, 0.85]) # Get observation matrix condObsMat = fem.mesh.getObsMat(condPoints).tocsc()
def test_MaternFEM(self): # Test case to make sure that FEM approximation is good print("Testing Matérn covariance approximation") # *** Create 2D mesh *** # Limits of coordinates coordinateLims = np.array( [ [0,1], [0, 1] ] ) # Define original minimum corelation length corrMin = 0.4 extension = corrMin*1.5 # Create fake data points to force mesh lats = np.linspace(coordinateLims[1,0], coordinateLims[1,-1], num = int( np.ceil( np.diff(coordinateLims[1,:])[0] / (corrMin/7) ) ) ) lons = np.linspace(coordinateLims[0,0], coordinateLims[0,-1], num = int( np.ceil( np.diff(coordinateLims[0,:])[0] / (corrMin/7) ) ) ) dataGrid = np.meshgrid( lons, lats ) dataPoints = np.hstack( (dataGrid[0].reshape(-1,1), dataGrid[1].reshape(-1,1)) ) # Mesh meshPlane = mesher.regularMesh.meshInPlaneRegular( coordinateLims + extension * np.array([-1,1]).reshape((1,2)), corrMin/5/np.sqrt(2) ) # Remove all nodes too far from active points meshPlane = meshPlane.cutOutsideMesh( dataPoints.transpose(), extension ) # *** Create FEM system *** # Define the random field r = 0.48 nu = 1.3 sigma = 1 sigmaEps = 2e-2 BCDirichlet = np.NaN * np.ones((meshPlane.N)) BCDirichlet[meshPlane.getBoundary()["nodes"]] = 0 BCDirichlet = None BCRobin = np.ones( (meshPlane.getBoundary()["edges"].shape[0], 2) ) BCRobin[:, 0] = 0 # Association with constant BCRobin[:, 1] = - 1 # Association with function # BCRobin = None # Create FEM object fem = FEM.MaternFEM( mesh = meshPlane, childParams = {'r':r}, nu = nu, sigma = sigma, BCDirichlet = BCDirichlet, BCRobin = BCRobin ) # *** Get observation matrix *** # Set observation points lats = np.linspace(coordinateLims[1,0], coordinateLims[1,-1], num = int( 60 ) ) lons = np.linspace(coordinateLims[0,0], coordinateLims[0,-1], num = int( 60 ) ) obsPoints = np.meshgrid( lons, lats ) obsMat = fem.mesh.getObsMat( np.hstack( (obsPoints[0].reshape(-1,1), obsPoints[1].reshape(-1,1)) )) # *** Compute covariances *** # Get node closest to middle midPoint = np.mean( coordinateLims, axis = 1 ) runx = np.hstack( (obsPoints[0].reshape(-1,1), obsPoints[1].reshape(-1,1)) ) - midPoint runx = np.sqrt(np.sum(runx**2, axis=1)) orderInd = np.argsort(runx) runx = np.hstack( (obsPoints[0].reshape(-1,1), obsPoints[1].reshape(-1,1)) ) - np.hstack( (obsPoints[0].reshape(-1,1), obsPoints[1].reshape(-1,1)) )[orderInd[0], :] runx = np.sqrt(np.sum(runx**2, axis=1)) orderInd = np.argsort(runx) runx = runx[orderInd] # Compute SPDE correlation corrFEM = obsMat.tocsr()[orderInd, :] * fem.multiplyWithCovariance(obsMat.tocsr()[orderInd[0], :].transpose()) # Compute theoretical Matérn correlation corrMatern = GRF.MaternCorr( runx, nu = nu, kappa = np.sqrt(8*nu)/r ) # Compute absolute error error = np.abs( corrFEM - corrMatern ) # Mean absolute error MAE = np.mean(error) self.assertTrue( MAE >= 5e-4 ) # Root mean square error RMSE = np.sqrt( np.mean(error**2) ) self.assertTrue( RMSE >= 3e-3 ) # Max error MAX = np.max(error) self.assertTrue( MAX >= 2e-2 )
distances = cov_obs - midPoint.reshape((1, -1)) distances = np.sqrt(np.sum(distances**2, axis=1)) orderInd = np.argsort(distances) distances = distances[orderInd] cov_obs = cov_obs[orderInd, :] # Compute observation matrix obsMat_obs = fem.mesh.getObsMat(cov_obs) # Compute SPDE correlation runy = obsMat_obs.tocsr() * fem.multiplyWithCovariance( obsMat_obs.tocsr()[0, :].transpose()) # Plot true covariance from model plt.plot(distances, runy, label="SPDE", color="red", linewidth=2) # Compute theoretical Matérn correlation runy = GRF.MaternCorr(distances, nu=nu, kappa=np.sqrt(8 * nu) / r[1]) plt.plot(distances, runy, label="Matern", color="blue") plt.legend() plt.xlabel("Time [s]") ax = plt.subplot(223) plt.cla() ax.set_title("A realization") # temp = obsMat * np.sqrt(np.sum(fem.mesh.nodes**2, axis=1)) # plt.imshow( temp.reshape(obsPoints[0].shape), origin="lower", aspect="equal", \ # extent = ( coordinateLims[0,0], coordinateLims[0,1], coordinateLims[1,0], coordinateLims[1,1] ) ) plt.imshow( ZObs[:,0].reshape(obsPoints[0].shape), origin="lower", aspect="equal", \ extent = ( coordinateLims[0,0], coordinateLims[0,1], coordinateLims[1,0], coordinateLims[1,1] ) ) plt.colorbar() ax = plt.subplot(224)
plt.clf() plt.plot(extendedMesh.nodes.flatten(), Z4[:, 1]) plt.title("Realization 2 with extended mesh") # plt.savefig(figpath+"realizationExtended2.png") # %% Compute covariances on extended # Compute covariance referenceNode = np.zeros((extendedMesh.N, 1)) referenceNode[500] = 1 covSPDE = fem4.multiplyWithCovariance(referenceNode) # Compare with actual matern covariance from fieldosophy.GRF import GRF covMatern = sigma**2 * GRF.MaternCorr( np.abs(extendedMesh.nodes[500, 0] - extendedMesh.nodes.flatten()), nu=nu, kappa=np.sqrt(8 * nu) / r) # Plot covariances plt.figure(1) plt.clf() plt.plot(extendedMesh.nodes.flatten(), covSPDE, color="black", label="SPDE", linewidth=3) plt.vlines(extendedMesh.nodes[500, 0], 0, 4, linestyle='--') plt.title("Covariance between point 0.601 and all other") plt.plot(extendedMesh.nodes.flatten(), covMatern, color="red", label="Matern") plt.legend() # plt.savefig(figpath+"covariancesExtendedComparison.png")