Opened 6 years ago
Closed 6 years ago
#653 closed task (fixed)
Investigate matrix size question in ropp_1dvar
| Reported by: | Ian Culverwell | Owned by: | Ian Culverwell |
|---|---|---|---|
| Priority: | normal | Milestone: | 10.0 |
| Component: | ropp_1dvar | Version: | 9.0 |
| Keywords: | Cc: |
Description
Joe Nielsen (DMI) reports the following issue.
Ian, I do not expect you to know the details of this, but maybe you
can give me a hint or suggestion? The problem is the use of
State1DFM varaibles, especially the state % cov property/variable;
In ropp_fm_types it is defined as a compressed matrix as I
understand it:
TYPE(matrix_pp) :: cov ! Error covariance
In ropp_1dvar/common/ropp_1dvar_diagnostics.f90 the state variables
is declared like this:
TYPE(State1DFM), INTENT(inout) :: state
....
And the further down it is used like this:
! 2.2 Calculate error covariance of the solution
! ----------------------------------------------
Bm1 = matrix_invert(state % cov)
Rm1 = matrix_invert(obs % cov)
Kt = TRANSPOSE(K)
CALL matrix_toast(Rm1, Kt, KtRm1K)
S = Bm1 + KtRm1K
state % cov = matrix_invert(S)
(all the matrices are allocated as full matrices)
How can that work? matrix_invert outputs a full matrix, and
matrix_toast understands only full matrices. Looks like an error,
but I hope there is an explanation....
I am suddenly getting a bit worried here because I copy/pasted this
part into our RE1 code at some point (only for postprocessing
though).
thanks
joe
Change history (7)
comment:1 by , 6 years ago
comment:2 by , 6 years ago
Joe replied
Hi Ian
It seems like ropp_1dvar_covar returns a full covariance
matrix - which does not make sense since the supposedly
overlayed ropp_1dvar_covar_bg code explicitly writes a
packed cov matrix. I have dumped B like this
IF ( bg%state_ok ) CALL ropp_1dvar_covar (bg, config)
Bmat=bg%cov
write(*,*) 'shape Bmat', shape(Bmat)
write(*,*) 'Bmat start'
write(*,'(E15.7)') Bmat
write(*,*) 'Bmat end'
write(*,*) 'shape Rm', shape(Rm)
- and plottet Bmat;
Bmat is full (and correct) no doubt.
Look, I really need to move on with the GPAC 2.4 which is
due Friday (last week). So what I do for now is that I
code under the assumption that bg%cov is full, which
seems to be style other places in ROPP. I will let you
decide whether this needs a ROPP-ticket.
I noted this: In my first attempt I failed to allocate
Bmat which resulted in an runtime error saying that the
matrix needs to be at least 275x275 (ie. full) hinting
that the compiler thinks that the output of
ropp_1dvar_covar contains a full cov matrix.
Obvious next move would be to check whether
ropp_1dvar_covar_bg is ever reached. It looks to me as if
it is somehow bypassed...
joe
comment:3 by , 6 years ago
While we're here, ropp_1dvar/math/matrix/matrix_invert.f90 has lots of variable declarations like
real(wp), dimension((int(sqrt(8.*size(A%d))+1)-1)/2, &
(int(sqrt(8.*size(A%d))+1)-1)/2) :: x
where size(A%d) = the number of elements in the packed arrays = n(n+1)/2 for an n x n unpacked array. The bit of algebra (int(sqrt(8.*size(A%d))+1)-1)/2 is presumably designed to return n. And so it does - but rather indirectly:
(int(sqrt(8.*size(A%d))+1)-1)/2 = (int(sqrt(4n(n+1))+1)-1)/2
But
4n2 < 4n(n+1) < 4(n+1)2
=> 2n < sqrt(4n(n+1)) < 2(n+1)
=> 2n + 1 < sqrt(4n(n+1)) + 1 < 2(n+1) + 1
=> int(sqrt(4n(n+1))+1) = 2n + 1
=> (int(sqrt(4n(n+1))+1)-1)/2 = n
OK. But the alternative expression (nint(sqrt(8.*size(A%d)+1))-1)/2 does the job much more directly:
(nint(sqrt(8.*size(A%d)+1))-1)/2
(nint(sqrt(4n(n+1)+1))-1)/2
(nint(sqrt((2n+1)2)-1)/2
(nint(2n+1)-1)/2
n
Perhaps, since we still need a nint to handle rounding errors, there's not much in it. But at least this note might help future developers who worry that the ROPP expression is incorrect.
comment:4 by , 6 years ago
(Better still: 4n2 < 4n(n+1) < 4(n+1/2)2
=> 2n + 1 < sqrt(4n(n+1)) + 1 < 2(n+1/2) + 1 = 2n + 2
=> int(sqrt(4n(n+1))+1) = 2n + 1 as before.)
comment:5 by , 6 years ago
It's all a result of operator overloading.
When the code says
diag % bg_refrac % cov (of type matrix_pp) = R (of type real(:, :))
it is ‘overloading’ the operator ‘=’.
The entry
interface assignment(=)
in ropp_1dvar/math/matrix/matrix.f90 shows that in this case we are calling
subroutine matrix_full2ppt(pp, data)
in ropp_1dvar/math/matrix/matrix_assign.f90, which in turn calls
subroutine matrix_full2pp_alloc_double(array, packed, uplo)
in ropp_1dvar/math/matrix/matrix_full2pp_alloc.f90,
which finally does the packing of the elements of R into the %d component of diag % bg_refrac % cov.
(matrix_full2ppt actually calls matrix_full2pp_alloc, but this calls matrix_full2pp_alloc_double for these variables, as a result of the interface block in matrix.f90.)
It’s involved, but logical and very powerful, because another chain of calls would allow us to reverse the assignment and say
R (of type real(:, :)) = diag % bg_refrac % cov (of type matrix_pp)
Basically, the meaning of '=' in 'LHS = RHS' depends on the Fortran types of LHS and RHS.
comment:6 by , 6 years ago
Overloading operators and generic interfaces are powerful features of fortran90, and actually we use them all over the place in ROPP, e.g. you can call ropp_io_free on an ROprof structure, a covariance matrix, a vlist of ‘extra data’ etc, all as a result of the ropp_io_free interface block in ropp_io/ropp/rop_io.f90. And we often write roprof1 = roprof2, which only makes sense because ropp_io_assign_rotype copies each element of the roprof2 structure to the corresponding element of roprof1.
You can write anything1 = anything2 as long as ‘=’ has been overwritten for the fortran types of anything1 and anything2. So you can probably do it for any two ROPP matrices in ROPP – I doubt that Chris would have left holes. The compiler will let you know pretty quickly if the underlying infrastructure isn’t in place.
comment:7 by , 6 years ago
| Resolution: | → fixed |
|---|---|
| Status: | new → closed |
I think this answers the question. Closing the ticket.

I replied