Changeset 638


Ignore:
Timestamp:
12/18/17 12:33:31 (6 years ago)
Author:
dubos
Message:

devel/unstructured : code reorganization

Location:
codes/icosagcm/devel/src/unstructured
Files:
2 added
1 edited

Legend:

Unmodified
Added
Removed
  • codes/icosagcm/devel/src/unstructured/caldyn_unstructured.F90

    r635 r638  
    22  USE ISO_C_BINDING 
    33  USE OMP_LIB 
    4 #ifdef CPP_USING_XIOS 
    5   USE xios 
    6 #endif 
     4  USE data_unstructured_mod 
    75  IMPLICIT NONE 
    8   PRIVATE 
    96  SAVE 
     7 
     8CONTAINS 
     9 
     10#define INDICES1 ij,l,iq,iedge,edge,ivertex,vertex,ij_left,ij_right 
     11#define INDICES2 ij_up,ij_down,itrisk,edge_trisk,kup,kdown 
     12#define DECLARE_INDICES INTEGER INDICES1,INDICES2 
     13#define PHI_BOT(ij) Phi_bot 
     14#define PHI_BOT_VAR 0. 
    1015 
    1116#define BINDC_(thename) BIND(C, name=#thename) 
    1217#define BINDC(thename) BINDC_(dynamico_ ## thename) 
    13 ! 
     18 
    1419#define DBL REAL(C_DOUBLE) 
    1520#define DOUBLE1(m) DBL, DIMENSION(m) 
    1621#define DOUBLE2(m,n) DBL, DIMENSION(m,n) 
    1722#define DOUBLE3(m,n,p) DBL, DIMENSION(m,n,p) 
    18 #define INDEX INTEGER(C_INT) 
    19 #define PHI_BOT(ij) Phi_bot 
    20 #define PHI_BOT_VAR 0. 
    21 ! 
    22   INTEGER, PARAMETER :: eta_mass=1, eta_lag=2, & 
    23        thermo_theta=1, thermo_entropy=2, thermo_moist=3, thermo_boussinesq=4, & 
    24        caldyn_vert_cons=1 
    25   INTEGER(C_INT),  BIND(C) :: caldyn_thermo=thermo_theta, caldyn_eta=eta_lag, & 
    26        caldyn_vert_variant=caldyn_vert_cons, nb_threads=0 
    27   LOGICAL(C_BOOL), BIND(C) :: hydrostatic=.TRUE., debug_hevi_solver=.TRUE., rigid=.TRUE. 
    28 ! 
    29   INDEX, BIND(C) :: llm, nqdyn, edge_num, primal_num, dual_num, & 
    30        max_primal_deg, max_dual_deg, max_trisk_deg 
    31   INDEX, ALLOCATABLE, PRIVATE :: & ! deg(ij) = nb of vertices = nb of edges of primal/dual cell ij 
    32        primal_deg(:), primal_edge(:,:), primal_vertex(:,:), primal_ne(:,:), &  
    33        dual_deg(:), dual_edge(:,:), dual_vertex(:,:), dual_ne(:,:), & 
    34        trisk_deg(:), trisk(:,:), & 
    35        left(:), right(:), up(:), down(:) 
    36   ! left and right are adjacent primal cells 
    37   ! flux is positive when going from left to right 
    38   ! up and down are adjacent dual cells 
    39   ! circulation is positive when going from down to up 
    40 !  
    41   DBL, BIND(C) :: elapsed, g, ptop, cpp, cppv, Rd, Rv, preff, Treff, & 
    42       pbot, Phi_bot, rho_bot 
    43   DBL :: kappa 
    44   DOUBLE1(:), ALLOCATABLE, PRIVATE   :: le_de, fv, Av, Ai 
    45   DOUBLE2(:,:), ALLOCATABLE, PRIVATE :: Riv2, wee, ap,bp, mass_bl, mass_dak, mass_dbk 
    46 ! 
    47   INTEGER(C_INT), BIND(C) :: comm_icosa 
    48  
    49 #ifdef CPP_USING_XIOS 
    50   TYPE(xios_context) :: ctx_hdl 
    51 #endif 
    52  
    53 CONTAINS 
    54 ! 
    55 !-------------------------------------- KERNELS -------------------------------------- 
    56 ! 
    57 ! 
    58 #define DECLARE_INDICES INTEGER ij,l,iq,iedge,edge,ivertex,vertex,ij_left,ij_right,ij_up,ij_down,itrisk,edge_trisk,kup,kdown 
    5923 
    6024#define FIELD_PS      DOUBLE1(primal_num) 
     
    6529#define FIELD_THETA   DOUBLE3(llm, primal_num, nqdyn) 
    6630#define FIELD_GEOPOT  DOUBLE2(llm+1, primal_num) 
    67 ! 
     31 
    6832#define HASNAN(field) (ANY(.NOT.ABS(field)<1e20)) 
    69 ! 
    70 SUBROUTINE caldyn_unstructured(tau, mass_col,rhodz,theta_rhodz,u,geopot,w, & ! IN : flow state 
    71                                theta,ps,pk,hflux,qv, &    ! OUT : diags (except surface geopot : IN) 
    72                                dmass_col,drhodz,dtheta_rhodz,du_fast,du_slow, & 
    73                                dPhi_fast, dPhi_slow, dW_fast, dW_slow) BINDC(caldyn_unstructured) ! OUT : tendencies 
    74   DBL, VALUE :: tau 
    75   FIELD_MASS   :: rhodz, drhodz, pk, berni         ! IN, OUT, DIAG 
    76   FIELD_THETA  :: theta_rhodz, dtheta_rhodz, theta ! IN, OUT, DIAG 
    77   FIELD_GEOPOT :: wflux, w, geopot, &              ! DIAG, INOUT 
    78        dPhi_fast, dPhi_slow, dW_fast, dW_slow      ! OUT 
    79   FIELD_U      :: u,du_fast,du_slow,hflux,qu       ! INOUT,OUT,OUT,DIAG 
    80   FIELD_Z      :: qv                               ! DIAG 
    81   FIELD_PS     :: ps,dmass_col,mass_col            ! OUT,OUT,IN (if eta_mass) or OUT,UNUSED,UNUSED (if eta_lag) 
    82   DOUBLE2(llm+1, edge_num) :: wwuu 
    83   DBL          :: time1,time2 
    84   INTEGER :: ij 
    8533 
    86 !  CALL CPU_TIME(time1) 
    87   time1=OMP_GET_WTIME() 
     34!----------------------------- Non-Hydrostatic ----------------------------- 
    8835 
    89   IF(hydrostatic) THEN 
    90  
    91     !$OMP PARALLEL NUM_THREADS(nb_threads) 
    92     !$OMP DO SCHEDULE(STATIC) 
    93     DO ij=1,edge_num 
    94       du_fast(:,ij)=0. 
    95       du_slow(:,ij)=0. 
    96     END DO 
    97     !$OMP END DO 
    98     CALL compute_theta(mass_col,rhodz,theta_rhodz, theta) 
    99     CALL compute_geopot(rhodz,theta, ps,pk,geopot) 
    100  
    101     CALL compute_caldyn_fast(tau, pk,berni,theta,geopot, du_fast,u) 
    102  
    103     CALL compute_pvort_only(rhodz,u,qv,qu) 
    104     CALL compute_caldyn_slow_hydro(rhodz,theta,u, berni,hflux,du_slow) 
    105     CALL compute_coriolis(hflux,theta,qu, drhodz,dtheta_rhodz,du_slow) 
    106     IF(caldyn_eta == eta_mass) THEN 
    107        CALL caldyn_vert(drhodz,rhodz,theta,u, dmass_col,wflux,dtheta_rhodz,du_slow,wwuu) 
    108     END IF 
    109 !$OMP END PARALLEL 
    110  
    111   ELSE ! NH 
    112     DO ij=1,edge_num 
    113       du_fast(:,ij)=0. 
    114       du_slow(:,ij)=0. 
    115     END DO 
    116     DO ij=1,primal_num 
    117       wflux(1,ij)=0. 
    118       wflux(llm+1,ij)=0. 
    119     END DO 
    120     CALL compute_theta(mass_col,rhodz,theta_rhodz, theta) 
    121     CALL compute_caldyn_solver(tau,rhodz,theta,pk,geopot,W,dPhi_fast,dW_fast,du_fast) 
    122     CALL compute_caldyn_fast(tau, pk,berni,theta,geopot, du_fast,u) 
    123     CALL compute_pvort_only(rhodz,u,qv,qu) 
    124     CALL compute_caldyn_slow_NH(u,rhodz,geopot,W, hflux,du_slow,dPhi_slow,dW_slow)  
    125     CALL compute_coriolis(hflux,theta,qu, drhodz,dtheta_rhodz,du_slow) 
    126     IF(caldyn_eta == eta_mass) THEN 
    127        CALL caldyn_vert(drhodz,rhodz,theta,u, dmass_col,wflux,dtheta_rhodz,du_slow,wwuu) 
    128        CALL compute_caldyn_vert_NH(rhodz,geopot,W,wflux, du_slow,dPhi_slow,dW_slow) 
    129     END IF 
    130   END IF 
    131   
    132   time2=OMP_GET_WTIME() 
    133 !  CALL CPU_TIME(time2) 
    134   elapsed = elapsed + time2-time1 
    135 END SUBROUTINE caldyn_unstructured 
    136 ! 
    137 !----------------------------- Non-Hydrostatic ----------------------------- 
    138 ! 
    13936SUBROUTINE compute_NH_geopot(tau,dummy, m_ik, m_il, theta, W_il, Phi_il) 
    14037  FIELD_MASS   :: m_ik, theta, p_ik, A_ik, C_ik   ! IN*2,LOCAL*3 
     
    14542#include "../kernels_unst/compute_NH_geopot.k90" 
    14643END SUBROUTINE compute_NH_geopot 
    147 ! 
     44 
    14845SUBROUTINE compute_caldyn_slow_NH(u,rhodz,Phi,W, hflux,du,dPhi,dW) 
    14946  FIELD_U      :: u, hflux, du   ! IN, OUT, OUT 
     
    15552#include "../kernels_unst/caldyn_slow_NH.k90" 
    15653END SUBROUTINE compute_caldyn_slow_NH 
    157 ! 
     54 
    15855SUBROUTINE compute_caldyn_solver(tau,rhodz,theta,pk,geopot,W,dPhi,dW,du) 
    15956  DBL, INTENT(IN) :: tau 
     
    16663#include "../kernels_unst/caldyn_solver.k90" 
    16764END SUBROUTINE compute_caldyn_solver 
    168 ! 
     65 
    16966SUBROUTINE compute_caldyn_vert_NH(mass,geopot,W,wflux, du,dPhi,dW) 
    17067  FIELD_MASS   :: mass, eta_dot, wcov, W_etadot 
     
    17572#include "../kernels_unst/caldyn_vert_NH.k90" 
    17673END SUBROUTINE compute_caldyn_vert_NH 
    177 ! 
     74 
    17875!----------------------------- Hydrostatic ------------------------------- 
    179 ! 
     76 
    18077SUBROUTINE compute_geopot(rhodz,theta,ps,pk,geopot) 
    18178  FIELD_MASS  :: rhodz,pk   ! IN, OUT 
     
    19794#include "../kernels_unst/caldyn_slow_hydro.k90" 
    19895END SUBROUTINE compute_caldyn_slow_hydro 
    199 ! 
     96 
    20097!---------------------------------- Generic ------------------------------ 
    201 ! 
     98 
    20299SUBROUTINE caldyn_vert(convm,rhodz,theta,u, dmass_col,wflux,dtheta_rhodz,du, wwuu) 
    203100  FIELD_PS    :: dmass_col 
     
    214111#include "../kernels_unst/caldyn_vert.k90" 
    215112END SUBROUTINE caldyn_vert 
    216 ! 
     113 
    217114SUBROUTINE compute_coriolis(hflux,theta,qu, convm,dtheta_rhodz,du) 
    218115  FIELD_U     :: hflux, Ftheta, qu, du 
     
    223120#include "../kernels_unst/coriolis.k90" 
    224121END SUBROUTINE 
    225 ! 
     122 
    226123SUBROUTINE compute_theta(mass_col,rhodz,theta_rhodz, theta) 
    227124  FIELD_PS :: mass_col 
     
    232129#include "../kernels_unst/theta.k90" 
    233130END SUBROUTINE 
    234 ! 
     131 
    235132SUBROUTINE compute_pvort_only(rhodz,u,qv,qu) 
    236133  FIELD_MASS :: rhodz 
     
    241138#include "../kernels_unst/pvort_only.k90" 
    242139END SUBROUTINE compute_pvort_only 
    243 ! 
     140 
    244141SUBROUTINE compute_caldyn_fast(tau, pk,berni,theta,geopot, du,u) 
    245142  DBL, INTENT(IN) :: tau 
     
    254151 
    255152END SUBROUTINE compute_caldyn_fast 
    256 ! 
     153 
    257154!----------------------------- Unused ----------------------------- 
    258 ! 
     155 
    259156SUBROUTINE gradient(b,grad) BINDC(gradient) 
    260157  DOUBLE2(llm,primal_num) :: b 
     
    273170  !$OMP END PARALLEL 
    274171END SUBROUTINE 
    275 ! 
    276 !---------------------------- CONTEXT INITIALIZATION -------------------------- 
    277 ! 
    278 #define ALLOC1(v,n1) IF(ALLOCATED(v)) DEALLOCATE(v) ; ALLOCATE(v(n1)) 
    279 #define ALLOC2(v,n1,n2) IF(ALLOCATED(v)) DEALLOCATE(v) ; ALLOCATE(v(n1,n2)) 
    280  
    281 SUBROUTINE init_mesh( &  
    282      primal_deg_, primal_edge_, primal_ne_, & 
    283      dual_deg_, dual_edge_, dual_ne_, dual_vertex_, & 
    284      left_, right_, up_, down_ ,& 
    285      trisk_deg_, trisk_) BINDC(init_mesh) 
    286   INDEX :: primal_deg_(primal_num), primal_edge_(max_primal_deg,primal_num), & 
    287        primal_ne_(max_primal_deg,primal_num), & 
    288        dual_deg_(dual_num), dual_edge_(max_dual_deg,dual_num), & 
    289        dual_ne_(max_dual_deg,dual_num), & 
    290        dual_vertex_(max_dual_deg,dual_num), & 
    291        trisk_deg_(edge_num), trisk_(max_trisk_deg, edge_num) 
    292   INDEX, DIMENSION(edge_num) :: left_, right_, down_, up_ 
    293  
    294   PRINT *, 'init_mesh ...' 
    295   PRINT *, 'Primal mesh : ', primal_num, max_primal_deg 
    296   PRINT *, 'Dual mesh   : ', dual_num, max_dual_deg 
    297   PRINT *, 'Edge mesh   : ', edge_num, max_trisk_deg 
    298   PRINT *, 'Vertical levels :', llm 
    299   ALLOC1(primal_deg, primal_num) 
    300   ALLOC2(primal_edge, max_primal_deg,primal_num) 
    301   ALLOC2(primal_ne, max_primal_deg,primal_num) 
    302   ALLOC1(dual_deg,dual_num) 
    303   ALLOC2(dual_edge, max_dual_deg,dual_num) 
    304   ALLOC2(dual_ne, max_dual_deg,dual_num) 
    305   ALLOC2(dual_vertex, max_dual_deg,dual_num) 
    306   ALLOC1(trisk_deg, edge_num) 
    307   ALLOC2(trisk, max_trisk_deg, edge_num) 
    308   PRINT *, SHAPE(trisk), edge_num 
    309   ALLOC1(left, edge_num) 
    310   ALLOC1(right, edge_num) 
    311   ALLOC1(up, edge_num) 
    312   ALLOC1(down, edge_num) 
    313   primal_deg(:) = primal_deg_(:) 
    314   primal_edge(:,:) = primal_edge_(:,:) 
    315   primal_ne(:,:) = primal_ne_(:,:) 
    316   dual_deg(:) = dual_deg_(:) 
    317   dual_edge(:,:) = dual_edge_(:,:) 
    318   dual_ne(:,:) = dual_ne_(:,:) 
    319   dual_vertex(:,:) = dual_vertex_(:,:) 
    320   IF(MINVAL(dual_deg)<3) THEN 
    321      STOP 'At least one dual cell has less than 3 vertices' 
    322   END IF 
    323   IF(MINVAL(primal_deg)<3) THEN 
    324      STOP 'At least one primal cell has less than 3 vertices' 
    325   END IF 
    326   left(:)=left_(:) 
    327   right(:)=right_(:) 
    328   down(:)=down_(:) 
    329   up=up_(:) 
    330   trisk_deg(:)=trisk_deg_(:) 
    331   trisk(:,:)=trisk_(:,:) 
    332   PRINT *, MAXVAL(primal_edge), edge_num 
    333   PRINT *, MAXVAL(dual_edge), edge_num 
    334   PRINT *, MAXVAL(dual_vertex), dual_num 
    335   PRINT *, MAXVAL(trisk), edge_num 
    336   PRINT *, MAX(MAXVAL(left),MAXVAL(right)), primal_num 
    337   PRINT *, MAX(MAXVAL(up),MAXVAL(down)), dual_num 
    338   PRINT *, SHAPE(trisk), edge_num 
    339   PRINT *,' ... Done.' 
    340 END SUBROUTINE init_mesh 
    341  
    342 SUBROUTINE init_metric(Ai_, Av_, fv_, le_de_, Riv2_, wee_) BINDC(init_metric) 
    343   DOUBLE1(primal_num) :: Ai_ 
    344   DOUBLE1(dual_num)   :: Av_, fv_ 
    345   DOUBLE1(edge_num)   :: le_de_ 
    346   DOUBLE2(max_dual_deg,dual_num) :: Riv2_ 
    347   DOUBLE2(max_trisk_deg,edge_num) :: wee_ 
    348   PRINT *, 'init_metric ...' 
    349   ALLOC1(Ai,primal_num) 
    350   ALLOC1(Av,dual_num) 
    351   ALLOC1(fv,dual_num) 
    352   ALLOC1(le_de,edge_num) 
    353   ALLOC2(Riv2, max_dual_deg, dual_num) 
    354   ALLOC2(wee, max_trisk_deg, edge_num) 
    355   Ai(:) = Ai_(:) 
    356   Av(:) = Av_(:) 
    357   fv(:) = fv_(:) 
    358   le_de(:) = le_de_(:) 
    359   Riv2(:,:)=Riv2_(:,:) 
    360   wee(:,:) = wee_(:,:) 
    361   PRINT *, MAXVAL(ABS(Ai)) 
    362   PRINT *, MAXVAL(ABS(Av)) 
    363   PRINT *, MAXVAL(ABS(fv)) 
    364   PRINT *, MAXVAL(ABS(le_de)) 
    365   PRINT *, MAXVAL(ABS(Riv2)) 
    366   PRINT *, MAXVAL(ABS(wee)) 
    367   PRINT *, MINVAL(right), MAXVAL(right) 
    368   PRINT *, MINVAL(right), MAXVAL(left) 
    369   PRINT *,' ... Done.' 
    370   IF(nb_threads==0) nb_threads=OMP_GET_MAX_THREADS() 
    371   PRINT *,'OpenMP : max_threads, num_procs, nb_threads', OMP_GET_MAX_THREADS(), omp_get_num_procs(), nb_threads 
    372  
    373 END SUBROUTINE init_metric 
    374 ! 
    375 SUBROUTINE init_params() BINDC(init_params) 
    376   PRINT *, 'Setting physical parameters ...' 
    377   IF(hydrostatic) THEN 
    378      PRINT *, 'Hydrostatic dynamics (HPE)' 
    379   ELSE 
    380      PRINT *, 'Non-hydrostatic dynamics (Euler)' 
    381   END IF 
    382   kappa = Rd/cpp 
    383   PRINT *, 'g = ',g 
    384   PRINT *, 'preff = ',preff 
    385   PRINT *, 'Treff = ',Treff 
    386   PRINT *, 'Rd = ',Rd 
    387   PRINT *, 'cpp = ',cpp 
    388   PRINT *, 'kappa = ',kappa 
    389   PRINT *, '... Done' 
    390 END SUBROUTINE init_params 
    391 ! 
    392 SUBROUTINE init_hybrid(bl,dak,dbk) BINDC(init_hybrid) 
    393   DOUBLE2(llm+1, primal_num) :: bl 
    394   DOUBLE2(llm, primal_num) :: dak,dbk 
    395   PRINT *, 'Setting hybrid coefficients ...' 
    396   ALLOC2(mass_bl, llm+1, primal_num) 
    397   ALLOC2(mass_dak, llm, primal_num) 
    398   ALLOC2(mass_dbk, llm, primal_num) 
    399   mass_bl(:,:)  = bl(:,:) 
    400   mass_dak(:,:) = dak(:,:) 
    401   mass_dbk(:,:) = dbk(:,:) 
    402   PRINT *, '... Done, llm = ', llm 
    403 END SUBROUTINE Init_hybrid 
    404  
    405 !---------------------------------------------- XIOS ----------------------------------------- 
    406  
    407 #ifdef CPP_USING_XIOS 
    408  
    409   SUBROUTINE setup_xios() BINDC(setup_xios) 
    410     ! MPI_INIT / MPI_finalize are assumed to be called BEFORE/AFTER this routine 
    411     ! This is the case when calling from Python after importing mpi4py 
    412     INTEGER :: ierr, mpi_threading_mode 
    413      
    414     PRINT *, 'Initialize XIOS and obtain our communicator' 
    415     CALL xios_initialize("icosagcm",return_comm=comm_icosa) 
    416      
    417     PRINT *, 'Initialize our XIOS context' 
    418      
    419     CALL xios_context_initialize("icosagcm",comm_icosa) 
    420     CALL xios_get_handle("icosagcm",ctx_hdl) 
    421     CALL xios_set_current_context(ctx_hdl) 
    422     !   CALL xios_set_axis_attr("lev",n_glo=llm ,value=lev_value) ; 
    423     !   CALL xios_set_axis_attr("levp1",n_glo=llm+1 ,value=lev_valuep1) ; 
    424     !   CALL xios_set_axis_attr("nq",n_glo=nqtot, value=nq_value) ; 
    425     !   CALL xios_set_domaingroup_attr("i",ni_glo=ncell_tot, ibegin=displ, ni=ncell) 
    426     !   CALL xios_set_domaingroup_attr("i", data_dim=1, type='unstructured' , nvertex=6, i_index=ind_glo) 
    427     !   CALL xios_set_domaingroup_attr("i",lonvalue_1d=lon, latvalue_1d=lat, bounds_lon_1d=bounds_lon, bounds_lat_1d=bounds_lat) 
    428     !   CALL xios_set_domain_attr("u",ni_glo=ncell_tot, ibegin=displ, ni=ncell) 
    429     !   CALL xios_set_domain_attr("u", data_dim=1, type='unstructured' , nvertex=2, i_index=ind_glo) 
    430     !  CALL xios_set_domain_attr("u",lonvalue_1d=lon, latvalue_1d=lat, bounds_lon_1d=bounds_lon, bounds_lat_1d=bounds_lat) 
    431     !   CALL xios_set_domain_attr("v",ni_glo=ncell_tot, ibegin=displ, ni=ncell) 
    432     !   CALL xios_set_domain_attr("v", data_dim=1, type='unstructured' , nvertex=3) 
    433     !   CALL xios_set_domain_attr("v",lonvalue_1d=lon, latvalue_1d=lat, bounds_lon_1d=bounds_lon, bounds_lat_1d=bounds_lat) 
    434     !   CALL xios_set_timestep(dtime)   
    435     !   CALL xios_set_fieldgroup_attr("standard_output", freq_op=itau_out*xios_timestep, freq_offset=(itau_out-1)*xios_timestep)     
    436     ! CALL xios_close_context_definition() 
    437      
    438     ! PRINT *, 'Read data' 
    439     ! CALL xios_recv_field(name,field) 
    440      
    441     ! PRINT *,'Write data' 
    442     ! CALL xios_send_field(name,field_tmp) 
    443      
    444    !   PRINT *, 'Flush to disk, clean up and die' 
    445    !   CALL xios_context_finalize 
    446   END SUBROUTINE setup_xios 
    447 ! 
    448   SUBROUTINE call_xios_set_timestep(dt) BINDC(xios_set_timestep) 
    449     DBL, VALUE :: dt 
    450     TYPE(xios_duration)      :: dtime 
    451     dtime%second=dt 
    452     CALL xios_set_timestep(dtime) 
    453   END SUBROUTINE call_xios_set_timestep 
    454  
    455   SUBROUTINE call_xios_update_calendar(step) BINDC(xios_update_calendar) 
    456     INDEX, value :: step 
    457     CALL xios_update_calendar(step) 
    458   END SUBROUTINE call_xios_update_calendar 
    459  
    460 #endif 
    461172 
    462173END MODULE caldyn_unstructured_mod 
Note: See TracChangeset for help on using the changeset viewer.