void model_print(model* m, char offset[]) { int i; enkf_printf("%smodel info:\n", offset); enkf_printf("%s name = %s\n", offset, m->name); enkf_printf("%s %d variables:\n", offset, m->nvar); for (i = 0; i < m->nvar; ++i) { variable* v = &m->vars[i]; enkf_printf("%s %s:\n", offset, v->name); enkf_printf("%s grid = \"%s\"\n", offset, grid_getname(model_getgridbyid(m, v->gridid))); if (isnan(v->inf_ratio)) enkf_printf("%s inflation = %.3f PLAIN\n", offset, v->inflation); else enkf_printf("%s inflation = %.3f %.2f\n", offset, v->inflation, v->inf_ratio); if (!isnan(v->deflation)) enkf_printf("%s randomise: deflation = %.3f, sigma = %.3f\n", offset, v->deflation, v->sigma); } enkf_printf("%s %d modeldata:\n", offset, m->ndata); for (i = 0; i < m->ndata; ++i) { enkf_printf("%s %s:\n", offset, m->data[i].tag); if (m->data[i].alloctype == ALLOCTYPE_1D) enkf_printf("%s type = 1D\n", offset); else if (m->data[i].alloctype == ALLOCTYPE_2D) enkf_printf("%s type = 2D\n", offset); else if (m->data[i].alloctype == ALLOCTYPE_3D) enkf_printf("%s type = 3D\n", offset); } }
/** Updates ensemble observations by applying X5 */ static void update_HE(dasystem* das) { model* m = das->m; int ngrid = model_getngrid(m); int gid; observations* obs = das->obs; int e, o; float* HEi_f; float* HEi_a; char do_T = 'T'; float alpha = 1.0f; float beta = 0.0f; int inc = 1; enkf_printf(" updating HE:\n"); assert(das->s_mode == S_MODE_HE_f); HEi_f = malloc(das->nmem * sizeof(ENSOBSTYPE)); HEi_a = malloc(das->nmem * sizeof(ENSOBSTYPE)); /* * the following code for interpolation of X5 essentially coincides with * that in das_updatefields() */ for (gid = 0, o = 0; gid < ngrid && o < obs->nobs; ++gid) { void* grid = model_getgridbyid(m, gid); int periodic_i = grid_isperiodic_x(grid); int periodic_j = grid_isperiodic_y(grid); char fname_X5[MAXSTRLEN]; int ncid; int varid; int dimids[3]; size_t dimlens[3]; size_t start[3], count[3]; float** X5j = NULL; float** X5jj = NULL; float** X5jj1 = NULL; float** X5jj2 = NULL; int mni, mnj; int* iiter; int* jiter; int i, j, ni, nj; int jj, stepj, ii, stepi; assert(obs->obstypes[obs->data[o].type].gridid == gid); das_getfname_X5(das, grid, fname_X5); ncw_open(fname_X5, NC_NOWRITE, &ncid); ncw_inq_varid(fname_X5, ncid, "X5", &varid); ncw_inq_vardimid(fname_X5, ncid, varid, dimids); for (i = 0; i < 3; ++i) ncw_inq_dimlen(fname_X5, ncid, dimids[i], &dimlens[i]); ni = dimlens[1]; nj = dimlens[0]; assert((int) dimlens[2] == das->nmem * das->nmem); jiter = malloc((nj + 1) * sizeof(int)); /* "+ 1" to handle periodic * grids */ iiter = malloc((ni + 1) * sizeof(int)); for (j = 0, i = 0; j < nj; ++j, i += das->stride) jiter[j] = i; if (periodic_j) jiter[nj] = jiter[nj - 1] + das->stride; for (i = 0, j = 0; i < ni; ++i, j += das->stride) iiter[i] = j; if (periodic_i) iiter[ni] = iiter[ni - 1] + das->stride; grid_getdims(grid, &mni, &mnj, NULL); start[0] = 0; start[1] = 0; start[2] = 0; count[0] = 1; count[1] = ni; count[2] = das->nmem * das->nmem; X5j = alloc2d(mni, das->nmem * das->nmem, sizeof(float)); if (das->stride > 1) { X5jj = alloc2d(ni, das->nmem * das->nmem, sizeof(float)); X5jj1 = alloc2d(ni, das->nmem * das->nmem, sizeof(float)); X5jj2 = alloc2d(ni, das->nmem * das->nmem, sizeof(float)); ncw_get_vara_float(fname_X5, ncid, varid, start, count, X5jj2[0]); } /* * jj, ii are the indices of the subsampled grid; i, j are the indices * of the model grid */ for (jj = 0, j = 0; jj < nj; ++jj) { for (stepj = 0; stepj < das->stride && j < mnj; ++stepj, ++j) { if (das->stride == 1) { /* * no interpolation necessary; simply read the ETMs for the * j-th row from disk */ start[0] = j; ncw_get_vara_float(fname_X5, ncid, varid, start, count, X5j[0]); } else { /* * the following code interpolates the ETM back to the * original grid, first by j, and then by i */ if (stepj == 0) { memcpy(X5jj[0], X5jj2[0], ni * das->nmem * das->nmem * sizeof(float)); memcpy(X5jj1[0], X5jj2[0], ni * das->nmem * das->nmem * sizeof(float)); if (jj < nj - 1 || periodic_j) { start[0] = (jj + 1) % nj; ncw_get_vara_float(fname_X5, ncid, varid, start, count, X5jj2[0]); } } else { float weight2 = (float) stepj / das->stride; float weight1 = (float) 1.0 - weight2; for (ii = 0; ii < ni; ++ii) { float* X5jjii = X5jj[ii]; float* X5jj1ii = X5jj1[ii]; float* X5jj2ii = X5jj2[ii]; for (e = 0; e < das->nmem * das->nmem; ++e) X5jjii[e] = X5jj1ii[e] * weight1 + X5jj2ii[e] * weight2; } } for (ii = 0, i = 0; ii < ni; ++ii) { for (stepi = 0; stepi < das->stride && i < mni; ++stepi, ++i) { if (stepi == 0) memcpy(X5j[i], X5jj[ii], das->nmem * das->nmem * sizeof(float)); else { float weight2 = (float) stepi / das->stride; float weight1 = (float) 1.0 - weight2; float* X5jjii1 = X5jj[ii]; float* X5ji = X5j[i]; float* X5jjii2; if (ii < ni - 1) X5jjii2 = X5jj[ii + 1]; else X5jjii2 = X5jj[(periodic_i) ? (ii + 1) % ni : ii]; for (e = 0; e < das->nmem * das->nmem; ++e) X5ji[e] = X5jjii1[e] * weight1 + X5jjii2[e] * weight2; } } } } /* stride != 1 */ /* * (at this stage X5j should contain the array of X5 matrices * for the j-th row of the grid) */ if (o >= obs->nobs) break; if ((int) (obs->data[o].fj) > j) continue; for (; o < obs->nobs && (int) (obs->data[o].fj) == j; ++o) { float inflation = model_getvarinflation(m, obs->obstypes[obs->data[o].type].vid); /* * HE(i, :) = HE(i, :) * X5 */ i = (int) (obs->data[o].fi); for (e = 0; e < das->nmem; ++e) HEi_f[e] = das->S[e][o]; sgemv_(&do_T, &das->nmem, &das->nmem, &alpha, X5j[i], &das->nmem, HEi_f, &inc, &beta, HEi_a, &inc); /* * applying inflation: */ if (fabsf(inflation - 1.0f) > EPSF) { float v_av = 0.0f; for (e = 0; e < das->nmem; ++e) v_av += HEi_a[e]; v_av /= (float) das->nmem; for (e = 0; e < das->nmem; ++e) HEi_a[e] = (HEi_a[e] - v_av) * inflation + v_av; } for (e = 0; e < das->nmem; ++e) das->S[e][o] = HEi_a[e]; } } /* for stepj */ } /* for jj */ ncw_close(fname_X5, ncid); free(iiter); free(jiter); free2d(X5j); if (das->stride > 1) { free2d(X5jj); free2d(X5jj1); free2d(X5jj2); } } /* for gid */ free(HEi_a); free(HEi_f); das->s_mode = S_MODE_HE_a; } /* update_HE() */
static void update_Hx(dasystem* das) { model* m = das->m; int ngrid = model_getngrid(m); int gid; observations* obs = das->obs; int e, o; enkf_printf(" updating Hx:\n"); assert(das->s_mode == S_MODE_HE_f); /* * the following code for interpolation of X5 essentially coincides with * that in das_updatefields() */ for (gid = 0, o = 0; gid < ngrid && o < obs->nobs; ++gid) { void* grid = model_getgridbyid(m, gid); int periodic_i = grid_isperiodic_x(grid); int periodic_j = grid_isperiodic_y(grid); char fname_w[MAXSTRLEN]; int ncid; int varid; int dimids[3]; size_t dimlens[3]; size_t start[3], count[3]; float** wj = NULL; float** wjj = NULL; float** wjj1 = NULL; float** wjj2 = NULL; int mni, mnj; int* iiter; int* jiter; int i, j, ni, nj; int jj, stepj, ii, stepi; assert(obs->obstypes[obs->data[o].type].gridid == gid); das_getfname_w(das, grid, fname_w); ncw_open(fname_w, NC_NOWRITE, &ncid); ncw_inq_varid(fname_w, ncid, "w", &varid); ncw_inq_vardimid(fname_w, ncid, varid, dimids); for (i = 0; i < 3; ++i) ncw_inq_dimlen(fname_w, ncid, dimids[i], &dimlens[i]); ni = dimlens[1]; nj = dimlens[0]; assert((int) dimlens[2] == das->nmem); jiter = malloc((nj + 1) * sizeof(int)); /* "+ 1" to handle periodic * grids */ iiter = malloc((ni + 1) * sizeof(int)); for (j = 0, i = 0; j < nj; ++j, i += das->stride) jiter[j] = i; if (periodic_j) jiter[nj] = jiter[nj - 1] + das->stride; for (i = 0, j = 0; i < ni; ++i, j += das->stride) iiter[i] = j; if (periodic_i) iiter[ni] = iiter[ni - 1] + das->stride; grid_getdims(grid, &mni, &mnj, NULL); start[0] = 0; start[1] = 0; start[2] = 0; count[0] = 1; count[1] = ni; count[2] = das->nmem; wj = alloc2d(mni, das->nmem, sizeof(float)); if (das->stride > 1) { wjj = alloc2d(ni, das->nmem, sizeof(float)); wjj1 = alloc2d(ni, das->nmem, sizeof(float)); wjj2 = alloc2d(ni, das->nmem, sizeof(float)); ncw_get_vara_float(fname_w, ncid, varid, start, count, wjj2[0]); } /* * jj, ii are the indices of the subsampled grid; i, j are the indices * of the model grid */ for (jj = 0, j = 0; jj < nj; ++jj) { for (stepj = 0; stepj < das->stride && j < mnj; ++stepj, ++j) { if (das->stride == 1) { /* * no interpolation necessary; simply read the ETMs for the * j-th row from disk */ start[0] = j; ncw_get_vara_float(fname_w, ncid, varid, start, count, wj[0]); } else { /* * the following code interpolates the ETM back to the * original grid, first by j, and then by i */ if (stepj == 0) { memcpy(wjj[0], wjj2[0], ni * das->nmem * sizeof(float)); memcpy(wjj1[0], wjj2[0], ni * das->nmem * sizeof(float)); if (jj < nj - 1 || periodic_j) { start[0] = (jj + 1) % nj; ncw_get_vara_float(fname_w, ncid, varid, start, count, wjj2[0]); } } else { float weight2 = (float) stepj / das->stride; float weight1 = (float) 1.0 - weight2; for (ii = 0; ii < ni; ++ii) { float* wjjii = wjj[ii]; float* wjj1ii = wjj1[ii]; float* wjj2ii = wjj2[ii]; for (e = 0; e < das->nmem; ++e) wjjii[e] = wjj1ii[e] * weight1 + wjj2ii[e] * weight2; } } for (ii = 0, i = 0; ii < ni; ++ii) { for (stepi = 0; stepi < das->stride && i < mni; ++stepi, ++i) { if (stepi == 0) memcpy(wj[i], wjj[ii], das->nmem * sizeof(float)); else { float weight2 = (float) stepi / das->stride; float weight1 = (float) 1.0 - weight2; float* wjjii1 = wjj[ii]; float* wji = wj[i]; float* wjjii2; if (ii < ni - 1) wjjii2 = wjj[ii + 1]; else wjjii2 = wjj[(periodic_i) ? (ii + 1) % ni : ii]; for (e = 0; e < das->nmem; ++e) wji[e] = wjjii1[e] * weight1 + wjjii2[e] * weight2; } } } } /* stride != 1 */ /* * (at this stage wj should contain the array of b vectors for * the j-th row of the grid) */ if (o >= obs->nobs) break; if ((int) (obs->data[o].fj) > j) continue; for (; o < obs->nobs && (int) (obs->data[o].fj) == j; ++o) { double dHx = 0.0; double Hx = 0.0; for (e = 0; e < das->nmem; ++e) Hx += das->S[e][o]; Hx /= (double) das->nmem; i = (int) (obs->data[o].fi); /* * HE(i, :) += HA(i, :) * b * 1' */ for (e = 0; e < das->nmem; ++e) dHx += (das->S[e][o] - Hx) * wj[i][e]; for (e = 0; e < das->nmem; ++e) das->S[e][o] += dHx; } } /* for stepj */ } /* for jj */ ncw_close(fname_w, ncid); free(iiter); free(jiter); free2d(wj); if (das->stride > 1) { free2d(wjj); free2d(wjj1); free2d(wjj2); } } /* for gid */ das->s_mode = S_MODE_HE_a; } /* update_Hx() */