1module var1D_mod
2 ! MODULE var1D_mod (prefix='var1D' category='4. Data Object transformations')
3 !
4 !:Purpose: contains all 1Dvar-related methods.
5 !
6 use columnData_mod
7 use gridStatevector_mod
8 use horizontalCoord_mod
9 use midasMpi_mod
10 use obsSpaceData_mod
11 use timeCoord_mod
12 use verticalCoord_mod
13 use codeprecision_mod
14 use mathphysconstants_mod
15
16 implicit none
17 save
18 private
19
20 ! public procedures
21 public :: var1D_Setup, var1D_Finalize
22 public :: var1D_transferColumnToYGrid
23 ! public variables
24 public :: var1D_validHeaderIndex, var1D_validHeaderCount
25
26 logical :: initialized = .false.
27 integer, external :: get_max_rss
28 integer, allocatable :: var1D_validHeaderIndex(:) ! pointeur vers les colonnes assimilables pour minimiser la taille du vecteur de controle
29 integer :: var1D_validHeaderCount ! taille effective de var1D_validHeaderIndex
30
31contains
32
33 !--------------------------------------------------------------------------
34 ! var1D_setup
35 !--------------------------------------------------------------------------
36 subroutine var1D_setup(obsSpaceData)
37 !
38 !:Purpose: to setup var1D module
39 !
40 implicit none
41
42 ! Arguments:
43 type (struct_obs), intent(in) :: obsSpaceData
44
45 ! Locals:
46 integer :: countGood, headerIndex
47 integer :: bodyStart, bodyEnd, bodyIndex
48
49 if(mmpi_myid == 0) write(*,*) 'var1D_setup: Starting'
50 if(mmpi_myid == 0) write(*,*) 'Memory Used: ', get_max_rss()/1024, 'Mb'
51
52 !we want to count how many obs are really assimilable to minimize controlvector size
53 var1D_validHeaderCount = 0
54 allocate( var1D_validHeaderIndex(obs_numHeader(obsSpaceData)) )
55 do headerIndex = 1, obs_numHeader(obsSpaceData)
56 bodyStart = obs_headElem_i(obsSpaceData, OBS_RLN, headerIndex)
57 bodyEnd = obs_headElem_i(obsSpaceData, OBS_NLV, headerIndex) + bodyStart - 1
58 countGood = 0
59 do bodyIndex = bodyStart, bodyEnd
60 if (obs_bodyElem_i(obsSpaceData, OBS_ASS, bodyIndex) == obs_assimilated) countGood = countGood + 1
61 end do
62 if (countGood > 0) then
63 var1D_validHeaderCount = var1D_validHeaderCount + 1
64 var1D_validHeaderIndex(var1D_validHeaderCount) = headerIndex
65 if (var1D_validHeaderCount == 1) write(*,*) 'first OBS', headerIndex
66 end if
67 end do
68 initialized = .true.
69 write(*,*) 'var1D_setup: var1D_validHeaderCount, obs_numHeader(obsSpaceData)', var1D_validHeaderCount, obs_numHeader(obsSpaceData)
70
71 end subroutine var1D_setup
72
73 !--------------------------------------------------------------------------
74 ! var1D_Finalize
75 !--------------------------------------------------------------------------
76 subroutine var1D_Finalize()
77 !
78 !:Purpose: to deallocate memory used by internal module structures
79 !
80 implicit none
81
82 if (initialized) then
83 deallocate( var1D_validHeaderIndex )
84 end if
85
86 end subroutine var1D_Finalize
87
88 !--------------------------------------------------------------------------
89 ! var1D_transferColumnToYGrid
90 !--------------------------------------------------------------------------
91 subroutine var1D_transferColumnToYGrid( stateVector, obsSpaceData, column, varList)
92 !
93 !:Purpose: to transfer content of a columndata object to a statevector object
94 ! without interpolation (to be used in 1DVar mode to write increments on Y grid).
95 !
96 implicit none
97
98 ! Arguments:
99 type(struct_gsv), intent(inout) :: stateVector
100 type(struct_obs), intent(in) :: obsSpaceData
101 type(struct_columnData), intent(inout) :: column
102 character(len=4), intent(in) :: varList(:)
103
104 ! Locals:
105 type(struct_hco), pointer :: hco_yGrid
106 integer :: varIndex, globalObsIndex, obsIndex, taskIndex, headerIndex
107 integer, allocatable :: var1D_validHeaderCountAllTasks(:), obsOffset(:)
108 real(8), pointer :: myColumn(:), myField(:,:,:)
109 real(8), allocatable, target :: dummy(:)
110 integer :: var1D_validHeaderCountMpiGlobal, var1D_validHeaderCountMax, ierr, status
111 real(8) :: lat, lon
112 integer :: varDim, tag
113
114 call rpn_comm_barrier("GRID",ierr)
115 allocate( obsOffset(0:mmpi_nprocs-1) )
116 if (mmpi_myid ==0) then
117 allocate( var1D_validHeaderCountAllTasks(mmpi_nprocs) )
118 else
119 allocate(var1D_validHeaderCountAllTasks(1))
120 end if
121
122 call rpn_comm_gather(var1D_validHeaderCount , 1, 'MPI_INTEGER', var1D_validHeaderCountAllTasks, 1,'MPI_INTEGER', 0, "GRID", ierr )
123 if (mmpi_myId ==0) then
124 var1D_validHeaderCountMpiGlobal = sum( var1D_validHeaderCountAllTasks(:) )
125 var1D_validHeaderCountMax = maxval( var1D_validHeaderCountAllTasks(:) )
126 obsOffset(0) = 0
127 do taskIndex = 1, mmpi_nprocs - 1
128 obsOffset(taskIndex) = obsOffset(taskIndex - 1) + var1D_validHeaderCountAllTasks(taskIndex)
129 end do
130 write(*,*) 'var1D_transferColumnToYGrid: obsOffset: ', obsOffset(:)
131 end if
132 call rpn_comm_bcast( obsOffset, mmpi_nprocs, 'MPI_INTEGER', 0, "GRID",ierr )
133 call rpn_comm_bcast( var1D_validHeaderCountMax, 1, 'MPI_INTEGER', 0, "GRID",ierr )
134
135 call hco_setupYgrid(hco_Ygrid, 1, var1D_validHeaderCountMpiGlobal)
136 if (mmpi_myId ==0) then
137 call gsv_allocate(stateVector, numstep=tim_nstepobsinc, hco_ptr=hco_Ygrid, vco_ptr=column%vco, &
138 datestamp_opt=tim_getDatestamp(), mpi_local_opt=.false., &
139 dataKind_opt=pre_incrReal, allocHeight_opt=.false., allocPressure_opt=.false., &
140 besilent_opt=.false.)
141 write(*,*) 'Memory Used: ', get_max_rss()/1024, 'Mb'
142 end if
143
144 write(*,*) 'var1D_transferColumnToYGrid: start of lat-lon dissemination'
145 do obsIndex = 1, var1D_validHeaderCountMax
146 if (obsIndex <= var1D_validHeaderCount ) then
147 headerIndex = var1D_validHeaderIndex(obsIndex)
148 lat = obs_headElem_r(obsSpaceData, OBS_LAT, headerIndex)
149 lon = obs_headElem_r(obsSpaceData, OBS_LON, headerIndex)
150 else
151 lat = MPC_missingValue_R8
152 lon = MPC_missingValue_R8
153 end if
154 if (mmpi_myId == 0) then
155 if ( obsIndex <= var1D_validHeaderCount ) then
156 hco_yGrid%lat2d_4(1, obsIndex) = lat
157 hco_yGrid%lon2d_4(1, obsIndex) = lon
158 end if
159 else
160 tag = 2 * mmpi_myID
161 call rpn_comm_send( lat, 1, 'mpi_real8', 0, tag, 'GRID', ierr )
162 call rpn_comm_send( lon, 1, 'mpi_real8', 0, tag + 1, 'GRID', ierr )
163 end if
164
165 if (mmpi_myId == 0) then
166 do taskIndex = 1, mmpi_nprocs - 1
167 tag = 2 * taskIndex
168 call rpn_comm_recv( lat, 1, 'mpi_real8', taskIndex, tag, 'GRID', status, ierr )
169 call rpn_comm_recv( lon, 1, 'mpi_real8', taskIndex, tag+1, 'GRID', status, ierr )
170 if (lat /= MPC_missingValue_R8 .and. lon /= MPC_missingValue_R8) then
171 globalObsIndex = obsIndex + obsOffset(taskIndex)
172 hco_yGrid%lat2d_4(1, globalObsIndex) = lat
173 hco_yGrid%lon2d_4(1, globalObsIndex) = lon
174 end if
175 end do
176 end if
177 call rpn_comm_barrier("GRID",ierr)
178 end do
179
180 call rpn_comm_barrier("GRID",ierr)
181 write(*,*) 'var1D_transferColumnToYGrid: end of lat-lon dissemination'
182
183 do varIndex = 1, size(varList)
184 write(*,*) 'var1D_transferColumnToYGrid: start of dissemination for ', varList(varIndex)
185 if (mmpi_myId == 0 ) then
186 call gsv_getField(stateVector, myField, varName_opt=varList(varIndex), stepIndex_opt=1)
187 varDim = gsv_getNumLevFromVarName(stateVector, varList(varIndex))
188 end if
189 call rpn_comm_bcast(varDim, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
190 allocate(dummy(varDim))
191 dummy(:) = MPC_missingValue_R8
192 do obsIndex = 1, var1D_validHeaderCountMax
193 if (obsIndex <= var1D_validHeaderCount ) then
194 headerIndex = var1D_validHeaderIndex(obsIndex)
195 myColumn => col_getColumn(column, headerIndex, varName_opt=varList(varIndex))
196 else
197 myColumn => dummy
198 end if
199 if (mmpi_myId == 0) then
200 if ( obsIndex <= var1D_validHeaderCount ) then
201 myField(1, obsIndex, :) = myColumn(:)
202 end if
203 else
204 tag = mmpi_myId
205 call rpn_comm_send(myColumn , varDim, 'mpi_real8', 0, tag, 'GRID', ierr )
206 end if
207
208 if (mmpi_myId == 0) then
209 do taskIndex = 1, mmpi_nprocs - 1
210 tag = taskIndex
211 call rpn_comm_recv(myColumn, varDim, 'mpi_real8', taskIndex, tag, 'GRID', status, ierr )
212 if (all( myColumn /= MPC_missingValue_R8)) then
213 globalObsIndex = obsIndex + obsOffset(taskIndex)
214 myField(1, globalObsIndex, :) = myColumn(:)
215 end if
216 end do
217 end if
218 end do
219
220 write(*,*) 'var1D_transferColumnToYGrid: end of dissemination for ', varList(varIndex)
221 deallocate(dummy)
222
223 end do
224
225 call rpn_comm_barrier("GRID", ierr)
226 deallocate( obsOffset )
227 deallocate( var1D_validHeaderCountAllTasks )
228
229 end subroutine var1D_transferColumnToYGrid
230
231end module var1D_mod