Actual source code: ex1.c
1: static char help[] = "Tests basic creation and destruction of PetscDA objects, and a simple ETKF analysis step.\n\n";
2: #include <petscda.h>
4: int main(int argc, char **argv)
5: {
6: PetscDA da;
7: Mat H;
8: Vec x_true, y_obs, obs_error_var;
9: Vec x_mean_forecast, x_mean_analysis;
10: PetscInt state_size = 10, obs_size = 10, ensemble_size = 20;
11: PetscRandom rng;
12: PetscInt i;
13: PetscReal norm;
15: PetscFunctionBeginUser;
16: PetscCall(PetscInitialize(&argc, &argv, (char *)0, help));
18: /* Create the DA object */
19: PetscCall(PetscDACreate(PETSC_COMM_WORLD, &da));
20: PetscCall(PetscDASetType(da, PETSCDAETKF));
21: PetscCall(PetscDASetSizes(da, state_size, obs_size));
22: PetscCall(PetscDAEnsembleSetSize(da, ensemble_size));
23: PetscCall(PetscDASetFromOptions(da));
24: PetscCall(PetscDASetUp(da));
26: /* Initialize random number generator */
27: PetscCall(PetscRandomCreate(PETSC_COMM_WORLD, &rng));
28: PetscCall(PetscRandomSetFromOptions(rng));
30: /* Create identity observation matrix H (obs_size x state_size) */
31: PetscCall(MatCreateAIJ(PETSC_COMM_WORLD, PETSC_DECIDE, PETSC_DECIDE, obs_size, state_size, 1, NULL, 0, NULL, &H));
32: PetscCall(MatSetFromOptions(H));
33: PetscCall(MatAssemblyBegin(H, MAT_FINAL_ASSEMBLY));
34: PetscCall(MatAssemblyEnd(H, MAT_FINAL_ASSEMBLY));
35: PetscCall(MatShift(H, 1.0));
37: /* Create vectors using MatCreateVecs from H */
38: PetscCall(MatCreateVecs(H, &x_true, &y_obs));
39: PetscCall(VecSet(x_true, 1.0)); /* True state is all 1s */
41: PetscCall(VecDuplicate(y_obs, &obs_error_var));
42: PetscCall(VecSet(obs_error_var, 0.1)); /* Observation error variance */
43: PetscCall(PetscDASetObsErrorVariance(da, obs_error_var));
45: /* Create synthetic observation: y = x_true (identity observation, no noise for this simple test) */
46: PetscCall(VecCopy(x_true, y_obs));
48: /* Initialize ensemble with some spread around 0 (far from truth 1.0) */
49: for (i = 0; i < ensemble_size; i++) {
50: Vec member;
51: PetscCall(VecDuplicate(x_true, &member));
52: PetscCall(VecSetRandom(member, rng)); /* Uniform random [0, 1] */
53: PetscCall(PetscDAEnsembleSetMember(da, i, member));
54: PetscCall(VecDestroy(&member));
55: }
57: /* Compute forecast mean before analysis */
58: PetscCall(VecDuplicate(x_true, &x_mean_forecast));
59: PetscCall(PetscDAEnsembleComputeMean(da, x_mean_forecast));
61: /* Check forecast error */
62: PetscCall(VecAXPY(x_mean_forecast, -1.0, x_true));
63: PetscCall(VecNorm(x_mean_forecast, NORM_2, &norm));
64: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Forecast error norm: %g\n", (double)norm));
66: /* Perform Analysis Step */
67: PetscCall(PetscDAEnsembleAnalysis(da, y_obs, H));
69: /* Compute analysis mean */
70: PetscCall(VecDuplicate(x_true, &x_mean_analysis));
71: PetscCall(PetscDAEnsembleComputeMean(da, x_mean_analysis));
73: /* Check analysis error */
74: PetscCall(VecAXPY(x_mean_analysis, -1.0, x_true));
75: PetscCall(VecNorm(x_mean_analysis, NORM_2, &norm));
76: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Analysis error norm: %g\n", (double)norm));
78: /* The analysis should move the ensemble closer to the observation (truth) */
79: /* Since observation error is small (0.1) and prior spread is ~0.08, it should pull towards observation */
81: PetscCall(PetscDAViewFromOptions(da, NULL, "-petscda_view"));
83: /* Cleanup */
84: PetscCall(MatDestroy(&H));
85: PetscCall(VecDestroy(&x_true));
86: PetscCall(VecDestroy(&y_obs));
87: PetscCall(VecDestroy(&obs_error_var));
88: PetscCall(VecDestroy(&x_mean_forecast));
89: PetscCall(VecDestroy(&x_mean_analysis));
90: PetscCall(PetscRandomDestroy(&rng));
91: PetscCall(PetscDADestroy(&da));
93: PetscCall(PetscFinalize());
94: return 0;
95: }
97: /*TEST
99: test:
100: suffix: 1
101: requires: !complex
102: args: -petscda_view
104: test:
105: suffix: chol
106: requires: !complex
107: args: -petscda_view -petscda_ensemble_sqrt_type cholesky
109: TEST*/