source: codes/icosagcm/devel/src/unstructured/data_unstructured.F90 @ 949

Last change on this file since 949 was 949, checked in by dubos, 5 years ago

devel : generic compute_caldyn_slow_hydro + fixes

File size: 10.6 KB
Line 
1MODULE data_unstructured_mod
2  USE ISO_C_BINDING
3  USE earth_const, ONLY : thermo_theta
4  USE mpipara, ONLY : is_mpi_master
5  USE grid_param, ONLY : llm, nqdyn, primal_num, edge_num, dual_num, &
6       max_primal_deg, max_dual_deg, max_trisk_deg
7  USE geometry, ONLY : le, le_de, fv, Av, Ai, wee, Riv2
8#ifdef CPP_USING_OMP
9  USE OMP_LIB
10#endif
11  IMPLICIT NONE
12  SAVE
13
14
15#include "unstructured.h90"
16
17  INTEGER, PARAMETER :: eta_mass=1, eta_lag=2, &
18       caldyn_vert_cons=1, max_nb_stage=5
19  INDEX,  BIND(C) :: caldyn_eta=eta_lag, &
20       caldyn_vert_variant=caldyn_vert_cons, nb_threads=0, nb_stage=0
21  LOGICAL(C_BOOL), BIND(C) :: hydrostatic=.TRUE., debug_on=.FALSE.
22  LOGICAL(C_BOOL), BIND(C, NAME='debug_hevi_solver') :: debug_hevi_solver_=.TRUE.
23
24#ifdef CPP_MIXED_PREC
25  LOGICAL(C_BOOL), BIND(C) :: mixed_precision=.TRUE.
26#else
27  LOGICAL(C_BOOL), BIND(C) :: mixed_precision=.FALSE.
28#endif
29
30  INDEX, POINTER :: & ! deg(ij) = nb of vertices = nb of edges of primal/dual cell ij
31       primal_deg(:), primal_edge(:,:), primal_vertex(:,:), primal_ne(:,:), & 
32       dual_deg(:), dual_edge(:,:), dual_vertex(:,:), dual_ne(:,:), &
33       trisk_deg(:), trisk(:,:), &
34       left(:), right(:), up(:), down(:)
35  ! left and right are adjacent primal cells
36  ! flux is positive when going from left to right
37  ! up and down are adjacent dual cells
38  ! circulation is positive when going from down to up
39
40  TIME, PARAMETER :: print_trace_interval = 1.
41  TIME, BIND(C) :: elapsed
42  NUM, BIND(C) :: ptop, pbot, Phi_bot, rho_bot
43  NUM1(max_nb_stage), BIND(C)              :: tauj       ! diagonal of fast Butcher tableau
44  NUM2(max_nb_stage,max_nb_stage), BIND(C) :: cslj, cflj ! slow and fast modified Butcher tableaus
45  NUM2(:,:), POINTER          :: centroid, xyz_v, ap,bp, mass_bl, mass_dak, mass_dbk
46  INTEGER(C_INT), BIND(C) :: comm_icosa
47
48  INTEGER, PARAMETER :: id_dev1=1, id_dev2=2, &
49       id_pvort_only=3, id_slow_hydro=4, id_fast=5, id_coriolis=6, id_theta=7, id_geopot=8, id_vert=9, &
50       id_solver=10, id_slow_NH=11, id_NH_geopot=12, id_vert_NH=13, id_update=14, id_halo=15, &
51       id_scalar_laplacian=16, nb_routines=16 
52  TIME, PRIVATE :: start_time, time_spent(nb_routines) ! time spent in each kernel
53  INTEGER, PRIVATE :: current_id, nb_calls(nb_routines)
54  INTEGER(KIND=8), PRIVATE :: bytes(nb_routines) ! bytes read or written by each kernel
55  CHARACTER(len = 10) :: id_name(nb_routines) = &
56       (/'dev1      ', 'dev2      ', &
57       'pvort_only', 'slow_hydro', 'fast      ', 'coriolis  ', 'theta     ', 'geopot    ', 'vert      ', &
58       'solver    ', 'slow_NH   ', 'NH_geopot ', 'vert_NH   ',  'update    ', 'halo_xchg ', 'scalar_lap' /)
59
60  INTEGER, PARAMETER ::transfer_primal=1, transfer_edge=2, transfer_dual=3, transfer_max=3
61  TYPE Halo_transfer
62     INTEGER :: ranks ! size of arrays rank, len
63     INTEGER, ALLOCATABLE :: rank(:), & ! MPI ranks to communicate with
64          num(:), & ! number of cells to send to / receive from other MPI ranks
65          cells(:) ! local indices of cells to send/receive
66     NUM, ALLOCATABLE :: buf2(:,:)
67  END TYPE Halo_transfer
68  TYPE(Halo_transfer), TARGET :: send_info(transfer_max), recv_info(transfer_max)
69
70CONTAINS
71
72  !----------------------------      PROFILING      --------------------------
73
74#ifndef CPP_USING_OMP
75  FUNCTION omp_get_wtime()
76    TIME :: omp_get_wtime
77    CALL CPU_TIME(omp_get_wtime)
78  END FUNCTION omp_get_wtime
79
80  FUNCTION omp_get_num_procs()
81    INTEGER :: omp_get_num_procs
82    omp_get_num_procs=1
83  END FUNCTION omp_get_num_procs
84
85  FUNCTION omp_get_max_threads()
86    INTEGER :: omp_get_max_threads
87    omp_get_max_threads=1
88  END FUNCTION omp_get_max_threads
89#endif
90
91  SUBROUTINE init_trace()
92    !$OMP MASTER
93    time_spent(:)=0.
94    bytes(:)=0
95    nb_calls(:)=0
96    !$OMP END MASTER
97  END SUBROUTINE init_trace
98
99  SUBROUTINE print_trace_() BIND(C, name='dynamico_print_trace')
100    INTEGER :: id
101    TIME :: total_spent
102    total_spent=SUM(time_spent)
103    IF(is_mpi_master) THEN
104       PRINT *, '========================= Performance metrics ========================='
105       PRINT *, 'Total time spent in instrumented code (seconds) :', total_spent
106       PRINT *, 'Name, #calls, %time, microsec/call, MB/sec'   
107       DO id=1,nb_routines
108          IF(nb_calls(id)>0) PRINT *, id_name(id), nb_calls(id), INT(100.*time_spent(id)/total_spent), &
109               INT(1e6*time_spent(id)/nb_calls(id)), INT(1e-6*bytes(id)/time_spent(id))
110       END DO
111    END IF
112  END SUBROUTINE print_trace_
113
114  SUBROUTINE print_trace()
115    !$OMP MASTER
116       IF(SUM(time_spent)>print_trace_interval) THEN
117          CALL print_trace_
118          CALL init_trace()
119       END IF
120    !$OMP END MASTER
121  END SUBROUTINE print_trace
122
123  SUBROUTINE enter_trace(id, nbytes)
124    INTEGER :: id, nbytes
125    !$OMP MASTER
126    current_id = id
127    bytes(id) = bytes(id) + nbytes
128    nb_calls(id)=nb_calls(id)+1
129    start_time = OMP_GET_WTIME()
130    !$OMP END MASTER
131  END SUBROUTINE enter_trace
132
133  SUBROUTINE exit_trace()
134    TIME :: elapsed
135    !$OMP MASTER
136    elapsed = OMP_GET_WTIME()-start_time
137    IF(elapsed<0.) elapsed=0.
138    time_spent(current_id) = time_spent(current_id) + elapsed
139    !$OMP END MASTER
140  END SUBROUTINE exit_trace
141
142  !---------------------------- CONTEXT INITIALIZATION --------------------------
143
144!#define ALLOC1(v,n1) IF(ALLOCATED(v)) DEALLOCATE(v) ; ALLOCATE(v(n1))
145!#define ALLOC2(v,n1,n2) IF(ALLOCATED(v)) DEALLOCATE(v) ; ALLOCATE(v(n1,n2))
146#define ALLOC1(v,n1) IF(ASSOCIATED(v)) DEALLOCATE(v) ; ALLOCATE(v(n1))
147#define ALLOC2(v,n1,n2) IF(ASSOCIATED(v)) DEALLOCATE(v) ; ALLOCATE(v(n1,n2))
148#define ALLOC3(v,n1,n2,n3) IF(ASSOCIATED(v)) DEALLOCATE(v) ; ALLOCATE(v(n1,n2,n3))
149
150  SUBROUTINE init_mesh( & 
151       primal_deg_, primal_edge_, primal_ne_, &
152       dual_deg_, dual_edge_, dual_ne_, dual_vertex_, &
153       left_, right_, up_, down_ ,&
154       trisk_deg_, trisk_) BINDC(init_mesh)
155    INDEX :: primal_deg_(primal_num), primal_edge_(max_primal_deg,primal_num), &
156         primal_ne_(max_primal_deg,primal_num), &
157         dual_deg_(dual_num), dual_edge_(max_dual_deg,dual_num), &
158         dual_ne_(max_dual_deg,dual_num), &
159         dual_vertex_(max_dual_deg,dual_num), &
160         trisk_deg_(edge_num), trisk_(max_trisk_deg, edge_num)
161    INDEX, DIMENSION(edge_num) :: left_, right_, down_, up_
162
163    IF(is_mpi_master) THEN
164       PRINT *, 'init_mesh ...'
165       PRINT *, 'Primal mesh : ', primal_num, max_primal_deg
166       PRINT *, 'Dual mesh   : ', dual_num, max_dual_deg
167       PRINT *, '       Edge mesh   : ', edge_num, max_trisk_deg
168       PRINT *, 'Vertical levels :', llm
169    END IF
170    ALLOC1(primal_deg, primal_num)
171    ALLOC2(primal_edge, max_primal_deg,primal_num)
172    ALLOC2(primal_ne, max_primal_deg,primal_num)
173    ALLOC1(dual_deg,dual_num)
174    ALLOC2(dual_edge, max_dual_deg,dual_num)
175    ALLOC2(dual_ne, max_dual_deg,dual_num)
176    ALLOC2(dual_vertex, max_dual_deg,dual_num)
177    ALLOC1(trisk_deg, edge_num)
178    ALLOC2(trisk, max_trisk_deg, edge_num)
179    ALLOC1(left, edge_num)
180    ALLOC1(right, edge_num)
181    ALLOC1(up, edge_num)
182    ALLOC1(down, edge_num)
183    primal_deg(:) = primal_deg_(:)
184    primal_edge(:,:) = primal_edge_(:,:)
185    primal_ne(:,:) = primal_ne_(:,:)
186    dual_deg(:) = dual_deg_(:)
187    dual_edge(:,:) = dual_edge_(:,:)
188    dual_ne(:,:) = dual_ne_(:,:)
189    dual_vertex(:,:) = dual_vertex_(:,:)
190    IF(MINVAL(dual_deg)<2) THEN
191       STOP 'At least one dual cell has less than 2 vertices'
192    END IF
193    IF(MINVAL(primal_deg)<2) THEN
194       STOP 'At least one primal cell has less than 2 vertices'
195    END IF
196    left(:)=left_(:)
197    right(:)=right_(:)
198    down(:)=down_(:)
199    up=up_(:)
200    trisk_deg(:)=trisk_deg_(:)
201    trisk(:,:)=trisk_(:,:)
202    IF(is_mpi_master) THEN
203       PRINT *, MAXVAL(primal_edge), edge_num
204       PRINT *, MAXVAL(dual_edge), edge_num
205       PRINT *, MAXVAL(dual_vertex), dual_num
206       PRINT *, MAXVAL(trisk), edge_num
207       PRINT *, MAX(MAXVAL(left),MAXVAL(right)), primal_num
208       PRINT *, MAX(MAXVAL(up),MAXVAL(down)), dual_num
209       PRINT *, SHAPE(trisk), edge_num
210       PRINT *,' ... Done.'
211    END IF
212  END SUBROUTINE init_mesh
213
214  ! Input arrays to init_metric and init_hybrid are declared DBL
215  ! => always float64 on the Python side
216  ! They are copied to Fortran arrays of type NUM (float or double)
217
218  SUBROUTINE init_metric(Ai_, Av_, fv_, le_de_, Riv2_, wee_) BINDC(init_metric)
219    DBL :: Ai_(primal_num), Av_(dual_num), fv_(dual_num), le_de_(edge_num), &
220         Riv2_(max_dual_deg,dual_num), wee_(max_trisk_deg,edge_num)
221    IF(is_mpi_master) PRINT *, 'init_metric ...'
222    ALLOC1(Ai,primal_num)
223    ALLOC1(Av,dual_num)
224    ALLOC1(fv,dual_num)
225    ALLOC1(le_de,edge_num)
226    ALLOC2(Riv2, max_dual_deg, dual_num)
227    ALLOC3(wee, max_trisk_deg, edge_num, 1)
228    Ai(:) = Ai_(:)
229    Av(:) = Av_(:)
230    fv(:) = fv_(:)
231    le_de(:) = le_de_(:)
232    Riv2(:,:)=Riv2_(:,:)
233    wee(:,:,1) = wee_(:,:)
234    IF(is_mpi_master) THEN
235       PRINT *, 'Max Ai : ',    MAXVAL(ABS(Ai))
236       PRINT *, 'Max Av : ',    MAXVAL(ABS(Av))
237       PRINT *, 'Max fv : ',    MAXVAL(ABS(fv))
238       PRINT *, 'Max le_de : ', MAXVAL(ABS(le_de))
239       PRINT *, 'Max Riv2 : ',  MAXVAL(ABS(Riv2))
240       PRINT *, 'Max wee : ',   MAXVAL(ABS(wee))
241       PRINT *, MINVAL(right),  MAXVAL(right)
242       PRINT *, MINVAL(right),  MAXVAL(left)
243       PRINT *,' ... Done.'
244       IF(nb_threads==0) nb_threads=OMP_GET_MAX_THREADS()
245       PRINT *,'OpenMP : max_threads, num_procs, nb_threads', OMP_GET_MAX_THREADS(), OMP_GET_NUM_PROCS(), nb_threads
246    END IF
247  END SUBROUTINE init_metric
248  !
249  SUBROUTINE show_openmp() BINDC(show_openmp)
250    PRINT *,'OpenMP : max_threads, num_procs', OMP_GET_MAX_THREADS(), OMP_GET_NUM_PROCS()
251  END SUBROUTINE show_openmp
252  !
253  SUBROUTINE init_params() BINDC(init_params)
254    USE earth_const
255    kappa = Rd/cpp
256    IF(is_mpi_master) THEN
257       PRINT *, 'Setting physical parameters ...'
258       IF(hydrostatic) THEN
259          PRINT *, 'Hydrostatic dynamics (HPE)'
260       ELSE
261          PRINT *, 'Non-hydrostatic dynamics (Euler)'
262       END IF
263       PRINT *, 'g = ',g
264       PRINT *, 'preff = ',preff
265       PRINT *, 'Treff = ',Treff
266       PRINT *, 'Rd = ',Rd
267       PRINT *, 'cpp = ',cpp
268       PRINT *, 'kappa = ',kappa
269       PRINT *, '... Done'
270    END IF
271    CALL init_trace
272  END SUBROUTINE init_params
273  !
274  SUBROUTINE init_hybrid(bl,dak,dbk) BINDC(init_hybrid)
275    DBL :: bl(llm+1, primal_num), &
276         dak(llm, primal_num), dbk(llm, primal_num)
277    IF(is_mpi_master) PRINT *, 'Setting hybrid coefficients ...'
278    ALLOC2(mass_bl, llm+1, primal_num)
279    ALLOC2(mass_dak, llm, primal_num)
280    ALLOC2(mass_dbk, llm, primal_num)
281    mass_bl(:,:)  = bl(:,:)
282    mass_dak(:,:) = dak(:,:)
283    mass_dbk(:,:) = dbk(:,:)
284    IF(is_mpi_master) PRINT *, '... Done, llm = ', llm
285  END SUBROUTINE Init_hybrid
286
287END MODULE data_unstructured_mod
Note: See TracBrowser for help on using the repository browser.