-
Notifications
You must be signed in to change notification settings - Fork 1
/
mod_lorenz63_3dvar.f90
136 lines (114 loc) · 2.96 KB
/
mod_lorenz63_3dvar.f90
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
module mod_lorenz63_3dvar
!$$$ program documentation block
! . . .
! program name: mod_lorenz63_3dvar
! programmer: da,cheng org: umd date: 2015-Jan-11
!
! purpose:
! 3D-Var system for the Lorenz63 system
!
! revision history:
! 2015-Jan-11 da - creator
!
! file dependencies:
!
! attributes:
! language: fortran 90
! machine :
!
!
!$$$ end documentation block
use mod_type, only : rdef, rdp
use mod_math, only : invmtx
Use mod_optimization, only : run_lbfgs
implicit none
private
public :: lorenz63_3dvar
integer,parameter :: nx = 3
integer,parameter :: nyo = 3
integer,parameter :: kitermax = 100
real(rdp),parameter :: epsl = 1.d-6
contains
subroutine lorenz63_3dvar( xb, B, lyo, yo, erro, xa )
implicit none
! passed args
real(rdef),intent(in ) :: xb(nx)
real(rdef),intent(in ) :: B(nx,nx)
logical, intent(in ) :: lyo(nyo)
real(rdef),intent(in ) :: yo(nyo)
real(rdef),intent(in ) :: erro(nyo)
real(rdef),intent( out) :: xa(nx)
! local vars
real(rdef) :: invB(nx,nx), invR(nyo)
real(rdp) :: x(nx)
real(rdp) :: Jc, Jo, Jb
real(rdp) :: dJc(nx), dJo(nx), dJb(nx)
integer :: kiter
integer :: ierr
integer :: i, j
! get B^-1, and R^-1
Call invmtx( nx, B, invB, ierr )
Write(6,*) "B ="
Do i = 1, nx
Write(6,*) ( B(i,j), j = 1, nx )
Enddo
Write(6,*) "inv(B) ="
Do i = 1, nx
Write(6,*) ( invB(i,j), j = 1, nx )
Enddo
If ( ierr /= 0 ) Stop "[lorenz63_3dvar] error: fail to get inverse of B"
Do i = 1, nyo
If ( lyo(i) ) Then
invR(i) = 1.d0/( erro(i)*erro(i) )
Endif
Enddo
! Set xa=xb at the inital step
x = xb
kiter = 0
! Minimization loop
lp_mini: Do
! Calcualte Jb = 0.5 * ( x - xb) * B^-1 * ( x - xb )
Jb = 0.0d0
Do i = 1, nx
Do j = 1, nx
Jb = Jb + 0.5d0*( x(i)-xb(i) )*( x(j)-xb(j) )*invB(i,j)
Enddo
Enddo
! Calculate Jo = 0.5 * ( h[x] - yo ) * R^-1 * ( h[x] - yo )
Jo = 0.0d0
Do i = 1, nyo
If ( lyo(i) ) Then
Jo = Jo + 0.5d0*( x(i)-yo(i) )*( x(i)-yo(i) )*invR(i)
Endif
Enddo
! Calculate total cost function Jc = Jb + Jo
Jc = Jb + Jo
! Calculate Gradient dJb = B^-1 * ( x - xb )
dJb = 0.0d0
Do i = 1, nx
Do j = 1, nx
dJb(i) = dJb(i) + invB(i,j) * ( x(j)-xb(j) )
Enddo
Enddo
! Calculate Gradient dJo = H^T * R^-1 * ( h[x] - yo )
dJo = 0.0d0
Do i = 1, nx
If ( lyo(i) ) Then
dJo(i) = invR(i) * ( x(i) - yo(i) )
Endif
Enddo
! Calculate Total gradient dJc = dJo + dJb
dJc = dJo + dJb
!
Call run_lbfgs( nx, x, Jc, dJc, epsl, ierr )
If ( ierr < 0 ) Stop "[lorenz63_3dvar] error:fail to run lbfgs."
kiter = kiter + 1
If ( kiter > kitermax ) Then
Write(6,*) "[lorenz63_3dvar] warning: maximum iter reached. "
exit lp_mini
Endif
If ( ierr == 0 ) exit lp_mini
Enddo lp_mini
xa = x
endsubroutine
endmodule